@lmjs/core 1.0.7 → 2.0.0
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/build/bundle.js +264 -0
- package/build/plugins-registry.js +216 -0
- package/dist/lumenjs-core-with-plugins.js +59258 -0
- package/dist/lumenjs-core.js +50 -0
- package/dist/lumenjs-plugins.css +2822 -0
- package/package.json +59 -28
- package/src/_re.js +2307 -0
- package/src/dom-shim.js +473 -0
- package/src/index-bootstrap.js +47 -0
- package/src/lstnrs.js +1391 -0
- package/src/walk.js +749 -0
- package/src/workers/css.js +1 -0
- package/src/workers/cssRaw.js +1173 -0
- package/src/workers/esp.js +1 -0
- package/src/workers/espRaw.js +78 -0
- package/src/workers/up.js +1 -0
- package/src/workers/upRaw.js +491 -0
- package/src/workers/work.js +1 -0
- package/src/workers/workRaw.js +1097 -0
- package/src/ws.js +1162 -0
- package/vendor/astring.js +3 -0
- package/vendor/bootstrap2-less-stubs/mixins.less +16 -0
- package/vendor/bootstrap2-less-stubs/variables.less +13 -0
- package/vendor/md5.js +1 -0
- package/vendor/reconnecting-websocket.js +4118 -0
- package/vendor/webworker-helper.js +1 -0
- package/LICENSE +0 -201
- package/README.md +0 -3
- package/index.js +0 -14
package/src/dom-shim.js
ADDED
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
// dom-shim.js — a minimal jQuery-compatible layer.
|
|
2
|
+
//
|
|
3
|
+
// Scope, deliberately narrow: covers exactly the surface LumenJS's own core
|
|
4
|
+
// (_re.js, walk.js, ws.js, lstnrs.js) uses internally, plus the documented
|
|
5
|
+
// app-facing API (el.css/.data/.val/.attr, el[0], .trigger) from
|
|
6
|
+
// lumenjs-spec.md §6.3/§10. Scoped by grepping actual usage across the core
|
|
7
|
+
// files, not guessed.
|
|
8
|
+
//
|
|
9
|
+
// This is NOT a jQuery replacement for everything — optional plugins
|
|
10
|
+
// (Select2, Flickity, the colorpicker, etc.) stay on real jQuery when a page
|
|
11
|
+
// opts into them, since they're third-party code written against jQuery's
|
|
12
|
+
// actual $.fn plugin architecture. This shim only has to satisfy the core
|
|
13
|
+
// runtime, which is what makes it small.
|
|
14
|
+
(function (global) {
|
|
15
|
+
function toArray(x) {
|
|
16
|
+
if (x == null) return [];
|
|
17
|
+
if (typeof NodeList !== 'undefined' && x instanceof NodeList) return Array.prototype.slice.call(x);
|
|
18
|
+
if (typeof HTMLCollection !== 'undefined' && x instanceof HTMLCollection) return Array.prototype.slice.call(x);
|
|
19
|
+
if (Array.isArray(x)) return x;
|
|
20
|
+
if (x instanceof $) return Array.prototype.slice.call(x);
|
|
21
|
+
return [x];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function $(selector, context) {
|
|
25
|
+
if (!(this instanceof $)) return new $(selector, context);
|
|
26
|
+
|
|
27
|
+
var els = [];
|
|
28
|
+
var sel = undefined;
|
|
29
|
+
if (!selector) {
|
|
30
|
+
els = [];
|
|
31
|
+
} else if (typeof selector === 'string') {
|
|
32
|
+
var trimmed = selector.trim();
|
|
33
|
+
if (trimmed[0] === '<') {
|
|
34
|
+
var tpl = document.createElement('template');
|
|
35
|
+
tpl.innerHTML = trimmed;
|
|
36
|
+
els = toArray(tpl.content.childNodes).filter(function (n) { return n.nodeType === 1; });
|
|
37
|
+
} else {
|
|
38
|
+
sel = selector;
|
|
39
|
+
var root = context ? (context instanceof $ ? context[0] : context) : document;
|
|
40
|
+
els = root ? toArray(root.querySelectorAll(selector)) : [];
|
|
41
|
+
}
|
|
42
|
+
} else {
|
|
43
|
+
els = toArray(selector);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
for (var i = 0; i < els.length; i++) this[i] = els[i];
|
|
47
|
+
this.length = els.length;
|
|
48
|
+
this.selector = sel;
|
|
49
|
+
return this;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
$.fn = $.prototype;
|
|
53
|
+
$.fn.jquery = 'lumenjs-shim';
|
|
54
|
+
|
|
55
|
+
$.fn.extend = function (methods) {
|
|
56
|
+
for (var k in methods) if (Object.prototype.hasOwnProperty.call(methods, k)) $.fn[k] = methods[k];
|
|
57
|
+
return $;
|
|
58
|
+
};
|
|
59
|
+
$.extend = function (target) {
|
|
60
|
+
for (var i = 1; i < arguments.length; i++) {
|
|
61
|
+
var src = arguments[i];
|
|
62
|
+
for (var k in src) if (Object.prototype.hasOwnProperty.call(src, k)) target[k] = src[k];
|
|
63
|
+
}
|
|
64
|
+
return target;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// jQuery's own Event wrapper — used internally by the vendored WebWorker
|
|
68
|
+
// helper (`new $.Event(type)`, then it assigns custom properties onto
|
|
69
|
+
// the result). A plain native Event supports arbitrary property
|
|
70
|
+
// assignment already, so this just needs to exist as a constructor.
|
|
71
|
+
$.Event = function (type, props) {
|
|
72
|
+
var e = typeof type === 'string' ? new Event(type, { bubbles: true, cancelable: true }) : type;
|
|
73
|
+
if (props) for (var k in props) e[k] = props[k];
|
|
74
|
+
return e;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
$.proxy = function (fn, context) { return fn.bind(context); };
|
|
78
|
+
$.trim = function (s) { return (s == null ? '' : String(s)).trim(); };
|
|
79
|
+
$.inArray = function (val, arr) { return Array.prototype.indexOf.call(arr, val); };
|
|
80
|
+
$.each = function (arr, fn) {
|
|
81
|
+
if (Array.isArray(arr) || arr instanceof $) {
|
|
82
|
+
for (var i = 0; i < arr.length; i++) if (fn.call(arr[i], i, arr[i]) === false) break;
|
|
83
|
+
} else {
|
|
84
|
+
for (var k in arr) if (fn.call(arr[k], k, arr[k]) === false) break;
|
|
85
|
+
}
|
|
86
|
+
return arr;
|
|
87
|
+
};
|
|
88
|
+
// Minimal fetch-based $.ajax — covers ws.js's one call site (a plain
|
|
89
|
+
// GET/POST with success/error callbacks), not jQuery's full option set.
|
|
90
|
+
// Fires the global ajaxStart/ajaxStop events real jQuery provides for a
|
|
91
|
+
// loading-indicator pattern (`$(document).ajaxStart(...)`) — used at
|
|
92
|
+
// _re.js's top level.
|
|
93
|
+
var _ajaxActive = 0;
|
|
94
|
+
$.ajax = function (opts) {
|
|
95
|
+
opts = opts || {};
|
|
96
|
+
var method = (opts.method || opts.type || 'GET').toUpperCase();
|
|
97
|
+
var init = { method: method, headers: opts.headers || {} };
|
|
98
|
+
if (opts.data != null && method !== 'GET') {
|
|
99
|
+
init.body = typeof opts.data === 'string' ? opts.data : JSON.stringify(opts.data);
|
|
100
|
+
}
|
|
101
|
+
if (_ajaxActive === 0) $(document).trigger('ajaxStart');
|
|
102
|
+
_ajaxActive++;
|
|
103
|
+
$(document).trigger('ajaxSend');
|
|
104
|
+
return fetch(opts.url, init)
|
|
105
|
+
.then(function (res) {
|
|
106
|
+
var ct = res.headers.get('content-type') || '';
|
|
107
|
+
return ct.indexOf('json') > -1 ? res.json() : res.text();
|
|
108
|
+
})
|
|
109
|
+
.then(function (data) {
|
|
110
|
+
opts.success && opts.success(data);
|
|
111
|
+
$(document).trigger('ajaxSuccess');
|
|
112
|
+
return data;
|
|
113
|
+
})
|
|
114
|
+
.catch(function (err) {
|
|
115
|
+
opts.error && opts.error(err);
|
|
116
|
+
$(document).trigger('ajaxError');
|
|
117
|
+
throw err;
|
|
118
|
+
})
|
|
119
|
+
.finally(function () {
|
|
120
|
+
_ajaxActive--;
|
|
121
|
+
$(document).trigger('ajaxComplete');
|
|
122
|
+
if (_ajaxActive === 0) $(document).trigger('ajaxStop');
|
|
123
|
+
});
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
$.fn.each = function (fn) {
|
|
127
|
+
for (var i = 0; i < this.length; i++) if (fn.call(this[i], i, this[i]) === false) break;
|
|
128
|
+
return this;
|
|
129
|
+
};
|
|
130
|
+
$.fn.get = function (i) { return i === undefined ? toArray(this) : this[i]; };
|
|
131
|
+
|
|
132
|
+
$.fn.attr = function (name, value) {
|
|
133
|
+
if (value === undefined) return this[0] ? this[0].getAttribute(name) : undefined;
|
|
134
|
+
return this.each(function () { this.setAttribute(name, value); });
|
|
135
|
+
};
|
|
136
|
+
$.fn.removeAttr = function (name) {
|
|
137
|
+
return this.each(function () { this.removeAttribute(name); });
|
|
138
|
+
};
|
|
139
|
+
// Not a real jQuery method — LumenJS's own $.fn.extend addition
|
|
140
|
+
// (lstnrs.js), kept here since the core relies on it directly.
|
|
141
|
+
//
|
|
142
|
+
// 2026-09-16, real bug found and fixed: native `hasAttribute` can never
|
|
143
|
+
// see a `@`-prefixed name (`@click`, `@sort`, ...) — vendor/
|
|
144
|
+
// reconnecting-websocket.js monkey-patches HTMLElement.prototype.
|
|
145
|
+
// setAttribute/getAttribute/removeAttribute so any `@`-prefixed write
|
|
146
|
+
// is redirected to `el.events[name]` instead of the real attribute
|
|
147
|
+
// store (deliberate, real V2 framework behavior, not something this
|
|
148
|
+
// shim invented — see that file). Native `hasAttribute` was never part
|
|
149
|
+
// of that patch, so it always returned false for these, and lstnrs.js's
|
|
150
|
+
// processEv() bails immediately on `!el.hasAttr("@" + n)` — meaning
|
|
151
|
+
// every `@`-event handler's before/after-guard and payload lookup was
|
|
152
|
+
// unreachable. `getAttribute` *is* patch-aware, so route through that
|
|
153
|
+
// instead — correct for both real attributes (native getAttribute
|
|
154
|
+
// returns null when absent) and `@`-prefixed ones.
|
|
155
|
+
$.fn.hasAttr = function (name) {
|
|
156
|
+
return !!(this[0] && this[0].getAttribute(name) != null);
|
|
157
|
+
};
|
|
158
|
+
$.fn.data = function (key, value) {
|
|
159
|
+
if (value === undefined) {
|
|
160
|
+
if (!this[0]) return undefined;
|
|
161
|
+
if (key === undefined) return Object.assign({}, this[0].dataset);
|
|
162
|
+
var v = this[0].dataset[key];
|
|
163
|
+
try { return JSON.parse(v); } catch (e) { return v; }
|
|
164
|
+
}
|
|
165
|
+
return this.each(function () { this.dataset[key] = typeof value === 'string' ? value : JSON.stringify(value); });
|
|
166
|
+
};
|
|
167
|
+
$.fn.val = function (value) {
|
|
168
|
+
if (value === undefined) return this[0] ? this[0].value : undefined;
|
|
169
|
+
return this.each(function () { this.value = value; });
|
|
170
|
+
};
|
|
171
|
+
$.fn.html = function (value) {
|
|
172
|
+
if (value === undefined) return this[0] ? this[0].innerHTML : undefined;
|
|
173
|
+
// 2026-09-14, real bug found alongside .append()'s: _re.js calls
|
|
174
|
+
// `.html(_rel._RealDOM)` (an array of real Nodes, e.g. for a
|
|
175
|
+
// rendered layout/view) and `.html(_re._RealDOM)` for the view
|
|
176
|
+
// itself — a bare string assignment (`this.innerHTML = value`)
|
|
177
|
+
// coerces an array via toString(), producing garbage text like
|
|
178
|
+
// "[object HTMLDivElement]" instead of actually inserting the
|
|
179
|
+
// rendered content. Route anything non-string through the same
|
|
180
|
+
// append() normalization instead.
|
|
181
|
+
if (typeof value !== 'string') {
|
|
182
|
+
var nodes = _normalizeAppendable([value]);
|
|
183
|
+
return this.each(function () {
|
|
184
|
+
this.innerHTML = '';
|
|
185
|
+
var self = this;
|
|
186
|
+
nodes.forEach(function (n) { self.appendChild(n); });
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
return this.each(function () { this.innerHTML = value; });
|
|
190
|
+
};
|
|
191
|
+
$.fn.css = function (name, value) {
|
|
192
|
+
if (typeof name === 'object') {
|
|
193
|
+
return this.each(function () {
|
|
194
|
+
var el = this;
|
|
195
|
+
for (var k in name) el.style[k] = name[k];
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
if (value === undefined) return this[0] ? getComputedStyle(this[0])[name] : undefined;
|
|
199
|
+
return this.each(function () { this.style[name] = value; });
|
|
200
|
+
};
|
|
201
|
+
$.fn.addClass = function (cls) {
|
|
202
|
+
var list = cls.split(/\s+/).filter(Boolean);
|
|
203
|
+
return this.each(function () { this.classList.add.apply(this.classList, list); });
|
|
204
|
+
};
|
|
205
|
+
$.fn.removeClass = function (cls) {
|
|
206
|
+
var list = cls.split(/\s+/).filter(Boolean);
|
|
207
|
+
return this.each(function () { this.classList.remove.apply(this.classList, list); });
|
|
208
|
+
};
|
|
209
|
+
$.fn.hasClass = function (cls) { return !!(this[0] && this[0].classList.contains(cls)); };
|
|
210
|
+
$.fn.toggleClass = function (cls, force) {
|
|
211
|
+
var list = cls.split(/\s+/).filter(Boolean);
|
|
212
|
+
return this.each(function () {
|
|
213
|
+
var el = this;
|
|
214
|
+
list.forEach(function (c) { el.classList.toggle(c, force); });
|
|
215
|
+
});
|
|
216
|
+
};
|
|
217
|
+
$.fn.remove = function () {
|
|
218
|
+
return this.each(function () { this.parentNode && this.parentNode.removeChild(this); });
|
|
219
|
+
};
|
|
220
|
+
// Flattens real jQuery's .append()/.prepend() calling convention — any
|
|
221
|
+
// number of arguments, each a string, a real Node, a $-wrapped
|
|
222
|
+
// element, or an array of any of those — into a flat list of real
|
|
223
|
+
// Nodes. Anything else (a plain object, a number, etc.) is silently
|
|
224
|
+
// dropped, matching real jQuery's tolerance for garbage input.
|
|
225
|
+
//
|
|
226
|
+
// 2026-09-14, real bug found testing a real project against a real dev
|
|
227
|
+
// server: this file's old `.append(content)` only ever looked at its
|
|
228
|
+
// FIRST argument and assumed it was a string, a Node, or $-wrapped —
|
|
229
|
+
// `_re.js`'s `el.append(..._re._RealDOM)` (spreading a Node array) hit
|
|
230
|
+
// this whenever _RealDOM had zero or more-than-one entries, and a
|
|
231
|
+
// pre-existing, vestigial `$("body").append({beajs:true, ...})` call
|
|
232
|
+
// in vendor/reconnecting-websocket.js (a plain object, not a Node —
|
|
233
|
+
// dead/legacy code, evidenced by the commented-out line right above
|
|
234
|
+
// it) crashed outright instead of being silently ignored the way real
|
|
235
|
+
// jQuery would have.
|
|
236
|
+
function _normalizeAppendable(args) {
|
|
237
|
+
var out = [];
|
|
238
|
+
function add(item) {
|
|
239
|
+
if (item == null) return;
|
|
240
|
+
if (Array.isArray(item)) { item.forEach(add); return; }
|
|
241
|
+
if (item instanceof $) { for (var i = 0; i < item.length; i++) add(item[i]); return; }
|
|
242
|
+
if (typeof item === 'string') {
|
|
243
|
+
var tpl = document.createElement('template');
|
|
244
|
+
tpl.innerHTML = item;
|
|
245
|
+
while (tpl.content.firstChild) out.push(tpl.content.removeChild(tpl.content.firstChild));
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
if (item instanceof Node) { out.push(item); return; }
|
|
249
|
+
}
|
|
250
|
+
for (var i = 0; i < args.length; i++) add(args[i]);
|
|
251
|
+
return out;
|
|
252
|
+
}
|
|
253
|
+
$.fn.append = function () {
|
|
254
|
+
if (arguments.length === 1 && typeof arguments[0] === 'string') {
|
|
255
|
+
var html = arguments[0];
|
|
256
|
+
return this.each(function () { this.insertAdjacentHTML('beforeend', html); });
|
|
257
|
+
}
|
|
258
|
+
var nodes = _normalizeAppendable(arguments);
|
|
259
|
+
return this.each(function () {
|
|
260
|
+
var self = this;
|
|
261
|
+
nodes.forEach(function (n) { self.appendChild(n); });
|
|
262
|
+
});
|
|
263
|
+
};
|
|
264
|
+
$.fn.prepend = function () {
|
|
265
|
+
if (arguments.length === 1 && typeof arguments[0] === 'string') {
|
|
266
|
+
var html = arguments[0];
|
|
267
|
+
return this.each(function () { this.insertAdjacentHTML('afterbegin', html); });
|
|
268
|
+
}
|
|
269
|
+
var nodes = _normalizeAppendable(arguments);
|
|
270
|
+
return this.each(function () {
|
|
271
|
+
var self = this;
|
|
272
|
+
var ref = self.firstChild;
|
|
273
|
+
nodes.forEach(function (n) { self.insertBefore(n, ref); });
|
|
274
|
+
});
|
|
275
|
+
};
|
|
276
|
+
$.fn.after = function (content) {
|
|
277
|
+
return this.each(function () {
|
|
278
|
+
if (typeof content === 'string') this.insertAdjacentHTML('afterend', content);
|
|
279
|
+
else this.parentNode.insertBefore(content instanceof $ ? content[0] : content, this.nextSibling);
|
|
280
|
+
});
|
|
281
|
+
};
|
|
282
|
+
$.fn.appendTo = function (target) { $(target).append(this); return this; };
|
|
283
|
+
// Real layout metrics (jsdom has no rendering engine, so these will
|
|
284
|
+
// read 0 here — harmless for anything that isn't actually testing
|
|
285
|
+
// pixel measurements, which nothing in this codebase's core does).
|
|
286
|
+
$.fn.width = function () { return this[0] ? this[0].offsetWidth : 0; };
|
|
287
|
+
$.fn.height = function () { return this[0] ? this[0].offsetHeight : 0; };
|
|
288
|
+
$.fn.outerWidth = function (includeMargin) {
|
|
289
|
+
if (!this[0]) return 0;
|
|
290
|
+
var w = this[0].offsetWidth;
|
|
291
|
+
if (includeMargin) {
|
|
292
|
+
var s = getComputedStyle(this[0]);
|
|
293
|
+
w += parseFloat(s.marginLeft || 0) + parseFloat(s.marginRight || 0);
|
|
294
|
+
}
|
|
295
|
+
return w;
|
|
296
|
+
};
|
|
297
|
+
$.fn.outerHeight = function (includeMargin) {
|
|
298
|
+
if (!this[0]) return 0;
|
|
299
|
+
var h = this[0].offsetHeight;
|
|
300
|
+
if (includeMargin) {
|
|
301
|
+
var s = getComputedStyle(this[0]);
|
|
302
|
+
h += parseFloat(s.marginTop || 0) + parseFloat(s.marginBottom || 0);
|
|
303
|
+
}
|
|
304
|
+
return h;
|
|
305
|
+
};
|
|
306
|
+
$.fn.parent = function () { return $(this[0] ? this[0].parentElement : null); };
|
|
307
|
+
$.fn.next = function () { return $(this[0] ? this[0].nextElementSibling : null); };
|
|
308
|
+
$.fn.closest = function (sel) { return $(this[0] ? this[0].closest(sel) : null); };
|
|
309
|
+
$.fn.ready = function (fn) {
|
|
310
|
+
if (document.readyState !== 'loading') fn($);
|
|
311
|
+
else document.addEventListener('DOMContentLoaded', function () { fn($); });
|
|
312
|
+
return this;
|
|
313
|
+
};
|
|
314
|
+
// jQuery's full family of global ajax events — all just named events on
|
|
315
|
+
// document under the hood, registered/fired the same way.
|
|
316
|
+
['ajaxStart', 'ajaxStop', 'ajaxSend', 'ajaxSuccess', 'ajaxError', 'ajaxComplete'].forEach(function (name) {
|
|
317
|
+
$.fn[name] = function (fn) { return this.on(name, fn); };
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
// ---- Events ----
|
|
321
|
+
// A handful of event names need translating for delegation to actually
|
|
322
|
+
// work — left as-is, these would silently never fire, exactly the class
|
|
323
|
+
// of bug point 6 exists to stop happening. `touch` isn't a real DOM
|
|
324
|
+
// event name at all. `focus`/`blur` are real, but don't bubble, so
|
|
325
|
+
// delegating them from `document`/`body` (lstnrs.js's whole pattern)
|
|
326
|
+
// requires their bubbling equivalents instead — this is what real
|
|
327
|
+
// jQuery does internally for the same reason.
|
|
328
|
+
var EVENT_NAME_MAP = { touch: 'touchstart', focus: 'focusin', blur: 'focusout' };
|
|
329
|
+
|
|
330
|
+
// jQuery lets you `.on()`/`.trigger()` an arbitrary plain object, not
|
|
331
|
+
// just DOM nodes — real jQuery keeps its own event table for that case.
|
|
332
|
+
// Needed here: the vendored WebWorker helper wraps itself (`$(this)`)
|
|
333
|
+
// and uses `.on()`/`.trigger()` purely as a pub/sub bus, never touching
|
|
334
|
+
// the DOM. Bridge non-Node targets to a real EventTarget instead of
|
|
335
|
+
// assuming addEventListener always exists.
|
|
336
|
+
var _eventBuses = typeof WeakMap !== 'undefined' ? new WeakMap() : null;
|
|
337
|
+
function _isNode(x) {
|
|
338
|
+
return x === window || x === document || (typeof Node !== 'undefined' && x instanceof Node);
|
|
339
|
+
}
|
|
340
|
+
// 2026-09-14, real bug found testing a real project end-to-end: the
|
|
341
|
+
// same WebWorker helper ALSO does `$(this.getNativeWorker()).on(
|
|
342
|
+
// "message", ...)` to receive real messages posted FROM the actual
|
|
343
|
+
// worker thread. A native `Worker` isn't a DOM Node, so `_isNode` was
|
|
344
|
+
// false and this got routed through the fake WeakMap-bridged
|
|
345
|
+
// EventTarget below instead of the real Worker instance's own native
|
|
346
|
+
// event system — meaning real `message` events the browser itself
|
|
347
|
+
// dispatches on the Worker never reached it, and the worker's
|
|
348
|
+
// load/start handshake (which is entirely message-driven) silently
|
|
349
|
+
// stalled forever. Any object that's already a genuine EventTarget
|
|
350
|
+
// (Worker, WebSocket, XMLHttpRequest, ...) should be used directly,
|
|
351
|
+
// not bridged.
|
|
352
|
+
function _isRealEventTarget(x) {
|
|
353
|
+
return x != null && typeof x.addEventListener === 'function' && typeof x.dispatchEvent === 'function';
|
|
354
|
+
}
|
|
355
|
+
function _eventTargetFor(x) {
|
|
356
|
+
if (_isNode(x) || _isRealEventTarget(x)) return x;
|
|
357
|
+
if (!_eventBuses.has(x)) _eventBuses.set(x, new EventTarget());
|
|
358
|
+
return _eventBuses.get(x);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// 2026-09-16, real bug found and fixed: lstnrs.js delegates every
|
|
362
|
+
// @click/@sort/@drag/... binding via `$("body").on(evt, "[\\@name]",
|
|
363
|
+
// handler)` — 34 call sites, all this exact single-attribute-presence
|
|
364
|
+
// shape. Native `Element.prototype.closest()` (used below for every
|
|
365
|
+
// other selector) matches against the browser's real internal
|
|
366
|
+
// attribute storage, which can never see the `@`-prefixed redirect
|
|
367
|
+
// described in $.fn.hasAttr's comment above — so a delegated `@`-event
|
|
368
|
+
// listener could never fire at all, in any environment, real browser
|
|
369
|
+
// included (confirmed against an actual `lm build` output driven by
|
|
370
|
+
// real Chrome, not just jsdom). Detect that exact selector shape and
|
|
371
|
+
// walk up manually using `getAttribute` (patch-aware) instead of
|
|
372
|
+
// native closest(); every other selector (e.g. lstnrs.js's own
|
|
373
|
+
// "[up] [browse]") is untouched, still native.
|
|
374
|
+
var AT_ATTR_SELECTOR = /^\[\\@([\w-]+)\]$/;
|
|
375
|
+
$.fn.on = function (events, selector, handler) {
|
|
376
|
+
if (typeof selector === 'function') { handler = selector; selector = null; }
|
|
377
|
+
var evts = events.split(/\s+/).filter(Boolean);
|
|
378
|
+
var atMatch = selector && AT_ATTR_SELECTOR.exec(selector);
|
|
379
|
+
var atAttr = atMatch ? '@' + atMatch[1] : null;
|
|
380
|
+
return this.each(function () {
|
|
381
|
+
var node = this;
|
|
382
|
+
var bus = _eventTargetFor(node);
|
|
383
|
+
evts.forEach(function (evt) {
|
|
384
|
+
var real = EVENT_NAME_MAP[evt] || evt;
|
|
385
|
+
bus.addEventListener(real, function (e) {
|
|
386
|
+
if (atAttr) {
|
|
387
|
+
var el = e.target;
|
|
388
|
+
var match = null;
|
|
389
|
+
while (el && el.nodeType === 1) {
|
|
390
|
+
if (el.getAttribute(atAttr) != null) { match = el; break; }
|
|
391
|
+
el = el.parentElement;
|
|
392
|
+
}
|
|
393
|
+
if (match && node.contains(match)) handler.call(match, e);
|
|
394
|
+
} else if (selector && _isNode(node)) {
|
|
395
|
+
var match2 = e.target.closest(selector);
|
|
396
|
+
if (match2 && node.contains(match2)) handler.call(match2, e);
|
|
397
|
+
} else {
|
|
398
|
+
handler.call(node, e);
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
});
|
|
402
|
+
});
|
|
403
|
+
};
|
|
404
|
+
// No .live() — 2026-09-13: confirmed every call site in lstnrs.js was
|
|
405
|
+
// internal (never part of the app-facing API), and the file already
|
|
406
|
+
// uses `$("body").on(event, selector, handler)` everywhere else for the
|
|
407
|
+
// exact same pattern. Migrated all 11 sites to that instead of shimming
|
|
408
|
+
// a deprecated jQuery API just to keep two spellings of one thing.
|
|
409
|
+
$.fn.click = function (handler) { return handler ? this.on('click', handler) : this.trigger('click'); };
|
|
410
|
+
$.fn.keydown = function (handler) { return handler ? this.on('keydown', handler) : this.trigger('keydown'); };
|
|
411
|
+
$.fn.trigger = function (type, data) {
|
|
412
|
+
return this.each(function () {
|
|
413
|
+
var bus = _eventTargetFor(this);
|
|
414
|
+
var ev;
|
|
415
|
+
if (type instanceof Event) {
|
|
416
|
+
// 2026-09-14, real bug found testing a real project end-to-
|
|
417
|
+
// end: the vendored WebWorker helper (vendor/webworker-
|
|
418
|
+
// helper.js) builds `$.Event(name)` — a real Event — then
|
|
419
|
+
// assigns custom properties onto it (e.g. `.worker`) and
|
|
420
|
+
// triggers with THAT OBJECT, not a name string. The old
|
|
421
|
+
// code here did `new Event(type, ...)` regardless, so
|
|
422
|
+
// passing an Event object as `type` got silently coerced
|
|
423
|
+
// to garbage like "[object Event]" by the native Event
|
|
424
|
+
// constructor — no error, just an event nothing ever
|
|
425
|
+
// matched, which is why _csswrk (the scoped-CSS worker,
|
|
426
|
+
// gating renderView() itself) never got past its
|
|
427
|
+
// INITIALIZED state: its own start()/load() sequence is
|
|
428
|
+
// entirely driven by trigger()ing exactly this pattern.
|
|
429
|
+
// Dispatch the existing Event as-is so its custom
|
|
430
|
+
// properties survive.
|
|
431
|
+
ev = type;
|
|
432
|
+
} else if (type && typeof type === 'object' && typeof type.type === 'string') {
|
|
433
|
+
ev = new Event(type.type, { bubbles: _isNode(this) });
|
|
434
|
+
for (var k in type) {
|
|
435
|
+
if (k !== 'type' && Object.prototype.hasOwnProperty.call(type, k)) {
|
|
436
|
+
try { ev[k] = type[k]; } catch (e) { /* read-only Event own-property, e.g. `target` */ }
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
} else {
|
|
440
|
+
ev = new Event(type, { bubbles: _isNode(this) });
|
|
441
|
+
}
|
|
442
|
+
if (data !== undefined) ev.detail = data;
|
|
443
|
+
bus.dispatchEvent(ev);
|
|
444
|
+
});
|
|
445
|
+
};
|
|
446
|
+
// Real removal needs the original listener reference, which this shim
|
|
447
|
+
// doesn't track (LumenJS's own model is delegation-first — see
|
|
448
|
+
// lumenjs-spec.md §5.6 — so long-lived per-node listeners needing unbind
|
|
449
|
+
// are already the exception, not the pattern). Kept for API completeness.
|
|
450
|
+
$.fn.unbind = function () { return this; };
|
|
451
|
+
|
|
452
|
+
// jQuery's shorthand event methods (2026-09-14, real gap found testing
|
|
453
|
+
// a real project's vendor code end-to-end — `$(el).keyup(...)` threw
|
|
454
|
+
// "not a function", never caught before because nothing had exercised
|
|
455
|
+
// this vendor code path this far). `.eventname(handler)` binds,
|
|
456
|
+
// `.eventname()` triggers — matching real jQuery exactly.
|
|
457
|
+
["click", "dblclick", "keyup", "keydown", "keypress", "focus", "blur",
|
|
458
|
+
"change", "submit", "focusin", "focusout", "mouseenter", "mouseleave",
|
|
459
|
+
"mouseover", "mouseout", "mousedown", "mouseup", "mousemove",
|
|
460
|
+
"resize", "scroll", "load", "select"].forEach(function (name) {
|
|
461
|
+
$.fn[name] = function (handler) {
|
|
462
|
+
return handler ? this.on(name, handler) : this.trigger(name);
|
|
463
|
+
};
|
|
464
|
+
});
|
|
465
|
+
$.fn.hover = function (enter, leave) {
|
|
466
|
+
this.on('mouseenter', enter);
|
|
467
|
+
this.on('mouseleave', leave || enter);
|
|
468
|
+
return this;
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
global.$ = $;
|
|
472
|
+
global.jQuery = $;
|
|
473
|
+
})(typeof window !== 'undefined' ? window : globalThis);
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// index.js bootstrap (2026-09-14). index.js no longer has a <script> tag
|
|
2
|
+
// in index.html (see packages/cli's scaffold + dev-server middleware); its
|
|
3
|
+
// top-level vars are compiled server-side into _vt.Global.vars (walk.js /
|
|
4
|
+
// _re.js), and this is what actually fetches and runs that compiled code
|
|
5
|
+
// in dev.
|
|
6
|
+
//
|
|
7
|
+
// Placement (see build/bundle.js): concatenated right after the WHOLE
|
|
8
|
+
// vendor/reconnecting-websocket.js file, which is where `Reactor` comes
|
|
9
|
+
// from (index.js's compiled code calls it as its last line) — but also
|
|
10
|
+
// where real index.js scripts commonly reference other framework globals
|
|
11
|
+
// defined much later in that same file (`cookies`, `session`, ...), so
|
|
12
|
+
// running only after `Reactor` specifically isn't enough (tried that
|
|
13
|
+
// first, 2026-09-14 — see git history). That vendor file's own
|
|
14
|
+
// $(document).ready(...) handler, which needs Reactor() to have already
|
|
15
|
+
// run (it reads appSettings.Base), is guarded to retry instead of
|
|
16
|
+
// assuming this file has already run by the time it fires — see
|
|
17
|
+
// `_lumenReadyHandler` in that file's own comment for why that guarantee
|
|
18
|
+
// doesn't actually hold (jQuery's ready() can fire synchronously, at
|
|
19
|
+
// registration time, before this file gets a chance to run).
|
|
20
|
+
//
|
|
21
|
+
// Uses console.log directly, not `cl` — this runs after _re.js's own
|
|
22
|
+
// `var cl = console.log;`, so `cl` would work too, but there's no reason
|
|
23
|
+
// to depend on that when a bare console.log is just as simple.
|
|
24
|
+
if (typeof _beaTn === 'undefined' || !_beaTn) {
|
|
25
|
+
if (typeof XMLHttpRequest === 'function') {
|
|
26
|
+
try {
|
|
27
|
+
var _idxXhr = new XMLHttpRequest();
|
|
28
|
+
_idxXhr.open('GET', '/index.js', false); // synchronous — see comment above
|
|
29
|
+
_idxXhr.send(null);
|
|
30
|
+
if (_idxXhr.status >= 200 && _idxXhr.status < 300) {
|
|
31
|
+
// Indirect eval (the comma-expression form), not `new
|
|
32
|
+
// Function`: a `function` executes in its OWN fresh scope,
|
|
33
|
+
// so a top-level `function greet(){}` inside it would
|
|
34
|
+
// become a local variable of that wrapper, not a real
|
|
35
|
+
// global — breaking the documented V1 pattern of calling
|
|
36
|
+
// index.js-declared functions straight from view markup
|
|
37
|
+
// (e.g. `onclick="greet()"`, resolved against window).
|
|
38
|
+
// Indirect eval runs in true global scope instead.
|
|
39
|
+
(0, eval)(_idxXhr.responseText);
|
|
40
|
+
} else {
|
|
41
|
+
console.log('Failed to load index.js: HTTP ' + _idxXhr.status);
|
|
42
|
+
}
|
|
43
|
+
} catch (e) {
|
|
44
|
+
console.log('Failed to load index.js: ', e);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|