on 4587d3d help sign in
elk/runtime/Render/Element.js
268 lines 7.8 kB history raw
2ElmRuntime.Render.Element = function() {
3'use strict';
5var Utils = use(ElmRuntime.Render.Utils);
6var newElement = Utils.newElement, addTo = Utils.addTo, extract = Utils.extract;
8function setProps(props, e) {
9 e.style.width = (props.width |0) + 'px';
10 e.style.height = (props.height|0) + 'px';
11 if (props.opacity !== 1) { e.style.opacity = props.opacity; }
12 if (props.color.ctor === 'Just') {
13 e.style.backgroundColor = extract(props.color._0);
14 }
15 if (props.tag !== '') { e.id = props.tag; }
16 if (props.href !== '') {
17 var a = newElement('a');
18 a.href = props.href;
19 addTo(a,e);
20 return a;
21 }
22 return e;
25function image(props, img) {
26 switch (img._0.ctor) {
27 case 'Plain': return plainImage(img._3);
28 case 'Fitted': return fittedImage(props.width, props.height, img._3);
29 case 'Cropped': return croppedImage(img,props.width,props.height,img._3);
30 }
33function plainImage(src) {
34 var img = newElement('img');
35 img.src = src;
36 img.name = src;
37 img.style.display = "block";
38 return img;
41function fittedImage(w, h, src) {
42 var e = newElement('div');
43 e.style.position = "relative";
44 e.style.overflow = "hidden";
46 var img = newElement('img');
47 img.onload = function() {
48 img.style.position = 'absolute';
49 img.style.margin = 'auto';
51 var sw = w, sh = h;
52 if (w / h > this.width / this.height) {
53 sh = Math.round(this.height * w / this.width);
54 } else {
55 sw = Math.round(this.width * h / this.height);
56 }
57 img.style.width = sw + 'px';
58 img.style.height = sh + 'px';
59 img.style.left = ((w - sw) / 2) + 'px';
60 img.style.top = ((h - sh) / 2) + 'px';
61 };
62 img.src = src;
63 img.name = src;
64 addTo(e,img);
65 return e;
68function croppedImage(elem, w, h, src) {
69 var pos = elem._0._0;
70 var e = newElement('div');
71 e.style.position = "relative";
72 e.style.overflow = "hidden";
74 var img = newElement('img');
75 img.onload = function() {
76 img.style.position = 'absolute';
77 img.style.margin = 'auto';
78 var sw = w / elem._1, sh = h / elem._2;
79 img.style.width = ((this.width * sw)|0) + 'px';
80 img.style.height = ((this.height * sh)|0) + 'px';
81 img.style.left = ((- pos._0 * sw)|0) + 'px';
82 img.style.top = ((- pos._1 * sh)|0) + 'px';
83 };
84 img.src = src;
85 img.name = src;
86 addTo(e,img);
87 return e;
90function goIn(e) { e.style.position = 'absolute'; return e; }
91function goDown(e) { return e }
92function goRight(e) { e.style.styleFloat = e.style.cssFloat = "left"; return e; }
93function flowWith(f, array) {
94 var container = newElement('div');
95 for (var i = array.length; i--; ) {
96 addTo(container, f(render(array[i])));
97 }
98 return container;
101function flow(dir,elist) {
102 var array = fromList(elist);
103 switch(dir.ctor) {
104 case "DDown": array.reverse();
105 case "DUp": return flowWith(goDown,array);
106 case "DRight": array.reverse();
107 case "DLeft": return flowWith(goRight,array);
108 case "DOut": array.reverse();
109 case "DIn": return flowWith(goIn,array);
110 }
113function toPos(pos) {
114 switch(pos[0]) {
115 case "Absolute": return pos[1] + "px";
116 case "Relative": return (pos[1] * 100) + "%";
117 }
120function addTransform(style, trans) {
121 style.transform = trans;
122 style.msTransform = trans;
123 style.MozTransform = trans;
124 style.webkitTransform = trans;
125 style.OTransform = trans;
128function removeTransform(style) {
129 style.transform = 'none';
130 style.msTransform = 'none';
131 style.MozTransform = 'none';
132 style.webkitTransform = 'none';
133 style.OTransform = 'none';
136function setPos(pos,w,h,e) {
137 e.style.position = 'absolute';
138 e.style.margin = 'auto';
139 var transform = '';
140 switch(pos.horizontal) {
141 case 'P': e.style.right = toPos(pos.x); break;
142 case 'Z': transform = 'translateX(' + ((-w/2)|0) + 'px) ';
143 case 'N': e.style.left = toPos(pos.x); break;
144 }
145 switch(pos.vertical) {
146 case 'N': e.style.bottom = toPos(pos.x); break;
147 case 'Z': transform += 'translateY(' + ((-h/2)|0) + 'px)';
148 case 'P': e.style.top = toPos(pos.x); break;
149 }
150 if (transform !== '') addTransform(e.style, transform);
151 return e;
154function container(pos,elem) {
155 var e = render(elem);
156 setPos(pos, elem.props.width, elem.props.height, e);
157 var div = newElement('div');
158 div.style.position = 'relative';
159 div.style.overflow = 'hidden';
160 addTo(div,e);
161 return div;
164function rawHtml(html) {
165 var e = newElement('div');
166 e.innerHTML = html;
167 return e;
170function render(elem) { return setProps(elem.props, makeElement(elem)); }
171function makeElement(e) {
172 switch(e.element.ctor) {
173 case 'Image': return image(e.props, e.element);
174 case 'Flow': return flow(e.element._0, e.element._1);
175 case 'Container': return container(e.element._0, e.element._1);
176 case 'Spacer': return newElement('div');
177 case 'RawHtml': return rawHtml(e.element._0);
178 case 'DomNode': return e.element._0;
179 }
182function update(node, curr, next) {
183 if (node.tagName === 'A') { node = node.firstChild; }
184 if (curr.props.id === next.props.id) return false;
185 if (curr.element.ctor !== next.element.ctor) {
186 node.parentNode.replaceChild(render(next),node);
187 return true;
188 }
189 var nextE = next.element, currE = curr.element;
190 switch(nextE.ctor) {
191 case "Spacer": break;
192 case "RawHtml": if (nextE._0 !== currE._0) node.innerHTML = nextE._0; break;
193 case "Image":
194 if (nextE._0.ctor === 'Plain') {
195 if (nextE._3 !== currE._3) node.src = nextE._3;
196 } else if (!eq(nextE,currE) ||
197 next.props.width !== curr.props.width ||
198 next.props.height !== curr.props.height) {
199 node.parentNode.replaceChild(render(next),node);
200 return true;
201 }
202 break;
203 case "Flow":
204 if (nextE._0.ctor !== currE._0.ctor) {
205 node.parentNode.replaceChild(render(next),node);
206 return true;
207 }
208 var nexts = nextE._1;
209 var kids = node.childNodes;
210 if (nexts.length !== kids.length) {
211 node.parentNode.replaceChild(render(next),node);
212 return true;
213 }
214 var currs = currE._1;
215 var goDir = function(x) { return x; };
216 switch(nextE[1][0]) {
217 case "DDown": case "DUp": goDir = goDown; break;
218 case "DRight": case "DLeft": goDir = goRight; break;
219 case "DOut": case "DIn": goDir = goIn; break;
220 }
221 for (var i = kids.length; i-- ;) {
222 update(kids[i],currs[i],nexts[i]);
223 goDir(kids[i]);
224 }
225 break;
226 case "Container":
227 var inner = node.firstChild;
228 if (!update(inner, currE._1, nextE._1)) {
229 if (nextE._0.horizontal.ctor !== currE._0.horizontal.ctor) {
230 inner.style.left = inner.style.right = 'none';
231 removeTransform(inner.style);
232 }
233 if (nextE._0.vertical.ctor !== currE._0.vertical.ctor) {
234 inner.style.top = inner.style.bottom = 'none';
235 removeTransform(inner.style);
236 }
237 }
238 setPos(nextE._0, next.props.width, next.props.height, node.firstChild);
239 break;
240 case "DomNode":
241 if (next._0 !== curr._0) node.parentNode.replaceChild(render(next),node);
242 break;
243 }
244 var props = next.props, currP = curr.props, e = node;
245 if (props.width !== currP.width) e.style.width = (props.width |0) + 'px';
246 if (props.height !== currP.height) e.style.height = (props.height|0) + 'px';
247 if (props.opacity !== 1 && props.opacity !== currP.opacity) {
248 e.style.opacity = props.opacity;
249 }
250 var nextColor = (props.color.ctor === 'Just' ?
251 extract(props.color._0) : 'transparent');
252 if (e.style.backgroundColor !== nextColor) e.style.backgroundColor = nextColor;
253 if (props.tag !== currP.tag) { e.id = props.tag; }
254 if (props.href !== currP.href) {
255 if (currP.href === '') {
256 var a = newElement('a');
257 a.href = props.href;
258 addTo(a,e);
259 e.parentNode.replaceChild(a,e);
260 } else {
261 node.parentNode.href = props.href;
262 }
263 }
266return { render:render, update:update };
268};