9var Display = { FULLSCREEN: 0, COMPONENT: 1, NONE: 2 };
11Elm.fullscreen = function(module, ports) {
12 var container = document.createElement('div');
13 document.body.appendChild(container);
14 return init(Display.FULLSCREEN, container, module, ports || {});
17Elm.embed = function(module, container, ports) {
18 var tag = container.tagName;
20 throw new Error('Elm.node must be given a DIV, not a ' + tag + '.');
21 } else if (container.hasChildNodes()) {
22 throw new Error('Elm.node must be given an empty DIV. No children allowed!');
24 return init(Display.COMPONENT, container, module, ports || {});
27Elm.worker = function(module, ports) {
28 return init(Display.NONE, {}, module, ports || {});
31function init(display, container, module, ports, moduleToReplace) {
32 // defining state needed for an instance of the Elm RTS
36 * Elm's time traveling debugger lets you interrupt the smooth flow of time
37 * by pausing and continuing program execution. To ensure the user sees a
38 * program that moves smoothly through the pause/continue time gap,
39 * we need to adjsut the value of Date.now().
41 var timer = function() {
44 var now = function() {
45 return Date.now() - inducedDelay;
48 var addDelay = function(d) {
58 var updateInProgress = false;
59 function notify(id, v) {
60 if (updateInProgress) {
62 'The notify function has been called synchronously!\n' +
63 'This can lead to frames being dropped.\n' +
64 'Definitely report this to <https://github.com/elm-lang/Elm/issues>\n');
66 updateInProgress = true;
67 var timestep = timer.now();
68 for (var i = inputs.length; i--; ) {
69 inputs[i].recv(timestep, id, v);
71 updateInProgress = false;
73 function setTimeout(func, delay) {
74 window.setTimeout(func, delay);
78 function addListener(relevantInputs, domNode, eventName, func) {
79 domNode.addEventListener(eventName, func);
81 relevantInputs: relevantInputs,
86 listeners.push(listener);
90 for (var key in ports) {
93 // create the actual RTS. Any impure modules will attach themselves to this
94 // object. This permits many Elm programs to be embedded per document.
97 setTimeout: setTimeout,
99 addListener: addListener,
102 ports: { incoming:ports, outgoing:{}, uses:portUses },
104 isFullscreen: function() { return display === Display.FULLSCREEN; },
105 isEmbed: function() { return display === Display.COMPONENT; },
106 isWorker: function() { return display === Display.NONE; }
109 function swap(newModule) {
110 removeListeners(listeners);
111 var div = document.createElement('div');
112 var newElm = init(display, div, newModule, ports, elm);
114 // elm.swap = newElm.swap;
119 removeListeners(listeners);
124 var reportAnyErrors = function() {};
126 Module = module.make(elm);
129 var directions = "<br/> Open the developer console for more details."
130 Module.main = Elm.Text.make(elm).leftAligned('<code>' + e.message + directions + '</code>');
131 reportAnyErrors = function() { throw e; }
133 inputs = filterDeadInputs(inputs);
134 filterListeners(inputs, listeners);
135 addReceivers(elm.ports.outgoing);
136 if (display !== Display.NONE) {
137 var graphicsNode = initGraphics(elm, Module);
139 if (typeof moduleToReplace !== 'undefined') {
140 hotSwap(moduleToReplace, elm);
142 // rerender scene if graphics are enabled.
143 if (typeof graphicsNode !== 'undefined') {
144 graphicsNode.recv(0, true, 0);
151 ports:elm.ports.outgoing,
156function checkPorts(elm) {
157 var portUses = elm.ports.uses;
158 for (var key in portUses) {
159 var uses = portUses[key]
162 "Initialization Error: provided port '" + key +
163 "' to a module that does not take it as in input.\n" +
164 "Remove '" + key + "' from the module initialization code.");
165 } else if (uses > 1) {
167 "Initialization Error: port '" + key +
168 "' has been declared multiple times in the Elm code.\n" +
169 "Remove declarations until there is exactly one.");
175//// FILTER SIGNALS ////
177// TODO: move this code into the signal module and create a function
178// Signal.initializeGraph that actually instantiates everything.
180function filterListeners(inputs, listeners) {
182 for (var i = listeners.length; i--; ) {
183 var listener = listeners[i];
184 for (var j = inputs.length; j--; ) {
185 if (listener.relevantInputs.indexOf(inputs[j].id) >= 0) {
189 listener.domNode.removeEventListener(listener.eventName, listener.func);
193function removeListeners(listeners) {
194 for (var i = listeners.length; i--; ) {
195 var listener = listeners[i];
196 listener.domNode.removeEventListener(listener.eventName, listener.func);
200// add receivers for built-in ports if they are defined
201function addReceivers(ports) {
202 if ('log' in ports) {
203 ports.log.subscribe(function(v) { console.log(v) });
205 if ('stdout' in ports) {
206 var process = process || {};
207 var handler = process.stdout
208 ? function(v) { process.stdout.write(v); }
209 : function(v) { console.log(v); };
210 ports.stdout.subscribe(handler);
212 if ('stderr' in ports) {
213 var process = process || {};
214 var handler = process.stderr
215 ? function(v) { process.stderr.write(v); }
216 : function(v) { console.log('Error:' + v); };
217 ports.stderr.subscribe(handler);
219 if ('title' in ports) {
220 if (typeof ports.title === 'string') {
221 document.title = ports.title;
223 ports.title.subscribe(function(v) { document.title = v; });
226 if ('redirect' in ports) {
227 ports.redirect.subscribe(function(v) {
228 if (v.length > 0) window.location = v;
231 if ('favicon' in ports) {
232 if (typeof ports.favicon === 'string') {
233 changeFavicon(ports.favicon);
235 ports.favicon.subscribe(changeFavicon);
238 function changeFavicon(src) {
239 var link = document.createElement('link');
240 var oldLink = document.getElementById('elm-favicon');
241 link.id = 'elm-favicon';
242 link.rel = 'shortcut icon';
245 document.head.removeChild(oldLink);
247 document.head.appendChild(link);
252function filterDeadInputs(inputs) {
254 for (var i = inputs.length; i--; ) {
255 if (isAlive(inputs[i])) temp.push(inputs[i]);
261function isAlive(input) {
262 if (!('defaultNumberOfKids' in input)) return true;
263 var len = input.kids.length;
264 if (len === 0) return false;
265 if (len > input.defaultNumberOfKids) return true;
267 for (var i = len; i--; ) {
268 alive = alive || isAlive(input.kids[i]);
276function initGraphics(elm, Module) {
277 if (!('main' in Module)) {
278 throw new Error("'main' is missing! What do I display?!");
281 var signalGraph = Module.main;
283 // make sure the signal graph is actually a signal & extract the visual model
284 var Signal = Elm.Native.Signal.make(elm);
285 if (!('recv' in signalGraph)) {
286 signalGraph = Signal.constant(signalGraph);
288 var currentScene = signalGraph.value;
290 // Add the currentScene to the DOM
291 var Element = Elm.Native.Graphics.Element.make(elm);
292 elm.node.appendChild(Element.render(currentScene));
294 // set up updates so that the DOM is adjusted as necessary.
295 var savedScene = currentScene;
296 var previousDrawId = 0;
297 function domUpdate(newScene) {
298 previousDrawId = draw(previousDrawId, function(_) {
299 Element.update(elm.node.firstChild, savedScene, newScene);
300 if (elm.Native.Window) elm.Native.Window.values.resizeIfNeeded();
301 savedScene = newScene;
304 var renderer = A2(Signal.lift, domUpdate, signalGraph);
306 // must check for resize after 'renderer' is created so
307 // that changes show up.
308 if (elm.Native.Window) elm.Native.Window.values.resizeIfNeeded();
314// define function for drawing efficiently
316// draw : RequestID -> (() -> ()) -> RequestID
318// Takes a "RequestID" allowing you to cancel old requests if possible.
319// Returns a "RequestID" so you can refer to past requests.
321function draw(previousRequestID, callback) {
323 return previousRequestID;
326var vendors = ['ms', 'moz', 'webkit', 'o'];
327var win = typeof window !== 'undefined' ? window : {};
328for (var i = 0; i < vendors.length && !win.requestAnimationFrame; ++i) {
329 win.requestAnimationFrame = win[vendors[i]+'RequestAnimationFrame'];
330 win.cancelAnimationFrame = win[vendors[i]+'CancelAnimationFrame'] ||
331 win[vendors[i]+'CancelRequestAnimationFrame'];
333if (win.requestAnimationFrame && win.cancelAnimationFrame) {
334 draw = function(previousRequestID, callback) {
335 win.cancelAnimationFrame(previousRequestID);
336 return win.requestAnimationFrame(callback);
341//// HOT SWAPPING ////
343// Returns boolean indicating if the swap was successful.
344// Requires that the two signal graphs have exactly the same
346function hotSwap(from, to) {
347 function similar(nodeOld,nodeNew) {
348 var idOkay = nodeOld.id === nodeNew.id;
349 var lengthOkay = nodeOld.kids.length === nodeNew.kids.length;
350 return idOkay && lengthOkay;
352 function swap(nodeOld,nodeNew) {
353 nodeNew.value = nodeOld.value;
356 var canSwap = depthFirstTraversals(similar, from.inputs, to.inputs);
358 depthFirstTraversals(swap, from.inputs, to.inputs);
360 from.node.parentNode.replaceChild(to.node, from.node);
365// Returns false if the node operation f ever fails.
366function depthFirstTraversals(f, queueOld, queueNew) {
367 if (queueOld.length !== queueNew.length) return false;
368 queueOld = queueOld.slice(0);
369 queueNew = queueNew.slice(0);
372 while (queueOld.length > 0 && queueNew.length > 0) {
373 var nodeOld = queueOld.pop();
374 var nodeNew = queueNew.pop();
375 if (seen.indexOf(nodeOld.id) < 0) {
376 if (!f(nodeOld, nodeNew)) return false;
377 queueOld = queueOld.concat(nodeOld.kids);
378 queueNew = queueNew.concat(nodeNew.kids);
379 seen.push(nodeOld.id);
389 function wrapper(a) { return function(b) { return fun(a,b) } }
396 function wrapper(a) {
397 return function(b) { return function(c) { return fun(a,b,c) }}
405 function wrapper(a) { return function(b) { return function(c) {
406 return function(d) { return fun(a,b,c,d) }}}
414 function wrapper(a) { return function(b) { return function(c) {
415 return function(d) { return function(e) { return fun(a,b,c,d,e) }}}}
423 function wrapper(a) { return function(b) { return function(c) {
424 return function(d) { return function(e) { return function(f) {
425 return fun(a,b,c,d,e,f) }}}}}
433 function wrapper(a) { return function(b) { return function(c) {
434 return function(d) { return function(e) { return function(f) {
435 return function(g) { return fun(a,b,c,d,e,f,g) }}}}}}
443 function wrapper(a) { return function(b) { return function(c) {
444 return function(d) { return function(e) { return function(f) {
445 return function(g) { return function(h) {return fun(a,b,c,d,e,f,g,h)}}}}}}}
453 function wrapper(a) { return function(b) { return function(c) {
454 return function(d) { return function(e) { return function(f) {
455 return function(g) { return function(h) { return function(i) {
456 return fun(a,b,c,d,e,f,g,h,i) }}}}}}}}
463function A2(fun,a,b) {
464 return fun.arity === 2
468function A3(fun,a,b,c) {
469 return fun.arity === 3
473function A4(fun,a,b,c,d) {
474 return fun.arity === 4
478function A5(fun,a,b,c,d,e) {
479 return fun.arity === 5
480 ? fun.func(a,b,c,d,e)
481 : fun(a)(b)(c)(d)(e);
483function A6(fun,a,b,c,d,e,f) {
484 return fun.arity === 6
485 ? fun.func(a,b,c,d,e,f)
486 : fun(a)(b)(c)(d)(e)(f);
488function A7(fun,a,b,c,d,e,f,g) {
489 return fun.arity === 7
490 ? fun.func(a,b,c,d,e,f,g)
491 : fun(a)(b)(c)(d)(e)(f)(g);
493function A8(fun,a,b,c,d,e,f,g,h) {
494 return fun.arity === 8
495 ? fun.func(a,b,c,d,e,f,g,h)
496 : fun(a)(b)(c)(d)(e)(f)(g)(h);
498function A9(fun,a,b,c,d,e,f,g,h,i) {
499 return fun.arity === 9
500 ? fun.func(a,b,c,d,e,f,g,h,i)
501 : fun(a)(b)(c)(d)(e)(f)(g)(h)(i);
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list