mirror of
https://github.com/bigskysoftware/htmx.git
synced 2025-09-30 14:31:47 +00:00
hook in tokenizer implementation
This commit is contained in:
parent
586829e097
commit
18220b3283
135
src/htmx.js
135
src/htmx.js
@ -366,7 +366,7 @@ return (function () {
|
||||
} else if (targetStr.indexOf("closest ") === 0) {
|
||||
return closest(elt, targetStr.substr(8));
|
||||
} else if (targetStr.indexOf("find ") === 0) {
|
||||
return find(elt, targetStr.substr(5));
|
||||
return find(elt, targetStr.substr(5));
|
||||
} else {
|
||||
return getDocument().querySelector(targetStr);
|
||||
}
|
||||
@ -642,6 +642,7 @@ return (function () {
|
||||
var SYMBOL_START = /[_$a-zA-Z]/;
|
||||
var SYMBOL_CONT = /[_$a-zA-Z0-9]/;
|
||||
var STRINGISH_START = ['"', "'", "/"];
|
||||
var NOT_WHITESPACE = /[^\s]/;
|
||||
function tokenizeString(str) {
|
||||
var tokens = [];
|
||||
var position = 0;
|
||||
@ -673,19 +674,20 @@ return (function () {
|
||||
return tokens;
|
||||
}
|
||||
|
||||
function isPossibleRelativeReference(token, last) {
|
||||
return SYMBOL_START.exec(token.charAt(0)) &&
|
||||
token !== "true" &&
|
||||
token !== "false" &&
|
||||
token !== "this" &&
|
||||
last !== ".";
|
||||
}
|
||||
function isPossibleRelativeReference(token, last, paramName) {
|
||||
return SYMBOL_START.exec(token.charAt(0)) &&
|
||||
token !== "true" &&
|
||||
token !== "false" &&
|
||||
token !== "this" &&
|
||||
token !== paramName &&
|
||||
last !== ".";
|
||||
}
|
||||
|
||||
function maybeGenerateConditional(tokens) {
|
||||
function maybeGenerateConditional(tokens, paramName) {
|
||||
if (tokens[0] === '[') {
|
||||
tokens.shift();
|
||||
var bracketCount = 1;
|
||||
var conditional = "(function(__val){ return (";
|
||||
var conditional = "(function(" + paramName + "){ return (";
|
||||
var last = null;
|
||||
while (tokens.length > 0) {
|
||||
var token = tokens[0];
|
||||
@ -696,13 +698,18 @@ return (function () {
|
||||
conditional = conditional + "true";
|
||||
}
|
||||
tokens.shift();
|
||||
return conditional + ")})";
|
||||
conditional += ")})";
|
||||
try {
|
||||
return eval(conditional);
|
||||
} catch (e) {
|
||||
triggerErrorEvent(getDocument(), "htmx:syntax:error", {error:e})
|
||||
}
|
||||
}
|
||||
} else if (token === "[") {
|
||||
bracketCount++;
|
||||
}
|
||||
if (isPossibleRelativeReference(token, last)) {
|
||||
conditional = conditional += "((__val." + token + ") ? (__val." + token + ") : (" + token + "))";
|
||||
if (isPossibleRelativeReference(token, last, paramName)) {
|
||||
conditional += "((" + paramName + "." + token + ") ? (" + paramName + "." + token + ") : (window." + token + "))";
|
||||
} else {
|
||||
conditional = conditional + token;
|
||||
}
|
||||
@ -711,49 +718,73 @@ return (function () {
|
||||
}
|
||||
}
|
||||
|
||||
function consumeUntil(tokens, match) {
|
||||
var result = "";
|
||||
while (tokens.length > 0 && !tokens[0].match(match)) {
|
||||
result += tokens.shift();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function getTriggerSpecs(elt) {
|
||||
|
||||
var explicitTrigger = getAttributeValue(elt, 'hx-trigger');
|
||||
var triggerSpecs = [];
|
||||
if (explicitTrigger) {
|
||||
var triggerSpecs = explicitTrigger.split(',').map(function(triggerString) {
|
||||
var tokens = splitOnWhitespace(triggerString.trim());
|
||||
var trigger = tokens[0]; // splitOnWhitespace returns at least one element
|
||||
if (!trigger)
|
||||
return null;
|
||||
|
||||
if (trigger === "every")
|
||||
return {trigger: 'every', pollInterval: parseInterval(tokens[1])};
|
||||
if (trigger.indexOf("sse:") === 0)
|
||||
return {trigger: 'sse', sseEvent: trigger.substr(4)};
|
||||
|
||||
var triggerSpec = {trigger: trigger};
|
||||
for (var i = 1; i < tokens.length; i++) {
|
||||
var token = tokens[i].trim();
|
||||
if (token === "changed") {
|
||||
triggerSpec.changed = true;
|
||||
}
|
||||
if (token === "once") {
|
||||
triggerSpec.once = true;
|
||||
}
|
||||
if (token.indexOf("delay:") === 0) {
|
||||
triggerSpec.delay = parseInterval(token.substr(6));
|
||||
}
|
||||
if (token.indexOf("throttle:") === 0) {
|
||||
triggerSpec.throttle = parseInterval(token.substr(9));
|
||||
var tokens = tokenizeString(explicitTrigger);
|
||||
do {
|
||||
consumeUntil(tokens, NOT_WHITESPACE);
|
||||
var initialLength = tokens.length;
|
||||
var trigger = consumeUntil(tokens, /[,\[\s]/);
|
||||
if (trigger !== "") {
|
||||
if (trigger === "every") {
|
||||
var every = {trigger: 'every'};
|
||||
consumeUntil(tokens, NOT_WHITESPACE);
|
||||
every.pollInterval = parseInterval(consumeUntil(tokens, WHITESPACE));
|
||||
triggerSpecs.push(every);
|
||||
} else if (trigger.indexOf("sse:") === 0) {
|
||||
triggerSpecs.push({trigger: 'sse', sseEvent: trigger.substr(4)});
|
||||
} else {
|
||||
var triggerSpec = {trigger: trigger};
|
||||
var eventFilter = maybeGenerateConditional(tokens, "evt");
|
||||
if (eventFilter) {
|
||||
triggerSpec.eventFilter = eventFilter;
|
||||
}
|
||||
while (tokens.length > 0 && tokens[0] !== ",") {
|
||||
consumeUntil(tokens, NOT_WHITESPACE)
|
||||
var token = tokens.shift();
|
||||
if (token === "changed") {
|
||||
triggerSpec.changed = true;
|
||||
} else if (token === "once") {
|
||||
triggerSpec.once = true;
|
||||
} else if (token === "delay" && tokens[0] === ":") {
|
||||
tokens.shift();
|
||||
triggerSpec.delay = parseInterval(consumeUntil(tokens, WHITESPACE));
|
||||
} else if (token === "throttle" && tokens[0] === ":") {
|
||||
tokens.shift();
|
||||
triggerSpec.throttle = parseInterval(consumeUntil(tokens, WHITESPACE));
|
||||
} else {
|
||||
triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()});
|
||||
}
|
||||
}
|
||||
triggerSpecs.push(triggerSpec);
|
||||
}
|
||||
}
|
||||
return triggerSpec;
|
||||
}).filter(function(x){ return x !== null });
|
||||
|
||||
if (triggerSpecs.length)
|
||||
return triggerSpecs;
|
||||
if (tokens.length === initialLength) {
|
||||
triggerErrorEvent(elt, "htmx:syntax:error", {token:tokens.shift()});
|
||||
}
|
||||
consumeUntil(tokens, NOT_WHITESPACE);
|
||||
} while (tokens[0] === "," && tokens.shift())
|
||||
}
|
||||
|
||||
if (matches(elt, 'form'))
|
||||
if (triggerSpecs.length > 0) {
|
||||
return triggerSpecs;
|
||||
} else if (matches(elt, 'form')) {
|
||||
return [{trigger: 'submit'}];
|
||||
if (matches(elt, 'input, textarea, select'))
|
||||
} else if (matches(elt, 'input, textarea, select')) {
|
||||
return [{trigger: 'change'}];
|
||||
return [{trigger: 'click'}];
|
||||
} else {
|
||||
return [{trigger: 'click'}];
|
||||
}
|
||||
}
|
||||
|
||||
function cancelPolling(elt) {
|
||||
@ -806,6 +837,10 @@ return (function () {
|
||||
|
||||
function addEventListener(elt, verb, path, nodeData, triggerSpec, explicitCancel) {
|
||||
var eventListener = function (evt) {
|
||||
if (triggerSpec.eventFilter &&
|
||||
triggerSpec.eventFilter(evt) !== true) {
|
||||
return;
|
||||
}
|
||||
if (ignoreBoostedAnchorCtrlClick(elt, evt)) {
|
||||
return;
|
||||
}
|
||||
@ -972,7 +1007,7 @@ return (function () {
|
||||
if (value[0] === "connect") {
|
||||
processSSESource(elt, value[1]);
|
||||
}
|
||||
|
||||
|
||||
if ((value[0] === "swap")) {
|
||||
processSSESwap(elt, value[1])
|
||||
}
|
||||
@ -1000,12 +1035,12 @@ return (function () {
|
||||
|
||||
///////////////////////////
|
||||
// TODO: merge this code with AJAX and WebSockets code in the future.
|
||||
|
||||
|
||||
var response = event.data;
|
||||
withExtensions(elt, function(extension){
|
||||
response = extension.transformResponse(response, null, elt);
|
||||
});
|
||||
|
||||
|
||||
var swapSpec = getSwapSpecification(elt)
|
||||
var target = getTarget(elt)
|
||||
var settleInfo = makeSettleInfo(elt);
|
||||
|
@ -89,7 +89,6 @@ describe("hx-trigger attribute", function(){
|
||||
it('non-default value works w/ data-* prefix', function()
|
||||
{
|
||||
this.server.respondWith("GET", "/test", "Clicked!");
|
||||
|
||||
var form = make('<form data-hx-get="/test" data-hx-trigger="click">Click Me!</form>');
|
||||
form.click();
|
||||
form.innerHTML.should.equal("Click Me!");
|
||||
@ -113,8 +112,6 @@ describe("hx-trigger attribute", function(){
|
||||
div.innerHTML.should.equal("Requests: 2");
|
||||
});
|
||||
|
||||
|
||||
|
||||
it("parses spec strings", function()
|
||||
{
|
||||
var specExamples = {
|
||||
@ -131,9 +128,7 @@ describe("hx-trigger attribute", function(){
|
||||
"event1, event2": [{trigger: 'event1'}, {trigger: 'event2'}],
|
||||
"event1 once, event2 changed": [{trigger: 'event1', once: true}, {trigger: 'event2', changed: true}],
|
||||
"event1,": [{trigger: 'event1'}],
|
||||
",event1": [{trigger: 'event1'}],
|
||||
" ": [{trigger: 'click'}],
|
||||
",": [{trigger: 'click'}]
|
||||
}
|
||||
|
||||
for (var specString in specExamples) {
|
||||
@ -157,4 +152,19 @@ describe("hx-trigger attribute", function(){
|
||||
spec.should.deep.equal([{trigger: 'change'}]);
|
||||
})
|
||||
|
||||
it('filters properly with filter spec', function(){
|
||||
this.server.respondWith("GET", "/test", "Called!");
|
||||
var form = make('<form hx-get="/test" hx-trigger="evt[foo]">Not Called</form>');
|
||||
form.click();
|
||||
form.innerHTML.should.equal("Not Called");
|
||||
var event = htmx._("makeEvent")('evt');
|
||||
form.dispatchEvent(event);
|
||||
this.server.respond();
|
||||
form.innerHTML.should.equal("Not Called");
|
||||
event.foo = true;
|
||||
form.dispatchEvent(event);
|
||||
this.server.respond();
|
||||
form.innerHTML.should.equal("Called!");
|
||||
})
|
||||
|
||||
})
|
||||
|
@ -19,16 +19,16 @@ describe("Core htmx tokenizer tests", function(){
|
||||
it('tokenizes properly', function()
|
||||
{
|
||||
tokenizeTest("", []);
|
||||
tokenizeTest(" ", []);
|
||||
tokenizeTest(" ", [" ", " "]);
|
||||
tokenizeTest("(", ["("]);
|
||||
tokenizeTest("()", ["(", ")"]);
|
||||
tokenizeTest("(,)", ["(", ",", ")"]);
|
||||
tokenizeTest(" ( ) ", ["(", ")"]);
|
||||
tokenizeTest(" && ) ", ["&&", ")"]);
|
||||
tokenizeTest(" && ) 'asdf'", ["&&", ")", "'asdf'"]);
|
||||
tokenizeTest(" && ) ',asdf'", ["&&", ")", "',asdf'"]);
|
||||
tokenizeTest(" ( ) ", [" ", "(", " ", ")", " "]);
|
||||
tokenizeTest(" && ) ", [" ", "&", "&", " ", ")", " "]);
|
||||
tokenizeTest(" && ) 'asdf'", [" ", "&", "&", " ", ")", " ", "'asdf'"]);
|
||||
tokenizeTest(" && ) ',asdf'", [" ", "&", "&", " ", ")", " ", "',asdf'"]);
|
||||
tokenizeTest('",asdf"', ['",asdf"']);
|
||||
tokenizeTest('&& ) ",asdf"', ["&&", ")", '",asdf"']);
|
||||
tokenizeTest('&& ) ",asdf"', ["&", "&", " ", ")", " ", '",asdf"']);
|
||||
});
|
||||
|
||||
it('generates conditionals property', function()
|
||||
|
Loading…
x
Reference in New Issue
Block a user