hyperclayjs 1.24.2 → 1.24.4
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.
- package/README.md +7 -7
- package/package.json +1 -1
- package/src/communication/behaviorCollector.js +2 -2
- package/src/communication/live-sync.js +13 -24
- package/src/core/adminContenteditable.js +1 -1
- package/src/core/adminInputs.js +2 -2
- package/src/core/adminOnClick.js +1 -1
- package/src/core/adminResources.js +2 -2
- package/src/core/adminSystem.js +4 -0
- package/src/core/autosave.js +2 -2
- package/src/core/savePageCore.js +7 -6
- package/src/custom-attributes/ajaxElements.js +7 -5
- package/src/custom-attributes/refetchOnSave.js +33 -0
- package/src/dom-utilities/getDataFromForm.js +1 -1
- package/src/hyperclay.js +5 -4
- package/src/utilities/cookie.js +3 -3
- package/src/core/tailwindInject.js +0 -56
package/README.md
CHANGED
|
@@ -66,19 +66,19 @@ import 'hyperclayjs/presets/standard.js';
|
|
|
66
66
|
| save-system | 13.4KB | CMD+S, [trigger-save] button, savestatus attribute |
|
|
67
67
|
| save-toast | 0.9KB | Toast notifications for save events |
|
|
68
68
|
| snapshot | 10.8KB | Source of truth for page state - captures DOM snapshots for save and sync |
|
|
69
|
-
| tailwind-inject | 1.4KB | Injects tailwind CSS link with cache-bust on save |
|
|
70
69
|
| unsaved-warning | 1.3KB | Warn before leaving page with unsaved changes |
|
|
71
70
|
|
|
72
71
|
### Custom Attributes (HTML enhancements)
|
|
73
72
|
|
|
74
73
|
| Module | Size | Description |
|
|
75
74
|
|--------|------|-------------|
|
|
76
|
-
| ajax-elements | 2.
|
|
75
|
+
| ajax-elements | 2.8KB | [ajax-form], [ajax-button] for async form submissions |
|
|
77
76
|
| dom-helpers | 6.8KB | el.nearest, el.val, el.text, el.exec, el.cycle |
|
|
78
77
|
| event-attrs | 5.3KB | [onclickaway], [onclickchildren], [onclone], [onpagemutation], [onrender] |
|
|
79
78
|
| input-helpers | 3.9KB | [prevent-enter], [autosize] for textareas |
|
|
80
79
|
| movable | 2.5KB | Free-positioning drag with [movable] and [movable-handle], edit mode only |
|
|
81
80
|
| onaftersave | 1KB | [onaftersave] attribute - run JS when save status changes |
|
|
81
|
+
| refetch-on-save | 0.9KB | Flash-free refetch of href/src resources on save via [refetch-on-save] attribute |
|
|
82
82
|
| save-freeze | 2.8KB | [save-freeze] attribute - freeze element innerHTML for saves, live DOM changes freely |
|
|
83
83
|
| sortable | 3.4KB | Drag-drop sorting with [sortable], lazy-loads ~118KB Sortable.js in edit mode |
|
|
84
84
|
|
|
@@ -123,7 +123,7 @@ import 'hyperclayjs/presets/standard.js';
|
|
|
123
123
|
| Module | Size | Description |
|
|
124
124
|
|--------|------|-------------|
|
|
125
125
|
| file-upload | 10.7KB | File upload with progress |
|
|
126
|
-
| live-sync | 11.
|
|
126
|
+
| live-sync | 11.6KB | Real-time DOM sync across browsers |
|
|
127
127
|
| send-message | 1.3KB | Message sending utility |
|
|
128
128
|
|
|
129
129
|
### Vendor Libraries (Third-party libraries)
|
|
@@ -144,7 +144,7 @@ Standard feature set for most use cases
|
|
|
144
144
|
|
|
145
145
|
**Modules:** `save-core`, `snapshot`, `save-system`, `unsaved-warning`, `edit-mode-helpers`, `persist`, `option-visibility`, `event-attrs`, `dom-helpers`, `toast`, `save-toast`, `export-to-window`, `view-mode-excludes-edit-modules`
|
|
146
146
|
|
|
147
|
-
### Everything (~
|
|
147
|
+
### Everything (~224.9KB)
|
|
148
148
|
All available features
|
|
149
149
|
|
|
150
150
|
Includes all available modules across all categories.
|
|
@@ -342,16 +342,16 @@ myFeature();
|
|
|
342
342
|
|
|
343
343
|
### Before
|
|
344
344
|
```html
|
|
345
|
-
<script src="/js/old-hyperclay.js"></script>
|
|
345
|
+
<script src="/public/js/old-hyperclay.js"></script>
|
|
346
346
|
```
|
|
347
347
|
|
|
348
348
|
### After
|
|
349
349
|
```html
|
|
350
350
|
<!-- Use preset -->
|
|
351
|
-
<script src="/js/hyperclay.js?preset=standard" type="module"></script>
|
|
351
|
+
<script src="/public/js/hyperclay.js?preset=standard" type="module"></script>
|
|
352
352
|
|
|
353
353
|
<!-- Or specific features -->
|
|
354
|
-
<script src="/js/hyperclay.js?features=save,edit-mode-helpers,toast" type="module"></script>
|
|
354
|
+
<script src="/public/js/hyperclay.js?features=save,edit-mode-helpers,toast" type="module"></script>
|
|
355
355
|
```
|
|
356
356
|
|
|
357
357
|
## Contributing
|
package/package.json
CHANGED
|
@@ -84,7 +84,7 @@ const behaviorCollector = (() => {
|
|
|
84
84
|
const scrollEvent = {
|
|
85
85
|
position: position,
|
|
86
86
|
timestamp: now,
|
|
87
|
-
direction: position > data.navigation.lastScrollPosition ? 'down' : 'up',
|
|
87
|
+
direction: position === data.navigation.lastScrollPosition ? null : (position > data.navigation.lastScrollPosition ? 'down' : 'up'),
|
|
88
88
|
isTrusted: e.isTrusted
|
|
89
89
|
};
|
|
90
90
|
|
|
@@ -96,7 +96,7 @@ const behaviorCollector = (() => {
|
|
|
96
96
|
|
|
97
97
|
if (data.scrollEvents.length > 1) {
|
|
98
98
|
const lastEvent = data.scrollEvents[data.scrollEvents.length - 2];
|
|
99
|
-
if (lastEvent.direction !== scrollEvent.direction) {
|
|
99
|
+
if (lastEvent.direction && scrollEvent.direction && lastEvent.direction !== scrollEvent.direction) {
|
|
100
100
|
data.navigation.scrollDirectionChanges++;
|
|
101
101
|
}
|
|
102
102
|
}
|
|
@@ -137,39 +137,28 @@ class LiveSync {
|
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
/**
|
|
140
|
-
* Auto-detect the current site
|
|
141
|
-
* Returns
|
|
140
|
+
* Auto-detect the current site file path from the URL
|
|
141
|
+
* Returns the path including extension (e.g., card-canvas.html)
|
|
142
142
|
*
|
|
143
143
|
* Handles:
|
|
144
|
-
* - /
|
|
145
|
-
* - /about
|
|
146
|
-
* - /about.
|
|
147
|
-
* - /about/
|
|
148
|
-
* - /
|
|
149
|
-
* - /pages/contact/ -> pages/contact/index
|
|
144
|
+
* - / -> index.html
|
|
145
|
+
* - /about.html -> about.html
|
|
146
|
+
* - /about.htmlclay -> about.htmlclay
|
|
147
|
+
* - /about.html/dashboard -> about.html (SPA route stripped)
|
|
148
|
+
* - /blog/app.htmlclay/settings -> blog/app.htmlclay (SPA route stripped)
|
|
150
149
|
*/
|
|
151
150
|
detectCurrentFile() {
|
|
152
151
|
let pathname = window.location.pathname;
|
|
153
152
|
|
|
154
|
-
// Root path
|
|
155
153
|
if (pathname === '/') {
|
|
156
|
-
return 'index';
|
|
154
|
+
return 'index.html';
|
|
157
155
|
}
|
|
158
156
|
|
|
159
|
-
// Remove leading slash
|
|
160
157
|
pathname = pathname.replace(/^\//, '');
|
|
161
158
|
|
|
162
|
-
|
|
163
|
-
if (
|
|
164
|
-
return pathname + 'index';
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Remove .html extension if present
|
|
168
|
-
if (pathname.endsWith('.html')) {
|
|
169
|
-
return pathname.slice(0, -5);
|
|
170
|
-
}
|
|
159
|
+
const htmlMatch = pathname.match(/^(.*?\.html(?:clay)?)/);
|
|
160
|
+
if (htmlMatch) return htmlMatch[1];
|
|
171
161
|
|
|
172
|
-
// Already a site identifier
|
|
173
162
|
return pathname;
|
|
174
163
|
}
|
|
175
164
|
|
|
@@ -180,7 +169,8 @@ class LiveSync {
|
|
|
180
169
|
connect() {
|
|
181
170
|
if (this.isDestroyed) return;
|
|
182
171
|
|
|
183
|
-
const
|
|
172
|
+
const pageUrl = encodeURIComponent(window.location.href);
|
|
173
|
+
const url = `/live-sync/stream?page-url=${pageUrl}`;
|
|
184
174
|
this.sse = new EventSource(url);
|
|
185
175
|
|
|
186
176
|
this.sse.onopen = () => {
|
|
@@ -276,9 +266,8 @@ class LiveSync {
|
|
|
276
266
|
|
|
277
267
|
fetch('/live-sync/save', {
|
|
278
268
|
method: 'POST',
|
|
279
|
-
headers: { 'Content-Type': 'application/json' },
|
|
269
|
+
headers: { 'Content-Type': 'application/json', 'Page-URL': window.location.href },
|
|
280
270
|
body: JSON.stringify({
|
|
281
|
-
file: this.currentFile,
|
|
282
271
|
html: html,
|
|
283
272
|
sender: this.clientId
|
|
284
273
|
})
|
|
@@ -2,7 +2,7 @@ import { isEditMode, isOwner } from "./isAdminOfCurrentResource.js";
|
|
|
2
2
|
import onDomReady from "../dom-utilities/onDomReady.js";
|
|
3
3
|
import {beforeSave} from "./savePage.js";
|
|
4
4
|
|
|
5
|
-
const SELECTOR = '[editmode\\:contenteditable]';
|
|
5
|
+
export const SELECTOR = '[editmode\\:contenteditable]';
|
|
6
6
|
|
|
7
7
|
export function disableContentEditableBeforeSave () {
|
|
8
8
|
beforeSave(docElem => {
|
package/src/core/adminInputs.js
CHANGED
|
@@ -2,8 +2,8 @@ import { isEditMode, isOwner } from "./isAdminOfCurrentResource.js";
|
|
|
2
2
|
import onDomReady from "../dom-utilities/onDomReady.js";
|
|
3
3
|
import { beforeSave } from "./savePage.js";
|
|
4
4
|
|
|
5
|
-
const SELECTOR_DISABLED = '[viewmode\\:disabled]';
|
|
6
|
-
const SELECTOR_READONLY = '[viewmode\\:readonly]';
|
|
5
|
+
export const SELECTOR_DISABLED = '[viewmode\\:disabled]';
|
|
6
|
+
export const SELECTOR_READONLY = '[viewmode\\:readonly]';
|
|
7
7
|
|
|
8
8
|
export function disableAdminInputsBeforeSave() {
|
|
9
9
|
beforeSave(docElem => {
|
package/src/core/adminOnClick.js
CHANGED
|
@@ -2,7 +2,7 @@ import { isEditMode, isOwner } from "./isAdminOfCurrentResource.js";
|
|
|
2
2
|
import onDomReady from "../dom-utilities/onDomReady.js";
|
|
3
3
|
import {beforeSave} from "./savePage.js";
|
|
4
4
|
|
|
5
|
-
const SELECTOR = '[editmode\\:onclick]';
|
|
5
|
+
export const SELECTOR = '[editmode\\:onclick]';
|
|
6
6
|
|
|
7
7
|
export function disableOnClickBeforeSave () {
|
|
8
8
|
beforeSave(docElem => {
|
|
@@ -2,8 +2,8 @@ import { isEditMode, isOwner } from "./isAdminOfCurrentResource.js";
|
|
|
2
2
|
import onDomReady from "../dom-utilities/onDomReady.js";
|
|
3
3
|
import {beforeSave} from "./savePage.js";
|
|
4
4
|
|
|
5
|
-
const SELECTOR = '[editmode\\:resource]:is(style, link, script)';
|
|
6
|
-
const SELECTOR_INERT = '[editmode\\:resource]:is(style, link, script)[type^="inert/"]';
|
|
5
|
+
export const SELECTOR = '[editmode\\:resource]:is(style, link, script)';
|
|
6
|
+
export const SELECTOR_INERT = '[editmode\\:resource]:is(style, link, script)[type^="inert/"]';
|
|
7
7
|
|
|
8
8
|
export function disableAdminResourcesBeforeSave () {
|
|
9
9
|
beforeSave(docElem => {
|
package/src/core/adminSystem.js
CHANGED
|
@@ -4,7 +4,11 @@ import { init as initInputs } from './adminInputs.js';
|
|
|
4
4
|
import { init as initOnClick } from './adminOnClick.js';
|
|
5
5
|
import { init as initResources } from './adminResources.js';
|
|
6
6
|
|
|
7
|
+
let initialized = false;
|
|
8
|
+
|
|
7
9
|
function init() {
|
|
10
|
+
if (initialized) return;
|
|
11
|
+
initialized = true;
|
|
8
12
|
initContenteditable();
|
|
9
13
|
initInputs();
|
|
10
14
|
initOnClick();
|
package/src/core/autosave.js
CHANGED
|
@@ -20,7 +20,7 @@ import { savePageThrottled } from "./savePage.js";
|
|
|
20
20
|
*/
|
|
21
21
|
function initSavePageOnChange() {
|
|
22
22
|
Mutation.onAnyChange({
|
|
23
|
-
debounce:
|
|
23
|
+
debounce: 1500,
|
|
24
24
|
omitChangeDetails: true
|
|
25
25
|
}, () => {
|
|
26
26
|
savePageThrottled();
|
|
@@ -36,7 +36,7 @@ function initSaveOnPersistInput() {
|
|
|
36
36
|
document.addEventListener('input', (e) => {
|
|
37
37
|
if (!e.target.closest('[persist]')) return;
|
|
38
38
|
clearTimeout(inputSaveTimer);
|
|
39
|
-
inputSaveTimer = setTimeout(savePageThrottled,
|
|
39
|
+
inputSaveTimer = setTimeout(savePageThrottled, 1500);
|
|
40
40
|
}, true);
|
|
41
41
|
}
|
|
42
42
|
|
package/src/core/savePageCore.js
CHANGED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
* For full save system with state management, use savePage.js instead.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import cookie from "../utilities/cookie.js";
|
|
11
10
|
import { isEditMode } from "./isAdminOfCurrentResource.js";
|
|
12
11
|
import {
|
|
13
12
|
captureForSave,
|
|
@@ -24,7 +23,7 @@ import {
|
|
|
24
23
|
// =============================================================================
|
|
25
24
|
|
|
26
25
|
let saveInProgress = false;
|
|
27
|
-
const saveEndpoint =
|
|
26
|
+
const saveEndpoint = '/save';
|
|
28
27
|
|
|
29
28
|
/**
|
|
30
29
|
* Check if a save is currently in progress.
|
|
@@ -119,12 +118,13 @@ export function savePage(callback = () => {}) {
|
|
|
119
118
|
const fetchOptions = {
|
|
120
119
|
method: 'POST',
|
|
121
120
|
credentials: 'include',
|
|
122
|
-
signal: controller.signal
|
|
121
|
+
signal: controller.signal,
|
|
122
|
+
headers: { 'Page-URL': window.location.href }
|
|
123
123
|
};
|
|
124
124
|
|
|
125
125
|
if (isHyperclayLocal && window.__hyperclaySnapshotHtml) {
|
|
126
126
|
// Send JSON with both stripped content and full snapshot for platform live sync
|
|
127
|
-
fetchOptions.headers
|
|
127
|
+
fetchOptions.headers['Content-Type'] = 'application/json';
|
|
128
128
|
fetchOptions.body = JSON.stringify({
|
|
129
129
|
content: currentContents,
|
|
130
130
|
snapshotHtml: window.__hyperclaySnapshotHtml
|
|
@@ -213,12 +213,13 @@ export function saveHtml(html, callback = () => {}) {
|
|
|
213
213
|
const fetchOptions = {
|
|
214
214
|
method: 'POST',
|
|
215
215
|
credentials: 'include',
|
|
216
|
-
signal: controller.signal
|
|
216
|
+
signal: controller.signal,
|
|
217
|
+
headers: { 'Page-URL': window.location.href }
|
|
217
218
|
};
|
|
218
219
|
|
|
219
220
|
if (isHyperclayLocal && window.__hyperclaySnapshotHtml) {
|
|
220
221
|
// Send JSON with both stripped content and full snapshot for platform live sync
|
|
221
|
-
fetchOptions.headers
|
|
222
|
+
fetchOptions.headers['Content-Type'] = 'application/json';
|
|
222
223
|
fetchOptions.body = JSON.stringify({
|
|
223
224
|
content: html,
|
|
224
225
|
snapshotHtml: window.__hyperclaySnapshotHtml
|
|
@@ -49,11 +49,13 @@ function submitAjax(elem) {
|
|
|
49
49
|
},
|
|
50
50
|
body: JSON.stringify(data)
|
|
51
51
|
})
|
|
52
|
-
.then(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
.then(async (res) => {
|
|
53
|
+
const contentType = res.headers.get('content-type') || '';
|
|
54
|
+
let resData = {};
|
|
55
|
+
if (res.status !== 204 && contentType.includes('application/json')) {
|
|
56
|
+
resData = await res.json();
|
|
57
|
+
}
|
|
58
|
+
handleResponse(elem, { ...resData, ok: res.ok, msgType: res.ok ? "success" : "error" });
|
|
57
59
|
})
|
|
58
60
|
.catch(error => console.error('Error:', error));
|
|
59
61
|
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
function swapElement(el) {
|
|
2
|
+
const attr = el.hasAttribute('href') ? 'href' : el.hasAttribute('src') ? 'src' : null;
|
|
3
|
+
if (!attr) return;
|
|
4
|
+
|
|
5
|
+
const oldValue = el.getAttribute(attr);
|
|
6
|
+
const url = new URL(oldValue, location.href);
|
|
7
|
+
url.searchParams.set('v', Date.now());
|
|
8
|
+
const isSameOrigin = url.origin === location.origin;
|
|
9
|
+
|
|
10
|
+
const newEl = document.createElement(el.tagName);
|
|
11
|
+
for (const { name, value } of el.attributes) {
|
|
12
|
+
newEl.setAttribute(name, value);
|
|
13
|
+
}
|
|
14
|
+
newEl.setAttribute(attr, isSameOrigin ? url.pathname + url.search : url.href);
|
|
15
|
+
newEl.setAttribute('save-ignore', '');
|
|
16
|
+
|
|
17
|
+
el.insertAdjacentElement('afterend', newEl);
|
|
18
|
+
|
|
19
|
+
newEl.onload = () => el.remove();
|
|
20
|
+
setTimeout(() => {
|
|
21
|
+
if (el.parentNode) el.remove();
|
|
22
|
+
}, 2000);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function init() {
|
|
26
|
+
document.addEventListener('hyperclay:save-saved', () => {
|
|
27
|
+
document.querySelectorAll('[refetch-on-save]').forEach(swapElement);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
init();
|
|
32
|
+
|
|
33
|
+
export default init;
|
|
@@ -5,7 +5,7 @@ function getDataFromForm(container) {
|
|
|
5
5
|
// Helper function to process a single element
|
|
6
6
|
const processElement = (elem) => {
|
|
7
7
|
const name = elem.getAttribute('name');
|
|
8
|
-
const value = elem.
|
|
8
|
+
const value = elem.value || elem.getAttribute('value');
|
|
9
9
|
|
|
10
10
|
// Skip elements without a name or with a disabled attribute
|
|
11
11
|
if (!name || elem.disabled) return;
|
package/src/hyperclay.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* DO NOT EDIT THIS FILE DIRECTLY — it is generated from build/hyperclay.template.js
|
|
3
3
|
*
|
|
4
|
-
* HyperclayJS v1.24.
|
|
4
|
+
* HyperclayJS v1.24.4 - Minimal Browser-Native Loader
|
|
5
5
|
*
|
|
6
6
|
* Modules auto-init when imported (no separate init call needed).
|
|
7
7
|
* Include `export-to-window` feature to export to window.hyperclay.
|
|
@@ -68,7 +68,7 @@ const MODULE_PATHS = {
|
|
|
68
68
|
"send-message": "./communication/sendMessage.js",
|
|
69
69
|
"file-upload": "./communication/uploadFile.js",
|
|
70
70
|
"live-sync": "./communication/live-sync.js",
|
|
71
|
-
"
|
|
71
|
+
"refetch-on-save": "./custom-attributes/refetchOnSave.js",
|
|
72
72
|
"export-to-window": "./core/exportToWindow.js"
|
|
73
73
|
};
|
|
74
74
|
const PRESETS = {
|
|
@@ -145,6 +145,7 @@ const PRESETS = {
|
|
|
145
145
|
"behavior-collector",
|
|
146
146
|
"send-message",
|
|
147
147
|
"file-upload",
|
|
148
|
+
"refetch-on-save",
|
|
148
149
|
"export-to-window",
|
|
149
150
|
"view-mode-excludes-edit-modules"
|
|
150
151
|
]
|
|
@@ -193,7 +194,7 @@ const PRESETS = {
|
|
|
193
194
|
"send-message",
|
|
194
195
|
"file-upload",
|
|
195
196
|
"live-sync",
|
|
196
|
-
"
|
|
197
|
+
"refetch-on-save",
|
|
197
198
|
"export-to-window",
|
|
198
199
|
"view-mode-excludes-edit-modules"
|
|
199
200
|
]
|
|
@@ -216,7 +217,7 @@ const EDIT_MODE_ONLY = new Set([
|
|
|
216
217
|
"hyper-morph",
|
|
217
218
|
"file-upload",
|
|
218
219
|
"live-sync",
|
|
219
|
-
"
|
|
220
|
+
"refetch-on-save"
|
|
220
221
|
]);
|
|
221
222
|
|
|
222
223
|
// Parse URL (use import.meta.url for ES modules since document.currentScript is null)
|
package/src/utilities/cookie.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
// e.g. Cookie.get("
|
|
1
|
+
// e.g. Cookie.get("isAdminOfCurrentResource")
|
|
2
2
|
function get (cookieName) {
|
|
3
3
|
const cookies = document.cookie.split('; ');
|
|
4
4
|
const cookie = cookies.find(row => row.startsWith(`${cookieName}=`));
|
|
5
5
|
if (!cookie) return null;
|
|
6
|
-
const cookieValue = cookie.
|
|
6
|
+
const cookieValue = cookie.slice(cookieName.length + 1);
|
|
7
7
|
try {
|
|
8
8
|
return JSON.parse(decodeURIComponent(cookieValue));
|
|
9
9
|
} catch (err) {
|
|
@@ -11,7 +11,7 @@ function get (cookieName) {
|
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
// e.g. Cookie.remove("
|
|
14
|
+
// e.g. Cookie.remove("isAdminOfCurrentResource")
|
|
15
15
|
function remove(name) {
|
|
16
16
|
// Clear from current path
|
|
17
17
|
document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/;`
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { insertStyles } from '../dom-utilities/insertStyleTag.js';
|
|
2
|
-
import cookie from '../utilities/cookie.js';
|
|
3
|
-
|
|
4
|
-
function findTailwindLink(resourceName) {
|
|
5
|
-
const targetPath = `/tailwindcss/${resourceName}.css`;
|
|
6
|
-
return [...document.querySelectorAll('link[rel="stylesheet"]')]
|
|
7
|
-
.find(el => {
|
|
8
|
-
try {
|
|
9
|
-
const url = new URL(el.getAttribute('href'), location.href);
|
|
10
|
-
return url.pathname === targetPath;
|
|
11
|
-
} catch {
|
|
12
|
-
return false;
|
|
13
|
-
}
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function swapTailwindLink() {
|
|
18
|
-
const currentResource = cookie.get('currentResource');
|
|
19
|
-
if (!currentResource) return;
|
|
20
|
-
|
|
21
|
-
const oldLink = findTailwindLink(currentResource);
|
|
22
|
-
if (!oldLink) return;
|
|
23
|
-
|
|
24
|
-
const newLink = document.createElement('link');
|
|
25
|
-
newLink.rel = 'stylesheet';
|
|
26
|
-
const url = new URL(oldLink.getAttribute('href'), location.href);
|
|
27
|
-
url.searchParams.set('v', Date.now());
|
|
28
|
-
newLink.href = url.href;
|
|
29
|
-
newLink.setAttribute('save-ignore', '');
|
|
30
|
-
|
|
31
|
-
oldLink.insertAdjacentElement('afterend', newLink);
|
|
32
|
-
|
|
33
|
-
newLink.onload = () => {
|
|
34
|
-
oldLink.remove();
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
setTimeout(() => {
|
|
38
|
-
if (oldLink.parentNode) {
|
|
39
|
-
oldLink.remove();
|
|
40
|
-
}
|
|
41
|
-
}, 2000);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function init() {
|
|
45
|
-
const currentResource = cookie.get('currentResource');
|
|
46
|
-
if (!currentResource) return;
|
|
47
|
-
|
|
48
|
-
const href = `/tailwindcss/${currentResource}.css`;
|
|
49
|
-
insertStyles(href, (link) => {
|
|
50
|
-
link.setAttribute('save-ignore', '');
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
document.addEventListener('hyperclay:save-saved', swapTailwindLink);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
init();
|