mnfst 0.5.31 → 0.5.33
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/dist/manifest.js +11 -3
- package/dist/manifest.router.js +107 -32
- package/package.json +1 -1
package/dist/manifest.js
CHANGED
|
@@ -117,10 +117,13 @@
|
|
|
117
117
|
return new Promise((resolve, reject) => {
|
|
118
118
|
const url = getPluginUrl(pluginName, version);
|
|
119
119
|
|
|
120
|
-
//
|
|
120
|
+
// Skip if script with same src already in DOM (e.g. prerendered HTML or second loader run)
|
|
121
121
|
const existing = document.querySelector(`script[src="${url}"]`);
|
|
122
|
-
if (existing
|
|
123
|
-
return resolve();
|
|
122
|
+
if (existing) {
|
|
123
|
+
if (existing.complete) return resolve();
|
|
124
|
+
existing.addEventListener('load', () => resolve());
|
|
125
|
+
existing.addEventListener('error', () => reject(new Error(`Failed to load ${pluginName} from ${url}`)));
|
|
126
|
+
return;
|
|
124
127
|
}
|
|
125
128
|
|
|
126
129
|
const script = document.createElement('script');
|
|
@@ -297,6 +300,11 @@
|
|
|
297
300
|
detectAppwriteFromManifest();
|
|
298
301
|
|
|
299
302
|
if (config && config.plugins.length > 0) {
|
|
303
|
+
if (window.__manifestLoaderStarted) {
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
window.__manifestLoaderStarted = true;
|
|
307
|
+
|
|
300
308
|
const MANIFEST_DEPENDENT_PLUGINS = [
|
|
301
309
|
'data', 'localization', 'components',
|
|
302
310
|
'appwrite-auth', 'appwrite-data', 'appwrite-presence'
|
package/dist/manifest.router.js
CHANGED
|
@@ -169,7 +169,12 @@ function getBasePath() {
|
|
|
169
169
|
|
|
170
170
|
function pathnameToLogical(pathname) {
|
|
171
171
|
const base = getBasePath();
|
|
172
|
-
if (!base
|
|
172
|
+
if (!base) {
|
|
173
|
+
const p = (pathname || '/').replace(/\/$/, '') || '/';
|
|
174
|
+
if (p === '/' || p === '/index.html' || p === '/index') return '/';
|
|
175
|
+
return p.startsWith('/') ? p : '/' + p;
|
|
176
|
+
}
|
|
177
|
+
if (pathname === base || pathname === base + '/') return '/';
|
|
173
178
|
if (pathname.startsWith(base + '/')) {
|
|
174
179
|
let logical = pathname.slice(base.length) || '/';
|
|
175
180
|
if (logical === '/index.html' || logical === '/index') logical = '/';
|
|
@@ -592,6 +597,39 @@ function shouldElementBeVisible(element, normalizedPath) {
|
|
|
592
597
|
return true;
|
|
593
598
|
}
|
|
594
599
|
|
|
600
|
+
// Resolve :attr and x-bind:attr whose value is $x.path so injected meta/link have real content (SPA + prerender).
|
|
601
|
+
function resolveDataHeadBindings(element) {
|
|
602
|
+
const x = typeof window !== 'undefined' && window.$x;
|
|
603
|
+
if (!x) return;
|
|
604
|
+
const toResolve = [];
|
|
605
|
+
for (let i = 0; i < element.attributes.length; i++) {
|
|
606
|
+
const attr = element.attributes[i];
|
|
607
|
+
const name = attr.name;
|
|
608
|
+
let bindingAttr = null;
|
|
609
|
+
if (name.startsWith(':')) bindingAttr = name.slice(1);
|
|
610
|
+
else if (name.startsWith('x-bind:')) bindingAttr = name.slice(7);
|
|
611
|
+
if (!bindingAttr) continue;
|
|
612
|
+
const expr = (attr.value || '').trim();
|
|
613
|
+
if (!expr.startsWith('$x.')) continue;
|
|
614
|
+
const path = expr.slice(3).trim();
|
|
615
|
+
if (!path) continue;
|
|
616
|
+
toResolve.push({ bindingName: attr.name, attrName: bindingAttr, path });
|
|
617
|
+
}
|
|
618
|
+
for (const { bindingName, attrName, path } of toResolve) {
|
|
619
|
+
let value;
|
|
620
|
+
try {
|
|
621
|
+
value = path.split('.').reduce(function (obj, key) {
|
|
622
|
+
return obj != null && typeof obj === 'object' ? obj[key] : undefined;
|
|
623
|
+
}, x);
|
|
624
|
+
} catch (e) {
|
|
625
|
+
continue;
|
|
626
|
+
}
|
|
627
|
+
if (value === undefined) continue;
|
|
628
|
+
element.setAttribute(attrName, String(value));
|
|
629
|
+
element.removeAttribute(bindingName);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
|
|
595
633
|
// Generate unique identifier for head content
|
|
596
634
|
function generateHeadId(element) {
|
|
597
635
|
const position = element.getAttribute('data-order');
|
|
@@ -627,10 +665,14 @@ function processElementHeadContent(element, normalizedPath) {
|
|
|
627
665
|
const isVisible = shouldElementBeVisible(element, normalizedPath);
|
|
628
666
|
|
|
629
667
|
if (isVisible) {
|
|
630
|
-
//
|
|
668
|
+
// Skip if already injected (in-memory) or already present in DOM (e.g. prerendered)
|
|
631
669
|
if (injectedHeadContent.has(headId)) {
|
|
632
670
|
return;
|
|
633
671
|
}
|
|
672
|
+
if (document.head.querySelector(`[data-route-head="${headId}"]`)) {
|
|
673
|
+
injectedHeadContent.add(headId);
|
|
674
|
+
return;
|
|
675
|
+
}
|
|
634
676
|
|
|
635
677
|
// Add new head content
|
|
636
678
|
Array.from(headTemplate.content.children).forEach(child => {
|
|
@@ -641,8 +683,9 @@ function processElementHeadContent(element, normalizedPath) {
|
|
|
641
683
|
script.setAttribute('data-route-head', headId);
|
|
642
684
|
document.head.appendChild(script);
|
|
643
685
|
} else {
|
|
644
|
-
// For other elements, clone and add
|
|
686
|
+
// For other elements, clone and add (resolve $x bindings so meta/link have real values in SPA)
|
|
645
687
|
const clonedChild = child.cloneNode(true);
|
|
688
|
+
resolveDataHeadBindings(clonedChild);
|
|
646
689
|
clonedChild.setAttribute('data-route-head', headId);
|
|
647
690
|
document.head.appendChild(clonedChild);
|
|
648
691
|
}
|
|
@@ -826,6 +869,29 @@ window.ManifestRoutingHead = {
|
|
|
826
869
|
|
|
827
870
|
// Router anchors
|
|
828
871
|
|
|
872
|
+
// Parse pipeline syntax: 'scope | targets' (shared for directive and route-change handler)
|
|
873
|
+
function parseAnchorsExpression(expr) {
|
|
874
|
+
if (!expr || expr.trim() === '') {
|
|
875
|
+
return { scope: '', targets: 'h1, h2, h3, h4, h5, h6' };
|
|
876
|
+
}
|
|
877
|
+
if (expr.includes('|')) {
|
|
878
|
+
const parts = expr.split('|').map(p => p.trim());
|
|
879
|
+
return {
|
|
880
|
+
scope: parts[0] || '',
|
|
881
|
+
targets: parts[1] || 'h1, h2, h3, h4, h5, h6'
|
|
882
|
+
};
|
|
883
|
+
}
|
|
884
|
+
return { scope: '', targets: expr };
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
function isVisible(el) {
|
|
888
|
+
if (!el || !el.getBoundingClientRect) return false;
|
|
889
|
+
const rect = el.getBoundingClientRect();
|
|
890
|
+
if (rect.width === 0 && rect.height === 0) return false;
|
|
891
|
+
const style = window.getComputedStyle(el);
|
|
892
|
+
return style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0';
|
|
893
|
+
}
|
|
894
|
+
|
|
829
895
|
// Anchors functionality
|
|
830
896
|
function initializeAnchors() {
|
|
831
897
|
|
|
@@ -834,24 +900,9 @@ function initializeAnchors() {
|
|
|
834
900
|
|
|
835
901
|
|
|
836
902
|
try {
|
|
837
|
-
|
|
838
|
-
const parseExpression = (expr) => {
|
|
839
|
-
if (!expr || expr.trim() === '') {
|
|
840
|
-
return { scope: '', targets: 'h1, h2, h3, h4, h5, h6' };
|
|
841
|
-
}
|
|
903
|
+
const parseExpression = parseAnchorsExpression;
|
|
842
904
|
|
|
843
|
-
|
|
844
|
-
const parts = expr.split('|').map(p => p.trim());
|
|
845
|
-
return {
|
|
846
|
-
scope: parts[0] || '',
|
|
847
|
-
targets: parts[1] || 'h1, h2, h3, h4, h5, h6'
|
|
848
|
-
};
|
|
849
|
-
} else {
|
|
850
|
-
return { scope: '', targets: expr };
|
|
851
|
-
}
|
|
852
|
-
};
|
|
853
|
-
|
|
854
|
-
// Extract anchors function
|
|
905
|
+
// Extract anchors function (only from visible scope containers to avoid prior-route content)
|
|
855
906
|
const extractAnchors = (expr) => {
|
|
856
907
|
const parsed = parseExpression(expr);
|
|
857
908
|
|
|
@@ -859,7 +910,8 @@ function initializeAnchors() {
|
|
|
859
910
|
if (!parsed.scope) {
|
|
860
911
|
containers = [document.body];
|
|
861
912
|
} else {
|
|
862
|
-
|
|
913
|
+
const all = Array.from(document.querySelectorAll(parsed.scope));
|
|
914
|
+
containers = all.filter(isVisible);
|
|
863
915
|
}
|
|
864
916
|
|
|
865
917
|
let elements = [];
|
|
@@ -1122,21 +1174,44 @@ document.addEventListener('alpine:init', () => {
|
|
|
1122
1174
|
}
|
|
1123
1175
|
});
|
|
1124
1176
|
|
|
1125
|
-
// Refresh anchors when route changes
|
|
1177
|
+
// Refresh anchors when route changes — wait for scope DOM to update (e.g. x-markdown) to avoid showing prior page's anchors
|
|
1126
1178
|
window.addEventListener('manifest:route-change', () => {
|
|
1127
|
-
// Immediately clear the store to hide the h5 element
|
|
1128
1179
|
Alpine.store('anchors', { count: 0 });
|
|
1129
1180
|
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1181
|
+
const runWhenScopeReady = (el) => {
|
|
1182
|
+
const expression = el.getAttribute('x-anchors');
|
|
1183
|
+
if (!expression || !el._x_anchorRefresh) return;
|
|
1184
|
+
const { scope } = parseAnchorsExpression(expression);
|
|
1185
|
+
if (!scope) {
|
|
1186
|
+
setTimeout(() => el._x_anchorRefresh(), 400);
|
|
1187
|
+
return;
|
|
1188
|
+
}
|
|
1189
|
+
const containers = Array.from(document.querySelectorAll(scope)).filter(isVisible);
|
|
1190
|
+
const container = containers[0];
|
|
1191
|
+
if (!container) {
|
|
1192
|
+
el._x_anchorRefresh();
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1195
|
+
let done = false;
|
|
1196
|
+
const finish = () => {
|
|
1197
|
+
if (done) return;
|
|
1198
|
+
done = true;
|
|
1199
|
+
observer?.disconnect();
|
|
1200
|
+
clearTimeout(fallback);
|
|
1201
|
+
el._x_anchorRefresh();
|
|
1202
|
+
};
|
|
1203
|
+
let t = 0;
|
|
1204
|
+
const observer = new MutationObserver(() => {
|
|
1205
|
+
clearTimeout(t);
|
|
1206
|
+
t = setTimeout(finish, 50);
|
|
1138
1207
|
});
|
|
1139
|
-
|
|
1208
|
+
observer.observe(container, { childList: true, subtree: true });
|
|
1209
|
+
const fallback = setTimeout(finish, 800);
|
|
1210
|
+
};
|
|
1211
|
+
|
|
1212
|
+
requestAnimationFrame(() => {
|
|
1213
|
+
document.querySelectorAll('[x-anchors]').forEach(runWhenScopeReady);
|
|
1214
|
+
});
|
|
1140
1215
|
});
|
|
1141
1216
|
|
|
1142
1217
|
// Refresh anchors when hash changes (for active state updates)
|