1 // Copyright 2009-2012 by contributors, MIT License
2 // vim: ts=4 sts=4 sw=4 expandtab
4 // Module systems magic dance
5 (function (definition) {
7 if (typeof define == "function") {
10 } else if (typeof YUI == "function") {
11 YUI.add("es5", definition);
12 // CommonJS and <script>
19 * Brings an environment as close to ECMAScript 5 compliance
20 * as is possible with the facilities of erstwhile engines.
22 * Annotated ES5: http://es5.github.com/ (specific links below)
23 * ES5 Spec: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
24 * Required reading: http://javascriptweblog.wordpress.com/2011/12/05/extending-javascript-natives/
33 // http://es5.github.com/#x15.3.4.5
35 if (!Function.prototype.bind) {
36 Function.prototype.bind = function bind(that) { // .length is 1
37 // 1. Let Target be the this value.
39 // 2. If IsCallable(Target) is false, throw a TypeError exception.
40 if (typeof target != "function") {
41 throw new TypeError("Function.prototype.bind called on incompatible " + target);
43 // 3. Let A be a new (possibly empty) internal list of all of the
44 // argument values provided after thisArg (arg1, arg2 etc), in order.
45 // XXX slicedArgs will stand in for "A" if used
46 var args = slice.call(arguments, 1); // for normal call
47 // 4. Let F be a new native ECMAScript object.
48 // 11. Set the [[Prototype]] internal property of F to the standard
49 // built-in Function prototype object as specified in 15.3.3.1.
50 // 12. Set the [[Call]] internal property of F as described in
52 // 13. Set the [[Construct]] internal property of F as described in
54 // 14. Set the [[HasInstance]] internal property of F as described in
56 var bound = function () {
58 if (this instanceof bound) {
59 // 15.3.4.5.2 [[Construct]]
60 // When the [[Construct]] internal method of a function object,
61 // F that was created using the bind function is called with a
62 // list of arguments ExtraArgs, the following steps are taken:
63 // 1. Let target be the value of F's [[TargetFunction]]
65 // 2. If target has no [[Construct]] internal method, a
66 // TypeError exception is thrown.
67 // 3. Let boundArgs be the value of F's [[BoundArgs]] internal
69 // 4. Let args be a new list containing the same values as the
70 // list boundArgs in the same order followed by the same
71 // values as the list ExtraArgs in the same order.
72 // 5. Return the result of calling the [[Construct]] internal
73 // method of target providing args as the arguments.
76 F.prototype = target.prototype;
79 var result = target.apply(
81 args.concat(slice.call(arguments))
83 if (Object(result) === result) {
89 // 15.3.4.5.1 [[Call]]
90 // When the [[Call]] internal method of a function object, F,
91 // which was created using the bind function is called with a
92 // this value and a list of arguments ExtraArgs, the following
94 // 1. Let boundArgs be the value of F's [[BoundArgs]] internal
96 // 2. Let boundThis be the value of F's [[BoundThis]] internal
98 // 3. Let target be the value of F's [[TargetFunction]] internal
100 // 4. Let args be a new list containing the same values as the
101 // list boundArgs in the same order followed by the same
102 // values as the list ExtraArgs in the same order.
103 // 5. Return the result of calling the [[Call]] internal method
104 // of target providing boundThis as the this value and
105 // providing args as the arguments.
107 // equiv: target.call(this, ...boundArgs, ...args)
110 args.concat(slice.call(arguments))
116 // XXX bound.length is never writable, so don't even try
118 // 15. If the [[Class]] internal property of Target is "Function", then
119 // a. Let L be the length property of Target minus the length of A.
120 // b. Set the length own property of F to either 0 or L, whichever is
122 // 16. Else set the length own property of F to 0.
123 // 17. Set the attributes of the length own property of F to the values
124 // specified in 15.3.5.1.
127 // 18. Set the [[Extensible]] internal property of F to true.
130 // 19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3).
131 // 20. Call the [[DefineOwnProperty]] internal method of F with
132 // arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]:
133 // thrower, [[Enumerable]]: false, [[Configurable]]: false}, and
135 // 21. Call the [[DefineOwnProperty]] internal method of F with
136 // arguments "arguments", PropertyDescriptor {[[Get]]: thrower,
137 // [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false},
141 // NOTE Function objects created using Function.prototype.bind do not
142 // have a prototype property or the [[Code]], [[FormalParameters]], and
143 // [[Scope]] internal properties.
144 // XXX can't delete prototype in pure-js.
151 // Shortcut to an often accessed properties, in order to avoid multiple
152 // dereference that costs universally.
153 // _Please note: Shortcuts are defined after `Function.prototype.bind` as we
154 // us it in defining shortcuts.
155 var call = Function.prototype.call;
156 var prototypeOfArray = Array.prototype;
157 var prototypeOfObject = Object.prototype;
158 var slice = prototypeOfArray.slice;
159 // Having a toString local variable name breaks in Opera so use _toString.
160 var _toString = call.bind(prototypeOfObject.toString);
161 var owns = call.bind(prototypeOfObject.hasOwnProperty);
163 // If JS engine supports accessors creating shortcuts.
168 var supportsAccessors;
169 if ((supportsAccessors = owns(prototypeOfObject, "__defineGetter__"))) {
170 defineGetter = call.bind(prototypeOfObject.__defineGetter__);
171 defineSetter = call.bind(prototypeOfObject.__defineSetter__);
172 lookupGetter = call.bind(prototypeOfObject.__lookupGetter__);
173 lookupSetter = call.bind(prototypeOfObject.__lookupSetter__);
182 // http://es5.github.com/#x15.4.3.2
183 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray
184 if (!Array.isArray) {
185 Array.isArray = function isArray(obj) {
186 return _toString(obj) == "[object Array]";
190 // The IsCallable() check in the Array functions
191 // has been replaced with a strict check on the
192 // internal class of the object to trap cases where
193 // the provided function was actually a regular
194 // expression literal, which in V8 and
195 // JavaScriptCore is a typeof "function". Only in
196 // V8 are regular expression literals permitted as
197 // reduce parameters, so it is desirable in the
198 // general case for the shim to match the more
199 // strict and common behavior of rejecting regular
203 // http://es5.github.com/#x15.4.4.18
204 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/forEach
205 if (!Array.prototype.forEach) {
206 Array.prototype.forEach = function forEach(fun /*, thisp*/) {
207 var self = toObject(this),
208 thisp = arguments[1],
210 length = self.length >>> 0;
212 // If no callback function or if callback is not a callable function
213 if (_toString(fun) != "[object Function]") {
214 throw new TypeError(); // TODO message
217 while (++i < length) {
219 // Invoke the callback function with call, passing arguments:
220 // context, property value, property key, thisArg object context
221 fun.call(thisp, self[i], i, self);
228 // http://es5.github.com/#x15.4.4.19
229 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map
230 if (!Array.prototype.map) {
231 Array.prototype.map = function map(fun /*, thisp*/) {
232 var self = toObject(this),
233 length = self.length >>> 0,
234 result = Array(length),
235 thisp = arguments[1];
237 // If no callback function or if callback is not a callable function
238 if (_toString(fun) != "[object Function]") {
239 throw new TypeError(fun + " is not a function");
242 for (var i = 0; i < length; i++) {
244 result[i] = fun.call(thisp, self[i], i, self);
251 // http://es5.github.com/#x15.4.4.20
252 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter
253 if (!Array.prototype.filter) {
254 Array.prototype.filter = function filter(fun /*, thisp */) {
255 var self = toObject(this),
256 length = self.length >>> 0,
259 thisp = arguments[1];
261 // If no callback function or if callback is not a callable function
262 if (_toString(fun) != "[object Function]") {
263 throw new TypeError(fun + " is not a function");
266 for (var i = 0; i < length; i++) {
269 if (fun.call(thisp, value, i, self)) {
279 // http://es5.github.com/#x15.4.4.16
280 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/every
281 if (!Array.prototype.every) {
282 Array.prototype.every = function every(fun /*, thisp */) {
283 var self = toObject(this),
284 length = self.length >>> 0,
285 thisp = arguments[1];
287 // If no callback function or if callback is not a callable function
288 if (_toString(fun) != "[object Function]") {
289 throw new TypeError(fun + " is not a function");
292 for (var i = 0; i < length; i++) {
293 if (i in self && !fun.call(thisp, self[i], i, self)) {
302 // http://es5.github.com/#x15.4.4.17
303 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some
304 if (!Array.prototype.some) {
305 Array.prototype.some = function some(fun /*, thisp */) {
306 var self = toObject(this),
307 length = self.length >>> 0,
308 thisp = arguments[1];
310 // If no callback function or if callback is not a callable function
311 if (_toString(fun) != "[object Function]") {
312 throw new TypeError(fun + " is not a function");
315 for (var i = 0; i < length; i++) {
316 if (i in self && fun.call(thisp, self[i], i, self)) {
325 // http://es5.github.com/#x15.4.4.21
326 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduce
327 if (!Array.prototype.reduce) {
328 Array.prototype.reduce = function reduce(fun /*, initial*/) {
329 var self = toObject(this),
330 length = self.length >>> 0;
332 // If no callback function or if callback is not a callable function
333 if (_toString(fun) != "[object Function]") {
334 throw new TypeError(fun + " is not a function");
337 // no value to return if no initial value and an empty array
338 if (!length && arguments.length == 1) {
339 throw new TypeError('reduce of empty array with no initial value');
344 if (arguments.length >= 2) {
345 result = arguments[1];
353 // if array contains no values, no initial value to return
355 throw new TypeError('reduce of empty array with no initial value');
360 for (; i < length; i++) {
362 result = fun.call(void 0, result, self[i], i, self);
371 // http://es5.github.com/#x15.4.4.22
372 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduceRight
373 if (!Array.prototype.reduceRight) {
374 Array.prototype.reduceRight = function reduceRight(fun /*, initial*/) {
375 var self = toObject(this),
376 length = self.length >>> 0;
378 // If no callback function or if callback is not a callable function
379 if (_toString(fun) != "[object Function]") {
380 throw new TypeError(fun + " is not a function");
383 // no value to return if no initial value, empty array
384 if (!length && arguments.length == 1) {
385 throw new TypeError('reduceRight of empty array with no initial value');
388 var result, i = length - 1;
389 if (arguments.length >= 2) {
390 result = arguments[1];
398 // if array contains no values, no initial value to return
400 throw new TypeError('reduceRight of empty array with no initial value');
407 result = fun.call(void 0, result, self[i], i, self);
416 // http://es5.github.com/#x15.4.4.14
417 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
418 if (!Array.prototype.indexOf) {
419 Array.prototype.indexOf = function indexOf(sought /*, fromIndex */ ) {
420 var self = toObject(this),
421 length = self.length >>> 0;
428 if (arguments.length > 1) {
429 i = toInteger(arguments[1]);
432 // handle negative indices
433 i = i >= 0 ? i : Math.max(0, length + i);
434 for (; i < length; i++) {
435 if (i in self && self[i] === sought) {
444 // http://es5.github.com/#x15.4.4.15
445 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/lastIndexOf
446 if (!Array.prototype.lastIndexOf) {
447 Array.prototype.lastIndexOf = function lastIndexOf(sought /*, fromIndex */) {
448 var self = toObject(this),
449 length = self.length >>> 0;
455 if (arguments.length > 1) {
456 i = Math.min(i, toInteger(arguments[1]));
458 // handle negative indices
459 i = i >= 0 ? i : length - Math.abs(i);
460 for (; i >= 0; i--) {
461 if (i in self && sought === self[i]) {
475 // http://es5.github.com/#x15.2.3.14
477 // http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation
478 var hasDontEnumBug = true,
485 "propertyIsEnumerable",
488 dontEnumsLength = dontEnums.length;
490 for (var key in {"toString": null}) {
491 hasDontEnumBug = false;
494 Object.keys = function keys(object) {
496 if ((typeof object != "object" && typeof object != "function") || object === null) {
497 throw new TypeError("Object.keys called on a non-object");
501 for (var name in object) {
502 if (owns(object, name)) {
507 if (hasDontEnumBug) {
508 for (var i = 0, ii = dontEnumsLength; i < ii; i++) {
509 var dontEnum = dontEnums[i];
510 if (owns(object, dontEnum)) {
526 // http://es5.github.com/#x15.9.5.43
527 // This function returns a String value represent the instance in time
528 // represented by this Date object. The format of the String is the Date Time
529 // string format defined in 15.9.1.15. All fields are present in the String.
530 // The time zone is always UTC, denoted by the suffix Z. If the time value of
531 // this object is not a finite Number a RangeError exception is thrown.
532 if (!Date.prototype.toISOString || (new Date(-62198755200000).toISOString().indexOf('-000001') === -1)) {
533 Date.prototype.toISOString = function toISOString() {
534 var result, length, value, year;
535 if (!isFinite(this)) {
536 throw new RangeError("Date.prototype.toISOString called on non-finite value.");
539 // the date time string format is specified in 15.9.1.15.
540 result = [this.getUTCMonth() + 1, this.getUTCDate(),
541 this.getUTCHours(), this.getUTCMinutes(), this.getUTCSeconds()];
542 year = this.getUTCFullYear();
543 year = (year < 0 ? '-' : (year > 9999 ? '+' : '')) + ('00000' + Math.abs(year)).slice(0 <= year && year <= 9999 ? -4 : -6);
545 length = result.length;
547 value = result[length];
548 // pad months, days, hours, minutes, and seconds to have two digits.
550 result[length] = "0" + value;
553 // pad milliseconds to have three digits.
554 return year + "-" + result.slice(0, 2).join("-") + "T" + result.slice(2).join(":") + "." +
555 ("000" + this.getUTCMilliseconds()).slice(-3) + "Z";
560 // http://es5.github.com/#x15.9.4.4
562 Date.now = function now() {
563 return new Date().getTime();
568 // http://es5.github.com/#x15.9.5.44
569 // This function provides a String representation of a Date object for use by
570 // JSON.stringify (15.12.3).
571 if (!Date.prototype.toJSON) {
572 Date.prototype.toJSON = function toJSON(key) {
573 // When the toJSON method is called with argument key, the following
576 // 1. Let O be the result of calling ToObject, giving it the this
577 // value as its argument.
578 // 2. Let tv be ToPrimitive(O, hint Number).
579 // 3. If tv is a Number and is not finite, return null.
581 // 4. Let toISO be the result of calling the [[Get]] internal method of
582 // O with argument "toISOString".
583 // 5. If IsCallable(toISO) is false, throw a TypeError exception.
584 if (typeof this.toISOString != "function") {
585 throw new TypeError('toISOString property is not callable');
587 // 6. Return the result of calling the [[Call]] internal method of
588 // toISO with O as the this value and an empty argument list.
589 return this.toISOString();
591 // NOTE 1 The argument is ignored.
593 // NOTE 2 The toJSON function is intentionally generic; it does not
594 // require that its this value be a Date object. Therefore, it can be
595 // transferred to other kinds of objects for use as a method. However,
596 // it does require that any such object have a toISOString method. An
597 // object is free to use the argument key to filter its
603 // http://es5.github.com/#x15.9.4.2
604 // based on work shared by Daniel Friesen (dantman)
605 // http://gist.github.com/303249
606 if (!Date.parse || Date.parse("+275760-09-13T00:00:00.000Z") !== 8.64e15) {
607 // XXX global assignment won't work in embeddings that use
608 // an alternate object for the context.
609 Date = (function(NativeDate) {
612 var Date = function Date(Y, M, D, h, m, s, ms) {
613 var length = arguments.length;
614 if (this instanceof NativeDate) {
615 var date = length == 1 && String(Y) === Y ? // isString(Y)
616 // We explicitly pass it through parse:
617 new NativeDate(Date.parse(Y)) :
618 // We have to manually make calls depending on argument
620 length >= 7 ? new NativeDate(Y, M, D, h, m, s, ms) :
621 length >= 6 ? new NativeDate(Y, M, D, h, m, s) :
622 length >= 5 ? new NativeDate(Y, M, D, h, m) :
623 length >= 4 ? new NativeDate(Y, M, D, h) :
624 length >= 3 ? new NativeDate(Y, M, D) :
625 length >= 2 ? new NativeDate(Y, M) :
626 length >= 1 ? new NativeDate(Y) :
628 // Prevent mixups with unfixed Date object
629 date.constructor = Date;
632 return NativeDate.apply(this, arguments);
635 // 15.9.1.15 Date Time String Format.
636 var isoDateExpression = new RegExp("^" +
637 "(\\d{4}|[\+\-]\\d{6})" + // four-digit year capture or sign + 6-digit extended year
638 "(?:-(\\d{2})" + // optional month capture
639 "(?:-(\\d{2})" + // optional day capture
640 "(?:" + // capture hours:minutes:seconds.milliseconds
641 "T(\\d{2})" + // hours capture
642 ":(\\d{2})" + // minutes capture
643 "(?:" + // optional :seconds.milliseconds
644 ":(\\d{2})" + // seconds capture
645 "(?:\\.(\\d{3}))?" + // milliseconds capture
647 "(?:" + // capture UTC offset component
648 "Z|" + // UTC capture
649 "(?:" + // offset specifier +/-hours:minutes
650 "([-+])" + // sign capture
651 "(\\d{2})" + // hours offset capture
652 ":(\\d{2})" + // minutes offset capture
657 // Copy any custom methods a 3rd party library may have added
658 for (var key in NativeDate) {
659 Date[key] = NativeDate[key];
662 // Copy "native" methods explicitly; they may be non-enumerable
663 Date.now = NativeDate.now;
664 Date.UTC = NativeDate.UTC;
665 Date.prototype = NativeDate.prototype;
666 Date.prototype.constructor = Date;
668 // Upgrade Date.parse to handle simplified ISO 8601 strings
669 Date.parse = function parse(string) {
670 var match = isoDateExpression.exec(string);
672 match.shift(); // kill match[0], the full match
673 // parse months, days, hours, minutes, seconds, and milliseconds
674 for (var i = 1; i < 7; i++) {
675 // provide default values if necessary
676 match[i] = +(match[i] || (i < 3 ? 1 : 0));
677 // match[1] is the month. Months are 0-11 in JavaScript
678 // `Date` objects, but 1-12 in ISO notation, so we
685 // parse the UTC offset component
686 var minuteOffset = +match.pop(), hourOffset = +match.pop(), sign = match.pop();
688 // compute the explicit time zone offset if specified
691 // detect invalid offsets and return early
692 if (hourOffset > 23 || minuteOffset > 59) {
696 // express the provided time zone offset in minutes. The offset is
697 // negative for time zones west of UTC; positive otherwise.
698 offset = (hourOffset * 60 + minuteOffset) * 6e4 * (sign == "+" ? -1 : 1);
701 // Date.UTC for years between 0 and 99 converts year to 1900 + year
702 // The Gregorian calendar has a 400-year cycle, so
703 // to Date.UTC(year + 400, .... ) - 12622780800000 == Date.UTC(year, ...),
704 // where 12622780800000 - number of milliseconds in Gregorian calendar 400 years
705 var year = +match[0];
706 if (0 <= year && year <= 99) {
707 match[0] = year + 400;
708 return NativeDate.UTC.apply(this, match) + offset - 12622780800000;
711 // compute a new UTC date value, accounting for the optional offset
712 return NativeDate.UTC.apply(this, match) + offset;
714 return NativeDate.parse.apply(this, arguments);
727 // http://es5.github.com/#x15.5.4.20
728 var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" +
729 "\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" +
731 if (!String.prototype.trim || ws.trim()) {
732 // http://blog.stevenlevithan.com/archives/faster-trim-javascript
733 // http://perfectionkills.com/whitespace-deviations/
735 var trimBeginRegexp = new RegExp("^" + ws + ws + "*"),
736 trimEndRegexp = new RegExp(ws + ws + "*$");
737 String.prototype.trim = function trim() {
738 if (this === undefined || this === null) {
739 throw new TypeError("can't convert "+this+" to object");
741 return String(this).replace(trimBeginRegexp, "").replace(trimEndRegexp, "");
751 // http://es5.github.com/#x9.4
752 // http://jsperf.com/to-integer
753 var toInteger = function (n) {
755 if (n !== n) { // isNaN
757 } else if (n !== 0 && n !== (1/0) && n !== -(1/0)) {
758 n = (n > 0 || -1) * Math.floor(Math.abs(n));
763 var prepareString = "a"[0] != "a";
765 // http://es5.github.com/#x9.9
766 var toObject = function (o) {
767 if (o == null) { // this matches both null and undefined
768 throw new TypeError("can't convert "+o+" to object");
770 // If the implementation doesn't support by-index access of
771 // string characters (ex. IE < 9), split the string
772 if (prepareString && typeof o == "string" && o) {