bitwrench 2.0.18 → 2.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +86 -81
- package/dist/bitwrench-bccl.cjs.js +221 -48
- package/dist/bitwrench-bccl.cjs.min.js +3 -3
- package/dist/bitwrench-bccl.esm.js +221 -48
- package/dist/bitwrench-bccl.esm.min.js +3 -3
- package/dist/bitwrench-bccl.umd.js +221 -48
- package/dist/bitwrench-bccl.umd.min.js +3 -3
- package/dist/bitwrench-code-edit.cjs.js +7 -9
- package/dist/bitwrench-code-edit.cjs.min.js +5 -7
- package/dist/bitwrench-code-edit.es5.js +6 -8
- package/dist/bitwrench-code-edit.es5.min.js +5 -7
- package/dist/bitwrench-code-edit.esm.js +7 -9
- package/dist/bitwrench-code-edit.esm.min.js +5 -7
- package/dist/bitwrench-code-edit.umd.js +7 -9
- package/dist/bitwrench-code-edit.umd.min.js +5 -7
- package/dist/bitwrench-debug.js +268 -0
- package/dist/bitwrench-debug.min.js +3 -0
- package/dist/bitwrench-lean.cjs.js +250 -1574
- package/dist/bitwrench-lean.cjs.min.js +6 -6
- package/dist/bitwrench-lean.es5.js +344 -1661
- package/dist/bitwrench-lean.es5.min.js +4 -4
- package/dist/bitwrench-lean.esm.js +250 -1574
- package/dist/bitwrench-lean.esm.min.js +6 -6
- package/dist/bitwrench-lean.umd.js +250 -1574
- package/dist/bitwrench-lean.umd.min.js +6 -6
- package/dist/bitwrench-util-css.cjs.js +1 -1
- package/dist/bitwrench-util-css.cjs.min.js +1 -1
- package/dist/bitwrench-util-css.es5.js +1 -1
- package/dist/bitwrench-util-css.es5.min.js +1 -1
- package/dist/bitwrench-util-css.esm.js +1 -1
- package/dist/bitwrench-util-css.esm.min.js +1 -1
- package/dist/bitwrench-util-css.umd.js +1 -1
- package/dist/bitwrench-util-css.umd.min.js +1 -1
- package/dist/bitwrench.cjs.js +510 -1660
- package/dist/bitwrench.cjs.min.js +7 -7
- package/dist/bitwrench.css +80 -33
- package/dist/bitwrench.es5.js +569 -1694
- package/dist/bitwrench.es5.min.js +5 -5
- package/dist/bitwrench.esm.js +510 -1660
- package/dist/bitwrench.esm.min.js +7 -7
- package/dist/bitwrench.min.css +1 -1
- package/dist/bitwrench.umd.js +510 -1660
- package/dist/bitwrench.umd.min.js +7 -7
- package/dist/builds.json +133 -111
- package/dist/bwserve.cjs.js +2 -2
- package/dist/bwserve.esm.js +2 -2
- package/dist/sri.json +46 -44
- package/package.json +5 -3
- package/readme.html +86 -75
- package/src/bitwrench-bccl-entry.js +3 -4
- package/src/bitwrench-bccl.js +217 -43
- package/src/bitwrench-code-edit.js +6 -8
- package/src/bitwrench-debug.js +245 -0
- package/src/bitwrench-styles.js +35 -8
- package/src/bitwrench.js +212 -1563
- package/src/cli/attach.js +53 -21
- package/src/cli/serve.js +179 -3
- package/src/version.js +3 -3
package/dist/bitwrench.es5.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! bitwrench v2.0.
|
|
1
|
+
/*! bitwrench v2.0.19 | 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) :
|
|
@@ -190,14 +190,14 @@
|
|
|
190
190
|
*/
|
|
191
191
|
|
|
192
192
|
var VERSION_INFO = {
|
|
193
|
-
version: '2.0.
|
|
193
|
+
version: '2.0.19',
|
|
194
194
|
name: 'bitwrench',
|
|
195
195
|
description: 'A library for javascript UI functions.',
|
|
196
196
|
license: 'BSD-2-Clause',
|
|
197
197
|
homepage: 'https://deftio.github.com/bitwrench/pages',
|
|
198
198
|
repository: 'git+https://github.com/deftio/bitwrench.git',
|
|
199
199
|
author: 'manu a. chatterjee <deftio@deftio.com> (https://deftio.com/)',
|
|
200
|
-
buildDate: '2026-03-
|
|
200
|
+
buildDate: '2026-03-22T19:09:32.608Z'
|
|
201
201
|
};
|
|
202
202
|
|
|
203
203
|
/**
|
|
@@ -3088,7 +3088,9 @@
|
|
|
3088
3088
|
'.bw_modal_header': {
|
|
3089
3089
|
'display': 'flex',
|
|
3090
3090
|
'align-items': 'center',
|
|
3091
|
-
'justify-content': 'space-between'
|
|
3091
|
+
'justify-content': 'space-between',
|
|
3092
|
+
'padding': '1rem 1.25rem',
|
|
3093
|
+
'border-bottom': '1px solid transparent'
|
|
3092
3094
|
},
|
|
3093
3095
|
'.bw_modal_title': {
|
|
3094
3096
|
'margin': '0',
|
|
@@ -3098,14 +3100,17 @@
|
|
|
3098
3100
|
},
|
|
3099
3101
|
'.bw_modal_body': {
|
|
3100
3102
|
'position': 'relative',
|
|
3101
|
-
'flex': '1 1 auto'
|
|
3103
|
+
'flex': '1 1 auto',
|
|
3104
|
+
'padding': '1rem 1.25rem'
|
|
3102
3105
|
},
|
|
3103
3106
|
'.bw_modal_footer': {
|
|
3104
3107
|
'display': 'flex',
|
|
3105
3108
|
'flex-wrap': 'wrap',
|
|
3106
3109
|
'align-items': 'center',
|
|
3107
3110
|
'justify-content': 'flex-end',
|
|
3108
|
-
'gap': '0.5rem'
|
|
3111
|
+
'gap': '0.5rem',
|
|
3112
|
+
'padding': '0.75rem 1.25rem',
|
|
3113
|
+
'border-top': '1px solid transparent'
|
|
3109
3114
|
}
|
|
3110
3115
|
},
|
|
3111
3116
|
// ---- Toast ----
|
|
@@ -3163,9 +3168,12 @@
|
|
|
3163
3168
|
'display': 'flex',
|
|
3164
3169
|
'align-items': 'center',
|
|
3165
3170
|
'justify-content': 'space-between',
|
|
3166
|
-
'
|
|
3171
|
+
'padding': '0.5rem 0.75rem',
|
|
3172
|
+
'font-size': '0.875rem',
|
|
3173
|
+
'border-bottom': '1px solid transparent'
|
|
3167
3174
|
},
|
|
3168
3175
|
'.bw_toast_body': {
|
|
3176
|
+
'padding': '0.5rem 0.75rem',
|
|
3169
3177
|
'font-size': '0.9375rem'
|
|
3170
3178
|
}
|
|
3171
3179
|
},
|
|
@@ -3195,6 +3203,7 @@
|
|
|
3195
3203
|
'padding': '0.5rem 0',
|
|
3196
3204
|
'margin': '0.125rem 0 0',
|
|
3197
3205
|
'background-clip': 'padding-box',
|
|
3206
|
+
'border': '1px solid transparent',
|
|
3198
3207
|
'opacity': '0',
|
|
3199
3208
|
'visibility': 'hidden',
|
|
3200
3209
|
'pointer-events': 'none'
|
|
@@ -3211,6 +3220,7 @@
|
|
|
3211
3220
|
'.bw_dropdown_item': {
|
|
3212
3221
|
'display': 'block',
|
|
3213
3222
|
'width': '100%',
|
|
3223
|
+
'padding': '0.4rem 1rem',
|
|
3214
3224
|
'clear': 'both',
|
|
3215
3225
|
'font-weight': '400',
|
|
3216
3226
|
'text-align': 'inherit',
|
|
@@ -3218,7 +3228,8 @@
|
|
|
3218
3228
|
'white-space': 'nowrap',
|
|
3219
3229
|
'background-color': 'transparent',
|
|
3220
3230
|
'border': '0',
|
|
3221
|
-
'font-size': '0.9375rem'
|
|
3231
|
+
'font-size': '0.9375rem',
|
|
3232
|
+
'cursor': 'pointer'
|
|
3222
3233
|
},
|
|
3223
3234
|
'.bw_dropdown_item:focus-visible': {
|
|
3224
3235
|
'outline': '2px solid currentColor',
|
|
@@ -4104,6 +4115,67 @@
|
|
|
4104
4115
|
rules['.bw_text_center'] = {
|
|
4105
4116
|
'text-align': 'center'
|
|
4106
4117
|
};
|
|
4118
|
+
rules['.bw_text_justify'] = {
|
|
4119
|
+
'text-align': 'justify'
|
|
4120
|
+
};
|
|
4121
|
+
|
|
4122
|
+
// Font weight
|
|
4123
|
+
rules['.bw_fw_bold'] = {
|
|
4124
|
+
'font-weight': '700'
|
|
4125
|
+
};
|
|
4126
|
+
rules['.bw_fw_semibold'] = {
|
|
4127
|
+
'font-weight': '600'
|
|
4128
|
+
};
|
|
4129
|
+
rules['.bw_fw_normal'] = {
|
|
4130
|
+
'font-weight': '400'
|
|
4131
|
+
};
|
|
4132
|
+
rules['.bw_fw_light'] = {
|
|
4133
|
+
'font-weight': '300'
|
|
4134
|
+
};
|
|
4135
|
+
|
|
4136
|
+
// Font style
|
|
4137
|
+
rules['.bw_fst_italic'] = {
|
|
4138
|
+
'font-style': 'italic'
|
|
4139
|
+
};
|
|
4140
|
+
rules['.bw_fst_normal'] = {
|
|
4141
|
+
'font-style': 'normal'
|
|
4142
|
+
};
|
|
4143
|
+
|
|
4144
|
+
// Text decoration
|
|
4145
|
+
rules['.bw_text_underline'] = {
|
|
4146
|
+
'text-decoration': 'underline'
|
|
4147
|
+
};
|
|
4148
|
+
rules['.bw_text_line_through'] = {
|
|
4149
|
+
'text-decoration': 'line-through'
|
|
4150
|
+
};
|
|
4151
|
+
rules['.bw_text_decoration_none'] = {
|
|
4152
|
+
'text-decoration': 'none'
|
|
4153
|
+
};
|
|
4154
|
+
|
|
4155
|
+
// Text transform
|
|
4156
|
+
rules['.bw_text_uppercase'] = {
|
|
4157
|
+
'text-transform': 'uppercase'
|
|
4158
|
+
};
|
|
4159
|
+
rules['.bw_text_lowercase'] = {
|
|
4160
|
+
'text-transform': 'lowercase'
|
|
4161
|
+
};
|
|
4162
|
+
rules['.bw_text_capitalize'] = {
|
|
4163
|
+
'text-transform': 'capitalize'
|
|
4164
|
+
};
|
|
4165
|
+
|
|
4166
|
+
// Font size
|
|
4167
|
+
rules['.bw_fs_sm'] = {
|
|
4168
|
+
'font-size': '0.875rem'
|
|
4169
|
+
};
|
|
4170
|
+
rules['.bw_fs_base'] = {
|
|
4171
|
+
'font-size': '1rem'
|
|
4172
|
+
};
|
|
4173
|
+
rules['.bw_fs_lg'] = {
|
|
4174
|
+
'font-size': '1.25rem'
|
|
4175
|
+
};
|
|
4176
|
+
rules['.bw_fs_xl'] = {
|
|
4177
|
+
'font-size': '1.5rem'
|
|
4178
|
+
};
|
|
4107
4179
|
|
|
4108
4180
|
// Flexbox
|
|
4109
4181
|
var jc = {
|
|
@@ -5420,7 +5492,12 @@
|
|
|
5420
5492
|
},
|
|
5421
5493
|
o: {
|
|
5422
5494
|
type: 'card',
|
|
5423
|
-
state: props.state || {}
|
|
5495
|
+
state: props.state || {},
|
|
5496
|
+
slots: {
|
|
5497
|
+
title: '.bw_card_title',
|
|
5498
|
+
content: '.bw_card_body',
|
|
5499
|
+
footer: '.bw_card_footer'
|
|
5500
|
+
}
|
|
5424
5501
|
}
|
|
5425
5502
|
};
|
|
5426
5503
|
}
|
|
@@ -5433,7 +5510,12 @@
|
|
|
5433
5510
|
c: cardContent,
|
|
5434
5511
|
o: {
|
|
5435
5512
|
type: 'card',
|
|
5436
|
-
state: props.state || {}
|
|
5513
|
+
state: props.state || {},
|
|
5514
|
+
slots: {
|
|
5515
|
+
title: '.bw_card_title',
|
|
5516
|
+
content: '.bw_card_body',
|
|
5517
|
+
footer: '.bw_card_footer'
|
|
5518
|
+
}
|
|
5437
5519
|
}
|
|
5438
5520
|
};
|
|
5439
5521
|
}
|
|
@@ -5790,6 +5872,26 @@
|
|
|
5790
5872
|
actualActiveIndex = index;
|
|
5791
5873
|
}
|
|
5792
5874
|
});
|
|
5875
|
+
|
|
5876
|
+
// Shared tab switching logic
|
|
5877
|
+
function switchTab(el, index) {
|
|
5878
|
+
var allTabs = el.querySelectorAll('.bw_nav_link');
|
|
5879
|
+
var allPanes = el.querySelectorAll('.bw_tab_pane');
|
|
5880
|
+
if (index < 0 || index >= allTabs.length) return;
|
|
5881
|
+
allTabs.forEach(function (t) {
|
|
5882
|
+
t.classList.remove('active');
|
|
5883
|
+
t.setAttribute('aria-selected', 'false');
|
|
5884
|
+
t.setAttribute('tabindex', '-1');
|
|
5885
|
+
});
|
|
5886
|
+
allPanes.forEach(function (p) {
|
|
5887
|
+
p.classList.remove('active');
|
|
5888
|
+
});
|
|
5889
|
+
allTabs[index].classList.add('active');
|
|
5890
|
+
allTabs[index].setAttribute('aria-selected', 'true');
|
|
5891
|
+
allTabs[index].setAttribute('tabindex', '0');
|
|
5892
|
+
allPanes[index].classList.add('active');
|
|
5893
|
+
if (el._bw_state) el._bw_state.activeIndex = index;
|
|
5894
|
+
}
|
|
5793
5895
|
return {
|
|
5794
5896
|
t: 'div',
|
|
5795
5897
|
a: {
|
|
@@ -5816,24 +5918,8 @@
|
|
|
5816
5918
|
role: 'tab',
|
|
5817
5919
|
tabindex: index === actualActiveIndex ? '0' : '-1',
|
|
5818
5920
|
'aria-selected': index === actualActiveIndex ? 'true' : 'false',
|
|
5819
|
-
'data-tab-index': index,
|
|
5820
5921
|
onclick: function onclick(e) {
|
|
5821
|
-
|
|
5822
|
-
var allTabs = tabsContainer.querySelectorAll('.bw_nav_link');
|
|
5823
|
-
var allPanes = tabsContainer.querySelectorAll('.bw_tab_pane');
|
|
5824
|
-
allTabs.forEach(function (t) {
|
|
5825
|
-
t.classList.remove('active');
|
|
5826
|
-
t.setAttribute('aria-selected', 'false');
|
|
5827
|
-
t.setAttribute('tabindex', '-1');
|
|
5828
|
-
});
|
|
5829
|
-
allPanes.forEach(function (p) {
|
|
5830
|
-
return p.classList.remove('active');
|
|
5831
|
-
});
|
|
5832
|
-
e.target.classList.add('active');
|
|
5833
|
-
e.target.setAttribute('aria-selected', 'true');
|
|
5834
|
-
e.target.setAttribute('tabindex', '0');
|
|
5835
|
-
var targetIndex = parseInt(e.target.getAttribute('data-tab-index'));
|
|
5836
|
-
allPanes[targetIndex].classList.add('active');
|
|
5922
|
+
switchTab(e.target.closest('.bw_tabs'), index);
|
|
5837
5923
|
}
|
|
5838
5924
|
},
|
|
5839
5925
|
c: tab.label
|
|
@@ -5861,6 +5947,12 @@
|
|
|
5861
5947
|
state: {
|
|
5862
5948
|
activeIndex: actualActiveIndex
|
|
5863
5949
|
},
|
|
5950
|
+
handle: {
|
|
5951
|
+
setActiveTab: switchTab,
|
|
5952
|
+
getActiveTab: function getActiveTab(el) {
|
|
5953
|
+
return el._bw_state && el._bw_state.activeIndex || 0;
|
|
5954
|
+
}
|
|
5955
|
+
},
|
|
5864
5956
|
mounted: function mounted(el) {
|
|
5865
5957
|
var tablist = el.querySelector('[role="tablist"]');
|
|
5866
5958
|
if (!tablist) return;
|
|
@@ -5950,7 +6042,15 @@
|
|
|
5950
6042
|
}
|
|
5951
6043
|
},
|
|
5952
6044
|
c: '×'
|
|
5953
|
-
}].filter(Boolean)
|
|
6045
|
+
}].filter(Boolean),
|
|
6046
|
+
o: {
|
|
6047
|
+
type: 'alert',
|
|
6048
|
+
handle: {
|
|
6049
|
+
dismiss: function dismiss(el) {
|
|
6050
|
+
if (el && el.parentNode) el.parentNode.removeChild(el);
|
|
6051
|
+
}
|
|
6052
|
+
}
|
|
6053
|
+
}
|
|
5954
6054
|
};
|
|
5955
6055
|
}
|
|
5956
6056
|
|
|
@@ -6052,6 +6152,24 @@
|
|
|
6052
6152
|
'aria-valuemax': max
|
|
6053
6153
|
},
|
|
6054
6154
|
c: label || "".concat(percentage, "%")
|
|
6155
|
+
},
|
|
6156
|
+
o: {
|
|
6157
|
+
type: 'progress',
|
|
6158
|
+
handle: {
|
|
6159
|
+
setValue: function setValue(el, n) {
|
|
6160
|
+
var bar = el.querySelector('.bw_progress_bar');
|
|
6161
|
+
if (!bar) return;
|
|
6162
|
+
var maxVal = parseInt(bar.getAttribute('aria-valuemax')) || 100;
|
|
6163
|
+
var pct = Math.round(n / maxVal * 100);
|
|
6164
|
+
bar.style.width = pct + '%';
|
|
6165
|
+
bar.setAttribute('aria-valuenow', n);
|
|
6166
|
+
bar.textContent = pct + '%';
|
|
6167
|
+
},
|
|
6168
|
+
getValue: function getValue(el) {
|
|
6169
|
+
var bar = el.querySelector('.bw_progress_bar');
|
|
6170
|
+
return bar ? parseInt(bar.getAttribute('aria-valuenow')) || 0 : 0;
|
|
6171
|
+
}
|
|
6172
|
+
}
|
|
6055
6173
|
}
|
|
6056
6174
|
};
|
|
6057
6175
|
}
|
|
@@ -7183,6 +7301,29 @@
|
|
|
7183
7301
|
"class": "bw_pagination ".concat(size ? 'bw_pagination_' + size : '', " ").concat(className).trim()
|
|
7184
7302
|
},
|
|
7185
7303
|
c: items
|
|
7304
|
+
},
|
|
7305
|
+
o: {
|
|
7306
|
+
type: 'pagination',
|
|
7307
|
+
state: {
|
|
7308
|
+
currentPage: currentPage,
|
|
7309
|
+
pages: pages
|
|
7310
|
+
},
|
|
7311
|
+
handle: {
|
|
7312
|
+
setPage: function setPage(el, n) {
|
|
7313
|
+
if (n < 1 || n > pages) return;
|
|
7314
|
+
var allItems = el.querySelectorAll('.bw_page_item');
|
|
7315
|
+
for (var i = 0; i < allItems.length; i++) {
|
|
7316
|
+
allItems[i].classList.remove('bw_active');
|
|
7317
|
+
}
|
|
7318
|
+
// +1 offset: first item is prev arrow
|
|
7319
|
+
if (allItems[n]) allItems[n].classList.add('bw_active');
|
|
7320
|
+
if (el._bw_state) el._bw_state.currentPage = n;
|
|
7321
|
+
if (onPageChange) onPageChange(n);
|
|
7322
|
+
},
|
|
7323
|
+
getPage: function getPage(el) {
|
|
7324
|
+
return el._bw_state && el._bw_state.currentPage || 1;
|
|
7325
|
+
}
|
|
7326
|
+
}
|
|
7186
7327
|
}
|
|
7187
7328
|
};
|
|
7188
7329
|
}
|
|
@@ -7339,7 +7480,6 @@
|
|
|
7339
7480
|
"class": "bw_accordion_button ".concat(item.open ? '' : 'bw_collapsed').trim(),
|
|
7340
7481
|
type: 'button',
|
|
7341
7482
|
'aria-expanded': item.open ? 'true' : 'false',
|
|
7342
|
-
'data-accordion-index': index,
|
|
7343
7483
|
onclick: function onclick(e) {
|
|
7344
7484
|
var btn = e.target.closest('.bw_accordion_button');
|
|
7345
7485
|
var accordionEl = btn.closest('.bw_accordion');
|
|
@@ -7416,6 +7556,42 @@
|
|
|
7416
7556
|
type: 'accordion',
|
|
7417
7557
|
state: {
|
|
7418
7558
|
multiOpen: multiOpen
|
|
7559
|
+
},
|
|
7560
|
+
handle: {
|
|
7561
|
+
toggle: function toggle(el, index) {
|
|
7562
|
+
var items = el.querySelectorAll('.bw_accordion_item');
|
|
7563
|
+
if (index < 0 || index >= items.length) return;
|
|
7564
|
+
var btn = items[index].querySelector('.bw_accordion_button');
|
|
7565
|
+
if (btn) btn.click();
|
|
7566
|
+
},
|
|
7567
|
+
openAll: function openAll(el) {
|
|
7568
|
+
var items = el.querySelectorAll('.bw_accordion_item');
|
|
7569
|
+
for (var i = 0; i < items.length; i++) {
|
|
7570
|
+
var collapse = items[i].querySelector('.bw_accordion_collapse');
|
|
7571
|
+
var btn = items[i].querySelector('.bw_accordion_button');
|
|
7572
|
+
if (!collapse.classList.contains('bw_collapse_show')) {
|
|
7573
|
+
collapse.classList.add('bw_collapse_show');
|
|
7574
|
+
collapse.style.maxHeight = 'none';
|
|
7575
|
+
btn.classList.remove('bw_collapsed');
|
|
7576
|
+
btn.setAttribute('aria-expanded', 'true');
|
|
7577
|
+
}
|
|
7578
|
+
}
|
|
7579
|
+
},
|
|
7580
|
+
closeAll: function closeAll(el) {
|
|
7581
|
+
var items = el.querySelectorAll('.bw_accordion_item');
|
|
7582
|
+
for (var i = 0; i < items.length; i++) {
|
|
7583
|
+
var collapse = items[i].querySelector('.bw_accordion_collapse');
|
|
7584
|
+
var btn = items[i].querySelector('.bw_accordion_button');
|
|
7585
|
+
if (collapse.classList.contains('bw_collapse_show')) {
|
|
7586
|
+
collapse.style.maxHeight = collapse.scrollHeight + 'px';
|
|
7587
|
+
collapse.offsetHeight;
|
|
7588
|
+
collapse.style.maxHeight = '0px';
|
|
7589
|
+
collapse.classList.remove('bw_collapse_show');
|
|
7590
|
+
btn.classList.add('bw_collapsed');
|
|
7591
|
+
btn.setAttribute('aria-expanded', 'false');
|
|
7592
|
+
}
|
|
7593
|
+
}
|
|
7594
|
+
}
|
|
7419
7595
|
}
|
|
7420
7596
|
}
|
|
7421
7597
|
};
|
|
@@ -7518,6 +7694,16 @@
|
|
|
7518
7694
|
},
|
|
7519
7695
|
o: {
|
|
7520
7696
|
type: 'modal',
|
|
7697
|
+
handle: {
|
|
7698
|
+
open: function open(el) {
|
|
7699
|
+
el.classList.add('bw_modal_show');
|
|
7700
|
+
el.style.display = 'flex';
|
|
7701
|
+
document.body.style.overflow = 'hidden';
|
|
7702
|
+
},
|
|
7703
|
+
close: function close(el) {
|
|
7704
|
+
closeModal(el);
|
|
7705
|
+
}
|
|
7706
|
+
},
|
|
7521
7707
|
mounted: function mounted(el) {
|
|
7522
7708
|
// Click backdrop to close
|
|
7523
7709
|
el.addEventListener('click', function (e) {
|
|
@@ -7579,9 +7765,8 @@
|
|
|
7579
7765
|
return {
|
|
7580
7766
|
t: 'div',
|
|
7581
7767
|
a: {
|
|
7582
|
-
"class": "bw_toast ".concat(variantClass(variant), " ").concat(className).trim(),
|
|
7583
|
-
role: 'alert'
|
|
7584
|
-
'data-position': position
|
|
7768
|
+
"class": "bw_toast ".concat(variantClass(variant), " bw_toast_").concat(position.replace(/-/g, '_'), " ").concat(className).trim(),
|
|
7769
|
+
role: 'alert'
|
|
7585
7770
|
},
|
|
7586
7771
|
c: [title && {
|
|
7587
7772
|
t: 'div',
|
|
@@ -7618,6 +7803,14 @@
|
|
|
7618
7803
|
}].filter(Boolean),
|
|
7619
7804
|
o: {
|
|
7620
7805
|
type: 'toast',
|
|
7806
|
+
handle: {
|
|
7807
|
+
dismiss: function dismiss(el) {
|
|
7808
|
+
el.classList.add('bw_toast_hiding');
|
|
7809
|
+
setTimeout(function () {
|
|
7810
|
+
if (el.parentNode) el.parentNode.removeChild(el);
|
|
7811
|
+
}, 300);
|
|
7812
|
+
}
|
|
7813
|
+
},
|
|
7621
7814
|
mounted: function mounted(el) {
|
|
7622
7815
|
// Trigger show animation
|
|
7623
7816
|
requestAnimationFrame(function () {
|
|
@@ -7993,11 +8186,11 @@
|
|
|
7993
8186
|
className = _props$className26 === void 0 ? '' : _props$className26;
|
|
7994
8187
|
|
|
7995
8188
|
// Shared navigation logic
|
|
7996
|
-
function
|
|
8189
|
+
function _goToSlide(carouselEl, index) {
|
|
7997
8190
|
var total = carouselEl.querySelectorAll('.bw_carousel_slide').length;
|
|
7998
8191
|
if (index < 0) index = total - 1;
|
|
7999
8192
|
if (index >= total) index = 0;
|
|
8000
|
-
carouselEl.
|
|
8193
|
+
carouselEl._bw_carouselIndex = index;
|
|
8001
8194
|
var track = carouselEl.querySelector('.bw_carousel_track');
|
|
8002
8195
|
track.style.transform = 'translateX(-' + index * 100 + '%)';
|
|
8003
8196
|
// Update indicators
|
|
@@ -8051,8 +8244,8 @@
|
|
|
8051
8244
|
'aria-label': 'Previous slide',
|
|
8052
8245
|
onclick: function onclick(e) {
|
|
8053
8246
|
var carousel = e.target.closest('.bw_carousel');
|
|
8054
|
-
var idx =
|
|
8055
|
-
|
|
8247
|
+
var idx = carousel._bw_carouselIndex || 0;
|
|
8248
|
+
_goToSlide(carousel, idx - 1);
|
|
8056
8249
|
}
|
|
8057
8250
|
},
|
|
8058
8251
|
c: {
|
|
@@ -8072,8 +8265,8 @@
|
|
|
8072
8265
|
'aria-label': 'Next slide',
|
|
8073
8266
|
onclick: function onclick(e) {
|
|
8074
8267
|
var carousel = e.target.closest('.bw_carousel');
|
|
8075
|
-
var idx =
|
|
8076
|
-
|
|
8268
|
+
var idx = carousel._bw_carouselIndex || 0;
|
|
8269
|
+
_goToSlide(carousel, idx + 1);
|
|
8077
8270
|
}
|
|
8078
8271
|
},
|
|
8079
8272
|
c: {
|
|
@@ -8101,11 +8294,9 @@
|
|
|
8101
8294
|
"class": 'bw_carousel_indicator' + (i === startIndex ? ' active' : ''),
|
|
8102
8295
|
type: 'button',
|
|
8103
8296
|
'aria-label': 'Go to slide ' + (i + 1),
|
|
8104
|
-
'data-slide-index': i,
|
|
8105
8297
|
onclick: function onclick(e) {
|
|
8106
8298
|
var carousel = e.target.closest('.bw_carousel');
|
|
8107
|
-
|
|
8108
|
-
goToSlide(carousel, idx);
|
|
8299
|
+
_goToSlide(carousel, i);
|
|
8109
8300
|
}
|
|
8110
8301
|
}
|
|
8111
8302
|
};
|
|
@@ -8118,8 +8309,7 @@
|
|
|
8118
8309
|
"class": ('bw_carousel ' + className).trim(),
|
|
8119
8310
|
style: 'height: ' + height,
|
|
8120
8311
|
tabindex: '0',
|
|
8121
|
-
'aria-roledescription': 'carousel'
|
|
8122
|
-
'data-carousel-index': startIndex
|
|
8312
|
+
'aria-roledescription': 'carousel'
|
|
8123
8313
|
},
|
|
8124
8314
|
c: children,
|
|
8125
8315
|
o: {
|
|
@@ -8129,23 +8319,52 @@
|
|
|
8129
8319
|
autoPlay: autoPlay,
|
|
8130
8320
|
interval: interval
|
|
8131
8321
|
},
|
|
8322
|
+
handle: {
|
|
8323
|
+
goToSlide: function goToSlide(el, index) {
|
|
8324
|
+
_goToSlide(el, index);
|
|
8325
|
+
},
|
|
8326
|
+
next: function next(el) {
|
|
8327
|
+
_goToSlide(el, (el._bw_carouselIndex || 0) + 1);
|
|
8328
|
+
},
|
|
8329
|
+
prev: function prev(el) {
|
|
8330
|
+
_goToSlide(el, (el._bw_carouselIndex || 0) - 1);
|
|
8331
|
+
},
|
|
8332
|
+
getActiveIndex: function getActiveIndex(el) {
|
|
8333
|
+
return el._bw_carouselIndex || 0;
|
|
8334
|
+
},
|
|
8335
|
+
pause: function pause(el) {
|
|
8336
|
+
if (el._bw_carouselInterval) {
|
|
8337
|
+
clearInterval(el._bw_carouselInterval);
|
|
8338
|
+
el._bw_carouselInterval = null;
|
|
8339
|
+
}
|
|
8340
|
+
},
|
|
8341
|
+
play: function play(el) {
|
|
8342
|
+
if (!el._bw_carouselInterval && el._bw_state) {
|
|
8343
|
+
var ms = el._bw_state.interval || 5000;
|
|
8344
|
+
el._bw_carouselInterval = setInterval(function () {
|
|
8345
|
+
_goToSlide(el, (el._bw_carouselIndex || 0) + 1);
|
|
8346
|
+
}, ms);
|
|
8347
|
+
}
|
|
8348
|
+
}
|
|
8349
|
+
},
|
|
8132
8350
|
mounted: function mounted(el) {
|
|
8351
|
+
el._bw_carouselIndex = startIndex;
|
|
8133
8352
|
// Keyboard navigation
|
|
8134
8353
|
el.addEventListener('keydown', function (e) {
|
|
8135
|
-
var idx =
|
|
8354
|
+
var idx = el._bw_carouselIndex || 0;
|
|
8136
8355
|
if (e.key === 'ArrowLeft') {
|
|
8137
8356
|
e.preventDefault();
|
|
8138
|
-
|
|
8357
|
+
_goToSlide(el, idx - 1);
|
|
8139
8358
|
} else if (e.key === 'ArrowRight') {
|
|
8140
8359
|
e.preventDefault();
|
|
8141
|
-
|
|
8360
|
+
_goToSlide(el, idx + 1);
|
|
8142
8361
|
}
|
|
8143
8362
|
});
|
|
8144
8363
|
// Auto-play
|
|
8145
8364
|
if (autoPlay) {
|
|
8146
8365
|
var intervalId = setInterval(function () {
|
|
8147
|
-
var idx =
|
|
8148
|
-
|
|
8366
|
+
var idx = el._bw_carouselIndex || 0;
|
|
8367
|
+
_goToSlide(el, idx + 1);
|
|
8149
8368
|
}, interval);
|
|
8150
8369
|
el._bw_carouselInterval = intervalId;
|
|
8151
8370
|
// Pause on hover/focus for usability
|
|
@@ -8154,8 +8373,8 @@
|
|
|
8154
8373
|
});
|
|
8155
8374
|
el.addEventListener('mouseleave', function () {
|
|
8156
8375
|
el._bw_carouselInterval = setInterval(function () {
|
|
8157
|
-
var idx =
|
|
8158
|
-
|
|
8376
|
+
var idx = el._bw_carouselIndex || 0;
|
|
8377
|
+
_goToSlide(el, idx + 1);
|
|
8159
8378
|
}, interval);
|
|
8160
8379
|
});
|
|
8161
8380
|
}
|
|
@@ -8276,7 +8495,11 @@
|
|
|
8276
8495
|
},
|
|
8277
8496
|
c: children,
|
|
8278
8497
|
o: {
|
|
8279
|
-
type: 'stat-card'
|
|
8498
|
+
type: 'stat-card',
|
|
8499
|
+
slots: {
|
|
8500
|
+
value: '.bw_stat_value',
|
|
8501
|
+
label: '.bw_stat_label'
|
|
8502
|
+
}
|
|
8280
8503
|
}
|
|
8281
8504
|
};
|
|
8282
8505
|
}
|
|
@@ -9013,8 +9236,7 @@
|
|
|
9013
9236
|
return {
|
|
9014
9237
|
t: 'span',
|
|
9015
9238
|
a: {
|
|
9016
|
-
"class": 'bw_chip'
|
|
9017
|
-
'data-chip-value': text
|
|
9239
|
+
"class": 'bw_chip'
|
|
9018
9240
|
},
|
|
9019
9241
|
c: [text, {
|
|
9020
9242
|
t: 'button',
|
|
@@ -9024,9 +9246,8 @@
|
|
|
9024
9246
|
'aria-label': 'Remove ' + text,
|
|
9025
9247
|
onclick: function onclick(e) {
|
|
9026
9248
|
var chip = e.target.closest('.bw_chip');
|
|
9027
|
-
var val = chip.getAttribute('data-chip-value');
|
|
9028
9249
|
chip.parentNode.removeChild(chip);
|
|
9029
|
-
if (onRemove) onRemove(
|
|
9250
|
+
if (onRemove) onRemove(text);
|
|
9030
9251
|
}
|
|
9031
9252
|
},
|
|
9032
9253
|
c: "\xD7"
|
|
@@ -9052,7 +9273,7 @@
|
|
|
9052
9273
|
// Insert chip before the input
|
|
9053
9274
|
var chipEl = document.createElement('span');
|
|
9054
9275
|
chipEl.className = 'bw_chip';
|
|
9055
|
-
chipEl.
|
|
9276
|
+
chipEl._bw_chipValue = val;
|
|
9056
9277
|
chipEl.innerHTML = '';
|
|
9057
9278
|
chipEl.textContent = val;
|
|
9058
9279
|
var removeBtn = document.createElement('button');
|
|
@@ -9075,7 +9296,7 @@
|
|
|
9075
9296
|
var chipEls = wrapper.querySelectorAll('.bw_chip');
|
|
9076
9297
|
if (chipEls.length) {
|
|
9077
9298
|
var last = chipEls[chipEls.length - 1];
|
|
9078
|
-
var removedVal = last.
|
|
9299
|
+
var removedVal = last._bw_chipValue || last.firstChild.textContent;
|
|
9079
9300
|
last.parentNode.removeChild(last);
|
|
9080
9301
|
if (onRemove) onRemove(removedVal);
|
|
9081
9302
|
}
|
|
@@ -9084,7 +9305,50 @@
|
|
|
9084
9305
|
}
|
|
9085
9306
|
}]),
|
|
9086
9307
|
o: {
|
|
9087
|
-
type: 'chip-input'
|
|
9308
|
+
type: 'chip-input',
|
|
9309
|
+
handle: {
|
|
9310
|
+
addChip: function addChip(el, text) {
|
|
9311
|
+
if (!text) return;
|
|
9312
|
+
var input = el.querySelector('.bw_chip_field');
|
|
9313
|
+
var chipEl = document.createElement('span');
|
|
9314
|
+
chipEl.className = 'bw_chip';
|
|
9315
|
+
chipEl._bw_chipValue = text;
|
|
9316
|
+
chipEl.textContent = text;
|
|
9317
|
+
var removeBtn = document.createElement('button');
|
|
9318
|
+
removeBtn.type = 'button';
|
|
9319
|
+
removeBtn.className = 'bw_chip_remove';
|
|
9320
|
+
removeBtn.setAttribute('aria-label', 'Remove ' + text);
|
|
9321
|
+
removeBtn.textContent = "\xD7";
|
|
9322
|
+
removeBtn.onclick = function () {
|
|
9323
|
+
chipEl.parentNode.removeChild(chipEl);
|
|
9324
|
+
};
|
|
9325
|
+
chipEl.appendChild(removeBtn);
|
|
9326
|
+
el.insertBefore(chipEl, input);
|
|
9327
|
+
},
|
|
9328
|
+
removeChip: function removeChip(el, text) {
|
|
9329
|
+
var chips = el.querySelectorAll('.bw_chip');
|
|
9330
|
+
for (var i = 0; i < chips.length; i++) {
|
|
9331
|
+
if ((chips[i]._bw_chipValue || chips[i].firstChild.textContent) === text) {
|
|
9332
|
+
chips[i].parentNode.removeChild(chips[i]);
|
|
9333
|
+
return;
|
|
9334
|
+
}
|
|
9335
|
+
}
|
|
9336
|
+
},
|
|
9337
|
+
getChips: function getChips(el) {
|
|
9338
|
+
var chips = el.querySelectorAll('.bw_chip');
|
|
9339
|
+
var values = [];
|
|
9340
|
+
for (var i = 0; i < chips.length; i++) {
|
|
9341
|
+
values.push(chips[i]._bw_chipValue || chips[i].firstChild.textContent);
|
|
9342
|
+
}
|
|
9343
|
+
return values;
|
|
9344
|
+
},
|
|
9345
|
+
clear: function clear(el) {
|
|
9346
|
+
var chips = el.querySelectorAll('.bw_chip');
|
|
9347
|
+
for (var i = chips.length - 1; i >= 0; i--) {
|
|
9348
|
+
chips[i].parentNode.removeChild(chips[i]);
|
|
9349
|
+
}
|
|
9350
|
+
}
|
|
9351
|
+
}
|
|
9088
9352
|
}
|
|
9089
9353
|
};
|
|
9090
9354
|
}
|
|
@@ -9362,12 +9626,11 @@
|
|
|
9362
9626
|
// monotonic ID for subscriptions
|
|
9363
9627
|
|
|
9364
9628
|
// ── Node reference cache ──────────────────────────────────────────────
|
|
9365
|
-
// Fast O(1) lookup for elements by
|
|
9629
|
+
// Fast O(1) lookup for elements by id attribute or bw_uuid_* class.
|
|
9366
9630
|
//
|
|
9367
9631
|
// Populated by bw.createDOM() when elements have:
|
|
9368
|
-
// - data-bw_id attribute (user-declared addressable elements)
|
|
9369
9632
|
// - id attribute (standard HTML id)
|
|
9370
|
-
// -
|
|
9633
|
+
// - bw_uuid_* class (lifecycle-managed or explicitly addressed elements)
|
|
9371
9634
|
//
|
|
9372
9635
|
// Cleaned up by bw.cleanup() when elements are destroyed via bitwrench APIs.
|
|
9373
9636
|
// On cache miss, falls back to querySelector/getElementById — never fails,
|
|
@@ -9375,7 +9638,7 @@
|
|
|
9375
9638
|
// via parentNode === null check (IE11-safe, unlike el.isConnected).
|
|
9376
9639
|
//
|
|
9377
9640
|
// Elements created via bw.createDOM() also get el._bw_refs — a local map of
|
|
9378
|
-
// child
|
|
9641
|
+
// child id/UUID -> DOM node ref for fast parent->child access in o.render.
|
|
9379
9642
|
// This is the bitwrench equivalent of React's compiled template "holes".
|
|
9380
9643
|
//
|
|
9381
9644
|
// Contract: if you remove elements outside of bitwrench APIs (raw el.remove()),
|
|
@@ -9454,7 +9717,6 @@
|
|
|
9454
9717
|
// _cw console.warn 8
|
|
9455
9718
|
// _cl console.log 11
|
|
9456
9719
|
// _ce console.error 4
|
|
9457
|
-
// _chp ComponentHandle.prototype 28 (defined after constructor)
|
|
9458
9720
|
//
|
|
9459
9721
|
// Note: document.createElement etc. are NOT aliased because they require
|
|
9460
9722
|
// `this === document` and .bind() would add overhead on every call.
|
|
@@ -9638,15 +9900,15 @@
|
|
|
9638
9900
|
* 1. Check `bw._nodeMap[id]` — if found and still attached (parentNode !== null), return it
|
|
9639
9901
|
* 2. If cached ref is detached (parentNode === null), remove stale entry
|
|
9640
9902
|
* 3. Fall back to `document.getElementById(id)` then `document.querySelector(...)`
|
|
9641
|
-
* 4.
|
|
9642
|
-
* 5.
|
|
9903
|
+
* 4. Try class-based lookup for bw_uuid_* tokens (UUID addressing)
|
|
9904
|
+
* 5. Cache the result for next time
|
|
9643
9905
|
*
|
|
9644
9906
|
* Accepts a DOM element directly (pass-through) or a string identifier.
|
|
9645
9907
|
* String identifiers are tried as: direct map key, getElementById,
|
|
9646
9908
|
* querySelector (for CSS selectors starting with . or #), and
|
|
9647
|
-
*
|
|
9909
|
+
* bw_uuid_* class selector.
|
|
9648
9910
|
*
|
|
9649
|
-
* @param {string|Element} id - Element ID, CSS selector,
|
|
9911
|
+
* @param {string|Element} id - Element ID, CSS selector, bw_uuid_* class, or DOM element
|
|
9650
9912
|
* @returns {Element|null} The DOM element, or null if not found
|
|
9651
9913
|
* @category Internal
|
|
9652
9914
|
*/
|
|
@@ -9675,17 +9937,12 @@
|
|
|
9675
9937
|
el = document.querySelector(id);
|
|
9676
9938
|
}
|
|
9677
9939
|
|
|
9678
|
-
// 4. Try
|
|
9679
|
-
if (!el) {
|
|
9680
|
-
el = document.querySelector('[data-bw_id="' + id + '"]');
|
|
9681
|
-
}
|
|
9682
|
-
|
|
9683
|
-
// 5. Try class-based lookup for bw_uuid_* tokens (UUID addressing)
|
|
9940
|
+
// 4. Try class-based lookup for bw_uuid_* tokens (UUID addressing)
|
|
9684
9941
|
if (!el && id.indexOf('bw_uuid_') === 0) {
|
|
9685
9942
|
el = document.querySelector('.' + id);
|
|
9686
9943
|
}
|
|
9687
9944
|
|
|
9688
|
-
//
|
|
9945
|
+
// 5. Cache the result for next time
|
|
9689
9946
|
if (el) {
|
|
9690
9947
|
bw._nodeMap[id] = el;
|
|
9691
9948
|
}
|
|
@@ -9696,17 +9953,17 @@
|
|
|
9696
9953
|
* Register a DOM element in the node cache under one or more keys.
|
|
9697
9954
|
*
|
|
9698
9955
|
* Called internally by `bw.createDOM()`. Registers elements that have
|
|
9699
|
-
* id attributes,
|
|
9956
|
+
* id attributes, UUID classes, or both.
|
|
9700
9957
|
*
|
|
9701
9958
|
* @param {Element} el - DOM element to register
|
|
9702
|
-
* @param {string} [
|
|
9959
|
+
* @param {string} [uuid] - bw_uuid_* class token to register under
|
|
9703
9960
|
* @category Internal
|
|
9704
9961
|
*/
|
|
9705
|
-
bw._registerNode = function (el,
|
|
9962
|
+
bw._registerNode = function (el, uuid) {
|
|
9706
9963
|
if (!el) return;
|
|
9707
|
-
// Register under
|
|
9708
|
-
if (
|
|
9709
|
-
bw._nodeMap[
|
|
9964
|
+
// Register under UUID class token
|
|
9965
|
+
if (uuid) {
|
|
9966
|
+
bw._nodeMap[uuid] = el;
|
|
9710
9967
|
}
|
|
9711
9968
|
// Register under id attribute
|
|
9712
9969
|
var htmlId = el.getAttribute ? el.getAttribute('id') : null;
|
|
@@ -9722,13 +9979,13 @@
|
|
|
9722
9979
|
* through bitwrench APIs.
|
|
9723
9980
|
*
|
|
9724
9981
|
* @param {Element} el - DOM element to deregister
|
|
9725
|
-
* @param {string} [
|
|
9982
|
+
* @param {string} [uuid] - bw_uuid_* class token to remove
|
|
9726
9983
|
* @category Internal
|
|
9727
9984
|
*/
|
|
9728
|
-
bw._deregisterNode = function (el,
|
|
9729
|
-
// Remove
|
|
9730
|
-
if (
|
|
9731
|
-
delete bw._nodeMap[
|
|
9985
|
+
bw._deregisterNode = function (el, uuid) {
|
|
9986
|
+
// Remove UUID class entry
|
|
9987
|
+
if (uuid) {
|
|
9988
|
+
delete bw._nodeMap[uuid];
|
|
9732
9989
|
}
|
|
9733
9990
|
// Remove id attribute entry
|
|
9734
9991
|
var htmlId = el && el.getAttribute ? el.getAttribute('id') : null;
|
|
@@ -9741,6 +9998,13 @@
|
|
|
9741
9998
|
// bw.assignUUID() / bw.getUUID() — Explicit UUID addressing for TACO objects
|
|
9742
9999
|
// ===================================================================================
|
|
9743
10000
|
|
|
10001
|
+
/**
|
|
10002
|
+
* Marker class for elements with lifecycle hooks (mounted/unmount/render/state).
|
|
10003
|
+
* Used by cleanup() to find lifecycle-managed elements via querySelectorAll('.bw_lc').
|
|
10004
|
+
* @private
|
|
10005
|
+
*/
|
|
10006
|
+
var _BW_LC = 'bw_lc';
|
|
10007
|
+
|
|
9744
10008
|
/**
|
|
9745
10009
|
* Regex to match a bw_uuid_* token in a class string.
|
|
9746
10010
|
* @private
|
|
@@ -9926,20 +10190,10 @@
|
|
|
9926
10190
|
* // => '<div class="card"><p>Content here</p></div>'
|
|
9927
10191
|
*/
|
|
9928
10192
|
bw.html = function (taco) {
|
|
9929
|
-
var _attrs$class;
|
|
9930
10193
|
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
9931
10194
|
// Handle null/undefined
|
|
9932
10195
|
if (taco == null) return '';
|
|
9933
10196
|
|
|
9934
|
-
// Handle ComponentHandle — use its .taco
|
|
9935
|
-
if (taco && taco._bwComponent === true) {
|
|
9936
|
-
var compOptions = Object.assign({}, options);
|
|
9937
|
-
if (!compOptions.state && taco._state) {
|
|
9938
|
-
compOptions.state = taco._state;
|
|
9939
|
-
}
|
|
9940
|
-
return bw.html(taco.taco, compOptions);
|
|
9941
|
-
}
|
|
9942
|
-
|
|
9943
10197
|
// Handle arrays of TACOs
|
|
9944
10198
|
if (_isA(taco)) {
|
|
9945
10199
|
return taco.map(function (t) {
|
|
@@ -9952,24 +10206,6 @@
|
|
|
9952
10206
|
return taco.v;
|
|
9953
10207
|
}
|
|
9954
10208
|
|
|
9955
|
-
// Handle bw.when() markers
|
|
9956
|
-
if (taco && taco._bwWhen && options.state) {
|
|
9957
|
-
var whenExpr = taco.expr.replace(/^\$\{|\}$/g, '');
|
|
9958
|
-
var whenVal = options.compile ? bw._resolveTemplate('${' + whenExpr + '}', options.state, true) : bw._evaluatePath(options.state, whenExpr);
|
|
9959
|
-
var branch = whenVal ? taco.branches[0] : taco.branches[1] || null;
|
|
9960
|
-
return branch ? bw.html(branch, options) : '';
|
|
9961
|
-
}
|
|
9962
|
-
|
|
9963
|
-
// Handle bw.each() markers
|
|
9964
|
-
if (taco && taco._bwEach && options.state) {
|
|
9965
|
-
var eachExpr = taco.expr.replace(/^\$\{|\}$/g, '');
|
|
9966
|
-
var arr = bw._evaluatePath(options.state, eachExpr);
|
|
9967
|
-
if (!_isA(arr)) return '';
|
|
9968
|
-
return arr.map(function (item, idx) {
|
|
9969
|
-
return bw.html(taco.factory(item, idx), options);
|
|
9970
|
-
}).join('');
|
|
9971
|
-
}
|
|
9972
|
-
|
|
9973
10209
|
// Handle primitives and non-TACO objects
|
|
9974
10210
|
if (!_is(taco, 'object') || !taco.t) {
|
|
9975
10211
|
var str = options.raw ? String(taco) : bw.escapeHTML(String(taco));
|
|
@@ -10043,14 +10279,14 @@
|
|
|
10043
10279
|
}
|
|
10044
10280
|
}
|
|
10045
10281
|
|
|
10046
|
-
// Add
|
|
10047
|
-
if ((opts.mounted || opts.unmount) && !(
|
|
10048
|
-
var
|
|
10282
|
+
// Add bw_uuid + bw_lc classes if lifecycle hooks present
|
|
10283
|
+
if ((opts.mounted || opts.unmount) && !_UUID_RE.test(attrs["class"] || '')) {
|
|
10284
|
+
var uuid = bw.uuid('uuid');
|
|
10049
10285
|
attrStr = attrStr.replace(/class="([^"]*)"/, function (_match, classes) {
|
|
10050
|
-
return "class=\"".concat(classes, "
|
|
10286
|
+
return "class=\"".concat(classes, " ").concat(uuid, " ").concat(_BW_LC, "\"").trim();
|
|
10051
10287
|
});
|
|
10052
10288
|
if (!attrStr.includes('class=')) {
|
|
10053
|
-
attrStr += " class=\"
|
|
10289
|
+
attrStr += " class=\"".concat(uuid, " ").concat(_BW_LC, "\"");
|
|
10054
10290
|
}
|
|
10055
10291
|
}
|
|
10056
10292
|
|
|
@@ -10277,11 +10513,6 @@
|
|
|
10277
10513
|
return frag;
|
|
10278
10514
|
}
|
|
10279
10515
|
|
|
10280
|
-
// Handle ComponentHandle — extract .taco for DOM creation
|
|
10281
|
-
if (taco && taco._bwComponent === true) {
|
|
10282
|
-
return bw.createDOM(taco.taco, options);
|
|
10283
|
-
}
|
|
10284
|
-
|
|
10285
10516
|
// Handle text nodes
|
|
10286
10517
|
if (!_is(taco, 'object') || !taco.t) {
|
|
10287
10518
|
return document.createTextNode(String(taco));
|
|
@@ -10328,24 +10559,19 @@
|
|
|
10328
10559
|
}
|
|
10329
10560
|
|
|
10330
10561
|
// Add children, building _bw_refs for fast parent→child access.
|
|
10331
|
-
// Children with
|
|
10562
|
+
// Children with id attributes or bw_uuid_* classes get local refs on the parent,
|
|
10332
10563
|
// so o.render functions can access them without any DOM lookup.
|
|
10333
10564
|
if (content != null) {
|
|
10334
10565
|
if (_isA(content)) {
|
|
10335
10566
|
content.forEach(function (child) {
|
|
10336
10567
|
if (child != null) {
|
|
10337
|
-
// Handle ComponentHandle in content arrays (Level 2 children)
|
|
10338
|
-
if (child._bwComponent === true) {
|
|
10339
|
-
child.mount(el);
|
|
10340
|
-
return;
|
|
10341
|
-
}
|
|
10342
10568
|
var childEl = bw.createDOM(child, options);
|
|
10343
10569
|
el.appendChild(childEl);
|
|
10344
10570
|
// Build local refs for addressable children
|
|
10345
|
-
var
|
|
10346
|
-
if (
|
|
10571
|
+
var childRefId = child && child.a ? child.a.id || bw.getUUID(child) : null;
|
|
10572
|
+
if (childRefId) {
|
|
10347
10573
|
if (!el._bw_refs) el._bw_refs = {};
|
|
10348
|
-
el._bw_refs[
|
|
10574
|
+
el._bw_refs[childRefId] = childEl;
|
|
10349
10575
|
}
|
|
10350
10576
|
// Bubble up grandchild refs (flatten one level)
|
|
10351
10577
|
if (childEl._bw_refs) {
|
|
@@ -10361,16 +10587,13 @@
|
|
|
10361
10587
|
} else if (_is(content, 'object') && content.__bw_raw) {
|
|
10362
10588
|
// Raw HTML content — inject via innerHTML
|
|
10363
10589
|
el.innerHTML = content.v;
|
|
10364
|
-
} else if (content._bwComponent === true) {
|
|
10365
|
-
// Single ComponentHandle as content
|
|
10366
|
-
content.mount(el);
|
|
10367
10590
|
} else if (_is(content, 'object') && content.t) {
|
|
10368
10591
|
var childEl = bw.createDOM(content, options);
|
|
10369
10592
|
el.appendChild(childEl);
|
|
10370
|
-
var
|
|
10371
|
-
if (
|
|
10593
|
+
var childRefId = content.a ? content.a.id || bw.getUUID(content) : null;
|
|
10594
|
+
if (childRefId) {
|
|
10372
10595
|
if (!el._bw_refs) el._bw_refs = {};
|
|
10373
|
-
el._bw_refs[
|
|
10596
|
+
el._bw_refs[childRefId] = childEl;
|
|
10374
10597
|
}
|
|
10375
10598
|
if (childEl._bw_refs) {
|
|
10376
10599
|
if (!el._bw_refs) el._bw_refs = {};
|
|
@@ -10400,56 +10623,87 @@
|
|
|
10400
10623
|
|
|
10401
10624
|
// Handle lifecycle hooks and state
|
|
10402
10625
|
if (opts.mounted || opts.unmount || opts.render || opts.state) {
|
|
10403
|
-
|
|
10404
|
-
el.
|
|
10626
|
+
// Ensure element has a UUID class for identity
|
|
10627
|
+
var uuid = bw.getUUID(el) || bw.uuid('uuid');
|
|
10628
|
+
el.classList.add(uuid);
|
|
10629
|
+
el.classList.add(_BW_LC);
|
|
10405
10630
|
|
|
10406
|
-
// Register in node cache under
|
|
10407
|
-
bw._registerNode(el,
|
|
10631
|
+
// Register in node cache under UUID class
|
|
10632
|
+
bw._registerNode(el, uuid);
|
|
10408
10633
|
|
|
10409
10634
|
// Store state
|
|
10410
10635
|
if (opts.state) {
|
|
10411
10636
|
el._bw_state = opts.state;
|
|
10412
10637
|
}
|
|
10413
10638
|
|
|
10414
|
-
// o.render —
|
|
10639
|
+
// o.render — store the render function for bw.update()
|
|
10415
10640
|
if (opts.render) {
|
|
10416
10641
|
el._bw_render = opts.render;
|
|
10417
|
-
|
|
10418
|
-
_cw('bw.createDOM: o.render and o.mounted are mutually exclusive. o.render wins.');
|
|
10419
|
-
}
|
|
10642
|
+
}
|
|
10420
10643
|
|
|
10421
|
-
|
|
10644
|
+
// Determine what to call on mount:
|
|
10645
|
+
// - If o.mounted exists, call it (it can call el._bw_render() for initial render)
|
|
10646
|
+
// - Otherwise if o.render exists, auto-call it as a convenience shorthand
|
|
10647
|
+
var mountFn = opts.mounted || (opts.render ? function (mountEl) {
|
|
10648
|
+
opts.render(mountEl, mountEl._bw_state || {});
|
|
10649
|
+
} : null);
|
|
10650
|
+
if (mountFn) {
|
|
10422
10651
|
if (document.body.contains(el)) {
|
|
10423
|
-
|
|
10652
|
+
mountFn(el, el._bw_state || {});
|
|
10424
10653
|
} else {
|
|
10425
10654
|
requestAnimationFrame(function () {
|
|
10426
10655
|
if (document.body.contains(el)) {
|
|
10427
|
-
|
|
10428
|
-
}
|
|
10429
|
-
});
|
|
10430
|
-
}
|
|
10431
|
-
} else if (opts.mounted) {
|
|
10432
|
-
// Queue mounted callback (legacy pattern)
|
|
10433
|
-
if (document.body.contains(el)) {
|
|
10434
|
-
opts.mounted(el, el._bw_state || {});
|
|
10435
|
-
} else {
|
|
10436
|
-
requestAnimationFrame(function () {
|
|
10437
|
-
if (document.body.contains(el)) {
|
|
10438
|
-
opts.mounted(el, el._bw_state || {});
|
|
10656
|
+
mountFn(el, el._bw_state || {});
|
|
10439
10657
|
}
|
|
10440
10658
|
});
|
|
10441
10659
|
}
|
|
10442
10660
|
}
|
|
10443
10661
|
|
|
10444
|
-
// Store unmount callback
|
|
10662
|
+
// Store unmount callback keyed by UUID class
|
|
10445
10663
|
if (opts.unmount) {
|
|
10446
|
-
bw._unmountCallbacks.set(
|
|
10664
|
+
bw._unmountCallbacks.set(uuid, function () {
|
|
10447
10665
|
opts.unmount(el, el._bw_state || {});
|
|
10448
10666
|
});
|
|
10449
10667
|
}
|
|
10450
|
-
}
|
|
10451
|
-
|
|
10452
|
-
|
|
10668
|
+
}
|
|
10669
|
+
|
|
10670
|
+
// Component handle: attach methods to el.bw namespace
|
|
10671
|
+
if (opts.handle || opts.slots) {
|
|
10672
|
+
if (!el.bw) el.bw = {};
|
|
10673
|
+
|
|
10674
|
+
// Explicit handle methods: fn(el, ...args) -> el.bw.method(...args)
|
|
10675
|
+
if (opts.handle) {
|
|
10676
|
+
for (var hk in opts.handle) {
|
|
10677
|
+
if (_hop.call(opts.handle, hk)) {
|
|
10678
|
+
el.bw[hk] = opts.handle[hk].bind(null, el);
|
|
10679
|
+
}
|
|
10680
|
+
}
|
|
10681
|
+
}
|
|
10682
|
+
|
|
10683
|
+
// Slot declarations: auto-generate setX/getX pairs
|
|
10684
|
+
if (opts.slots) {
|
|
10685
|
+
for (var sk in opts.slots) {
|
|
10686
|
+
if (_hop.call(opts.slots, sk)) {
|
|
10687
|
+
(function (name, selector) {
|
|
10688
|
+
var cap = name.charAt(0).toUpperCase() + name.slice(1);
|
|
10689
|
+
el.bw['set' + cap] = function (value) {
|
|
10690
|
+
var t = el.querySelector(selector);
|
|
10691
|
+
if (!t) return;
|
|
10692
|
+
if (value != null && _typeof(value) === 'object' && value.t) {
|
|
10693
|
+
t.innerHTML = '';
|
|
10694
|
+
t.appendChild(bw.createDOM(value));
|
|
10695
|
+
} else {
|
|
10696
|
+
t.textContent = value != null ? String(value) : '';
|
|
10697
|
+
}
|
|
10698
|
+
};
|
|
10699
|
+
el.bw['get' + cap] = function () {
|
|
10700
|
+
var t = el.querySelector(selector);
|
|
10701
|
+
return t ? t.textContent : '';
|
|
10702
|
+
};
|
|
10703
|
+
})(sk, opts.slots[sk]);
|
|
10704
|
+
}
|
|
10705
|
+
}
|
|
10706
|
+
}
|
|
10453
10707
|
}
|
|
10454
10708
|
return el;
|
|
10455
10709
|
};
|
|
@@ -10495,7 +10749,7 @@
|
|
|
10495
10749
|
// the target is the mount point, not the content being replaced)
|
|
10496
10750
|
var savedState = targetEl._bw_state;
|
|
10497
10751
|
var savedRender = targetEl._bw_render;
|
|
10498
|
-
var
|
|
10752
|
+
var savedUuid = bw.getUUID(targetEl);
|
|
10499
10753
|
var savedSubs = targetEl._bw_subs;
|
|
10500
10754
|
|
|
10501
10755
|
// Temporarily remove _bw_subs so cleanup doesn't call them
|
|
@@ -10506,35 +10760,20 @@
|
|
|
10506
10760
|
// Restore the target's own state/render/subs after cleanup
|
|
10507
10761
|
if (savedState !== undefined) targetEl._bw_state = savedState;
|
|
10508
10762
|
if (savedRender) targetEl._bw_render = savedRender;
|
|
10509
|
-
if (
|
|
10510
|
-
|
|
10511
|
-
|
|
10512
|
-
bw._registerNode(targetEl, savedBwId);
|
|
10763
|
+
if (savedUuid) {
|
|
10764
|
+
// UUID class stays on element through cleanup; re-register in cache
|
|
10765
|
+
bw._registerNode(targetEl, savedUuid);
|
|
10513
10766
|
}
|
|
10514
10767
|
if (savedSubs) targetEl._bw_subs = savedSubs;
|
|
10515
10768
|
|
|
10516
10769
|
// Clear and mount new content
|
|
10517
10770
|
targetEl.innerHTML = '';
|
|
10518
10771
|
if (taco != null) {
|
|
10519
|
-
// Handle ComponentHandle (reactive components from bw.component())
|
|
10520
|
-
if (taco._bwComponent === true) {
|
|
10521
|
-
taco.mount(targetEl);
|
|
10522
|
-
}
|
|
10523
|
-
// Handle component handles (objects with element property)
|
|
10524
|
-
else if (taco.element instanceof Element) {
|
|
10525
|
-
targetEl.appendChild(taco.element);
|
|
10526
|
-
}
|
|
10527
10772
|
// Handle arrays
|
|
10528
|
-
|
|
10773
|
+
if (_isA(taco)) {
|
|
10529
10774
|
taco.forEach(function (t) {
|
|
10530
10775
|
if (t != null) {
|
|
10531
|
-
|
|
10532
|
-
t.mount(targetEl);
|
|
10533
|
-
} else if (t.element instanceof Element) {
|
|
10534
|
-
targetEl.appendChild(t.element);
|
|
10535
|
-
} else {
|
|
10536
|
-
targetEl.appendChild(bw.createDOM(t, options));
|
|
10537
|
-
}
|
|
10776
|
+
targetEl.appendChild(bw.createDOM(t, options));
|
|
10538
10777
|
}
|
|
10539
10778
|
});
|
|
10540
10779
|
}
|
|
@@ -10546,197 +10785,40 @@
|
|
|
10546
10785
|
return targetEl;
|
|
10547
10786
|
};
|
|
10548
10787
|
|
|
10549
|
-
|
|
10550
|
-
|
|
10551
|
-
|
|
10552
|
-
|
|
10553
|
-
|
|
10554
|
-
|
|
10555
|
-
* @param {Object} handle - Component handle
|
|
10556
|
-
* @param {Object} props - Initial props
|
|
10557
|
-
* @returns {Object} Compiled props object with getters/setters
|
|
10558
|
-
* @category DOM Generation
|
|
10559
|
-
*/
|
|
10560
|
-
bw.compileProps = function (handle) {
|
|
10561
|
-
var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
10562
|
-
var compiledProps = {};
|
|
10563
|
-
_keys(props).forEach(function (key) {
|
|
10564
|
-
// Create getter/setter for each prop
|
|
10565
|
-
Object.defineProperty(compiledProps, key, {
|
|
10566
|
-
get: function get() {
|
|
10567
|
-
return handle._props[key];
|
|
10568
|
-
},
|
|
10569
|
-
set: function set(value) {
|
|
10570
|
-
var oldValue = handle._props[key];
|
|
10571
|
-
if (oldValue !== value) {
|
|
10572
|
-
handle._props[key] = value;
|
|
10573
|
-
// Trigger update if prop changed
|
|
10574
|
-
if (handle.onPropChange) {
|
|
10575
|
-
handle.onPropChange(key, value, oldValue);
|
|
10576
|
-
}
|
|
10577
|
-
}
|
|
10578
|
-
},
|
|
10579
|
-
enumerable: true,
|
|
10580
|
-
configurable: true
|
|
10581
|
-
});
|
|
10582
|
-
});
|
|
10583
|
-
return compiledProps;
|
|
10788
|
+
// Deprecation stubs for removed ComponentHandle APIs
|
|
10789
|
+
bw.compileProps = function () {
|
|
10790
|
+
throw new Error('bw.compileProps() removed in v2.0.19. Use o.handle/o.slots instead.');
|
|
10791
|
+
};
|
|
10792
|
+
bw.renderComponent = function () {
|
|
10793
|
+
throw new Error('bw.renderComponent() removed in v2.0.19. Use bw.mount() with o.handle/o.slots instead.');
|
|
10584
10794
|
};
|
|
10585
10795
|
|
|
10586
10796
|
/**
|
|
10587
|
-
*
|
|
10797
|
+
* Mount a TACO into a target element and return the created root element.
|
|
10798
|
+
* Like bw.DOM() but returns the root element of the TACO (not the container),
|
|
10799
|
+
* giving direct access to el.bw handle methods.
|
|
10588
10800
|
*
|
|
10589
|
-
*
|
|
10590
|
-
*
|
|
10591
|
-
*
|
|
10592
|
-
* @
|
|
10593
|
-
* @param {Object} [options] - Render options
|
|
10594
|
-
* @returns {Object} Component handle with element, props, state, update(), destroy()
|
|
10801
|
+
* @param {string|Element} target - CSS selector or DOM element
|
|
10802
|
+
* @param {Object} taco - TACO to render
|
|
10803
|
+
* @param {Object} [options] - Mount options
|
|
10804
|
+
* @returns {Element} The created root element
|
|
10595
10805
|
* @category DOM Generation
|
|
10596
|
-
|
|
10597
|
-
|
|
10598
|
-
|
|
10599
|
-
|
|
10600
|
-
|
|
10601
|
-
|
|
10602
|
-
|
|
10603
|
-
|
|
10604
|
-
|
|
10605
|
-
|
|
10606
|
-
|
|
10607
|
-
|
|
10608
|
-
|
|
10609
|
-
|
|
10610
|
-
|
|
10611
|
-
|
|
10612
|
-
// Get compiled props with getters/setters
|
|
10613
|
-
get props() {
|
|
10614
|
-
if (!this._compiledProps) {
|
|
10615
|
-
this._compiledProps = bw.compileProps(this, this._props);
|
|
10616
|
-
}
|
|
10617
|
-
return this._compiledProps;
|
|
10618
|
-
},
|
|
10619
|
-
/**
|
|
10620
|
-
* Query all matching elements within this component
|
|
10621
|
-
* @param {string} selector - CSS selector
|
|
10622
|
-
* @returns {NodeList} Matching elements
|
|
10623
|
-
*/
|
|
10624
|
-
$: function $(selector) {
|
|
10625
|
-
return this.element.querySelectorAll(selector);
|
|
10626
|
-
},
|
|
10627
|
-
/**
|
|
10628
|
-
* Query the first matching element within this component
|
|
10629
|
-
* @param {string} selector - CSS selector
|
|
10630
|
-
* @returns {Element|null} First matching element or null
|
|
10631
|
-
*/
|
|
10632
|
-
$first: function $first(selector) {
|
|
10633
|
-
return this.element.querySelector(selector);
|
|
10634
|
-
},
|
|
10635
|
-
/**
|
|
10636
|
-
* Update component with new props and re-render in place
|
|
10637
|
-
* @param {Object} newProps - Properties to merge into current props
|
|
10638
|
-
* @returns {Object} this handle (for chaining)
|
|
10639
|
-
*/
|
|
10640
|
-
update: function update(newProps) {
|
|
10641
|
-
// Update internal props
|
|
10642
|
-
Object.assign(this._props, newProps);
|
|
10643
|
-
|
|
10644
|
-
// Rebuild TACO with new props
|
|
10645
|
-
var newTaco = _objectSpread2(_objectSpread2({}, this.taco), {}, {
|
|
10646
|
-
a: _objectSpread2(_objectSpread2({}, this.taco.a), newProps)
|
|
10647
|
-
});
|
|
10648
|
-
var newElement = bw.createDOM(newTaco, options);
|
|
10649
|
-
|
|
10650
|
-
// Replace in DOM
|
|
10651
|
-
this.element.replaceWith(newElement);
|
|
10652
|
-
this.element = newElement;
|
|
10653
|
-
this.taco = newTaco;
|
|
10654
|
-
return this;
|
|
10655
|
-
},
|
|
10656
|
-
/**
|
|
10657
|
-
* Re-render the component from its current TACO, replacing the DOM element
|
|
10658
|
-
* @returns {Object} this handle (for chaining)
|
|
10659
|
-
*/
|
|
10660
|
-
render: function render() {
|
|
10661
|
-
var newElement = bw.createDOM(this.taco, options);
|
|
10662
|
-
this.element.replaceWith(newElement);
|
|
10663
|
-
this.element = newElement;
|
|
10664
|
-
return this;
|
|
10665
|
-
},
|
|
10666
|
-
/**
|
|
10667
|
-
* Called when a compiled prop value changes. Override to customize behavior.
|
|
10668
|
-
* Default implementation triggers a full re-render.
|
|
10669
|
-
* @param {string} key - Property name that changed
|
|
10670
|
-
* @param {*} newValue - New property value
|
|
10671
|
-
* @param {*} oldValue - Previous property value
|
|
10672
|
-
*/
|
|
10673
|
-
onPropChange: function onPropChange(_key, _newValue, _oldValue) {
|
|
10674
|
-
// Auto re-render on prop change by default
|
|
10675
|
-
this.render();
|
|
10676
|
-
},
|
|
10677
|
-
// State management
|
|
10678
|
-
get state() {
|
|
10679
|
-
return this._state;
|
|
10680
|
-
},
|
|
10681
|
-
set state(newState) {
|
|
10682
|
-
this._state = newState;
|
|
10683
|
-
this.render();
|
|
10684
|
-
},
|
|
10685
|
-
/**
|
|
10686
|
-
* Merge state updates and re-render the component
|
|
10687
|
-
* @param {Object} updates - State properties to merge
|
|
10688
|
-
* @returns {Object} this handle (for chaining)
|
|
10689
|
-
*/
|
|
10690
|
-
setState: function setState(updates) {
|
|
10691
|
-
Object.assign(this._state, updates);
|
|
10692
|
-
this.render();
|
|
10693
|
-
return this;
|
|
10694
|
-
},
|
|
10695
|
-
/**
|
|
10696
|
-
* Register a child component under a name for later retrieval
|
|
10697
|
-
* @param {string} name - Child name key
|
|
10698
|
-
* @param {Object} component - Child component handle
|
|
10699
|
-
* @returns {Object} this handle (for chaining)
|
|
10700
|
-
*/
|
|
10701
|
-
addChild: function addChild(name, component) {
|
|
10702
|
-
this._children[name] = component;
|
|
10703
|
-
return this;
|
|
10704
|
-
},
|
|
10705
|
-
/**
|
|
10706
|
-
* Retrieve a registered child component by name
|
|
10707
|
-
* @param {string} name - Child name key
|
|
10708
|
-
* @returns {Object|undefined} Child component handle
|
|
10709
|
-
*/
|
|
10710
|
-
getChild: function getChild(name) {
|
|
10711
|
-
return this._children[name];
|
|
10712
|
-
},
|
|
10713
|
-
/**
|
|
10714
|
-
* Destroy this component and all registered children
|
|
10715
|
-
*
|
|
10716
|
-
* Calls destroy() recursively on children, runs bw.cleanup(),
|
|
10717
|
-
* removes the element from DOM, and clears all internal references.
|
|
10718
|
-
*/
|
|
10719
|
-
destroy: function destroy() {
|
|
10720
|
-
// Destroy children first
|
|
10721
|
-
Object.values(this._children).forEach(function (child) {
|
|
10722
|
-
if (child && child.destroy) child.destroy();
|
|
10723
|
-
});
|
|
10724
|
-
|
|
10725
|
-
// Clean up this component
|
|
10726
|
-
bw.cleanup(this.element);
|
|
10727
|
-
this.element.remove();
|
|
10728
|
-
|
|
10729
|
-
// Clear references
|
|
10730
|
-
this._children = {};
|
|
10731
|
-
this._props = {};
|
|
10732
|
-
this._state = {};
|
|
10733
|
-
this._compiledProps = null;
|
|
10734
|
-
}
|
|
10735
|
-
};
|
|
10736
|
-
|
|
10737
|
-
// Store handle reference on element
|
|
10738
|
-
element._bwHandle = handle;
|
|
10739
|
-
return handle;
|
|
10806
|
+
* @example
|
|
10807
|
+
* var el = bw.mount('#app', bw.makeCarousel({ items: slides }));
|
|
10808
|
+
* el.bw.goToSlide(2);
|
|
10809
|
+
* el.bw.next();
|
|
10810
|
+
*/
|
|
10811
|
+
bw.mount = function (target, taco, options) {
|
|
10812
|
+
var container = _is(target, 'string') ? bw.$(target)[0] : target;
|
|
10813
|
+
if (!container) {
|
|
10814
|
+
_cw('bw.mount: target not found');
|
|
10815
|
+
return null;
|
|
10816
|
+
}
|
|
10817
|
+
bw.cleanup(container);
|
|
10818
|
+
container.innerHTML = '';
|
|
10819
|
+
var el = bw.createDOM(taco, options || {});
|
|
10820
|
+
container.appendChild(el);
|
|
10821
|
+
return el;
|
|
10740
10822
|
};
|
|
10741
10823
|
|
|
10742
10824
|
/**
|
|
@@ -10757,32 +10839,27 @@
|
|
|
10757
10839
|
bw.cleanup = function (element) {
|
|
10758
10840
|
if (!bw._isBrowser || !element) return;
|
|
10759
10841
|
|
|
10760
|
-
// Deregister UUID classes from node cache
|
|
10761
|
-
// Covers elements that have UUID but no data-bw_id
|
|
10762
|
-
var selfUuidMatch = element.className && element.className.match(_UUID_RE);
|
|
10763
|
-
if (selfUuidMatch) delete bw._nodeMap[selfUuidMatch[0]];
|
|
10842
|
+
// Deregister UUID classes from node cache for non-lifecycle UUID elements
|
|
10764
10843
|
var uuidEls = element.querySelectorAll('[class*="bw_uuid_"]');
|
|
10765
10844
|
uuidEls.forEach(function (uel) {
|
|
10766
10845
|
var m = uel.className && uel.className.match(_UUID_RE);
|
|
10767
10846
|
if (m) delete bw._nodeMap[m[0]];
|
|
10768
10847
|
});
|
|
10769
10848
|
|
|
10770
|
-
// Find all elements
|
|
10771
|
-
var elements = element.querySelectorAll('
|
|
10849
|
+
// Find all lifecycle-managed elements (have bw_lc marker class)
|
|
10850
|
+
var elements = element.querySelectorAll('.' + _BW_LC);
|
|
10772
10851
|
elements.forEach(function (el) {
|
|
10773
|
-
var
|
|
10774
|
-
|
|
10775
|
-
|
|
10776
|
-
callback
|
|
10777
|
-
|
|
10778
|
-
|
|
10779
|
-
|
|
10780
|
-
// Deregister from node cache
|
|
10781
|
-
bw._deregisterNode(el, id);
|
|
10852
|
+
var uuid = bw.getUUID(el);
|
|
10853
|
+
if (uuid) {
|
|
10854
|
+
var callback = bw._unmountCallbacks.get(uuid);
|
|
10855
|
+
if (callback) {
|
|
10856
|
+
callback();
|
|
10857
|
+
bw._unmountCallbacks["delete"](uuid);
|
|
10858
|
+
}
|
|
10782
10859
|
|
|
10783
|
-
|
|
10784
|
-
|
|
10785
|
-
|
|
10860
|
+
// Deregister from node cache
|
|
10861
|
+
bw._deregisterNode(el, uuid);
|
|
10862
|
+
}
|
|
10786
10863
|
|
|
10787
10864
|
// Clean up pub/sub subscriptions tied to this element
|
|
10788
10865
|
if (el._bw_subs) {
|
|
@@ -10799,20 +10876,17 @@
|
|
|
10799
10876
|
});
|
|
10800
10877
|
|
|
10801
10878
|
// Check element itself
|
|
10802
|
-
var
|
|
10803
|
-
if (
|
|
10804
|
-
|
|
10879
|
+
var selfUuid = bw.getUUID(element);
|
|
10880
|
+
if (selfUuid) {
|
|
10881
|
+
delete bw._nodeMap[selfUuid];
|
|
10882
|
+
var callback = bw._unmountCallbacks.get(selfUuid);
|
|
10805
10883
|
if (callback) {
|
|
10806
10884
|
callback();
|
|
10807
|
-
bw._unmountCallbacks["delete"](
|
|
10885
|
+
bw._unmountCallbacks["delete"](selfUuid);
|
|
10808
10886
|
}
|
|
10809
10887
|
|
|
10810
10888
|
// Deregister from node cache
|
|
10811
|
-
bw._deregisterNode(element,
|
|
10812
|
-
|
|
10813
|
-
// Deregister UUID class from node cache
|
|
10814
|
-
var elemUuidMatch = element.className && element.className.match(_UUID_RE);
|
|
10815
|
-
if (elemUuidMatch) delete bw._nodeMap[elemUuidMatch[0]];
|
|
10889
|
+
bw._deregisterNode(element, selfUuid);
|
|
10816
10890
|
|
|
10817
10891
|
// Clean up pub/sub subscriptions tied to element itself
|
|
10818
10892
|
if (element._bw_subs) {
|
|
@@ -10824,12 +10898,13 @@
|
|
|
10824
10898
|
delete element._bw_state;
|
|
10825
10899
|
delete element._bw_render;
|
|
10826
10900
|
delete element._bw_refs;
|
|
10827
|
-
|
|
10828
|
-
//
|
|
10829
|
-
if (element.
|
|
10830
|
-
element.
|
|
10831
|
-
|
|
10832
|
-
|
|
10901
|
+
} else {
|
|
10902
|
+
// No UUID on element itself, but still check for _bw_subs (from bw.sub())
|
|
10903
|
+
if (element._bw_subs) {
|
|
10904
|
+
element._bw_subs.forEach(function (unsub) {
|
|
10905
|
+
unsub();
|
|
10906
|
+
});
|
|
10907
|
+
delete element._bw_subs;
|
|
10833
10908
|
}
|
|
10834
10909
|
}
|
|
10835
10910
|
};
|
|
@@ -10845,7 +10920,7 @@
|
|
|
10845
10920
|
* Calls `el._bw_render(el, state)` and emits `bw:statechange` so other
|
|
10846
10921
|
* components can react without tight coupling.
|
|
10847
10922
|
*
|
|
10848
|
-
* @param {string|Element} target - Element ID,
|
|
10923
|
+
* @param {string|Element} target - Element ID, bw_uuid_* class, CSS selector, or DOM element
|
|
10849
10924
|
* @returns {Element|null} The element, or null if not found / no render function
|
|
10850
10925
|
* @category State Management
|
|
10851
10926
|
* @see bw.patch
|
|
@@ -10870,7 +10945,7 @@
|
|
|
10870
10945
|
* Use `bw.patch()` for lightweight value updates (scores, labels, counters)
|
|
10871
10946
|
* and `bw.update()` for full structural re-renders.
|
|
10872
10947
|
*
|
|
10873
|
-
* @param {string|Element} id - Element ID,
|
|
10948
|
+
* @param {string|Element} id - Element ID, bw_uuid_* class, CSS selector, or DOM element.
|
|
10874
10949
|
* Uses node cache for O(1) lookup; falls back to DOM query on cache miss.
|
|
10875
10950
|
* @param {string|Object} content - New text content, or TACO object to replace children
|
|
10876
10951
|
* @param {string} [attr] - If provided, sets this attribute instead of content
|
|
@@ -10944,7 +11019,7 @@
|
|
|
10944
11019
|
* bubble by default so ancestor elements can listen. Use with `bw.on()` for
|
|
10945
11020
|
* DOM-scoped communication between components.
|
|
10946
11021
|
*
|
|
10947
|
-
* @param {string|Element} target - Element ID,
|
|
11022
|
+
* @param {string|Element} target - Element ID, bw_uuid_* class, CSS selector, or DOM element.
|
|
10948
11023
|
* Uses node cache for O(1) lookup; falls back to DOM query on cache miss.
|
|
10949
11024
|
* @param {string} eventName - Event name (will be prefixed with 'bw:')
|
|
10950
11025
|
* @param {*} [detail] - Data to pass with the event
|
|
@@ -10971,7 +11046,7 @@
|
|
|
10971
11046
|
* is the first argument so you don't need to destructure `e.detail`.
|
|
10972
11047
|
* Events bubble, so you can listen on an ancestor element.
|
|
10973
11048
|
*
|
|
10974
|
-
* @param {string|Element} target - Element ID,
|
|
11049
|
+
* @param {string|Element} target - Element ID, bw_uuid_* class, CSS selector, or DOM element.
|
|
10975
11050
|
* Uses node cache for O(1) lookup; falls back to DOM query on cache miss.
|
|
10976
11051
|
* @param {string} eventName - Event name (will be prefixed with 'bw:')
|
|
10977
11052
|
* @param {Function} handler - Called with (detail, event)
|
|
@@ -11073,10 +11148,12 @@
|
|
|
11073
11148
|
if (el) {
|
|
11074
11149
|
if (!el._bw_subs) el._bw_subs = [];
|
|
11075
11150
|
el._bw_subs.push(unsub);
|
|
11076
|
-
// Ensure element has
|
|
11077
|
-
if (!
|
|
11078
|
-
|
|
11079
|
-
|
|
11151
|
+
// Ensure element has UUID + bw_lc so bw.cleanup() finds it
|
|
11152
|
+
if (!bw.getUUID(el)) {
|
|
11153
|
+
el.classList.add(bw.uuid('uuid'));
|
|
11154
|
+
}
|
|
11155
|
+
if (!el.classList.contains(_BW_LC)) {
|
|
11156
|
+
el.classList.add(_BW_LC);
|
|
11080
11157
|
}
|
|
11081
11158
|
}
|
|
11082
11159
|
return unsub;
|
|
@@ -11299,1170 +11376,77 @@
|
|
|
11299
11376
|
return result;
|
|
11300
11377
|
};
|
|
11301
11378
|
|
|
11302
|
-
/**
|
|
11303
|
-
* Extract top-level state keys that an expression depends on.
|
|
11304
|
-
* @param {string} expr - Expression string
|
|
11305
|
-
* @param {string[]} stateKeys - Declared state keys
|
|
11306
|
-
* @returns {string[]} Matching dependency keys
|
|
11307
|
-
* @private
|
|
11308
|
-
*/
|
|
11309
|
-
bw._extractDeps = function (expr, stateKeys) {
|
|
11310
|
-
var deps = [];
|
|
11311
|
-
for (var i = 0; i < stateKeys.length; i++) {
|
|
11312
|
-
var key = stateKeys[i];
|
|
11313
|
-
// Match word boundary: key must be preceded by start/non-word and followed by non-word/end
|
|
11314
|
-
var re = new RegExp('(?:^|[^\\w$.])' + key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '(?:[^\\w$]|$)');
|
|
11315
|
-
if (re.test(expr) || expr === key || expr.indexOf(key + '.') === 0) {
|
|
11316
|
-
deps.push(key);
|
|
11317
|
-
}
|
|
11318
|
-
}
|
|
11319
|
-
return deps;
|
|
11320
|
-
};
|
|
11321
|
-
|
|
11322
11379
|
// ===================================================================================
|
|
11323
|
-
//
|
|
11380
|
+
// Deprecation stubs for removed ComponentHandle APIs (v2.0.19)
|
|
11324
11381
|
// ===================================================================================
|
|
11325
11382
|
|
|
11326
|
-
bw.
|
|
11327
|
-
bw.
|
|
11383
|
+
bw._extractDeps = undefined;
|
|
11384
|
+
bw._dirtyComponents = undefined;
|
|
11385
|
+
bw._flushScheduled = undefined;
|
|
11386
|
+
bw._scheduleFlush = undefined;
|
|
11387
|
+
bw._doFlush = undefined;
|
|
11388
|
+
bw._ComponentHandle = undefined;
|
|
11328
11389
|
|
|
11329
11390
|
/**
|
|
11330
|
-
*
|
|
11331
|
-
*
|
|
11391
|
+
* No-op flush (ComponentHandle removed in v2.0.19).
|
|
11392
|
+
* Kept as no-op for backward compatibility.
|
|
11393
|
+
* @category Component
|
|
11332
11394
|
*/
|
|
11333
|
-
bw.
|
|
11334
|
-
|
|
11335
|
-
bw.
|
|
11336
|
-
if (typeof Promise !== 'undefined') {
|
|
11337
|
-
Promise.resolve().then(bw._doFlush);
|
|
11338
|
-
} else {
|
|
11339
|
-
setTimeout(bw._doFlush, 0);
|
|
11340
|
-
}
|
|
11395
|
+
bw.flush = function () {};
|
|
11396
|
+
bw.when = function () {
|
|
11397
|
+
throw new Error('bw.when() removed in v2.0.19. Use conditional logic in o.render instead.');
|
|
11341
11398
|
};
|
|
11342
|
-
|
|
11343
|
-
|
|
11344
|
-
|
|
11345
|
-
|
|
11346
|
-
|
|
11347
|
-
bw._doFlush = function () {
|
|
11348
|
-
bw._flushScheduled = false;
|
|
11349
|
-
var queue = bw._dirtyComponents.slice();
|
|
11350
|
-
bw._dirtyComponents = [];
|
|
11351
|
-
// Deduplicate by _bwId
|
|
11352
|
-
var seen = {};
|
|
11353
|
-
for (var i = 0; i < queue.length; i++) {
|
|
11354
|
-
var comp = queue[i];
|
|
11355
|
-
if (!seen[comp._bwId]) {
|
|
11356
|
-
seen[comp._bwId] = true;
|
|
11357
|
-
comp._flush();
|
|
11358
|
-
}
|
|
11359
|
-
}
|
|
11399
|
+
bw.each = function () {
|
|
11400
|
+
throw new Error('bw.each() removed in v2.0.19. Use array mapping in o.render instead.');
|
|
11401
|
+
};
|
|
11402
|
+
bw.component = function () {
|
|
11403
|
+
throw new Error('bw.component() removed in v2.0.19. Use o.handle/o.slots on TACO options instead.');
|
|
11360
11404
|
};
|
|
11361
11405
|
|
|
11406
|
+
// ===================================================================================
|
|
11407
|
+
// bw.message() — SendMessage() for the web
|
|
11408
|
+
// ===================================================================================
|
|
11409
|
+
|
|
11362
11410
|
/**
|
|
11363
|
-
*
|
|
11364
|
-
*
|
|
11411
|
+
* Dispatch a message to a component by UUID, CSS class, or selector.
|
|
11412
|
+
* Finds the element, looks up el.bw, and calls the named method.
|
|
11413
|
+
* This is the bitwrench equivalent of Win32 SendMessage(hwnd, msg, wParam, lParam).
|
|
11365
11414
|
*
|
|
11415
|
+
* @param {string} target - Component UUID (bw_uuid_*), CSS class, or selector
|
|
11416
|
+
* @param {string} action - Method name to call on el.bw
|
|
11417
|
+
* @param {*} data - Data to pass to the method
|
|
11418
|
+
* @returns {boolean} True if message was dispatched successfully
|
|
11366
11419
|
* @category Component
|
|
11420
|
+
* @example
|
|
11421
|
+
* bw.message('my_carousel', 'goToSlide', 2);
|
|
11422
|
+
* // Or from SSE handler:
|
|
11423
|
+
* es.onmessage = function(e) {
|
|
11424
|
+
* var msg = JSON.parse(e.data);
|
|
11425
|
+
* bw.message(msg.target, msg.action, msg.data);
|
|
11426
|
+
* };
|
|
11367
11427
|
*/
|
|
11368
|
-
bw.
|
|
11369
|
-
bw.
|
|
11428
|
+
bw.message = function (target, action, data) {
|
|
11429
|
+
var el = bw._el(target);
|
|
11430
|
+
if (!el) el = bw.$('.' + target)[0];
|
|
11431
|
+
if (!el || !el.bw || typeof el.bw[action] !== 'function') {
|
|
11432
|
+
_cw('bw.message: no handle method "' + action + '" on ' + target);
|
|
11433
|
+
return false;
|
|
11434
|
+
}
|
|
11435
|
+
el.bw[action](data);
|
|
11436
|
+
return true;
|
|
11370
11437
|
};
|
|
11371
11438
|
|
|
11372
11439
|
// ===================================================================================
|
|
11373
|
-
//
|
|
11440
|
+
// bw.apply() / bw.parseJSONFlex() — Server-driven UI protocol
|
|
11374
11441
|
// ===================================================================================
|
|
11375
11442
|
|
|
11376
11443
|
/**
|
|
11377
|
-
*
|
|
11378
|
-
*
|
|
11379
|
-
*
|
|
11380
|
-
*
|
|
11381
|
-
* @param {Object} taco - TACO definition {t, a, c, o}
|
|
11382
|
-
* @constructor
|
|
11444
|
+
* Registry of named functions sent via register messages.
|
|
11445
|
+
* Populated by bw.apply({ type: 'register', name, body }).
|
|
11446
|
+
* Invoked by bw.apply({ type: 'call', name, args }).
|
|
11383
11447
|
* @private
|
|
11384
11448
|
*/
|
|
11385
|
-
|
|
11386
|
-
this._bwComponent = true; // duck-type marker
|
|
11387
|
-
this._bwId = bw.uuid('comp');
|
|
11388
|
-
this.taco = taco;
|
|
11389
|
-
this.element = null;
|
|
11390
|
-
this.mounted = false;
|
|
11391
|
-
var o = taco.o || {};
|
|
11392
|
-
// Copy initial state
|
|
11393
|
-
this._state = {};
|
|
11394
|
-
if (o.state) {
|
|
11395
|
-
for (var k in o.state) {
|
|
11396
|
-
if (_hop.call(o.state, k)) {
|
|
11397
|
-
this._state[k] = o.state[k];
|
|
11398
|
-
}
|
|
11399
|
-
}
|
|
11400
|
-
}
|
|
11401
|
-
// Copy actions
|
|
11402
|
-
this._actions = {};
|
|
11403
|
-
if (o.actions) {
|
|
11404
|
-
for (var k2 in o.actions) {
|
|
11405
|
-
if (_hop.call(o.actions, k2)) {
|
|
11406
|
-
this._actions[k2] = o.actions[k2];
|
|
11407
|
-
}
|
|
11408
|
-
}
|
|
11409
|
-
}
|
|
11410
|
-
// Promote o.methods to handle API (MFC/Qt pattern: component owns its methods)
|
|
11411
|
-
this._methods = {};
|
|
11412
|
-
if (o.methods) {
|
|
11413
|
-
var self = this;
|
|
11414
|
-
for (var k3 in o.methods) {
|
|
11415
|
-
if (_hop.call(o.methods, k3)) {
|
|
11416
|
-
this._methods[k3] = o.methods[k3];
|
|
11417
|
-
(function (methodName, methodFn) {
|
|
11418
|
-
self[methodName] = function () {
|
|
11419
|
-
var args = [self].concat(Array.prototype.slice.call(arguments));
|
|
11420
|
-
return methodFn.apply(null, args);
|
|
11421
|
-
};
|
|
11422
|
-
})(k3, o.methods[k3]);
|
|
11423
|
-
}
|
|
11424
|
-
}
|
|
11425
|
-
}
|
|
11426
|
-
// User tag for addressing via bw.message()
|
|
11427
|
-
this._userTag = null;
|
|
11428
|
-
// Lifecycle hooks
|
|
11429
|
-
this._hooks = {
|
|
11430
|
-
willMount: o.willMount || null,
|
|
11431
|
-
mounted: o.mounted || null,
|
|
11432
|
-
willUpdate: o.willUpdate || null,
|
|
11433
|
-
onUpdate: o.onUpdate || o.updated || null,
|
|
11434
|
-
unmount: o.unmount || null,
|
|
11435
|
-
willDestroy: o.willDestroy || null
|
|
11436
|
-
};
|
|
11437
|
-
// Binding tracking
|
|
11438
|
-
this._bindings = [];
|
|
11439
|
-
this._dirtyKeys = {};
|
|
11440
|
-
this._scheduled = false;
|
|
11441
|
-
this._subs = [];
|
|
11442
|
-
this._eventListeners = [];
|
|
11443
|
-
this._registeredActions = [];
|
|
11444
|
-
this._prevValues = {};
|
|
11445
|
-
this._compile = !!o.compile;
|
|
11446
|
-
this._bw_refs = {};
|
|
11447
|
-
this._refCounter = 0;
|
|
11448
|
-
// Child component ownership (Bug #5)
|
|
11449
|
-
this._children = [];
|
|
11450
|
-
this._parent = null;
|
|
11451
|
-
// Factory metadata for BCCL rebuild (Bug #6)
|
|
11452
|
-
this._factory = taco._bwFactory || null;
|
|
11453
|
-
}
|
|
11454
|
-
|
|
11455
|
-
// Short alias for ComponentHandle.prototype (see alias block at top of file).
|
|
11456
|
-
// 28 method definitions × 25 chars = ~700B raw savings in minified output.
|
|
11457
|
-
var _chp = ComponentHandle.prototype;
|
|
11458
|
-
|
|
11459
|
-
// ── State Methods ──
|
|
11460
|
-
|
|
11461
|
-
/**
|
|
11462
|
-
* Get a state value. Dot-path supported: `get('user.name')`
|
|
11463
|
-
*/
|
|
11464
|
-
_chp.get = function (key) {
|
|
11465
|
-
return bw._evaluatePath(this._state, key);
|
|
11466
|
-
};
|
|
11467
|
-
|
|
11468
|
-
/**
|
|
11469
|
-
* Set a state value. Dot-path supported. Schedules re-render.
|
|
11470
|
-
* @param {string} key - State key (dot-path)
|
|
11471
|
-
* @param {*} value - New value
|
|
11472
|
-
* @param {Object} [opts] - Options. `{sync: true}` for immediate flush.
|
|
11473
|
-
*/
|
|
11474
|
-
_chp.set = function (key, value, opts) {
|
|
11475
|
-
// Dot-path set
|
|
11476
|
-
var parts = key.split('.');
|
|
11477
|
-
var obj = this._state;
|
|
11478
|
-
for (var i = 0; i < parts.length - 1; i++) {
|
|
11479
|
-
if (!_is(obj[parts[i]], 'object')) {
|
|
11480
|
-
if (bw.debug) _cw('bw.debug: set() — auto-creating intermediate "' + parts[i] + '" in path "' + key + '"');
|
|
11481
|
-
obj[parts[i]] = {};
|
|
11482
|
-
}
|
|
11483
|
-
obj = obj[parts[i]];
|
|
11484
|
-
}
|
|
11485
|
-
obj[parts[parts.length - 1]] = value;
|
|
11486
|
-
// Mark top-level key dirty
|
|
11487
|
-
this._dirtyKeys[parts[0]] = true;
|
|
11488
|
-
if (this.mounted) {
|
|
11489
|
-
if (opts && opts.sync) {
|
|
11490
|
-
this._flush();
|
|
11491
|
-
} else {
|
|
11492
|
-
this._scheduleDirty();
|
|
11493
|
-
}
|
|
11494
|
-
}
|
|
11495
|
-
};
|
|
11496
|
-
|
|
11497
|
-
/**
|
|
11498
|
-
* Get a shallow clone of the full state.
|
|
11499
|
-
*/
|
|
11500
|
-
_chp.getState = function () {
|
|
11501
|
-
var clone = {};
|
|
11502
|
-
for (var k in this._state) {
|
|
11503
|
-
if (_hop.call(this._state, k)) {
|
|
11504
|
-
clone[k] = this._state[k];
|
|
11505
|
-
}
|
|
11506
|
-
}
|
|
11507
|
-
return clone;
|
|
11508
|
-
};
|
|
11509
|
-
|
|
11510
|
-
/**
|
|
11511
|
-
* Merge multiple state keys. Schedules re-render.
|
|
11512
|
-
* @param {Object} updates - Key-value pairs to merge
|
|
11513
|
-
* @param {Object} [opts] - Options. `{sync: true}` for immediate flush.
|
|
11514
|
-
*/
|
|
11515
|
-
_chp.setState = function (updates, opts) {
|
|
11516
|
-
for (var k in updates) {
|
|
11517
|
-
if (_hop.call(updates, k)) {
|
|
11518
|
-
this._state[k] = updates[k];
|
|
11519
|
-
this._dirtyKeys[k] = true;
|
|
11520
|
-
}
|
|
11521
|
-
}
|
|
11522
|
-
if (this.mounted) {
|
|
11523
|
-
if (opts && opts.sync) {
|
|
11524
|
-
this._flush();
|
|
11525
|
-
} else {
|
|
11526
|
-
this._scheduleDirty();
|
|
11527
|
-
}
|
|
11528
|
-
}
|
|
11529
|
-
};
|
|
11530
|
-
|
|
11531
|
-
/**
|
|
11532
|
-
* Push a value onto an array in state. Clones the array.
|
|
11533
|
-
*/
|
|
11534
|
-
_chp.push = function (key, val) {
|
|
11535
|
-
var arr = this.get(key);
|
|
11536
|
-
var newArr = _isA(arr) ? arr.slice() : [];
|
|
11537
|
-
newArr.push(val);
|
|
11538
|
-
this.set(key, newArr);
|
|
11539
|
-
};
|
|
11540
|
-
|
|
11541
|
-
/**
|
|
11542
|
-
* Splice an array in state. Clones the array.
|
|
11543
|
-
*/
|
|
11544
|
-
_chp.splice = function (key, start, deleteCount) {
|
|
11545
|
-
var arr = this.get(key);
|
|
11546
|
-
var newArr = _isA(arr) ? arr.slice() : [];
|
|
11547
|
-
var args = [start, deleteCount].concat(Array.prototype.slice.call(arguments, 3));
|
|
11548
|
-
Array.prototype.splice.apply(newArr, args);
|
|
11549
|
-
this.set(key, newArr);
|
|
11550
|
-
};
|
|
11551
|
-
|
|
11552
|
-
// ── Scheduling ──
|
|
11553
|
-
|
|
11554
|
-
_chp._scheduleDirty = function () {
|
|
11555
|
-
if (!this._scheduled) {
|
|
11556
|
-
this._scheduled = true;
|
|
11557
|
-
bw._dirtyComponents.push(this);
|
|
11558
|
-
bw._scheduleFlush();
|
|
11559
|
-
}
|
|
11560
|
-
};
|
|
11561
|
-
|
|
11562
|
-
// ── Binding Compilation ──
|
|
11563
|
-
|
|
11564
|
-
/**
|
|
11565
|
-
* Walk the TACO tree and extract ${expr} bindings.
|
|
11566
|
-
* Creates binding descriptors with refIds for targeted DOM updates.
|
|
11567
|
-
* @private
|
|
11568
|
-
*/
|
|
11569
|
-
_chp._compileBindings = function () {
|
|
11570
|
-
this._bindings = [];
|
|
11571
|
-
this._refCounter = 0;
|
|
11572
|
-
var stateKeys = _keys(this._state);
|
|
11573
|
-
var self = this;
|
|
11574
|
-
function walkTaco(taco, path) {
|
|
11575
|
-
if (!_is(taco, 'object') || !taco.t) return taco;
|
|
11576
|
-
|
|
11577
|
-
// Check content for bindings
|
|
11578
|
-
if (_is(taco.c, 'string') && taco.c.indexOf('${') >= 0) {
|
|
11579
|
-
var refId = 'bw_ref_' + self._refCounter++;
|
|
11580
|
-
var parsed = bw._parseBindings(taco.c);
|
|
11581
|
-
var deps = [];
|
|
11582
|
-
for (var j = 0; j < parsed.length; j++) {
|
|
11583
|
-
deps = deps.concat(bw._extractDeps(parsed[j].expr, stateKeys));
|
|
11584
|
-
}
|
|
11585
|
-
self._bindings.push({
|
|
11586
|
-
expr: taco.c,
|
|
11587
|
-
type: 'content',
|
|
11588
|
-
refId: refId,
|
|
11589
|
-
deps: deps,
|
|
11590
|
-
template: taco.c
|
|
11591
|
-
});
|
|
11592
|
-
// Inject data-bw_ref on the TACO for createDOM to pick up
|
|
11593
|
-
if (!taco.a) taco.a = {};
|
|
11594
|
-
taco.a['data-bw_ref'] = refId;
|
|
11595
|
-
}
|
|
11596
|
-
|
|
11597
|
-
// Check attributes for bindings
|
|
11598
|
-
if (taco.a) {
|
|
11599
|
-
for (var attrName in taco.a) {
|
|
11600
|
-
if (!_hop.call(taco.a, attrName)) continue;
|
|
11601
|
-
if (attrName === 'data-bw_ref') continue;
|
|
11602
|
-
var attrVal = taco.a[attrName];
|
|
11603
|
-
if (_is(attrVal, 'string') && attrVal.indexOf('${') >= 0) {
|
|
11604
|
-
var refId2 = 'bw_ref_' + self._refCounter++;
|
|
11605
|
-
var parsed2 = bw._parseBindings(attrVal);
|
|
11606
|
-
var deps2 = [];
|
|
11607
|
-
for (var j2 = 0; j2 < parsed2.length; j2++) {
|
|
11608
|
-
deps2 = deps2.concat(bw._extractDeps(parsed2[j2].expr, stateKeys));
|
|
11609
|
-
}
|
|
11610
|
-
self._bindings.push({
|
|
11611
|
-
expr: attrVal,
|
|
11612
|
-
type: 'attribute',
|
|
11613
|
-
attrName: attrName,
|
|
11614
|
-
refId: refId2,
|
|
11615
|
-
deps: deps2,
|
|
11616
|
-
template: attrVal
|
|
11617
|
-
});
|
|
11618
|
-
if (!taco.a) taco.a = {};
|
|
11619
|
-
taco.a['data-bw_ref'] = taco.a['data-bw_ref'] || refId2;
|
|
11620
|
-
// If multiple attribute bindings on same element, store additional marker
|
|
11621
|
-
if (taco.a['data-bw_ref'] !== refId2) {
|
|
11622
|
-
taco.a['data-bw_ref_' + attrName] = refId2;
|
|
11623
|
-
}
|
|
11624
|
-
}
|
|
11625
|
-
}
|
|
11626
|
-
}
|
|
11627
|
-
|
|
11628
|
-
// Recurse into children
|
|
11629
|
-
if (_isA(taco.c)) {
|
|
11630
|
-
for (var i = 0; i < taco.c.length; i++) {
|
|
11631
|
-
// Wrap string children with ${expr} in a span so patches target the span, not the parent
|
|
11632
|
-
if (_is(taco.c[i], 'string') && taco.c[i].indexOf('${') >= 0) {
|
|
11633
|
-
var mixedRefId = 'bw_ref_' + self._refCounter++;
|
|
11634
|
-
var mixedParsed = bw._parseBindings(taco.c[i]);
|
|
11635
|
-
var mixedDeps = [];
|
|
11636
|
-
for (var mi = 0; mi < mixedParsed.length; mi++) {
|
|
11637
|
-
mixedDeps = mixedDeps.concat(bw._extractDeps(mixedParsed[mi].expr, stateKeys));
|
|
11638
|
-
}
|
|
11639
|
-
self._bindings.push({
|
|
11640
|
-
expr: taco.c[i],
|
|
11641
|
-
type: 'content',
|
|
11642
|
-
refId: mixedRefId,
|
|
11643
|
-
deps: mixedDeps,
|
|
11644
|
-
template: taco.c[i]
|
|
11645
|
-
});
|
|
11646
|
-
// Replace string with a span wrapper so textContent targets the span only
|
|
11647
|
-
taco.c[i] = {
|
|
11648
|
-
t: 'span',
|
|
11649
|
-
a: {
|
|
11650
|
-
'data-bw_ref': mixedRefId,
|
|
11651
|
-
style: 'display:contents'
|
|
11652
|
-
},
|
|
11653
|
-
c: taco.c[i]
|
|
11654
|
-
};
|
|
11655
|
-
}
|
|
11656
|
-
if (_is(taco.c[i], 'object') && taco.c[i].t) {
|
|
11657
|
-
walkTaco(taco.c[i], path.concat(i));
|
|
11658
|
-
}
|
|
11659
|
-
// Handle bw.when/bw.each markers
|
|
11660
|
-
if (taco.c[i] && taco.c[i]._bwWhen) {
|
|
11661
|
-
var whenRefId = 'bw_ref_' + self._refCounter++;
|
|
11662
|
-
var whenDeps = bw._extractDeps(taco.c[i].expr.replace(/^\$\{|\}$/g, ''), stateKeys);
|
|
11663
|
-
self._bindings.push({
|
|
11664
|
-
expr: taco.c[i].expr,
|
|
11665
|
-
type: 'structural',
|
|
11666
|
-
subtype: 'when',
|
|
11667
|
-
refId: whenRefId,
|
|
11668
|
-
deps: whenDeps,
|
|
11669
|
-
branches: taco.c[i].branches,
|
|
11670
|
-
index: i,
|
|
11671
|
-
parentPath: path
|
|
11672
|
-
});
|
|
11673
|
-
taco.c[i]._refId = whenRefId;
|
|
11674
|
-
}
|
|
11675
|
-
if (taco.c[i] && taco.c[i]._bwEach) {
|
|
11676
|
-
var eachRefId = 'bw_ref_' + self._refCounter++;
|
|
11677
|
-
var eachDeps = bw._extractDeps(taco.c[i].expr.replace(/^\$\{|\}$/g, ''), stateKeys);
|
|
11678
|
-
self._bindings.push({
|
|
11679
|
-
expr: taco.c[i].expr,
|
|
11680
|
-
type: 'structural',
|
|
11681
|
-
subtype: 'each',
|
|
11682
|
-
refId: eachRefId,
|
|
11683
|
-
deps: eachDeps,
|
|
11684
|
-
factory: taco.c[i].factory,
|
|
11685
|
-
index: i,
|
|
11686
|
-
parentPath: path
|
|
11687
|
-
});
|
|
11688
|
-
taco.c[i]._refId = eachRefId;
|
|
11689
|
-
}
|
|
11690
|
-
}
|
|
11691
|
-
} else if (_is(taco.c, 'object') && taco.c.t) {
|
|
11692
|
-
walkTaco(taco.c, path.concat(0));
|
|
11693
|
-
}
|
|
11694
|
-
return taco;
|
|
11695
|
-
}
|
|
11696
|
-
walkTaco(this.taco, []);
|
|
11697
|
-
};
|
|
11698
|
-
|
|
11699
|
-
// ── DOM Reference Collection ──
|
|
11700
|
-
|
|
11701
|
-
/**
|
|
11702
|
-
* Build ref map from the live DOM after createDOM.
|
|
11703
|
-
* @private
|
|
11704
|
-
*/
|
|
11705
|
-
_chp._collectRefs = function () {
|
|
11706
|
-
this._bw_refs = {};
|
|
11707
|
-
if (!this.element) return;
|
|
11708
|
-
var els = this.element.querySelectorAll('[data-bw_ref]');
|
|
11709
|
-
for (var i = 0; i < els.length; i++) {
|
|
11710
|
-
this._bw_refs[els[i].getAttribute('data-bw_ref')] = els[i];
|
|
11711
|
-
}
|
|
11712
|
-
// Also check root element
|
|
11713
|
-
var rootRef = this.element.getAttribute && this.element.getAttribute('data-bw_ref');
|
|
11714
|
-
if (rootRef) {
|
|
11715
|
-
this._bw_refs[rootRef] = this.element;
|
|
11716
|
-
}
|
|
11717
|
-
};
|
|
11718
|
-
|
|
11719
|
-
// ── Lifecycle ──
|
|
11720
|
-
|
|
11721
|
-
/**
|
|
11722
|
-
* Mount the component into a parent DOM element.
|
|
11723
|
-
* Creates DOM, compiles bindings, registers actions, and calls lifecycle hooks.
|
|
11724
|
-
* @param {Element} parentEl - DOM element to mount into
|
|
11725
|
-
*/
|
|
11726
|
-
_chp.mount = function (parentEl) {
|
|
11727
|
-
// willMount hook
|
|
11728
|
-
if (this._hooks.willMount) this._hooks.willMount(this);
|
|
11729
|
-
|
|
11730
|
-
// Save original TACO for re-renders (structural changes clone from this)
|
|
11731
|
-
if (!this._originalTaco) {
|
|
11732
|
-
this._originalTaco = this.taco;
|
|
11733
|
-
}
|
|
11734
|
-
|
|
11735
|
-
// Deep-clone TACO so binding annotations don't mutate original.
|
|
11736
|
-
// Custom clone to preserve _bwWhen/_bwEach markers and their factory functions.
|
|
11737
|
-
this.taco = this._deepCloneTaco(this._originalTaco);
|
|
11738
|
-
|
|
11739
|
-
// Compile bindings (annotates TACO with data-bw_ref attributes)
|
|
11740
|
-
this._compileBindings();
|
|
11741
|
-
|
|
11742
|
-
// Prepare TACO: resolve initial binding values, evaluate when/each
|
|
11743
|
-
this._prepareTaco(this.taco);
|
|
11744
|
-
|
|
11745
|
-
// Register named actions in function registry
|
|
11746
|
-
var self = this;
|
|
11747
|
-
for (var actionName in this._actions) {
|
|
11748
|
-
if (_hop.call(this._actions, actionName)) {
|
|
11749
|
-
var registeredName = this._bwId + '_' + actionName;
|
|
11750
|
-
(function (aName) {
|
|
11751
|
-
bw.funcRegister(function (evt) {
|
|
11752
|
-
self._actions[aName](self, evt);
|
|
11753
|
-
}, registeredName);
|
|
11754
|
-
})(actionName);
|
|
11755
|
-
this._registeredActions.push(registeredName);
|
|
11756
|
-
}
|
|
11757
|
-
}
|
|
11758
|
-
|
|
11759
|
-
// Wire action names in onclick etc. to dispatch strings
|
|
11760
|
-
this._wireActions(this.taco);
|
|
11761
|
-
|
|
11762
|
-
// Create DOM (strip o before createDOM to prevent double lifecycle)
|
|
11763
|
-
var tacoForDOM = this._tacoForDOM(this.taco);
|
|
11764
|
-
this.element = bw.createDOM(tacoForDOM);
|
|
11765
|
-
this.element._bwComponentHandle = this;
|
|
11766
|
-
this.element.setAttribute('data-bw_comp_id', this._bwId);
|
|
11767
|
-
|
|
11768
|
-
// Restore o.render from original TACO (stripped by _tacoForDOM)
|
|
11769
|
-
if (this.taco.o && this.taco.o.render) {
|
|
11770
|
-
this.element._bw_render = this.taco.o.render;
|
|
11771
|
-
}
|
|
11772
|
-
if (this._userTag) {
|
|
11773
|
-
this.element.classList.add(this._userTag);
|
|
11774
|
-
}
|
|
11775
|
-
|
|
11776
|
-
// Append to parent
|
|
11777
|
-
parentEl.appendChild(this.element);
|
|
11778
|
-
|
|
11779
|
-
// Collect refs from live DOM
|
|
11780
|
-
this._collectRefs();
|
|
11781
|
-
|
|
11782
|
-
// Resolve initial bindings and apply to DOM
|
|
11783
|
-
this._resolveAndApplyAll();
|
|
11784
|
-
this.mounted = true;
|
|
11785
|
-
|
|
11786
|
-
// Scan for child ComponentHandles and link parent/child (Bug #5)
|
|
11787
|
-
var childEls = this.element.querySelectorAll('[data-bw_comp_id]');
|
|
11788
|
-
for (var ci = 0; ci < childEls.length; ci++) {
|
|
11789
|
-
var ch = childEls[ci]._bwComponentHandle;
|
|
11790
|
-
if (ch && ch !== this && !ch._parent) {
|
|
11791
|
-
ch._parent = this;
|
|
11792
|
-
this._children.push(ch);
|
|
11793
|
-
}
|
|
11794
|
-
}
|
|
11795
|
-
|
|
11796
|
-
// mounted hook (backward compat: fn.length === 2 wraps (el, state))
|
|
11797
|
-
if (this._hooks.mounted) {
|
|
11798
|
-
if (this._hooks.mounted.length === 2) {
|
|
11799
|
-
this._hooks.mounted(this.element, this.getState());
|
|
11800
|
-
} else {
|
|
11801
|
-
this._hooks.mounted(this);
|
|
11802
|
-
}
|
|
11803
|
-
}
|
|
11804
|
-
|
|
11805
|
-
// Invoke o.render on initial mount (if present)
|
|
11806
|
-
if (this.element._bw_render) {
|
|
11807
|
-
this.element._bw_render(this.element, this._state);
|
|
11808
|
-
}
|
|
11809
|
-
};
|
|
11810
|
-
|
|
11811
|
-
/**
|
|
11812
|
-
* Prepare TACO for initial render: resolve when/each markers.
|
|
11813
|
-
* @private
|
|
11814
|
-
*/
|
|
11815
|
-
_chp._prepareTaco = function (taco) {
|
|
11816
|
-
if (!_is(taco, 'object')) return;
|
|
11817
|
-
if (_isA(taco.c)) {
|
|
11818
|
-
for (var i = taco.c.length - 1; i >= 0; i--) {
|
|
11819
|
-
var child = taco.c[i];
|
|
11820
|
-
if (child && child._bwWhen) {
|
|
11821
|
-
var exprStr = child.expr.replace(/^\$\{|\}$/g, '');
|
|
11822
|
-
var val;
|
|
11823
|
-
if (this._compile) {
|
|
11824
|
-
try {
|
|
11825
|
-
val = new Function('state', 'with(state){return (' + exprStr + ');}')(this._state);
|
|
11826
|
-
} catch (e) {
|
|
11827
|
-
val = false;
|
|
11828
|
-
}
|
|
11829
|
-
} else {
|
|
11830
|
-
val = bw._evaluatePath(this._state, exprStr);
|
|
11831
|
-
}
|
|
11832
|
-
var branch = val ? child.branches[0] : child.branches[1] || null;
|
|
11833
|
-
if (branch) {
|
|
11834
|
-
// Wrap in a container so we can track it
|
|
11835
|
-
taco.c[i] = {
|
|
11836
|
-
t: 'span',
|
|
11837
|
-
a: {
|
|
11838
|
-
'data-bw_when': child._refId,
|
|
11839
|
-
style: 'display:contents'
|
|
11840
|
-
},
|
|
11841
|
-
c: branch
|
|
11842
|
-
};
|
|
11843
|
-
} else {
|
|
11844
|
-
taco.c[i] = {
|
|
11845
|
-
t: 'span',
|
|
11846
|
-
a: {
|
|
11847
|
-
'data-bw_when': child._refId,
|
|
11848
|
-
style: 'display:contents'
|
|
11849
|
-
},
|
|
11850
|
-
c: ''
|
|
11851
|
-
};
|
|
11852
|
-
}
|
|
11853
|
-
}
|
|
11854
|
-
if (child && child._bwEach) {
|
|
11855
|
-
var eachExprStr = child.expr.replace(/^\$\{|\}$/g, '');
|
|
11856
|
-
var arr = bw._evaluatePath(this._state, eachExprStr);
|
|
11857
|
-
var items = [];
|
|
11858
|
-
if (_isA(arr)) {
|
|
11859
|
-
for (var j = 0; j < arr.length; j++) {
|
|
11860
|
-
items.push(child.factory(arr[j], j));
|
|
11861
|
-
}
|
|
11862
|
-
}
|
|
11863
|
-
taco.c[i] = {
|
|
11864
|
-
t: 'span',
|
|
11865
|
-
a: {
|
|
11866
|
-
'data-bw_each': child._refId,
|
|
11867
|
-
style: 'display:contents'
|
|
11868
|
-
},
|
|
11869
|
-
c: items
|
|
11870
|
-
};
|
|
11871
|
-
}
|
|
11872
|
-
if (_is(taco.c[i], 'object') && taco.c[i].t) {
|
|
11873
|
-
this._prepareTaco(taco.c[i]);
|
|
11874
|
-
}
|
|
11875
|
-
}
|
|
11876
|
-
} else if (_is(taco.c, 'object') && taco.c.t) {
|
|
11877
|
-
this._prepareTaco(taco.c);
|
|
11878
|
-
}
|
|
11879
|
-
};
|
|
11880
|
-
|
|
11881
|
-
/**
|
|
11882
|
-
* Wire action name strings (in onclick etc.) to dispatch function calls.
|
|
11883
|
-
* @private
|
|
11884
|
-
*/
|
|
11885
|
-
_chp._wireActions = function (taco) {
|
|
11886
|
-
if (!_is(taco, 'object') || !taco.t) return;
|
|
11887
|
-
if (taco.a) {
|
|
11888
|
-
for (var key in taco.a) {
|
|
11889
|
-
if (!_hop.call(taco.a, key)) continue;
|
|
11890
|
-
if (key.startsWith('on') && _is(taco.a[key], 'string')) {
|
|
11891
|
-
var actionName = taco.a[key];
|
|
11892
|
-
if (actionName in this._actions) {
|
|
11893
|
-
var registeredName = this._bwId + '_' + actionName;
|
|
11894
|
-
// Replace string with actual function for createDOM event binding
|
|
11895
|
-
(function (rName) {
|
|
11896
|
-
taco.a[key] = function (evt) {
|
|
11897
|
-
bw.funcGetById(rName)(evt);
|
|
11898
|
-
};
|
|
11899
|
-
})(registeredName);
|
|
11900
|
-
}
|
|
11901
|
-
}
|
|
11902
|
-
}
|
|
11903
|
-
}
|
|
11904
|
-
if (_isA(taco.c)) {
|
|
11905
|
-
for (var i = 0; i < taco.c.length; i++) {
|
|
11906
|
-
this._wireActions(taco.c[i]);
|
|
11907
|
-
}
|
|
11908
|
-
} else if (_is(taco.c, 'object') && taco.c.t) {
|
|
11909
|
-
this._wireActions(taco.c);
|
|
11910
|
-
}
|
|
11911
|
-
};
|
|
11912
|
-
|
|
11913
|
-
/**
|
|
11914
|
-
* Deep-clone a TACO tree, preserving _bwWhen/_bwEach markers and their factories.
|
|
11915
|
-
* @private
|
|
11916
|
-
*/
|
|
11917
|
-
_chp._deepCloneTaco = function (taco) {
|
|
11918
|
-
if (taco == null) return taco;
|
|
11919
|
-
// Preserve _bwWhen / _bwEach markers (contain functions)
|
|
11920
|
-
if (taco._bwWhen) {
|
|
11921
|
-
return {
|
|
11922
|
-
_bwWhen: true,
|
|
11923
|
-
expr: taco.expr,
|
|
11924
|
-
branches: [this._deepCloneTaco(taco.branches[0]), taco.branches[1] ? this._deepCloneTaco(taco.branches[1]) : null],
|
|
11925
|
-
_refId: taco._refId
|
|
11926
|
-
};
|
|
11927
|
-
}
|
|
11928
|
-
if (taco._bwEach) {
|
|
11929
|
-
return {
|
|
11930
|
-
_bwEach: true,
|
|
11931
|
-
expr: taco.expr,
|
|
11932
|
-
factory: taco.factory,
|
|
11933
|
-
_refId: taco._refId
|
|
11934
|
-
};
|
|
11935
|
-
}
|
|
11936
|
-
if (!_is(taco, 'object') || !taco.t) return taco;
|
|
11937
|
-
var result = {
|
|
11938
|
-
t: taco.t
|
|
11939
|
-
};
|
|
11940
|
-
if (taco.a) {
|
|
11941
|
-
result.a = {};
|
|
11942
|
-
for (var k in taco.a) {
|
|
11943
|
-
if (_hop.call(taco.a, k)) result.a[k] = taco.a[k];
|
|
11944
|
-
}
|
|
11945
|
-
}
|
|
11946
|
-
if (taco.c != null) {
|
|
11947
|
-
if (_isA(taco.c)) {
|
|
11948
|
-
result.c = taco.c.map(function (child) {
|
|
11949
|
-
return this._deepCloneTaco(child);
|
|
11950
|
-
}.bind(this));
|
|
11951
|
-
} else if (_is(taco.c, 'object')) {
|
|
11952
|
-
result.c = this._deepCloneTaco(taco.c);
|
|
11953
|
-
} else {
|
|
11954
|
-
result.c = taco.c;
|
|
11955
|
-
}
|
|
11956
|
-
}
|
|
11957
|
-
if (taco.o) result.o = taco.o; // Keep o reference (not deep-cloned; hooks are functions)
|
|
11958
|
-
return result;
|
|
11959
|
-
};
|
|
11960
|
-
|
|
11961
|
-
/**
|
|
11962
|
-
* Create a copy of TACO suitable for createDOM (strips o to prevent double lifecycle).
|
|
11963
|
-
* @private
|
|
11964
|
-
*/
|
|
11965
|
-
_chp._tacoForDOM = function (taco) {
|
|
11966
|
-
if (!_is(taco, 'object') || !taco.t) return taco;
|
|
11967
|
-
var result = {
|
|
11968
|
-
t: taco.t
|
|
11969
|
-
};
|
|
11970
|
-
if (taco.a) result.a = taco.a;
|
|
11971
|
-
if (taco.c != null) {
|
|
11972
|
-
if (_isA(taco.c)) {
|
|
11973
|
-
result.c = taco.c.map(function (child) {
|
|
11974
|
-
return this._tacoForDOM(child);
|
|
11975
|
-
}.bind(this));
|
|
11976
|
-
} else if (_is(taco.c, 'object') && taco.c.t) {
|
|
11977
|
-
result.c = this._tacoForDOM(taco.c);
|
|
11978
|
-
} else {
|
|
11979
|
-
result.c = taco.c;
|
|
11980
|
-
}
|
|
11981
|
-
}
|
|
11982
|
-
// Intentionally strip o (no mounted/unmount/state/render on sub-elements)
|
|
11983
|
-
if (taco.o && (taco.o.mounted || taco.o.render || taco.o.unmount)) {
|
|
11984
|
-
_cw('bw: _tacoForDOM stripped o.mounted/render/unmount from child <' + taco.t + '>. Use onclick attribute or bw.component() for child interactivity.');
|
|
11985
|
-
}
|
|
11986
|
-
return result;
|
|
11987
|
-
};
|
|
11988
|
-
|
|
11989
|
-
/**
|
|
11990
|
-
* Unmount: remove from DOM, deactivate, preserve state for re-mount.
|
|
11991
|
-
*/
|
|
11992
|
-
_chp.unmount = function () {
|
|
11993
|
-
if (!this.mounted) return;
|
|
11994
|
-
|
|
11995
|
-
// unmount hook
|
|
11996
|
-
if (this._hooks.unmount) {
|
|
11997
|
-
this._hooks.unmount(this);
|
|
11998
|
-
}
|
|
11999
|
-
|
|
12000
|
-
// Remove DOM event listeners
|
|
12001
|
-
for (var i = 0; i < this._eventListeners.length; i++) {
|
|
12002
|
-
var l = this._eventListeners[i];
|
|
12003
|
-
if (this.element) {
|
|
12004
|
-
this.element.removeEventListener(l.event, l.handler);
|
|
12005
|
-
}
|
|
12006
|
-
}
|
|
12007
|
-
this._eventListeners = [];
|
|
12008
|
-
|
|
12009
|
-
// Unsubscribe pub/sub
|
|
12010
|
-
for (var j = 0; j < this._subs.length; j++) {
|
|
12011
|
-
this._subs[j]();
|
|
12012
|
-
}
|
|
12013
|
-
this._subs = [];
|
|
12014
|
-
|
|
12015
|
-
// Remove from DOM
|
|
12016
|
-
if (this.element && this.element.parentNode) {
|
|
12017
|
-
this.element.parentNode.removeChild(this.element);
|
|
12018
|
-
}
|
|
12019
|
-
this.mounted = false;
|
|
12020
|
-
// State preserved — can re-mount
|
|
12021
|
-
};
|
|
12022
|
-
|
|
12023
|
-
/**
|
|
12024
|
-
* Destroy: unmount + clear state + unregister actions.
|
|
12025
|
-
*/
|
|
12026
|
-
_chp.destroy = function () {
|
|
12027
|
-
// willDestroy hook
|
|
12028
|
-
if (this._hooks.willDestroy) {
|
|
12029
|
-
this._hooks.willDestroy(this);
|
|
12030
|
-
}
|
|
12031
|
-
|
|
12032
|
-
// Cascade destroy to children depth-first (Bug #5)
|
|
12033
|
-
for (var ci = this._children.length - 1; ci >= 0; ci--) {
|
|
12034
|
-
this._children[ci].destroy();
|
|
12035
|
-
}
|
|
12036
|
-
this._children = [];
|
|
12037
|
-
if (this._parent) {
|
|
12038
|
-
var idx = this._parent._children.indexOf(this);
|
|
12039
|
-
if (idx >= 0) this._parent._children.splice(idx, 1);
|
|
12040
|
-
this._parent = null;
|
|
12041
|
-
}
|
|
12042
|
-
this.unmount();
|
|
12043
|
-
|
|
12044
|
-
// Unregister actions from function registry
|
|
12045
|
-
for (var i = 0; i < this._registeredActions.length; i++) {
|
|
12046
|
-
bw.funcUnregister(this._registeredActions[i]);
|
|
12047
|
-
}
|
|
12048
|
-
this._registeredActions = [];
|
|
12049
|
-
|
|
12050
|
-
// Clear state
|
|
12051
|
-
this._state = {};
|
|
12052
|
-
this._bindings = [];
|
|
12053
|
-
this._bw_refs = {};
|
|
12054
|
-
this._prevValues = {};
|
|
12055
|
-
this._dirtyKeys = {};
|
|
12056
|
-
if (this.element) {
|
|
12057
|
-
delete this.element._bwComponentHandle;
|
|
12058
|
-
this.element = null;
|
|
12059
|
-
}
|
|
12060
|
-
};
|
|
12061
|
-
|
|
12062
|
-
// ── Flush & Binding Resolution ──
|
|
12063
|
-
|
|
12064
|
-
/**
|
|
12065
|
-
* Flush dirty state: resolve changed bindings and apply to DOM.
|
|
12066
|
-
* @private
|
|
12067
|
-
*/
|
|
12068
|
-
_chp._flush = function () {
|
|
12069
|
-
this._scheduled = false;
|
|
12070
|
-
var changedKeys = _keys(this._dirtyKeys);
|
|
12071
|
-
this._dirtyKeys = {};
|
|
12072
|
-
if (changedKeys.length === 0 || !this.mounted) return;
|
|
12073
|
-
|
|
12074
|
-
// Factory rebuild: if a BCCL factory exists and changed keys overlap factory props,
|
|
12075
|
-
// rebuild the TACO from the factory with merged state (Bug #6)
|
|
12076
|
-
if (this._factory) {
|
|
12077
|
-
var rebuildNeeded = false;
|
|
12078
|
-
for (var fi = 0; fi < changedKeys.length; fi++) {
|
|
12079
|
-
if (_hop.call(this._factory.props, changedKeys[fi])) {
|
|
12080
|
-
rebuildNeeded = true;
|
|
12081
|
-
break;
|
|
12082
|
-
}
|
|
12083
|
-
}
|
|
12084
|
-
if (rebuildNeeded) {
|
|
12085
|
-
var merged = {};
|
|
12086
|
-
for (var mk in this._factory.props) if (_hop.call(this._factory.props, mk)) merged[mk] = this._factory.props[mk];
|
|
12087
|
-
for (var sk in this._state) if (_hop.call(this._state, sk)) merged[sk] = this._state[sk];
|
|
12088
|
-
this._factory.props = merged;
|
|
12089
|
-
var newTaco = bw.make(this._factory.type, merged);
|
|
12090
|
-
newTaco._bwFactory = this._factory;
|
|
12091
|
-
this.taco = newTaco;
|
|
12092
|
-
this._originalTaco = this._deepCloneTaco(newTaco);
|
|
12093
|
-
this._render();
|
|
12094
|
-
if (this._hooks.onUpdate) this._hooks.onUpdate(this, changedKeys);
|
|
12095
|
-
return;
|
|
12096
|
-
}
|
|
12097
|
-
}
|
|
12098
|
-
|
|
12099
|
-
// willUpdate hook
|
|
12100
|
-
if (this._hooks.willUpdate) {
|
|
12101
|
-
this._hooks.willUpdate(this, changedKeys);
|
|
12102
|
-
}
|
|
12103
|
-
|
|
12104
|
-
// Check if any structural bindings are affected
|
|
12105
|
-
var needsFullRender = false;
|
|
12106
|
-
for (var i = 0; i < this._bindings.length; i++) {
|
|
12107
|
-
var b = this._bindings[i];
|
|
12108
|
-
if (b.type === 'structural') {
|
|
12109
|
-
for (var j = 0; j < b.deps.length; j++) {
|
|
12110
|
-
if (changedKeys.indexOf(b.deps[j]) >= 0) {
|
|
12111
|
-
needsFullRender = true;
|
|
12112
|
-
break;
|
|
12113
|
-
}
|
|
12114
|
-
}
|
|
12115
|
-
if (needsFullRender) break;
|
|
12116
|
-
}
|
|
12117
|
-
}
|
|
12118
|
-
if (needsFullRender) {
|
|
12119
|
-
this._render();
|
|
12120
|
-
} else {
|
|
12121
|
-
var patches = this._resolveBindings(changedKeys);
|
|
12122
|
-
this._applyPatches(patches);
|
|
12123
|
-
}
|
|
12124
|
-
|
|
12125
|
-
// onUpdate hook
|
|
12126
|
-
if (this._hooks.onUpdate) {
|
|
12127
|
-
this._hooks.onUpdate(this, changedKeys);
|
|
12128
|
-
}
|
|
12129
|
-
};
|
|
12130
|
-
|
|
12131
|
-
/**
|
|
12132
|
-
* Resolve bindings whose deps intersect with changedKeys.
|
|
12133
|
-
* Returns list of patches to apply.
|
|
12134
|
-
* @private
|
|
12135
|
-
*/
|
|
12136
|
-
_chp._resolveBindings = function (changedKeys) {
|
|
12137
|
-
var patches = [];
|
|
12138
|
-
for (var i = 0; i < this._bindings.length; i++) {
|
|
12139
|
-
var b = this._bindings[i];
|
|
12140
|
-
if (b.type === 'structural') continue;
|
|
12141
|
-
|
|
12142
|
-
// Check if any dep matches
|
|
12143
|
-
var affected = false;
|
|
12144
|
-
for (var j = 0; j < b.deps.length; j++) {
|
|
12145
|
-
if (changedKeys.indexOf(b.deps[j]) >= 0) {
|
|
12146
|
-
affected = true;
|
|
12147
|
-
break;
|
|
12148
|
-
}
|
|
12149
|
-
}
|
|
12150
|
-
if (!affected) continue;
|
|
12151
|
-
|
|
12152
|
-
// Evaluate
|
|
12153
|
-
var newVal = bw._resolveTemplate(b.template, this._state, this._compile);
|
|
12154
|
-
var prevKey = b.refId + '_' + (b.attrName || 'content');
|
|
12155
|
-
if (this._prevValues[prevKey] !== newVal) {
|
|
12156
|
-
this._prevValues[prevKey] = newVal;
|
|
12157
|
-
patches.push({
|
|
12158
|
-
refId: b.refId,
|
|
12159
|
-
type: b.type,
|
|
12160
|
-
attrName: b.attrName,
|
|
12161
|
-
value: newVal
|
|
12162
|
-
});
|
|
12163
|
-
}
|
|
12164
|
-
}
|
|
12165
|
-
return patches;
|
|
12166
|
-
};
|
|
12167
|
-
|
|
12168
|
-
/**
|
|
12169
|
-
* Apply patches to DOM.
|
|
12170
|
-
* @private
|
|
12171
|
-
*/
|
|
12172
|
-
_chp._applyPatches = function (patches) {
|
|
12173
|
-
for (var i = 0; i < patches.length; i++) {
|
|
12174
|
-
var p = patches[i];
|
|
12175
|
-
var el = this._bw_refs[p.refId];
|
|
12176
|
-
if (!el) {
|
|
12177
|
-
if (bw.debug) _cw('bw.debug: _applyPatches — ref "' + p.refId + '" not found in DOM');
|
|
12178
|
-
continue;
|
|
12179
|
-
}
|
|
12180
|
-
if (p.type === 'content') {
|
|
12181
|
-
el.textContent = p.value;
|
|
12182
|
-
} else if (p.type === 'attribute') {
|
|
12183
|
-
if (p.attrName === 'class') {
|
|
12184
|
-
el.className = p.value;
|
|
12185
|
-
} else {
|
|
12186
|
-
el.setAttribute(p.attrName, p.value);
|
|
12187
|
-
}
|
|
12188
|
-
}
|
|
12189
|
-
}
|
|
12190
|
-
};
|
|
12191
|
-
|
|
12192
|
-
/**
|
|
12193
|
-
* Resolve all bindings and apply (used for initial render).
|
|
12194
|
-
* @private
|
|
12195
|
-
*/
|
|
12196
|
-
_chp._resolveAndApplyAll = function () {
|
|
12197
|
-
var patches = [];
|
|
12198
|
-
for (var i = 0; i < this._bindings.length; i++) {
|
|
12199
|
-
var b = this._bindings[i];
|
|
12200
|
-
if (b.type === 'structural') continue;
|
|
12201
|
-
var newVal = bw._resolveTemplate(b.template, this._state, this._compile);
|
|
12202
|
-
var prevKey = b.refId + '_' + (b.attrName || 'content');
|
|
12203
|
-
this._prevValues[prevKey] = newVal;
|
|
12204
|
-
patches.push({
|
|
12205
|
-
refId: b.refId,
|
|
12206
|
-
type: b.type,
|
|
12207
|
-
attrName: b.attrName,
|
|
12208
|
-
value: newVal
|
|
12209
|
-
});
|
|
12210
|
-
}
|
|
12211
|
-
this._applyPatches(patches);
|
|
12212
|
-
};
|
|
12213
|
-
|
|
12214
|
-
/**
|
|
12215
|
-
* Full re-render for structural changes (when/each branch switches).
|
|
12216
|
-
* @private
|
|
12217
|
-
*/
|
|
12218
|
-
_chp._render = function () {
|
|
12219
|
-
if (!this.element || !this.element.parentNode) return;
|
|
12220
|
-
var parent = this.element.parentNode;
|
|
12221
|
-
var nextSibling = this.element.nextSibling;
|
|
12222
|
-
|
|
12223
|
-
// Remove old DOM
|
|
12224
|
-
parent.removeChild(this.element);
|
|
12225
|
-
|
|
12226
|
-
// Re-prepare TACO with current state (deep clone preserving functions)
|
|
12227
|
-
this.taco = this._deepCloneTaco(this._originalTaco || this.taco);
|
|
12228
|
-
|
|
12229
|
-
// Re-compile bindings and prepare
|
|
12230
|
-
this._compileBindings();
|
|
12231
|
-
this._prepareTaco(this.taco);
|
|
12232
|
-
this._wireActions(this.taco);
|
|
12233
|
-
var tacoForDOM = this._tacoForDOM(this.taco);
|
|
12234
|
-
this.element = bw.createDOM(tacoForDOM);
|
|
12235
|
-
this.element._bwComponentHandle = this;
|
|
12236
|
-
this.element.setAttribute('data-bw_comp_id', this._bwId);
|
|
12237
|
-
|
|
12238
|
-
// Re-insert at same position
|
|
12239
|
-
if (nextSibling) {
|
|
12240
|
-
parent.insertBefore(this.element, nextSibling);
|
|
12241
|
-
} else {
|
|
12242
|
-
parent.appendChild(this.element);
|
|
12243
|
-
}
|
|
12244
|
-
|
|
12245
|
-
// Re-collect refs and apply all bindings
|
|
12246
|
-
this._collectRefs();
|
|
12247
|
-
this._resolveAndApplyAll();
|
|
12248
|
-
};
|
|
12249
|
-
|
|
12250
|
-
// ── Event & Pub/Sub Methods ──
|
|
12251
|
-
|
|
12252
|
-
/**
|
|
12253
|
-
* Add a DOM event listener on the component's root element.
|
|
12254
|
-
* @param {string} event - Event name (e.g., 'click')
|
|
12255
|
-
* @param {Function} handler - Event handler
|
|
12256
|
-
*/
|
|
12257
|
-
_chp.on = function (event, handler) {
|
|
12258
|
-
if (this.element) {
|
|
12259
|
-
this.element.addEventListener(event, handler);
|
|
12260
|
-
}
|
|
12261
|
-
this._eventListeners.push({
|
|
12262
|
-
event: event,
|
|
12263
|
-
handler: handler
|
|
12264
|
-
});
|
|
12265
|
-
};
|
|
12266
|
-
|
|
12267
|
-
/**
|
|
12268
|
-
* Remove a DOM event listener.
|
|
12269
|
-
* @param {string} event - Event name
|
|
12270
|
-
* @param {Function} handler - Handler to remove
|
|
12271
|
-
*/
|
|
12272
|
-
_chp.off = function (event, handler) {
|
|
12273
|
-
if (this.element) {
|
|
12274
|
-
this.element.removeEventListener(event, handler);
|
|
12275
|
-
}
|
|
12276
|
-
this._eventListeners = this._eventListeners.filter(function (l) {
|
|
12277
|
-
return !(l.event === event && l.handler === handler);
|
|
12278
|
-
});
|
|
12279
|
-
};
|
|
12280
|
-
|
|
12281
|
-
/**
|
|
12282
|
-
* Subscribe to a pub/sub topic. Lifecycle-tied: auto-unsubs on destroy.
|
|
12283
|
-
* @param {string} topic - Topic name
|
|
12284
|
-
* @param {Function} handler - Handler function
|
|
12285
|
-
* @returns {Function} Unsubscribe function
|
|
12286
|
-
*/
|
|
12287
|
-
_chp.sub = function (topic, handler) {
|
|
12288
|
-
var unsub = bw.sub(topic, handler);
|
|
12289
|
-
this._subs.push(unsub);
|
|
12290
|
-
return unsub;
|
|
12291
|
-
};
|
|
12292
|
-
|
|
12293
|
-
/**
|
|
12294
|
-
* Call a named action.
|
|
12295
|
-
* @param {string} name - Action name
|
|
12296
|
-
* @param {...*} args - Arguments passed after comp
|
|
12297
|
-
*/
|
|
12298
|
-
_chp.action = function (name) {
|
|
12299
|
-
var fn = this._actions[name];
|
|
12300
|
-
if (!fn) {
|
|
12301
|
-
_cw('ComponentHandle.action: unknown action "' + name + '"');
|
|
12302
|
-
return;
|
|
12303
|
-
}
|
|
12304
|
-
var args = [this].concat(Array.prototype.slice.call(arguments, 1));
|
|
12305
|
-
return fn.apply(null, args);
|
|
12306
|
-
};
|
|
12307
|
-
|
|
12308
|
-
/**
|
|
12309
|
-
* querySelector within the component's DOM.
|
|
12310
|
-
* @param {string} sel - CSS selector
|
|
12311
|
-
* @returns {Element|null}
|
|
12312
|
-
*/
|
|
12313
|
-
_chp.select = function (sel) {
|
|
12314
|
-
return this.element ? this.element.querySelector(sel) : null;
|
|
12315
|
-
};
|
|
12316
|
-
|
|
12317
|
-
/**
|
|
12318
|
-
* querySelectorAll within the component's DOM.
|
|
12319
|
-
* @param {string} sel - CSS selector
|
|
12320
|
-
* @returns {Element[]}
|
|
12321
|
-
*/
|
|
12322
|
-
_chp.selectAll = function (sel) {
|
|
12323
|
-
if (!this.element) return [];
|
|
12324
|
-
return Array.prototype.slice.call(this.element.querySelectorAll(sel));
|
|
12325
|
-
};
|
|
12326
|
-
|
|
12327
|
-
/**
|
|
12328
|
-
* Tag this component with a user-defined ID for addressing via bw.message().
|
|
12329
|
-
* The tag is added as a CSS class on the root element (DOM IS the registry).
|
|
12330
|
-
* @param {string} tag - User-defined identifier (e.g. 'dashboard_prod_east')
|
|
12331
|
-
* @returns {ComponentHandle} this (for chaining)
|
|
12332
|
-
*/
|
|
12333
|
-
_chp.userTag = function (tag) {
|
|
12334
|
-
this._userTag = tag;
|
|
12335
|
-
if (this.element) {
|
|
12336
|
-
this.element.classList.add(tag);
|
|
12337
|
-
}
|
|
12338
|
-
return this;
|
|
12339
|
-
};
|
|
12340
|
-
|
|
12341
|
-
// Expose ComponentHandle on bw (for testing and advanced use)
|
|
12342
|
-
bw._ComponentHandle = ComponentHandle;
|
|
12343
|
-
|
|
12344
|
-
// ===================================================================================
|
|
12345
|
-
// Control Flow Helpers
|
|
12346
|
-
// ===================================================================================
|
|
12347
|
-
|
|
12348
|
-
/**
|
|
12349
|
-
* Conditional rendering helper.
|
|
12350
|
-
* Returns a marker object that ComponentHandle detects during binding compilation.
|
|
12351
|
-
* In static contexts (bw.html with state), evaluates immediately.
|
|
12352
|
-
*
|
|
12353
|
-
* @param {string} expr - Expression string like '${loggedIn}'
|
|
12354
|
-
* @param {Object} tacoTrue - TACO to render when truthy
|
|
12355
|
-
* @param {Object} [tacoFalse] - TACO to render when falsy
|
|
12356
|
-
* @returns {Object} Marker object with _bwWhen flag
|
|
12357
|
-
* @category Component
|
|
12358
|
-
*/
|
|
12359
|
-
bw.when = function (expr, tacoTrue, tacoFalse) {
|
|
12360
|
-
return {
|
|
12361
|
-
_bwWhen: true,
|
|
12362
|
-
expr: expr,
|
|
12363
|
-
branches: [tacoTrue, tacoFalse || null]
|
|
12364
|
-
};
|
|
12365
|
-
};
|
|
12366
|
-
|
|
12367
|
-
/**
|
|
12368
|
-
* List rendering helper.
|
|
12369
|
-
* Returns a marker object that ComponentHandle detects during binding compilation.
|
|
12370
|
-
*
|
|
12371
|
-
* @param {string} expr - Expression string like '${items}'
|
|
12372
|
-
* @param {Function} fn - Factory function(item, index) returning TACO
|
|
12373
|
-
* @returns {Object} Marker object with _bwEach flag
|
|
12374
|
-
* @category Component
|
|
12375
|
-
*/
|
|
12376
|
-
bw.each = function (expr, fn) {
|
|
12377
|
-
return {
|
|
12378
|
-
_bwEach: true,
|
|
12379
|
-
expr: expr,
|
|
12380
|
-
factory: fn
|
|
12381
|
-
};
|
|
12382
|
-
};
|
|
12383
|
-
|
|
12384
|
-
// ===================================================================================
|
|
12385
|
-
// bw.component() — Factory for ComponentHandle
|
|
12386
|
-
// ===================================================================================
|
|
12387
|
-
|
|
12388
|
-
/**
|
|
12389
|
-
* Create a ComponentHandle from a TACO definition.
|
|
12390
|
-
* The returned handle has .get(), .set(), .mount(), .destroy(), etc.
|
|
12391
|
-
*
|
|
12392
|
-
* @param {Object} taco - TACO definition with {t, a, c, o}
|
|
12393
|
-
* @returns {ComponentHandle} Reactive component handle
|
|
12394
|
-
* @category Component
|
|
12395
|
-
* @see bw.DOM
|
|
12396
|
-
* @example
|
|
12397
|
-
* var counter = bw.component({
|
|
12398
|
-
* t: 'div', c: [{ t: 'h3', c: 'Count: ${count}' }],
|
|
12399
|
-
* o: { state: { count: 0 } }
|
|
12400
|
-
* });
|
|
12401
|
-
* bw.DOM('#app', counter);
|
|
12402
|
-
* counter.set('count', 42); // DOM auto-updates
|
|
12403
|
-
*/
|
|
12404
|
-
bw.component = function (taco) {
|
|
12405
|
-
return new ComponentHandle(taco);
|
|
12406
|
-
};
|
|
12407
|
-
|
|
12408
|
-
// ===================================================================================
|
|
12409
|
-
// bw.message() — SendMessage() for the web
|
|
12410
|
-
// ===================================================================================
|
|
12411
|
-
|
|
12412
|
-
/**
|
|
12413
|
-
* Dispatch a message to a component by UUID or user tag.
|
|
12414
|
-
* Finds the component's DOM element, looks up its ComponentHandle,
|
|
12415
|
-
* and calls the named method. This is the bitwrench equivalent of
|
|
12416
|
-
* Win32 SendMessage(hwnd, msg, wParam, lParam).
|
|
12417
|
-
*
|
|
12418
|
-
* @param {string} target - Component UUID (bw_uuid_*), comp ID (data-bw_comp_id), or user tag (CSS class)
|
|
12419
|
-
* @param {string} action - Method name to call on the component
|
|
12420
|
-
* @param {*} data - Data to pass to the method
|
|
12421
|
-
* @returns {boolean} True if message was dispatched successfully
|
|
12422
|
-
* @category Component
|
|
12423
|
-
* @example
|
|
12424
|
-
* // Tag a component
|
|
12425
|
-
* myDash.userTag('dashboard_prod');
|
|
12426
|
-
* // Dispatch locally
|
|
12427
|
-
* bw.message('dashboard_prod', 'addAlert', { severity: 'warning', text: 'CPU spike' });
|
|
12428
|
-
* // Or from SSE handler:
|
|
12429
|
-
* es.onmessage = function(e) {
|
|
12430
|
-
* var msg = JSON.parse(e.data);
|
|
12431
|
-
* bw.message(msg.target, msg.action, msg.data);
|
|
12432
|
-
* };
|
|
12433
|
-
*/
|
|
12434
|
-
bw.message = function (target, action, data) {
|
|
12435
|
-
// Try bw._el() first (handles UUID class, nodeMap cache, getElementById)
|
|
12436
|
-
var el = bw._el(target);
|
|
12437
|
-
// Then try data-bw_comp_id attribute
|
|
12438
|
-
if (!el || !el._bwComponentHandle) {
|
|
12439
|
-
el = bw.$('[data-bw_comp_id="' + target + '"]')[0];
|
|
12440
|
-
}
|
|
12441
|
-
// Then try CSS class (user tag)
|
|
12442
|
-
if (!el || !el._bwComponentHandle) {
|
|
12443
|
-
el = bw.$('.' + target)[0];
|
|
12444
|
-
}
|
|
12445
|
-
if (!el || !el._bwComponentHandle) return false;
|
|
12446
|
-
var comp = el._bwComponentHandle;
|
|
12447
|
-
if (!_is(comp[action], 'function')) {
|
|
12448
|
-
_cw('bw.message: unknown action "' + action + '" on component ' + target);
|
|
12449
|
-
return false;
|
|
12450
|
-
}
|
|
12451
|
-
comp[action](data);
|
|
12452
|
-
return true;
|
|
12453
|
-
};
|
|
12454
|
-
|
|
12455
|
-
// ===================================================================================
|
|
12456
|
-
// bw.apply() / bw.parseJSONFlex() — Server-driven UI protocol
|
|
12457
|
-
// ===================================================================================
|
|
12458
|
-
|
|
12459
|
-
/**
|
|
12460
|
-
* Registry of named functions sent via register messages.
|
|
12461
|
-
* Populated by bw.apply({ type: 'register', name, body }).
|
|
12462
|
-
* Invoked by bw.apply({ type: 'call', name, args }).
|
|
12463
|
-
* @private
|
|
12464
|
-
*/
|
|
12465
|
-
bw._clientFunctions = {};
|
|
11449
|
+
bw._clientFunctions = {};
|
|
12466
11450
|
|
|
12467
11451
|
/**
|
|
12468
11452
|
* Whether exec messages are allowed. Set by bwclient connect opts.allowExec.
|
|
@@ -12655,142 +11639,32 @@
|
|
|
12655
11639
|
// ===================================================================================
|
|
12656
11640
|
|
|
12657
11641
|
/**
|
|
12658
|
-
* Inspect a
|
|
12659
|
-
* Works with DOM elements
|
|
12660
|
-
* Returns the ComponentHandle for console chaining.
|
|
11642
|
+
* Inspect a DOM element's bitwrench state, handle methods, and metadata.
|
|
11643
|
+
* Works with DOM elements or CSS selectors.
|
|
12661
11644
|
*
|
|
12662
|
-
* @param {string|Element
|
|
12663
|
-
* @returns {
|
|
11645
|
+
* @param {string|Element} target - Selector or DOM element
|
|
11646
|
+
* @returns {Element|null} The element, or null if not found
|
|
12664
11647
|
* @category Component
|
|
12665
11648
|
* @example
|
|
12666
|
-
*
|
|
11649
|
+
* bw.inspect('#my-carousel');
|
|
12667
11650
|
* bw.inspect($0);
|
|
12668
|
-
* // Or by selector:
|
|
12669
|
-
* var h = bw.inspect('#my-dashboard');
|
|
12670
|
-
* h.set('count', 99); // chain from returned handle
|
|
12671
11651
|
*/
|
|
12672
11652
|
bw.inspect = function (target) {
|
|
12673
|
-
var el = target;
|
|
12674
|
-
|
|
12675
|
-
|
|
12676
|
-
el = target.element;
|
|
12677
|
-
comp = target;
|
|
12678
|
-
} else {
|
|
12679
|
-
if (_is(target, 'string')) {
|
|
12680
|
-
el = bw.$(target)[0];
|
|
12681
|
-
}
|
|
12682
|
-
if (!el) {
|
|
12683
|
-
_cw('bw.inspect: element not found');
|
|
12684
|
-
return null;
|
|
12685
|
-
}
|
|
12686
|
-
comp = el._bwComponentHandle;
|
|
12687
|
-
}
|
|
12688
|
-
if (!comp) {
|
|
12689
|
-
_cl('bw.inspect: no ComponentHandle on this element');
|
|
12690
|
-
_cl(' Tag:', el.tagName);
|
|
12691
|
-
_cl(' Classes:', el.className);
|
|
12692
|
-
_cl(' _bw_state:', el._bw_state || '(none)');
|
|
11653
|
+
var el = _is(target, 'string') ? bw.$(target)[0] : target;
|
|
11654
|
+
if (!el) {
|
|
11655
|
+
_cw('bw.inspect: element not found');
|
|
12693
11656
|
return null;
|
|
12694
11657
|
}
|
|
12695
|
-
|
|
12696
|
-
|
|
12697
|
-
|
|
12698
|
-
|
|
12699
|
-
|
|
12700
|
-
console.group('Component: ' + comp._bwId);
|
|
12701
|
-
_cl('State:', comp._state);
|
|
12702
|
-
_cl('Bindings:', comp._bindings.length, '(deps:', deps, ')');
|
|
12703
|
-
_cl('Methods:', _keys(comp._methods));
|
|
12704
|
-
_cl('Actions:', _keys(comp._actions));
|
|
12705
|
-
_cl('User tag:', comp._userTag || '(none)');
|
|
12706
|
-
_cl('Mounted:', comp.mounted);
|
|
12707
|
-
_cl('Element:', comp.element);
|
|
11658
|
+
console.group('Element: ' + (bw.getUUID(el) || el.id || el.tagName));
|
|
11659
|
+
_cl('State:', el._bw_state || '(none)');
|
|
11660
|
+
_cl('Handle:', el.bw ? _keys(el.bw) : '(none)');
|
|
11661
|
+
_cl('Classes:', el.className);
|
|
11662
|
+
_cl('Refs:', el._bw_refs || '(none)');
|
|
12708
11663
|
console.groupEnd();
|
|
12709
|
-
return
|
|
11664
|
+
return el;
|
|
12710
11665
|
};
|
|
12711
|
-
|
|
12712
|
-
|
|
12713
|
-
// bw.compile() — Pre-compile TACO into optimized factory
|
|
12714
|
-
// ===================================================================================
|
|
12715
|
-
|
|
12716
|
-
/**
|
|
12717
|
-
* Pre-compile a TACO definition into a factory function.
|
|
12718
|
-
* The factory produces ComponentHandles with pre-compiled binding evaluators.
|
|
12719
|
-
*
|
|
12720
|
-
* Phase 1: validates API surface. Template cloning optimization deferred.
|
|
12721
|
-
*
|
|
12722
|
-
* @param {Object} taco - TACO definition
|
|
12723
|
-
* @returns {Function} Factory function(initialState?) → ComponentHandle
|
|
12724
|
-
* @category Component
|
|
12725
|
-
*/
|
|
12726
|
-
bw.compile = function (taco) {
|
|
12727
|
-
// Pre-extract all binding expressions
|
|
12728
|
-
var precompiled = [];
|
|
12729
|
-
function walkExpressions(node) {
|
|
12730
|
-
if (!_is(node, 'object')) return;
|
|
12731
|
-
if (_is(node.c, 'string') && node.c.indexOf('${') >= 0) {
|
|
12732
|
-
var parsed = bw._parseBindings(node.c);
|
|
12733
|
-
for (var i = 0; i < parsed.length; i++) {
|
|
12734
|
-
try {
|
|
12735
|
-
precompiled.push({
|
|
12736
|
-
expr: parsed[i].expr,
|
|
12737
|
-
fn: new Function('state', 'with(state){return (' + parsed[i].expr + ');}')
|
|
12738
|
-
});
|
|
12739
|
-
} catch (e) {
|
|
12740
|
-
precompiled.push({
|
|
12741
|
-
expr: parsed[i].expr,
|
|
12742
|
-
fn: function fn() {
|
|
12743
|
-
return '';
|
|
12744
|
-
}
|
|
12745
|
-
});
|
|
12746
|
-
}
|
|
12747
|
-
}
|
|
12748
|
-
}
|
|
12749
|
-
if (node.a) {
|
|
12750
|
-
for (var key in node.a) {
|
|
12751
|
-
if (_hop.call(node.a, key)) {
|
|
12752
|
-
var v = node.a[key];
|
|
12753
|
-
if (_is(v, 'string') && v.indexOf('${') >= 0) {
|
|
12754
|
-
var parsed2 = bw._parseBindings(v);
|
|
12755
|
-
for (var j = 0; j < parsed2.length; j++) {
|
|
12756
|
-
try {
|
|
12757
|
-
precompiled.push({
|
|
12758
|
-
expr: parsed2[j].expr,
|
|
12759
|
-
fn: new Function('state', 'with(state){return (' + parsed2[j].expr + ');}')
|
|
12760
|
-
});
|
|
12761
|
-
} catch (e2) {
|
|
12762
|
-
precompiled.push({
|
|
12763
|
-
expr: parsed2[j].expr,
|
|
12764
|
-
fn: function fn() {
|
|
12765
|
-
return '';
|
|
12766
|
-
}
|
|
12767
|
-
});
|
|
12768
|
-
}
|
|
12769
|
-
}
|
|
12770
|
-
}
|
|
12771
|
-
}
|
|
12772
|
-
}
|
|
12773
|
-
}
|
|
12774
|
-
if (_isA(node.c)) {
|
|
12775
|
-
for (var k = 0; k < node.c.length; k++) walkExpressions(node.c[k]);
|
|
12776
|
-
} else if (_is(node.c, 'object') && node.c.t) {
|
|
12777
|
-
walkExpressions(node.c);
|
|
12778
|
-
}
|
|
12779
|
-
}
|
|
12780
|
-
walkExpressions(taco);
|
|
12781
|
-
return function (initialState) {
|
|
12782
|
-
var handle = new ComponentHandle(taco);
|
|
12783
|
-
handle._compile = true;
|
|
12784
|
-
handle._precompiledBindings = precompiled;
|
|
12785
|
-
if (initialState) {
|
|
12786
|
-
for (var k in initialState) {
|
|
12787
|
-
if (_hop.call(initialState, k)) {
|
|
12788
|
-
handle._state[k] = initialState[k];
|
|
12789
|
-
}
|
|
12790
|
-
}
|
|
12791
|
-
}
|
|
12792
|
-
return handle;
|
|
12793
|
-
};
|
|
11666
|
+
bw.compile = function () {
|
|
11667
|
+
throw new Error('bw.compile() removed in v2.0.19. Use o.handle/o.slots on TACO options instead.');
|
|
12794
11668
|
};
|
|
12795
11669
|
|
|
12796
11670
|
/**
|
|
@@ -14096,7 +12970,7 @@
|
|
|
14096
12970
|
* handle.destroy();
|
|
14097
12971
|
*/
|
|
14098
12972
|
bw.render = function (element, position, taco) {
|
|
14099
|
-
var _taco$
|
|
12973
|
+
var _taco$o3, _taco$o4, _taco$o5;
|
|
14100
12974
|
// Get target element
|
|
14101
12975
|
var targetEl = _is(element, 'string') ? document.querySelector(element) : element;
|
|
14102
12976
|
if (!targetEl) {
|
|
@@ -14108,8 +12982,8 @@
|
|
|
14108
12982
|
};
|
|
14109
12983
|
}
|
|
14110
12984
|
|
|
14111
|
-
// Generate unique
|
|
14112
|
-
var componentId = ((_taco$
|
|
12985
|
+
// Generate unique UUID class if not provided
|
|
12986
|
+
var componentId = ((_taco$o3 = taco.o) === null || _taco$o3 === void 0 ? void 0 : _taco$o3.id) || bw.uuid('uuid');
|
|
14113
12987
|
|
|
14114
12988
|
// Create DOM element
|
|
14115
12989
|
var domElement;
|
|
@@ -14124,8 +12998,9 @@
|
|
|
14124
12998
|
};
|
|
14125
12999
|
}
|
|
14126
13000
|
|
|
14127
|
-
// Add component ID
|
|
14128
|
-
domElement.
|
|
13001
|
+
// Add component ID as class + lifecycle marker
|
|
13002
|
+
domElement.classList.add(componentId);
|
|
13003
|
+
domElement.classList.add(_BW_LC);
|
|
14129
13004
|
|
|
14130
13005
|
// Insert into DOM based on position
|
|
14131
13006
|
try {
|
|
@@ -14165,7 +13040,7 @@
|
|
|
14165
13040
|
status_code: 'success',
|
|
14166
13041
|
// Reference to original TACO
|
|
14167
13042
|
_taco: _objectSpread2({}, taco),
|
|
14168
|
-
_state: _objectSpread2({}, ((_taco$
|
|
13043
|
+
_state: _objectSpread2({}, ((_taco$o4 = taco.o) === null || _taco$o4 === void 0 ? void 0 : _taco$o4.state) || {}),
|
|
14169
13044
|
_mounted: true,
|
|
14170
13045
|
// Get DOM element
|
|
14171
13046
|
get element() {
|
|
@@ -14196,7 +13071,8 @@
|
|
|
14196
13071
|
|
|
14197
13072
|
// Re-render
|
|
14198
13073
|
var newElement = bw.createDOM(this._taco);
|
|
14199
|
-
newElement.
|
|
13074
|
+
newElement.classList.add(componentId);
|
|
13075
|
+
newElement.classList.add(_BW_LC);
|
|
14200
13076
|
|
|
14201
13077
|
// Replace in DOM
|
|
14202
13078
|
parent.replaceChild(newElement, this.element);
|
|
@@ -14323,7 +13199,7 @@
|
|
|
14323
13199
|
bw._componentRegistry.set(componentId, handle);
|
|
14324
13200
|
|
|
14325
13201
|
// Call mounted lifecycle
|
|
14326
|
-
if ((_taco$
|
|
13202
|
+
if ((_taco$o5 = taco.o) !== null && _taco$o5 !== void 0 && _taco$o5.mounted) {
|
|
14327
13203
|
taco.o.mounted(domElement, handle);
|
|
14328
13204
|
}
|
|
14329
13205
|
return handle;
|
|
@@ -14371,16 +13247,15 @@
|
|
|
14371
13247
|
// Variant class helper: bw.variantClass('primary') → 'bw_primary'
|
|
14372
13248
|
bw.variantClass = variantClass;
|
|
14373
13249
|
|
|
14374
|
-
// Create functions that return
|
|
13250
|
+
// Create functions that return DOM elements (createCard, createTable, etc.)
|
|
14375
13251
|
Object.entries(components).forEach(function (_ref11) {
|
|
14376
13252
|
var _ref12 = _slicedToArray(_ref11, 2),
|
|
14377
13253
|
name = _ref12[0],
|
|
14378
13254
|
fn = _ref12[1];
|
|
14379
13255
|
if (name.startsWith('make')) {
|
|
14380
|
-
var createName = 'create' + name.substring(4);
|
|
13256
|
+
var createName = 'create' + name.substring(4);
|
|
14381
13257
|
bw[createName] = function (props) {
|
|
14382
|
-
|
|
14383
|
-
return bw.renderComponent(taco);
|
|
13258
|
+
return bw.createDOM(fn(props));
|
|
14384
13259
|
};
|
|
14385
13260
|
}
|
|
14386
13261
|
});
|