lightview 2.0.6 → 2.0.8
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 +1 -1
- package/docs/about.html +1 -7
- package/docs/assets/js/examplify.js +6 -0
- package/docs/getting-started/index.html +1 -1
- package/docs/index.html +0 -4
- package/lightview-router.js +94 -299
- package/lightview-x.js +174 -504
- package/lightview.js +123 -107
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ Access the full documentaion at [lightview.dev](https://lightview.dev).
|
|
|
7
7
|
|
|
8
8
|
This NPM package is both the library and the website supporting the library. The website is built using Lightview. The core library files are in the root directory. The Website entry point is index.html and the restr of the site is under ./docs. The site is served by a Cloudflare pages deployment.
|
|
9
9
|
|
|
10
|
-
**Core**: ~
|
|
10
|
+
**Core**: ~7.5KB | **Additional Hypermedia Extensions and Component Library Support**: ~15KB | **Router**: ~3KB
|
|
11
11
|
|
|
12
12
|
Fast: This [gallery of components](https://lightview.dev/docs/components/) loads in about 1 second:
|
|
13
13
|
|
package/docs/about.html
CHANGED
|
@@ -108,12 +108,6 @@
|
|
|
108
108
|
it lean and modular so your apps stay fast.
|
|
109
109
|
</p>
|
|
110
110
|
</div>
|
|
111
|
-
<div class="feature-card">
|
|
112
|
-
<h3 class="feature-title">🔌 Zero Dependencies</h3>
|
|
113
|
-
<p class="feature-description">
|
|
114
|
-
No external dependencies. No supply chain worries. No version conflicts. Just works.
|
|
115
|
-
</p>
|
|
116
|
-
</div>
|
|
117
111
|
<div class="feature-card">
|
|
118
112
|
<h3 class="feature-title">🚀 No Build Step</h3>
|
|
119
113
|
<p class="feature-description">
|
|
@@ -131,7 +125,7 @@
|
|
|
131
125
|
<h3 class="feature-title">😊 Have Fun</h3>
|
|
132
126
|
<p class="feature-description">
|
|
133
127
|
Coding should spark joy. Simple API, clear and interactive docs, helpful errors. Built for humans
|
|
134
|
-
who like to smile.
|
|
128
|
+
who like to smile and LLMs that need structure (so humans don't cry about slop).
|
|
135
129
|
</p>
|
|
136
130
|
</div>
|
|
137
131
|
</div>
|
|
@@ -159,6 +159,11 @@ function examplify(target, options = {}) {
|
|
|
159
159
|
function getIframeContent(codeContent) {
|
|
160
160
|
const currentTheme = document.documentElement.getAttribute('data-theme');
|
|
161
161
|
const themeAttr = currentTheme ? ` data-theme="${currentTheme}"` : '';
|
|
162
|
+
|
|
163
|
+
const path = window.location.pathname;
|
|
164
|
+
const baseDir = path.substring(0, path.lastIndexOf('/') + 1);
|
|
165
|
+
const baseTag = useOrigin ? `<base href="${useOrigin}${baseDir}">` : '';
|
|
166
|
+
|
|
162
167
|
const autoResizeScript = autoResize ? `
|
|
163
168
|
<script>
|
|
164
169
|
const frameId = '${iframeId}';
|
|
@@ -193,6 +198,7 @@ function examplify(target, options = {}) {
|
|
|
193
198
|
return `<!DOCTYPE html>
|
|
194
199
|
<html${themeAttr}>
|
|
195
200
|
<head>
|
|
201
|
+
${baseTag}
|
|
196
202
|
<style>
|
|
197
203
|
/* Hide body until stylesheets are loaded to prevent FOUC */
|
|
198
204
|
body {
|
|
@@ -145,7 +145,7 @@ const { div, h1, p, style } = tags;
|
|
|
145
145
|
// These functions return Lightview elements (access raw DOM via .domEl)
|
|
146
146
|
const App = div({ class: 'hero' },
|
|
147
147
|
h1('Welcome to Lightview'),
|
|
148
|
-
p('Lightview is a
|
|
148
|
+
p('Lightview is a library for building modern web interfaces.')
|
|
149
149
|
);
|
|
150
150
|
|
|
151
151
|
// 2. The $ Function for Selections & Content
|
package/docs/index.html
CHANGED
|
@@ -19,10 +19,6 @@
|
|
|
19
19
|
<a href="./getting-started/" class="btn btn-primary btn-lg">Get Started</a>
|
|
20
20
|
</div>
|
|
21
21
|
<div class="hero-stats">
|
|
22
|
-
<div class="hero-stat">
|
|
23
|
-
<div class="hero-stat-value">Zero</div>
|
|
24
|
-
<div class="hero-stat-label">Dependencies</div>
|
|
25
|
-
</div>
|
|
26
22
|
<div class="hero-stat">
|
|
27
23
|
<div class="hero-stat-value">Zero</div>
|
|
28
24
|
<div class="hero-stat-label">Build Steps</div>
|
package/lightview-router.js
CHANGED
|
@@ -1,364 +1,159 @@
|
|
|
1
1
|
(() => {
|
|
2
|
+
/**
|
|
3
|
+
* LIGHTVIEW ROUTER
|
|
4
|
+
* A lightweight, pipeline-based History API router with middleware support.
|
|
5
|
+
*/
|
|
2
6
|
// ============= LIGHTVIEW ROUTER =============
|
|
3
7
|
// Pipeline-based History API router with middleware support
|
|
4
8
|
|
|
5
9
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* @param {string} shellPath - Relative path to the shell (e.g., '/index.html')
|
|
10
|
+
* Shell-based routing helper. If the 'content' element is missing,
|
|
11
|
+
* redirects to a shell path with the current path in the 'load' query parameter.
|
|
9
12
|
*/
|
|
10
13
|
const base = (shellPath) => {
|
|
11
|
-
if (typeof window === 'undefined') return;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if (inShell) return;
|
|
16
|
-
|
|
17
|
-
// Get current path relative to domain root
|
|
18
|
-
const currentPath = window.location.pathname;
|
|
19
|
-
|
|
20
|
-
// Build shell URL with load parameter
|
|
21
|
-
const shellUrl = new URL(shellPath, window.location.href);
|
|
22
|
-
shellUrl.searchParams.set('load', currentPath);
|
|
23
|
-
|
|
24
|
-
// Redirect to shell
|
|
25
|
-
window.location.href = shellUrl.toString();
|
|
14
|
+
if (typeof window === 'undefined' || document.getElementById('content')) return;
|
|
15
|
+
const url = new URL(shellPath, window.location.href);
|
|
16
|
+
url.searchParams.set('load', window.location.pathname);
|
|
17
|
+
window.location.href = url.toString();
|
|
26
18
|
};
|
|
27
19
|
|
|
28
20
|
/**
|
|
29
|
-
*
|
|
21
|
+
* Creates a new router instance.
|
|
22
|
+
* @param {Object} options - Router configuration.
|
|
30
23
|
*/
|
|
31
24
|
const router = (options = {}) => {
|
|
32
|
-
const {
|
|
33
|
-
base = '',
|
|
34
|
-
contentEl = null,
|
|
35
|
-
notFound = null,
|
|
36
|
-
debug = false,
|
|
37
|
-
onResponse = null,
|
|
38
|
-
onStart = null
|
|
39
|
-
} = options;
|
|
40
|
-
|
|
25
|
+
const { base = '', contentEl, notFound, debug, onResponse, onStart } = options;
|
|
41
26
|
const chains = [];
|
|
42
27
|
|
|
43
28
|
/**
|
|
44
|
-
*
|
|
29
|
+
* Normalizes paths by adding leading slash and removing trailing slash.
|
|
45
30
|
*/
|
|
46
|
-
const normalizePath = (
|
|
47
|
-
if (!
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
try {
|
|
52
|
-
const url = new URL(path, window.location.origin);
|
|
53
|
-
path = url.pathname;
|
|
54
|
-
} catch (e) {
|
|
55
|
-
// Invalid URL, treat as path
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (base && path.startsWith(base)) {
|
|
60
|
-
path = path.slice(base.length);
|
|
61
|
-
}
|
|
62
|
-
if (!path.startsWith('/')) {
|
|
63
|
-
path = '/' + path;
|
|
64
|
-
}
|
|
65
|
-
if (path.length > 1 && path.endsWith('/')) {
|
|
66
|
-
path = path.slice(0, -1);
|
|
67
|
-
}
|
|
68
|
-
return path;
|
|
31
|
+
const normalizePath = (p) => {
|
|
32
|
+
if (!p) return '/';
|
|
33
|
+
try { if (p.startsWith('http') || p.startsWith('//')) p = new URL(p, window.location.origin).pathname; } catch (e) { /* Invalid URL */ }
|
|
34
|
+
if (base && p.startsWith(base)) p = p.slice(base.length);
|
|
35
|
+
return p.replace(/\/+$/, '').replace(/^([^/])/, '/$1') || '/';
|
|
69
36
|
};
|
|
70
37
|
|
|
71
|
-
/**
|
|
72
|
-
* Convert a matcher (string/regexp) into a function
|
|
73
|
-
* Returns: (input) => params OR null (if no match)
|
|
74
|
-
*/
|
|
75
38
|
const createMatcher = (pattern) => {
|
|
76
|
-
if (pattern
|
|
77
|
-
return (ctx) => {
|
|
78
|
-
const path = typeof ctx === 'string' ? ctx : ctx.path;
|
|
79
|
-
const match = path.match(pattern);
|
|
80
|
-
return match ? { match, ...ctx } : null;
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (typeof pattern === 'string') {
|
|
85
|
-
return (ctx) => {
|
|
86
|
-
const path = typeof ctx === 'string' ? ctx : ctx.path;
|
|
87
|
-
|
|
88
|
-
// Specific check: if pattern is exactly '*', match everything
|
|
89
|
-
if (pattern === '*') return { path, wildcard: path, ...ctx };
|
|
90
|
-
|
|
91
|
-
// Exact match
|
|
92
|
-
if (pattern === path) return { path, ...ctx };
|
|
93
|
-
|
|
94
|
-
// Wildcard /api/*
|
|
95
|
-
if (pattern.includes('*')) {
|
|
96
|
-
const regexStr = '^' + pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/\\\*/g, '(.*)') + '$';
|
|
97
|
-
const regex = new RegExp(regexStr);
|
|
98
|
-
const match = path.match(regex);
|
|
99
|
-
if (match) {
|
|
100
|
-
return { path, wildcard: match[1], ...ctx };
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Named params /user/:id
|
|
105
|
-
if (pattern.includes(':')) {
|
|
106
|
-
const keys = [];
|
|
107
|
-
const regexStr = '^' + pattern.replace(/:([^/]+)/g, (_, key) => {
|
|
108
|
-
keys.push(key);
|
|
109
|
-
return '([^/]+)';
|
|
110
|
-
}) + '$';
|
|
111
|
-
const match = path.match(new RegExp(regexStr));
|
|
112
|
-
|
|
113
|
-
if (match) {
|
|
114
|
-
const params = {};
|
|
115
|
-
keys.forEach((key, i) => {
|
|
116
|
-
params[key] = match[i + 1];
|
|
117
|
-
});
|
|
118
|
-
return { path, params, ...ctx };
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return null;
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return pattern; // Already a function
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Convert a replacement string into a function
|
|
131
|
-
* Returns: (ctx) => updated context with new path
|
|
132
|
-
*/
|
|
133
|
-
const createReplacer = (pattern) => {
|
|
39
|
+
if (typeof pattern === 'function') return pattern;
|
|
134
40
|
return (ctx) => {
|
|
135
|
-
|
|
136
|
-
if (
|
|
137
|
-
|
|
41
|
+
const { path } = ctx;
|
|
42
|
+
if (pattern instanceof RegExp) {
|
|
43
|
+
const m = path.match(pattern);
|
|
44
|
+
return m ? { ...ctx, match: m } : null;
|
|
138
45
|
}
|
|
139
|
-
if (
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
46
|
+
if (pattern === '*' || pattern === path) return { ...ctx, wildcard: path };
|
|
47
|
+
|
|
48
|
+
const keys = [];
|
|
49
|
+
const regexStr = '^' + pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
50
|
+
.replace(/\\\*/g, '(.*)')
|
|
51
|
+
.replace(/:([^/]+)/g, (_, k) => (keys.push(k), '([^/]+)')) + '$';
|
|
52
|
+
const m = path.match(new RegExp(regexStr));
|
|
53
|
+
if (m) {
|
|
54
|
+
const params = {};
|
|
55
|
+
keys.forEach((k, i) => params[k] = m[i + 1]);
|
|
56
|
+
return { ...ctx, params, wildcard: m[1] };
|
|
143
57
|
}
|
|
144
|
-
|
|
145
|
-
return { ...ctx, path: newPath };
|
|
58
|
+
return null;
|
|
146
59
|
};
|
|
147
60
|
};
|
|
148
61
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
62
|
+
const createReplacer = (pat) => (ctx) => ({
|
|
63
|
+
...ctx,
|
|
64
|
+
path: pat.replace(/\*|:([^/]+)/g, (m, k) => (k ? ctx.params?.[k] : ctx.wildcard) || m)
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const fetchHandler = async (ctx) => {
|
|
155
68
|
try {
|
|
156
|
-
const res = await fetch(path);
|
|
69
|
+
const res = await fetch(ctx.path);
|
|
157
70
|
if (res.ok) return res;
|
|
158
|
-
} catch (e) {
|
|
159
|
-
if (debug) console.error('[Router] Fetch error:', e);
|
|
160
|
-
}
|
|
71
|
+
} catch (e) { if (debug) console.error('[Router] Fetch error:', e); }
|
|
161
72
|
return null;
|
|
162
73
|
};
|
|
163
74
|
|
|
164
75
|
/**
|
|
165
|
-
*
|
|
166
|
-
* usage: router.use(pattern, replacement, handler, ...)
|
|
167
|
-
*
|
|
168
|
-
* If contentEl is set and the chain ends with a string (path) or has no handlers,
|
|
169
|
-
* the router automatically appends a fetch handler.
|
|
76
|
+
* Adds a route or middleware to the router's pipeline.
|
|
170
77
|
*/
|
|
171
78
|
const use = (...args) => {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
const firstArg = args[0];
|
|
175
|
-
|
|
176
|
-
if (typeof firstArg !== 'function') {
|
|
177
|
-
chain.push(createMatcher(firstArg));
|
|
178
|
-
} else {
|
|
179
|
-
chain.push(firstArg);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
let hasCustomHandler = false;
|
|
183
|
-
for (let i = 1; i < args.length; i++) {
|
|
184
|
-
const arg = args[i];
|
|
185
|
-
if (typeof arg === 'string') {
|
|
186
|
-
chain.push(createReplacer(arg));
|
|
187
|
-
} else if (typeof arg === 'function') {
|
|
188
|
-
chain.push(arg);
|
|
189
|
-
hasCustomHandler = true;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// If contentEl is set and no custom handler provided, append default fetch
|
|
194
|
-
if (contentEl && !hasCustomHandler) {
|
|
195
|
-
chain.push(defaultFetchHandler);
|
|
196
|
-
}
|
|
197
|
-
|
|
79
|
+
const chain = args.map((arg, i) => (i === 0 && typeof arg !== 'function') ? createMatcher(arg) : (typeof arg === 'string' ? createReplacer(arg) : arg));
|
|
80
|
+
if (contentEl && !chain.some(f => f.name === 'fetchHandler' || args.some(a => typeof a === 'function'))) chain.push(fetchHandler);
|
|
198
81
|
chains.push(chain);
|
|
199
82
|
return routerInstance;
|
|
200
83
|
};
|
|
201
84
|
|
|
202
85
|
/**
|
|
203
|
-
*
|
|
86
|
+
* Processes a path through the registered chains.
|
|
204
87
|
*/
|
|
205
|
-
const route = async (
|
|
206
|
-
let
|
|
207
|
-
|
|
208
|
-
let context = { path: currentPath, contentEl };
|
|
209
|
-
|
|
210
|
-
if (debug) console.log(`[Router] Routing: ${currentPath}`);
|
|
88
|
+
const route = async (raw) => {
|
|
89
|
+
let ctx = { path: normalizePath(raw), contentEl };
|
|
90
|
+
if (debug) console.log(`[Router] Routing: ${ctx.path}`);
|
|
211
91
|
|
|
212
92
|
for (const chain of chains) {
|
|
213
|
-
let
|
|
214
|
-
let chainFailed = false;
|
|
215
|
-
|
|
93
|
+
let res = ctx, failed = false;
|
|
216
94
|
for (const fn of chain) {
|
|
217
95
|
try {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
if (
|
|
221
|
-
|
|
222
|
-
chainFailed = true;
|
|
223
|
-
break;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
chainResult = result;
|
|
227
|
-
} catch (err) {
|
|
228
|
-
console.error('[Router] Error in route chain:', err);
|
|
229
|
-
chainFailed = true;
|
|
230
|
-
break;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
if (!chainFailed) {
|
|
235
|
-
// Fallthrough with updated context
|
|
236
|
-
if (typeof chainResult === 'string') {
|
|
237
|
-
context = { path: chainResult, contentEl };
|
|
238
|
-
if (debug) console.log(`[Router] Path updated to: ${chainResult}`);
|
|
239
|
-
} else if (chainResult && chainResult.path) {
|
|
240
|
-
context = chainResult;
|
|
241
|
-
// Ensure contentEl is preserved if not in result
|
|
242
|
-
if (!context.contentEl) context.contentEl = contentEl;
|
|
243
|
-
}
|
|
96
|
+
res = await fn(res);
|
|
97
|
+
if (res instanceof Response) return res;
|
|
98
|
+
if (!res) { failed = true; break; }
|
|
99
|
+
} catch (e) { console.error('[Router] Chain error:', e); failed = true; break; }
|
|
244
100
|
}
|
|
101
|
+
if (!failed) ctx = typeof res === 'string' ? { ...ctx, path: res } : { ...ctx, ...res };
|
|
245
102
|
}
|
|
246
|
-
|
|
247
|
-
if (notFound) return notFound(context);
|
|
248
|
-
return null;
|
|
103
|
+
return notFound ? notFound(ctx) : null;
|
|
249
104
|
};
|
|
250
105
|
|
|
251
106
|
const handleRequest = async (path) => {
|
|
252
107
|
if (onStart) onStart(path);
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
if (
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
const html = await response.text();
|
|
264
|
-
contentEl.innerHTML = html;
|
|
265
|
-
|
|
266
|
-
// Re-execute scripts in the loaded content
|
|
267
|
-
const scripts = contentEl.querySelectorAll('script');
|
|
268
|
-
scripts.forEach(script => {
|
|
269
|
-
const newScript = document.createElement('script');
|
|
270
|
-
if (script.type) newScript.type = script.type;
|
|
271
|
-
if (script.src) {
|
|
272
|
-
newScript.src = script.src;
|
|
273
|
-
} else {
|
|
274
|
-
newScript.textContent = script.textContent;
|
|
275
|
-
}
|
|
276
|
-
script.parentNode.replaceChild(newScript, script);
|
|
108
|
+
const res = await route(path);
|
|
109
|
+
if (!res) return console.warn(`[Router] No route: ${path}`);
|
|
110
|
+
|
|
111
|
+
if (res.ok && contentEl) {
|
|
112
|
+
contentEl.innerHTML = await res.text();
|
|
113
|
+
contentEl.querySelectorAll('script').forEach(s => {
|
|
114
|
+
const n = document.createElement('script');
|
|
115
|
+
[...s.attributes].forEach(a => n.setAttribute(a.name, a.value));
|
|
116
|
+
n.textContent = s.textContent;
|
|
117
|
+
s.replaceWith(n);
|
|
277
118
|
});
|
|
278
119
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
if (onResponse) {
|
|
282
|
-
await onResponse(response, path);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
return response;
|
|
120
|
+
if (onResponse) await onResponse(res, path);
|
|
121
|
+
return res;
|
|
286
122
|
};
|
|
287
123
|
|
|
124
|
+
/**
|
|
125
|
+
* Navigates to a new path and updates the browser history.
|
|
126
|
+
*/
|
|
288
127
|
const navigate = (path) => {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
let dest = response?.url;
|
|
293
|
-
if (dest && (dest.startsWith('http') || dest.startsWith('//'))) {
|
|
294
|
-
try {
|
|
295
|
-
const u = new URL(dest, window.location.origin);
|
|
296
|
-
dest = u.pathname + u.search + u.hash;
|
|
297
|
-
} catch (e) { }
|
|
298
|
-
}
|
|
299
|
-
// Fallback to intent if response has no URL
|
|
300
|
-
if (!dest) dest = fullPath;
|
|
128
|
+
const p = normalizePath(path);
|
|
129
|
+
return handleRequest(base + p).then(r => {
|
|
130
|
+
let dest = r?.url ? new URL(r.url, window.location.origin).pathname : base + p;
|
|
301
131
|
window.history.pushState({ path: dest }, '', dest);
|
|
302
|
-
}).catch(
|
|
303
|
-
console.error('[Router] Error handling request:', err);
|
|
304
|
-
})
|
|
132
|
+
}).catch(e => console.error('[Router] Nav error:', e));
|
|
305
133
|
};
|
|
306
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Starts the router by handling the initial path and setting up event listeners.
|
|
137
|
+
*/
|
|
307
138
|
const start = async () => {
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
handleRequest(path);
|
|
314
|
-
});
|
|
315
|
-
|
|
316
|
-
document.addEventListener('click', (e) => {
|
|
317
|
-
const link = e.target.closest('a[href]');
|
|
318
|
-
if (!link) return;
|
|
319
|
-
const href = link.getAttribute('href');
|
|
320
|
-
if (
|
|
321
|
-
!href || href.startsWith('http') || href.startsWith('//') ||
|
|
322
|
-
href.startsWith('#') || href.startsWith('mailto:') ||
|
|
323
|
-
link.target === '_blank'
|
|
324
|
-
) return;
|
|
325
|
-
|
|
139
|
+
const load = new URLSearchParams(window.location.search).get('load');
|
|
140
|
+
window.onpopstate = (e) => handleRequest(e.state?.path || normalizePath(window.location.pathname));
|
|
141
|
+
document.onclick = (e) => {
|
|
142
|
+
const a = e.target.closest('a[href]');
|
|
143
|
+
if (!a || a.target === '_blank' || /^(http|#|mailto|tel)/.test(a.getAttribute('href'))) return;
|
|
326
144
|
e.preventDefault();
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
if (loadPath) {
|
|
333
|
-
window.history.replaceState({ path: loadPath }, '', loadPath);
|
|
334
|
-
handleRequest(loadPath);
|
|
335
|
-
} else {
|
|
336
|
-
const initialPath = normalizePath(window.location.pathname);
|
|
337
|
-
window.history.replaceState({ path: initialPath }, '', base + initialPath);
|
|
338
|
-
handleRequest(initialPath);
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
return routerInstance;
|
|
342
|
-
};
|
|
343
|
-
|
|
344
|
-
const routerInstance = {
|
|
345
|
-
use,
|
|
346
|
-
navigate,
|
|
347
|
-
start
|
|
145
|
+
navigate(normalizePath(new URL(a.href, document.baseURI).pathname));
|
|
146
|
+
};
|
|
147
|
+
const init = load || normalizePath(window.location.pathname);
|
|
148
|
+
window.history.replaceState({ path: init }, '', base + init);
|
|
149
|
+
return handleRequest(init).then(() => routerInstance);
|
|
348
150
|
};
|
|
349
151
|
|
|
152
|
+
const routerInstance = { use, navigate, start };
|
|
350
153
|
return routerInstance;
|
|
351
154
|
};
|
|
352
155
|
|
|
353
|
-
const LightviewRouter = {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
};
|
|
357
|
-
|
|
358
|
-
if (typeof module !== 'undefined' && module.exports) {
|
|
359
|
-
module.exports = LightviewRouter;
|
|
360
|
-
}
|
|
361
|
-
if (typeof window !== 'undefined') {
|
|
362
|
-
window.LightviewRouter = LightviewRouter;
|
|
363
|
-
}
|
|
156
|
+
const LightviewRouter = { base, router };
|
|
157
|
+
if (typeof module !== 'undefined' && module.exports) module.exports = LightviewRouter;
|
|
158
|
+
else if (typeof window !== 'undefined') window.LightviewRouter = LightviewRouter;
|
|
364
159
|
})();
|