mooToolsScriptText.js 53 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318
  1. //Core, Array, String, Function, Number, Class, Object, Object.Extras, Locale, Date, Locale.en-US.Date, Locale.zh-CH.Date, JSON
  2. /*
  3. ---
  4. name: Prefix
  5. description: Loads MooTools as a CommonJS Module.
  6. license: MIT-style license.
  7. copyright: Copyright (c) 2010 [Christoph Pojer](http://cpojer.net/).
  8. authors: Christoph Pojer
  9. provides: [Prefix]
  10. ...
  11. */
  12. var GLOBAL_ITEMS = function(){
  13. var items = [];
  14. for (var key in this)
  15. items.push(key);
  16. return items;
  17. }();
  18. /*
  19. ---
  20. name: Core
  21. description: The heart of MooTools.
  22. license: MIT-style license.
  23. copyright: Copyright (c) 2006-2012 [Valerio Proietti](http://mad4milk.net/).
  24. authors: The MooTools production team (http://mootools.net/developers/)
  25. inspiration:
  26. - Class implementation inspired by [Base.js](http://dean.edwards.name/weblog/2006/03/base/) Copyright (c) 2006 Dean Edwards, [GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)
  27. - Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php)
  28. provides: [Core, MooTools, Type, typeOf, instanceOf, Native]
  29. ...
  30. */
  31. (function(){
  32. this.MooTools = {
  33. version: '1.5.0dev',
  34. build: '%build%'
  35. };
  36. // typeOf, instanceOf
  37. var typeOf = this.typeOf = function(item){
  38. if (item == null) return 'null';
  39. if (item.$family != null) return item.$family();
  40. if (item.nodeName){
  41. if (item.nodeType == 1) return 'element';
  42. if (item.nodeType == 3) return (/\S/).test(item.nodeValue) ? 'textnode' : 'whitespace';
  43. } else if (typeof item.length == 'number'){
  44. if (item.callee) return 'arguments';
  45. if ('item' in item) return 'collection';
  46. }
  47. return typeof item;
  48. };
  49. var instanceOf = this.instanceOf = function(item, object){
  50. if (item == null) return false;
  51. var constructor = item.$constructor || item.constructor;
  52. while (constructor){
  53. if (constructor === object) return true;
  54. constructor = constructor.parent;
  55. }
  56. /*<ltIE8>*/
  57. if (!item.hasOwnProperty) return false;
  58. /*</ltIE8>*/
  59. return item instanceof object;
  60. };
  61. // Function overloading
  62. var Function = this.Function;
  63. var enumerables = true;
  64. for (var i in {toString: 1}) enumerables = null;
  65. if (enumerables) enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'constructor'];
  66. Function.prototype.overloadSetter = function(usePlural){
  67. var self = this;
  68. return function(a, b){
  69. if (a == null) return this;
  70. if (usePlural || typeof a != 'string'){
  71. for (var k in a) self.call(this, k, a[k]);
  72. if (enumerables) for (var i = enumerables.length; i--;){
  73. k = enumerables[i];
  74. if (a.hasOwnProperty(k)) self.call(this, k, a[k]);
  75. }
  76. } else {
  77. self.call(this, a, b);
  78. }
  79. return this;
  80. };
  81. };
  82. Function.prototype.overloadGetter = function(usePlural){
  83. var self = this;
  84. return function(a){
  85. var args, result;
  86. if (typeof a != 'string') args = a;
  87. else if (arguments.length > 1) args = arguments;
  88. else if (usePlural) args = [a];
  89. if (args){
  90. result = {};
  91. for (var i = 0; i < args.length; i++) result[args[i]] = self.call(this, args[i]);
  92. } else {
  93. result = self.call(this, a);
  94. }
  95. return result;
  96. };
  97. };
  98. Function.prototype.extend = function(key, value){
  99. this[key] = value;
  100. }.overloadSetter();
  101. Function.prototype.implement = function(key, value){
  102. this.prototype[key] = value;
  103. }.overloadSetter();
  104. // From
  105. var slice = Array.prototype.slice;
  106. Function.from = function(item){
  107. return (typeOf(item) == 'function') ? item : function(){
  108. return item;
  109. };
  110. };
  111. Function.convert = Function.from;
  112. Array.from = function(item){
  113. if (item == null) return [];
  114. return (Type.isEnumerable(item) && typeof item != 'string') ? (typeOf(item) == 'array') ? item : slice.call(item) : [item];
  115. };
  116. Array.convert = Array.from;
  117. Number.from = function(item){
  118. var number = parseFloat(item);
  119. return isFinite(number) ? number : null;
  120. };
  121. Number.convert = Number.from;
  122. String.from = function(item){
  123. return item + '';
  124. };
  125. String.convert = String.from;
  126. // hide, protect
  127. Function.implement({
  128. hide: function(){
  129. this.$hidden = true;
  130. return this;
  131. },
  132. protect: function(){
  133. this.$protected = true;
  134. return this;
  135. }
  136. });
  137. // Type
  138. var Type = this.Type = function(name, object){
  139. if (name){
  140. var lower = name.toLowerCase();
  141. var typeCheck = function(item){
  142. return (typeOf(item) == lower);
  143. };
  144. Type['is' + name] = typeCheck;
  145. if (object != null){
  146. object.prototype.$family = (function(){
  147. return lower;
  148. }).hide();
  149. }
  150. }
  151. if (object == null) return null;
  152. object.extend(this);
  153. object.$constructor = Type;
  154. object.prototype.$constructor = object;
  155. return object;
  156. };
  157. var toString = Object.prototype.toString;
  158. Type.isEnumerable = function(item){
  159. return (item != null && typeof item.length == 'number' && toString.call(item) != '[object Function]' );
  160. };
  161. var hooks = {};
  162. var hooksOf = function(object){
  163. var type = typeOf(object.prototype);
  164. return hooks[type] || (hooks[type] = []);
  165. };
  166. var implement = function(name, method){
  167. if (method && method.$hidden) return;
  168. var hooks = hooksOf(this);
  169. for (var i = 0; i < hooks.length; i++){
  170. var hook = hooks[i];
  171. if (typeOf(hook) == 'type') implement.call(hook, name, method);
  172. else hook.call(this, name, method);
  173. }
  174. var previous = this.prototype[name];
  175. if (previous == null || !previous.$protected) this.prototype[name] = method;
  176. if (this[name] == null && typeOf(method) == 'function') extend.call(this, name, function(item){
  177. return method.apply(item, slice.call(arguments, 1));
  178. });
  179. };
  180. var extend = function(name, method){
  181. if (method && method.$hidden) return;
  182. var previous = this[name];
  183. if (previous == null || !previous.$protected) this[name] = method;
  184. };
  185. Type.implement({
  186. implement: implement.overloadSetter(),
  187. extend: extend.overloadSetter(),
  188. alias: function(name, existing){
  189. implement.call(this, name, this.prototype[existing]);
  190. }.overloadSetter(),
  191. mirror: function(hook){
  192. hooksOf(this).push(hook);
  193. return this;
  194. }
  195. });
  196. new Type('Type', Type);
  197. // Default Types
  198. var force = function(name, object, methods){
  199. var isType = (object != Object),
  200. prototype = object.prototype;
  201. if (isType) object = new Type(name, object);
  202. for (var i = 0, l = methods.length; i < l; i++){
  203. var key = methods[i],
  204. generic = object[key],
  205. proto = prototype[key];
  206. if (generic) generic.protect();
  207. if (isType && proto) object.implement(key, proto.protect());
  208. }
  209. if (isType){
  210. var methodsEnumerable = prototype.propertyIsEnumerable(methods[0]);
  211. object.forEachMethod = function(fn){
  212. if (!methodsEnumerable) for (var i = 0, l = methods.length; i < l; i++){
  213. fn.call(prototype, prototype[methods[i]], methods[i]);
  214. }
  215. for (var key in prototype) fn.call(prototype, prototype[key], key);
  216. };
  217. }
  218. return force;
  219. };
  220. force('String', String, [
  221. 'charAt', 'charCodeAt', 'concat', 'indexOf', 'lastIndexOf', 'match', 'quote', 'replace', 'search',
  222. 'slice', 'split', 'substr', 'substring', 'trim', 'toLowerCase', 'toUpperCase'
  223. ])('Array', Array, [
  224. 'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice',
  225. 'indexOf', 'lastIndexOf', 'filter', 'forEach', 'every', 'map', 'some', 'reduce', 'reduceRight'
  226. ])('Number', Number, [
  227. 'toExponential', 'toFixed', 'toLocaleString', 'toPrecision'
  228. ])('Function', Function, [
  229. 'apply', 'call', 'bind'
  230. ])('RegExp', RegExp, [
  231. 'exec', 'test'
  232. ])('Object', Object, [
  233. 'create', 'defineProperty', 'defineProperties', 'keys',
  234. 'getPrototypeOf', 'getOwnPropertyDescriptor', 'getOwnPropertyNames',
  235. 'preventExtensions', 'isExtensible', 'seal', 'isSealed', 'freeze', 'isFrozen'
  236. ])('Date', Date, ['now']);
  237. Object.extend = extend.overloadSetter();
  238. Date.extend('now', function(){
  239. return +(new Date);
  240. });
  241. new Type('Boolean', Boolean);
  242. // fixes NaN returning as Number
  243. Number.prototype.$family = function(){
  244. return isFinite(this) ? 'number' : 'null';
  245. }.hide();
  246. // Number.random
  247. Number.extend('random', function(min, max){
  248. return Math.floor(Math.random() * (max - min + 1) + min);
  249. });
  250. // forEach, each
  251. var hasOwnProperty = Object.prototype.hasOwnProperty;
  252. Object.extend('forEach', function(object, fn, bind){
  253. for (var key in object){
  254. if (hasOwnProperty.call(object, key)) fn.call(bind, object[key], key, object);
  255. }
  256. });
  257. Object.each = Object.forEach;
  258. Array.implement({
  259. /*<!ES5>*/
  260. forEach: function(fn, bind){
  261. for (var i = 0, l = this.length; i < l; i++){
  262. if (i in this) fn.call(bind, this[i], i, this);
  263. }
  264. },
  265. /*</!ES5>*/
  266. each: function(fn, bind){
  267. Array.forEach(this, fn, bind);
  268. return this;
  269. }
  270. });
  271. // Array & Object cloning, Object merging and appending
  272. var cloneOf = function(item){
  273. switch (typeOf(item)){
  274. case 'array': return item.clone();
  275. case 'object': return Object.clone(item);
  276. default: return item;
  277. }
  278. };
  279. Array.implement('clone', function(){
  280. var i = this.length, clone = new Array(i);
  281. while (i--) clone[i] = cloneOf(this[i]);
  282. return clone;
  283. });
  284. var mergeOne = function(source, key, current){
  285. switch (typeOf(current)){
  286. case 'object':
  287. if (typeOf(source[key]) == 'object') Object.merge(source[key], current);
  288. else source[key] = Object.clone(current);
  289. break;
  290. case 'array': source[key] = current.clone(); break;
  291. default: source[key] = current;
  292. }
  293. return source;
  294. };
  295. Object.extend({
  296. merge: function(source, k, v){
  297. if (typeOf(k) == 'string') return mergeOne(source, k, v);
  298. for (var i = 1, l = arguments.length; i < l; i++){
  299. var object = arguments[i];
  300. for (var key in object) mergeOne(source, key, object[key]);
  301. }
  302. return source;
  303. },
  304. clone: function(object){
  305. var clone = {};
  306. for (var key in object) clone[key] = cloneOf(object[key]);
  307. return clone;
  308. },
  309. append: function(original){
  310. for (var i = 1, l = arguments.length; i < l; i++){
  311. var extended = arguments[i] || {};
  312. for (var key in extended) original[key] = extended[key];
  313. }
  314. return original;
  315. }
  316. });
  317. // Object-less types
  318. ['Object', 'WhiteSpace', 'TextNode', 'Collection', 'Arguments'].each(function(name){
  319. new Type(name);
  320. });
  321. // Unique ID
  322. var UID = Date.now();
  323. String.extend('uniqueID', function(){
  324. return (UID++).toString(36);
  325. });
  326. })();
  327. /*
  328. ---
  329. name: Array
  330. description: Contains Array Prototypes like each, contains, and erase.
  331. license: MIT-style license.
  332. requires: Type
  333. provides: Array
  334. ...
  335. */
  336. Array.implement({
  337. /*<!ES5>*/
  338. every: function(fn, bind){
  339. for (var i = 0, l = this.length >>> 0; i < l; i++){
  340. if ((i in this) && !fn.call(bind, this[i], i, this)) return false;
  341. }
  342. return true;
  343. },
  344. filter: function(fn, bind){
  345. var results = [];
  346. for (var value, i = 0, l = this.length >>> 0; i < l; i++) if (i in this){
  347. value = this[i];
  348. if (fn.call(bind, value, i, this)) results.push(value);
  349. }
  350. return results;
  351. },
  352. indexOf: function(item, from){
  353. var length = this.length >>> 0;
  354. for (var i = (from < 0) ? Math.max(0, length + from) : from || 0; i < length; i++){
  355. if (this[i] === item) return i;
  356. }
  357. return -1;
  358. },
  359. map: function(fn, bind){
  360. var length = this.length >>> 0, results = Array(length);
  361. for (var i = 0; i < length; i++){
  362. if (i in this) results[i] = fn.call(bind, this[i], i, this);
  363. }
  364. return results;
  365. },
  366. some: function(fn, bind){
  367. for (var i = 0, l = this.length >>> 0; i < l; i++){
  368. if ((i in this) && fn.call(bind, this[i], i, this)) return true;
  369. }
  370. return false;
  371. },
  372. /*</!ES5>*/
  373. clean: function(){
  374. return this.filter(function(item){
  375. return item != null;
  376. });
  377. },
  378. invoke: function(methodName){
  379. var args = Array.slice(arguments, 1);
  380. return this.map(function(item){
  381. return item[methodName].apply(item, args);
  382. });
  383. },
  384. associate: function(keys){
  385. var obj = {}, length = Math.min(this.length, keys.length);
  386. for (var i = 0; i < length; i++) obj[keys[i]] = this[i];
  387. return obj;
  388. },
  389. link: function(object){
  390. var result = {};
  391. for (var i = 0, l = this.length; i < l; i++){
  392. for (var key in object){
  393. if (object[key](this[i])){
  394. result[key] = this[i];
  395. delete object[key];
  396. break;
  397. }
  398. }
  399. }
  400. return result;
  401. },
  402. contains: function(item, from){
  403. return this.indexOf(item, from) != -1;
  404. },
  405. append: function(array){
  406. this.push.apply(this, array);
  407. return this;
  408. },
  409. getLast: function(){
  410. return (this.length) ? this[this.length - 1] : null;
  411. },
  412. getRandom: function(){
  413. return (this.length) ? this[Number.random(0, this.length - 1)] : null;
  414. },
  415. include: function(item){
  416. if (!this.contains(item)) this.push(item);
  417. return this;
  418. },
  419. combine: function(array){
  420. for (var i = 0, l = array.length; i < l; i++) this.include(array[i]);
  421. return this;
  422. },
  423. erase: function(item){
  424. for (var i = this.length; i--;){
  425. if (this[i] === item) this.splice(i, 1);
  426. }
  427. return this;
  428. },
  429. empty: function(){
  430. this.length = 0;
  431. return this;
  432. },
  433. flatten: function(){
  434. var array = [];
  435. for (var i = 0, l = this.length; i < l; i++){
  436. var type = typeOf(this[i]);
  437. if (type == 'null') continue;
  438. array = array.concat((type == 'array' || type == 'collection' || type == 'arguments' || instanceOf(this[i], Array)) ? Array.flatten(this[i]) : this[i]);
  439. }
  440. return array;
  441. },
  442. pick: function(){
  443. for (var i = 0, l = this.length; i < l; i++){
  444. if (this[i] != null) return this[i];
  445. }
  446. return null;
  447. },
  448. hexToRgb: function(array){
  449. if (this.length != 3) return null;
  450. var rgb = this.map(function(value){
  451. if (value.length == 1) value += value;
  452. return value.toInt(16);
  453. });
  454. return (array) ? rgb : 'rgb(' + rgb + ')';
  455. },
  456. rgbToHex: function(array){
  457. if (this.length < 3) return null;
  458. if (this.length == 4 && this[3] == 0 && !array) return 'transparent';
  459. var hex = [];
  460. for (var i = 0; i < 3; i++){
  461. var bit = (this[i] - 0).toString(16);
  462. hex.push((bit.length == 1) ? '0' + bit : bit);
  463. }
  464. return (array) ? hex : '#' + hex.join('');
  465. }
  466. });
  467. /*
  468. ---
  469. name: String
  470. description: Contains String Prototypes like camelCase, capitalize, test, and toInt.
  471. license: MIT-style license.
  472. requires: Type
  473. provides: String
  474. ...
  475. */
  476. String.implement({
  477. test: function(regex, params){
  478. return ((typeOf(regex) == 'regexp') ? regex : new RegExp('' + regex, params)).test(this);
  479. },
  480. contains: function(string, separator){
  481. return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : String(this).indexOf(string) > -1;
  482. },
  483. trim: function(){
  484. return String(this).replace(/^\s+|\s+$/g, '');
  485. },
  486. clean: function(){
  487. return String(this).replace(/\s+/g, ' ').trim();
  488. },
  489. camelCase: function(){
  490. return String(this).replace(/-\D/g, function(match){
  491. return match.charAt(1).toUpperCase();
  492. });
  493. },
  494. hyphenate: function(){
  495. return String(this).replace(/[A-Z]/g, function(match){
  496. return ('-' + match.charAt(0).toLowerCase());
  497. });
  498. },
  499. capitalize: function(){
  500. return String(this).replace(/\b[a-z]/g, function(match){
  501. return match.toUpperCase();
  502. });
  503. },
  504. escapeRegExp: function(){
  505. return String(this).replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
  506. },
  507. toInt: function(base){
  508. return parseInt(this, base || 10);
  509. },
  510. toFloat: function(){
  511. return parseFloat(this);
  512. },
  513. hexToRgb: function(array){
  514. var hex = String(this).match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
  515. return (hex) ? hex.slice(1).hexToRgb(array) : null;
  516. },
  517. rgbToHex: function(array){
  518. var rgb = String(this).match(/\d{1,3}/g);
  519. return (rgb) ? rgb.rgbToHex(array) : null;
  520. },
  521. substitute: function(object, regexp){
  522. return String(this).replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){
  523. if (match.charAt(0) == '\\') return match.slice(1);
  524. return (object[name] != null) ? object[name] : '';
  525. });
  526. }
  527. });
  528. /*
  529. ---
  530. name: Function
  531. description: Contains Function Prototypes like create, bind, pass, and delay.
  532. license: MIT-style license.
  533. requires: Type
  534. provides: Function
  535. ...
  536. */
  537. Function.extend({
  538. attempt: function(){
  539. for (var i = 0, l = arguments.length; i < l; i++){
  540. try {
  541. return arguments[i]();
  542. } catch (e){}
  543. }
  544. return null;
  545. }
  546. });
  547. Function.implement({
  548. attempt: function(args, bind){
  549. try {
  550. return this.apply(bind, Array.from(args));
  551. } catch (e){}
  552. return null;
  553. },
  554. /*<!ES5-bind>*/
  555. bind: function(that){
  556. var self = this,
  557. args = arguments.length > 1 ? Array.slice(arguments, 1) : null,
  558. F = function(){};
  559. var bound = function(){
  560. var context = that, length = arguments.length;
  561. if (this instanceof bound){
  562. F.prototype = self.prototype;
  563. context = new F;
  564. }
  565. var result = (!args && !length)
  566. ? self.call(context)
  567. : self.apply(context, args && length ? args.concat(Array.slice(arguments)) : args || arguments);
  568. return context == that ? result : context;
  569. };
  570. return bound;
  571. },
  572. /*</!ES5-bind>*/
  573. pass: function(args, bind){
  574. var self = this;
  575. if (args != null) args = Array.from(args);
  576. return function(){
  577. return self.apply(bind, args || arguments);
  578. };
  579. },
  580. delay: function(delay, bind, args){
  581. return setTimeout(this.pass((args == null ? [] : args), bind), delay);
  582. },
  583. periodical: function(periodical, bind, args){
  584. return setInterval(this.pass((args == null ? [] : args), bind), periodical);
  585. }
  586. });
  587. /*
  588. ---
  589. name: Number
  590. description: Contains Number Prototypes like limit, round, times, and ceil.
  591. license: MIT-style license.
  592. requires: Type
  593. provides: Number
  594. ...
  595. */
  596. Number.implement({
  597. limit: function(min, max){
  598. return Math.min(max, Math.max(min, this));
  599. },
  600. round: function(precision){
  601. precision = Math.pow(10, precision || 0).toFixed(precision < 0 ? -precision : 0);
  602. return Math.round(this * precision) / precision;
  603. },
  604. times: function(fn, bind){
  605. for (var i = 0; i < this; i++) fn.call(bind, i, this);
  606. },
  607. toFloat: function(){
  608. return parseFloat(this);
  609. },
  610. toInt: function(base){
  611. return parseInt(this, base || 10);
  612. }
  613. });
  614. Number.alias('each', 'times');
  615. (function(math){
  616. var methods = {};
  617. math.each(function(name){
  618. if (!Number[name]) methods[name] = function(){
  619. return Math[name].apply(null, [this].concat(Array.from(arguments)));
  620. };
  621. });
  622. Number.implement(methods);
  623. })(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']);
  624. /*
  625. ---
  626. name: Class
  627. description: Contains the Class Function for easily creating, extending, and implementing reusable Classes.
  628. license: MIT-style license.
  629. requires: [Array, String, Function, Number]
  630. provides: Class
  631. ...
  632. */
  633. (function(){
  634. var Class = this.Class = new Type('Class', function(params){
  635. if (instanceOf(params, Function)) params = {initialize: params};
  636. var newClass = function(){
  637. reset(this);
  638. if (newClass.$prototyping) return this;
  639. this.$caller = null;
  640. var value = (this.initialize) ? this.initialize.apply(this, arguments) : this;
  641. this.$caller = this.caller = null;
  642. return value;
  643. }.extend(this).implement(params);
  644. newClass.$constructor = Class;
  645. newClass.prototype.$constructor = newClass;
  646. newClass.prototype.parent = parent;
  647. return newClass;
  648. });
  649. var parent = function(){
  650. if (!this.$caller) throw new Error('The method "parent" cannot be called.');
  651. var name = this.$caller.$name,
  652. parent = this.$caller.$owner.parent,
  653. previous = (parent) ? parent.prototype[name] : null;
  654. if (!previous) throw new Error('The method "' + name + '" has no parent.');
  655. return previous.apply(this, arguments);
  656. };
  657. var reset = function(object){
  658. for (var key in object){
  659. var value = object[key];
  660. switch (typeOf(value)){
  661. case 'object':
  662. var F = function(){};
  663. F.prototype = value;
  664. object[key] = reset(new F);
  665. break;
  666. case 'array': object[key] = value.clone(); break;
  667. }
  668. }
  669. return object;
  670. };
  671. var wrap = function(self, key, method){
  672. if (method.$origin) method = method.$origin;
  673. var wrapper = function(){
  674. if (method.$protected && this.$caller == null) throw new Error('The method "' + key + '" cannot be called.');
  675. var caller = this.caller, current = this.$caller;
  676. this.caller = current; this.$caller = wrapper;
  677. var result = method.apply(this, arguments);
  678. this.$caller = current; this.caller = caller;
  679. return result;
  680. }.extend({$owner: self, $origin: method, $name: key});
  681. return wrapper;
  682. };
  683. var implement = function(key, value, retain){
  684. if (Class.Mutators.hasOwnProperty(key)){
  685. value = Class.Mutators[key].call(this, value);
  686. if (value == null) return this;
  687. }
  688. if (typeOf(value) == 'function'){
  689. if (value.$hidden) return this;
  690. this.prototype[key] = (retain) ? value : wrap(this, key, value);
  691. } else {
  692. Object.merge(this.prototype, key, value);
  693. }
  694. return this;
  695. };
  696. var getInstance = function(klass){
  697. klass.$prototyping = true;
  698. var proto = new klass;
  699. delete klass.$prototyping;
  700. return proto;
  701. };
  702. Class.implement('implement', implement.overloadSetter());
  703. Class.Mutators = {
  704. Extends: function(parent){
  705. this.parent = parent;
  706. this.prototype = getInstance(parent);
  707. },
  708. Implements: function(items){
  709. Array.from(items).each(function(item){
  710. var instance = new item;
  711. for (var key in instance) implement.call(this, key, instance[key], true);
  712. }, this);
  713. }
  714. };
  715. })();
  716. /*
  717. ---
  718. name: Class.Extras
  719. description: Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks.
  720. license: MIT-style license.
  721. requires: Class
  722. provides: [Class.Extras, Chain, Events, Options]
  723. ...
  724. */
  725. (function(){
  726. this.Chain = new Class({
  727. $chain: [],
  728. chain: function(){
  729. this.$chain.append(Array.flatten(arguments));
  730. return this;
  731. },
  732. callChain: function(){
  733. return (this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false;
  734. },
  735. clearChain: function(){
  736. this.$chain.empty();
  737. return this;
  738. }
  739. });
  740. var removeOn = function(string){
  741. return string.replace(/^on([A-Z])/, function(full, first){
  742. return first.toLowerCase();
  743. });
  744. };
  745. this.Events = new Class({
  746. $events: {},
  747. addEvent: function(type, fn, internal){
  748. type = removeOn(type);
  749. this.$events[type] = (this.$events[type] || []).include(fn);
  750. if (internal) fn.internal = true;
  751. return this;
  752. },
  753. addEvents: function(events){
  754. for (var type in events) this.addEvent(type, events[type]);
  755. return this;
  756. },
  757. fireEvent: function(type, args, delay){
  758. type = removeOn(type);
  759. var events = this.$events[type];
  760. if (!events) return this;
  761. args = Array.from(args);
  762. events.each(function(fn){
  763. if (delay) fn.delay(delay, this, args);
  764. else fn.apply(this, args);
  765. }, this);
  766. return this;
  767. },
  768. removeEvent: function(type, fn){
  769. type = removeOn(type);
  770. var events = this.$events[type];
  771. if (events && !fn.internal){
  772. var index = events.indexOf(fn);
  773. if (index != -1) delete events[index];
  774. }
  775. return this;
  776. },
  777. removeEvents: function(events){
  778. var type;
  779. if (typeOf(events) == 'object'){
  780. for (type in events) this.removeEvent(type, events[type]);
  781. return this;
  782. }
  783. if (events) events = removeOn(events);
  784. for (type in this.$events){
  785. if (events && events != type) continue;
  786. var fns = this.$events[type];
  787. for (var i = fns.length; i--;) if (i in fns){
  788. this.removeEvent(type, fns[i]);
  789. }
  790. }
  791. return this;
  792. }
  793. });
  794. this.Options = new Class({
  795. setOptions: function(){
  796. var options = this.options = Object.merge.apply(null, [{}, this.options].append(arguments));
  797. if (this.addEvent) for (var option in options){
  798. if (typeOf(options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue;
  799. this.addEvent(option, options[option]);
  800. delete options[option];
  801. }
  802. return this;
  803. }
  804. });
  805. })();
  806. /*
  807. ---
  808. name: Object
  809. description: Object generic methods
  810. license: MIT-style license.
  811. requires: Type
  812. provides: [Object, Hash]
  813. ...
  814. */
  815. (function(){
  816. var hasOwnProperty = Object.prototype.hasOwnProperty;
  817. Object.extend({
  818. subset: function(object, keys){
  819. var results = {};
  820. for (var i = 0, l = keys.length; i < l; i++){
  821. var k = keys[i];
  822. if (k in object) results[k] = object[k];
  823. }
  824. return results;
  825. },
  826. map: function(object, fn, bind){
  827. var results = {};
  828. for (var key in object){
  829. if (hasOwnProperty.call(object, key)) results[key] = fn.call(bind, object[key], key, object);
  830. }
  831. return results;
  832. },
  833. filter: function(object, fn, bind){
  834. var results = {};
  835. for (var key in object){
  836. var value = object[key];
  837. if (hasOwnProperty.call(object, key) && fn.call(bind, value, key, object)) results[key] = value;
  838. }
  839. return results;
  840. },
  841. every: function(object, fn, bind){
  842. for (var key in object){
  843. if (hasOwnProperty.call(object, key) && !fn.call(bind, object[key], key)) return false;
  844. }
  845. return true;
  846. },
  847. some: function(object, fn, bind){
  848. for (var key in object){
  849. if (hasOwnProperty.call(object, key) && fn.call(bind, object[key], key)) return true;
  850. }
  851. return false;
  852. },
  853. keys: function(object){
  854. var keys = [];
  855. for (var key in object){
  856. if (hasOwnProperty.call(object, key)) keys.push(key);
  857. }
  858. return keys;
  859. },
  860. values: function(object){
  861. var values = [];
  862. for (var key in object){
  863. if (hasOwnProperty.call(object, key)) values.push(object[key]);
  864. }
  865. return values;
  866. },
  867. getLength: function(object){
  868. return Object.keys(object).length;
  869. },
  870. keyOf: function(object, value){
  871. for (var key in object){
  872. if (hasOwnProperty.call(object, key) && object[key] === value) return key;
  873. }
  874. return null;
  875. },
  876. contains: function(object, value){
  877. return Object.keyOf(object, value) != null;
  878. },
  879. toQueryString: function(object, base){
  880. var queryString = [];
  881. Object.each(object, function(value, key){
  882. if (base) key = base + '[' + key + ']';
  883. var result;
  884. switch (typeOf(value)){
  885. case 'object': result = Object.toQueryString(value, key); break;
  886. case 'array':
  887. var qs = {};
  888. value.each(function(val, i){
  889. qs[i] = val;
  890. });
  891. result = Object.toQueryString(qs, key);
  892. break;
  893. default: result = key + '=' + encodeURIComponent(value);
  894. }
  895. if (value != null) queryString.push(result);
  896. });
  897. return queryString.join('&');
  898. }
  899. });
  900. })();
  901. /*
  902. ---
  903. name: Loader
  904. description: Loads MooTools as a CommonJS Module.
  905. license: MIT-style license.
  906. copyright: Copyright (c) 2010 [Christoph Pojer](http://cpojer.net/).
  907. authors: Christoph Pojer
  908. requires: [Core/Core, Core/Object]
  909. provides: [Loader]
  910. ...
  911. */
  912. if (typeof exports != 'undefined') (function(){
  913. for (var key in this) if (!GLOBAL_ITEMS.contains(key)){
  914. exports[key] = this[key];
  915. }
  916. exports.apply = function(object){
  917. Object.append(object, exports);
  918. };
  919. })();
  920. /*
  921. ---
  922. script: More.js
  923. name: More
  924. description: MooTools More
  925. license: MIT-style license
  926. authors:
  927. - Guillermo Rauch
  928. - Thomas Aylott
  929. - Scott Kyle
  930. - Arian Stolwijk
  931. - Tim Wienk
  932. - Christoph Pojer
  933. - Aaron Newton
  934. - Jacob Thornton
  935. requires:
  936. - Core/MooTools
  937. provides: [MooTools.More]
  938. ...
  939. */
  940. MooTools.More = {
  941. version: '1.6.1-dev',
  942. build: '%build%'
  943. };
  944. /*
  945. ---
  946. script: Object.Extras.js
  947. name: Object.Extras
  948. description: Extra Object generics, like getFromPath which allows a path notation to child elements.
  949. license: MIT-style license
  950. authors:
  951. - Aaron Newton
  952. requires:
  953. - Core/Object
  954. - MooTools.More
  955. provides: [Object.Extras]
  956. ...
  957. */
  958. (function(){
  959. var defined = function(value){
  960. return value != null;
  961. };
  962. var hasOwnProperty = Object.prototype.hasOwnProperty;
  963. Object.extend({
  964. getFromPath: function(source, parts){
  965. if (typeof parts == 'string') parts = parts.split('.');
  966. for (var i = 0, l = parts.length; i < l; i++){
  967. if (hasOwnProperty.call(source, parts[i])) source = source[parts[i]];
  968. else return null;
  969. }
  970. return source;
  971. },
  972. cleanValues: function(object, method){
  973. method = method || defined;
  974. for (var key in object) if (!method(object[key])){
  975. delete object[key];
  976. }
  977. return object;
  978. },
  979. erase: function(object, key){
  980. if (hasOwnProperty.call(object, key)) delete object[key];
  981. return object;
  982. },
  983. run: function(object){
  984. var args = Array.slice(arguments, 1);
  985. for (var key in object) if (object[key].apply){
  986. object[key].apply(object, args);
  987. }
  988. return object;
  989. }
  990. });
  991. })();
  992. /*
  993. ---
  994. script: Locale.js
  995. name: Locale
  996. description: Provides methods for localization.
  997. license: MIT-style license
  998. authors:
  999. - Aaron Newton
  1000. - Arian Stolwijk
  1001. requires:
  1002. - Core/Events
  1003. - Object.Extras
  1004. - MooTools.More
  1005. provides: [Locale, Lang]
  1006. ...
  1007. */
  1008. (function(){
  1009. var current = null,
  1010. locales = {},
  1011. inherits = {};
  1012. var getSet = function(set){
  1013. if (instanceOf(set, Locale.Set)) return set;
  1014. else return locales[set];
  1015. };
  1016. var Locale = this.Locale = {
  1017. define: function(locale, set, key, value){
  1018. var name;
  1019. if (instanceOf(locale, Locale.Set)){
  1020. name = locale.name;
  1021. if (name) locales[name] = locale;
  1022. } else {
  1023. name = locale;
  1024. if (!locales[name]) locales[name] = new Locale.Set(name);
  1025. locale = locales[name];
  1026. }
  1027. if (set) locale.define(set, key, value);
  1028. if (!current) current = locale;
  1029. return locale;
  1030. },
  1031. use: function(locale){
  1032. locale = getSet(locale);
  1033. if (locale){
  1034. current = locale;
  1035. this.fireEvent('change', locale);
  1036. }
  1037. return this;
  1038. },
  1039. getCurrent: function(){
  1040. return current;
  1041. },
  1042. get: function(key, args){
  1043. return (current) ? current.get(key, args) : '';
  1044. },
  1045. inherit: function(locale, inherits, set){
  1046. locale = getSet(locale);
  1047. if (locale) locale.inherit(inherits, set);
  1048. return this;
  1049. },
  1050. list: function(){
  1051. return Object.keys(locales);
  1052. }
  1053. };
  1054. Object.append(Locale, new Events);
  1055. Locale.Set = new Class({
  1056. sets: {},
  1057. inherits: {
  1058. locales: [],
  1059. sets: {}
  1060. },
  1061. initialize: function(name){
  1062. this.name = name || '';
  1063. },
  1064. define: function(set, key, value){
  1065. var defineData = this.sets[set];
  1066. if (!defineData) defineData = {};
  1067. if (key){
  1068. if (typeOf(key) == 'object') defineData = Object.merge(defineData, key);
  1069. else defineData[key] = value;
  1070. }
  1071. this.sets[set] = defineData;
  1072. return this;
  1073. },
  1074. get: function(key, args, _base){
  1075. var value = Object.getFromPath(this.sets, key);
  1076. if (value != null){
  1077. var type = typeOf(value);
  1078. if (type == 'function') value = value.apply(null, Array.convert(args));
  1079. else if (type == 'object') value = Object.clone(value);
  1080. return value;
  1081. }
  1082. // get value of inherited locales
  1083. var index = key.indexOf('.'),
  1084. set = index < 0 ? key : key.substr(0, index),
  1085. names = (this.inherits.sets[set] || []).combine(this.inherits.locales).include('en-US');
  1086. if (!_base) _base = [];
  1087. for (var i = 0, l = names.length; i < l; i++){
  1088. if (_base.contains(names[i])) continue;
  1089. _base.include(names[i]);
  1090. var locale = locales[names[i]];
  1091. if (!locale) continue;
  1092. value = locale.get(key, args, _base);
  1093. if (value != null) return value;
  1094. }
  1095. return '';
  1096. },
  1097. inherit: function(names, set){
  1098. names = Array.convert(names);
  1099. if (set && !this.inherits.sets[set]) this.inherits.sets[set] = [];
  1100. var l = names.length;
  1101. while (l--) (set ? this.inherits.sets[set] : this.inherits.locales).unshift(names[l]);
  1102. return this;
  1103. }
  1104. });
  1105. })();
  1106. /*
  1107. ---
  1108. name: Locale.en-US.Date
  1109. description: Date messages for US English.
  1110. license: MIT-style license
  1111. authors:
  1112. - Aaron Newton
  1113. requires:
  1114. - Locale
  1115. provides: [Locale.en-US.Date]
  1116. ...
  1117. */
  1118. Locale.define('en-US', 'Date', {
  1119. months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
  1120. months_abbr: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
  1121. days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
  1122. days_abbr: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
  1123. // Culture's date order: MM/DD/YYYY
  1124. dateOrder: ['month', 'date', 'year'],
  1125. shortDate: '%m/%d/%Y',
  1126. shortTime: '%I:%M%p',
  1127. AM: 'AM',
  1128. PM: 'PM',
  1129. firstDayOfWeek: 0,
  1130. // Date.Extras
  1131. ordinal: function(dayOfMonth){
  1132. // 1st, 2nd, 3rd, etc.
  1133. return (dayOfMonth > 3 && dayOfMonth < 21) ? 'th' : ['th', 'st', 'nd', 'rd', 'th'][Math.min(dayOfMonth % 10, 4)];
  1134. },
  1135. lessThanMinuteAgo: 'less than a minute ago',
  1136. minuteAgo: 'about a minute ago',
  1137. minutesAgo: '{delta} minutes ago',
  1138. hourAgo: 'about an hour ago',
  1139. hoursAgo: 'about {delta} hours ago',
  1140. dayAgo: '1 day ago',
  1141. daysAgo: '{delta} days ago',
  1142. weekAgo: '1 week ago',
  1143. weeksAgo: '{delta} weeks ago',
  1144. monthAgo: '1 month ago',
  1145. monthsAgo: '{delta} months ago',
  1146. yearAgo: '1 year ago',
  1147. yearsAgo: '{delta} years ago',
  1148. lessThanMinuteUntil: 'less than a minute from now',
  1149. minuteUntil: 'about a minute from now',
  1150. minutesUntil: '{delta} minutes from now',
  1151. hourUntil: 'about an hour from now',
  1152. hoursUntil: 'about {delta} hours from now',
  1153. dayUntil: '1 day from now',
  1154. daysUntil: '{delta} days from now',
  1155. weekUntil: '1 week from now',
  1156. weeksUntil: '{delta} weeks from now',
  1157. monthUntil: '1 month from now',
  1158. monthsUntil: '{delta} months from now',
  1159. yearUntil: '1 year from now',
  1160. yearsUntil: '{delta} years from now'
  1161. });
  1162. /*
  1163. ---
  1164. script: Date.js
  1165. name: Date
  1166. description: Extends the Date native object to include methods useful in managing dates.
  1167. license: MIT-style license
  1168. authors:
  1169. - Aaron Newton
  1170. - Nicholas Barthelemy - https://svn.nbarthelemy.com/date-js/
  1171. - Harald Kirshner - mail [at] digitarald.de; http://digitarald.de
  1172. - Scott Kyle - scott [at] appden.com; http://appden.com
  1173. requires:
  1174. - Core/Array
  1175. - Core/String
  1176. - Core/Number
  1177. - MooTools.More
  1178. - Locale
  1179. - Locale.en-US.Date
  1180. provides: [Date]
  1181. ...
  1182. */
  1183. (function(){
  1184. var Date = this.Date;
  1185. var DateMethods = Date.Methods = {
  1186. ms: 'Milliseconds',
  1187. year: 'FullYear',
  1188. min: 'Minutes',
  1189. mo: 'Month',
  1190. sec: 'Seconds',
  1191. hr: 'Hours'
  1192. };
  1193. [
  1194. 'Date', 'Day', 'FullYear', 'Hours', 'Milliseconds', 'Minutes', 'Month', 'Seconds', 'Time', 'TimezoneOffset',
  1195. 'Week', 'Timezone', 'GMTOffset', 'DayOfYear', 'LastMonth', 'LastDayOfMonth', 'UTCDate', 'UTCDay', 'UTCFullYear',
  1196. 'AMPM', 'Ordinal', 'UTCHours', 'UTCMilliseconds', 'UTCMinutes', 'UTCMonth', 'UTCSeconds', 'UTCMilliseconds'
  1197. ].each(function(method){
  1198. Date.Methods[method.toLowerCase()] = method;
  1199. });
  1200. var pad = function(n, digits, string){
  1201. if (digits == 1) return n;
  1202. return n < Math.pow(10, digits - 1) ? (string || '0') + pad(n, digits - 1, string) : n;
  1203. };
  1204. Date.implement({
  1205. set: function(prop, value){
  1206. prop = prop.toLowerCase();
  1207. var method = DateMethods[prop] && 'set' + DateMethods[prop];
  1208. if (method && this[method]) this[method](value);
  1209. return this;
  1210. }.overloadSetter(),
  1211. get: function(prop){
  1212. prop = prop.toLowerCase();
  1213. var method = DateMethods[prop] && 'get' + DateMethods[prop];
  1214. if (method && this[method]) return this[method]();
  1215. return null;
  1216. }.overloadGetter(),
  1217. clone: function(){
  1218. return new Date(this.get('time'));
  1219. },
  1220. increment: function(interval, times){
  1221. interval = interval || 'day';
  1222. times = times != null ? times : 1;
  1223. switch (interval){
  1224. case 'year':
  1225. return this.increment('month', times * 12);
  1226. case 'month':
  1227. var d = this.get('date');
  1228. this.set('date', 1).set('mo', this.get('mo') + times);
  1229. return this.set('date', d.min(this.get('lastdayofmonth')));
  1230. case 'week':
  1231. return this.increment('day', times * 7);
  1232. case 'day':
  1233. return this.set('date', this.get('date') + times);
  1234. }
  1235. if (!Date.units[interval]) throw new Error(interval + ' is not a supported interval');
  1236. return this.set('time', this.get('time') + times * Date.units[interval]());
  1237. },
  1238. decrement: function(interval, times){
  1239. return this.increment(interval, -1 * (times != null ? times : 1));
  1240. },
  1241. isLeapYear: function(){
  1242. return Date.isLeapYear(this.get('year'));
  1243. },
  1244. clearTime: function(){
  1245. return this.set({hr: 0, min: 0, sec: 0, ms: 0});
  1246. },
  1247. diff: function(date, resolution){
  1248. if (typeOf(date) == 'string') date = Date.parse(date);
  1249. return ((date - this) / Date.units[resolution || 'day'](3, 3)).round(); // non-leap year, 30-day month
  1250. },
  1251. getLastDayOfMonth: function(){
  1252. return Date.daysInMonth(this.get('mo'), this.get('year'));
  1253. },
  1254. getDayOfYear: function(){
  1255. return (Date.UTC(this.get('year'), this.get('mo'), this.get('date') + 1)
  1256. - Date.UTC(this.get('year'), 0, 1)) / Date.units.day();
  1257. },
  1258. setDay: function(day, firstDayOfWeek){
  1259. if (firstDayOfWeek == null){
  1260. firstDayOfWeek = Date.getMsg('firstDayOfWeek');
  1261. if (firstDayOfWeek === '') firstDayOfWeek = 1;
  1262. }
  1263. day = (7 + Date.parseDay(day, true) - firstDayOfWeek) % 7;
  1264. var currentDay = (7 + this.get('day') - firstDayOfWeek) % 7;
  1265. return this.increment('day', day - currentDay);
  1266. },
  1267. getWeek: function(firstDayOfWeek){
  1268. if (firstDayOfWeek == null){
  1269. firstDayOfWeek = Date.getMsg('firstDayOfWeek');
  1270. if (firstDayOfWeek === '') firstDayOfWeek = 1;
  1271. }
  1272. var date = this,
  1273. dayOfWeek = (7 + date.get('day') - firstDayOfWeek) % 7,
  1274. dividend = 0,
  1275. firstDayOfYear;
  1276. if (firstDayOfWeek == 1){
  1277. // ISO-8601, week belongs to year that has the most days of the week (i.e. has the thursday of the week)
  1278. var month = date.get('month'),
  1279. startOfWeek = date.get('date') - dayOfWeek;
  1280. if (month == 11 && startOfWeek > 28) return 1; // Week 1 of next year
  1281. if (month == 0 && startOfWeek < -2){
  1282. // Use a date from last year to determine the week
  1283. date = new Date(date).decrement('day', dayOfWeek);
  1284. dayOfWeek = 0;
  1285. }
  1286. firstDayOfYear = new Date(date.get('year'), 0, 1).get('day') || 7;
  1287. if (firstDayOfYear > 4) dividend = -7; // First week of the year is not week 1
  1288. } else {
  1289. // In other cultures the first week of the year is always week 1 and the last week always 53 or 54.
  1290. // Days in the same week can have a different weeknumber if the week spreads across two years.
  1291. firstDayOfYear = new Date(date.get('year'), 0, 1).get('day');
  1292. }
  1293. dividend += date.get('dayofyear');
  1294. dividend += 6 - dayOfWeek; // Add days so we calculate the current date's week as a full week
  1295. dividend += (7 + firstDayOfYear - firstDayOfWeek) % 7; // Make up for first week of the year not being a full week
  1296. return (dividend / 7);
  1297. },
  1298. getOrdinal: function(day){
  1299. return Date.getMsg('ordinal', day || this.get('date'));
  1300. },
  1301. getTimezone: function(){
  1302. return this.toString()
  1303. .replace(/^.*? ([A-Z]{3}).[0-9]{4}.*$/, '$1')
  1304. .replace(/^.*?\(([A-Z])[a-z]+ ([A-Z])[a-z]+ ([A-Z])[a-z]+\)$/, '$1$2$3');
  1305. },
  1306. getGMTOffset: function(){
  1307. var off = this.get('timezoneOffset');
  1308. return ((off > 0) ? '-' : '+') + pad((off.abs() / 60).floor(), 2) + pad(off % 60, 2);
  1309. },
  1310. setAMPM: function(ampm){
  1311. ampm = ampm.toUpperCase();
  1312. var hr = this.get('hr');
  1313. if (hr > 11 && ampm == 'AM') return this.decrement('hour', 12);
  1314. else if (hr < 12 && ampm == 'PM') return this.increment('hour', 12);
  1315. return this;
  1316. },
  1317. getAMPM: function(){
  1318. return (this.get('hr') < 12) ? 'AM' : 'PM';
  1319. },
  1320. parse: function(str){
  1321. this.set('time', Date.parse(str));
  1322. return this;
  1323. },
  1324. isValid: function(date){
  1325. if (!date) date = this;
  1326. return typeOf(date) == 'date' && !isNaN(date.valueOf());
  1327. },
  1328. format: function(format){
  1329. if (!this.isValid()) return 'invalid date';
  1330. if (!format) format = '%x %X';
  1331. if (typeof format == 'string') format = formats[format.toLowerCase()] || format;
  1332. if (typeof format == 'function') return format(this);
  1333. var d = this;
  1334. return format.replace(/%([a-z%])/gi,
  1335. function($0, $1){
  1336. switch ($1){
  1337. case 'a': return Date.getMsg('days_abbr')[d.get('day')];
  1338. case 'A': return Date.getMsg('days')[d.get('day')];
  1339. case 'b': return Date.getMsg('months_abbr')[d.get('month')];
  1340. case 'B': return Date.getMsg('months')[d.get('month')];
  1341. case 'c': return d.format('%a %b %d %H:%M:%S %Y');
  1342. case 'd': return pad(d.get('date'), 2);
  1343. case 'e': return pad(d.get('date'), 2, ' ');
  1344. case 'H': return pad(d.get('hr'), 2);
  1345. case 'I': return pad((d.get('hr') % 12) || 12, 2);
  1346. case 'j': return pad(d.get('dayofyear'), 3);
  1347. case 'k': return pad(d.get('hr'), 2, ' ');
  1348. case 'l': return pad((d.get('hr') % 12) || 12, 2, ' ');
  1349. case 'L': return pad(d.get('ms'), 3);
  1350. case 'm': return pad((d.get('mo') + 1), 2);
  1351. case 'M': return pad(d.get('min'), 2);
  1352. case 'o': return d.get('ordinal');
  1353. case 'p': return Date.getMsg(d.get('ampm'));
  1354. case 's': return Math.round(d / 1000);
  1355. case 'S': return pad(d.get('seconds'), 2);
  1356. case 'T': return d.format('%H:%M:%S');
  1357. case 'U': return pad(d.get('week'), 2);
  1358. case 'w': return d.get('day');
  1359. case 'x': return d.format(Date.getMsg('shortDate'));
  1360. case 'X': return d.format(Date.getMsg('shortTime'));
  1361. case 'y': return d.get('year').toString().substr(2);
  1362. case 'Y': return d.get('year');
  1363. case 'z': return d.get('GMTOffset');
  1364. case 'Z': return d.get('Timezone');
  1365. }
  1366. return $1;
  1367. }
  1368. );
  1369. },
  1370. toISOString: function(){
  1371. return this.format('iso8601');
  1372. }
  1373. }).alias({
  1374. toJSON: 'toISOString',
  1375. compare: 'diff',
  1376. strftime: 'format'
  1377. });
  1378. // The day and month abbreviations are standardized, so we cannot use simply %a and %b because they will get localized
  1379. var rfcDayAbbr = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
  1380. rfcMonthAbbr = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
  1381. var formats = {
  1382. db: '%Y-%m-%d %H:%M:%S',
  1383. compact: '%Y%m%dT%H%M%S',
  1384. 'short': '%d %b %H:%M',
  1385. 'long': '%B %d, %Y %H:%M',
  1386. rfc822: function(date){
  1387. return rfcDayAbbr[date.get('day')] + date.format(', %d ') + rfcMonthAbbr[date.get('month')] + date.format(' %Y %H:%M:%S %Z');
  1388. },
  1389. rfc2822: function(date){
  1390. return rfcDayAbbr[date.get('day')] + date.format(', %d ') + rfcMonthAbbr[date.get('month')] + date.format(' %Y %H:%M:%S %z');
  1391. },
  1392. iso8601: function(date){
  1393. return (
  1394. date.getUTCFullYear() + '-' +
  1395. pad(date.getUTCMonth() + 1, 2) + '-' +
  1396. pad(date.getUTCDate(), 2) + 'T' +
  1397. pad(date.getUTCHours(), 2) + ':' +
  1398. pad(date.getUTCMinutes(), 2) + ':' +
  1399. pad(date.getUTCSeconds(), 2) + '.' +
  1400. pad(date.getUTCMilliseconds(), 3) + 'Z'
  1401. );
  1402. }
  1403. };
  1404. var parsePatterns = [],
  1405. nativeParse = Date.parse;
  1406. var parseWord = function(type, word, num){
  1407. var ret = -1,
  1408. translated = Date.getMsg(type + 's');
  1409. switch (typeOf(word)){
  1410. case 'object':
  1411. ret = translated[word.get(type)];
  1412. break;
  1413. case 'number':
  1414. ret = translated[word];
  1415. if (!ret) throw new Error('Invalid ' + type + ' index: ' + word);
  1416. break;
  1417. case 'string':
  1418. var match = translated.filter(function(name){
  1419. return this.test(name);
  1420. }, new RegExp('^' + word, 'i'));
  1421. if (!match.length) throw new Error('Invalid ' + type + ' string');
  1422. if (match.length > 1) throw new Error('Ambiguous ' + type);
  1423. ret = match[0];
  1424. }
  1425. return (num) ? translated.indexOf(ret) : ret;
  1426. };
  1427. var startCentury = 1900,
  1428. startYear = 70;
  1429. Date.extend({
  1430. getMsg: function(key, args){
  1431. return Locale.get('Date.' + key, args);
  1432. },
  1433. units: {
  1434. ms: Function.convert(1),
  1435. second: Function.convert(1000),
  1436. minute: Function.convert(60000),
  1437. hour: Function.convert(3600000),
  1438. day: Function.convert(86400000),
  1439. week: Function.convert(608400000),
  1440. month: function(month, year){
  1441. var d = new Date;
  1442. return Date.daysInMonth(month != null ? month : d.get('mo'), year != null ? year : d.get('year')) * 86400000;
  1443. },
  1444. year: function(year){
  1445. year = year || new Date().get('year');
  1446. return Date.isLeapYear(year) ? 31622400000 : 31536000000;
  1447. }
  1448. },
  1449. daysInMonth: function(month, year){
  1450. return [31, Date.isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
  1451. },
  1452. isLeapYear: function(year){
  1453. return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
  1454. },
  1455. parse: function(from){
  1456. var t = typeOf(from);
  1457. if (t == 'number') return new Date(from);
  1458. if (t != 'string') return from;
  1459. from = from.clean();
  1460. if (!from.length) return null;
  1461. var parsed;
  1462. parsePatterns.some(function(pattern){
  1463. var bits = pattern.re.exec(from);
  1464. return (bits) ? (parsed = pattern.handler(bits)) : false;
  1465. });
  1466. if (!(parsed && parsed.isValid())){
  1467. parsed = new Date(nativeParse(from));
  1468. if (!(parsed && parsed.isValid())) parsed = new Date(from.toInt());
  1469. }
  1470. return parsed;
  1471. },
  1472. parseDay: function(day, num){
  1473. return parseWord('day', day, num);
  1474. },
  1475. parseMonth: function(month, num){
  1476. return parseWord('month', month, num);
  1477. },
  1478. parseUTC: function(value){
  1479. var localDate = new Date(value);
  1480. var utcSeconds = Date.UTC(
  1481. localDate.get('year'),
  1482. localDate.get('mo'),
  1483. localDate.get('date'),
  1484. localDate.get('hr'),
  1485. localDate.get('min'),
  1486. localDate.get('sec'),
  1487. localDate.get('ms')
  1488. );
  1489. return new Date(utcSeconds);
  1490. },
  1491. orderIndex: function(unit){
  1492. return Date.getMsg('dateOrder').indexOf(unit) + 1;
  1493. },
  1494. defineFormat: function(name, format){
  1495. formats[name] = format;
  1496. return this;
  1497. },
  1498. defineParser: function(pattern){
  1499. parsePatterns.push((pattern.re && pattern.handler) ? pattern : build(pattern));
  1500. return this;
  1501. },
  1502. defineParsers: function(){
  1503. Array.flatten(arguments).each(Date.defineParser);
  1504. return this;
  1505. },
  1506. define2DigitYearStart: function(year){
  1507. startYear = year % 100;
  1508. startCentury = year - startYear;
  1509. return this;
  1510. }
  1511. }).extend({
  1512. defineFormats: Date.defineFormat.overloadSetter()
  1513. });
  1514. var regexOf = function(type){
  1515. return new RegExp('(?:' + Date.getMsg(type).map(function(name){
  1516. return name.substr(0, 3);
  1517. }).join('|') + ')[a-z]*');
  1518. };
  1519. var replacers = function(key){
  1520. switch (key){
  1521. case 'T':
  1522. return '%H:%M:%S';
  1523. case 'x': // iso8601 covers yyyy-mm-dd, so just check if month is first
  1524. return ((Date.orderIndex('month') == 1) ? '%m[-./]%d' : '%d[-./]%m') + '([-./]%y)?';
  1525. case 'X':
  1526. return '%H([.:]%M)?([.:]%S([.:]%s)?)? ?%p? ?%z?';
  1527. }
  1528. return null;
  1529. };
  1530. var keys = {
  1531. d: /[0-2]?[0-9]|3[01]/,
  1532. H: /[01]?[0-9]|2[0-3]/,
  1533. I: /0?[1-9]|1[0-2]/,
  1534. M: /[0-5]?\d/,
  1535. s: /\d+/,
  1536. o: /[a-z]*/,
  1537. p: /[ap]\.?m\.?/,
  1538. y: /\d{2}|\d{4}/,
  1539. Y: /\d{4}/,
  1540. z: /Z|[+-]\d{2}(?::?\d{2})?/
  1541. };
  1542. keys.m = keys.I;
  1543. keys.S = keys.M;
  1544. var currentLanguage;
  1545. var recompile = function(language){
  1546. currentLanguage = language;
  1547. keys.a = keys.A = regexOf('days');
  1548. keys.b = keys.B = regexOf('months');
  1549. parsePatterns.each(function(pattern, i){
  1550. if (pattern.format) parsePatterns[i] = build(pattern.format);
  1551. });
  1552. };
  1553. var build = function(format){
  1554. if (!currentLanguage) return {format: format};
  1555. var parsed = [];
  1556. var re = (format.source || format) // allow format to be regex
  1557. .replace(/%([a-z])/gi,
  1558. function($0, $1){
  1559. return replacers($1) || $0;
  1560. }
  1561. ).replace(/\((?!\?)/g, '(?:') // make all groups non-capturing
  1562. .replace(/ (?!\?|\*)/g, ',? ') // be forgiving with spaces and commas
  1563. .replace(/%([a-z%])/gi,
  1564. function($0, $1){
  1565. var p = keys[$1];
  1566. if (!p) return $1;
  1567. parsed.push($1);
  1568. return '(' + p.source + ')';
  1569. }
  1570. ).replace(/\[a-z\]/gi, '[a-z\\u00c0-\\uffff;\&]'); // handle unicode words
  1571. return {
  1572. format: format,
  1573. re: new RegExp('^' + re + '$', 'i'),
  1574. handler: function(bits){
  1575. bits = bits.slice(1).associate(parsed);
  1576. var date = new Date().clearTime(),
  1577. year = bits.y || bits.Y;
  1578. if (year != null) handle.call(date, 'y', year); // need to start in the right year
  1579. if ('d' in bits) handle.call(date, 'd', 1);
  1580. if ('m' in bits || bits.b || bits.B) handle.call(date, 'm', 1);
  1581. for (var key in bits) handle.call(date, key, bits[key]);
  1582. return date;
  1583. }
  1584. };
  1585. };
  1586. var handle = function(key, value){
  1587. if (!value) return this;
  1588. switch (key){
  1589. case 'a': case 'A': return this.set('day', Date.parseDay(value, true));
  1590. case 'b': case 'B': return this.set('mo', Date.parseMonth(value, true));
  1591. case 'd': return this.set('date', value);
  1592. case 'H': case 'I': return this.set('hr', value);
  1593. case 'm': return this.set('mo', value - 1);
  1594. case 'M': return this.set('min', value);
  1595. case 'p': return this.set('ampm', value.replace(/\./g, ''));
  1596. case 'S': return this.set('sec', value);
  1597. case 's': return this.set('ms', ('0.' + value) * 1000);
  1598. case 'w': return this.set('day', value);
  1599. case 'Y': return this.set('year', value);
  1600. case 'y':
  1601. value = +value;
  1602. if (value < 100) value += startCentury + (value < startYear ? 100 : 0);
  1603. return this.set('year', value);
  1604. case 'z':
  1605. if (value == 'Z') value = '+00';
  1606. var offset = value.match(/([+-])(\d{2}):?(\d{2})?/);
  1607. offset = (offset[1] + '1') * (offset[2] * 60 + (+offset[3] || 0)) + this.getTimezoneOffset();
  1608. return this.set('time', this - offset * 60000);
  1609. }
  1610. return this;
  1611. };
  1612. Date.defineParsers(
  1613. '%Y([-./]%m([-./]%d((T| )%X)?)?)?', // "1999-12-31", "1999-12-31 11:59pm", "1999-12-31 23:59:59", ISO8601
  1614. '%Y%m%d(T%H(%M%S?)?)?', // "19991231", "19991231T1159", compact
  1615. '%x( %X)?', // "12/31", "12.31.99", "12-31-1999", "12/31/2008 11:59 PM"
  1616. '%d%o( %b( %Y)?)?( %X)?', // "31st", "31st December", "31 Dec 1999", "31 Dec 1999 11:59pm"
  1617. '%b( %d%o)?( %Y)?( %X)?', // Same as above with month and day switched
  1618. '%Y %b( %d%o( %X)?)?', // Same as above with year coming first
  1619. '%o %b %d %X %z %Y', // "Thu Oct 22 08:11:23 +0000 2009"
  1620. '%T', // %H:%M:%S
  1621. '%H:%M( ?%p)?' // "11:05pm", "11:05 am" and "11:05"
  1622. );
  1623. Locale.addEvent('change', function(language){
  1624. if (Locale.get('Date')) recompile(language);
  1625. }).fireEvent('change', Locale.getCurrent());
  1626. })();
  1627. /*
  1628. ---
  1629. name: Locale.zh-CH.Date
  1630. description: Date messages for Chinese (simplified and traditional).
  1631. license: MIT-style license
  1632. authors:
  1633. - YMind Chan
  1634. requires:
  1635. - Locale
  1636. provides: [Locale.zh-CH.Date]
  1637. ...
  1638. */
  1639. // Simplified Chinese
  1640. Locale.define('zh-CHS', 'Date', {
  1641. months: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
  1642. months_abbr: ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二'],
  1643. days: ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'],
  1644. days_abbr: ['日', '一', '二', '三', '四', '五', '六'],
  1645. // Culture's date order: YYYY-MM-DD
  1646. dateOrder: ['year', 'month', 'date'],
  1647. shortDate: '%Y-%m-%d',
  1648. shortTime: '%I:%M%p',
  1649. AM: 'AM',
  1650. PM: 'PM',
  1651. firstDayOfWeek: 1,
  1652. // Date.Extras
  1653. ordinal: '',
  1654. lessThanMinuteAgo: '不到1分钟前',
  1655. minuteAgo: '大约1分钟前',
  1656. minutesAgo: '{delta}分钟之前',
  1657. hourAgo: '大约1小时前',
  1658. hoursAgo: '大约{delta}小时前',
  1659. dayAgo: '1天前',
  1660. daysAgo: '{delta}天前',
  1661. weekAgo: '1星期前',
  1662. weeksAgo: '{delta}星期前',
  1663. monthAgo: '1个月前',
  1664. monthsAgo: '{delta}个月前',
  1665. yearAgo: '1年前',
  1666. yearsAgo: '{delta}年前',
  1667. lessThanMinuteUntil: '从现在开始不到1分钟',
  1668. minuteUntil: '从现在开始約1分钟',
  1669. minutesUntil: '从现在开始约{delta}分钟',
  1670. hourUntil: '从现在开始1小时',
  1671. hoursUntil: '从现在开始约{delta}小时',
  1672. dayUntil: '从现在开始1天',
  1673. daysUntil: '从现在开始{delta}天',
  1674. weekUntil: '从现在开始1星期',
  1675. weeksUntil: '从现在开始{delta}星期',
  1676. monthUntil: '从现在开始一个月',
  1677. monthsUntil: '从现在开始{delta}个月',
  1678. yearUntil: '从现在开始1年',
  1679. yearsUntil: '从现在开始{delta}年'
  1680. });
  1681. // Traditional Chinese
  1682. Locale.define('zh-CHT', 'Date', {
  1683. months: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
  1684. months_abbr: ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二'],
  1685. days: ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'],
  1686. days_abbr: ['日', '一', '二', '三', '四', '五', '六'],
  1687. // Culture's date order: YYYY-MM-DD
  1688. dateOrder: ['year', 'month', 'date'],
  1689. shortDate: '%Y-%m-%d',
  1690. shortTime: '%I:%M%p',
  1691. AM: 'AM',
  1692. PM: 'PM',
  1693. firstDayOfWeek: 1,
  1694. // Date.Extras
  1695. ordinal: '',
  1696. lessThanMinuteAgo: '不到1分鐘前',
  1697. minuteAgo: '大約1分鐘前',
  1698. minutesAgo: '{delta}分鐘之前',
  1699. hourAgo: '大約1小時前',
  1700. hoursAgo: '大約{delta}小時前',
  1701. dayAgo: '1天前',
  1702. daysAgo: '{delta}天前',
  1703. weekAgo: '1星期前',
  1704. weeksAgo: '{delta}星期前',
  1705. monthAgo: '1个月前',
  1706. monthsAgo: '{delta}个月前',
  1707. yearAgo: '1年前',
  1708. yearsAgo: '{delta}年前',
  1709. lessThanMinuteUntil: '從現在開始不到1分鐘',
  1710. minuteUntil: '從現在開始約1分鐘',
  1711. minutesUntil: '從現在開始約{delta}分鐘',
  1712. hourUntil: '從現在開始1小時',
  1713. hoursUntil: '從現在開始約{delta}小時',
  1714. dayUntil: '從現在開始1天',
  1715. daysUntil: '從現在開始{delta}天',
  1716. weekUntil: '從現在開始1星期',
  1717. weeksUntil: '從現在開始{delta}星期',
  1718. monthUntil: '從現在開始一個月',
  1719. monthsUntil: '從現在開始{delta}個月',
  1720. yearUntil: '從現在開始1年',
  1721. yearsUntil: '從現在開始{delta}年'
  1722. });
  1723. /*
  1724. ---
  1725. name: JSON
  1726. description: JSON encoder and decoder.
  1727. license: MIT-style license.
  1728. SeeAlso: <http://www.json.org/>
  1729. requires: [Array, String, Number, Function]
  1730. provides: JSON
  1731. ...
  1732. */
  1733. if (typeof JSON == 'undefined') this.JSON = {};
  1734. (function(){
  1735. var special = {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'};
  1736. var escape = function(chr){
  1737. return special[chr] || '\\u' + ('0000' + chr.charCodeAt(0).toString(16)).slice(-4);
  1738. };
  1739. JSON.validate = function(string){
  1740. string = string.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
  1741. replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
  1742. replace(/(?:^|:|,)(?:\s*\[)+/g, '');
  1743. return (/^[\],:{}\s]*$/).test(string);
  1744. };
  1745. JSON.encode = JSON.stringify ? function(obj){
  1746. return JSON.stringify(obj);
  1747. } : function(obj){
  1748. if (obj && obj.toJSON) obj = obj.toJSON();
  1749. switch (typeOf(obj)){
  1750. case 'string':
  1751. return '"' + obj.replace(/[\x00-\x1f\\"]/g, escape) + '"';
  1752. case 'array':
  1753. return '[' + obj.map(JSON.encode).clean() + ']';
  1754. case 'object': case 'hash':
  1755. var string = [];
  1756. Object.each(obj, function(value, key){
  1757. var json = JSON.encode(value);
  1758. if (json) string.push(JSON.encode(key) + ':' + json);
  1759. });
  1760. return '{' + string + '}';
  1761. case 'number': case 'boolean': return '' + obj;
  1762. case 'null': return 'null';
  1763. }
  1764. return null;
  1765. };
  1766. JSON.decode = function(string, secure){
  1767. if (!string || typeOf(string) != 'string') return null;
  1768. if (secure || JSON.secure){
  1769. if (JSON.parse) return JSON.parse(string);
  1770. if (!JSON.validate(string)) throw new Error('JSON could not decode the input; security is enabled and the value is not secure.');
  1771. }
  1772. return eval('(' + string + ')');
  1773. };
  1774. })();