PageRenderTime 167ms CodeModel.GetById 71ms app.highlight 37ms RepoModel.GetById 53ms app.codeStats 0ms

/wwwroot/demo/js/global-es5.js

http://github.com/AF83/ucengine
JavaScript | 553 lines | 304 code | 59 blank | 190 comment | 110 complexity | f9ef266cf67fc65d54f561451e1380e9 MD5 | raw file
  1
  2/*!
  3    Copyright (c) 2009, 280 North Inc. http://280north.com/
  4    MIT License. http://github.com/280north/narwhal/blob/master/README.md
  5*/
  6
  7// Brings an environment as close to ECMAScript 5 compliance
  8// as is possible with the facilities of erstwhile engines.
  9
 10// ES5 Draft
 11// http://www.ecma-international.org/publications/files/drafts/tc39-2009-050.pdf
 12
 13// NOTE: this is a draft, and as such, the URL is subject to change.  If the
 14// link is broken, check in the parent directory for the latest TC39 PDF.
 15// http://www.ecma-international.org/publications/files/drafts/
 16
 17// Previous ES5 Draft
 18// http://www.ecma-international.org/publications/files/drafts/tc39-2009-025.pdf
 19// This is a broken link to the previous draft of ES5 on which most of the
 20// numbered specification references and quotes herein were taken.  Updating
 21// these references and quotes to reflect the new document would be a welcome
 22// volunteer project.
 23
 24//
 25// Array
 26// =====
 27//
 28
 29// ES5 15.4.3.2 
 30if (!Array.isArray) {
 31    Array.isArray = function(obj) {
 32        return Object.prototype.toString.call(obj) == "[object Array]";
 33    };
 34}
 35
 36// ES5 15.4.4.18
 37if (!Array.prototype.forEach) {
 38    Array.prototype.forEach =  function(block, thisObject) {
 39        var len = this.length >>> 0;
 40        for (var i = 0; i < len; i++) {
 41            if (i in this) {
 42                block.call(thisObject, this[i], i, this);
 43            }
 44        }
 45    };
 46}
 47
 48// ES5 15.4.4.19
 49// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map
 50if (!Array.prototype.map) {
 51    Array.prototype.map = function(fun /*, thisp*/) {
 52        var len = this.length >>> 0;
 53        if (typeof fun != "function")
 54          throw new TypeError();
 55
 56        var res = new Array(len);
 57        var thisp = arguments[1];
 58        for (var i = 0; i < len; i++) {
 59            if (i in this)
 60                res[i] = fun.call(thisp, this[i], i, this);
 61        }
 62
 63        return res;
 64    };
 65}
 66
 67// ES5 15.4.4.20
 68if (!Array.prototype.filter) {
 69    Array.prototype.filter = function (block /*, thisp */) {
 70        var values = [];
 71        var thisp = arguments[1];
 72        for (var i = 0; i < this.length; i++)
 73            if (block.call(thisp, this[i]))
 74                values.push(this[i]);
 75        return values;
 76    };
 77}
 78
 79// ES5 15.4.4.16
 80if (!Array.prototype.every) {
 81    Array.prototype.every = function (block /*, thisp */) {
 82        var thisp = arguments[1];
 83        for (var i = 0; i < this.length; i++)
 84            if (!block.call(thisp, this[i]))
 85                return false;
 86        return true;
 87    };
 88}
 89
 90// ES5 15.4.4.17
 91if (!Array.prototype.some) {
 92    Array.prototype.some = function (block /*, thisp */) {
 93        var thisp = arguments[1];
 94        for (var i = 0; i < this.length; i++)
 95            if (block.call(thisp, this[i]))
 96                return true;
 97        return false;
 98    };
 99}
100
101// ES5 15.4.4.21
102// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduce
103if (!Array.prototype.reduce) {
104    Array.prototype.reduce = function(fun /*, initial*/) {
105        var len = this.length >>> 0;
106        if (typeof fun != "function")
107            throw new TypeError();
108
109        // no value to return if no initial value and an empty array
110        if (len == 0 && arguments.length == 1)
111            throw new TypeError();
112
113        var i = 0;
114        if (arguments.length >= 2) {
115            var rv = arguments[1];
116        } else {
117            do {
118                if (i in this) {
119                    rv = this[i++];
120                    break;
121                }
122
123                // if array contains no values, no initial value to return
124                if (++i >= len)
125                    throw new TypeError();
126            } while (true);
127        }
128
129        for (; i < len; i++) {
130            if (i in this)
131                rv = fun.call(null, rv, this[i], i, this);
132        }
133
134        return rv;
135    };
136}
137
138// ES5 15.4.4.22
139// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduceRight
140if (!Array.prototype.reduceRight) {
141    Array.prototype.reduceRight = function(fun /*, initial*/) {
142        var len = this.length >>> 0;
143        if (typeof fun != "function")
144            throw new TypeError();
145
146        // no value to return if no initial value, empty array
147        if (len == 0 && arguments.length == 1)
148            throw new TypeError();
149
150        var i = len - 1;
151        if (arguments.length >= 2) {
152            var rv = arguments[1];
153        } else {
154            do {
155                if (i in this) {
156                    rv = this[i--];
157                    break;
158                }
159
160                // if array contains no values, no initial value to return
161                if (--i < 0)
162                    throw new TypeError();
163            } while (true);
164        }
165
166        for (; i >= 0; i--) {
167            if (i in this)
168                rv = fun.call(null, rv, this[i], i, this);
169        }
170
171        return rv;
172    };
173}
174
175// ES5 15.4.4.14
176if (!Array.prototype.indexOf) {
177    Array.prototype.indexOf = function (value /*, fromIndex */ ) {
178        var length = this.length;
179        if (!length)
180            return -1;
181        var i = arguments[1] || 0;
182        if (i >= length)
183            return -1;
184        if (i < 0)
185            i += length;
186        for (; i < length; i++) {
187            if (!Object.prototype.hasOwnProperty.call(this, i))
188                continue;
189            if (value === this[i])
190                return i;
191        }
192        return -1;
193    };
194}
195
196// ES5 15.4.4.15
197if (!Array.prototype.lastIndexOf) {
198    Array.prototype.lastIndexOf = function (value /*, fromIndex */) {
199        var length = this.length;
200        if (!length)
201            return -1;
202        var i = arguments[1] || length;
203        if (i < 0)
204            i += length;
205        i = Math.min(i, length - 1);
206        for (; i >= 0; i--) {
207            if (!Object.prototype.hasOwnProperty.call(this, i))
208                continue;
209            if (value === this[i])
210                return i;
211        }
212        return -1;
213    };
214}
215
216//
217// Object
218// ======
219// 
220
221// ES5 15.2.3.2
222if (!Object.getPrototypeOf) {
223    Object.getPrototypeOf = function (object) {
224        return object.__proto__;
225        // or undefined if not available in this engine
226    };
227}
228
229// ES5 15.2.3.3
230if (!Object.getOwnPropertyDescriptor) {
231    Object.getOwnPropertyDescriptor = function (object) {
232        return {}; // XXX
233    };
234}
235
236// ES5 15.2.3.4
237if (!Object.getOwnPropertyNames) {
238    Object.getOwnPropertyNames = function (object) {
239        return Object.keys(object);
240    };
241}
242
243// ES5 15.2.3.5 
244if (!Object.create) {
245    Object.create = function(prototype, properties) {
246        if (typeof prototype != "object" || prototype === null)
247            throw new TypeError("typeof prototype["+(typeof prototype)+"] != 'object'");
248        function Type() {};
249        Type.prototype = prototype;
250        var object = new Type();
251        if (typeof properties !== "undefined")
252            Object.defineProperties(object, properties);
253        return object;
254    };
255}
256
257// ES5 15.2.3.6
258if (!Object.defineProperty) {
259    Object.defineProperty = function(object, property, descriptor) {
260        var has = Object.prototype.hasOwnProperty;
261        if (typeof descriptor == "object" && object.__defineGetter__) {
262            if (has.call(descriptor, "value")) {
263                if (!object.__lookupGetter__(property) && !object.__lookupSetter__(property))
264                    // data property defined and no pre-existing accessors
265                    object[property] = descriptor.value;
266                if (has.call(descriptor, "get") || has.call(descriptor, "set"))
267                    // descriptor has a value property but accessor already exists
268                    throw new TypeError("Object doesn't support this action");
269            }
270            // fail silently if "writable", "enumerable", or "configurable"
271            // are requested but not supported
272            /*
273            // alternate approach:
274            if ( // can't implement these features; allow false but not true
275                !(has.call(descriptor, "writable") ? descriptor.writable : true) ||
276                !(has.call(descriptor, "enumerable") ? descriptor.enumerable : true) ||
277                !(has.call(descriptor, "configurable") ? descriptor.configurable : true)
278            )
279                throw new RangeError(
280                    "This implementation of Object.defineProperty does not " +
281                    "support configurable, enumerable, or writable."
282                );
283            */
284            else if (typeof descriptor.get == "function")
285                object.__defineGetter__(property, descriptor.get);
286            if (typeof descriptor.set == "function")
287                object.__defineSetter__(property, descriptor.set);
288        }
289        return object;
290    };
291}
292
293// ES5 15.2.3.7
294if (!Object.defineProperties) {
295    Object.defineProperties = function(object, properties) {
296        for (var property in properties) {
297            if (Object.prototype.hasOwnProperty.call(properties, property))
298                Object.defineProperty(object, property, properties[property]);
299        }
300        return object;
301    };
302}
303
304// ES5 15.2.3.8
305if (!Object.seal) {
306    Object.seal = function (object) {
307        return object;
308    };
309}
310
311// ES5 15.2.3.9
312if (!Object.freeze) {
313    Object.freeze = function (object) {
314        return object;
315    };
316}
317
318// ES5 15.2.3.10
319if (!Object.preventExtensions) {
320    Object.preventExtensions = function (object) {
321        return object;
322    };
323}
324
325// ES5 15.2.3.11
326if (!Object.isSealed) {
327    Object.isSealed = function (object) {
328        return false;
329    };
330}
331
332// ES5 15.2.3.12
333if (!Object.isFrozen) {
334    Object.isFrozen = function (object) {
335        return false;
336    };
337}
338
339// ES5 15.2.3.13
340if (!Object.isExtensible) {
341    Object.isExtensible = function (object) {
342        return true;
343    };
344}
345
346// ES5 15.2.3.14
347if (!Object.keys) {
348    Object.keys = function (object) {
349        var keys = [];
350        for (var name in object) {
351            if (Object.prototype.hasOwnProperty.call(object, name)) {
352                keys.push(name);
353            }
354        }
355        return keys;
356    };
357}
358
359//
360// Date
361// ====
362//
363
364// ES5 15.9.5.43
365// Format a Date object as a string according to a subset of the ISO-8601 standard.
366// Useful in Atom, among other things.
367if (!Date.prototype.toISOString) {
368    Date.prototype.toISOString = function() {
369        return (
370            this.getFullYear() + "-" +
371            (this.getMonth() + 1) + "-" +
372            this.getDate() + "T" +
373            this.getHours() + ":" +
374            this.getMinutes() + ":" +
375            this.getSeconds() + "Z"
376        ); 
377    }
378}
379
380// ES5 15.9.4.4
381if (!Date.now) {
382    Date.now = function () {
383        return new Date().getTime();
384    };
385}
386
387// ES5 15.9.5.44
388if (!Date.prototype.toJSON) {
389    Date.prototype.toJSON = function (key) {
390        // This function provides a String representation of a Date object for
391        // use by JSON.stringify (15.12.3). When the toJSON method is called
392        // with argument key, the following steps are taken:
393
394        // 1.  Let O be the result of calling ToObject, giving it the this
395        // value as its argument.
396        // 2. Let tv be ToPrimitive(O, hint Number).
397        // 3. If tv is a Number and is not finite, return null.
398        // XXX
399        // 4. Let toISO be the result of calling the [[Get]] internal method of
400        // O with argument "toISOString".
401        // 5. If IsCallable(toISO) is false, throw a TypeError exception.
402        if (typeof this.toISOString != "function")
403            throw new TypeError();
404        // 6. Return the result of calling the [[Call]] internal method of
405        // toISO with O as the this value and an empty argument list.
406        return this.toISOString();
407
408        // NOTE 1 The argument is ignored.
409
410        // NOTE 2 The toJSON function is intentionally generic; it does not
411        // require that its this value be a Date object. Therefore, it can be
412        // transferred to other kinds of objects for use as a method. However,
413        // it does require that any such object have a toISOString method. An
414        // object is free to use the argument key to filter its
415        // stringification.
416    };
417}
418
419// 
420// Function
421// ========
422// 
423
424// ES-5 15.3.4.5
425// http://www.ecma-international.org/publications/files/drafts/tc39-2009-025.pdf
426var slice = Array.prototype.slice;
427if (!Function.prototype.bind) {
428    Function.prototype.bind = function (that) { // .length is 1
429        // 1. Let Target be the this value.
430        var target = this;
431        // 2. If IsCallable(Target) is false, throw a TypeError exception.
432        // XXX this gets pretty close, for all intents and purposes, letting 
433        // some duck-types slide
434        if (typeof target.apply != "function" || typeof target.call != "function")
435            return new TypeError();
436        // 3. Let A be a new (possibly empty) internal list of all of the
437        //   argument values provided after thisArg (arg1, arg2 etc), in order.
438        var args = slice.call(arguments);
439        // 4. Let F be a new native ECMAScript object.
440        // 9. Set the [[Prototype]] internal property of F to the standard
441        //   built-in Function prototype object as specified in 15.3.3.1.
442        // 10. Set the [[Call]] internal property of F as described in
443        //   15.3.4.5.1.
444        // 11. Set the [[Construct]] internal property of F as described in
445        //   15.3.4.5.2.
446        // 12. Set the [[HasInstance]] internal property of F as described in
447        //   15.3.4.5.3.
448        // 13. The [[Scope]] internal property of F is unused and need not
449        //   exist.
450        var bound = function () {
451
452            if (this instanceof bound) {
453                // 15.3.4.5.2 [[Construct]]
454                // When the [[Construct]] internal method of a function object,
455                // F that was created using the bind function is called with a
456                // list of arguments ExtraArgs the following steps are taken:
457                // 1. Let target be the value of F's [[TargetFunction]]
458                //   internal property.
459                // 2. If target has no [[Construct]] internal method, a
460                //   TypeError exception is thrown.
461                // 3. Let boundArgs be the value of F's [[BoundArgs]] internal
462                //   property.
463                // 4. Let args be a new list containing the same values as the
464                //   list boundArgs in the same order followed by the same
465                //   values as the list ExtraArgs in the same order.
466
467                var self = Object.create(target.prototype);
468                target.apply(self, args.concat(slice.call(arguments)));
469                return self;
470
471            } else {
472                // 15.3.4.5.1 [[Call]]
473                // When the [[Call]] internal method of a function object, F,
474                // which was created using the bind function is called with a
475                // this value and a list of arguments ExtraArgs the following
476                // steps are taken:
477                // 1. Let boundArgs be the value of F's [[BoundArgs]] internal
478                //   property.
479                // 2. Let boundThis be the value of F's [[BoundThis]] internal
480                //   property.
481                // 3. Let target be the value of F's [[TargetFunction]] internal
482                //   property.
483                // 4. Let args be a new list containing the same values as the list
484                //   boundArgs in the same order followed by the same values as
485                //   the list ExtraArgs in the same order. 5.  Return the
486                //   result of calling the [[Call]] internal method of target
487                //   providing boundThis as the this value and providing args
488                //   as the arguments.
489
490                // equiv: target.call(this, ...boundArgs, ...args)
491                return target.call.apply(
492                    target,
493                    args.concat(slice.call(arguments))
494                );
495
496            }
497
498        };
499        // 5. Set the [[TargetFunction]] internal property of F to Target.
500        // extra:
501        bound.bound = target;
502        // 6. Set the [[BoundThis]] internal property of F to the value of
503        // thisArg.
504        // extra:
505        bound.boundTo = that;
506        // 7. Set the [[BoundArgs]] internal property of F to A.
507        // extra:
508        bound.boundArgs = args;
509        bound.length = (
510            // 14. If the [[Class]] internal property of Target is "Function", then
511            typeof target == "function" ?
512            // a. Let L be the length property of Target minus the length of A.
513            // b. Set the length own property of F to either 0 or L, whichever is larger.
514            Math.max(target.length - args.length, 0) :
515            // 15. Else set the length own property of F to 0.
516            0
517        )
518        // 16. The length own property of F is given attributes as specified in
519        //   15.3.5.1.
520        // TODO
521        // 17. Set the [[Extensible]] internal property of F to true.
522        // TODO
523        // 18. Call the [[DefineOwnProperty]] internal method of F with
524        //   arguments "caller", PropertyDescriptor {[[Value]]: null,
525        //   [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]:
526        //   false}, and false.
527        // TODO
528        // 19. Call the [[DefineOwnProperty]] internal method of F with
529        //   arguments "arguments", PropertyDescriptor {[[Value]]: null,
530        //   [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]:
531        //   false}, and false.
532        // TODO
533        // NOTE Function objects created using Function.prototype.bind do not
534        // have a prototype property.
535        // XXX can't delete it in pure-js.
536        return bound;
537    };
538}
539
540//
541// String
542// ======
543//
544
545// ES5 15.5.4.20
546if (!String.prototype.trim) {
547    // http://blog.stevenlevithan.com/archives/faster-trim-javascript
548    var trimBeginRegexp = /^\s\s*/;
549    var trimEndRegexp = /\s\s*$/;
550    String.prototype.trim = function () {
551        return String(this).replace(trimBeginRegexp, '').replace(trimEndRegexp, '');
552    };
553}