-
Notifications
You must be signed in to change notification settings - Fork 1
Open
Description
/// <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;
};
});
Metadata
Metadata
Assignees
Labels
No labels