@@ -2,6 +2,9 @@
2(function() {
2(function() {
3'use strict';
3'use strict';
5+var Display = { FULLSCREEN: 0, COMPONENT: 1, NONE: 2 };
5Elm.fullscreen = function(module, ports) {
8Elm.fullscreen = function(module, ports) {
6 var style = document.createElement('style');
9 var style = document.createElement('style');
7 style.type = 'text/css';
10 style.type = 'text/css';
@@ -10,7 +13,7 @@ Elm.fullscreen = function(module, ports) {
10 document.head.appendChild(style);
13 document.head.appendChild(style);
11 var container = document.createElement('div');
14 var container = document.createElement('div');
12 document.body.appendChild(container);
15 document.body.appendChild(container);
13− return init(ElmRuntime.Display.FULLSCREEN, container, module, ports || {});
16+ return init(Display.FULLSCREEN, container, module, ports || {});
16Elm.embed = function(module, container, ports) {
19Elm.embed = function(module, container, ports) {
@@ -20,11 +23,11 @@ Elm.embed = function(module, container, ports) {
20 } else if (container.hasChildNodes()) {
23 } else if (container.hasChildNodes()) {
21 throw new Error('Elm.node must be given an empty DIV. No children allowed!');
24 throw new Error('Elm.node must be given an empty DIV. No children allowed!');
23− return init(ElmRuntime.Display.COMPONENT, container, module, ports || {});
26+ return init(Display.COMPONENT, container, module, ports || {});
26Elm.worker = function(module, ports) {
29Elm.worker = function(module, ports) {
27− return init(ElmRuntime.Display.NONE, {}, module, ports || {});
30+ return init(Display.NONE, {}, module, ports || {});
30function init(display, container, module, ports, moduleToReplace) {
33function init(display, container, module, ports, moduleToReplace) {
@@ -96,7 +99,6 @@ function init(display, container, module, ports, moduleToReplace) {
96 setTimeout:setTimeout,
99 setTimeout:setTimeout,
97 node:container,
100 node:container,
98 display:display,
101 display:display,
99− id:ElmRuntime.guid(),
100 addListener:addListener,
102 addListener:addListener,
101 inputs:inputs,
103 inputs:inputs,
102 timer:timer,
104 timer:timer,
@@ -127,10 +129,10 @@ function init(display, container, module, ports, moduleToReplace) {
127 Module.main = Elm.Text.make(elm).leftAligned('<code>' + e.message + directions + '</code>');
129 Module.main = Elm.Text.make(elm).leftAligned('<code>' + e.message + directions + '</code>');
128 reportAnyErrors = function() { throw e; }
130 reportAnyErrors = function() { throw e; }
130− inputs = ElmRuntime.filterDeadInputs(inputs);
132+ inputs = filterDeadInputs(inputs);
131 filterListeners(inputs, listeners);
133 filterListeners(inputs, listeners);
132 addReceivers(elm.ports.outgoing);
134 addReceivers(elm.ports.outgoing);
133− if (display !== ElmRuntime.Display.NONE) {
135+ if (display !== Display.NONE) {
134 var graphicsNode = initGraphics(elm, Module);
136 var graphicsNode = initGraphics(elm, Module);
136 if (typeof moduleToReplace !== 'undefined') {
138 if (typeof moduleToReplace !== 'undefined') {
@@ -239,6 +241,31 @@ function addReceivers(ports) {
245+function filterDeadInputs(inputs) {
247+ for (var i = inputs.length; i--; ) {
248+ if (isAlive(inputs[i])) temp.push(inputs[i]);
254+function isAlive(input) {
255+ if (!('defaultNumberOfKids' in input)) return true;
256+ var len = input.kids.length;
257+ if (len === 0) return false;
258+ if (len > input.defaultNumberOfKids) return true;
260+ for (var i = len; i--; ) {
261+ alive = alive || isAlive(input.kids[i]);
242function initGraphics(elm, Module) {
269function initGraphics(elm, Module) {
243 if (!('main' in Module)) {
270 if (!('main' in Module)) {
244 throw new Error("'main' is missing! What do I display?!");
271 throw new Error("'main' is missing! What do I display?!");
@@ -254,15 +281,15 @@ function initGraphics(elm, Module) {
254 var currentScene = signalGraph.value;
281 var currentScene = signalGraph.value;
256 // Add the currentScene to the DOM
283 // Add the currentScene to the DOM
257− var Render = ElmRuntime.use(ElmRuntime.Render.Element);
284+ var Element = Elm.Native.Graphics.Element.make(elm);
258− elm.node.appendChild(Render.render(currentScene));
285+ elm.node.appendChild(Element.render(currentScene));
260 // set up updates so that the DOM is adjusted as necessary.
287 // set up updates so that the DOM is adjusted as necessary.
261 var savedScene = currentScene;
288 var savedScene = currentScene;
262 var previousDrawId = 0;
289 var previousDrawId = 0;
263 function domUpdate(newScene) {
290 function domUpdate(newScene) {
264− previousDrawId = ElmRuntime.draw(previousDrawId, function(_) {
291+ previousDrawId = draw(previousDrawId, function(_) {
265− Render.update(elm.node.firstChild, savedScene, newScene);
292+ Element.update(elm.node.firstChild, savedScene, newScene);
266 if (elm.Native.Window) elm.Native.Window.values.resizeIfNeeded();
293 if (elm.Native.Window) elm.Native.Window.values.resizeIfNeeded();
267 savedScene = newScene;
294 savedScene = newScene;
@@ -276,4 +303,31 @@ function initGraphics(elm, Module) {
276 return renderer;
303 return renderer;
307+// define function for drawing efficiently
309+// draw : RequestID -> (() -> ()) -> RequestID
311+// Takes a "RequestID" allowing you to cancel old requests if possible.
312+// Returns a "RequestID" so you can refer to past requests.
314+function draw(previousRequestID, callback) {
316+ return previousRequestID;
319+var vendors = ['ms', 'moz', 'webkit', 'o'];
320+var win = typeof window !== 'undefined' ? window : {};
321+for (var i = 0; i < vendors.length && !win.requestAnimationFrame; ++i) {
322+ win.requestAnimationFrame = win[vendors[i]+'RequestAnimationFrame'];
323+ win.cancelAnimationFrame = win[vendors[i]+'CancelAnimationFrame'] ||
324+ win[vendors[i]+'CancelRequestAnimationFrame'];
326+if (win.requestAnimationFrame && win.cancelAnimationFrame) {
327+ draw = function(previousRequestID, callback) {
328+ win.cancelAnimationFrame(previousRequestID);
329+ return win.requestAnimationFrame(callback);