| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390 |
- import { vnode } from "./vnode.js";
- import * as is from "./is.js";
- import { htmlDomApi } from "./htmldomapi.js";
- function isUndef(s) {
- return s === undefined;
- }
- function isDef(s) {
- return s !== undefined;
- }
- const emptyNode = vnode("", {}, [], undefined, undefined);
- function sameVnode(vnode1, vnode2) {
- var _a, _b;
- const isSameKey = vnode1.key === vnode2.key;
- const isSameIs = ((_a = vnode1.data) === null || _a === void 0 ? void 0 : _a.is) === ((_b = vnode2.data) === null || _b === void 0 ? void 0 : _b.is);
- const isSameSel = vnode1.sel === vnode2.sel;
- const isSameTextOrFragment = !vnode1.sel && vnode1.sel === vnode2.sel
- ? typeof vnode1.text === typeof vnode2.text
- : true;
- return isSameSel && isSameKey && isSameIs && isSameTextOrFragment;
- }
- /**
- * @todo Remove this function when the document fragment is considered stable.
- */
- function documentFragmentIsNotSupported() {
- throw new Error("The document fragment is not supported on this platform.");
- }
- function isElement(api, vnode) {
- return api.isElement(vnode);
- }
- function isDocumentFragment(api, vnode) {
- return api.isDocumentFragment(vnode);
- }
- function createKeyToOldIdx(children, beginIdx, endIdx) {
- var _a;
- const map = {};
- for (let i = beginIdx; i <= endIdx; ++i) {
- const key = (_a = children[i]) === null || _a === void 0 ? void 0 : _a.key;
- if (key !== undefined) {
- map[key] = i;
- }
- }
- return map;
- }
- const hooks = [
- "create",
- "update",
- "remove",
- "destroy",
- "pre",
- "post"
- ];
- export function init(modules, domApi, options) {
- const cbs = {
- create: [],
- update: [],
- remove: [],
- destroy: [],
- pre: [],
- post: []
- };
- const api = domApi !== undefined ? domApi : htmlDomApi;
- for (const hook of hooks) {
- for (const module of modules) {
- const currentHook = module[hook];
- if (currentHook !== undefined) {
- cbs[hook].push(currentHook);
- }
- }
- }
- function emptyNodeAt(elm) {
- const id = elm.id ? "#" + elm.id : "";
- // elm.className doesn't return a string when elm is an SVG element inside a shadowRoot.
- // https://stackoverflow.com/questions/29454340/detecting-classname-of-svganimatedstring
- const classes = elm.getAttribute("class");
- const c = classes ? "." + classes.split(" ").join(".") : "";
- return vnode(api.tagName(elm).toLowerCase() + id + c, {}, [], undefined, elm);
- }
- function emptyDocumentFragmentAt(frag) {
- return vnode(undefined, {}, [], undefined, frag);
- }
- function createRmCb(childElm, listeners) {
- return function rmCb() {
- if (--listeners === 0) {
- const parent = api.parentNode(childElm);
- if (parent !== null) {
- api.removeChild(parent, childElm);
- }
- }
- };
- }
- function createElm(vnode, insertedVnodeQueue) {
- var _a, _b, _c, _d;
- let i;
- let data = vnode.data;
- if (data !== undefined) {
- const init = (_a = data.hook) === null || _a === void 0 ? void 0 : _a.init;
- if (isDef(init)) {
- init(vnode);
- data = vnode.data;
- }
- }
- const children = vnode.children;
- const sel = vnode.sel;
- if (sel === "!") {
- if (isUndef(vnode.text)) {
- vnode.text = "";
- }
- vnode.elm = api.createComment(vnode.text);
- }
- else if (sel === "") {
- // textNode has no selector
- vnode.elm = api.createTextNode(vnode.text);
- }
- else if (sel !== undefined) {
- // Parse selector
- const hashIdx = sel.indexOf("#");
- const dotIdx = sel.indexOf(".", hashIdx);
- const hash = hashIdx > 0 ? hashIdx : sel.length;
- const dot = dotIdx > 0 ? dotIdx : sel.length;
- const tag = hashIdx !== -1 || dotIdx !== -1
- ? sel.slice(0, Math.min(hash, dot))
- : sel;
- const elm = (vnode.elm =
- isDef(data) && isDef((i = data.ns))
- ? api.createElementNS(i, tag, data)
- : api.createElement(tag, data));
- 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 (is.primitive(vnode.text) &&
- (!is.array(children) || children.length === 0)) {
- // allow h1 and similar nodes to be created w/ text and empty child list
- api.appendChild(elm, api.createTextNode(vnode.text));
- }
- if (is.array(children)) {
- for (i = 0; i < children.length; ++i) {
- const ch = children[i];
- if (ch != null) {
- api.appendChild(elm, createElm(ch, insertedVnodeQueue));
- }
- }
- }
- const 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 if (((_c = options === null || options === void 0 ? void 0 : options.experimental) === null || _c === void 0 ? void 0 : _c.fragments) && vnode.children) {
- vnode.elm = ((_d = api.createDocumentFragment) !== null && _d !== void 0 ? _d : documentFragmentIsNotSupported)();
- for (i = 0; i < cbs.create.length; ++i)
- cbs.create[i](emptyNode, vnode);
- for (i = 0; i < vnode.children.length; ++i) {
- const ch = vnode.children[i];
- if (ch != null) {
- api.appendChild(vnode.elm, createElm(ch, insertedVnodeQueue));
- }
- }
- }
- else {
- vnode.elm = api.createTextNode(vnode.text);
- }
- return vnode.elm;
- }
- function addVnodes(parentElm, before, vnodes, startIdx, endIdx, insertedVnodeQueue) {
- for (; startIdx <= endIdx; ++startIdx) {
- const ch = vnodes[startIdx];
- if (ch != null) {
- api.insertBefore(parentElm, createElm(ch, insertedVnodeQueue), before);
- }
- }
- }
- function invokeDestroyHook(vnode) {
- var _a, _b;
- const 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 (let i = 0; i < cbs.destroy.length; ++i)
- cbs.destroy[i](vnode);
- if (vnode.children !== undefined) {
- for (let j = 0; j < vnode.children.length; ++j) {
- const 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) {
- let listeners;
- let rm;
- const ch = vnodes[startIdx];
- if (ch != null) {
- if (isDef(ch.sel)) {
- invokeDestroyHook(ch);
- listeners = cbs.remove.length + 1;
- rm = createRmCb(ch.elm, listeners);
- for (let i = 0; i < cbs.remove.length; ++i)
- cbs.remove[i](ch, rm);
- const 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 if (ch.children) {
- // Fragment node
- invokeDestroyHook(ch);
- removeVnodes(parentElm, ch.children, 0, ch.children.length - 1);
- }
- else {
- // Text node
- api.removeChild(parentElm, ch.elm);
- }
- }
- }
- }
- function updateChildren(parentElm, oldCh, newCh, insertedVnodeQueue) {
- let oldStartIdx = 0;
- let newStartIdx = 0;
- let oldEndIdx = oldCh.length - 1;
- let oldStartVnode = oldCh[0];
- let oldEndVnode = oldCh[oldEndIdx];
- let newEndIdx = newCh.length - 1;
- let newStartVnode = newCh[0];
- let newEndVnode = newCh[newEndIdx];
- let oldKeyToIdx;
- let idxInOld;
- let elmToMove;
- let before;
- 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)) {
- // `newStartVnode` is new, create and insert it in beginning
- api.insertBefore(parentElm, createElm(newStartVnode, insertedVnodeQueue), oldStartVnode.elm);
- newStartVnode = newCh[++newStartIdx];
- }
- else if (isUndef(oldKeyToIdx[newEndVnode.key])) {
- // `newEndVnode` is new, create and insert it in the end
- api.insertBefore(parentElm, createElm(newEndVnode, insertedVnodeQueue), api.nextSibling(oldEndVnode.elm));
- newEndVnode = newCh[--newEndIdx];
- }
- else {
- // Neither of the new endpoints are new vnodes, so we make progress by
- // moving `newStartVnode` into position
- 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 (newStartIdx <= newEndIdx) {
- before = newCh[newEndIdx + 1] == null ? null : newCh[newEndIdx + 1].elm;
- addVnodes(parentElm, before, newCh, newStartIdx, newEndIdx, insertedVnodeQueue);
- }
- if (oldStartIdx <= oldEndIdx) {
- removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx);
- }
- }
- function patchVnode(oldVnode, vnode, insertedVnodeQueue) {
- var _a, _b, _c, _d, _e, _f, _g, _h;
- const 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);
- const elm = (vnode.elm = oldVnode.elm);
- if (oldVnode === vnode)
- return;
- if (vnode.data !== undefined ||
- (isDef(vnode.text) && vnode.text !== oldVnode.text)) {
- (_c = vnode.data) !== null && _c !== void 0 ? _c : (vnode.data = {});
- (_d = oldVnode.data) !== null && _d !== void 0 ? _d : (oldVnode.data = {});
- for (let i = 0; i < cbs.update.length; ++i)
- cbs.update[i](oldVnode, vnode);
- (_g = (_f = (_e = vnode.data) === null || _e === void 0 ? void 0 : _e.hook) === null || _f === void 0 ? void 0 : _f.update) === null || _g === void 0 ? void 0 : _g.call(_f, oldVnode, vnode);
- }
- const oldCh = oldVnode.children;
- const ch = vnode.children;
- 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);
- }
- (_h = hook === null || hook === void 0 ? void 0 : hook.postpatch) === null || _h === void 0 ? void 0 : _h.call(hook, oldVnode, vnode);
- }
- return function patch(oldVnode, vnode) {
- let i, elm, parent;
- const insertedVnodeQueue = [];
- for (i = 0; i < cbs.pre.length; ++i)
- cbs.pre[i]();
- if (isElement(api, oldVnode)) {
- oldVnode = emptyNodeAt(oldVnode);
- }
- else if (isDocumentFragment(api, oldVnode)) {
- oldVnode = emptyDocumentFragmentAt(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;
- };
- }
- //# sourceMappingURL=init.js.map
|