UNPKG

snabbdom

Version:

A virtual DOM library with focus on simplicity, modularity, powerful features and performance.

567 lines (508 loc) 17.8 kB
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ 'use strict'; var VNode = require('./vnode'); var is = require('./is'); function addNS(data, children) { data.ns = 'http://www.w3.org/2000/svg'; if (children !== undefined) { for (var i = 0; i < children.length; ++i) { addNS(children[i].data, children[i].children); } } } module.exports = function h(sel, b, c) { var data = {}, children, text, i; if (arguments.length === 3) { data = b; if (is.array(c)) { children = c; } else if (is.primitive(c)) { text = c; } } else if (arguments.length === 2) { if (is.array(b)) { children = b; } else if (is.primitive(b)) { text = b; } else { data = b; } } if (is.array(children)) { for (i = 0; i < children.length; ++i) { if (is.primitive(children[i])) children[i] = VNode(undefined, undefined, undefined, children[i]); } } if (sel[0] === 's' && sel[1] === 'v' && sel[2] === 'g') { addNS(data, children); } return VNode(sel, data, children, text, undefined); }; },{"./is":2,"./vnode":7}],2:[function(require,module,exports){ 'use strict'; module.exports = { array: Array.isArray, primitive: function primitive(s) { return typeof s === 'string' || typeof s === 'number'; } }; },{}],3:[function(require,module,exports){ "use strict"; var booleanAttrs = ["allowfullscreen", "async", "autofocus", "autoplay", "checked", "compact", "controls", "declare", "default", "defaultchecked", "defaultmuted", "defaultselected", "defer", "disabled", "draggable", "enabled", "formnovalidate", "hidden", "indeterminate", "inert", "ismap", "itemscope", "loop", "multiple", "muted", "nohref", "noresize", "noshade", "novalidate", "nowrap", "open", "pauseonexit", "readonly", "required", "reversed", "scoped", "seamless", "selected", "sortable", "spellcheck", "translate", "truespeed", "typemustmatch", "visible"]; var booleanAttrsDict = {}; for (var i = 0, len = booleanAttrs.length; i < len; i++) { booleanAttrsDict[booleanAttrs[i]] = true; } function updateAttrs(oldVnode, vnode) { var key, cur, old, elm = vnode.elm, oldAttrs = oldVnode.data.attrs || {}, attrs = vnode.data.attrs || {}; // update modified attributes, add new attributes for (key in attrs) { cur = attrs[key]; old = oldAttrs[key]; if (old !== cur) { // TODO: add support to namespaced attributes (setAttributeNS) if (!cur && booleanAttrsDict[key]) elm.removeAttribute(key);else elm.setAttribute(key, cur); } } //remove removed attributes // use `in` operator since the previous `for` iteration uses it (.i.e. add even attributes with undefined value) // the other option is to remove all attributes with value == undefined for (key in oldAttrs) { if (!(key in attrs)) { elm.removeAttribute(key); } } } module.exports = { create: updateAttrs, update: updateAttrs }; },{}],4:[function(require,module,exports){ 'use strict'; var is = require('../is'); function arrInvoker(arr) { return function () { // Special case when length is two, for performance arr.length === 2 ? arr[0](arr[1]) : arr[0].apply(undefined, arr.slice(1)); }; } function fnInvoker(o) { return function (ev) { o.fn(ev); }; } function updateEventListeners(oldVnode, vnode) { var name, cur, old, elm = vnode.elm, oldOn = oldVnode.data.on || {}, on = vnode.data.on; if (!on) return; for (name in on) { cur = on[name]; old = oldOn[name]; if (old === undefined) { if (is.array(cur)) { elm.addEventListener(name, arrInvoker(cur)); } else { cur = { fn: cur }; on[name] = cur; elm.addEventListener(name, fnInvoker(cur)); } } else if (is.array(old)) { // Deliberately modify old array since it's captured in closure created with `arrInvoker` old.length = cur.length; for (var i = 0; i < old.length; ++i) { old[i] = cur[i]; }on[name] = old; } else { old.fn = cur; on[name] = old; } } } module.exports = { create: updateEventListeners, update: updateEventListeners }; },{"../is":2}],5:[function(require,module,exports){ 'use strict'; var raf = window && window.requestAnimationFrame || setTimeout; var nextFrame = function nextFrame(fn) { raf(function () { raf(fn); }); }; function setNextFrame(obj, prop, val) { nextFrame(function () { obj[prop] = val; }); } function updateStyle(oldVnode, vnode) { var cur, name, elm = vnode.elm, oldStyle = oldVnode.data.style || {}, style = vnode.data.style || {}, oldHasDel = 'delayed' in oldStyle; for (name in oldStyle) { if (!style[name]) { elm.style[name] = ''; } } for (name in style) { cur = style[name]; if (name === 'delayed') { for (name in style.delayed) { cur = style.delayed[name]; if (!oldHasDel || cur !== oldStyle.delayed[name]) { setNextFrame(elm.style, name, cur); } } } else if (name !== 'remove' && cur !== oldStyle[name]) { elm.style[name] = cur; } } } function applyDestroyStyle(vnode) { var style, name, elm = vnode.elm, s = vnode.data.style; if (!s || !(style = s.destroy)) return; for (name in style) { elm.style[name] = style[name]; } } function applyRemoveStyle(vnode, rm) { var s = vnode.data.style; if (!s || !s.remove) { rm(); return; } var name, elm = vnode.elm, idx, i = 0, maxDur = 0, compStyle, style = s.remove, amount = 0, applied = []; for (name in style) { applied.push(name); elm.style[name] = style[name]; } compStyle = getComputedStyle(elm); var props = compStyle['transition-property'].split(', '); for (; i < props.length; ++i) { if (applied.indexOf(props[i]) !== -1) amount++; } elm.addEventListener('transitionend', function (ev) { if (ev.target === elm) --amount; if (amount === 0) rm(); }); } module.exports = { create: updateStyle, update: updateStyle, destroy: applyDestroyStyle, remove: applyRemoveStyle }; },{}],6:[function(require,module,exports){ // jshint newcap: false /* global require, module, document, Element */ 'use strict'; var VNode = require('./vnode'); var is = require('./is'); function isUndef(s) { return s === undefined; } function isDef(s) { return s !== undefined; } function emptyNodeAt(elm) { return VNode(elm.tagName, {}, [], undefined, elm); } var emptyNode = VNode('', {}, [], undefined, undefined); function sameVnode(vnode1, vnode2) { return vnode1.key === vnode2.key && vnode1.sel === vnode2.sel; } function createKeyToOldIdx(children, beginIdx, endIdx) { var i, map = {}, key; for (i = beginIdx; i <= endIdx; ++i) { key = children[i].key; if (isDef(key)) map[key] = i; } return map; } function createRmCb(childElm, listeners) { return function () { if (--listeners === 0) childElm.parentElement.removeChild(childElm); }; } var hooks = ['create', 'update', 'remove', 'destroy', 'pre', 'post']; function init(modules) { var i, j, cbs = {}; for (i = 0; i < hooks.length; ++i) { cbs[hooks[i]] = []; for (j = 0; j < modules.length; ++j) { if (modules[j][hooks[i]] !== undefined) cbs[hooks[i]].push(modules[j][hooks[i]]); } } function createElm(vnode, insertedVnodeQueue) { var i, data = vnode.data; if (isDef(data)) { if (isDef(i = data.hook) && isDef(i = i.init)) i(vnode); if (isDef(i = data.vnode)) vnode = i; } var elm, children = vnode.children, sel = vnode.sel; if (isDef(sel)) { // Parse selector var hashIdx = sel.indexOf('#'); var dotIdx = sel.indexOf('.', hashIdx); var hash = hashIdx > 0 ? hashIdx : sel.length; var dot = dotIdx > 0 ? dotIdx : sel.length; var tag = hashIdx !== -1 || dotIdx !== -1 ? sel.slice(0, Math.min(hash, dot)) : sel; elm = vnode.elm = isDef(data) && isDef(i = data.ns) ? document.createElementNS(i, tag) : document.createElement(tag); if (hash < dot) elm.id = sel.slice(hash + 1, dot); if (dotIdx > 0) elm.className = sel.slice(dot + 1).replace(/\./g, ' '); if (is.array(children)) { for (i = 0; i < children.length; ++i) { elm.appendChild(createElm(children[i], insertedVnodeQueue)); } } else if (is.primitive(vnode.text)) { elm.appendChild(document.createTextNode(vnode.text)); } for (i = 0; i < cbs.create.length; ++i) { cbs.create[i](emptyNode, vnode); }i = vnode.data.hook; // Reuse variable if (isDef(i)) { if (i.create) i.create(emptyNode, vnode); if (i.insert) insertedVnodeQueue.push(vnode); } } else { elm = vnode.elm = document.createTextNode(vnode.text); } return vnode.elm; } function addVnodes(parentElm, before, vnodes, startIdx, endIdx, insertedVnodeQueue) { for (; startIdx <= endIdx; ++startIdx) { parentElm.insertBefore(createElm(vnodes[startIdx], insertedVnodeQueue), before); } } function invokeDestroyHook(vnode) { var i = vnode.data, j; if (isDef(i)) { if (isDef(i = i.hook) && isDef(i = i.destroy)) i(vnode); for (i = 0; i < cbs.destroy.length; ++i) { cbs.destroy[i](vnode); }if (isDef(i = vnode.children)) { for (j = 0; j < vnode.children.length; ++j) { invokeDestroyHook(vnode.children[j]); } } } } function removeVnodes(parentElm, vnodes, startIdx, endIdx) { for (; startIdx <= endIdx; ++startIdx) { var i, listeners, rm, ch = vnodes[startIdx]; if (isDef(ch)) { if (isDef(ch.sel)) { invokeDestroyHook(ch); listeners = cbs.remove.length + 1; rm = createRmCb(ch.elm, listeners); for (i = 0; i < cbs.remove.length; ++i) { cbs.remove[i](ch, rm); }if (isDef(i = ch.data) && isDef(i = i.hook) && isDef(i = i.remove)) { i(ch, rm); } else { rm(); } } else { // Text node parentElm.removeChild(ch.elm); } } } } function updateChildren(parentElm, oldCh, newCh, insertedVnodeQueue) { var oldStartIdx = 0, newStartIdx = 0; var oldEndIdx = oldCh.length - 1; var oldStartVnode = oldCh[0]; var oldEndVnode = oldCh[oldEndIdx]; var newEndIdx = newCh.length - 1; var newStartVnode = newCh[0]; var newEndVnode = newCh[newEndIdx]; var oldKeyToIdx, idxInOld, elmToMove, before; while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) { if (isUndef(oldStartVnode)) { oldStartVnode = oldCh[++oldStartIdx]; // Vnode has been moved left } else if (isUndef(oldEndVnode)) { oldEndVnode = oldCh[--oldEndIdx]; } else if (sameVnode(oldStartVnode, newStartVnode)) { patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue); oldStartVnode = oldCh[++oldStartIdx]; newStartVnode = newCh[++newStartIdx]; } else if (sameVnode(oldEndVnode, newEndVnode)) { patchVnode(oldEndVnode, newEndVnode, insertedVnodeQueue); oldEndVnode = oldCh[--oldEndIdx]; newEndVnode = newCh[--newEndIdx]; } else if (sameVnode(oldStartVnode, newEndVnode)) { // Vnode moved right patchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue); parentElm.insertBefore(oldStartVnode.elm, oldEndVnode.elm.nextSibling); oldStartVnode = oldCh[++oldStartIdx]; newEndVnode = newCh[--newEndIdx]; } else if (sameVnode(oldEndVnode, newStartVnode)) { // Vnode moved left patchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue); parentElm.insertBefore(oldEndVnode.elm, oldStartVnode.elm); oldEndVnode = oldCh[--oldEndIdx]; newStartVnode = newCh[++newStartIdx]; } else { if (isUndef(oldKeyToIdx)) oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx); idxInOld = oldKeyToIdx[newStartVnode.key]; if (isUndef(idxInOld)) { // New element parentElm.insertBefore(createElm(newStartVnode, insertedVnodeQueue), oldStartVnode.elm); newStartVnode = newCh[++newStartIdx]; } else { elmToMove = oldCh[idxInOld]; patchVnode(elmToMove, newStartVnode, insertedVnodeQueue); oldCh[idxInOld] = undefined; parentElm.insertBefore(elmToMove.elm, oldStartVnode.elm); newStartVnode = newCh[++newStartIdx]; } } } if (oldStartIdx > oldEndIdx) { before = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm; addVnodes(parentElm, before, newCh, newStartIdx, newEndIdx, insertedVnodeQueue); } else if (newStartIdx > newEndIdx) { removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx); } } function patchVnode(oldVnode, vnode, insertedVnodeQueue) { var i, hook; if (isDef(i = vnode.data) && isDef(hook = i.hook) && isDef(i = hook.prepatch)) { i(oldVnode, vnode); } if (isDef(i = oldVnode.data) && isDef(i = i.vnode)) oldVnode = i; if (isDef(i = vnode.data) && isDef(i = i.vnode)) vnode = i; var elm = vnode.elm = oldVnode.elm, oldCh = oldVnode.children, ch = vnode.children; if (oldVnode === vnode) return; if (isDef(vnode.data)) { for (i = 0; i < cbs.update.length; ++i) { cbs.update[i](oldVnode, vnode); }i = vnode.data.hook; if (isDef(i) && isDef(i = i.update)) i(oldVnode, vnode); } if (isUndef(vnode.text)) { if (isDef(oldCh) && isDef(ch)) { if (oldCh !== ch) updateChildren(elm, oldCh, ch, insertedVnodeQueue); } else if (isDef(ch)) { addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue); } else if (isDef(oldCh)) { removeVnodes(elm, oldCh, 0, oldCh.length - 1); } } else if (oldVnode.text !== vnode.text) { elm.textContent = vnode.text; } if (isDef(hook) && isDef(i = hook.postpatch)) { i(oldVnode, vnode); } } return function (oldVnode, vnode) { var i; var insertedVnodeQueue = []; for (i = 0; i < cbs.pre.length; ++i) { cbs.pre[i](); }if (oldVnode instanceof Element) { if (oldVnode.parentElement !== null) { createElm(vnode, insertedVnodeQueue); oldVnode.parentElement.replaceChild(vnode.elm, oldVnode); } else { oldVnode = emptyNodeAt(oldVnode); patchVnode(oldVnode, vnode, insertedVnodeQueue); } } else { patchVnode(oldVnode, vnode, insertedVnodeQueue); } for (i = 0; i < insertedVnodeQueue.length; ++i) { insertedVnodeQueue[i].data.hook.insert(insertedVnodeQueue[i]); } for (i = 0; i < cbs.post.length; ++i) { cbs.post[i](); }return vnode; }; } module.exports = { init: init }; },{"./is":2,"./vnode":7}],7:[function(require,module,exports){ "use strict"; module.exports = function (sel, data, children, text, elm) { var key = data === undefined ? undefined : data.key; return { sel: sel, data: data, children: children, text: text, elm: elm, key: key }; }; },{}],8:[function(require,module,exports){ 'use strict'; var snabbdom = require('../../snabbdom.js'); var patch = snabbdom.init([require('../../modules/attributes'), require('../../modules/style'), require('../../modules/eventlisteners')]); var h = require('../../h.js'); var vnode; var data = { degRotation: 0 }; function gRotation() { //console.log("gRotation: %s", data.degRotation); return "rotate(" + data.degRotation + "deg)"; } function triangleClick(id) { console.log("triangleClick: %s", id); render(); } function handleRotate(degs) { data.degRotation += degs; console.log("handleRotate: %s, %s", degs, data.degRotation); render(); } function handleReset(degs) { data.degRotation = degs; console.log("handleReset: %s", degs); render(); } function render() { vnode = patch(vnode, view(data)); } var hTriangle = function hTriangle(id, degRotation) { return h("polygon#" + id, { attrs: { points: "-50,-88 0,-175 50,-88", transform: "rotate(" + degRotation + ")", "stroke-width": 3 }, on: { click: [triangleClick, id] } }); }; var view = function view(data) { return h("div.view", [h("h1", "Snabbdom SVG Carousel"), h("svg", { attrs: { width: 380, height: 380, viewBox: [-190, -190, 380, 380] } }, [h("g#carousel", { style: { "-webkit-transform": gRotation(), transform: gRotation() } }, [hTriangle("yellow", 0), hTriangle("green", 60), hTriangle("magenta", 120), hTriangle("red", 180), hTriangle("cyan", 240), hTriangle("blue", 300)])]), h("button", { on: { click: [handleRotate, 60] } }, "Rotate Clockwise"), h("button", { on: { click: [handleRotate, -60] } }, "Rotate Anticlockwise"), h("button", { on: { click: [handleReset, 0] } }, "Reset")]); }; window.addEventListener("DOMContentLoaded", function () { var container = document.getElementById("container"); vnode = patch(container, view(data)); render(); }); },{"../../h.js":1,"../../modules/attributes":3,"../../modules/eventlisteners":4,"../../modules/style":5,"../../snabbdom.js":6}]},{},[8]);