ElmRuntime.Render.Element = function() { 'use strict'; var Utils = ElmRuntime.use(ElmRuntime.Render.Utils); var newElement = Utils.newElement, extract = Utils.extract, addTransform = Utils.addTransform, removeTransform = Utils.removeTransform, fromList = Utils.fromList, eq = Utils.eq; function setProps(elem, e) { var props = elem.props; var element = elem.element; if (element.adjustWidth) { props.width -= element.adjustWidth; } if (element.adjustHeight) { props.height -= element.adjustHeight; } e.style.width = (props.width |0) + 'px'; e.style.height = (props.height|0) + 'px'; if (props.opacity !== 1) { e.style.opacity = props.opacity; } if (props.color.ctor === 'Just') { e.style.backgroundColor = extract(props.color._0); } if (props.tag !== '') { e.id = props.tag; } if (props.href !== '') { var a = newElement('a'); a.href = props.href; a.style.width = '100%'; a.style.height = '100%'; a.style.top = 0; a.style.left = 0; a.style.display = 'block'; a.style.position = 'absolute'; e.style.position = 'relative'; e.appendChild(a); } if (props.hover.ctor !== '_Tuple0') { e.style.pointerEvents = 'auto'; e.elm_hover_handler = props.hover; e.elm_hover_count = 0; e.addEventListener('mouseover', function() { if (e.elm_hover_count++ > 0) return; var handler = e.elm_hover_handler; if (handler !== null) { handler(true); } }); e.addEventListener('mouseout', function(evt) { if (e.contains(evt.toElement || evt.relatedTarget)) return; e.elm_hover_count = 0; var handler = e.elm_hover_handler; if (handler !== null) { handler(false); } }); } if (props.click.ctor !== '_Tuple0') { e.style.pointerEvents = 'auto'; e.elm_click_handler = props.click; e.addEventListener('click', function() { e.elm_click_handler(Tuple0); }); } return e; } function image(props, img) { switch (img._0.ctor) { case 'Plain': return plainImage(img._3); case 'Fitted': return fittedImage(props.width, props.height, img._3); case 'Cropped': return croppedImage(img,props.width,props.height,img._3); case 'Tiled': return tiledImage(img._3); } } function plainImage(src) { var img = newElement('img'); img.src = src; img.name = src; img.style.display = "block"; return img; } function tiledImage(src) { var div = newElement('div'); div.style.backgroundImage = 'url(' + src + ')'; return div; } function fittedImage(w, h, src) { var div = newElement('div'); div.style.background = 'url(' + src + ') no-repeat center'; div.style.webkitBackgroundSize = 'cover'; div.style.MozBackgroundSize = 'cover'; div.style.OBackgroundSize = 'cover'; div.style.backgroundSize = 'cover'; return div; } function croppedImage(elem, w, h, src) { var pos = elem._0._0; var e = newElement('div'); e.style.overflow = "hidden"; var img = newElement('img'); img.onload = function() { var sw = w / elem._1, sh = h / elem._2; img.style.width = ((this.width * sw)|0) + 'px'; img.style.height = ((this.height * sh)|0) + 'px'; img.style.marginLeft = ((- pos._0 * sw)|0) + 'px'; img.style.marginTop = ((- pos._1 * sh)|0) + 'px'; }; img.src = src; img.name = src; e.appendChild(img); return e; } function goIn(e) { e.style.position = 'absolute'; return e; } function goDown(e) { return e } function goRight(e) { e.style.styleFloat = e.style.cssFloat = "left"; return e; } function flowWith(f, array) { var container = newElement('div'); if (f == goIn) container.style.pointerEvents = 'none'; for (var i = array.length; i--; ) { container.appendChild(f(render(array[i]))); } return container; } function flow(dir,elist) { var array = fromList(elist); switch(dir.ctor) { case "DDown": array.reverse(); case "DUp": return flowWith(goDown,array); case "DRight": array.reverse(); case "DLeft": return flowWith(goRight,array); case "DOut": array.reverse(); case "DIn": return flowWith(goIn,array); } } function toPos(pos) { switch(pos.ctor) { case "Absolute": return pos._0 + "px"; case "Relative": return (pos._0 * 100) + "%"; } } // must clear right, left, top, bottom, and transform // before calling this function function setPos(pos,w,h,e) { e.style.position = 'absolute'; e.style.margin = 'auto'; var transform = ''; switch(pos.horizontal.ctor) { case 'P': e.style.right = toPos(pos.x); e.style.removeProperty('left'); break; case 'Z': transform = 'translateX(' + ((-w/2)|0) + 'px) '; case 'N': e.style.left = toPos(pos.x); e.style.removeProperty('right'); break; } switch(pos.vertical.ctor) { case 'N': e.style.bottom = toPos(pos.y); e.style.removeProperty('top'); break; case 'Z': transform += 'translateY(' + ((-h/2)|0) + 'px)'; case 'P': e.style.top = toPos(pos.y); e.style.removeProperty('bottom'); break; } if (transform !== '') addTransform(e.style, transform); return e; } function container(pos,elem) { var e = render(elem); setPos(pos, elem.props.width, elem.props.height, e); var div = newElement('div'); div.style.position = 'relative'; div.style.overflow = 'hidden'; div.appendChild(e); return div; } function rawHtml(elem) { var html = elem.html; var args = elem.args; var guid = elem.guid; var align = elem.align; var div = newElement('div'); div.innerHTML = html; div.style.visibility = "hidden"; if (align) div.style.textAlign = align; document.body.appendChild(div); for (var i = args.length; i--; ) { var arg = args[i]; var span = document.getElementById('md-' + guid + '-' + i); if (arg.isText) { span.innerHTML = arg; } else { span.style.display = 'block'; span.style.width = arg.props.width + 'px'; span.style.height = arg.props.height + 'px'; span.appendChild(render(arg)); } } document.body.removeChild(div); div.style.visibility = 'visible'; return div; } function render(elem) { return setProps(elem, makeElement(elem)); } function makeElement(e) { var elem = e.element; switch(elem.ctor) { case 'Image': return image(e.props, elem); case 'Flow': return flow(elem._0, elem._1); case 'Container': return container(elem._0, elem._1); case 'Spacer': return newElement('div'); case 'RawHtml': return rawHtml(elem); case 'Custom': return elem.render(elem.model); } } function update(node, curr, next) { if (node.tagName === 'A') { node = node.firstChild; } if (curr.props.id === next.props.id) return updateProps(node, curr, next); if (curr.element.ctor !== next.element.ctor) { node.parentNode.replaceChild(render(next),node); return true; } var nextE = next.element, currE = curr.element; switch(nextE.ctor) { case "Spacer": break; case "RawHtml": // only markdown blocks have guids, so this must be a text block if (nextE.guid === null) { if(currE.html.valueOf() !== nextE.html.valueOf()) { node.innerHTML = nextE.html; } break; } if (nextE.guid !== currE.guid) { node.parentNode.replaceChild(render(next),node); return true; } var nargs = nextE.args; var cargs = currE.args; for (var i = nargs.length; i--; ) { var narg = nargs[i]; var carg = cargs[i] if (narg == carg) continue; var span = document.getElementById('md-' + currE.guid + '-' + i); if (narg.isElement) { if (carg.isElement) { update(span, carg, narg); } else { span.style.display = 'block'; var e = render(narg); span.innerHTML = ''; span.appendChild(e); } } else { span.style.display = 'inline'; span.innerHTML = narg; } } break; case "Image": if (nextE._0.ctor === 'Plain') { if (nextE._3 !== currE._3) node.src = nextE._3; } else if (!eq(nextE,currE) || next.props.width !== curr.props.width || next.props.height !== curr.props.height) { node.parentNode.replaceChild(render(next),node); return true; } break; case "Flow": var arr = fromList(nextE._1); for (var i = arr.length; i--; ) { arr[i] = arr[i].element.ctor; } if (nextE._0.ctor !== currE._0.ctor) { node.parentNode.replaceChild(render(next),node); return true; } var nexts = fromList(nextE._1); var kids = node.childNodes; if (nexts.length !== kids.length) { node.parentNode.replaceChild(render(next),node); return true; } var currs = fromList(currE._1); var goDir = function(x) { return x; }; switch(nextE._0.ctor) { case "DDown": case "DUp": goDir = goDown; break; case "DRight": case "DLeft": goDir = goRight; break; case "DOut": case "DIn": goDir = goIn; break; } for (var i = kids.length; i-- ;) { update(kids[i],currs[i],nexts[i]); goDir(kids[i]); } break; case "Container": update(node.firstChild, currE._1, nextE._1); setPos(nextE._0, nextE._1.props.width, nextE._1.props.height, node.firstChild); break; case "Custom": if (currE.type === nextE.type) { var done = nextE.update(node, currE.model, nextE.model); if (done) return; } else { return node.parentNode.replaceChild(render(next), node); } } updateProps(node, curr, next); } function updateProps(node, curr, next) { var props = next.props; var currP = curr.props; var e = node; var element = next.element; if (element.adjustWidth) { props.width -= element.adjustWidth; } if (element.adjustHeight) { props.height -= element.adjustHeight; } if (props.width !== currP.width) e.style.width = (props.width |0) + 'px'; if (props.height !== currP.height) e.style.height = (props.height|0) + 'px'; if (props.opacity !== 1 && props.opacity !== currP.opacity) { e.style.opacity = props.opacity; } var nextColor = (props.color.ctor === 'Just' ? extract(props.color._0) : ''); if (e.style.backgroundColor !== nextColor) { e.style.backgroundColor = (nextColor === '' ? 'transparent' : nextColor); } if (props.tag !== currP.tag) { e.id = props.tag; } if (props.href !== currP.href) { if (currP.href === '') { var a = newElement('a'); a.href = props.href; a.style.width = '100%'; a.style.height = '100%'; a.style.top = 0; a.style.left = 0; a.style.display = 'block'; a.style.position = 'absolute'; e.style.position = 'relative'; e.appendChild(a); } else { node.lastNode.href = props.href; } } // update hover handlers if (props.hover.ctor !== '_Tuple0') { e.elm_hover_handler = props.hover; } else if (e.elm_hover_handler) { e.elm_hover_handler = null; } // update click handlers if (props.click.ctor !== '_Tuple0') { e.elm_click_handler = props.click; } else if (e.elm_click_handler) { e.elm_click_handler = null; } } return { render:render, update:update }; };