1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 | (function(){
|
7 |
|
8 | var api = null;
|
9 |
|
10 | function log() {
|
11 |
|
12 | }
|
13 |
|
14 | function mergeHead(newContent, defaultMergeStrategy) {
|
15 |
|
16 | if (newContent && newContent.indexOf('<head') > -1) {
|
17 | const htmlDoc = document.createElement("html");
|
18 |
|
19 | var contentWithSvgsRemoved = newContent.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim, '');
|
20 |
|
21 | var headTag = contentWithSvgsRemoved.match(/(<head(\s[^>]*>|>)([\s\S]*?)<\/head>)/im);
|
22 |
|
23 |
|
24 | if (headTag) {
|
25 |
|
26 | var added = []
|
27 | var removed = []
|
28 | var preserved = []
|
29 | var nodesToAppend = []
|
30 |
|
31 | htmlDoc.innerHTML = headTag;
|
32 | var newHeadTag = htmlDoc.querySelector("head");
|
33 | if (newHeadTag == null) {
|
34 | return;
|
35 | } else {
|
36 |
|
37 | var srcToNewHeadNodes = new Map();
|
38 | for (const newHeadChild of newHeadTag.children) {
|
39 | srcToNewHeadNodes.set(newHeadChild.outerHTML, newHeadChild);
|
40 | }
|
41 | }
|
42 |
|
43 |
|
44 |
|
45 |
|
46 | var mergeStrategy = api.getAttributeValue(newHeadTag, "hx-head") || defaultMergeStrategy;
|
47 |
|
48 |
|
49 | var currentHead = document.head;
|
50 | for (const currentHeadElt of currentHead.children) {
|
51 |
|
52 |
|
53 | var inNewContent = srcToNewHeadNodes.has(currentHeadElt.outerHTML);
|
54 | var isReAppended = currentHeadElt.getAttribute("hx-head") === "re-eval";
|
55 | var isPreserved = api.getAttributeValue(currentHeadElt, "hx-preserve") === "true";
|
56 | if (inNewContent || isPreserved) {
|
57 | if (isReAppended) {
|
58 |
|
59 | removed.push(currentHeadElt);
|
60 | } else {
|
61 |
|
62 |
|
63 | srcToNewHeadNodes.delete(currentHeadElt.outerHTML);
|
64 | preserved.push(currentHeadElt);
|
65 | }
|
66 | } else {
|
67 | if (mergeStrategy === "append") {
|
68 |
|
69 |
|
70 | if (isReAppended) {
|
71 | removed.push(currentHeadElt);
|
72 | nodesToAppend.push(currentHeadElt);
|
73 | }
|
74 | } else {
|
75 |
|
76 | if (api.triggerEvent(document.body, "htmx:removingHeadElement", {headElement: currentHeadElt}) !== false) {
|
77 | removed.push(currentHeadElt);
|
78 | }
|
79 | }
|
80 | }
|
81 | }
|
82 |
|
83 |
|
84 |
|
85 | nodesToAppend.push(...srcToNewHeadNodes.values());
|
86 | log("to append: ", nodesToAppend);
|
87 |
|
88 | for (const newNode of nodesToAppend) {
|
89 | log("adding: ", newNode);
|
90 | var newElt = document.createRange().createContextualFragment(newNode.outerHTML);
|
91 | log(newElt);
|
92 | if (api.triggerEvent(document.body, "htmx:addingHeadElement", {headElement: newElt}) !== false) {
|
93 | currentHead.appendChild(newElt);
|
94 | added.push(newElt);
|
95 | }
|
96 | }
|
97 |
|
98 |
|
99 |
|
100 | for (const removedElement of removed) {
|
101 | if (api.triggerEvent(document.body, "htmx:removingHeadElement", {headElement: removedElement}) !== false) {
|
102 | currentHead.removeChild(removedElement);
|
103 | }
|
104 | }
|
105 |
|
106 | api.triggerEvent(document.body, "htmx:afterHeadMerge", {added: added, kept: preserved, removed: removed});
|
107 | }
|
108 | }
|
109 | }
|
110 |
|
111 | htmx.defineExtension("head-support", {
|
112 | init: function(apiRef) {
|
113 |
|
114 | api = apiRef;
|
115 |
|
116 | htmx.on('htmx:afterSwap', function(evt){
|
117 | var serverResponse = evt.detail.xhr.response;
|
118 | if (api.triggerEvent(document.body, "htmx:beforeHeadMerge", evt.detail)) {
|
119 | mergeHead(serverResponse, evt.detail.boosted ? "merge" : "append");
|
120 | }
|
121 | })
|
122 |
|
123 | htmx.on('htmx:historyRestore', function(evt){
|
124 | if (api.triggerEvent(document.body, "htmx:beforeHeadMerge", evt.detail)) {
|
125 | if (evt.detail.cacheMiss) {
|
126 | mergeHead(evt.detail.serverResponse, "merge");
|
127 | } else {
|
128 | mergeHead(evt.detail.item.head, "merge");
|
129 | }
|
130 | }
|
131 | })
|
132 |
|
133 | htmx.on('htmx:historyItemCreated', function(evt){
|
134 | var historyItem = evt.detail.item;
|
135 | historyItem.head = document.head.outerHTML;
|
136 | })
|
137 | }
|
138 | });
|
139 |
|
140 | })() |
\ | No newline at end of file |