Skip to content

Commit 0a912e1

Browse files
committed
Further work on vwindow, refactoring Artifact for Modulo.js as well
1 parent ad32fa2 commit 0a912e1

13 files changed

+896
-83
lines changed

docs/demos/mdu/utils/vwindow2.js

Lines changed: 801 additions & 0 deletions
Large diffs are not rendered by default.

docs/demos/tests/asset_manager.test.html

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
These tests are useful as unit tests testing the AssetManager core class
33
and "build" command
44
-->
5-
<Component name="AssetManager"><TestSuite>
5+
<Component name="BuildCommandAndAssetManager"><TestSuite >
66

77
<Test name="modulo.assets unit tests">
88
<script name="modulo.assets exists">
@@ -98,7 +98,7 @@
9898
<script name="assets.buildJavaScript exists">
9999
const originalRegistry = modulo.registry;
100100
const originalConfig = modulo.config;
101-
const { deepClone, cloneStub } = modulo.registry.utils;
101+
const { deepClone } = modulo.registry.utils;
102102

103103
function _prepIsolatedModulo(callback = null) {
104104
// Now, let's make a fresh modulo, and see if we can "load" the
@@ -144,9 +144,9 @@
144144
mod2._customElements = customElements;
145145
if (callback) {
146146
callback(mod2, fakeWindow);
147-
if (fakeWindow.moduloBuild) {
148-
mod2.start(fakeWindow.moduloBuild);
149-
}
147+
/*if (fakeWindow.moduloBuild) {
148+
//mod2.start(fakeWindow.moduloBuild);
149+
}*/
150150
}
151151
return mod2;
152152
}
@@ -298,11 +298,14 @@
298298

299299
<script name="commands.build produces files with expected names and sizes">
300300
const files = window._buildCommandAndRun(false, null);
301-
const expectedFns = JSON.stringify([
301+
let expectedFns = JSON.stringify([
302302
'modulo-build-xxxxxxxx.css',
303303
'modulo-build-xxxxxxxx.js',
304304
'index.html',
305305
]);
306+
if (window.location.pathname.includes('virtualdom_test_2.html')) {
307+
expectedFns = expectedFns.replace('index.html', 'virtualdom_test_2.html');
308+
}
306309
const actualFns = JSON.stringify(files.map(({ filename }) => filename));
307310
const [ cssSize, jsSize, htmlSize ] = files.map(({ text }) => (text || '').trim().length).concat([-1, -1, -1]); // have -1 as placeholder
308311
assert: expectedFns === actualFns && jsSize > 2500 && cssSize === 0 && htmlSize > 500

docs/demos/tests/browser_build.test.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Component name="BrowserBuildTester"><TestSuite solo>
1+
<Component name="BrowserBuildTester"><TestSuite>
22

33
<Test name="Test AssetManager functionality">
44
<script name="Ensure instantiates with expected properties">

docs/demos/tests/cparts/component.test.html

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,7 @@
1616
<script name="Ensure component exists and innerHTML starts as null">
1717
const { innerHTML } = component
1818
component.innerHTML = '<div id="test"><p>Abc</p></div>'
19-
// Note: Need to change this if we ever change lc methods
20-
if (element.lifecycle) {
21-
element.lifecycle([ 'render', 'reconcile', 'update' ])
22-
} else {
23-
element.cparts.component.lifecycle([ 'render', 'reconcile', 'update' ])
24-
}
19+
element.cparts.component._lifecycle([ 'render', 'reconcile', 'update' ])
2520
assert: innerHTML === null
2621
</script>
2722

docs/demos/tests/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
Composition tests are disabled because:
3030
1. Require component.slot to work 100%
3131
2. Require <PassThrough to be rewritten as <x-PassThrough
32+
<Library -src="./browser_build.test.html"></Library>
3233
<Library -src="/demos/tests/composition.test.html"></Library>
3334
<Library -src="/demos/tests/cparts/component_mode.test.html"></Library>
3435
<Library -src="/demos/tests/reconciler1.test.html"></Library>

docs/demos/wip/virtualdom_test_2.html

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<!DOCTYPE html>
2+
<script src="/js/Modulo.js"></script>
3+
<script src="/demos/mdu/cparts/TestSuite.js"></script>
4+
<script src="/demos/mdu/utils/vwindow2.js"></script>
5+
6+
<script>
7+
8+
const vw = new modulo.registry.engines.VirtualWindow(modulo);
9+
vw.navigate('http://localhost:3334/demos/wip/min_start_1.html').then(() => {
10+
console.log(vw.window.document.innerHTML);
11+
/*
12+
console.log(vw.window.modulo);
13+
setTimeout(() => {
14+
console.log(vw.window.modulo);
15+
console.log(vw.window.document.innerHTML);
16+
}, 1000);
17+
*/
18+
});
19+
20+
</script>

docs/js/Modulo.js

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ modulo.register('core', class DOMLoader {
309309

310310
modulo.register('processor', function src (modulo, def, value) {
311311
const { getParentDefPath } = modulo.registry.utils;
312-
def.Source = (new URL(value, getParentDefPath(modulo, def))).href;
312+
def.Source = (new window.URL(value, getParentDefPath(modulo, def))).href;
313313
modulo.fetchQueue.fetch(def.Source).then(text => {
314314
def.Content = (text || '') + (def.Content || '');
315315
});
@@ -364,20 +364,6 @@ modulo.register('util', function initComponentClass (modulo, def, cls) {
364364
}
365365
}
366366

367-
/*
368-
// TODO INP: Refactor away factoryCallback, or turn into processor
369-
modulo.register('processor', function renderObj (modulo, def, value) {
370-
const parentDef = modulo.definitions[def.Parent];
371-
const isLower = key => key[0].toLowerCase() === key[0];
372-
const data = modulo.registry.utils.keyFilter(def, isLower);
373-
parendDef.initRenderObj[value || def.Name] = data;
374-
});
375-
const defs = def.ChildrenNames.map(defName => modulo.definitions[defName]);
376-
def.initRenderObj = { elementClass: cls };
377-
modulo.repeatProcessors(defs, 'Factory');
378-
const initRenderObj = def.initRenderObj;
379-
*/
380-
381367
cls.prototype.init = function init () {
382368
this.modulo = modulo;
383369
this.isMounted = false;
@@ -1310,17 +1296,17 @@ modulo.register('cpart', class Script {
13101296
const isDirRegEx = /(Unmount|Mount)$/;
13111297
def.Directives = getAutoExportNames(value).filter(s => s.match(isDirRegEx));
13121298
const { ChildrenNames } = modulo.definitions[def.Parent] || { };
1313-
const sibNames = (ChildrenNames || []).map(n => modulo.definitions[n].Name);
1314-
sibNames.push('component', 'element', 'cparts'); // Add in extras
1315-
const varNames = sibNames.filter(name => value.includes(name));
1299+
const sibs = (ChildrenNames || []).map(n => modulo.definitions[n].Name);
1300+
sibs.push('component', 'element', 'cparts'); // Add in extras
1301+
const varNames = sibs.filter(name => value.includes(name)); // Used only
13161302
// Build def.Code to wrap the user-provided code and export local vars
13171303
def.Code = `var script = { exports: {} }; `;
13181304
def.Code += varNames.length ? `var ${ varNames.join(', ') };` : '';
13191305
def.Code += '\n' + value + '\nreturn {';
13201306
for (const s of getAutoExportNames(value)) {
13211307
def.Code += `"${s}": typeof ${s} !== "undefined" ? ${s} : undefined, `;
13221308
}
1323-
def.Code += `setLocalVariables: function(o) {`
1309+
def.Code += `setLocalVariables: function (o) {`
13241310
def.Code += varNames.map(name => `${ name }=o.${ name }`).join('; ');
13251311
def.Code += `}, exports: script.exports }\n`
13261312
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "mdu.js",
33
"author": "michaelb",
4-
"version": "0.0.48",
4+
"version": "0.0.49",
55
"description": "Lightweight, easy-to-learn Web Component JavaScript framework",
66
"homepage": "https://modulojs.org/",
77
"main": "./src/Modulo.js",

src/Modulo.js

Lines changed: 49 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,6 @@ window.Modulo = class Modulo {
1212
this.stores = {}; // Global data store (by default, only used by State)
1313
}
1414

15-
start(elem, callback = null) { // XXX DEAD CODE
16-
this.loadFromDOM(elem, null, true);
17-
this.preprocessAndDefine(callback);
18-
}
19-
2015
register(type, cls, defaults = undefined) {
2116
type = (`${type}s` in this.registry) ? `${type}s` : type; // pluralize
2217
if (type in this.registry.registryCallbacks) {
@@ -45,6 +40,30 @@ window.Modulo = class Modulo {
4540
return inst;
4641
}
4742

43+
instanceParts(def, extra, parts = {}) {
44+
// Loop through all children, instancing each class with configuration
45+
const allNames = [ def.DefinitionName ].concat(def.ChildrenNames);
46+
for (const def of allNames.map(name => this.definitions[name])) {
47+
parts[def.RenderObj || def.Name] = this.instance(def, extra);
48+
}
49+
return parts;
50+
}
51+
52+
lifecycle(parts, renderObj, lifecycleNames) {
53+
for (const lifecycleName of lifecycleNames) {
54+
const methodName = lifecycleName + 'Callback';
55+
for (const [ name, obj ] of Object.entries(parts)) {
56+
if (!(methodName in obj)) {
57+
continue; // Skip if obj has not registered callback
58+
}
59+
const result = obj[methodName].call(obj, renderObj);
60+
if (result) {
61+
renderObj[obj.conf.RenderObj || obj.conf.Name] = result;
62+
}
63+
}
64+
}
65+
}
66+
4867
preprocessAndDefine(cb) {
4968
this.fetchQueue.wait(() => {
5069
this.repeatProcessors(null, 'DefBuilders', () => {
@@ -370,20 +389,15 @@ modulo.register('util', function initComponentClass (modulo, def, cls) {
370389
this.isModulo = true;
371390
this.originalHTML = null;
372391
this.originalChildren = [];
373-
this.cparts = {};
374-
// Loop through all children, instancing each class with configuration
375-
const allNames = [ def.DefinitionName ].concat(def.ChildrenNames);
376-
for (const def of allNames.map(name => modulo.definitions[name])) {
377-
this.cparts[def.RenderObj || def.Name] = modulo.instance(def, { element: this });
378-
}
392+
this.cparts = modulo.instanceParts(def, { element: this });
379393
};
380394

381395
// Mount the element, optionally "merging" in the modulo-original-html attr
382396
cls.prototype.parsedCallback = function parsedCallback() {
383397
const htmlOriginal = this.getAttribute('modulo-original-html');
384398
const original = ((!htmlOriginal || htmlOriginal === '') ? this :
385399
modulo.registry.utils.makeDiv(htmlOriginal));
386-
this.cparts.component.lifecycle([ 'initialized' ]);
400+
this.cparts.component._lifecycle([ 'initialized' ]);
387401
this.rerender(original); // render and re-mount it's own childNodes
388402
if (this.hasAttribute('modulo-original-html')) {
389403
const { reconciler } = this.cparts.component;
@@ -419,10 +433,7 @@ modulo.register('processor', function mainRequire (modulo, conf, value) {
419433
});
420434

421435
modulo.register('cpart', class Artifact {
422-
// TODO: Refactor Component logic to be shared with Artifact (maybe using
423-
// preprocessors?). Refactor this to use something more generalized for
424-
// children, so it shares code flow with component. Generally, this is a mess!
425-
static build(modulo, def) {
436+
buildCommandCallback({ modulo, def }) {
426437
const finish = () => {
427438
const { saveFileAs, hash } = modulo.registry.utils;
428439
const children = (def.ChildrenNames || []).map(n => modulo.definitions[n]);
@@ -491,6 +502,7 @@ modulo.register('cpart', class Artifact {
491502
}, {
492503
Contains: 'cparts',
493504
DefinedAs: 'name',
505+
RenderObj: 'artifact',
494506
DefLoaders: [ 'DefTarget', 'DefinedAs', 'Src', 'Content' ],
495507
});
496508

@@ -541,6 +553,7 @@ modulo.register('coreDef', class Component {
541553
return ${ className };
542554
`;
543555
}
556+
544557
rerender(original = null) {
545558
if (original) {
546559
if (this.element.originalHTML === null) {
@@ -549,28 +562,17 @@ modulo.register('coreDef', class Component {
549562
this.element.originalChildren = Array.from(
550563
original.hasChildNodes() ? original.childNodes : []);
551564
}
552-
this.lifecycle([ 'prepare', 'render', 'reconcile', 'update' ]);
565+
this._lifecycle([ 'prepare', 'render', 'reconcile', 'update' ]);
553566
}
554567

555568
getCurrentRenderObj() {
556569
return (this.element.eventRenderObj || this.element.renderObj || this.element.initRenderObj);
557570
}
558571

559-
lifecycle(lifecycleNames, rObj={}) {
572+
_lifecycle(lifecycleNames, rObj={}) {
560573
const renderObj = Object.assign({}, rObj, this.getCurrentRenderObj());
561574
this.element.renderObj = renderObj;
562-
for (const lifecycleName of lifecycleNames) {
563-
const methodName = lifecycleName + 'Callback';
564-
for (const [ name, obj ] of Object.entries(this.element.cparts)) {
565-
if (!(methodName in obj)) {
566-
continue; // Skip if obj has not registered callback
567-
}
568-
const result = obj[methodName].call(obj, renderObj);
569-
if (result) {
570-
renderObj[obj.conf.RenderObj || obj.conf.Name] = result;
571-
}
572-
}
573-
}
575+
this.modulo.lifecycle(this.element.cparts, renderObj, lifecycleNames);
574576
//this.element.renderObj = null; // ?rendering is over, set to null
575577
}
576578

@@ -645,10 +647,10 @@ modulo.register('coreDef', class Component {
645647
}
646648

647649
handleEvent(func, payload, ev) {
648-
this.lifecycle([ 'event' ]);
650+
this._lifecycle([ 'event' ]);
649651
const { value } = (ev.target || {}); // Get value if is <INPUT>, etc
650652
func.call(null, payload === undefined ? value : payload, ev);
651-
this.lifecycle([ 'eventCleanup' ]); // todo: should this go below rerender()?
653+
this._lifecycle([ 'eventCleanup' ]); // todo: should this go below rerender()?
652654
if (this.attrs.rerender !== 'manual') {
653655
this.element.rerender(); // always rerender after events
654656
}
@@ -1736,16 +1738,12 @@ modulo.register('engine', class Reconciler {
17361738
}
17371739

17381740
applyPatch(node, method, arg, arg2) { // take that, rule of 3!
1739-
//if (!node || !node[method]) { console.error('NO NODE:', node, method, arg, arg2) } // XXX
17401741
if (method === 'node-value') {
17411742
node.nodeValue = arg;
17421743
} else if (method === 'insertBefore') {
17431744
node.insertBefore(arg, arg2); // Needs 2 arguments
1744-
} else if (method === 'attr-append') { // Append string to existing
1745-
node.setAttribute(arg, (node.getAttribute(arg) || '') + arg2); // TODO: DEAD CODE
17461745
} else if (method.startsWith('directive-')) {
1747-
// TODO: Possibly, remove 'directive-' prefix, unnecessary
1748-
method = method.substr('directive-'.length);
1746+
method = method.substr('directive-'.length); // TODO: RM prefix (or generalizze)
17491747
node[method].call(node, arg); // invoke directive method
17501748
} else {
17511749
node[method].call(node, arg); // invoke method
@@ -1858,9 +1856,22 @@ modulo.register('command', function build (modulo, opts = {}) {
18581856
const filter = opts.filter || (({ Type }) => Type === 'Artifact');
18591857
modulo.config.IS_BUILD = true;
18601858
opts.callback = opts.callback || (() => {});
1859+
/*
1860+
// TODO: Use this to refactor modulo-original-html into Component class
1861+
for (const elem of document.querySelectorAll('*')) {
1862+
// Escape hatch for CParts / Scripts to hook in on a per-component basis
1863+
if (elem.isModulo && elem.cparts && elem.cparts.component) {
1864+
elem.cparts.component._lifecycle([ 'prepareBuild', 'build' ]);
1865+
}
1866+
}
1867+
*/
18611868
const artifacts = Object.values(modulo.definitions).filter(filter);
18621869
const buildNext = () => {
1863-
modulo.registry.cparts.Artifact.build(modulo, artifacts.shift());
1870+
const artifact = artifacts.shift();
1871+
const artifactParts = modulo.instanceParts(artifact, {});
1872+
const buildObj = { modulo, def: artifact };
1873+
modulo.lifecycle(artifactParts, buildObj, [ 'buildCommand' ]);
1874+
//modulo.repeatProcessors(artifacts, 'ArtifactBuilders');
18641875
modulo.fetchQueue.enqueueAll(artifacts.length > 0 ? buildNext : opts.callback);
18651876
};
18661877
modulo.assert(artifacts.length, 'Build filter produced no artifacts');

tests/asset_manager.test.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
These tests are useful as unit tests testing the AssetManager core class
33
and "build" command
44
-->
5-
<Component name="AssetManager"><TestSuite solo>
5+
<Component name="BuildCommandAndAssetManager"><TestSuite >
66

77
<Test name="modulo.assets unit tests">
88
<script name="modulo.assets exists">
@@ -98,7 +98,7 @@
9898
<script name="assets.buildJavaScript exists">
9999
const originalRegistry = modulo.registry;
100100
const originalConfig = modulo.config;
101-
const { deepClone, cloneStub } = modulo.registry.utils;
101+
const { deepClone } = modulo.registry.utils;
102102

103103
function _prepIsolatedModulo(callback = null) {
104104
// Now, let's make a fresh modulo, and see if we can "load" the
@@ -144,9 +144,9 @@
144144
mod2._customElements = customElements;
145145
if (callback) {
146146
callback(mod2, fakeWindow);
147-
if (fakeWindow.moduloBuild) {
148-
mod2.start(fakeWindow.moduloBuild);
149-
}
147+
/*if (fakeWindow.moduloBuild) {
148+
//mod2.start(fakeWindow.moduloBuild);
149+
}*/
150150
}
151151
return mod2;
152152
}

tests/browser_build.test.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Component name="BrowserBuildTester"><TestSuite solo>
1+
<Component name="BrowserBuildTester"><TestSuite>
22

33
<Test name="Test AssetManager functionality">
44
<script name="Ensure instantiates with expected properties">

tests/cparts/component.test.html

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,7 @@
1616
<script name="Ensure component exists and innerHTML starts as null">
1717
const { innerHTML } = component
1818
component.innerHTML = '<div id="test"><p>Abc</p></div>'
19-
// Note: Need to change this if we ever change lc methods
20-
if (element.lifecycle) {
21-
element.lifecycle([ 'render', 'reconcile', 'update' ])
22-
} else {
23-
element.cparts.component.lifecycle([ 'render', 'reconcile', 'update' ])
24-
}
19+
element.cparts.component._lifecycle([ 'render', 'reconcile', 'update' ])
2520
assert: innerHTML === null
2621
</script>
2722

tests/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
Composition tests are disabled because:
3030
1. Require component.slot to work 100%
3131
2. Require <PassThrough to be rewritten as <x-PassThrough
32+
<Library -src="./browser_build.test.html"></Library>
3233
<Library -src="/demos/tests/composition.test.html"></Library>
3334
<Library -src="/demos/tests/cparts/component_mode.test.html"></Library>
3435
<Library -src="/demos/tests/reconciler1.test.html"></Library>

0 commit comments

Comments
 (0)