support document as an extended query selector and plug it in for the from: clause in triggers

This commit is contained in:
carson 2021-07-06 15:27:51 -06:00
parent a28b7f865b
commit bbf2ae4412
2 changed files with 93 additions and 73 deletions

View File

@ -364,6 +364,8 @@ return (function () {
return [closest(elt, selector.substr(8))]; return [closest(elt, selector.substr(8))];
} else if (selector.indexOf("find ") === 0) { } else if (selector.indexOf("find ") === 0) {
return [find(elt, selector.substr(5))]; return [find(elt, selector.substr(5))];
} else if (selector === 'document') {
return [document];
} else { } else {
return getDocument().querySelectorAll(selector); return getDocument().querySelectorAll(selector);
} }
@ -988,86 +990,90 @@ return (function () {
} }
function addEventListener(elt, verb, path, nodeData, triggerSpec, explicitCancel) { function addEventListener(elt, verb, path, nodeData, triggerSpec, explicitCancel) {
var eltToListenOn = elt; var eltsToListenOn;
if (triggerSpec.from) { if (triggerSpec.from) {
eltToListenOn = find(triggerSpec.from); eltsToListenOn = querySelectorAllExt(elt, triggerSpec.from);
} else {
eltsToListenOn = [elt];
} }
var eventListener = function (evt) { forEach(eltsToListenOn, function (eltToListenOn) {
if (!bodyContains(elt)) { var eventListener = function (evt) {
eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener); if (!bodyContains(elt)) {
return; eltToListenOn.removeEventListener(triggerSpec.trigger, eventListener);
}
if (ignoreBoostedAnchorCtrlClick(elt, evt)) {
return;
}
if(explicitCancel || shouldCancel(elt)){
evt.preventDefault();
}
if (maybeFilterEvent(triggerSpec, evt)) {
return;
}
var eventData = getInternalData(evt);
eventData.triggerSpec = triggerSpec;
if (eventData.handledFor == null) {
eventData.handledFor = [];
}
var elementData = getInternalData(elt);
if (eventData.handledFor.indexOf(elt) < 0) {
eventData.handledFor.push(elt);
if (triggerSpec.consume) {
evt.stopPropagation();
}
if (triggerSpec.target && evt.target) {
if (!matches(evt.target, triggerSpec.target)) {
return;
}
}
if (triggerSpec.once) {
if (elementData.triggeredOnce) {
return;
} else {
elementData.triggeredOnce = true;
}
}
if (triggerSpec.changed) {
if (elementData.lastValue === elt.value) {
return;
} else {
elementData.lastValue = elt.value;
}
}
if (elementData.delayed) {
clearTimeout(elementData.delayed);
}
if (elementData.throttle) {
return; return;
} }
if (ignoreBoostedAnchorCtrlClick(elt, evt)) {
if (triggerSpec.throttle) { return;
if(!elementData.throttle) {
issueAjaxRequest(verb, path, elt, evt);
elementData.throttle = setTimeout(function(){
elementData.throttle = null;
}, triggerSpec.throttle);
}
} else if (triggerSpec.delay) {
elementData.delayed = setTimeout(function(){
issueAjaxRequest(verb, path, elt, evt);
}, triggerSpec.delay);
} else {
issueAjaxRequest(verb, path, elt, evt);
} }
if (explicitCancel || shouldCancel(elt)) {
evt.preventDefault();
}
if (maybeFilterEvent(triggerSpec, evt)) {
return;
}
var eventData = getInternalData(evt);
eventData.triggerSpec = triggerSpec;
if (eventData.handledFor == null) {
eventData.handledFor = [];
}
var elementData = getInternalData(elt);
if (eventData.handledFor.indexOf(elt) < 0) {
eventData.handledFor.push(elt);
if (triggerSpec.consume) {
evt.stopPropagation();
}
if (triggerSpec.target && evt.target) {
if (!matches(evt.target, triggerSpec.target)) {
return;
}
}
if (triggerSpec.once) {
if (elementData.triggeredOnce) {
return;
} else {
elementData.triggeredOnce = true;
}
}
if (triggerSpec.changed) {
if (elementData.lastValue === elt.value) {
return;
} else {
elementData.lastValue = elt.value;
}
}
if (elementData.delayed) {
clearTimeout(elementData.delayed);
}
if (elementData.throttle) {
return;
}
if (triggerSpec.throttle) {
if (!elementData.throttle) {
issueAjaxRequest(verb, path, elt, evt);
elementData.throttle = setTimeout(function () {
elementData.throttle = null;
}, triggerSpec.throttle);
}
} else if (triggerSpec.delay) {
elementData.delayed = setTimeout(function () {
issueAjaxRequest(verb, path, elt, evt);
}, triggerSpec.delay);
} else {
issueAjaxRequest(verb, path, elt, evt);
}
}
};
if (nodeData.listenerInfos == null) {
nodeData.listenerInfos = [];
} }
}; nodeData.listenerInfos.push({
if (nodeData.listenerInfos == null) { trigger: triggerSpec.trigger,
nodeData.listenerInfos = []; listener: eventListener,
} on: eltToListenOn
nodeData.listenerInfos.push({ })
trigger: triggerSpec.trigger, eltToListenOn.addEventListener(triggerSpec.trigger, eventListener);
listener: eventListener,
on: eltToListenOn
}) })
eltToListenOn.addEventListener(triggerSpec.trigger, eventListener);
} }
var windowIsScrolling = false // used by initScrollHandler var windowIsScrolling = false // used by initScrollHandler

View File

@ -381,6 +381,20 @@ describe("hx-trigger attribute", function(){
div1.innerHTML.should.equal("Requests: 1"); div1.innerHTML.should.equal("Requests: 1");
}); });
it('from clause works with document selector', function()
{
var requests = 0;
this.server.respondWith("GET", "/test", function (xhr) {
requests++;
xhr.respond(200, {}, "Requests: " + requests);
});
var div1 = make('<div hx-trigger="foo from:document" hx-get="/test">Requests: 0</div>');
div1.innerHTML.should.equal("Requests: 0");
htmx.trigger(document, 'foo');
this.server.respond();
div1.innerHTML.should.equal("Requests: 1");
});
it('event listeners on other elements are removed when an element is swapped out', function() it('event listeners on other elements are removed when an element is swapped out', function()
{ {
var requests = 0; var requests = 0;