mirror of
https://github.com/marko-js/marko.git
synced 2025-12-08 19:26:05 +00:00
Diffing/Keying fixes (#1094)
* Updates the diffing algorithm to use an HTMLFragment node as an abstraction rather than keeping track of startNode and endNode all throughout the diffing algorithm.
* Uses the HTMLFragment for the <${dynamic}> tag and <include> tags to preserve server-rendered content for which the renderBody is not available in the browser.
* Component ids are based on the resulting parent tree (not the owner tree). This means we cannot rely on the ids in the global lookup, so component key/refs are now also stored on the component instance.
* Static node trees are now only auto assigned a key for the top-level node (instead of all nodes).
* Server comment starting markers now have the component's key serialized so the component can be attached to its owner
* Server comment markers no longer have the id on the closing marker, it is stack based.
* Normalize differences between hydration and client-rendering, so post mount the DOM looks the same regardless of whether a component was server or client rendered.
* fix matching up fragments when hydrating by taking components and normalized text nodes into account
* remove wrapping divs in test, should no longer be needed. address hydration issue with alternate fragment matching approach.
* add fragment to dom if there's a parentNode even if no startNode
* add test for mismatched hydration
* don't detach components before moving
* use fragments to preserve renderBody content
* use ___finishFragment as the incomplete fragment marker
* ensure fragments get destroyed properly and dom node key sequences don't continue from previous renders
* use parent/owner terminology in more places, component ids are now parent scoped, key/ref components are attached to their owner for both client + server render, server comment boundaries include the owner and the key in addition to the fully scoped component id, autokeyed dom nodes are attached to their parent, hydration now uses a stack: ids in ending comment nodes not needed, hydration checks to see if a component has been initialized and will attach keys directly to the owner if so
* add mutation guards for text/comment nodes, add mutation guard for input value
* make component-pages test better represent streaming hydration, fix html/head/body hydration in a better/more generic way
* add test for async rendered keyrefs
* add test for repeated mult-level transclusion
* Autokeyed elements are now stored on the parent rather than the owner. User assigned key/refs are still stored on the owner component. Because of this, user assigned keys are now prefixed (with @) to differentiate them from autokeys. This also has the benefit that assigning numeric keys can no longer conflict with the autokeys.
* add re-rendering the intermediate container to one of the new tests
This commit is contained in:
parent
e9b08cb41e
commit
df79fcc5f0
2
package-lock.json
generated
2
package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "marko",
|
||||
"version": "4.12.5",
|
||||
"version": "4.12.5-2",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "marko",
|
||||
"version": "4.12.5",
|
||||
"version": "4.12.5-2",
|
||||
"license": "MIT",
|
||||
"description": "UI Components + streaming, async, high performance, HTML templating for Node.js and the browser.",
|
||||
"scripts": {
|
||||
|
||||
@ -84,6 +84,7 @@ class HtmlElementVDOM extends Node {
|
||||
this.dynamicAttributes = def.dynamicAttributes;
|
||||
this.key = def.key;
|
||||
this.runtimeFlags = def.runtimeFlags;
|
||||
this.isAutoKeyed = def.isAutoKeyed;
|
||||
|
||||
this.isSVG = false;
|
||||
this.isTextArea = false;
|
||||
@ -279,7 +280,10 @@ class HtmlElementVDOM extends Node {
|
||||
createArgs[INDEX_ATTRS] = attributesArg;
|
||||
}
|
||||
|
||||
if (key) {
|
||||
if (
|
||||
key &&
|
||||
(!this.isAutoKeyed || !this.isStatic || this.createElementId)
|
||||
) {
|
||||
createArgs[INDEX_KEY] = key;
|
||||
|
||||
if (!this.isStatic) {
|
||||
|
||||
@ -39,6 +39,7 @@ module.exports = function(node, codegen, vdomUtil) {
|
||||
var properties = codegen.generateCode(node.getProperties());
|
||||
var dynamicAttributes = codegen.generateCode(node.dynamicAttributes);
|
||||
var key = node.key;
|
||||
var isAutoKeyed = node.isAutoKeyed;
|
||||
var runtimeFlags = node.runtimeFlags;
|
||||
var nextConstId = node.nextConstId;
|
||||
|
||||
@ -91,7 +92,8 @@ module.exports = function(node, codegen, vdomUtil) {
|
||||
isHtmlOnly,
|
||||
dynamicAttributes,
|
||||
nextConstId,
|
||||
runtimeFlags
|
||||
runtimeFlags,
|
||||
isAutoKeyed
|
||||
});
|
||||
|
||||
if (bodyOnlyIf) {
|
||||
|
||||
@ -140,12 +140,6 @@ function checkInputChanged(existingComponent, oldInput, newInput) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function getNodes(component) {
|
||||
var nodes = [];
|
||||
component.___forEachNode(nodes.push.bind(nodes));
|
||||
return nodes;
|
||||
}
|
||||
|
||||
var componentProto;
|
||||
|
||||
/**
|
||||
@ -157,8 +151,7 @@ function Component(id) {
|
||||
EventEmitter.call(this);
|
||||
this.id = id;
|
||||
this.___state = null;
|
||||
this.___startNode = null;
|
||||
this.___endNode = null;
|
||||
this.___rootNode = null;
|
||||
this.___subscriptions = null;
|
||||
this.___domEventListenerHandles = null;
|
||||
this.___bubblingDomEvents = null; // Used to keep track of bubbling DOM events for components rendered on the server
|
||||
@ -230,9 +223,9 @@ Component.prototype = componentProto = {
|
||||
},
|
||||
getEl: function(key, index) {
|
||||
if (key) {
|
||||
return this.___keyedElements[resolveKeyHelper(key, index)];
|
||||
return this.___keyedElements["@" + resolveKeyHelper(key, index)];
|
||||
} else {
|
||||
return this.___startNode;
|
||||
return this.___rootNode && this.___rootNode.firstChild;
|
||||
}
|
||||
},
|
||||
getEls: function(key) {
|
||||
@ -248,29 +241,33 @@ Component.prototype = componentProto = {
|
||||
return els;
|
||||
},
|
||||
getComponent: function(key, index) {
|
||||
return componentLookup[resolveComponentIdHelper(this, key, index)];
|
||||
var rootNode = this.___keyedElements[resolveKeyHelper(key, index)];
|
||||
if (/\[\]$/.test(key)) {
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
if ("MARKO_DEBUG") {
|
||||
complain(
|
||||
"A repeated key[] was passed to getComponent. Use a non-repeating key if there is only one of these components."
|
||||
);
|
||||
}
|
||||
rootNode = rootNode && rootNode[Object.keys(rootNode)[0]];
|
||||
}
|
||||
return rootNode && rootNode.___markoComponent;
|
||||
},
|
||||
getComponents: function(key) {
|
||||
key = key + "[]";
|
||||
|
||||
var components = [];
|
||||
var i = 0;
|
||||
var component;
|
||||
while (
|
||||
(component =
|
||||
componentLookup[resolveComponentIdHelper(this, key, i)])
|
||||
) {
|
||||
components.push(component);
|
||||
i++;
|
||||
}
|
||||
return components;
|
||||
var lookup = this.___keyedElements[key + "[]"];
|
||||
return lookup
|
||||
? Object.keys(lookup).map(function(key) {
|
||||
return lookup[key].___markoComponent;
|
||||
})
|
||||
: [];
|
||||
},
|
||||
destroy: function() {
|
||||
if (this.___destroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
var nodes = getNodes(this);
|
||||
var root = this.___rootNode;
|
||||
var nodes = this.___rootNode.nodes;
|
||||
|
||||
this.___destroyShallow();
|
||||
|
||||
@ -282,6 +279,8 @@ Component.prototype = componentProto = {
|
||||
}
|
||||
});
|
||||
|
||||
root.detached = true;
|
||||
|
||||
delete componentLookup[this.id];
|
||||
},
|
||||
|
||||
@ -293,9 +292,9 @@ Component.prototype = componentProto = {
|
||||
emitLifecycleEvent(this, "destroy");
|
||||
this.___destroyed = true;
|
||||
|
||||
this.___startNode.___markoComponent = undefined;
|
||||
this.___rootNode.___markoComponent = undefined;
|
||||
|
||||
this.___startNode = this.___endNode = null;
|
||||
this.___rootNode = null;
|
||||
|
||||
// Unsubscribe from all DOM events
|
||||
this.___removeDOMEventListeners();
|
||||
@ -492,8 +491,7 @@ Component.prototype = componentProto = {
|
||||
throw TypeError();
|
||||
}
|
||||
|
||||
var startNode = this.___startNode;
|
||||
var endNodeNextSibling = this.___endNode.nextSibling;
|
||||
var rootNode = this.___rootNode;
|
||||
|
||||
var doc = self.___document;
|
||||
var input = this.___renderInput || this.___input;
|
||||
@ -514,16 +512,9 @@ Component.prototype = componentProto = {
|
||||
|
||||
var result = new RenderResult(out);
|
||||
|
||||
var targetNode = out.___getOutput();
|
||||
var targetNode = out.___getOutput().___firstChild;
|
||||
|
||||
morphdom(
|
||||
startNode.parentNode,
|
||||
startNode,
|
||||
endNodeNextSibling,
|
||||
targetNode,
|
||||
doc,
|
||||
componentsContext
|
||||
);
|
||||
morphdom(rootNode, targetNode, doc, componentsContext);
|
||||
|
||||
result.afterInsert(doc);
|
||||
});
|
||||
@ -532,23 +523,9 @@ Component.prototype = componentProto = {
|
||||
},
|
||||
|
||||
___detach: function() {
|
||||
var fragment = this.___document.createDocumentFragment();
|
||||
this.___forEachNode(fragment.appendChild.bind(fragment));
|
||||
return fragment;
|
||||
},
|
||||
|
||||
___forEachNode: function(callback) {
|
||||
var currentNode = this.___startNode;
|
||||
var endNode = this.___endNode;
|
||||
|
||||
for (;;) {
|
||||
var nextSibling = currentNode.nextSibling;
|
||||
callback(currentNode);
|
||||
if (currentNode == endNode) {
|
||||
break;
|
||||
}
|
||||
currentNode = nextSibling;
|
||||
}
|
||||
var root = this.___rootNode;
|
||||
root.remove();
|
||||
return root;
|
||||
},
|
||||
|
||||
___removeDOMEventListeners: function() {
|
||||
@ -589,12 +566,7 @@ Component.prototype = componentProto = {
|
||||
'The "this.el" attribute is deprecated. Please use "this.getEl(key)" instead.'
|
||||
);
|
||||
}
|
||||
var el = this.___startNode;
|
||||
while (el) {
|
||||
if (el.nodeType === ELEMENT_NODE) return el;
|
||||
if (el === this.___endNode) return;
|
||||
el = el.nextSibling;
|
||||
}
|
||||
return this.___rootNode && this.___rootNode.firstChild;
|
||||
},
|
||||
|
||||
get els() {
|
||||
@ -604,7 +576,9 @@ Component.prototype = componentProto = {
|
||||
'The "this.els" attribute is deprecated. Please use "this.getEls(key)" instead.'
|
||||
);
|
||||
}
|
||||
return getNodes(this).filter(function(el) {
|
||||
return (this.___rootNode ? this.___rootNode.nodes : []).filter(function(
|
||||
el
|
||||
) {
|
||||
return el.nodeType === ELEMENT_NODE;
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
var ComponentDef = require("./ComponentDef");
|
||||
|
||||
module.exports = function beginComponent(componentsContext, component) {
|
||||
module.exports = function beginComponent(
|
||||
componentsContext,
|
||||
component,
|
||||
key,
|
||||
ownerComponentDef
|
||||
) {
|
||||
var componentId = component.id;
|
||||
|
||||
var globalContext = componentsContext.___globalContext;
|
||||
@ -13,6 +18,6 @@ module.exports = function beginComponent(componentsContext, component) {
|
||||
componentsContext.___components.push(componentDef);
|
||||
|
||||
var out = componentsContext.___out;
|
||||
out.bc(component);
|
||||
out.bc(component, key, ownerComponentDef && ownerComponentDef.___component);
|
||||
return componentDef;
|
||||
};
|
||||
|
||||
@ -9,8 +9,9 @@ var FLAG_WILL_RERENDER_IN_BROWSER = 1;
|
||||
module.exports = function beginComponent(
|
||||
componentsContext,
|
||||
component,
|
||||
key,
|
||||
ownerComponentDef,
|
||||
isSplitComponent,
|
||||
parentComponentDef,
|
||||
isImplicitComponent
|
||||
) {
|
||||
var globalContext = componentsContext.___globalContext;
|
||||
@ -25,8 +26,8 @@ module.exports = function beginComponent(
|
||||
|
||||
// On the server
|
||||
if (
|
||||
parentComponentDef &&
|
||||
parentComponentDef.___flags & FLAG_WILL_RERENDER_IN_BROWSER
|
||||
ownerComponentDef &&
|
||||
ownerComponentDef.___flags & FLAG_WILL_RERENDER_IN_BROWSER
|
||||
) {
|
||||
componentDef.___flags |= FLAG_WILL_RERENDER_IN_BROWSER;
|
||||
return componentDef;
|
||||
@ -47,9 +48,20 @@ module.exports = function beginComponent(
|
||||
|
||||
if (isSplitComponent === false && out.global.noBrowserRerender !== true) {
|
||||
componentDef.___flags |= FLAG_WILL_RERENDER_IN_BROWSER;
|
||||
out.w("<!--M#" + componentId + "-->");
|
||||
}
|
||||
|
||||
if (ownerComponentDef && key != null) {
|
||||
out.w(
|
||||
"<!--M^" +
|
||||
componentId +
|
||||
" " +
|
||||
ownerComponentDef.id +
|
||||
" " +
|
||||
key +
|
||||
"-->"
|
||||
);
|
||||
} else {
|
||||
out.w("<!--M^" + componentId + "-->");
|
||||
out.w("<!--M#" + componentId + "-->");
|
||||
}
|
||||
|
||||
return componentDef;
|
||||
|
||||
@ -2,6 +2,6 @@
|
||||
|
||||
module.exports = function endComponent(out, componentDef) {
|
||||
if (componentDef.___renderBoundary) {
|
||||
out.w("<!--M/" + componentDef.id + "-->");
|
||||
out.w("<!--M/-->");
|
||||
}
|
||||
};
|
||||
|
||||
@ -3,36 +3,82 @@ var warp10Finalize = require("warp10/finalize");
|
||||
var eventDelegation = require("./event-delegation");
|
||||
var win = window;
|
||||
var defaultDocument = document;
|
||||
var createFragmentNode = require("../morphdom/fragment").___createFragmentNode;
|
||||
var componentsUtil = require("./util");
|
||||
var componentLookup = componentsUtil.___componentLookup;
|
||||
var addComponentRootToKeyedElements =
|
||||
componentsUtil.___addComponentRootToKeyedElements;
|
||||
var ComponentDef = require("./ComponentDef");
|
||||
var registry = require("./registry");
|
||||
var serverRenderedGlobals = {};
|
||||
var serverComponentStartNodes = {};
|
||||
var serverComponentEndNodes = {};
|
||||
var serverComponentRootNodes = {};
|
||||
var keyedElementsByComponentId = {};
|
||||
|
||||
var FLAG_WILL_RERENDER_IN_BROWSER = 1;
|
||||
var FLAG_HAS_BODY_EL = 2;
|
||||
var FLAG_HAS_HEAD_EL = 4;
|
||||
|
||||
function indexServerComponentBoundaries(node) {
|
||||
function indexServerComponentBoundaries(node, stack) {
|
||||
var componentId;
|
||||
var ownerId;
|
||||
var ownerComponent;
|
||||
var keyedElements;
|
||||
var nextSibling;
|
||||
stack = stack || [];
|
||||
|
||||
node = node.firstChild;
|
||||
while (node) {
|
||||
nextSibling = node.nextSibling;
|
||||
if (node.nodeType === 8) {
|
||||
// Comment node
|
||||
var commentValue = node.nodeValue;
|
||||
if (commentValue[0] === "M") {
|
||||
componentId = commentValue.substring(2);
|
||||
|
||||
var firstChar = commentValue[1];
|
||||
|
||||
if (firstChar === "/") {
|
||||
serverComponentEndNodes[componentId] = node;
|
||||
} else if (firstChar === "^" || firstChar === "#") {
|
||||
serverComponentStartNodes[componentId] = node;
|
||||
if (firstChar === "^" || firstChar === "#") {
|
||||
stack.push(node);
|
||||
} else if (firstChar === "/") {
|
||||
var endNode = node;
|
||||
var startNode = stack.pop();
|
||||
var rootNode;
|
||||
|
||||
if (startNode.parentNode === endNode.parentNode) {
|
||||
rootNode = createFragmentNode(
|
||||
startNode.nextSibling,
|
||||
endNode
|
||||
);
|
||||
} else {
|
||||
rootNode = createFragmentNode(
|
||||
endNode.parentNode.firstChild,
|
||||
endNode
|
||||
);
|
||||
}
|
||||
|
||||
componentId = startNode.nodeValue.substring(2);
|
||||
firstChar = startNode.nodeValue[1];
|
||||
|
||||
if (firstChar === "^") {
|
||||
var parts = componentId.split(/ /g);
|
||||
var key = parts[2];
|
||||
ownerId = parts[1];
|
||||
componentId = parts[0];
|
||||
if ((ownerComponent = componentLookup[ownerId])) {
|
||||
keyedElements = ownerComponent.___keyedElements;
|
||||
} else {
|
||||
keyedElements =
|
||||
keyedElementsByComponentId[ownerId] ||
|
||||
(keyedElementsByComponentId[ownerId] = {});
|
||||
}
|
||||
addComponentRootToKeyedElements(
|
||||
keyedElements,
|
||||
key,
|
||||
rootNode,
|
||||
componentId
|
||||
);
|
||||
}
|
||||
|
||||
serverComponentRootNodes[componentId] = rootNode;
|
||||
|
||||
startNode.parentNode.removeChild(startNode);
|
||||
endNode.parentNode.removeChild(endNode);
|
||||
}
|
||||
}
|
||||
} else if (node.nodeType === 1) {
|
||||
@ -41,11 +87,15 @@ function indexServerComponentBoundaries(node) {
|
||||
var markoProps = node.getAttribute("data-marko");
|
||||
if (markoKey) {
|
||||
var separatorIndex = markoKey.indexOf(" ");
|
||||
componentId = markoKey.substring(separatorIndex + 1);
|
||||
ownerId = markoKey.substring(separatorIndex + 1);
|
||||
markoKey = markoKey.substring(0, separatorIndex);
|
||||
var keyedElements =
|
||||
keyedElementsByComponentId[componentId] ||
|
||||
(keyedElementsByComponentId[componentId] = {});
|
||||
if ((ownerComponent = componentLookup[ownerId])) {
|
||||
keyedElements = ownerComponent.___keyedElements;
|
||||
} else {
|
||||
keyedElements =
|
||||
keyedElementsByComponentId[ownerId] ||
|
||||
(keyedElementsByComponentId[ownerId] = {});
|
||||
}
|
||||
keyedElements[markoKey] = node;
|
||||
}
|
||||
if (markoProps) {
|
||||
@ -58,10 +108,10 @@ function indexServerComponentBoundaries(node) {
|
||||
}
|
||||
});
|
||||
}
|
||||
indexServerComponentBoundaries(node);
|
||||
indexServerComponentBoundaries(node, stack);
|
||||
}
|
||||
|
||||
node = node.nextSibling;
|
||||
node = nextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
@ -238,68 +288,39 @@ function initServerRendered(renderedComponents, doc) {
|
||||
serverRenderedGlobals,
|
||||
registry
|
||||
);
|
||||
var componentId = componentDef.id;
|
||||
var component = componentDef.___component;
|
||||
|
||||
var startNode;
|
||||
var endNode;
|
||||
var flags = componentDef.___flags;
|
||||
if ((flags & 6) === 6) {
|
||||
startNode = document.head;
|
||||
endNode = document.body;
|
||||
} else if (flags & FLAG_HAS_BODY_EL) {
|
||||
startNode = endNode = document.body;
|
||||
} else if (flags & FLAG_HAS_HEAD_EL) {
|
||||
startNode = endNode = document.head;
|
||||
} else {
|
||||
var startNodeComment = serverComponentStartNodes[componentId];
|
||||
var endNodeComment = serverComponentEndNodes[componentId];
|
||||
|
||||
startNode = startNodeComment.nextSibling;
|
||||
|
||||
if (startNode === endNodeComment) {
|
||||
// Component has no output nodes so just mount to the start comment node
|
||||
// and we will remove the end comment node
|
||||
startNode = endNode = startNodeComment;
|
||||
} else {
|
||||
delete serverComponentStartNodes[componentId];
|
||||
startNodeComment.parentNode.removeChild(startNodeComment);
|
||||
|
||||
if (startNode.parentNode === document) {
|
||||
endNode = startNode = document.documentElement;
|
||||
} else {
|
||||
// Remove the start and end comment nodes and use the inner nodes
|
||||
// as the boundary
|
||||
endNode = endNodeComment.previousSibling;
|
||||
if (!hydrateComponent(componentDef, doc)) {
|
||||
// hydrateComponent will return false if there is not rootNode
|
||||
// for the component. If this is the case, we'll wait until the
|
||||
// DOM has fully loaded to attempt to init the component again.
|
||||
doc.addEventListener("DOMContentLoaded", function() {
|
||||
if (!hydrateComponent(componentDef, doc)) {
|
||||
indexServerComponentBoundaries(doc);
|
||||
hydrateComponent(componentDef, doc);
|
||||
}
|
||||
}
|
||||
|
||||
if (endNodeComment) {
|
||||
delete serverComponentEndNodes[componentId];
|
||||
endNodeComment.parentNode.removeChild(endNodeComment);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function hydrateComponent(componentDef, doc) {
|
||||
var componentId = componentDef.id;
|
||||
var component = componentDef.___component;
|
||||
var rootNode = serverComponentRootNodes[componentId];
|
||||
|
||||
if (rootNode) {
|
||||
delete serverComponentRootNodes[componentId];
|
||||
|
||||
component.___rootNode = rootNode;
|
||||
rootNode.___markoComponent = component;
|
||||
component.___keyedElements =
|
||||
keyedElementsByComponentId[componentId] || {};
|
||||
component.___startNode = startNode;
|
||||
component.___endNode = endNode;
|
||||
|
||||
startNode.___markoComponent = component;
|
||||
|
||||
delete keyedElementsByComponentId[componentId];
|
||||
|
||||
// Mark the start node so that we know we need to skip past this
|
||||
// node when matching up children
|
||||
startNode.___startNode = true;
|
||||
|
||||
// Mark the end node so that when we attempt to find boundaries
|
||||
// for nested UI components we don't accidentally go outside the boundary
|
||||
// of the parent component
|
||||
endNode.___endNode = true;
|
||||
|
||||
initComponent(componentDef, doc || defaultDocument);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
exports.___initClientRendered = initClientRendered;
|
||||
|
||||
@ -50,34 +50,24 @@ function createRendererFunc(templateRenderFunc, componentProps) {
|
||||
var isRerender = component !== undefined;
|
||||
var id = assignedId;
|
||||
var isExisting;
|
||||
var customEvents;
|
||||
var scope;
|
||||
var parentComponentDef;
|
||||
var ownerComponentDef = out.___assignedComponentDef;
|
||||
var ownerComponentId = ownerComponentDef && ownerComponentDef.id;
|
||||
var key = out.___assignedKey;
|
||||
var customEvents = out.___assignedCustomEvents;
|
||||
|
||||
if (component) {
|
||||
id = component.id;
|
||||
isExisting = true;
|
||||
globalComponentsContext.___rerenderComponent = null;
|
||||
} else {
|
||||
parentComponentDef = componentsContext.___componentDef;
|
||||
var componentDefFromArgs;
|
||||
if ((componentDefFromArgs = out.___assignedComponentDef)) {
|
||||
scope = componentDefFromArgs.id;
|
||||
if ((parentComponentDef = componentsContext.___componentDef)) {
|
||||
out.___assignedComponentDef = null;
|
||||
|
||||
customEvents = out.___assignedCustomEvents;
|
||||
var key = out.___assignedKey;
|
||||
|
||||
if (key != null) {
|
||||
key = key.toString();
|
||||
}
|
||||
id =
|
||||
id ||
|
||||
resolveComponentKey(
|
||||
globalComponentsContext,
|
||||
key,
|
||||
componentDefFromArgs
|
||||
);
|
||||
id = id || resolveComponentKey(key, parentComponentDef);
|
||||
} else if (parentComponentDef) {
|
||||
id = parentComponentDef.___nextComponentId();
|
||||
} else {
|
||||
@ -94,7 +84,7 @@ function createRendererFunc(templateRenderFunc, componentProps) {
|
||||
out,
|
||||
typeName,
|
||||
customEvents,
|
||||
scope
|
||||
ownerComponentId
|
||||
);
|
||||
} else {
|
||||
if (!component) {
|
||||
@ -185,8 +175,9 @@ function createRendererFunc(templateRenderFunc, componentProps) {
|
||||
var componentDef = beginComponent(
|
||||
componentsContext,
|
||||
component,
|
||||
isSplit,
|
||||
parentComponentDef
|
||||
key,
|
||||
ownerComponentDef,
|
||||
isSplit
|
||||
);
|
||||
|
||||
// This is a hack, but we have to swap out the component instance stored with this node
|
||||
@ -227,11 +218,11 @@ function createRendererFunc(templateRenderFunc, componentProps) {
|
||||
if (customEvents && componentDef.___component) {
|
||||
if (registry.___isServer) {
|
||||
componentDef.___customEvents = customEvents;
|
||||
componentDef.___scope = scope;
|
||||
componentDef.___scope = ownerComponentId;
|
||||
} else {
|
||||
componentDef.___component.___setCustomEvents(
|
||||
customEvents,
|
||||
scope
|
||||
ownerComponentId
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,17 +12,11 @@ var endComponent = require("./endComponent");
|
||||
|
||||
var COMPONENT_BEGIN_ASYNC_ADDED_KEY = "$wa";
|
||||
|
||||
function resolveComponentKey(
|
||||
globalComponentsContext,
|
||||
key,
|
||||
ownerComponentDef,
|
||||
parentComponentDef
|
||||
) {
|
||||
function resolveComponentKey(key, parentComponentDef) {
|
||||
if (key[0] === "#") {
|
||||
return key.substring(1);
|
||||
} else {
|
||||
parentComponentDef = parentComponentDef || ownerComponentDef;
|
||||
return parentComponentDef.___nextKey(ownerComponentDef.id + "-" + key);
|
||||
return parentComponentDef.id + "-" + parentComponentDef.___nextKey(key);
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,9 +71,10 @@ function createRendererFunc(
|
||||
var id;
|
||||
var isExisting;
|
||||
var customEvents;
|
||||
var scope;
|
||||
var parentComponentDef = componentsContext.___componentDef;
|
||||
var ownerComponentDef = out.___assignedComponentDef;
|
||||
var ownerComponentId = ownerComponentDef && ownerComponentDef.id;
|
||||
var key = out.___assignedKey;
|
||||
|
||||
if (component) {
|
||||
// If component is provided then we are currently rendering
|
||||
@ -93,23 +88,17 @@ function createRendererFunc(
|
||||
// DOM (if any) so we will need to resolve the component ID from
|
||||
// the assigned key. We also need to handle any custom event bindings
|
||||
// that were provided.
|
||||
if (ownerComponentDef) {
|
||||
if (parentComponentDef) {
|
||||
// console.log('componentArgs:', componentArgs);
|
||||
scope = ownerComponentDef.id;
|
||||
out.___assignedComponentDef = null;
|
||||
|
||||
customEvents = out.___assignedCustomEvents;
|
||||
var key = out.___assignedKey;
|
||||
|
||||
if (key != null) {
|
||||
id = resolveComponentKey(
|
||||
globalComponentsContext,
|
||||
key.toString(),
|
||||
ownerComponentDef,
|
||||
parentComponentDef
|
||||
);
|
||||
} else {
|
||||
id = ownerComponentDef.___nextComponentId();
|
||||
id = parentComponentDef.___nextComponentId();
|
||||
}
|
||||
} else {
|
||||
id = globalComponentsContext.___nextComponentId();
|
||||
@ -128,7 +117,7 @@ function createRendererFunc(
|
||||
out,
|
||||
typeName,
|
||||
customEvents,
|
||||
scope
|
||||
ownerComponentId
|
||||
);
|
||||
|
||||
// This is the final input after running the lifecycle methods.
|
||||
@ -176,7 +165,10 @@ function createRendererFunc(
|
||||
component.___updateQueued = true;
|
||||
|
||||
if (customEvents !== undefined) {
|
||||
component.___setCustomEvents(customEvents, scope);
|
||||
component.___setCustomEvents(
|
||||
customEvents,
|
||||
ownerComponentId
|
||||
);
|
||||
}
|
||||
|
||||
if (isExisting === false) {
|
||||
@ -212,8 +204,9 @@ function createRendererFunc(
|
||||
var componentDef = beginComponent(
|
||||
componentsContext,
|
||||
component,
|
||||
isSplit,
|
||||
key,
|
||||
ownerComponentDef,
|
||||
isSplit,
|
||||
isImplicitComponent
|
||||
);
|
||||
|
||||
|
||||
@ -88,7 +88,6 @@ module.exports = function assignComponentId(isRepeated) {
|
||||
true /* user assigned key */
|
||||
);
|
||||
} else {
|
||||
idExpression = assignedKey;
|
||||
if (el.data.userAssignedKey !== false) {
|
||||
if (
|
||||
context.data.hasLegacyForKey ||
|
||||
@ -101,7 +100,18 @@ module.exports = function assignComponentId(isRepeated) {
|
||||
}
|
||||
}
|
||||
|
||||
el.setKey(assignedKey);
|
||||
// mark as user-assigned key (@)
|
||||
if (assignedKey.type === "Literal") {
|
||||
idExpression = builder.literal("@" + assignedKey.value);
|
||||
} else {
|
||||
idExpression = builder.binaryExpression(
|
||||
builder.literal("@"),
|
||||
"+",
|
||||
assignedKey
|
||||
);
|
||||
}
|
||||
|
||||
el.setKey(idExpression);
|
||||
this.serializeKey();
|
||||
}
|
||||
} else {
|
||||
@ -109,6 +119,8 @@ module.exports = function assignComponentId(isRepeated) {
|
||||
let parentForKey = getParentForKeyVar(el, this);
|
||||
let uniqueKey = this.nextUniqueId();
|
||||
|
||||
el.isAutoKeyed = true;
|
||||
|
||||
nestedIdExpression = isRepeated
|
||||
? builder.literal(uniqueKey + "[]")
|
||||
: builder.literal(uniqueKey.toString());
|
||||
|
||||
@ -1,10 +1,6 @@
|
||||
"use strict";
|
||||
const generateRegisterComponentCode = require("../util/generateRegisterComponentCode");
|
||||
|
||||
// var FLAG_WILL_RERENDER_IN_BROWSER = 1;
|
||||
var FLAG_HAS_BODY_EL = 2;
|
||||
var FLAG_HAS_HEAD_EL = 4;
|
||||
|
||||
module.exports = function handleComponentBind(options) {
|
||||
let context = this.context;
|
||||
let builder = this.builder;
|
||||
@ -87,31 +83,6 @@ module.exports = function handleComponentBind(options) {
|
||||
return;
|
||||
}
|
||||
|
||||
var flags = 0;
|
||||
|
||||
rootNodes.forEach(rootNode => {
|
||||
if (rootNode.type === "HtmlElement") {
|
||||
if (rootNode.tagName === "body") {
|
||||
flags |= FLAG_HAS_BODY_EL;
|
||||
} else if (rootNode.tagName === "head") {
|
||||
flags |= FLAG_HAS_HEAD_EL;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (flags) {
|
||||
context.root.appendChild(
|
||||
builder.assignment(
|
||||
builder.memberExpression(
|
||||
builder.identifier("__component"),
|
||||
builder.identifier("___flags")
|
||||
),
|
||||
builder.literal(flags),
|
||||
"|="
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
let markoComponentVar;
|
||||
|
||||
if (rendererModule) {
|
||||
|
||||
@ -6,6 +6,14 @@ var componentLookup = {};
|
||||
var defaultDocument = document;
|
||||
var EMPTY_OBJECT = {};
|
||||
|
||||
function getParentComponentForEl(node) {
|
||||
while (node && !node.___markoComponent) {
|
||||
node = node.previousSibling || node.parentNode;
|
||||
node = (node && node.fragment) || node;
|
||||
}
|
||||
return node && node.___markoComponent;
|
||||
}
|
||||
|
||||
function getComponentForEl(el, doc) {
|
||||
if (el) {
|
||||
var node =
|
||||
@ -13,7 +21,7 @@ function getComponentForEl(el, doc) {
|
||||
? (doc || defaultDocument).getElementById(el)
|
||||
: el;
|
||||
if (node) {
|
||||
return node.___markoComponent;
|
||||
return getParentComponentForEl(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -50,7 +58,7 @@ function emitLifecycleEvent(component, eventType, eventArg1, eventArg2) {
|
||||
}
|
||||
|
||||
function destroyComponentForNode(node) {
|
||||
var componentToDestroy = node.___markoComponent;
|
||||
var componentToDestroy = (node.fragment || node).___markoComponent;
|
||||
if (componentToDestroy) {
|
||||
componentToDestroy.___destroyShallow();
|
||||
delete componentLookup[componentToDestroy.id];
|
||||
@ -58,17 +66,23 @@ function destroyComponentForNode(node) {
|
||||
}
|
||||
function destroyNodeRecursive(node, component) {
|
||||
destroyComponentForNode(node);
|
||||
if (node.nodeType === 1) {
|
||||
if (node.nodeType === 1 || node.nodeType === 12) {
|
||||
var key;
|
||||
|
||||
if (component && (key = node.___markoKey)) {
|
||||
if (node === component.___keyedElements[key]) {
|
||||
delete component.___keyedElements[key];
|
||||
if (node.___markoComponent && /\[\]$/.test(key)) {
|
||||
delete component.___keyedElements[key][
|
||||
node.___markoComponent.id
|
||||
];
|
||||
} else {
|
||||
delete component.___keyedElements[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var curChild = node.firstChild;
|
||||
while (curChild) {
|
||||
while (curChild && curChild !== node.endNode) {
|
||||
destroyNodeRecursive(curChild, component);
|
||||
curChild = curChild.nextSibling;
|
||||
}
|
||||
@ -122,6 +136,28 @@ function getMarkoPropsFromEl(el) {
|
||||
return virtualProps;
|
||||
}
|
||||
|
||||
function normalizeComponentKey(key, parentId) {
|
||||
if (key[0] === "#") {
|
||||
key = key.replace("#" + parentId + "-", "");
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
function addComponentRootToKeyedElements(
|
||||
keyedElements,
|
||||
key,
|
||||
rootNode,
|
||||
componentId
|
||||
) {
|
||||
if (/\[\]$/.test(key)) {
|
||||
var repeatedElementsForKey = (keyedElements[key] =
|
||||
keyedElements[key] || {});
|
||||
repeatedElementsForKey[componentId] = rootNode;
|
||||
} else {
|
||||
keyedElements[key] = rootNode;
|
||||
}
|
||||
}
|
||||
|
||||
exports.___runtimeId = runtimeId;
|
||||
exports.___componentLookup = componentLookup;
|
||||
exports.___getComponentForEl = getComponentForEl;
|
||||
@ -131,3 +167,5 @@ exports.___destroyNodeRecursive = destroyNodeRecursive;
|
||||
exports.___nextComponentIdProvider = nextComponentIdProvider;
|
||||
exports.___attachBubblingEvent = attachBubblingEvent;
|
||||
exports.___getMarkoPropsFromEl = getMarkoPropsFromEl;
|
||||
exports.___addComponentRootToKeyedElements = addComponentRootToKeyedElements;
|
||||
exports.___normalizeComponentKey = normalizeComponentKey;
|
||||
|
||||
81
src/morphdom/fragment.js
Normal file
81
src/morphdom/fragment.js
Normal file
@ -0,0 +1,81 @@
|
||||
var helpers = require("./helpers");
|
||||
var insertBefore = helpers.___insertBefore;
|
||||
|
||||
var fragmentPrototype = {
|
||||
nodeType: 12,
|
||||
get firstChild() {
|
||||
let firstChild = this.startNode.nextSibling;
|
||||
return firstChild === this.endNode ? undefined : firstChild;
|
||||
},
|
||||
get lastChild() {
|
||||
let lastChild = this.endNode.previousSibling;
|
||||
return lastChild === this.startNode ? undefined : lastChild;
|
||||
},
|
||||
get parentNode() {
|
||||
let parentNode = this.startNode.parentNode;
|
||||
return parentNode === this.detachedContainer ? undefined : parentNode;
|
||||
},
|
||||
get nextSibling() {
|
||||
return this.endNode.nextSibling;
|
||||
},
|
||||
get nodes() {
|
||||
const nodes = [];
|
||||
let current = this.startNode;
|
||||
while (current !== this.endNode) {
|
||||
nodes.push(current);
|
||||
current = current.nextSibling;
|
||||
}
|
||||
nodes.push(current);
|
||||
return nodes;
|
||||
},
|
||||
insertBefore(newChildNode, referenceNode) {
|
||||
const actualReference =
|
||||
referenceNode == null ? this.endNode : referenceNode;
|
||||
return insertBefore(
|
||||
newChildNode,
|
||||
actualReference,
|
||||
this.startNode.parentNode
|
||||
);
|
||||
},
|
||||
insertInto(newParentNode, referenceNode) {
|
||||
this.nodes.forEach(function(node) {
|
||||
insertBefore(node, referenceNode, newParentNode);
|
||||
});
|
||||
return this;
|
||||
},
|
||||
remove() {
|
||||
this.nodes.forEach(function(node) {
|
||||
this.detachedContainer.appendChild(node);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function createFragmentNode(startNode, nextNode, parentNode) {
|
||||
var fragment = Object.create(fragmentPrototype);
|
||||
fragment.startNode = document.createTextNode("");
|
||||
fragment.endNode = document.createTextNode("");
|
||||
fragment.startNode.fragment = fragment;
|
||||
fragment.endNode.fragment = fragment;
|
||||
var detachedContainer = (fragment.detachedContainer = document.createDocumentFragment());
|
||||
parentNode =
|
||||
parentNode || (startNode && startNode.parentNode) || detachedContainer;
|
||||
insertBefore(fragment.startNode, startNode, parentNode);
|
||||
insertBefore(fragment.endNode, nextNode, parentNode);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
function beginFragmentNode(startNode, parentNode) {
|
||||
var fragment = createFragmentNode(startNode, null, parentNode);
|
||||
fragment.___finishFragment = function(nextNode) {
|
||||
fragment.___finishFragment = null;
|
||||
insertBefore(
|
||||
fragment.endNode,
|
||||
nextNode,
|
||||
parentNode || startNode.parentNode
|
||||
);
|
||||
};
|
||||
return fragment;
|
||||
}
|
||||
|
||||
exports.___createFragmentNode = createFragmentNode;
|
||||
exports.___beginFragmentNode = beginFragmentNode;
|
||||
42
src/morphdom/helpers.js
Normal file
42
src/morphdom/helpers.js
Normal file
@ -0,0 +1,42 @@
|
||||
function insertBefore(node, referenceNode, parentNode) {
|
||||
if (node.insertInto) {
|
||||
return node.insertInto(parentNode, referenceNode);
|
||||
}
|
||||
return parentNode.insertBefore(
|
||||
node,
|
||||
(referenceNode && referenceNode.startNode) || referenceNode
|
||||
);
|
||||
}
|
||||
|
||||
function insertAfter(node, referenceNode, parentNode) {
|
||||
return insertBefore(
|
||||
node,
|
||||
referenceNode && referenceNode.nextSibling,
|
||||
parentNode
|
||||
);
|
||||
}
|
||||
|
||||
function nextSibling(node) {
|
||||
var next = node.nextSibling;
|
||||
var fragment = next && next.fragment;
|
||||
if (fragment) {
|
||||
return next === fragment.startNode ? fragment : null;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
function firstChild(node) {
|
||||
var next = node.firstChild;
|
||||
return (next && next.fragment) || next;
|
||||
}
|
||||
|
||||
function removeChild(node) {
|
||||
if (node.remove) node.remove();
|
||||
else node.parentNode.removeChild(node);
|
||||
}
|
||||
|
||||
exports.___insertBefore = insertBefore;
|
||||
exports.___insertAfter = insertAfter;
|
||||
exports.___nextSibling = nextSibling;
|
||||
exports.___firstChild = firstChild;
|
||||
exports.___removeChild = removeChild;
|
||||
@ -3,15 +3,29 @@ var specialElHandlers = require("./specialElHandlers");
|
||||
var componentsUtil = require("../components/util");
|
||||
var existingComponentLookup = componentsUtil.___componentLookup;
|
||||
var destroyNodeRecursive = componentsUtil.___destroyNodeRecursive;
|
||||
var addComponentRootToKeyedElements =
|
||||
componentsUtil.___addComponentRootToKeyedElements;
|
||||
var normalizeComponentKey = componentsUtil.___normalizeComponentKey;
|
||||
var VElement = require("../runtime/vdom/vdom").___VElement;
|
||||
var virtualizeElement = VElement.___virtualize;
|
||||
var morphAttrs = VElement.___morphAttrs;
|
||||
var eventDelegation = require("../components/event-delegation");
|
||||
var fragment = require("./fragment");
|
||||
var helpers = require("./helpers");
|
||||
|
||||
var insertBefore = helpers.___insertBefore;
|
||||
var insertAfter = helpers.___insertAfter;
|
||||
var nextSibling = helpers.___nextSibling;
|
||||
var firstChild = helpers.___firstChild;
|
||||
var removeChild = helpers.___removeChild;
|
||||
var createFragmentNode = fragment.___createFragmentNode;
|
||||
var beginFragmentNode = fragment.___beginFragmentNode;
|
||||
|
||||
var ELEMENT_NODE = 1;
|
||||
var TEXT_NODE = 3;
|
||||
var COMMENT_NODE = 8;
|
||||
var COMPONENT_NODE = 2;
|
||||
var FRAGMENT_NODE = 12;
|
||||
|
||||
// var FLAG_IS_SVG = 1;
|
||||
// var FLAG_IS_TEXTAREA = 2;
|
||||
@ -19,6 +33,10 @@ var COMPONENT_NODE = 2;
|
||||
var FLAG_PRESERVE = 8;
|
||||
// var FLAG_CUSTOM_ELEMENT = 16;
|
||||
|
||||
function isAutoKey(key) {
|
||||
return !/^@/.test(key);
|
||||
}
|
||||
|
||||
function compareNodeNames(fromEl, toEl) {
|
||||
return fromEl.___nodeName === toEl.___nodeName;
|
||||
}
|
||||
@ -29,54 +47,40 @@ function onNodeAdded(node, componentsContext) {
|
||||
}
|
||||
}
|
||||
|
||||
function insertBefore(node, referenceNode, parentNode) {
|
||||
return parentNode.insertBefore(node, referenceNode);
|
||||
}
|
||||
|
||||
function insertAfter(node, referenceNode, parentNode) {
|
||||
return parentNode.insertBefore(
|
||||
node,
|
||||
referenceNode && referenceNode.nextSibling
|
||||
);
|
||||
}
|
||||
|
||||
function morphdom(
|
||||
parentNode,
|
||||
startNode,
|
||||
endNode,
|
||||
toNode,
|
||||
doc,
|
||||
componentsContext
|
||||
) {
|
||||
function morphdom(fromNode, toNode, doc, componentsContext) {
|
||||
var globalComponentsContext;
|
||||
var isRerenderInBrowser = false;
|
||||
var keySequences = {};
|
||||
|
||||
if (componentsContext) {
|
||||
globalComponentsContext = componentsContext.___globalContext;
|
||||
isRerenderInBrowser = globalComponentsContext.___isRerenderInBrowser;
|
||||
}
|
||||
|
||||
function createMarkerComment() {
|
||||
return doc.createComment("$marko");
|
||||
}
|
||||
|
||||
function insertVirtualNodeBefore(
|
||||
vNode,
|
||||
key,
|
||||
referenceEl,
|
||||
parentEl,
|
||||
component
|
||||
ownerComponent,
|
||||
parentComponent
|
||||
) {
|
||||
var realNode = vNode.___actualize(doc);
|
||||
insertBefore(realNode, referenceEl, parentEl);
|
||||
|
||||
if (vNode.___nodeType === ELEMENT_NODE) {
|
||||
if (
|
||||
vNode.___nodeType === ELEMENT_NODE ||
|
||||
vNode.___nodeType === FRAGMENT_NODE
|
||||
) {
|
||||
if (key) {
|
||||
realNode.___markoKey = key;
|
||||
component.___keyedElements[key] = realNode;
|
||||
(isAutoKey(key)
|
||||
? parentComponent
|
||||
: ownerComponent
|
||||
).___keyedElements[key] = realNode;
|
||||
}
|
||||
|
||||
morphChildren(realNode, null, null, vNode, component);
|
||||
morphChildren(realNode, vNode, parentComponent);
|
||||
}
|
||||
|
||||
onNodeAdded(realNode, componentsContext);
|
||||
@ -86,144 +90,45 @@ function morphdom(
|
||||
vComponent,
|
||||
referenceNode,
|
||||
referenceNodeParentEl,
|
||||
component
|
||||
component,
|
||||
key,
|
||||
ownerComponent,
|
||||
parentComponent
|
||||
) {
|
||||
component.___startNode = component.___endNode = insertBefore(
|
||||
createMarkerComment(),
|
||||
var rootNode = (component.___rootNode = insertBefore(
|
||||
createFragmentNode(),
|
||||
referenceNode,
|
||||
referenceNodeParentEl
|
||||
);
|
||||
morphComponent(referenceNodeParentEl, component, vComponent);
|
||||
));
|
||||
rootNode.___markoComponent = component;
|
||||
|
||||
if (key && ownerComponent) {
|
||||
key = normalizeComponentKey(key, parentComponent.id);
|
||||
addComponentRootToKeyedElements(
|
||||
ownerComponent.___keyedElements,
|
||||
key,
|
||||
rootNode,
|
||||
component.id
|
||||
);
|
||||
rootNode.___markoKey = key;
|
||||
}
|
||||
|
||||
morphComponent(component, vComponent);
|
||||
}
|
||||
|
||||
function resolveComponentEndNode(startNode, vChild, parentNode) {
|
||||
var endNode = startNode;
|
||||
|
||||
// We track text nodes because multiple adjacent VText nodes should
|
||||
// be treated as a single VText node for purposes of pairing with HTML
|
||||
// that was rendered on the server since browsers will only see
|
||||
// a single text node
|
||||
var isPrevText = vChild.___nodeType === TEXT_NODE;
|
||||
|
||||
while ((vChild = vChild.___nextSibling)) {
|
||||
var nextRealNode = endNode.nextSibling;
|
||||
|
||||
// We stop when there are no more corresponding real nodes or when
|
||||
// we reach the end boundary for our UI component
|
||||
if (!nextRealNode || nextRealNode.___endNode) {
|
||||
break;
|
||||
}
|
||||
var isText = vChild.___nodeType === TEXT_NODE;
|
||||
if (isText && isPrevText) {
|
||||
// Pretend like we didn't see this VText node since it
|
||||
// the previous vnode was also a VText node
|
||||
continue;
|
||||
}
|
||||
endNode = nextRealNode;
|
||||
isPrevText = isText;
|
||||
}
|
||||
|
||||
if (endNode === startNode) {
|
||||
return insertAfter(createMarkerComment(), startNode, parentNode);
|
||||
}
|
||||
|
||||
return endNode;
|
||||
}
|
||||
|
||||
function morphComponent(parentFromNode, component, vComponent) {
|
||||
// We create a key sequence to generate unique keys since a key
|
||||
// can be repeated
|
||||
component.___keySequence = globalComponentsContext.___createKeySequence();
|
||||
|
||||
var startNode = component.___startNode;
|
||||
var endNode = component.___endNode;
|
||||
startNode.___markoComponent = undefined;
|
||||
endNode.___endNode = undefined;
|
||||
|
||||
var beforeChild = startNode.previousSibling;
|
||||
var afterChild = endNode.nextSibling;
|
||||
var tempChild;
|
||||
|
||||
if (!beforeChild) {
|
||||
tempChild = beforeChild = insertBefore(
|
||||
createMarkerComment(),
|
||||
startNode,
|
||||
parentFromNode
|
||||
);
|
||||
}
|
||||
|
||||
morphChildren(
|
||||
parentFromNode,
|
||||
startNode,
|
||||
afterChild,
|
||||
vComponent,
|
||||
component
|
||||
);
|
||||
|
||||
endNode = undefined;
|
||||
|
||||
startNode = beforeChild.nextSibling;
|
||||
if (!startNode || startNode === afterChild) {
|
||||
startNode = endNode = insertAfter(
|
||||
createMarkerComment(),
|
||||
beforeChild,
|
||||
parentFromNode
|
||||
);
|
||||
}
|
||||
|
||||
if (tempChild) {
|
||||
parentFromNode.removeChild(tempChild);
|
||||
}
|
||||
|
||||
if (!endNode) {
|
||||
if (afterChild) {
|
||||
endNode = afterChild.previousSibling;
|
||||
} else {
|
||||
endNode = parentFromNode.lastChild;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we don't use a detached node as the component boundary and
|
||||
// we can't use a node that is already the boundary node for another component
|
||||
if (
|
||||
startNode.___markoDetached !== undefined ||
|
||||
startNode.___markoComponent
|
||||
) {
|
||||
startNode = insertBefore(
|
||||
createMarkerComment(),
|
||||
startNode,
|
||||
parentFromNode
|
||||
);
|
||||
}
|
||||
|
||||
if (endNode.___markoDetached !== undefined || endNode.___endNode) {
|
||||
endNode = insertAfter(
|
||||
createMarkerComment(),
|
||||
endNode,
|
||||
parentFromNode
|
||||
);
|
||||
}
|
||||
|
||||
startNode.___markoComponent = component;
|
||||
endNode.___endNode = true;
|
||||
|
||||
component.___startNode = startNode;
|
||||
component.___endNode = endNode;
|
||||
|
||||
component.___keySequence = undefined; // We don't need to track keys anymore
|
||||
|
||||
return afterChild;
|
||||
function morphComponent(component, vComponent) {
|
||||
morphChildren(component.___rootNode, vComponent, component);
|
||||
}
|
||||
|
||||
var detachedNodes = [];
|
||||
|
||||
function detachNode(node, parentNode, component) {
|
||||
if (node.nodeType === ELEMENT_NODE) {
|
||||
function detachNode(node, parentNode, ownerComponent) {
|
||||
if (node.nodeType === ELEMENT_NODE || node.nodeType === FRAGMENT_NODE) {
|
||||
detachedNodes.push(node);
|
||||
node.___markoDetached = component || true;
|
||||
node.___markoDetached = ownerComponent || true;
|
||||
} else {
|
||||
destroyNodeRecursive(node);
|
||||
parentNode.removeChild(node);
|
||||
removeChild(node);
|
||||
}
|
||||
}
|
||||
|
||||
@ -231,14 +136,8 @@ function morphdom(
|
||||
component.destroy();
|
||||
}
|
||||
|
||||
function morphChildren(
|
||||
parentFromNode,
|
||||
startNode,
|
||||
endNode,
|
||||
toNode,
|
||||
component
|
||||
) {
|
||||
var curFromNodeChild = startNode;
|
||||
function morphChildren(fromNode, toNode, parentComponent) {
|
||||
var curFromNodeChild = firstChild(fromNode);
|
||||
var curToNodeChild = toNode.___firstChild;
|
||||
|
||||
var curToNodeKey;
|
||||
@ -255,56 +154,57 @@ function morphdom(
|
||||
outer: while (curToNodeChild) {
|
||||
toNextSibling = curToNodeChild.___nextSibling;
|
||||
curToNodeType = curToNodeChild.___nodeType;
|
||||
curToNodeKey = curToNodeChild.___key;
|
||||
|
||||
var componentForNode = curToNodeChild.___component || component;
|
||||
var ownerComponent =
|
||||
curToNodeChild.___ownerComponent || parentComponent;
|
||||
var referenceComponent;
|
||||
|
||||
if (curToNodeType === COMPONENT_NODE) {
|
||||
var component = curToNodeChild.___component;
|
||||
if (
|
||||
(matchingFromComponent =
|
||||
existingComponentLookup[componentForNode.id]) ===
|
||||
undefined
|
||||
existingComponentLookup[component.id]) === undefined
|
||||
) {
|
||||
if (isRerenderInBrowser === true) {
|
||||
var firstVChild = curToNodeChild.___firstChild;
|
||||
if (firstVChild) {
|
||||
if (!curFromNodeChild) {
|
||||
curFromNodeChild = insertBefore(
|
||||
createMarkerComment(),
|
||||
null,
|
||||
parentFromNode
|
||||
);
|
||||
}
|
||||
var rootNode = beginFragmentNode(
|
||||
curFromNodeChild,
|
||||
fromNode
|
||||
);
|
||||
component.___rootNode = rootNode;
|
||||
rootNode.___markoComponent = component;
|
||||
|
||||
componentForNode.___startNode = curFromNodeChild;
|
||||
componentForNode.___endNode = resolveComponentEndNode(
|
||||
curFromNodeChild,
|
||||
firstVChild,
|
||||
parentFromNode
|
||||
if (ownerComponent && curToNodeKey) {
|
||||
curToNodeKey = normalizeComponentKey(
|
||||
curToNodeKey,
|
||||
parentComponent.id
|
||||
);
|
||||
} else {
|
||||
componentForNode.___startNode = componentForNode.___endNode = insertBefore(
|
||||
createMarkerComment(),
|
||||
curFromNodeChild,
|
||||
parentFromNode
|
||||
addComponentRootToKeyedElements(
|
||||
ownerComponent.___keyedElements,
|
||||
curToNodeKey,
|
||||
rootNode,
|
||||
component.id
|
||||
);
|
||||
rootNode.___markoKey = curToNodeKey;
|
||||
}
|
||||
|
||||
curFromNodeChild = morphComponent(
|
||||
parentFromNode,
|
||||
componentForNode,
|
||||
curToNodeChild
|
||||
);
|
||||
morphComponent(component, curToNodeChild);
|
||||
|
||||
curFromNodeChild = nextSibling(rootNode);
|
||||
} else {
|
||||
insertVirtualComponentBefore(
|
||||
curToNodeChild,
|
||||
curFromNodeChild,
|
||||
parentFromNode,
|
||||
componentForNode
|
||||
fromNode,
|
||||
component,
|
||||
curToNodeKey,
|
||||
ownerComponent,
|
||||
parentComponent
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (
|
||||
matchingFromComponent.___startNode !== curFromNodeChild
|
||||
matchingFromComponent.___rootNode !== curFromNodeChild
|
||||
) {
|
||||
if (
|
||||
curFromNodeChild &&
|
||||
@ -316,66 +216,67 @@ function morphdom(
|
||||
) {
|
||||
// The component associated with the current real DOM node was not rendered
|
||||
// so we should just remove it out of the real DOM by destroying it
|
||||
curFromNodeChild =
|
||||
fromComponent.___endNode.nextSibling;
|
||||
curFromNodeChild = nextSibling(
|
||||
fromComponent.___rootNode
|
||||
);
|
||||
destroyComponent(fromComponent);
|
||||
continue;
|
||||
}
|
||||
|
||||
// We need to move the existing component into
|
||||
// the correct location and preserve focus.
|
||||
var activeElement = doc.activeElement;
|
||||
// the correct location
|
||||
insertBefore(
|
||||
matchingFromComponent.___detach(),
|
||||
matchingFromComponent.___rootNode,
|
||||
curFromNodeChild,
|
||||
parentFromNode
|
||||
fromNode
|
||||
);
|
||||
// This focus patch should be a temporary fix.
|
||||
if (
|
||||
activeElement !== doc.activeElement &&
|
||||
activeElement.focus
|
||||
) {
|
||||
activeElement.focus();
|
||||
}
|
||||
} else {
|
||||
curFromNodeChild =
|
||||
curFromNodeChild && nextSibling(curFromNodeChild);
|
||||
}
|
||||
|
||||
if (curToNodeChild.___preserve) {
|
||||
curFromNodeChild =
|
||||
matchingFromComponent.___endNode.nextSibling;
|
||||
} else {
|
||||
curFromNodeChild = morphComponent(
|
||||
parentFromNode,
|
||||
componentForNode,
|
||||
curToNodeChild
|
||||
);
|
||||
if (!curToNodeChild.___preserve) {
|
||||
morphComponent(component, curToNodeChild);
|
||||
}
|
||||
}
|
||||
|
||||
curToNodeChild = toNextSibling;
|
||||
continue;
|
||||
} else if ((curToNodeKey = curToNodeChild.___key)) {
|
||||
} else if (curToNodeKey) {
|
||||
curVFromNodeChild = undefined;
|
||||
curFromNodeKey = undefined;
|
||||
|
||||
if (isAutoKey(curToNodeKey)) {
|
||||
if (ownerComponent !== parentComponent) {
|
||||
curToNodeKey += ":" + ownerComponent.id;
|
||||
}
|
||||
referenceComponent = parentComponent;
|
||||
} else {
|
||||
referenceComponent = ownerComponent;
|
||||
}
|
||||
|
||||
var keySequence =
|
||||
componentForNode.___keySequence ||
|
||||
(componentForNode.___keySequence = globalComponentsContext.___createKeySequence());
|
||||
keySequences[referenceComponent.id] ||
|
||||
(keySequences[
|
||||
referenceComponent.id
|
||||
] = globalComponentsContext.___createKeySequence());
|
||||
|
||||
// We have a keyed element. This is the fast path for matching
|
||||
// up elements
|
||||
curToNodeKey = keySequence.___nextKey(curToNodeKey);
|
||||
|
||||
if (curFromNodeChild) {
|
||||
if (curFromNodeChild !== endNode) {
|
||||
curFromNodeKey = curFromNodeChild.___markoKey;
|
||||
curVFromNodeChild = curFromNodeChild.___markoVElement;
|
||||
fromNextSibling = curFromNodeChild.nextSibling;
|
||||
}
|
||||
curFromNodeKey = curFromNodeChild.___markoKey;
|
||||
curVFromNodeChild = curFromNodeChild.___markoVElement;
|
||||
fromNextSibling = nextSibling(curFromNodeChild);
|
||||
}
|
||||
|
||||
if (curFromNodeKey === curToNodeKey) {
|
||||
// Elements line up. Now we just have to make sure they are compatible
|
||||
if ((curToNodeChild.___flags & FLAG_PRESERVE) === 0) {
|
||||
if (
|
||||
(curToNodeChild.___flags & FLAG_PRESERVE) === 0 &&
|
||||
!curToNodeChild.___preserve
|
||||
) {
|
||||
// We just skip over the fromNode if it is preserved
|
||||
|
||||
if (
|
||||
@ -385,15 +286,16 @@ function morphdom(
|
||||
curFromNodeChild,
|
||||
curVFromNodeChild,
|
||||
curToNodeChild,
|
||||
componentForNode,
|
||||
curToNodeKey
|
||||
curToNodeKey,
|
||||
ownerComponent,
|
||||
parentComponent
|
||||
);
|
||||
} else {
|
||||
// Remove the old node
|
||||
detachNode(
|
||||
curFromNodeChild,
|
||||
parentFromNode,
|
||||
componentForNode
|
||||
fromNode,
|
||||
ownerComponent
|
||||
);
|
||||
|
||||
// Incompatible nodes. Just move the target VNode into the DOM at this position
|
||||
@ -401,8 +303,9 @@ function morphdom(
|
||||
curToNodeChild,
|
||||
curToNodeKey,
|
||||
curFromNodeChild,
|
||||
parentFromNode,
|
||||
componentForNode
|
||||
fromNode,
|
||||
ownerComponent,
|
||||
parentComponent
|
||||
);
|
||||
}
|
||||
} else {
|
||||
@ -411,38 +314,76 @@ function morphdom(
|
||||
} else {
|
||||
if (
|
||||
(matchingFromEl =
|
||||
componentForNode.___keyedElements[curToNodeKey]) ===
|
||||
undefined
|
||||
) {
|
||||
if (
|
||||
isRerenderInBrowser === true &&
|
||||
curFromNodeChild &&
|
||||
curFromNodeChild.nodeType === ELEMENT_NODE &&
|
||||
curFromNodeChild.nodeName ===
|
||||
curToNodeChild.___nodeName
|
||||
) {
|
||||
curVFromNodeChild = virtualizeElement(
|
||||
curFromNodeChild
|
||||
);
|
||||
curFromNodeChild.___markoKey = curToNodeKey;
|
||||
morphEl(
|
||||
curFromNodeChild,
|
||||
curVFromNodeChild,
|
||||
curToNodeChild,
|
||||
componentForNode,
|
||||
referenceComponent.___keyedElements[
|
||||
curToNodeKey
|
||||
);
|
||||
curToNodeChild = toNextSibling;
|
||||
curFromNodeChild = fromNextSibling;
|
||||
continue;
|
||||
]) === undefined
|
||||
) {
|
||||
if (isRerenderInBrowser === true && curFromNodeChild) {
|
||||
if (
|
||||
curFromNodeChild.nodeType === ELEMENT_NODE &&
|
||||
curFromNodeChild.nodeName ===
|
||||
curToNodeChild.___nodeName
|
||||
) {
|
||||
curVFromNodeChild = virtualizeElement(
|
||||
curFromNodeChild
|
||||
);
|
||||
curFromNodeChild.___markoKey = curToNodeKey;
|
||||
morphEl(
|
||||
curFromNodeChild,
|
||||
curVFromNodeChild,
|
||||
curToNodeChild,
|
||||
curToNodeKey,
|
||||
ownerComponent,
|
||||
parentComponent
|
||||
);
|
||||
curToNodeChild = toNextSibling;
|
||||
curFromNodeChild = fromNextSibling;
|
||||
continue;
|
||||
} else if (
|
||||
curToNodeChild.___nodeType === FRAGMENT_NODE &&
|
||||
curFromNodeChild.nodeType === COMMENT_NODE
|
||||
) {
|
||||
var content = curFromNodeChild.nodeValue;
|
||||
if (content == "F#" + curToNodeKey) {
|
||||
var endNode = curFromNodeChild;
|
||||
while (
|
||||
endNode.nodeType !== COMMENT_NODE ||
|
||||
endNode.nodeValue !== "F/"
|
||||
)
|
||||
endNode = endNode.nextSibling;
|
||||
|
||||
var fragment = createFragmentNode(
|
||||
curFromNodeChild,
|
||||
endNode.nextSibling,
|
||||
fromNode
|
||||
);
|
||||
fragment.___markoKey = curToNodeKey;
|
||||
fragment.___markoVElement = curToNodeChild;
|
||||
removeChild(curFromNodeChild);
|
||||
removeChild(endNode);
|
||||
|
||||
if (!curToNodeChild.___preserve) {
|
||||
morphChildren(
|
||||
fragment,
|
||||
curToNodeChild,
|
||||
parentComponent
|
||||
);
|
||||
}
|
||||
|
||||
curToNodeChild = toNextSibling;
|
||||
curFromNodeChild = fragment.nextSibling;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
insertVirtualNodeBefore(
|
||||
curToNodeChild,
|
||||
curToNodeKey,
|
||||
curFromNodeChild,
|
||||
parentFromNode,
|
||||
componentForNode
|
||||
fromNode,
|
||||
ownerComponent,
|
||||
parentComponent
|
||||
);
|
||||
fromNextSibling = curFromNodeChild;
|
||||
} else {
|
||||
@ -479,7 +420,7 @@ function morphdom(
|
||||
insertBefore(
|
||||
matchingFromEl,
|
||||
curFromNodeChild,
|
||||
parentFromNode
|
||||
fromNode
|
||||
);
|
||||
} else {
|
||||
// Single element removal
|
||||
@ -488,14 +429,15 @@ function morphdom(
|
||||
// and the matching real DOM node will fall into
|
||||
// place. We will continue diffing with next sibling
|
||||
// after the real DOM node that just fell into place
|
||||
fromNextSibling =
|
||||
fromNextSibling.nextSibling;
|
||||
fromNextSibling = nextSibling(
|
||||
fromNextSibling
|
||||
);
|
||||
|
||||
if (curFromNodeChild) {
|
||||
detachNode(
|
||||
curFromNodeChild,
|
||||
parentFromNode,
|
||||
componentForNode
|
||||
fromNode,
|
||||
ownerComponent
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -509,14 +451,14 @@ function morphdom(
|
||||
insertAfter(
|
||||
matchingFromEl,
|
||||
curFromNodeChild,
|
||||
parentFromNode
|
||||
fromNode
|
||||
);
|
||||
|
||||
if (curFromNodeChild) {
|
||||
detachNode(
|
||||
curFromNodeChild,
|
||||
parentFromNode,
|
||||
componentForNode
|
||||
fromNode,
|
||||
ownerComponent
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -529,9 +471,9 @@ function morphdom(
|
||||
matchingFromEl,
|
||||
curVFromNodeChild,
|
||||
curToNodeChild,
|
||||
componentForNode,
|
||||
curToNodeKey,
|
||||
curToNodeKey
|
||||
ownerComponent,
|
||||
parentComponent
|
||||
);
|
||||
}
|
||||
} else {
|
||||
@ -539,13 +481,14 @@ function morphdom(
|
||||
curToNodeChild,
|
||||
curToNodeKey,
|
||||
curFromNodeChild,
|
||||
parentFromNode,
|
||||
componentForNode
|
||||
fromNode,
|
||||
ownerComponent,
|
||||
parentComponent
|
||||
);
|
||||
detachNode(
|
||||
matchingFromEl,
|
||||
parentFromNode,
|
||||
componentForNode
|
||||
fromNode,
|
||||
ownerComponent
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -559,18 +502,17 @@ function morphdom(
|
||||
// The know the target node is not a VComponent node and we know
|
||||
// it is also not a preserve node. Let's now match up the HTML
|
||||
// element, text node, comment, etc.
|
||||
while (curFromNodeChild && curFromNodeChild !== endNode) {
|
||||
if (
|
||||
(fromComponent = curFromNodeChild.___markoComponent) &&
|
||||
fromComponent !== componentForNode
|
||||
) {
|
||||
while (curFromNodeChild) {
|
||||
fromNextSibling = nextSibling(curFromNodeChild);
|
||||
|
||||
if ((fromComponent = curFromNodeChild.___markoComponent)) {
|
||||
// The current "to" element is not associated with a component,
|
||||
// but the current "from" element is associated with a component
|
||||
|
||||
// Even if we destroy the current component in the original
|
||||
// DOM or not, we still need to skip over it since it is
|
||||
// not compatible with the current "to" node
|
||||
curFromNodeChild = fromComponent.___endNode.nextSibling;
|
||||
curFromNodeChild = fromNextSibling;
|
||||
|
||||
if (
|
||||
!globalComponentsContext.___renderedComponentsById[
|
||||
@ -583,8 +525,6 @@ function morphdom(
|
||||
continue; // Move to the next "from" node
|
||||
}
|
||||
|
||||
fromNextSibling = curFromNodeChild.nextSibling;
|
||||
|
||||
var curFromNodeType = curFromNodeChild.nodeType;
|
||||
|
||||
var isCompatible = undefined;
|
||||
@ -626,8 +566,9 @@ function morphdom(
|
||||
curFromNodeChild,
|
||||
curVFromNodeChild,
|
||||
curToNodeChild,
|
||||
component,
|
||||
curToNodeKey
|
||||
curToNodeKey,
|
||||
ownerComponent,
|
||||
parentComponent
|
||||
);
|
||||
}
|
||||
} else if (
|
||||
@ -638,44 +579,10 @@ function morphdom(
|
||||
isCompatible = true;
|
||||
// Simply update nodeValue on the original node to
|
||||
// change the text value
|
||||
|
||||
var content = curFromNodeChild.nodeValue;
|
||||
if (content == curToNodeChild.___nodeValue) {
|
||||
if (/^F\^/.test(content)) {
|
||||
var closingContent = content.replace(
|
||||
/^F\^/,
|
||||
"F/"
|
||||
);
|
||||
while (
|
||||
(curFromNodeChild =
|
||||
curFromNodeChild.nextSibling)
|
||||
) {
|
||||
if (
|
||||
curFromNodeChild.nodeValue ===
|
||||
closingContent
|
||||
) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (
|
||||
(curToNodeChild =
|
||||
curToNodeChild.___nextSibling)
|
||||
) {
|
||||
if (
|
||||
curToNodeChild.___nodeValue ===
|
||||
closingContent
|
||||
) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
curToNodeChild = curToNodeChild.___nextSibling;
|
||||
curFromNodeChild =
|
||||
curFromNodeChild === endNode
|
||||
? null
|
||||
: curFromNodeChild.nextSibling;
|
||||
continue outer;
|
||||
}
|
||||
} else {
|
||||
if (
|
||||
curFromNodeChild.nodeValue !==
|
||||
curToNodeChild.___nodeValue
|
||||
) {
|
||||
curFromNodeChild.nodeValue =
|
||||
curToNodeChild.___nodeValue;
|
||||
}
|
||||
@ -695,18 +602,10 @@ function morphdom(
|
||||
curFromNodeKey
|
||||
] === undefined
|
||||
) {
|
||||
detachNode(
|
||||
curFromNodeChild,
|
||||
parentFromNode,
|
||||
componentForNode
|
||||
);
|
||||
detachNode(curFromNodeChild, fromNode, ownerComponent);
|
||||
}
|
||||
} else {
|
||||
detachNode(
|
||||
curFromNodeChild,
|
||||
parentFromNode,
|
||||
componentForNode
|
||||
);
|
||||
detachNode(curFromNodeChild, fromNode, ownerComponent);
|
||||
}
|
||||
|
||||
curFromNodeChild = fromNextSibling;
|
||||
@ -720,54 +619,69 @@ function morphdom(
|
||||
curToNodeChild,
|
||||
curToNodeKey,
|
||||
curFromNodeChild,
|
||||
parentFromNode,
|
||||
componentForNode
|
||||
fromNode,
|
||||
ownerComponent,
|
||||
parentComponent
|
||||
);
|
||||
|
||||
curToNodeChild = toNextSibling;
|
||||
curFromNodeChild = fromNextSibling;
|
||||
}
|
||||
|
||||
// We have processed all of the "to nodes". If curFromNodeChild is
|
||||
// non-null then we still have some from nodes left over that need
|
||||
// to be removed
|
||||
while (
|
||||
curFromNodeChild &&
|
||||
(endNode === null || curFromNodeChild !== endNode)
|
||||
) {
|
||||
fromNextSibling = curFromNodeChild.nextSibling;
|
||||
// We have processed all of the "to nodes".
|
||||
if (fromNode.___finishFragment) {
|
||||
// If we are in an unfinished fragment, we have reached the end of the nodes
|
||||
// we were matching up and need to end the fragment
|
||||
fromNode.___finishFragment(curFromNodeChild);
|
||||
} else {
|
||||
// If curFromNodeChild is non-null then we still have some from nodes
|
||||
// left over that need to be removed
|
||||
while (curFromNodeChild) {
|
||||
fromNextSibling = nextSibling(curFromNodeChild);
|
||||
|
||||
if ((fromComponent = curFromNodeChild.___markoComponent)) {
|
||||
curFromNodeChild = fromComponent.___endNode.nextSibling;
|
||||
if (
|
||||
!globalComponentsContext.___renderedComponentsById[
|
||||
fromComponent.id
|
||||
]
|
||||
) {
|
||||
destroyComponent(fromComponent);
|
||||
if ((fromComponent = curFromNodeChild.___markoComponent)) {
|
||||
curFromNodeChild = fromNextSibling;
|
||||
if (
|
||||
!globalComponentsContext.___renderedComponentsById[
|
||||
fromComponent.id
|
||||
]
|
||||
) {
|
||||
destroyComponent(fromComponent);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
|
||||
curVFromNodeChild = curFromNodeChild.___markoVElement;
|
||||
|
||||
// For transcluded content, we need to check if the element belongs to a different component
|
||||
// context than the current component and ensure it gets removed from its key index.
|
||||
if (isAutoKey(fromNode.___markoKey)) {
|
||||
referenceComponent = parentComponent;
|
||||
} else {
|
||||
referenceComponent =
|
||||
curVFromNodeChild &&
|
||||
curVFromNodeChild.___ownerComponent;
|
||||
}
|
||||
|
||||
detachNode(curFromNodeChild, fromNode, referenceComponent);
|
||||
|
||||
curFromNodeChild = fromNextSibling;
|
||||
}
|
||||
|
||||
curVFromNodeChild = curFromNodeChild.___markoVElement;
|
||||
|
||||
// For transcluded content, we need to check if the element belongs to a different component
|
||||
// context than the current component and ensure it gets removed from its key index.
|
||||
fromComponent =
|
||||
(curVFromNodeChild && curVFromNodeChild.___component) ||
|
||||
component;
|
||||
|
||||
detachNode(curFromNodeChild, parentFromNode, fromComponent);
|
||||
|
||||
curFromNodeChild = fromNextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
function morphEl(fromEl, vFromEl, toEl, component, toElKey) {
|
||||
function morphEl(
|
||||
fromEl,
|
||||
vFromEl,
|
||||
toEl,
|
||||
toElKey,
|
||||
ownerComponent,
|
||||
parentComponent
|
||||
) {
|
||||
var nodeName = toEl.___nodeName;
|
||||
|
||||
if (isRerenderInBrowser === true && toElKey) {
|
||||
component.___keyedElements[toElKey] = fromEl;
|
||||
ownerComponent.___keyedElements[toElKey] = fromEl;
|
||||
}
|
||||
|
||||
var constId = toEl.___constId;
|
||||
@ -786,7 +700,7 @@ function morphdom(
|
||||
}
|
||||
|
||||
if (nodeName !== "TEXTAREA") {
|
||||
morphChildren(fromEl, fromEl.firstChild, null, toEl, component);
|
||||
morphChildren(fromEl, toEl, parentComponent);
|
||||
}
|
||||
|
||||
var specialElHandler = specialElHandlers[nodeName];
|
||||
@ -795,7 +709,7 @@ function morphdom(
|
||||
}
|
||||
} // END: morphEl(...)
|
||||
|
||||
morphChildren(parentNode, startNode, endNode, toNode);
|
||||
morphChildren(fromNode, toNode, toNode.___component);
|
||||
|
||||
detachedNodes.forEach(function(node) {
|
||||
var detachedFromComponent = node.___markoDetached;
|
||||
@ -813,7 +727,7 @@ function morphdom(
|
||||
);
|
||||
|
||||
if (eventDelegation.___handleNodeDetach(node) != false) {
|
||||
node.parentNode.removeChild(node);
|
||||
removeChild(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ SpecialElHandlers.prototype = {
|
||||
fromEl.value = toEl.___value;
|
||||
}
|
||||
|
||||
if (!toEl.___hasAttribute("value")) {
|
||||
if (fromEl.hasAttribute("value") && !toEl.___hasAttribute("value")) {
|
||||
fromEl.removeAttribute("value");
|
||||
}
|
||||
},
|
||||
@ -63,18 +63,21 @@ SpecialElHandlers.prototype = {
|
||||
SELECT: function(fromEl, toEl) {
|
||||
if (!toEl.___hasAttribute("multiple")) {
|
||||
var i = -1;
|
||||
var selected = 0;
|
||||
var curChild = toEl.___firstChild;
|
||||
while (curChild) {
|
||||
if (curChild.___nodeName == "OPTION") {
|
||||
i++;
|
||||
if (curChild.___hasAttribute("selected")) {
|
||||
break;
|
||||
selected = i;
|
||||
}
|
||||
}
|
||||
curChild = curChild.___nextSibling;
|
||||
}
|
||||
|
||||
fromEl.selectedIndex = i;
|
||||
if (fromEl.selectedIndex !== selected) {
|
||||
fromEl.selectedIndex = selected;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
"use strict";
|
||||
var removeDashes = require("../compiler/util/removeDashes");
|
||||
var ComponentsContext = require("../components/ComponentsContext");
|
||||
var getComponentsContext = ComponentsContext.___getComponentsContext;
|
||||
var ComponentDef = require("../components/ComponentDef");
|
||||
var isArray = Array.isArray;
|
||||
var RENDER_BODY_TOKEN = "%FN";
|
||||
var RENDER_BODY_TO_JSON = function() {
|
||||
@ -105,8 +108,8 @@ var helpers = {
|
||||
*/
|
||||
d: function dynamicTag(tag, attrs, out, componentDef, key, customEvents) {
|
||||
if (tag) {
|
||||
var component = componentDef && componentDef.___component;
|
||||
if (typeof tag === "string") {
|
||||
var component = componentDef && componentDef.component;
|
||||
var events =
|
||||
customEvents &&
|
||||
customEvents.reduce(function(events, eventArray) {
|
||||
@ -161,17 +164,28 @@ var helpers = {
|
||||
|
||||
if (isFn || isToken) {
|
||||
var flags = componentDef ? componentDef.___flags : 0;
|
||||
var parentId = componentDef ? componentDef.id : "";
|
||||
var willRerender =
|
||||
flags & FLAG_WILL_RERENDER_IN_BROWSER;
|
||||
var resolvedKey = parentId + " " + key;
|
||||
var insertMarkers = IS_SERVER ? willRerender : isToken;
|
||||
if (insertMarkers) out.comment("F^" + resolvedKey);
|
||||
var preserve = IS_SERVER ? willRerender : isToken;
|
||||
out.___beginFragment(key, component, preserve);
|
||||
if (isFn) {
|
||||
var componentsContext = getComponentsContext(out);
|
||||
var parentComponentDef =
|
||||
componentsContext.___componentDef;
|
||||
var globalContext =
|
||||
componentsContext.___globalContext;
|
||||
componentsContext.___componentDef = new ComponentDef(
|
||||
component,
|
||||
parentComponentDef.id +
|
||||
"-" +
|
||||
parentComponentDef.___nextKey(key),
|
||||
globalContext
|
||||
);
|
||||
render.toJSON = RENDER_BODY_TO_JSON;
|
||||
render(out, attrs);
|
||||
componentsContext.___componentDef = parentComponentDef;
|
||||
}
|
||||
if (insertMarkers) out.comment("F/" + resolvedKey);
|
||||
out.___endFragment();
|
||||
} else {
|
||||
out.error("Invalid dynamic tag value");
|
||||
}
|
||||
|
||||
@ -500,6 +500,24 @@ var proto = (AsyncStream.prototype = {
|
||||
this.write(escapeXml(str));
|
||||
},
|
||||
|
||||
___beginFragment: function(key, component, preserve) {
|
||||
if (preserve) {
|
||||
this.write("<!--F#" + escapeXml(key) + "-->");
|
||||
}
|
||||
if (this._elStack) {
|
||||
this._elStack.push(preserve);
|
||||
} else {
|
||||
this._elStack = [preserve];
|
||||
}
|
||||
},
|
||||
|
||||
___endFragment: function() {
|
||||
var preserve = this._elStack.pop();
|
||||
if (preserve) {
|
||||
this.write("<!--F/-->");
|
||||
}
|
||||
},
|
||||
|
||||
___getNode: function(doc) {
|
||||
var node = this._node;
|
||||
var curEl;
|
||||
|
||||
@ -5,6 +5,7 @@ var VDocumentFragment = vdom.___VDocumentFragment;
|
||||
var VComment = vdom.___VComment;
|
||||
var VText = vdom.___VText;
|
||||
var VComponent = vdom.___VComponent;
|
||||
var VFragment = vdom.___VFragment;
|
||||
var virtualizeHTML = vdom.___virtualizeHTML;
|
||||
var RenderResult = require("../RenderResult");
|
||||
var defaultDocument = vdom.___defaultDocument;
|
||||
@ -56,13 +57,13 @@ var proto = (AsyncVDOMBuilder.prototype = {
|
||||
___isOut: true,
|
||||
___document: defaultDocument,
|
||||
|
||||
bc: function(component) {
|
||||
var vComponent = new VComponent(component);
|
||||
bc: function(component, key, ownerComponent) {
|
||||
var vComponent = new VComponent(component, key, ownerComponent);
|
||||
return this.___beginNode(vComponent, 0, true);
|
||||
},
|
||||
|
||||
___preserveComponent: function(component) {
|
||||
var vComponent = new VComponent(component, true);
|
||||
___preserveComponent: function(component, key, ownerComponent) {
|
||||
var vComponent = new VComponent(component, key, ownerComponent, true);
|
||||
this.___beginNode(vComponent, 0);
|
||||
},
|
||||
|
||||
@ -122,7 +123,7 @@ var proto = (AsyncVDOMBuilder.prototype = {
|
||||
// and a node can only have one parent node.
|
||||
var clone = node.___cloneNode();
|
||||
this.node(clone);
|
||||
clone.___component = component;
|
||||
clone.___ownerComponent = component;
|
||||
|
||||
return this;
|
||||
},
|
||||
@ -208,6 +209,16 @@ var proto = (AsyncVDOMBuilder.prototype = {
|
||||
return this;
|
||||
},
|
||||
|
||||
___beginFragment: function(key, component, preserve) {
|
||||
var fragment = new VFragment(key, component, preserve);
|
||||
this.___beginNode(fragment, null, true);
|
||||
return this;
|
||||
},
|
||||
|
||||
___endFragment: function() {
|
||||
this.endElement();
|
||||
},
|
||||
|
||||
endElement: function() {
|
||||
var stack = this.___stack;
|
||||
stack.pop();
|
||||
@ -417,7 +428,7 @@ var proto = (AsyncVDOMBuilder.prototype = {
|
||||
// Create the root document fragment node
|
||||
doc = doc || this.___document || document;
|
||||
this.___vnode = node = vdomTree.___actualize(doc);
|
||||
morphdom(node, null, null, vdomTree, doc, this.___components);
|
||||
morphdom(node, vdomTree, doc, this.___components);
|
||||
}
|
||||
return node;
|
||||
},
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
var VNode = require("./VNode");
|
||||
var inherit = require("raptor-util/inherit");
|
||||
|
||||
function VComponent(component, preserve) {
|
||||
function VComponent(component, key, ownerComponent, preserve) {
|
||||
this.___VNode(null /* childCount */);
|
||||
this.___key = key;
|
||||
this.___component = component;
|
||||
this.___ownerComponent = ownerComponent;
|
||||
this.___preserve = preserve;
|
||||
}
|
||||
|
||||
|
||||
@ -60,7 +60,15 @@ function VElementClone(other) {
|
||||
this.___isTextArea = other.___isTextArea;
|
||||
}
|
||||
|
||||
function VElement(tagName, attrs, key, component, childCount, flags, props) {
|
||||
function VElement(
|
||||
tagName,
|
||||
attrs,
|
||||
key,
|
||||
ownerComponent,
|
||||
childCount,
|
||||
flags,
|
||||
props
|
||||
) {
|
||||
this.___VNode(childCount);
|
||||
|
||||
var constId;
|
||||
@ -81,7 +89,7 @@ function VElement(tagName, attrs, key, component, childCount, flags, props) {
|
||||
}
|
||||
|
||||
this.___key = key;
|
||||
this.___component = component;
|
||||
this.___ownerComponent = ownerComponent;
|
||||
this.___attributes = attrs || EMPTY_OBJECT;
|
||||
this.___properties = props || EMPTY_OBJECT;
|
||||
this.___namespaceURI = namespaceURI;
|
||||
@ -105,13 +113,13 @@ VElement.prototype = {
|
||||
* @param {int|null} attrCount The number of attributes (or `null` if not known)
|
||||
* @param {int|null} childCount The number of child nodes (or `null` if not known)
|
||||
*/
|
||||
e: function(tagName, attrs, key, component, childCount, flags, props) {
|
||||
e: function(tagName, attrs, key, ownerComponent, childCount, flags, props) {
|
||||
var child = this.___appendChild(
|
||||
new VElement(
|
||||
tagName,
|
||||
attrs,
|
||||
key,
|
||||
component,
|
||||
ownerComponent,
|
||||
childCount,
|
||||
flags,
|
||||
props
|
||||
@ -132,13 +140,21 @@ VElement.prototype = {
|
||||
* @param {int|null} attrCount The number of attributes (or `null` if not known)
|
||||
* @param {int|null} childCount The number of child nodes (or `null` if not known)
|
||||
*/
|
||||
ed: function(tagName, attrs, key, component, childCount, flags, props) {
|
||||
ed: function(
|
||||
tagName,
|
||||
attrs,
|
||||
key,
|
||||
ownerComponent,
|
||||
childCount,
|
||||
flags,
|
||||
props
|
||||
) {
|
||||
var child = this.___appendChild(
|
||||
VElement.___createElementDynamicTag(
|
||||
tagName,
|
||||
attrs,
|
||||
key,
|
||||
component,
|
||||
ownerComponent,
|
||||
childCount,
|
||||
flags,
|
||||
props
|
||||
@ -158,9 +174,9 @@ VElement.prototype = {
|
||||
*
|
||||
* @param {String} value The value for the new Comment node
|
||||
*/
|
||||
n: function(node, component) {
|
||||
n: function(node, ownerComponent) {
|
||||
node = node.___cloneNode();
|
||||
node.___component = component;
|
||||
node.___ownerComponent = ownerComponent;
|
||||
this.___appendChild(node);
|
||||
return this.___finishChild();
|
||||
},
|
||||
@ -238,7 +254,12 @@ defineProperty(proto, "___value", {
|
||||
if (value == null) {
|
||||
value = this.___attributes.value;
|
||||
}
|
||||
return value != null ? toString(value) : "";
|
||||
return value != null
|
||||
? toString(value)
|
||||
: this.___attributes.type === "checkbox" ||
|
||||
this.___attributes.type === "radio"
|
||||
? "on"
|
||||
: "";
|
||||
}
|
||||
});
|
||||
|
||||
@ -246,7 +267,7 @@ VElement.___createElementDynamicTag = function(
|
||||
tagName,
|
||||
attrs,
|
||||
key,
|
||||
component,
|
||||
ownerComponent,
|
||||
childCount,
|
||||
flags,
|
||||
props
|
||||
@ -257,7 +278,7 @@ VElement.___createElementDynamicTag = function(
|
||||
tagName,
|
||||
attrs,
|
||||
key,
|
||||
component,
|
||||
ownerComponent,
|
||||
childCount,
|
||||
flags,
|
||||
props
|
||||
@ -307,7 +328,7 @@ function virtualizeElement(node, virtualizeChildNodes) {
|
||||
tagName,
|
||||
attrs,
|
||||
null /*key*/,
|
||||
null /*component*/,
|
||||
null /*ownerComponent*/,
|
||||
0 /*child count*/,
|
||||
flags,
|
||||
null /*props*/
|
||||
|
||||
25
src/runtime/vdom/VFragment.js
Normal file
25
src/runtime/vdom/VFragment.js
Normal file
@ -0,0 +1,25 @@
|
||||
var VNode = require("./VNode");
|
||||
var inherit = require("raptor-util/inherit");
|
||||
var createFragmentNode = require("../../morphdom/fragment")
|
||||
.___createFragmentNode;
|
||||
|
||||
function VFragment(key, ownerComponent, preserve) {
|
||||
this.___VNode(null /* childCount */);
|
||||
this.___key = key;
|
||||
this.___ownerComponent = ownerComponent;
|
||||
this.___preserve = preserve;
|
||||
}
|
||||
|
||||
VFragment.prototype = {
|
||||
___nodeType: 12,
|
||||
___actualize: function() {
|
||||
var fragment = createFragmentNode();
|
||||
fragment.___markoKey = this.___key;
|
||||
fragment.___markoVElement = this;
|
||||
return fragment;
|
||||
}
|
||||
};
|
||||
|
||||
inherit(VFragment, VNode);
|
||||
|
||||
module.exports = VFragment;
|
||||
@ -11,7 +11,7 @@ VNode.prototype = {
|
||||
this.___nextSiblingInternal = null;
|
||||
},
|
||||
|
||||
___component: null,
|
||||
___ownerComponent: null,
|
||||
|
||||
get ___firstChild() {
|
||||
var firstChild = this.___firstChildInternal;
|
||||
|
||||
@ -4,6 +4,7 @@ var VDocumentFragment = require("./VDocumentFragment");
|
||||
var VElement = require("./VElement");
|
||||
var VText = require("./VText");
|
||||
var VComponent = require("./VComponent");
|
||||
var VFragment = require("./VFragment");
|
||||
|
||||
var defaultDocument = typeof document != "undefined" && document;
|
||||
var specialHtmlRegexp = /[&<]/;
|
||||
@ -91,6 +92,7 @@ exports.___VDocumentFragment = VDocumentFragment;
|
||||
exports.___VElement = VElement;
|
||||
exports.___VText = VText;
|
||||
exports.___VComponent = VComponent;
|
||||
exports.___VFragment = VFragment;
|
||||
exports.___virtualize = virtualize;
|
||||
exports.___virtualizeHTML = virtualizeHTML;
|
||||
exports.___defaultDocument = defaultDocument;
|
||||
|
||||
@ -37,15 +37,18 @@ function doInclude(input, out, throwError) {
|
||||
var willRerenderInBrowser =
|
||||
componentDef &&
|
||||
componentDef.___flags & FLAG_WILL_RERENDER_IN_BROWSER;
|
||||
var key = (componentDef && componentDef.id) + " " + out.___assignedKey;
|
||||
var isFn = renderBody !== RENDER_BODY_TOKEN;
|
||||
var insertMarkers = (IS_SERVER && willRerenderInBrowser) || !isFn;
|
||||
if (insertMarkers) out.comment("F^" + key);
|
||||
if (renderBody !== RENDER_BODY_TOKEN) {
|
||||
var preserve = (IS_SERVER && willRerenderInBrowser) || !isFn;
|
||||
out.___beginFragment(
|
||||
out.___assignedKey,
|
||||
componentDef && componentDef.___component,
|
||||
preserve
|
||||
);
|
||||
if (isFn) {
|
||||
renderBody.toJSON = RENDER_BODY_TO_JSON;
|
||||
renderBody(out, arg);
|
||||
}
|
||||
if (insertMarkers) out.comment("F/" + key);
|
||||
out.___endFragment();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -21,7 +21,7 @@ var marko_template = module.exports = require("marko/src/vdom").t(),
|
||||
.e("a", {
|
||||
"xlink:href": "https://developer.mozilla.org/en-US/docs/SVG",
|
||||
target: "_blank"
|
||||
}, "1", null, 0, 1);
|
||||
}, null, null, 0, 1);
|
||||
|
||||
function render(input, out, __component, component, state) {
|
||||
var data = input;
|
||||
|
||||
@ -22,7 +22,7 @@ var marko_template = module.exports = require("marko/src/vdom").t(),
|
||||
cx: "100",
|
||||
cy: "100",
|
||||
r: "100"
|
||||
}, "1", null, 0, 1);
|
||||
}, null, null, 0, 1);
|
||||
|
||||
function render(input, out, __component, component, state) {
|
||||
var data = input;
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
class {
|
||||
onCreate() {
|
||||
this.message = "Hello";
|
||||
}
|
||||
}
|
||||
|
||||
<div/>
|
||||
@ -0,0 +1,3 @@
|
||||
class {}
|
||||
|
||||
<hello key="something[]"/>
|
||||
@ -0,0 +1,6 @@
|
||||
var expect = require("chai").expect;
|
||||
|
||||
module.exports = function(helpers) {
|
||||
var component = helpers.mount(require.resolve("./index"), {});
|
||||
expect(component.getComponent("something[]").message).to.equal("Hello");
|
||||
};
|
||||
@ -11,8 +11,8 @@ module.exports = function(helpers) {
|
||||
var nextSibling = document.createElement("div");
|
||||
helpers.targetEl.appendChild(nextSibling);
|
||||
|
||||
expect(widget.el.previousSibling).to.equal(previousSibling);
|
||||
expect(widget.el.nextSibling).to.equal(nextSibling);
|
||||
expect(widget.el.previousElementSibling).to.equal(previousSibling);
|
||||
expect(widget.el.nextElementSibling).to.equal(nextSibling);
|
||||
|
||||
var parentNode = widget.el.parentNode;
|
||||
|
||||
@ -29,10 +29,10 @@ module.exports = function(helpers) {
|
||||
expect(widget.el.parentNode).to.equal(parentNode);
|
||||
// expect(widget.el !== oldEl).to.equal(true);
|
||||
|
||||
expect(helpers.targetEl.childNodes.length).to.equal(3);
|
||||
expect(helpers.targetEl.childNodes[0]).to.equal(previousSibling);
|
||||
expect(helpers.targetEl.childNodes[1]).to.equal(widget.el);
|
||||
expect(helpers.targetEl.childNodes[2]).to.equal(nextSibling);
|
||||
expect(helpers.targetEl.children.length).to.equal(3);
|
||||
expect(helpers.targetEl.children[0]).to.equal(previousSibling);
|
||||
expect(helpers.targetEl.children[1]).to.equal(widget.el);
|
||||
expect(helpers.targetEl.children[2]).to.equal(nextSibling);
|
||||
};
|
||||
|
||||
module.exports.skip_hydrate = "a split widget cannot re-render when hydrated";
|
||||
|
||||
@ -4,18 +4,12 @@ module.exports = function(helpers) {
|
||||
var component = helpers.mount(require.resolve("./index"), {});
|
||||
var innerComponent = component.getComponent("inner");
|
||||
|
||||
expect(innerComponent.___startNode.className).to.equal("inner");
|
||||
expect(component.___startNode).to.not.equal(innerComponent.___startNode);
|
||||
expect(component.___endNode).to.not.equal(innerComponent.___endNode);
|
||||
expect(helpers.targetEl.querySelector(".inner").innerHTML).to.equal("0");
|
||||
|
||||
component.state.count++;
|
||||
component.update();
|
||||
|
||||
innerComponent = component.getComponent("inner");
|
||||
expect(component.getComponent("inner")).to.equal(innerComponent);
|
||||
|
||||
expect(innerComponent.___startNode.className).to.equal("inner");
|
||||
expect(component.___startNode).to.not.equal(innerComponent.___startNode);
|
||||
expect(component.___endNode).to.not.equal(innerComponent.___endNode);
|
||||
expect(helpers.targetEl.querySelector(".inner").innerHTML).to.equal("1");
|
||||
};
|
||||
|
||||
@ -6,11 +6,18 @@ module.exports = function(helpers) {
|
||||
color: colors[0]
|
||||
});
|
||||
|
||||
expect(component.events.length).to.equal(1);
|
||||
expect(component.events[0].color).to.equal("blue");
|
||||
expect(component.events[0].node).to.equal(
|
||||
component.el.querySelectorAll("li")[0]
|
||||
);
|
||||
if (helpers.isHydrate) {
|
||||
// When hydrating, the first color item was rendered on the
|
||||
// server so there is no corresponding attach event f
|
||||
// we'll push an empty event so the indexes line up
|
||||
component.events.push(null);
|
||||
} else {
|
||||
expect(component.events.length).to.equal(1);
|
||||
expect(component.events[0].color).to.equal("blue");
|
||||
expect(component.events[0].node).to.equal(
|
||||
component.el.querySelectorAll("li")[0]
|
||||
);
|
||||
}
|
||||
|
||||
component.input = { color: colors[1] };
|
||||
component.update();
|
||||
|
||||
@ -34,5 +34,3 @@ module.exports = function(helpers) {
|
||||
component.update();
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.fails = "issue #1059";
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
class {}
|
||||
|
||||
<card for(i in [1,2,3,4])>
|
||||
<div.body key="transcluded">
|
||||
<div.body key=`transcluded:${i}`>
|
||||
<span>${i}</span>
|
||||
</div>
|
||||
</card>
|
||||
|
||||
@ -5,6 +5,6 @@ module.exports = function(helpers) {
|
||||
var targetEl = helpers.targetEl;
|
||||
var innerHTML = targetEl.innerHTML;
|
||||
expect(innerHTML).to.equal(
|
||||
'<!--$marko--><div class="card"><div class="body"><span>1</span></div></div><div class="card"><div class="body"><span>2</span></div></div><div class="card"><div class="body"><span>3</span></div></div><div class="card"><div class="body"><span>4</span></div></div><!--$marko-->'
|
||||
'<div class="card"><div class="body"><span>1</span></div></div><div class="card"><div class="body"><span>2</span></div></div><div class="card"><div class="body"><span>3</span></div></div><div class="card"><div class="body"><span>4</span></div></div>'
|
||||
);
|
||||
};
|
||||
|
||||
@ -3,5 +3,3 @@ module.exports = function(helpers) {
|
||||
component.setState("showLast", false);
|
||||
component.update();
|
||||
};
|
||||
|
||||
module.exports.fails_hydrate = "issue #1051";
|
||||
|
||||
@ -9,8 +9,10 @@ module.exports = function(helpers, done) {
|
||||
.render({ name: "John" })
|
||||
.then(function(result) {
|
||||
result.replace(targetEl);
|
||||
expect(component.el.firstChild.className).to.equal("hello");
|
||||
expect(component.el.firstChild.innerHTML).to.equal("Hello John");
|
||||
expect(component.el.firstElementChild.className).to.equal("hello");
|
||||
expect(component.el.firstElementChild.innerHTML).to.equal(
|
||||
"Hello John"
|
||||
);
|
||||
done();
|
||||
})
|
||||
.catch(function(err) {
|
||||
|
||||
@ -7,6 +7,6 @@ module.exports = function(helpers) {
|
||||
var targetEl = component.getEl("target");
|
||||
hello.renderSync({ name: "John" }).replace(targetEl);
|
||||
|
||||
expect(component.el.firstChild.className).to.equal("hello");
|
||||
expect(component.el.firstChild.innerHTML).to.equal("Hello John");
|
||||
expect(component.el.firstElementChild.className).to.equal("hello");
|
||||
expect(component.el.firstElementChild.innerHTML).to.equal("Hello John");
|
||||
};
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
class {
|
||||
onMount() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
<div.bar>
|
||||
Hello
|
||||
</div>
|
||||
<div.bar>
|
||||
World
|
||||
</div>
|
||||
@ -0,0 +1,8 @@
|
||||
class {
|
||||
onMount() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
<div.foo>
|
||||
</div>
|
||||
@ -0,0 +1,10 @@
|
||||
class {
|
||||
onMount() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
<if (typeof window !== 'undefined')>
|
||||
<app-foo/>
|
||||
<a href="ebay.com">eBay</a>
|
||||
</if>
|
||||
@ -0,0 +1,16 @@
|
||||
var expect = require("chai").expect;
|
||||
|
||||
module.exports = function(helpers) {
|
||||
var component = helpers.mount(require.resolve("./index"), {});
|
||||
|
||||
expect(helpers.targetEl.innerHTML).to.equal(
|
||||
'<div class="foo"></div><a href="ebay.com">eBay</a>'
|
||||
);
|
||||
|
||||
component.forceUpdate();
|
||||
component.update();
|
||||
|
||||
expect(helpers.targetEl.innerHTML).to.equal(
|
||||
'<div class="foo"></div><a href="ebay.com">eBay</a>'
|
||||
);
|
||||
};
|
||||
@ -14,5 +14,3 @@ module.exports = function(helpers) {
|
||||
component.update();
|
||||
expect(helpers.targetEl.textContent).to.equal("Hello world");
|
||||
};
|
||||
|
||||
module.exports.fails = "issue #1033";
|
||||
|
||||
@ -8,24 +8,26 @@ module.exports = function(helpers) {
|
||||
expect(buttonComponent).to.exist;
|
||||
expect(countComponent).to.exist;
|
||||
|
||||
// TODO: enable this part of the test
|
||||
/*
|
||||
expect(buttonComponent.el.innerHTML).to.contain('0');
|
||||
expect(buttonComponent.el.className).to.equal('app-button app-button-small');
|
||||
expect(buttonComponent.el.innerHTML).to.contain("0");
|
||||
expect(buttonComponent.el.className).to.equal(
|
||||
"app-button app-button-small"
|
||||
);
|
||||
|
||||
buttonComponent.setSize('large');
|
||||
buttonComponent.setSize("large");
|
||||
buttonComponent.update();
|
||||
expect(buttonComponent.el.innerHTML).to.contxain('0');
|
||||
expect(buttonComponent.el.className).to.equal('app-button app-button-large');
|
||||
expect(buttonComponent.el.innerHTML).to.contain("0");
|
||||
expect(buttonComponent.el.className).to.equal(
|
||||
"app-button app-button-large"
|
||||
);
|
||||
|
||||
debugger;
|
||||
countComponent.increment();
|
||||
countComponent.update();
|
||||
expect(buttonComponent.el.innerHTML).to.contain('1');
|
||||
expect(buttonComponent.el.innerHTML).to.contain("1");
|
||||
|
||||
buttonComponent.setSize('small');
|
||||
buttonComponent.setSize("small");
|
||||
buttonComponent.update();
|
||||
expect(buttonComponent.el.innerHTML).to.contain('1');
|
||||
expect(buttonComponent.el.className).to.equal('app-button app-button-small');
|
||||
*/
|
||||
expect(buttonComponent.el.innerHTML).to.contain("1");
|
||||
expect(buttonComponent.el.className).to.equal(
|
||||
"app-button app-button-small"
|
||||
);
|
||||
};
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
class {}
|
||||
|
||||
<${input}/>
|
||||
@ -0,0 +1,11 @@
|
||||
class {
|
||||
onCreate() {
|
||||
this.state = { count:0 };
|
||||
}
|
||||
|
||||
increment() {
|
||||
this.state.count++;
|
||||
}
|
||||
}
|
||||
|
||||
-- ${state.count}
|
||||
@ -0,0 +1,5 @@
|
||||
class {}
|
||||
|
||||
<for(i from 1 to 3)>
|
||||
<${input}/>
|
||||
</for>
|
||||
@ -0,0 +1,7 @@
|
||||
class {}
|
||||
|
||||
<list>
|
||||
<container key="container[]">
|
||||
<counter key="counter[]"/>
|
||||
</container>
|
||||
</list>
|
||||
@ -0,0 +1,33 @@
|
||||
var expect = require("chai").expect;
|
||||
|
||||
module.exports = function(helpers) {
|
||||
var root = helpers.mount(require.resolve("./index"));
|
||||
var counters = root.getComponents("counter");
|
||||
var containers = root.getComponents("container");
|
||||
|
||||
expect(helpers.targetEl.textContent).to.equal("000");
|
||||
|
||||
counters[0].increment();
|
||||
counters[0].update();
|
||||
counters[1].increment();
|
||||
counters[1].increment();
|
||||
counters[1].update();
|
||||
counters[2].increment();
|
||||
counters[2].increment();
|
||||
counters[2].increment();
|
||||
counters[2].update();
|
||||
|
||||
expect(helpers.targetEl.textContent).to.equal("123");
|
||||
|
||||
containers[1].forceUpdate();
|
||||
containers[1].update();
|
||||
containers[2].forceUpdate();
|
||||
containers[2].update();
|
||||
|
||||
expect(helpers.targetEl.textContent).to.equal("123");
|
||||
|
||||
counters[2].increment();
|
||||
counters[2].update();
|
||||
|
||||
expect(helpers.targetEl.textContent).to.equal("124");
|
||||
};
|
||||
@ -4,6 +4,4 @@ class {
|
||||
}
|
||||
}
|
||||
|
||||
<div>
|
||||
<counter key="counter" if(!state.hideOwnCounter)/>|<include(input.renderBody)/>
|
||||
</div>
|
||||
<counter key="counter" if(!state.hideOwnCounter)/><span>|</span><${input}/>
|
||||
@ -33,13 +33,18 @@ function runClientTest(fixture) {
|
||||
if (isAsync) {
|
||||
testFunc(helpers, cleanupAndFinish);
|
||||
} else {
|
||||
testFunc(helpers);
|
||||
cleanupAndFinish();
|
||||
let err;
|
||||
try {
|
||||
testFunc(helpers);
|
||||
} catch (e) {
|
||||
err = e;
|
||||
}
|
||||
cleanupAndFinish(err);
|
||||
}
|
||||
|
||||
function cleanupAndFinish(err) {
|
||||
// Cache components for use in hydrate run.
|
||||
context.rendered = helpers.rendered;
|
||||
if (!err) context.rendered = helpers.rendered;
|
||||
helpers.instances.forEach(instance => instance.destroy());
|
||||
helpers.targetEl.innerHTML = "";
|
||||
done(err);
|
||||
|
||||
@ -32,7 +32,7 @@ function render(input, out, __component, component, state) {
|
||||
|
||||
out.w("</ul>");
|
||||
|
||||
var __key5 = __component.___nextKey("preservedP");
|
||||
var __key5 = __component.___nextKey("@preservedP");
|
||||
|
||||
out.w("<p>");
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ var marko_template = module.exports = require("marko/src/vdom").t(__filename),
|
||||
marko_node0 = marko_createElement("HEAD", null, "1", null, 1, 0, {
|
||||
i: marko_const_nextId()
|
||||
})
|
||||
.e("TITLE", null, "2", null, 1)
|
||||
.e("TITLE", null, null, null, 1)
|
||||
.t("Hello"),
|
||||
marko_node1 = marko_createElement("H1", null, "4", null, 1, 0, {
|
||||
i: marko_const_nextId()
|
||||
|
||||
@ -18,7 +18,7 @@ var marko_template = module.exports = require("marko/src/vdom").t(__filename),
|
||||
function render(input, out, __component, component, state) {
|
||||
var data = input;
|
||||
|
||||
out.e("H1", null, input.myStartKey, component, 0);
|
||||
out.e("H1", null, "@" + input.myStartKey, component, 0);
|
||||
|
||||
my_component_tag({}, out, __component, "0");
|
||||
}
|
||||
|
||||
@ -13,9 +13,9 @@ var marko_template = module.exports = require("marko/src/vdom").t(__filename),
|
||||
function render(input, out, __component, component, state) {
|
||||
var data = input;
|
||||
|
||||
out.e("H1", null, input.myStartKey, component, 0);
|
||||
out.e("H1", null, "@" + input.myStartKey, component, 0);
|
||||
|
||||
out.e("DIV", null, input.myEndKey, component, 0);
|
||||
out.e("DIV", null, "@" + input.myEndKey, component, 0);
|
||||
}
|
||||
|
||||
marko_template._ = marko_renderer(render, {
|
||||
|
||||
@ -13,10 +13,10 @@ var marko_template = module.exports = require("marko/src/vdom").t(__filename),
|
||||
marko_createElement = marko_helpers.e,
|
||||
marko_const = marko_helpers.const,
|
||||
marko_const_nextId = marko_const("339bea"),
|
||||
marko_node0 = marko_createElement("H1", null, "myStart", null, 0, 0, {
|
||||
marko_node0 = marko_createElement("H1", null, "@myStart", null, 0, 0, {
|
||||
i: marko_const_nextId()
|
||||
}),
|
||||
marko_node1 = marko_createElement("DIV", null, "myEnd", null, 0, 0, {
|
||||
marko_node1 = marko_createElement("DIV", null, "@myEnd", null, 0, 0, {
|
||||
i: marko_const_nextId()
|
||||
});
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ describe(path.basename(__dirname), function() {
|
||||
var app = window.app;
|
||||
app.forceUpdate();
|
||||
app.update();
|
||||
expect(app.getEl().outerHTML).to.equal(undefined);
|
||||
expect(app.getEl()).to.equal(undefined);
|
||||
app.input = { show: true };
|
||||
app.forceUpdate();
|
||||
app.update();
|
||||
|
||||
@ -2,7 +2,7 @@ var path = require("path");
|
||||
var expect = require("chai").expect;
|
||||
|
||||
describe(path.basename(__dirname), function() {
|
||||
it.fails("should update correctly", function() {
|
||||
it("should update correctly", function() {
|
||||
var component = window.component;
|
||||
var $button = component.getEl("button");
|
||||
expect($button.textContent).to.eql("button label");
|
||||
@ -10,7 +10,6 @@ describe(path.basename(__dirname), function() {
|
||||
$button.click();
|
||||
component.update();
|
||||
|
||||
expect($button.textContent).to.eql("button label test");
|
||||
}).details =
|
||||
"issue #912";
|
||||
expect($button.textContent).to.eql("button labeltest");
|
||||
});
|
||||
});
|
||||
|
||||
@ -0,0 +1,2 @@
|
||||
class {}
|
||||
<div/>
|
||||
@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
onMount() {
|
||||
window.component = this;
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,6 @@
|
||||
$ var promise = new Promise(resolve => setTimeout(resolve, 100));
|
||||
|
||||
<await(_ from promise) client-reorder>
|
||||
<div key="div"/>
|
||||
<app-child key="child"/>
|
||||
</await>
|
||||
@ -0,0 +1,16 @@
|
||||
<marko no-browser-rerender />
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<title> Marko Test</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="test"/>
|
||||
<div id="mocha"/>
|
||||
<div id="testsTarget" />
|
||||
|
||||
<app-hello />
|
||||
</body>
|
||||
</html>
|
||||
10
test/components-pages/fixtures/split-async-keys/tests.js
Normal file
10
test/components-pages/fixtures/split-async-keys/tests.js
Normal file
@ -0,0 +1,10 @@
|
||||
var path = require("path");
|
||||
var expect = require("chai").expect;
|
||||
|
||||
describe(path.basename(__dirname), function() {
|
||||
it("should initialize components correctly across async boundaries", function(done) {
|
||||
expect(window.component.getEl("div")).to.not.equal(undefined);
|
||||
expect(window.component.getComponent("child")).to.not.equal(undefined);
|
||||
done();
|
||||
});
|
||||
});
|
||||
@ -18,18 +18,24 @@ function run(fixture) {
|
||||
var testFile = resolve("tests.js");
|
||||
var templateFile = resolve("template.marko");
|
||||
var template = require(templateFile);
|
||||
return template.render({}).then(function(html) {
|
||||
var browser = createBrowserWithMarko(__dirname, String(html), {
|
||||
beforeParse(window, browser) {
|
||||
browser.require("../../components");
|
||||
browser.require(templateFile);
|
||||
}
|
||||
return template
|
||||
.render({})
|
||||
.then(function(html) {
|
||||
var browser = createBrowserWithMarko(__dirname, String(html), {
|
||||
beforeParse(window, browser) {
|
||||
browser.require("../../components");
|
||||
browser.window.$initComponents();
|
||||
browser.require(templateFile);
|
||||
}
|
||||
});
|
||||
after(function() {
|
||||
browser.window.close();
|
||||
});
|
||||
return browser;
|
||||
})
|
||||
.then(function(browser) {
|
||||
browser.window.document.close();
|
||||
browser.require(testFile);
|
||||
});
|
||||
after(function() {
|
||||
browser.window.close();
|
||||
});
|
||||
browser.require(testFile);
|
||||
browser.window.$initComponents();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -1 +1 @@
|
||||
<!--M#s0--><div class="a">Hello Frank</div><!--M/s0-->
|
||||
<!--M#s0--><div class="a">Hello Frank</div><!--M/-->
|
||||
@ -1 +1 @@
|
||||
<!--M#s0--><div class="a">Hello Frank</div><!--M/s0-->
|
||||
<!--M#s0--><div class="a">Hello Frank</div><!--M/-->
|
||||
@ -1 +1 @@
|
||||
<!--M#s0--><div class="b">Hello Frank</div><!--M/s0-->
|
||||
<!--M#s0--><div class="b">Hello Frank</div><!--M/-->
|
||||
@ -1 +1 @@
|
||||
<!--M#s0--><div class="b">Hello Jane</div><!--M/s0-->
|
||||
<!--M#s0--><div class="b">Hello Jane</div><!--M/-->
|
||||
@ -42,9 +42,6 @@ autotest("fixtures", fixture => {
|
||||
encoding: "utf8"
|
||||
});
|
||||
|
||||
var parentNode = fromNode;
|
||||
var startNode = fromNode.firstChild;
|
||||
var endNode = null;
|
||||
var toNode = targetVEl;
|
||||
var doc = fromDocument;
|
||||
var componentsContext = {
|
||||
@ -55,14 +52,7 @@ autotest("fixtures", fixture => {
|
||||
}
|
||||
};
|
||||
|
||||
morphdom(
|
||||
parentNode,
|
||||
startNode,
|
||||
endNode,
|
||||
toNode,
|
||||
doc,
|
||||
componentsContext
|
||||
);
|
||||
morphdom(fromNode, toNode, doc, componentsContext);
|
||||
|
||||
var actualHTML = serializeNode(fromNode);
|
||||
snapshot(actualHTML, ".html");
|
||||
|
||||
@ -1 +1 @@
|
||||
<html><body><div class="inner"><div class="inner-inner"><!--M#s0-6--><div>Hello inner-inner</div><!--M/s0-6--></div><!--M#s0-7--><div>Hello inner</div><!--M/s0-7--></div><script>(function(){var w=window;w.$components=(w.$components||[]).concat({"w":[["s0-6",0,{"name":"inner-inner"},{"f":1}],["s0-7",0,{"name":"inner"},{"f":1}]],"t":["/marko-test$1.0.0/render/fixtures-async/components-await-beginAsync/components/hello/index.marko"]})||w.$components})()</script><!--M#s0-8--><div>Hello outer</div><!--M/s0-8--><script>(function(){var w=window;w.$components=(w.$components||[]).concat({"w":[["s0-8",0,{"name":"outer"},{"f":1}]],"t":["/marko-test$1.0.0/render/fixtures-async/components-await-beginAsync/components/hello/index.marko"]})||w.$components})()</script></body></html>
|
||||
<html><body><div class="inner"><div class="inner-inner"><!--M^s0-6 s0 6--><div>Hello inner-inner</div><!--M/--></div><!--M^s0-7 s0 7--><div>Hello inner</div><!--M/--></div><script>(function(){var w=window;w.$components=(w.$components||[]).concat({"w":[["s0-6",0,{"name":"inner-inner"},{"f":1}],["s0-7",0,{"name":"inner"},{"f":1}]],"t":["/marko-test$1.0.0/render/fixtures-async/components-await-beginAsync/components/hello/index.marko"]})||w.$components})()</script><!--M^s0-8 s0 8--><div>Hello outer</div><!--M/--><script>(function(){var w=window;w.$components=(w.$components||[]).concat({"w":[["s0-8",0,{"name":"outer"},{"f":1}]],"t":["/marko-test$1.0.0/render/fixtures-async/components-await-beginAsync/components/hello/index.marko"]})||w.$components})()</script></body></html>
|
||||
@ -1 +1 @@
|
||||
<html><head><title>Welcome Frank</title></head><body><!--M#s0-4--><div>Hello</div><!--M/s0-4--><script>(function(){var w=window;w.$components=(w.$components||[]).concat({"w":[["s0-4",0,{},{"f":1}]],"t":["/marko-test$1.0.0/render/fixtures-async/components-await-title/components/hello/index.marko"]})||w.$components})()</script></body></html>
|
||||
<html><head><title>Welcome Frank</title></head><body><!--M^s0-0-4 s0 4--><div>Hello</div><!--M/--><script>(function(){var w=window;w.$components=(w.$components||[]).concat({"w":[["s0-0-4",0,{},{"f":1}]],"t":["/marko-test$1.0.0/render/fixtures-async/components-await-title/components/hello/index.marko"]})||w.$components})()</script></body></html>
|
||||
@ -0,0 +1 @@
|
||||
exports.skip_vdom = "server-rendered vdom comment boundaries are not a concern";
|
||||
@ -1 +1 @@
|
||||
<html><body><div class="inner"><div class="inner-inner"><!--M#s0-6--><div>Hello inner-inner</div><!--M/s0-6--></div><script>(function(){var w=window;w.$components=(w.$components||[]).concat({"w":[["s0-6",0,{"name":"inner-inner"},{"f":1}]],"t":["/marko-test$1.0.0/render/fixtures-async/components-await/components/hello/index.marko"]})||w.$components})()</script><!--M#s0-7--><div>Hello inner</div><!--M/s0-7--></div><script>(function(){var w=window;w.$components=(w.$components||[]).concat({"w":[["s0-7",0,{"name":"inner"},{"f":1}]],"t":["/marko-test$1.0.0/render/fixtures-async/components-await/components/hello/index.marko"]})||w.$components})()</script><!--M#s0-8--><div>Hello outer</div><!--M/s0-8--><script>(function(){var w=window;w.$components=(w.$components||[]).concat({"w":[["s0-8",0,{"name":"outer"},{"f":1}]],"t":["/marko-test$1.0.0/render/fixtures-async/components-await/components/hello/index.marko"]})||w.$components})()</script></body></html>
|
||||
<html><body><div class="inner"><div class="inner-inner"><!--M^s0-6 s0 6--><div>Hello inner-inner</div><!--M/--></div><script>(function(){var w=window;w.$components=(w.$components||[]).concat({"w":[["s0-6",0,{"name":"inner-inner"},{"f":1}]],"t":["/marko-test$1.0.0/render/fixtures-async/components-await/components/hello/index.marko"]})||w.$components})()</script><!--M^s0-7 s0 7--><div>Hello inner</div><!--M/--></div><script>(function(){var w=window;w.$components=(w.$components||[]).concat({"w":[["s0-7",0,{"name":"inner"},{"f":1}]],"t":["/marko-test$1.0.0/render/fixtures-async/components-await/components/hello/index.marko"]})||w.$components})()</script><!--M^s0-8 s0 8--><div>Hello outer</div><!--M/--><script>(function(){var w=window;w.$components=(w.$components||[]).concat({"w":[["s0-8",0,{"name":"outer"},{"f":1}]],"t":["/marko-test$1.0.0/render/fixtures-async/components-await/components/hello/index.marko"]})||w.$components})()</script></body></html>
|
||||
@ -1 +1 @@
|
||||
<!--M#s0--><div id="s0-buttonDescription">Submit the form thing</div><button aria-described-by="s0-buttonDescription">Submit</button><!--M/s0-->
|
||||
<!--M#s0--><div id="s0-buttonDescription">Submit the form thing</div><button aria-described-by="s0-buttonDescription">Submit</button><!--M/-->
|
||||
@ -1 +1 @@
|
||||
<!--M#s0--><div id="s0-buttonDescription">Submit the form thing</div><button aria-described-by="s0-buttonDescription">Submit</button><!--M/s0-->
|
||||
<!--M#s0--><div id="s0-buttonDescription">Submit the form thing</div><button aria-described-by="s0-buttonDescription">Submit</button><!--M/-->
|
||||
@ -1 +1 @@
|
||||
<!--M#s0--><div><input id="s0-checkbox"><label for="s0-checkbox"></label></div><!--M/s0-->
|
||||
<!--M#s0--><div><input id="s0-checkbox"><label for="s0-checkbox"></label></div><!--M/-->
|
||||
@ -1 +1 @@
|
||||
<div><!--M#s0-1--><div class="hello">Hello Frank!</div><!--M/s0-1--></div>
|
||||
<div><!--M^s0-1 s0 1--><div class="hello">Hello Frank!</div><!--M/--></div>
|
||||
1
test/render/fixtures/component-file-export-class/test.js
Normal file
1
test/render/fixtures/component-file-export-class/test.js
Normal file
@ -0,0 +1 @@
|
||||
exports.skip_vdom = "server-rendered vdom comment boundaries are not a concern";
|
||||
@ -1 +1 @@
|
||||
<!--M#s0--><div><input id="s0-checkbox"><label for="s0-checkbox"></label></div><!--M/s0-->
|
||||
<!--M#s0--><div><input id="s0-checkbox"><label for="s0-checkbox"></label></div><!--M/-->
|
||||
@ -1 +1 @@
|
||||
<!--M#s0--><label for="s0-submitButton">Submit</label><button id="s0-submitButton">Submit</button><!--M/s0-->
|
||||
<!--M#s0--><label for="s0-submitButton">Submit</label><button id="s0-submitButton">Submit</button><!--M/-->
|
||||
@ -1 +1 @@
|
||||
<!--M#s0--><!DOCTYPE html><html lang="en"><body>Hello <script>(function(){var w=window;w.$components=(w.$components||[]).concat({"w":[["s0",0,{"name":"World"},{"f":1,"s":{"foo-0":"bar\u2028","foo-1":"bar\u2029","foo-2":"\u2028bar\u2029","foo-3":"Hello \u003C/script> \u2028bar\u2029"}}]],"t":["/marko-test$1.0.0/render/fixtures/component-safe-json/template.marko"]})||w.$components})()</script></body></html><!--M/s0-->
|
||||
<!--M#s0--><!DOCTYPE html><html lang="en"><body>Hello <script>(function(){var w=window;w.$components=(w.$components||[]).concat({"w":[["s0",0,{"name":"World"},{"f":1,"s":{"foo-0":"bar\u2028","foo-1":"bar\u2029","foo-2":"\u2028bar\u2029","foo-3":"Hello \u003C/script> \u2028bar\u2029"}}]],"t":["/marko-test$1.0.0/render/fixtures/component-safe-json/template.marko"]})||w.$components})()</script></body></html><!--M/-->
|
||||
@ -1 +1 @@
|
||||
<html><head>Components</head><body><!--M#s0-3--><div><h1>foo1</h1><div><h1>bar1</h1></div><div><h1>bar2</h1></div><div><h1>foo-split1</h1><div><h1>split-child1</h1></div><div><h1>split-child2</h1></div></div><div><h1>foo-split2</h1><div><h1>split-child1</h1></div><div><h1>split-child2</h1></div></div></div><!--M/s0-3--><!--M#s0-4--><div><h1>foo2</h1><div><h1>bar1</h1></div><div><h1>bar2</h1></div><div><h1>foo-split1</h1><div><h1>split-child1</h1></div><div><h1>split-child2</h1></div></div><div><h1>foo-split2</h1><div><h1>split-child1</h1></div><div><h1>split-child2</h1></div></div></div><!--M/s0-4--><!--M^s0-5--><div><h1>split1</h1><!--M^s0-5-split-child1--><div><h1>split-child1</h1></div><!--M/s0-5-split-child1--><!--M^s0-5-split-child2--><div><h1>split-child2</h1></div><!--M/s0-5-split-child2--></div><!--M/s0-5--><!--M^s0-6--><div><h1>split2</h1><!--M^s0-6-split-child1--><div><h1>split-child1</h1></div><!--M/s0-6-split-child1--><!--M^s0-6-split-child2--><div><h1>split-child2</h1></div><!--M/s0-6-split-child2--></div><!--M/s0-6--><script>(function(){var w=window;w.$components=(w.$components||[]).concat({"w":[["s0-6-split-child2",0,{"name":"split-child2"},{}],["s0-6-split-child1",0,{"name":"split-child1"},{}],["s0-6",1,{"name":"split2"},{}],["s0-5-split-child2",0,{"name":"split-child2"},{}],["s0-5-split-child1",0,{"name":"split-child1"},{}],["s0-5",1,{"name":"split1"},{}],["s0-4",2,{"name":"foo2"},{"f":1}],["s0-3",2,{"name":"foo1"},{"f":1}]],"t":["/marko-test$1.0.0/render/fixtures/components/components/split/components/split-child/component-browser","/marko-test$1.0.0/render/fixtures/components/components/split/component-browser","/marko-test$1.0.0/render/fixtures/components/components/foo/index.marko"]})||w.$components})()</script></body></html>
|
||||
<html><head>Components</head><body><!--M^s0-3 s0 3--><div><h1>foo1</h1><div><h1>bar1</h1></div><div><h1>bar2</h1></div><div><h1>foo-split1</h1><div><h1>split-child1</h1></div><div><h1>split-child2</h1></div></div><div><h1>foo-split2</h1><div><h1>split-child1</h1></div><div><h1>split-child2</h1></div></div></div><!--M/--><!--M^s0-4 s0 4--><div><h1>foo2</h1><div><h1>bar1</h1></div><div><h1>bar2</h1></div><div><h1>foo-split1</h1><div><h1>split-child1</h1></div><div><h1>split-child2</h1></div></div><div><h1>foo-split2</h1><div><h1>split-child1</h1></div><div><h1>split-child2</h1></div></div></div><!--M/--><!--M^s0-5 s0 5--><div><h1>split1</h1><!--M^s0-5-split-child1 s0-5 split-child1--><div><h1>split-child1</h1></div><!--M/--><!--M^s0-5-split-child2 s0-5 split-child2--><div><h1>split-child2</h1></div><!--M/--></div><!--M/--><!--M^s0-6 s0 6--><div><h1>split2</h1><!--M^s0-6-split-child1 s0-6 split-child1--><div><h1>split-child1</h1></div><!--M/--><!--M^s0-6-split-child2 s0-6 split-child2--><div><h1>split-child2</h1></div><!--M/--></div><!--M/--><script>(function(){var w=window;w.$components=(w.$components||[]).concat({"w":[["s0-6-split-child2",0,{"name":"split-child2"},{}],["s0-6-split-child1",0,{"name":"split-child1"},{}],["s0-6",1,{"name":"split2"},{}],["s0-5-split-child2",0,{"name":"split-child2"},{}],["s0-5-split-child1",0,{"name":"split-child1"},{}],["s0-5",1,{"name":"split1"},{}],["s0-4",2,{"name":"foo2"},{"f":1}],["s0-3",2,{"name":"foo1"},{"f":1}]],"t":["/marko-test$1.0.0/render/fixtures/components/components/split/components/split-child/component-browser","/marko-test$1.0.0/render/fixtures/components/components/split/component-browser","/marko-test$1.0.0/render/fixtures/components/components/foo/index.marko"]})||w.$components})()</script></body></html>
|
||||
Loading…
x
Reference in New Issue
Block a user