@@ -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,36 @@ 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+ for (var i = inputs.length; i--; ) {
37+ inputs[i].recv(timestep, id, v);
38+ }
4539 }
4640
4741 container.offsetX = 0;
4842 container.offsetY = 0;
4943
44+ var listeners = [];
45+ function addListener(relevantInputs, domNode, eventName, func) {
46+ domNode.addEventListener(eventName, func);
47+ var listener = {
48+ relevantInputs: relevantInputs,
49+ domNode: domNode,
50+ eventName: eventName,
51+ func: func
52+ };
53+ listeners.push(listener);
54+ }
55+
5056 // create the actual RTS. Any impure modules will attach themselves to this
5157 // 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
58+ var elm = {
59+ notify:notify,
60+ node:container,
61+ display:display,
62+ id:ElmRuntime.guid(),
63+ addListener:addListener,
64+ inputs:inputs
5765 };
5866
5967 // Set up methods to communicate with Elm program from JS.
@@ -75,8 +83,8 @@ function init(display, container, module, moduleToReplace) {
7583 });
7684
7785 function swap(newModule) {
86+ removeListeners(listeners);
7887 var div = document.createElement('div');
79− if (container.id) { div.id = container.id; }
8088 var newElm = init(display, div, newModule, elm);
8189 // elm.send = newElm.send;
8290 // elm.recv = newElm.recv;
@@ -86,6 +94,7 @@ function init(display, container, module, moduleToReplace) {
8694
8795 var Module = module(elm);
8896 inputs = ElmRuntime.filterDeadInputs(inputs);
97+ filterListeners(inputs, listeners);
8998 if (display !== ElmRuntime.Display.NONE) {
9099 var graphicsNode = initGraphics(elm, Module);
91100 }
@@ -102,6 +111,26 @@ function init(display, container, module, moduleToReplace) {
102111 return { send:send, recv:recv, swap:swap };
103112};
104113
114+function filterListeners(inputs, listeners) {
115+ loop:
116+ for (var i = listeners.length; i--; ) {
117+ var listener = listeners[i];
118+ for (var j = inputs.length; j--; ) {
119+ if (listener.relevantInputs.indexOf(inputs[j].id) >= 0) {
120+ continue loop;
121+ }
122+ }
123+ listener.domNode.removeEventListener(listener.eventName, listener.func);
124+ }
125+}
126+
127+function removeListeners(listeners) {
128+ for (var i = listeners.length; i--; ) {
129+ var listener = listeners[i];
130+ listener.domNode.removeEventListener(listener.eventName, listener.func);
131+ }
132+}
133+
105134function initGraphics(elm, Module) {
106135 if (!('main' in Module))
107136 throw new Error("'main' is missing! What do I display?!");