chore: extract & cache commonly accessed variables
This commit is contained in:
parent
b70a3addd3
commit
98794a668e
3 changed files with 54 additions and 41 deletions
91
mithril.js
91
mithril.js
|
|
@ -4,6 +4,20 @@ Mithril = m = new function app(window, undefined) {
|
||||||
var parser = /(?:(^|#|\.)([^#\.\[\]]+))|(\[.+?\])/g, attrParser = /\[(.+?)(?:=("|'|)(.*?)\2)?\]/;
|
var parser = /(?:(^|#|\.)([^#\.\[\]]+))|(\[.+?\])/g, attrParser = /\[(.+?)(?:=("|'|)(.*?)\2)?\]/;
|
||||||
var voidElements = /AREA|BASE|BR|COL|COMMAND|EMBED|HR|IMG|INPUT|KEYGEN|LINK|META|PARAM|SOURCE|TRACK|WBR/;
|
var voidElements = /AREA|BASE|BR|COL|COMMAND|EMBED|HR|IMG|INPUT|KEYGEN|LINK|META|PARAM|SOURCE|TRACK|WBR/;
|
||||||
|
|
||||||
|
// caching commonly used variables
|
||||||
|
var $document, $location, $requestAnimationFrame, $cancelAnimationFrame;
|
||||||
|
|
||||||
|
// self invoking function needed because of the way mocks work
|
||||||
|
function initialize(window){
|
||||||
|
$document = window.document;
|
||||||
|
$location = window.location;
|
||||||
|
$cancelAnimationFrame = window.cancelAnimationFrame || window.clearTimeout;
|
||||||
|
$requestAnimationFrame = window.requestAnimationFrame || window.setTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
initialize(window);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @typedef {String} Tag
|
* @typedef {String} Tag
|
||||||
* A string that looks like -> div.classname#id[param=one][param2=two]
|
* A string that looks like -> div.classname#id[param=one][param2=two]
|
||||||
|
|
@ -121,10 +135,10 @@ Mithril = m = new function app(window, undefined) {
|
||||||
action: MOVE,
|
action: MOVE,
|
||||||
index: i,
|
index: i,
|
||||||
from: existing[key].index,
|
from: existing[key].index,
|
||||||
element: parentElement.childNodes[existing[key].index] || window.document.createElement("div")
|
element: parentElement.childNodes[existing[key].index] || $document.createElement("div")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else unkeyed.push({index: i, element: parentElement.childNodes[i] || window.document.createElement("div")})
|
else unkeyed.push({index: i, element: parentElement.childNodes[i] || $document.createElement("div")})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var actions = Object.keys(existing).map(function(key) {return existing[key]});
|
var actions = Object.keys(existing).map(function(key) {return existing[key]});
|
||||||
|
|
@ -137,7 +151,7 @@ Mithril = m = new function app(window, undefined) {
|
||||||
newCached.splice(change.index, 1)
|
newCached.splice(change.index, 1)
|
||||||
}
|
}
|
||||||
if (change.action == INSERTION) {
|
if (change.action == INSERTION) {
|
||||||
var dummy = window.document.createElement("div");
|
var dummy = $document.createElement("div");
|
||||||
dummy.key = data[change.index].attrs.key;
|
dummy.key = data[change.index].attrs.key;
|
||||||
parentElement.insertBefore(dummy, parentElement.childNodes[change.index] || null);
|
parentElement.insertBefore(dummy, parentElement.childNodes[change.index] || null);
|
||||||
newCached.splice(change.index, 0, {attrs: {key: data[change.index].attrs.key}, nodes: [dummy]})
|
newCached.splice(change.index, 0, {attrs: {key: data[change.index].attrs.key}, nodes: [dummy]})
|
||||||
|
|
@ -198,7 +212,7 @@ Mithril = m = new function app(window, undefined) {
|
||||||
else if (data != null && dataType == sObj) {
|
else if (data != null && dataType == sObj) {
|
||||||
if (!data.attrs) data.attrs = {};
|
if (!data.attrs) data.attrs = {};
|
||||||
if (!cached.attrs) cached.attrs = {};
|
if (!cached.attrs) cached.attrs = {};
|
||||||
|
|
||||||
var dataAttrKeys = Object.keys(data.attrs);
|
var dataAttrKeys = Object.keys(data.attrs);
|
||||||
//if an element is different enough from the one in cache, recreate it
|
//if an element is different enough from the one in cache, recreate it
|
||||||
if (data.tag != cached.tag || dataAttrKeys.join() != Object.keys(cached.attrs).join() || data.attrs.id != cached.attrs.id) {
|
if (data.tag != cached.tag || dataAttrKeys.join() != Object.keys(cached.attrs).join() || data.attrs.id != cached.attrs.id) {
|
||||||
|
|
@ -212,7 +226,7 @@ Mithril = m = new function app(window, undefined) {
|
||||||
else if (data.tag === "svg") namespace = "http://www.w3.org/2000/svg";
|
else if (data.tag === "svg") namespace = "http://www.w3.org/2000/svg";
|
||||||
else if (data.tag === "math") namespace = "http://www.w3.org/1998/Math/MathML";
|
else if (data.tag === "math") namespace = "http://www.w3.org/1998/Math/MathML";
|
||||||
if (isNew) {
|
if (isNew) {
|
||||||
node = namespace === undefined ? window.document.createElement(data.tag) : window.document.createElementNS(namespace, data.tag);
|
node = namespace === undefined ? $document.createElement(data.tag) : $document.createElementNS(namespace, data.tag);
|
||||||
cached = {
|
cached = {
|
||||||
tag: data.tag,
|
tag: data.tag,
|
||||||
//set attributes first, then create children
|
//set attributes first, then create children
|
||||||
|
|
@ -255,7 +269,7 @@ Mithril = m = new function app(window, undefined) {
|
||||||
nodes = injectHTML(parentElement, index, data)
|
nodes = injectHTML(parentElement, index, data)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
nodes = [window.document.createTextNode(data)];
|
nodes = [$document.createTextNode(data)];
|
||||||
if (!parentElement.nodeName.match(voidElements)) parentElement.insertBefore(nodes[0], parentElement.childNodes[index] || null)
|
if (!parentElement.nodeName.match(voidElements)) parentElement.insertBefore(nodes[0], parentElement.childNodes[index] || null)
|
||||||
}
|
}
|
||||||
cached = "string number boolean".indexOf(typeof data) > -1 ? new data.constructor(data) : data;
|
cached = "string number boolean".indexOf(typeof data) > -1 ? new data.constructor(data) : data;
|
||||||
|
|
@ -263,7 +277,7 @@ Mithril = m = new function app(window, undefined) {
|
||||||
}
|
}
|
||||||
else if (cached.valueOf() !== data.valueOf() || shouldReattach === true) {
|
else if (cached.valueOf() !== data.valueOf() || shouldReattach === true) {
|
||||||
nodes = cached.nodes;
|
nodes = cached.nodes;
|
||||||
if (!editable || editable !== window.document.activeElement) {
|
if (!editable || editable !== $document.activeElement) {
|
||||||
if (data.$trusted) {
|
if (data.$trusted) {
|
||||||
clear(nodes, cached);
|
clear(nodes, cached);
|
||||||
nodes = injectHTML(parentElement, index, data)
|
nodes = injectHTML(parentElement, index, data)
|
||||||
|
|
@ -276,7 +290,7 @@ Mithril = m = new function app(window, undefined) {
|
||||||
else {
|
else {
|
||||||
if (nodes[0].nodeType == 1 || nodes.length > 1) { //was a trusted string
|
if (nodes[0].nodeType == 1 || nodes.length > 1) { //was a trusted string
|
||||||
clear(cached.nodes, cached);
|
clear(cached.nodes, cached);
|
||||||
nodes = [window.document.createTextNode(data)]
|
nodes = [$document.createTextNode(data)]
|
||||||
}
|
}
|
||||||
parentElement.insertBefore(nodes[0], parentElement.childNodes[index] || null);
|
parentElement.insertBefore(nodes[0], parentElement.childNodes[index] || null);
|
||||||
nodes[0].nodeValue = data
|
nodes[0].nodeValue = data
|
||||||
|
|
@ -359,7 +373,7 @@ Mithril = m = new function app(window, undefined) {
|
||||||
var nextSibling = parentElement.childNodes[index];
|
var nextSibling = parentElement.childNodes[index];
|
||||||
if (nextSibling) {
|
if (nextSibling) {
|
||||||
var isElement = nextSibling.nodeType != 1;
|
var isElement = nextSibling.nodeType != 1;
|
||||||
var placeholder = window.document.createElement("span");
|
var placeholder = $document.createElement("span");
|
||||||
if (isElement) {
|
if (isElement) {
|
||||||
parentElement.insertBefore(placeholder, nextSibling || null);
|
parentElement.insertBefore(placeholder, nextSibling || null);
|
||||||
placeholder.insertAdjacentHTML("beforebegin", data);
|
placeholder.insertAdjacentHTML("beforebegin", data);
|
||||||
|
|
@ -405,12 +419,12 @@ Mithril = m = new function app(window, undefined) {
|
||||||
var html;
|
var html;
|
||||||
var documentNode = {
|
var documentNode = {
|
||||||
appendChild: function(node) {
|
appendChild: function(node) {
|
||||||
if (html === undefined) html = window.document.createElement("html");
|
if (html === undefined) html = $document.createElement("html");
|
||||||
if (window.document.documentElement && window.document.documentElement !== node) {
|
if ($document.documentElement && $document.documentElement !== node) {
|
||||||
window.document.replaceChild(node, window.document.documentElement)
|
$document.replaceChild(node, $document.documentElement)
|
||||||
}
|
}
|
||||||
else window.document.appendChild(node);
|
else $document.appendChild(node);
|
||||||
this.childNodes = window.document.childNodes
|
this.childNodes = $document.childNodes
|
||||||
},
|
},
|
||||||
insertBefore: function(node) {
|
insertBefore: function(node) {
|
||||||
this.appendChild(node)
|
this.appendChild(node)
|
||||||
|
|
@ -422,8 +436,8 @@ Mithril = m = new function app(window, undefined) {
|
||||||
var configs = [];
|
var configs = [];
|
||||||
if (!root) throw new Error("Please ensure the DOM element exists before rendering a template into it.");
|
if (!root) throw new Error("Please ensure the DOM element exists before rendering a template into it.");
|
||||||
var id = getCellCacheKey(root);
|
var id = getCellCacheKey(root);
|
||||||
var isDocumentRoot = root == window.document;
|
var isDocumentRoot = root == $document;
|
||||||
var node = isDocumentRoot || root == window.document.documentElement ? documentNode : root;
|
var node = isDocumentRoot || root == $document.documentElement ? documentNode : root;
|
||||||
if (isDocumentRoot && cell.tag != "html") cell = {tag: "html", attrs: {}, children: cell};
|
if (isDocumentRoot && cell.tag != "html") cell = {tag: "html", attrs: {}, children: cell};
|
||||||
if (cellCache[id] === undefined) clear(node.childNodes);
|
if (cellCache[id] === undefined) clear(node.childNodes);
|
||||||
if (forceRecreation === true) reset(root);
|
if (forceRecreation === true) reset(root);
|
||||||
|
|
@ -492,21 +506,19 @@ Mithril = m = new function app(window, undefined) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
m.redraw = function(force) {
|
m.redraw = function(force) {
|
||||||
var cancel = window.cancelAnimationFrame || window.clearTimeout;
|
|
||||||
var defer = window.requestAnimationFrame || window.setTimeout;
|
|
||||||
//lastRedrawId is a positive number if a second redraw is requested before the next animation frame
|
//lastRedrawId is a positive number if a second redraw is requested before the next animation frame
|
||||||
//lastRedrawID is null if it's the first redraw and not an event handler
|
//lastRedrawID is null if it's the first redraw and not an event handler
|
||||||
if (lastRedrawId && force !== true) {
|
if (lastRedrawId && force !== true) {
|
||||||
//when setTimeout: only reschedule redraw if time between now and previous redraw is bigger than a frame, otherwise keep currently scheduled timeout
|
//when setTimeout: only reschedule redraw if time between now and previous redraw is bigger than a frame, otherwise keep currently scheduled timeout
|
||||||
//when rAF: always reschedule redraw
|
//when rAF: always reschedule redraw
|
||||||
if (new Date - lastRedrawCallTime > FRAME_BUDGET || defer == window.requestAnimationFrame) {
|
if (new Date - lastRedrawCallTime > FRAME_BUDGET || $requestAnimationFrame == window.requestAnimationFrame) {
|
||||||
if (lastRedrawId > 0) cancel(lastRedrawId);
|
if (lastRedrawId > 0) $cancelAnimationFrame(lastRedrawId);
|
||||||
lastRedrawId = defer(redraw, FRAME_BUDGET)
|
lastRedrawId = $requestAnimationFrame(redraw, FRAME_BUDGET)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
redraw();
|
redraw();
|
||||||
lastRedrawId = defer(function() {lastRedrawId = null}, FRAME_BUDGET)
|
lastRedrawId = $requestAnimationFrame(function() {lastRedrawId = null}, FRAME_BUDGET)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
m.redraw.strategy = m.prop();
|
m.redraw.strategy = m.prop();
|
||||||
|
|
@ -558,8 +570,8 @@ Mithril = m = new function app(window, undefined) {
|
||||||
};
|
};
|
||||||
var listener = m.route.mode == "hash" ? "onhashchange" : "onpopstate";
|
var listener = m.route.mode == "hash" ? "onhashchange" : "onpopstate";
|
||||||
window[listener] = function() {
|
window[listener] = function() {
|
||||||
if (currentRoute != normalizeRoute(window.location[m.route.mode])) {
|
if (currentRoute != normalizeRoute($location[m.route.mode])) {
|
||||||
redirect(window.location[m.route.mode])
|
redirect($location[m.route.mode])
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
computePostRedrawHook = setScroll;
|
computePostRedrawHook = setScroll;
|
||||||
|
|
@ -570,7 +582,7 @@ Mithril = m = new function app(window, undefined) {
|
||||||
var element = arguments[0];
|
var element = arguments[0];
|
||||||
var isInitialized = arguments[1];
|
var isInitialized = arguments[1];
|
||||||
var context = arguments[2];
|
var context = arguments[2];
|
||||||
element.href = (m.route.mode !== 'pathname' ? window.location.pathname : '') + modes[m.route.mode] + this.attrs.href;
|
element.href = (m.route.mode !== 'pathname' ? $location.pathname : '') + modes[m.route.mode] + this.attrs.href;
|
||||||
element.removeEventListener("click", routeUnobtrusive);
|
element.removeEventListener("click", routeUnobtrusive);
|
||||||
element.addEventListener("click", routeUnobtrusive)
|
element.addEventListener("click", routeUnobtrusive)
|
||||||
}
|
}
|
||||||
|
|
@ -584,12 +596,12 @@ Mithril = m = new function app(window, undefined) {
|
||||||
|
|
||||||
if (window.history.pushState) {
|
if (window.history.pushState) {
|
||||||
computePostRedrawHook = function() {
|
computePostRedrawHook = function() {
|
||||||
window.history[shouldReplaceHistoryEntry ? "replaceState" : "pushState"](null, window.document.title, modes[m.route.mode] + currentRoute);
|
window.history[shouldReplaceHistoryEntry ? "replaceState" : "pushState"](null, $document.title, modes[m.route.mode] + currentRoute);
|
||||||
setScroll()
|
setScroll()
|
||||||
};
|
};
|
||||||
redirect(modes[m.route.mode] + currentRoute)
|
redirect(modes[m.route.mode] + currentRoute)
|
||||||
}
|
}
|
||||||
else window.location[m.route.mode] = currentRoute
|
else $location[m.route.mode] = currentRoute
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
m.route.param = function(key) {return routeParams[key]};
|
m.route.param = function(key) {return routeParams[key]};
|
||||||
|
|
@ -633,7 +645,7 @@ Mithril = m = new function app(window, undefined) {
|
||||||
m.route(currentTarget[m.route.mode].slice(modes[m.route.mode].length), args)
|
m.route(currentTarget[m.route.mode].slice(modes[m.route.mode].length), args)
|
||||||
}
|
}
|
||||||
function setScroll() {
|
function setScroll() {
|
||||||
if (m.route.mode != "hash" && window.location.hash) window.location.hash = window.location.hash;
|
if (m.route.mode != "hash" && $location.hash) $location.hash = $location.hash;
|
||||||
else window.scrollTo(0, 0)
|
else window.scrollTo(0, 0)
|
||||||
}
|
}
|
||||||
function buildQueryString(object, prefix) {
|
function buildQueryString(object, prefix) {
|
||||||
|
|
@ -698,7 +710,7 @@ Mithril = m = new function app(window, undefined) {
|
||||||
if (!state) {
|
if (!state) {
|
||||||
promiseValue = value;
|
promiseValue = value;
|
||||||
state = REJECTING;
|
state = REJECTING;
|
||||||
|
|
||||||
fire()
|
fire()
|
||||||
}
|
}
|
||||||
return this
|
return this
|
||||||
|
|
@ -717,7 +729,7 @@ Mithril = m = new function app(window, undefined) {
|
||||||
}
|
}
|
||||||
return deferred.promise
|
return deferred.promise
|
||||||
};
|
};
|
||||||
|
|
||||||
function finish(type) {
|
function finish(type) {
|
||||||
state = type || REJECTED;
|
state = type || REJECTED;
|
||||||
next.map(function(deferred) {
|
next.map(function(deferred) {
|
||||||
|
|
@ -833,10 +845,10 @@ Mithril = m = new function app(window, undefined) {
|
||||||
function ajax(options) {
|
function ajax(options) {
|
||||||
if (options.dataType && options.dataType.toLowerCase() === "jsonp") {
|
if (options.dataType && options.dataType.toLowerCase() === "jsonp") {
|
||||||
var callbackKey = "mithril_callback_" + new Date().getTime() + "_" + (Math.round(Math.random() * 1e16)).toString(36);
|
var callbackKey = "mithril_callback_" + new Date().getTime() + "_" + (Math.round(Math.random() * 1e16)).toString(36);
|
||||||
var script = window.document.createElement("script");
|
var script = $document.createElement("script");
|
||||||
|
|
||||||
window[callbackKey] = function(resp) {
|
window[callbackKey] = function(resp) {
|
||||||
window.document.body.removeChild(script);
|
$document.body.removeChild(script);
|
||||||
options.onload({
|
options.onload({
|
||||||
type: "load",
|
type: "load",
|
||||||
target: {
|
target: {
|
||||||
|
|
@ -847,7 +859,7 @@ Mithril = m = new function app(window, undefined) {
|
||||||
};
|
};
|
||||||
|
|
||||||
script.onerror = function(e) {
|
script.onerror = function(e) {
|
||||||
window.document.body.removeChild(script);
|
$document.body.removeChild(script);
|
||||||
|
|
||||||
options.onerror({
|
options.onerror({
|
||||||
type: "error",
|
type: "error",
|
||||||
|
|
@ -870,7 +882,7 @@ Mithril = m = new function app(window, undefined) {
|
||||||
+ (options.callbackKey ? options.callbackKey : "callback")
|
+ (options.callbackKey ? options.callbackKey : "callback")
|
||||||
+ "=" + callbackKey
|
+ "=" + callbackKey
|
||||||
+ "&" + buildQueryString(options.data || {});
|
+ "&" + buildQueryString(options.data || {});
|
||||||
window.document.body.appendChild(script)
|
$document.body.appendChild(script)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var xhr = new window.XMLHttpRequest;
|
var xhr = new window.XMLHttpRequest;
|
||||||
|
|
@ -953,7 +965,10 @@ Mithril = m = new function app(window, undefined) {
|
||||||
};
|
};
|
||||||
|
|
||||||
//testing API
|
//testing API
|
||||||
m.deps = function(mock) {return window = mock || window};
|
m.deps = function(mock) {
|
||||||
|
initialize(window = mock || window);
|
||||||
|
return window;
|
||||||
|
};
|
||||||
//for internal testing only, do not use `m.deps.factory`
|
//for internal testing only, do not use `m.deps.factory`
|
||||||
m.deps.factory = app;
|
m.deps.factory = app;
|
||||||
|
|
||||||
|
|
@ -961,6 +976,4 @@ Mithril = m = new function app(window, undefined) {
|
||||||
}(typeof window != "undefined" ? window : {});
|
}(typeof window != "undefined" ? window : {});
|
||||||
|
|
||||||
if (typeof module != "undefined" && module !== null) module.exports = m;
|
if (typeof module != "undefined" && module !== null) module.exports = m;
|
||||||
if (typeof define == "function" && define.amd) define(function() {return m})
|
if (typeof define == "function" && define.amd) define(function() {return m});
|
||||||
|
|
||||||
;;;
|
|
||||||
|
|
|
||||||
2
mithril.min.js
vendored
2
mithril.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue