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
|
@@ -1,24 +1,25 @@
|
|
|
1
|
-
/*! bitwrench-lean v2.0.
|
|
1
|
+
/*! bitwrench-lean 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
|
/**
|
|
@@ -3349,7 +3350,7 @@
|
|
|
3349
3350
|
__monkey_patch_is_nodejs__: {
|
|
3350
3351
|
_value: 'ignore',
|
|
3351
3352
|
set: function(x) {
|
|
3352
|
-
this._value = (
|
|
3353
|
+
this._value = _is(x, 'boolean') ? x : 'ignore';
|
|
3353
3354
|
},
|
|
3354
3355
|
get: function() {
|
|
3355
3356
|
return this._value;
|
|
@@ -3397,6 +3398,67 @@
|
|
|
3397
3398
|
configurable: true
|
|
3398
3399
|
});
|
|
3399
3400
|
|
|
3401
|
+
// ── Internal aliases ─────────────────────────────────────────────────────
|
|
3402
|
+
// Short names for frequently-used builtins and internal methods.
|
|
3403
|
+
// Same pattern as v1 (_to = bw.typeOf, etc.).
|
|
3404
|
+
//
|
|
3405
|
+
// Why: Terser can't shorten global property chains (console.warn,
|
|
3406
|
+
// Object.prototype.hasOwnProperty, Array.isArray, document.createElement)
|
|
3407
|
+
// because it can't prove they're side-effect-free. We can, so we alias
|
|
3408
|
+
// them here. Each alias saves bytes in the minified output, and the short
|
|
3409
|
+
// names also reduce visual noise in the hot paths (binding pipeline,
|
|
3410
|
+
// createDOM, etc.).
|
|
3411
|
+
//
|
|
3412
|
+
// Alias Target Sites
|
|
3413
|
+
// ───────── ────────────────────────────────────── ─────
|
|
3414
|
+
// _hop Object.prototype.hasOwnProperty 15
|
|
3415
|
+
// _isA Array.isArray 25
|
|
3416
|
+
// _keys Object.keys 7
|
|
3417
|
+
// _to bw.typeOf (type string) 26
|
|
3418
|
+
// _is type check boolean: _is(x,'string') ~50
|
|
3419
|
+
// _cw console.warn 8
|
|
3420
|
+
// _cl console.log 11
|
|
3421
|
+
// _ce console.error 4
|
|
3422
|
+
// _chp ComponentHandle.prototype 28 (defined after constructor)
|
|
3423
|
+
//
|
|
3424
|
+
// Note: document.createElement etc. are NOT aliased because they require
|
|
3425
|
+
// `this === document` and .bind() would add overhead on every call.
|
|
3426
|
+
// Console aliases use thin wrappers (not direct refs) so test monkey-
|
|
3427
|
+
// patching of console.warn/log/error continues to work.
|
|
3428
|
+
//
|
|
3429
|
+
// `typeof x` for UNDECLARED globals (window, document, process, require,
|
|
3430
|
+
// EventSource, navigator, Promise, __filename, import.meta) MUST stay as
|
|
3431
|
+
// raw `typeof` — calling _to(x) when x doesn't exist throws ReferenceError.
|
|
3432
|
+
//
|
|
3433
|
+
// ── v1 functional type helpers (kept for reference, not currently used) ──
|
|
3434
|
+
// _toa(x, type, trueVal, falseVal) — bw.typeAssign:
|
|
3435
|
+
// returns trueVal if _to(x)===type, else falseVal.
|
|
3436
|
+
// Replaces: (typeof x === 'string') ? A : B → _toa(x,'string',A,B)
|
|
3437
|
+
// _toc(x, type, trueVal, falseVal) — bw.typeConvert:
|
|
3438
|
+
// same as _toa but if trueVal/falseVal are functions, calls them with x.
|
|
3439
|
+
// Replaces: typeof x === 'string' ? fn(x) : default → _toc(x,'string',fn,default)
|
|
3440
|
+
// Uncomment if pattern frequency justifies them:
|
|
3441
|
+
// var _toa = function(x, t, y, n) { return _to(x) === t ? y : n; };
|
|
3442
|
+
// 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); };
|
|
3443
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
3444
|
+
var _hop = Object.prototype.hasOwnProperty;
|
|
3445
|
+
var _isA = Array.isArray;
|
|
3446
|
+
var _keys = Object.keys;
|
|
3447
|
+
var _to = typeOf; // imported from bitwrench-utils.js
|
|
3448
|
+
var _is = function(x, t) { var r = _to(x); return r === t || r.toLowerCase() === t; };
|
|
3449
|
+
// Console aliases use thin wrappers (not direct references) so that test
|
|
3450
|
+
// code can monkey-patch console.warn/log/error and the patches take effect.
|
|
3451
|
+
var _cw = function() { console.warn.apply(console, arguments); };
|
|
3452
|
+
var _cl = function() { console.log.apply(console, arguments); };
|
|
3453
|
+
var _ce = function() { console.error.apply(console, arguments); };
|
|
3454
|
+
|
|
3455
|
+
/**
|
|
3456
|
+
* Debug flag. When true, emits console.warn for silent binding failures
|
|
3457
|
+
* (missing paths, null refs, auto-created intermediate objects).
|
|
3458
|
+
* @type {boolean}
|
|
3459
|
+
*/
|
|
3460
|
+
bw.debug = false;
|
|
3461
|
+
|
|
3400
3462
|
/**
|
|
3401
3463
|
* Lazy-resolve Node.js `fs` module.
|
|
3402
3464
|
* Tries require('fs') first (available in CJS/UMD Node.js builds),
|
|
@@ -3544,7 +3606,7 @@
|
|
|
3544
3606
|
*/
|
|
3545
3607
|
bw._el = function(id) {
|
|
3546
3608
|
// Pass-through for DOM elements
|
|
3547
|
-
if (
|
|
3609
|
+
if (!_is(id, 'string')) return id || null;
|
|
3548
3610
|
if (!id) return null;
|
|
3549
3611
|
if (!bw._isBrowser) return null;
|
|
3550
3612
|
|
|
@@ -3640,7 +3702,7 @@
|
|
|
3640
3702
|
* // => '<b>Hello</b> & "world"'
|
|
3641
3703
|
*/
|
|
3642
3704
|
bw.escapeHTML = function(str) {
|
|
3643
|
-
if (
|
|
3705
|
+
if (!_is(str, 'string')) return '';
|
|
3644
3706
|
|
|
3645
3707
|
const escapeMap = {
|
|
3646
3708
|
'&': '&',
|
|
@@ -3713,7 +3775,7 @@
|
|
|
3713
3775
|
}
|
|
3714
3776
|
|
|
3715
3777
|
// Handle arrays of TACOs
|
|
3716
|
-
if (
|
|
3778
|
+
if (_isA(taco)) {
|
|
3717
3779
|
return taco.map(t => bw.html(t, options)).join('');
|
|
3718
3780
|
}
|
|
3719
3781
|
|
|
@@ -3736,15 +3798,15 @@
|
|
|
3736
3798
|
if (taco && taco._bwEach && options.state) {
|
|
3737
3799
|
var eachExpr = taco.expr.replace(/^\$\{|\}$/g, '');
|
|
3738
3800
|
var arr = bw._evaluatePath(options.state, eachExpr);
|
|
3739
|
-
if (!
|
|
3801
|
+
if (!_isA(arr)) return '';
|
|
3740
3802
|
return arr.map(function(item, idx) { return bw.html(taco.factory(item, idx), options); }).join('');
|
|
3741
3803
|
}
|
|
3742
3804
|
|
|
3743
3805
|
// Handle primitives and non-TACO objects
|
|
3744
|
-
if (
|
|
3806
|
+
if (!_is(taco, 'object') || !taco.t) {
|
|
3745
3807
|
var str = options.raw ? String(taco) : bw.escapeHTML(String(taco));
|
|
3746
3808
|
// Resolve template bindings if state provided
|
|
3747
|
-
if (options.state &&
|
|
3809
|
+
if (options.state && _is(str, 'string') && str.indexOf('${') >= 0) {
|
|
3748
3810
|
str = bw._resolveTemplate(str, options.state, !!options.compile);
|
|
3749
3811
|
}
|
|
3750
3812
|
return str;
|
|
@@ -3764,10 +3826,18 @@
|
|
|
3764
3826
|
// Skip null, undefined, false
|
|
3765
3827
|
if (value == null || value === false) continue;
|
|
3766
3828
|
|
|
3767
|
-
//
|
|
3768
|
-
if (key.startsWith('on'))
|
|
3829
|
+
// Serialize event handlers via funcRegister
|
|
3830
|
+
if (key.startsWith('on')) {
|
|
3831
|
+
if (_is(value, 'function')) {
|
|
3832
|
+
var fnId = bw.funcRegister(value);
|
|
3833
|
+
attrStr += ' ' + key + '="' + bw.funcGetDispatchStr(fnId, 'event') + '"';
|
|
3834
|
+
} else if (_is(value, 'string')) {
|
|
3835
|
+
attrStr += ' ' + key + '="' + bw.escapeHTML(value) + '"';
|
|
3836
|
+
}
|
|
3837
|
+
continue;
|
|
3838
|
+
}
|
|
3769
3839
|
|
|
3770
|
-
if (key === 'style' &&
|
|
3840
|
+
if (key === 'style' && _is(value, 'object')) {
|
|
3771
3841
|
// Convert style object to string
|
|
3772
3842
|
const styleStr = Object.entries(value)
|
|
3773
3843
|
.filter(([, v]) => v != null)
|
|
@@ -3778,7 +3848,7 @@
|
|
|
3778
3848
|
}
|
|
3779
3849
|
} else if (key === 'class') {
|
|
3780
3850
|
// Handle class as array or string
|
|
3781
|
-
const classStr =
|
|
3851
|
+
const classStr = _isA(value) ? value.filter(Boolean).join(' ') : String(value);
|
|
3782
3852
|
if (classStr) {
|
|
3783
3853
|
attrStr += ` class="${bw.escapeHTML(classStr)}"`;
|
|
3784
3854
|
}
|
|
@@ -3814,13 +3884,184 @@
|
|
|
3814
3884
|
// Process content recursively
|
|
3815
3885
|
let contentStr = content != null ? bw.html(content, options) : '';
|
|
3816
3886
|
// Resolve template bindings in content if state provided
|
|
3817
|
-
if (options.state &&
|
|
3887
|
+
if (options.state && _is(contentStr, 'string') && contentStr.indexOf('${') >= 0) {
|
|
3818
3888
|
contentStr = bw._resolveTemplate(contentStr, options.state, !!options.compile);
|
|
3819
3889
|
}
|
|
3820
3890
|
|
|
3821
3891
|
return `<${tag}${attrStr}>${contentStr}</${tag}>`;
|
|
3822
3892
|
};
|
|
3823
3893
|
|
|
3894
|
+
/**
|
|
3895
|
+
* Generate a complete, self-contained HTML document from TACO content.
|
|
3896
|
+
*
|
|
3897
|
+
* Produces a full `<!DOCTYPE html>` page with configurable runtime injection,
|
|
3898
|
+
* func registry emission (so serialized event handlers work), optional theme,
|
|
3899
|
+
* and extra head elements. Designed for static site generation, offline/airgapped
|
|
3900
|
+
* use, and the "static site that isn't static" workflow.
|
|
3901
|
+
*
|
|
3902
|
+
* @param {Object} [opts={}] - Page options
|
|
3903
|
+
* @param {Object|string|Array} [opts.body=''] - Body content: TACO, string, or array
|
|
3904
|
+
* @param {string} [opts.title='bitwrench'] - Page title
|
|
3905
|
+
* @param {Object} [opts.state] - State for ${expr} resolution in bw.html()
|
|
3906
|
+
* @param {string} [opts.runtime='shim'] - Runtime level: 'inline'|'cdn'|'shim'|'none'
|
|
3907
|
+
* @param {string} [opts.css=''] - Additional CSS for <style> block
|
|
3908
|
+
* @param {string|Object} [opts.theme=null] - Theme preset name or config object
|
|
3909
|
+
* @param {Array} [opts.head=[]] - Extra TACO elements rendered into <head>
|
|
3910
|
+
* @param {string} [opts.favicon=''] - Favicon URL
|
|
3911
|
+
* @param {string} [opts.lang='en'] - HTML lang attribute
|
|
3912
|
+
* @returns {string} Complete HTML document string
|
|
3913
|
+
* @category DOM Generation
|
|
3914
|
+
* @see bw.html
|
|
3915
|
+
* @example
|
|
3916
|
+
* bw.htmlPage({
|
|
3917
|
+
* title: 'My App',
|
|
3918
|
+
* body: { t: 'h1', c: 'Hello World' },
|
|
3919
|
+
* runtime: 'shim'
|
|
3920
|
+
* })
|
|
3921
|
+
*/
|
|
3922
|
+
bw.htmlPage = function(opts) {
|
|
3923
|
+
opts = opts || {};
|
|
3924
|
+
var title = opts.title || 'bitwrench';
|
|
3925
|
+
var body = opts.body || '';
|
|
3926
|
+
var state = opts.state || undefined;
|
|
3927
|
+
var runtime = opts.runtime || 'shim';
|
|
3928
|
+
var css = opts.css || '';
|
|
3929
|
+
var theme = opts.theme || null;
|
|
3930
|
+
var headExtra = opts.head || [];
|
|
3931
|
+
var favicon = opts.favicon || '';
|
|
3932
|
+
var lang = opts.lang || 'en';
|
|
3933
|
+
|
|
3934
|
+
// Snapshot funcRegistry counter before rendering
|
|
3935
|
+
var fnCounterBefore = bw._fnIDCounter;
|
|
3936
|
+
|
|
3937
|
+
// Render body content
|
|
3938
|
+
var bodyHTML = '';
|
|
3939
|
+
if (_is(body, 'string')) {
|
|
3940
|
+
bodyHTML = body;
|
|
3941
|
+
} else {
|
|
3942
|
+
var htmlOpts = {};
|
|
3943
|
+
if (state) htmlOpts.state = state;
|
|
3944
|
+
bodyHTML = bw.html(body, htmlOpts);
|
|
3945
|
+
}
|
|
3946
|
+
|
|
3947
|
+
// Collect functions registered during this render
|
|
3948
|
+
var fnCounterAfter = bw._fnIDCounter;
|
|
3949
|
+
var registryEntries = '';
|
|
3950
|
+
for (var i = fnCounterBefore; i < fnCounterAfter; i++) {
|
|
3951
|
+
var fnKey = 'bw_fn_' + i;
|
|
3952
|
+
if (bw._fnRegistry[fnKey]) {
|
|
3953
|
+
registryEntries += 'bw._fnRegistry[\'' + fnKey + '\']=' +
|
|
3954
|
+
bw._fnRegistry[fnKey].toString() + ';\n';
|
|
3955
|
+
}
|
|
3956
|
+
}
|
|
3957
|
+
|
|
3958
|
+
// Build runtime script for <head>
|
|
3959
|
+
var runtimeHead = '';
|
|
3960
|
+
if (runtime === 'inline') {
|
|
3961
|
+
// Read UMD bundle synchronously if in Node.js
|
|
3962
|
+
var umdSource = null;
|
|
3963
|
+
if (bw._isNode) {
|
|
3964
|
+
try {
|
|
3965
|
+
var fs = (typeof require === 'function') ? require('fs') : null;
|
|
3966
|
+
var pathMod = (typeof require === 'function') ? require('path') : null;
|
|
3967
|
+
if (fs && pathMod) {
|
|
3968
|
+
// Resolve dist/ relative to this source file
|
|
3969
|
+
var srcDir = '';
|
|
3970
|
+
try { srcDir = pathMod.dirname((typeof __filename !== 'undefined') ? __filename : ''); }
|
|
3971
|
+
catch(e2) { /* ESM: __filename not available */ }
|
|
3972
|
+
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-lean.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-lean.umd.js', document.baseURI).href))) {
|
|
3973
|
+
var url = (typeof require === 'function') ? require('url') : null;
|
|
3974
|
+
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-lean.umd.js', document.baseURI).href))));
|
|
3975
|
+
}
|
|
3976
|
+
if (srcDir) {
|
|
3977
|
+
var distPath = pathMod.resolve(srcDir, '../dist/bitwrench.umd.min.js');
|
|
3978
|
+
umdSource = fs.readFileSync(distPath, 'utf8');
|
|
3979
|
+
}
|
|
3980
|
+
}
|
|
3981
|
+
} catch(e) { /* fall through */ }
|
|
3982
|
+
}
|
|
3983
|
+
if (umdSource) {
|
|
3984
|
+
runtimeHead = '<script>' + umdSource + '</script>';
|
|
3985
|
+
} else {
|
|
3986
|
+
// Fallback to shim in browser or if dist not available
|
|
3987
|
+
runtimeHead = '<script>' + bw._FUNC_REGISTRY_SHIM + '</script>';
|
|
3988
|
+
}
|
|
3989
|
+
} else if (runtime === 'cdn') {
|
|
3990
|
+
runtimeHead = '<script src="https://cdn.jsdelivr.net/npm/bitwrench@2/dist/bitwrench.umd.min.js"></script>';
|
|
3991
|
+
} else if (runtime === 'shim') {
|
|
3992
|
+
runtimeHead = '<script>' + bw._FUNC_REGISTRY_SHIM + '</script>';
|
|
3993
|
+
}
|
|
3994
|
+
// runtime === 'none' → empty
|
|
3995
|
+
|
|
3996
|
+
// Theme CSS
|
|
3997
|
+
var themeCSS = '';
|
|
3998
|
+
if (theme) {
|
|
3999
|
+
var themeConfig = _is(theme, 'string')
|
|
4000
|
+
? (THEME_PRESETS[theme.toLowerCase()] || null)
|
|
4001
|
+
: theme;
|
|
4002
|
+
if (themeConfig) {
|
|
4003
|
+
var themeResult = bw.generateTheme('', Object.assign({}, themeConfig, { inject: false }));
|
|
4004
|
+
themeCSS = themeResult.css;
|
|
4005
|
+
}
|
|
4006
|
+
}
|
|
4007
|
+
|
|
4008
|
+
// Extra <head> elements
|
|
4009
|
+
var headHTML = '';
|
|
4010
|
+
if (_isA(headExtra) && headExtra.length > 0) {
|
|
4011
|
+
headHTML = headExtra.map(function(el) { return bw.html(el); }).join('\n');
|
|
4012
|
+
}
|
|
4013
|
+
|
|
4014
|
+
// Favicon
|
|
4015
|
+
var faviconTag = '';
|
|
4016
|
+
if (favicon) {
|
|
4017
|
+
var safeFavicon = favicon.replace(/[&<>"']/g, function(c) {
|
|
4018
|
+
return ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' })[c];
|
|
4019
|
+
});
|
|
4020
|
+
faviconTag = '<link rel="icon" href="' + safeFavicon + '">';
|
|
4021
|
+
}
|
|
4022
|
+
|
|
4023
|
+
// Escaped title
|
|
4024
|
+
var safeTitle = bw.escapeHTML(title);
|
|
4025
|
+
|
|
4026
|
+
// Combine all CSS
|
|
4027
|
+
var allCSS = (themeCSS ? themeCSS + '\n' : '') + css;
|
|
4028
|
+
|
|
4029
|
+
// Body-end script: registry entries + optional loadDefaultStyles
|
|
4030
|
+
var bodyEndScript = '';
|
|
4031
|
+
var bodyEndParts = [];
|
|
4032
|
+
if (registryEntries) {
|
|
4033
|
+
bodyEndParts.push(registryEntries);
|
|
4034
|
+
}
|
|
4035
|
+
if (runtime === 'inline' || runtime === 'cdn') {
|
|
4036
|
+
bodyEndParts.push('if(typeof bw!=="undefined"){bw.loadDefaultStyles();}');
|
|
4037
|
+
}
|
|
4038
|
+
if (bodyEndParts.length > 0) {
|
|
4039
|
+
bodyEndScript = '<script>\n' + bodyEndParts.join('\n') + '\n</script>';
|
|
4040
|
+
}
|
|
4041
|
+
|
|
4042
|
+
// Assemble document
|
|
4043
|
+
var parts = [
|
|
4044
|
+
'<!DOCTYPE html>',
|
|
4045
|
+
'<html lang="' + lang + '">',
|
|
4046
|
+
'<head>',
|
|
4047
|
+
'<meta charset="UTF-8">',
|
|
4048
|
+
'<meta name="viewport" content="width=device-width, initial-scale=1">'
|
|
4049
|
+
];
|
|
4050
|
+
parts.push('<title>' + safeTitle + '</title>');
|
|
4051
|
+
if (faviconTag) parts.push(faviconTag);
|
|
4052
|
+
if (runtimeHead) parts.push(runtimeHead);
|
|
4053
|
+
if (headHTML) parts.push(headHTML);
|
|
4054
|
+
if (allCSS) parts.push('<style>' + allCSS + '</style>');
|
|
4055
|
+
parts.push('</head>');
|
|
4056
|
+
parts.push('<body>');
|
|
4057
|
+
parts.push(bodyHTML);
|
|
4058
|
+
if (bodyEndScript) parts.push(bodyEndScript);
|
|
4059
|
+
parts.push('</body>');
|
|
4060
|
+
parts.push('</html>');
|
|
4061
|
+
|
|
4062
|
+
return parts.join('\n');
|
|
4063
|
+
};
|
|
4064
|
+
|
|
3824
4065
|
/**
|
|
3825
4066
|
* Create a live DOM element from a TACO object (browser only).
|
|
3826
4067
|
*
|
|
@@ -3865,7 +4106,7 @@
|
|
|
3865
4106
|
}
|
|
3866
4107
|
|
|
3867
4108
|
// Handle text nodes
|
|
3868
|
-
if (
|
|
4109
|
+
if (!_is(taco, 'object') || !taco.t) {
|
|
3869
4110
|
return document.createTextNode(String(taco));
|
|
3870
4111
|
}
|
|
3871
4112
|
|
|
@@ -3878,16 +4119,16 @@
|
|
|
3878
4119
|
for (const [key, value] of Object.entries(attrs)) {
|
|
3879
4120
|
if (value == null || value === false) continue;
|
|
3880
4121
|
|
|
3881
|
-
if (key === 'style' &&
|
|
4122
|
+
if (key === 'style' && _is(value, 'object')) {
|
|
3882
4123
|
// Apply styles directly
|
|
3883
4124
|
Object.assign(el.style, value);
|
|
3884
4125
|
} else if (key === 'class') {
|
|
3885
4126
|
// Handle class as array or string
|
|
3886
|
-
const classStr =
|
|
4127
|
+
const classStr = _isA(value) ? value.filter(Boolean).join(' ') : String(value);
|
|
3887
4128
|
if (classStr) {
|
|
3888
4129
|
el.className = classStr;
|
|
3889
4130
|
}
|
|
3890
|
-
} else if (key.startsWith('on') &&
|
|
4131
|
+
} else if (key.startsWith('on') && _is(value, 'function')) {
|
|
3891
4132
|
// Event handlers
|
|
3892
4133
|
const eventName = key.slice(2).toLowerCase();
|
|
3893
4134
|
el.addEventListener(eventName, value);
|
|
@@ -3907,7 +4148,7 @@
|
|
|
3907
4148
|
// Children with data-bw_id or id attributes get local refs on the parent,
|
|
3908
4149
|
// so o.render functions can access them without any DOM lookup.
|
|
3909
4150
|
if (content != null) {
|
|
3910
|
-
if (
|
|
4151
|
+
if (_isA(content)) {
|
|
3911
4152
|
content.forEach(child => {
|
|
3912
4153
|
if (child != null) {
|
|
3913
4154
|
// Handle ComponentHandle in content arrays (Level 2 children)
|
|
@@ -3927,20 +4168,20 @@
|
|
|
3927
4168
|
if (childEl._bw_refs) {
|
|
3928
4169
|
if (!el._bw_refs) el._bw_refs = {};
|
|
3929
4170
|
for (var rk in childEl._bw_refs) {
|
|
3930
|
-
if (
|
|
4171
|
+
if (_hop.call(childEl._bw_refs, rk)) {
|
|
3931
4172
|
el._bw_refs[rk] = childEl._bw_refs[rk];
|
|
3932
4173
|
}
|
|
3933
4174
|
}
|
|
3934
4175
|
}
|
|
3935
4176
|
}
|
|
3936
4177
|
});
|
|
3937
|
-
} else if (
|
|
4178
|
+
} else if (_is(content, 'object') && content.__bw_raw) {
|
|
3938
4179
|
// Raw HTML content — inject via innerHTML
|
|
3939
4180
|
el.innerHTML = content.v;
|
|
3940
4181
|
} else if (content._bwComponent === true) {
|
|
3941
4182
|
// Single ComponentHandle as content
|
|
3942
4183
|
content.mount(el);
|
|
3943
|
-
} else if (
|
|
4184
|
+
} else if (_is(content, 'object') && content.t) {
|
|
3944
4185
|
var childEl = bw.createDOM(content, options);
|
|
3945
4186
|
el.appendChild(childEl);
|
|
3946
4187
|
var childBwId = content.a ? (content.a['data-bw_id'] || content.a.id) : null;
|
|
@@ -3951,7 +4192,7 @@
|
|
|
3951
4192
|
if (childEl._bw_refs) {
|
|
3952
4193
|
if (!el._bw_refs) el._bw_refs = {};
|
|
3953
4194
|
for (var rk in childEl._bw_refs) {
|
|
3954
|
-
if (
|
|
4195
|
+
if (_hop.call(childEl._bw_refs, rk)) {
|
|
3955
4196
|
el._bw_refs[rk] = childEl._bw_refs[rk];
|
|
3956
4197
|
}
|
|
3957
4198
|
}
|
|
@@ -3984,7 +4225,7 @@
|
|
|
3984
4225
|
el._bw_render = opts.render;
|
|
3985
4226
|
|
|
3986
4227
|
if (opts.mounted) {
|
|
3987
|
-
|
|
4228
|
+
_cw('bw.createDOM: o.render and o.mounted are mutually exclusive. o.render wins.');
|
|
3988
4229
|
}
|
|
3989
4230
|
|
|
3990
4231
|
// Queue initial render (same timing as mounted)
|
|
@@ -4057,7 +4298,7 @@
|
|
|
4057
4298
|
const targetEl = bw._el(target);
|
|
4058
4299
|
|
|
4059
4300
|
if (!targetEl) {
|
|
4060
|
-
|
|
4301
|
+
_ce('bw.DOM: Target element not found:', target);
|
|
4061
4302
|
return null;
|
|
4062
4303
|
}
|
|
4063
4304
|
|
|
@@ -4097,7 +4338,7 @@
|
|
|
4097
4338
|
targetEl.appendChild(taco.element);
|
|
4098
4339
|
}
|
|
4099
4340
|
// Handle arrays
|
|
4100
|
-
else if (
|
|
4341
|
+
else if (_isA(taco)) {
|
|
4101
4342
|
taco.forEach(t => {
|
|
4102
4343
|
if (t != null) {
|
|
4103
4344
|
if (t._bwComponent === true) {
|
|
@@ -4133,7 +4374,7 @@
|
|
|
4133
4374
|
bw.compileProps = function(handle, props = {}) {
|
|
4134
4375
|
const compiledProps = {};
|
|
4135
4376
|
|
|
4136
|
-
|
|
4377
|
+
_keys(props).forEach(key => {
|
|
4137
4378
|
// Create getter/setter for each prop
|
|
4138
4379
|
Object.defineProperty(compiledProps, key, {
|
|
4139
4380
|
get() {
|
|
@@ -4451,17 +4692,17 @@
|
|
|
4451
4692
|
if (attr) {
|
|
4452
4693
|
// Patch an attribute
|
|
4453
4694
|
el.setAttribute(attr, String(content));
|
|
4454
|
-
} else if (
|
|
4695
|
+
} else if (_isA(content)) {
|
|
4455
4696
|
// Patch with array of children (strings and/or TACOs)
|
|
4456
4697
|
el.innerHTML = '';
|
|
4457
4698
|
content.forEach(function(item) {
|
|
4458
|
-
if (
|
|
4699
|
+
if (_is(item, 'string') || _is(item, 'number')) {
|
|
4459
4700
|
el.appendChild(document.createTextNode(String(item)));
|
|
4460
4701
|
} else if (item && item.t) {
|
|
4461
4702
|
el.appendChild(bw.createDOM(item));
|
|
4462
4703
|
}
|
|
4463
4704
|
});
|
|
4464
|
-
} else if (
|
|
4705
|
+
} else if (_is(content, 'object') && content.t) {
|
|
4465
4706
|
// Patch with a TACO — replace children
|
|
4466
4707
|
el.innerHTML = '';
|
|
4467
4708
|
el.appendChild(bw.createDOM(content));
|
|
@@ -4492,7 +4733,7 @@
|
|
|
4492
4733
|
bw.patchAll = function(patches) {
|
|
4493
4734
|
var results = {};
|
|
4494
4735
|
for (var id in patches) {
|
|
4495
|
-
if (
|
|
4736
|
+
if (_hop.call(patches, id)) {
|
|
4496
4737
|
results[id] = bw.patch(id, patches[id]);
|
|
4497
4738
|
}
|
|
4498
4739
|
}
|
|
@@ -4589,7 +4830,7 @@
|
|
|
4589
4830
|
snapshot[i].handler(detail);
|
|
4590
4831
|
called++;
|
|
4591
4832
|
} catch (err) {
|
|
4592
|
-
|
|
4833
|
+
_cw('bw.pub: subscriber error on topic "' + topic + '":', err);
|
|
4593
4834
|
}
|
|
4594
4835
|
}
|
|
4595
4836
|
return called;
|
|
@@ -4685,8 +4926,8 @@
|
|
|
4685
4926
|
* @see bw.funcGetDispatchStr
|
|
4686
4927
|
*/
|
|
4687
4928
|
bw.funcRegister = function(fn, name) {
|
|
4688
|
-
if (
|
|
4689
|
-
var fnID = (
|
|
4929
|
+
if (!_is(fn, 'function')) return '';
|
|
4930
|
+
var fnID = (_is(name, 'string') && name.length > 0) ? name : ('bw_fn_' + bw._fnIDCounter++);
|
|
4690
4931
|
bw._fnRegistry[fnID] = fn;
|
|
4691
4932
|
return fnID;
|
|
4692
4933
|
};
|
|
@@ -4705,7 +4946,7 @@
|
|
|
4705
4946
|
bw.funcGetById = function(name, errFn) {
|
|
4706
4947
|
name = String(name);
|
|
4707
4948
|
if (name in bw._fnRegistry) return bw._fnRegistry[name];
|
|
4708
|
-
return (
|
|
4949
|
+
return _is(errFn, 'function') ? errFn : function() { _cw('bw.funcGetById: unregistered fn "' + name + '"'); };
|
|
4709
4950
|
};
|
|
4710
4951
|
|
|
4711
4952
|
/**
|
|
@@ -4746,13 +4987,30 @@
|
|
|
4746
4987
|
bw.funcGetRegistry = function() {
|
|
4747
4988
|
var copy = {};
|
|
4748
4989
|
for (var k in bw._fnRegistry) {
|
|
4749
|
-
if (
|
|
4990
|
+
if (_hop.call(bw._fnRegistry, k)) {
|
|
4750
4991
|
copy[k] = bw._fnRegistry[k];
|
|
4751
4992
|
}
|
|
4752
4993
|
}
|
|
4753
4994
|
return copy;
|
|
4754
4995
|
};
|
|
4755
4996
|
|
|
4997
|
+
/**
|
|
4998
|
+
* Minimal runtime shim for funcRegister dispatch in static HTML.
|
|
4999
|
+
* When embedded in a `<script>` tag, provides just enough infrastructure
|
|
5000
|
+
* for `bw.funcGetById()` calls to resolve. The actual function bodies
|
|
5001
|
+
* are emitted separately as `bw._fnRegistry['bw_fn_X'] = ...;` assignments.
|
|
5002
|
+
* @type {string}
|
|
5003
|
+
* @category Function Registry
|
|
5004
|
+
*/
|
|
5005
|
+
bw._FUNC_REGISTRY_SHIM = '(function(){var bw=window.bw||(window.bw={});' +
|
|
5006
|
+
'if(!bw._fnRegistry)bw._fnRegistry={};' +
|
|
5007
|
+
'bw.funcGetById=function(n){return bw._fnRegistry[n]||function(){' +
|
|
5008
|
+
'console.warn("bw: unregistered fn "+n)};};' +
|
|
5009
|
+
'bw.funcRegister=function(fn,name){' +
|
|
5010
|
+
'var id=name||("bw_fn_"+(bw._fnIDCounter=(bw._fnIDCounter||0)+1));' +
|
|
5011
|
+
'bw._fnRegistry[id]=fn;return id;};' +
|
|
5012
|
+
'window.bw=bw;})();';
|
|
5013
|
+
|
|
4756
5014
|
// ===================================================================================
|
|
4757
5015
|
// Template Binding Utilities
|
|
4758
5016
|
// ===================================================================================
|
|
@@ -4780,7 +5038,10 @@
|
|
|
4780
5038
|
var parts = path.split('.');
|
|
4781
5039
|
var val = state;
|
|
4782
5040
|
for (var i = 0; i < parts.length; i++) {
|
|
4783
|
-
if (val == null)
|
|
5041
|
+
if (val == null) {
|
|
5042
|
+
if (bw.debug) _cw('bw.debug: _evaluatePath — null at key "' + parts[i] + '" in path "' + path + '"');
|
|
5043
|
+
return '';
|
|
5044
|
+
}
|
|
4784
5045
|
val = val[parts[i]];
|
|
4785
5046
|
}
|
|
4786
5047
|
return (val == null) ? '' : val;
|
|
@@ -4800,7 +5061,7 @@
|
|
|
4800
5061
|
*/
|
|
4801
5062
|
bw._compiledExprs = {};
|
|
4802
5063
|
bw._resolveTemplate = function(str, state, compile) {
|
|
4803
|
-
if (
|
|
5064
|
+
if (!_is(str, 'string') || str.indexOf('${') < 0) return str;
|
|
4804
5065
|
var bindings = bw._parseBindings(str);
|
|
4805
5066
|
if (bindings.length === 0) return str;
|
|
4806
5067
|
|
|
@@ -4822,6 +5083,7 @@
|
|
|
4822
5083
|
try {
|
|
4823
5084
|
val = bw._compiledExprs[b.expr](state);
|
|
4824
5085
|
} catch (e) {
|
|
5086
|
+
if (bw.debug) _cw('bw.debug: _resolveTemplate — Tier 2 eval failed for "${' + b.expr + '}":', e.message);
|
|
4825
5087
|
val = '';
|
|
4826
5088
|
}
|
|
4827
5089
|
} else {
|
|
@@ -4930,7 +5192,7 @@
|
|
|
4930
5192
|
this._state = {};
|
|
4931
5193
|
if (o.state) {
|
|
4932
5194
|
for (var k in o.state) {
|
|
4933
|
-
if (
|
|
5195
|
+
if (_hop.call(o.state, k)) {
|
|
4934
5196
|
this._state[k] = o.state[k];
|
|
4935
5197
|
}
|
|
4936
5198
|
}
|
|
@@ -4939,7 +5201,7 @@
|
|
|
4939
5201
|
this._actions = {};
|
|
4940
5202
|
if (o.actions) {
|
|
4941
5203
|
for (var k2 in o.actions) {
|
|
4942
|
-
if (
|
|
5204
|
+
if (_hop.call(o.actions, k2)) {
|
|
4943
5205
|
this._actions[k2] = o.actions[k2];
|
|
4944
5206
|
}
|
|
4945
5207
|
}
|
|
@@ -4949,7 +5211,7 @@
|
|
|
4949
5211
|
if (o.methods) {
|
|
4950
5212
|
var self = this;
|
|
4951
5213
|
for (var k3 in o.methods) {
|
|
4952
|
-
if (
|
|
5214
|
+
if (_hop.call(o.methods, k3)) {
|
|
4953
5215
|
this._methods[k3] = o.methods[k3];
|
|
4954
5216
|
(function(methodName, methodFn) {
|
|
4955
5217
|
self[methodName] = function() {
|
|
@@ -4982,14 +5244,23 @@
|
|
|
4982
5244
|
this._compile = !!o.compile;
|
|
4983
5245
|
this._bw_refs = {};
|
|
4984
5246
|
this._refCounter = 0;
|
|
5247
|
+
// Child component ownership (Bug #5)
|
|
5248
|
+
this._children = [];
|
|
5249
|
+
this._parent = null;
|
|
5250
|
+
// Factory metadata for BCCL rebuild (Bug #6)
|
|
5251
|
+
this._factory = taco._bwFactory || null;
|
|
4985
5252
|
}
|
|
4986
5253
|
|
|
5254
|
+
// Short alias for ComponentHandle.prototype (see alias block at top of file).
|
|
5255
|
+
// 28 method definitions × 25 chars = ~700B raw savings in minified output.
|
|
5256
|
+
var _chp = ComponentHandle.prototype;
|
|
5257
|
+
|
|
4987
5258
|
// ── State Methods ──
|
|
4988
5259
|
|
|
4989
5260
|
/**
|
|
4990
5261
|
* Get a state value. Dot-path supported: `get('user.name')`
|
|
4991
5262
|
*/
|
|
4992
|
-
|
|
5263
|
+
_chp.get = function(key) {
|
|
4993
5264
|
return bw._evaluatePath(this._state, key);
|
|
4994
5265
|
};
|
|
4995
5266
|
|
|
@@ -4999,12 +5270,13 @@
|
|
|
4999
5270
|
* @param {*} value - New value
|
|
5000
5271
|
* @param {Object} [opts] - Options. `{sync: true}` for immediate flush.
|
|
5001
5272
|
*/
|
|
5002
|
-
|
|
5273
|
+
_chp.set = function(key, value, opts) {
|
|
5003
5274
|
// Dot-path set
|
|
5004
5275
|
var parts = key.split('.');
|
|
5005
5276
|
var obj = this._state;
|
|
5006
5277
|
for (var i = 0; i < parts.length - 1; i++) {
|
|
5007
|
-
if (obj[parts[i]]
|
|
5278
|
+
if (!_is(obj[parts[i]], 'object')) {
|
|
5279
|
+
if (bw.debug) _cw('bw.debug: set() — auto-creating intermediate "' + parts[i] + '" in path "' + key + '"');
|
|
5008
5280
|
obj[parts[i]] = {};
|
|
5009
5281
|
}
|
|
5010
5282
|
obj = obj[parts[i]];
|
|
@@ -5024,10 +5296,10 @@
|
|
|
5024
5296
|
/**
|
|
5025
5297
|
* Get a shallow clone of the full state.
|
|
5026
5298
|
*/
|
|
5027
|
-
|
|
5299
|
+
_chp.getState = function() {
|
|
5028
5300
|
var clone = {};
|
|
5029
5301
|
for (var k in this._state) {
|
|
5030
|
-
if (
|
|
5302
|
+
if (_hop.call(this._state, k)) {
|
|
5031
5303
|
clone[k] = this._state[k];
|
|
5032
5304
|
}
|
|
5033
5305
|
}
|
|
@@ -5039,9 +5311,9 @@
|
|
|
5039
5311
|
* @param {Object} updates - Key-value pairs to merge
|
|
5040
5312
|
* @param {Object} [opts] - Options. `{sync: true}` for immediate flush.
|
|
5041
5313
|
*/
|
|
5042
|
-
|
|
5314
|
+
_chp.setState = function(updates, opts) {
|
|
5043
5315
|
for (var k in updates) {
|
|
5044
|
-
if (
|
|
5316
|
+
if (_hop.call(updates, k)) {
|
|
5045
5317
|
this._state[k] = updates[k];
|
|
5046
5318
|
this._dirtyKeys[k] = true;
|
|
5047
5319
|
}
|
|
@@ -5058,9 +5330,9 @@
|
|
|
5058
5330
|
/**
|
|
5059
5331
|
* Push a value onto an array in state. Clones the array.
|
|
5060
5332
|
*/
|
|
5061
|
-
|
|
5333
|
+
_chp.push = function(key, val) {
|
|
5062
5334
|
var arr = this.get(key);
|
|
5063
|
-
var newArr =
|
|
5335
|
+
var newArr = _isA(arr) ? arr.slice() : [];
|
|
5064
5336
|
newArr.push(val);
|
|
5065
5337
|
this.set(key, newArr);
|
|
5066
5338
|
};
|
|
@@ -5068,9 +5340,9 @@
|
|
|
5068
5340
|
/**
|
|
5069
5341
|
* Splice an array in state. Clones the array.
|
|
5070
5342
|
*/
|
|
5071
|
-
|
|
5343
|
+
_chp.splice = function(key, start, deleteCount) {
|
|
5072
5344
|
var arr = this.get(key);
|
|
5073
|
-
var newArr =
|
|
5345
|
+
var newArr = _isA(arr) ? arr.slice() : [];
|
|
5074
5346
|
var args = [start, deleteCount].concat(Array.prototype.slice.call(arguments, 3));
|
|
5075
5347
|
Array.prototype.splice.apply(newArr, args);
|
|
5076
5348
|
this.set(key, newArr);
|
|
@@ -5078,7 +5350,7 @@
|
|
|
5078
5350
|
|
|
5079
5351
|
// ── Scheduling ──
|
|
5080
5352
|
|
|
5081
|
-
|
|
5353
|
+
_chp._scheduleDirty = function() {
|
|
5082
5354
|
if (!this._scheduled) {
|
|
5083
5355
|
this._scheduled = true;
|
|
5084
5356
|
bw._dirtyComponents.push(this);
|
|
@@ -5093,17 +5365,17 @@
|
|
|
5093
5365
|
* Creates binding descriptors with refIds for targeted DOM updates.
|
|
5094
5366
|
* @private
|
|
5095
5367
|
*/
|
|
5096
|
-
|
|
5368
|
+
_chp._compileBindings = function() {
|
|
5097
5369
|
this._bindings = [];
|
|
5098
5370
|
this._refCounter = 0;
|
|
5099
|
-
var stateKeys =
|
|
5371
|
+
var stateKeys = _keys(this._state);
|
|
5100
5372
|
var self = this;
|
|
5101
5373
|
|
|
5102
5374
|
function walkTaco(taco, path) {
|
|
5103
|
-
if (taco
|
|
5375
|
+
if (!_is(taco, 'object') || !taco.t) return taco;
|
|
5104
5376
|
|
|
5105
5377
|
// Check content for bindings
|
|
5106
|
-
if (
|
|
5378
|
+
if (_is(taco.c, 'string') && taco.c.indexOf('${') >= 0) {
|
|
5107
5379
|
var refId = 'bw_ref_' + self._refCounter++;
|
|
5108
5380
|
var parsed = bw._parseBindings(taco.c);
|
|
5109
5381
|
var deps = [];
|
|
@@ -5125,10 +5397,10 @@
|
|
|
5125
5397
|
// Check attributes for bindings
|
|
5126
5398
|
if (taco.a) {
|
|
5127
5399
|
for (var attrName in taco.a) {
|
|
5128
|
-
if (!
|
|
5400
|
+
if (!_hop.call(taco.a, attrName)) continue;
|
|
5129
5401
|
if (attrName === 'data-bw_ref') continue;
|
|
5130
5402
|
var attrVal = taco.a[attrName];
|
|
5131
|
-
if (
|
|
5403
|
+
if (_is(attrVal, 'string') && attrVal.indexOf('${') >= 0) {
|
|
5132
5404
|
var refId2 = 'bw_ref_' + self._refCounter++;
|
|
5133
5405
|
var parsed2 = bw._parseBindings(attrVal);
|
|
5134
5406
|
var deps2 = [];
|
|
@@ -5154,9 +5426,27 @@
|
|
|
5154
5426
|
}
|
|
5155
5427
|
|
|
5156
5428
|
// Recurse into children
|
|
5157
|
-
if (
|
|
5429
|
+
if (_isA(taco.c)) {
|
|
5158
5430
|
for (var i = 0; i < taco.c.length; i++) {
|
|
5159
|
-
|
|
5431
|
+
// Wrap string children with ${expr} in a span so patches target the span, not the parent
|
|
5432
|
+
if (_is(taco.c[i], 'string') && taco.c[i].indexOf('${') >= 0) {
|
|
5433
|
+
var mixedRefId = 'bw_ref_' + self._refCounter++;
|
|
5434
|
+
var mixedParsed = bw._parseBindings(taco.c[i]);
|
|
5435
|
+
var mixedDeps = [];
|
|
5436
|
+
for (var mi = 0; mi < mixedParsed.length; mi++) {
|
|
5437
|
+
mixedDeps = mixedDeps.concat(bw._extractDeps(mixedParsed[mi].expr, stateKeys));
|
|
5438
|
+
}
|
|
5439
|
+
self._bindings.push({
|
|
5440
|
+
expr: taco.c[i],
|
|
5441
|
+
type: 'content',
|
|
5442
|
+
refId: mixedRefId,
|
|
5443
|
+
deps: mixedDeps,
|
|
5444
|
+
template: taco.c[i]
|
|
5445
|
+
});
|
|
5446
|
+
// Replace string with a span wrapper so textContent targets the span only
|
|
5447
|
+
taco.c[i] = { t: 'span', a: { 'data-bw_ref': mixedRefId, style: 'display:contents' }, c: taco.c[i] };
|
|
5448
|
+
}
|
|
5449
|
+
if (_is(taco.c[i], 'object') && taco.c[i].t) {
|
|
5160
5450
|
walkTaco(taco.c[i], path.concat(i));
|
|
5161
5451
|
}
|
|
5162
5452
|
// Handle bw.when/bw.each markers
|
|
@@ -5191,7 +5481,7 @@
|
|
|
5191
5481
|
taco.c[i]._refId = eachRefId;
|
|
5192
5482
|
}
|
|
5193
5483
|
}
|
|
5194
|
-
} else if (taco.c
|
|
5484
|
+
} else if (_is(taco.c, 'object') && taco.c.t) {
|
|
5195
5485
|
walkTaco(taco.c, path.concat(0));
|
|
5196
5486
|
}
|
|
5197
5487
|
|
|
@@ -5207,7 +5497,7 @@
|
|
|
5207
5497
|
* Build ref map from the live DOM after createDOM.
|
|
5208
5498
|
* @private
|
|
5209
5499
|
*/
|
|
5210
|
-
|
|
5500
|
+
_chp._collectRefs = function() {
|
|
5211
5501
|
this._bw_refs = {};
|
|
5212
5502
|
if (!this.element) return;
|
|
5213
5503
|
var els = this.element.querySelectorAll('[data-bw_ref]');
|
|
@@ -5228,7 +5518,7 @@
|
|
|
5228
5518
|
* Creates DOM, compiles bindings, registers actions, and calls lifecycle hooks.
|
|
5229
5519
|
* @param {Element} parentEl - DOM element to mount into
|
|
5230
5520
|
*/
|
|
5231
|
-
|
|
5521
|
+
_chp.mount = function(parentEl) {
|
|
5232
5522
|
// willMount hook
|
|
5233
5523
|
if (this._hooks.willMount) this._hooks.willMount(this);
|
|
5234
5524
|
|
|
@@ -5250,7 +5540,7 @@
|
|
|
5250
5540
|
// Register named actions in function registry
|
|
5251
5541
|
var self = this;
|
|
5252
5542
|
for (var actionName in this._actions) {
|
|
5253
|
-
if (
|
|
5543
|
+
if (_hop.call(this._actions, actionName)) {
|
|
5254
5544
|
var registeredName = this._bwId + '_' + actionName;
|
|
5255
5545
|
(function(aName) {
|
|
5256
5546
|
bw.funcRegister(function(evt) {
|
|
@@ -5269,6 +5559,11 @@
|
|
|
5269
5559
|
this.element = bw.createDOM(tacoForDOM);
|
|
5270
5560
|
this.element._bwComponentHandle = this;
|
|
5271
5561
|
this.element.setAttribute('data-bw_comp_id', this._bwId);
|
|
5562
|
+
|
|
5563
|
+
// Restore o.render from original TACO (stripped by _tacoForDOM)
|
|
5564
|
+
if (this.taco.o && this.taco.o.render) {
|
|
5565
|
+
this.element._bw_render = this.taco.o.render;
|
|
5566
|
+
}
|
|
5272
5567
|
if (this._userTag) {
|
|
5273
5568
|
this.element.classList.add(this._userTag);
|
|
5274
5569
|
}
|
|
@@ -5284,6 +5579,16 @@
|
|
|
5284
5579
|
|
|
5285
5580
|
this.mounted = true;
|
|
5286
5581
|
|
|
5582
|
+
// Scan for child ComponentHandles and link parent/child (Bug #5)
|
|
5583
|
+
var childEls = this.element.querySelectorAll('[data-bw_comp_id]');
|
|
5584
|
+
for (var ci = 0; ci < childEls.length; ci++) {
|
|
5585
|
+
var ch = childEls[ci]._bwComponentHandle;
|
|
5586
|
+
if (ch && ch !== this && !ch._parent) {
|
|
5587
|
+
ch._parent = this;
|
|
5588
|
+
this._children.push(ch);
|
|
5589
|
+
}
|
|
5590
|
+
}
|
|
5591
|
+
|
|
5287
5592
|
// mounted hook (backward compat: fn.length === 2 wraps (el, state))
|
|
5288
5593
|
if (this._hooks.mounted) {
|
|
5289
5594
|
if (this._hooks.mounted.length === 2) {
|
|
@@ -5292,16 +5597,21 @@
|
|
|
5292
5597
|
this._hooks.mounted(this);
|
|
5293
5598
|
}
|
|
5294
5599
|
}
|
|
5600
|
+
|
|
5601
|
+
// Invoke o.render on initial mount (if present)
|
|
5602
|
+
if (this.element._bw_render) {
|
|
5603
|
+
this.element._bw_render(this.element, this._state);
|
|
5604
|
+
}
|
|
5295
5605
|
};
|
|
5296
5606
|
|
|
5297
5607
|
/**
|
|
5298
5608
|
* Prepare TACO for initial render: resolve when/each markers.
|
|
5299
5609
|
* @private
|
|
5300
5610
|
*/
|
|
5301
|
-
|
|
5302
|
-
if (!taco
|
|
5611
|
+
_chp._prepareTaco = function(taco) {
|
|
5612
|
+
if (!_is(taco, 'object')) return;
|
|
5303
5613
|
|
|
5304
|
-
if (
|
|
5614
|
+
if (_isA(taco.c)) {
|
|
5305
5615
|
for (var i = taco.c.length - 1; i >= 0; i--) {
|
|
5306
5616
|
var child = taco.c[i];
|
|
5307
5617
|
if (child && child._bwWhen) {
|
|
@@ -5326,18 +5636,18 @@
|
|
|
5326
5636
|
var eachExprStr = child.expr.replace(/^\$\{|\}$/g, '');
|
|
5327
5637
|
var arr = bw._evaluatePath(this._state, eachExprStr);
|
|
5328
5638
|
var items = [];
|
|
5329
|
-
if (
|
|
5639
|
+
if (_isA(arr)) {
|
|
5330
5640
|
for (var j = 0; j < arr.length; j++) {
|
|
5331
5641
|
items.push(child.factory(arr[j], j));
|
|
5332
5642
|
}
|
|
5333
5643
|
}
|
|
5334
5644
|
taco.c[i] = { t: 'span', a: { 'data-bw_each': child._refId, style: 'display:contents' }, c: items };
|
|
5335
5645
|
}
|
|
5336
|
-
if (taco.c[i]
|
|
5646
|
+
if (_is(taco.c[i], 'object') && taco.c[i].t) {
|
|
5337
5647
|
this._prepareTaco(taco.c[i]);
|
|
5338
5648
|
}
|
|
5339
5649
|
}
|
|
5340
|
-
} else if (taco.c
|
|
5650
|
+
} else if (_is(taco.c, 'object') && taco.c.t) {
|
|
5341
5651
|
this._prepareTaco(taco.c);
|
|
5342
5652
|
}
|
|
5343
5653
|
};
|
|
@@ -5346,12 +5656,12 @@
|
|
|
5346
5656
|
* Wire action name strings (in onclick etc.) to dispatch function calls.
|
|
5347
5657
|
* @private
|
|
5348
5658
|
*/
|
|
5349
|
-
|
|
5350
|
-
if (!taco
|
|
5659
|
+
_chp._wireActions = function(taco) {
|
|
5660
|
+
if (!_is(taco, 'object') || !taco.t) return;
|
|
5351
5661
|
if (taco.a) {
|
|
5352
5662
|
for (var key in taco.a) {
|
|
5353
|
-
if (!
|
|
5354
|
-
if (key.startsWith('on') &&
|
|
5663
|
+
if (!_hop.call(taco.a, key)) continue;
|
|
5664
|
+
if (key.startsWith('on') && _is(taco.a[key], 'string')) {
|
|
5355
5665
|
var actionName = taco.a[key];
|
|
5356
5666
|
if (actionName in this._actions) {
|
|
5357
5667
|
var registeredName = this._bwId + '_' + actionName;
|
|
@@ -5365,11 +5675,11 @@
|
|
|
5365
5675
|
}
|
|
5366
5676
|
}
|
|
5367
5677
|
}
|
|
5368
|
-
if (
|
|
5678
|
+
if (_isA(taco.c)) {
|
|
5369
5679
|
for (var i = 0; i < taco.c.length; i++) {
|
|
5370
5680
|
this._wireActions(taco.c[i]);
|
|
5371
5681
|
}
|
|
5372
|
-
} else if (taco.c
|
|
5682
|
+
} else if (_is(taco.c, 'object') && taco.c.t) {
|
|
5373
5683
|
this._wireActions(taco.c);
|
|
5374
5684
|
}
|
|
5375
5685
|
};
|
|
@@ -5378,7 +5688,7 @@
|
|
|
5378
5688
|
* Deep-clone a TACO tree, preserving _bwWhen/_bwEach markers and their factories.
|
|
5379
5689
|
* @private
|
|
5380
5690
|
*/
|
|
5381
|
-
|
|
5691
|
+
_chp._deepCloneTaco = function(taco) {
|
|
5382
5692
|
if (taco == null) return taco;
|
|
5383
5693
|
// Preserve _bwWhen / _bwEach markers (contain functions)
|
|
5384
5694
|
if (taco._bwWhen) {
|
|
@@ -5390,18 +5700,18 @@
|
|
|
5390
5700
|
if (taco._bwEach) {
|
|
5391
5701
|
return { _bwEach: true, expr: taco.expr, factory: taco.factory, _refId: taco._refId };
|
|
5392
5702
|
}
|
|
5393
|
-
if (
|
|
5703
|
+
if (!_is(taco, 'object') || !taco.t) return taco;
|
|
5394
5704
|
var result = { t: taco.t };
|
|
5395
5705
|
if (taco.a) {
|
|
5396
5706
|
result.a = {};
|
|
5397
5707
|
for (var k in taco.a) {
|
|
5398
|
-
if (
|
|
5708
|
+
if (_hop.call(taco.a, k)) result.a[k] = taco.a[k];
|
|
5399
5709
|
}
|
|
5400
5710
|
}
|
|
5401
5711
|
if (taco.c != null) {
|
|
5402
|
-
if (
|
|
5712
|
+
if (_isA(taco.c)) {
|
|
5403
5713
|
result.c = taco.c.map(function(child) { return this._deepCloneTaco(child); }.bind(this));
|
|
5404
|
-
} else if (
|
|
5714
|
+
} else if (_is(taco.c, 'object')) {
|
|
5405
5715
|
result.c = this._deepCloneTaco(taco.c);
|
|
5406
5716
|
} else {
|
|
5407
5717
|
result.c = taco.c;
|
|
@@ -5415,27 +5725,31 @@
|
|
|
5415
5725
|
* Create a copy of TACO suitable for createDOM (strips o to prevent double lifecycle).
|
|
5416
5726
|
* @private
|
|
5417
5727
|
*/
|
|
5418
|
-
|
|
5419
|
-
if (!taco
|
|
5728
|
+
_chp._tacoForDOM = function(taco) {
|
|
5729
|
+
if (!_is(taco, 'object') || !taco.t) return taco;
|
|
5420
5730
|
var result = { t: taco.t };
|
|
5421
5731
|
if (taco.a) result.a = taco.a;
|
|
5422
5732
|
if (taco.c != null) {
|
|
5423
|
-
if (
|
|
5733
|
+
if (_isA(taco.c)) {
|
|
5424
5734
|
result.c = taco.c.map(function(child) { return this._tacoForDOM(child); }.bind(this));
|
|
5425
|
-
} else if (
|
|
5735
|
+
} else if (_is(taco.c, 'object') && taco.c.t) {
|
|
5426
5736
|
result.c = this._tacoForDOM(taco.c);
|
|
5427
5737
|
} else {
|
|
5428
5738
|
result.c = taco.c;
|
|
5429
5739
|
}
|
|
5430
5740
|
}
|
|
5431
5741
|
// Intentionally strip o (no mounted/unmount/state/render on sub-elements)
|
|
5742
|
+
if (taco.o && (taco.o.mounted || taco.o.render || taco.o.unmount)) {
|
|
5743
|
+
_cw('bw: _tacoForDOM stripped o.mounted/render/unmount from child <' + taco.t +
|
|
5744
|
+
'>. Use onclick attribute or bw.component() for child interactivity.');
|
|
5745
|
+
}
|
|
5432
5746
|
return result;
|
|
5433
5747
|
};
|
|
5434
5748
|
|
|
5435
5749
|
/**
|
|
5436
5750
|
* Unmount: remove from DOM, deactivate, preserve state for re-mount.
|
|
5437
5751
|
*/
|
|
5438
|
-
|
|
5752
|
+
_chp.unmount = function() {
|
|
5439
5753
|
if (!this.mounted) return;
|
|
5440
5754
|
|
|
5441
5755
|
// unmount hook
|
|
@@ -5470,12 +5784,23 @@
|
|
|
5470
5784
|
/**
|
|
5471
5785
|
* Destroy: unmount + clear state + unregister actions.
|
|
5472
5786
|
*/
|
|
5473
|
-
|
|
5787
|
+
_chp.destroy = function() {
|
|
5474
5788
|
// willDestroy hook
|
|
5475
5789
|
if (this._hooks.willDestroy) {
|
|
5476
5790
|
this._hooks.willDestroy(this);
|
|
5477
5791
|
}
|
|
5478
5792
|
|
|
5793
|
+
// Cascade destroy to children depth-first (Bug #5)
|
|
5794
|
+
for (var ci = this._children.length - 1; ci >= 0; ci--) {
|
|
5795
|
+
this._children[ci].destroy();
|
|
5796
|
+
}
|
|
5797
|
+
this._children = [];
|
|
5798
|
+
if (this._parent) {
|
|
5799
|
+
var idx = this._parent._children.indexOf(this);
|
|
5800
|
+
if (idx >= 0) this._parent._children.splice(idx, 1);
|
|
5801
|
+
this._parent = null;
|
|
5802
|
+
}
|
|
5803
|
+
|
|
5479
5804
|
this.unmount();
|
|
5480
5805
|
|
|
5481
5806
|
// Unregister actions from function registry
|
|
@@ -5502,12 +5827,36 @@
|
|
|
5502
5827
|
* Flush dirty state: resolve changed bindings and apply to DOM.
|
|
5503
5828
|
* @private
|
|
5504
5829
|
*/
|
|
5505
|
-
|
|
5830
|
+
_chp._flush = function() {
|
|
5506
5831
|
this._scheduled = false;
|
|
5507
|
-
var changedKeys =
|
|
5832
|
+
var changedKeys = _keys(this._dirtyKeys);
|
|
5508
5833
|
this._dirtyKeys = {};
|
|
5509
5834
|
if (changedKeys.length === 0 || !this.mounted) return;
|
|
5510
5835
|
|
|
5836
|
+
// Factory rebuild: if a BCCL factory exists and changed keys overlap factory props,
|
|
5837
|
+
// rebuild the TACO from the factory with merged state (Bug #6)
|
|
5838
|
+
if (this._factory) {
|
|
5839
|
+
var rebuildNeeded = false;
|
|
5840
|
+
for (var fi = 0; fi < changedKeys.length; fi++) {
|
|
5841
|
+
if (_hop.call(this._factory.props, changedKeys[fi])) {
|
|
5842
|
+
rebuildNeeded = true; break;
|
|
5843
|
+
}
|
|
5844
|
+
}
|
|
5845
|
+
if (rebuildNeeded) {
|
|
5846
|
+
var merged = {};
|
|
5847
|
+
for (var mk in this._factory.props) if (_hop.call(this._factory.props, mk)) merged[mk] = this._factory.props[mk];
|
|
5848
|
+
for (var sk in this._state) if (_hop.call(this._state, sk)) merged[sk] = this._state[sk];
|
|
5849
|
+
this._factory.props = merged;
|
|
5850
|
+
var newTaco = bw.make(this._factory.type, merged);
|
|
5851
|
+
newTaco._bwFactory = this._factory;
|
|
5852
|
+
this.taco = newTaco;
|
|
5853
|
+
this._originalTaco = this._deepCloneTaco(newTaco);
|
|
5854
|
+
this._render();
|
|
5855
|
+
if (this._hooks.onUpdate) this._hooks.onUpdate(this, changedKeys);
|
|
5856
|
+
return;
|
|
5857
|
+
}
|
|
5858
|
+
}
|
|
5859
|
+
|
|
5511
5860
|
// willUpdate hook
|
|
5512
5861
|
if (this._hooks.willUpdate) {
|
|
5513
5862
|
this._hooks.willUpdate(this, changedKeys);
|
|
@@ -5546,7 +5895,7 @@
|
|
|
5546
5895
|
* Returns list of patches to apply.
|
|
5547
5896
|
* @private
|
|
5548
5897
|
*/
|
|
5549
|
-
|
|
5898
|
+
_chp._resolveBindings = function(changedKeys) {
|
|
5550
5899
|
var patches = [];
|
|
5551
5900
|
for (var i = 0; i < this._bindings.length; i++) {
|
|
5552
5901
|
var b = this._bindings[i];
|
|
@@ -5582,11 +5931,14 @@
|
|
|
5582
5931
|
* Apply patches to DOM.
|
|
5583
5932
|
* @private
|
|
5584
5933
|
*/
|
|
5585
|
-
|
|
5934
|
+
_chp._applyPatches = function(patches) {
|
|
5586
5935
|
for (var i = 0; i < patches.length; i++) {
|
|
5587
5936
|
var p = patches[i];
|
|
5588
5937
|
var el = this._bw_refs[p.refId];
|
|
5589
|
-
if (!el)
|
|
5938
|
+
if (!el) {
|
|
5939
|
+
if (bw.debug) _cw('bw.debug: _applyPatches — ref "' + p.refId + '" not found in DOM');
|
|
5940
|
+
continue;
|
|
5941
|
+
}
|
|
5590
5942
|
if (p.type === 'content') {
|
|
5591
5943
|
el.textContent = p.value;
|
|
5592
5944
|
} else if (p.type === 'attribute') {
|
|
@@ -5603,7 +5955,7 @@
|
|
|
5603
5955
|
* Resolve all bindings and apply (used for initial render).
|
|
5604
5956
|
* @private
|
|
5605
5957
|
*/
|
|
5606
|
-
|
|
5958
|
+
_chp._resolveAndApplyAll = function() {
|
|
5607
5959
|
var patches = [];
|
|
5608
5960
|
for (var i = 0; i < this._bindings.length; i++) {
|
|
5609
5961
|
var b = this._bindings[i];
|
|
@@ -5626,7 +5978,7 @@
|
|
|
5626
5978
|
* Full re-render for structural changes (when/each branch switches).
|
|
5627
5979
|
* @private
|
|
5628
5980
|
*/
|
|
5629
|
-
|
|
5981
|
+
_chp._render = function() {
|
|
5630
5982
|
if (!this.element || !this.element.parentNode) return;
|
|
5631
5983
|
var parent = this.element.parentNode;
|
|
5632
5984
|
var nextSibling = this.element.nextSibling;
|
|
@@ -5666,7 +6018,7 @@
|
|
|
5666
6018
|
* @param {string} event - Event name (e.g., 'click')
|
|
5667
6019
|
* @param {Function} handler - Event handler
|
|
5668
6020
|
*/
|
|
5669
|
-
|
|
6021
|
+
_chp.on = function(event, handler) {
|
|
5670
6022
|
if (this.element) {
|
|
5671
6023
|
this.element.addEventListener(event, handler);
|
|
5672
6024
|
}
|
|
@@ -5678,7 +6030,7 @@
|
|
|
5678
6030
|
* @param {string} event - Event name
|
|
5679
6031
|
* @param {Function} handler - Handler to remove
|
|
5680
6032
|
*/
|
|
5681
|
-
|
|
6033
|
+
_chp.off = function(event, handler) {
|
|
5682
6034
|
if (this.element) {
|
|
5683
6035
|
this.element.removeEventListener(event, handler);
|
|
5684
6036
|
}
|
|
@@ -5693,7 +6045,7 @@
|
|
|
5693
6045
|
* @param {Function} handler - Handler function
|
|
5694
6046
|
* @returns {Function} Unsubscribe function
|
|
5695
6047
|
*/
|
|
5696
|
-
|
|
6048
|
+
_chp.sub = function(topic, handler) {
|
|
5697
6049
|
var unsub = bw.sub(topic, handler);
|
|
5698
6050
|
this._subs.push(unsub);
|
|
5699
6051
|
return unsub;
|
|
@@ -5704,10 +6056,10 @@
|
|
|
5704
6056
|
* @param {string} name - Action name
|
|
5705
6057
|
* @param {...*} args - Arguments passed after comp
|
|
5706
6058
|
*/
|
|
5707
|
-
|
|
6059
|
+
_chp.action = function(name) {
|
|
5708
6060
|
var fn = this._actions[name];
|
|
5709
6061
|
if (!fn) {
|
|
5710
|
-
|
|
6062
|
+
_cw('ComponentHandle.action: unknown action "' + name + '"');
|
|
5711
6063
|
return;
|
|
5712
6064
|
}
|
|
5713
6065
|
var args = [this].concat(Array.prototype.slice.call(arguments, 1));
|
|
@@ -5719,7 +6071,7 @@
|
|
|
5719
6071
|
* @param {string} sel - CSS selector
|
|
5720
6072
|
* @returns {Element|null}
|
|
5721
6073
|
*/
|
|
5722
|
-
|
|
6074
|
+
_chp.select = function(sel) {
|
|
5723
6075
|
return this.element ? this.element.querySelector(sel) : null;
|
|
5724
6076
|
};
|
|
5725
6077
|
|
|
@@ -5728,7 +6080,7 @@
|
|
|
5728
6080
|
* @param {string} sel - CSS selector
|
|
5729
6081
|
* @returns {Element[]}
|
|
5730
6082
|
*/
|
|
5731
|
-
|
|
6083
|
+
_chp.selectAll = function(sel) {
|
|
5732
6084
|
if (!this.element) return [];
|
|
5733
6085
|
return Array.prototype.slice.call(this.element.querySelectorAll(sel));
|
|
5734
6086
|
};
|
|
@@ -5739,7 +6091,7 @@
|
|
|
5739
6091
|
* @param {string} tag - User-defined identifier (e.g. 'dashboard_prod_east')
|
|
5740
6092
|
* @returns {ComponentHandle} this (for chaining)
|
|
5741
6093
|
*/
|
|
5742
|
-
|
|
6094
|
+
_chp.userTag = function(tag) {
|
|
5743
6095
|
this._userTag = tag;
|
|
5744
6096
|
if (this.element) {
|
|
5745
6097
|
this.element.classList.add(tag);
|
|
@@ -5840,8 +6192,8 @@
|
|
|
5840
6192
|
}
|
|
5841
6193
|
if (!el || !el._bwComponentHandle) return false;
|
|
5842
6194
|
var comp = el._bwComponentHandle;
|
|
5843
|
-
if (
|
|
5844
|
-
|
|
6195
|
+
if (!_is(comp[action], 'function')) {
|
|
6196
|
+
_cw('bw.message: unknown action "' + action + '" on component ' + target);
|
|
5845
6197
|
return false;
|
|
5846
6198
|
}
|
|
5847
6199
|
comp[action](data);
|
|
@@ -5878,7 +6230,7 @@
|
|
|
5878
6230
|
},
|
|
5879
6231
|
focus: function(selector) {
|
|
5880
6232
|
var el = bw._el(selector);
|
|
5881
|
-
if (el &&
|
|
6233
|
+
if (el && _is(el.focus, 'function')) el.focus();
|
|
5882
6234
|
},
|
|
5883
6235
|
download: function(filename, content, mimeType) {
|
|
5884
6236
|
if (typeof document === 'undefined') return;
|
|
@@ -6043,12 +6395,12 @@
|
|
|
6043
6395
|
} else if (type === 'remove') {
|
|
6044
6396
|
var toRemove = bw._el(target);
|
|
6045
6397
|
if (!toRemove) return false;
|
|
6046
|
-
if (
|
|
6398
|
+
if (_is(bw.cleanup, 'function')) bw.cleanup(toRemove);
|
|
6047
6399
|
toRemove.remove();
|
|
6048
6400
|
return true;
|
|
6049
6401
|
|
|
6050
6402
|
} else if (type === 'batch') {
|
|
6051
|
-
if (!
|
|
6403
|
+
if (!_isA(msg.ops)) return false;
|
|
6052
6404
|
var allOk = true;
|
|
6053
6405
|
msg.ops.forEach(function(op) {
|
|
6054
6406
|
if (!bw.clientApply(op)) allOk = false;
|
|
@@ -6064,26 +6416,26 @@
|
|
|
6064
6416
|
bw._clientFunctions[msg.name] = new Function('return ' + msg.body)();
|
|
6065
6417
|
return true;
|
|
6066
6418
|
} catch (e) {
|
|
6067
|
-
|
|
6419
|
+
_ce('[bw] register error:', msg.name, e);
|
|
6068
6420
|
return false;
|
|
6069
6421
|
}
|
|
6070
6422
|
|
|
6071
6423
|
} else if (type === 'call') {
|
|
6072
6424
|
if (!msg.name) return false;
|
|
6073
6425
|
var fn = bw._clientFunctions[msg.name] || bw._builtinClientFunctions[msg.name];
|
|
6074
|
-
if (
|
|
6426
|
+
if (!_is(fn, 'function')) return false;
|
|
6075
6427
|
try {
|
|
6076
|
-
var args =
|
|
6428
|
+
var args = _isA(msg.args) ? msg.args : [];
|
|
6077
6429
|
fn.apply(null, args);
|
|
6078
6430
|
return true;
|
|
6079
6431
|
} catch (e) {
|
|
6080
|
-
|
|
6432
|
+
_ce('[bw] call error:', msg.name, e);
|
|
6081
6433
|
return false;
|
|
6082
6434
|
}
|
|
6083
6435
|
|
|
6084
6436
|
} else if (type === 'exec') {
|
|
6085
6437
|
if (!bw._allowExec) {
|
|
6086
|
-
|
|
6438
|
+
_cw('[bw] exec rejected: allowExec is not enabled');
|
|
6087
6439
|
return false;
|
|
6088
6440
|
}
|
|
6089
6441
|
if (!msg.code) return false;
|
|
@@ -6091,7 +6443,7 @@
|
|
|
6091
6443
|
new Function(msg.code)();
|
|
6092
6444
|
return true;
|
|
6093
6445
|
} catch (e) {
|
|
6094
|
-
|
|
6446
|
+
_ce('[bw] exec error:', e);
|
|
6095
6447
|
return false;
|
|
6096
6448
|
}
|
|
6097
6449
|
}
|
|
@@ -6139,7 +6491,7 @@
|
|
|
6139
6491
|
|
|
6140
6492
|
function handleMessage(data) {
|
|
6141
6493
|
try {
|
|
6142
|
-
var msg =
|
|
6494
|
+
var msg = _is(data, 'string') ? bw.clientParse(data) : data;
|
|
6143
6495
|
if (onMessage) onMessage(msg);
|
|
6144
6496
|
if (handlers.message) handlers.message(msg);
|
|
6145
6497
|
bw.clientApply(msg);
|
|
@@ -6177,7 +6529,7 @@
|
|
|
6177
6529
|
setStatus('connected');
|
|
6178
6530
|
conn._pollTimer = setInterval(function() {
|
|
6179
6531
|
fetch(url).then(function(r) { return r.json(); }).then(function(msgs) {
|
|
6180
|
-
if (
|
|
6532
|
+
if (_isA(msgs)) {
|
|
6181
6533
|
msgs.forEach(handleMessage);
|
|
6182
6534
|
} else if (msgs && msgs.type) {
|
|
6183
6535
|
handleMessage(msgs);
|
|
@@ -6259,33 +6611,33 @@
|
|
|
6259
6611
|
el = target.element;
|
|
6260
6612
|
comp = target;
|
|
6261
6613
|
} else {
|
|
6262
|
-
if (
|
|
6614
|
+
if (_is(target, 'string')) {
|
|
6263
6615
|
el = bw.$(target)[0];
|
|
6264
6616
|
}
|
|
6265
6617
|
if (!el) {
|
|
6266
|
-
|
|
6618
|
+
_cw('bw.inspect: element not found');
|
|
6267
6619
|
return null;
|
|
6268
6620
|
}
|
|
6269
6621
|
comp = el._bwComponentHandle;
|
|
6270
6622
|
}
|
|
6271
6623
|
if (!comp) {
|
|
6272
|
-
|
|
6273
|
-
|
|
6274
|
-
|
|
6275
|
-
|
|
6624
|
+
_cl('bw.inspect: no ComponentHandle on this element');
|
|
6625
|
+
_cl(' Tag:', el.tagName);
|
|
6626
|
+
_cl(' Classes:', el.className);
|
|
6627
|
+
_cl(' _bw_state:', el._bw_state || '(none)');
|
|
6276
6628
|
return null;
|
|
6277
6629
|
}
|
|
6278
6630
|
var deps = comp._bindings.reduce(function(s, b) {
|
|
6279
6631
|
return s.concat(b.deps || []);
|
|
6280
6632
|
}, []).filter(function(v, i, a) { return a.indexOf(v) === i; });
|
|
6281
6633
|
console.group('Component: ' + comp._bwId);
|
|
6282
|
-
|
|
6283
|
-
|
|
6284
|
-
|
|
6285
|
-
|
|
6286
|
-
|
|
6287
|
-
|
|
6288
|
-
|
|
6634
|
+
_cl('State:', comp._state);
|
|
6635
|
+
_cl('Bindings:', comp._bindings.length, '(deps:', deps, ')');
|
|
6636
|
+
_cl('Methods:', _keys(comp._methods));
|
|
6637
|
+
_cl('Actions:', _keys(comp._actions));
|
|
6638
|
+
_cl('User tag:', comp._userTag || '(none)');
|
|
6639
|
+
_cl('Mounted:', comp.mounted);
|
|
6640
|
+
_cl('Element:', comp.element);
|
|
6289
6641
|
console.groupEnd();
|
|
6290
6642
|
return comp;
|
|
6291
6643
|
};
|
|
@@ -6308,8 +6660,8 @@
|
|
|
6308
6660
|
// Pre-extract all binding expressions
|
|
6309
6661
|
var precompiled = [];
|
|
6310
6662
|
function walkExpressions(node) {
|
|
6311
|
-
if (!node
|
|
6312
|
-
if (
|
|
6663
|
+
if (!_is(node, 'object')) return;
|
|
6664
|
+
if (_is(node.c, 'string') && node.c.indexOf('${') >= 0) {
|
|
6313
6665
|
var parsed = bw._parseBindings(node.c);
|
|
6314
6666
|
for (var i = 0; i < parsed.length; i++) {
|
|
6315
6667
|
try {
|
|
@@ -6324,9 +6676,9 @@
|
|
|
6324
6676
|
}
|
|
6325
6677
|
if (node.a) {
|
|
6326
6678
|
for (var key in node.a) {
|
|
6327
|
-
if (
|
|
6679
|
+
if (_hop.call(node.a, key)) {
|
|
6328
6680
|
var v = node.a[key];
|
|
6329
|
-
if (
|
|
6681
|
+
if (_is(v, 'string') && v.indexOf('${') >= 0) {
|
|
6330
6682
|
var parsed2 = bw._parseBindings(v);
|
|
6331
6683
|
for (var j = 0; j < parsed2.length; j++) {
|
|
6332
6684
|
try {
|
|
@@ -6342,9 +6694,9 @@
|
|
|
6342
6694
|
}
|
|
6343
6695
|
}
|
|
6344
6696
|
}
|
|
6345
|
-
if (
|
|
6697
|
+
if (_isA(node.c)) {
|
|
6346
6698
|
for (var k = 0; k < node.c.length; k++) walkExpressions(node.c[k]);
|
|
6347
|
-
} else if (node.c
|
|
6699
|
+
} else if (_is(node.c, 'object') && node.c.t) {
|
|
6348
6700
|
walkExpressions(node.c);
|
|
6349
6701
|
}
|
|
6350
6702
|
}
|
|
@@ -6356,7 +6708,7 @@
|
|
|
6356
6708
|
handle._precompiledBindings = precompiled;
|
|
6357
6709
|
if (initialState) {
|
|
6358
6710
|
for (var k in initialState) {
|
|
6359
|
-
if (
|
|
6711
|
+
if (_hop.call(initialState, k)) {
|
|
6360
6712
|
handle._state[k] = initialState[k];
|
|
6361
6713
|
}
|
|
6362
6714
|
}
|
|
@@ -6387,18 +6739,18 @@
|
|
|
6387
6739
|
bw.css = function(rules, options = {}) {
|
|
6388
6740
|
const { minify = false, pretty = !minify } = options;
|
|
6389
6741
|
|
|
6390
|
-
if (
|
|
6742
|
+
if (_is(rules, 'string')) return rules;
|
|
6391
6743
|
|
|
6392
6744
|
let css = '';
|
|
6393
6745
|
const indent = pretty ? ' ' : '';
|
|
6394
6746
|
const newline = pretty ? '\n' : '';
|
|
6395
6747
|
const space = pretty ? ' ' : '';
|
|
6396
6748
|
|
|
6397
|
-
if (
|
|
6749
|
+
if (_isA(rules)) {
|
|
6398
6750
|
css = rules.map(rule => bw.css(rule, options)).join(newline);
|
|
6399
|
-
} else if (
|
|
6751
|
+
} else if (_is(rules, 'object')) {
|
|
6400
6752
|
Object.entries(rules).forEach(([selector, styles]) => {
|
|
6401
|
-
if (
|
|
6753
|
+
if (_is(styles, 'object')) {
|
|
6402
6754
|
// Handle @media, @keyframes, @supports — recurse into nested block
|
|
6403
6755
|
if (selector.charAt(0) === '@') {
|
|
6404
6756
|
const inner = bw.css(styles, options);
|
|
@@ -6447,7 +6799,7 @@
|
|
|
6447
6799
|
*/
|
|
6448
6800
|
bw.injectCSS = function(css, options = {}) {
|
|
6449
6801
|
if (!bw._isBrowser) {
|
|
6450
|
-
|
|
6802
|
+
_cw('bw.injectCSS requires a DOM environment');
|
|
6451
6803
|
return null;
|
|
6452
6804
|
}
|
|
6453
6805
|
|
|
@@ -6464,7 +6816,7 @@
|
|
|
6464
6816
|
}
|
|
6465
6817
|
|
|
6466
6818
|
// Convert CSS if needed
|
|
6467
|
-
const cssStr =
|
|
6819
|
+
const cssStr = _is(css, 'string') ? css : bw.css(css, options);
|
|
6468
6820
|
|
|
6469
6821
|
// Set or append CSS
|
|
6470
6822
|
if (append && styleEl.textContent) {
|
|
@@ -6494,7 +6846,7 @@
|
|
|
6494
6846
|
var result = {};
|
|
6495
6847
|
for (var i = 0; i < arguments.length; i++) {
|
|
6496
6848
|
var arg = arguments[i];
|
|
6497
|
-
if (arg
|
|
6849
|
+
if (_is(arg, 'object')) Object.assign(result, arg);
|
|
6498
6850
|
}
|
|
6499
6851
|
return result;
|
|
6500
6852
|
};
|
|
@@ -6617,7 +6969,7 @@
|
|
|
6617
6969
|
bw.responsive = function(selector, breakpoints) {
|
|
6618
6970
|
var sizes = { sm: '576px', md: '768px', lg: '992px', xl: '1200px' };
|
|
6619
6971
|
var parts = [];
|
|
6620
|
-
|
|
6972
|
+
_keys(breakpoints).forEach(function(key) {
|
|
6621
6973
|
var rules = {};
|
|
6622
6974
|
if (key === 'base') {
|
|
6623
6975
|
rules[selector] = breakpoints[key];
|
|
@@ -6689,18 +7041,18 @@
|
|
|
6689
7041
|
if (!selector) return [];
|
|
6690
7042
|
|
|
6691
7043
|
// Already an array
|
|
6692
|
-
if (
|
|
7044
|
+
if (_isA(selector)) return selector;
|
|
6693
7045
|
|
|
6694
7046
|
// Single element
|
|
6695
7047
|
if (selector.nodeType) return [selector];
|
|
6696
7048
|
|
|
6697
7049
|
// NodeList or HTMLCollection
|
|
6698
|
-
if (selector.length !== undefined &&
|
|
7050
|
+
if (selector.length !== undefined && !_is(selector, 'string')) {
|
|
6699
7051
|
return Array.from(selector);
|
|
6700
7052
|
}
|
|
6701
7053
|
|
|
6702
7054
|
// CSS selector string
|
|
6703
|
-
if (
|
|
7055
|
+
if (_is(selector, 'string')) {
|
|
6704
7056
|
return Array.from(document.querySelectorAll(selector));
|
|
6705
7057
|
}
|
|
6706
7058
|
|
|
@@ -7204,7 +7556,7 @@
|
|
|
7204
7556
|
|
|
7205
7557
|
// Auto-detect columns if not provided
|
|
7206
7558
|
const cols = columns || (data.length > 0
|
|
7207
|
-
?
|
|
7559
|
+
? _keys(data[0]).map(key => ({ key, label: key }))
|
|
7208
7560
|
: []);
|
|
7209
7561
|
|
|
7210
7562
|
// Current sort state
|
|
@@ -7219,7 +7571,7 @@
|
|
|
7219
7571
|
const bVal = b[currentSortColumn];
|
|
7220
7572
|
|
|
7221
7573
|
// Handle different types
|
|
7222
|
-
if (
|
|
7574
|
+
if (_is(aVal, 'number') && _is(bVal, 'number')) {
|
|
7223
7575
|
return currentSortDirection === 'asc' ? aVal - bVal : bVal - aVal;
|
|
7224
7576
|
}
|
|
7225
7577
|
|
|
@@ -7329,7 +7681,7 @@
|
|
|
7329
7681
|
bw.makeTableFromArray = function(config) {
|
|
7330
7682
|
const { data = [], headerRow = true, columns, ...rest } = config;
|
|
7331
7683
|
|
|
7332
|
-
if (!
|
|
7684
|
+
if (!_isA(data) || data.length === 0) {
|
|
7333
7685
|
return bw.makeTable({ data: [], columns: columns || [], ...rest });
|
|
7334
7686
|
}
|
|
7335
7687
|
|
|
@@ -7411,7 +7763,7 @@
|
|
|
7411
7763
|
className = ''
|
|
7412
7764
|
} = config;
|
|
7413
7765
|
|
|
7414
|
-
if (!
|
|
7766
|
+
if (!_isA(data) || data.length === 0) {
|
|
7415
7767
|
return { t: 'div', a: { class: ('bw_bar_chart_container ' + className).trim() }, c: '' };
|
|
7416
7768
|
}
|
|
7417
7769
|
|
|
@@ -7560,7 +7912,7 @@
|
|
|
7560
7912
|
*/
|
|
7561
7913
|
bw.render = function(element, position, taco) {
|
|
7562
7914
|
// Get target element
|
|
7563
|
-
const targetEl =
|
|
7915
|
+
const targetEl = _is(element, 'string')
|
|
7564
7916
|
? document.querySelector(element)
|
|
7565
7917
|
: element;
|
|
7566
7918
|
|
|
@@ -7710,7 +8062,7 @@
|
|
|
7710
8062
|
setContent(content) {
|
|
7711
8063
|
this._taco.c = content;
|
|
7712
8064
|
if (this.element) {
|
|
7713
|
-
if (
|
|
8065
|
+
if (_is(content, 'string')) {
|
|
7714
8066
|
this.element.textContent = content;
|
|
7715
8067
|
} else {
|
|
7716
8068
|
// Re-render for complex content
|