@@ -10,7 +10,7 @@ Elm.fullscreen = function(module, ports) {
10 document.head.appendChild(style);
10 document.head.appendChild(style);
11 var container = document.createElement('div');
11 var container = document.createElement('div');
12 document.body.appendChild(container);
12 document.body.appendChild(container);
13− return init(ElmRuntime.Display.FULLSCREEN, container, module, ports);
13+ return init(ElmRuntime.Display.FULLSCREEN, container, module, ports || {});
16Elm.embed = function(module, container, ports) {
16Elm.embed = function(module, container, ports) {
@@ -20,17 +20,37 @@ Elm.embed = function(module, container, ports) {
20 } else if (container.hasChildNodes()) {
20 } else if (container.hasChildNodes()) {
21 throw new Error('Elm.node must be given an empty DIV. No children allowed!');
21 throw new Error('Elm.node must be given an empty DIV. No children allowed!');
23− return init(ElmRuntime.Display.COMPONENT, container, module, ports);
23+ return init(ElmRuntime.Display.COMPONENT, container, module, ports || {});
26Elm.worker = function(module, ports) {
26Elm.worker = function(module, ports) {
27− return init(ElmRuntime.Display.NONE, {}, module, ports);
27+ return init(ElmRuntime.Display.NONE, {}, module, ports || {});
30Elm.input = function(defaultValue, errorHandler) {
30Elm.input = function(defaultValue, errorHandler) {
32+ function subscribe(handler) {
33+ subscribers.push(handler);
35+ function unsubscribe(handler) {
36+ subscribers.pop(subscribers.indexOf(handler));
38+ function send(value) {
39+ var len = subscribers.length;
40+ for (var i = 0; i < len; ++i) {
41+ subscribers[i](value);
46+ internal: { defaultValue:defaultValue,
47+ errorHandler:errorHandler,
48+ subscribe: subscribe,
49+ unsubscribe: unsubscribe }
33−function init(display, container, module, moduleToReplace, ports) {
53+function init(display, container, module, ports, moduleToReplace) {
34 // defining state needed for an instance of the Elm RTS
54 // defining state needed for an instance of the Elm RTS
35 var inputs = [];
55 var inputs = [];
@@ -62,6 +82,10 @@ function init(display, container, module, moduleToReplace, ports) {
62 listeners.push(listener);
82 listeners.push(listener);
86+ for (var key in ports) {
65 // create the actual RTS. Any impure modules will attach themselves to this
89 // create the actual RTS. Any impure modules will attach themselves to this
66 // object. This permits many Elm programs to be embedded per document.
90 // object. This permits many Elm programs to be embedded per document.
67 var elm = {
91 var elm = {
@@ -71,14 +95,13 @@ function init(display, container, module, moduleToReplace, ports) {
71 id:ElmRuntime.guid(),
95 id:ElmRuntime.guid(),
72 addListener:addListener,
96 addListener:addListener,
73 inputs:inputs,
97 inputs:inputs,
74− ports_in:ports,
98+ ports: { incoming:ports, outgoing:{}, uses:portUses }
78 function swap(newModule) {
101 function swap(newModule) {
79 removeListeners(listeners);
102 removeListeners(listeners);
80 var div = document.createElement('div');
103 var div = document.createElement('div');
81− var newElm = init(display, div, newModule, elm);
104+ var newElm = init(display, div, newModule, ports, elm);
82 inputs = [];
105 inputs = [];
83 // elm.swap = newElm.swap;
106 // elm.swap = newElm.swap;
84 return newElm;
107 return newElm;
@@ -88,6 +111,7 @@ function init(display, container, module, moduleToReplace, ports) {
88 var reportAnyErrors = function() {};
111 var reportAnyErrors = function() {};
90 Module = module.make(elm);
113 Module = module.make(elm);
91 } catch(e) {
115 } catch(e) {
92 var directions = "<br/> Open the developer console for more details."
116 var directions = "<br/> Open the developer console for more details."
93 Module.main = Elm.Text.make(elm).text('<code>' + e.message + directions + '</code>');
117 Module.main = Elm.Text.make(elm).text('<code>' + e.message + directions + '</code>');
@@ -95,7 +119,7 @@ function init(display, container, module, moduleToReplace, ports) {
96 inputs = ElmRuntime.filterDeadInputs(inputs);
120 inputs = ElmRuntime.filterDeadInputs(inputs);
97 filterListeners(inputs, listeners);
121 filterListeners(inputs, listeners);
98− addReceivers(elm.ports_out);
122+ addReceivers(elm.ports.outgoing);
99 if (display !== ElmRuntime.Display.NONE) {
123 if (display !== ElmRuntime.Display.NONE) {
100 var graphicsNode = initGraphics(elm, Module);
124 var graphicsNode = initGraphics(elm, Module);
@@ -109,9 +133,26 @@ function init(display, container, module, moduleToReplace, ports) {
111 reportAnyErrors();
135 reportAnyErrors();
112− return { swap:swap, ports:elm.ports_out };
136+ return { swap:swap, output:elm.ports.outgoing };
139+function checkPorts(elm) {
140+ var portUses = elm.ports.uses;
141+ for (var key in portUses) {
142+ var uses = portUses[key]
145+ "Initialization Error: there is no port named '" + key + "'.\n" +
146+ "You should probably remove that input from your initialization code.");
147+ } else if (uses > 1) {
149+ "Initialization Error: port '" + key +
150+ "' has been declared multiple times in the Elm code.\n" +
151+ "Remove declarations until there is exactly one.");
115function filterListeners(inputs, listeners) {
156function filterListeners(inputs, listeners) {
117 for (var i = listeners.length; i--; ) {
158 for (var i = listeners.length; i--; ) {
@@ -134,27 +175,27 @@ function removeListeners(listeners) {
135// add receivers for built-in ports if they are defined
176// add receivers for built-in ports if they are defined
136function addReceivers(ports) {
177function addReceivers(ports) {
137− if ('log' in ports) {
178+ if ('log' in ports) {
138− ports.log.subscribe(function(v) { console.log(v) });
179+ ports.log.subscribe(function(v) { console.log(v) });
140− if ('stdout' in ports) {
181+ if ('stdout' in ports) {
141− var handler = process ? function(v) { process.stdout.write(v); }
182+ var handler = process ? function(v) { process.stdout.write(v); }
142− : function(v) { console.log(v); };
183+ : function(v) { console.log(v); };
143− ports.stdout.subscribe(handler);
184+ ports.stdout.subscribe(handler);
145− if ('stderr' in ports) {
186+ if ('stderr' in ports) {
146− var handler = process ? function(v) { process.stderr.write(v); }
187+ var handler = process ? function(v) { process.stderr.write(v); }
147− : function(v) { console.log('Error:' + v); };
188+ : function(v) { console.log('Error:' + v); };
148− ports.stderr.subscribe(handler);
189+ ports.stderr.subscribe(handler);
150− if ('title' in ports) {
191+ if ('title' in ports) {
151− ports.title.subscribe(function(v) { document.title = v; });
192+ ports.title.subscribe(function(v) { document.title = v; });
153− if ('redirect' in ports) {
194+ if ('redirect' in ports) {
154− ports.redirect.subscribe(function(v) {
195+ ports.redirect.subscribe(function(v) {
155− if (v.length > 0) window.location = v;
196+ if (v.length > 0) window.location = v;
160function initGraphics(elm, Module) {
201function initGraphics(elm, Module) {