mootools.js 50 KB

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