on master help sign in
Get basic hot-swapping working.
3d5d60aevancz
runtime/HotSwap.js+18−13
@@ -5,33 +5,38 @@
5// structure.
5// structure.
6ElmRuntime.swap = function(from, to) {
6ElmRuntime.swap = function(from, to) {
7 function similar(nodeOld,nodeNew) {
7 function similar(nodeOld,nodeNew) {
8− return nodeOld.kids.length === nodeNew.kids.length;
8+ idOkay = nodeOld.id === nodeNew.id;
9+ lengthOkay = nodeOld.kids.length === nodeNew.kids.length;
10+ return idOkay && lengthOkay;
9 }
11 }
10 function swap(nodeOld,nodeNew) {
12 function swap(nodeOld,nodeNew) {
11 nodeNew.value = nodeOld.value;
13 nodeNew.value = nodeOld.value;
12 return true;
14 return true;
13 }
15 }
14− from_ = from.__private__;
15− to_ = to.__private__;
16− var canSwap = depthFirstTraversals(similar, from_.inputs, to_.inputs);
16+ var canSwap = depthFirstTraversals(similar, from.inputs, to.inputs);
17− if (canSwap) {
18− depthFirstTraversals(swap, from_.inputs, to_.inputs);
17+ if (canSwap) { depthFirstTraversals(swap, from.inputs, to.inputs); }
19− to.send("(!@#$%^&*)", null);
20− }
21− from_.container.parentNode.replaceChild(to_.container, from_.container);
18+ from.node.parentNode.replaceChild(to.node, from.node);
22 return canSwap;
19 return canSwap;
23}
20}
24
21
25// Returns false if the node operation f ever fails.
22// Returns false if the node operation f ever fails.
26function depthFirstTraversals(f, queueOld, queueNew) {
23function depthFirstTraversals(f, queueOld, queueNew) {
24+ if (queueOld.length !== queueNew.length) return false;
25+ queueOld = queueOld.slice(0);
26+ queueNew = queueNew.slice(0);
27+
28+ var seen = [];
27 while (queueOld.length > 0 && queueNew.length > 0) {
29 while (queueOld.length > 0 && queueNew.length > 0) {
28 var nodeOld = queueOld.pop();
30 var nodeOld = queueOld.pop();
29 var nodeNew = queueNew.pop();
31 var nodeNew = queueNew.pop();
32+ if (seen.indexOf(nodeOld.id) < 0) {
30− if (!f(nodeOld, nodeNew)) return false;
33+ if (!f(nodeOld, nodeNew)) return false;
31− queueOld = queueOld.concat(nodeOld.kids);
34+ queueOld = queueOld.concat(nodeOld.kids);
32− queueNew = queueNew.concat(nodeNew.kids);
35+ queueNew = queueNew.concat(nodeNew.kids);
36+ seen.push(nodeOld.id);
37+ }
33 }
38 }
34− return queueOld.length === queueNew.length;
39+ return true;
35}
40}
36
41
37}())
42}())
runtime/Init.js+29−10
@@ -29,7 +29,7 @@ Elm.worker = function(module) {
29 return init(ElmRuntime.Display.NONE, {}, module);
29 return init(ElmRuntime.Display.NONE, {}, module);
30};
30};
31
31
32−function init(display, container, module) {
32+function init(display, container, module, moduleToReplace) {
33 // defining state needed for an instance of the Elm RTS
33 // defining state needed for an instance of the Elm RTS
34 var inputs = [];
34 var inputs = [];
35
35
@@ -74,18 +74,38 @@ function init(display, container, module) {
74 if (e.value.length > 0) { window.location = e.value; }
74 if (e.value.length > 0) { window.location = e.value; }
75 });
75 });
76
76
77+ function swap(newModule) {
78+ var div = document.createElement('div');
79+ if (container.id) { div.id = container.id; }
80+ var newElm = init(display, div, newModule, elm);
81+ // elm.send = newElm.send;
82+ // elm.recv = newElm.recv;
83+ // elm.swap = newElm.swap;
84+ return newElm;
85+ }
86+
77 var Module = module(elm);
87 var Module = module(elm);
78 inputs = ElmRuntime.filterDeadInputs(inputs);
88 inputs = ElmRuntime.filterDeadInputs(inputs);
89+ if (display !== ElmRuntime.Display.NONE) {
90+ var graphicsNode = initGraphics(elm, Module);
91+ }
92+ if (typeof moduleToReplace !== 'undefined') {
93+ ElmRuntime.swap(moduleToReplace, elm);
94+
95+ // rerender scene if graphics are enabled.
96+ if (typeof graphicsNode !== 'undefined') {
97+ graphicsNode.value = A2( Elm.Graphics.Element(elm).spacer, 0, 0 );
98+ graphicsNode.recv(0, true, 0);
99+ }
100+ }
79
101
80− // If graphics are not enabled, escape early, skip over setting up DOM stuff.
81− if (display !== ElmRuntime.Display.NONE) { initGraphics(elm, Module); }
82−
83− return { send:send, recv:recv,
102+ return { send:send, recv:recv, swap:swap };
84− __private__ : { inputs:inputs, container:container } };
85};
103};
86
104
87function initGraphics(elm, Module) {
105function initGraphics(elm, Module) {
106+ if (!('main' in Module))
88− if (!('main' in Module)) throw new Error("'main' is missing! What do I display?!");
107+ throw new Error("'main' is missing! What do I display?!");
108+
89 var signalGraph = Module.main;
109 var signalGraph = Module.main;
90
110
91 // make sure the signal graph is actually a signal & extract the visual model
111 // make sure the signal graph is actually a signal & extract the visual model
@@ -101,15 +121,14 @@ function initGraphics(elm, Module) {
101 if (elm.Native.Window) elm.Native.Window.resizeIfNeeded();
121 if (elm.Native.Window) elm.Native.Window.resizeIfNeeded();
102
122
103 // set up updates so that the DOM is adjusted as necessary.
123 // set up updates so that the DOM is adjusted as necessary.
104− function domUpdate(newScene) {
124+ function domUpdate(newScene, currentScene) {
105 ElmRuntime.draw(function(_) {
125 ElmRuntime.draw(function(_) {
106 Render.update(elm.node.firstChild, currentScene, newScene);
126 Render.update(elm.node.firstChild, currentScene, newScene);
107− currentScene = newScene;
108 if (elm.Native.Window) elm.Native.Window.resizeIfNeeded();
127 if (elm.Native.Window) elm.Native.Window.resizeIfNeeded();
109 });
128 });
110 return newScene;
129 return newScene;
111 }
130 }
112− A2(Signal.lift, domUpdate, signalGraph);
131+ return A3(Signal.foldp, F2(domUpdate), currentScene, signalGraph);
113}
132}
114
133
115}());
134}());