/wwwroot/demo/js/global-es5.js
JavaScript | 553 lines | 304 code | 59 blank | 190 comment | 110 complexity | f9ef266cf67fc65d54f561451e1380e9 MD5 | raw file
-
- /*!
- Copyright (c) 2009, 280 North Inc. http://280north.com/
- MIT License. http://github.com/280north/narwhal/blob/master/README.md
- */
-
- // Brings an environment as close to ECMAScript 5 compliance
- // as is possible with the facilities of erstwhile engines.
-
- // ES5 Draft
- // http://www.ecma-international.org/publications/files/drafts/tc39-2009-050.pdf
-
- // NOTE: this is a draft, and as such, the URL is subject to change. If the
- // link is broken, check in the parent directory for the latest TC39 PDF.
- // http://www.ecma-international.org/publications/files/drafts/
-
- // Previous ES5 Draft
- // http://www.ecma-international.org/publications/files/drafts/tc39-2009-025.pdf
- // This is a broken link to the previous draft of ES5 on which most of the
- // numbered specification references and quotes herein were taken. Updating
- // these references and quotes to reflect the new document would be a welcome
- // volunteer project.
-
- //
- // Array
- // =====
- //
-
- // ES5 15.4.3.2
- if (!Array.isArray) {
- Array.isArray = function(obj) {
- return Object.prototype.toString.call(obj) == "[object Array]";
- };
- }
-
- // ES5 15.4.4.18
- if (!Array.prototype.forEach) {
- Array.prototype.forEach = function(block, thisObject) {
- var len = this.length >>> 0;
- for (var i = 0; i < len; i++) {
- if (i in this) {
- block.call(thisObject, this[i], i, this);
- }
- }
- };
- }
-
- // ES5 15.4.4.19
- // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map
- if (!Array.prototype.map) {
- Array.prototype.map = function(fun /*, thisp*/) {
- var len = this.length >>> 0;
- if (typeof fun != "function")
- throw new TypeError();
-
- var res = new Array(len);
- var thisp = arguments[1];
- for (var i = 0; i < len; i++) {
- if (i in this)
- res[i] = fun.call(thisp, this[i], i, this);
- }
-
- return res;
- };
- }
-
- // ES5 15.4.4.20
- if (!Array.prototype.filter) {
- Array.prototype.filter = function (block /*, thisp */) {
- var values = [];
- var thisp = arguments[1];
- for (var i = 0; i < this.length; i++)
- if (block.call(thisp, this[i]))
- values.push(this[i]);
- return values;
- };
- }
-
- // ES5 15.4.4.16
- if (!Array.prototype.every) {
- Array.prototype.every = function (block /*, thisp */) {
- var thisp = arguments[1];
- for (var i = 0; i < this.length; i++)
- if (!block.call(thisp, this[i]))
- return false;
- return true;
- };
- }
-
- // ES5 15.4.4.17
- if (!Array.prototype.some) {
- Array.prototype.some = function (block /*, thisp */) {
- var thisp = arguments[1];
- for (var i = 0; i < this.length; i++)
- if (block.call(thisp, this[i]))
- return true;
- return false;
- };
- }
-
- // ES5 15.4.4.21
- // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduce
- if (!Array.prototype.reduce) {
- Array.prototype.reduce = function(fun /*, initial*/) {
- var len = this.length >>> 0;
- if (typeof fun != "function")
- throw new TypeError();
-
- // no value to return if no initial value and an empty array
- if (len == 0 && arguments.length == 1)
- throw new TypeError();
-
- var i = 0;
- if (arguments.length >= 2) {
- var rv = arguments[1];
- } else {
- do {
- if (i in this) {
- rv = this[i++];
- break;
- }
-
- // if array contains no values, no initial value to return
- if (++i >= len)
- throw new TypeError();
- } while (true);
- }
-
- for (; i < len; i++) {
- if (i in this)
- rv = fun.call(null, rv, this[i], i, this);
- }
-
- return rv;
- };
- }
-
- // ES5 15.4.4.22
- // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduceRight
- if (!Array.prototype.reduceRight) {
- Array.prototype.reduceRight = function(fun /*, initial*/) {
- var len = this.length >>> 0;
- if (typeof fun != "function")
- throw new TypeError();
-
- // no value to return if no initial value, empty array
- if (len == 0 && arguments.length == 1)
- throw new TypeError();
-
- var i = len - 1;
- if (arguments.length >= 2) {
- var rv = arguments[1];
- } else {
- do {
- if (i in this) {
- rv = this[i--];
- break;
- }
-
- // if array contains no values, no initial value to return
- if (--i < 0)
- throw new TypeError();
- } while (true);
- }
-
- for (; i >= 0; i--) {
- if (i in this)
- rv = fun.call(null, rv, this[i], i, this);
- }
-
- return rv;
- };
- }
-
- // ES5 15.4.4.14
- if (!Array.prototype.indexOf) {
- Array.prototype.indexOf = function (value /*, fromIndex */ ) {
- var length = this.length;
- if (!length)
- return -1;
- var i = arguments[1] || 0;
- if (i >= length)
- return -1;
- if (i < 0)
- i += length;
- for (; i < length; i++) {
- if (!Object.prototype.hasOwnProperty.call(this, i))
- continue;
- if (value === this[i])
- return i;
- }
- return -1;
- };
- }
-
- // ES5 15.4.4.15
- if (!Array.prototype.lastIndexOf) {
- Array.prototype.lastIndexOf = function (value /*, fromIndex */) {
- var length = this.length;
- if (!length)
- return -1;
- var i = arguments[1] || length;
- if (i < 0)
- i += length;
- i = Math.min(i, length - 1);
- for (; i >= 0; i--) {
- if (!Object.prototype.hasOwnProperty.call(this, i))
- continue;
- if (value === this[i])
- return i;
- }
- return -1;
- };
- }
-
- //
- // Object
- // ======
- //
-
- // ES5 15.2.3.2
- if (!Object.getPrototypeOf) {
- Object.getPrototypeOf = function (object) {
- return object.__proto__;
- // or undefined if not available in this engine
- };
- }
-
- // ES5 15.2.3.3
- if (!Object.getOwnPropertyDescriptor) {
- Object.getOwnPropertyDescriptor = function (object) {
- return {}; // XXX
- };
- }
-
- // ES5 15.2.3.4
- if (!Object.getOwnPropertyNames) {
- Object.getOwnPropertyNames = function (object) {
- return Object.keys(object);
- };
- }
-
- // ES5 15.2.3.5
- if (!Object.create) {
- Object.create = function(prototype, properties) {
- if (typeof prototype != "object" || prototype === null)
- throw new TypeError("typeof prototype["+(typeof prototype)+"] != 'object'");
- function Type() {};
- Type.prototype = prototype;
- var object = new Type();
- if (typeof properties !== "undefined")
- Object.defineProperties(object, properties);
- return object;
- };
- }
-
- // ES5 15.2.3.6
- if (!Object.defineProperty) {
- Object.defineProperty = function(object, property, descriptor) {
- var has = Object.prototype.hasOwnProperty;
- if (typeof descriptor == "object" && object.__defineGetter__) {
- if (has.call(descriptor, "value")) {
- if (!object.__lookupGetter__(property) && !object.__lookupSetter__(property))
- // data property defined and no pre-existing accessors
- object[property] = descriptor.value;
- if (has.call(descriptor, "get") || has.call(descriptor, "set"))
- // descriptor has a value property but accessor already exists
- throw new TypeError("Object doesn't support this action");
- }
- // fail silently if "writable", "enumerable", or "configurable"
- // are requested but not supported
- /*
- // alternate approach:
- if ( // can't implement these features; allow false but not true
- !(has.call(descriptor, "writable") ? descriptor.writable : true) ||
- !(has.call(descriptor, "enumerable") ? descriptor.enumerable : true) ||
- !(has.call(descriptor, "configurable") ? descriptor.configurable : true)
- )
- throw new RangeError(
- "This implementation of Object.defineProperty does not " +
- "support configurable, enumerable, or writable."
- );
- */
- else if (typeof descriptor.get == "function")
- object.__defineGetter__(property, descriptor.get);
- if (typeof descriptor.set == "function")
- object.__defineSetter__(property, descriptor.set);
- }
- return object;
- };
- }
-
- // ES5 15.2.3.7
- if (!Object.defineProperties) {
- Object.defineProperties = function(object, properties) {
- for (var property in properties) {
- if (Object.prototype.hasOwnProperty.call(properties, property))
- Object.defineProperty(object, property, properties[property]);
- }
- return object;
- };
- }
-
- // ES5 15.2.3.8
- if (!Object.seal) {
- Object.seal = function (object) {
- return object;
- };
- }
-
- // ES5 15.2.3.9
- if (!Object.freeze) {
- Object.freeze = function (object) {
- return object;
- };
- }
-
- // ES5 15.2.3.10
- if (!Object.preventExtensions) {
- Object.preventExtensions = function (object) {
- return object;
- };
- }
-
- // ES5 15.2.3.11
- if (!Object.isSealed) {
- Object.isSealed = function (object) {
- return false;
- };
- }
-
- // ES5 15.2.3.12
- if (!Object.isFrozen) {
- Object.isFrozen = function (object) {
- return false;
- };
- }
-
- // ES5 15.2.3.13
- if (!Object.isExtensible) {
- Object.isExtensible = function (object) {
- return true;
- };
- }
-
- // ES5 15.2.3.14
- if (!Object.keys) {
- Object.keys = function (object) {
- var keys = [];
- for (var name in object) {
- if (Object.prototype.hasOwnProperty.call(object, name)) {
- keys.push(name);
- }
- }
- return keys;
- };
- }
-
- //
- // Date
- // ====
- //
-
- // ES5 15.9.5.43
- // Format a Date object as a string according to a subset of the ISO-8601 standard.
- // Useful in Atom, among other things.
- if (!Date.prototype.toISOString) {
- Date.prototype.toISOString = function() {
- return (
- this.getFullYear() + "-" +
- (this.getMonth() + 1) + "-" +
- this.getDate() + "T" +
- this.getHours() + ":" +
- this.getMinutes() + ":" +
- this.getSeconds() + "Z"
- );
- }
- }
-
- // ES5 15.9.4.4
- if (!Date.now) {
- Date.now = function () {
- return new Date().getTime();
- };
- }
-
- // ES5 15.9.5.44
- if (!Date.prototype.toJSON) {
- Date.prototype.toJSON = function (key) {
- // This function provides a String representation of a Date object for
- // use by JSON.stringify (15.12.3). When the toJSON method is called
- // with argument key, the following steps are taken:
-
- // 1. Let O be the result of calling ToObject, giving it the this
- // value as its argument.
- // 2. Let tv be ToPrimitive(O, hint Number).
- // 3. If tv is a Number and is not finite, return null.
- // XXX
- // 4. Let toISO be the result of calling the [[Get]] internal method of
- // O with argument "toISOString".
- // 5. If IsCallable(toISO) is false, throw a TypeError exception.
- if (typeof this.toISOString != "function")
- throw new TypeError();
- // 6. Return the result of calling the [[Call]] internal method of
- // toISO with O as the this value and an empty argument list.
- return this.toISOString();
-
- // NOTE 1 The argument is ignored.
-
- // NOTE 2 The toJSON function is intentionally generic; it does not
- // require that its this value be a Date object. Therefore, it can be
- // transferred to other kinds of objects for use as a method. However,
- // it does require that any such object have a toISOString method. An
- // object is free to use the argument key to filter its
- // stringification.
- };
- }
-
- //
- // Function
- // ========
- //
-
- // ES-5 15.3.4.5
- // http://www.ecma-international.org/publications/files/drafts/tc39-2009-025.pdf
- var slice = Array.prototype.slice;
- if (!Function.prototype.bind) {
- Function.prototype.bind = function (that) { // .length is 1
- // 1. Let Target be the this value.
- var target = this;
- // 2. If IsCallable(Target) is false, throw a TypeError exception.
- // XXX this gets pretty close, for all intents and purposes, letting
- // some duck-types slide
- if (typeof target.apply != "function" || typeof target.call != "function")
- return new TypeError();
- // 3. Let A be a new (possibly empty) internal list of all of the
- // argument values provided after thisArg (arg1, arg2 etc), in order.
- var args = slice.call(arguments);
- // 4. Let F be a new native ECMAScript object.
- // 9. Set the [[Prototype]] internal property of F to the standard
- // built-in Function prototype object as specified in 15.3.3.1.
- // 10. Set the [[Call]] internal property of F as described in
- // 15.3.4.5.1.
- // 11. Set the [[Construct]] internal property of F as described in
- // 15.3.4.5.2.
- // 12. Set the [[HasInstance]] internal property of F as described in
- // 15.3.4.5.3.
- // 13. The [[Scope]] internal property of F is unused and need not
- // exist.
- var bound = function () {
-
- if (this instanceof bound) {
- // 15.3.4.5.2 [[Construct]]
- // When the [[Construct]] internal method of a function object,
- // F that was created using the bind function is called with a
- // list of arguments ExtraArgs the following steps are taken:
- // 1. Let target be the value of F's [[TargetFunction]]
- // internal property.
- // 2. If target has no [[Construct]] internal method, a
- // TypeError exception is thrown.
- // 3. Let boundArgs be the value of F's [[BoundArgs]] internal
- // property.
- // 4. Let args be a new list containing the same values as the
- // list boundArgs in the same order followed by the same
- // values as the list ExtraArgs in the same order.
-
- var self = Object.create(target.prototype);
- target.apply(self, args.concat(slice.call(arguments)));
- return self;
-
- } else {
- // 15.3.4.5.1 [[Call]]
- // When the [[Call]] internal method of a function object, F,
- // which was created using the bind function is called with a
- // this value and a list of arguments ExtraArgs the following
- // steps are taken:
- // 1. Let boundArgs be the value of F's [[BoundArgs]] internal
- // property.
- // 2. Let boundThis be the value of F's [[BoundThis]] internal
- // property.
- // 3. Let target be the value of F's [[TargetFunction]] internal
- // property.
- // 4. Let args be a new list containing the same values as the list
- // boundArgs in the same order followed by the same values as
- // the list ExtraArgs in the same order. 5. Return the
- // result of calling the [[Call]] internal method of target
- // providing boundThis as the this value and providing args
- // as the arguments.
-
- // equiv: target.call(this, ...boundArgs, ...args)
- return target.call.apply(
- target,
- args.concat(slice.call(arguments))
- );
-
- }
-
- };
- // 5. Set the [[TargetFunction]] internal property of F to Target.
- // extra:
- bound.bound = target;
- // 6. Set the [[BoundThis]] internal property of F to the value of
- // thisArg.
- // extra:
- bound.boundTo = that;
- // 7. Set the [[BoundArgs]] internal property of F to A.
- // extra:
- bound.boundArgs = args;
- bound.length = (
- // 14. If the [[Class]] internal property of Target is "Function", then
- typeof target == "function" ?
- // a. Let L be the length property of Target minus the length of A.
- // b. Set the length own property of F to either 0 or L, whichever is larger.
- Math.max(target.length - args.length, 0) :
- // 15. Else set the length own property of F to 0.
- 0
- )
- // 16. The length own property of F is given attributes as specified in
- // 15.3.5.1.
- // TODO
- // 17. Set the [[Extensible]] internal property of F to true.
- // TODO
- // 18. Call the [[DefineOwnProperty]] internal method of F with
- // arguments "caller", PropertyDescriptor {[[Value]]: null,
- // [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]:
- // false}, and false.
- // TODO
- // 19. Call the [[DefineOwnProperty]] internal method of F with
- // arguments "arguments", PropertyDescriptor {[[Value]]: null,
- // [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]:
- // false}, and false.
- // TODO
- // NOTE Function objects created using Function.prototype.bind do not
- // have a prototype property.
- // XXX can't delete it in pure-js.
- return bound;
- };
- }
-
- //
- // String
- // ======
- //
-
- // ES5 15.5.4.20
- if (!String.prototype.trim) {
- // http://blog.stevenlevithan.com/archives/faster-trim-javascript
- var trimBeginRegexp = /^\s\s*/;
- var trimEndRegexp = /\s\s*$/;
- String.prototype.trim = function () {
- return String(this).replace(trimBeginRegexp, '').replace(trimEndRegexp, '');
- };
- }