htmx.org 4.0.0-alpha4 → 4.0.0-alpha6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,7 +10,7 @@
10
10
  }
11
11
  }
12
12
 
13
- htmx.defineExtension('compat', {
13
+ htmx.registerExtension('compat', {
14
14
  init: (internalAPI) => {
15
15
  api = internalAPI;
16
16
 
@@ -24,14 +24,68 @@
24
24
  htmx.config.noSwap.push("4xx", "5xx");
25
25
  }
26
26
  },
27
- htmx_after_implicitInheritance : function(elt, detail) {
28
- // TODO - how should we alert users? collect a report? just log?
29
- // TODO - needs a config option to enable
27
+ // Re-delegate new events to old event names for backwards compatibility
28
+ htmx_after_implicitInheritance: function (elt, detail) {
29
+ if (!htmx.config.compat?.suppressInheritanceLogs) {
30
+ console.log("IMPLICIT INHERITANCE DETECTED, attribute: " + detail.name + ", elt: ", elt, ", inherited from: ", detail.parent)
31
+ let evt = new CustomEvent("htmxImplicitInheritace", {
32
+ detail,
33
+ cancelable: true,
34
+ bubbles : true,
35
+ composed: true,
36
+ });
37
+ elt.dispatchEvent(evt)
38
+ }
30
39
  },
31
- // TODO - catch all new events and redelegate to old event names as best we can
32
- // this can probably be done as a map... See www/content/migration-guide-htmx-4.md:94
33
40
  htmx_after_init: function (elt, detail) {
34
41
  maybeRetriggerEvent(elt, "htmx:afterOnLoad", detail);
42
+ maybeRetriggerEvent(elt, "htmx:afterProcessNode", detail);
43
+ maybeRetriggerEvent(elt, "htmx:load", detail);
44
+ },
45
+ htmx_after_request: function (elt, detail) {
46
+ maybeRetriggerEvent(elt, "htmx:afterRequest", detail);
47
+ },
48
+ htmx_after_swap: function (elt, detail) {
49
+ maybeRetriggerEvent(elt, "htmx:afterSettle", detail);
50
+ maybeRetriggerEvent(elt, "htmx:afterSwap", detail);
51
+ },
52
+ htmx_before_cleanup: function (elt, detail) {
53
+ maybeRetriggerEvent(elt, "htmx:beforeCleanupElement", detail);
54
+ },
55
+ htmx_before_history_update: function (elt, detail) {
56
+ maybeRetriggerEvent(elt, "htmx:beforeHistoryUpdate", detail);
57
+ maybeRetriggerEvent(elt, "htmx:beforeHistorySave", detail);
58
+ },
59
+ htmx_before_init: function (elt, detail) {
60
+ maybeRetriggerEvent(elt, "htmx:beforeOnLoad", detail);
61
+ },
62
+ htmx_before_process: function (elt, detail) {
63
+ maybeRetriggerEvent(elt, "htmx:beforeProcessNode", detail);
64
+ },
65
+ htmx_before_request: function (elt, detail) {
66
+ maybeRetriggerEvent(elt, "htmx:beforeRequest", detail);
67
+ maybeRetriggerEvent(elt, "htmx:beforeSend", detail);
68
+ },
69
+ htmx_before_swap: function (elt, detail) {
70
+ maybeRetriggerEvent(elt, "htmx:beforeSwap", detail);
71
+ },
72
+ htmx_before_viewTransition: function (elt, detail) {
73
+ maybeRetriggerEvent(elt, "htmx:beforeTransition", detail);
74
+ },
75
+ htmx_config_request: function (elt, detail) {
76
+ maybeRetriggerEvent(elt, "htmx:configRequest", detail);
77
+ },
78
+ htmx_before_restore_history: function (elt, detail) {
79
+ maybeRetriggerEvent(elt, "htmx:historyRestore", detail);
80
+ },
81
+ htmx_after_push_into_history: function (elt, detail) {
82
+ maybeRetriggerEvent(elt, "htmx:pushedIntoHistory", detail);
83
+ },
84
+ htmx_after_replace_into_history: function (elt, detail) {
85
+ maybeRetriggerEvent(elt, "htmx:replacedInHistory", detail);
86
+ },
87
+ htmx_error: function (elt, detail) {
88
+ maybeRetriggerEvent(elt, "htmx:targetError", detail);
35
89
  },
36
90
  });
37
91
  })()
@@ -1 +1 @@
1
- (()=>{let t;htmx.defineExtension("compat",{init:i=>{t=i,htmx.config.compat?.useExplicitInheritace||(htmx.config.implicitInheritance=!0),htmx.config.compat?.swapErrorResponseCodes||htmx.config.noSwap.push("4xx","5xx")},htmx_after_implicitInheritance:function(t,i){},htmx_after_init:function(t,i){!function(t,i,n){htmx.config.compat?.doNotTriggerOldEvents||htmx.trigger(t,i,n)}(t,"htmx:afterOnLoad",i)}})})();
1
+ (()=>{let t;function e(t,e,o){htmx.config.compat?.doNotTriggerOldEvents||htmx.trigger(t,e,o)}htmx.registerExtension("compat",{init:e=>{t=e,htmx.config.compat?.useExplicitInheritace||(htmx.config.implicitInheritance=!0),htmx.config.compat?.swapErrorResponseCodes||htmx.config.noSwap.push("4xx","5xx")},htmx_after_implicitInheritance:function(t,e){if(!htmx.config.compat?.suppressInheritanceLogs){console.log("IMPLICIT INHERITANCE DETECTED, attribute: "+e.name+", elt: ",t,", inherited from: ",e.parent);let o=new CustomEvent("htmxImplicitInheritace",{detail:e,cancelable:!0,bubbles:!0,composed:!0});t.dispatchEvent(o)}},htmx_after_init:function(t,o){e(t,"htmx:afterOnLoad",o),e(t,"htmx:afterProcessNode",o),e(t,"htmx:load",o)},htmx_after_request:function(t,o){e(t,"htmx:afterRequest",o)},htmx_after_swap:function(t,o){e(t,"htmx:afterSettle",o),e(t,"htmx:afterSwap",o)},htmx_before_cleanup:function(t,o){e(t,"htmx:beforeCleanupElement",o)},htmx_before_history_update:function(t,o){e(t,"htmx:beforeHistoryUpdate",o),e(t,"htmx:beforeHistorySave",o)},htmx_before_init:function(t,o){e(t,"htmx:beforeOnLoad",o)},htmx_before_process:function(t,o){e(t,"htmx:beforeProcessNode",o)},htmx_before_request:function(t,o){e(t,"htmx:beforeRequest",o),e(t,"htmx:beforeSend",o)},htmx_before_swap:function(t,o){e(t,"htmx:beforeSwap",o)},htmx_before_viewTransition:function(t,o){e(t,"htmx:beforeTransition",o)},htmx_config_request:function(t,o){e(t,"htmx:configRequest",o)},htmx_before_restore_history:function(t,o){e(t,"htmx:historyRestore",o)},htmx_after_push_into_history:function(t,o){e(t,"htmx:pushedIntoHistory",o)},htmx_after_replace_into_history:function(t,o){e(t,"htmx:replacedInHistory",o)},htmx_error:function(t,o){e(t,"htmx:targetError",o)}})})();
@@ -1 +1 @@
1
- {"version":3,"names":["api","htmx","defineExtension","init","internalAPI","config","compat","useExplicitInheritace","implicitInheritance","swapErrorResponseCodes","noSwap","push","htmx_after_implicitInheritance","elt","detail","htmx_after_init","evtName","doNotTriggerOldEvents","trigger","maybeRetriggerEvent"],"sources":["dist/ext/hx-compat.js"],"mappings":"AAAA,MAII,IAAIA,EAQJC,KAAKC,gBAAgB,SAAU,CAC3BC,KAAOC,IACHJ,EAAMI,EAGDH,KAAKI,OAAOC,QAAQC,wBACrBN,KAAKI,OAAOG,qBAAsB,GAIjCP,KAAKI,OAAOC,QAAQG,wBACrBR,KAAKI,OAAOK,OAAOC,KAAK,MAAO,QAGvCC,+BAAiC,SAASC,EAAKC,GAG/C,EAGAC,gBAAiB,SAAUF,EAAKC,IA1BpC,SAA6BD,EAAKG,EAASF,GAClCb,KAAKI,OAAOC,QAAQW,uBACrBhB,KAAKiB,QAAQL,EAAKG,EAASF,EAEnC,CAuBQK,CAAoBN,EAAK,mBAAoBC,EACjD,GAEP,EApCD","ignoreList":[]}
1
+ {"version":3,"names":["api","maybeRetriggerEvent","elt","evtName","detail","htmx","config","compat","doNotTriggerOldEvents","trigger","registerExtension","init","internalAPI","useExplicitInheritace","implicitInheritance","swapErrorResponseCodes","noSwap","push","htmx_after_implicitInheritance","suppressInheritanceLogs","console","log","name","parent","evt","CustomEvent","cancelable","bubbles","composed","dispatchEvent","htmx_after_init","htmx_after_request","htmx_after_swap","htmx_before_cleanup","htmx_before_history_update","htmx_before_init","htmx_before_process","htmx_before_request","htmx_before_swap","htmx_before_viewTransition","htmx_config_request","htmx_before_restore_history","htmx_after_push_into_history","htmx_after_replace_into_history","htmx_error"],"sources":["dist/ext/hx-compat.js"],"mappings":"AAAA,MAII,IAAIA,EAEJ,SAASC,EAAoBC,EAAKC,EAASC,GAClCC,KAAKC,OAAOC,QAAQC,uBACrBH,KAAKI,QAAQP,EAAKC,EAASC,EAEnC,CAEAC,KAAKK,kBAAkB,SAAU,CAC7BC,KAAOC,IACHZ,EAAMY,EAGDP,KAAKC,OAAOC,QAAQM,wBACrBR,KAAKC,OAAOQ,qBAAsB,GAIjCT,KAAKC,OAAOC,QAAQQ,wBACrBV,KAAKC,OAAOU,OAAOC,KAAK,MAAO,QAIvCC,+BAAgC,SAAUhB,EAAKE,GAC3C,IAAKC,KAAKC,OAAOC,QAAQY,wBAAyB,CAC9CC,QAAQC,IAAI,6CAA+CjB,EAAOkB,KAAO,UAAWpB,EAAK,qBAAsBE,EAAOmB,QACtH,IAAIC,EAAM,IAAIC,YAAY,yBAA0B,CAChDrB,SACAsB,YAAY,EACZC,SAAU,EACVC,UAAU,IAEd1B,EAAI2B,cAAcL,EACtB,CACJ,EACAM,gBAAiB,SAAU5B,EAAKE,GAC5BH,EAAoBC,EAAK,mBAAoBE,GAC7CH,EAAoBC,EAAK,wBAAyBE,GAClDH,EAAoBC,EAAK,YAAaE,EAC1C,EACA2B,mBAAoB,SAAU7B,EAAKE,GAC/BH,EAAoBC,EAAK,oBAAqBE,EAClD,EACA4B,gBAAiB,SAAU9B,EAAKE,GAC5BH,EAAoBC,EAAK,mBAAoBE,GAC7CH,EAAoBC,EAAK,iBAAkBE,EAC/C,EACA6B,oBAAqB,SAAU/B,EAAKE,GAChCH,EAAoBC,EAAK,4BAA6BE,EAC1D,EACA8B,2BAA4B,SAAUhC,EAAKE,GACvCH,EAAoBC,EAAK,2BAA4BE,GACrDH,EAAoBC,EAAK,yBAA0BE,EACvD,EACA+B,iBAAkB,SAAUjC,EAAKE,GAC7BH,EAAoBC,EAAK,oBAAqBE,EAClD,EACAgC,oBAAqB,SAAUlC,EAAKE,GAChCH,EAAoBC,EAAK,yBAA0BE,EACvD,EACAiC,oBAAqB,SAAUnC,EAAKE,GAChCH,EAAoBC,EAAK,qBAAsBE,GAC/CH,EAAoBC,EAAK,kBAAmBE,EAChD,EACAkC,iBAAkB,SAAUpC,EAAKE,GAC7BH,EAAoBC,EAAK,kBAAmBE,EAChD,EACAmC,2BAA4B,SAAUrC,EAAKE,GACvCH,EAAoBC,EAAK,wBAAyBE,EACtD,EACAoC,oBAAqB,SAAUtC,EAAKE,GAChCH,EAAoBC,EAAK,qBAAsBE,EACnD,EACAqC,4BAA6B,SAAUvC,EAAKE,GACxCH,EAAoBC,EAAK,sBAAuBE,EACpD,EACAsC,6BAA8B,SAAUxC,EAAKE,GACzCH,EAAoBC,EAAK,yBAA0BE,EACvD,EACAuC,gCAAiC,SAAUzC,EAAKE,GAC5CH,EAAoBC,EAAK,yBAA0BE,EACvD,EACAwC,WAAY,SAAU1C,EAAKE,GACvBH,EAAoBC,EAAK,mBAAoBE,EACjD,GAEP,EA1FD","ignoreList":[]}
@@ -0,0 +1,129 @@
1
+ //==========================================================
2
+ // head-support.js
3
+ //
4
+ // An extension to add head tag merging.
5
+ //==========================================================
6
+ (function () {
7
+
8
+ let api
9
+
10
+ function log() {
11
+ //console.log(arguments)
12
+ }
13
+
14
+ function mergeHead(newContent, defaultMergeStrategy) {
15
+
16
+ if (newContent && newContent.indexOf('<head') > -1) {
17
+ const htmlDoc = document.createElement("html")
18
+ // remove svgs to avoid conflicts
19
+ let contentWithSvgsRemoved = newContent.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim, '')
20
+ // extract head tag
21
+ let headTag = contentWithSvgsRemoved.match(/(<head(\s[^>]*>|>)([\s\S]*?)<\/head>)/im)
22
+
23
+ // if the head tag exists...
24
+ if (headTag) {
25
+
26
+ let added = []
27
+ let removed = []
28
+ let preserved = []
29
+ let nodesToAppend = []
30
+
31
+ htmlDoc.innerHTML = headTag
32
+ let newHeadTag = htmlDoc.querySelector("head")
33
+ let currentHead = document.head
34
+
35
+ if (newHeadTag == null) {
36
+ return
37
+ }
38
+
39
+ // put all new head elements into a Map, by their outerHTML
40
+ let srcToNewHeadNodes = new Map()
41
+ for (const newHeadChild of newHeadTag.children) {
42
+ srcToNewHeadNodes.set(newHeadChild.outerHTML, newHeadChild)
43
+ }
44
+
45
+ // determine merge strategy
46
+ let mergeStrategy = api.attributeValue(newHeadTag, "hx-head") || defaultMergeStrategy
47
+
48
+ // get the current head
49
+ for (const currentHeadElt of currentHead.children) {
50
+
51
+ // If the current head element is in the map
52
+ let inNewContent = srcToNewHeadNodes.has(currentHeadElt.outerHTML)
53
+ let isReAppended = currentHeadElt.getAttribute("hx-head") === "re-eval"
54
+ let isPreserved = api.attributeValue(currentHeadElt, "hx-preserve") === "true"
55
+ if (inNewContent || isPreserved) {
56
+ if (isReAppended) {
57
+ // remove the current version and let the new version replace it and re-execute
58
+ removed.push(currentHeadElt)
59
+ } else {
60
+ // this element already exists and should not be re-appended, so remove it from
61
+ // the new content map, preserving it in the DOM
62
+ srcToNewHeadNodes.delete(currentHeadElt.outerHTML)
63
+ preserved.push(currentHeadElt)
64
+ }
65
+ } else {
66
+ if (mergeStrategy === "append") {
67
+ // we are appending and this existing element is not new content
68
+ // so if and only if it is marked for re-append do we do anything
69
+ if (isReAppended) {
70
+ removed.push(currentHeadElt)
71
+ nodesToAppend.push(currentHeadElt)
72
+ }
73
+ } else {
74
+ // if this is a merge, we remove this content since it is not in the new head
75
+ if (htmx.trigger(document.body, "htmx:before:head:remove", {headElement: currentHeadElt}) !== false) {
76
+ removed.push(currentHeadElt)
77
+ }
78
+ }
79
+ }
80
+ }
81
+
82
+ // Push the remaining new head elements in the Map into the
83
+ // nodes to append to the head tag
84
+ nodesToAppend.push(...srcToNewHeadNodes.values())
85
+ log("to append: ", nodesToAppend)
86
+
87
+ for (const newNode of nodesToAppend) {
88
+ log("adding: ", newNode)
89
+ let newElt = document.createRange().createContextualFragment(newNode.outerHTML)
90
+ log(newElt)
91
+ if (htmx.trigger(document.body, "htmx:before:head:add", {headElement: newElt}) !== false) {
92
+ currentHead.appendChild(newElt)
93
+ added.push(newElt)
94
+ }
95
+ }
96
+
97
+ // remove all removed elements, after we have appended the new elements to avoid
98
+ // additional network requests for things like style sheets
99
+ for (const removedElement of removed) {
100
+ if (htmx.trigger(document.body, "htmx:before:head:remove", {headElement: removedElement}) !== false) {
101
+ currentHead.removeChild(removedElement)
102
+ }
103
+ }
104
+
105
+ htmx.trigger(document.body, "htmx:after:head:merge", {
106
+ added: added,
107
+ kept: preserved,
108
+ removed: removed
109
+ })
110
+ }
111
+ }
112
+ }
113
+
114
+ htmx.registerExtension("hx-head", {
115
+ init: (internalAPI) => {
116
+ api = internalAPI;
117
+ },
118
+ htmx_after_swap: (elt, detail) => {
119
+ let ctx = detail.ctx
120
+ let target = ctx.target
121
+ // TODO - is there a better way to handle this? it used to be based on if the element was boosted
122
+ let defaultMergeStrategy = target === document.body ? "merge" : "append";
123
+ if (htmx.trigger(document.body, "htmx:before:head:merge", detail)) {
124
+ mergeHead(ctx.text, defaultMergeStrategy)
125
+ }
126
+ }
127
+ })
128
+
129
+ })()
@@ -0,0 +1 @@
1
+ !function(){let e;function t(){}htmx.registerExtension("hx-head",{init:t=>{e=t},htmx_after_swap:(r,d)=>{let h=d.ctx,o=h.target===document.body?"merge":"append";htmx.trigger(document.body,"htmx:before:head:merge",d)&&function(r,d){if(r&&r.indexOf("<head")>-1){const h=document.createElement("html");let o=r.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"").match(/(<head(\s[^>]*>|>)([\s\S]*?)<\/head>)/im);if(o){let r=[],a=[],n=[],m=[];h.innerHTML=o;let u=h.querySelector("head"),l=document.head;if(null==u)return;let c=new Map;for(const e of u.children)c.set(e.outerHTML,e);let i=e.attributeValue(u,"hx-head")||d;for(const t of l.children){let r=c.has(t.outerHTML),d="re-eval"===t.getAttribute("hx-head"),h="true"===e.attributeValue(t,"hx-preserve");r||h?d?a.push(t):(c.delete(t.outerHTML),n.push(t)):"append"===i?d&&(a.push(t),m.push(t)):!1!==htmx.trigger(document.body,"htmx:before:head:remove",{headElement:t})&&a.push(t)}m.push(...c.values());for(const e of m){t();let d=document.createRange().createContextualFragment(e.outerHTML);t(),!1!==htmx.trigger(document.body,"htmx:before:head:add",{headElement:d})&&(l.appendChild(d),r.push(d))}for(const e of a)!1!==htmx.trigger(document.body,"htmx:before:head:remove",{headElement:e})&&l.removeChild(e);htmx.trigger(document.body,"htmx:after:head:merge",{added:r,kept:n,removed:a})}}}(h.text,o)}})}();
@@ -0,0 +1 @@
1
+ {"version":3,"names":["api","log","htmx","registerExtension","init","internalAPI","htmx_after_swap","elt","detail","ctx","defaultMergeStrategy","target","document","body","trigger","newContent","indexOf","htmlDoc","createElement","headTag","replace","match","added","removed","preserved","nodesToAppend","innerHTML","newHeadTag","querySelector","currentHead","head","srcToNewHeadNodes","Map","newHeadChild","children","set","outerHTML","mergeStrategy","attributeValue","currentHeadElt","inNewContent","has","isReAppended","getAttribute","isPreserved","push","delete","headElement","values","newNode","newElt","createRange","createContextualFragment","appendChild","removedElement","removeChild","kept","mergeHead","text"],"sources":["dist/ext/hx-head.js"],"mappings":"CAKA,WAEI,IAAIA,EAEJ,SAASC,IAET,CAsGAC,KAAKC,kBAAkB,UAAW,CAC9BC,KAAOC,IACHL,EAAMK,GAEVC,gBAAiB,CAACC,EAAKC,KACnB,IAAIC,EAAMD,EAAOC,IAGbC,EAFSD,EAAIE,SAEqBC,SAASC,KAAO,QAAU,SAC5DX,KAAKY,QAAQF,SAASC,KAAM,yBAA0BL,IA7GlE,SAAmBO,EAAYL,GAE3B,GAAIK,GAAcA,EAAWC,QAAQ,UAAY,EAAG,CAChD,MAAMC,EAAUL,SAASM,cAAc,QAEvC,IAEIC,EAFyBJ,EAAWK,QAAQ,uCAAwC,IAEnDC,MAAM,2CAG3C,GAAIF,EAAS,CAET,IAAIG,EAAQ,GACRC,EAAU,GACVC,EAAY,GACZC,EAAgB,GAEpBR,EAAQS,UAAYP,EACpB,IAAIQ,EAAaV,EAAQW,cAAc,QACnCC,EAAcjB,SAASkB,KAE3B,GAAkB,MAAdH,EACA,OAIJ,IAAII,EAAoB,IAAIC,IAC5B,IAAK,MAAMC,KAAgBN,EAAWO,SAClCH,EAAkBI,IAAIF,EAAaG,UAAWH,GAIlD,IAAII,EAAgBrC,EAAIsC,eAAeX,EAAY,YAAcjB,EAGjE,IAAK,MAAM6B,KAAkBV,EAAYK,SAAU,CAG/C,IAAIM,EAAeT,EAAkBU,IAAIF,EAAeH,WACpDM,EAA0D,YAA3CH,EAAeI,aAAa,WAC3CC,EAAoE,SAAtD5C,EAAIsC,eAAeC,EAAgB,eACjDC,GAAgBI,EACZF,EAEAnB,EAAQsB,KAAKN,IAIbR,EAAkBe,OAAOP,EAAeH,WACxCZ,EAAUqB,KAAKN,IAGG,WAAlBF,EAGIK,IACAnB,EAAQsB,KAAKN,GACbd,EAAcoB,KAAKN,KAIuE,IAA1FrC,KAAKY,QAAQF,SAASC,KAAM,0BAA2B,CAACkC,YAAaR,KACrEhB,EAAQsB,KAAKN,EAI7B,CAIAd,EAAcoB,QAAQd,EAAkBiB,UAGxC,IAAK,MAAMC,KAAWxB,EAAe,CACjCxB,IACA,IAAIiD,EAAStC,SAASuC,cAAcC,yBAAyBH,EAAQb,WACrEnC,KACmF,IAA/EC,KAAKY,QAAQF,SAASC,KAAM,uBAAwB,CAACkC,YAAaG,MAClErB,EAAYwB,YAAYH,GACxB5B,EAAMuB,KAAKK,GAEnB,CAIA,IAAK,MAAMI,KAAkB/B,GACqE,IAA1FrB,KAAKY,QAAQF,SAASC,KAAM,0BAA2B,CAACkC,YAAaO,KACrEzB,EAAY0B,YAAYD,GAIhCpD,KAAKY,QAAQF,SAASC,KAAM,wBAAyB,CACjDS,MAAOA,EACPkC,KAAMhC,EACND,QAASA,GAEjB,CACJ,CACJ,CAYYkC,CAAUhD,EAAIiD,KAAMhD,KAKnC,CA3HD","ignoreList":[]}
@@ -5,17 +5,26 @@
5
5
  let preloadSpec = api.attributeValue(elt, "hx-preload");
6
6
  if (!preloadSpec && !elt._htmx?.boosted) return;
7
7
 
8
- let eventName;
9
- let timeout;
8
+ let preloadEvents = []
9
+ let timeout = 5000;
10
10
  if (preloadSpec) {
11
11
  let specs = api.parseTriggerSpecs(preloadSpec);
12
12
  if (specs.length === 0) return;
13
- let spec = specs[0];
14
- eventName = spec.name;
15
- timeout = spec.timeout ? htmx.parseInterval(spec.timeout) : 5000;
13
+ for (const spec of specs) {
14
+ preloadEvents.push(spec.name)
15
+ if (spec.timeout) {
16
+ timeout = htmx.parseInterval(spec.timeout)
17
+ }
18
+ }
16
19
  } else {
17
- eventName = htmx.config?.preload?.boostEvent || "mousedown"
18
- timeout = htmx.config?.preload?.boostTimeout ? htmx.parseInterval(htmx.config?.preload?.boostTimeout) : 5000;
20
+ //only boosted links are supported
21
+ if (elt.tagName === "A") {
22
+ if(htmx.config?.preload?.boostTimeout) {
23
+ timeout = htmx.parseInterval(htmx.config.preload.boostTimeout)
24
+ }
25
+ preloadEvents.push(htmx.config?.preload?.boostEvent || "mousedown");
26
+ preloadEvents.push("touchstart");
27
+ }
19
28
  }
20
29
 
21
30
  let preloadListener = async (evt) => {
@@ -47,9 +56,11 @@
47
56
  delete elt._htmx.preload;
48
57
  }
49
58
  };
50
- elt.addEventListener(eventName, preloadListener);
59
+ for (let eventName of preloadEvents) {
60
+ elt.addEventListener(eventName, preloadListener);
61
+ }
51
62
  elt._htmx.preloadListener = preloadListener;
52
- elt._htmx.preloadEvent = eventName;
63
+ elt._htmx.preloadEvents = preloadEvents;
53
64
  }
54
65
 
55
66
  htmx.registerExtension('preload', {
@@ -76,7 +87,9 @@
76
87
 
77
88
  htmx_before_cleanup: (elt) => {
78
89
  if (elt._htmx?.preloadListener) {
79
- elt.removeEventListener(elt._htmx.preloadEvent, elt._htmx.preloadListener);
90
+ for (let eventName of elt._htmx.preloadEvents) {
91
+ elt.removeEventListener(eventName, elt._htmx.preloadListener);
92
+ }
80
93
  }
81
94
  }
82
95
  });
@@ -1 +1 @@
1
- (()=>{let e;htmx.registerExtension("preload",{init:t=>{e=t},htmx_after_init:t=>{!function(t){let r,o,a=e.attributeValue(t,"hx-preload");if(!a&&!t._htmx?.boosted)return;if(a){let t=e.parseTriggerSpecs(a);if(0===t.length)return;let l=t[0];r=l.name,o=l.timeout?htmx.parseInterval(l.timeout):5e3}else r=htmx.config?.preload?.boostEvent||"mousedown",o=htmx.config?.preload?.boostTimeout?htmx.parseInterval(htmx.config?.preload?.boostTimeout):5e3;let l=async r=>{let{method:a}=e.determineMethodAndAction(t,r);if("GET"!==a)return;if(t._htmx?.preload)return;let l=e.createRequestContext(t,r),n=t.form||t.closest("form"),m=e.collectFormData(t,n,r.submitter);e.handleHxVals(t,m);let h=l.request.action.replace?.(/#.*$/,""),i=new URLSearchParams(m);i.size&&(h+=(/\?/.test(h)?"&":"?")+i),t._htmx.preload={prefetch:fetch(h,l.request),action:h,expiresAt:Date.now()+o};try{await t._htmx.preload.prefetch}catch(e){delete t._htmx.preload}};t.addEventListener(r,l),t._htmx.preloadListener=l,t._htmx.preloadEvent=r}(t)},htmx_before_request:(e,t)=>{let{ctx:r}=t;if(e._htmx?.preload&&e._htmx.preload.action===r.request.action&&Date.now()<e._htmx.preload.expiresAt){let t=e._htmx.preload.prefetch;r.fetch=()=>t,delete e._htmx.preload}else e._htmx&&delete e._htmx.preload},htmx_before_cleanup:e=>{e._htmx?.preloadListener&&e.removeEventListener(e._htmx.preloadEvent,e._htmx.preloadListener)}})})();
1
+ (()=>{let e;htmx.registerExtension("preload",{init:t=>{e=t},htmx_after_init:t=>{!function(t){let r=e.attributeValue(t,"hx-preload");if(!r&&!t._htmx?.boosted)return;let o=[],a=5e3;if(r){let t=e.parseTriggerSpecs(r);if(0===t.length)return;for(const e of t)o.push(e.name),e.timeout&&(a=htmx.parseInterval(e.timeout))}else"A"===t.tagName&&(htmx.config?.preload?.boostTimeout&&(a=htmx.parseInterval(htmx.config.preload.boostTimeout)),o.push(htmx.config?.preload?.boostEvent||"mousedown"),o.push("touchstart"));let l=async r=>{let{method:o}=e.determineMethodAndAction(t,r);if("GET"!==o)return;if(t._htmx?.preload)return;let l=e.createRequestContext(t,r),n=t.form||t.closest("form"),h=e.collectFormData(t,n,r.submitter);e.handleHxVals(t,h);let m=l.request.action.replace?.(/#.*$/,""),s=new URLSearchParams(h);s.size&&(m+=(/\?/.test(m)?"&":"?")+s),t._htmx.preload={prefetch:fetch(m,l.request),action:m,expiresAt:Date.now()+a};try{await t._htmx.preload.prefetch}catch(e){delete t._htmx.preload}};for(let e of o)t.addEventListener(e,l);t._htmx.preloadListener=l,t._htmx.preloadEvents=o}(t)},htmx_before_request:(e,t)=>{let{ctx:r}=t;if(e._htmx?.preload&&e._htmx.preload.action===r.request.action&&Date.now()<e._htmx.preload.expiresAt){let t=e._htmx.preload.prefetch;r.fetch=()=>t,delete e._htmx.preload}else e._htmx&&delete e._htmx.preload},htmx_before_cleanup:e=>{if(e._htmx?.preloadListener)for(let t of e._htmx.preloadEvents)e.removeEventListener(t,e._htmx.preloadListener)}})})();
@@ -1 +1 @@
1
- {"version":3,"names":["api","htmx","registerExtension","init","internalAPI","htmx_after_init","elt","eventName","timeout","preloadSpec","attributeValue","_htmx","boosted","specs","parseTriggerSpecs","length","spec","name","parseInterval","config","preload","boostEvent","boostTimeout","preloadListener","async","evt","method","determineMethodAndAction","ctx","createRequestContext","form","closest","body","collectFormData","submitter","handleHxVals","action","request","replace","params","URLSearchParams","size","test","prefetch","fetch","expiresAt","Date","now","error","addEventListener","preloadEvent","initializePreload","htmx_before_request","detail","htmx_before_cleanup","removeEventListener"],"sources":["dist/ext/hx-preload.js"],"mappings":"AAAA,MACI,IAAIA,EAqDJC,KAAKC,kBAAkB,UAAW,CAC9BC,KAAOC,IACHJ,EAAMI,GAGVC,gBAAkBC,KAxDtB,SAA2BA,GACvB,IAGIC,EACAC,EAJAC,EAAcT,EAAIU,eAAeJ,EAAK,cAC1C,IAAKG,IAAgBH,EAAIK,OAAOC,QAAS,OAIzC,GAAIH,EAAa,CACb,IAAII,EAAQb,EAAIc,kBAAkBL,GAClC,GAAqB,IAAjBI,EAAME,OAAc,OACxB,IAAIC,EAAOH,EAAM,GACjBN,EAAYS,EAAKC,KACjBT,EAAUQ,EAAKR,QAAUP,KAAKiB,cAAcF,EAAKR,SAAW,GAChE,MACID,EAAYN,KAAKkB,QAAQC,SAASC,YAAc,YAChDb,EAAUP,KAAKkB,QAAQC,SAASE,aAAerB,KAAKiB,cAAcjB,KAAKkB,QAAQC,SAASE,cAAgB,IAG5G,IAAIC,EAAkBC,MAAOC,IACzB,IAAIC,OAACA,GAAU1B,EAAI2B,yBAAyBrB,EAAKmB,GACjD,GAAe,QAAXC,EAAkB,OAEtB,GAAIpB,EAAIK,OAAOS,QAAS,OAExB,IAAIQ,EAAM5B,EAAI6B,qBAAqBvB,EAAKmB,GACpCK,EAAOxB,EAAIwB,MAAQxB,EAAIyB,QAAQ,QAC/BC,EAAOhC,EAAIiC,gBAAgB3B,EAAKwB,EAAML,EAAIS,WAC9ClC,EAAImC,aAAa7B,EAAK0B,GAEtB,IAAII,EAASR,EAAIS,QAAQD,OAAOE,UAAU,OAAQ,IAG9CC,EAAS,IAAIC,gBAAgBR,GAC7BO,EAAOE,OAAML,IAAW,KAAKM,KAAKN,GAAU,IAAM,KAAOG,GAE7DjC,EAAIK,MAAMS,QAAU,CAChBuB,SAAUC,MAAMR,EAAQR,EAAIS,SAC5BD,OAAQA,EACRS,UAAWC,KAAKC,MAAQvC,GAG5B,UACUF,EAAIK,MAAMS,QAAQuB,QAC5B,CAAE,MAAOK,UACE1C,EAAIK,MAAMS,OACrB,GAEJd,EAAI2C,iBAAiB1C,EAAWgB,GAChCjB,EAAIK,MAAMY,gBAAkBA,EAC5BjB,EAAIK,MAAMuC,aAAe3C,CAC7B,CAQQ4C,CAAkB7C,IAGtB8C,oBAAqB,CAAC9C,EAAK+C,KACvB,IAAIzB,IAACA,GAAOyB,EACZ,GAAI/C,EAAIK,OAAOS,SACXd,EAAIK,MAAMS,QAAQgB,SAAWR,EAAIS,QAAQD,QACzCU,KAAKC,MAAQzC,EAAIK,MAAMS,QAAQyB,UAAW,CAC1C,IAAIF,EAAWrC,EAAIK,MAAMS,QAAQuB,SACjCf,EAAIgB,MAAQ,IAAMD,SACXrC,EAAIK,MAAMS,OACrB,MACQd,EAAIK,cAAcL,EAAIK,MAAMS,SAIxCkC,oBAAsBhD,IACdA,EAAIK,OAAOY,iBACXjB,EAAIiD,oBAAoBjD,EAAIK,MAAMuC,aAAc5C,EAAIK,MAAMY,mBAIzE,EAlFD","ignoreList":[]}
1
+ {"version":3,"names":["api","htmx","registerExtension","init","internalAPI","htmx_after_init","elt","preloadSpec","attributeValue","_htmx","boosted","preloadEvents","timeout","specs","parseTriggerSpecs","length","spec","push","name","parseInterval","tagName","config","preload","boostTimeout","boostEvent","preloadListener","async","evt","method","determineMethodAndAction","ctx","createRequestContext","form","closest","body","collectFormData","submitter","handleHxVals","action","request","replace","params","URLSearchParams","size","test","prefetch","fetch","expiresAt","Date","now","error","eventName","addEventListener","initializePreload","htmx_before_request","detail","htmx_before_cleanup","removeEventListener"],"sources":["dist/ext/hx-preload.js"],"mappings":"AAAA,MACI,IAAIA,EAgEJC,KAAKC,kBAAkB,UAAW,CAC9BC,KAAOC,IACHJ,EAAMI,GAGVC,gBAAkBC,KAnEtB,SAA2BA,GACvB,IAAIC,EAAcP,EAAIQ,eAAeF,EAAK,cAC1C,IAAKC,IAAgBD,EAAIG,OAAOC,QAAS,OAEzC,IAAIC,EAAgB,GAChBC,EAAU,IACd,GAAIL,EAAa,CACb,IAAIM,EAAQb,EAAIc,kBAAkBP,GAClC,GAAqB,IAAjBM,EAAME,OAAc,OACxB,IAAK,MAAMC,KAAQH,EACfF,EAAcM,KAAKD,EAAKE,MACpBF,EAAKJ,UACLA,EAAUX,KAAKkB,cAAcH,EAAKJ,SAG9C,KAEwB,MAAhBN,EAAIc,UACDnB,KAAKoB,QAAQC,SAASC,eACrBX,EAAUX,KAAKkB,cAAclB,KAAKoB,OAAOC,QAAQC,eAErDZ,EAAcM,KAAKhB,KAAKoB,QAAQC,SAASE,YAAc,aACvDb,EAAcM,KAAK,eAI3B,IAAIQ,EAAkBC,MAAOC,IACzB,IAAIC,OAACA,GAAU5B,EAAI6B,yBAAyBvB,EAAKqB,GACjD,GAAe,QAAXC,EAAkB,OAEtB,GAAItB,EAAIG,OAAOa,QAAS,OAExB,IAAIQ,EAAM9B,EAAI+B,qBAAqBzB,EAAKqB,GACpCK,EAAO1B,EAAI0B,MAAQ1B,EAAI2B,QAAQ,QAC/BC,EAAOlC,EAAImC,gBAAgB7B,EAAK0B,EAAML,EAAIS,WAC9CpC,EAAIqC,aAAa/B,EAAK4B,GAEtB,IAAII,EAASR,EAAIS,QAAQD,OAAOE,UAAU,OAAQ,IAG9CC,EAAS,IAAIC,gBAAgBR,GAC7BO,EAAOE,OAAML,IAAW,KAAKM,KAAKN,GAAU,IAAM,KAAOG,GAE7DnC,EAAIG,MAAMa,QAAU,CAChBuB,SAAUC,MAAMR,EAAQR,EAAIS,SAC5BD,OAAQA,EACRS,UAAWC,KAAKC,MAAQrC,GAG5B,UACUN,EAAIG,MAAMa,QAAQuB,QAC5B,CAAE,MAAOK,UACE5C,EAAIG,MAAMa,OACrB,GAEJ,IAAK,IAAI6B,KAAaxC,EAClBL,EAAI8C,iBAAiBD,EAAW1B,GAEpCnB,EAAIG,MAAMgB,gBAAkBA,EAC5BnB,EAAIG,MAAME,cAAgBA,CAC9B,CAQQ0C,CAAkB/C,IAGtBgD,oBAAqB,CAAChD,EAAKiD,KACvB,IAAIzB,IAACA,GAAOyB,EACZ,GAAIjD,EAAIG,OAAOa,SACXhB,EAAIG,MAAMa,QAAQgB,SAAWR,EAAIS,QAAQD,QACzCU,KAAKC,MAAQ3C,EAAIG,MAAMa,QAAQyB,UAAW,CAC1C,IAAIF,EAAWvC,EAAIG,MAAMa,QAAQuB,SACjCf,EAAIgB,MAAQ,IAAMD,SACXvC,EAAIG,MAAMa,OACrB,MACQhB,EAAIG,cAAcH,EAAIG,MAAMa,SAIxCkC,oBAAsBlD,IAClB,GAAIA,EAAIG,OAAOgB,gBACX,IAAK,IAAI0B,KAAa7C,EAAIG,MAAME,cAC5BL,EAAImD,oBAAoBN,EAAW7C,EAAIG,MAAMgB,mBAKhE,EA/FD","ignoreList":[]}
@@ -0,0 +1,89 @@
1
+ //==========================================================
2
+ // hx-upsert.js
3
+ //
4
+ // An extension to add 'upsert' swap style that updates
5
+ // existing elements by ID and inserts new ones.
6
+ //
7
+ // Modifiers:
8
+ // key:attr - attribute name for sorting (default: id)
9
+ // sort - sort ascending
10
+ // sort:desc - sort descending
11
+ // prepend - prepend elements without keys (default: append)
12
+ //==========================================================
13
+ (() => {
14
+ let api;
15
+
16
+ htmx.registerExtension('upsert', {
17
+ init: (internalAPI) => {
18
+ api = internalAPI;
19
+ },
20
+ htmx_process_upsert: (templateElt, detail) => {
21
+ let {ctx, tasks} = detail;
22
+ let swapSpec = {style: 'upsert'};
23
+ let key = templateElt.getAttribute('key');
24
+ let sort = templateElt.getAttribute('sort');
25
+ let prepend = templateElt.hasAttribute('prepend');
26
+ if (key) swapSpec.key = key;
27
+ if (sort !== null) swapSpec.sort = sort || true;
28
+ if (prepend) swapSpec.prepend = true;
29
+ tasks.push({
30
+ type: 'partial',
31
+ fragment: templateElt.content.cloneNode(true),
32
+ target: api.attributeValue(templateElt, 'hx-target'),
33
+ swapSpec,
34
+ sourceElement: ctx.sourceElement
35
+ });
36
+ },
37
+ handle_swap: (style, target, fragment, swapSpec) => {
38
+ if (style === 'upsert') {
39
+ let keyAttr = swapSpec.key || 'id';
40
+ let desc = swapSpec.sort === 'desc';
41
+ let firstChild = target.firstChild;
42
+
43
+ let getKey = (el) => el.getAttribute(keyAttr) || el.id;
44
+
45
+ let compare = (a, b) => {
46
+ let result = a.localeCompare(b, undefined, {numeric: true});
47
+ return desc ? -result : result;
48
+ };
49
+
50
+ for (let newEl of Array.from(fragment.children)) {
51
+ let id = newEl.id;
52
+ if (id) {
53
+ let existing = document.getElementById(id);
54
+ if (existing) {
55
+ existing.outerHTML = newEl.outerHTML
56
+ continue;
57
+ }
58
+ }
59
+
60
+ let newKey = getKey(newEl);
61
+ if (!newKey) {
62
+ if (swapSpec.prepend) {
63
+ target.insertBefore(newEl, firstChild);
64
+ } else {
65
+ target.appendChild(newEl);
66
+ }
67
+ continue;
68
+ }
69
+
70
+ let inserted = false;
71
+ for (let child of target.children) {
72
+ let childKey = getKey(child);
73
+ if (childKey && compare(newKey, childKey) < 0) {
74
+ target.insertBefore(newEl, child);
75
+ inserted = true;
76
+ break;
77
+ }
78
+ }
79
+
80
+ if (!inserted) {
81
+ target.appendChild(newEl);
82
+ }
83
+ }
84
+ return true;
85
+ }
86
+ return false;
87
+ }
88
+ });
89
+ })();
@@ -0,0 +1 @@
1
+ (()=>{let e;htmx.registerExtension("upsert",{init:t=>{e=t},htmx_process_upsert:(t,r)=>{let{ctx:i,tasks:n}=r,l={style:"upsert"},o=t.getAttribute("key"),s=t.getAttribute("sort"),u=t.hasAttribute("prepend");o&&(l.key=o),null!==s&&(l.sort=s||!0),u&&(l.prepend=!0),n.push({type:"partial",fragment:t.content.cloneNode(!0),target:e.attributeValue(t,"hx-target"),swapSpec:l,sourceElement:i.sourceElement})},handle_swap:(e,t,r,i)=>{if("upsert"===e){let e=i.key||"id",n="desc"===i.sort,l=t.firstChild,o=t=>t.getAttribute(e)||t.id,s=(e,t)=>{let r=e.localeCompare(t,void 0,{numeric:!0});return n?-r:r};for(let e of Array.from(r.children)){let r=e.id;if(r){let t=document.getElementById(r);if(t){t.outerHTML=e.outerHTML;continue}}let n=o(e);if(!n){i.prepend?t.insertBefore(e,l):t.appendChild(e);continue}let u=!1;for(let r of t.children){let i=o(r);if(i&&s(n,i)<0){t.insertBefore(e,r),u=!0;break}}u||t.appendChild(e)}return!0}return!1}})})();
@@ -0,0 +1 @@
1
+ {"version":3,"names":["api","htmx","registerExtension","init","internalAPI","htmx_process_upsert","templateElt","detail","ctx","tasks","swapSpec","style","key","getAttribute","sort","prepend","hasAttribute","push","type","fragment","content","cloneNode","target","attributeValue","sourceElement","handle_swap","keyAttr","desc","firstChild","getKey","el","id","compare","a","b","result","localeCompare","undefined","numeric","newEl","Array","from","children","existing","document","getElementById","outerHTML","newKey","insertBefore","appendChild","inserted","child","childKey"],"sources":["dist/ext/hx-upsert.js"],"mappings":"AAYA,MACI,IAAIA,EAEJC,KAAKC,kBAAkB,SAAU,CAC7BC,KAAOC,IACHJ,EAAMI,GAEVC,oBAAqB,CAACC,EAAaC,KAC/B,IAAIC,IAACA,EAAGC,MAAEA,GAASF,EACfG,EAAW,CAACC,MAAO,UACnBC,EAAMN,EAAYO,aAAa,OAC/BC,EAAOR,EAAYO,aAAa,QAChCE,EAAUT,EAAYU,aAAa,WACnCJ,IAAKF,EAASE,IAAMA,GACX,OAATE,IAAeJ,EAASI,KAAOA,IAAQ,GACvCC,IAASL,EAASK,SAAU,GAChCN,EAAMQ,KAAK,CACPC,KAAM,UACNC,SAAUb,EAAYc,QAAQC,WAAU,GACxCC,OAAQtB,EAAIuB,eAAejB,EAAa,aACxCI,WACAc,cAAehB,EAAIgB,iBAG3BC,YAAa,CAACd,EAAOW,EAAQH,EAAUT,KACnC,GAAc,WAAVC,EAAoB,CACpB,IAAIe,EAAUhB,EAASE,KAAO,KAC1Be,EAAyB,SAAlBjB,EAASI,KAChBc,EAAaN,EAAOM,WAEpBC,EAAUC,GAAOA,EAAGjB,aAAaa,IAAYI,EAAGC,GAEhDC,EAAU,CAACC,EAAGC,KACd,IAAIC,EAASF,EAAEG,cAAcF,OAAGG,EAAW,CAACC,SAAS,IACrD,OAAOX,GAAQQ,EAASA,GAG5B,IAAK,IAAII,KAASC,MAAMC,KAAKtB,EAASuB,UAAW,CAC7C,IAAIX,EAAKQ,EAAMR,GACf,GAAIA,EAAI,CACJ,IAAIY,EAAWC,SAASC,eAAed,GACvC,GAAIY,EAAU,CACVA,EAASG,UAAYP,EAAMO,UAC3B,QACJ,CACJ,CAEA,IAAIC,EAASlB,EAAOU,GACpB,IAAKQ,EAAQ,CACLrC,EAASK,QACTO,EAAO0B,aAAaT,EAAOX,GAE3BN,EAAO2B,YAAYV,GAEvB,QACJ,CAEA,IAAIW,GAAW,EACf,IAAK,IAAIC,KAAS7B,EAAOoB,SAAU,CAC/B,IAAIU,EAAWvB,EAAOsB,GACtB,GAAIC,GAAYpB,EAAQe,EAAQK,GAAY,EAAG,CAC3C9B,EAAO0B,aAAaT,EAAOY,GAC3BD,GAAW,EACX,KACJ,CACJ,CAEKA,GACD5B,EAAO2B,YAAYV,EAE3B,CACA,OAAO,CACX,CACA,OAAO,IAGlB,EA5ED","ignoreList":[]}