dhxmvp
Version:
A complete boilerplate for building online, offline and syncable MVP Single Page Applications using DHTMLX.
1,113 lines (999 loc) • 67.1 kB
JavaScript
/* jshint -W024 */
/* jshint expr:true */
var splash_base64 = "",
loading_gif = "data:image/gif;base64,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";
window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction;
window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;
// Production steps of ECMA-262, Edition 5, 15.4.4.19
// Reference: http://es5.github.io/#x15.4.4.19
if (!Array.prototype.map) {
Array.prototype.map = function(callback, thisArg) {
var T, A, k;
if (this === null) {
throw new TypeError(' this is null or not defined');
}
// 1. Let O be the result of calling ToObject passing the |this|
// value as the argument.
var O = Object(this);
// 2. Let lenValue be the result of calling the Get internal
// method of O with the argument "length".
// 3. Let len be ToUint32(lenValue).
var len = O.length >>> 0;
// 4. If IsCallable(callback) is false, throw a TypeError exception.
// See: http://es5.github.com/#x9.11
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
// 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
if (arguments.length > 1) {
T = thisArg;
}
// 6. Let A be a new array created as if by the expression new Array(len)
// where Array is the standard built-in constructor with that name and
// len is the value of len.
A = new Array(len);
// 7. Let k be 0
k = 0;
// 8. Repeat, while k < len
while (k < len) {
var kValue, mappedValue;
// a. Let Pk be ToString(k).
// This is implicit for LHS operands of the in operator
// b. Let kPresent be the result of calling the HasProperty internal
// method of O with argument Pk.
// This step can be combined with c
// c. If kPresent is true, then
if (k in O) {
// i. Let kValue be the result of calling the Get internal
// method of O with argument Pk.
kValue = O[k];
// ii. Let mappedValue be the result of calling the Call internal
// method of callback with T as the this value and argument
// list containing kValue, k, and O.
mappedValue = callback.call(T, kValue, k, O);
// iii. Call the DefineOwnProperty internal method of A with arguments
// Pk, Property Descriptor
// { Value: mappedValue,
// Writable: true,
// Enumerable: true,
// Configurable: true },
// and false.
// In browsers that support Object.defineProperty, use the following:
// Object.defineProperty(A, k, {
// value: mappedValue,
// writable: true,
// enumerable: true,
// configurable: true
// });
// For best browser support, use the following:
A[k] = mappedValue;
}
// d. Increase k by 1.
k++;
}
// 9. return A
return A;
};
}
// Production steps of ECMA-262, Edition 5, 15.4.4.21
// Reference: http://es5.github.io/#x15.4.4.21
if (!Array.prototype.reduce) {
Array.prototype.reduce = function(callback /*, initialValue*/ ) {
'use strict';
if (this === null) {
throw new TypeError('Array.prototype.reduce called on null or undefined');
}
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
var t = Object(this),
len = t.length >>> 0,
k = 0,
value;
if (arguments.length == 2) {
value = arguments[1];
} else {
while (k < len && !(k in t)) {
k++;
}
if (k >= len) {
throw new TypeError('Reduce of empty array with no initial value');
}
value = t[k++];
}
for (; k < len; k++) {
if (k in t) {
value = callback(value, t[k], k, t);
}
}
return value;
};
}
// Production steps of ECMA-262, Edition 5, 15.4.4.22
// Reference: http://es5.github.io/#x15.4.4.22
if ('function' !== typeof Array.prototype.reduceRight) {
Array.prototype.reduceRight = function(callback /*, initialValue*/) {
'use strict';
if (null === this || 'undefined' === typeof this) {
throw new TypeError('Array.prototype.reduce called on null or undefined' );
}
if ('function' !== typeof callback) {
throw new TypeError(callback + ' is not a function');
}
var t = Object(this), len = t.length >>> 0, k = len - 1, value;
if (arguments.length >= 2) {
value = arguments[1];
} else {
while (k >= 0 && !(k in t)) {
k--;
}
if (k < 0) {
throw new TypeError('Reduce of empty array with no initial value');
}
value = t[k--];
}
for (; k >= 0; k--) {
if (k in t) {
value = callback(value, t[k], k, t);
}
}
return value;
};
}
// Production steps of ECMA-262, Edition 5, 15.4.4.17
// Reference: http://es5.github.io/#x15.4.4.17
if (!Array.prototype.some) {
Array.prototype.some = function(fun /*, thisArg*/ ) {
'use strict';
if (this === null) {
throw new TypeError('Array.prototype.some called on null or undefined');
}
if (typeof fun !== 'function') {
throw new TypeError();
}
var t = Object(this);
var len = t.length >>> 0;
var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
for (var i = 0; i < len; i++) {
if (i in t && fun.call(thisArg, t[i], i, t)) {
return true;
}
}
return false;
};
}
if (!Array.prototype.every) {
Array.prototype.every = function(callbackfn, thisArg) {
'use strict';
var T, k;
if (this === null) {
throw new TypeError('this is null or not defined');
}
// 1. Let O be the result of calling ToObject passing the this
// value as the argument.
var O = Object(this);
// 2. Let lenValue be the result of calling the Get internal method
// of O with the argument "length".
// 3. Let len be ToUint32(lenValue).
var len = O.length >>> 0;
// 4. If IsCallable(callbackfn) is false, throw a TypeError exception.
if (typeof callbackfn !== 'function') {
throw new TypeError();
}
// 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
if (arguments.length > 1) {
T = thisArg;
}
// 6. Let k be 0.
k = 0;
// 7. Repeat, while k < len
while (k < len) {
var kValue;
// a. Let Pk be ToString(k).
// This is implicit for LHS operands of the in operator
// b. Let kPresent be the result of calling the HasProperty internal
// method of O with argument Pk.
// This step can be combined with c
// c. If kPresent is true, then
if (k in O) {
// i. Let kValue be the result of calling the Get internal method
// of O with argument Pk.
kValue = O[k];
// ii. Let testResult be the result of calling the Call internal method
// of callbackfn with T as the this value and argument list
// containing kValue, k, and O.
var testResult = callbackfn.call(T, kValue, k, O);
// iii. If ToBoolean(testResult) is false, return false.
if (!testResult) {
return false;
}
}
k++;
}
return true;
};
}
Array.prototype.dataCount = function() {
'use strict';
return this.length;
};
if (!Array.prototype.forEach) {
Array.prototype.forEach = function forEach(callback, thisArg) {
var T, k;
if (this === null) {
throw new TypeError("this is null or not defined");
}
var O = Object(this);
var len = O.length >>> 0; // Hack to convert O.length to a UInt32
if ({}.toString.call(callback) !== "[object Function]") {
throw new TypeError(callback + " is not a function");
}
if (thisArg) {
T = thisArg;
}
k = 0;
while (k < len) {
var kValue;
if (Object.prototype.hasOwnProperty.call(O, k)) {
kValue = O[k];
callback.call(T, kValue, k, O);
}
k++;
}
};
}
if (!Array.prototype.contains) {
Array.prototype.contains = function(value) {
for (var p = 0; p < this.length; p++) {
if (this[p] === value) return true;
}
return false;
};
}
Array.prototype.clean = function(deleteValue) {
for (var i = 0; i < this.length; i++) {
if (this[i] == deleteValue) {
this.splice(i, 1);
i--;
}
}
return this;
};
String.prototype.CFC = function() {
return '<u>' + this.charAt(0).toUpperCase() + '</u>' + this.slice(1);
};
String.prototype.soundex = function(p) {
var i, j, l,
m = {
BFPV: 1,
CGJKQSXZ: 2,
DT: 3,
L: 4,
MN: 5,
R: 6
},
r = (s = this.toUpperCase().replace(/[^A-Z]/g, "").split("")).splice(0, 1);
p = isNaN(p) ? 4 : p > 10 ? 10 : p < 4 ? 4 : p;
for (i = -1, l = s.length; ++i < l;)
for (j in m)
if (j.indexOf(s[i]) + 1 && r[r.length - 1] != m[j] && r.push(m[j])) break;
return r.length > p && (r.length = p), r.join("") + (new Array(p - r.length + 1)).join("0");
};
if (!String.prototype.trim) {
(function() {
// Make sure we trim BOM and NBSP
var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
String.prototype.trim = function() {
return this.replace(rtrim, '');
};
})();
}
String.prototype.realToDouble = function() {
var value = this;
value = value.replace(/\D/g, "");
value = +value / 100;
return value.toFixed(2);
};
/*String.prototype.extenso = function(c) {
var ex = [
["zero", "um", "dois", "três", "quatro", "cinco", "seis", "sete", "oito", "nove", "dez", "onze", "doze", "treze", "quatorze", "quinze", "dezesseis", "dezessete", "dezoito", "dezenove"],
["dez", "vinte", "trinta", "quarenta", "cinqüenta", "sessenta", "setenta", "oitenta", "noventa"],
["cem", "cento", "duzentos", "trezentos", "quatrocentos", "quinhentos", "seiscentos", "setecentos", "oitocentos", "novecentos"],
["mil", "milhão", "bilhão", "trilhão", "quadrilhão", "quintilhão", "sextilhão", "setilhão", "octilhão", "nonilhão", "decilhão", "undecilhão", "dodecilhão", "tredecilhão", "quatrodecilhão", "quindecilhão", "sedecilhão", "septendecilhão", "octencilhão", "nonencilhão"]
];
var a, v, i, n = this.replace(c ? /[^,\d]/g : /\D/g, "").split(","),
e = " e ",
$ = "real",
d = "centavo",
sl;
for (var f = n.length - 1, l, j = -1, r = [], s = [], t = ""; ++j <= f; s = []) {
j && (n[j] = (("." + n[j]) * 1).toFixed(2).slice(2));
if (!(a = (v = n[j]).slice((l = v.length) % 3).match(/\d{3}/g), v = l % 3 ? [v.slice(0, l % 3)] : [], v = a ? v.concat(a) : v).length) continue;
for (a = -1, l = v.length; ++a < l; t = "") {
if (!(i = v[a] * 1)) continue;
i % 100 < 20 && (t += ex[0][i % 100]) || i % 100 + 1 && (t += ex[1][(i % 100 / 10 >> 0) - 1] + (i % 10 ? e + ex[0][i % 10] : ""));
s.push((i < 100 ? t : !(i % 100) ? ex[2][i == 100 ? 0 : i / 100 >> 0] : (ex[2][i / 100 >> 0] + e + t)) + ((t = l - a - 2) > -1 ? " " + (i > 1 && t > 0 ? ex[3][t].replace("ão", "ões") : ex[3][t]) : ""));
}
a = ((sl = s.length) > 1 ? (a = s.pop(), s.join(" ") + e + a) : s.join("") || ((!j && (n[j + 1] * 1 > 0) || r.length) ? "" : ex[0][0]));
a && r.push(a + (c ? (" " + (v.join("") * 1 > 1 ? j ? d + "s" : (/0{6,}$/.test(n[0]) ? "de " : "") + $.replace("l", "is") : j ? d : $)) : ""));
}
return r.join(e);
};*/
// Extend the default Number object with a formatMoney() method:
// usage: someVar.formatMoney(decimalPlaces, symbol, thousandsSeparator, decimalSeparator)
// defaults: (2, "$", ",", ".")
Number.prototype.formatMoney = function(places, symbol, thousand, decimal) {
places = !isNaN(places = Math.abs(places)) ? places : 2;
symbol = symbol !== undefined ? symbol : "$";
thousand = thousand || ",";
decimal = decimal || ".";
var number = this,
negative = number < 0 ? "-" : "",
i = parseInt(number = Math.abs(+number || 0).toFixed(places), 10) + "",
j = (j = i.length) > 3 ? j % 3 : 0;
return symbol + negative + (j ? i.substr(0, j) + thousand : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + thousand) + (places ? decimal + Math.abs(number - i).toFixed(places).slice(2) : "");
};
Date.prototype.addDays = function(days)
{
var dat = new Date(this.valueOf());
dat.setDate(dat.getDate() + days);
return dat;
};
Date.prototype.addHours = function(h) {
this.setTime(this.getTime() + (h*60*60*1000));
return this;
};
Date.prototype.addMinutes = function(h) {
this.setTime(this.getTime() + (h*60*1000));
return this;
};
/*if (!Element.prototype.addEventListener) {
var oListeners = {};
function runListeners(oEvent) {
if (!oEvent) { oEvent = window.event; }
for (var iLstId = 0, iElId = 0, oEvtListeners = oListeners[oEvent.type]; iElId < oEvtListeners.aEls.length; iElId++) {
if (oEvtListeners.aEls[iElId] === this) {
for (iLstId; iLstId < oEvtListeners.aEvts[iElId].length; iLstId++) { oEvtListeners.aEvts[iElId][iLstId].call(this, oEvent); }
break;
}
}
}
//Element.prototype.addEventListener = function (sEventType, fListener , useCapture (will be ignored!) )
Element.prototype.addEventListener = function (sEventType, fListener) {
if (oListeners.hasOwnProperty(sEventType)) {
var oEvtListeners = oListeners[sEventType];
for (var nElIdx = -1, iElId = 0; iElId < oEvtListeners.aEls.length; iElId++) {
if (oEvtListeners.aEls[iElId] === this) { nElIdx = iElId; break; }
}
if (nElIdx === -1) {
oEvtListeners.aEls.push(this);
oEvtListeners.aEvts.push([fListener]);
this["on" + sEventType] = runListeners;
} else {
var aElListeners = oEvtListeners.aEvts[nElIdx];
if (this["on" + sEventType] !== runListeners) {
aElListeners.splice(0);
this["on" + sEventType] = runListeners;
}
for (var iLstId = 0; iLstId < aElListeners.length; iLstId++) {
if (aElListeners[iLstId] === fListener) { return; }
}
aElListeners.push(fListener);
}
} else {
oListeners[sEventType] = { aEls: [this], aEvts: [ [fListener] ] };
this["on" + sEventType] = runListeners;
}
};
//Element.prototype.removeEventListener = function (sEventType, fListener , useCapture (will be ignored!))
Element.prototype.removeEventListener = function (sEventType, fListener ) {
if (!oListeners.hasOwnProperty(sEventType)) { return; }
var oEvtListeners = oListeners[sEventType];
for (var nElIdx = -1, iElId = 0; iElId < oEvtListeners.aEls.length; iElId++) {
if (oEvtListeners.aEls[iElId] === this) { nElIdx = iElId; break; }
}
if (nElIdx === -1) { return; }
for (var iLstId = 0, aElListeners = oEvtListeners.aEvts[nElIdx]; iLstId < aElListeners.length; iLstId++) {
if (aElListeners[iLstId] === fListener) { aElListeners.splice(iLstId, 1); }
}
};
}
*/
/*======================= BUILD CONSOLE OBJECT ========================*/
// create a noop console object if the browser doesn't provide one ...
if (!window.console) {
window.console = {};
}
// IE has a console that has a 'log' function but no 'debug'. to make console.debug work in IE,
// we just map the function. (extend for info etc if needed)
else {
if (!window.console.debug && typeof window.console.log !== 'undefined') {
window.console.debug = window.console.log;
}
}
// ... and create all functions we expect the console to have (took from firebug).
var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
for (var i = 0; i < names.length; ++i) {
if (!window.console[names[i]]) {
window.console[names[i]] = function() {};
}
}
// Copyright © 2015 BankFacil, http://bankfacil.com.br
// MIT license -> http://bankfacil.mit-license.org/
(function(root, factory) {
if (typeof define === 'function' && define.amd) {
define(factory);
} else if (typeof exports === 'object') {
module.exports = factory();
} else {
root.VMasker = factory();
}
}(this, function() {
var DIGIT = "9",
ALPHA = "A",
ALPHANUM = "S",
BY_PASS_KEYS = [9, 16, 17, 18, 36, 37, 38, 39, 40, 91, 92, 93],
isAllowedKeyCode = function(keyCode) {
for (var i = 0, len = BY_PASS_KEYS.length; i < len; i++) {
if (keyCode == BY_PASS_KEYS[i]) {
return false;
}
}
return true;
},
mergeMoneyOptions = function(opts) {
opts = opts || {};
opts = {
precision: opts.hasOwnProperty("precision") ? opts.precision : 2,
separator: opts.separator || ",",
delimiter: opts.delimiter || ".",
unit: opts.unit && (opts.unit.replace(/[\s]/g,'') + " ") || "",
suffixUnit: opts.suffixUnit && (" " + opts.suffixUnit.replace(/[\s]/g,'')) || "",
zeroCents: opts.zeroCents,
lastOutput: opts.lastOutput
};
opts.moneyPrecision = opts.zeroCents ? 0 : opts.precision;
return opts;
},
// Fill wildcards past index in output with placeholder
addPlaceholdersToOutput = function(output, index, placeholder) {
for (; index < output.length; index++) {
if(output[index] === DIGIT || output[index] === ALPHA || output[index] === ALPHANUM) {
output[index] = placeholder;
}
}
return output;
}
;
var VanillaMasker = function(elements) {
this.elements = elements;
};
VanillaMasker.prototype.unbindElementToMask = function() {
for (var i = 0, len = this.elements.length; i < len; i++) {
this.elements[i].lastOutput = "";
this.elements[i].onkeyup = false;
this.elements[i].onkeydown = false;
if (this.elements[i].value.length) {
this.elements[i].value = this.elements[i].value.replace(/\D/g, '');
}
}
};
VanillaMasker.prototype.bindElementToMask = function(maskFunction) {
var that = this,
onType = function(e) {
e = e || window.event;
var source = e.target || e.srcElement;
if (isAllowedKeyCode(e.keyCode)) {
setTimeout(function() {
that.opts.lastOutput = source.lastOutput;
source.value = VMasker[maskFunction](source.value, that.opts);
source.lastOutput = source.value;
if (source.setSelectionRange && that.opts.suffixUnit) {
source.setSelectionRange(source.value.length, (source.value.length - that.opts.suffixUnit.length));
}
}, 0);
}
}
;
for (var i = 0, len = this.elements.length; i < len; i++) {
this.elements[i].lastOutput = "";
this.elements[i].onkeyup = onType;
if (this.elements[i].value.length) {
this.elements[i].value = VMasker[maskFunction](this.elements[i].value, this.opts);
}
}
};
VanillaMasker.prototype.maskMoney = function(opts) {
this.opts = mergeMoneyOptions(opts);
this.bindElementToMask("toMoney");
};
VanillaMasker.prototype.maskNumber = function() {
this.opts = {};
this.bindElementToMask("toNumber");
};
VanillaMasker.prototype.maskAlphaNum = function() {
this.opts = {};
this.bindElementToMask("toAlphaNumeric");
};
VanillaMasker.prototype.maskPattern = function(pattern) {
this.opts = {pattern: pattern};
this.bindElementToMask("toPattern");
};
VanillaMasker.prototype.unMask = function() {
this.unbindElementToMask();
};
var VMasker = function(el) {
if (!el) {
throw new Error("VanillaMasker: There is no element to bind.");
}
var elements = ("length" in el) ? (el.length ? el : []) : [el];
return new VanillaMasker(elements);
};
VMasker.toMoney = function(value, opts) {
opts = mergeMoneyOptions(opts);
if (opts.zeroCents) {
opts.lastOutput = opts.lastOutput || "";
var zeroMatcher = ("("+ opts.separator +"[0]{0,"+ opts.precision +"})"),
zeroRegExp = new RegExp(zeroMatcher, "g"),
digitsLength = value.toString().replace(/[\D]/g, "").length || 0,
lastDigitLength = opts.lastOutput.toString().replace(/[\D]/g, "").length || 0
;
value = value.toString().replace(zeroRegExp, "");
if (digitsLength < lastDigitLength) {
value = value.slice(0, value.length - 1);
}
}
var number = value.toString().replace(/[\D]/g, ""),
clearDelimiter = new RegExp("^(0|\\"+ opts.delimiter +")"),
clearSeparator = new RegExp("(\\"+ opts.separator +")$"),
money = number.substr(0, number.length - opts.moneyPrecision),
masked = money.substr(0, money.length % 3),
cents = new Array(opts.precision + 1).join("0")
;
money = money.substr(money.length % 3, money.length);
for (var i = 0, len = money.length; i < len; i++) {
if (i % 3 === 0) {
masked += opts.delimiter;
}
masked += money[i];
}
masked = masked.replace(clearDelimiter, "");
masked = masked.length ? masked : "0";
if (!opts.zeroCents) {
var beginCents = number.length - opts.precision,
centsValue = number.substr(beginCents, opts.precision),
centsLength = centsValue.length,
centsSliced = (opts.precision > centsLength) ? opts.precision : centsLength
;
cents = (cents + centsValue).slice(-centsSliced);
}
var output = opts.unit + masked + opts.separator + cents + opts.suffixUnit;
return output.replace(clearSeparator, "");
};
VMasker.toPattern = function(value, opts) {
var pattern = (typeof opts === 'object' ? opts.pattern : opts),
patternChars = pattern.replace(/\W/g, ''),
output = pattern.split(""),
values = value.toString().replace(/\W/g, ""),
charsValues = values.replace(/\W/g, ''),
index = 0,
i,
outputLength = output.length,
placeholder = (typeof opts === 'object' ? opts.placeholder : undefined)
;
for (i = 0; i < outputLength; i++) {
// Reached the end of input
if (index >= values.length) {
if (patternChars.length == charsValues.length) {
return output.join("");
}
else if ((placeholder !== undefined) && (patternChars.length > charsValues.length)) {
return addPlaceholdersToOutput(output, i, placeholder).join("");
}
else {
break;
}
}
// Remaining chars in input
else{
if ((output[i] === DIGIT && values[index].match(/[0-9]/)) ||
(output[i] === ALPHA && values[index].match(/[a-zA-Z]/)) ||
(output[i] === ALPHANUM && values[index].match(/[0-9a-zA-Z]/))) {
output[i] = values[index++];
} else if (output[i] === DIGIT || output[i] === ALPHA || output[i] === ALPHANUM) {
if(placeholder !== undefined){
return addPlaceholdersToOutput(output, i, placeholder).join("");
}
else{
return output.slice(0, i).join("");
}
}
}
}
return output.join("").substr(0, i);
};
VMasker.toNumber = function(value) {
return value.toString().replace(/(?!^-)[^0-9]/g, "");
};
VMasker.toAlphaNumeric = function(value) {
return value.toString().replace(/[^a-z0-9 ]+/i, "");
};
return VMasker;
}));
/*!
* Object.observe "lite" polyfill - v0.2.4
* by Massimo Artizzu (MaxArt2501)
*
* https://github.com/MaxArt2501/object-observe
*
* Licensed under the MIT License
* See LICENSE for details
*/
// Some type definitions
/**
* This represents the data relative to an observed object
* @typedef {Object} ObjectData
* @property {Map<Handler, HandlerData>} handlers
* @property {String[]} properties
* @property {*[]} values
* @property {Notifier} notifier
*/
/**
* Function definition of a handler
* @callback Handler
* @param {ChangeRecord[]} changes
*/
/**
* This represents the data relative to an observed object and one of its
* handlers
* @typedef {Object} HandlerData
* @property {Map<Object, ObservedData>} observed
* @property {ChangeRecord[]} changeRecords
*/
/**
* @typedef {Object} ObservedData
* @property {String[]} acceptList
* @property {ObjectData} data
*/
/**
* Type definition for a change. Any other property can be added using
* the notify() or performChange() methods of the notifier.
* @typedef {Object} ChangeRecord
* @property {String} type
* @property {Object} object
* @property {String} [name]
* @property {*} [oldValue]
* @property {Number} [index]
*/
/**
* Type definition for a notifier (what Object.getNotifier returns)
* @typedef {Object} Notifier
* @property {Function} notify
* @property {Function} performChange
*/
/**
* Function called with Notifier.performChange. It may optionally return a
* ChangeRecord that gets automatically notified, but `type` and `object`
* properties are overridden.
* @callback Performer
* @returns {ChangeRecord|undefined}
*/
Object.observe || (function(O, A, root, _undefined) {
"use strict";
/**
* Relates observed objects and their data
* @type {Map<Object, ObjectData}
*/
var observed,
/**
* List of handlers and their data
* @type {Map<Handler, Map<Object, HandlerData>>}
*/
handlers,
defaultAcceptList = ["add", "update", "delete", "reconfigure", "setPrototype", "preventExtensions"];
// Functions for internal usage
/**
* Checks if the argument is an Array object. Polyfills Array.isArray.
* @function isArray
* @param {?*} object
* @returns {Boolean}
*/
var isArray = A.isArray || (function(toString) {
return function(object) {
return toString.call(object) === "[object Array]";
};
})(O.prototype.toString),
/**
* Returns the index of an item in a collection, or -1 if not found.
* Uses the generic Array.indexOf or Array.prototype.indexOf if available.
* @function inArray
* @param {Array} array
* @param {*} pivot Item to look for
* @param {Number} [start=0] Index to start from
* @returns {Number}
*/
inArray = A.prototype.indexOf ? A.indexOf || function(array, pivot, start) {
return A.prototype.indexOf.call(array, pivot, start);
} : function(array, pivot, start) {
for (var i = start || 0; i < array.length; i++)
if (array[i] === pivot)
return i;
return -1;
},
/**
* Returns an instance of Map, or a Map-like object is Map is not
* supported or doesn't support forEach()
* @function createMap
* @returns {Map}
*/
createMap = root.Map === _undefined || !Map.prototype.forEach ? function() {
// Lightweight shim of Map. Lacks clear(), entries(), keys() and
// values() (the last 3 not supported by IE11, so can't use them),
// it doesn't handle the constructor's argument (like IE11) and of
// course it doesn't support for...of.
// Chrome 31-35 and Firefox 13-24 have a basic support of Map, but
// they lack forEach(), so their native implementation is bad for
// this polyfill. (Chrome 36+ supports Object.observe.)
var keys = [],
values = [];
return {
size: 0,
has: function(key) {
return inArray(keys, key) > -1;
},
get: function(key) {
return values[inArray(keys, key)];
},
set: function(key, value) {
var i = inArray(keys, key);
if (i === -1) {
keys.push(key);
values.push(value);
this.size++;
} else values[i] = value;
},
"delete": function(key) {
var i = inArray(keys, key);
if (i > -1) {
keys.splice(i, 1);
values.splice(i, 1);
this.size--;
}
},
forEach: function(callback /*, thisObj*/ ) {
for (var i = 0; i < keys.length; i++)
callback.call(arguments[1], values[i], keys[i], this);
}
};
} : function() {
return new Map();
},
/**
* Simple shim for Object.getOwnPropertyNames when is not available
* Misses checks on object, don't use as a replacement of Object.keys/getOwnPropertyNames
* @function getProps
* @param {Object} object
* @returns {String[]}
*/
getProps = O.getOwnPropertyNames ? (function() {
var func = O.getOwnPropertyNames, x,
strict = (function() { return !this; }());
if( strict )
{
// Strict mode is supported
// In strict mode, we can't access to "arguments", "caller" and
// "callee" properties of functions. Object.getOwnPropertyNames
// returns [ "prototype", "length", "name" ] in Firefox; it returns
// "caller" and "arguments" too in Chrome and in Internet
// Explorer, so those values must be filtered.
var avoid = (func(inArray).join(" ") + " ").replace(/prototype |length |name /g, "").slice(0, -1).split(" ");
if (avoid.length) func = function(object) {
var props = O.getOwnPropertyNames(object);
if (typeof object === "function")
for (var i = 0, j; i < avoid.length;)
if ((j = inArray(props, avoid[i++])) > -1)
props.splice(j, 1);
return props;
};
}
return func;
})() : function(object) {
// Poor-mouth version with for...in (IE8-)
var props = [],
prop, hop;
if ("hasOwnProperty" in object) {
for (prop in object)
if (object.hasOwnProperty(prop))
props.push(prop);
} else {
hop = O.hasOwnProperty;
for (prop in object)
if (hop.call(object, prop))
props.push(prop);
}
// Inserting a common non-enumerable property of arrays
if (isArray(object))
props.push("length");
return props;
},
/**
* Sets up the next check and delivering iteration, using
* requestAnimationFrame or a (close) polyfill.
* @function nextFrame
* @param {function} func
* @returns {number}
*/
nextFrame = root.requestAnimationFrame || root.webkitRequestAnimationFrame || (function() {
var initial = +new Date(),
last = initial;
return function(func) {
return setTimeout(function() {
func((last = +new Date()) - initial);
}, 17);
};
})(),
/**
* Sets up the observation of an object
* @function doObserve
* @param {Object} object
* @param {Handler} handler
* @param {String[]} [acceptList]
*/
doObserve = function(object, handler, acceptList) {
var data = observed.get(object);
if (data) {
performPropertyChecks(data, object);
setHandler(object, data, handler, acceptList);
} else {
data = createObjectData(object);
setHandler(object, data, handler, acceptList);
if (observed.size === 1)
// Let the observation begin!
nextFrame(runGlobalLoop);
}
},
/**
* Creates the initial data for an observed object
* @function createObjectData
* @param {Object} object
*/
createObjectData = function(object, data) {
var props = getProps(object),
values = [],
i = 0;
data = {
handlers: createMap(),
properties: props,
values: values,
notifier: retrieveNotifier(object, data)
};
while (i < props.length)
values[i] = object[props[i++]];
observed.set(object, data);
return data;
},
/**
* Performs basic property value change checks on an observed object
* @function performPropertyChecks
* @param {ObjectData} data
* @param {Object} object
* @param {String} [except] Doesn't deliver the changes to the
* handlers that accept this type
*/
performPropertyChecks = function(data, object, except) {
if (!data.handlers.size) return;
var props, proplen, keys,
values = data.values,
i = 0,
idx,
key, value, ovalue;
props = data.properties.slice();
proplen = props.length;
keys = getProps(object);
// Check for value additions/changes
while (i < keys.length) {
key = keys[i++];
idx = inArray(props, key);
value = object[key];
if (idx === -1) {
addChangeRecord(object, data, {
name: key,
type: "add",
object: object
}, except);
data.properties.push(key);
values.push(value);
} else {
ovalue = values[idx];
props[idx] = null;
proplen--;
if (ovalue === value ? ovalue === 0 && 1 / ovalue !== 1 / value : ovalue === ovalue || value === value) {
addChangeRecord(object, data, {
name: key,
type: "update",
object: object,
oldValue: ovalue
}, except);
data.values[idx] = value;
}
}
}
// Checks if some property has been deleted
for (i = props.length; proplen && i--;)
if (props[i] !== null) {
addChangeRecord(object, data, {
name: props[i],
type: "delete",
object: object,
oldValue: values[i]
}, except);
data.properties.splice(i, 1);
data.values.splice(i, 1);
proplen--;
}
},
/**
* Sets up the main loop for object observation and change notification
* It stops if no object is observed.
* @function runGlobalLoop
*/
runGlobalLoop = function() {
if (observed.size) {
observed.forEach(performPropertyChecks);
handlers.forEach(deliverHandlerRecords);
nextFrame(runGlobalLoop);
}
},
/**
* Deliver the change records relative to a certain handler, and resets
* the record list.
* @param {HandlerData} hdata
* @param {Handler} handler
*/
deliverHandlerRecords = function(hdata, handler) {
var records = hdata.changeRecords;
if (records.length) {
hdata.changeRecords = [];
handler(records);
}
},
/**
* Returns the notifier for an object - whether it's observed or not
* @function retrieveNotifier
* @param {Object} object
* @param {ObjectData} [data]
* @returns {Notifier}
*/
retrieveNotifier = function(object, data) {
if (arguments.length < 2)
data = observed.get(object);
/** @type {Notifier} */
return data && data.notifier || {
/**
* @method notify
* @see http://arv.github.io/ecmascript-object-observe/#notifierprototype._notify
* @memberof Notifier
* @param {ChangeRecord} changeRecord
*/
notify: function(changeRecord) {
changeRecord.type = changeRecord.type; // Just to check the property is there...
// If there's no data, the object has been unobserved
var data = observed.get(object);
if (data) {
var recordCopy = {
object: object
},
prop;
for (prop in changeRecord)
if (prop !== "object")
recordCopy[prop] = changeRecord[prop];
addChangeRecord(object, data, recordCopy);
}
},
/**
* @method performChange
* @see http://arv.github.io/ecmascript-object-observe/#notifierprototype_.performchange
* @memberof Notifier
* @param {String} changeType
* @param