on master help sign in
Get basic hot-swapping working.
commit3d5d60a47ddb1cd357db91543a323bffc241ba23 authorevancz <info@elm-lang.org> dateFri 31 May 2013, 10:40 (13 years ago) parentcb154ac
2 files changed+47−23
runtime/HotSwap.js+18−13 runtime/Init.js+29−10
runtime/HotSwap.js+18−13
@@ -5,33 +5,38 @@
55// structure.
66ElmRuntime.swap = function(from, to) {
77 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;
911 }
1012 function swap(nodeOld,nodeNew) {
1113 nodeNew.value = nodeOld.value;
1214 return true;
1315 }
14− from_ = from.__private__;
15− to_ = to.__private__;
16− var canSwap = depthFirstTraversals(similar, from_.inputs, to_.inputs);
17− if (canSwap) {
18− depthFirstTraversals(swap, from_.inputs, to_.inputs);
19− to.send("(!@#$%^&*)", null);
20− }
21− from_.container.parentNode.replaceChild(to_.container, from_.container);
16+ var canSwap = depthFirstTraversals(similar, from.inputs, to.inputs);
17+ if (canSwap) { depthFirstTraversals(swap, from.inputs, to.inputs); }
18+ from.node.parentNode.replaceChild(to.node, from.node);
2219 return canSwap;
2320}
2421
2522// Returns false if the node operation f ever fails.
2623function 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 = [];
2729 while (queueOld.length > 0 && queueNew.length > 0) {
2830 var nodeOld = queueOld.pop();
2931 var nodeNew = queueNew.pop();
30− if (!f(nodeOld, nodeNew)) return false;
31− queueOld = queueOld.concat(nodeOld.kids);
32− queueNew = queueNew.concat(nodeNew.kids);
32+ if (seen.indexOf(nodeOld.id) < 0) {
33+ if (!f(nodeOld, nodeNew)) return false;
34+ queueOld = queueOld.concat(nodeOld.kids);
35+ queueNew = queueNew.concat(nodeNew.kids);
36+ seen.push(nodeOld.id);
37+ }
3338 }
34− return queueOld.length === queueNew.length;
39+ return true;
3540}
3641
3742}())
runtime/Init.js+29−10
@@ -29,7 +29,7 @@ Elm.worker = function(module) {
2929 return init(ElmRuntime.Display.NONE, {}, module);
3030};
3131
32−function init(display, container, module) {
32+function init(display, container, module, moduleToReplace) {
3333 // defining state needed for an instance of the Elm RTS
3434 var inputs = [];
3535
@@ -74,18 +74,38 @@ function init(display, container, module) {
7474 if (e.value.length > 0) { window.location = e.value; }
7575 });
7676
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+
7787 var Module = module(elm);
7888 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+ }
79101
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,
84− __private__ : { inputs:inputs, container:container } };
102+ return { send:send, recv:recv, swap:swap };
85103};
86104
87105function initGraphics(elm, Module) {
88− if (!('main' in Module)) throw new Error("'main' is missing! What do I display?!");
106+ if (!('main' in Module))
107+ throw new Error("'main' is missing! What do I display?!");
108+
89109 var signalGraph = Module.main;
90110
91111 // make sure the signal graph is actually a signal & extract the visual model
@@ -101,15 +121,14 @@ function initGraphics(elm, Module) {
101121 if (elm.Native.Window) elm.Native.Window.resizeIfNeeded();
102122
103123 // set up updates so that the DOM is adjusted as necessary.
104− function domUpdate(newScene) {
124+ function domUpdate(newScene, currentScene) {
105125 ElmRuntime.draw(function(_) {
106126 Render.update(elm.node.firstChild, currentScene, newScene);
107− currentScene = newScene;
108127 if (elm.Native.Window) elm.Native.Window.resizeIfNeeded();
109128 });
110129 return newScene;
111130 }
112− A2(Signal.lift, domUpdate, signalGraph);
131+ return A3(Signal.foldp, F2(domUpdate), currentScene, signalGraph);
113132}
114133
115134}());