bitwrench 2.0.16 → 2.0.17
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/bitwrench-bccl.cjs.js +6 -2
- package/dist/bitwrench-bccl.cjs.min.js +3 -3
- package/dist/bitwrench-bccl.esm.js +6 -2
- package/dist/bitwrench-bccl.esm.min.js +3 -3
- package/dist/bitwrench-bccl.umd.js +6 -2
- package/dist/bitwrench-bccl.umd.min.js +2 -2
- package/dist/bitwrench-code-edit.cjs.js +1 -1
- package/dist/bitwrench-code-edit.cjs.min.js +1 -1
- package/dist/bitwrench-code-edit.es5.js +1 -1
- package/dist/bitwrench-code-edit.es5.min.js +1 -1
- package/dist/bitwrench-code-edit.esm.js +1 -1
- package/dist/bitwrench-code-edit.esm.min.js +1 -1
- package/dist/bitwrench-code-edit.umd.js +1 -1
- package/dist/bitwrench-code-edit.umd.min.js +1 -1
- package/dist/bitwrench-lean.cjs.js +506 -154
- package/dist/bitwrench-lean.cjs.min.js +7 -7
- package/dist/bitwrench-lean.es5.js +517 -155
- package/dist/bitwrench-lean.es5.min.js +5 -5
- package/dist/bitwrench-lean.esm.js +505 -154
- package/dist/bitwrench-lean.esm.min.js +6 -6
- package/dist/bitwrench-lean.umd.js +506 -154
- package/dist/bitwrench-lean.umd.min.js +7 -7
- package/dist/bitwrench.cjs.js +511 -155
- package/dist/bitwrench.cjs.min.js +8 -8
- package/dist/bitwrench.es5.js +525 -156
- package/dist/bitwrench.es5.min.js +6 -6
- package/dist/bitwrench.esm.js +510 -155
- package/dist/bitwrench.esm.min.js +8 -8
- package/dist/bitwrench.umd.js +511 -155
- package/dist/bitwrench.umd.min.js +8 -8
- package/dist/builds.json +82 -82
- package/dist/bwserve.cjs.js +16 -2
- package/dist/bwserve.esm.js +16 -2
- package/dist/sri.json +34 -34
- package/package.json +4 -2
- package/readme.html +1 -1
- package/src/bitwrench-bccl.js +5 -1
- package/src/bitwrench.js +502 -151
- package/src/bwserve/index.js +12 -1
- package/src/bwserve/shell.js +3 -0
- package/src/cli/layout-default.js +47 -32
- package/src/version.js +3 -3
package/dist/bitwrench.umd.js
CHANGED
|
@@ -1,24 +1,25 @@
|
|
|
1
|
-
/*! bitwrench v2.0.
|
|
1
|
+
/*! bitwrench v2.0.17 | BSD-2-Clause | https://deftio.github.com/bitwrench/pages */
|
|
2
2
|
(function (global, factory) {
|
|
3
3
|
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
|
4
4
|
typeof define === 'function' && define.amd ? define(factory) :
|
|
5
5
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.bw = factory());
|
|
6
6
|
})(this, (function () { 'use strict';
|
|
7
7
|
|
|
8
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
8
9
|
/**
|
|
9
10
|
* Auto-generated version file from package.json
|
|
10
11
|
* DO NOT EDIT DIRECTLY - Use npm run generate-version
|
|
11
12
|
*/
|
|
12
13
|
|
|
13
14
|
const VERSION_INFO = {
|
|
14
|
-
version: '2.0.
|
|
15
|
+
version: '2.0.17',
|
|
15
16
|
name: 'bitwrench',
|
|
16
17
|
description: 'A library for javascript UI functions.',
|
|
17
18
|
license: 'BSD-2-Clause',
|
|
18
19
|
homepage: 'https://deftio.github.com/bitwrench/pages',
|
|
19
20
|
repository: 'git+https://github.com/deftio/bitwrench.git',
|
|
20
21
|
author: 'manu a. chatterjee <deftio@deftio.com> (https://deftio.com/)',
|
|
21
|
-
buildDate: '2026-03-
|
|
22
|
+
buildDate: '2026-03-13T23:15:10.823Z'
|
|
22
23
|
};
|
|
23
24
|
|
|
24
25
|
/**
|
|
@@ -6880,7 +6881,11 @@
|
|
|
6880
6881
|
function make(type, props) {
|
|
6881
6882
|
var def = BCCL[type];
|
|
6882
6883
|
if (!def) throw new Error('bw.make: unknown component type "' + type + '". Available: ' + Object.keys(BCCL).join(', '));
|
|
6883
|
-
|
|
6884
|
+
var taco = def.make(props || {});
|
|
6885
|
+
if (taco && typeof taco === 'object') {
|
|
6886
|
+
taco._bwFactory = { type: type, props: props || {} };
|
|
6887
|
+
}
|
|
6888
|
+
return taco;
|
|
6884
6889
|
}
|
|
6885
6890
|
|
|
6886
6891
|
var components = /*#__PURE__*/Object.freeze({
|
|
@@ -7001,7 +7006,7 @@
|
|
|
7001
7006
|
__monkey_patch_is_nodejs__: {
|
|
7002
7007
|
_value: 'ignore',
|
|
7003
7008
|
set: function(x) {
|
|
7004
|
-
this._value = (
|
|
7009
|
+
this._value = _is(x, 'boolean') ? x : 'ignore';
|
|
7005
7010
|
},
|
|
7006
7011
|
get: function() {
|
|
7007
7012
|
return this._value;
|
|
@@ -7049,6 +7054,67 @@
|
|
|
7049
7054
|
configurable: true
|
|
7050
7055
|
});
|
|
7051
7056
|
|
|
7057
|
+
// ── Internal aliases ─────────────────────────────────────────────────────
|
|
7058
|
+
// Short names for frequently-used builtins and internal methods.
|
|
7059
|
+
// Same pattern as v1 (_to = bw.typeOf, etc.).
|
|
7060
|
+
//
|
|
7061
|
+
// Why: Terser can't shorten global property chains (console.warn,
|
|
7062
|
+
// Object.prototype.hasOwnProperty, Array.isArray, document.createElement)
|
|
7063
|
+
// because it can't prove they're side-effect-free. We can, so we alias
|
|
7064
|
+
// them here. Each alias saves bytes in the minified output, and the short
|
|
7065
|
+
// names also reduce visual noise in the hot paths (binding pipeline,
|
|
7066
|
+
// createDOM, etc.).
|
|
7067
|
+
//
|
|
7068
|
+
// Alias Target Sites
|
|
7069
|
+
// ───────── ────────────────────────────────────── ─────
|
|
7070
|
+
// _hop Object.prototype.hasOwnProperty 15
|
|
7071
|
+
// _isA Array.isArray 25
|
|
7072
|
+
// _keys Object.keys 7
|
|
7073
|
+
// _to bw.typeOf (type string) 26
|
|
7074
|
+
// _is type check boolean: _is(x,'string') ~50
|
|
7075
|
+
// _cw console.warn 8
|
|
7076
|
+
// _cl console.log 11
|
|
7077
|
+
// _ce console.error 4
|
|
7078
|
+
// _chp ComponentHandle.prototype 28 (defined after constructor)
|
|
7079
|
+
//
|
|
7080
|
+
// Note: document.createElement etc. are NOT aliased because they require
|
|
7081
|
+
// `this === document` and .bind() would add overhead on every call.
|
|
7082
|
+
// Console aliases use thin wrappers (not direct refs) so test monkey-
|
|
7083
|
+
// patching of console.warn/log/error continues to work.
|
|
7084
|
+
//
|
|
7085
|
+
// `typeof x` for UNDECLARED globals (window, document, process, require,
|
|
7086
|
+
// EventSource, navigator, Promise, __filename, import.meta) MUST stay as
|
|
7087
|
+
// raw `typeof` — calling _to(x) when x doesn't exist throws ReferenceError.
|
|
7088
|
+
//
|
|
7089
|
+
// ── v1 functional type helpers (kept for reference, not currently used) ──
|
|
7090
|
+
// _toa(x, type, trueVal, falseVal) — bw.typeAssign:
|
|
7091
|
+
// returns trueVal if _to(x)===type, else falseVal.
|
|
7092
|
+
// Replaces: (typeof x === 'string') ? A : B → _toa(x,'string',A,B)
|
|
7093
|
+
// _toc(x, type, trueVal, falseVal) — bw.typeConvert:
|
|
7094
|
+
// same as _toa but if trueVal/falseVal are functions, calls them with x.
|
|
7095
|
+
// Replaces: typeof x === 'string' ? fn(x) : default → _toc(x,'string',fn,default)
|
|
7096
|
+
// Uncomment if pattern frequency justifies them:
|
|
7097
|
+
// var _toa = function(x, t, y, n) { return _to(x) === t ? y : n; };
|
|
7098
|
+
// var _toc = function(x, t, y, n) { var r = _to(x)===t; return r ? (_to(y)==='function'?y(x):y) : (_to(n)==='function'?n(x):n); };
|
|
7099
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
7100
|
+
var _hop = Object.prototype.hasOwnProperty;
|
|
7101
|
+
var _isA = Array.isArray;
|
|
7102
|
+
var _keys = Object.keys;
|
|
7103
|
+
var _to = typeOf; // imported from bitwrench-utils.js
|
|
7104
|
+
var _is = function(x, t) { var r = _to(x); return r === t || r.toLowerCase() === t; };
|
|
7105
|
+
// Console aliases use thin wrappers (not direct references) so that test
|
|
7106
|
+
// code can monkey-patch console.warn/log/error and the patches take effect.
|
|
7107
|
+
var _cw = function() { console.warn.apply(console, arguments); };
|
|
7108
|
+
var _cl = function() { console.log.apply(console, arguments); };
|
|
7109
|
+
var _ce = function() { console.error.apply(console, arguments); };
|
|
7110
|
+
|
|
7111
|
+
/**
|
|
7112
|
+
* Debug flag. When true, emits console.warn for silent binding failures
|
|
7113
|
+
* (missing paths, null refs, auto-created intermediate objects).
|
|
7114
|
+
* @type {boolean}
|
|
7115
|
+
*/
|
|
7116
|
+
bw.debug = false;
|
|
7117
|
+
|
|
7052
7118
|
/**
|
|
7053
7119
|
* Lazy-resolve Node.js `fs` module.
|
|
7054
7120
|
* Tries require('fs') first (available in CJS/UMD Node.js builds),
|
|
@@ -7196,7 +7262,7 @@
|
|
|
7196
7262
|
*/
|
|
7197
7263
|
bw._el = function(id) {
|
|
7198
7264
|
// Pass-through for DOM elements
|
|
7199
|
-
if (
|
|
7265
|
+
if (!_is(id, 'string')) return id || null;
|
|
7200
7266
|
if (!id) return null;
|
|
7201
7267
|
if (!bw._isBrowser) return null;
|
|
7202
7268
|
|
|
@@ -7292,7 +7358,7 @@
|
|
|
7292
7358
|
* // => '<b>Hello</b> & "world"'
|
|
7293
7359
|
*/
|
|
7294
7360
|
bw.escapeHTML = function(str) {
|
|
7295
|
-
if (
|
|
7361
|
+
if (!_is(str, 'string')) return '';
|
|
7296
7362
|
|
|
7297
7363
|
const escapeMap = {
|
|
7298
7364
|
'&': '&',
|
|
@@ -7365,7 +7431,7 @@
|
|
|
7365
7431
|
}
|
|
7366
7432
|
|
|
7367
7433
|
// Handle arrays of TACOs
|
|
7368
|
-
if (
|
|
7434
|
+
if (_isA(taco)) {
|
|
7369
7435
|
return taco.map(t => bw.html(t, options)).join('');
|
|
7370
7436
|
}
|
|
7371
7437
|
|
|
@@ -7388,15 +7454,15 @@
|
|
|
7388
7454
|
if (taco && taco._bwEach && options.state) {
|
|
7389
7455
|
var eachExpr = taco.expr.replace(/^\$\{|\}$/g, '');
|
|
7390
7456
|
var arr = bw._evaluatePath(options.state, eachExpr);
|
|
7391
|
-
if (!
|
|
7457
|
+
if (!_isA(arr)) return '';
|
|
7392
7458
|
return arr.map(function(item, idx) { return bw.html(taco.factory(item, idx), options); }).join('');
|
|
7393
7459
|
}
|
|
7394
7460
|
|
|
7395
7461
|
// Handle primitives and non-TACO objects
|
|
7396
|
-
if (
|
|
7462
|
+
if (!_is(taco, 'object') || !taco.t) {
|
|
7397
7463
|
var str = options.raw ? String(taco) : bw.escapeHTML(String(taco));
|
|
7398
7464
|
// Resolve template bindings if state provided
|
|
7399
|
-
if (options.state &&
|
|
7465
|
+
if (options.state && _is(str, 'string') && str.indexOf('${') >= 0) {
|
|
7400
7466
|
str = bw._resolveTemplate(str, options.state, !!options.compile);
|
|
7401
7467
|
}
|
|
7402
7468
|
return str;
|
|
@@ -7416,10 +7482,18 @@
|
|
|
7416
7482
|
// Skip null, undefined, false
|
|
7417
7483
|
if (value == null || value === false) continue;
|
|
7418
7484
|
|
|
7419
|
-
//
|
|
7420
|
-
if (key.startsWith('on'))
|
|
7485
|
+
// Serialize event handlers via funcRegister
|
|
7486
|
+
if (key.startsWith('on')) {
|
|
7487
|
+
if (_is(value, 'function')) {
|
|
7488
|
+
var fnId = bw.funcRegister(value);
|
|
7489
|
+
attrStr += ' ' + key + '="' + bw.funcGetDispatchStr(fnId, 'event') + '"';
|
|
7490
|
+
} else if (_is(value, 'string')) {
|
|
7491
|
+
attrStr += ' ' + key + '="' + bw.escapeHTML(value) + '"';
|
|
7492
|
+
}
|
|
7493
|
+
continue;
|
|
7494
|
+
}
|
|
7421
7495
|
|
|
7422
|
-
if (key === 'style' &&
|
|
7496
|
+
if (key === 'style' && _is(value, 'object')) {
|
|
7423
7497
|
// Convert style object to string
|
|
7424
7498
|
const styleStr = Object.entries(value)
|
|
7425
7499
|
.filter(([, v]) => v != null)
|
|
@@ -7430,7 +7504,7 @@
|
|
|
7430
7504
|
}
|
|
7431
7505
|
} else if (key === 'class') {
|
|
7432
7506
|
// Handle class as array or string
|
|
7433
|
-
const classStr =
|
|
7507
|
+
const classStr = _isA(value) ? value.filter(Boolean).join(' ') : String(value);
|
|
7434
7508
|
if (classStr) {
|
|
7435
7509
|
attrStr += ` class="${bw.escapeHTML(classStr)}"`;
|
|
7436
7510
|
}
|
|
@@ -7466,13 +7540,184 @@
|
|
|
7466
7540
|
// Process content recursively
|
|
7467
7541
|
let contentStr = content != null ? bw.html(content, options) : '';
|
|
7468
7542
|
// Resolve template bindings in content if state provided
|
|
7469
|
-
if (options.state &&
|
|
7543
|
+
if (options.state && _is(contentStr, 'string') && contentStr.indexOf('${') >= 0) {
|
|
7470
7544
|
contentStr = bw._resolveTemplate(contentStr, options.state, !!options.compile);
|
|
7471
7545
|
}
|
|
7472
7546
|
|
|
7473
7547
|
return `<${tag}${attrStr}>${contentStr}</${tag}>`;
|
|
7474
7548
|
};
|
|
7475
7549
|
|
|
7550
|
+
/**
|
|
7551
|
+
* Generate a complete, self-contained HTML document from TACO content.
|
|
7552
|
+
*
|
|
7553
|
+
* Produces a full `<!DOCTYPE html>` page with configurable runtime injection,
|
|
7554
|
+
* func registry emission (so serialized event handlers work), optional theme,
|
|
7555
|
+
* and extra head elements. Designed for static site generation, offline/airgapped
|
|
7556
|
+
* use, and the "static site that isn't static" workflow.
|
|
7557
|
+
*
|
|
7558
|
+
* @param {Object} [opts={}] - Page options
|
|
7559
|
+
* @param {Object|string|Array} [opts.body=''] - Body content: TACO, string, or array
|
|
7560
|
+
* @param {string} [opts.title='bitwrench'] - Page title
|
|
7561
|
+
* @param {Object} [opts.state] - State for ${expr} resolution in bw.html()
|
|
7562
|
+
* @param {string} [opts.runtime='shim'] - Runtime level: 'inline'|'cdn'|'shim'|'none'
|
|
7563
|
+
* @param {string} [opts.css=''] - Additional CSS for <style> block
|
|
7564
|
+
* @param {string|Object} [opts.theme=null] - Theme preset name or config object
|
|
7565
|
+
* @param {Array} [opts.head=[]] - Extra TACO elements rendered into <head>
|
|
7566
|
+
* @param {string} [opts.favicon=''] - Favicon URL
|
|
7567
|
+
* @param {string} [opts.lang='en'] - HTML lang attribute
|
|
7568
|
+
* @returns {string} Complete HTML document string
|
|
7569
|
+
* @category DOM Generation
|
|
7570
|
+
* @see bw.html
|
|
7571
|
+
* @example
|
|
7572
|
+
* bw.htmlPage({
|
|
7573
|
+
* title: 'My App',
|
|
7574
|
+
* body: { t: 'h1', c: 'Hello World' },
|
|
7575
|
+
* runtime: 'shim'
|
|
7576
|
+
* })
|
|
7577
|
+
*/
|
|
7578
|
+
bw.htmlPage = function(opts) {
|
|
7579
|
+
opts = opts || {};
|
|
7580
|
+
var title = opts.title || 'bitwrench';
|
|
7581
|
+
var body = opts.body || '';
|
|
7582
|
+
var state = opts.state || undefined;
|
|
7583
|
+
var runtime = opts.runtime || 'shim';
|
|
7584
|
+
var css = opts.css || '';
|
|
7585
|
+
var theme = opts.theme || null;
|
|
7586
|
+
var headExtra = opts.head || [];
|
|
7587
|
+
var favicon = opts.favicon || '';
|
|
7588
|
+
var lang = opts.lang || 'en';
|
|
7589
|
+
|
|
7590
|
+
// Snapshot funcRegistry counter before rendering
|
|
7591
|
+
var fnCounterBefore = bw._fnIDCounter;
|
|
7592
|
+
|
|
7593
|
+
// Render body content
|
|
7594
|
+
var bodyHTML = '';
|
|
7595
|
+
if (_is(body, 'string')) {
|
|
7596
|
+
bodyHTML = body;
|
|
7597
|
+
} else {
|
|
7598
|
+
var htmlOpts = {};
|
|
7599
|
+
if (state) htmlOpts.state = state;
|
|
7600
|
+
bodyHTML = bw.html(body, htmlOpts);
|
|
7601
|
+
}
|
|
7602
|
+
|
|
7603
|
+
// Collect functions registered during this render
|
|
7604
|
+
var fnCounterAfter = bw._fnIDCounter;
|
|
7605
|
+
var registryEntries = '';
|
|
7606
|
+
for (var i = fnCounterBefore; i < fnCounterAfter; i++) {
|
|
7607
|
+
var fnKey = 'bw_fn_' + i;
|
|
7608
|
+
if (bw._fnRegistry[fnKey]) {
|
|
7609
|
+
registryEntries += 'bw._fnRegistry[\'' + fnKey + '\']=' +
|
|
7610
|
+
bw._fnRegistry[fnKey].toString() + ';\n';
|
|
7611
|
+
}
|
|
7612
|
+
}
|
|
7613
|
+
|
|
7614
|
+
// Build runtime script for <head>
|
|
7615
|
+
var runtimeHead = '';
|
|
7616
|
+
if (runtime === 'inline') {
|
|
7617
|
+
// Read UMD bundle synchronously if in Node.js
|
|
7618
|
+
var umdSource = null;
|
|
7619
|
+
if (bw._isNode) {
|
|
7620
|
+
try {
|
|
7621
|
+
var fs = (typeof require === 'function') ? require('fs') : null;
|
|
7622
|
+
var pathMod = (typeof require === 'function') ? require('path') : null;
|
|
7623
|
+
if (fs && pathMod) {
|
|
7624
|
+
// Resolve dist/ relative to this source file
|
|
7625
|
+
var srcDir = '';
|
|
7626
|
+
try { srcDir = pathMod.dirname((typeof __filename !== 'undefined') ? __filename : ''); }
|
|
7627
|
+
catch(e2) { /* ESM: __filename not available */ }
|
|
7628
|
+
if (!srcDir && typeof ({ url: (typeof document === 'undefined' && typeof location === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : typeof document === 'undefined' ? location.href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('bitwrench.umd.js', document.baseURI).href)) }) !== 'undefined' && (typeof document === 'undefined' && typeof location === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : typeof document === 'undefined' ? location.href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('bitwrench.umd.js', document.baseURI).href))) {
|
|
7629
|
+
var url = (typeof require === 'function') ? require('url') : null;
|
|
7630
|
+
if (url && url.fileURLToPath) srcDir = pathMod.dirname(url.fileURLToPath((typeof document === 'undefined' && typeof location === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : typeof document === 'undefined' ? location.href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('bitwrench.umd.js', document.baseURI).href))));
|
|
7631
|
+
}
|
|
7632
|
+
if (srcDir) {
|
|
7633
|
+
var distPath = pathMod.resolve(srcDir, '../dist/bitwrench.umd.min.js');
|
|
7634
|
+
umdSource = fs.readFileSync(distPath, 'utf8');
|
|
7635
|
+
}
|
|
7636
|
+
}
|
|
7637
|
+
} catch(e) { /* fall through */ }
|
|
7638
|
+
}
|
|
7639
|
+
if (umdSource) {
|
|
7640
|
+
runtimeHead = '<script>' + umdSource + '</script>';
|
|
7641
|
+
} else {
|
|
7642
|
+
// Fallback to shim in browser or if dist not available
|
|
7643
|
+
runtimeHead = '<script>' + bw._FUNC_REGISTRY_SHIM + '</script>';
|
|
7644
|
+
}
|
|
7645
|
+
} else if (runtime === 'cdn') {
|
|
7646
|
+
runtimeHead = '<script src="https://cdn.jsdelivr.net/npm/bitwrench@2/dist/bitwrench.umd.min.js"></script>';
|
|
7647
|
+
} else if (runtime === 'shim') {
|
|
7648
|
+
runtimeHead = '<script>' + bw._FUNC_REGISTRY_SHIM + '</script>';
|
|
7649
|
+
}
|
|
7650
|
+
// runtime === 'none' → empty
|
|
7651
|
+
|
|
7652
|
+
// Theme CSS
|
|
7653
|
+
var themeCSS = '';
|
|
7654
|
+
if (theme) {
|
|
7655
|
+
var themeConfig = _is(theme, 'string')
|
|
7656
|
+
? (THEME_PRESETS[theme.toLowerCase()] || null)
|
|
7657
|
+
: theme;
|
|
7658
|
+
if (themeConfig) {
|
|
7659
|
+
var themeResult = bw.generateTheme('', Object.assign({}, themeConfig, { inject: false }));
|
|
7660
|
+
themeCSS = themeResult.css;
|
|
7661
|
+
}
|
|
7662
|
+
}
|
|
7663
|
+
|
|
7664
|
+
// Extra <head> elements
|
|
7665
|
+
var headHTML = '';
|
|
7666
|
+
if (_isA(headExtra) && headExtra.length > 0) {
|
|
7667
|
+
headHTML = headExtra.map(function(el) { return bw.html(el); }).join('\n');
|
|
7668
|
+
}
|
|
7669
|
+
|
|
7670
|
+
// Favicon
|
|
7671
|
+
var faviconTag = '';
|
|
7672
|
+
if (favicon) {
|
|
7673
|
+
var safeFavicon = favicon.replace(/[&<>"']/g, function(c) {
|
|
7674
|
+
return ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' })[c];
|
|
7675
|
+
});
|
|
7676
|
+
faviconTag = '<link rel="icon" href="' + safeFavicon + '">';
|
|
7677
|
+
}
|
|
7678
|
+
|
|
7679
|
+
// Escaped title
|
|
7680
|
+
var safeTitle = bw.escapeHTML(title);
|
|
7681
|
+
|
|
7682
|
+
// Combine all CSS
|
|
7683
|
+
var allCSS = (themeCSS ? themeCSS + '\n' : '') + css;
|
|
7684
|
+
|
|
7685
|
+
// Body-end script: registry entries + optional loadDefaultStyles
|
|
7686
|
+
var bodyEndScript = '';
|
|
7687
|
+
var bodyEndParts = [];
|
|
7688
|
+
if (registryEntries) {
|
|
7689
|
+
bodyEndParts.push(registryEntries);
|
|
7690
|
+
}
|
|
7691
|
+
if (runtime === 'inline' || runtime === 'cdn') {
|
|
7692
|
+
bodyEndParts.push('if(typeof bw!=="undefined"){bw.loadDefaultStyles();}');
|
|
7693
|
+
}
|
|
7694
|
+
if (bodyEndParts.length > 0) {
|
|
7695
|
+
bodyEndScript = '<script>\n' + bodyEndParts.join('\n') + '\n</script>';
|
|
7696
|
+
}
|
|
7697
|
+
|
|
7698
|
+
// Assemble document
|
|
7699
|
+
var parts = [
|
|
7700
|
+
'<!DOCTYPE html>',
|
|
7701
|
+
'<html lang="' + lang + '">',
|
|
7702
|
+
'<head>',
|
|
7703
|
+
'<meta charset="UTF-8">',
|
|
7704
|
+
'<meta name="viewport" content="width=device-width, initial-scale=1">'
|
|
7705
|
+
];
|
|
7706
|
+
parts.push('<title>' + safeTitle + '</title>');
|
|
7707
|
+
if (faviconTag) parts.push(faviconTag);
|
|
7708
|
+
if (runtimeHead) parts.push(runtimeHead);
|
|
7709
|
+
if (headHTML) parts.push(headHTML);
|
|
7710
|
+
if (allCSS) parts.push('<style>' + allCSS + '</style>');
|
|
7711
|
+
parts.push('</head>');
|
|
7712
|
+
parts.push('<body>');
|
|
7713
|
+
parts.push(bodyHTML);
|
|
7714
|
+
if (bodyEndScript) parts.push(bodyEndScript);
|
|
7715
|
+
parts.push('</body>');
|
|
7716
|
+
parts.push('</html>');
|
|
7717
|
+
|
|
7718
|
+
return parts.join('\n');
|
|
7719
|
+
};
|
|
7720
|
+
|
|
7476
7721
|
/**
|
|
7477
7722
|
* Create a live DOM element from a TACO object (browser only).
|
|
7478
7723
|
*
|
|
@@ -7517,7 +7762,7 @@
|
|
|
7517
7762
|
}
|
|
7518
7763
|
|
|
7519
7764
|
// Handle text nodes
|
|
7520
|
-
if (
|
|
7765
|
+
if (!_is(taco, 'object') || !taco.t) {
|
|
7521
7766
|
return document.createTextNode(String(taco));
|
|
7522
7767
|
}
|
|
7523
7768
|
|
|
@@ -7530,16 +7775,16 @@
|
|
|
7530
7775
|
for (const [key, value] of Object.entries(attrs)) {
|
|
7531
7776
|
if (value == null || value === false) continue;
|
|
7532
7777
|
|
|
7533
|
-
if (key === 'style' &&
|
|
7778
|
+
if (key === 'style' && _is(value, 'object')) {
|
|
7534
7779
|
// Apply styles directly
|
|
7535
7780
|
Object.assign(el.style, value);
|
|
7536
7781
|
} else if (key === 'class') {
|
|
7537
7782
|
// Handle class as array or string
|
|
7538
|
-
const classStr =
|
|
7783
|
+
const classStr = _isA(value) ? value.filter(Boolean).join(' ') : String(value);
|
|
7539
7784
|
if (classStr) {
|
|
7540
7785
|
el.className = classStr;
|
|
7541
7786
|
}
|
|
7542
|
-
} else if (key.startsWith('on') &&
|
|
7787
|
+
} else if (key.startsWith('on') && _is(value, 'function')) {
|
|
7543
7788
|
// Event handlers
|
|
7544
7789
|
const eventName = key.slice(2).toLowerCase();
|
|
7545
7790
|
el.addEventListener(eventName, value);
|
|
@@ -7559,7 +7804,7 @@
|
|
|
7559
7804
|
// Children with data-bw_id or id attributes get local refs on the parent,
|
|
7560
7805
|
// so o.render functions can access them without any DOM lookup.
|
|
7561
7806
|
if (content != null) {
|
|
7562
|
-
if (
|
|
7807
|
+
if (_isA(content)) {
|
|
7563
7808
|
content.forEach(child => {
|
|
7564
7809
|
if (child != null) {
|
|
7565
7810
|
// Handle ComponentHandle in content arrays (Level 2 children)
|
|
@@ -7579,20 +7824,20 @@
|
|
|
7579
7824
|
if (childEl._bw_refs) {
|
|
7580
7825
|
if (!el._bw_refs) el._bw_refs = {};
|
|
7581
7826
|
for (var rk in childEl._bw_refs) {
|
|
7582
|
-
if (
|
|
7827
|
+
if (_hop.call(childEl._bw_refs, rk)) {
|
|
7583
7828
|
el._bw_refs[rk] = childEl._bw_refs[rk];
|
|
7584
7829
|
}
|
|
7585
7830
|
}
|
|
7586
7831
|
}
|
|
7587
7832
|
}
|
|
7588
7833
|
});
|
|
7589
|
-
} else if (
|
|
7834
|
+
} else if (_is(content, 'object') && content.__bw_raw) {
|
|
7590
7835
|
// Raw HTML content — inject via innerHTML
|
|
7591
7836
|
el.innerHTML = content.v;
|
|
7592
7837
|
} else if (content._bwComponent === true) {
|
|
7593
7838
|
// Single ComponentHandle as content
|
|
7594
7839
|
content.mount(el);
|
|
7595
|
-
} else if (
|
|
7840
|
+
} else if (_is(content, 'object') && content.t) {
|
|
7596
7841
|
var childEl = bw.createDOM(content, options);
|
|
7597
7842
|
el.appendChild(childEl);
|
|
7598
7843
|
var childBwId = content.a ? (content.a['data-bw_id'] || content.a.id) : null;
|
|
@@ -7603,7 +7848,7 @@
|
|
|
7603
7848
|
if (childEl._bw_refs) {
|
|
7604
7849
|
if (!el._bw_refs) el._bw_refs = {};
|
|
7605
7850
|
for (var rk in childEl._bw_refs) {
|
|
7606
|
-
if (
|
|
7851
|
+
if (_hop.call(childEl._bw_refs, rk)) {
|
|
7607
7852
|
el._bw_refs[rk] = childEl._bw_refs[rk];
|
|
7608
7853
|
}
|
|
7609
7854
|
}
|
|
@@ -7636,7 +7881,7 @@
|
|
|
7636
7881
|
el._bw_render = opts.render;
|
|
7637
7882
|
|
|
7638
7883
|
if (opts.mounted) {
|
|
7639
|
-
|
|
7884
|
+
_cw('bw.createDOM: o.render and o.mounted are mutually exclusive. o.render wins.');
|
|
7640
7885
|
}
|
|
7641
7886
|
|
|
7642
7887
|
// Queue initial render (same timing as mounted)
|
|
@@ -7709,7 +7954,7 @@
|
|
|
7709
7954
|
const targetEl = bw._el(target);
|
|
7710
7955
|
|
|
7711
7956
|
if (!targetEl) {
|
|
7712
|
-
|
|
7957
|
+
_ce('bw.DOM: Target element not found:', target);
|
|
7713
7958
|
return null;
|
|
7714
7959
|
}
|
|
7715
7960
|
|
|
@@ -7749,7 +7994,7 @@
|
|
|
7749
7994
|
targetEl.appendChild(taco.element);
|
|
7750
7995
|
}
|
|
7751
7996
|
// Handle arrays
|
|
7752
|
-
else if (
|
|
7997
|
+
else if (_isA(taco)) {
|
|
7753
7998
|
taco.forEach(t => {
|
|
7754
7999
|
if (t != null) {
|
|
7755
8000
|
if (t._bwComponent === true) {
|
|
@@ -7785,7 +8030,7 @@
|
|
|
7785
8030
|
bw.compileProps = function(handle, props = {}) {
|
|
7786
8031
|
const compiledProps = {};
|
|
7787
8032
|
|
|
7788
|
-
|
|
8033
|
+
_keys(props).forEach(key => {
|
|
7789
8034
|
// Create getter/setter for each prop
|
|
7790
8035
|
Object.defineProperty(compiledProps, key, {
|
|
7791
8036
|
get() {
|
|
@@ -8103,17 +8348,17 @@
|
|
|
8103
8348
|
if (attr) {
|
|
8104
8349
|
// Patch an attribute
|
|
8105
8350
|
el.setAttribute(attr, String(content));
|
|
8106
|
-
} else if (
|
|
8351
|
+
} else if (_isA(content)) {
|
|
8107
8352
|
// Patch with array of children (strings and/or TACOs)
|
|
8108
8353
|
el.innerHTML = '';
|
|
8109
8354
|
content.forEach(function(item) {
|
|
8110
|
-
if (
|
|
8355
|
+
if (_is(item, 'string') || _is(item, 'number')) {
|
|
8111
8356
|
el.appendChild(document.createTextNode(String(item)));
|
|
8112
8357
|
} else if (item && item.t) {
|
|
8113
8358
|
el.appendChild(bw.createDOM(item));
|
|
8114
8359
|
}
|
|
8115
8360
|
});
|
|
8116
|
-
} else if (
|
|
8361
|
+
} else if (_is(content, 'object') && content.t) {
|
|
8117
8362
|
// Patch with a TACO — replace children
|
|
8118
8363
|
el.innerHTML = '';
|
|
8119
8364
|
el.appendChild(bw.createDOM(content));
|
|
@@ -8144,7 +8389,7 @@
|
|
|
8144
8389
|
bw.patchAll = function(patches) {
|
|
8145
8390
|
var results = {};
|
|
8146
8391
|
for (var id in patches) {
|
|
8147
|
-
if (
|
|
8392
|
+
if (_hop.call(patches, id)) {
|
|
8148
8393
|
results[id] = bw.patch(id, patches[id]);
|
|
8149
8394
|
}
|
|
8150
8395
|
}
|
|
@@ -8241,7 +8486,7 @@
|
|
|
8241
8486
|
snapshot[i].handler(detail);
|
|
8242
8487
|
called++;
|
|
8243
8488
|
} catch (err) {
|
|
8244
|
-
|
|
8489
|
+
_cw('bw.pub: subscriber error on topic "' + topic + '":', err);
|
|
8245
8490
|
}
|
|
8246
8491
|
}
|
|
8247
8492
|
return called;
|
|
@@ -8337,8 +8582,8 @@
|
|
|
8337
8582
|
* @see bw.funcGetDispatchStr
|
|
8338
8583
|
*/
|
|
8339
8584
|
bw.funcRegister = function(fn, name) {
|
|
8340
|
-
if (
|
|
8341
|
-
var fnID = (
|
|
8585
|
+
if (!_is(fn, 'function')) return '';
|
|
8586
|
+
var fnID = (_is(name, 'string') && name.length > 0) ? name : ('bw_fn_' + bw._fnIDCounter++);
|
|
8342
8587
|
bw._fnRegistry[fnID] = fn;
|
|
8343
8588
|
return fnID;
|
|
8344
8589
|
};
|
|
@@ -8357,7 +8602,7 @@
|
|
|
8357
8602
|
bw.funcGetById = function(name, errFn) {
|
|
8358
8603
|
name = String(name);
|
|
8359
8604
|
if (name in bw._fnRegistry) return bw._fnRegistry[name];
|
|
8360
|
-
return (
|
|
8605
|
+
return _is(errFn, 'function') ? errFn : function() { _cw('bw.funcGetById: unregistered fn "' + name + '"'); };
|
|
8361
8606
|
};
|
|
8362
8607
|
|
|
8363
8608
|
/**
|
|
@@ -8398,13 +8643,30 @@
|
|
|
8398
8643
|
bw.funcGetRegistry = function() {
|
|
8399
8644
|
var copy = {};
|
|
8400
8645
|
for (var k in bw._fnRegistry) {
|
|
8401
|
-
if (
|
|
8646
|
+
if (_hop.call(bw._fnRegistry, k)) {
|
|
8402
8647
|
copy[k] = bw._fnRegistry[k];
|
|
8403
8648
|
}
|
|
8404
8649
|
}
|
|
8405
8650
|
return copy;
|
|
8406
8651
|
};
|
|
8407
8652
|
|
|
8653
|
+
/**
|
|
8654
|
+
* Minimal runtime shim for funcRegister dispatch in static HTML.
|
|
8655
|
+
* When embedded in a `<script>` tag, provides just enough infrastructure
|
|
8656
|
+
* for `bw.funcGetById()` calls to resolve. The actual function bodies
|
|
8657
|
+
* are emitted separately as `bw._fnRegistry['bw_fn_X'] = ...;` assignments.
|
|
8658
|
+
* @type {string}
|
|
8659
|
+
* @category Function Registry
|
|
8660
|
+
*/
|
|
8661
|
+
bw._FUNC_REGISTRY_SHIM = '(function(){var bw=window.bw||(window.bw={});' +
|
|
8662
|
+
'if(!bw._fnRegistry)bw._fnRegistry={};' +
|
|
8663
|
+
'bw.funcGetById=function(n){return bw._fnRegistry[n]||function(){' +
|
|
8664
|
+
'console.warn("bw: unregistered fn "+n)};};' +
|
|
8665
|
+
'bw.funcRegister=function(fn,name){' +
|
|
8666
|
+
'var id=name||("bw_fn_"+(bw._fnIDCounter=(bw._fnIDCounter||0)+1));' +
|
|
8667
|
+
'bw._fnRegistry[id]=fn;return id;};' +
|
|
8668
|
+
'window.bw=bw;})();';
|
|
8669
|
+
|
|
8408
8670
|
// ===================================================================================
|
|
8409
8671
|
// Template Binding Utilities
|
|
8410
8672
|
// ===================================================================================
|
|
@@ -8432,7 +8694,10 @@
|
|
|
8432
8694
|
var parts = path.split('.');
|
|
8433
8695
|
var val = state;
|
|
8434
8696
|
for (var i = 0; i < parts.length; i++) {
|
|
8435
|
-
if (val == null)
|
|
8697
|
+
if (val == null) {
|
|
8698
|
+
if (bw.debug) _cw('bw.debug: _evaluatePath — null at key "' + parts[i] + '" in path "' + path + '"');
|
|
8699
|
+
return '';
|
|
8700
|
+
}
|
|
8436
8701
|
val = val[parts[i]];
|
|
8437
8702
|
}
|
|
8438
8703
|
return (val == null) ? '' : val;
|
|
@@ -8452,7 +8717,7 @@
|
|
|
8452
8717
|
*/
|
|
8453
8718
|
bw._compiledExprs = {};
|
|
8454
8719
|
bw._resolveTemplate = function(str, state, compile) {
|
|
8455
|
-
if (
|
|
8720
|
+
if (!_is(str, 'string') || str.indexOf('${') < 0) return str;
|
|
8456
8721
|
var bindings = bw._parseBindings(str);
|
|
8457
8722
|
if (bindings.length === 0) return str;
|
|
8458
8723
|
|
|
@@ -8474,6 +8739,7 @@
|
|
|
8474
8739
|
try {
|
|
8475
8740
|
val = bw._compiledExprs[b.expr](state);
|
|
8476
8741
|
} catch (e) {
|
|
8742
|
+
if (bw.debug) _cw('bw.debug: _resolveTemplate — Tier 2 eval failed for "${' + b.expr + '}":', e.message);
|
|
8477
8743
|
val = '';
|
|
8478
8744
|
}
|
|
8479
8745
|
} else {
|
|
@@ -8582,7 +8848,7 @@
|
|
|
8582
8848
|
this._state = {};
|
|
8583
8849
|
if (o.state) {
|
|
8584
8850
|
for (var k in o.state) {
|
|
8585
|
-
if (
|
|
8851
|
+
if (_hop.call(o.state, k)) {
|
|
8586
8852
|
this._state[k] = o.state[k];
|
|
8587
8853
|
}
|
|
8588
8854
|
}
|
|
@@ -8591,7 +8857,7 @@
|
|
|
8591
8857
|
this._actions = {};
|
|
8592
8858
|
if (o.actions) {
|
|
8593
8859
|
for (var k2 in o.actions) {
|
|
8594
|
-
if (
|
|
8860
|
+
if (_hop.call(o.actions, k2)) {
|
|
8595
8861
|
this._actions[k2] = o.actions[k2];
|
|
8596
8862
|
}
|
|
8597
8863
|
}
|
|
@@ -8601,7 +8867,7 @@
|
|
|
8601
8867
|
if (o.methods) {
|
|
8602
8868
|
var self = this;
|
|
8603
8869
|
for (var k3 in o.methods) {
|
|
8604
|
-
if (
|
|
8870
|
+
if (_hop.call(o.methods, k3)) {
|
|
8605
8871
|
this._methods[k3] = o.methods[k3];
|
|
8606
8872
|
(function(methodName, methodFn) {
|
|
8607
8873
|
self[methodName] = function() {
|
|
@@ -8634,14 +8900,23 @@
|
|
|
8634
8900
|
this._compile = !!o.compile;
|
|
8635
8901
|
this._bw_refs = {};
|
|
8636
8902
|
this._refCounter = 0;
|
|
8903
|
+
// Child component ownership (Bug #5)
|
|
8904
|
+
this._children = [];
|
|
8905
|
+
this._parent = null;
|
|
8906
|
+
// Factory metadata for BCCL rebuild (Bug #6)
|
|
8907
|
+
this._factory = taco._bwFactory || null;
|
|
8637
8908
|
}
|
|
8638
8909
|
|
|
8910
|
+
// Short alias for ComponentHandle.prototype (see alias block at top of file).
|
|
8911
|
+
// 28 method definitions × 25 chars = ~700B raw savings in minified output.
|
|
8912
|
+
var _chp = ComponentHandle.prototype;
|
|
8913
|
+
|
|
8639
8914
|
// ── State Methods ──
|
|
8640
8915
|
|
|
8641
8916
|
/**
|
|
8642
8917
|
* Get a state value. Dot-path supported: `get('user.name')`
|
|
8643
8918
|
*/
|
|
8644
|
-
|
|
8919
|
+
_chp.get = function(key) {
|
|
8645
8920
|
return bw._evaluatePath(this._state, key);
|
|
8646
8921
|
};
|
|
8647
8922
|
|
|
@@ -8651,12 +8926,13 @@
|
|
|
8651
8926
|
* @param {*} value - New value
|
|
8652
8927
|
* @param {Object} [opts] - Options. `{sync: true}` for immediate flush.
|
|
8653
8928
|
*/
|
|
8654
|
-
|
|
8929
|
+
_chp.set = function(key, value, opts) {
|
|
8655
8930
|
// Dot-path set
|
|
8656
8931
|
var parts = key.split('.');
|
|
8657
8932
|
var obj = this._state;
|
|
8658
8933
|
for (var i = 0; i < parts.length - 1; i++) {
|
|
8659
|
-
if (obj[parts[i]]
|
|
8934
|
+
if (!_is(obj[parts[i]], 'object')) {
|
|
8935
|
+
if (bw.debug) _cw('bw.debug: set() — auto-creating intermediate "' + parts[i] + '" in path "' + key + '"');
|
|
8660
8936
|
obj[parts[i]] = {};
|
|
8661
8937
|
}
|
|
8662
8938
|
obj = obj[parts[i]];
|
|
@@ -8676,10 +8952,10 @@
|
|
|
8676
8952
|
/**
|
|
8677
8953
|
* Get a shallow clone of the full state.
|
|
8678
8954
|
*/
|
|
8679
|
-
|
|
8955
|
+
_chp.getState = function() {
|
|
8680
8956
|
var clone = {};
|
|
8681
8957
|
for (var k in this._state) {
|
|
8682
|
-
if (
|
|
8958
|
+
if (_hop.call(this._state, k)) {
|
|
8683
8959
|
clone[k] = this._state[k];
|
|
8684
8960
|
}
|
|
8685
8961
|
}
|
|
@@ -8691,9 +8967,9 @@
|
|
|
8691
8967
|
* @param {Object} updates - Key-value pairs to merge
|
|
8692
8968
|
* @param {Object} [opts] - Options. `{sync: true}` for immediate flush.
|
|
8693
8969
|
*/
|
|
8694
|
-
|
|
8970
|
+
_chp.setState = function(updates, opts) {
|
|
8695
8971
|
for (var k in updates) {
|
|
8696
|
-
if (
|
|
8972
|
+
if (_hop.call(updates, k)) {
|
|
8697
8973
|
this._state[k] = updates[k];
|
|
8698
8974
|
this._dirtyKeys[k] = true;
|
|
8699
8975
|
}
|
|
@@ -8710,9 +8986,9 @@
|
|
|
8710
8986
|
/**
|
|
8711
8987
|
* Push a value onto an array in state. Clones the array.
|
|
8712
8988
|
*/
|
|
8713
|
-
|
|
8989
|
+
_chp.push = function(key, val) {
|
|
8714
8990
|
var arr = this.get(key);
|
|
8715
|
-
var newArr =
|
|
8991
|
+
var newArr = _isA(arr) ? arr.slice() : [];
|
|
8716
8992
|
newArr.push(val);
|
|
8717
8993
|
this.set(key, newArr);
|
|
8718
8994
|
};
|
|
@@ -8720,9 +8996,9 @@
|
|
|
8720
8996
|
/**
|
|
8721
8997
|
* Splice an array in state. Clones the array.
|
|
8722
8998
|
*/
|
|
8723
|
-
|
|
8999
|
+
_chp.splice = function(key, start, deleteCount) {
|
|
8724
9000
|
var arr = this.get(key);
|
|
8725
|
-
var newArr =
|
|
9001
|
+
var newArr = _isA(arr) ? arr.slice() : [];
|
|
8726
9002
|
var args = [start, deleteCount].concat(Array.prototype.slice.call(arguments, 3));
|
|
8727
9003
|
Array.prototype.splice.apply(newArr, args);
|
|
8728
9004
|
this.set(key, newArr);
|
|
@@ -8730,7 +9006,7 @@
|
|
|
8730
9006
|
|
|
8731
9007
|
// ── Scheduling ──
|
|
8732
9008
|
|
|
8733
|
-
|
|
9009
|
+
_chp._scheduleDirty = function() {
|
|
8734
9010
|
if (!this._scheduled) {
|
|
8735
9011
|
this._scheduled = true;
|
|
8736
9012
|
bw._dirtyComponents.push(this);
|
|
@@ -8745,17 +9021,17 @@
|
|
|
8745
9021
|
* Creates binding descriptors with refIds for targeted DOM updates.
|
|
8746
9022
|
* @private
|
|
8747
9023
|
*/
|
|
8748
|
-
|
|
9024
|
+
_chp._compileBindings = function() {
|
|
8749
9025
|
this._bindings = [];
|
|
8750
9026
|
this._refCounter = 0;
|
|
8751
|
-
var stateKeys =
|
|
9027
|
+
var stateKeys = _keys(this._state);
|
|
8752
9028
|
var self = this;
|
|
8753
9029
|
|
|
8754
9030
|
function walkTaco(taco, path) {
|
|
8755
|
-
if (taco
|
|
9031
|
+
if (!_is(taco, 'object') || !taco.t) return taco;
|
|
8756
9032
|
|
|
8757
9033
|
// Check content for bindings
|
|
8758
|
-
if (
|
|
9034
|
+
if (_is(taco.c, 'string') && taco.c.indexOf('${') >= 0) {
|
|
8759
9035
|
var refId = 'bw_ref_' + self._refCounter++;
|
|
8760
9036
|
var parsed = bw._parseBindings(taco.c);
|
|
8761
9037
|
var deps = [];
|
|
@@ -8777,10 +9053,10 @@
|
|
|
8777
9053
|
// Check attributes for bindings
|
|
8778
9054
|
if (taco.a) {
|
|
8779
9055
|
for (var attrName in taco.a) {
|
|
8780
|
-
if (!
|
|
9056
|
+
if (!_hop.call(taco.a, attrName)) continue;
|
|
8781
9057
|
if (attrName === 'data-bw_ref') continue;
|
|
8782
9058
|
var attrVal = taco.a[attrName];
|
|
8783
|
-
if (
|
|
9059
|
+
if (_is(attrVal, 'string') && attrVal.indexOf('${') >= 0) {
|
|
8784
9060
|
var refId2 = 'bw_ref_' + self._refCounter++;
|
|
8785
9061
|
var parsed2 = bw._parseBindings(attrVal);
|
|
8786
9062
|
var deps2 = [];
|
|
@@ -8806,9 +9082,27 @@
|
|
|
8806
9082
|
}
|
|
8807
9083
|
|
|
8808
9084
|
// Recurse into children
|
|
8809
|
-
if (
|
|
9085
|
+
if (_isA(taco.c)) {
|
|
8810
9086
|
for (var i = 0; i < taco.c.length; i++) {
|
|
8811
|
-
|
|
9087
|
+
// Wrap string children with ${expr} in a span so patches target the span, not the parent
|
|
9088
|
+
if (_is(taco.c[i], 'string') && taco.c[i].indexOf('${') >= 0) {
|
|
9089
|
+
var mixedRefId = 'bw_ref_' + self._refCounter++;
|
|
9090
|
+
var mixedParsed = bw._parseBindings(taco.c[i]);
|
|
9091
|
+
var mixedDeps = [];
|
|
9092
|
+
for (var mi = 0; mi < mixedParsed.length; mi++) {
|
|
9093
|
+
mixedDeps = mixedDeps.concat(bw._extractDeps(mixedParsed[mi].expr, stateKeys));
|
|
9094
|
+
}
|
|
9095
|
+
self._bindings.push({
|
|
9096
|
+
expr: taco.c[i],
|
|
9097
|
+
type: 'content',
|
|
9098
|
+
refId: mixedRefId,
|
|
9099
|
+
deps: mixedDeps,
|
|
9100
|
+
template: taco.c[i]
|
|
9101
|
+
});
|
|
9102
|
+
// Replace string with a span wrapper so textContent targets the span only
|
|
9103
|
+
taco.c[i] = { t: 'span', a: { 'data-bw_ref': mixedRefId, style: 'display:contents' }, c: taco.c[i] };
|
|
9104
|
+
}
|
|
9105
|
+
if (_is(taco.c[i], 'object') && taco.c[i].t) {
|
|
8812
9106
|
walkTaco(taco.c[i], path.concat(i));
|
|
8813
9107
|
}
|
|
8814
9108
|
// Handle bw.when/bw.each markers
|
|
@@ -8843,7 +9137,7 @@
|
|
|
8843
9137
|
taco.c[i]._refId = eachRefId;
|
|
8844
9138
|
}
|
|
8845
9139
|
}
|
|
8846
|
-
} else if (taco.c
|
|
9140
|
+
} else if (_is(taco.c, 'object') && taco.c.t) {
|
|
8847
9141
|
walkTaco(taco.c, path.concat(0));
|
|
8848
9142
|
}
|
|
8849
9143
|
|
|
@@ -8859,7 +9153,7 @@
|
|
|
8859
9153
|
* Build ref map from the live DOM after createDOM.
|
|
8860
9154
|
* @private
|
|
8861
9155
|
*/
|
|
8862
|
-
|
|
9156
|
+
_chp._collectRefs = function() {
|
|
8863
9157
|
this._bw_refs = {};
|
|
8864
9158
|
if (!this.element) return;
|
|
8865
9159
|
var els = this.element.querySelectorAll('[data-bw_ref]');
|
|
@@ -8880,7 +9174,7 @@
|
|
|
8880
9174
|
* Creates DOM, compiles bindings, registers actions, and calls lifecycle hooks.
|
|
8881
9175
|
* @param {Element} parentEl - DOM element to mount into
|
|
8882
9176
|
*/
|
|
8883
|
-
|
|
9177
|
+
_chp.mount = function(parentEl) {
|
|
8884
9178
|
// willMount hook
|
|
8885
9179
|
if (this._hooks.willMount) this._hooks.willMount(this);
|
|
8886
9180
|
|
|
@@ -8902,7 +9196,7 @@
|
|
|
8902
9196
|
// Register named actions in function registry
|
|
8903
9197
|
var self = this;
|
|
8904
9198
|
for (var actionName in this._actions) {
|
|
8905
|
-
if (
|
|
9199
|
+
if (_hop.call(this._actions, actionName)) {
|
|
8906
9200
|
var registeredName = this._bwId + '_' + actionName;
|
|
8907
9201
|
(function(aName) {
|
|
8908
9202
|
bw.funcRegister(function(evt) {
|
|
@@ -8921,6 +9215,11 @@
|
|
|
8921
9215
|
this.element = bw.createDOM(tacoForDOM);
|
|
8922
9216
|
this.element._bwComponentHandle = this;
|
|
8923
9217
|
this.element.setAttribute('data-bw_comp_id', this._bwId);
|
|
9218
|
+
|
|
9219
|
+
// Restore o.render from original TACO (stripped by _tacoForDOM)
|
|
9220
|
+
if (this.taco.o && this.taco.o.render) {
|
|
9221
|
+
this.element._bw_render = this.taco.o.render;
|
|
9222
|
+
}
|
|
8924
9223
|
if (this._userTag) {
|
|
8925
9224
|
this.element.classList.add(this._userTag);
|
|
8926
9225
|
}
|
|
@@ -8936,6 +9235,16 @@
|
|
|
8936
9235
|
|
|
8937
9236
|
this.mounted = true;
|
|
8938
9237
|
|
|
9238
|
+
// Scan for child ComponentHandles and link parent/child (Bug #5)
|
|
9239
|
+
var childEls = this.element.querySelectorAll('[data-bw_comp_id]');
|
|
9240
|
+
for (var ci = 0; ci < childEls.length; ci++) {
|
|
9241
|
+
var ch = childEls[ci]._bwComponentHandle;
|
|
9242
|
+
if (ch && ch !== this && !ch._parent) {
|
|
9243
|
+
ch._parent = this;
|
|
9244
|
+
this._children.push(ch);
|
|
9245
|
+
}
|
|
9246
|
+
}
|
|
9247
|
+
|
|
8939
9248
|
// mounted hook (backward compat: fn.length === 2 wraps (el, state))
|
|
8940
9249
|
if (this._hooks.mounted) {
|
|
8941
9250
|
if (this._hooks.mounted.length === 2) {
|
|
@@ -8944,16 +9253,21 @@
|
|
|
8944
9253
|
this._hooks.mounted(this);
|
|
8945
9254
|
}
|
|
8946
9255
|
}
|
|
9256
|
+
|
|
9257
|
+
// Invoke o.render on initial mount (if present)
|
|
9258
|
+
if (this.element._bw_render) {
|
|
9259
|
+
this.element._bw_render(this.element, this._state);
|
|
9260
|
+
}
|
|
8947
9261
|
};
|
|
8948
9262
|
|
|
8949
9263
|
/**
|
|
8950
9264
|
* Prepare TACO for initial render: resolve when/each markers.
|
|
8951
9265
|
* @private
|
|
8952
9266
|
*/
|
|
8953
|
-
|
|
8954
|
-
if (!taco
|
|
9267
|
+
_chp._prepareTaco = function(taco) {
|
|
9268
|
+
if (!_is(taco, 'object')) return;
|
|
8955
9269
|
|
|
8956
|
-
if (
|
|
9270
|
+
if (_isA(taco.c)) {
|
|
8957
9271
|
for (var i = taco.c.length - 1; i >= 0; i--) {
|
|
8958
9272
|
var child = taco.c[i];
|
|
8959
9273
|
if (child && child._bwWhen) {
|
|
@@ -8978,18 +9292,18 @@
|
|
|
8978
9292
|
var eachExprStr = child.expr.replace(/^\$\{|\}$/g, '');
|
|
8979
9293
|
var arr = bw._evaluatePath(this._state, eachExprStr);
|
|
8980
9294
|
var items = [];
|
|
8981
|
-
if (
|
|
9295
|
+
if (_isA(arr)) {
|
|
8982
9296
|
for (var j = 0; j < arr.length; j++) {
|
|
8983
9297
|
items.push(child.factory(arr[j], j));
|
|
8984
9298
|
}
|
|
8985
9299
|
}
|
|
8986
9300
|
taco.c[i] = { t: 'span', a: { 'data-bw_each': child._refId, style: 'display:contents' }, c: items };
|
|
8987
9301
|
}
|
|
8988
|
-
if (taco.c[i]
|
|
9302
|
+
if (_is(taco.c[i], 'object') && taco.c[i].t) {
|
|
8989
9303
|
this._prepareTaco(taco.c[i]);
|
|
8990
9304
|
}
|
|
8991
9305
|
}
|
|
8992
|
-
} else if (taco.c
|
|
9306
|
+
} else if (_is(taco.c, 'object') && taco.c.t) {
|
|
8993
9307
|
this._prepareTaco(taco.c);
|
|
8994
9308
|
}
|
|
8995
9309
|
};
|
|
@@ -8998,12 +9312,12 @@
|
|
|
8998
9312
|
* Wire action name strings (in onclick etc.) to dispatch function calls.
|
|
8999
9313
|
* @private
|
|
9000
9314
|
*/
|
|
9001
|
-
|
|
9002
|
-
if (!taco
|
|
9315
|
+
_chp._wireActions = function(taco) {
|
|
9316
|
+
if (!_is(taco, 'object') || !taco.t) return;
|
|
9003
9317
|
if (taco.a) {
|
|
9004
9318
|
for (var key in taco.a) {
|
|
9005
|
-
if (!
|
|
9006
|
-
if (key.startsWith('on') &&
|
|
9319
|
+
if (!_hop.call(taco.a, key)) continue;
|
|
9320
|
+
if (key.startsWith('on') && _is(taco.a[key], 'string')) {
|
|
9007
9321
|
var actionName = taco.a[key];
|
|
9008
9322
|
if (actionName in this._actions) {
|
|
9009
9323
|
var registeredName = this._bwId + '_' + actionName;
|
|
@@ -9017,11 +9331,11 @@
|
|
|
9017
9331
|
}
|
|
9018
9332
|
}
|
|
9019
9333
|
}
|
|
9020
|
-
if (
|
|
9334
|
+
if (_isA(taco.c)) {
|
|
9021
9335
|
for (var i = 0; i < taco.c.length; i++) {
|
|
9022
9336
|
this._wireActions(taco.c[i]);
|
|
9023
9337
|
}
|
|
9024
|
-
} else if (taco.c
|
|
9338
|
+
} else if (_is(taco.c, 'object') && taco.c.t) {
|
|
9025
9339
|
this._wireActions(taco.c);
|
|
9026
9340
|
}
|
|
9027
9341
|
};
|
|
@@ -9030,7 +9344,7 @@
|
|
|
9030
9344
|
* Deep-clone a TACO tree, preserving _bwWhen/_bwEach markers and their factories.
|
|
9031
9345
|
* @private
|
|
9032
9346
|
*/
|
|
9033
|
-
|
|
9347
|
+
_chp._deepCloneTaco = function(taco) {
|
|
9034
9348
|
if (taco == null) return taco;
|
|
9035
9349
|
// Preserve _bwWhen / _bwEach markers (contain functions)
|
|
9036
9350
|
if (taco._bwWhen) {
|
|
@@ -9042,18 +9356,18 @@
|
|
|
9042
9356
|
if (taco._bwEach) {
|
|
9043
9357
|
return { _bwEach: true, expr: taco.expr, factory: taco.factory, _refId: taco._refId };
|
|
9044
9358
|
}
|
|
9045
|
-
if (
|
|
9359
|
+
if (!_is(taco, 'object') || !taco.t) return taco;
|
|
9046
9360
|
var result = { t: taco.t };
|
|
9047
9361
|
if (taco.a) {
|
|
9048
9362
|
result.a = {};
|
|
9049
9363
|
for (var k in taco.a) {
|
|
9050
|
-
if (
|
|
9364
|
+
if (_hop.call(taco.a, k)) result.a[k] = taco.a[k];
|
|
9051
9365
|
}
|
|
9052
9366
|
}
|
|
9053
9367
|
if (taco.c != null) {
|
|
9054
|
-
if (
|
|
9368
|
+
if (_isA(taco.c)) {
|
|
9055
9369
|
result.c = taco.c.map(function(child) { return this._deepCloneTaco(child); }.bind(this));
|
|
9056
|
-
} else if (
|
|
9370
|
+
} else if (_is(taco.c, 'object')) {
|
|
9057
9371
|
result.c = this._deepCloneTaco(taco.c);
|
|
9058
9372
|
} else {
|
|
9059
9373
|
result.c = taco.c;
|
|
@@ -9067,27 +9381,31 @@
|
|
|
9067
9381
|
* Create a copy of TACO suitable for createDOM (strips o to prevent double lifecycle).
|
|
9068
9382
|
* @private
|
|
9069
9383
|
*/
|
|
9070
|
-
|
|
9071
|
-
if (!taco
|
|
9384
|
+
_chp._tacoForDOM = function(taco) {
|
|
9385
|
+
if (!_is(taco, 'object') || !taco.t) return taco;
|
|
9072
9386
|
var result = { t: taco.t };
|
|
9073
9387
|
if (taco.a) result.a = taco.a;
|
|
9074
9388
|
if (taco.c != null) {
|
|
9075
|
-
if (
|
|
9389
|
+
if (_isA(taco.c)) {
|
|
9076
9390
|
result.c = taco.c.map(function(child) { return this._tacoForDOM(child); }.bind(this));
|
|
9077
|
-
} else if (
|
|
9391
|
+
} else if (_is(taco.c, 'object') && taco.c.t) {
|
|
9078
9392
|
result.c = this._tacoForDOM(taco.c);
|
|
9079
9393
|
} else {
|
|
9080
9394
|
result.c = taco.c;
|
|
9081
9395
|
}
|
|
9082
9396
|
}
|
|
9083
9397
|
// Intentionally strip o (no mounted/unmount/state/render on sub-elements)
|
|
9398
|
+
if (taco.o && (taco.o.mounted || taco.o.render || taco.o.unmount)) {
|
|
9399
|
+
_cw('bw: _tacoForDOM stripped o.mounted/render/unmount from child <' + taco.t +
|
|
9400
|
+
'>. Use onclick attribute or bw.component() for child interactivity.');
|
|
9401
|
+
}
|
|
9084
9402
|
return result;
|
|
9085
9403
|
};
|
|
9086
9404
|
|
|
9087
9405
|
/**
|
|
9088
9406
|
* Unmount: remove from DOM, deactivate, preserve state for re-mount.
|
|
9089
9407
|
*/
|
|
9090
|
-
|
|
9408
|
+
_chp.unmount = function() {
|
|
9091
9409
|
if (!this.mounted) return;
|
|
9092
9410
|
|
|
9093
9411
|
// unmount hook
|
|
@@ -9122,12 +9440,23 @@
|
|
|
9122
9440
|
/**
|
|
9123
9441
|
* Destroy: unmount + clear state + unregister actions.
|
|
9124
9442
|
*/
|
|
9125
|
-
|
|
9443
|
+
_chp.destroy = function() {
|
|
9126
9444
|
// willDestroy hook
|
|
9127
9445
|
if (this._hooks.willDestroy) {
|
|
9128
9446
|
this._hooks.willDestroy(this);
|
|
9129
9447
|
}
|
|
9130
9448
|
|
|
9449
|
+
// Cascade destroy to children depth-first (Bug #5)
|
|
9450
|
+
for (var ci = this._children.length - 1; ci >= 0; ci--) {
|
|
9451
|
+
this._children[ci].destroy();
|
|
9452
|
+
}
|
|
9453
|
+
this._children = [];
|
|
9454
|
+
if (this._parent) {
|
|
9455
|
+
var idx = this._parent._children.indexOf(this);
|
|
9456
|
+
if (idx >= 0) this._parent._children.splice(idx, 1);
|
|
9457
|
+
this._parent = null;
|
|
9458
|
+
}
|
|
9459
|
+
|
|
9131
9460
|
this.unmount();
|
|
9132
9461
|
|
|
9133
9462
|
// Unregister actions from function registry
|
|
@@ -9154,12 +9483,36 @@
|
|
|
9154
9483
|
* Flush dirty state: resolve changed bindings and apply to DOM.
|
|
9155
9484
|
* @private
|
|
9156
9485
|
*/
|
|
9157
|
-
|
|
9486
|
+
_chp._flush = function() {
|
|
9158
9487
|
this._scheduled = false;
|
|
9159
|
-
var changedKeys =
|
|
9488
|
+
var changedKeys = _keys(this._dirtyKeys);
|
|
9160
9489
|
this._dirtyKeys = {};
|
|
9161
9490
|
if (changedKeys.length === 0 || !this.mounted) return;
|
|
9162
9491
|
|
|
9492
|
+
// Factory rebuild: if a BCCL factory exists and changed keys overlap factory props,
|
|
9493
|
+
// rebuild the TACO from the factory with merged state (Bug #6)
|
|
9494
|
+
if (this._factory) {
|
|
9495
|
+
var rebuildNeeded = false;
|
|
9496
|
+
for (var fi = 0; fi < changedKeys.length; fi++) {
|
|
9497
|
+
if (_hop.call(this._factory.props, changedKeys[fi])) {
|
|
9498
|
+
rebuildNeeded = true; break;
|
|
9499
|
+
}
|
|
9500
|
+
}
|
|
9501
|
+
if (rebuildNeeded) {
|
|
9502
|
+
var merged = {};
|
|
9503
|
+
for (var mk in this._factory.props) if (_hop.call(this._factory.props, mk)) merged[mk] = this._factory.props[mk];
|
|
9504
|
+
for (var sk in this._state) if (_hop.call(this._state, sk)) merged[sk] = this._state[sk];
|
|
9505
|
+
this._factory.props = merged;
|
|
9506
|
+
var newTaco = bw.make(this._factory.type, merged);
|
|
9507
|
+
newTaco._bwFactory = this._factory;
|
|
9508
|
+
this.taco = newTaco;
|
|
9509
|
+
this._originalTaco = this._deepCloneTaco(newTaco);
|
|
9510
|
+
this._render();
|
|
9511
|
+
if (this._hooks.onUpdate) this._hooks.onUpdate(this, changedKeys);
|
|
9512
|
+
return;
|
|
9513
|
+
}
|
|
9514
|
+
}
|
|
9515
|
+
|
|
9163
9516
|
// willUpdate hook
|
|
9164
9517
|
if (this._hooks.willUpdate) {
|
|
9165
9518
|
this._hooks.willUpdate(this, changedKeys);
|
|
@@ -9198,7 +9551,7 @@
|
|
|
9198
9551
|
* Returns list of patches to apply.
|
|
9199
9552
|
* @private
|
|
9200
9553
|
*/
|
|
9201
|
-
|
|
9554
|
+
_chp._resolveBindings = function(changedKeys) {
|
|
9202
9555
|
var patches = [];
|
|
9203
9556
|
for (var i = 0; i < this._bindings.length; i++) {
|
|
9204
9557
|
var b = this._bindings[i];
|
|
@@ -9234,11 +9587,14 @@
|
|
|
9234
9587
|
* Apply patches to DOM.
|
|
9235
9588
|
* @private
|
|
9236
9589
|
*/
|
|
9237
|
-
|
|
9590
|
+
_chp._applyPatches = function(patches) {
|
|
9238
9591
|
for (var i = 0; i < patches.length; i++) {
|
|
9239
9592
|
var p = patches[i];
|
|
9240
9593
|
var el = this._bw_refs[p.refId];
|
|
9241
|
-
if (!el)
|
|
9594
|
+
if (!el) {
|
|
9595
|
+
if (bw.debug) _cw('bw.debug: _applyPatches — ref "' + p.refId + '" not found in DOM');
|
|
9596
|
+
continue;
|
|
9597
|
+
}
|
|
9242
9598
|
if (p.type === 'content') {
|
|
9243
9599
|
el.textContent = p.value;
|
|
9244
9600
|
} else if (p.type === 'attribute') {
|
|
@@ -9255,7 +9611,7 @@
|
|
|
9255
9611
|
* Resolve all bindings and apply (used for initial render).
|
|
9256
9612
|
* @private
|
|
9257
9613
|
*/
|
|
9258
|
-
|
|
9614
|
+
_chp._resolveAndApplyAll = function() {
|
|
9259
9615
|
var patches = [];
|
|
9260
9616
|
for (var i = 0; i < this._bindings.length; i++) {
|
|
9261
9617
|
var b = this._bindings[i];
|
|
@@ -9278,7 +9634,7 @@
|
|
|
9278
9634
|
* Full re-render for structural changes (when/each branch switches).
|
|
9279
9635
|
* @private
|
|
9280
9636
|
*/
|
|
9281
|
-
|
|
9637
|
+
_chp._render = function() {
|
|
9282
9638
|
if (!this.element || !this.element.parentNode) return;
|
|
9283
9639
|
var parent = this.element.parentNode;
|
|
9284
9640
|
var nextSibling = this.element.nextSibling;
|
|
@@ -9318,7 +9674,7 @@
|
|
|
9318
9674
|
* @param {string} event - Event name (e.g., 'click')
|
|
9319
9675
|
* @param {Function} handler - Event handler
|
|
9320
9676
|
*/
|
|
9321
|
-
|
|
9677
|
+
_chp.on = function(event, handler) {
|
|
9322
9678
|
if (this.element) {
|
|
9323
9679
|
this.element.addEventListener(event, handler);
|
|
9324
9680
|
}
|
|
@@ -9330,7 +9686,7 @@
|
|
|
9330
9686
|
* @param {string} event - Event name
|
|
9331
9687
|
* @param {Function} handler - Handler to remove
|
|
9332
9688
|
*/
|
|
9333
|
-
|
|
9689
|
+
_chp.off = function(event, handler) {
|
|
9334
9690
|
if (this.element) {
|
|
9335
9691
|
this.element.removeEventListener(event, handler);
|
|
9336
9692
|
}
|
|
@@ -9345,7 +9701,7 @@
|
|
|
9345
9701
|
* @param {Function} handler - Handler function
|
|
9346
9702
|
* @returns {Function} Unsubscribe function
|
|
9347
9703
|
*/
|
|
9348
|
-
|
|
9704
|
+
_chp.sub = function(topic, handler) {
|
|
9349
9705
|
var unsub = bw.sub(topic, handler);
|
|
9350
9706
|
this._subs.push(unsub);
|
|
9351
9707
|
return unsub;
|
|
@@ -9356,10 +9712,10 @@
|
|
|
9356
9712
|
* @param {string} name - Action name
|
|
9357
9713
|
* @param {...*} args - Arguments passed after comp
|
|
9358
9714
|
*/
|
|
9359
|
-
|
|
9715
|
+
_chp.action = function(name) {
|
|
9360
9716
|
var fn = this._actions[name];
|
|
9361
9717
|
if (!fn) {
|
|
9362
|
-
|
|
9718
|
+
_cw('ComponentHandle.action: unknown action "' + name + '"');
|
|
9363
9719
|
return;
|
|
9364
9720
|
}
|
|
9365
9721
|
var args = [this].concat(Array.prototype.slice.call(arguments, 1));
|
|
@@ -9371,7 +9727,7 @@
|
|
|
9371
9727
|
* @param {string} sel - CSS selector
|
|
9372
9728
|
* @returns {Element|null}
|
|
9373
9729
|
*/
|
|
9374
|
-
|
|
9730
|
+
_chp.select = function(sel) {
|
|
9375
9731
|
return this.element ? this.element.querySelector(sel) : null;
|
|
9376
9732
|
};
|
|
9377
9733
|
|
|
@@ -9380,7 +9736,7 @@
|
|
|
9380
9736
|
* @param {string} sel - CSS selector
|
|
9381
9737
|
* @returns {Element[]}
|
|
9382
9738
|
*/
|
|
9383
|
-
|
|
9739
|
+
_chp.selectAll = function(sel) {
|
|
9384
9740
|
if (!this.element) return [];
|
|
9385
9741
|
return Array.prototype.slice.call(this.element.querySelectorAll(sel));
|
|
9386
9742
|
};
|
|
@@ -9391,7 +9747,7 @@
|
|
|
9391
9747
|
* @param {string} tag - User-defined identifier (e.g. 'dashboard_prod_east')
|
|
9392
9748
|
* @returns {ComponentHandle} this (for chaining)
|
|
9393
9749
|
*/
|
|
9394
|
-
|
|
9750
|
+
_chp.userTag = function(tag) {
|
|
9395
9751
|
this._userTag = tag;
|
|
9396
9752
|
if (this.element) {
|
|
9397
9753
|
this.element.classList.add(tag);
|
|
@@ -9492,8 +9848,8 @@
|
|
|
9492
9848
|
}
|
|
9493
9849
|
if (!el || !el._bwComponentHandle) return false;
|
|
9494
9850
|
var comp = el._bwComponentHandle;
|
|
9495
|
-
if (
|
|
9496
|
-
|
|
9851
|
+
if (!_is(comp[action], 'function')) {
|
|
9852
|
+
_cw('bw.message: unknown action "' + action + '" on component ' + target);
|
|
9497
9853
|
return false;
|
|
9498
9854
|
}
|
|
9499
9855
|
comp[action](data);
|
|
@@ -9530,7 +9886,7 @@
|
|
|
9530
9886
|
},
|
|
9531
9887
|
focus: function(selector) {
|
|
9532
9888
|
var el = bw._el(selector);
|
|
9533
|
-
if (el &&
|
|
9889
|
+
if (el && _is(el.focus, 'function')) el.focus();
|
|
9534
9890
|
},
|
|
9535
9891
|
download: function(filename, content, mimeType) {
|
|
9536
9892
|
if (typeof document === 'undefined') return;
|
|
@@ -9695,12 +10051,12 @@
|
|
|
9695
10051
|
} else if (type === 'remove') {
|
|
9696
10052
|
var toRemove = bw._el(target);
|
|
9697
10053
|
if (!toRemove) return false;
|
|
9698
|
-
if (
|
|
10054
|
+
if (_is(bw.cleanup, 'function')) bw.cleanup(toRemove);
|
|
9699
10055
|
toRemove.remove();
|
|
9700
10056
|
return true;
|
|
9701
10057
|
|
|
9702
10058
|
} else if (type === 'batch') {
|
|
9703
|
-
if (!
|
|
10059
|
+
if (!_isA(msg.ops)) return false;
|
|
9704
10060
|
var allOk = true;
|
|
9705
10061
|
msg.ops.forEach(function(op) {
|
|
9706
10062
|
if (!bw.clientApply(op)) allOk = false;
|
|
@@ -9716,26 +10072,26 @@
|
|
|
9716
10072
|
bw._clientFunctions[msg.name] = new Function('return ' + msg.body)();
|
|
9717
10073
|
return true;
|
|
9718
10074
|
} catch (e) {
|
|
9719
|
-
|
|
10075
|
+
_ce('[bw] register error:', msg.name, e);
|
|
9720
10076
|
return false;
|
|
9721
10077
|
}
|
|
9722
10078
|
|
|
9723
10079
|
} else if (type === 'call') {
|
|
9724
10080
|
if (!msg.name) return false;
|
|
9725
10081
|
var fn = bw._clientFunctions[msg.name] || bw._builtinClientFunctions[msg.name];
|
|
9726
|
-
if (
|
|
10082
|
+
if (!_is(fn, 'function')) return false;
|
|
9727
10083
|
try {
|
|
9728
|
-
var args =
|
|
10084
|
+
var args = _isA(msg.args) ? msg.args : [];
|
|
9729
10085
|
fn.apply(null, args);
|
|
9730
10086
|
return true;
|
|
9731
10087
|
} catch (e) {
|
|
9732
|
-
|
|
10088
|
+
_ce('[bw] call error:', msg.name, e);
|
|
9733
10089
|
return false;
|
|
9734
10090
|
}
|
|
9735
10091
|
|
|
9736
10092
|
} else if (type === 'exec') {
|
|
9737
10093
|
if (!bw._allowExec) {
|
|
9738
|
-
|
|
10094
|
+
_cw('[bw] exec rejected: allowExec is not enabled');
|
|
9739
10095
|
return false;
|
|
9740
10096
|
}
|
|
9741
10097
|
if (!msg.code) return false;
|
|
@@ -9743,7 +10099,7 @@
|
|
|
9743
10099
|
new Function(msg.code)();
|
|
9744
10100
|
return true;
|
|
9745
10101
|
} catch (e) {
|
|
9746
|
-
|
|
10102
|
+
_ce('[bw] exec error:', e);
|
|
9747
10103
|
return false;
|
|
9748
10104
|
}
|
|
9749
10105
|
}
|
|
@@ -9791,7 +10147,7 @@
|
|
|
9791
10147
|
|
|
9792
10148
|
function handleMessage(data) {
|
|
9793
10149
|
try {
|
|
9794
|
-
var msg =
|
|
10150
|
+
var msg = _is(data, 'string') ? bw.clientParse(data) : data;
|
|
9795
10151
|
if (onMessage) onMessage(msg);
|
|
9796
10152
|
if (handlers.message) handlers.message(msg);
|
|
9797
10153
|
bw.clientApply(msg);
|
|
@@ -9829,7 +10185,7 @@
|
|
|
9829
10185
|
setStatus('connected');
|
|
9830
10186
|
conn._pollTimer = setInterval(function() {
|
|
9831
10187
|
fetch(url).then(function(r) { return r.json(); }).then(function(msgs) {
|
|
9832
|
-
if (
|
|
10188
|
+
if (_isA(msgs)) {
|
|
9833
10189
|
msgs.forEach(handleMessage);
|
|
9834
10190
|
} else if (msgs && msgs.type) {
|
|
9835
10191
|
handleMessage(msgs);
|
|
@@ -9911,33 +10267,33 @@
|
|
|
9911
10267
|
el = target.element;
|
|
9912
10268
|
comp = target;
|
|
9913
10269
|
} else {
|
|
9914
|
-
if (
|
|
10270
|
+
if (_is(target, 'string')) {
|
|
9915
10271
|
el = bw.$(target)[0];
|
|
9916
10272
|
}
|
|
9917
10273
|
if (!el) {
|
|
9918
|
-
|
|
10274
|
+
_cw('bw.inspect: element not found');
|
|
9919
10275
|
return null;
|
|
9920
10276
|
}
|
|
9921
10277
|
comp = el._bwComponentHandle;
|
|
9922
10278
|
}
|
|
9923
10279
|
if (!comp) {
|
|
9924
|
-
|
|
9925
|
-
|
|
9926
|
-
|
|
9927
|
-
|
|
10280
|
+
_cl('bw.inspect: no ComponentHandle on this element');
|
|
10281
|
+
_cl(' Tag:', el.tagName);
|
|
10282
|
+
_cl(' Classes:', el.className);
|
|
10283
|
+
_cl(' _bw_state:', el._bw_state || '(none)');
|
|
9928
10284
|
return null;
|
|
9929
10285
|
}
|
|
9930
10286
|
var deps = comp._bindings.reduce(function(s, b) {
|
|
9931
10287
|
return s.concat(b.deps || []);
|
|
9932
10288
|
}, []).filter(function(v, i, a) { return a.indexOf(v) === i; });
|
|
9933
10289
|
console.group('Component: ' + comp._bwId);
|
|
9934
|
-
|
|
9935
|
-
|
|
9936
|
-
|
|
9937
|
-
|
|
9938
|
-
|
|
9939
|
-
|
|
9940
|
-
|
|
10290
|
+
_cl('State:', comp._state);
|
|
10291
|
+
_cl('Bindings:', comp._bindings.length, '(deps:', deps, ')');
|
|
10292
|
+
_cl('Methods:', _keys(comp._methods));
|
|
10293
|
+
_cl('Actions:', _keys(comp._actions));
|
|
10294
|
+
_cl('User tag:', comp._userTag || '(none)');
|
|
10295
|
+
_cl('Mounted:', comp.mounted);
|
|
10296
|
+
_cl('Element:', comp.element);
|
|
9941
10297
|
console.groupEnd();
|
|
9942
10298
|
return comp;
|
|
9943
10299
|
};
|
|
@@ -9960,8 +10316,8 @@
|
|
|
9960
10316
|
// Pre-extract all binding expressions
|
|
9961
10317
|
var precompiled = [];
|
|
9962
10318
|
function walkExpressions(node) {
|
|
9963
|
-
if (!node
|
|
9964
|
-
if (
|
|
10319
|
+
if (!_is(node, 'object')) return;
|
|
10320
|
+
if (_is(node.c, 'string') && node.c.indexOf('${') >= 0) {
|
|
9965
10321
|
var parsed = bw._parseBindings(node.c);
|
|
9966
10322
|
for (var i = 0; i < parsed.length; i++) {
|
|
9967
10323
|
try {
|
|
@@ -9976,9 +10332,9 @@
|
|
|
9976
10332
|
}
|
|
9977
10333
|
if (node.a) {
|
|
9978
10334
|
for (var key in node.a) {
|
|
9979
|
-
if (
|
|
10335
|
+
if (_hop.call(node.a, key)) {
|
|
9980
10336
|
var v = node.a[key];
|
|
9981
|
-
if (
|
|
10337
|
+
if (_is(v, 'string') && v.indexOf('${') >= 0) {
|
|
9982
10338
|
var parsed2 = bw._parseBindings(v);
|
|
9983
10339
|
for (var j = 0; j < parsed2.length; j++) {
|
|
9984
10340
|
try {
|
|
@@ -9994,9 +10350,9 @@
|
|
|
9994
10350
|
}
|
|
9995
10351
|
}
|
|
9996
10352
|
}
|
|
9997
|
-
if (
|
|
10353
|
+
if (_isA(node.c)) {
|
|
9998
10354
|
for (var k = 0; k < node.c.length; k++) walkExpressions(node.c[k]);
|
|
9999
|
-
} else if (node.c
|
|
10355
|
+
} else if (_is(node.c, 'object') && node.c.t) {
|
|
10000
10356
|
walkExpressions(node.c);
|
|
10001
10357
|
}
|
|
10002
10358
|
}
|
|
@@ -10008,7 +10364,7 @@
|
|
|
10008
10364
|
handle._precompiledBindings = precompiled;
|
|
10009
10365
|
if (initialState) {
|
|
10010
10366
|
for (var k in initialState) {
|
|
10011
|
-
if (
|
|
10367
|
+
if (_hop.call(initialState, k)) {
|
|
10012
10368
|
handle._state[k] = initialState[k];
|
|
10013
10369
|
}
|
|
10014
10370
|
}
|
|
@@ -10039,18 +10395,18 @@
|
|
|
10039
10395
|
bw.css = function(rules, options = {}) {
|
|
10040
10396
|
const { minify = false, pretty = !minify } = options;
|
|
10041
10397
|
|
|
10042
|
-
if (
|
|
10398
|
+
if (_is(rules, 'string')) return rules;
|
|
10043
10399
|
|
|
10044
10400
|
let css = '';
|
|
10045
10401
|
const indent = pretty ? ' ' : '';
|
|
10046
10402
|
const newline = pretty ? '\n' : '';
|
|
10047
10403
|
const space = pretty ? ' ' : '';
|
|
10048
10404
|
|
|
10049
|
-
if (
|
|
10405
|
+
if (_isA(rules)) {
|
|
10050
10406
|
css = rules.map(rule => bw.css(rule, options)).join(newline);
|
|
10051
|
-
} else if (
|
|
10407
|
+
} else if (_is(rules, 'object')) {
|
|
10052
10408
|
Object.entries(rules).forEach(([selector, styles]) => {
|
|
10053
|
-
if (
|
|
10409
|
+
if (_is(styles, 'object')) {
|
|
10054
10410
|
// Handle @media, @keyframes, @supports — recurse into nested block
|
|
10055
10411
|
if (selector.charAt(0) === '@') {
|
|
10056
10412
|
const inner = bw.css(styles, options);
|
|
@@ -10099,7 +10455,7 @@
|
|
|
10099
10455
|
*/
|
|
10100
10456
|
bw.injectCSS = function(css, options = {}) {
|
|
10101
10457
|
if (!bw._isBrowser) {
|
|
10102
|
-
|
|
10458
|
+
_cw('bw.injectCSS requires a DOM environment');
|
|
10103
10459
|
return null;
|
|
10104
10460
|
}
|
|
10105
10461
|
|
|
@@ -10116,7 +10472,7 @@
|
|
|
10116
10472
|
}
|
|
10117
10473
|
|
|
10118
10474
|
// Convert CSS if needed
|
|
10119
|
-
const cssStr =
|
|
10475
|
+
const cssStr = _is(css, 'string') ? css : bw.css(css, options);
|
|
10120
10476
|
|
|
10121
10477
|
// Set or append CSS
|
|
10122
10478
|
if (append && styleEl.textContent) {
|
|
@@ -10146,7 +10502,7 @@
|
|
|
10146
10502
|
var result = {};
|
|
10147
10503
|
for (var i = 0; i < arguments.length; i++) {
|
|
10148
10504
|
var arg = arguments[i];
|
|
10149
|
-
if (arg
|
|
10505
|
+
if (_is(arg, 'object')) Object.assign(result, arg);
|
|
10150
10506
|
}
|
|
10151
10507
|
return result;
|
|
10152
10508
|
};
|
|
@@ -10269,7 +10625,7 @@
|
|
|
10269
10625
|
bw.responsive = function(selector, breakpoints) {
|
|
10270
10626
|
var sizes = { sm: '576px', md: '768px', lg: '992px', xl: '1200px' };
|
|
10271
10627
|
var parts = [];
|
|
10272
|
-
|
|
10628
|
+
_keys(breakpoints).forEach(function(key) {
|
|
10273
10629
|
var rules = {};
|
|
10274
10630
|
if (key === 'base') {
|
|
10275
10631
|
rules[selector] = breakpoints[key];
|
|
@@ -10341,18 +10697,18 @@
|
|
|
10341
10697
|
if (!selector) return [];
|
|
10342
10698
|
|
|
10343
10699
|
// Already an array
|
|
10344
|
-
if (
|
|
10700
|
+
if (_isA(selector)) return selector;
|
|
10345
10701
|
|
|
10346
10702
|
// Single element
|
|
10347
10703
|
if (selector.nodeType) return [selector];
|
|
10348
10704
|
|
|
10349
10705
|
// NodeList or HTMLCollection
|
|
10350
|
-
if (selector.length !== undefined &&
|
|
10706
|
+
if (selector.length !== undefined && !_is(selector, 'string')) {
|
|
10351
10707
|
return Array.from(selector);
|
|
10352
10708
|
}
|
|
10353
10709
|
|
|
10354
10710
|
// CSS selector string
|
|
10355
|
-
if (
|
|
10711
|
+
if (_is(selector, 'string')) {
|
|
10356
10712
|
return Array.from(document.querySelectorAll(selector));
|
|
10357
10713
|
}
|
|
10358
10714
|
|
|
@@ -10856,7 +11212,7 @@
|
|
|
10856
11212
|
|
|
10857
11213
|
// Auto-detect columns if not provided
|
|
10858
11214
|
const cols = columns || (data.length > 0
|
|
10859
|
-
?
|
|
11215
|
+
? _keys(data[0]).map(key => ({ key, label: key }))
|
|
10860
11216
|
: []);
|
|
10861
11217
|
|
|
10862
11218
|
// Current sort state
|
|
@@ -10871,7 +11227,7 @@
|
|
|
10871
11227
|
const bVal = b[currentSortColumn];
|
|
10872
11228
|
|
|
10873
11229
|
// Handle different types
|
|
10874
|
-
if (
|
|
11230
|
+
if (_is(aVal, 'number') && _is(bVal, 'number')) {
|
|
10875
11231
|
return currentSortDirection === 'asc' ? aVal - bVal : bVal - aVal;
|
|
10876
11232
|
}
|
|
10877
11233
|
|
|
@@ -10981,7 +11337,7 @@
|
|
|
10981
11337
|
bw.makeTableFromArray = function(config) {
|
|
10982
11338
|
const { data = [], headerRow = true, columns, ...rest } = config;
|
|
10983
11339
|
|
|
10984
|
-
if (!
|
|
11340
|
+
if (!_isA(data) || data.length === 0) {
|
|
10985
11341
|
return bw.makeTable({ data: [], columns: columns || [], ...rest });
|
|
10986
11342
|
}
|
|
10987
11343
|
|
|
@@ -11063,7 +11419,7 @@
|
|
|
11063
11419
|
className = ''
|
|
11064
11420
|
} = config;
|
|
11065
11421
|
|
|
11066
|
-
if (!
|
|
11422
|
+
if (!_isA(data) || data.length === 0) {
|
|
11067
11423
|
return { t: 'div', a: { class: ('bw_bar_chart_container ' + className).trim() }, c: '' };
|
|
11068
11424
|
}
|
|
11069
11425
|
|
|
@@ -11212,7 +11568,7 @@
|
|
|
11212
11568
|
*/
|
|
11213
11569
|
bw.render = function(element, position, taco) {
|
|
11214
11570
|
// Get target element
|
|
11215
|
-
const targetEl =
|
|
11571
|
+
const targetEl = _is(element, 'string')
|
|
11216
11572
|
? document.querySelector(element)
|
|
11217
11573
|
: element;
|
|
11218
11574
|
|
|
@@ -11362,7 +11718,7 @@
|
|
|
11362
11718
|
setContent(content) {
|
|
11363
11719
|
this._taco.c = content;
|
|
11364
11720
|
if (this.element) {
|
|
11365
|
-
if (
|
|
11721
|
+
if (_is(content, 'string')) {
|
|
11366
11722
|
this.element.textContent = content;
|
|
11367
11723
|
} else {
|
|
11368
11724
|
// Re-render for complex content
|