@@ -13,14 +13,12 @@ Elm.fullscreen = function(module) {
13 return init(ElmRuntime.Display.FULLSCREEN, container, module);
13 return init(ElmRuntime.Display.FULLSCREEN, container, module);
16−Elm.byId = function(id, module) {
16+Elm.domNode = function(container, module) {
17− var container = document.getElementById(id);
18 var tag = container.tagName;
17 var tag = container.tagName;
19 if (tag !== 'DIV') {
18 if (tag !== 'DIV') {
20− throw new Error('Elm.byId must be given a div, not a ' + tag + '.');
19+ throw new Error('Elm.node must be given a DIV, not a ' + tag + '.');
22− while (container.hasChildNodes()) {
20+ } else if (container.hasChildNodes()) {
23− container.removeChild(container.lastChild);
21+ throw new Error('Elm.node must be given an empty DIV. No children allowed!');
25 return init(ElmRuntime.Display.COMPONENT, container, module);
23 return init(ElmRuntime.Display.COMPONENT, container, module);
@@ -34,26 +32,39 @@ function init(display, container, module, moduleToReplace) {
34 var inputs = [];
32 var inputs = [];
36 function notify(id, v) {
34 function notify(id, v) {
37− var timestep = Date.now();
35+ var timestep = Date.now();
38− var hasListener = false;
36+ var changed = false;
39− for (var i = inputs.length; i--; ) {
37+ for (var i = inputs.length; i--; ) {
40− // must maintain the order of this stmt to avoid having the ||
38+ // order is important here to avoid short-circuiting
41− // short-circuiting the necessary work of recv
42− hasListener = inputs[i].recv(timestep, id, v) || hasListener;
39+ changed = inputs[i].recv(timestep, id, v) || changed;
44− return hasListener;
41+ return changed;
47 container.offsetX = 0;
44 container.offsetX = 0;
48 container.offsetY = 0;
45 container.offsetY = 0;
48+ function addListener(relevantInputs, domNode, eventName, func) {
49+ domNode.addEventListener(eventName, func);
51+ relevantInputs: relevantInputs,
53+ eventName: eventName,
56+ listeners.push(listener);
50 // create the actual RTS. Any impure modules will attach themselves to this
59 // create the actual RTS. Any impure modules will attach themselves to this
51 // object. This permits many Elm programs to be embedded per document.
60 // object. This permits many Elm programs to be embedded per document.
52− var elm = { notify:notify,
62+ notify:notify,
53− node:container,
63+ node:container,
54− display:display,
64+ display:display,
55− id:ElmRuntime.guid(),
65+ id:ElmRuntime.guid(),
66+ addListener:addListener,
56− inputs:inputs
67+ inputs:inputs
59 // Set up methods to communicate with Elm program from JS.
70 // Set up methods to communicate with Elm program from JS.
@@ -75,9 +86,10 @@ function init(display, container, module, moduleToReplace) {
77 function swap(newModule) {
88 function swap(newModule) {
89+ removeListeners(listeners);
78 var div = document.createElement('div');
90 var div = document.createElement('div');
79− if (container.id) { div.id = container.id; }
80 var newElm = init(display, div, newModule, elm);
91 var newElm = init(display, div, newModule, elm);
81 // elm.send = newElm.send;
93 // elm.send = newElm.send;
82 // elm.recv = newElm.recv;
94 // elm.recv = newElm.recv;
83 // elm.swap = newElm.swap;
95 // elm.swap = newElm.swap;
@@ -86,6 +98,7 @@ function init(display, container, module, moduleToReplace) {
87 var Module = module(elm);
99 var Module = module(elm);
88 inputs = ElmRuntime.filterDeadInputs(inputs);
100 inputs = ElmRuntime.filterDeadInputs(inputs);
101+ filterListeners(inputs, listeners);
89 if (display !== ElmRuntime.Display.NONE) {
102 if (display !== ElmRuntime.Display.NONE) {
90 var graphicsNode = initGraphics(elm, Module);
103 var graphicsNode = initGraphics(elm, Module);
@@ -102,6 +115,26 @@ function init(display, container, module, moduleToReplace) {
102 return { send:send, recv:recv, swap:swap };
115 return { send:send, recv:recv, swap:swap };
118+function filterListeners(inputs, listeners) {
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) {
127+ listener.domNode.removeEventListener(listener.eventName, listener.func);
131+function removeListeners(listeners) {
132+ for (var i = listeners.length; i--; ) {
133+ var listener = listeners[i];
134+ listener.domNode.removeEventListener(listener.eventName, listener.func);
105function initGraphics(elm, Module) {
138function initGraphics(elm, Module) {
106 if (!('main' in Module))
139 if (!('main' in Module))
107 throw new Error("'main' is missing! What do I display?!");
140 throw new Error("'main' is missing! What do I display?!");