diff --git a/packages/templating/package.js b/packages/templating/package.js index a43805b71a..d26089a3da 100644 --- a/packages/templating/package.js +++ b/packages/templating/package.js @@ -12,7 +12,7 @@ Package._transitional_registerBuildPlugin({ name: "compileTemplates", use: ['spacebars'], sources: [ - 'plugin/html2_scanner.js', + 'plugin/html_scanner.js', 'plugin/compile-templates.js' ] }); @@ -45,7 +45,7 @@ Package.on_test(function (api) { 'templating_tests.html' ], 'client'); api.add_files([ - 'plugin/html2_scanner.js', + 'plugin/html_scanner.js', 'scanner_tests.js' ], 'server'); }); diff --git a/packages/templating/plugin/html2_scanner.js b/packages/templating/plugin/html_scanner.js similarity index 100% rename from packages/templating/plugin/html2_scanner.js rename to packages/templating/plugin/html_scanner.js diff --git a/packages/ui/attrs2.js b/packages/ui/attrs.js similarity index 100% rename from packages/ui/attrs2.js rename to packages/ui/attrs.js diff --git a/packages/ui/dombackend2.js b/packages/ui/dombackend.js similarity index 100% rename from packages/ui/dombackend2.js rename to packages/ui/dombackend.js diff --git a/packages/ui/each2.js b/packages/ui/each.js similarity index 100% rename from packages/ui/each2.js rename to packages/ui/each.js diff --git a/packages/ui/package.js b/packages/ui/package.js index 661a121365..990c8a0faa 100644 --- a/packages/ui/package.js +++ b/packages/ui/package.js @@ -18,13 +18,13 @@ Package.on_use(function (api) { api.add_files(['exceptions.js', 'base.js']); - api.add_files(['dombackend2.js', + api.add_files(['dombackend.js', 'domrange.js'], 'client'); - api.add_files(['attrs2.js', - 'render2.js', + api.add_files(['attrs.js', + 'render.js', 'components.js', - 'each2.js', + 'each.js', 'fields.js' ]); @@ -41,9 +41,8 @@ Package.on_test(function (api) { api.add_files([ 'base_tests.js', - 'render_tests.js', 'domrange_tests.js', - 'render2_tests.js', + 'render_tests.js', 'dombackend_tests.js' ], 'client'); }); diff --git a/packages/ui/render2.js b/packages/ui/render.js similarity index 100% rename from packages/ui/render2.js rename to packages/ui/render.js diff --git a/packages/ui/render2_tests.js b/packages/ui/render2_tests.js deleted file mode 100644 index 38c19896da..0000000000 --- a/packages/ui/render2_tests.js +++ /dev/null @@ -1,472 +0,0 @@ -var materialize = UI.materialize; -var toHTML = UI.toHTML; -var toCode = UI.toCode; - -var P = HTML.Tag.P; -var CharRef = HTML.CharRef; -var DIV = HTML.Tag.DIV; -var Comment = HTML.Comment; -var BR = HTML.Tag.BR; -var A = HTML.Tag.A; -var UL = HTML.Tag.UL; -var LI = HTML.Tag.LI; -var SPAN = HTML.Tag.SPAN; -var HR = HTML.Tag.HR; - -Tinytest.add("ui - render2 - basic", function (test) { - var run = function (input, expectedInnerHTML, expectedHTML, expectedCode) { - var div = document.createElement("DIV"); - materialize(input, div); - test.equal(canonicalizeHtml(div.innerHTML), expectedInnerHTML); - test.equal(toHTML(input), expectedHTML); - test.equal(toCode(input), expectedCode); - }; - - run(P('Hello'), - '
Hello
', - 'Hello
', - 'HTML.Tag.P("Hello")'); - - run(null, '', '', 'null'); - run([], '', '', '[]'); - run([null, null], '', '', '[null, null]'); - - // Test crazy character references - - // `𝕫` is "Mathematical double-struck small z" a.k.a. "open-face z" - run(P(CharRef({html: '𝕫', str: '\ud835\udd6b'})), - '\ud835\udd6b
', - '𝕫
', - 'HTML.Tag.P(HTML.CharRef({html: "𝕫", str: "\\ud835\\udd6b"}))'); - - run(P({id: CharRef({html: '𝕫', str: '\ud835\udd6b'})}, 'Hello'), - 'Hello
', - 'Hello
', - 'HTML.Tag.P({id: HTML.CharRef({html: "𝕫", str: "\\ud835\\udd6b"})}, "Hello")'); - - run(P({id: [CharRef({html: '𝕫', str: '\ud835\udd6b'}), '!']}, 'Hello'), - 'Hello
', - 'Hello
', - 'HTML.Tag.P({id: [HTML.CharRef({html: "𝕫", str: "\\ud835\\udd6b"}), "!"]}, "Hello")'); - - // Test comments - - run(DIV(Comment('Test')), - '', // our innerHTML-canonicalization function kills comment contents - '', - 'HTML.Tag.DIV(HTML.Comment("Test"))'); - - // Test arrays - - run([P('Hello'), P('World')], - 'Hello
World
', - 'Hello
World
', - '[HTML.Tag.P("Hello"), HTML.Tag.P("World")]'); - - // Test slightly more complicated structure - - run(DIV({'class': 'foo'}, UL(LI(P(A({href: '#one'}, 'One'))), - LI(P('Two', BR(), 'Three')))), - 'Two
Three
Two
Three
Hello
'); - - var div = document.createElement("DIV"); - materialize(test1, div); - test.equal(canonicalizeHtml(div.innerHTML), "Hello
"); - - R.set('World'); - Deps.flush(); - test.equal(canonicalizeHtml(div.innerHTML), "World
"); - })(); - - // Reactively change an array of text nodes - (function () { - var R = ReactiveVar(['Hello', ' World']); - var test1 = P(function () { return R.get(); }); - - test.equal(toHTML(test1), 'Hello World
'); - - var div = document.createElement("DIV"); - materialize(test1, div); - test.equal(canonicalizeHtml(div.innerHTML), "Hello World
"); - - R.set(['Goodbye', ' World']); - Deps.flush(); - test.equal(canonicalizeHtml(div.innerHTML), "Goodbye World
"); - })(); - -}); - -Tinytest.add("ui - render2 - closure GC", function (test) { - // test that removing parent element removes listeners and stops autoruns. - (function () { - var R = ReactiveVar('Hello'); - var test1 = P(function () { return R.get(); }); - - var div = document.createElement("DIV"); - materialize(test1, div); - test.equal(canonicalizeHtml(div.innerHTML), "Hello
"); - - R.set('World'); - Deps.flush(); - test.equal(canonicalizeHtml(div.innerHTML), "World
"); - - test.equal(R.numListeners(), 1); - - $(div).remove(); - - test.equal(R.numListeners(), 0); - - R.set('Steve'); - Deps.flush(); - // should not have changed: - test.equal(canonicalizeHtml(div.innerHTML), "World
"); - })(); - -}); - -Tinytest.add("ui - render2 - reactive attributes", function (test) { - (function () { - var R = ReactiveVar({'class': ['david gre', CharRef({html: 'ë', str: '\u00eb'}), 'nspan'], - id: 'foo'}); - - var spanCode = SPAN({$attrs: function () { return R.get(); }}); - test.equal(typeof spanCode.attrs, 'function'); - - test.equal(toHTML(spanCode), ''); - - test.equal(R.numListeners(), 0); - - var div = document.createElement("DIV"); - materialize(spanCode, div); - test.equal(canonicalizeHtml(div.innerHTML), ''); - - test.equal(R.numListeners(), 1); - - var span = div.firstChild; - test.equal(span.nodeName, 'SPAN'); - span.className += ' blah'; - - R.set({'class': 'david smith', id: 'bar'}); - Deps.flush(); - test.equal(canonicalizeHtml(div.innerHTML), ''); - test.equal(R.numListeners(), 1); - - R.set({}); - Deps.flush(); - test.equal(canonicalizeHtml(div.innerHTML), ''); - test.equal(R.numListeners(), 1); - - $(div).remove(); - - test.equal(R.numListeners(), 0); - })(); - - // Test `null`, `undefined`, and `[]` attributes - (function () { - var R = ReactiveVar({id: 'foo', - aaa: null, - bbb: undefined, - ccc: [], - ddd: [null], - eee: [undefined], - fff: [[]], - ggg: ['x', ['y', ['z']]]}); - - var spanCode = SPAN({$attrs: function () { return R.get(); }}); - - test.equal(toHTML(spanCode), ''); - test.equal(toCode(SPAN(R.get())), - 'HTML.Tag.SPAN({id: "foo", ggg: ["x", ["y", ["z"]]]})'); - - var div = document.createElement("DIV"); - materialize(spanCode, div); - var span = div.firstChild; - test.equal(span.nodeName, 'SPAN'); - - test.equal(canonicalizeHtml(div.innerHTML), ''); - R.set({id: 'foo', ggg: [[], [], []]}); - Deps.flush(); - test.equal(canonicalizeHtml(div.innerHTML), ''); - - R.set({id: 'foo', ggg: null}); - Deps.flush(); - test.equal(canonicalizeHtml(div.innerHTML), ''); - - R.set({id: 'foo', ggg: ''}); - Deps.flush(); - test.equal(canonicalizeHtml(div.innerHTML), ''); - - $(span).remove(); - - test.equal(R.numListeners(), 0); - })(); -}); - -Tinytest.add("ui - render2 - components", function (test) { - (function () { - var counter = 1; - var buf = []; - - var myComponent = UI.Component.extend({ - init: function () { - // `this` is the component instance - var number = counter++; - this.number = number; - - if (this.parent) - buf.push('parent of ' + this.number + ' is ' + this.parent.number); - - this.data = function () { - return this.number; - }; - }, - created: function () { - // `this` is the template instance - buf.push('created ' + this.data); - }, - render: function () { - // `this` is the component instance - return [String(this.number), - - (this.number < 3 ? myComponent : HR())]; - }, - rendered: function () { - // `this` is the template instance - var nodeDescr = function (node) { - if (node.nodeType === 8) // comment - return ''; - if (node.nodeType === 3) // text - return node.nodeValue; - - return node.nodeName; - }; - - var start = this.firstNode; - var end = this.lastNode; - // skip marker nodes - while (start !== end && ! nodeDescr(start)) - start = start.nextSibling; - while (end !== start && ! nodeDescr(end)) - end = end.previousSibling; - - - // `this` is the template instance - buf.push('dom-' + this.data + ' is ' + nodeDescr(start) +'..' + - nodeDescr(end)); - }, - destroyed: function () { - // `this` is the template instance - buf.push('destroyed ' + this.data); - } - }); - - var div = document.createElement("DIV"); - - materialize(myComponent, div); - test.equal(buf, ['created 1', - 'parent of 2 is 1', - 'created 2', - 'parent of 3 is 2', - 'created 3', - // (proper order for these has not be thought out:) - 'dom-1 is 1..HR', - 'dom-2 is 2..HR', - 'dom-3 is 3..HR']); - - test.equal(canonicalizeHtml(div.innerHTML), '123Hello
', + 'Hello
', + 'HTML.Tag.P("Hello")'); + + run(null, '', '', 'null'); + run([], '', '', '[]'); + run([null, null], '', '', '[null, null]'); + + // Test crazy character references + + // `𝕫` is "Mathematical double-struck small z" a.k.a. "open-face z" + run(P(CharRef({html: '𝕫', str: '\ud835\udd6b'})), + '\ud835\udd6b
', + '𝕫
', + 'HTML.Tag.P(HTML.CharRef({html: "𝕫", str: "\\ud835\\udd6b"}))'); + + run(P({id: CharRef({html: '𝕫', str: '\ud835\udd6b'})}, 'Hello'), + 'Hello
', + 'Hello
', + 'HTML.Tag.P({id: HTML.CharRef({html: "𝕫", str: "\\ud835\\udd6b"})}, "Hello")'); + + run(P({id: [CharRef({html: '𝕫', str: '\ud835\udd6b'}), '!']}, 'Hello'), + 'Hello
', + 'Hello
', + 'HTML.Tag.P({id: [HTML.CharRef({html: "𝕫", str: "\\ud835\\udd6b"}), "!"]}, "Hello")'); + + // Test comments + + run(DIV(Comment('Test')), + '', // our innerHTML-canonicalization function kills comment contents + '', + 'HTML.Tag.DIV(HTML.Comment("Test"))'); + + // Test arrays + + run([P('Hello'), P('World')], + 'Hello
World
', + 'Hello
World
', + '[HTML.Tag.P("Hello"), HTML.Tag.P("World")]'); + + // Test slightly more complicated structure + + run(DIV({'class': 'foo'}, UL(LI(P(A({href: '#one'}, 'One'))), + LI(P('Two', BR(), 'Three')))), + 'Two
Three
Two
Three
Hello
'); + + var div = document.createElement("DIV"); + materialize(test1, div); + test.equal(canonicalizeHtml(div.innerHTML), "Hello
"); + + R.set('World'); + Deps.flush(); + test.equal(canonicalizeHtml(div.innerHTML), "World
"); })(); + // Reactively change an array of text nodes (function () { - var c = UI.Component.extend({ - render: function (buf) { - buf.write("Hello World
'); - (function () { - var R = ReactiveVar("blam"); - var c = UI.Component.extend({ - render: function (buf) { - buf.write( - "foo", - UI.Text.withData(function () { return R.get(); }), - "bar"); - } - }); + var div = document.createElement("DIV"); + materialize(test1, div); + test.equal(canonicalizeHtml(div.innerHTML), "Hello World
"); - c.build(); - test.equal($(c._offscreen).html(), "fooblambar"); - R.set("ki"); + R.set(['Goodbye', ' World']); Deps.flush(); - test.equal($(c._offscreen).html(), "fookibar"); - c.destroy(); - test.equal(R.numListeners(), 0); - })(); - - - - (function () { - var R = ReactiveVar("Goodbye World
"); })(); }); -Tinytest.add("ui - if/unless", function (test) { - var hello = UI.Text.withData("hello"); - var world = UI.Text.withData("world"); - var R = ReactiveVar('true'); - var renderedCounts = [0, 0, 0]; - var c = UI.Component.extend({ - rendered: function () { renderedCounts[0]++; }, - render: function (buf) { - buf.write( - UI.If.extend({ - data: function () { - return R.get().charAt(0) === 't'; - }, - content: hello, - elseContent: world, - rendered: function () { - renderedCounts[1]++; - } - }), - UI.Unless.extend({ - data: function () { - return R.get().charAt(0) === 't'; - }, - content: hello, - elseContent: world, - rendered: function () { - renderedCounts[2]++; - } - })); - } +Tinytest.add("ui - render2 - closure GC", function (test) { + // test that removing parent element removes listeners and stops autoruns. + (function () { + var R = ReactiveVar('Hello'); + var test1 = P(function () { return R.get(); }); + + var div = document.createElement("DIV"); + materialize(test1, div); + test.equal(canonicalizeHtml(div.innerHTML), "Hello
"); + + R.set('World'); + Deps.flush(); + test.equal(canonicalizeHtml(div.innerHTML), "World
"); + + test.equal(R.numListeners(), 1); + + $(div).remove(); + + test.equal(R.numListeners(), 0); + + R.set('Steve'); + Deps.flush(); + // should not have changed: + test.equal(canonicalizeHtml(div.innerHTML), "World
"); + })(); + +}); + +Tinytest.add("ui - render2 - reactive attributes", function (test) { + (function () { + var R = ReactiveVar({'class': ['david gre', CharRef({html: 'ë', str: '\u00eb'}), 'nspan'], + id: 'foo'}); + + var spanCode = SPAN({$attrs: function () { return R.get(); }}); + test.equal(typeof spanCode.attrs, 'function'); + + test.equal(toHTML(spanCode), ''); + + test.equal(R.numListeners(), 0); + + var div = document.createElement("DIV"); + materialize(spanCode, div); + test.equal(canonicalizeHtml(div.innerHTML), ''); + + test.equal(R.numListeners(), 1); + + var span = div.firstChild; + test.equal(span.nodeName, 'SPAN'); + span.className += ' blah'; + + R.set({'class': 'david smith', id: 'bar'}); + Deps.flush(); + test.equal(canonicalizeHtml(div.innerHTML), ''); + test.equal(R.numListeners(), 1); + + R.set({}); + Deps.flush(); + test.equal(canonicalizeHtml(div.innerHTML), ''); + test.equal(R.numListeners(), 1); + + $(div).remove(); + + test.equal(R.numListeners(), 0); + })(); + + // Test `null`, `undefined`, and `[]` attributes + (function () { + var R = ReactiveVar({id: 'foo', + aaa: null, + bbb: undefined, + ccc: [], + ddd: [null], + eee: [undefined], + fff: [[]], + ggg: ['x', ['y', ['z']]]}); + + var spanCode = SPAN({$attrs: function () { return R.get(); }}); + + test.equal(toHTML(spanCode), ''); + test.equal(toCode(SPAN(R.get())), + 'HTML.Tag.SPAN({id: "foo", ggg: ["x", ["y", ["z"]]]})'); + + var div = document.createElement("DIV"); + materialize(spanCode, div); + var span = div.firstChild; + test.equal(span.nodeName, 'SPAN'); + + test.equal(canonicalizeHtml(div.innerHTML), ''); + R.set({id: 'foo', ggg: [[], [], []]}); + Deps.flush(); + test.equal(canonicalizeHtml(div.innerHTML), ''); + + R.set({id: 'foo', ggg: null}); + Deps.flush(); + test.equal(canonicalizeHtml(div.innerHTML), ''); + + R.set({id: 'foo', ggg: ''}); + Deps.flush(); + test.equal(canonicalizeHtml(div.innerHTML), ''); + + $(span).remove(); + + test.equal(R.numListeners(), 0); + })(); +}); + +Tinytest.add("ui - render2 - components", function (test) { + (function () { + var counter = 1; + var buf = []; + + var myComponent = UI.Component.extend({ + init: function () { + // `this` is the component instance + var number = counter++; + this.number = number; + + if (this.parent) + buf.push('parent of ' + this.number + ' is ' + this.parent.number); + + this.data = function () { + return this.number; + }; + }, + created: function () { + // `this` is the template instance + buf.push('created ' + this.data); + }, + render: function () { + // `this` is the component instance + return [String(this.number), + + (this.number < 3 ? myComponent : HR())]; + }, + rendered: function () { + // `this` is the template instance + var nodeDescr = function (node) { + if (node.nodeType === 8) // comment + return ''; + if (node.nodeType === 3) // text + return node.nodeValue; + + return node.nodeName; + }; + + var start = this.firstNode; + var end = this.lastNode; + // skip marker nodes + while (start !== end && ! nodeDescr(start)) + start = start.nextSibling; + while (end !== start && ! nodeDescr(end)) + end = end.previousSibling; + + + // `this` is the template instance + buf.push('dom-' + this.data + ' is ' + nodeDescr(start) +'..' + + nodeDescr(end)); + }, + destroyed: function () { + // `this` is the template instance + buf.push('destroyed ' + this.data); + } + }); + + var div = document.createElement("DIV"); + + materialize(myComponent, div); + test.equal(buf, ['created 1', + 'parent of 2 is 1', + 'created 2', + 'parent of 3 is 2', + 'created 3', + // (proper order for these has not be thought out:) + 'dom-1 is 1..HR', + 'dom-2 is 2..HR', + 'dom-3 is 3..HR']); + + test.equal(canonicalizeHtml(div.innerHTML), '123