es5-shim.js 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963
  1. // Copyright 2009-2012 by contributors, MIT License
  2. // vim: ts=4 sts=4 sw=4 expandtab
  3. // Module systems magic dance
  4. (function (definition) {
  5. // RequireJS
  6. if (typeof define == "function") {
  7. define(definition);
  8. // YUI3
  9. } else if (typeof YUI == "function") {
  10. YUI.add("es5", definition);
  11. // CommonJS and <script>
  12. } else {
  13. definition();
  14. }
  15. })(function () {
  16. /**
  17. * Brings an environment as close to ECMAScript 5 compliance
  18. * as is possible with the facilities of erstwhile engines.
  19. *
  20. * Annotated ES5: http://es5.github.com/ (specific links below)
  21. * ES5 Spec: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
  22. * Required reading: http://javascriptweblog.wordpress.com/2011/12/05/extending-javascript-natives/
  23. */
  24. //
  25. // Function
  26. // ========
  27. //
  28. // ES-5 15.3.4.5
  29. // http://es5.github.com/#x15.3.4.5
  30. if (!Function.prototype.bind) {
  31. Function.prototype.bind = function bind(that) { // .length is 1
  32. // 1. Let Target be the this value.
  33. var target = this;
  34. // 2. If IsCallable(Target) is false, throw a TypeError exception.
  35. if (typeof target != "function") {
  36. throw new TypeError("Function.prototype.bind called on incompatible " + target);
  37. }
  38. // 3. Let A be a new (possibly empty) internal list of all of the
  39. // argument values provided after thisArg (arg1, arg2 etc), in order.
  40. // XXX slicedArgs will stand in for "A" if used
  41. var args = slice.call(arguments, 1); // for normal call
  42. // 4. Let F be a new native ECMAScript object.
  43. // 11. Set the [[Prototype]] internal property of F to the standard
  44. // built-in Function prototype object as specified in 15.3.3.1.
  45. // 12. Set the [[Call]] internal property of F as described in
  46. // 15.3.4.5.1.
  47. // 13. Set the [[Construct]] internal property of F as described in
  48. // 15.3.4.5.2.
  49. // 14. Set the [[HasInstance]] internal property of F as described in
  50. // 15.3.4.5.3.
  51. var bound = function () {
  52. if (this instanceof bound) {
  53. // 15.3.4.5.2 [[Construct]]
  54. // When the [[Construct]] internal method of a function object,
  55. // F that was created using the bind function is called with a
  56. // list of arguments ExtraArgs, the following steps are taken:
  57. // 1. Let target be the value of F's [[TargetFunction]]
  58. // internal property.
  59. // 2. If target has no [[Construct]] internal method, a
  60. // TypeError exception is thrown.
  61. // 3. Let boundArgs be the value of F's [[BoundArgs]] internal
  62. // property.
  63. // 4. Let args be a new list containing the same values as the
  64. // list boundArgs in the same order followed by the same
  65. // values as the list ExtraArgs in the same order.
  66. // 5. Return the result of calling the [[Construct]] internal
  67. // method of target providing args as the arguments.
  68. var result = target.apply(
  69. this,
  70. args.concat(slice.call(arguments))
  71. );
  72. if (Object(result) === result) {
  73. return result;
  74. }
  75. return this;
  76. } else {
  77. // 15.3.4.5.1 [[Call]]
  78. // When the [[Call]] internal method of a function object, F,
  79. // which was created using the bind function is called with a
  80. // this value and a list of arguments ExtraArgs, the following
  81. // steps are taken:
  82. // 1. Let boundArgs be the value of F's [[BoundArgs]] internal
  83. // property.
  84. // 2. Let boundThis be the value of F's [[BoundThis]] internal
  85. // property.
  86. // 3. Let target be the value of F's [[TargetFunction]] internal
  87. // property.
  88. // 4. Let args be a new list containing the same values as the
  89. // list boundArgs in the same order followed by the same
  90. // values as the list ExtraArgs in the same order.
  91. // 5. Return the result of calling the [[Call]] internal method
  92. // of target providing boundThis as the this value and
  93. // providing args as the arguments.
  94. // equiv: target.call(this, ...boundArgs, ...args)
  95. return target.apply(
  96. that,
  97. args.concat(slice.call(arguments))
  98. );
  99. }
  100. };
  101. if(target.prototype) {
  102. bound.prototype = Object.create(target.prototype);
  103. }
  104. // XXX bound.length is never writable, so don't even try
  105. //
  106. // 15. If the [[Class]] internal property of Target is "Function", then
  107. // a. Let L be the length property of Target minus the length of A.
  108. // b. Set the length own property of F to either 0 or L, whichever is
  109. // larger.
  110. // 16. Else set the length own property of F to 0.
  111. // 17. Set the attributes of the length own property of F to the values
  112. // specified in 15.3.5.1.
  113. // TODO
  114. // 18. Set the [[Extensible]] internal property of F to true.
  115. // TODO
  116. // 19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3).
  117. // 20. Call the [[DefineOwnProperty]] internal method of F with
  118. // arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]:
  119. // thrower, [[Enumerable]]: false, [[Configurable]]: false}, and
  120. // false.
  121. // 21. Call the [[DefineOwnProperty]] internal method of F with
  122. // arguments "arguments", PropertyDescriptor {[[Get]]: thrower,
  123. // [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false},
  124. // and false.
  125. // TODO
  126. // NOTE Function objects created using Function.prototype.bind do not
  127. // have a prototype property or the [[Code]], [[FormalParameters]], and
  128. // [[Scope]] internal properties.
  129. // XXX can't delete prototype in pure-js.
  130. // 22. Return F.
  131. return bound;
  132. };
  133. }
  134. // Shortcut to an often accessed properties, in order to avoid multiple
  135. // dereference that costs universally.
  136. // _Please note: Shortcuts are defined after `Function.prototype.bind` as we
  137. // us it in defining shortcuts.
  138. var call = Function.prototype.call;
  139. var prototypeOfArray = Array.prototype;
  140. var prototypeOfObject = Object.prototype;
  141. var slice = prototypeOfArray.slice;
  142. // Having a toString local variable name breaks in Opera so use _toString.
  143. var _toString = call.bind(prototypeOfObject.toString);
  144. var owns = call.bind(prototypeOfObject.hasOwnProperty);
  145. // If JS engine supports accessors creating shortcuts.
  146. var defineGetter;
  147. var defineSetter;
  148. var lookupGetter;
  149. var lookupSetter;
  150. var supportsAccessors;
  151. if ((supportsAccessors = owns(prototypeOfObject, "__defineGetter__"))) {
  152. defineGetter = call.bind(prototypeOfObject.__defineGetter__);
  153. defineSetter = call.bind(prototypeOfObject.__defineSetter__);
  154. lookupGetter = call.bind(prototypeOfObject.__lookupGetter__);
  155. lookupSetter = call.bind(prototypeOfObject.__lookupSetter__);
  156. }
  157. //
  158. // Array
  159. // =====
  160. //
  161. // ES5 15.4.4.12
  162. // http://es5.github.com/#x15.4.4.12
  163. // Default value for second param
  164. // [bugfix, ielt9, old browsers]
  165. // IE < 9 bug: [1,2].splice(0).join("") == "" but should be "12"
  166. if ([1,2].splice(0).length != 2) {
  167. var array_splice = Array.prototype.splice;
  168. Array.prototype.splice = function(start, deleteCount) {
  169. if (!arguments.length) {
  170. return [];
  171. } else {
  172. return array_splice.apply(this, [
  173. start === void 0 ? 0 : start,
  174. deleteCount === void 0 ? (this.length - start) : deleteCount
  175. ].concat(slice.call(arguments, 2)))
  176. }
  177. };
  178. }
  179. // ES5 15.4.3.2
  180. // http://es5.github.com/#x15.4.3.2
  181. // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray
  182. if (!Array.isArray) {
  183. Array.isArray = function isArray(obj) {
  184. return _toString(obj) == "[object Array]";
  185. };
  186. }
  187. // The IsCallable() check in the Array functions
  188. // has been replaced with a strict check on the
  189. // internal class of the object to trap cases where
  190. // the provided function was actually a regular
  191. // expression literal, which in V8 and
  192. // JavaScriptCore is a typeof "function". Only in
  193. // V8 are regular expression literals permitted as
  194. // reduce parameters, so it is desirable in the
  195. // general case for the shim to match the more
  196. // strict and common behavior of rejecting regular
  197. // expressions.
  198. // ES5 15.4.4.18
  199. // http://es5.github.com/#x15.4.4.18
  200. // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/forEach
  201. // Check failure of by-index access of string characters (IE < 9)
  202. // and failure of `0 in boxedString` (Rhino)
  203. var boxedString = Object("a"),
  204. splitString = boxedString[0] != "a" || !(0 in boxedString);
  205. if (!Array.prototype.forEach) {
  206. Array.prototype.forEach = function forEach(fun /*, thisp*/) {
  207. var object = toObject(this),
  208. self = splitString && _toString(this) == "[object String]" ?
  209. this.split("") :
  210. object,
  211. thisp = arguments[1],
  212. i = -1,
  213. length = self.length >>> 0;
  214. // If no callback function or if callback is not a callable function
  215. if (_toString(fun) != "[object Function]") {
  216. throw new TypeError(); // TODO message
  217. }
  218. while (++i < length) {
  219. if (i in self) {
  220. // Invoke the callback function with call, passing arguments:
  221. // context, property value, property key, thisArg object
  222. // context
  223. fun.call(thisp, self[i], i, object);
  224. }
  225. }
  226. };
  227. }
  228. // ES5 15.4.4.19
  229. // http://es5.github.com/#x15.4.4.19
  230. // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map
  231. if (!Array.prototype.map) {
  232. Array.prototype.map = function map(fun /*, thisp*/) {
  233. var object = toObject(this),
  234. self = splitString && _toString(this) == "[object String]" ?
  235. this.split("") :
  236. object,
  237. length = self.length >>> 0,
  238. result = Array(length),
  239. thisp = arguments[1];
  240. // If no callback function or if callback is not a callable function
  241. if (_toString(fun) != "[object Function]") {
  242. throw new TypeError(fun + " is not a function");
  243. }
  244. for (var i = 0; i < length; i++) {
  245. if (i in self)
  246. result[i] = fun.call(thisp, self[i], i, object);
  247. }
  248. return result;
  249. };
  250. }
  251. // ES5 15.4.4.20
  252. // http://es5.github.com/#x15.4.4.20
  253. // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter
  254. if (!Array.prototype.filter) {
  255. Array.prototype.filter = function filter(fun /*, thisp */) {
  256. var object = toObject(this),
  257. self = splitString && _toString(this) == "[object String]" ?
  258. this.split("") :
  259. object,
  260. length = self.length >>> 0,
  261. result = [],
  262. value,
  263. thisp = arguments[1];
  264. // If no callback function or if callback is not a callable function
  265. if (_toString(fun) != "[object Function]") {
  266. throw new TypeError(fun + " is not a function");
  267. }
  268. for (var i = 0; i < length; i++) {
  269. if (i in self) {
  270. value = self[i];
  271. if (fun.call(thisp, value, i, object)) {
  272. result.push(value);
  273. }
  274. }
  275. }
  276. return result;
  277. };
  278. }
  279. // ES5 15.4.4.16
  280. // http://es5.github.com/#x15.4.4.16
  281. // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/every
  282. if (!Array.prototype.every) {
  283. Array.prototype.every = function every(fun /*, thisp */) {
  284. var object = toObject(this),
  285. self = splitString && _toString(this) == "[object String]" ?
  286. this.split("") :
  287. object,
  288. length = self.length >>> 0,
  289. thisp = arguments[1];
  290. // If no callback function or if callback is not a callable function
  291. if (_toString(fun) != "[object Function]") {
  292. throw new TypeError(fun + " is not a function");
  293. }
  294. for (var i = 0; i < length; i++) {
  295. if (i in self && !fun.call(thisp, self[i], i, object)) {
  296. return false;
  297. }
  298. }
  299. return true;
  300. };
  301. }
  302. // ES5 15.4.4.17
  303. // http://es5.github.com/#x15.4.4.17
  304. // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some
  305. if (!Array.prototype.some) {
  306. Array.prototype.some = function some(fun /*, thisp */) {
  307. var object = toObject(this),
  308. self = splitString && _toString(this) == "[object String]" ?
  309. this.split("") :
  310. object,
  311. length = self.length >>> 0,
  312. thisp = arguments[1];
  313. // If no callback function or if callback is not a callable function
  314. if (_toString(fun) != "[object Function]") {
  315. throw new TypeError(fun + " is not a function");
  316. }
  317. for (var i = 0; i < length; i++) {
  318. if (i in self && fun.call(thisp, self[i], i, object)) {
  319. return true;
  320. }
  321. }
  322. return false;
  323. };
  324. }
  325. // ES5 15.4.4.21
  326. // http://es5.github.com/#x15.4.4.21
  327. // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduce
  328. if (!Array.prototype.reduce) {
  329. Array.prototype.reduce = function reduce(fun /*, initial*/) {
  330. var object = toObject(this),
  331. self = splitString && _toString(this) == "[object String]" ?
  332. this.split("") :
  333. object,
  334. length = self.length >>> 0;
  335. // If no callback function or if callback is not a callable function
  336. if (_toString(fun) != "[object Function]") {
  337. throw new TypeError(fun + " is not a function");
  338. }
  339. // no value to return if no initial value and an empty array
  340. if (!length && arguments.length == 1) {
  341. throw new TypeError("reduce of empty array with no initial value");
  342. }
  343. var i = 0;
  344. var result;
  345. if (arguments.length >= 2) {
  346. result = arguments[1];
  347. } else {
  348. do {
  349. if (i in self) {
  350. result = self[i++];
  351. break;
  352. }
  353. // if array contains no values, no initial value to return
  354. if (++i >= length) {
  355. throw new TypeError("reduce of empty array with no initial value");
  356. }
  357. } while (true);
  358. }
  359. for (; i < length; i++) {
  360. if (i in self) {
  361. result = fun.call(void 0, result, self[i], i, object);
  362. }
  363. }
  364. return result;
  365. };
  366. }
  367. // ES5 15.4.4.22
  368. // http://es5.github.com/#x15.4.4.22
  369. // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduceRight
  370. if (!Array.prototype.reduceRight) {
  371. Array.prototype.reduceRight = function reduceRight(fun /*, initial*/) {
  372. var object = toObject(this),
  373. self = splitString && _toString(this) == "[object String]" ?
  374. this.split("") :
  375. object,
  376. length = self.length >>> 0;
  377. // If no callback function or if callback is not a callable function
  378. if (_toString(fun) != "[object Function]") {
  379. throw new TypeError(fun + " is not a function");
  380. }
  381. // no value to return if no initial value, empty array
  382. if (!length && arguments.length == 1) {
  383. throw new TypeError("reduceRight of empty array with no initial value");
  384. }
  385. var result, i = length - 1;
  386. if (arguments.length >= 2) {
  387. result = arguments[1];
  388. } else {
  389. do {
  390. if (i in self) {
  391. result = self[i--];
  392. break;
  393. }
  394. // if array contains no values, no initial value to return
  395. if (--i < 0) {
  396. throw new TypeError("reduceRight of empty array with no initial value");
  397. }
  398. } while (true);
  399. }
  400. do {
  401. if (i in this) {
  402. result = fun.call(void 0, result, self[i], i, object);
  403. }
  404. } while (i--);
  405. return result;
  406. };
  407. }
  408. // ES5 15.4.4.14
  409. // http://es5.github.com/#x15.4.4.14
  410. // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
  411. if (!Array.prototype.indexOf || ([0, 1].indexOf(1, 2) != -1)) {
  412. Array.prototype.indexOf = function indexOf(sought /*, fromIndex */ ) {
  413. var self = splitString && _toString(this) == "[object String]" ?
  414. this.split("") :
  415. toObject(this),
  416. length = self.length >>> 0;
  417. if (!length) {
  418. return -1;
  419. }
  420. var i = 0;
  421. if (arguments.length > 1) {
  422. i = toInteger(arguments[1]);
  423. }
  424. // handle negative indices
  425. i = i >= 0 ? i : Math.max(0, length + i);
  426. for (; i < length; i++) {
  427. if (i in self && self[i] === sought) {
  428. return i;
  429. }
  430. }
  431. return -1;
  432. };
  433. }
  434. // ES5 15.4.4.15
  435. // http://es5.github.com/#x15.4.4.15
  436. // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/lastIndexOf
  437. if (!Array.prototype.lastIndexOf || ([0, 1].lastIndexOf(0, -3) != -1)) {
  438. Array.prototype.lastIndexOf = function lastIndexOf(sought /*, fromIndex */) {
  439. var self = splitString && _toString(this) == "[object String]" ?
  440. this.split("") :
  441. toObject(this),
  442. length = self.length >>> 0;
  443. if (!length) {
  444. return -1;
  445. }
  446. var i = length - 1;
  447. if (arguments.length > 1) {
  448. i = Math.min(i, toInteger(arguments[1]));
  449. }
  450. // handle negative indices
  451. i = i >= 0 ? i : length - Math.abs(i);
  452. for (; i >= 0; i--) {
  453. if (i in self && sought === self[i]) {
  454. return i;
  455. }
  456. }
  457. return -1;
  458. };
  459. }
  460. //
  461. // Object
  462. // ======
  463. //
  464. // ES5 15.2.3.14
  465. // http://es5.github.com/#x15.2.3.14
  466. if (!Object.keys) {
  467. // http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation
  468. var hasDontEnumBug = true,
  469. dontEnums = [
  470. "toString",
  471. "toLocaleString",
  472. "valueOf",
  473. "hasOwnProperty",
  474. "isPrototypeOf",
  475. "propertyIsEnumerable",
  476. "constructor"
  477. ],
  478. dontEnumsLength = dontEnums.length;
  479. for (var key in {"toString": null}) {
  480. hasDontEnumBug = false;
  481. }
  482. Object.keys = function keys(object) {
  483. if (
  484. (typeof object != "object" && typeof object != "function") ||
  485. object === null
  486. ) {
  487. throw new TypeError("Object.keys called on a non-object");
  488. }
  489. var keys = [];
  490. for (var name in object) {
  491. if (owns(object, name)) {
  492. keys.push(name);
  493. }
  494. }
  495. if (hasDontEnumBug) {
  496. for (var i = 0, ii = dontEnumsLength; i < ii; i++) {
  497. var dontEnum = dontEnums[i];
  498. if (owns(object, dontEnum)) {
  499. keys.push(dontEnum);
  500. }
  501. }
  502. }
  503. return keys;
  504. };
  505. }
  506. //
  507. // Date
  508. // ====
  509. //
  510. // ES5 15.9.5.43
  511. // http://es5.github.com/#x15.9.5.43
  512. // This function returns a String value represent the instance in time
  513. // represented by this Date object. The format of the String is the Date Time
  514. // string format defined in 15.9.1.15. All fields are present in the String.
  515. // The time zone is always UTC, denoted by the suffix Z. If the time value of
  516. // this object is not a finite Number a RangeError exception is thrown.
  517. var negativeDate = -62198755200000,
  518. negativeYearString = "-000001";
  519. if (
  520. !Date.prototype.toISOString ||
  521. (new Date(negativeDate).toISOString().indexOf(negativeYearString) === -1)
  522. ) {
  523. Date.prototype.toISOString = function toISOString() {
  524. var result, length, value, year, month;
  525. if (!isFinite(this)) {
  526. throw new RangeError("Date.prototype.toISOString called on non-finite value.");
  527. }
  528. year = this.getUTCFullYear();
  529. month = this.getUTCMonth();
  530. // see https://github.com/kriskowal/es5-shim/issues/111
  531. year += Math.floor(month / 12);
  532. month = (month % 12 + 12) % 12;
  533. // the date time string format is specified in 15.9.1.15.
  534. result = [month + 1, this.getUTCDate(),
  535. this.getUTCHours(), this.getUTCMinutes(), this.getUTCSeconds()];
  536. year = (
  537. (year < 0 ? "-" : (year > 9999 ? "+" : "")) +
  538. ("00000" + Math.abs(year))
  539. .slice(0 <= year && year <= 9999 ? -4 : -6)
  540. );
  541. length = result.length;
  542. while (length--) {
  543. value = result[length];
  544. // pad months, days, hours, minutes, and seconds to have two
  545. // digits.
  546. if (value < 10) {
  547. result[length] = "0" + value;
  548. }
  549. }
  550. // pad milliseconds to have three digits.
  551. return (
  552. year + "-" + result.slice(0, 2).join("-") +
  553. "T" + result.slice(2).join(":") + "." +
  554. ("000" + this.getUTCMilliseconds()).slice(-3) + "Z"
  555. );
  556. };
  557. }
  558. // ES5 15.9.5.44
  559. // http://es5.github.com/#x15.9.5.44
  560. // This function provides a String representation of a Date object for use by
  561. // JSON.stringify (15.12.3).
  562. var dateToJSONIsSupported = false;
  563. try {
  564. dateToJSONIsSupported = (
  565. Date.prototype.toJSON &&
  566. new Date(NaN).toJSON() === null &&
  567. new Date(negativeDate).toJSON().indexOf(negativeYearString) !== -1 &&
  568. Date.prototype.toJSON.call({ // generic
  569. toISOString: function () {
  570. return true;
  571. }
  572. })
  573. );
  574. } catch (e) {
  575. }
  576. if (!dateToJSONIsSupported) {
  577. Date.prototype.toJSON = function toJSON(key) {
  578. // When the toJSON method is called with argument key, the following
  579. // steps are taken:
  580. // 1. Let O be the result of calling ToObject, giving it the this
  581. // value as its argument.
  582. // 2. Let tv be toPrimitive(O, hint Number).
  583. var o = Object(this),
  584. tv = toPrimitive(o),
  585. toISO;
  586. // 3. If tv is a Number and is not finite, return null.
  587. if (typeof tv === "number" && !isFinite(tv)) {
  588. return null;
  589. }
  590. // 4. Let toISO be the result of calling the [[Get]] internal method of
  591. // O with argument "toISOString".
  592. toISO = o.toISOString;
  593. // 5. If IsCallable(toISO) is false, throw a TypeError exception.
  594. if (typeof toISO != "function") {
  595. throw new TypeError("toISOString property is not callable");
  596. }
  597. // 6. Return the result of calling the [[Call]] internal method of
  598. // toISO with O as the this value and an empty argument list.
  599. return toISO.call(o);
  600. // NOTE 1 The argument is ignored.
  601. // NOTE 2 The toJSON function is intentionally generic; it does not
  602. // require that its this value be a Date object. Therefore, it can be
  603. // transferred to other kinds of objects for use as a method. However,
  604. // it does require that any such object have a toISOString method. An
  605. // object is free to use the argument key to filter its
  606. // stringification.
  607. };
  608. }
  609. // ES5 15.9.4.2
  610. // http://es5.github.com/#x15.9.4.2
  611. // based on work shared by Daniel Friesen (dantman)
  612. // http://gist.github.com/303249
  613. if (!Date.parse || "Date.parse is buggy") {
  614. // XXX global assignment won't work in embeddings that use
  615. // an alternate object for the context.
  616. Date = (function(NativeDate) {
  617. // Date.length === 7
  618. var newDate = function Date(Y, M, D, h, m, s, ms) {
  619. var length = arguments.length;
  620. if (this instanceof NativeDate) {
  621. var date = length == 1 && String(Y) === Y ? // isString(Y)
  622. // We explicitly pass it through parse:
  623. new NativeDate(newDate.parse(Y)) :
  624. // We have to manually make calls depending on argument
  625. // length here
  626. length >= 7 ? new NativeDate(Y, M, D, h, m, s, ms) :
  627. length >= 6 ? new NativeDate(Y, M, D, h, m, s) :
  628. length >= 5 ? new NativeDate(Y, M, D, h, m) :
  629. length >= 4 ? new NativeDate(Y, M, D, h) :
  630. length >= 3 ? new NativeDate(Y, M, D) :
  631. length >= 2 ? new NativeDate(Y, M) :
  632. length >= 1 ? new NativeDate(Y) :
  633. new NativeDate();
  634. // Prevent mixups with unfixed Date object
  635. date.constructor = newDate;
  636. return date;
  637. }
  638. return NativeDate.apply(this, arguments);
  639. };
  640. // 15.9.1.15 Date Time String Format.
  641. var isoDateExpression = new RegExp("^" +
  642. "(\\d{4}|[\+\-]\\d{6})" + // four-digit year capture or sign +
  643. // 6-digit extended year
  644. "(?:-(\\d{2})" + // optional month capture
  645. "(?:-(\\d{2})" + // optional day capture
  646. "(?:" + // capture hours:minutes:seconds.milliseconds
  647. "T(\\d{2})" + // hours capture
  648. ":(\\d{2})" + // minutes capture
  649. "(?:" + // optional :seconds.milliseconds
  650. ":(\\d{2})" + // seconds capture
  651. "(?:\\.(\\d{3}))?" + // milliseconds capture
  652. ")?" +
  653. "(" + // capture UTC offset component
  654. "Z|" + // UTC capture
  655. "(?:" + // offset specifier +/-hours:minutes
  656. "([-+])" + // sign capture
  657. "(\\d{2})" + // hours offset capture
  658. ":(\\d{2})" + // minutes offset capture
  659. ")" +
  660. ")?)?)?)?" +
  661. "$");
  662. var months = [
  663. 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
  664. ];
  665. function dayFromMonth(year, month) {
  666. var t = month > 1 ? 1 : 0;
  667. return (
  668. months[month] +
  669. Math.floor((year - 1969 + t) / 4) -
  670. Math.floor((year - 1901 + t) / 100) +
  671. Math.floor((year - 1601 + t) / 400) +
  672. 365 * (year - 1970)
  673. );
  674. }
  675. // Copy any custom methods a 3rd party library may have added
  676. for (var key in NativeDate) {
  677. newDate[key] = NativeDate[key];
  678. }
  679. // Copy "native" methods explicitly; they may be non-enumerable
  680. newDate.now = NativeDate.now;
  681. newDate.UTC = NativeDate.UTC;
  682. newDate.prototype = NativeDate.prototype;
  683. newDate.prototype.constructor = Date;
  684. // Upgrade Date.parse to handle simplified ISO 8601 strings
  685. newDate.parse = function parse(string) {
  686. var match = isoDateExpression.exec(string);
  687. if (match) {
  688. // parse months, days, hours, minutes, seconds, and milliseconds
  689. // provide default values if necessary
  690. // parse the UTC offset component
  691. var year = Number(match[1]),
  692. month = Number(match[2] || 1) - 1,
  693. day = Number(match[3] || 1) - 1,
  694. hour = Number(match[4] || 0),
  695. minute = Number(match[5] || 0),
  696. second = Number(match[6] || 0),
  697. millisecond = Number(match[7] || 0),
  698. // When time zone is missed, local offset should be used
  699. // (ES 5.1 bug)
  700. // see https://bugs.ecmascript.org/show_bug.cgi?id=112
  701. offset = !match[4] || match[8] ?
  702. 0 : Number(new Date(1970, 0)),
  703. signOffset = match[9] === "-" ? 1 : -1,
  704. hourOffset = Number(match[10] || 0),
  705. minuteOffset = Number(match[11] || 0),
  706. result;
  707. if (
  708. hour < (
  709. minute > 0 || second > 0 || millisecond > 0 ?
  710. 24 : 25
  711. ) &&
  712. minute < 60 && second < 60 && millisecond < 1000 &&
  713. month > -1 && month < 12 && hourOffset < 24 &&
  714. minuteOffset < 60 && // detect invalid offsets
  715. day > -1 &&
  716. day < (
  717. dayFromMonth(year, month + 1) -
  718. dayFromMonth(year, month)
  719. )
  720. ) {
  721. result = (
  722. (dayFromMonth(year, month) + day) * 24 +
  723. hour +
  724. hourOffset * signOffset
  725. ) * 60;
  726. result = (
  727. (result + minute + minuteOffset * signOffset) * 60 +
  728. second
  729. ) * 1000 + millisecond + offset;
  730. if (-8.64e15 <= result && result <= 8.64e15) {
  731. return result;
  732. }
  733. }
  734. return NaN;
  735. }
  736. return NativeDate.parse.apply(this, arguments);
  737. };
  738. return newDate;
  739. })(Date);
  740. }
  741. // ES5 15.9.4.4
  742. // http://es5.github.com/#x15.9.4.4
  743. if (!Date.now) {
  744. Date.now = function now() {
  745. return new Date().getTime();
  746. };
  747. }
  748. //
  749. // String
  750. // ======
  751. //
  752. // ES5 15.5.4.14
  753. // http://es5.github.com/#x15.5.4.14
  754. // [bugfix, chrome]
  755. // If separator is undefined, then the result array contains just one String,
  756. // which is the this value (converted to a String). If limit is not undefined,
  757. // then the output array is truncated so that it contains no more than limit
  758. // elements.
  759. // "0".split(undefined, 0) -> []
  760. if("0".split(void 0, 0).length) {
  761. var string_split = String.prototype.split;
  762. String.prototype.split = function(separator, limit) {
  763. if(separator === void 0 && limit === 0)return [];
  764. return string_split.apply(this, arguments);
  765. }
  766. }
  767. // ECMA-262, 3rd B.2.3
  768. // Note an ECMAScript standart, although ECMAScript 3rd Edition has a
  769. // non-normative section suggesting uniform semantics and it should be
  770. // normalized across all browsers
  771. // [bugfix, IE lt 9] IE < 9 substr() with negative value not working in IE
  772. if("".substr && "0b".substr(-1) !== "b") {
  773. var string_substr = String.prototype.substr;
  774. /**
  775. * Get the substring of a string
  776. * @param {integer} start where to start the substring
  777. * @param {integer} length how many characters to return
  778. * @return {string}
  779. */
  780. String.prototype.substr = function(start, length) {
  781. return string_substr.call(
  782. this,
  783. start < 0 ? (start = this.length + start) < 0 ? 0 : start : start,
  784. length
  785. );
  786. }
  787. }
  788. // ES5 15.5.4.20
  789. // http://es5.github.com/#x15.5.4.20
  790. var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" +
  791. "\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" +
  792. "\u2029\uFEFF";
  793. if (!String.prototype.trim || ws.trim()) {
  794. // http://blog.stevenlevithan.com/archives/faster-trim-javascript
  795. // http://perfectionkills.com/whitespace-deviations/
  796. ws = "[" + ws + "]";
  797. var trimBeginRegexp = new RegExp("^" + ws + ws + "*"),
  798. trimEndRegexp = new RegExp(ws + ws + "*$");
  799. String.prototype.trim = function trim() {
  800. if (this === undefined || this === null) {
  801. throw new TypeError("can't convert "+this+" to object");
  802. }
  803. return String(this)
  804. .replace(trimBeginRegexp, "")
  805. .replace(trimEndRegexp, "");
  806. };
  807. }
  808. //
  809. // Util
  810. // ======
  811. //
  812. // ES5 9.4
  813. // http://es5.github.com/#x9.4
  814. // http://jsperf.com/to-integer
  815. function toInteger(n) {
  816. n = +n;
  817. if (n !== n) { // isNaN
  818. n = 0;
  819. } else if (n !== 0 && n !== (1/0) && n !== -(1/0)) {
  820. n = (n > 0 || -1) * Math.floor(Math.abs(n));
  821. }
  822. return n;
  823. }
  824. function isPrimitive(input) {
  825. var type = typeof input;
  826. return (
  827. input === null ||
  828. type === "undefined" ||
  829. type === "boolean" ||
  830. type === "number" ||
  831. type === "string"
  832. );
  833. }
  834. function toPrimitive(input) {
  835. var val, valueOf, toString;
  836. if (isPrimitive(input)) {
  837. return input;
  838. }
  839. valueOf = input.valueOf;
  840. if (typeof valueOf === "function") {
  841. val = valueOf.call(input);
  842. if (isPrimitive(val)) {
  843. return val;
  844. }
  845. }
  846. toString = input.toString;
  847. if (typeof toString === "function") {
  848. val = toString.call(input);
  849. if (isPrimitive(val)) {
  850. return val;
  851. }
  852. }
  853. throw new TypeError();
  854. }
  855. // ES5 9.9
  856. // http://es5.github.com/#x9.9
  857. var toObject = function (o) {
  858. if (o == null) { // this matches both null and undefined
  859. throw new TypeError("can't convert "+o+" to object");
  860. }
  861. return Object(o);
  862. };
  863. });