Open infinnie opened 6 years ago
/// <reference path="/node_modules/jquery/dist/jquery.min.js"/> define("vendors/app", ["jquery"], function ($) { "use strict"; var globalInvokeLaterStack = [], raf = "requestAnimationFrame" in window ? requestAnimationFrame.bind(window) : function (f) { return setTimeout(f, 1); }, _guid = 0, lookUp = {}, eventLookUp = {}; return function app(props) { var appState, appView = props.view, appActions = {}, appEvents = {}, appMixins = props.mixins || [], appRoot = props.root || document.body, element, oldNode, renderLock; $.map(appMixins.concat(props), function (mixin) { mixin = typeof mixin === "function" ? mixin(emit) : mixin; $.map(mixin.events || [], function (event, key) { appEvents[key] = (appEvents[key] || []).concat(event); }); appState = merge(appState, mixin.state); initialize(appActions, mixin.actions); }); requestRender( (oldNode = emit("load", (element = appRoot.children[0]))) === element && (oldNode = element = null) ); function initialize(actions, withActions, lastName) { $.map(withActions || [], function (action, key) { var name = lastName ? lastName + "." + key : key if (typeof action === "function") { actions[key] = function (data) { emit("action", { name: name, data: data }); var result = emit("resolve", action(appState, appActions, data)); return typeof result === "function" ? result(update) : update(result); } } else { initialize(actions[key] || (actions[key] = {}), action, name); } }); } function render(cb) { element = patch( appRoot, element, oldNode, (oldNode = emit("render", appView)(appState, appActions)), (renderLock = !renderLock) ); while ((cb = globalInvokeLaterStack.pop())) { cb(); } } function requestRender() { if (appView && !renderLock) { raf(render, (renderLock = !renderLock)); } } function update(withState) { if (typeof withState === "function") { return update(withState(appState)); } if (withState && (withState = emit("update", merge(appState, withState)))) { requestRender((appState = withState)); } return appState } function emit(name, data) { return ( $.map(appEvents[name] || [], function (cb) { var result = cb(appState, appActions, data); if (result != null) { data = result; } }), data ); } function merge(a, b) { var obj = {}, i; for (i in a) { obj[i] = a[i] } for (i in b) { obj[i] = b[i] } return obj } function getKey(node) { if (node && (node = node.data)) { return node.key } } function createElement(node, isSVG) { var element; if (typeof node === "string") { element = document.createTextNode(node); } else { element = (isSVG = isSVG || node.tag === "svg") ? document.createElementNS("http://www.w3.org/2000/svg", node.tag) : document.createElement(node.tag); if (node.data && node.data.oncreate) { globalInvokeLaterStack.push(function () { node.data.oncreate(element) }); } for (var i in node.data) { setData(element, i, node.data[i]); } for (var i = 0; i < node.children.length;) { element.appendChild(createElement(node.children[i++], isSVG)); } } return element; } // TODO function setData(element, name, value, oldValue) { var prefix = /^\$/, tempName, guid; if (name === "key") { } else if (name === "style") { for (var i in merge(oldValue, (value = value || {}))) { element.style[i] = value[i] || ""; } } else if (prefix.test(name)) { tempName = name.replace(prefix, "") + ".app"; // do something // https://api.jquery.com/attr/ guid = $(element).attr("data-unique-id"); if (typeof guid === "undefined") { guid = _guid; $(element).attr("data-unique-id", guid); _guid++; } lookUp[guid] = lookUp[guid] || {}; lookUp[guid][tempName] = value; if (name === "$input" && typeof element.addEventListener === "undefined") { $(element).off("propertychange.app").on("propertychange.app", function () { $(this).trigger("input.app"); }); } if (!eventLookUp[tempName]) { eventLookUp[tempName] = true; $(document).on(tempName, "[data-unique-id]", function () { var guid = $(this).attr("data-unique-id"); if (lookUp[guid] && typeof lookUp[guid][tempName] === "function") { return lookUp[guid][tempName].apply(this, arguments); } }); } } else { try { element[name] = value } catch (_) { } if (typeof value !== "function") { if (value || 0 === value) { try { element.setAttribute(name, value); } catch (someException) { } } else { element.removeAttribute(name) } } } } function updateElement(element, oldData, data) { for (var i in merge(oldData, data)) { var value = data[i] var oldValue = i === "value" || i === "checked" ? element[i] : oldData[i] if (value !== oldValue) { setData(element, i, value, oldValue) } } if (data && data.onupdate) { globalInvokeLaterStack.push(function () { data.onupdate(element, oldData) }) } } function removeElement(element, data) { if (data && data.onremove) { data.onremove(element) } else { // do something $(element).find("[data-unique-id]").andSelf().each(function () { var guid = $(this).attr("data-unique-id"); if (lookUp[guid]) { delete lookUp[guid]; } }); $(element).remove(); } } function patch(parent, element, oldNode, node, isSVG, nextSibling) { /// <param name="element" type="Array"/> if ($.isArray(node)) { if ($.isArray(element) && $.isArray(oldNode)) { var elementCopy = element.slice(0), oldCopy = oldNode.slice(0); var ret = $.map(node, function (t, i) { return patch(parent, elementCopy.shift(), oldCopy.shift(), t, isSVG, nextSibling); // ... }); $(elementCopy).each(function (i) { removeElement(this, oldNode[i] && oldNode[i].data); }); return ret; } return $.map(node, function (t, i) { return patch(parent, i === 0 ? element : null, i === 0 ? oldNode : null, t, isSVG, nextSibling); }); } if ($.isArray(element)) { var remaining = element.slice(1), remainingNodes; element = element[0]; if ($.isArray(oldNode)) { remainingNodes = oldNode.slice(1); oldNode = oldNode[0]; } $(remaining).each(function (i) { removeElement(this, remainingNodes && remainingNodes[i] && remainingNodes[i].data); }); } if (oldNode == null) { element = parent.insertBefore(createElement(node, isSVG), element || null); } else if (node.tag != null && node.tag === oldNode.tag && node.tag !== "img") { updateElement(element, oldNode.data, node.data) isSVG = isSVG || node.tag === "svg" var len = node.children.length var oldLen = oldNode.children.length var oldKeyed = {} var oldElements = [] var keyed = {}, i, j; for (i = 0; i < oldLen; i++) { var oldElement = (oldElements[i] = element.childNodes[i]) var oldChild = oldNode.children[i] var oldKey = getKey(oldChild) if (null != oldKey) { oldKeyed[oldKey] = [oldElement, oldChild] } } i = 0; j = 0; while (j < len) { var oldElement = oldElements[i] var oldChild = oldNode.children[i] var newChild = node.children[j] var oldKey = getKey(oldChild) if (keyed[oldKey]) { i++ continue } var newKey = getKey(newChild) var keyedNode = oldKeyed[newKey] || [] if (null == newKey) { if (null == oldKey) { patch(element, oldElement, oldChild, newChild, isSVG) j++ } i++ } else { if (oldKey === newKey) { patch(element, keyedNode[0], keyedNode[1], newChild, isSVG) i++ } else if (keyedNode[0]) { element.insertBefore(keyedNode[0], oldElement) patch(element, keyedNode[0], keyedNode[1], newChild, isSVG) } else { patch(element, oldElement, null, newChild, isSVG) } j++ keyed[newKey] = newChild } } while (i < oldLen) { var oldChild = oldNode.children[i] var oldKey = getKey(oldChild) if (null == oldKey) { removeElement(oldElements[i], oldChild.data) } i++ } for (i in oldKeyed) { keyedNode = oldKeyed[i] var reusableNode = keyedNode[1] if (!keyed[reusableNode.data.key]) { removeElement(keyedNode[0], reusableNode.data) } } } else if (element && node !== element.nodeValue) { if (typeof node === "string" && typeof oldNode === "string") { element.nodeValue = node } else { element = parent.insertBefore( createElement(node, isSVG), (nextSibling = element) ) removeElement(nextSibling, oldNode.data) } } return element; } return emit; }; });