Elm.Native.Ports = {}; Elm.Native.Ports.make = function(elm) { elm.Native = elm.Native || {}; elm.Native.Ports = elm.Native.Ports || {}; if (elm.Native.Ports.values) return elm.Native.Ports.values; var Signal = Elm.Signal.make(elm); function incomingSignal(converter) { converter.isSignal = true; return converter; } function outgoingSignal(converter) { return function(signal) { var subscribers = [] function subscribe(handler) { subscribers.push(handler); } function unsubscribe(handler) { subscribers.pop(subscribers.indexOf(handler)); } A2( Signal.lift, function(value) { var val = converter(value); var len = subscribers.length; for (var i = 0; i < len; ++i) { subscribers[i](val); } }, signal); return { subscribe:subscribe, unsubscribe:unsubscribe }; } } function portIn(name, converter) { var jsValue = elm.ports.incoming[name]; if (jsValue === undefined) { throw new Error("Initialization Error: port '" + name + "' was not given an input!"); } elm.ports.uses[name] += 1; try { var elmValue = converter(jsValue); } catch(e) { throw new Error("Initialization Error on port '" + name + "': \n" + e.message); } // just return a static value if it is not a signal if (!converter.isSignal) { return elmValue; } // create a signal if necessary var signal = Signal.constant(elmValue); function send(jsValue) { try { var elmValue = converter(jsValue); } catch(e) { throw new Error("Error sending to port '" + name + "': \n" + e.message); } setTimeout(function() { elm.notify(signal.id, elmValue); }, 0); } elm.ports.outgoing[name] = { send:send }; return signal; } function portOut(name, converter, value) { try { elm.ports.outgoing[name] = converter(value); } catch(e) { throw new Error("Initialization Error on port '" + name + "': \n" + e.message); } return value; } return elm.Native.Ports.values = { incomingSignal: incomingSignal, outgoingSignal: outgoingSignal, portOut: portOut, portIn: portIn }; };