This repository has been archived by the owner. It is now read-only.
Permalink
Fetching contributors…
Cannot retrieve contributors at this time
1882 lines (1536 sloc) 37 KB
var _elm_lang$virtual_dom$VirtualDom_Debug$wrap;
var _elm_lang$virtual_dom$VirtualDom_Debug$wrapWithFlags;
var _elm_lang$virtual_dom$Native_VirtualDom = function() {
var STYLE_KEY = 'STYLE';
var EVENT_KEY = 'EVENT';
var ATTR_KEY = 'ATTR';
var ATTR_NS_KEY = 'ATTR_NS';
var localDoc = typeof document !== 'undefined' ? document : {};
//////////// VIRTUAL DOM NODES ////////////
function text(string)
{
return {
type: 'text',
text: string
};
}
function node(tag)
{
return F2(function(factList, kidList) {
return nodeHelp(tag, factList, kidList);
});
}
function nodeHelp(tag, factList, kidList)
{
var organized = organizeFacts(factList);
var namespace = organized.namespace;
var facts = organized.facts;
var children = [];
var descendantsCount = 0;
while (kidList.ctor !== '[]')
{
var kid = kidList._0;
descendantsCount += (kid.descendantsCount || 0);
children.push(kid);
kidList = kidList._1;
}
descendantsCount += children.length;
return {
type: 'node',
tag: tag,
facts: facts,
children: children,
namespace: namespace,
descendantsCount: descendantsCount
};
}
function keyedNode(tag, factList, kidList)
{
var organized = organizeFacts(factList);
var namespace = organized.namespace;
var facts = organized.facts;
var children = [];
var descendantsCount = 0;
while (kidList.ctor !== '[]')
{
var kid = kidList._0;
descendantsCount += (kid._1.descendantsCount || 0);
children.push(kid);
kidList = kidList._1;
}
descendantsCount += children.length;
return {
type: 'keyed-node',
tag: tag,
facts: facts,
children: children,
namespace: namespace,
descendantsCount: descendantsCount
};
}
function custom(factList, model, impl)
{
var facts = organizeFacts(factList).facts;
return {
type: 'custom',
facts: facts,
model: model,
impl: impl
};
}
function map(tagger, node)
{
return {
type: 'tagger',
tagger: tagger,
node: node,
descendantsCount: 1 + (node.descendantsCount || 0)
};
}
function thunk(func, args, thunk)
{
return {
type: 'thunk',
func: func,
args: args,
thunk: thunk,
node: undefined
};
}
function lazy(fn, a)
{
return thunk(fn, [a], function() {
return fn(a);
});
}
function lazy2(fn, a, b)
{
return thunk(fn, [a,b], function() {
return A2(fn, a, b);
});
}
function lazy3(fn, a, b, c)
{
return thunk(fn, [a,b,c], function() {
return A3(fn, a, b, c);
});
}
// FACTS
function organizeFacts(factList)
{
var namespace, facts = {};
while (factList.ctor !== '[]')
{
var entry = factList._0;
var key = entry.key;
if (key === ATTR_KEY || key === ATTR_NS_KEY || key === EVENT_KEY)
{
var subFacts = facts[key] || {};
subFacts[entry.realKey] = entry.value;
facts[key] = subFacts;
}
else if (key === STYLE_KEY)
{
var styles = facts[key] || {};
var styleList = entry.value;
while (styleList.ctor !== '[]')
{
var style = styleList._0;
styles[style._0] = style._1;
styleList = styleList._1;
}
facts[key] = styles;
}
else if (key === 'namespace')
{
namespace = entry.value;
}
else if (key === 'className')
{
var classes = facts[key];
facts[key] = typeof classes === 'undefined'
? entry.value
: classes + ' ' + entry.value;
}
else
{
facts[key] = entry.value;
}
factList = factList._1;
}
return {
facts: facts,
namespace: namespace
};
}
//////////// PROPERTIES AND ATTRIBUTES ////////////
function style(value)
{
return {
key: STYLE_KEY,
value: value
};
}
function property(key, value)
{
return {
key: key,
value: value
};
}
function attribute(key, value)
{
return {
key: ATTR_KEY,
realKey: key,
value: value
};
}
function attributeNS(namespace, key, value)
{
return {
key: ATTR_NS_KEY,
realKey: key,
value: {
value: value,
namespace: namespace
}
};
}
function on(name, options, decoder)
{
return {
key: EVENT_KEY,
realKey: name,
value: {
options: options,
decoder: decoder
}
};
}
function equalEvents(a, b)
{
if (a.options !== b.options)
{
if (a.options.stopPropagation !== b.options.stopPropagation || a.options.preventDefault !== b.options.preventDefault)
{
return false;
}
}
return _elm_lang$core$Native_Json.equality(a.decoder, b.decoder);
}
function mapProperty(func, property)
{
if (property.key !== EVENT_KEY)
{
return property;
}
return on(
property.realKey,
property.value.options,
A2(_elm_lang$core$Json_Decode$map, func, property.value.decoder)
);
}
//////////// RENDER ////////////
function render(vNode, eventNode)
{
switch (vNode.type)
{
case 'thunk':
if (!vNode.node)
{
vNode.node = vNode.thunk();
}
return render(vNode.node, eventNode);
case 'tagger':
var subNode = vNode.node;
var tagger = vNode.tagger;
while (subNode.type === 'tagger')
{
typeof tagger !== 'object'
? tagger = [tagger, subNode.tagger]
: tagger.push(subNode.tagger);
subNode = subNode.node;
}
var subEventRoot = { tagger: tagger, parent: eventNode };
var domNode = render(subNode, subEventRoot);
domNode.elm_event_node_ref = subEventRoot;
return domNode;
case 'text':
return localDoc.createTextNode(vNode.text);
case 'node':
var domNode = vNode.namespace
? localDoc.createElementNS(vNode.namespace, vNode.tag)
: localDoc.createElement(vNode.tag);
applyFacts(domNode, eventNode, vNode.facts);
var children = vNode.children;
for (var i = 0; i < children.length; i++)
{
domNode.appendChild(render(children[i], eventNode));
}
return domNode;
case 'keyed-node':
var domNode = vNode.namespace
? localDoc.createElementNS(vNode.namespace, vNode.tag)
: localDoc.createElement(vNode.tag);
applyFacts(domNode, eventNode, vNode.facts);
var children = vNode.children;
for (var i = 0; i < children.length; i++)
{
domNode.appendChild(render(children[i]._1, eventNode));
}
return domNode;
case 'custom':
var domNode = vNode.impl.render(vNode.model);
applyFacts(domNode, eventNode, vNode.facts);
return domNode;
}
}
//////////// APPLY FACTS ////////////
function applyFacts(domNode, eventNode, facts)
{
for (var key in facts)
{
var value = facts[key];
switch (key)
{
case STYLE_KEY:
applyStyles(domNode, value);
break;
case EVENT_KEY:
applyEvents(domNode, eventNode, value);
break;
case ATTR_KEY:
applyAttrs(domNode, value);
break;
case ATTR_NS_KEY:
applyAttrsNS(domNode, value);
break;
case 'value':
if (domNode[key] !== value)
{
domNode[key] = value;
}
break;
default:
domNode[key] = value;
break;
}
}
}
function applyStyles(domNode, styles)
{
var domNodeStyle = domNode.style;
for (var key in styles)
{
domNodeStyle[key] = styles[key];
}
}
function applyEvents(domNode, eventNode, events)
{
var allHandlers = domNode.elm_handlers || {};
for (var key in events)
{
var handler = allHandlers[key];
var value = events[key];
if (typeof value === 'undefined')
{
domNode.removeEventListener(key, handler);
allHandlers[key] = undefined;
}
else if (typeof handler === 'undefined')
{
var handler = makeEventHandler(eventNode, value);
domNode.addEventListener(key, handler);
allHandlers[key] = handler;
}
else
{
handler.info = value;
}
}
domNode.elm_handlers = allHandlers;
}
function makeEventHandler(eventNode, info)
{
function eventHandler(event)
{
var info = eventHandler.info;
var value = A2(_elm_lang$core$Native_Json.run, info.decoder, event);
if (value.ctor === 'Ok')
{
var options = info.options;
if (options.stopPropagation)
{
event.stopPropagation();
}
if (options.preventDefault)
{
event.preventDefault();
}
var message = value._0;
var currentEventNode = eventNode;
while (currentEventNode)
{
var tagger = currentEventNode.tagger;
if (typeof tagger === 'function')
{
message = tagger(message);
}
else
{
for (var i = tagger.length; i--; )
{
message = tagger[i](message);
}
}
currentEventNode = currentEventNode.parent;
}
}
};
eventHandler.info = info;
return eventHandler;
}
function applyAttrs(domNode, attrs)
{
for (var key in attrs)
{
var value = attrs[key];
if (typeof value === 'undefined')
{
domNode.removeAttribute(key);
}
else
{
domNode.setAttribute(key, value);
}
}
}
function applyAttrsNS(domNode, nsAttrs)
{
for (var key in nsAttrs)
{
var pair = nsAttrs[key];
var namespace = pair.namespace;
var value = pair.value;
if (typeof value === 'undefined')
{
domNode.removeAttributeNS(namespace, key);
}
else
{
domNode.setAttributeNS(namespace, key, value);
}
}
}
//////////// DIFF ////////////
function diff(a, b)
{
var patches = [];
diffHelp(a, b, patches, 0);
return patches;
}
function makePatch(type, index, data)
{
return {
index: index,
type: type,
data: data,
domNode: undefined,
eventNode: undefined
};
}
function diffHelp(a, b, patches, index)
{
if (a === b)
{
return;
}
var aType = a.type;
var bType = b.type;
// Bail if you run into different types of nodes. Implies that the
// structure has changed significantly and it's not worth a diff.
if (aType !== bType)
{
patches.push(makePatch('p-redraw', index, b));
return;
}
// Now we know that both nodes are the same type.
switch (bType)
{
case 'thunk':
var aArgs = a.args;
var bArgs = b.args;
var i = aArgs.length;
var same = a.func === b.func && i === bArgs.length;
while (same && i--)
{
same = aArgs[i] === bArgs[i];
}
if (same)
{
b.node = a.node;
return;
}
b.node = b.thunk();
var subPatches = [];
diffHelp(a.node, b.node, subPatches, 0);
if (subPatches.length > 0)
{
patches.push(makePatch('p-thunk', index, subPatches));
}
return;
case 'tagger':
// gather nested taggers
var aTaggers = a.tagger;
var bTaggers = b.tagger;
var nesting = false;
var aSubNode = a.node;
while (aSubNode.type === 'tagger')
{
nesting = true;
typeof aTaggers !== 'object'
? aTaggers = [aTaggers, aSubNode.tagger]
: aTaggers.push(aSubNode.tagger);
aSubNode = aSubNode.node;
}
var bSubNode = b.node;
while (bSubNode.type === 'tagger')
{
nesting = true;
typeof bTaggers !== 'object'
? bTaggers = [bTaggers, bSubNode.tagger]
: bTaggers.push(bSubNode.tagger);
bSubNode = bSubNode.node;
}
// Just bail if different numbers of taggers. This implies the
// structure of the virtual DOM has changed.
if (nesting && aTaggers.length !== bTaggers.length)
{
patches.push(makePatch('p-redraw', index, b));
return;
}
// check if taggers are "the same"
if (nesting ? !pairwiseRefEqual(aTaggers, bTaggers) : aTaggers !== bTaggers)
{
patches.push(makePatch('p-tagger', index, bTaggers));
}
// diff everything below the taggers
diffHelp(aSubNode, bSubNode, patches, index + 1);
return;
case 'text':
if (a.text !== b.text)
{
patches.push(makePatch('p-text', index, b.text));
return;
}
return;
case 'node':
// Bail if obvious indicators have changed. Implies more serious
// structural changes such that it's not worth it to diff.
if (a.tag !== b.tag || a.namespace !== b.namespace)
{
patches.push(makePatch('p-redraw', index, b));
return;
}
var factsDiff = diffFacts(a.facts, b.facts);
if (typeof factsDiff !== 'undefined')
{
patches.push(makePatch('p-facts', index, factsDiff));
}
diffChildren(a, b, patches, index);
return;
case 'keyed-node':
// Bail if obvious indicators have changed. Implies more serious
// structural changes such that it's not worth it to diff.
if (a.tag !== b.tag || a.namespace !== b.namespace)
{
patches.push(makePatch('p-redraw', index, b));
return;
}
var factsDiff = diffFacts(a.facts, b.facts);
if (typeof factsDiff !== 'undefined')
{
patches.push(makePatch('p-facts', index, factsDiff));
}
diffKeyedChildren(a, b, patches, index);
return;
case 'custom':
if (a.impl !== b.impl)
{
patches.push(makePatch('p-redraw', index, b));
return;
}
var factsDiff = diffFacts(a.facts, b.facts);
if (typeof factsDiff !== 'undefined')
{
patches.push(makePatch('p-facts', index, factsDiff));
}
var patch = b.impl.diff(a,b);
if (patch)
{
patches.push(makePatch('p-custom', index, patch));
return;
}
return;
}
}
// assumes the incoming arrays are the same length
function pairwiseRefEqual(as, bs)
{
for (var i = 0; i < as.length; i++)
{
if (as[i] !== bs[i])
{
return false;
}
}
return true;
}
// TODO Instead of creating a new diff object, it's possible to just test if
// there *is* a diff. During the actual patch, do the diff again and make the
// modifications directly. This way, there's no new allocations. Worth it?
function diffFacts(a, b, category)
{
var diff;
// look for changes and removals
for (var aKey in a)
{
if (aKey === STYLE_KEY || aKey === EVENT_KEY || aKey === ATTR_KEY || aKey === ATTR_NS_KEY)
{
var subDiff = diffFacts(a[aKey], b[aKey] || {}, aKey);
if (subDiff)
{
diff = diff || {};
diff[aKey] = subDiff;
}
continue;
}
// remove if not in the new facts
if (!(aKey in b))
{
diff = diff || {};
diff[aKey] =
(typeof category === 'undefined')
? (typeof a[aKey] === 'string' ? '' : null)
:
(category === STYLE_KEY)
? ''
:
(category === EVENT_KEY || category === ATTR_KEY)
? undefined
:
{ namespace: a[aKey].namespace, value: undefined };
continue;
}
var aValue = a[aKey];
var bValue = b[aKey];
// reference equal, so don't worry about it
if (aValue === bValue && aKey !== 'value'
|| category === EVENT_KEY && equalEvents(aValue, bValue))
{
continue;
}
diff = diff || {};
diff[aKey] = bValue;
}
// add new stuff
for (var bKey in b)
{
if (!(bKey in a))
{
diff = diff || {};
diff[bKey] = b[bKey];
}
}
return diff;
}
function diffChildren(aParent, bParent, patches, rootIndex)
{
var aChildren = aParent.children;
var bChildren = bParent.children;
var aLen = aChildren.length;
var bLen = bChildren.length;
// FIGURE OUT IF THERE ARE INSERTS OR REMOVALS
if (aLen > bLen)
{
patches.push(makePatch('p-remove-last', rootIndex, aLen - bLen));
}
else if (aLen < bLen)
{
patches.push(makePatch('p-append', rootIndex, bChildren.slice(aLen)));
}
// PAIRWISE DIFF EVERYTHING ELSE
var index = rootIndex;
var minLen = aLen < bLen ? aLen : bLen;
for (var i = 0; i < minLen; i++)
{
index++;
var aChild = aChildren[i];
diffHelp(aChild, bChildren[i], patches, index);
index += aChild.descendantsCount || 0;
}
}
//////////// KEYED DIFF ////////////
function diffKeyedChildren(aParent, bParent, patches, rootIndex)
{
var localPatches = [];
var changes = {}; // Dict String Entry
var inserts = []; // Array { index : Int, entry : Entry }
// type Entry = { tag : String, vnode : VNode, index : Int, data : _ }
var aChildren = aParent.children;
var bChildren = bParent.children;
var aLen = aChildren.length;
var bLen = bChildren.length;
var aIndex = 0;
var bIndex = 0;
var index = rootIndex;
while (aIndex < aLen && bIndex < bLen)
{
var a = aChildren[aIndex];
var b = bChildren[bIndex];
var aKey = a._0;
var bKey = b._0;
var aNode = a._1;
var bNode = b._1;
// check if keys match
if (aKey === bKey)
{
index++;
diffHelp(aNode, bNode, localPatches, index);
index += aNode.descendantsCount || 0;
aIndex++;
bIndex++;
continue;
}
// look ahead 1 to detect insertions and removals.
var aLookAhead = aIndex + 1 < aLen;
var bLookAhead = bIndex + 1 < bLen;
if (aLookAhead)
{
var aNext = aChildren[aIndex + 1];
var aNextKey = aNext._0;
var aNextNode = aNext._1;
var oldMatch = bKey === aNextKey;
}
if (bLookAhead)
{
var bNext = bChildren[bIndex + 1];
var bNextKey = bNext._0;
var bNextNode = bNext._1;
var newMatch = aKey === bNextKey;
}
// swap a and b
if (aLookAhead && bLookAhead && newMatch && oldMatch)
{
index++;
diffHelp(aNode, bNextNode, localPatches, index);
insertNode(changes, localPatches, aKey, bNode, bIndex, inserts);
index += aNode.descendantsCount || 0;
index++;
removeNode(changes, localPatches, aKey, aNextNode, index);
index += aNextNode.descendantsCount || 0;
aIndex += 2;
bIndex += 2;
continue;
}
// insert b
if (bLookAhead && newMatch)
{
index++;
insertNode(changes, localPatches, bKey, bNode, bIndex, inserts);
diffHelp(aNode, bNextNode, localPatches, index);
index += aNode.descendantsCount || 0;
aIndex += 1;
bIndex += 2;
continue;
}
// remove a
if (aLookAhead && oldMatch)
{
index++;
removeNode(changes, localPatches, aKey, aNode, index);
index += aNode.descendantsCount || 0;
index++;
diffHelp(aNextNode, bNode, localPatches, index);
index += aNextNode.descendantsCount || 0;
aIndex += 2;
bIndex += 1;
continue;
}
// remove a, insert b
if (aLookAhead && bLookAhead && aNextKey === bNextKey)
{
index++;
removeNode(changes, localPatches, aKey, aNode, index);
insertNode(changes, localPatches, bKey, bNode, bIndex, inserts);
index += aNode.descendantsCount || 0;
index++;
diffHelp(aNextNode, bNextNode, localPatches, index);
index += aNextNode.descendantsCount || 0;
aIndex += 2;
bIndex += 2;
continue;
}
break;
}
// eat up any remaining nodes with removeNode and insertNode
while (aIndex < aLen)
{
index++;
var a = aChildren[aIndex];
var aNode = a._1;
removeNode(changes, localPatches, a._0, aNode, index);
index += aNode.descendantsCount || 0;
aIndex++;
}
var endInserts;
while (bIndex < bLen)
{
endInserts = endInserts || [];
var b = bChildren[bIndex];
insertNode(changes, localPatches, b._0, b._1, undefined, endInserts);
bIndex++;
}
if (localPatches.length > 0 || inserts.length > 0 || typeof endInserts !== 'undefined')
{
patches.push(makePatch('p-reorder', rootIndex, {
patches: localPatches,
inserts: inserts,
endInserts: endInserts
}));
}
}
//////////// CHANGES FROM KEYED DIFF ////////////
var POSTFIX = '_elmW6BL';
function insertNode(changes, localPatches, key, vnode, bIndex, inserts)
{
var entry = changes[key];
// never seen this key before
if (typeof entry === 'undefined')
{
entry = {
tag: 'insert',
vnode: vnode,
index: bIndex,
data: undefined
};
inserts.push({ index: bIndex, entry: entry });
changes[key] = entry;
return;
}
// this key was removed earlier, a match!
if (entry.tag === 'remove')
{
inserts.push({ index: bIndex, entry: entry });
entry.tag = 'move';
var subPatches = [];
diffHelp(entry.vnode, vnode, subPatches, entry.index);
entry.index = bIndex;
entry.data.data = {
patches: subPatches,
entry: entry
};
return;
}
// this key has already been inserted or moved, a duplicate!
insertNode(changes, localPatches, key + POSTFIX, vnode, bIndex, inserts);
}
function removeNode(changes, localPatches, key, vnode, index)
{
var entry = changes[key];
// never seen this key before
if (typeof entry === 'undefined')
{
var patch = makePatch('p-remove', index, undefined);
localPatches.push(patch);
changes[key] = {
tag: 'remove',
vnode: vnode,
index: index,
data: patch
};
return;
}
// this key was inserted earlier, a match!
if (entry.tag === 'insert')
{
entry.tag = 'move';
var subPatches = [];
diffHelp(vnode, entry.vnode, subPatches, index);
var patch = makePatch('p-remove', index, {
patches: subPatches,
entry: entry
});
localPatches.push(patch);
return;
}
// this key has already been removed or moved, a duplicate!
removeNode(changes, localPatches, key + POSTFIX, vnode, index);
}
//////////// ADD DOM NODES ////////////
//
// Each DOM node has an "index" assigned in order of traversal. It is important
// to minimize our crawl over the actual DOM, so these indexes (along with the
// descendantsCount of virtual nodes) let us skip touching entire subtrees of
// the DOM if we know there are no patches there.
function addDomNodes(domNode, vNode, patches, eventNode)
{
addDomNodesHelp(domNode, vNode, patches, 0, 0, vNode.descendantsCount, eventNode);
}
// assumes `patches` is non-empty and indexes increase monotonically.
function addDomNodesHelp(domNode, vNode, patches, i, low, high, eventNode)
{
var patch = patches[i];
var index = patch.index;
while (index === low)
{
var patchType = patch.type;
if (patchType === 'p-thunk')
{
addDomNodes(domNode, vNode.node, patch.data, eventNode);
}
else if (patchType === 'p-reorder')
{
patch.domNode = domNode;
patch.eventNode = eventNode;
var subPatches = patch.data.patches;
if (subPatches.length > 0)
{
addDomNodesHelp(domNode, vNode, subPatches, 0, low, high, eventNode);
}
}
else if (patchType === 'p-remove')
{
patch.domNode = domNode;
patch.eventNode = eventNode;
var data = patch.data;
if (typeof data !== 'undefined')
{
data.entry.data = domNode;
var subPatches = data.patches;
if (subPatches.length > 0)
{
addDomNodesHelp(domNode, vNode, subPatches, 0, low, high, eventNode);
}
}
}
else
{
patch.domNode = domNode;
patch.eventNode = eventNode;
}
i++;
if (!(patch = patches[i]) || (index = patch.index) > high)
{
return i;
}
}
switch (vNode.type)
{
case 'tagger':
var subNode = vNode.node;
while (subNode.type === "tagger")
{
subNode = subNode.node;
}
return addDomNodesHelp(domNode, subNode, patches, i, low + 1, high, domNode.elm_event_node_ref);
case 'node':
var vChildren = vNode.children;
var childNodes = domNode.childNodes;
for (var j = 0; j < vChildren.length; j++)
{
low++;
var vChild = vChildren[j];
var nextLow = low + (vChild.descendantsCount || 0);
if (low <= index && index <= nextLow)
{
i = addDomNodesHelp(childNodes[j], vChild, patches, i, low, nextLow, eventNode);
if (!(patch = patches[i]) || (index = patch.index) > high)
{
return i;
}
}
low = nextLow;
}
return i;
case 'keyed-node':
var vChildren = vNode.children;
var childNodes = domNode.childNodes;
for (var j = 0; j < vChildren.length; j++)
{
low++;
var vChild = vChildren[j]._1;
var nextLow = low + (vChild.descendantsCount || 0);
if (low <= index && index <= nextLow)
{
i = addDomNodesHelp(childNodes[j], vChild, patches, i, low, nextLow, eventNode);
if (!(patch = patches[i]) || (index = patch.index) > high)
{
return i;
}
}
low = nextLow;
}
return i;
case 'text':
case 'thunk':
throw new Error('should never traverse `text` or `thunk` nodes like this');
}
}
//////////// APPLY PATCHES ////////////
function applyPatches(rootDomNode, oldVirtualNode, patches, eventNode)
{
if (patches.length === 0)
{
return rootDomNode;
}
addDomNodes(rootDomNode, oldVirtualNode, patches, eventNode);
return applyPatchesHelp(rootDomNode, patches);
}
function applyPatchesHelp(rootDomNode, patches)
{
for (var i = 0; i < patches.length; i++)
{
var patch = patches[i];
var localDomNode = patch.domNode
var newNode = applyPatch(localDomNode, patch);
if (localDomNode === rootDomNode)
{
rootDomNode = newNode;
}
}
return rootDomNode;
}
function applyPatch(domNode, patch)
{
switch (patch.type)
{
case 'p-redraw':
return applyPatchRedraw(domNode, patch.data, patch.eventNode);
case 'p-facts':
applyFacts(domNode, patch.eventNode, patch.data);
return domNode;
case 'p-text':
domNode.replaceData(0, domNode.length, patch.data);
return domNode;
case 'p-thunk':
return applyPatchesHelp(domNode, patch.data);
case 'p-tagger':
if (typeof domNode.elm_event_node_ref !== 'undefined')
{
domNode.elm_event_node_ref.tagger = patch.data;
}
else
{
domNode.elm_event_node_ref = { tagger: patch.data, parent: patch.eventNode };
}
return domNode;
case 'p-remove-last':
var i = patch.data;
while (i--)
{
domNode.removeChild(domNode.lastChild);
}
return domNode;
case 'p-append':
var newNodes = patch.data;
for (var i = 0; i < newNodes.length; i++)
{
domNode.appendChild(render(newNodes[i], patch.eventNode));
}
return domNode;
case 'p-remove':
var data = patch.data;
if (typeof data === 'undefined')
{
domNode.parentNode.removeChild(domNode);
return domNode;
}
var entry = data.entry;
if (typeof entry.index !== 'undefined')
{
domNode.parentNode.removeChild(domNode);
}
entry.data = applyPatchesHelp(domNode, data.patches);
return domNode;
case 'p-reorder':
return applyPatchReorder(domNode, patch);
case 'p-custom':
var impl = patch.data;
return impl.applyPatch(domNode, impl.data);
default:
throw new Error('Ran into an unknown patch!');
}
}
function applyPatchRedraw(domNode, vNode, eventNode)
{
var parentNode = domNode.parentNode;
var newNode = render(vNode, eventNode);
if (typeof newNode.elm_event_node_ref === 'undefined')
{
newNode.elm_event_node_ref = domNode.elm_event_node_ref;
}
if (parentNode && newNode !== domNode)
{
parentNode.replaceChild(newNode, domNode);
}
return newNode;
}
function applyPatchReorder(domNode, patch)
{
var data = patch.data;
// remove end inserts
var frag = applyPatchReorderEndInsertsHelp(data.endInserts, patch);
// removals
domNode = applyPatchesHelp(domNode, data.patches);
// inserts
var inserts = data.inserts;
for (var i = 0; i < inserts.length; i++)
{
var insert = inserts[i];
var entry = insert.entry;
var node = entry.tag === 'move'
? entry.data
: render(entry.vnode, patch.eventNode);
domNode.insertBefore(node, domNode.childNodes[insert.index]);
}
// add end inserts
if (typeof frag !== 'undefined')
{
domNode.appendChild(frag);
}
return domNode;
}
function applyPatchReorderEndInsertsHelp(endInserts, patch)
{
if (typeof endInserts === 'undefined')
{
return;
}
var frag = localDoc.createDocumentFragment();
for (var i = 0; i < endInserts.length; i++)
{
var insert = endInserts[i];
var entry = insert.entry;
frag.appendChild(entry.tag === 'move'
? entry.data
: render(entry.vnode, patch.eventNode)
);
}
return frag;
}
// PROGRAMS
var program = makeProgram(checkNoFlags);
var programWithFlags = makeProgram(checkYesFlags);
function makeProgram(flagChecker)
{
return F2(function(debugWrap, impl)
{
return function(flagDecoder)
{
return function(object, moduleName, debugMetadata)
{
var checker = flagChecker(flagDecoder, moduleName);
if (typeof debugMetadata === 'undefined')
{
normalSetup(impl, object, moduleName, checker);
}
else
{
debugSetup(A2(debugWrap, debugMetadata, impl), object, moduleName, checker);
}
};
};
});
}
function staticProgram(vNode)
{
var nothing = _elm_lang$core$Native_Utils.Tuple2(
_elm_lang$core$Native_Utils.Tuple0,
_elm_lang$core$Platform_Cmd$none
);
return A2(program, _elm_lang$virtual_dom$VirtualDom_Debug$wrap, {
init: nothing,
view: function() { return vNode; },
update: F2(function() { return nothing; }),
subscriptions: function() { return _elm_lang$core$Platform_Sub$none; }
})();
}
// FLAG CHECKERS
function checkNoFlags(flagDecoder, moduleName)
{
return function(init, flags, domNode)
{
if (typeof flags === 'undefined')
{
return init;
}
var errorMessage =
'The `' + moduleName + '` module does not need flags.\n'
+ 'Initialize it with no arguments and you should be all set!';
crash(errorMessage, domNode);
};
}
function checkYesFlags(flagDecoder, moduleName)
{
return function(init, flags, domNode)
{
if (typeof flagDecoder === 'undefined')
{
var errorMessage =
'Are you trying to sneak a Never value into Elm? Trickster!\n'
+ 'It looks like ' + moduleName + '.main is defined with `programWithFlags` but has type `Program Never`.\n'
+ 'Use `program` instead if you do not want flags.'
crash(errorMessage, domNode);
}
var result = A2(_elm_lang$core$Native_Json.run, flagDecoder, flags);
if (result.ctor === 'Ok')
{
return init(result._0);
}
var errorMessage =
'Trying to initialize the `' + moduleName + '` module with an unexpected flag.\n'
+ 'I tried to convert it to an Elm value, but ran into this problem:\n\n'
+ result._0;
crash(errorMessage, domNode);
};
}
function crash(errorMessage, domNode)
{
if (domNode)
{
domNode.innerHTML =
'<div style="padding-left:1em;">'
+ '<h2 style="font-weight:normal;"><b>Oops!</b> Something went wrong when starting your Elm program.</h2>'
+ '<pre style="padding-left:1em;">' + errorMessage + '</pre>'
+ '</div>';
}
throw new Error(errorMessage);
}
// NORMAL SETUP
function normalSetup(impl, object, moduleName, flagChecker)
{
object['embed'] = function embed(node, flags)
{
while (node.lastChild)
{
node.removeChild(node.lastChild);
}
return _elm_lang$core$Native_Platform.initialize(
flagChecker(impl.init, flags, node),
impl.update,
impl.subscriptions,
normalRenderer(node, impl.view)
);
};
object['fullscreen'] = function fullscreen(flags)
{
return _elm_lang$core$Native_Platform.initialize(
flagChecker(impl.init, flags, document.body),
impl.update,
impl.subscriptions,
normalRenderer(document.body, impl.view)
);
};
}
function normalRenderer(parentNode, view)
{
return function(tagger, initialModel)
{
var eventNode = { tagger: tagger, parent: undefined };
var initialVirtualNode = view(initialModel);
var domNode = render(initialVirtualNode, eventNode);
parentNode.appendChild(domNode);
return makeStepper(domNode, view, initialVirtualNode, eventNode);
};
}
// STEPPER
var rAF =
typeof requestAnimationFrame !== 'undefined'
? requestAnimationFrame
: function(callback) { setTimeout(callback, 1000 / 60); };
function makeStepper(domNode, view, initialVirtualNode, eventNode)
{
var state = 'NO_REQUEST';
var currNode = initialVirtualNode;
var nextModel;
function updateIfNeeded()
{
switch (state)
{
case 'NO_REQUEST':
throw new Error(
'Unexpected draw callback.\n' +
'Please report this to <https://github.com/elm-lang/virtual-dom/issues>.'
);
case 'PENDING_REQUEST':
rAF(updateIfNeeded);
state = 'EXTRA_REQUEST';
var nextNode = view(nextModel);
var patches = diff(currNode, nextNode);
domNode = applyPatches(domNode, currNode, patches, eventNode);
currNode = nextNode;
return;
case 'EXTRA_REQUEST':
state = 'NO_REQUEST';
return;
}
}
return function stepper(model)
{
if (state === 'NO_REQUEST')
{
rAF(updateIfNeeded);
}
state = 'PENDING_REQUEST';
nextModel = model;
};
}
// DEBUG SETUP
function debugSetup(impl, object, moduleName, flagChecker)
{
object['fullscreen'] = function fullscreen(flags)
{
var popoutRef = { doc: undefined };
return _elm_lang$core$Native_Platform.initialize(
flagChecker(impl.init, flags, document.body),
impl.update(scrollTask(popoutRef)),
impl.subscriptions,
debugRenderer(moduleName, document.body, popoutRef, impl.view, impl.viewIn, impl.viewOut)
);
};
object['embed'] = function fullscreen(node, flags)
{
var popoutRef = { doc: undefined };
return _elm_lang$core$Native_Platform.initialize(
flagChecker(impl.init, flags, node),
impl.update(scrollTask(popoutRef)),
impl.subscriptions,
debugRenderer(moduleName, node, popoutRef, impl.view, impl.viewIn, impl.viewOut)
);
};
}
function scrollTask(popoutRef)
{
return _elm_lang$core$Native_Scheduler.nativeBinding(function(callback)
{
var doc = popoutRef.doc;
if (doc)
{
var msgs = doc.getElementsByClassName('debugger-sidebar-messages')[0];
if (msgs)
{
msgs.scrollTop = msgs.scrollHeight;
}
}
callback(_elm_lang$core$Native_Scheduler.succeed(_elm_lang$core$Native_Utils.Tuple0));
});
}
function debugRenderer(moduleName, parentNode, popoutRef, view, viewIn, viewOut)
{
return function(tagger, initialModel)
{
var appEventNode = { tagger: tagger, parent: undefined };
var eventNode = { tagger: tagger, parent: undefined };
// make normal stepper
var appVirtualNode = view(initialModel);
var appNode = render(appVirtualNode, appEventNode);
parentNode.appendChild(appNode);
var appStepper = makeStepper(appNode, view, appVirtualNode, appEventNode);
// make overlay stepper
var overVirtualNode = viewIn(initialModel)._1;
var overNode = render(overVirtualNode, eventNode);
parentNode.appendChild(overNode);
var wrappedViewIn = wrapViewIn(appEventNode, overNode, viewIn);
var overStepper = makeStepper(overNode, wrappedViewIn, overVirtualNode, eventNode);
// make debugger stepper
var debugStepper = makeDebugStepper(initialModel, viewOut, eventNode, parentNode, moduleName, popoutRef);
return function stepper(model)
{
appStepper(model);
overStepper(model);
debugStepper(model);
}
};
}
function makeDebugStepper(initialModel, view, eventNode, parentNode, moduleName, popoutRef)
{
var curr;
var domNode;
return function stepper(model)
{
if (!model.isDebuggerOpen)
{
return;
}
if (!popoutRef.doc)
{
curr = view(model);
domNode = openDebugWindow(moduleName, popoutRef, curr, eventNode);
return;
}
// switch to document of popout
localDoc = popoutRef.doc;
var next = view(model);
var patches = diff(curr, next);
domNode = applyPatches(domNode, curr, patches, eventNode);
curr = next;
// switch back to normal document
localDoc = document;
};
}
function openDebugWindow(moduleName, popoutRef, virtualNode, eventNode)
{
var w = 900;
var h = 360;
var x = screen.width - w;
var y = screen.height - h;
var debugWindow = window.open('', '', 'width=' + w + ',height=' + h + ',left=' + x + ',top=' + y);
// switch to window document
localDoc = debugWindow.document;
popoutRef.doc = localDoc;
localDoc.title = 'Debugger - ' + moduleName;
localDoc.body.style.margin = '0';
localDoc.body.style.padding = '0';
var domNode = render(virtualNode, eventNode);
localDoc.body.appendChild(domNode);
localDoc.addEventListener('keydown', function(event) {
if (event.metaKey && event.which === 82)
{
window.location.reload();
}
if (event.which === 38)
{
eventNode.tagger({ ctor: 'Up' });
event.preventDefault();
}
if (event.which === 40)
{
eventNode.tagger({ ctor: 'Down' });
event.preventDefault();
}
});
function close()
{
popoutRef.doc = undefined;
debugWindow.close();
}
window.addEventListener('unload', close);
debugWindow.addEventListener('unload', function() {
popoutRef.doc = undefined;
window.removeEventListener('unload', close);
eventNode.tagger({ ctor: 'Close' });
});
// switch back to the normal document
localDoc = document;
return domNode;
}
// BLOCK EVENTS
function wrapViewIn(appEventNode, overlayNode, viewIn)
{
var ignorer = makeIgnorer(overlayNode);
var blocking = 'Normal';
var overflow;
var normalTagger = appEventNode.tagger;
var blockTagger = function() {};
return function(model)
{
var tuple = viewIn(model);
var newBlocking = tuple._0.ctor;
appEventNode.tagger = newBlocking === 'Normal' ? normalTagger : blockTagger;
if (blocking !== newBlocking)
{
traverse('removeEventListener', ignorer, blocking);
traverse('addEventListener', ignorer, newBlocking);
if (blocking === 'Normal')
{
overflow = document.body.style.overflow;
document.body.style.overflow = 'hidden';
}
if (newBlocking === 'Normal')
{
document.body.style.overflow = overflow;
}
blocking = newBlocking;
}
return tuple._1;
}
}
function traverse(verbEventListener, ignorer, blocking)
{
switch(blocking)
{
case 'Normal':
return;
case 'Pause':
return traverseHelp(verbEventListener, ignorer, mostEvents);
case 'Message':
return traverseHelp(verbEventListener, ignorer, allEvents);
}
}
function traverseHelp(verbEventListener, handler, eventNames)
{
for (var i = 0; i < eventNames.length; i++)
{
document.body[verbEventListener](eventNames[i], handler, true);
}
}
function makeIgnorer(overlayNode)
{
return function(event)
{
if (event.type === 'keydown' && event.metaKey && event.which === 82)
{
return;
}
var isScroll = event.type === 'scroll' || event.type === 'wheel';
var node = event.target;
while (node !== null)
{
if (node.className === 'elm-overlay-message-details' && isScroll)
{
return;
}
if (node === overlayNode && !isScroll)
{
return;
}
node = node.parentNode;
}
event.stopPropagation();
event.preventDefault();
}
}
var mostEvents = [
'click', 'dblclick', 'mousemove',
'mouseup', 'mousedown', 'mouseenter', 'mouseleave',
'touchstart', 'touchend', 'touchcancel', 'touchmove',
'pointerdown', 'pointerup', 'pointerover', 'pointerout',
'pointerenter', 'pointerleave', 'pointermove', 'pointercancel',
'dragstart', 'drag', 'dragend', 'dragenter', 'dragover', 'dragleave', 'drop',
'keyup', 'keydown', 'keypress',
'input', 'change',
'focus', 'blur'
];
var allEvents = mostEvents.concat('wheel', 'scroll');
return {
node: node,
text: text,
custom: custom,
map: F2(map),
on: F3(on),
style: style,
property: F2(property),
attribute: F2(attribute),
attributeNS: F3(attributeNS),
mapProperty: F2(mapProperty),
lazy: F2(lazy),
lazy2: F3(lazy2),
lazy3: F4(lazy3),
keyedNode: F3(keyedNode),
program: program,
programWithFlags: programWithFlags,
staticProgram: staticProgram
};
}();