diff --git a/packages/ui/base.js b/packages/ui/base.js index 8375a2cf1c..7321e44945 100644 --- a/packages/ui/base.js +++ b/packages/ui/base.js @@ -198,867 +198,6 @@ _extend(UI.Component, { //}; -/* -_extend(UI.Component, { - // Parent Component in the composition hierarchy. - // An inited - parent: null, - // Child Components in the composition hierarchy, - // in a dictionary keyed on their `guid` property. - // - // For memory efficiency, childless Components share - // the same dictionary. - children: SEALED_EMPTY_OBJECT, - - // # component.add(child) - // - // Adds `child` to this component in the parent/child - // hierarchy. - // - // Components must be assembled from "top to bottom." Each - // component must either be added as a child of another, - // or made a root using `component.makeRoot()`, before - // it can receive its own children. This ensures that - // every component already knows its parent when it is - // initialized. A component's parent is permanent; the - // component cannot be removed or reparented without - // destroying it. - // - // The child is not built or put into the DOM. - // The `append`, `prepend`, and `insertBefore` - // methods all add their argument as a child in addition - // to building it if necessary and putting it into the - // component's DOM. - // - // Requires `component` is not destroyed. - add: function (child) { - var self = this; - - if (self.isDestroyed) - throw new Error("Can't add child to a destroyed component"); - if (! self.isInited) - throw new Error("Component must be inited already to add a child"); - - var guid = child.guid; - - if (self.children[guid]) - throw new Error("Child already added to this component!"); - - if (child.isInited) - throw new Error("Child already inited, can't add to a different parent"); - - // allocate a new dictionary to hold children if necessary - if (self.children === SEALED_EMPTY_OBJECT) - self.children = {}; - - self.children[guid] = child; - - child.parent = self; - - // Note on ordering of these two lines: You see `isInited` - // as `true` from `init` callbacks, even though - // linguistically it seems odd that you are marked - // inited before `init` is called. What's really going - // on is `init` is a callback which would normally be - // named in the past tense; for example, we'd set - // `isAdded` to true and then call the `added` callback. - // - // `isInited` in fact means essentially "has been added/ - // instantiated", and `init` is the callback you get - // when that happens. - child.isInited = true; - Deps.nonreactive(function () { - callChainedCallback(child, 'init'); - }); - - // useful in: `this.foo = this.add(Foo.extend())` - return child; - }, - - hasChild: function (comp) { - this._requireNotDestroyed(); - this._requireInited(); - - return this.children[comp.guid] === comp; - }, - - // Init this Component without giving it a parent; it will - // never have a parent and always be the root of its own - // parent/child hierarchy. - // - // This is primarily intended for unit testing, or embedding - // Meteor UI. - makeRoot: function (comp) { - if (this.isInited) { - if (this.parent) - throw new Error("Component already parented"); - throw new Error("Component already inited as a root"); - } - - this.isInited = true; - callChainedCallback(this, 'init'); - }, - - remove: function (child) { - var self = this; - - self._requireNotDestroyed(); - - if (! child) { - // Support `()` form of args; remove self. - // Can't `remove()` if we are a root or haven't been - // inited. - if (! self.isInited || ! self.parent) - throw new Error("Component to remove must have a parent"); - self.parent.remove(self); - return; - } - - // Child is inited but may or may not be built. - // Child may be destroyed. - - // Note that child is not removed from the DOM if it is already - // destroyed. This is used when a Component is rebuilt -- the - // children are first destroyed, then removed as children, then - // removed from the DOM wholesale in one operation. - if (child.isBuilt && ! child.isDestroyed && - child.isAttached) { - - child.detach(true); // _forDestruction = true - } - - var guid = child.guid; - if (! self.children[guid]) - throw new Error("Child not found (id " + guid + ")"); - - delete self.children[guid]; - // (don't delete child.parent pointer, could be useful - // in destroyed callback?) - - child.destroy(); - - } -}); - -_extend(UI.Component, { - // If the Component is built into DOM, `start` and `end` - // are the first and last *nodes or Components* in this - // Component's subtree of DOM nodes and Components. - start: null, - end: null, - - firstNode: function () { - this._requireBuilt(); - this._requireNotDestroyed(); - - return UI.isComponent(this.start) ? - this.start.firstNode() : this.start; - }, - - lastNode: function () { - this._requireBuilt(); - this._requireNotDestroyed(); - - return UI.isComponent(this.end) ? - this.end.lastNode() : this.end; - }, - - parentNode: function () { - return this.firstNode().parentNode; - }, - - // Built Components are either attached or detached. - // An attached Component is assumed to be part of - // its parent's DOM tree (or for a root Component, the - // document). A detached Component lives in its own private - // offscreen DIV. Components start detached (offscreen) but - // are typically attached immediately. They may then be - // attached and detached at will, which inserts and removes - // them from the parent's DOM. A detached Component has - // a functional DOM and can have attached and detached - // children. - // - // Components should only be inserted into the DOM by calling - // `append`, `insertBefore`, et al. on their parent, or - // for a root using `attachRoot`. - isAttached: false, - - // DIV holding offscreen content (when component is built and not attached). - // It's a DIV rather than a fragment so that jQuery can run against it. - _offscreen: null, - - // `content` and `elseContent` must be Components or functions - // that return components. - content: Empty, - elseContent: Empty, - - // The `render` method is overridden by compiled templates - // and other components to declare the component's - // constituent HTML/DOM and children. It's called during - // building on the client, and it can also be used on the - // client or server to generate initial HTML. - render: function (buf) { - buf.write(this.content); - }, - - _populate: function (div) { - var self = this; - - var buf = makeRenderBuffer(self); - self.render(buf); - - var html = buf.getHtml(); - - $(div).append(html); - - // returns info object with {start, end} - return buf.wireUpDOM(div); - }, - - build: function () { - var self = this; - - self._requireNotDestroyed(); - if (self.isBuilt) - throw new Error("Component already built"); - - if (! self.isInited) - self.makeRoot(); - - self._rebuilder = self.autorun(function (c) { - // record set of children that existed before, - // or null (for efficiency) - var oldChildren = null; - for (var k in self.children) - (oldChildren || (oldChildren = {}))[k] = true; - - if (c.firstRun) { - var div = makeSafeDiv(); - // capture reactivity: - var info = self._populate(div); - - if (! div.firstChild) - div.appendChild(createEmptyComment()); - - self._offscreen = div; - self.start = info.start || div.firstChild; - self.end = info.end || div.lastChild; - } else { - // capture reactivity: - self._rebuild(c.builtChildren); - } - - var newChildren = null; - for (var k in self.children) - if (! (oldChildren && oldChildren[k])) - (newChildren || (newChildren = {}))[k] = self.children[k]; - - // `builtChildren` is actually children *added* during build - c.builtChildren = newChildren; - - // don't capture dependencies, but provide a - // parent autorun (so that any autoruns created - // from a built callback are stopped on rebuild) - var x = Deps.autorun(function (c) { - if (c.firstRun) { - self.isBuilt = true; - self._callOnNextBuiltCallbacks(); - - // FAKE-ISH (NON-DELEGATED) EVENT MAP STUFF - if (self._events && self._events.length) { - _.each(self._events, function (info) { - $(self.firstNode().parentNode).find(info.selector).on( - info.type, function (evt) { - if (self.containsElement(evt.currentTarget)) - info.handler(evt); - }); - }); - } - - callChainedCallback(self, 'rendered'); - } - }); - Deps.onInvalidate(function () { - x.stop(); - }); - }); - }, - - // Don't call this directly. It implements the re-run of the - // build autorun, so it assumes it's already inside the appropriate - // reactive computation. - // - // `builtChildren` is a map of children that were added during - // the previous build (as opposed to at some other time, such as - // earlier from an `init` callback). - _rebuild: function (builtChildren) { - var self = this; - - if (! (self.isBuilt && ! self.isDestroyed)) - throw new Error("Assertion failed in _rebuild"); - - // Should work whether this component is detached or attached! - // In other words, it may reside in an offscreen element. - - var firstNode = self.firstNode(); - var lastNode = self.lastNode(); - var parentNode = lastNode.parentNode; - var nextNode = lastNode.nextSibling || null; - var prevNode = firstNode.previousSibling || null; - - // for efficiency, do a quick check to see if we've *ever* - // had children or if we are still using the prototype's - // empty object. - if (self.children !== UI.Component.children) { - Deps.nonreactive(function () { - // kill children from last render, and also any - // attached children - var children = self.children; - for (var k in children) { - var child = children[k]; - if (builtChildren && builtChildren[k]) { - // destroy first, then remove - // (which doesn't affect DOM, which we will - // remove all at once) - child.destroy(); - self.remove(child); - } else if (child.isAttached) { - // detach the child; we don't have a good way - // of keeping this from affecting the DOM - child.detach(); - } - } - }); - } - - var oldNodes = []; - // must be careful as call to `detach` above may have - // must with firstNode or lastNode - for (var n = prevNode ? prevNode.nextSibling : - parentNode.firstChild; - n && n !== nextNode; - n = n.nextSibling) - oldNodes.push(n); - - $(oldNodes).remove(); - - var div = makeSafeDiv(); - // set `self.start` to null so that calls to `attach` from - // `_populate` don't try to do start/end pointer logic. - self.start = self.end = null; - var info = self._populate(div); - if (! div.firstChild) - div.appendChild(createEmptyComment()); - - self.start = info.start || div.firstChild; - self.end = info.end || div.lastChild; - insertNodesBefore(div.childNodes, parentNode, nextNode); - }, - - // Internal method used by insertBefore, render buffer, - // and attachRoot. - _attach: function (parentNode, beforeNode) { - var self = this; - - self._requireNotDestroyed(); - - if (! self.isInited) - throw new Error("Component to attach must be inited"); - - if (! self.isBuilt) - self.build(); - - if (self.isAttached) - throw new Error("Component already attached; must be detached first"); - - if ((! parentNode) || ! parentNode.nodeType) - throw new Error("first argument to attach must be a Node"); - if (beforeNode && ! beforeNode.nodeType) - throw new Error("second argument to attach must be a Node" + - " if given"); - - insertNodesBefore(self._offscreen.childNodes, - parentNode, beforeNode); - - self._offscreen = null; - self.isAttached = true; - - var parent = self.parent; - // We could be a root (and have no parent). Parent could - // theoretically be destroyed, or not yet built (if we - // are currently building). - // - // We use a falsy `parent.start` as a cue that this is a - // rebuild, another case where we skip the start/end adjustment - // logic. - // - // `attach` is special in that it is used during building - // and rebuilding; it is not required that the parent is - // completely built. - if (parent && parent.isBuilt && ! parent.isDestroyed && - parent.start) { - if (parent.isEmpty()) { - var comment = parent.start; - parent.start = parent.end = self; - comment.parentNode.removeChild(comment); - } else { - if (parent.firstNode() === self.lastNode().nextSibling) - parent.start = self; - if (parent.lastNode() === self.firstNode().previousSibling) - parent.end = self; - } - } - - callChainedCallback(self, 'attached'); - }, - - isEmpty: function () { - this._requireBuilt(); - this._requireNotDestroyed(); - - var start = this.start; - return start === this.end && - ! UI.isComponent(start) && isEmptyComment(start); - }, - - // # component.detach() - // - // Component must be built and attached. Removes this component's - // DOM and puts it into an offscreen storage. Updates the parent's - // `start` and `end` and populates it with a comment if it becomes - // empty. - detach: function (_forDestruction) { - var self = this; - - self._requireBuilt(); - self._requireNotDestroyed(); - if (! self.isAttached) - throw new Error("Component not attached"); - - var parent = self.parent; - var A = self.firstNode(); - var B = self.lastNode(); - - // We could be a root (and have no parent). Parent could - // theoretically be destroyed, or not yet built. - if (parent && parent.isBuilt && ! parent.isDestroyed) { - // Do some magic to update the - // firstNode and lastNode. The main issue is we need to - // know if the new firstNode or lastNode is part of a - // child component or not, because if it is, we need to - // set `start` or `end` to the component rather than the - // node. Since we don't have any pointers from the DOM - // and can't make any assumptions about the structure of - // the component, we have to do a search over our children. - // Repeatedly detaching the first or last of O(N) top-level - // components is asymptotically bad -- O(n^2). - // - // Components that manage large numbers of top-level components - // should override _findStartComponent and _findEndComponent. - if (parent.start === self) { - if (parent.end === self) { - // we're emptying the parent; populate it with a - // comment in an appropriate place (adjacent to - // the not-yet-extracted DOM) and set pointers. - var comment = createEmptyComment(); - A.parentNode.insertBefore(comment, A); - parent.start = parent.end = comment; - } else { - // Removing component at the beginning of parent. - // - // Figure out if the following top-level node is the - // first node of a Component. - var newFirstNode = B.nextSibling; - parent.start = parent._findStartComponent(newFirstNode); - if (! (parent.start && parent.start.firstNode() === newFirstNode)) - parent.start = newFirstNode; - } - } else if (parent.end === self) { - // Removing component at the end of parent. - // - // Figure out if the previous top-level node is the - // last node of a Component. - var newLastNode = A.previousSibling; - parent.end = parent._findEndComponent(newLastNode); - if (! (parent.end && parent.end.lastNode() === newLastNode)) - parent.end = newLastNode; - } - } - - var nodes = []; - for (var n = A; n !== B; n = n.nextSibling) - nodes.push(n); - nodes.push(B); - - if (_forDestruction === true) { - $(nodes).remove(); - } else { - // Move nodes into an offscreen div, preserving - // any event handlers and data associated with the nodes. - var div = makeSafeDiv(); - $(div).append(nodes); - - self._offscreen = div; - self.isAttached = false; - - callChainedCallback(self, 'detached'); - } - }, - - // # component.append(childOrDom) - // - // childOrDom is a Component, or node, or HTML string, - // or array of elements (various things a la jQuery). - // - // Given `child`: It must be a child of this component or addable - // as one. Builds it if necessary. Attaches it at the end of - // this component. Updates `start` and `end` of this component. - - append: function (childOrDom) { - this.insertAfter(childOrDom, this.lastNode()); - }, - - prepend: function (childOrDom) { - this.insertBefore(childOrDom, this.firstNode()); - }, - - // # component.insertBefore(childOrDom, before, parentNode) - // - // `before` is a Component or node. parentNode is only used - // if `before` is null. It defaults to the Component's - // parentNode. - // - // See append. - - insertBefore: function (childOrDom, before, parentNode) { - var self = this; - - self._requireBuilt(); - self._requireNotDestroyed(); - - if (UI.isComponent(before)) { - before = before.firstNode(); - } else if (! before) { - if ((! parentNode) || (parentNode === self.parentNode())) { - before = self.lastNode().nextSibling; - parentNode = parentNode || self.parentNode(); - } - } - parentNode = parentNode || before.parentNode; - - if (UI.isComponent(childOrDom)) { - var child = childOrDom; - - child._requireNotDestroyed(); - - if (! child.isInited) { - self.add(child); - } else if (child.parent !== self) { - throw new Error("Can only append/prepend/insert" + - " a child (or a component addable as one)"); - } - - child._attach(parentNode, before); - } else { - var nodes; - if (typeof childOrDom === 'string') { - nodes = $.parseHTML(childOrDom) || []; - } else if (childOrDom.nodeType) { - nodes = [childOrDom]; - } else if (typeof childOrDom.length === 'number' && - typeof childOrDom === 'object') { - nodes = Array.prototype.slice.call(childOrDom); - } else { - throw new Error( - "Expected HTML, DOM node, array, or Component, found " + - childOrDom); - } - - if (nodes.length) { - insertNodesBefore(nodes, parentNode, before); - - if (self.isEmpty()) { - var comment = self.start; - comment.parentNode.removeChild(comment); - self.start = nodes[0]; - self.end = nodes[nodes.length - 1]; - } else if (before === self.firstNode()) { - self.start = nodes[0]; - } else if (nodes[0].previousSibling === self.lastNode()) { - self.end = nodes[nodes.length - 1]; - } - } - } - }, - - insertAfter: function (childOrDom, after, parentNode) { - var self = this; - - if (UI.isComponent(after)) { - after = after.lastNode(); - } else if (! after) { - if ((! parentNode) || (parentNode === self.parentNode())) { - after = self.firstNode().previousSibling; - parentNode = parentNode || self.parentNode(); - } - } - parentNode = parentNode || after.parentNode; - - this.insertBefore(childOrDom, after.nextSibling, parentNode); - }, - - // Is `elem` between `this.firstNode()` and `this.lastNode()`? - containsElement: function (elem) { - if (elem.nodeType !== 1) - throw new Error("containsElement requires an Element node"); - - var self = this; - self._requireBuilt(); - self._requireNotDestroyed(); - - var firstNode = self.firstNode(); - var lastNode = self.lastNode(); - if (! elementContains(firstNode.parentNode, elem)) - return false; - - // because compareElementIndex only works on elements, we find - // previous and next element siblings. (previousSiblingElement and - // nextSiblingElement do the same thing but they neither work on - // IE8 nor are they available on text nodes) - var prevElem = firstNode.previousSibling; - while (prevElem && prevElem.nodeType !== 1) - prevElem = prevElem.previousSibling; - var nextElem = lastNode.nextSibling; - while (nextElem && nextElem.nodeType !== 1) - nextElem = nextElem.nextSibling; - - // element must not be "at or before" prevElem - if (prevElem && compareElementIndex(prevElem, elem) >= 0) - return false; - // element must not be "at or after" nextElem - if (nextElem && compareElementIndex(elem, nextElem) >= 0) - return false; - return true; - }, - - // Take element `elem` and find the innermost component containing - // it which is either this component or a descendent of this component. - findByElement: function (elem) { - if (elem.nodeType !== 1) - throw new Error("findByElement requires an Element node"); - - var self = this; - self._requireBuilt(); - - if (! self.containsElement(elem)) - return null; - - var children = self.children; - // XXX linear-time scan through all child components, - // running DOM comparison methods that may themselves - // be O(N). Not sure what the constants are like. - for (var k in children) { - var child = children[k]; - if (child.isBuilt && (! child.isDestroyed) && - child.isAttached) { - var found = child.findByElement(elem); - if (found) - return found; - } - } - - return self; - }, -*/ -/* -_extend(UI.Component, { - $: function (selector) { - var self = this; - - UI._requireDom(self); - UI._requireNotDestroyed(self); - - var firstNode = self.dom.getFirstNode(); - var parentNode = firstNode.parentNode; - var prevNode = firstNode.previousSibling; - var nextNode = self.dom.getLastNode().nextSibling; - - // Don't assume `results` has jQuery API; a plain array - // should do just as well. However, if we do have a jQuery - // array, we want to end up with one also. - var results = $(selector, self.dom.parentNode()); - - // Function that selects only elements that are actually in this - // Component, out of elements that are descendents of the Component's - // parentNode in the DOM (but may be, or descend from, siblings of - // this Component's top-level nodes that aren't between `start` and - // `end` inclusive). - var filterFunc = function (elem) { - // handle jQuery's arguments to filter, where the node - // is in `this` and the index is the first argument. - if (typeof elem === 'number') - elem = this; - - if (prevNode && compareElementIndex(prevNode, elem) >= 0) - return false; - if (nextNode && compareElementIndex(elem, nextNode) >= 0) - return false; - return true; - }; - - if (! results.filter) { - // not a jQuery array, and not a browser with - // Array.prototype.filter (e.g. IE <9) - var newResults = []; - for (var i = 0; i < results.length; i++) { - var x = results[i]; - if (filterFunc(x)) - newResults.push(x); - } - results = newResults; - } else { - // `results.filter` is either jQuery's or ECMAScript's `filter` - results = results.filter(filterFunc); - } - - return results; - } -}); -*/ -/* - autorun: function (compFunc) { - var self = this; - - self._requireNotDestroyed(); - - // XXX so many nested functions... Deps.nonreactive here - // feels heavyweight, but we don't want building a child - // while building a parent to mean that when the parent - // rebuilds, the child automatically does. - var c = Deps.nonreactive(function () { - return Deps.autorun(compFunc); - }); - - self._computations = self._computations || []; - self._computations.push(c); - - return c; - }, - - replaceChild: function (oldChild, newChild) { - var self = this; - - self._requireBuilt(); - self._requireNotDestroyed(); - oldChild._requireBuilt(); - oldChild._requireNotDestroyed(); - if (! oldChild.isAttached) - throw new Error("Child to replace must be attached"); - - var lastNode = oldChild.lastNode(); - var parentNode = lastNode.parentNode; - var nextNode = lastNode.nextSibling; - - oldChild.remove(); - self.insertBefore(newChild, nextNode, parentNode); - }, - - swapChild: function (oldChild, newChild) { - var self = this; - - self._requireBuilt(); - self._requireNotDestroyed(); - oldChild._requireBuilt(); - oldChild._requireNotDestroyed(); - if (! oldChild.isAttached) - throw new Error("Child to swap out must be attached"); - - var lastNode = oldChild.lastNode(); - var parentNode = lastNode.parentNode; - var nextNode = lastNode.nextSibling; - - oldChild.detach(); - self.insertBefore(newChild, nextNode, parentNode); - }, - - _onNextBuilt: function (cb) { - var self = this; - var cbs = self._builtCallbacks; - if (! cbs) - cbs = self._builtCallbacks = []; - cbs.push(cb); - }, - - _callOnNextBuiltCallbacks: function () { - var self = this; - var cbs = self._builtCallbacks; - if (cbs) { - for (var i = 0, N = cbs.length; i < N; i++) - cbs[i](self); - self._builtCallbacks.length = 0; - } - }, - - // Return a child whose firstNode() may be `firstNode`. - // If such a child exists, it must be found by this function. - // If no such child exists, this function may return null - // or a wrong guess at a child. Subclasses that know, - // for example, the earliest child component in the DOM - // at all times can supply that as a guess. - _findStartComponent: function (firstNode) { - var children = this.children; - // linear-time scan until found - for (var k in children) { - var c = children[k]; - if (c.isBuilt && c.isAttached && - c.firstNode() === firstNode) - return c; - } - return null; - }, - - _findEndComponent: function (lastNode) { - var children = this.children; - // linear-time scan until found - for (var k in children) { - var c = children[k]; - if (c.isBuilt && c.isAttached && - c.lastNode() === lastNode) - return c; - } - return null; - } - - // If Component is ever emptied, it gets an empty comment node. - // This case is treated specially and the comment is removed - // if you then, say, append a node or component. However, - // the developer doing advanced things needs to be aware of - // this case or they may be surprised there is a node there - // that they didn't put there, e.g. if they call remove() on - // the last component and then start inserting DOM nodes - // manually. - - // You are free to manipulate the DOM of your component, excluding - // the regions that belong to child components, though if you do it - // using jQuery or any other means besides the methods here - // (attach, detach, append, prepend, insert), you are responsible - // for ensuring that `start` and `end` point to the first and last - // *node or Component* at the top level of the component's DOM, - // and that the component does not become empty - -}); - - -var emptyCommentProp = 'meteor-ui-empty'; -var createEmptyComment = function (beforeNode) { - var x = document.createComment("empty"); - x[emptyCommentProp] = true; - return x; -}; -var isEmptyComment = function (node) { - return node.nodeType === 8 && node[emptyCommentProp] === true; -}; -*/ // Returns 0 if the nodes are the same or either one contains the other; // otherwise, -1 if a comes before b, or else 1 if b comes before a in // document order. @@ -1079,48 +218,6 @@ var compareElementIndex = function (a, b) { return (a.sourceIndex < b.sourceIndex ? -1 : 1); } }; -/* -// Returns true if element a contains node b and is not node b. -var elementContains = function (a, b) { - if (a.nodeType !== 1) // ELEMENT - return false; - if (a === b) - return false; - - if (a.compareDocumentPosition) { - return a.compareDocumentPosition(b) & 0x10; - } else { - // Should be only old IE and maybe other old browsers here. - // Modern Safari has both functions but seems to get contains() wrong. - // IE can't handle b being a text node. We work around this - // by doing a direct parent test now. - b = b.parentNode; - if (! (b && b.nodeType === 1)) // ELEMENT - return false; - if (a === b) - return true; - - return a.contains(b); - } -}; - -var insertNodesBefore = function (nodes, parentNode, beforeNode) { - if (beforeNode) { - $(nodes).insertBefore(beforeNode); - } else { - $(nodes).appendTo(parentNode); - } -}; - -var makeSafeDiv = function () { - // create a DIV in a DocumentFragment, where the DocumentFragment - // is created by jQuery, which uses tricks to create a "safe" - // fragment for HTML5 tags in IE <9. - var div = document.createElement("DIV"); - var frag = $.buildFragment([div], document); - return div; -}; -*/ UI.body = UI.Component.extend({ kind: 'body', diff --git a/packages/ui/render.js b/packages/ui/render.js index 3e2fc99243..2bbfc3d49d 100644 --- a/packages/ui/render.js +++ b/packages/ui/render.js @@ -88,87 +88,6 @@ UI.render = function (kind, props, parentComp) { }; -/* -// Render an instance of a component kind directly into the DOM, -// optionally with a parentComp (for e.g. name resolution). -// `parentNode` must be an ELEMENT, not a fragment. -UI.renderTo = function (kind, props, - parentNode, beforeNode, parentComp) { - // XXX too bad we don't validate arguments before mutating - // the DOM - var range = new DomRange; - // Insert new DomRange's start/end markers - DomRange.insert(range, parentNode, beforeNode); - -// var nodes = range.getNodes(); -// for (var i = 0, N = nodes.length; i < N; i++) -// parentNode.insertBefore(nodes[i], - // IE needs null -// beforeNode || null); - - - return UI.renderToRange(kind, props, range, parentComp, true); -}; - -UI.renderToRange = function (kind, props, range, parentComp, _XXXrenderTo) { - - // XXX Handle case where kind is function reactively. - // Reuse the same DomRange. - if ((typeof kind) === 'function') { - // XXX scope this autorun - Deps.autorun(function (c) { - if (c.firstRun) { - kind = kind(); - } else { - debugger; // XXX - } - }); - } - - if (kind === null) - return null; - if (! UI.isComponent(kind)) - throw new Error("Expected Component, function, or null"); - if (kind.isInited) - throw new Error("Expected uninited Component"); - - var comp = kind.extend(props); - - comp.dom = range; - // XXXXXX - if (_XXXrenderTo) { - range.component = comp; - comp.parented(); - } - // XXXXXX - comp.isInited = true; - if (parentComp) - comp.parent = parentComp; - - if (comp.init) - comp.init(); - - if (comp.render) { - // XXX scope this autorun - Deps.autorun(function (c) { - if (! c.firstRun) { - range.removeAll(); - } - var buf = makeRenderBuffer(); - comp.render(buf); - buf.build(comp); - }); - } - - // XXX think about this callback's semantics - if (comp.rendered) - comp.rendered(); - - return comp; - -}; -*/ - var ESCAPED_CHARS_UNQUOTED_REGEX = /[&<>]/g; var ESCAPED_CHARS_QUOTED_REGEX = /[&<>"]/g;