on master help sign in
Move to initializing with three different functions: fullscreen, node, and worker.

Add code to ensure that mouse and touch positions are reported relative to the embedded Elm node. Remove the elm_ prefix from the events for logging, redirects, and title changes. Should be silo'd by the `elm` and not escape into the global event namespace.

commit7ce550901c1eacb7c8fd581da81f1f5dc128c165 authorevancz <info@elm-lang.org> dateTue 14 May 2013, 16:29 (13 years ago) parentd5a099f
9 files changed+96−77
compiler/Gen/GenerateHtml.hs+1−1 libraries/Native/Show.js−18 libraries/Native/Signal/Keyboard.js+8−8 libraries/Native/Signal/Mouse.js+3−3 libraries/Native/Signal/Touch.js+12−8 libraries/Native/Signal/Window.js+9−5 libraries/Native/Utils.js+17 runtime/Init.js+44−34 runtime/Utils.js+2
compiler/Gen/GenerateHtml.hs+1−1
@@ -71,5 +71,5 @@ createHtml jsStyle libLoc title js noscript moduleToLoad =
7171 makeScript Readable (Left libLoc)
7272 makeScript jsStyle js
7373 H.body $ do
74− H.script ! A.type_ "text/javascript" $ preEscapedToMarkup ("Elm.init(Elm." ++ moduleToLoad ++ ")" :: String)
74+ H.script ! A.type_ "text/javascript" $ preEscapedToMarkup ("Elm.fullscreen(Elm." ++ moduleToLoad ++ ")" :: String)
7575 H.noscript $ preEscapedToMarkup noscript
libraries/Native/Show.js−18
@@ -13,24 +13,6 @@ Elm.Native.Show = function(elm) {
1313 var Json = Elm.Json(elm);
1414 var Tuple2 = Elm.Native.Utils(elm).Tuple2;
1515
16− elm.node.addEventListener('log', function(e) { console.log(e.value); });
17− elm.node.addEventListener('title', function(e) {document.title = e.value;});
18− elm.node.addEventListener('redirect', function(e) {
19− if (e.value.length > 0) { window.location = e.value; }
20− });
21− elm.node.addEventListener('viewport', function(e) {
22− var node = document.getElementById('elm_viewport');
23− if (!node) {
24− node = document.createElement('meta');
25− node.id = 'elm_viewport';
26− node.name = 'viewport';
27− document.head.appendChild(node);
28− }
29− node.content = e.value;
30− Dispatcher.notify(elm.Window.dimensions.id,
31− Tuple2(elm.node.clientWidth, elm.node.clientHeight));
32− });
33−
3416 var toString = function(v) {
3517 if (typeof v === "function") {
3618 var name = v.func ? v.func.name : v.name;
libraries/Native/Signal/Keyboard.js+8−8
@@ -14,27 +14,27 @@ Elm.Native.Keyboard = function(elm) {
1414 if (NList.member(e.keyCode)(keysDown.value)) return;
1515 var list = NList.Cons(e.keyCode, keysDown.value);
1616 var hasListener = elm.notify(keysDown.id, list);
17− if (!hasListener) elm.node.removeEventListener('keydown', down);
17+ if (!hasListener) document.removeEventListener('keydown', down);
1818 }
1919 function up(e) {
2020 function notEq(kc) { return kc !== e.keyCode; }
2121 var codes = NList.filter(notEq)(keysDown.value);
2222 var hasListener = elm.notify(keysDown.id, codes);
23− if (!hasListener) elm.node.removeEventListener('keyup', up);
23+ if (!hasListener) document.removeEventListener('keyup', up);
2424 }
2525 function blur(e) {
2626 var hasListener = elm.notify(keysDown.id, NList.Nil);
27− if (!hasListener) elm.node.removeEventListener('blur', blur);
27+ if (!hasListener) document.removeEventListener('blur', blur);
2828 }
2929 function press(e) {
3030 var hasListener = elm.notify(lastKey.id, e.charCode || e.keyCode);
31− if (!hasListener) elm.node.removeEventListener('keypress', press);
31+ if (!hasListener) document.removeEventListener('keypress', press);
3232 }
3333
34− elm.node.addEventListener('keydown' , down );
35− elm.node.addEventListener('keyup' , up );
36− elm.node.addEventListener('blur' , blur );
37− elm.node.addEventListener('keypress', press);
34+ document.addEventListener('keydown' , down );
35+ document.addEventListener('keyup' , up );
36+ document.addEventListener('blur' , blur );
37+ document.addEventListener('keypress', press);
3838
3939 function keySignal(f) {
4040 var signal = A2( Signal.lift, f, keysDown );
libraries/Native/Signal/Mouse.js+3−3
@@ -21,7 +21,7 @@ Elm.Native.Mouse = function(elm) {
2121 var isDown = Signal.constant(false);
2222 var isClicked = Signal.constant(false);
2323 var clicks = Signal.constant(Utils.Tuple0);
24−
24+
2525 function getXY(e) {
2626 var posx = 0;
2727 var posy = 0;
@@ -35,10 +35,10 @@ Elm.Native.Mouse = function(elm) {
3535 posy = e.clientY + document.body.scrollTop +
3636 document.documentElement.scrollTop;
3737 }
38− return Utils.Tuple2(posx, posy);
38+ return Utils.Tuple2(posx-elm.node.offsetX, posy-elm.node.offsetY);
3939 }
4040
41− var node = elm.node.tagName === "BODY" ? document : elm.node;
41+ var node = elm.display === ElmRuntime.Display.FULLSCREEN ? document : elm.node;
4242
4343 function click(e) {
4444 var hasListener1 = elm.notify(isClicked.id, true);
libraries/Native/Signal/Touch.js+12−8
@@ -7,6 +7,7 @@ Elm.Native.Touch = function(elm) {
77
88 var Signal = Elm.Signal(elm);
99 var JS = Elm.JavaScript(elm);
10+ var _ = Elm.Native.Utils(elm);
1011
1112 function Dict() {
1213 this.keys = [];
@@ -44,24 +45,27 @@ Elm.Native.Touch = function(elm) {
4445 var r = dict.lookup(t.identifier);
4546 return {_ : {},
4647 id: t.identifier,
47− x : t.pageX,
48− y : t.pageY,
48+ x : t.pageX - elm.node.offsetX,
49+ y : t.pageY - elm.node.offsetY,
4950 x0: r.x,
5051 y0: r.y,
5152 t0: r.t
5253 };
5354 }
5455
55− var node = elm.node === document.body ? document : elm.node;
56+ var node = elm.display === ElmRuntime.Display.FULLSCREEN ? document : elm.node;
5657
5758 function start(e) {
58− dict.insert(e.identifier,{x:e.pageX,y:e.pageY,t:Date.now()});
59+ dict.insert(e.identifier,
60+ {x: e.pageX - elm.node.offsetX,
61+ y: e.pageY - elm.node.offsetY,
62+ t: Date.now()});
5963 }
6064 function end(e) {
6165 var t = dict.remove(e.identifier);
6266 if (Date.now() - t.t < tapTime) {
63− hasTap = true;
64− tap = {_:{}, x:t.x, y:t.y};
67+ hasTap = true;
68+ tap = {_:{}, x:t.x, y:t.y};
6569 }
6670 }
6771
@@ -87,8 +91,8 @@ Elm.Native.Touch = function(elm) {
8791 function move(e) {
8892 for (var i = root.value.length; i--; ) {
8993 if (root.value[i].id === mouseID) {
90− root.value[i].x = e.pageX;
91− root.value[i].y = e.pageY;
94+ root.value[i].x = e.pageX - elm.node.offsetX;
95+ root.value[i].y = e.pageY - elm.node.offsetY;
9296 elm.notify(root.id, root.value);
9397 break;
9498 }
libraries/Native/Signal/Window.js+9−5
@@ -10,7 +10,10 @@ Elm.Native.Window = function(elm) {
1010
1111 function getWidth() { return elm.node.clientWidth; }
1212 function getHeight() {
13− return document.body === elm.node ? window.innerHeight : elm.node.clientHeight;
13+ if (elm.display === ElmRuntime.Display.FULLSCREEN) {
14+ return window.innerHeight;
15+ }
16+ return elm.node.clientHeight;
1417 }
1518
1619 var dimensions = Signal.constant(Tuple2(getWidth(), getHeight()));
@@ -24,19 +27,20 @@ Elm.Native.Window = function(elm) {
2427 var height = A2(Signal.lift, function(p){return p._1}, dimensions);
2528 height.defaultNumberOfKids = 0;
2629
27− function resize(e) {
30+ function resizeIfNeeded() {
2831 var w = getWidth();
2932 var h = getHeight();
3033 if (dimensions.value._0 === w && dimensions.value._1 === h) return;
3134 var hasListener = elm.notify(dimensions.id, Tuple2(w,h));
32− if (!hasListener) window.removeEventListener('resize', resize);
35+ if (!hasListener) window.removeEventListener('resize', resizeIfNeeded);
3336 }
34− window.addEventListener('resize', resize);
37+ window.addEventListener('resize', resizeIfNeeded);
3538
3639 return elm.Native.Window = {
3740 dimensions:dimensions,
3841 width:width,
39− height:height
42+ height:height,
43+ resizeIfNeeded:resizeIfNeeded
4044 };
4145
4246};
libraries/Native/Utils.js+17
@@ -111,6 +111,23 @@ Elm.Native.Utils = function(elm) {
111111 return Tuple2(w,h);
112112 }
113113
114+ function adjustOffset() {
115+ var node = elm.node;
116+ var offsetX = offsetY = 0;
117+ if (node.offsetParent) {
118+ do {
119+ offsetX += node.offsetLeft;
120+ offsetY += node.offsetTop;
121+ } while (node = node.offsetParent);
122+ }
123+ node.offsetX = offsetX;
124+ node.offsetY = offsetY;
125+ }
126+
127+ if (elm.display === ElmRuntime.Display.COMPONENT) {
128+ elm.node.addEventListener('mouseover', adjustOffset);
129+ }
130+
114131 return elm.Native.Utils = {
115132 eq:eq,
116133 cmp:compare,
runtime/Init.js+44−34
@@ -1,7 +1,28 @@
11
2−Elm.init = function(module, baseNode) {
3− 'use strict';
2+(function() {
3+'use strict';
44
5+Elm.fullscreen = function(module) {
6+ var style = document.createElement('style');
7+ style.type = 'text/css';
8+ style.innerHTML = "html,head,body { padding:0; margin:0; }" +
9+ "body { font-family: calibri, helvetica, arial, sans-serif; }";
10+ document.head.appendChild(style);
11+ return init(ElmRuntime.Display.FULLSCREEN, document.body, module);
12+};
13+
14+Elm.node = function(width, height, module) {
15+ var container = document.createElement('div');
16+ container.style.width = width + 'px';
17+ container.style.height = height + 'px';
18+ return init(ElmRuntime.Display.COMPONENT, container, module);
19+};
20+
21+Elm.worker = function(module) {
22+ return init(ElmRuntime.Display.NONE, {}, module);
23+};
24+
25+function init(display, container, module) {
526 // defining state needed for an instance of the Elm RTS
627 var signalGraph = null;
728 var inputs = [];
@@ -18,19 +39,17 @@ Elm.init = function(module, baseNode) {
1839 return hasListener;
1940 }
2041
21− // ensure that baseNode exists and is properly formatted.
22− if (typeof baseNode === 'undefined') {
23− baseNode = document.body;
24− var style = document.createElement('style');
25− style.type = 'text/css';
26− style.innerHTML = "html,head,body { padding:0; margin:0; }" +
27− "body { font-family: calibri, helvetica, arial, sans-serif; }";
28− document.head.appendChild(style);
29− }
42+ container.offsetX = 0;
43+ container.offsetY = 0;
3044
3145 // create the actuall RTS. Any impure modules will attach themselves to this
3246 // object. This permits many Elm programs to be embedded per document.
33− var elm = {notify: notify, node: baseNode, id: ElmRuntime.guid(), inputs: inputs};
47+ var elm = { notify:notify,
48+ node:container,
49+ display:display,
50+ id:ElmRuntime.guid(),
51+ inputs:inputs
52+ };
3453
3554 // Set up methods to communicate with Elm program from JS.
3655 function send(name, value) {
@@ -44,15 +63,16 @@ Elm.init = function(module, baseNode) {
4463 document.addEventListener(name + '_' + elm.id, handler);
4564 }
4665
47− recv('elm_log', function(e) {console.log(e.value)});
48− recv('elm_title', function(e) {document.title = e.value});
49− recv('elm_redirect', function(e) {
66+ recv('log', function(e) {console.log(e.value)});
67+ recv('title', function(e) {document.title = e.value});
68+ recv('redirect', function(e) {
5069 if (e.value.length > 0) { window.location = e.value; }
5170 });
5271
5372 // If graphics are not enabled, escape early, skip over setting up DOM stuff.
54− if (baseNode === null) return { send : send, recv : recv };
55−
73+ if (display === ElmRuntime.Display.NONE) {
74+ return { send : send, recv : recv };
75+ }
5676
5777 var Render = ElmRuntime.use(ElmRuntime.Render.Element);
5878
@@ -66,22 +86,10 @@ Elm.init = function(module, baseNode) {
6686 visualModel = signalGraph.value;
6787 inputs = ElmRuntime.filterDeadInputs(inputs);
6888
69− var tuple2 = Elm.Native.Utils(elm).Tuple2;
70− function adjustWindow() {
71− if ('Window' in elm) {
72− var w = baseNode.clientWidth;
73− if (w !== elm.Window.dimensions.value._0) {
74− notify(elm.Window.dimensions.id,
75− tuple2(w, document.body === baseNode ?
76− window.innerHeight : baseNode.clientHeight));
77− }
78− }
79− }
80−
81− // Add the visualModel to the DOM
89+ // Add the visualModel to the DOM
8290 var renderNode = Render.render(visualModel)
83− baseNode.appendChild(renderNode);
84− adjustWindow();
91+ container.appendChild(renderNode);
92+ elm.Native.Window.resizeIfNeeded();
8593
8694 // set up updates so that the DOM is adjusted as necessary.
8795 var update = Render.update;
@@ -89,12 +97,14 @@ Elm.init = function(module, baseNode) {
8997 ElmRuntime.draw(function(_) {
9098 update(renderNode, visualModel, value);
9199 visualModel = value;
92− adjustWindow();
100+ elm.Native.Window.resizeIfNeeded();
93101 });
94102 return value;
95103 }
96104
97105 signalGraph = A2(Signal.lift, domUpdate, signalGraph);
98106
99− return { send : send, recv : recv };
107+ return { send : send, recv : recv, node : container };
100108};
109+
110+}());
runtime/Utils.js+2
@@ -2,6 +2,8 @@
22(function() {
33'use strict';
44
5+ElmRuntime.Display = { FULLSCREEN: 0, COMPONENT: 1, NONE: 2 };
6+
57ElmRuntime.counter = 0;
68ElmRuntime.guid = function() { return ElmRuntime.counter++; }
79