You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1323 lines
30 KiB
JavaScript
1323 lines
30 KiB
JavaScript
// MooTools: the javascript framework.
|
|
// Load this file's selection again by visiting: http://mootools.net/more/0a2b8625655481363709ef8d9ab1d0f4
|
|
// Or build this file again with packager using: packager build More/Date More/Date.Extras More/Hash More/Request.JSONP
|
|
/*
|
|
---
|
|
|
|
script: More.js
|
|
|
|
name: More
|
|
|
|
description: MooTools More
|
|
|
|
license: MIT-style license
|
|
|
|
authors:
|
|
- Guillermo Rauch
|
|
- Thomas Aylott
|
|
- Scott Kyle
|
|
- Arian Stolwijk
|
|
- Tim Wienk
|
|
- Christoph Pojer
|
|
- Aaron Newton
|
|
|
|
requires:
|
|
- Core/MooTools
|
|
|
|
provides: [MooTools.More]
|
|
|
|
...
|
|
*/
|
|
|
|
MooTools.More = {
|
|
'version': '1.3.1.1',
|
|
'build': '0292a3af1eea242b817fecf9daa127417d10d4ce'
|
|
};
|
|
|
|
|
|
/*
|
|
---
|
|
|
|
script: Object.Extras.js
|
|
|
|
name: Object.Extras
|
|
|
|
description: Extra Object generics, like getFromPath which allows a path notation to child elements.
|
|
|
|
license: MIT-style license
|
|
|
|
authors:
|
|
- Aaron Newton
|
|
|
|
requires:
|
|
- Core/Object
|
|
- /MooTools.More
|
|
|
|
provides: [Object.Extras]
|
|
|
|
...
|
|
*/
|
|
|
|
(function(){
|
|
|
|
var defined = function(value){
|
|
return value != null;
|
|
};
|
|
|
|
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
|
|
Object.extend({
|
|
|
|
getFromPath: function(source, parts){
|
|
if (typeof parts == 'string') parts = parts.split('.');
|
|
for (var i = 0, l = parts.length; i < l; i++){
|
|
if (hasOwnProperty.call(source, parts[i])) source = source[parts[i]];
|
|
else return null;
|
|
}
|
|
return source;
|
|
},
|
|
|
|
cleanValues: function(object, method){
|
|
method = method || defined;
|
|
for (var key in object) if (!method(object[key])){
|
|
delete object[key];
|
|
}
|
|
return object;
|
|
},
|
|
|
|
erase: function(object, key){
|
|
if (hasOwnProperty.call(object, key)) delete object[key];
|
|
return object;
|
|
},
|
|
|
|
run: function(object){
|
|
var args = Array.slice(arguments, 1);
|
|
for (var key in object) if (object[key].apply){
|
|
object[key].apply(object, args);
|
|
}
|
|
return object;
|
|
}
|
|
|
|
});
|
|
|
|
}).call(this);
|
|
|
|
|
|
/*
|
|
---
|
|
|
|
script: Locale.js
|
|
|
|
name: Locale
|
|
|
|
description: Provides methods for localization.
|
|
|
|
license: MIT-style license
|
|
|
|
authors:
|
|
- Aaron Newton
|
|
- Arian Stolwijk
|
|
|
|
requires:
|
|
- Core/Events
|
|
- /Object.Extras
|
|
- /MooTools.More
|
|
|
|
provides: [Locale, Lang]
|
|
|
|
...
|
|
*/
|
|
|
|
(function(){
|
|
|
|
var current = null,
|
|
locales = {},
|
|
inherits = {};
|
|
|
|
var getSet = function(set){
|
|
if (instanceOf(set, Locale.Set)) return set;
|
|
else return locales[set];
|
|
};
|
|
|
|
var Locale = this.Locale = {
|
|
|
|
define: function(locale, set, key, value){
|
|
var name;
|
|
if (instanceOf(locale, Locale.Set)){
|
|
name = locale.name;
|
|
if (name) locales[name] = locale;
|
|
} else {
|
|
name = locale;
|
|
if (!locales[name]) locales[name] = new Locale.Set(name);
|
|
locale = locales[name];
|
|
}
|
|
|
|
if (set) locale.define(set, key, value);
|
|
|
|
|
|
|
|
if (!current) current = locale;
|
|
|
|
return locale;
|
|
},
|
|
|
|
use: function(locale){
|
|
locale = getSet(locale);
|
|
|
|
if (locale){
|
|
current = locale;
|
|
|
|
this.fireEvent('change', locale);
|
|
|
|
|
|
}
|
|
|
|
return this;
|
|
},
|
|
|
|
getCurrent: function(){
|
|
return current;
|
|
},
|
|
|
|
get: function(key, args){
|
|
return (current) ? current.get(key, args) : '';
|
|
},
|
|
|
|
inherit: function(locale, inherits, set){
|
|
locale = getSet(locale);
|
|
|
|
if (locale) locale.inherit(inherits, set);
|
|
return this;
|
|
},
|
|
|
|
list: function(){
|
|
return Object.keys(locales);
|
|
}
|
|
|
|
};
|
|
|
|
Object.append(Locale, new Events);
|
|
|
|
Locale.Set = new Class({
|
|
|
|
sets: {},
|
|
|
|
inherits: {
|
|
locales: [],
|
|
sets: {}
|
|
},
|
|
|
|
initialize: function(name){
|
|
this.name = name || '';
|
|
},
|
|
|
|
define: function(set, key, value){
|
|
var defineData = this.sets[set];
|
|
if (!defineData) defineData = {};
|
|
|
|
if (key){
|
|
if (typeOf(key) == 'object') defineData = Object.merge(defineData, key);
|
|
else defineData[key] = value;
|
|
}
|
|
this.sets[set] = defineData;
|
|
|
|
return this;
|
|
},
|
|
|
|
get: function(key, args, _base){
|
|
var value = Object.getFromPath(this.sets, key);
|
|
if (value != null){
|
|
var type = typeOf(value);
|
|
if (type == 'function') value = value.apply(null, Array.from(args));
|
|
else if (type == 'object') value = Object.clone(value);
|
|
return value;
|
|
}
|
|
|
|
// get value of inherited locales
|
|
var index = key.indexOf('.'),
|
|
set = index < 0 ? key : key.substr(0, index),
|
|
names = (this.inherits.sets[set] || []).combine(this.inherits.locales).include('en-US');
|
|
if (!_base) _base = [];
|
|
|
|
for (var i = 0, l = names.length; i < l; i++){
|
|
if (_base.contains(names[i])) continue;
|
|
_base.include(names[i]);
|
|
|
|
var locale = locales[names[i]];
|
|
if (!locale) continue;
|
|
|
|
value = locale.get(key, args, _base);
|
|
if (value != null) return value;
|
|
}
|
|
|
|
return '';
|
|
},
|
|
|
|
inherit: function(names, set){
|
|
names = Array.from(names);
|
|
|
|
if (set && !this.inherits.sets[set]) this.inherits.sets[set] = [];
|
|
|
|
var l = names.length;
|
|
while (l--) (set ? this.inherits.sets[set] : this.inherits.locales).unshift(names[l]);
|
|
|
|
return this;
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
}).call(this);
|
|
|
|
|
|
/*
|
|
---
|
|
|
|
name: Locale.en-US.Date
|
|
|
|
description: Date messages for US English.
|
|
|
|
license: MIT-style license
|
|
|
|
authors:
|
|
- Aaron Newton
|
|
|
|
requires:
|
|
- /Locale
|
|
|
|
provides: [Locale.en-US.Date]
|
|
|
|
...
|
|
*/
|
|
|
|
Locale.define('en-US', 'Date', {
|
|
|
|
months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
|
|
months_abbr: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
|
|
days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
|
|
days_abbr: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
|
|
|
// Culture's date order: MM/DD/YYYY
|
|
dateOrder: ['month', 'date', 'year'],
|
|
shortDate: '%m/%d/%Y',
|
|
shortTime: '%I:%M%p',
|
|
AM: 'AM',
|
|
PM: 'PM',
|
|
firstDayOfWeek: 0,
|
|
|
|
// Date.Extras
|
|
ordinal: function(dayOfMonth){
|
|
// 1st, 2nd, 3rd, etc.
|
|
return (dayOfMonth > 3 && dayOfMonth < 21) ? 'th' : ['th', 'st', 'nd', 'rd', 'th'][Math.min(dayOfMonth % 10, 4)];
|
|
},
|
|
|
|
lessThanMinuteAgo: 'less than a minute ago',
|
|
minuteAgo: 'about a minute ago',
|
|
minutesAgo: '{delta} minutes ago',
|
|
hourAgo: 'about an hour ago',
|
|
hoursAgo: 'about {delta} hours ago',
|
|
dayAgo: '1 day ago',
|
|
daysAgo: '{delta} days ago',
|
|
weekAgo: '1 week ago',
|
|
weeksAgo: '{delta} weeks ago',
|
|
monthAgo: '1 month ago',
|
|
monthsAgo: '{delta} months ago',
|
|
yearAgo: '1 year ago',
|
|
yearsAgo: '{delta} years ago',
|
|
|
|
lessThanMinuteUntil: 'less than a minute from now',
|
|
minuteUntil: 'about a minute from now',
|
|
minutesUntil: '{delta} minutes from now',
|
|
hourUntil: 'about an hour from now',
|
|
hoursUntil: 'about {delta} hours from now',
|
|
dayUntil: '1 day from now',
|
|
daysUntil: '{delta} days from now',
|
|
weekUntil: '1 week from now',
|
|
weeksUntil: '{delta} weeks from now',
|
|
monthUntil: '1 month from now',
|
|
monthsUntil: '{delta} months from now',
|
|
yearUntil: '1 year from now',
|
|
yearsUntil: '{delta} years from now'
|
|
|
|
});
|
|
|
|
|
|
/*
|
|
---
|
|
|
|
script: Date.js
|
|
|
|
name: Date
|
|
|
|
description: Extends the Date native object to include methods useful in managing dates.
|
|
|
|
license: MIT-style license
|
|
|
|
authors:
|
|
- Aaron Newton
|
|
- Nicholas Barthelemy - https://svn.nbarthelemy.com/date-js/
|
|
- Harald Kirshner - mail [at] digitarald.de; http://digitarald.de
|
|
- Scott Kyle - scott [at] appden.com; http://appden.com
|
|
|
|
requires:
|
|
- Core/Array
|
|
- Core/String
|
|
- Core/Number
|
|
- MooTools.More
|
|
- Locale
|
|
- Locale.en-US.Date
|
|
|
|
provides: [Date]
|
|
|
|
...
|
|
*/
|
|
|
|
(function(){
|
|
|
|
var Date = this.Date;
|
|
|
|
var DateMethods = Date.Methods = {
|
|
ms: 'Milliseconds',
|
|
year: 'FullYear',
|
|
min: 'Minutes',
|
|
mo: 'Month',
|
|
sec: 'Seconds',
|
|
hr: 'Hours'
|
|
};
|
|
|
|
['Date', 'Day', 'FullYear', 'Hours', 'Milliseconds', 'Minutes', 'Month', 'Seconds', 'Time', 'TimezoneOffset',
|
|
'Week', 'Timezone', 'GMTOffset', 'DayOfYear', 'LastMonth', 'LastDayOfMonth', 'UTCDate', 'UTCDay', 'UTCFullYear',
|
|
'AMPM', 'Ordinal', 'UTCHours', 'UTCMilliseconds', 'UTCMinutes', 'UTCMonth', 'UTCSeconds', 'UTCMilliseconds'].each(function(method){
|
|
Date.Methods[method.toLowerCase()] = method;
|
|
});
|
|
|
|
var pad = function(n, digits, string){
|
|
if (digits == 1) return n;
|
|
return n < Math.pow(10, digits - 1) ? (string || '0') + pad(n, digits - 1, string) : n;
|
|
};
|
|
|
|
Date.implement({
|
|
|
|
set: function(prop, value){
|
|
prop = prop.toLowerCase();
|
|
var method = DateMethods[prop] && 'set' + DateMethods[prop];
|
|
if (method && this[method]) this[method](value);
|
|
return this;
|
|
}.overloadSetter(),
|
|
|
|
get: function(prop){
|
|
prop = prop.toLowerCase();
|
|
var method = DateMethods[prop] && 'get' + DateMethods[prop];
|
|
if (method && this[method]) return this[method]();
|
|
return null;
|
|
}.overloadGetter(),
|
|
|
|
clone: function(){
|
|
return new Date(this.get('time'));
|
|
},
|
|
|
|
increment: function(interval, times){
|
|
interval = interval || 'day';
|
|
times = times != null ? times : 1;
|
|
|
|
switch (interval){
|
|
case 'year':
|
|
return this.increment('month', times * 12);
|
|
case 'month':
|
|
var d = this.get('date');
|
|
this.set('date', 1).set('mo', this.get('mo') + times);
|
|
return this.set('date', d.min(this.get('lastdayofmonth')));
|
|
case 'week':
|
|
return this.increment('day', times * 7);
|
|
case 'day':
|
|
return this.set('date', this.get('date') + times);
|
|
}
|
|
|
|
if (!Date.units[interval]) throw new Error(interval + ' is not a supported interval');
|
|
|
|
return this.set('time', this.get('time') + times * Date.units[interval]());
|
|
},
|
|
|
|
decrement: function(interval, times){
|
|
return this.increment(interval, -1 * (times != null ? times : 1));
|
|
},
|
|
|
|
isLeapYear: function(){
|
|
return Date.isLeapYear(this.get('year'));
|
|
},
|
|
|
|
clearTime: function(){
|
|
return this.set({hr: 0, min: 0, sec: 0, ms: 0});
|
|
},
|
|
|
|
diff: function(date, resolution){
|
|
if (typeOf(date) == 'string') date = Date.parse(date);
|
|
|
|
return ((date - this) / Date.units[resolution || 'day'](3, 3)).round(); // non-leap year, 30-day month
|
|
},
|
|
|
|
getLastDayOfMonth: function(){
|
|
return Date.daysInMonth(this.get('mo'), this.get('year'));
|
|
},
|
|
|
|
getDayOfYear: function(){
|
|
return (Date.UTC(this.get('year'), this.get('mo'), this.get('date') + 1)
|
|
- Date.UTC(this.get('year'), 0, 1)) / Date.units.day();
|
|
},
|
|
|
|
setDay: function(day, firstDayOfWeek){
|
|
if (firstDayOfWeek == null){
|
|
firstDayOfWeek = Date.getMsg('firstDayOfWeek');
|
|
if (firstDayOfWeek === '') firstDayOfWeek = 1;
|
|
}
|
|
|
|
day = (7 + Date.parseDay(day, true) - firstDayOfWeek) % 7;
|
|
var currentDay = (7 + this.get('day') - firstDayOfWeek) % 7;
|
|
|
|
return this.increment('day', day - currentDay);
|
|
},
|
|
|
|
getWeek: function(firstDayOfWeek){
|
|
if (firstDayOfWeek == null){
|
|
firstDayOfWeek = Date.getMsg('firstDayOfWeek');
|
|
if (firstDayOfWeek === '') firstDayOfWeek = 1;
|
|
}
|
|
|
|
var date = this,
|
|
dayOfWeek = (7 + date.get('day') - firstDayOfWeek) % 7,
|
|
dividend = 0,
|
|
firstDayOfYear;
|
|
|
|
if (firstDayOfWeek == 1){
|
|
// ISO-8601, week belongs to year that has the most days of the week (i.e. has the thursday of the week)
|
|
var month = date.get('month'),
|
|
startOfWeek = date.get('date') - dayOfWeek;
|
|
|
|
if (month == 11 && startOfWeek > 28) return 1; // Week 1 of next year
|
|
|
|
if (month == 0 && startOfWeek < -2){
|
|
// Use a date from last year to determine the week
|
|
date = new Date(date).decrement('day', dayOfWeek);
|
|
dayOfWeek = 0;
|
|
}
|
|
|
|
firstDayOfYear = new Date(date.get('year'), 0, 1).get('day') || 7;
|
|
if (firstDayOfYear > 4) dividend = -7; // First week of the year is not week 1
|
|
} else {
|
|
// In other cultures the first week of the year is always week 1 and the last week always 53 or 54.
|
|
// Days in the same week can have a different weeknumber if the week spreads across two years.
|
|
firstDayOfYear = new Date(date.get('year'), 0, 1).get('day');
|
|
}
|
|
|
|
dividend += date.get('dayofyear');
|
|
dividend += 6 - dayOfWeek; // Add days so we calculate the current date's week as a full week
|
|
dividend += (7 + firstDayOfYear - firstDayOfWeek) % 7; // Make up for first week of the year not being a full week
|
|
|
|
return (dividend / 7);
|
|
},
|
|
|
|
getOrdinal: function(day){
|
|
return Date.getMsg('ordinal', day || this.get('date'));
|
|
},
|
|
|
|
getTimezone: function(){
|
|
return this.toString()
|
|
.replace(/^.*? ([A-Z]{3}).[0-9]{4}.*$/, '$1')
|
|
.replace(/^.*?\(([A-Z])[a-z]+ ([A-Z])[a-z]+ ([A-Z])[a-z]+\)$/, '$1$2$3');
|
|
},
|
|
|
|
getGMTOffset: function(){
|
|
var off = this.get('timezoneOffset');
|
|
return ((off > 0) ? '-' : '+') + pad((off.abs() / 60).floor(), 2) + pad(off % 60, 2);
|
|
},
|
|
|
|
setAMPM: function(ampm){
|
|
ampm = ampm.toUpperCase();
|
|
var hr = this.get('hr');
|
|
if (hr > 11 && ampm == 'AM') return this.decrement('hour', 12);
|
|
else if (hr < 12 && ampm == 'PM') return this.increment('hour', 12);
|
|
return this;
|
|
},
|
|
|
|
getAMPM: function(){
|
|
return (this.get('hr') < 12) ? 'AM' : 'PM';
|
|
},
|
|
|
|
parse: function(str){
|
|
this.set('time', Date.parse(str));
|
|
return this;
|
|
},
|
|
|
|
isValid: function(date){
|
|
return !isNaN((date || this).valueOf());
|
|
},
|
|
|
|
format: function(f){
|
|
if (!this.isValid()) return 'invalid date';
|
|
if (!f) f = '%x %X';
|
|
|
|
var formatLower = f.toLowerCase();
|
|
if (formatters[formatLower]) return formatters[formatLower](this); // it's a formatter!
|
|
f = formats[formatLower] || f; // replace short-hand with actual format
|
|
|
|
var d = this;
|
|
return f.replace(/%([a-z%])/gi,
|
|
function($0, $1){
|
|
switch ($1){
|
|
case 'a': return Date.getMsg('days_abbr')[d.get('day')];
|
|
case 'A': return Date.getMsg('days')[d.get('day')];
|
|
case 'b': return Date.getMsg('months_abbr')[d.get('month')];
|
|
case 'B': return Date.getMsg('months')[d.get('month')];
|
|
case 'c': return d.format('%a %b %d %H:%M:%S %Y');
|
|
case 'd': return pad(d.get('date'), 2);
|
|
case 'e': return pad(d.get('date'), 2, ' ');
|
|
case 'H': return pad(d.get('hr'), 2);
|
|
case 'I': return pad((d.get('hr') % 12) || 12, 2);
|
|
case 'j': return pad(d.get('dayofyear'), 3);
|
|
case 'k': return pad(d.get('hr'), 2, ' ');
|
|
case 'l': return pad((d.get('hr') % 12) || 12, 2, ' ');
|
|
case 'L': return pad(d.get('ms'), 3);
|
|
case 'm': return pad((d.get('mo') + 1), 2);
|
|
case 'M': return pad(d.get('min'), 2);
|
|
case 'o': return d.get('ordinal');
|
|
case 'p': return Date.getMsg(d.get('ampm'));
|
|
case 's': return Math.round(d / 1000);
|
|
case 'S': return pad(d.get('seconds'), 2);
|
|
case 'T': return d.format('%H:%M:%S');
|
|
case 'U': return pad(d.get('week'), 2);
|
|
case 'w': return d.get('day');
|
|
case 'x': return d.format(Date.getMsg('shortDate'));
|
|
case 'X': return d.format(Date.getMsg('shortTime'));
|
|
case 'y': return d.get('year').toString().substr(2);
|
|
case 'Y': return d.get('year');
|
|
case 'z': return d.get('GMTOffset');
|
|
case 'Z': return d.get('Timezone');
|
|
}
|
|
return $1;
|
|
}
|
|
);
|
|
},
|
|
|
|
toISOString: function(){
|
|
return this.format('iso8601');
|
|
}
|
|
|
|
}).alias({
|
|
toJSON: 'toISOString',
|
|
compare: 'diff',
|
|
strftime: 'format'
|
|
});
|
|
|
|
var formats = {
|
|
db: '%Y-%m-%d %H:%M:%S',
|
|
compact: '%Y%m%dT%H%M%S',
|
|
'short': '%d %b %H:%M',
|
|
'long': '%B %d, %Y %H:%M'
|
|
};
|
|
|
|
// The day and month abbreviations are standardized, so we cannot use simply %a and %b because they will get localized
|
|
var rfcDayAbbr = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
|
rfcMonthAbbr = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
|
|
|
var formatters = {
|
|
rfc822: function(date){
|
|
return rfcDayAbbr[date.get('day')] + date.format(', %d ') + rfcMonthAbbr[date.get('month')] + date.format(' %Y %H:%M:%S %Z');
|
|
},
|
|
rfc2822: function(date){
|
|
return rfcDayAbbr[date.get('day')] + date.format(', %d ') + rfcMonthAbbr[date.get('month')] + date.format(' %Y %H:%M:%S %z');
|
|
},
|
|
iso8601: function(date){
|
|
return (
|
|
date.getUTCFullYear() + '-' +
|
|
pad(date.getUTCMonth() + 1, 2) + '-' +
|
|
pad(date.getUTCDate(), 2) + 'T' +
|
|
pad(date.getUTCHours(), 2) + ':' +
|
|
pad(date.getUTCMinutes(), 2) + ':' +
|
|
pad(date.getUTCSeconds(), 2) + '.' +
|
|
pad(date.getUTCMilliseconds(), 3) + 'Z'
|
|
);
|
|
}
|
|
};
|
|
|
|
|
|
var parsePatterns = [],
|
|
nativeParse = Date.parse;
|
|
|
|
var parseWord = function(type, word, num){
|
|
var ret = -1,
|
|
translated = Date.getMsg(type + 's');
|
|
switch (typeOf(word)){
|
|
case 'object':
|
|
ret = translated[word.get(type)];
|
|
break;
|
|
case 'number':
|
|
ret = translated[word];
|
|
if (!ret) throw new Error('Invalid ' + type + ' index: ' + word);
|
|
break;
|
|
case 'string':
|
|
var match = translated.filter(function(name){
|
|
return this.test(name);
|
|
}, new RegExp('^' + word, 'i'));
|
|
if (!match.length) throw new Error('Invalid ' + type + ' string');
|
|
if (match.length > 1) throw new Error('Ambiguous ' + type);
|
|
ret = match[0];
|
|
}
|
|
|
|
return (num) ? translated.indexOf(ret) : ret;
|
|
};
|
|
|
|
var startCentury = 1900,
|
|
startYear = 70;
|
|
|
|
Date.extend({
|
|
|
|
getMsg: function(key, args){
|
|
return Locale.get('Date.' + key, args);
|
|
},
|
|
|
|
units: {
|
|
ms: Function.from(1),
|
|
second: Function.from(1000),
|
|
minute: Function.from(60000),
|
|
hour: Function.from(3600000),
|
|
day: Function.from(86400000),
|
|
week: Function.from(608400000),
|
|
month: function(month, year){
|
|
var d = new Date;
|
|
return Date.daysInMonth(month != null ? month : d.get('mo'), year != null ? year : d.get('year')) * 86400000;
|
|
},
|
|
year: function(year){
|
|
year = year || new Date().get('year');
|
|
return Date.isLeapYear(year) ? 31622400000 : 31536000000;
|
|
}
|
|
},
|
|
|
|
daysInMonth: function(month, year){
|
|
return [31, Date.isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
|
|
},
|
|
|
|
isLeapYear: function(year){
|
|
return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
|
|
},
|
|
|
|
parse: function(from){
|
|
var t = typeOf(from);
|
|
if (t == 'number') return new Date(from);
|
|
if (t != 'string') return from;
|
|
from = from.clean();
|
|
if (!from.length) return null;
|
|
|
|
var parsed;
|
|
parsePatterns.some(function(pattern){
|
|
var bits = pattern.re.exec(from);
|
|
return (bits) ? (parsed = pattern.handler(bits)) : false;
|
|
});
|
|
|
|
if (!(parsed && parsed.isValid())){
|
|
parsed = new Date(nativeParse(from));
|
|
if (!(parsed && parsed.isValid())) parsed = new Date(from.toInt());
|
|
}
|
|
return parsed;
|
|
},
|
|
|
|
parseDay: function(day, num){
|
|
return parseWord('day', day, num);
|
|
},
|
|
|
|
parseMonth: function(month, num){
|
|
return parseWord('month', month, num);
|
|
},
|
|
|
|
parseUTC: function(value){
|
|
var localDate = new Date(value);
|
|
var utcSeconds = Date.UTC(
|
|
localDate.get('year'),
|
|
localDate.get('mo'),
|
|
localDate.get('date'),
|
|
localDate.get('hr'),
|
|
localDate.get('min'),
|
|
localDate.get('sec'),
|
|
localDate.get('ms')
|
|
);
|
|
return new Date(utcSeconds);
|
|
},
|
|
|
|
orderIndex: function(unit){
|
|
return Date.getMsg('dateOrder').indexOf(unit) + 1;
|
|
},
|
|
|
|
defineFormat: function(name, format){
|
|
formats[name] = format;
|
|
return this;
|
|
},
|
|
|
|
defineFormats: function(formats){
|
|
for (var name in formats) Date.defineFormat(name, formats[name]);
|
|
return this;
|
|
},
|
|
|
|
|
|
|
|
defineParser: function(pattern){
|
|
parsePatterns.push((pattern.re && pattern.handler) ? pattern : build(pattern));
|
|
return this;
|
|
},
|
|
|
|
defineParsers: function(){
|
|
Array.flatten(arguments).each(Date.defineParser);
|
|
return this;
|
|
},
|
|
|
|
define2DigitYearStart: function(year){
|
|
startYear = year % 100;
|
|
startCentury = year - startYear;
|
|
return this;
|
|
}
|
|
|
|
});
|
|
|
|
var regexOf = function(type){
|
|
return new RegExp('(?:' + Date.getMsg(type).map(function(name){
|
|
return name.substr(0, 3);
|
|
}).join('|') + ')[a-z]*');
|
|
};
|
|
|
|
var replacers = function(key){
|
|
switch (key){
|
|
case 'T':
|
|
return '%H:%M:%S';
|
|
case 'x': // iso8601 covers yyyy-mm-dd, so just check if month is first
|
|
return ((Date.orderIndex('month') == 1) ? '%m[-./]%d' : '%d[-./]%m') + '([-./]%y)?';
|
|
case 'X':
|
|
return '%H([.:]%M)?([.:]%S([.:]%s)?)? ?%p? ?%z?';
|
|
}
|
|
return null;
|
|
};
|
|
|
|
var keys = {
|
|
d: /[0-2]?[0-9]|3[01]/,
|
|
H: /[01]?[0-9]|2[0-3]/,
|
|
I: /0?[1-9]|1[0-2]/,
|
|
M: /[0-5]?\d/,
|
|
s: /\d+/,
|
|
o: /[a-z]*/,
|
|
p: /[ap]\.?m\.?/,
|
|
y: /\d{2}|\d{4}/,
|
|
Y: /\d{4}/,
|
|
z: /Z|[+-]\d{2}(?::?\d{2})?/
|
|
};
|
|
|
|
keys.m = keys.I;
|
|
keys.S = keys.M;
|
|
|
|
var currentLanguage;
|
|
|
|
var recompile = function(language){
|
|
currentLanguage = language;
|
|
|
|
keys.a = keys.A = regexOf('days');
|
|
keys.b = keys.B = regexOf('months');
|
|
|
|
parsePatterns.each(function(pattern, i){
|
|
if (pattern.format) parsePatterns[i] = build(pattern.format);
|
|
});
|
|
};
|
|
|
|
var build = function(format){
|
|
if (!currentLanguage) return {format: format};
|
|
|
|
var parsed = [];
|
|
var re = (format.source || format) // allow format to be regex
|
|
.replace(/%([a-z])/gi,
|
|
function($0, $1){
|
|
return replacers($1) || $0;
|
|
}
|
|
).replace(/\((?!\?)/g, '(?:') // make all groups non-capturing
|
|
.replace(/ (?!\?|\*)/g, ',? ') // be forgiving with spaces and commas
|
|
.replace(/%([a-z%])/gi,
|
|
function($0, $1){
|
|
var p = keys[$1];
|
|
if (!p) return $1;
|
|
parsed.push($1);
|
|
return '(' + p.source + ')';
|
|
}
|
|
).replace(/\[a-z\]/gi, '[a-z\\u00c0-\\uffff;\&]'); // handle unicode words
|
|
|
|
return {
|
|
format: format,
|
|
re: new RegExp('^' + re + '$', 'i'),
|
|
handler: function(bits){
|
|
bits = bits.slice(1).associate(parsed);
|
|
var date = new Date().clearTime(),
|
|
year = bits.y || bits.Y;
|
|
|
|
if (year != null) handle.call(date, 'y', year); // need to start in the right year
|
|
if ('d' in bits) handle.call(date, 'd', 1);
|
|
if ('m' in bits || bits.b || bits.B) handle.call(date, 'm', 1);
|
|
|
|
for (var key in bits) handle.call(date, key, bits[key]);
|
|
return date;
|
|
}
|
|
};
|
|
};
|
|
|
|
var handle = function(key, value){
|
|
if (!value) return this;
|
|
|
|
switch (key){
|
|
case 'a': case 'A': return this.set('day', Date.parseDay(value, true));
|
|
case 'b': case 'B': return this.set('mo', Date.parseMonth(value, true));
|
|
case 'd': return this.set('date', value);
|
|
case 'H': case 'I': return this.set('hr', value);
|
|
case 'm': return this.set('mo', value - 1);
|
|
case 'M': return this.set('min', value);
|
|
case 'p': return this.set('ampm', value.replace(/\./g, ''));
|
|
case 'S': return this.set('sec', value);
|
|
case 's': return this.set('ms', ('0.' + value) * 1000);
|
|
case 'w': return this.set('day', value);
|
|
case 'Y': return this.set('year', value);
|
|
case 'y':
|
|
value = +value;
|
|
if (value < 100) value += startCentury + (value < startYear ? 100 : 0);
|
|
return this.set('year', value);
|
|
case 'z':
|
|
if (value == 'Z') value = '+00';
|
|
var offset = value.match(/([+-])(\d{2}):?(\d{2})?/);
|
|
offset = (offset[1] + '1') * (offset[2] * 60 + (+offset[3] || 0)) + this.getTimezoneOffset();
|
|
return this.set('time', this - offset * 60000);
|
|
}
|
|
|
|
return this;
|
|
};
|
|
|
|
Date.defineParsers(
|
|
'%Y([-./]%m([-./]%d((T| )%X)?)?)?', // "1999-12-31", "1999-12-31 11:59pm", "1999-12-31 23:59:59", ISO8601
|
|
'%Y%m%d(T%H(%M%S?)?)?', // "19991231", "19991231T1159", compact
|
|
'%x( %X)?', // "12/31", "12.31.99", "12-31-1999", "12/31/2008 11:59 PM"
|
|
'%d%o( %b( %Y)?)?( %X)?', // "31st", "31st December", "31 Dec 1999", "31 Dec 1999 11:59pm"
|
|
'%b( %d%o)?( %Y)?( %X)?', // Same as above with month and day switched
|
|
'%Y %b( %d%o( %X)?)?', // Same as above with year coming first
|
|
'%o %b %d %X %z %Y', // "Thu Oct 22 08:11:23 +0000 2009"
|
|
'%T', // %H:%M:%S
|
|
'%H:%M( ?%p)?' // "11:05pm", "11:05 am" and "11:05"
|
|
);
|
|
|
|
Locale.addEvent('change', function(language){
|
|
if (Locale.get('Date')) recompile(language);
|
|
}).fireEvent('change', Locale.getCurrent());
|
|
|
|
}).call(this);
|
|
|
|
|
|
/*
|
|
---
|
|
|
|
script: Date.Extras.js
|
|
|
|
name: Date.Extras
|
|
|
|
description: Extends the Date native object to include extra methods (on top of those in Date.js).
|
|
|
|
license: MIT-style license
|
|
|
|
authors:
|
|
- Aaron Newton
|
|
- Scott Kyle
|
|
|
|
requires:
|
|
- /Date
|
|
|
|
provides: [Date.Extras]
|
|
|
|
...
|
|
*/
|
|
|
|
Date.implement({
|
|
|
|
timeDiffInWords: function(to){
|
|
return Date.distanceOfTimeInWords(this, to || new Date);
|
|
},
|
|
|
|
timeDiff: function(to, separator){
|
|
if (to == null) to = new Date;
|
|
var delta = ((to - this) / 1000).floor();
|
|
|
|
var vals = [],
|
|
durations = [60, 60, 24, 365, 0],
|
|
names = ['s', 'm', 'h', 'd', 'y'],
|
|
value, duration;
|
|
|
|
for (var item = 0; item < durations.length; item++){
|
|
if (item && !delta) break;
|
|
value = delta;
|
|
if ((duration = durations[item])){
|
|
value = (delta % duration);
|
|
delta = (delta / duration).floor();
|
|
}
|
|
vals.unshift(value + (names[item] || ''));
|
|
}
|
|
|
|
return vals.join(separator || ':');
|
|
}
|
|
|
|
}).extend({
|
|
|
|
distanceOfTimeInWords: function(from, to){
|
|
return Date.getTimePhrase(((to - from) / 1000).toInt());
|
|
},
|
|
|
|
getTimePhrase: function(delta){
|
|
var suffix = (delta < 0) ? 'Until' : 'Ago';
|
|
if (delta < 0) delta *= -1;
|
|
|
|
var units = {
|
|
minute: 60,
|
|
hour: 60,
|
|
day: 24,
|
|
week: 7,
|
|
month: 52 / 12,
|
|
year: 12,
|
|
eon: Infinity
|
|
};
|
|
|
|
var msg = 'lessThanMinute';
|
|
|
|
for (var unit in units){
|
|
var interval = units[unit];
|
|
if (delta < 1.5 * interval){
|
|
if (delta > 0.75 * interval) msg = unit;
|
|
break;
|
|
}
|
|
delta /= interval;
|
|
msg = unit + 's';
|
|
}
|
|
|
|
delta = delta.round();
|
|
return Date.getMsg(msg + suffix, delta).substitute({delta: delta});
|
|
}
|
|
|
|
}).defineParsers(
|
|
|
|
{
|
|
// "today", "tomorrow", "yesterday"
|
|
re: /^(?:tod|tom|yes)/i,
|
|
handler: function(bits){
|
|
var d = new Date().clearTime();
|
|
switch (bits[0]){
|
|
case 'tom': return d.increment();
|
|
case 'yes': return d.decrement();
|
|
default: return d;
|
|
}
|
|
}
|
|
},
|
|
|
|
{
|
|
// "next Wednesday", "last Thursday"
|
|
re: /^(next|last) ([a-z]+)$/i,
|
|
handler: function(bits){
|
|
var d = new Date().clearTime();
|
|
var day = d.getDay();
|
|
var newDay = Date.parseDay(bits[2], true);
|
|
var addDays = newDay - day;
|
|
if (newDay <= day) addDays += 7;
|
|
if (bits[1] == 'last') addDays -= 7;
|
|
return d.set('date', d.getDate() + addDays);
|
|
}
|
|
}
|
|
|
|
).alias('timeAgoInWords', 'timeDiffInWords');
|
|
|
|
|
|
/*
|
|
---
|
|
|
|
name: Hash
|
|
|
|
description: Contains Hash Prototypes. Provides a means for overcoming the JavaScript practical impossibility of extending native Objects.
|
|
|
|
license: MIT-style license.
|
|
|
|
requires:
|
|
- Core/Object
|
|
- /MooTools.More
|
|
|
|
provides: [Hash]
|
|
|
|
...
|
|
*/
|
|
|
|
(function(){
|
|
|
|
if (this.Hash) return;
|
|
|
|
var Hash = this.Hash = new Type('Hash', function(object){
|
|
if (typeOf(object) == 'hash') object = Object.clone(object.getClean());
|
|
for (var key in object) this[key] = object[key];
|
|
return this;
|
|
});
|
|
|
|
this.$H = function(object){
|
|
return new Hash(object);
|
|
};
|
|
|
|
Hash.implement({
|
|
|
|
forEach: function(fn, bind){
|
|
Object.forEach(this, fn, bind);
|
|
},
|
|
|
|
getClean: function(){
|
|
var clean = {};
|
|
for (var key in this){
|
|
if (this.hasOwnProperty(key)) clean[key] = this[key];
|
|
}
|
|
return clean;
|
|
},
|
|
|
|
getLength: function(){
|
|
var length = 0;
|
|
for (var key in this){
|
|
if (this.hasOwnProperty(key)) length++;
|
|
}
|
|
return length;
|
|
}
|
|
|
|
});
|
|
|
|
Hash.alias('each', 'forEach');
|
|
|
|
Hash.implement({
|
|
|
|
has: Object.prototype.hasOwnProperty,
|
|
|
|
keyOf: function(value){
|
|
return Object.keyOf(this, value);
|
|
},
|
|
|
|
hasValue: function(value){
|
|
return Object.contains(this, value);
|
|
},
|
|
|
|
extend: function(properties){
|
|
Hash.each(properties || {}, function(value, key){
|
|
Hash.set(this, key, value);
|
|
}, this);
|
|
return this;
|
|
},
|
|
|
|
combine: function(properties){
|
|
Hash.each(properties || {}, function(value, key){
|
|
Hash.include(this, key, value);
|
|
}, this);
|
|
return this;
|
|
},
|
|
|
|
erase: function(key){
|
|
if (this.hasOwnProperty(key)) delete this[key];
|
|
return this;
|
|
},
|
|
|
|
get: function(key){
|
|
return (this.hasOwnProperty(key)) ? this[key] : null;
|
|
},
|
|
|
|
set: function(key, value){
|
|
if (!this[key] || this.hasOwnProperty(key)) this[key] = value;
|
|
return this;
|
|
},
|
|
|
|
empty: function(){
|
|
Hash.each(this, function(value, key){
|
|
delete this[key];
|
|
}, this);
|
|
return this;
|
|
},
|
|
|
|
include: function(key, value){
|
|
if (this[key] == undefined) this[key] = value;
|
|
return this;
|
|
},
|
|
|
|
map: function(fn, bind){
|
|
return new Hash(Object.map(this, fn, bind));
|
|
},
|
|
|
|
filter: function(fn, bind){
|
|
return new Hash(Object.filter(this, fn, bind));
|
|
},
|
|
|
|
every: function(fn, bind){
|
|
return Object.every(this, fn, bind);
|
|
},
|
|
|
|
some: function(fn, bind){
|
|
return Object.some(this, fn, bind);
|
|
},
|
|
|
|
getKeys: function(){
|
|
return Object.keys(this);
|
|
},
|
|
|
|
getValues: function(){
|
|
return Object.values(this);
|
|
},
|
|
|
|
toQueryString: function(base){
|
|
return Object.toQueryString(this, base);
|
|
}
|
|
|
|
});
|
|
|
|
Hash.alias({indexOf: 'keyOf', contains: 'hasValue'});
|
|
|
|
|
|
}).call(this);
|
|
|
|
|
|
|
|
/*
|
|
---
|
|
|
|
script: Request.JSONP.js
|
|
|
|
name: Request.JSONP
|
|
|
|
description: Defines Request.JSONP, a class for cross domain javascript via script injection.
|
|
|
|
license: MIT-style license
|
|
|
|
authors:
|
|
- Aaron Newton
|
|
- Guillermo Rauch
|
|
- Arian Stolwijk
|
|
|
|
requires:
|
|
- Core/Element
|
|
- Core/Request
|
|
- MooTools.More
|
|
|
|
provides: [Request.JSONP]
|
|
|
|
...
|
|
*/
|
|
|
|
Request.JSONP = new Class({
|
|
|
|
Implements: [Chain, Events, Options],
|
|
|
|
options: {
|
|
/*
|
|
onRequest: function(src, scriptElement){},
|
|
onComplete: function(data){},
|
|
onSuccess: function(data){},
|
|
onCancel: function(){},
|
|
onTimeout: function(){},
|
|
onError: function(){}, */
|
|
onRequest: function(src){
|
|
if (this.options.log && window.console && console.log){
|
|
console.log('JSONP retrieving script with url:' + src);
|
|
}
|
|
},
|
|
onError: function(src){
|
|
if (this.options.log && window.console && console.warn){
|
|
console.warn('JSONP '+ src +' will fail in Internet Explorer, which enforces a 2083 bytes length limit on URIs');
|
|
}
|
|
},
|
|
url: '',
|
|
callbackKey: 'callback',
|
|
injectScript: document.head,
|
|
data: '',
|
|
link: 'ignore',
|
|
timeout: 0,
|
|
log: false
|
|
},
|
|
|
|
initialize: function(options){
|
|
this.setOptions(options);
|
|
},
|
|
|
|
send: function(options){
|
|
if (!Request.prototype.check.call(this, options)) return this;
|
|
this.running = true;
|
|
|
|
var type = typeOf(options);
|
|
if (type == 'string' || type == 'element') options = {data: options};
|
|
options = Object.merge(this.options, options || {});
|
|
|
|
var data = options.data;
|
|
switch (typeOf(data)){
|
|
case 'element': data = document.id(data).toQueryString(); break;
|
|
case 'object': case 'hash': data = Object.toQueryString(data);
|
|
}
|
|
|
|
var index = this.index = Request.JSONP.counter++;
|
|
|
|
var src = options.url +
|
|
(options.url.test('\\?') ? '&' :'?') +
|
|
(options.callbackKey) +
|
|
'=Request.JSONP.request_map.request_'+ index +
|
|
(data ? '&' + data : '');
|
|
|
|
if (src.length > 2083) this.fireEvent('error', src);
|
|
|
|
Request.JSONP.request_map['request_' + index] = function(){
|
|
this.success(arguments, index);
|
|
}.bind(this);
|
|
|
|
var script = this.getScript(src).inject(options.injectScript);
|
|
this.fireEvent('request', [src, script]);
|
|
|
|
if (options.timeout) this.timeout.delay(options.timeout, this);
|
|
|
|
return this;
|
|
},
|
|
|
|
getScript: function(src){
|
|
if (!this.script) this.script = new Element('script[type=text/javascript]', {
|
|
async: true,
|
|
src: src
|
|
});
|
|
return this.script;
|
|
},
|
|
|
|
success: function(args, index){
|
|
if (!this.running) return false;
|
|
this.clear()
|
|
.fireEvent('complete', args).fireEvent('success', args)
|
|
.callChain();
|
|
},
|
|
|
|
cancel: function(){
|
|
if (this.running) this.clear().fireEvent('cancel');
|
|
return this;
|
|
},
|
|
|
|
isRunning: function(){
|
|
return !!this.running;
|
|
},
|
|
|
|
clear: function(){
|
|
this.running = false;
|
|
if (this.script){
|
|
this.script.destroy();
|
|
this.script = null;
|
|
}
|
|
return this;
|
|
},
|
|
|
|
timeout: function(){
|
|
if (this.running){
|
|
this.running = false;
|
|
this.fireEvent('timeout', [this.script.get('src'), this.script]).fireEvent('failure').cancel();
|
|
}
|
|
return this;
|
|
}
|
|
|
|
});
|
|
|
|
Request.JSONP.counter = 0;
|
|
Request.JSONP.request_map = {};
|
|
|
|
|