@@ -13,14 +13,12 @@ Elm.fullscreen = function(module) {
1313 return init(ElmRuntime.Display.FULLSCREEN, container, module);
1414};
1515
16−Elm.byId = function(id, module) {
17− var container = document.getElementById(id);
16+Elm.domNode = function(container, module) {
1817 var tag = container.tagName;
1918 if (tag !== 'DIV') {
20− throw new Error('Elm.byId must be given a div, not a ' + tag + '.');
21− }
22− while (container.hasChildNodes()) {
23− container.removeChild(container.lastChild);
19+ throw new Error('Elm.node must be given a DIV, not a ' + tag + '.');
20+ } else if (container.hasChildNodes()) {
21+ throw new Error('Elm.node must be given an empty DIV. No children allowed!');
2422 }
2523 return init(ElmRuntime.Display.COMPONENT, container, module);
2624};
@@ -34,26 +32,39 @@ function init(display, container, module, moduleToReplace) {
3432 var inputs = [];
3533
3634 function notify(id, v) {
37− var timestep = Date.now();
38− var hasListener = false;
39− for (var i = inputs.length; i--; ) {
40− // must maintain the order of this stmt to avoid having the ||
41− // short-circuiting the necessary work of recv
42− hasListener = inputs[i].recv(timestep, id, v) || hasListener;
43− }
44− return hasListener;
35+ var timestep = Date.now();
36+ var changed = false;
37+ for (var i = inputs.length; i--; ) {
38+ // order is important here to avoid short-circuiting
39+ changed = inputs[i].recv(timestep, id, v) || changed;
40+ }
41+ return changed;
4542 }
4643
4744 container.offsetX = 0;
4845 container.offsetY = 0;
4946
47+ var listeners = [];
48+ function addListener(relevantInputs, domNode, eventName, func) {
49+ domNode.addEventListener(eventName, func);
50+ var listener = {
51+ relevantInputs: relevantInputs,
52+ domNode: domNode,
53+ eventName: eventName,
54+ func: func
55+ };
56+ listeners.push(listener);
57+ }
58+
5059 // create the actual RTS. Any impure modules will attach themselves to this
5160 // object. This permits many Elm programs to be embedded per document.
52− var elm = { notify:notify,
53− node:container,
54− display:display,
55− id:ElmRuntime.guid(),
56− inputs:inputs
61+ var elm = {
62+ notify:notify,
63+ node:container,
64+ display:display,
65+ id:ElmRuntime.guid(),
66+ addListener:addListener,
67+ inputs:inputs
5768 };
5869
5970 // Set up methods to communicate with Elm program from JS.
@@ -75,9 +86,10 @@ function init(display, container, module, moduleToReplace) {
7586 });
7687
7788 function swap(newModule) {
89+ removeListeners(listeners);
7890 var div = document.createElement('div');
79− if (container.id) { div.id = container.id; }
8091 var newElm = init(display, div, newModule, elm);
92+ inputs = [];
8193 // elm.send = newElm.send;
8294 // elm.recv = newElm.recv;
8395 // elm.swap = newElm.swap;
@@ -86,6 +98,7 @@ function init(display, container, module, moduleToReplace) {
8698
8799 var Module = module(elm);
88100 inputs = ElmRuntime.filterDeadInputs(inputs);
101+ filterListeners(inputs, listeners);
89102 if (display !== ElmRuntime.Display.NONE) {
90103 var graphicsNode = initGraphics(elm, Module);
91104 }
@@ -102,6 +115,26 @@ function init(display, container, module, moduleToReplace) {
102115 return { send:send, recv:recv, swap:swap };
103116};
104117
118+function filterListeners(inputs, listeners) {
119+ loop:
120+ for (var i = listeners.length; i--; ) {
121+ var listener = listeners[i];
122+ for (var j = inputs.length; j--; ) {
123+ if (listener.relevantInputs.indexOf(inputs[j].id) >= 0) {
124+ continue loop;
125+ }
126+ }
127+ listener.domNode.removeEventListener(listener.eventName, listener.func);
128+ }
129+}
130+
131+function removeListeners(listeners) {
132+ for (var i = listeners.length; i--; ) {
133+ var listener = listeners[i];
134+ listener.domNode.removeEventListener(listener.eventName, listener.func);
135+ }
136+}
137+
105138function initGraphics(elm, Module) {
106139 if (!('main' in Module))
107140 throw new Error("'main' is missing! What do I display?!");