@webqit/oohtml 1.8.35 → 1.9.2

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.
@@ -2,523 +2,58 @@
2
2
  /**
3
3
  * @imports
4
4
  */
5
- import Observer from '@webqit/observer';
6
- import { _after,_before, _beforeLast } from '@webqit/util/str/index.js';
7
- import { _each, _merge, _get } from '@webqit/util/obj/index.js';
8
- import { _remove } from '@webqit/util/arr/index.js';
9
- import { _isFunction, _isTypeObject, _internals } from '@webqit/util/js/index.js';
5
+ import { _internals } from '@webqit/util/js/index.js';
10
6
  import domInit from '@webqit/browser-pie/src/dom/index.js';
11
- import { Parser, Runtime, Scope } from '@webqit/subscript';
12
- import { Block } from '@webqit/subscript/src/grammar.js';
7
+ import { Element } from './Element.js';
13
8
  import { config } from '../util.js';
14
9
 
15
- /**
16
- * ---------------------------
17
- * The Reflex class
18
- * ---------------------------
19
- */
20
-
21
10
  /**
22
11
  * @init
23
12
  *
24
13
  * @param Object config
25
14
  */
26
- export default function init(_config = null, onDomReady = false) {
15
+ export default function init( _config = null, onDomReady = false ) {
27
16
 
28
- const WebQit = domInit.call(this);
29
- if (onDomReady) {
30
- WebQit.DOM.ready(() => {
31
- init.call(this, _config, false);
32
- });
17
+ const WebQit = domInit.call( this );
18
+ if ( onDomReady ) {
19
+ WebQit.DOM.ready( () => {
20
+ init.call( this, _config, false );
21
+ } );
33
22
  return;
34
23
  }
35
24
 
36
- const window = WebQit.window;
37
- const document = WebQit.window.document;
38
25
  const mutations = WebQit.DOM.mutations;
39
-
40
- const globalRuntimeInitializationWaitlist = [];
41
- const _meta = config.call(this, {
42
- selectors: {script: 'script[type="subscript"]',},
43
- api: {bind: 'bind', unbind: 'unbind',},
26
+ const _meta = config.call( this, {
27
+ selectors: { script: 'script[type="subscript"]', },
28
+ api: { bind: 'bind', unbind: 'unbind', },
44
29
  script: {},
45
- }, _config);
46
- var globalRuntimeInitialized = _meta.get('script.autorun') !== false;
47
-
48
- // ----------------------
49
- // Helpers
50
- // ----------------------
51
-
52
- const scopeParams = { errorLevel: _meta.get('script.errlevel'), };
53
- const docCntxt = {};
54
- Observer.set(docCntxt, 'document', document);
55
- const globalScopeInstance = Scope.createStack([docCntxt, Scope.create(window)], scopeParams, {
56
- set: Observer.set,
57
- });
58
-
59
- const _getScriptBase = function(target) {
60
- var oohtmlBase = _internals(target, 'oohtml');
61
- if (!oohtmlBase.has('subscript')) {
62
- // Create scope
63
- const thisScope = {};
64
- const scriptBase = {
65
- scope: Scope.createStack([{}/** bindings scope */, thisScope/** the "this" scope */, globalScopeInstance/** global scope */], scopeParams, {
66
- set: Observer.set,
67
- }),
68
- };
69
- Observer.set(thisScope, 'this', target);
70
- oohtmlBase.set('subscript', scriptBase);
71
- scriptBase.console = {
72
- errors: [],
73
- infos: [],
74
- warnings: [],
75
- logs: [],
76
- exceptions: [],
77
- };
78
- }
79
- return oohtmlBase.get('subscript');
80
- };
81
-
82
- const getScriptBase = function(target) {
83
- var scriptBase = _getScriptBase(target);
84
- if (!scriptBase.handler) {
85
- // Binding mode?
86
- scriptBase.handler = e => {
87
- if (!scriptBase.inWaitlist) {
88
- applyBinding(scriptBase.srcCodes1, target, e);
89
- }
90
- };
91
- scriptBase.connected = c => {
92
- scriptBase.isConnected = c;
93
- if (c) {
94
- scriptBase.scope.observe(Observer, scriptBase.handler, { tags: [ scriptBase.handler ] });
95
- } else {
96
- // Unobserve only happens by tags
97
- scriptBase.scope.unobserve(Observer, { tags: [ scriptBase.handler ] });
98
- }
99
- };
100
- }
101
- if (!scriptBase.isConnected) {
102
- // =====================
103
- var mo = mutations.onRemoved(target, () => {
104
- scriptBase.connected(false);
105
- mo.disconnect();
106
- }, { ignoreTransients: true });
107
- scriptBase.connected(true);
108
- }
109
- return scriptBase;
110
- };
111
-
112
- const applyBinding = function(srcCodes, target, event) {
113
- var targetScriptBase = _getScriptBase(target);
114
- targetScriptBase.inWaitlist = false;
115
- var params = {
116
- references: (event || {}).references,
117
- catch: targetScriptBase.catch ? targetScriptBase.catch : e => {
118
- if (targetScriptBase.errorLevel === 2) {
119
- console.error(target, e);
120
- targetScriptBase.console.errors.push(e);
121
- } else if (targetScriptBase.errorLevel !== 0) {
122
- console.warn(target, e.message);
123
- targetScriptBase.console.warnings.push(e.message);
124
- }
125
- },
126
- trap: Observer,
127
- };
128
- srcCodes.forEach(srcCode => {
129
- Runtime.eval(srcCode, targetScriptBase.scope, params);
130
- });
131
- };
132
-
133
- // ----------------------
134
- // Capture scripts
135
- // ----------------------
136
-
137
- mutations.onPresent(_meta.get('selectors.script'), (scriptElement, p) => {
138
- if (!scriptElement.parentNode) {
139
- return;
140
- }
141
- // Remove
142
- var parentNode = scriptElement.parentNode,
143
- scriptBase = getScriptBase(parentNode);
144
- if (!_meta.get('isomorphic')) {
145
- scriptElement.remove();
146
- }
147
- scriptBase.scriptElements = scriptBase.scriptElements || [],
148
- scriptBase.srcCodes1 = scriptBase.srcCodes1 || [];
149
- if (scriptBase.scriptElements.includes(scriptElement)) {
150
- return;
151
- }
152
- scriptBase.scriptElements.push(scriptElement);
153
- var srcCode = (scriptElement.textContent || '').trim();
154
- if (!srcCode) {
155
- return;
156
- }
157
- // ------
158
- // Parse
159
- // ------
160
- var explain = [],
161
- shouldExplain = scriptElement.hasAttribute('explain') || _meta.get('script.explain'),
162
- srcCodeAST = parse(srcCode, {
163
- explain: shouldExplain ? explain : null,
164
- });
165
- scriptBase.srcCodes1.push(srcCodeAST);
166
- if (scriptElement.hasAttribute('scoped')) {
167
- //Observer.set(scriptBase.scope.stack.super.stack.main, 'this', parentNode);
168
- }
169
- if (shouldExplain) {
170
- scriptBase.console.logs.push(explain);
171
- console.log(parentNode, explain);
172
- }
173
- // ------
174
- // Eval
175
- // ------
176
- scriptBase.errorLevel = scriptElement.getAttribute('errors')
177
- ? parseInt(scriptElement.getAttribute('errors'))
178
- : _meta.get('script.errors');
179
- if (globalRuntimeInitialized || scriptBase.hasBindings || scriptElement.hasAttribute('autorun')) {
180
- applyBinding([ srcCodeAST ], parentNode);
181
- } else {
182
- scriptBase.inWaitlist = true;
183
- globalRuntimeInitializationWaitlist.push(parentNode);
184
- }
185
- });
30
+ }, _config );
186
31
 
187
- // ----------------------
188
- // Define the "local" binding method on Element.prototype
189
- // ----------------------
32
+ const subscriptElement = Element( class {} );
33
+ const $subscriptElement = new subscriptElement;
34
+ mutations.onPresent( _meta.get('selectors.script'), scriptElement => {
190
35
 
191
- if ('subscript' in window.Element.prototype) {
192
- throw new Error('The "Element" class already has a "subscript" property!');
193
- }
194
- Object.defineProperty(window.Element.prototype, 'subscript', {
195
- get: function() {
196
- let scriptBase = getScriptBase(this);
197
- if (!('bindings' in scriptBase)) {
198
- var $this = this;
199
-
200
- // ---------------------
201
-
202
- Object.defineProperty(scriptBase, 'bindings', {
203
- get: function() {
204
- if (!scriptBase.scopeInstanceProxy) {
205
- // Same proxy instance, even if scriptBase.scope.stack.main
206
- // is later changed
207
- scriptBase.scopeInstanceProxy = new Proxy(scriptBase.scope.stack.main, {
208
- set: (target, key, value) => {
209
- // NOTE that this element if in waitlist won't be called by this Observer.set()
210
- Observer.set(scriptBase.scope.stack.main, key, value);
211
- scriptBase.hasBindings = true;
212
- // Explicitly remove from waitlist
213
- if (globalRuntimeInitializationWaitlist.includes($this)) {
214
- _remove(globalRuntimeInitializationWaitlist, $this);
215
- applyBinding((scriptBase.srcCodes1 || []).concat(scriptBase.srcCodes2 || []), $this);
216
- }
217
- return true;
218
- },
219
- get: (target, key) => {
220
- return Observer.get(scriptBase.scope.stack.main, key);
221
- },
222
- deleteProperty: (target, key) => {
223
- return Observer.deleteProperty(scriptBase.scope.stack.main, key);
224
- },
225
- });
226
- }
227
- return scriptBase.scopeInstanceProxy;
228
- },
229
- });
230
-
231
- // ---------------------
232
-
233
- Object.defineProperty(scriptBase, 'bind', {
234
- value: function(binding, params = {}) {
235
- // NOTE that this element if in waitlist won't be called by this Observer.set()/Observer.set()
236
- if (params.update) {
237
- Observer.set(scriptBase.scope.stack.main, binding);
238
- } else {
239
- Observer.set(scriptBase.scope.stack, 'main', binding);
240
- }
241
- scriptBase.hasBindings = true;
242
- // Explicitly remove from waitlist
243
- if (globalRuntimeInitializationWaitlist.includes($this)) {
244
- _remove(globalRuntimeInitializationWaitlist, $this);
245
- applyBinding((scriptBase.srcCodes1 || []).concat(scriptBase.srcCodes2 || []), $this);
246
- }
247
- }
248
- });
249
-
250
- // ---------------------
251
-
252
- Object.defineProperty(scriptBase, _meta.get('api.unbind'), {
253
- value: function() {
254
- Observer.set(scriptBase.scope.stack, 'main', {});
255
- }
256
- });
257
- }
258
- return scriptBase;
36
+ let ownerNode = scriptElement.parentNode;
37
+ if ( !ownerNode ) return;
38
+ let embeds = _internals( ownerNode, 'oohtml', 'subscript' ).get( 'embeds' );
39
+ if ( !embeds ) {
40
+ embeds = new WeakSet;
41
+ _internals( ownerNode, 'oohtml', 'subscript' ).set( 'embeds', embeds );
259
42
  }
260
- });
43
+ if ( embeds.has( scriptElement ) ) return;
261
44
 
262
- // ----------------------
263
- // Define the global "scopedJS" object
264
- // ----------------------
45
+ subscriptElement.implementScript( ownerNode, scriptElement )();
46
+ $subscriptElement.connectedCallback.call( ownerNode );
47
+ embeds.add( scriptElement );
265
48
 
266
- if ('subscript' in document) {
267
- throw new Error('The "document" object already has a "subscript" property!');
268
- }
269
- var globalScopeInstanceProxy, globalSubscript = {};
270
- Object.defineProperty(document, 'subscript', {
271
- get: function() {
272
- if (!('bindings' in globalSubscript)) {
49
+ let mo = mutations.onRemoved( ownerNode, () => {
50
+ $subscriptElement.disconnectedCallback.call( ownerNode );
51
+ embeds.delete( scriptElement );
52
+ mo.disconnect();
53
+ }, { ignoreTransients: true });
273
54
 
274
- Object.defineProperty(globalSubscript, 'bindings', {
275
- get: function() {
276
- if (!globalScopeInstanceProxy) {
277
- // Same proxy instance, even if globalScopeInstance.stack.main
278
- // is later changed
279
- globalScopeInstanceProxy = new Proxy(globalScopeInstance.stack.main, {
280
- set: (target, key, value) => {
281
- // NOTE that elements in waitlist won't be called by this Observer.set()
282
- Observer.set(globalScopeInstance.stack.main, key, value);
283
- // Explicitly empty waitlist
284
- var waitingElement;
285
- while(waitingElement = globalRuntimeInitializationWaitlist.shift()) {
286
- var scriptBase = getScriptBase(waitingElement);
287
- applyBinding((scriptBase.srcCodes1 || []).concat(scriptBase.srcCodes2 || []), waitingElement);
288
- }
289
- globalRuntimeInitialized = true;
290
- return true;
291
- },
292
- get: (target, key) => {
293
- return Observer.get(globalScopeInstance.stack.main, key);
294
- },
295
- deleteProperty: (target, key) => {
296
- return Observer.deleteProperty(globalScopeInstance.stack.main, key);
297
- },
298
- });
299
- }
300
- return globalScopeInstanceProxy;
301
- },
302
- });
55
+ } );
303
56
 
304
- // ---------------------
57
+ WebQit.SubscriptElement = Element;
305
58
 
306
- Object.defineProperty(globalSubscript, 'bind', {
307
- value: function(binding, params = {}) {
308
- // NOTE that elements in waitlist won't be called by this Observer.set()/Observer.set()
309
- if (params.update) {
310
- Observer.set(globalScopeInstance.stack.main, binding);
311
- } else {
312
- Observer.set(globalScopeInstance.stack, 'main', binding);
313
- }
314
- // Explicitly empty waitlist
315
- var waitingElement;
316
- while(waitingElement = globalRuntimeInitializationWaitlist.shift()) {
317
- var scriptBase = getScriptBase(waitingElement);
318
- applyBinding((scriptBase.srcCodes1 || []).concat(scriptBase.srcCodes2 || []), waitingElement);
319
- }
320
- globalRuntimeInitialized = true;
321
- },
322
- });
323
-
324
- // ---------------------
325
-
326
- Object.defineProperty(globalSubscript, 'unbind', {
327
- value: function() {
328
- Observer.set(globalScopeInstance.stack, 'main', {});
329
- },
330
- });
331
-
332
- }
333
- return globalSubscript;
334
- },
335
- });
336
-
337
- // ----------------------
338
- // Define the global "SubscriptElement()" mixin
339
- // ----------------------
340
-
341
- WebQit.SubscriptElement = BaseElement => class extends BaseElement {
342
-
343
- /**
344
- * @constructor()
345
- */
346
- constructor() {
347
- super();
348
-
349
- // -----------------------
350
- // Parse methods that are reactive by their default parameters
351
- // -----------------------
352
-
353
- this._parametersContextGroups = {};
354
- this._parametersDefaultValsRefs = {};
355
- (this.constructor.subscriptParameterBlocks || []).forEach(methodName => {
356
- if (methodName.replaceAll(' ', '').endsWith('()')) {
357
- methodName = methodName.replaceAll('(', '').replaceAll('}', '');
358
- }
359
- if (methodName === 'constructor') {
360
- throw new Error(`Constructors cannot be reactive methods.`);
361
- }
362
- if (!_isFunction(this[methodName])) {
363
- throw new Error(`The implied reactive method "${methodName}" is not a function.`);
364
- }
365
- var srcCode = this[methodName].toString().trim();
366
- var parameters = _before(_after(srcCode, '('), ')').split(',').map(param => param.trim()).filter(param => param);
367
- if (!parameters.length) {
368
- throw new Error(`[${methodName}()]: Reactive methods must have parameters.`);
369
- }
370
- this._parametersContextGroups[methodName] = {};
371
- this._parametersDefaultValsRefs[methodName] = parameters.map(param => {
372
- if (!param.includes('=')) {
373
- throw new Error(`[${methodName}(${param})]: All parameters must have a default value.`);
374
- }
375
- var _param = param.split('=').map(p => p.trim());
376
- if (!_param[1].includes('.')) {
377
- throw new Error(`[${methodName}(${param})]: Parameter's default value must be a path reference.`);
378
- }
379
- var refArr = _param[1].replaceAll('?.', '.').split('.');
380
- var contextName = refArr.shift();
381
- var context = contextName === 'this' ? this : (
382
- contextName === 'document' ? document : (
383
- contextName === 'window' ? window : globalThis[contextName]
384
- )
385
- );
386
- if (!_isTypeObject(context)) {
387
- throw new Error(`[${methodName}(${param})]: Parameter's default value does not reference an object in scope.`);
388
- }
389
- if (!this._parametersContextGroups[methodName][contextName]) {
390
- this._parametersContextGroups[methodName][contextName] = { context, refs: [] };
391
- }
392
- this._parametersContextGroups[methodName][contextName].refs.push(refArr);
393
- return _param[1];
394
- });
395
- });
396
-
397
- // -----------------------
398
- // Parse whole reactive blocks
399
- // -----------------------
400
-
401
- var explain = [],
402
- shouldExplain = _meta.get('script.explain'),
403
- scriptBase = _getScriptBase(this);
404
- scriptBase.srcCodes2 = (this.constructor.subscriptBlocks || []).map(blockName => {
405
- if (blockName === 'constructor') {
406
- throw new Error(`Constructors cannot be reactive blocks.`);
407
- }
408
- if (!_isFunction(this[blockName])) {
409
- throw new Error(`The implied reactive block "${blockName}" is not a function.`);
410
- }
411
- var srcCode = this[blockName].toString().trim();
412
- if (!srcCode.replaceAll(' ', '').startsWith(`${blockName}(){`)) {
413
- throw new Error(`[${blockName}()]: Reactive blocks cannot have parameters.`);
414
- }
415
- return _beforeLast(_after(srcCode, '{'), '}');
416
- }).filter(srcCode => srcCode);
417
- scriptBase.srcCodes2 = scriptBase.srcCodes2.map(srcCode => parse(srcCode, {
418
- explain: shouldExplain ? explain : null,
419
- }));
420
- if (shouldExplain) {
421
- scriptBase.console.logs.push(explain);
422
- console.log(this, explain);
423
- }
424
- scriptBase.handler2 = e => {
425
- if (!scriptBase.inWaitlist) {
426
- applyBinding(scriptBase.srcCodes2, this, e);
427
- }
428
- };
429
-
430
- }
431
-
432
- /**
433
- * @connectedCallback()
434
- */
435
- connectedCallback() {
436
-
437
- // -----------------------
438
- // Bind methods that are reactive by their default parameters
439
- // -----------------------
440
-
441
- _each(this._parametersContextGroups, (methodName, parametersContextGroups) => {
442
- const parametersDefaultValsRefs = this._parametersDefaultValsRefs[methodName];
443
- _each(parametersContextGroups, (contextName, dfn) => {
444
- Observer.observe(dfn.context, dfn.refs, mutations => {
445
- var argsByRef = {};
446
- mutations.forEach(mutation => {
447
- argsByRef[`${contextName}.${mutation.path.join('.')}`] = mutation.value;
448
- });
449
- var args = parametersDefaultValsRefs.map(ref => {
450
- if (!argsByRef[ref]) {
451
- var refArr = ref.split('.');
452
- var contextName = refArr.shift();
453
- argsByRef[ref] = _get(parametersContextGroups[contextName].context, refArr, Observer);
454
- }
455
- return argsByRef[ref];
456
- });
457
- try {
458
- this[methodName](...args);
459
- } catch(e) {
460
- console.error(e);
461
- }
462
- }, { diff: true, suptree: true, tags: [ this, 'subscriptParameterBlocks' ] });
463
- });
464
- // Autorun?
465
- try {
466
- this[methodName]();
467
- } catch(e) {}
468
- });
469
-
470
- // -----------------------
471
- // Bind whole reactive blocks
472
- // -----------------------
473
-
474
- const scriptBase = _getScriptBase(this);
475
- // Autorun?
476
- if (globalRuntimeInitialized || scriptBase.hasBindings) {
477
- applyBinding(scriptBase.srcCodes2, this);
478
- } else {
479
- scriptBase.inWaitlist = true;
480
- globalRuntimeInitializationWaitlist.push(this);
481
- }
482
- scriptBase.scope.observe(Observer, scriptBase.handler2, { tags: [ scriptBase.handler2 ] });
483
-
484
- }
485
-
486
- /**
487
- * @disconnectedCallback()
488
- */
489
- disconnectedCallback() {
490
-
491
- // -----------------------
492
- // Unbind methods that are reactive by their default parameters
493
- // -----------------------
494
-
495
- _each(this._parametersContextGroups, (methodName, parametersContextGroups) => {
496
- _each(parametersContextGroups, (contextName, dfn) => {
497
- Observer.unobserve(dfn.context, null, null, { tags: [ this, 'subscriptParameterBlocks' ] });
498
- });
499
- });
500
-
501
- // -----------------------
502
- // Unbind whole reactive blocks
503
- // -----------------------
504
-
505
- const scriptBase = _getScriptBase(this);
506
- scriptBase.scope.unobserve(Observer, { tags: [ scriptBase.handler2 ] });
507
-
508
- }
509
- };
510
-
511
- };
512
-
513
- /**
514
- * @parse
515
- */
516
- const parseCache = {};
517
- function parse(srcCode, params = {}) {
518
- if (!parseCache[srcCode]) {
519
- if (!(parseCache[srcCode] = Parser.parse(srcCode, [Block], _merge({assert:false}, params)))) {
520
- parseCache[srcCode] = new Block([Parser.parse(srcCode, null, params)]);
521
- }
522
- }
523
- return parseCache[srcCode];
524
- }
59
+ }
@@ -3,11 +3,10 @@
3
3
  * @imports
4
4
  */
5
5
  const path = require('path');
6
+ const CompressionPlugin = require("compression-webpack-plugin");
6
7
 
7
- /**
8
- * @exports
9
- */
10
8
  module.exports = {
9
+ plugins: [ new CompressionPlugin() ],
11
10
  mode: process.argv.includes('--dev') ? 'development' : 'production',
12
11
  entry: {
13
12
  main: './src/browser-entry.js',