Forking what is left of ZeroNet and hopefully adding an AT Proto Frontend/Proxy
1(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.morphdom = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
2var specialElHandlers = {
3 /**
4 * Needed for IE. Apparently IE doesn't think
5 * that "selected" is an attribute when reading
6 * over the attributes using selectEl.attributes
7 */
8 OPTION: function(fromEl, toEl) {
9 if ((fromEl.selected = toEl.selected)) {
10 fromEl.setAttribute('selected', '');
11 } else {
12 fromEl.removeAttribute('selected', '');
13 }
14 },
15 /**
16 * The "value" attribute is special for the <input> element
17 * since it sets the initial value. Changing the "value"
18 * attribute without changing the "value" property will have
19 * no effect since it is only used to the set the initial value.
20 * Similar for the "checked" attribute.
21 */
22 /*INPUT: function(fromEl, toEl) {
23 fromEl.checked = toEl.checked;
24 fromEl.value = toEl.value;
25
26 if (!toEl.hasAttribute('checked')) {
27 fromEl.removeAttribute('checked');
28 }
29
30 if (!toEl.hasAttribute('value')) {
31 fromEl.removeAttribute('value');
32 }
33 }*/
34};
35
36function noop() {}
37
38/**
39 * Loop over all of the attributes on the target node and make sure the
40 * original DOM node has the same attributes. If an attribute
41 * found on the original node is not on the new node then remove it from
42 * the original node
43 * @param {HTMLElement} fromNode
44 * @param {HTMLElement} toNode
45 */
46function morphAttrs(fromNode, toNode) {
47 var attrs = toNode.attributes;
48 var i;
49 var attr;
50 var attrName;
51 var attrValue;
52 var foundAttrs = {};
53
54 for (i=attrs.length-1; i>=0; i--) {
55 attr = attrs[i];
56 if (attr.specified !== false) {
57 attrName = attr.name;
58 attrValue = attr.value;
59 foundAttrs[attrName] = true;
60
61 if (fromNode.getAttribute(attrName) !== attrValue) {
62 fromNode.setAttribute(attrName, attrValue);
63 }
64 }
65 }
66
67 // Delete any extra attributes found on the original DOM element that weren't
68 // found on the target element.
69 attrs = fromNode.attributes;
70
71 for (i=attrs.length-1; i>=0; i--) {
72 attr = attrs[i];
73 if (attr.specified !== false) {
74 attrName = attr.name;
75 if (!foundAttrs.hasOwnProperty(attrName)) {
76 fromNode.removeAttribute(attrName);
77 }
78 }
79 }
80}
81
82/**
83 * Copies the children of one DOM element to another DOM element
84 */
85function moveChildren(from, to) {
86 var curChild = from.firstChild;
87 while(curChild) {
88 var nextChild = curChild.nextSibling;
89 to.appendChild(curChild);
90 curChild = nextChild;
91 }
92 return to;
93}
94
95function morphdom(fromNode, toNode, options) {
96 if (!options) {
97 options = {};
98 }
99
100 if (typeof toNode === 'string') {
101 var newBodyEl = document.createElement('body');
102 newBodyEl.innerHTML = toNode;
103 toNode = newBodyEl.childNodes[0];
104 }
105
106 var savedEls = {}; // Used to save off DOM elements with IDs
107 var unmatchedEls = {};
108 var onNodeDiscarded = options.onNodeDiscarded || noop;
109 var onBeforeMorphEl = options.onBeforeMorphEl || noop;
110 var onBeforeMorphElChildren = options.onBeforeMorphElChildren || noop;
111
112 function removeNodeHelper(node, nestedInSavedEl) {
113 var id = node.id;
114 // If the node has an ID then save it off since we will want
115 // to reuse it in case the target DOM tree has a DOM element
116 // with the same ID
117 if (id) {
118 savedEls[id] = node;
119 } else if (!nestedInSavedEl) {
120 // If we are not nested in a saved element then we know that this node has been
121 // completely discarded and will not exist in the final DOM.
122 onNodeDiscarded(node);
123 }
124
125 if (node.nodeType === 1) {
126 var curChild = node.firstChild;
127 while(curChild) {
128 removeNodeHelper(curChild, nestedInSavedEl || id);
129 curChild = curChild.nextSibling;
130 }
131 }
132 }
133
134 function walkDiscardedChildNodes(node) {
135 if (node.nodeType === 1) {
136 var curChild = node.firstChild;
137 while(curChild) {
138
139
140 if (!curChild.id) {
141 // We only want to handle nodes that don't have an ID to avoid double
142 // walking the same saved element.
143
144 onNodeDiscarded(curChild);
145
146 // Walk recursively
147 walkDiscardedChildNodes(curChild);
148 }
149
150 curChild = curChild.nextSibling;
151 }
152 }
153 }
154
155 function removeNode(node, parentNode, alreadyVisited) {
156 parentNode.removeChild(node);
157
158 if (alreadyVisited) {
159 if (!node.id) {
160 onNodeDiscarded(node);
161 walkDiscardedChildNodes(node);
162 }
163 } else {
164 removeNodeHelper(node);
165 }
166 }
167
168 function morphEl(fromNode, toNode, alreadyVisited) {
169 if (toNode.id) {
170 // If an element with an ID is being morphed then it is will be in the final
171 // DOM so clear it out of the saved elements collection
172 delete savedEls[toNode.id];
173 }
174
175 if (onBeforeMorphEl(fromNode, toNode) === false) {
176 return;
177 }
178
179 morphAttrs(fromNode, toNode);
180
181 if (onBeforeMorphElChildren(fromNode, toNode) === false) {
182 return;
183 }
184
185 var curToNodeChild = toNode.firstChild;
186 var curFromNodeChild = fromNode.firstChild;
187 var curToNodeId;
188
189 var fromNextSibling;
190 var toNextSibling;
191 var savedEl;
192 var unmatchedEl;
193
194 outer: while(curToNodeChild) {
195 toNextSibling = curToNodeChild.nextSibling;
196 curToNodeId = curToNodeChild.id;
197
198 while(curFromNodeChild) {
199 var curFromNodeId = curFromNodeChild.id;
200 fromNextSibling = curFromNodeChild.nextSibling;
201
202 if (!alreadyVisited) {
203 if (curFromNodeId && (unmatchedEl = unmatchedEls[curFromNodeId])) {
204 unmatchedEl.parentNode.replaceChild(curFromNodeChild, unmatchedEl);
205 morphEl(curFromNodeChild, unmatchedEl, alreadyVisited);
206 curFromNodeChild = fromNextSibling;
207 continue;
208 }
209 }
210
211 var curFromNodeType = curFromNodeChild.nodeType;
212
213 if (curFromNodeType === curToNodeChild.nodeType) {
214 var isCompatible = false;
215
216 if (curFromNodeType === 1) { // Both nodes being compared are Element nodes
217 if (curFromNodeChild.tagName === curToNodeChild.tagName) {
218 // We have compatible DOM elements
219 if (curFromNodeId || curToNodeId) {
220 // If either DOM element has an ID then we handle
221 // those differently since we want to match up
222 // by ID
223 if (curToNodeId === curFromNodeId) {
224 isCompatible = true;
225 }
226 } else {
227 isCompatible = true;
228 }
229 }
230
231 if (isCompatible) {
232 // We found compatible DOM elements so add a
233 // task to morph the compatible DOM elements
234 morphEl(curFromNodeChild, curToNodeChild, alreadyVisited);
235 }
236 } else if (curFromNodeType === 3) { // Both nodes being compared are Text nodes
237 isCompatible = true;
238 curFromNodeChild.nodeValue = curToNodeChild.nodeValue;
239 }
240
241 if (isCompatible) {
242 curToNodeChild = toNextSibling;
243 curFromNodeChild = fromNextSibling;
244 continue outer;
245 }
246 }
247
248 // No compatible match so remove the old node from the DOM
249 removeNode(curFromNodeChild, fromNode, alreadyVisited);
250
251 curFromNodeChild = fromNextSibling;
252 }
253
254 if (curToNodeId) {
255 if ((savedEl = savedEls[curToNodeId])) {
256 morphEl(savedEl, curToNodeChild, true);
257 curToNodeChild = savedEl; // We want to append the saved element instead
258 } else {
259 // The current DOM element in the target tree has an ID
260 // but we did not find a match in any of the corresponding
261 // siblings. We just put the target element in the old DOM tree
262 // but if we later find an element in the old DOM tree that has
263 // a matching ID then we will replace the target element
264 // with the corresponding old element and morph the old element
265 unmatchedEls[curToNodeId] = curToNodeChild;
266 }
267 }
268
269 // If we got this far then we did not find a candidate match for our "to node"
270 // and we exhausted all of the children "from" nodes. Therefore, we will just
271 // append the current "to node" to the end
272 fromNode.appendChild(curToNodeChild);
273
274 curToNodeChild = toNextSibling;
275 curFromNodeChild = fromNextSibling;
276 }
277
278 // We have processed all of the "to nodes". If curFromNodeChild is non-null then
279 // we still have some from nodes left over that need to be removed
280 while(curFromNodeChild) {
281 fromNextSibling = curFromNodeChild.nextSibling;
282 removeNode(curFromNodeChild, fromNode, alreadyVisited);
283 curFromNodeChild = fromNextSibling;
284 }
285
286 var specialElHandler = specialElHandlers[fromNode.tagName];
287 if (specialElHandler) {
288 specialElHandler(fromNode, toNode);
289 }
290 }
291
292 var morphedNode = fromNode;
293 var morphedNodeType = morphedNode.nodeType;
294 var toNodeType = toNode.nodeType;
295
296 // Handle the case where we are given two DOM nodes that are not
297 // compatible (e.g. <div> --> <span> or <div> --> TEXT)
298 if (morphedNodeType === 1) {
299 if (toNodeType === 1) {
300 if (morphedNode.tagName !== toNode.tagName) {
301 onNodeDiscarded(fromNode);
302 morphedNode = moveChildren(morphedNode, document.createElement(toNode.tagName));
303 }
304 } else {
305 // Going from an element node to a text node
306 return toNode;
307 }
308 } else if (morphedNodeType === 3) { // Text node
309 if (toNodeType === 3) {
310 morphedNode.nodeValue = toNode.nodeValue;
311 return morphedNode;
312 } else {
313 onNodeDiscarded(fromNode);
314 // Text node to something else
315 return toNode;
316 }
317 }
318
319 morphEl(morphedNode, toNode, false);
320
321 // Fire the "onNodeDiscarded" event for any saved elements
322 // that never found a new home in the morphed DOM
323 for (var savedElId in savedEls) {
324 if (savedEls.hasOwnProperty(savedElId)) {
325 var savedEl = savedEls[savedElId];
326 onNodeDiscarded(savedEl);
327 walkDiscardedChildNodes(savedEl);
328 }
329 }
330
331 if (morphedNode !== fromNode && fromNode.parentNode) {
332 fromNode.parentNode.replaceChild(morphedNode, fromNode);
333 }
334
335 return morphedNode;
336}
337
338module.exports = morphdom;
339},{}]},{},[1])(1)
340});