Browse code

Update htmx lib

Benjamin Roth authored on08/03/2024 10:15:01
Showing1 changed files
... ...
@@ -48,9 +48,12 @@ htmx.defineExtension("preload", {
48 48
 				// in the future
49 49
 				var hxGet = node.getAttribute("hx-get") || node.getAttribute("data-hx-get")
50 50
 				if (hxGet) {
51
-					htmx.ajax("GET", hxGet, {handler:function(elt, info) {
52
-						done(info.xhr.responseText);
53
-					}});
51
+					htmx.ajax("GET", hxGet, {
52
+						source: node,
53
+						handler:function(elt, info) {
54
+							done(info.xhr.responseText);
55
+						}
56
+					});
54 57
 					return;
55 58
 				}
56 59
 
... ...
@@ -93,7 +96,7 @@ htmx.defineExtension("preload", {
93 96
 			// Apply the listener to the node
94 97
 			node.addEventListener(on, function(evt) {
95 98
 				if (node.preloadState === "PAUSE") { // Only add one event listener
96
-					node.preloadState = "READY"; // Requred for the `load` function to trigger
99
+					node.preloadState = "READY"; // Required for the `load` function to trigger
97 100
 
98 101
 					// Special handling for "mouseover" events.  Wait 100ms before triggering load.
99 102
 					if (on === "mouseover") {
Browse code

Initial htmx npm packages installation

Benjamin Roth authored on25/05/2023 09:52:13
Showing1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,144 @@
1
+// This adds the "preload" extension to htmx.  By default, this will 
2
+// preload the targets of any tags with `href` or `hx-get` attributes 
3
+// if they also have a `preload` attribute as well.  See documentation
4
+// for more details
5
+htmx.defineExtension("preload", {
6
+
7
+	onEvent: function(name, event) {
8
+
9
+		// Only take actions on "htmx:afterProcessNode"
10
+		if (name !== "htmx:afterProcessNode") {
11
+			return;
12
+		}
13
+
14
+		// SOME HELPER FUNCTIONS WE'LL NEED ALONG THE WAY
15
+
16
+		// attr gets the closest non-empty value from the attribute.
17
+		var attr = function(node, property) {
18
+			if (node == undefined) {return undefined;}
19
+			return node.getAttribute(property) || node.getAttribute("data-" + property) || attr(node.parentElement, property)
20
+		}
21
+		
22
+		// load handles the actual HTTP fetch, and uses htmx.ajax in cases where we're 
23
+		// preloading an htmx resource (this sends the same HTTP headers as a regular htmx request)
24
+		var load = function(node) {
25
+
26
+			// Called after a successful AJAX request, to mark the
27
+			// content as loaded (and prevent additional AJAX calls.)
28
+			var done = function(html) {
29
+				if (!node.preloadAlways) {
30
+					node.preloadState = "DONE"
31
+				}
32
+
33
+				if (attr(node, "preload-images") == "true") {
34
+					document.createElement("div").innerHTML = html // create and populate a node to load linked resources, too.
35
+				}
36
+			}
37
+
38
+			return function() {
39
+
40
+				// If this value has already been loaded, then do not try again.
41
+				if (node.preloadState !== "READY") {
42
+					return;
43
+				}
44
+
45
+				// Special handling for HX-GET - use built-in htmx.ajax function
46
+				// so that headers match other htmx requests, then set 
47
+				// node.preloadState = TRUE so that requests are not duplicated
48
+				// in the future
49
+				var hxGet = node.getAttribute("hx-get") || node.getAttribute("data-hx-get")
50
+				if (hxGet) {
51
+					htmx.ajax("GET", hxGet, {handler:function(elt, info) {
52
+						done(info.xhr.responseText);
53
+					}});
54
+					return;
55
+				}
56
+
57
+				// Otherwise, perform a standard xhr request, then set 
58
+				// node.preloadState = TRUE so that requests are not duplicated 
59
+				// in the future.
60
+				if (node.getAttribute("href")) {
61
+					var r = new XMLHttpRequest();
62
+					r.open("GET", node.getAttribute("href"));
63
+					r.onload = function() {done(r.responseText);};
64
+					r.send();
65
+					return;
66
+				}
67
+			}
68
+		}
69
+
70
+		// This function processes a specific node and sets up event handlers.
71
+		// We'll search for nodes and use it below.
72
+		var init = function(node) {
73
+
74
+			// If this node DOES NOT include a "GET" transaction, then there's nothing to do here.
75
+			if (node.getAttribute("href") + node.getAttribute("hx-get") + node.getAttribute("data-hx-get") == "") {
76
+				return;
77
+			}
78
+
79
+			// Guarantee that we only initialize each node once.
80
+			if (node.preloadState !== undefined) {
81
+				return;
82
+			}
83
+			
84
+			// Get event name from config.
85
+			var on = attr(node, "preload") || "mousedown"
86
+			const always = on.indexOf("always") !== -1
87
+			if (always) {
88
+				on = on.replace('always', '').trim()
89
+			}
90
+						
91
+			// FALL THROUGH to here means we need to add an EventListener
92
+	
93
+			// Apply the listener to the node
94
+			node.addEventListener(on, function(evt) {
95
+				if (node.preloadState === "PAUSE") { // Only add one event listener
96
+					node.preloadState = "READY"; // Requred for the `load` function to trigger
97
+
98
+					// Special handling for "mouseover" events.  Wait 100ms before triggering load.
99
+					if (on === "mouseover") {
100
+						window.setTimeout(load(node), 100);
101
+					} else {
102
+						load(node)() // all other events trigger immediately.
103
+					}
104
+				}
105
+			})
106
+
107
+			// Special handling for certain built-in event handlers
108
+			switch (on) {
109
+
110
+				case "mouseover":
111
+					// Mirror `touchstart` events (fires immediately)
112
+					node.addEventListener("touchstart", load(node));
113
+
114
+					// WHhen the mouse leaves, immediately disable the preload
115
+					node.addEventListener("mouseout", function(evt) {
116
+						if ((evt.target === node) && (node.preloadState === "READY")) {
117
+							node.preloadState = "PAUSE";
118
+						}
119
+					})
120
+					break;
121
+
122
+				case "mousedown":
123
+					 // Mirror `touchstart` events (fires immediately)
124
+					node.addEventListener("touchstart", load(node));
125
+					break;
126
+			}
127
+
128
+			// Mark the node as ready to run.
129
+			node.preloadState = "PAUSE";
130
+			node.preloadAlways = always;
131
+			htmx.trigger(node, "preload:init") // This event can be used to load content immediately.
132
+		}
133
+
134
+		// Search for all child nodes that have a "preload" attribute
135
+		event.target.querySelectorAll("[preload]").forEach(function(node) {
136
+
137
+			// Initialize the node with the "preload" attribute
138
+			init(node)
139
+
140
+			// Initialize all child elements that are anchors or have `hx-get` (use with care)
141
+			node.querySelectorAll("a,[hx-get],[data-hx-get]").forEach(init)
142
+		})
143
+	}
144
+})