on 89efcef help sign in
elk/runtime/Render/Element.js
259 lines 7.8 kB history raw
2ElmRuntime.Render.Element = function() {
3'use strict';
5var Utils = ElmRuntime.use(ElmRuntime.Render.Utils);
6var newElement = Utils.newElement, extract = Utils.extract,
7 addTransform = Utils.addTransform, removeTransform = Utils.removeTransform,
8 fromList = Utils.fromList, eq = Utils.eq;
10function setProps(props, e) {
11 e.style.width = (props.width |0) + 'px';
12 e.style.height = (props.height|0) + 'px';
13 if (props.opacity !== 1) { e.style.opacity = props.opacity; }
14 if (props.color.ctor === 'Just') {
15 e.style.backgroundColor = extract(props.color._0);
16 }
17 if (props.tag !== '') { e.id = props.tag; }
18 if (props.href !== '') {
19 var a = newElement('a');
20 a.href = props.href;
21 a.appendChild(e);
22 return a;
23 }
24 return e;
27function image(props, img) {
28 switch (img._0.ctor) {
29 case 'Plain': return plainImage(img._3);
30 case 'Fitted': return fittedImage(props.width, props.height, img._3);
31 case 'Cropped': return croppedImage(img,props.width,props.height,img._3);
32 case 'Tiled': return tiledImage(img._3);
33 }
36function plainImage(src) {
37 var img = newElement('img');
38 img.src = src;
39 img.name = src;
40 img.style.display = "block";
41 return img;
44function tiledImage(src) {
45 var div = newElement('div');
46 div.style.backgroundImage = 'url(' + src + ')';
47 return div;
50function fittedImage(w, h, src) {
51 var div = newElement('div');
52 div.style.background = 'url(' + src + ') no-repeat center';
53 div.style.webkitBackgroundSize = 'cover';
54 div.style.MozBackgroundSize = 'cover';
55 div.style.OBackgroundSize = 'cover';
56 div.style.backgroundSize = 'cover';
57 return div;
60function croppedImage(elem, w, h, src) {
61 var pos = elem._0._0;
62 var e = newElement('div');
63 e.style.position = "relative";
64 e.style.overflow = "hidden";
66 var img = newElement('img');
67 img.onload = function() {
68 img.style.position = 'absolute';
69 img.style.margin = 'auto';
70 var sw = w / elem._1, sh = h / elem._2;
71 img.style.width = ((this.width * sw)|0) + 'px';
72 img.style.height = ((this.height * sh)|0) + 'px';
73 img.style.left = ((- pos._0 * sw)|0) + 'px';
74 img.style.top = ((- pos._1 * sh)|0) + 'px';
75 };
76 img.src = src;
77 img.name = src;
78 e.appendChild(img);
79 return e;
82function goIn(e) { e.style.position = 'absolute'; return e; }
83function goDown(e) { return e }
84function goRight(e) { e.style.styleFloat = e.style.cssFloat = "left"; return e; }
85function flowWith(f, array) {
86 var container = newElement('div');
87 for (var i = array.length; i--; ) {
88 container.appendChild(f(render(array[i])));
89 }
90 return container;
93function flow(dir,elist) {
94 var array = fromList(elist);
95 switch(dir.ctor) {
96 case "DDown": array.reverse();
97 case "DUp": return flowWith(goDown,array);
98 case "DRight": array.reverse();
99 case "DLeft": return flowWith(goRight,array);
100 case "DOut": array.reverse();
101 case "DIn": return flowWith(goIn,array);
102 }
105function toPos(pos) {
106 switch(pos.ctor) {
107 case "Absolute": return pos._0 + "px";
108 case "Relative": return (pos._0 * 100) + "%";
109 }
112function setPos(pos,w,h,e) {
113 e.style.position = 'absolute';
114 e.style.margin = 'auto';
115 var transform = '';
116 switch(pos.horizontal.ctor) {
117 case 'P': e.style.right = toPos(pos.x); break;
118 case 'Z': transform = 'translateX(' + ((-w/2)|0) + 'px) ';
119 case 'N': e.style.left = toPos(pos.x); break;
120 }
121 switch(pos.vertical.ctor) {
122 case 'N': e.style.bottom = toPos(pos.y); break;
123 case 'Z': transform += 'translateY(' + ((-h/2)|0) + 'px)';
124 case 'P': e.style.top = toPos(pos.y); break;
125 }
126 if (transform !== '') addTransform(e.style, transform);
127 return e;
130function container(pos,elem) {
131 var e = render(elem);
132 setPos(pos, elem.props.width, elem.props.height, e);
133 var div = newElement('div');
134 div.style.position = 'relative';
135 div.style.overflow = 'hidden';
136 div.appendChild(e);
137 return div;
140function rawHtml(html) {
141 var e = newElement('div');
142 e.innerHTML = html;
143 return e;
146function render(elem) { return setProps(elem.props, makeElement(elem)); }
147function makeElement(e) {
148 var elem = e.element;
149 switch(elem.ctor) {
150 case 'Image': return image(e.props, elem);
151 case 'Flow': return flow(elem._0, elem._1);
152 case 'Container': return container(elem._0, elem._1);
153 case 'Spacer': return newElement('div');
154 case 'RawHtml': return rawHtml(elem._0);
155 case 'Custom': return elem.render(elem.model);
156 }
159function update(node, curr, next) {
160 if (node.tagName === 'A') { node = node.firstChild; }
161 if (curr.props.id === next.props.id) return updateProps(node, curr, next);
162 if (curr.element.ctor !== next.element.ctor) {
163 node.parentNode.replaceChild(render(next),node);
164 return true;
165 }
166 var nextE = next.element, currE = curr.element;
167 switch(nextE.ctor) {
168 case "Spacer": break;
169 case "RawHtml":
170 if (nextE._0 !== currE._0) node.innerHTML = nextE._0;
171 break;
172 case "Image":
173 if (nextE._0.ctor !== 'Plain') {
174 if (nextE._3 !== currE._3) node.src = nextE._3;
175 } else if (!eq(nextE,currE) ||
176 next.props.width !== curr.props.width ||
177 next.props.height !== curr.props.height) {
178 node.parentNode.replaceChild(render(next),node);
179 return true;
180 }
181 break;
182 case "Flow":
183 var arr = fromList(nextE._1);
184 for (var i = arr.length; i--; ) { arr[i] = arr[i].element.ctor; }
185 if (nextE._0.ctor !== currE._0.ctor) {
186 node.parentNode.replaceChild(render(next),node);
187 return true;
188 }
189 var nexts = fromList(nextE._1);
190 var kids = node.childNodes;
191 if (nexts.length !== kids.length) {
192 node.parentNode.replaceChild(render(next),node);
193 return true;
194 }
195 var currs = fromList(currE._1);
196 var goDir = function(x) { return x; };
197 switch(nextE._0.ctor) {
198 case "DDown": case "DUp": goDir = goDown; break;
199 case "DRight": case "DLeft": goDir = goRight; break;
200 case "DOut": case "DIn": goDir = goIn; break;
201 }
202 for (var i = kids.length; i-- ;) {
203 update(kids[i],currs[i],nexts[i]);
204 goDir(kids[i]);
205 }
206 break;
207 case "Container":
208 var inner = node.firstChild;
209 if (!update(inner, currE._1, nextE._1)) {
210 if (nextE._0.horizontal.ctor !== currE._0.horizontal.ctor) {
211 inner.style.left = inner.style.right = 'none';
212 removeTransform(inner.style);
213 }
214 if (nextE._0.vertical.ctor !== currE._0.vertical.ctor) {
215 inner.style.top = inner.style.bottom = 'none';
216 removeTransform(inner.style);
217 }
218 }
219 setPos(nextE._0, nextE._1.props.width, nextE._1.props.height, inner);
220 break;
221 case "Custom":
222 if (currE.type === nextE.type) {
223 var done = nextE.update(node, currE.model, nextE.model);
224 if (done) return;
225 } else {
226 return node.parentNode.replaceChild(render(next), node);
227 }
228 }
229 updateProps(node, curr, next);
232function updateProps(node, curr, next) {
233 var props = next.props, currP = curr.props, e = node;
234 if (props.width !== currP.width) e.style.width = (props.width |0) + 'px';
235 if (props.height !== currP.height) e.style.height = (props.height|0) + 'px';
236 if (props.opacity !== 1 && props.opacity !== currP.opacity) {
237 e.style.opacity = props.opacity;
238 }
239 var nextColor = (props.color.ctor === 'Just' ?
240 extract(props.color._0) : 'transparent');
241 if (e.style.backgroundColor !== nextColor) {
242 e.style.backgroundColor = nextColor;
243 }
244 if (props.tag !== currP.tag) { e.id = props.tag; }
245 if (props.href !== currP.href) {
246 if (currP.href === '') {
247 var a = newElement('a');
248 a.href = props.href;
249 a.appendChild(e);
250 e.parentNode.replaceChild(a,e);
251 } else {
252 node.parentNode.href = props.href;
253 }
254 }
257return { render:render, update:update };
259};