diff --git a/packages/templating/plugin/html_scanner.js b/packages/templating/plugin/html_scanner.js index e9044e9712..b9013c079c 100644 --- a/packages/templating/plugin/html_scanner.js +++ b/packages/templating/plugin/html_scanner.js @@ -172,7 +172,7 @@ html_scanner = { }); // We may be one of many `
` tags. - results.js += "\nUI.body.contentParts.push(UI.Component.extend({render: " + renderFuncCode + "}));\nMeteor.startup(function () { if (! UI.body.INSTANTIATED) { UI.body.INSTANTIATED = true; UI.materialize(UI.body, document.body); } });\n"; + results.js += "\nUI.body.contentParts.push(UI.Component.extend({render: " + renderFuncCode + "}));\nMeteor.startup(function () { if (! UI.body.INSTANTIATED) { UI.body.INSTANTIATED = true; UI.DomRange.insert(UI.render(UI.body).dom, document.body); } });\n"; } } catch (e) { if (e.scanner) { diff --git a/packages/ui/base.js b/packages/ui/base.js index 7e9bd34eac..dcd43838f6 100644 --- a/packages/ui/base.js +++ b/packages/ui/base.js @@ -355,18 +355,5 @@ UI.Component.notifyParented = function () { } }; -// XXX we don't really want this to be a user-visible callback, -// it's just a particular signal we need from DomRange. -UI.Component.removed = function () { - var self = this; - self.isDestroyed = true; - if (self.destroyed) { - Deps.nonreactive(function () { - updateTemplateInstance(self); - self.destroyed.call(self.templateInstance); - }); - } -}; - // past compat UI.Component.preserve = function () {}; diff --git a/packages/ui/domrange.js b/packages/ui/domrange.js index acb8b45b84..d7be406a7a 100644 --- a/packages/ui/domrange.js +++ b/packages/ui/domrange.js @@ -114,15 +114,15 @@ var rangeParented = function (range) { }); } - if (range.component.notifyParented) + if (range.component && range.component.notifyParented) range.component.notifyParented(); // recurse on member ranges var members = range.members; for (var k in members) { var mem = members[k]; - if ('dom' in mem) - rangeParented(mem.dom); + if (mem instanceof DomRange) + rangeParented(mem); } } }; @@ -137,8 +137,8 @@ var rangeRemoved = function (range) { // XXX clean up events in $_uievents // notify component of removal - if (range.component.removed) - range.component.removed(); + if (range.removed) + range.removed(); membersRemoved(range); } @@ -148,7 +148,7 @@ var nodeRemoved = function (node, viaBackend) { if (node.nodeType === 1) { // ELEMENT var comps = DomRange.getComponents(node); for (var i = 0, N = comps.length; i < N; i++) - rangeRemoved(comps[i].dom); + rangeRemoved(comps[i]); if (! viaBackend) DomBackend.removeElement(node); @@ -159,8 +159,8 @@ var membersRemoved = function (range) { var members = range.members; for (var k in members) { var mem = members[k]; - if ('dom' in mem) - rangeRemoved(mem.dom); + if (mem instanceof DomRange) + rangeRemoved(mem); else nodeRemoved(mem); } @@ -168,34 +168,16 @@ var membersRemoved = function (range) { var nextGuid = 1; -var DomRange = function (component) { - // This code supports IE 8 if `createTextNode` is changed - // to `createComment`. What we really should do is: - // - use comments in IE 8 - // - use TextNodes in all other browsers - // - keep a list of all DomRanges to avoid IE 9+ GC of - // TextNodes; this will probably help DomRange removal - // detection too. +var DomRange = function () { var start = createMarkerNode(); var end = createMarkerNode(); var fragment = DomBackend.newFragment([start, end]); fragment.$_uiIsOffscreen = true; - if (component) { - this.component = component; - component.dom = this; - // must NOT set `this.dom` to anything (even `null`) - // in this case. - } else { - // self-host - this.component = this; - this.dom = this; - } - this.start = start; this.end = end; - start.$ui = this.component; - end.$ui = this.component; + start.$ui = this; + end.$ui = this; this.members = {}; this.nextMemberId = 1; @@ -296,9 +278,9 @@ _extend(DomRange.prototype, { var members = this.members; if (members.hasOwnProperty(id)) { var oldMember = members[id]; - if ('dom' in oldMember) { + if (oldMember instanceof DomRange) { // range, does it still exist? - var oldRange = oldMember.dom; + var oldRange = oldMember; if (oldRange.start.parentNode !== parentNode) { delete members[id]; oldRange.owner = null; @@ -318,12 +300,10 @@ _extend(DomRange.prototype, { } } - if ('dom' in newMember) { - if (! newMember.dom) - throw new Error("Component not built"); + if (newMember instanceof DomRange) { // Range - var range = newMember.dom; - range.owner = this.component; + var range = newMember; + range.owner = this; var nodes = range.getNodes(); if (tbodyFixNeeded(nodes, parentNode)) @@ -345,7 +325,7 @@ _extend(DomRange.prototype, { // can't attach `$ui` to a TextNode in IE 8, so // don't bother on any browser. if (node.nodeType !== 3) - node.$ui = this.component; + node.$ui = this; if (tbodyFixNeeded(node, parentNode)) // may cause a refresh(); important that the @@ -384,14 +364,14 @@ _extend(DomRange.prototype, { if (! parentNode) return; - if ('dom' in member) { + if (member instanceof DomRange) { // Range - var range = member.dom; + var range = member; range.owner = null; // Don't mind if range (specifically its start // marker) has been removed already. if (range.start.parentNode === parentNode) - member.dom.remove(); + member.remove(); } else { // Node var node = member; @@ -418,9 +398,9 @@ _extend(DomRange.prototype, { if (! parentNode) return; - if ('dom' in member) { + if (member instanceof DomRange) { // Range - var range = member.dom; + var range = member; // Don't mind if range (specifically its start marker) // has been removed already. if (range.start.parentNode === parentNode) { @@ -458,9 +438,9 @@ _extend(DomRange.prototype, { for (var k in members) { // mem is a component (hosting a Range) or a Node var mem = members[k]; - if ('dom' in mem) { + if (mem instanceof DomRange) { // Range - var range = mem.dom; + var range = mem; if (range.start.parentNode === parentNode) { rangeFunc && rangeFunc(range); // still there } else { @@ -517,6 +497,7 @@ _extend(DomRange.prototype, { // see `getInsertionPoint`. Adding multiple members // at once using `add(array)` is faster. refresh: function () { + var parentNode = this.parentNode(); if (! parentNode) return; @@ -579,14 +560,13 @@ _extend(DomRange.prototype, { var nodeOwner; if (node.$ui && - (nodeOwner = node.$ui.dom) && + (nodeOwner = node.$ui) && ((nodeOwner === this && node !== this.start && node !== this.end && isSignificantNode(node)) || (nodeOwner !== this && - nodeOwner.owner && - nodeOwner.owner.dom === this && + nodeOwner.owner === this && nodeOwner.start === node))) { // found a member range or node // (excluding "insignificant" empty text nodes, @@ -602,10 +582,10 @@ _extend(DomRange.prototype, { // can't attach `$ui` to a TextNode in IE 8, so // don't bother on any browser. if (n.nodeType !== 3) - n.$ui = this.component; + n.$ui = this; } } - if (node.$ui.dom === this) { + if (node.$ui === this) { // Node firstNode = (firstNode || node); lastNode = node; @@ -614,7 +594,7 @@ _extend(DomRange.prototype, { // skip it and include its nodes in // firstNode/lastNode. firstNode = (firstNode || node); - node = node.$ui.dom.end; + node = node.$ui.end; lastNode = node; } } @@ -626,12 +606,12 @@ _extend(DomRange.prototype, { // nodes as well. for (var n; (n = firstNode.previousSibling) && - (n.$ui && n.$ui.dom === this || + (n.$ui && n.$ui === this || _contains(textNodes, n));) firstNode = n; for (var n; (n = lastNode.nextSibling) && - (n.$ui && n.$ui.dom === this || + (n.$ui && n.$ui === this || _contains(textNodes, n));) lastNode = n; // adjust our start/end pointers @@ -665,9 +645,9 @@ _extend(DomRange.prototype, { beforeId = ' ' + beforeId; var mem = members[beforeId]; - if ('dom' in mem) { + if (mem instanceof DomRange) { // Range - var range = mem.dom; + var range = mem; if (range.start.parentNode === parentNode) { // still there range.refresh(); @@ -723,25 +703,22 @@ DomRange.refresh = function (element) { var comps = DomRange.getComponents(element); for (var i = 0, N = comps.length; i < N; i++) - comps[i].dom.refresh(); + comps[i].refresh(); }; DomRange.getComponents = function (element) { var topLevelComps = []; for (var n = element.firstChild; n; n = n.nextSibling) { - if (n.$ui && n === n.$ui.dom.start && - ! n.$ui.dom.owner) + if (n.$ui && n === n.$ui.start && + ! n.$ui.owner) topLevelComps.push(n.$ui); } return topLevelComps; }; // `parentNode` must be an ELEMENT, not a fragment -DomRange.insert = function (component, parentNode, nextNode) { - var range = component.dom; - if (! range) - throw new Error("Expected a component with a DomRange"); +DomRange.insert = function (range, parentNode, nextNode) { var nodes = range.getNodes(); if (tbodyFixNeeded(nodes, parentNode)) parentNode = makeOrFindTbody(parentNode, nextNode); @@ -801,7 +778,7 @@ var makeOrFindTbody = function (parent, next) { var moveWithOwnersIntoTbody = function (range) { while (range.owner) - range = range.owner.dom; + range = range.owner; var nodes = range.getNodes(); // causes refresh var tbody = makeOrFindTbody(range.parentNode(), @@ -826,9 +803,9 @@ DomRange.prototype.contains = function (compOrNode) { return false; var range; - if ('dom' in compOrNode) { + if (compOrNode instanceof DomRange) { // Component - range = compOrNode.dom; + range = compOrNode; var pn = range.parentNode(); if (! pn) return false; @@ -849,14 +826,14 @@ DomRange.prototype.contains = function (compOrNode) { while (node.parentNode !== parentNode) node = node.parentNode; - range = node.$ui && node.$ui.dom; + range = node.$ui; } // Now see if `range` is truthy and either `this` // or an immediate subrange while (range && range !== this) - range = range.owner && range.owner.dom; + range = range.owner; return range === this; }; @@ -960,7 +937,7 @@ var HandlerRec = function (elem, type, selector, handler, $ui) { if ((! h.selector) && evt.currentTarget !== evt.target) // no selector means only fire on target return; - if (! h.$ui.dom.contains(evt.currentTarget)) + if (! h.$ui.contains(evt.currentTarget)) return; return h.handler.call(h.$ui, evt); }; @@ -1075,17 +1052,16 @@ DomRange.prototype.on = function (events, selector, handler) { } var handlerList = info.handlers; var handlerRec = new HandlerRec( - parentNode, type, selector, handler, this.component); + parentNode, type, selector, handler, this); handlerRec.bind(); handlerList.push(handlerRec); // move handlers of enclosing ranges to end - for (var r = (this.owner && this.owner.dom); - r; r = (r.owner && r.owner.dom)) { + for (var r = this.owner; r; r = r.owner) { // r is an enclosing DomRange for (var j = 0, Nj = handlerList.length; j < Nj; j++) { var h = handlerList[j]; - if (h.$ui && h.$ui.dom === r) { + if (h.$ui === r) { h.unbind(); h.bind(); handlerList.splice(j, 1); // remove handlerList[j] diff --git a/packages/ui/domrange_tests.js b/packages/ui/domrange_tests.js index 2bde284bf1..7ef3d94d94 100644 --- a/packages/ui/domrange_tests.js +++ b/packages/ui/domrange_tests.js @@ -5,23 +5,23 @@ var parseHTML = UI.DomBackend.parseHTML; // fake component; DomRange host var Comp = function (which) { this.which = which; - - new DomRange(this); + this.dom = new DomRange; + this.dom.component = this; }; var isStartMarker = function (n) { - return (n.$ui && n === n.$ui.dom.start); + return (n.$ui && n === n.$ui.start); }; var isEndMarker = function (n) { - return (n.$ui && n === n.$ui.dom.end); + return (n.$ui && n === n.$ui.end); }; var inDocument = function (range, func) { var onscreen = document.createElement("DIV"); onscreen.style.display = 'none'; document.body.appendChild(onscreen); - DomRange.insert(range.component, onscreen); + DomRange.insert(range, onscreen); try { func(range); } finally { @@ -72,7 +72,6 @@ Tinytest.add("ui - DomRange - basic", function (test) { test.equal(div.previousSibling, rStart); test.equal(div.nextSibling, rEnd); test.equal(div.$ui, r); - test.equal(div.$ui.dom, r); // add a subrange var s = new DomRange; @@ -143,8 +142,8 @@ Tinytest.add("ui - DomRange - shuffling", function (test) { else str += '-'; } else { - if (n.$ui.which) - str += n.$ui.which; + if (n.$ui.component && n.$ui.component.which) + str += n.$ui.component.which; else str += (n.nodeName || '?'); } @@ -170,12 +169,12 @@ Tinytest.add("ui - DomRange - shuffling", function (test) { var X = new Comp('X'); var Y = new Comp('Y'); var Z = new Comp('Z'); - r.add('X', X, 'I'); + r.add('X', X.dom, 'I'); X.dom.add(document.createElement("SPAN")); Y.dom.add(document.createElement("SPAN")); Z.dom.add(document.createElement("SPAN")); - r.add('Y', Y, 'U'); - r.add('Z', Z); + r.add('Y', Y.dom, 'U'); + r.add('Z', Z.dom); test.equal(spellDom(), '(B(X)I(Y)U(Z))'); @@ -190,21 +189,22 @@ Tinytest.add("ui - DomRange - shuffling", function (test) { r.moveBefore('U', 'Y'); test.equal(spellDom(), '((X)BAAIU(Y)(Z))'); + r.moveBefore('Z', 'X'); r.moveBefore('Y', 'X'); test.equal(spellDom(), '((Z)(Y)(X)BAAIU)'); - test.equal(r.get('X'), X); - test.equal(r.get('Y'), Y); - test.equal(r.get('Z'), Z); - test.equal(r.get('B'), B); - test.equal(r.get('I'), I); - test.equal(r.get('U'), U); + test.isTrue(r.get('X') === X.dom); + test.isTrue(r.get('Y') === Y.dom); + test.isTrue(r.get('Z') === Z.dom); + test.isTrue(r.get('B') === B); + test.isTrue(r.get('I') === I); + test.isTrue(r.get('U') === U); test.isFalse(r.owner); - test.equal(X.dom.owner, r); - test.equal(Y.dom.owner, r); - test.equal(Z.dom.owner, r); + test.isTrue(X.dom.owner === r); + test.isTrue(Y.dom.owner === r); + test.isTrue(Z.dom.owner === r); r.remove('Y'); test.equal(spellDom(), '((Z)(X)BAAIU)'); @@ -226,9 +226,9 @@ Tinytest.add("ui - DomRange - nested", function (test) { _.each(frag.childNodes, function (n) { var ui = n.$ui; if (isStartMarker(n)) - str += (ui.which ? ui.which : '('); + str += (ui.component ? ui.component.which : '('); else if (isEndMarker(n)) - str += (ui.which ? ui.which.toLowerCase() : ')'); + str += (ui.component ? ui.component.which.toLowerCase() : ')'); else str += '?'; }); @@ -240,16 +240,16 @@ Tinytest.add("ui - DomRange - nested", function (test) { var A,B,C,D,E,F; test.equal(spellDom(), '()'); - r.add(A = new Comp('A')); + r.add((A = new Comp('A')).dom); test.equal(spellDom(), '(Aa)'); - r.add('B', B = new Comp('B')); - r.add('C', C = new Comp('C'), 'B'); + r.add('B', (B = new Comp('B')).dom); + r.add('C', (C = new Comp('C')).dom, 'B'); test.equal(spellDom(), '(AaCcBb)'); - r.get('B').dom.add('D', D = new Comp('D')); - D.dom.add('E', new Comp('E')); + r.get('B').add('D', (D = new Comp('D')).dom); + D.dom.add('E', (E = new Comp('E')).dom); test.equal(spellDom(), '(AaCcBDEedb)'); - B.dom.add('F', F = new Comp('F')); + B.dom.add('F', (F = new Comp('F')).dom); test.equal(spellDom(), '(AaCcBDEedFfb)'); r.moveBefore('B', 'C'); @@ -305,7 +305,7 @@ Tinytest.add("ui - DomRange - external moves", function (test) { de.dom.add('Z', Z); de.dom.add(wsp()); cf.dom.add(wsp()); - cf.dom.add('de', de); + cf.dom.add('de', de.dom); cf.dom.add(wsp()); var gl = new Comp('gl'); var hk = new Comp('hk'); @@ -316,12 +316,12 @@ Tinytest.add("ui - DomRange - external moves", function (test) { // i-W-j test.equal(ij.dom.getNodes().length, 5); gl.dom.add(wsp()); - gl.dom.add('hk', hk); + gl.dom.add('hk', hk.dom); gl.dom.add(wsp()); // g-hk-l test.equal(gl.dom.getNodes().length, 6); hk.dom.add(wsp()); - hk.dom.add('ij', ij); + hk.dom.add('ij', ij.dom); hk.dom.add(wsp()); // h-i-W-j-k test.equal(hk.dom.getNodes().length, 9); @@ -329,12 +329,12 @@ Tinytest.add("ui - DomRange - external moves", function (test) { test.equal(gl.dom.getNodes().length, 13); var r = new DomRange; - r.dom.add('ab', ab); - r.dom.add(wsp()); - r.dom.add('cf', cf); - r.dom.add(wsp()); - r.dom.add('gl', gl); - r.dom.add('V', V); + r.add('ab', ab.dom); + r.add(wsp()); + r.add('cf', cf.dom); + r.add(wsp()); + r.add('gl', gl.dom); + r.add('V', V); var spellDom = function () { var frag = r.parentNode(); @@ -342,9 +342,9 @@ Tinytest.add("ui - DomRange - external moves", function (test) { _.each(frag.childNodes, function (n) { var ui = n.$ui; if (isStartMarker(n)) - str += (ui.which ? ui.which.charAt(0) : '('); + str += (ui.component ? ui.component.which.charAt(0) : '('); else if (isEndMarker(n)) - str += (ui.which ? ui.which.charAt(1) : ')'); + str += (ui.component ? ui.component.which.charAt(1) : ')'); else if (n.nodeType === 3) str += '-'; else @@ -359,12 +359,12 @@ Tinytest.add("ui - DomRange - external moves", function (test) { test.equal(spellDom(), strip('(a-X-b - c-d-Y-Z-e-f - g-h-i-W-j-k-l V)')); - test.equal(ab.dom.owner, r); - test.equal(cf.dom.owner, r); - test.equal(de.dom.owner, cf); - test.equal(gl.dom.owner, r); - test.equal(hk.dom.owner, gl); - test.equal(ij.dom.owner, hk); + test.isTrue(ab.dom.owner === r); + test.isTrue(cf.dom.owner === r); + test.isTrue(de.dom.owner === cf.dom); + test.isTrue(gl.dom.owner === r); + test.isTrue(hk.dom.owner === gl.dom); + test.isTrue(ij.dom.owner === hk.dom); // all right, now let's mess around with these elements! @@ -491,11 +491,13 @@ Tinytest.add("ui - DomRange - external moves", function (test) { Tinytest.add("ui - DomRange - tables", function (test) { var range = function (x) { - new DomRange(x); + // create a range x.dom containing an element x.el, + // inside that element, the range x.content.dom + x.dom = new DomRange; if (x.el) { x.dom.add(x.el); if (x.content) - DomRange.insert(x.content, x.el); + DomRange.insert(x.content.dom, x.el); } return x; }; @@ -525,7 +527,7 @@ Tinytest.add("ui - DomRange - tables", function (test) { test.equal(table.el.childNodes.length, 0); table.content = range({}); - DomRange.insert(table.content, table.el); + DomRange.insert(table.content.dom, table.el); // table has two children (start/end markers), no elements test.equal(table.el.childNodes.length, 2); test.notEqual(table.el.firstChild.nodeType, 1); @@ -545,11 +547,11 @@ Tinytest.add("ui - DomRange - tables", function (test) { test.equal(table.el.childNodes.length, 0); table.content = range({}); - DomRange.insert(table.content, table.el); + DomRange.insert(table.content.dom, table.el); var a1 = range({}); var a2 = range({}); - a1.dom.add(a2); - table.content.dom.add(a1); + a1.dom.add(a2.dom); + table.content.dom.add(a1.dom); // 6 marker nodes in table, no elements test.equal(table.el.childNodes.length, 6); test.equal($(table.el).find("*").length, 0); @@ -567,17 +569,17 @@ Tinytest.add("ui - DomRange - tables", function (test) { test.equal(table.el.childNodes.length, 0); table.content = range({}); - DomRange.insert(table.content, table.el); + DomRange.insert(table.content.dom, table.el); var b1 = range({}); var b2 = range({}); - table.content.dom.add(b1); + table.content.dom.add(b1.dom); b2.dom.add(document.createElement('tr')); // 4 marker nodes in table, no elements test.equal(table.el.childNodes.length, 4); test.equal($(table.el).find("*").length, 0); // shazam, adding b2, which contains a TR, // should move all the ranges into a TBODY. - b1.dom.add(b2); + b1.dom.add(b2.dom); test.equal(table.el.childNodes.length, 1); test.equal(table.el.firstChild.nodeName, 'TBODY'); test.equal(table.el.firstChild.childNodes.length, 7); @@ -594,8 +596,8 @@ Tinytest.add("ui - DomRange - tables", function (test) { var c1 = range({}); var c2 = range({}); - DomRange.insert(c1, table.el); - DomRange.insert(c2, table.el); + DomRange.insert(c1.dom, table.el); + DomRange.insert(c2.dom, table.el); test.equal(table.el.childNodes.length, 4); test.equal($(table.el).find("*").length, 0); c2.dom.add(document.createElement('tr')); @@ -745,22 +747,15 @@ Tinytest.add("ui - DomRange - contains", function (test) { Tinytest.add("ui - DomRange - constructor", function (test) { var r = new DomRange; - test.isTrue(r.dom === r); - test.isTrue(r.component === r); - var x = {}; - var s = new DomRange(x); - test.isTrue(x.dom === s); - test.isTrue(s.component === x); + test.isTrue(r.parentNode()); - test.isTrue(s.parentNode()); - - test.isTrue(s.start.$ui === x); - test.isTrue(s.end.$ui === x); + test.isTrue(r.start.$ui === r); + test.isTrue(r.end.$ui === r); var div = document.createElement('div'); - s.add(div); - test.isTrue(div.$ui === x); + r.add(div); + test.isTrue(div.$ui === r); }); Tinytest.add("ui - DomRange - get", function (test) { @@ -803,16 +798,6 @@ Tinytest.add("ui - DomRange - get", function (test) { test.isTrue(r.get('c') === c); test.isTrue(r.get('toString') === d); - - var x = {}; - var s = new DomRange(x); - - test.throws(function () { - r.add('s', s); - }); - - r.add('x', x); - test.isTrue(r.get('x') === x); }); // This test targets IE 9 and 10, which allow properties diff --git a/packages/ui/each.js b/packages/ui/each.js index 6ff266fe15..1d967d6515 100644 --- a/packages/ui/each.js +++ b/packages/ui/each.js @@ -100,7 +100,7 @@ UI.Each = Component.extend({ beforeId = LocalCollection._idStringify(beforeId); var renderedItem = UI.render(content.withData(dataFunc), self); - range.add(id, renderedItem, beforeId); + range.add(id, renderedItem.dom, beforeId); }, removed: function (id, item) { addToCount(-1); @@ -112,7 +112,7 @@ UI.Each = Component.extend({ beforeId && LocalCollection._idStringify(beforeId)); }, changed: function (id, newItem) { - range.get(LocalCollection._idStringify(id)).data.$set(newItem); + range.get(LocalCollection._idStringify(id)).component.data.$set(newItem); } }); diff --git a/packages/ui/render.js b/packages/ui/render.js index 02f1c69f77..0d6fd2d470 100644 --- a/packages/ui/render.js +++ b/packages/ui/render.js @@ -159,13 +159,11 @@ UI.emboxValue = function (funcOrValue, equals) { //////////////////////////////////////// -UI.insert = UI.DomRange && UI.DomRange.insert; - // Insert a DOM node or DomRange into a DOM element or DomRange. // // One of three things happens depending on what needs to be inserted into what: // - `range.add` (anything into DomRange) -// - `UI.insert` (DomRange into element) +// - `UI.DomRange.insert` (DomRange into element) // - `elem.insertBefore` (node into element) // // The optional `before` argument is an existing node or id to insert before in @@ -174,12 +172,11 @@ var insert = function (nodeOrRange, parent, before) { if (! parent) throw new Error("Materialization parent required"); - if (parent.component && parent.component.dom) { - // parent is DomRange; add node or range - parent.add(nodeOrRange.component || nodeOrRange, before); - } else if (nodeOrRange.component && nodeOrRange.component.dom) { + if (parent instanceof UI.DomRange) { + parent.add(nodeOrRange, before); + } else if (nodeOrRange instanceof UI.DomRange) { // parent is an element; inserting a range - UI.insert(nodeOrRange.component, parent, before); + UI.DomRange.insert(nodeOrRange, parent, before); } else { // parent is an element; inserting an element parent.insertBefore(nodeOrRange, before || null); // `null` for IE @@ -243,10 +240,13 @@ UI.render = function (kind, parentComponent) { var content = content = (inst.render && inst.render()); - var range = new UI.DomRange(inst); + var range = new UI.DomRange; + inst.dom = range; + range.component = inst; + materialize(content, range, null, inst); - inst.removed = function () { + range.removed = function () { inst.isDestroyed = true; if (inst.destroyed) { updateTemplateInstance(inst);