on f70fdaa help sign in
elk/runtime/Render.js
287 lines 8.1 kB history raw
2(function() {
3'use strict';
5function newElement(elementType) {
6 var e = document.createElement(elementType);
7 e.style.padding = "0";
8 e.style.margin = "0";
9 return e;
12function addTo(container, elem) {
13 container.appendChild(elem);
16function makeText(pos,txt) {
17 var e = newElement('div');
18 e.innerHTML = txt;
19 e.style.textAlign = pos;
20 return e;
23function setProps(props, e) {
24 e.style.width = (props.width |0) + 'px';
25 e.style.height = (props.height|0) + 'px';
26 if (props.opacity !== 1) { e.style.opacity = props.opacity; }
27 if (props.color.ctor === 'Just') {
28 e.style.backgroundColor = Elm.Color.extract(props.color._0);
29 }
30 if (props.tag !== '') { e.id = props.tag; }
31 if (props.href !== '') {
32 var a = newElement('a');
33 a.href = props.href;
34 addTo(a,e);
35 return a;
36 }
37 return e;
40function image(props, img) {
41 switch (img._0.ctor) {
42 case 'Plain': return plainImage(img._3);
43 case 'Fitted': return fittedImage(props.width, props.height, img._3);
44 case 'Cropped': return croppedImage(img._0._0,props.width,props.height,img._3);
45 }
48function plainImage(src) {
49 var img = newElement('img');
50 img.src = src;
51 img.name = src;
52 img.style.display = "block";
53 return img;
56function fittedImage(w, h, src) {
57 var e = newElement('div');
58 e.style.position = "relative";
59 e.style.overflow = "hidden";
61 var img = newElement('img');
62 img.onload = function() {
63 img.style.position = 'absolute';
64 img.style.margin = 'auto';
66 var sw = w, sh = h;
67 if (w / h > this.width / this.height) {
68 sh = Math.round(this.height * w / this.width);
69 } else {
70 sw = Math.round(this.width * h / this.height);
71 }
72 img.style.width = sw + 'px';
73 img.style.height = sh + 'px';
74 img.style.left = ((w - sw) / 2) + 'px';
75 img.style.top = ((h - sh) / 2) + 'px';
76 };
77 img.src = src;
78 img.name = src;
79 addTo(e,img);
80 return e;
83function croppedImage(pos, w, h, src) {
84 var e = newElement('div');
85 e.style.position = "relative";
86 e.style.overflow = "hidden";
88 var img = newElement('img');
89 img.onload = function() {
90 img.style.position = 'absolute';
91 img.style.margin = 'auto';
92 var sw = dimensions.width / w, sh = dimensions.height / h;
93 img.style.width = (this.width * sw) + 'px';
94 img.style.height = (this.height * sh) + 'px';
95 img.style.left = (- pos._0 * sw) + 'px';
96 img.style.top = (- pos._1 * sh) + 'px';
97 };
98 img.src = src;
99 img.name = src;
100 addTo(e,img);
101 return e;
104function goIn(e) { e.style.position = 'absolute'; return e; }
105function goDown(e) { return e }
106function goRight(e) { e.style.styleFloat = e.style.cssFloat = "left"; return e; }
107function flowWith(f, array) {
108 var container = newElement('div');
109 for (var i = array.length; i--; ) {
110 addTo(container, f(render(array[i])));
111 }
112 return container;
115function flow(dir,elist) {
116 var array = JS.fromList(elist);
117 switch(dir) {
118 case "DDown": array.reverse();
119 case "DUp": return flowWith(goDown,array);
120 case "DRight": array.reverse();
121 case "DLeft": return flowWith(goRight,array);
122 case "DOut": array.reverse();
123 case "DIn": return flowWith(goIn,array);
124 }
127function toPos(pos) {
128 switch(pos[0]) {
129 case "Absolute": return pos[1] + "px";
130 case "Relative": return (pos[1] * 100) + "%";
131 }
134function addTransform(style, trans) {
135 style.transform = trans;
136 style.msTransform = trans;
137 style.MozTransform = trans;
138 style.webkitTransform = trans;
139 style.OTransform = trans;
142function removeTransform(style) {
143 style.transform = 'none';
144 style.msTransform = 'none';
145 style.MozTransform = 'none';
146 style.webkitTransform = 'none';
147 style.OTransform = 'none';
150function setPos(pos,w,h,e) {
151 e.style.position = 'absolute';
152 e.style.margin = 'auto';
153 var transform = '';
154 switch(pos.horizontal) {
155 case 'P': e.style.right = toPos(pos.x); break;
156 case 'Z': transform = 'translateX(' + ((-w/2)|0) + 'px) ';
157 case 'N': e.style.left = toPos(pos.x); break;
158 }
159 switch(pos.vertical) {
160 case 'N': e.style.bottom = toPos(pos.x); break;
161 case 'Z': transform += 'translateY(' + ((-h/2)|0) + 'px)';
162 case 'P': e.style.top = toPos(pos.x); break;
163 }
164 if (transform !== '') addTransform(e.style, transform);
165 return e;
168function container(pos,elem) {
169 var e = render(elem);
170 setPos(pos, elem.props.width, elem.props.height, e);
171 var div = newElement('div');
172 div.style.position = 'relative';
173 div.style.overflow = 'hidden';
174 addTo(div,e);
175 return div;
178function rawHtml(html) {
179 var e = newElement('div');
180 e.innerHTML = html;
181 return e;
184function render(elem) { return setProps(elem.props, makeElement(elem)); }
185function makeElement(e) {
186 switch(e.element.ctor) {
187 case 'Image': return image(e.props, e.element);
188 case 'Flow': return flow(e.element._0, e.element._1);
189 case 'Container': return container(e.element._0, e.element._1);
190 case 'Spacer': return newElement('div');
191 case 'RawHtml': return rawHtml(e.element._0);
192 case 'DomNode': return e.element._0;
193 }
196function update(node, curr, next) {
197 if (node.tagName === 'A') { node = node.firstChild; }
198 if (curr.props.id === next.props.id) return false;
199 if (curr.element.ctor !== next.element.ctor) {
200 node.parentNode.replaceChild(render(next),node);
201 return true;
202 }
203 var nextE = next.element, currE = curr.element;
204 switch(nextE.ctor) {
205 case "Spacer": break;
206 case "RawHtml": if (nextE._0 !== currE._0) node.innerHTML = nextE._0; break;
207 case "Image":
208 if (nextE._0.ctor === 'Plain') {
209 if (nextE._3 !== currE._3) node.src = nextE._3;
210 } else if (!Value.eq(nextE,currE) ||
211 next.props.width !== curr.props.width ||
212 next.props.height !== curr.props.height) {
213 node.parentNode.replaceChild(render(next),node);
214 return true;
215 }
216 break;
217 case "Flow":
218 if (nextE._0.ctor !== currE._0.ctor) {
219 node.parentNode.replaceChild(render(next),node);
220 return true;
221 }
222 var nexts = nextE._1;
223 var kids = node.childNodes;
224 if (nexts.length !== kids.length) {
225 node.parentNode.replaceChild(render(next),node);
226 return true;
227 }
228 var currs = currE._1;
229 var goDir = function(x) { return x; };
230 switch(nextE[1][0]) {
231 case "DDown": case "DUp": goDir = goDown; break;
232 case "DRight": case "DLeft": goDir = goRight; break;
233 case "DOut": case "DIn": goDir = goIn; break;
234 }
235 for (var i = kids.length; i-- ;) {
236 update(kids[i],currs[i],nexts[i]);
237 goDir(kids[i]);
238 }
239 break;
240 case "Container":
241 var inner = node.firstChild;
242 if (!update(inner, currE._1, nextE._1)) {
243 if (nextE._0.horizontal.ctor !== currE._0.horizontal.ctor) {
244 inner.style.left = inner.style.right = 'none';
245 removeTransform(inner.style);
246 }
247 if (nextE._0.vertical.ctor !== currE._0.vertical.ctor) {
248 inner.style.top = inner.style.bottom = 'none';
249 removeTransform(inner.style);
250 }
251 }
252 setPos(nextE._0, next.props.width, next.props.height, node.firstChild);
253 break;
254 case "DomNode":
255 if (next._0 !== curr._0) node.parentNode.replaceChild(render(next),node);
256 break;
257 }
258 var props = next.props, currP = curr.props;
259 if (props.width !== currP.width) e.style.width = (props.width |0) + 'px';
260 if (props.height !== currP.height) e.style.height = (props.height|0) + 'px';
261 if (props.opacity !== 1 && props.opacity !== currP.opacity) {
262 e.style.opacity = props.opacity;
263 }
264 var nextColor = (props.color.ctor === 'Just' ?
265 Elm.Color.extract(props.color._0) : 'transparent');
266 if (e.style.backgroundColor !== nextColor) e.style.backgroundColor = nextColor;
267 if (props.tag !== currP.tag) { e.id = props.tag; }
268 if (props.href !== currP.href) {
269 if (currP.href === '') {
270 var a = newElement('a');
271 a.href = props.href;
272 addTo(a,e);
273 e.parentNode.replaceChild(a,e);
274 } else {
275 node.parentNode.href = props.href;
276 }
277 }
280Elm.Runtime = {
281 render:render,
282 update:update,
283 addTo:addTo,
284 newElement:newElement
285};
287}())