@webqit/oohtml 2.1.59 → 2.1.60

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/package.json CHANGED
@@ -14,7 +14,7 @@
14
14
  "wicg-proposal"
15
15
  ],
16
16
  "homepage": "https://webqit.io/tooling/oohtml",
17
- "version": "2.1.59",
17
+ "version": "2.1.60",
18
18
  "license": "MIT",
19
19
  "repository": {
20
20
  "type": "git",
@@ -29,8 +29,8 @@
29
29
  "scripts": {
30
30
  "test": "mocha --extension .test.js --exit",
31
31
  "test:coverage": "c8 --reporter=text-lcov npm run test | coveralls",
32
- "build": "esbuild main=src/targets.browser.js context-api=src/context-api/targets.browser.js bindings-api=src/bindings-api/targets.browser.js html-imports=src/html-imports/targets.browser.js html-bindings=src/html-bindings/targets.browser.js html-namespaces=src/html-namespaces/targets.browser.js scoped-js=src/scoped-js/targets.browser.js scoped-css=src/scoped-css/targets.browser.js --bundle --minify --sourcemap --outdir=dist",
33
- "preversion": "npm run build && git add -A dist",
32
+ "build": "esbuild main=src/targets.browser.js namespaced-html=src/namespaced-html/targets.browser.js scoped-css=src/scoped-css/targets.browser.js scoped-js=src/scoped-js/targets.browser.js context-api=src/context-api/targets.browser.js bindings-api=src/bindings-api/targets.browser.js html-imports=src/html-imports/targets.browser.js data-binding=src/data-binding/targets.browser.js --bundle --minify --sourcemap --outdir=dist",
33
+ "preversion": "npm run test && npm run build && git add -A dist",
34
34
  "postversion": "npm publish",
35
35
  "postpublish": "git push && git push --tags"
36
36
  },
@@ -41,7 +41,7 @@
41
41
  "@webqit/util": "^0.8.11"
42
42
  },
43
43
  "devDependencies": {
44
- "@webqit/oohtml-ssr": "^1.2.17",
44
+ "@webqit/oohtml-ssr": "^1.2.19",
45
45
  "chai": "^4.3.4",
46
46
  "coveralls": "^3.1.1",
47
47
  "esbuild": "^0.14.43",
@@ -9,6 +9,19 @@ export default class _HTMLBindingsProvider extends HTMLContextProvider {
9
9
 
10
10
  static type = 'bindings';
11
11
 
12
+ /**
13
+ * @createRequest
14
+ */
15
+ static createRequest( fields = {} ) {
16
+ const request = super.createRequest( fields );
17
+ if ( request.detail?.startsWith( '@' ) ) {
18
+ const [ contextName, ...detail ] = request.detail.slice( 1 ).split( '.' ).map( s => s.trim() );
19
+ request.contextName = contextName;
20
+ request.detail = detail.join( '.' );
21
+ }
22
+ return request;
23
+ }
24
+
12
25
  /**
13
26
  * @matchesRequest
14
27
  */
@@ -15,9 +15,11 @@ export { Observer }
15
15
  */
16
16
  export default function init( $config = {} ) {
17
17
  const { config, window } = _init.call( this, 'bindings-api', $config, {
18
- context: { attr: { contextname: 'contextname' }, },
18
+ context: { attr: { bindingscontext: 'bindings' }, },
19
19
  api: { bind: 'bind', bindings: 'bindings', },
20
20
  } );
21
+ config.CONTEXT_API = window.webqit.oohtml.configs.CONTEXT_API;
22
+ config.context.attr.contextname = config.CONTEXT_API.attr.contextname; // Inherit this
21
23
  window.webqit.HTMLBindingsProvider = class extends _HTMLBindingsProvider {
22
24
  static get config() { return config; }
23
25
  };
@@ -31,7 +33,8 @@ export default function init( $config = {} ) {
31
33
  * The internal bindings object
32
34
  * within elements and the document object.
33
35
  */
34
- function getBindingsObject( node ) {
36
+ function getBindingsObject( config, node ) {
37
+ const window = this;
35
38
  if ( !_( node ).has( 'bindings' ) ) {
36
39
  const bindingsObj = Object.create( null );
37
40
  _( node ).set( 'bindings', bindingsObj );
@@ -41,6 +44,13 @@ function getBindingsObject( node ) {
41
44
  detachBindingsContext.call( this, node, mutation.key );
42
45
  } else { attachBindingsContext.call( this, node, mutation.key ); }
43
46
  }
47
+ const props = Object.keys( bindingsObj );
48
+ const targetNode = node === window.document ? window.document.documentElement : node;
49
+ if ( props.length ) {
50
+ targetNode.setAttribute( config.context.attr.bindingscontext, props.join( ' ') );
51
+ } else {
52
+ targetNode.toggleAttribute( config.context.attr.bindingscontext, false );
53
+ }
44
54
  } );
45
55
  }
46
56
  return _( node ).get( 'bindings' );
@@ -61,14 +71,15 @@ function detachBindingsContext( host, key ) {
61
71
  /**
62
72
  * Exposes Bindings with native APIs.
63
73
  *
74
+ * @param Object config
64
75
  * @param document|Element target
65
76
  * @param Object bindings
66
77
  * @param Object params
67
78
  *
68
79
  * @return Void
69
80
  */
70
- function applyBindings( target, bindings, { merge, diff, namespace } = {} ) {
71
- const bindingsObj = getBindingsObject.call( this, target );
81
+ function applyBindings( config, target, bindings, { merge, diff, namespace } = {} ) {
82
+ const bindingsObj = getBindingsObject.call( this, config, target );
72
83
  const $params = { diff, namespace };
73
84
  const exitingKeys = merge ? [] : Observer.ownKeys( bindingsObj, $params ).filter( key => !( key in bindings ) );
74
85
  return Observer.batch( bindingsObj, () => {
@@ -93,15 +104,15 @@ function exposeAPIs( config ) {
93
104
  if ( config.api.bindings in window.Element.prototype ) { throw new Error( `The "Element" class already has a "${ config.api.bindings }" property!` ); }
94
105
  // Definitions
95
106
  Object.defineProperty( window.document, config.api.bind, { value: function( bindings, config = {} ) {
96
- return applyBindings.call( window, window.document, bindings, config );
107
+ return applyBindings.call( window, config, window.document, bindings );
97
108
  } });
98
109
  Object.defineProperty( window.document, config.api.bindings, { get: function() {
99
- return Observer.proxy( getBindingsObject.call( window, window.document ) );
110
+ return Observer.proxy( getBindingsObject.call( window, config, window.document ) );
100
111
  } });
101
112
  Object.defineProperty( window.Element.prototype, config.api.bind, { value: function( bindings, config = {} ) {
102
- return applyBindings.call( window, this, bindings, config );
113
+ return applyBindings.call( window, config, this, bindings );
103
114
  } });
104
115
  Object.defineProperty( window.Element.prototype, config.api.bindings, { get: function() {
105
- return Observer.proxy( getBindingsObject.call( window, this ) );
116
+ return Observer.proxy( getBindingsObject.call( window, config, this ) );
106
117
  } } );
107
118
  }
@@ -23,6 +23,7 @@ export {
23
23
  */
24
24
  export default function init( $config = {} ) {
25
25
  const { config, window } = _init.call( this, 'context-api', $config, {
26
+ attr: { contextname: 'contextname', },
26
27
  api: { context: 'context', },
27
28
  } );
28
29
  window.webqit.HTMLContextProvider = HTMLContextProvider;
@@ -16,7 +16,7 @@ import { _, _init } from '../util.js';
16
16
  */
17
17
  export default function init( $config = {} ) {
18
18
  const { config, window } = _init.call( this, 'html-bindings', $config, {
19
- attr: { bindings: 'bindings', itemIndex: 'data-index' },
19
+ attr: { binding: 'binding', itemIndex: 'data-index' },
20
20
  tokens: { nodeType: 'processing-instruction', tagStart: '?{', tagEnd: '}?', stateStart: '; [=', stateEnd: ']' },
21
21
  staticsensitivity: true,
22
22
  isomorphic: true,
@@ -24,7 +24,7 @@ export default function init( $config = {} ) {
24
24
  config.CONTEXT_API = window.webqit.oohtml.configs.CONTEXT_API;
25
25
  config.BINDINGS_API = window.webqit.oohtml.configs.BINDINGS_API;
26
26
  config.HTML_IMPORTS = window.webqit.oohtml.configs.HTML_IMPORTS;
27
- config.attrSelector = `[${ window.CSS.escape( config.attr.bindings ) }]`;
27
+ config.attrSelector = `[${ window.CSS.escape( config.attr.binding ) }]`;
28
28
  const discreteBindingsMatch = ( start, end ) => {
29
29
  const starting = `starts-with(., "${ start }")`;
30
30
  const ending = `substring(., string-length(.) - string-length("${ end }") + 1) = "${ end }"`;
@@ -56,7 +56,7 @@ function realtime( config ) {
56
56
  }
57
57
 
58
58
  function createDynamicScope( config, root ) {
59
- if ( _( root ).has( 'htBindings' ) ) return _( root ).get( 'htBindings' );
59
+ if ( _( root ).has( 'data-binding' ) ) return _( root ).get( 'data-binding' );
60
60
  const scope = {}, abortController = new AbortController;
61
61
  scope.$set__ = function( node, prop, val ) {
62
62
  node && ( node[ prop ] = val );
@@ -73,22 +73,22 @@ function createDynamicScope( config, root ) {
73
73
  },
74
74
  has: ( e, recieved, next ) => { return next( true ); }
75
75
  } );
76
- const instance = { scope, abortController, htBindings: new Map };
77
- _( root ).set( 'htBindings', instance );
76
+ const instance = { scope, abortController, bindings: new Map };
77
+ _( root ).set( 'data-binding', instance );
78
78
  return instance;
79
79
  }
80
80
 
81
81
  function cleanup( ...entries ) {
82
82
  for ( const node of entries ) {
83
83
  const root = node.nodeName === '#text' ? node.parentNode : node;
84
- const { htBindings, abortController } = _( root ).get( 'htBindings' ) || {};
85
- if ( !htBindings?.has( node ) ) return;
86
- htBindings.get( node ).state.dispose();
87
- htBindings.get( node ).signals.forEach( s => s.abort() );
88
- htBindings.delete( node );
89
- if ( !htBindings.size ) {
84
+ const { bindings, abortController } = _( root ).get( 'data-binding' ) || {};
85
+ if ( !bindings?.has( node ) ) return;
86
+ bindings.get( node ).state.dispose();
87
+ bindings.get( node ).signals.forEach( s => s.abort() );
88
+ bindings.delete( node );
89
+ if ( !bindings.size ) {
90
90
  abortController.abort();
91
- _( root ).delete( 'htBindings' );
91
+ _( root ).delete( 'data-binding' );
92
92
  }
93
93
  }
94
94
  }
@@ -127,24 +127,24 @@ async function mountDiscreteBindings( config, ...entries ) {
127
127
  }, [] );
128
128
 
129
129
  for ( const { textNode, template, anchorNode } of instances ) {
130
- const { scope: env, htBindings } = createDynamicScope( config, textNode.parentNode );
130
+ const { scope: env, bindings } = createDynamicScope( config, textNode.parentNode );
131
131
  let source = '';
132
132
  source += `let content = ((${ template.expr }) ?? '') + '';`;
133
133
  source += `$set__(this, 'nodeValue', content);`;
134
134
  if ( anchorNode ) { source += `$set__($anchorNode__, 'nodeValue', \`${ config.tokens.tagStart }${ template.expr }${ config.tokens.stateStart }\` + content.length + \`${ config.tokens.stateEnd } ${ config.tokens.tagEnd }\`);`; }
135
135
  const compiled = new StatefulAsyncFunction( '$signals__', `$anchorNode__`, source, { env } );
136
136
  const signals = [];
137
- htBindings.set( textNode, { compiled, signals, state: await compiled.call( textNode, signals, anchorNode ), } );
137
+ bindings.set( textNode, { compiled, signals, state: await compiled.call( textNode, signals, anchorNode ), } );
138
138
  }
139
139
  }
140
140
 
141
141
  async function mountInlineBindings( config, ...entries ) {
142
142
  for ( const node of entries ) {
143
- const source = parseInlineBindings( config, node.getAttribute( config.attr.bindings ) );
144
- const { scope: env, htBindings } = createDynamicScope( config, node );
143
+ const source = parseInlineBindings( config, node.getAttribute( config.attr.binding ) );
144
+ const { scope: env, bindings } = createDynamicScope( config, node );
145
145
  const compiled = new StatefulAsyncFunction( '$signals__', source, { env } );
146
146
  const signals = [];
147
- htBindings.set( node, { compiled, signals, state: await compiled.call( node, signals ), } );
147
+ bindings.set( node, { compiled, signals, state: await compiled.call( node, signals ), } );
148
148
  }
149
149
  }
150
150
 
@@ -87,7 +87,7 @@ export default function( config ) {
87
87
  priv.autoRestoreRealtime?.disconnect();
88
88
  if ( callback ) callback();
89
89
  const restore = () => {
90
- priv.anchorNode.replaceWith( this.el );
90
+ priv.anchorNode?.replaceWith( this.el );
91
91
  priv.anchorNode = null;
92
92
  this.el.setAttribute( 'data-nodecount', 0 );
93
93
  };
@@ -18,12 +18,13 @@ import { _, _init } from '../util.js';
18
18
  export default function init( $config = {} ) {
19
19
  const { config, realdom, window } = _init.call( this, 'html-imports', $config, {
20
20
  template: { attr: { moduledef: 'def', fragmentdef: 'def', extends: 'extends', inherits: 'inherits' }, api: { modules: 'modules', moduledef: 'def' }, },
21
- context: { attr: { importscontext: 'importscontext', contextname: 'contextname' }, api: { import: 'import' }, },
21
+ context: { attr: { importscontext: 'importscontext', }, api: { import: 'import' }, },
22
22
  import: { tagName: 'import', attr: { moduleref: 'ref' }, },
23
23
  staticsensitivity: true,
24
24
  isomorphic: true,
25
25
  } );
26
26
  config.CONTEXT_API = window.webqit.oohtml.configs.CONTEXT_API;
27
+ config.context.attr.contextname = config.CONTEXT_API.attr.contextname; // Inherit this
27
28
  config.templateSelector = `template[${ window.CSS.escape( config.template.attr.moduledef ) }]`;
28
29
  config.ownerContextSelector = [ config.context.attr.contextname, config.context.attr.importscontext ].map( a => `[${ window.CSS.escape( a ) }]` ).join( ',' );
29
30
  config.slottedElementsSelector = `[${ window.CSS.escape( config.template.attr.fragmentdef ) }]`;
package/src/index.js CHANGED
@@ -3,13 +3,13 @@
3
3
  * @imports
4
4
  */
5
5
  import Observer from '@webqit/observer';
6
+ import NamespacedHTML from './namespaced-html/index.js';
7
+ import ScopedCSS from './scoped-css/index.js';
8
+ import ScopedJS from './scoped-js/index.js';
6
9
  import ContextAPI from './context-api/index.js';
7
10
  import BindingsAPI from './bindings-api/index.js';
8
11
  import HTMLImports from './html-imports/index.js';
9
- import HTMLBindings from './html-bindings/index.js';
10
- import HTMLNamespaces from './html-namespaces/index.js';
11
- import ScopedCSS from './scoped-css/index.js';
12
- import ScopedJS from './scoped-js/index.js';
12
+ import DataBinding from './data-binding/index.js';
13
13
 
14
14
  /**
15
15
  * @exports
@@ -22,12 +22,12 @@ export { Observer }
22
22
  export default function init( configs = {} ) {
23
23
  if ( !this.webqit ) { this.webqit = {}; }
24
24
  // --------------
25
- ContextAPI.call( this, ( configs.CONTEXT_API || {} ) );
26
- BindingsAPI.call( this, ( configs.BINDINGS_API || {} ) );
27
- HTMLImports.call( this, ( configs.HTML_IMPORTS || {} ) ); // Depends ContextAPI
28
- HTMLBindings.call( this, ( configs.HTML_BRACELETS || {} ) ); // Depends ContextAPI, BindingsAPI, HTMLImports
29
- HTMLNamespaces.call( this, ( configs.HTML_NAMESPACES || {} ) );
25
+ NamespacedHTML.call( this, ( configs.NAMESPACED_HTML || {} ) );
30
26
  ScopedCSS.call( this, ( configs.SCOPED_CSS || {} ) );
31
27
  ScopedJS.call( this, ( configs.SCOPED_JS || {} ) );
28
+ ContextAPI.call( this, ( configs.CONTEXT_API || {} ) );
29
+ BindingsAPI.call( this, ( configs.BINDINGS_API || {} ) ); // Depends on ContextAPI
30
+ HTMLImports.call( this, ( configs.HTML_IMPORTS || {} ) ); // Depends on ContextAPI
31
+ DataBinding.call( this, ( configs.DATA_BINDING || {} ) ); // Depends on ContextAPI, BindingsAPI, HTMLImports
32
32
  // --------------
33
33
  }
@@ -13,7 +13,7 @@ export { Observer }
13
13
  * @param Object $config
14
14
  */
15
15
  export default function init( $config = {} ) {
16
- const { config, window } = _init.call( this, 'html-namespaces', $config, {
16
+ const { config, window } = _init.call( this, 'namespaced-html', $config, {
17
17
  id: { attr: 'id' },
18
18
  namespace: { attr: 'namespace', api: 'namespace', },
19
19
  target: { attr: ':target', event: ':target', scrolling: true },
@@ -162,9 +162,9 @@ describe(`HTML Imports`, function() {
162
162
  const body = `
163
163
  <div importscontext="temp0/temp1">
164
164
  <textarea def="input"></textarea>
165
- <!--<import ref="#input"></import>-->
165
+ <!--&lt;import ref="#input" data-nodecount="1"&gt;&lt;/import&gt;-->
166
166
  </div>`;
167
- const { document } = createDocument( head, body );
167
+ const { document } = createDocument( head, body, window => window.webqit.env = 'client' );
168
168
  await delay( 20 );
169
169
 
170
170
  const routingElement = document.body.firstElementChild;
@@ -195,10 +195,12 @@ describe(`HTML Imports`, function() {
195
195
  const body = `
196
196
  <div importscontext="temp0/temp1">
197
197
  <textarea def="input"></textarea>
198
- <!--<import ref="#input"></import>-->
198
+ <!--&lt;import ref="#input" data-nodecount="1"&gt;&lt;/import&gt;-->
199
199
  </div>`;
200
- const { document } = createDocument( head, body );
200
+ const { document } = createDocument( head, body, window => window.webqit.env = 'client' );
201
+ console.log('-----------1');
201
202
  await delay( 20 );
203
+ console.log('-----------2');
202
204
 
203
205
  const routingElement = document.body.firstElementChild;
204
206
  expect( routingElement.firstElementChild.nodeName ).to.eq( 'TEXTAREA' );
package/test/index.js CHANGED
@@ -21,7 +21,7 @@ export function createDocument( head = '', body = '', callback = null, ) {
21
21
  <!DOCTYPE html>
22
22
  <html>
23
23
  <head>
24
- <meta name="stateful-compiler-url" content="../stateful-js/dist/compiler.js">
24
+ <meta name="$f-compiler-url" content="../stateful-js/dist/compiler.js">
25
25
  <script ssr src="/dist/main.js"></script>
26
26
  ${ head }
27
27
  </head>
@@ -14,12 +14,12 @@ describe(`Test: Scoped JS`, function() {
14
14
  <h1>Hello World!</h1>
15
15
  <script scoped stateful>
16
16
  testRecords.push( this );
17
- console.log('-------scoped JS here.');
17
+ console.log('-------scoped JS here.', this);
18
18
  </script>`;
19
19
 
20
20
  const window = createDocument( head, body );
21
21
  window.testRecords = [];
22
- await delay( 160 ); // Takes time to dynamically load Reflex compiler
22
+ await delay( 300 ); // Takes time to dynamically load Reflex compiler
23
23
 
24
24
  expect( window.testRecords ).to.have.length( 1 );
25
25
  expect( window.testRecords[ 0 ] ).to.eql( window.document.body );