mnfst 0.5.32 → 0.5.34
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 +118 -39
- 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
|
@@ -163,6 +163,12 @@ window.ManifestRoutingPosition = {
|
|
|
163
163
|
let currentRoute = '/';
|
|
164
164
|
let isInternalNavigation = false;
|
|
165
165
|
|
|
166
|
+
function isPrerenderedStaticBuild() {
|
|
167
|
+
// When prerendered HTML is served as static pages, prefer normal browser navigation (MPA)
|
|
168
|
+
// so each URL loads its own prerendered HTML rather than SPA toggling.
|
|
169
|
+
return !!document.querySelector('meta[name="manifest:prerendered"][content="1"]');
|
|
170
|
+
}
|
|
171
|
+
|
|
166
172
|
function getBasePath() {
|
|
167
173
|
return (typeof window.getManifestBasePath === 'function' ? window.getManifestBasePath() : '') || '';
|
|
168
174
|
}
|
|
@@ -353,15 +359,18 @@ function initializeNavigation() {
|
|
|
353
359
|
// Set initial route (logical path for matching)
|
|
354
360
|
currentRoute = pathnameToLogical(window.location.pathname);
|
|
355
361
|
|
|
356
|
-
//
|
|
357
|
-
|
|
362
|
+
// In prerendered/static output, use default browser navigation (no interception)
|
|
363
|
+
if (!isPrerenderedStaticBuild()) {
|
|
364
|
+
// Intercept link clicks
|
|
365
|
+
interceptLinkClicks();
|
|
358
366
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
367
|
+
// Listen for popstate events (browser back/forward)
|
|
368
|
+
window.addEventListener('popstate', () => {
|
|
369
|
+
if (!isInternalNavigation) {
|
|
370
|
+
handleRouteChange();
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
}
|
|
365
374
|
|
|
366
375
|
// Handle initial route
|
|
367
376
|
handleRouteChange();
|
|
@@ -597,6 +606,39 @@ function shouldElementBeVisible(element, normalizedPath) {
|
|
|
597
606
|
return true;
|
|
598
607
|
}
|
|
599
608
|
|
|
609
|
+
// Resolve :attr and x-bind:attr whose value is $x.path so injected meta/link have real content (SPA + prerender).
|
|
610
|
+
function resolveDataHeadBindings(element) {
|
|
611
|
+
const x = typeof window !== 'undefined' && window.$x;
|
|
612
|
+
if (!x) return;
|
|
613
|
+
const toResolve = [];
|
|
614
|
+
for (let i = 0; i < element.attributes.length; i++) {
|
|
615
|
+
const attr = element.attributes[i];
|
|
616
|
+
const name = attr.name;
|
|
617
|
+
let bindingAttr = null;
|
|
618
|
+
if (name.startsWith(':')) bindingAttr = name.slice(1);
|
|
619
|
+
else if (name.startsWith('x-bind:')) bindingAttr = name.slice(7);
|
|
620
|
+
if (!bindingAttr) continue;
|
|
621
|
+
const expr = (attr.value || '').trim();
|
|
622
|
+
if (!expr.startsWith('$x.')) continue;
|
|
623
|
+
const path = expr.slice(3).trim();
|
|
624
|
+
if (!path) continue;
|
|
625
|
+
toResolve.push({ bindingName: attr.name, attrName: bindingAttr, path });
|
|
626
|
+
}
|
|
627
|
+
for (const { bindingName, attrName, path } of toResolve) {
|
|
628
|
+
let value;
|
|
629
|
+
try {
|
|
630
|
+
value = path.split('.').reduce(function (obj, key) {
|
|
631
|
+
return obj != null && typeof obj === 'object' ? obj[key] : undefined;
|
|
632
|
+
}, x);
|
|
633
|
+
} catch (e) {
|
|
634
|
+
continue;
|
|
635
|
+
}
|
|
636
|
+
if (value === undefined) continue;
|
|
637
|
+
element.setAttribute(attrName, String(value));
|
|
638
|
+
element.removeAttribute(bindingName);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
600
642
|
// Generate unique identifier for head content
|
|
601
643
|
function generateHeadId(element) {
|
|
602
644
|
const position = element.getAttribute('data-order');
|
|
@@ -632,10 +674,14 @@ function processElementHeadContent(element, normalizedPath) {
|
|
|
632
674
|
const isVisible = shouldElementBeVisible(element, normalizedPath);
|
|
633
675
|
|
|
634
676
|
if (isVisible) {
|
|
635
|
-
//
|
|
677
|
+
// Skip if already injected (in-memory) or already present in DOM (e.g. prerendered)
|
|
636
678
|
if (injectedHeadContent.has(headId)) {
|
|
637
679
|
return;
|
|
638
680
|
}
|
|
681
|
+
if (document.head.querySelector(`[data-route-head="${headId}"]`)) {
|
|
682
|
+
injectedHeadContent.add(headId);
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
639
685
|
|
|
640
686
|
// Add new head content
|
|
641
687
|
Array.from(headTemplate.content.children).forEach(child => {
|
|
@@ -646,8 +692,9 @@ function processElementHeadContent(element, normalizedPath) {
|
|
|
646
692
|
script.setAttribute('data-route-head', headId);
|
|
647
693
|
document.head.appendChild(script);
|
|
648
694
|
} else {
|
|
649
|
-
// For other elements, clone and add
|
|
695
|
+
// For other elements, clone and add (resolve $x bindings so meta/link have real values in SPA)
|
|
650
696
|
const clonedChild = child.cloneNode(true);
|
|
697
|
+
resolveDataHeadBindings(clonedChild);
|
|
651
698
|
clonedChild.setAttribute('data-route-head', headId);
|
|
652
699
|
document.head.appendChild(clonedChild);
|
|
653
700
|
}
|
|
@@ -831,6 +878,29 @@ window.ManifestRoutingHead = {
|
|
|
831
878
|
|
|
832
879
|
// Router anchors
|
|
833
880
|
|
|
881
|
+
// Parse pipeline syntax: 'scope | targets' (shared for directive and route-change handler)
|
|
882
|
+
function parseAnchorsExpression(expr) {
|
|
883
|
+
if (!expr || expr.trim() === '') {
|
|
884
|
+
return { scope: '', targets: 'h1, h2, h3, h4, h5, h6' };
|
|
885
|
+
}
|
|
886
|
+
if (expr.includes('|')) {
|
|
887
|
+
const parts = expr.split('|').map(p => p.trim());
|
|
888
|
+
return {
|
|
889
|
+
scope: parts[0] || '',
|
|
890
|
+
targets: parts[1] || 'h1, h2, h3, h4, h5, h6'
|
|
891
|
+
};
|
|
892
|
+
}
|
|
893
|
+
return { scope: '', targets: expr };
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
function isVisible(el) {
|
|
897
|
+
if (!el || !el.getBoundingClientRect) return false;
|
|
898
|
+
const rect = el.getBoundingClientRect();
|
|
899
|
+
if (rect.width === 0 && rect.height === 0) return false;
|
|
900
|
+
const style = window.getComputedStyle(el);
|
|
901
|
+
return style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0';
|
|
902
|
+
}
|
|
903
|
+
|
|
834
904
|
// Anchors functionality
|
|
835
905
|
function initializeAnchors() {
|
|
836
906
|
|
|
@@ -839,24 +909,9 @@ function initializeAnchors() {
|
|
|
839
909
|
|
|
840
910
|
|
|
841
911
|
try {
|
|
842
|
-
|
|
843
|
-
const parseExpression = (expr) => {
|
|
844
|
-
if (!expr || expr.trim() === '') {
|
|
845
|
-
return { scope: '', targets: 'h1, h2, h3, h4, h5, h6' };
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
if (expr.includes('|')) {
|
|
849
|
-
const parts = expr.split('|').map(p => p.trim());
|
|
850
|
-
return {
|
|
851
|
-
scope: parts[0] || '',
|
|
852
|
-
targets: parts[1] || 'h1, h2, h3, h4, h5, h6'
|
|
853
|
-
};
|
|
854
|
-
} else {
|
|
855
|
-
return { scope: '', targets: expr };
|
|
856
|
-
}
|
|
857
|
-
};
|
|
912
|
+
const parseExpression = parseAnchorsExpression;
|
|
858
913
|
|
|
859
|
-
// Extract anchors function
|
|
914
|
+
// Extract anchors function (only from visible scope containers to avoid prior-route content)
|
|
860
915
|
const extractAnchors = (expr) => {
|
|
861
916
|
const parsed = parseExpression(expr);
|
|
862
917
|
|
|
@@ -864,7 +919,8 @@ function initializeAnchors() {
|
|
|
864
919
|
if (!parsed.scope) {
|
|
865
920
|
containers = [document.body];
|
|
866
921
|
} else {
|
|
867
|
-
|
|
922
|
+
const all = Array.from(document.querySelectorAll(parsed.scope));
|
|
923
|
+
containers = all.filter(isVisible);
|
|
868
924
|
}
|
|
869
925
|
|
|
870
926
|
let elements = [];
|
|
@@ -1127,21 +1183,44 @@ document.addEventListener('alpine:init', () => {
|
|
|
1127
1183
|
}
|
|
1128
1184
|
});
|
|
1129
1185
|
|
|
1130
|
-
// Refresh anchors when route changes
|
|
1186
|
+
// Refresh anchors when route changes — wait for scope DOM to update (e.g. x-markdown) to avoid showing prior page's anchors
|
|
1131
1187
|
window.addEventListener('manifest:route-change', () => {
|
|
1132
|
-
// Immediately clear the store to hide the h5 element
|
|
1133
1188
|
Alpine.store('anchors', { count: 0 });
|
|
1134
1189
|
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1190
|
+
const runWhenScopeReady = (el) => {
|
|
1191
|
+
const expression = el.getAttribute('x-anchors');
|
|
1192
|
+
if (!expression || !el._x_anchorRefresh) return;
|
|
1193
|
+
const { scope } = parseAnchorsExpression(expression);
|
|
1194
|
+
if (!scope) {
|
|
1195
|
+
setTimeout(() => el._x_anchorRefresh(), 400);
|
|
1196
|
+
return;
|
|
1197
|
+
}
|
|
1198
|
+
const containers = Array.from(document.querySelectorAll(scope)).filter(isVisible);
|
|
1199
|
+
const container = containers[0];
|
|
1200
|
+
if (!container) {
|
|
1201
|
+
el._x_anchorRefresh();
|
|
1202
|
+
return;
|
|
1203
|
+
}
|
|
1204
|
+
let done = false;
|
|
1205
|
+
const finish = () => {
|
|
1206
|
+
if (done) return;
|
|
1207
|
+
done = true;
|
|
1208
|
+
observer?.disconnect();
|
|
1209
|
+
clearTimeout(fallback);
|
|
1210
|
+
el._x_anchorRefresh();
|
|
1211
|
+
};
|
|
1212
|
+
let t = 0;
|
|
1213
|
+
const observer = new MutationObserver(() => {
|
|
1214
|
+
clearTimeout(t);
|
|
1215
|
+
t = setTimeout(finish, 50);
|
|
1143
1216
|
});
|
|
1144
|
-
|
|
1217
|
+
observer.observe(container, { childList: true, subtree: true });
|
|
1218
|
+
const fallback = setTimeout(finish, 800);
|
|
1219
|
+
};
|
|
1220
|
+
|
|
1221
|
+
requestAnimationFrame(() => {
|
|
1222
|
+
document.querySelectorAll('[x-anchors]').forEach(runWhenScopeReady);
|
|
1223
|
+
});
|
|
1145
1224
|
});
|
|
1146
1225
|
|
|
1147
1226
|
// Refresh anchors when hash changes (for active state updates)
|