diff --git a/examples/dev.html b/examples/dev.html
index 03d77a1de..143fbbeb5 100644
--- a/examples/dev.html
+++ b/examples/dev.html
@@ -48,7 +48,10 @@
type: "bi.vertical",
items: [{
type: "bi.button",
- text: store.model.text
+ text: store.model.text,
+ handler: function () {
+ console.log("click");
+ }
}, {
type: "bi.label",
text: store.model.text
@@ -62,7 +65,12 @@
var Widget = BI.inherit(BI.Widget, {
props: {
- updateMode: "auto"
+ vdom: true
+ },
+ watch: {
+ text: function () {
+ this.reset();
+ }
},
setup: function () {
var child;
@@ -72,13 +80,13 @@
setInterval(function () {
store.toggle();
}, 1000);
- BI.watch("text", function () {
- child.reset();
- });
+ // BI.watch("text", function () {
+ // child.reset();
+ // });
return function () {
return {
type: "bi.vertical",
- vgap: 20,
+ vgap: store.model.expand ? 20 : 30,
items: [{
type: "demo.child",
ref: function (_ref) {
diff --git a/src/core/4.widget.js b/src/core/4.widget.js
index 8eb0d6a53..84ff65d99 100644
--- a/src/core/4.widget.js
+++ b/src/core/4.widget.js
@@ -38,7 +38,7 @@
extraCls: "",
cls: "",
css: null,
- updateMode: "manual" // manual / auto
+ vdom: false
});
},
@@ -165,6 +165,7 @@
this.element = BI.Widget._renderEngine.createElement(this);
}
this.element._isWidget = true;
+ (this.element[0]._Widget = this.element[0]._Widget || []).push(this);
this._initCurrent();
},
@@ -216,20 +217,45 @@
els = [els];
}
if (BI.isArray(els)) {
+ if (this.options.vdom) {
+ this.vnode = this._renderVNode();
+ var div = document.createElement("div");
+ this.element.append(div);
+ BI.patchVNode(div, this.vnode);
+ } else {
+ BI.each(els, function (i, el) {
+ if (el) {
+ BI._lazyCreateWidget(el, {
+ element: self
+ });
+ }
+ });
+ }
+ }
+ this._mount();
+ if (this.__async === true && isMounted) {
+ callLifeHook(this, "mounted");
+ this.fireEvent(BI.Events.MOUNT);
+ }
+ },
+
+ _renderVNode: function () {
+ var render = BI.isFunction(this.options.render) ? this.options.render : this.render;
+ var els = render && render.call(this);
+ if (BI.isPlainObject(els)) {
+ els = [els];
+ }
+ if (BI.isArray(els)) {
+ var container = document.createElement("div");
BI.each(els, function (i, el) {
if (el) {
BI._lazyCreateWidget(el, {
- element: self
+ element: container
});
}
});
}
- this._mount();
-
- if (this.__async === true && isMounted) {
- callLifeHook(this, "mounted");
- this.fireEvent(BI.Events.MOUNT);
- }
+ return BI.Element2Snabbdom(container);
},
_setParent: function (parent) {
@@ -578,6 +604,12 @@
if (this.__async === true || this.__asking === true) {
return;
}
+ if (this.options.vdom) {
+ var vnode = this._renderVNode();
+ BI.patchVNode(this.vnode, vnode);
+ this.vnode = vnode;
+ return;
+ }
// this._isMounted = false;
// this.purgeListeners();
this._empty();
diff --git a/src/core/8.snabdom.js b/src/core/8.snabdom.js
new file mode 100644
index 000000000..f16d8355d
--- /dev/null
+++ b/src/core/8.snabdom.js
@@ -0,0 +1,1052 @@
+(function (global, factory) {
+ factory(BI.Snabbdom = BI.Snabbdom || {});
+})(this, function (exports) {
+ 'use strict';
+
+ function createElement(tagName) {
+ return document.createElement(tagName);
+ }
+ function createElementNS(namespaceURI, qualifiedName) {
+ return document.createElementNS(namespaceURI, qualifiedName);
+ }
+ function createTextNode(text) {
+ return document.createTextNode(text);
+ }
+ function createComment(text) {
+ return document.createComment(text);
+ }
+ function insertBefore(parentNode, newNode, referenceNode) {
+ parentNode.insertBefore(newNode, referenceNode);
+ }
+ function removeChild(node, child) {
+ node.removeChild(child);
+ }
+ function appendChild(node, child) {
+ node.appendChild(child);
+ }
+ function parentNode(node) {
+ return node.parentNode;
+ }
+ function nextSibling(node) {
+ return node.nextSibling;
+ }
+ function tagName(elm) {
+ return elm.tagName;
+ }
+ function setTextContent(node, text) {
+ node.textContent = text;
+ }
+ function getTextContent(node) {
+ return node.textContent;
+ }
+ function isElement(node) {
+ return node.nodeType === 1;
+ }
+ function isText(node) {
+ return node.nodeType === 3;
+ }
+ function isComment(node) {
+ return node.nodeType === 8;
+ }
+ var htmlDomApi = {
+ createElement: createElement,
+ createElementNS: createElementNS,
+ createTextNode: createTextNode,
+ createComment: createComment,
+ insertBefore: insertBefore,
+ removeChild: removeChild,
+ appendChild: appendChild,
+ parentNode: parentNode,
+ nextSibling: nextSibling,
+ tagName: tagName,
+ setTextContent: setTextContent,
+ getTextContent: getTextContent,
+ isElement: isElement,
+ isText: isText,
+ isComment: isComment
+ };
+
+ function vnode(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 };
+ }
+
+ var array = Array.isArray;
+ function primitive(s) {
+ return typeof s === "string" || typeof s === "number";
+ }
+
+ function isUndef(s) {
+ return s === undefined;
+ }
+ function isDef(s) {
+ return s !== undefined;
+ }
+ var emptyNode = vnode("", {}, [], undefined, undefined);
+ function sameVnode(vnode1, vnode2) {
+ return vnode1.key === vnode2.key && vnode1.sel === vnode2.sel;
+ }
+ function isVnode(vnode) {
+ return vnode.sel !== undefined;
+ }
+ function createKeyToOldIdx(children, beginIdx, endIdx) {
+ var _a;
+ var map = {};
+ for (var i = beginIdx; i <= endIdx; ++i) {
+ var key = (_a = children[i]) === null || _a === void 0 ? void 0 : _a.key;
+ if (key !== undefined) {
+ map[key] = i;
+ }
+ }
+ return map;
+ }
+ var hooks = ["create", "update", "remove", "destroy", "pre", "post"];
+ function init(modules, domApi) {
+ var i = void 0;
+ var j = void 0;
+ var cbs = {
+ create: [],
+ update: [],
+ remove: [],
+ destroy: [],
+ pre: [],
+ post: []
+ };
+ var api = domApi !== undefined ? domApi : htmlDomApi;
+ for (i = 0; i < hooks.length; ++i) {
+ cbs[hooks[i]] = [];
+ for (j = 0; j < modules.length; ++j) {
+ var hook = modules[j][hooks[i]];
+ if (hook !== undefined) {
+ cbs[hooks[i]].push(hook);
+ }
+ }
+ }
+ function emptyNodeAt(elm) {
+ var id = elm.id ? "#" + elm.id : "";
+ var c = elm.className ? "." + elm.className.split(" ").join(".") : "";
+ return vnode(api.tagName(elm).toLowerCase() + id + c, {}, [], undefined, elm);
+ }
+ function createRmCb(childElm, listeners) {
+ return function rmCb() {
+ if (--listeners === 0) {
+ var parent = api.parentNode(childElm);
+ api.removeChild(parent, childElm);
+ }
+ };
+ }
+ function createElm(vnode, insertedVnodeQueue) {
+ var _a, _b;
+ var i = void 0;
+ var data = vnode.data;
+ if (data !== undefined) {
+ var _init = (_a = data.hook) === null || _a === void 0 ? void 0 : _a.init;
+ if (isDef(_init)) {
+ _init(vnode);
+ data = vnode.data;
+ }
+ }
+ var children = vnode.children;
+ var sel = vnode.sel;
+ if (sel === "!") {
+ if (isUndef(vnode.text)) {
+ vnode.text = "";
+ }
+ vnode.elm = api.createComment(vnode.text);
+ } else if (sel !== undefined) {
+ // 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;
+ var elm = vnode.elm = isDef(data) && isDef(i = data.ns) ? api.createElementNS(i, tag) : api.createElement(tag);
+ if (hash < dot) elm.setAttribute("id", sel.slice(hash + 1, dot));
+ if (dotIdx > 0) elm.setAttribute("class", sel.slice(dot + 1).replace(/\./g, " "));
+ for (i = 0; i < cbs.create.length; ++i) {
+ cbs.create[i](emptyNode, vnode);
+ }if (array(children)) {
+ for (i = 0; i < children.length; ++i) {
+ var ch = children[i];
+ if (ch != null) {
+ api.appendChild(elm, createElm(ch, insertedVnodeQueue));
+ }
+ }
+ } else if (primitive(vnode.text)) {
+ api.appendChild(elm, api.createTextNode(vnode.text));
+ }
+ var _hook = vnode.data.hook;
+ if (isDef(_hook)) {
+ (_b = _hook.create) === null || _b === void 0 ? void 0 : _b.call(_hook, emptyNode, vnode);
+ if (_hook.insert) {
+ insertedVnodeQueue.push(vnode);
+ }
+ }
+ } else {
+ vnode.elm = api.createTextNode(vnode.text);
+ }
+ return vnode.elm;
+ }
+ function addVnodes(parentElm, before, vnodes, startIdx, endIdx, insertedVnodeQueue) {
+ for (; startIdx <= endIdx; ++startIdx) {
+ var ch = vnodes[startIdx];
+ if (ch != null) {
+ api.insertBefore(parentElm, createElm(ch, insertedVnodeQueue), before);
+ }
+ }
+ }
+ function invokeDestroyHook(vnode) {
+ var _a, _b;
+ var data = vnode.data;
+ if (data !== undefined) {
+ (_b = (_a = data === null || data === void 0 ? void 0 : data.hook) === null || _a === void 0 ? void 0 : _a.destroy) === null || _b === void 0 ? void 0 : _b.call(_a, vnode);
+ for (var _i = 0; _i < cbs.destroy.length; ++_i) {
+ cbs.destroy[_i](vnode);
+ }if (vnode.children !== undefined) {
+ for (var _j = 0; _j < vnode.children.length; ++_j) {
+ var child = vnode.children[_j];
+ if (child != null && typeof child !== "string") {
+ invokeDestroyHook(child);
+ }
+ }
+ }
+ }
+ }
+ function removeVnodes(parentElm, vnodes, startIdx, endIdx) {
+ var _a, _b;
+ for (; startIdx <= endIdx; ++startIdx) {
+ var listeners = void 0;
+ var rm = void 0;
+ var ch = vnodes[startIdx];
+ if (ch != null) {
+ if (isDef(ch.sel)) {
+ invokeDestroyHook(ch);
+ listeners = cbs.remove.length + 1;
+ rm = createRmCb(ch.elm, listeners);
+ for (var _i2 = 0; _i2 < cbs.remove.length; ++_i2) {
+ cbs.remove[_i2](ch, rm);
+ }var removeHook = (_b = (_a = ch === null || ch === void 0 ? void 0 : ch.data) === null || _a === void 0 ? void 0 : _a.hook) === null || _b === void 0 ? void 0 : _b.remove;
+ if (isDef(removeHook)) {
+ removeHook(ch, rm);
+ } else {
+ rm();
+ }
+ } else {
+ // Text node
+ api.removeChild(parentElm, ch.elm);
+ }
+ }
+ }
+ }
+ function updateChildren(parentElm, oldCh, newCh, insertedVnodeQueue) {
+ var oldStartIdx = 0;
+ var 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 = void 0;
+ var idxInOld = void 0;
+ var elmToMove = void 0;
+ var before = void 0;
+ while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
+ if (oldStartVnode == null) {
+ oldStartVnode = oldCh[++oldStartIdx]; // Vnode might have been moved left
+ } else if (oldEndVnode == null) {
+ oldEndVnode = oldCh[--oldEndIdx];
+ } else if (newStartVnode == null) {
+ newStartVnode = newCh[++newStartIdx];
+ } else if (newEndVnode == null) {
+ newEndVnode = newCh[--newEndIdx];
+ } 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);
+ api.insertBefore(parentElm, oldStartVnode.elm, api.nextSibling(oldEndVnode.elm));
+ oldStartVnode = oldCh[++oldStartIdx];
+ newEndVnode = newCh[--newEndIdx];
+ } else if (sameVnode(oldEndVnode, newStartVnode)) {
+ // Vnode moved left
+ patchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue);
+ api.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm);
+ oldEndVnode = oldCh[--oldEndIdx];
+ newStartVnode = newCh[++newStartIdx];
+ } else {
+ if (oldKeyToIdx === undefined) {
+ oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx);
+ }
+ idxInOld = oldKeyToIdx[newStartVnode.key];
+ if (isUndef(idxInOld)) {
+ // New element
+ api.insertBefore(parentElm, createElm(newStartVnode, insertedVnodeQueue), oldStartVnode.elm);
+ } else {
+ elmToMove = oldCh[idxInOld];
+ if (elmToMove.sel !== newStartVnode.sel) {
+ api.insertBefore(parentElm, createElm(newStartVnode, insertedVnodeQueue), oldStartVnode.elm);
+ } else {
+ patchVnode(elmToMove, newStartVnode, insertedVnodeQueue);
+ oldCh[idxInOld] = undefined;
+ api.insertBefore(parentElm, elmToMove.elm, oldStartVnode.elm);
+ }
+ }
+ newStartVnode = newCh[++newStartIdx];
+ }
+ }
+ if (oldStartIdx <= oldEndIdx || newStartIdx <= newEndIdx) {
+ if (oldStartIdx > oldEndIdx) {
+ before = newCh[newEndIdx + 1] == null ? null : newCh[newEndIdx + 1].elm;
+ addVnodes(parentElm, before, newCh, newStartIdx, newEndIdx, insertedVnodeQueue);
+ } else {
+ removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx);
+ }
+ }
+ }
+ function patchVnode(oldVnode, vnode, insertedVnodeQueue) {
+ var _a, _b, _c, _d, _e;
+ var hook = (_a = vnode.data) === null || _a === void 0 ? void 0 : _a.hook;
+ (_b = hook === null || hook === void 0 ? void 0 : hook.prepatch) === null || _b === void 0 ? void 0 : _b.call(hook, oldVnode, vnode);
+ var elm = vnode.elm = oldVnode.elm;
+ var oldCh = oldVnode.children;
+ var ch = vnode.children;
+ if (oldVnode === vnode) return;
+ if (vnode.data !== undefined) {
+ for (var _i3 = 0; _i3 < cbs.update.length; ++_i3) {
+ cbs.update[_i3](oldVnode, vnode);
+ }(_d = (_c = vnode.data.hook) === null || _c === void 0 ? void 0 : _c.update) === null || _d === void 0 ? void 0 : _d.call(_c, oldVnode, vnode);
+ }
+ if (isUndef(vnode.text)) {
+ if (isDef(oldCh) && isDef(ch)) {
+ if (oldCh !== ch) updateChildren(elm, oldCh, ch, insertedVnodeQueue);
+ } else if (isDef(ch)) {
+ if (isDef(oldVnode.text)) api.setTextContent(elm, "");
+ addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue);
+ } else if (isDef(oldCh)) {
+ removeVnodes(elm, oldCh, 0, oldCh.length - 1);
+ } else if (isDef(oldVnode.text)) {
+ api.setTextContent(elm, "");
+ }
+ } else if (oldVnode.text !== vnode.text) {
+ if (isDef(oldCh)) {
+ removeVnodes(elm, oldCh, 0, oldCh.length - 1);
+ }
+ api.setTextContent(elm, vnode.text);
+ }
+ (_e = hook === null || hook === void 0 ? void 0 : hook.postpatch) === null || _e === void 0 ? void 0 : _e.call(hook, oldVnode, vnode);
+ }
+ return function patch(oldVnode, vnode) {
+ var i = void 0,
+ elm = void 0,
+ parent = void 0;
+ var insertedVnodeQueue = [];
+ for (i = 0; i < cbs.pre.length; ++i) {
+ cbs.pre[i]();
+ }if (!isVnode(oldVnode)) {
+ oldVnode = emptyNodeAt(oldVnode);
+ }
+ if (sameVnode(oldVnode, vnode)) {
+ patchVnode(oldVnode, vnode, insertedVnodeQueue);
+ } else {
+ elm = oldVnode.elm;
+ parent = api.parentNode(elm);
+ createElm(vnode, insertedVnodeQueue);
+ if (parent !== null) {
+ api.insertBefore(parent, vnode.elm, api.nextSibling(elm));
+ removeVnodes(parent, [oldVnode], 0, 0);
+ }
+ }
+ 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;
+ };
+ }
+
+ function addNS(data, children, sel) {
+ data.ns = "http://www.w3.org/2000/svg";
+ if (sel !== "foreignObject" && children !== undefined) {
+ for (var i = 0; i < children.length; ++i) {
+ var childData = children[i].data;
+ if (childData !== undefined) {
+ addNS(childData, children[i].children, children[i].sel);
+ }
+ }
+ }
+ }
+ function h(sel, b, c) {
+ var data = {};
+ var children = void 0;
+ var text = void 0;
+ var i = void 0;
+ if (c !== undefined) {
+ if (b !== null) {
+ data = b;
+ }
+ if (array(c)) {
+ children = c;
+ } else if (primitive(c)) {
+ text = c;
+ } else if (c && c.sel) {
+ children = [c];
+ }
+ } else if (b !== undefined && b !== null) {
+ if (array(b)) {
+ children = b;
+ } else if (primitive(b)) {
+ text = b;
+ } else if (b && b.sel) {
+ children = [b];
+ } else {
+ data = b;
+ }
+ }
+ if (children !== undefined) {
+ for (i = 0; i < children.length; ++i) {
+ if (primitive(children[i])) children[i] = vnode(undefined, undefined, undefined, children[i], undefined);
+ }
+ }
+ if (sel[0] === "s" && sel[1] === "v" && sel[2] === "g" && (sel.length === 3 || sel[3] === "." || sel[3] === "#")) {
+ addNS(data, children, sel);
+ }
+ return vnode(sel, data, children, text, undefined);
+ }
+
+ function copyToThunk(vnode, thunk) {
+ vnode.data.fn = thunk.data.fn;
+ vnode.data.args = thunk.data.args;
+ thunk.data = vnode.data;
+ thunk.children = vnode.children;
+ thunk.text = vnode.text;
+ thunk.elm = vnode.elm;
+ }
+ function init$1(thunk) {
+ var cur = thunk.data;
+ var vnode = cur.fn.apply(undefined, cur.args);
+ copyToThunk(vnode, thunk);
+ }
+ function prepatch(oldVnode, thunk) {
+ var i = void 0;
+ var old = oldVnode.data;
+ var cur = thunk.data;
+ var oldArgs = old.args;
+ var args = cur.args;
+ if (old.fn !== cur.fn || oldArgs.length !== args.length) {
+ copyToThunk(cur.fn.apply(undefined, args), thunk);
+ return;
+ }
+ for (i = 0; i < args.length; ++i) {
+ if (oldArgs[i] !== args[i]) {
+ copyToThunk(cur.fn.apply(undefined, args), thunk);
+ return;
+ }
+ }
+ copyToThunk(oldVnode, thunk);
+ }
+ var thunk = function thunk(sel, key, fn, args) {
+ if (args === undefined) {
+ args = fn;
+ fn = key;
+ key = undefined;
+ }
+ return h(sel, {
+ key: key,
+ hook: { init: init$1, prepatch: prepatch },
+ fn: fn,
+ args: args
+ });
+ };
+
+ function pre(vnode, newVnode) {
+ var attachData = vnode.data.attachData;
+ // Copy created placeholder and real element from old vnode
+ newVnode.data.attachData.placeholder = attachData.placeholder;
+ newVnode.data.attachData.real = attachData.real;
+ // Mount real element in vnode so the patch process operates on it
+ vnode.elm = vnode.data.attachData.real;
+ }
+ function post(_, vnode) {
+ // Mount dummy placeholder in vnode so potential reorders use it
+ vnode.elm = vnode.data.attachData.placeholder;
+ }
+ function destroy(vnode) {
+ // Remove placeholder
+ if (vnode.elm !== undefined) {
+ vnode.elm.parentNode.removeChild(vnode.elm);
+ }
+ // Remove real element from where it was inserted
+ vnode.elm = vnode.data.attachData.real;
+ }
+ function create(_, vnode) {
+ var real = vnode.elm;
+ var attachData = vnode.data.attachData;
+ var placeholder = document.createElement("span");
+ // Replace actual element with dummy placeholder
+ // Snabbdom will then insert placeholder instead
+ vnode.elm = placeholder;
+ attachData.target.appendChild(real);
+ attachData.real = real;
+ attachData.placeholder = placeholder;
+ }
+ function attachTo(target, vnode) {
+ if (vnode.data === undefined) vnode.data = {};
+ if (vnode.data.hook === undefined) vnode.data.hook = {};
+ var data = vnode.data;
+ var hook = vnode.data.hook;
+ data.attachData = { target: target, placeholder: undefined, real: undefined };
+ hook.create = create;
+ hook.prepatch = pre;
+ hook.postpatch = post;
+ hook.destroy = destroy;
+ return vnode;
+ }
+
+ function toVNode(node, domApi) {
+ var api = domApi !== undefined ? domApi : htmlDomApi;
+ var text = void 0;
+ if (api.isElement(node)) {
+ var id = node.id ? "#" + node.id : "";
+ var cn = node.getAttribute("class");
+ var c = cn ? "." + cn.split(" ").join(".") : "";
+ var sel = api.tagName(node).toLowerCase() + id + c;
+ var attrs = {};
+ var children = [];
+ var name = void 0;
+ var i = void 0,
+ n = void 0;
+ var elmAttrs = node.attributes;
+ var elmChildren = node.childNodes;
+ for (i = 0, n = elmAttrs.length; i < n; i++) {
+ name = elmAttrs[i].nodeName;
+ if (name !== "id" && name !== "class") {
+ attrs[name] = elmAttrs[i].nodeValue;
+ }
+ }
+ for (i = 0, n = elmChildren.length; i < n; i++) {
+ children.push(toVNode(elmChildren[i], domApi));
+ }
+ return vnode(sel, { attrs: attrs }, children, undefined, node);
+ } else if (api.isText(node)) {
+ text = api.getTextContent(node);
+ return vnode(undefined, undefined, undefined, text, node);
+ } else if (api.isComment(node)) {
+ text = api.getTextContent(node);
+ return vnode("!", {}, [], text, node);
+ } else {
+ return vnode("", {}, [], undefined, node);
+ }
+ }
+
+ var xlinkNS = "http://www.w3.org/1999/xlink";
+ var xmlNS = "http://www.w3.org/XML/1998/namespace";
+ var colonChar = 58;
+ var xChar = 120;
+ function updateAttrs(oldVnode, vnode) {
+ var key = void 0;
+ var elm = vnode.elm;
+ var oldAttrs = oldVnode.data.attrs;
+ var attrs = vnode.data.attrs;
+ if (!oldAttrs && !attrs) return;
+ if (oldAttrs === attrs) return;
+ oldAttrs = oldAttrs || {};
+ attrs = attrs || {};
+ // update modified attributes, add new attributes
+ for (key in attrs) {
+ var cur = attrs[key];
+ var old = oldAttrs[key];
+ if (old !== cur) {
+ if (cur === true) {
+ elm.setAttribute(key, "");
+ } else if (cur === false) {
+ elm.removeAttribute(key);
+ } else {
+ if (key.charCodeAt(0) !== xChar) {
+ elm.setAttribute(key, cur);
+ } else if (key.charCodeAt(3) === colonChar) {
+ // Assume xml namespace
+ elm.setAttributeNS(xmlNS, key, cur);
+ } else if (key.charCodeAt(5) === colonChar) {
+ // Assume xlink namespace
+ elm.setAttributeNS(xlinkNS, key, cur);
+ } 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);
+ }
+ }
+ }
+ var attributesModule = { create: updateAttrs, update: updateAttrs };
+
+ function updateClass(oldVnode, vnode) {
+ var cur = void 0;
+ var name = void 0;
+ var elm = vnode.elm;
+ var oldClass = oldVnode.data["class"];
+ var klass = vnode.data["class"];
+ if (!oldClass && !klass) return;
+ if (oldClass === klass) return;
+ oldClass = oldClass || {};
+ klass = klass || {};
+ for (name in oldClass) {
+ if (oldClass[name] && !Object.prototype.hasOwnProperty.call(klass, name)) {
+ // was `true` and now not provided
+ elm.classList.remove(name);
+ }
+ }
+ for (name in klass) {
+ cur = klass[name];
+ if (cur !== oldClass[name]) {
+ elm.classList[cur ? "add" : "remove"](name);
+ }
+ }
+ }
+ var classModule = { create: updateClass, update: updateClass };
+
+ var CAPS_REGEX = /[A-Z]/g;
+ function updateDataset(oldVnode, vnode) {
+ var elm = vnode.elm;
+ var oldDataset = oldVnode.data.dataset;
+ var dataset = vnode.data.dataset;
+ var key = void 0;
+ if (!oldDataset && !dataset) return;
+ if (oldDataset === dataset) return;
+ oldDataset = oldDataset || {};
+ dataset = dataset || {};
+ var d = elm.dataset;
+ for (key in oldDataset) {
+ if (!dataset[key]) {
+ if (d) {
+ if (key in d) {
+ delete d[key];
+ }
+ } else {
+ elm.removeAttribute("data-" + key.replace(CAPS_REGEX, "-$&").toLowerCase());
+ }
+ }
+ }
+ for (key in dataset) {
+ if (oldDataset[key] !== dataset[key]) {
+ if (d) {
+ d[key] = dataset[key];
+ } else {
+ elm.setAttribute("data-" + key.replace(CAPS_REGEX, "-$&").toLowerCase(), dataset[key]);
+ }
+ }
+ }
+ }
+ var datasetModule = { create: updateDataset, update: updateDataset };
+
+ function invokeHandler(handler, vnode, event) {
+ if (typeof handler === "function") {
+ // call function handler
+ handler.call(vnode, event, vnode);
+ } else if (typeof handler === "object") {
+ // call multiple handlers
+ for (var i = 0; i < handler.length; i++) {
+ invokeHandler(handler[i], vnode, event);
+ }
+ }
+ }
+ function handleEvent(event, vnode) {
+ var name = event.type;
+ var on = vnode.data.on;
+ // call event handler(s) if exists
+ if (on && on[name]) {
+ invokeHandler(on[name], vnode, event);
+ }
+ }
+ function createListener() {
+ return function handler(event) {
+ handleEvent(event, handler.vnode);
+ };
+ }
+ function updateEventListeners(oldVnode, vnode) {
+ var oldOn = oldVnode.data.on;
+ var oldListener = oldVnode.listener;
+ var oldElm = oldVnode.elm;
+ var on = vnode && vnode.data.on;
+ var elm = vnode && vnode.elm;
+ var name = void 0;
+ // optimization for reused immutable handlers
+ if (oldOn === on) {
+ return;
+ }
+ // remove existing listeners which no longer used
+ if (oldOn && oldListener) {
+ // if element changed or deleted we remove all existing listeners unconditionally
+ if (!on) {
+ for (name in oldOn) {
+ // remove listener if element was changed or existing listeners removed
+ oldElm.removeEventListener(name, oldListener, false);
+ }
+ } else {
+ for (name in oldOn) {
+ // remove listener if existing listener removed
+ if (!on[name]) {
+ oldElm.removeEventListener(name, oldListener, false);
+ }
+ }
+ }
+ }
+ // add new listeners which has not already attached
+ if (on) {
+ // reuse existing listener or create new
+ var listener = vnode.listener = oldVnode.listener || createListener();
+ // update vnode for listener
+ listener.vnode = vnode;
+ // if element changed or added we add all needed listeners unconditionally
+ if (!oldOn) {
+ for (name in on) {
+ // add listener if element was changed or new listeners added
+ elm.addEventListener(name, listener, false);
+ }
+ } else {
+ for (name in on) {
+ // add listener if new listener added
+ if (!oldOn[name]) {
+ elm.addEventListener(name, listener, false);
+ }
+ }
+ }
+ }
+ }
+ var eventListenersModule = {
+ create: updateEventListeners,
+ update: updateEventListeners,
+ destroy: updateEventListeners
+ };
+
+ var raf = typeof window !== "undefined" && window.requestAnimationFrame || setTimeout;
+ var nextFrame = function nextFrame(fn) {
+ raf(function () {
+ raf(fn);
+ });
+ };
+ function setNextFrame(obj, prop, val) {
+ nextFrame(function () {
+ obj[prop] = val;
+ });
+ }
+ function getTextNodeRect(textNode) {
+ var rect = void 0;
+ if (document.createRange) {
+ var range = document.createRange();
+ range.selectNodeContents(textNode);
+ if (range.getBoundingClientRect) {
+ rect = range.getBoundingClientRect();
+ }
+ }
+ return rect;
+ }
+ function calcTransformOrigin(isTextNode, textRect, boundingRect) {
+ if (isTextNode) {
+ if (textRect) {
+ // calculate pixels to center of text from left edge of bounding box
+ var relativeCenterX = textRect.left + textRect.width / 2 - boundingRect.left;
+ var relativeCenterY = textRect.top + textRect.height / 2 - boundingRect.top;
+ return relativeCenterX + "px " + relativeCenterY + "px";
+ }
+ }
+ return "0 0"; // top left
+ }
+ function getTextDx(oldTextRect, newTextRect) {
+ if (oldTextRect && newTextRect) {
+ return oldTextRect.left + oldTextRect.width / 2 - (newTextRect.left + newTextRect.width / 2);
+ }
+ return 0;
+ }
+ function getTextDy(oldTextRect, newTextRect) {
+ if (oldTextRect && newTextRect) {
+ return oldTextRect.top + oldTextRect.height / 2 - (newTextRect.top + newTextRect.height / 2);
+ }
+ return 0;
+ }
+ function isTextElement(elm) {
+ return elm.childNodes.length === 1 && elm.childNodes[0].nodeType === 3;
+ }
+ var removed = void 0;
+ var created = void 0;
+ function pre$1() {
+ removed = {};
+ created = [];
+ }
+ function create$1(oldVnode, vnode) {
+ var hero = vnode.data.hero;
+ if (hero && hero.id) {
+ created.push(hero.id);
+ created.push(vnode);
+ }
+ }
+ function destroy$1(vnode) {
+ var hero = vnode.data.hero;
+ if (hero && hero.id) {
+ var elm = vnode.elm;
+ vnode.isTextNode = isTextElement(elm); // is this a text node?
+ vnode.boundingRect = elm.getBoundingClientRect(); // save the bounding rectangle to a new property on the vnode
+ vnode.textRect = vnode.isTextNode ? getTextNodeRect(elm.childNodes[0]) : null; // save bounding rect of inner text node
+ var computedStyle = window.getComputedStyle(elm, undefined); // get current styles (includes inherited properties)
+ vnode.savedStyle = JSON.parse(JSON.stringify(computedStyle)); // save a copy of computed style values
+ removed[hero.id] = vnode;
+ }
+ }
+ function post$1() {
+ var i = void 0,
+ id = void 0,
+ newElm = void 0,
+ oldVnode = void 0,
+ oldElm = void 0,
+ hRatio = void 0,
+ wRatio = void 0,
+ oldRect = void 0,
+ newRect = void 0,
+ dx = void 0,
+ dy = void 0,
+ origTransform = void 0,
+ origTransition = void 0,
+ newStyle = void 0,
+ oldStyle = void 0,
+ newComputedStyle = void 0,
+ isTextNode = void 0,
+ newTextRect = void 0,
+ oldTextRect = void 0;
+ for (i = 0; i < created.length; i += 2) {
+ id = created[i];
+ newElm = created[i + 1].elm;
+ oldVnode = removed[id];
+ if (oldVnode) {
+ isTextNode = oldVnode.isTextNode && isTextElement(newElm); // Are old & new both text?
+ newStyle = newElm.style;
+ newComputedStyle = window.getComputedStyle(newElm, undefined); // get full computed style for new element
+ oldElm = oldVnode.elm;
+ oldStyle = oldElm.style;
+ // Overall element bounding boxes
+ newRect = newElm.getBoundingClientRect();
+ oldRect = oldVnode.boundingRect; // previously saved bounding rect
+ // Text node bounding boxes & distances
+ if (isTextNode) {
+ newTextRect = getTextNodeRect(newElm.childNodes[0]);
+ oldTextRect = oldVnode.textRect;
+ dx = getTextDx(oldTextRect, newTextRect);
+ dy = getTextDy(oldTextRect, newTextRect);
+ } else {
+ // Calculate distances between old & new positions
+ dx = oldRect.left - newRect.left;
+ dy = oldRect.top - newRect.top;
+ }
+ hRatio = newRect.height / Math.max(oldRect.height, 1);
+ wRatio = isTextNode ? hRatio : newRect.width / Math.max(oldRect.width, 1); // text scales based on hRatio
+ // Animate new element
+ origTransform = newStyle.transform;
+ origTransition = newStyle.transition;
+ if (newComputedStyle.display === "inline") {
+ // inline elements cannot be transformed
+ newStyle.display = "inline-block"; // this does not appear to have any negative side effects
+ }
+ newStyle.transition = origTransition + "transform 0s";
+ newStyle.transformOrigin = calcTransformOrigin(isTextNode, newTextRect, newRect);
+ newStyle.opacity = "0";
+ newStyle.transform = origTransform + "translate(" + dx + "px, " + dy + "px) " + "scale(" + 1 / wRatio + ", " + 1 / hRatio + ")";
+ setNextFrame(newStyle, "transition", origTransition);
+ setNextFrame(newStyle, "transform", origTransform);
+ setNextFrame(newStyle, "opacity", "1");
+ // Animate old element
+ for (var key in oldVnode.savedStyle) {
+ // re-apply saved inherited properties
+ if (String(parseInt(key)) !== key) {
+ var ms = key.substring(0, 2) === "ms";
+ var moz = key.substring(0, 3) === "moz";
+ var webkit = key.substring(0, 6) === "webkit";
+ if (!ms && !moz && !webkit) {
+ // ignore prefixed style properties
+ oldStyle[key] = oldVnode.savedStyle[key];
+ }
+ }
+ }
+ oldStyle.position = "absolute";
+ oldStyle.top = oldRect.top + "px"; // start at existing position
+ oldStyle.left = oldRect.left + "px";
+ oldStyle.width = oldRect.width + "px"; // Needed for elements who were sized relative to their parents
+ oldStyle.height = oldRect.height + "px"; // Needed for elements who were sized relative to their parents
+ oldStyle.margin = "0"; // Margin on hero element leads to incorrect positioning
+ oldStyle.transformOrigin = calcTransformOrigin(isTextNode, oldTextRect, oldRect);
+ oldStyle.transform = "";
+ oldStyle.opacity = "1";
+ document.body.appendChild(oldElm);
+ setNextFrame(oldStyle, "transform", "translate(" + -dx + "px, " + -dy + "px) scale(" + wRatio + ", " + hRatio + ")"); // scale must be on far right for translate to be correct
+ setNextFrame(oldStyle, "opacity", "0");
+ oldElm.addEventListener("transitionend", function (ev) {
+ if (ev.propertyName === "transform") {
+ document.body.removeChild(ev.target);
+ }
+ });
+ }
+ }
+ removed = created = undefined;
+ }
+ var heroModule = {
+ pre: pre$1,
+ create: create$1,
+ destroy: destroy$1,
+ post: post$1
+ };
+
+ function updateProps(oldVnode, vnode) {
+ var key = void 0;
+ var cur = void 0;
+ var old = void 0;
+ var elm = vnode.elm;
+ var oldProps = oldVnode.data.props;
+ var props = vnode.data.props;
+ if (!oldProps && !props) return;
+ if (oldProps === props) return;
+ oldProps = oldProps || {};
+ props = props || {};
+ for (key in props) {
+ cur = props[key];
+ old = oldProps[key];
+ if (old !== cur && (key !== "value" || elm[key] !== cur)) {
+ elm[key] = cur;
+ }
+ }
+ }
+ var propsModule = { create: updateProps, update: updateProps };
+
+ // Bindig `requestAnimationFrame` like this fixes a bug in IE/Edge. See #360 and #409.
+ var raf$1 = typeof window !== "undefined" && window.requestAnimationFrame.bind(window) || setTimeout;
+ var nextFrame$1 = function nextFrame$1(fn) {
+ raf$1(function () {
+ raf$1(fn);
+ });
+ };
+ var reflowForced = false;
+ function setNextFrame$1(obj, prop, val) {
+ nextFrame$1(function () {
+ obj[prop] = val;
+ });
+ }
+ function updateStyle(oldVnode, vnode) {
+ var cur = void 0;
+ var name = void 0;
+ var elm = vnode.elm;
+ var oldStyle = oldVnode.data.style;
+ var style = vnode.data.style;
+ if (!oldStyle && !style) return;
+ if (oldStyle === style) return;
+ oldStyle = oldStyle || {};
+ style = style || {};
+ var oldHasDel = "delayed" in oldStyle;
+ for (name in oldStyle) {
+ if (!style[name]) {
+ if (name[0] === "-" && name[1] === "-") {
+ elm.style.removeProperty(name);
+ } else {
+ elm.style[name] = "";
+ }
+ }
+ }
+ for (name in style) {
+ cur = style[name];
+ if (name === "delayed" && style.delayed) {
+ for (var name2 in style.delayed) {
+ cur = style.delayed[name2];
+ if (!oldHasDel || cur !== oldStyle.delayed[name2]) {
+ setNextFrame$1(elm.style, name2, cur);
+ }
+ }
+ } else if (name !== "remove" && cur !== oldStyle[name]) {
+ if (name[0] === "-" && name[1] === "-") {
+ elm.style.setProperty(name, cur);
+ } else {
+ elm.style[name] = cur;
+ }
+ }
+ }
+ }
+ function applyDestroyStyle(vnode) {
+ var style = void 0;
+ var name = void 0;
+ var elm = vnode.elm;
+ var 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;
+ }
+ if (!reflowForced) {
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
+ vnode.elm.offsetLeft;
+ reflowForced = true;
+ }
+ var name = void 0;
+ var elm = vnode.elm;
+ var i = 0;
+ var style = s.remove;
+ var amount = 0;
+ var applied = [];
+ for (name in style) {
+ applied.push(name);
+ elm.style[name] = style[name];
+ }
+ var 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();
+ });
+ }
+ function forceReflow() {
+ reflowForced = false;
+ }
+ var styleModule = {
+ pre: forceReflow,
+ create: updateStyle,
+ update: updateStyle,
+ destroy: applyDestroyStyle,
+ remove: applyRemoveStyle
+ };
+
+ exports.array = array;
+ exports.attachTo = attachTo;
+ exports.attributesModule = attributesModule;
+ exports.classModule = classModule;
+ exports.datasetModule = datasetModule;
+ exports.eventListenersModule = eventListenersModule;
+ exports.h = h;
+ exports.heroModule = heroModule;
+ exports.htmlDomApi = htmlDomApi;
+ exports.init = init;
+ exports.primitive = primitive;
+ exports.propsModule = propsModule;
+ exports.styleModule = styleModule;
+ exports.thunk = thunk;
+ exports.toVNode = toVNode;
+ exports.vnode = vnode;
+
+ exports.__esModule = true;
+});
diff --git a/src/core/element2Snabbdom.js b/src/core/element2Snabbdom.js
new file mode 100644
index 000000000..cb8d347bb
--- /dev/null
+++ b/src/core/element2Snabbdom.js
@@ -0,0 +1,42 @@
+!function () {
+ var patch = BI.Snabbdom.init([BI.Snabbdom.attributesModule, BI.Snabbdom.classModule, BI.Snabbdom.datasetModule, BI.Snabbdom.propsModule, BI.Snabbdom.styleModule, BI.Snabbdom.eventListenersModule]);
+ BI.Element2Snabbdom = function (parentNode) {
+ if (parentNode.nodeType === 3) {
+ return parentNode.textContent;
+ }
+ var data = BI.jQuery._data(parentNode);
+ var on = {};
+ BI.each(data && data.events, function (eventName, events) {
+ on[eventName] = function () {
+ var ob = this, args = arguments;
+ BI.each(events, function (i, ev) {
+ ev.handler.apply(ob, args);
+ });
+ };
+ });
+ var style = parentNode.getAttribute("style");
+ // var claz = parentNode.getAttribute("class");
+ var vnode = BI.Snabbdom.h(parentNode.nodeName, {
+ class: BI.makeObject(parentNode.classList),
+ props: {
+ style: style
+ },
+ on: on,
+ hook: {
+ create: function () {
+ BI.each(parentNode._Widget, function (i, w) {
+ w.element = $(vnode.elm);
+ });
+ }
+ }
+ }, BI.map(parentNode.childNodes, function (i, childNode) {
+ return BI.Element2Snabbdom(childNode);
+ }));
+ return vnode;
+ };
+
+ BI.patchVNode = function (element, node) {
+ patch(element, node);
+ };
+}();
+