Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
META-INF.resources.js.geojsf.object-observe.js Maven / Gradle / Ivy
/*!
* Object.observe 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} handlers
* @property {String[]} properties
* @property {*[]} values
* @property {Descriptor[]} descriptors
* @property {Notifier} notifier
* @property {Boolean} frozen
* @property {Boolean} extensible
* @property {Object} proto
*/
/**
* 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} 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) {
"use strict";
/**
* Relates observed objects and their data
* @type {Map>}
*/
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 = typeof 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;
try {
arguments.callee;
} catch (e) {
// 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;
},
/**
* Return the prototype of the object... if defined.
* @function getPrototype
* @param {Object} object
* @returns {Object}
*/
getPrototype = O.getPrototypeOf,
/**
* Return the descriptor of the object... if defined.
* IE8 supports a (useless) Object.getOwnPropertyDescriptor for DOM
* nodes only, so defineProperties is checked instead.
* @function getDescriptor
* @param {Object} object
* @param {String} property
* @returns {Descriptor}
*/
getDescriptor = O.defineProperties && O.getOwnPropertyDescriptor,
/**
* 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)
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 = [], descs, i = 0,
data = {
handlers: createMap(),
frozen: O.isFrozen ? O.isFrozen(object) : false,
extensible: O.isExtensible ? O.isExtensible(object) : true,
proto: getPrototype && getPrototype(object),
properties: props,
values: values,
notifier: retrieveNotifier(object, data)
};
if (getDescriptor) {
descs = data.descriptors = [];
while (i < props.length) {
descs[i] = getDescriptor(object, props[i]);
values[i] = object[props[i++]];
}
} else 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() {
var updateCheck = getDescriptor ? function(object, data, idx, except, descr) {
var key = data.properties[idx],
value = object[key],
ovalue = data.values[idx],
odesc = data.descriptors[idx];
if ("value" in descr && (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;
}
if (odesc.configurable && (!descr.configurable
|| descr.writable !== odesc.writable
|| descr.enumerable !== odesc.enumerable
|| descr.get !== odesc.get
|| descr.set !== odesc.set)) {
addChangeRecord(object, data, {
name: key,
type: "reconfigure",
object: object,
oldValue: ovalue
}, except);
data.descriptors[idx] = descr;
}
} : function(object, data, idx, except) {
var key = data.properties[idx],
value = object[key],
ovalue = data.values[idx];
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
var deletionCheck = getDescriptor ? function(object, props, proplen, data, except) {
var i = props.length, descr;
while (proplen && i--) {
if (props[i] !== null) {
descr = getDescriptor(object, props[i]);
proplen--;
// If there's no descriptor, the property has really
// been deleted; otherwise, it's been reconfigured so
// that's not enumerable anymore
if (descr) updateCheck(object, data, i, except, descr);
else {
addChangeRecord(object, data, {
name: props[i],
type: "delete",
object: object,
oldValue: data.values[i]
}, except);
data.properties.splice(i, 1);
data.values.splice(i, 1);
data.descriptors.splice(i, 1);
}
}
}
} : function(object, props, proplen, data, except) {
var i = props.length;
while (proplen && i--)
if (props[i] !== null) {
addChangeRecord(object, data, {
name: props[i],
type: "delete",
object: object,
oldValue: data.values[i]
}, except);
data.properties.splice(i, 1);
data.values.splice(i, 1);
proplen--;
}
};
return function(data, object, except) {
if (!data.handlers.size || data.frozen) return;
var props, proplen, keys,
values = data.values,
descs = data.descriptors,
i = 0, idx,
key, value,
proto, descr;
// If the object isn't extensible, we don't need to check for new
// or deleted properties
if (data.extensible) {
props = data.properties.slice();
proplen = props.length;
keys = getProps(object);
if (descs) {
while (i < keys.length) {
key = keys[i++];
idx = inArray(props, key);
descr = getDescriptor(object, key);
if (idx === -1) {
addChangeRecord(object, data, {
name: key,
type: "add",
object: object
}, except);
data.properties.push(key);
values.push(object[key]);
descs.push(descr);
} else {
props[idx] = null;
proplen--;
updateCheck(object, data, idx, except, descr);
}
}
deletionCheck(object, props, proplen, data, except);
if (!O.isExtensible(object)) {
data.extensible = false;
addChangeRecord(object, data, {
type: "preventExtensions",
object: object
}, except);
data.frozen = O.isFrozen(object);
}
} else {
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 {
props[idx] = null;
proplen--;
updateCheck(object, data, idx, except);
}
}
deletionCheck(object, props, proplen, data, except);
}
} else if (!data.frozen) {
// If the object is not extensible, but not frozen, we just have
// to check for value changes
for (; i < props.length; i++) {
key = props[i];
updateCheck(object, data, i, except, getDescriptor(object, key));
}
if (O.isFrozen(object))
data.frozen = true;
}
if (getPrototype) {
proto = getPrototype(object);
if (proto !== data.proto) {
addChangeRecord(object, data, {
type: "setPrototype",
name: "__proto__",
object: object,
oldValue: data.proto
});
data.proto = proto;
}
}
};
})(),
/**
* 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) {
if (hdata.changeRecords.length) {
handler(hdata.changeRecords);
hdata.changeRecords = [];
}
},
/**
* 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; // 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 {Performer} func The task performer
* @param {*} [thisObj] Used to set `this` when calling func
*/
performChange: function(changeType, func/*, thisObj*/) {
if (typeof changeType !== "string")
throw new TypeError("Invalid non-string changeType");
if (typeof func !== "function")
throw new TypeError("Cannot perform non-function");
// If there's no data, the object has been unobserved
var data = observed.get(object),
prop, changeRecord,
result = func.call(arguments[2]);
data && performPropertyChecks(data, object, changeType);
// If there's no data, the object has been unobserved
if (data && result && typeof result === "object") {
changeRecord = { object: object, type: changeType };
for (prop in result)
if (prop !== "object" && prop !== "type")
changeRecord[prop] = result[prop];
addChangeRecord(object, data, changeRecord);
}
}
};
},
/**
* Register (or redefines) an handler in the collection for a given
* object and a given type accept list.
* @function setHandler
* @param {Object} object
* @param {ObjectData} data
* @param {Handler} handler
* @param {String[]} acceptList
*/
setHandler = function(object, data, handler, acceptList) {
var hdata = handlers.get(handler);
if (!hdata)
handlers.set(handler, hdata = {
observed: createMap(),
changeRecords: []
});
hdata.observed.set(object, {
acceptList: acceptList.slice(),
data: data
});
data.handlers.set(handler, hdata);
},
/**
* Adds a change record in a given ObjectData
* @function addChangeRecord
* @param {Object} object
* @param {ObjectData} data
* @param {ChangeRecord} changeRecord
* @param {String} [except]
*/
addChangeRecord = function(object, data, changeRecord, except) {
data.handlers.forEach(function(hdata) {
var acceptList = hdata.observed.get(object).acceptList;
// If except is defined, Notifier.performChange has been
// called, with except as the type.
// All the handlers that accepts that type are skipped.
if ((typeof except !== "string"
|| inArray(acceptList, except) === -1)
&& inArray(acceptList, changeRecord.type) > -1)
hdata.changeRecords.push(changeRecord);
});
};
observed = createMap();
handlers = createMap();
/**
* @function Object.observe
* @see http://arv.github.io/ecmascript-object-observe/#Object.observe
* @param {Object} object
* @param {Handler} handler
* @param {String[]} [acceptList]
* @throws {TypeError}
* @returns {Object} The observed object
*/
O.observe = function observe(object, handler, acceptList) {
if (!object || typeof object !== "object" && typeof object !== "function")
throw new TypeError("Object.observe cannot observe non-object");
if (typeof handler !== "function")
throw new TypeError("Object.observe cannot deliver to non-function");
if (O.isFrozen && O.isFrozen(handler))
throw new TypeError("Object.observe cannot deliver to a frozen function object");
if (typeof acceptList === "undefined")
acceptList = defaultAcceptList;
else if (!acceptList || typeof acceptList !== "object")
throw new TypeError("Third argument to Object.observe must be an array of strings.");
doObserve(object, handler, acceptList);
return object;
};
/**
* @function Object.unobserve
* @see http://arv.github.io/ecmascript-object-observe/#Object.unobserve
* @param {Object} object
* @param {Handler} handler
* @throws {TypeError}
* @returns {Object} The given object
*/
O.unobserve = function unobserve(object, handler) {
if (object === null || typeof object !== "object" && typeof object !== "function")
throw new TypeError("Object.unobserve cannot unobserve non-object");
if (typeof handler !== "function")
throw new TypeError("Object.unobserve cannot deliver to non-function");
var hdata = handlers.get(handler), odata;
if (hdata && (odata = hdata.observed.get(object))) {
hdata.observed.forEach(function(odata, object) {
performPropertyChecks(odata.data, object);
});
nextFrame(function() {
deliverHandlerRecords(hdata, handler);
});
// In Firefox 13-18, size is a function, but createMap should fall
// back to the shim for those versions
if (hdata.observed.size === 1 && hdata.observed.has(object))
handlers["delete"](handler);
else hdata.observed["delete"](object);
if (odata.data.handlers.size === 1)
observed["delete"](object);
else odata.data.handlers["delete"](handler);
}
return object;
};
/**
* @function Object.getNotifier
* @see http://arv.github.io/ecmascript-object-observe/#GetNotifier
* @param {Object} object
* @throws {TypeError}
* @returns {Notifier}
*/
O.getNotifier = function getNotifier(object) {
if (object === null || typeof object !== "object" && typeof object !== "function")
throw new TypeError("Object.getNotifier cannot getNotifier non-object");
if (O.isFrozen && O.isFrozen(object)) return null;
return retrieveNotifier(object);
};
/**
* @function Object.deliverChangeRecords
* @see http://arv.github.io/ecmascript-object-observe/#Object.deliverChangeRecords
* @see http://arv.github.io/ecmascript-object-observe/#DeliverChangeRecords
* @param {Handler} handler
* @throws {TypeError}
*/
O.deliverChangeRecords = function deliverChangeRecords(handler) {
if (typeof handler !== "function")
throw new TypeError("Object.deliverChangeRecords cannot deliver to non-function");
var hdata = handlers.get(handler);
if (hdata) {
hdata.observed.forEach(function(odata, object) {
performPropertyChecks(odata.data, object);
});
deliverHandlerRecords(hdata, handler);
}
};
})(Object, Array, this);