mirror of
https://github.com/lazylibrarian/LazyLibrarian.git
synced 2026-06-12 01:28:41 -04:00
So branching to new branch, and will merge my changes from itsmeg ontop will merge branch back to head once everyone happy its stable.
3164 lines
75 KiB
JavaScript
3164 lines
75 KiB
JavaScript
// MooTools: the javascript framework.
|
|
// Load this file's selection again by visiting: http://mootools.net/more/43db227db7a621ebb062ee621432ae3d
|
|
// Or build this file again with packager using: packager build More/Events.Pseudos More/Date More/Date.Extras More/Element.Forms More/Element.Position More/Element.Shortcuts More/Fx.Scroll More/Fx.Slide More/Sortables More/Request.JSONP More/Request.Periodical
|
|
/*
|
|
---
|
|
|
|
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
|
|
- Jacob Thornton
|
|
|
|
requires:
|
|
- Core/MooTools
|
|
|
|
provides: [MooTools.More]
|
|
|
|
...
|
|
*/
|
|
|
|
MooTools.More = {
|
|
'version': '1.4.0.1',
|
|
'build': 'a4244edf2aa97ac8a196fc96082dd35af1abab87'
|
|
};
|
|
|
|
|
|
/*
|
|
---
|
|
|
|
name: Events.Pseudos
|
|
|
|
description: Adds the functionality to add pseudo events
|
|
|
|
license: MIT-style license
|
|
|
|
authors:
|
|
- Arian Stolwijk
|
|
|
|
requires: [Core/Class.Extras, Core/Slick.Parser, More/MooTools.More]
|
|
|
|
provides: [Events.Pseudos]
|
|
|
|
...
|
|
*/
|
|
|
|
(function(){
|
|
|
|
Events.Pseudos = function(pseudos, addEvent, removeEvent){
|
|
|
|
var storeKey = '_monitorEvents:';
|
|
|
|
var storageOf = function(object){
|
|
return {
|
|
store: object.store ? function(key, value){
|
|
object.store(storeKey + key, value);
|
|
} : function(key, value){
|
|
(object._monitorEvents || (object._monitorEvents = {}))[key] = value;
|
|
},
|
|
retrieve: object.retrieve ? function(key, dflt){
|
|
return object.retrieve(storeKey + key, dflt);
|
|
} : function(key, dflt){
|
|
if (!object._monitorEvents) return dflt;
|
|
return object._monitorEvents[key] || dflt;
|
|
}
|
|
};
|
|
};
|
|
|
|
var splitType = function(type){
|
|
if (type.indexOf(':') == -1 || !pseudos) return null;
|
|
|
|
var parsed = Slick.parse(type).expressions[0][0],
|
|
parsedPseudos = parsed.pseudos,
|
|
l = parsedPseudos.length,
|
|
splits = [];
|
|
|
|
while (l--){
|
|
var pseudo = parsedPseudos[l].key,
|
|
listener = pseudos[pseudo];
|
|
if (listener != null) splits.push({
|
|
event: parsed.tag,
|
|
value: parsedPseudos[l].value,
|
|
pseudo: pseudo,
|
|
original: type,
|
|
listener: listener
|
|
});
|
|
}
|
|
return splits.length ? splits : null;
|
|
};
|
|
|
|
return {
|
|
|
|
addEvent: function(type, fn, internal){
|
|
var split = splitType(type);
|
|
if (!split) return addEvent.call(this, type, fn, internal);
|
|
|
|
var storage = storageOf(this),
|
|
events = storage.retrieve(type, []),
|
|
eventType = split[0].event,
|
|
args = Array.slice(arguments, 2),
|
|
stack = fn,
|
|
self = this;
|
|
|
|
split.each(function(item){
|
|
var listener = item.listener,
|
|
stackFn = stack;
|
|
if (listener == false) eventType += ':' + item.pseudo + '(' + item.value + ')';
|
|
else stack = function(){
|
|
listener.call(self, item, stackFn, arguments, stack);
|
|
};
|
|
});
|
|
|
|
events.include({type: eventType, event: fn, monitor: stack});
|
|
storage.store(type, events);
|
|
|
|
if (type != eventType) addEvent.apply(this, [type, fn].concat(args));
|
|
return addEvent.apply(this, [eventType, stack].concat(args));
|
|
},
|
|
|
|
removeEvent: function(type, fn){
|
|
var split = splitType(type);
|
|
if (!split) return removeEvent.call(this, type, fn);
|
|
|
|
var storage = storageOf(this),
|
|
events = storage.retrieve(type);
|
|
if (!events) return this;
|
|
|
|
var args = Array.slice(arguments, 2);
|
|
|
|
removeEvent.apply(this, [type, fn].concat(args));
|
|
events.each(function(monitor, i){
|
|
if (!fn || monitor.event == fn) removeEvent.apply(this, [monitor.type, monitor.monitor].concat(args));
|
|
delete events[i];
|
|
}, this);
|
|
|
|
storage.store(type, events);
|
|
return this;
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
var pseudos = {
|
|
|
|
once: function(split, fn, args, monitor){
|
|
fn.apply(this, args);
|
|
this.removeEvent(split.event, monitor)
|
|
.removeEvent(split.original, fn);
|
|
},
|
|
|
|
throttle: function(split, fn, args){
|
|
if (!fn._throttled){
|
|
fn.apply(this, args);
|
|
fn._throttled = setTimeout(function(){
|
|
fn._throttled = false;
|
|
}, split.value || 250);
|
|
}
|
|
},
|
|
|
|
pause: function(split, fn, args){
|
|
clearTimeout(fn._pause);
|
|
fn._pause = fn.delay(split.value || 250, this, args);
|
|
}
|
|
|
|
};
|
|
|
|
Events.definePseudo = function(key, listener){
|
|
pseudos[key] = listener;
|
|
return this;
|
|
};
|
|
|
|
Events.lookupPseudo = function(key){
|
|
return pseudos[key];
|
|
};
|
|
|
|
var proto = Events.prototype;
|
|
Events.implement(Events.Pseudos(pseudos, proto.addEvent, proto.removeEvent));
|
|
|
|
['Request', 'Fx'].each(function(klass){
|
|
if (this[klass]) this[klass].implement(Events.prototype);
|
|
});
|
|
|
|
})();
|
|
|
|
|
|
/*
|
|
---
|
|
|
|
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;
|
|
}
|
|
|
|
});
|
|
|
|
})();
|
|
|
|
|
|
/*
|
|
---
|
|
|
|
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;
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
})();
|
|
|
|
|
|
/*
|
|
---
|
|
|
|
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){
|
|
if (!date) date = this;
|
|
return typeOf(date) == 'date' && !isNaN(date.valueOf());
|
|
},
|
|
|
|
format: function(format){
|
|
if (!this.isValid()) return 'invalid date';
|
|
|
|
if (!format) format = '%x %X';
|
|
if (typeof format == 'string') format = formats[format.toLowerCase()] || format;
|
|
if (typeof format == 'function') return format(this);
|
|
|
|
var d = this;
|
|
return format.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'
|
|
});
|
|
|
|
// 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 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',
|
|
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;
|
|
},
|
|
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
}).extend({
|
|
defineFormats: Date.defineFormat.overloadSetter()
|
|
});
|
|
|
|
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());
|
|
|
|
})();
|
|
|
|
|
|
/*
|
|
---
|
|
|
|
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().abs();
|
|
|
|
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');
|
|
|
|
|
|
/*
|
|
---
|
|
|
|
script: String.Extras.js
|
|
|
|
name: String.Extras
|
|
|
|
description: Extends the String native object to include methods useful in managing various kinds of strings (query strings, urls, html, etc).
|
|
|
|
license: MIT-style license
|
|
|
|
authors:
|
|
- Aaron Newton
|
|
- Guillermo Rauch
|
|
- Christopher Pitt
|
|
|
|
requires:
|
|
- Core/String
|
|
- Core/Array
|
|
- MooTools.More
|
|
|
|
provides: [String.Extras]
|
|
|
|
...
|
|
*/
|
|
|
|
(function(){
|
|
|
|
var special = {
|
|
'a': /[àáâãäåăą]/g,
|
|
'A': /[ÀÁÂÃÄÅĂĄ]/g,
|
|
'c': /[ćčç]/g,
|
|
'C': /[ĆČÇ]/g,
|
|
'd': /[ďđ]/g,
|
|
'D': /[ĎÐ]/g,
|
|
'e': /[èéêëěę]/g,
|
|
'E': /[ÈÉÊËĚĘ]/g,
|
|
'g': /[ğ]/g,
|
|
'G': /[Ğ]/g,
|
|
'i': /[ìíîï]/g,
|
|
'I': /[ÌÍÎÏ]/g,
|
|
'l': /[ĺľł]/g,
|
|
'L': /[ĹĽŁ]/g,
|
|
'n': /[ñňń]/g,
|
|
'N': /[ÑŇŃ]/g,
|
|
'o': /[òóôõöøő]/g,
|
|
'O': /[ÒÓÔÕÖØ]/g,
|
|
'r': /[řŕ]/g,
|
|
'R': /[ŘŔ]/g,
|
|
's': /[ššş]/g,
|
|
'S': /[ŠŞŚ]/g,
|
|
't': /[ťţ]/g,
|
|
'T': /[ŤŢ]/g,
|
|
'ue': /[ü]/g,
|
|
'UE': /[Ü]/g,
|
|
'u': /[ùúûůµ]/g,
|
|
'U': /[ÙÚÛŮ]/g,
|
|
'y': /[ÿý]/g,
|
|
'Y': /[ŸÝ]/g,
|
|
'z': /[žźż]/g,
|
|
'Z': /[ŽŹŻ]/g,
|
|
'th': /[þ]/g,
|
|
'TH': /[Þ]/g,
|
|
'dh': /[ð]/g,
|
|
'DH': /[Ð]/g,
|
|
'ss': /[ß]/g,
|
|
'oe': /[œ]/g,
|
|
'OE': /[Œ]/g,
|
|
'ae': /[æ]/g,
|
|
'AE': /[Æ]/g
|
|
},
|
|
|
|
tidy = {
|
|
' ': /[\xa0\u2002\u2003\u2009]/g,
|
|
'*': /[\xb7]/g,
|
|
'\'': /[\u2018\u2019]/g,
|
|
'"': /[\u201c\u201d]/g,
|
|
'...': /[\u2026]/g,
|
|
'-': /[\u2013]/g,
|
|
// '--': /[\u2014]/g,
|
|
'»': /[\uFFFD]/g
|
|
};
|
|
|
|
var walk = function(string, replacements){
|
|
var result = string, key;
|
|
for (key in replacements) result = result.replace(replacements[key], key);
|
|
return result;
|
|
};
|
|
|
|
var getRegexForTag = function(tag, contents){
|
|
tag = tag || '';
|
|
var regstr = contents ? "<" + tag + "(?!\\w)[^>]*>([\\s\\S]*?)<\/" + tag + "(?!\\w)>" : "<\/?" + tag + "([^>]+)?>",
|
|
reg = new RegExp(regstr, "gi");
|
|
return reg;
|
|
};
|
|
|
|
String.implement({
|
|
|
|
standardize: function(){
|
|
return walk(this, special);
|
|
},
|
|
|
|
repeat: function(times){
|
|
return new Array(times + 1).join(this);
|
|
},
|
|
|
|
pad: function(length, str, direction){
|
|
if (this.length >= length) return this;
|
|
|
|
var pad = (str == null ? ' ' : '' + str)
|
|
.repeat(length - this.length)
|
|
.substr(0, length - this.length);
|
|
|
|
if (!direction || direction == 'right') return this + pad;
|
|
if (direction == 'left') return pad + this;
|
|
|
|
return pad.substr(0, (pad.length / 2).floor()) + this + pad.substr(0, (pad.length / 2).ceil());
|
|
},
|
|
|
|
getTags: function(tag, contents){
|
|
return this.match(getRegexForTag(tag, contents)) || [];
|
|
},
|
|
|
|
stripTags: function(tag, contents){
|
|
return this.replace(getRegexForTag(tag, contents), '');
|
|
},
|
|
|
|
tidy: function(){
|
|
return walk(this, tidy);
|
|
},
|
|
|
|
truncate: function(max, trail, atChar){
|
|
var string = this;
|
|
if (trail == null && arguments.length == 1) trail = '…';
|
|
if (string.length > max){
|
|
string = string.substring(0, max);
|
|
if (atChar){
|
|
var index = string.lastIndexOf(atChar);
|
|
if (index != -1) string = string.substr(0, index);
|
|
}
|
|
if (trail) string += trail;
|
|
}
|
|
return string;
|
|
}
|
|
|
|
});
|
|
|
|
})();
|
|
|
|
|
|
/*
|
|
---
|
|
|
|
script: Element.Forms.js
|
|
|
|
name: Element.Forms
|
|
|
|
description: Extends the Element native object to include methods useful in managing inputs.
|
|
|
|
license: MIT-style license
|
|
|
|
authors:
|
|
- Aaron Newton
|
|
|
|
requires:
|
|
- Core/Element
|
|
- /String.Extras
|
|
- /MooTools.More
|
|
|
|
provides: [Element.Forms]
|
|
|
|
...
|
|
*/
|
|
|
|
Element.implement({
|
|
|
|
tidy: function(){
|
|
this.set('value', this.get('value').tidy());
|
|
},
|
|
|
|
getTextInRange: function(start, end){
|
|
return this.get('value').substring(start, end);
|
|
},
|
|
|
|
getSelectedText: function(){
|
|
if (this.setSelectionRange) return this.getTextInRange(this.getSelectionStart(), this.getSelectionEnd());
|
|
return document.selection.createRange().text;
|
|
},
|
|
|
|
getSelectedRange: function(){
|
|
if (this.selectionStart != null){
|
|
return {
|
|
start: this.selectionStart,
|
|
end: this.selectionEnd
|
|
};
|
|
}
|
|
|
|
var pos = {
|
|
start: 0,
|
|
end: 0
|
|
};
|
|
var range = this.getDocument().selection.createRange();
|
|
if (!range || range.parentElement() != this) return pos;
|
|
var duplicate = range.duplicate();
|
|
|
|
if (this.type == 'text'){
|
|
pos.start = 0 - duplicate.moveStart('character', -100000);
|
|
pos.end = pos.start + range.text.length;
|
|
} else {
|
|
var value = this.get('value');
|
|
var offset = value.length;
|
|
duplicate.moveToElementText(this);
|
|
duplicate.setEndPoint('StartToEnd', range);
|
|
if (duplicate.text.length) offset -= value.match(/[\n\r]*$/)[0].length;
|
|
pos.end = offset - duplicate.text.length;
|
|
duplicate.setEndPoint('StartToStart', range);
|
|
pos.start = offset - duplicate.text.length;
|
|
}
|
|
return pos;
|
|
},
|
|
|
|
getSelectionStart: function(){
|
|
return this.getSelectedRange().start;
|
|
},
|
|
|
|
getSelectionEnd: function(){
|
|
return this.getSelectedRange().end;
|
|
},
|
|
|
|
setCaretPosition: function(pos){
|
|
if (pos == 'end') pos = this.get('value').length;
|
|
this.selectRange(pos, pos);
|
|
return this;
|
|
},
|
|
|
|
getCaretPosition: function(){
|
|
return this.getSelectedRange().start;
|
|
},
|
|
|
|
selectRange: function(start, end){
|
|
if (this.setSelectionRange){
|
|
this.focus();
|
|
this.setSelectionRange(start, end);
|
|
} else {
|
|
var value = this.get('value');
|
|
var diff = value.substr(start, end - start).replace(/\r/g, '').length;
|
|
start = value.substr(0, start).replace(/\r/g, '').length;
|
|
var range = this.createTextRange();
|
|
range.collapse(true);
|
|
range.moveEnd('character', start + diff);
|
|
range.moveStart('character', start);
|
|
range.select();
|
|
}
|
|
return this;
|
|
},
|
|
|
|
insertAtCursor: function(value, select){
|
|
var pos = this.getSelectedRange();
|
|
var text = this.get('value');
|
|
this.set('value', text.substring(0, pos.start) + value + text.substring(pos.end, text.length));
|
|
if (select !== false) this.selectRange(pos.start, pos.start + value.length);
|
|
else this.setCaretPosition(pos.start + value.length);
|
|
return this;
|
|
},
|
|
|
|
insertAroundCursor: function(options, select){
|
|
options = Object.append({
|
|
before: '',
|
|
defaultMiddle: '',
|
|
after: ''
|
|
}, options);
|
|
|
|
var value = this.getSelectedText() || options.defaultMiddle;
|
|
var pos = this.getSelectedRange();
|
|
var text = this.get('value');
|
|
|
|
if (pos.start == pos.end){
|
|
this.set('value', text.substring(0, pos.start) + options.before + value + options.after + text.substring(pos.end, text.length));
|
|
this.selectRange(pos.start + options.before.length, pos.end + options.before.length + value.length);
|
|
} else {
|
|
var current = text.substring(pos.start, pos.end);
|
|
this.set('value', text.substring(0, pos.start) + options.before + current + options.after + text.substring(pos.end, text.length));
|
|
var selStart = pos.start + options.before.length;
|
|
if (select !== false) this.selectRange(selStart, selStart + current.length);
|
|
else this.setCaretPosition(selStart + text.length);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
});
|
|
|
|
|
|
/*
|
|
---
|
|
|
|
script: Element.Measure.js
|
|
|
|
name: Element.Measure
|
|
|
|
description: Extends the Element native object to include methods useful in measuring dimensions.
|
|
|
|
credits: "Element.measure / .expose methods by Daniel Steigerwald License: MIT-style license. Copyright: Copyright (c) 2008 Daniel Steigerwald, daniel.steigerwald.cz"
|
|
|
|
license: MIT-style license
|
|
|
|
authors:
|
|
- Aaron Newton
|
|
|
|
requires:
|
|
- Core/Element.Style
|
|
- Core/Element.Dimensions
|
|
- /MooTools.More
|
|
|
|
provides: [Element.Measure]
|
|
|
|
...
|
|
*/
|
|
|
|
(function(){
|
|
|
|
var getStylesList = function(styles, planes){
|
|
var list = [];
|
|
Object.each(planes, function(directions){
|
|
Object.each(directions, function(edge){
|
|
styles.each(function(style){
|
|
list.push(style + '-' + edge + (style == 'border' ? '-width' : ''));
|
|
});
|
|
});
|
|
});
|
|
return list;
|
|
};
|
|
|
|
var calculateEdgeSize = function(edge, styles){
|
|
var total = 0;
|
|
Object.each(styles, function(value, style){
|
|
if (style.test(edge)) total = total + value.toInt();
|
|
});
|
|
return total;
|
|
};
|
|
|
|
var isVisible = function(el){
|
|
return !!(!el || el.offsetHeight || el.offsetWidth);
|
|
};
|
|
|
|
|
|
Element.implement({
|
|
|
|
measure: function(fn){
|
|
if (isVisible(this)) return fn.call(this);
|
|
var parent = this.getParent(),
|
|
toMeasure = [];
|
|
while (!isVisible(parent) && parent != document.body){
|
|
toMeasure.push(parent.expose());
|
|
parent = parent.getParent();
|
|
}
|
|
var restore = this.expose(),
|
|
result = fn.call(this);
|
|
restore();
|
|
toMeasure.each(function(restore){
|
|
restore();
|
|
});
|
|
return result;
|
|
},
|
|
|
|
expose: function(){
|
|
if (this.getStyle('display') != 'none') return function(){};
|
|
var before = this.style.cssText;
|
|
this.setStyles({
|
|
display: 'block',
|
|
position: 'absolute',
|
|
visibility: 'hidden'
|
|
});
|
|
return function(){
|
|
this.style.cssText = before;
|
|
}.bind(this);
|
|
},
|
|
|
|
getDimensions: function(options){
|
|
options = Object.merge({computeSize: false}, options);
|
|
var dim = {x: 0, y: 0};
|
|
|
|
var getSize = function(el, options){
|
|
return (options.computeSize) ? el.getComputedSize(options) : el.getSize();
|
|
};
|
|
|
|
var parent = this.getParent('body');
|
|
|
|
if (parent && this.getStyle('display') == 'none'){
|
|
dim = this.measure(function(){
|
|
return getSize(this, options);
|
|
});
|
|
} else if (parent){
|
|
try { //safari sometimes crashes here, so catch it
|
|
dim = getSize(this, options);
|
|
}catch(e){}
|
|
}
|
|
|
|
return Object.append(dim, (dim.x || dim.x === 0) ? {
|
|
width: dim.x,
|
|
height: dim.y
|
|
} : {
|
|
x: dim.width,
|
|
y: dim.height
|
|
}
|
|
);
|
|
},
|
|
|
|
getComputedSize: function(options){
|
|
|
|
|
|
options = Object.merge({
|
|
styles: ['padding','border'],
|
|
planes: {
|
|
height: ['top','bottom'],
|
|
width: ['left','right']
|
|
},
|
|
mode: 'both'
|
|
}, options);
|
|
|
|
var styles = {},
|
|
size = {width: 0, height: 0},
|
|
dimensions;
|
|
|
|
if (options.mode == 'vertical'){
|
|
delete size.width;
|
|
delete options.planes.width;
|
|
} else if (options.mode == 'horizontal'){
|
|
delete size.height;
|
|
delete options.planes.height;
|
|
}
|
|
|
|
getStylesList(options.styles, options.planes).each(function(style){
|
|
styles[style] = this.getStyle(style).toInt();
|
|
}, this);
|
|
|
|
Object.each(options.planes, function(edges, plane){
|
|
|
|
var capitalized = plane.capitalize(),
|
|
style = this.getStyle(plane);
|
|
|
|
if (style == 'auto' && !dimensions) dimensions = this.getDimensions();
|
|
|
|
style = styles[plane] = (style == 'auto') ? dimensions[plane] : style.toInt();
|
|
size['total' + capitalized] = style;
|
|
|
|
edges.each(function(edge){
|
|
var edgesize = calculateEdgeSize(edge, styles);
|
|
size['computed' + edge.capitalize()] = edgesize;
|
|
size['total' + capitalized] += edgesize;
|
|
});
|
|
|
|
}, this);
|
|
|
|
return Object.append(size, styles);
|
|
}
|
|
|
|
});
|
|
|
|
})();
|
|
|
|
|
|
/*
|
|
---
|
|
|
|
script: Element.Position.js
|
|
|
|
name: Element.Position
|
|
|
|
description: Extends the Element native object to include methods useful positioning elements relative to others.
|
|
|
|
license: MIT-style license
|
|
|
|
authors:
|
|
- Aaron Newton
|
|
- Jacob Thornton
|
|
|
|
requires:
|
|
- Core/Options
|
|
- Core/Element.Dimensions
|
|
- Element.Measure
|
|
|
|
provides: [Element.Position]
|
|
|
|
...
|
|
*/
|
|
|
|
(function(original){
|
|
|
|
var local = Element.Position = {
|
|
|
|
options: {/*
|
|
edge: false,
|
|
returnPos: false,
|
|
minimum: {x: 0, y: 0},
|
|
maximum: {x: 0, y: 0},
|
|
relFixedPosition: false,
|
|
ignoreMargins: false,
|
|
ignoreScroll: false,
|
|
allowNegative: false,*/
|
|
relativeTo: document.body,
|
|
position: {
|
|
x: 'center', //left, center, right
|
|
y: 'center' //top, center, bottom
|
|
},
|
|
offset: {x: 0, y: 0}
|
|
},
|
|
|
|
getOptions: function(element, options){
|
|
options = Object.merge({}, local.options, options);
|
|
local.setPositionOption(options);
|
|
local.setEdgeOption(options);
|
|
local.setOffsetOption(element, options);
|
|
local.setDimensionsOption(element, options);
|
|
return options;
|
|
},
|
|
|
|
setPositionOption: function(options){
|
|
options.position = local.getCoordinateFromValue(options.position);
|
|
},
|
|
|
|
setEdgeOption: function(options){
|
|
var edgeOption = local.getCoordinateFromValue(options.edge);
|
|
options.edge = edgeOption ? edgeOption :
|
|
(options.position.x == 'center' && options.position.y == 'center') ? {x: 'center', y: 'center'} :
|
|
{x: 'left', y: 'top'};
|
|
},
|
|
|
|
setOffsetOption: function(element, options){
|
|
var parentOffset = {x: 0, y: 0},
|
|
offsetParent = element.measure(function(){
|
|
return document.id(this.getOffsetParent());
|
|
}),
|
|
parentScroll = offsetParent.getScroll();
|
|
|
|
if (!offsetParent || offsetParent == element.getDocument().body) return;
|
|
parentOffset = offsetParent.measure(function(){
|
|
var position = this.getPosition();
|
|
if (this.getStyle('position') == 'fixed'){
|
|
var scroll = window.getScroll();
|
|
position.x += scroll.x;
|
|
position.y += scroll.y;
|
|
}
|
|
return position;
|
|
});
|
|
|
|
options.offset = {
|
|
parentPositioned: offsetParent != document.id(options.relativeTo),
|
|
x: options.offset.x - parentOffset.x + parentScroll.x,
|
|
y: options.offset.y - parentOffset.y + parentScroll.y
|
|
};
|
|
},
|
|
|
|
setDimensionsOption: function(element, options){
|
|
options.dimensions = element.getDimensions({
|
|
computeSize: true,
|
|
styles: ['padding', 'border', 'margin']
|
|
});
|
|
},
|
|
|
|
getPosition: function(element, options){
|
|
var position = {};
|
|
options = local.getOptions(element, options);
|
|
var relativeTo = document.id(options.relativeTo) || document.body;
|
|
|
|
local.setPositionCoordinates(options, position, relativeTo);
|
|
if (options.edge) local.toEdge(position, options);
|
|
|
|
var offset = options.offset;
|
|
position.left = ((position.x >= 0 || offset.parentPositioned || options.allowNegative) ? position.x : 0).toInt();
|
|
position.top = ((position.y >= 0 || offset.parentPositioned || options.allowNegative) ? position.y : 0).toInt();
|
|
|
|
local.toMinMax(position, options);
|
|
|
|
if (options.relFixedPosition || relativeTo.getStyle('position') == 'fixed') local.toRelFixedPosition(relativeTo, position);
|
|
if (options.ignoreScroll) local.toIgnoreScroll(relativeTo, position);
|
|
if (options.ignoreMargins) local.toIgnoreMargins(position, options);
|
|
|
|
position.left = Math.ceil(position.left);
|
|
position.top = Math.ceil(position.top);
|
|
delete position.x;
|
|
delete position.y;
|
|
|
|
return position;
|
|
},
|
|
|
|
setPositionCoordinates: function(options, position, relativeTo){
|
|
var offsetY = options.offset.y,
|
|
offsetX = options.offset.x,
|
|
calc = (relativeTo == document.body) ? window.getScroll() : relativeTo.getPosition(),
|
|
top = calc.y,
|
|
left = calc.x,
|
|
winSize = window.getSize();
|
|
|
|
switch(options.position.x){
|
|
case 'left': position.x = left + offsetX; break;
|
|
case 'right': position.x = left + offsetX + relativeTo.offsetWidth; break;
|
|
default: position.x = left + ((relativeTo == document.body ? winSize.x : relativeTo.offsetWidth) / 2) + offsetX; break;
|
|
}
|
|
|
|
switch(options.position.y){
|
|
case 'top': position.y = top + offsetY; break;
|
|
case 'bottom': position.y = top + offsetY + relativeTo.offsetHeight; break;
|
|
default: position.y = top + ((relativeTo == document.body ? winSize.y : relativeTo.offsetHeight) / 2) + offsetY; break;
|
|
}
|
|
},
|
|
|
|
toMinMax: function(position, options){
|
|
var xy = {left: 'x', top: 'y'}, value;
|
|
['minimum', 'maximum'].each(function(minmax){
|
|
['left', 'top'].each(function(lr){
|
|
value = options[minmax] ? options[minmax][xy[lr]] : null;
|
|
if (value != null && ((minmax == 'minimum') ? position[lr] < value : position[lr] > value)) position[lr] = value;
|
|
});
|
|
});
|
|
},
|
|
|
|
toRelFixedPosition: function(relativeTo, position){
|
|
var winScroll = window.getScroll();
|
|
position.top += winScroll.y;
|
|
position.left += winScroll.x;
|
|
},
|
|
|
|
toIgnoreScroll: function(relativeTo, position){
|
|
var relScroll = relativeTo.getScroll();
|
|
position.top -= relScroll.y;
|
|
position.left -= relScroll.x;
|
|
},
|
|
|
|
toIgnoreMargins: function(position, options){
|
|
position.left += options.edge.x == 'right'
|
|
? options.dimensions['margin-right']
|
|
: (options.edge.x != 'center'
|
|
? -options.dimensions['margin-left']
|
|
: -options.dimensions['margin-left'] + ((options.dimensions['margin-right'] + options.dimensions['margin-left']) / 2));
|
|
|
|
position.top += options.edge.y == 'bottom'
|
|
? options.dimensions['margin-bottom']
|
|
: (options.edge.y != 'center'
|
|
? -options.dimensions['margin-top']
|
|
: -options.dimensions['margin-top'] + ((options.dimensions['margin-bottom'] + options.dimensions['margin-top']) / 2));
|
|
},
|
|
|
|
toEdge: function(position, options){
|
|
var edgeOffset = {},
|
|
dimensions = options.dimensions,
|
|
edge = options.edge;
|
|
|
|
switch(edge.x){
|
|
case 'left': edgeOffset.x = 0; break;
|
|
case 'right': edgeOffset.x = -dimensions.x - dimensions.computedRight - dimensions.computedLeft; break;
|
|
// center
|
|
default: edgeOffset.x = -(Math.round(dimensions.totalWidth / 2)); break;
|
|
}
|
|
|
|
switch(edge.y){
|
|
case 'top': edgeOffset.y = 0; break;
|
|
case 'bottom': edgeOffset.y = -dimensions.y - dimensions.computedTop - dimensions.computedBottom; break;
|
|
// center
|
|
default: edgeOffset.y = -(Math.round(dimensions.totalHeight / 2)); break;
|
|
}
|
|
|
|
position.x += edgeOffset.x;
|
|
position.y += edgeOffset.y;
|
|
},
|
|
|
|
getCoordinateFromValue: function(option){
|
|
if (typeOf(option) != 'string') return option;
|
|
option = option.toLowerCase();
|
|
|
|
return {
|
|
x: option.test('left') ? 'left'
|
|
: (option.test('right') ? 'right' : 'center'),
|
|
y: option.test(/upper|top/) ? 'top'
|
|
: (option.test('bottom') ? 'bottom' : 'center')
|
|
};
|
|
}
|
|
|
|
};
|
|
|
|
Element.implement({
|
|
|
|
position: function(options){
|
|
if (options && (options.x != null || options.y != null)){
|
|
return (original ? original.apply(this, arguments) : this);
|
|
}
|
|
var position = this.setStyle('position', 'absolute').calculatePosition(options);
|
|
return (options && options.returnPos) ? position : this.setStyles(position);
|
|
},
|
|
|
|
calculatePosition: function(options){
|
|
return local.getPosition(this, options);
|
|
}
|
|
|
|
});
|
|
|
|
})(Element.prototype.position);
|
|
|
|
|
|
/*
|
|
---
|
|
|
|
script: Element.Shortcuts.js
|
|
|
|
name: Element.Shortcuts
|
|
|
|
description: Extends the Element native object to include some shortcut methods.
|
|
|
|
license: MIT-style license
|
|
|
|
authors:
|
|
- Aaron Newton
|
|
|
|
requires:
|
|
- Core/Element.Style
|
|
- /MooTools.More
|
|
|
|
provides: [Element.Shortcuts]
|
|
|
|
...
|
|
*/
|
|
|
|
Element.implement({
|
|
|
|
isDisplayed: function(){
|
|
return this.getStyle('display') != 'none';
|
|
},
|
|
|
|
isVisible: function(){
|
|
var w = this.offsetWidth,
|
|
h = this.offsetHeight;
|
|
return (w == 0 && h == 0) ? false : (w > 0 && h > 0) ? true : this.style.display != 'none';
|
|
},
|
|
|
|
toggle: function(){
|
|
return this[this.isDisplayed() ? 'hide' : 'show']();
|
|
},
|
|
|
|
hide: function(){
|
|
var d;
|
|
try {
|
|
//IE fails here if the element is not in the dom
|
|
d = this.getStyle('display');
|
|
} catch(e){}
|
|
if (d == 'none') return this;
|
|
return this.store('element:_originalDisplay', d || '').setStyle('display', 'none');
|
|
},
|
|
|
|
show: function(display){
|
|
if (!display && this.isDisplayed()) return this;
|
|
display = display || this.retrieve('element:_originalDisplay') || 'block';
|
|
return this.setStyle('display', (display == 'none') ? 'block' : display);
|
|
},
|
|
|
|
swapClass: function(remove, add){
|
|
return this.removeClass(remove).addClass(add);
|
|
}
|
|
|
|
});
|
|
|
|
Document.implement({
|
|
|
|
clearSelection: function(){
|
|
if (window.getSelection){
|
|
var selection = window.getSelection();
|
|
if (selection && selection.removeAllRanges) selection.removeAllRanges();
|
|
} else if (document.selection && document.selection.empty){
|
|
try {
|
|
//IE fails here if selected element is not in dom
|
|
document.selection.empty();
|
|
} catch(e){}
|
|
}
|
|
}
|
|
|
|
});
|
|
|
|
|
|
/*
|
|
---
|
|
|
|
script: Fx.Scroll.js
|
|
|
|
name: Fx.Scroll
|
|
|
|
description: Effect to smoothly scroll any element, including the window.
|
|
|
|
license: MIT-style license
|
|
|
|
authors:
|
|
- Valerio Proietti
|
|
|
|
requires:
|
|
- Core/Fx
|
|
- Core/Element.Event
|
|
- Core/Element.Dimensions
|
|
- /MooTools.More
|
|
|
|
provides: [Fx.Scroll]
|
|
|
|
...
|
|
*/
|
|
|
|
(function(){
|
|
|
|
Fx.Scroll = new Class({
|
|
|
|
Extends: Fx,
|
|
|
|
options: {
|
|
offset: {x: 0, y: 0},
|
|
wheelStops: true
|
|
},
|
|
|
|
initialize: function(element, options){
|
|
this.element = this.subject = document.id(element);
|
|
this.parent(options);
|
|
|
|
if (typeOf(this.element) != 'element') this.element = document.id(this.element.getDocument().body);
|
|
|
|
if (this.options.wheelStops){
|
|
var stopper = this.element,
|
|
cancel = this.cancel.pass(false, this);
|
|
this.addEvent('start', function(){
|
|
stopper.addEvent('mousewheel', cancel);
|
|
}, true);
|
|
this.addEvent('complete', function(){
|
|
stopper.removeEvent('mousewheel', cancel);
|
|
}, true);
|
|
}
|
|
},
|
|
|
|
set: function(){
|
|
var now = Array.flatten(arguments);
|
|
if (Browser.firefox) now = [Math.round(now[0]), Math.round(now[1])]; // not needed anymore in newer firefox versions
|
|
this.element.scrollTo(now[0], now[1]);
|
|
return this;
|
|
},
|
|
|
|
compute: function(from, to, delta){
|
|
return [0, 1].map(function(i){
|
|
return Fx.compute(from[i], to[i], delta);
|
|
});
|
|
},
|
|
|
|
start: function(x, y){
|
|
if (!this.check(x, y)) return this;
|
|
var scroll = this.element.getScroll();
|
|
return this.parent([scroll.x, scroll.y], [x, y]);
|
|
},
|
|
|
|
calculateScroll: function(x, y){
|
|
var element = this.element,
|
|
scrollSize = element.getScrollSize(),
|
|
scroll = element.getScroll(),
|
|
size = element.getSize(),
|
|
offset = this.options.offset,
|
|
values = {x: x, y: y};
|
|
|
|
for (var z in values){
|
|
if (!values[z] && values[z] !== 0) values[z] = scroll[z];
|
|
if (typeOf(values[z]) != 'number') values[z] = scrollSize[z] - size[z];
|
|
values[z] += offset[z];
|
|
}
|
|
|
|
return [values.x, values.y];
|
|
},
|
|
|
|
toTop: function(){
|
|
return this.start.apply(this, this.calculateScroll(false, 0));
|
|
},
|
|
|
|
toLeft: function(){
|
|
return this.start.apply(this, this.calculateScroll(0, false));
|
|
},
|
|
|
|
toRight: function(){
|
|
return this.start.apply(this, this.calculateScroll('right', false));
|
|
},
|
|
|
|
toBottom: function(){
|
|
return this.start.apply(this, this.calculateScroll(false, 'bottom'));
|
|
},
|
|
|
|
toElement: function(el, axes){
|
|
axes = axes ? Array.from(axes) : ['x', 'y'];
|
|
var scroll = isBody(this.element) ? {x: 0, y: 0} : this.element.getScroll();
|
|
var position = Object.map(document.id(el).getPosition(this.element), function(value, axis){
|
|
return axes.contains(axis) ? value + scroll[axis] : false;
|
|
});
|
|
return this.start.apply(this, this.calculateScroll(position.x, position.y));
|
|
},
|
|
|
|
toElementEdge: function(el, axes, offset){
|
|
axes = axes ? Array.from(axes) : ['x', 'y'];
|
|
el = document.id(el);
|
|
var to = {},
|
|
position = el.getPosition(this.element),
|
|
size = el.getSize(),
|
|
scroll = this.element.getScroll(),
|
|
containerSize = this.element.getSize(),
|
|
edge = {
|
|
x: position.x + size.x,
|
|
y: position.y + size.y
|
|
};
|
|
|
|
['x', 'y'].each(function(axis){
|
|
if (axes.contains(axis)){
|
|
if (edge[axis] > scroll[axis] + containerSize[axis]) to[axis] = edge[axis] - containerSize[axis];
|
|
if (position[axis] < scroll[axis]) to[axis] = position[axis];
|
|
}
|
|
if (to[axis] == null) to[axis] = scroll[axis];
|
|
if (offset && offset[axis]) to[axis] = to[axis] + offset[axis];
|
|
}, this);
|
|
|
|
if (to.x != scroll.x || to.y != scroll.y) this.start(to.x, to.y);
|
|
return this;
|
|
},
|
|
|
|
toElementCenter: function(el, axes, offset){
|
|
axes = axes ? Array.from(axes) : ['x', 'y'];
|
|
el = document.id(el);
|
|
var to = {},
|
|
position = el.getPosition(this.element),
|
|
size = el.getSize(),
|
|
scroll = this.element.getScroll(),
|
|
containerSize = this.element.getSize();
|
|
|
|
['x', 'y'].each(function(axis){
|
|
if (axes.contains(axis)){
|
|
to[axis] = position[axis] - (containerSize[axis] - size[axis]) / 2;
|
|
}
|
|
if (to[axis] == null) to[axis] = scroll[axis];
|
|
if (offset && offset[axis]) to[axis] = to[axis] + offset[axis];
|
|
}, this);
|
|
|
|
if (to.x != scroll.x || to.y != scroll.y) this.start(to.x, to.y);
|
|
return this;
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
function isBody(element){
|
|
return (/^(?:body|html)$/i).test(element.tagName);
|
|
}
|
|
|
|
})();
|
|
|
|
|
|
/*
|
|
---
|
|
|
|
script: Fx.Slide.js
|
|
|
|
name: Fx.Slide
|
|
|
|
description: Effect to slide an element in and out of view.
|
|
|
|
license: MIT-style license
|
|
|
|
authors:
|
|
- Valerio Proietti
|
|
|
|
requires:
|
|
- Core/Fx
|
|
- Core/Element.Style
|
|
- /MooTools.More
|
|
|
|
provides: [Fx.Slide]
|
|
|
|
...
|
|
*/
|
|
|
|
Fx.Slide = new Class({
|
|
|
|
Extends: Fx,
|
|
|
|
options: {
|
|
mode: 'vertical',
|
|
wrapper: false,
|
|
hideOverflow: true,
|
|
resetHeight: false
|
|
},
|
|
|
|
initialize: function(element, options){
|
|
element = this.element = this.subject = document.id(element);
|
|
this.parent(options);
|
|
options = this.options;
|
|
|
|
var wrapper = element.retrieve('wrapper'),
|
|
styles = element.getStyles('margin', 'position', 'overflow');
|
|
|
|
if (options.hideOverflow) styles = Object.append(styles, {overflow: 'hidden'});
|
|
if (options.wrapper) wrapper = document.id(options.wrapper).setStyles(styles);
|
|
|
|
if (!wrapper) wrapper = new Element('div', {
|
|
styles: styles
|
|
}).wraps(element);
|
|
|
|
element.store('wrapper', wrapper).setStyle('margin', 0);
|
|
if (element.getStyle('overflow') == 'visible') element.setStyle('overflow', 'hidden');
|
|
|
|
this.now = [];
|
|
this.open = true;
|
|
this.wrapper = wrapper;
|
|
|
|
this.addEvent('complete', function(){
|
|
this.open = (wrapper['offset' + this.layout.capitalize()] != 0);
|
|
if (this.open && this.options.resetHeight) wrapper.setStyle('height', '');
|
|
}, true);
|
|
},
|
|
|
|
vertical: function(){
|
|
this.margin = 'margin-top';
|
|
this.layout = 'height';
|
|
this.offset = this.element.offsetHeight;
|
|
},
|
|
|
|
horizontal: function(){
|
|
this.margin = 'margin-left';
|
|
this.layout = 'width';
|
|
this.offset = this.element.offsetWidth;
|
|
},
|
|
|
|
set: function(now){
|
|
this.element.setStyle(this.margin, now[0]);
|
|
this.wrapper.setStyle(this.layout, now[1]);
|
|
return this;
|
|
},
|
|
|
|
compute: function(from, to, delta){
|
|
return [0, 1].map(function(i){
|
|
return Fx.compute(from[i], to[i], delta);
|
|
});
|
|
},
|
|
|
|
start: function(how, mode){
|
|
if (!this.check(how, mode)) return this;
|
|
this[mode || this.options.mode]();
|
|
|
|
var margin = this.element.getStyle(this.margin).toInt(),
|
|
layout = this.wrapper.getStyle(this.layout).toInt(),
|
|
caseIn = [[margin, layout], [0, this.offset]],
|
|
caseOut = [[margin, layout], [-this.offset, 0]],
|
|
start;
|
|
|
|
switch (how){
|
|
case 'in': start = caseIn; break;
|
|
case 'out': start = caseOut; break;
|
|
case 'toggle': start = (layout == 0) ? caseIn : caseOut;
|
|
}
|
|
return this.parent(start[0], start[1]);
|
|
},
|
|
|
|
slideIn: function(mode){
|
|
return this.start('in', mode);
|
|
},
|
|
|
|
slideOut: function(mode){
|
|
return this.start('out', mode);
|
|
},
|
|
|
|
hide: function(mode){
|
|
this[mode || this.options.mode]();
|
|
this.open = false;
|
|
return this.set([-this.offset, 0]);
|
|
},
|
|
|
|
show: function(mode){
|
|
this[mode || this.options.mode]();
|
|
this.open = true;
|
|
return this.set([0, this.offset]);
|
|
},
|
|
|
|
toggle: function(mode){
|
|
return this.start('toggle', mode);
|
|
}
|
|
|
|
});
|
|
|
|
Element.Properties.slide = {
|
|
|
|
set: function(options){
|
|
this.get('slide').cancel().setOptions(options);
|
|
return this;
|
|
},
|
|
|
|
get: function(){
|
|
var slide = this.retrieve('slide');
|
|
if (!slide){
|
|
slide = new Fx.Slide(this, {link: 'cancel'});
|
|
this.store('slide', slide);
|
|
}
|
|
return slide;
|
|
}
|
|
|
|
};
|
|
|
|
Element.implement({
|
|
|
|
slide: function(how, mode){
|
|
how = how || 'toggle';
|
|
var slide = this.get('slide'), toggle;
|
|
switch (how){
|
|
case 'hide': slide.hide(mode); break;
|
|
case 'show': slide.show(mode); break;
|
|
case 'toggle':
|
|
var flag = this.retrieve('slide:flag', slide.open);
|
|
slide[flag ? 'slideOut' : 'slideIn'](mode);
|
|
this.store('slide:flag', !flag);
|
|
toggle = true;
|
|
break;
|
|
default: slide.start(how, mode);
|
|
}
|
|
if (!toggle) this.eliminate('slide:flag');
|
|
return this;
|
|
}
|
|
|
|
});
|
|
|
|
|
|
/*
|
|
---
|
|
|
|
script: Drag.js
|
|
|
|
name: Drag
|
|
|
|
description: The base Drag Class. Can be used to drag and resize Elements using mouse events.
|
|
|
|
license: MIT-style license
|
|
|
|
authors:
|
|
- Valerio Proietti
|
|
- Tom Occhinno
|
|
- Jan Kassens
|
|
|
|
requires:
|
|
- Core/Events
|
|
- Core/Options
|
|
- Core/Element.Event
|
|
- Core/Element.Style
|
|
- Core/Element.Dimensions
|
|
- /MooTools.More
|
|
|
|
provides: [Drag]
|
|
...
|
|
|
|
*/
|
|
|
|
var Drag = new Class({
|
|
|
|
Implements: [Events, Options],
|
|
|
|
options: {/*
|
|
onBeforeStart: function(thisElement){},
|
|
onStart: function(thisElement, event){},
|
|
onSnap: function(thisElement){},
|
|
onDrag: function(thisElement, event){},
|
|
onCancel: function(thisElement){},
|
|
onComplete: function(thisElement, event){},*/
|
|
snap: 6,
|
|
unit: 'px',
|
|
grid: false,
|
|
style: true,
|
|
limit: false,
|
|
handle: false,
|
|
invert: false,
|
|
preventDefault: false,
|
|
stopPropagation: false,
|
|
modifiers: {x: 'left', y: 'top'}
|
|
},
|
|
|
|
initialize: function(){
|
|
var params = Array.link(arguments, {
|
|
'options': Type.isObject,
|
|
'element': function(obj){
|
|
return obj != null;
|
|
}
|
|
});
|
|
|
|
this.element = document.id(params.element);
|
|
this.document = this.element.getDocument();
|
|
this.setOptions(params.options || {});
|
|
var htype = typeOf(this.options.handle);
|
|
this.handles = ((htype == 'array' || htype == 'collection') ? $$(this.options.handle) : document.id(this.options.handle)) || this.element;
|
|
this.mouse = {'now': {}, 'pos': {}};
|
|
this.value = {'start': {}, 'now': {}};
|
|
|
|
this.selection = (Browser.ie) ? 'selectstart' : 'mousedown';
|
|
|
|
|
|
if (Browser.ie && !Drag.ondragstartFixed){
|
|
document.ondragstart = Function.from(false);
|
|
Drag.ondragstartFixed = true;
|
|
}
|
|
|
|
this.bound = {
|
|
start: this.start.bind(this),
|
|
check: this.check.bind(this),
|
|
drag: this.drag.bind(this),
|
|
stop: this.stop.bind(this),
|
|
cancel: this.cancel.bind(this),
|
|
eventStop: Function.from(false)
|
|
};
|
|
this.attach();
|
|
},
|
|
|
|
attach: function(){
|
|
this.handles.addEvent('mousedown', this.bound.start);
|
|
return this;
|
|
},
|
|
|
|
detach: function(){
|
|
this.handles.removeEvent('mousedown', this.bound.start);
|
|
return this;
|
|
},
|
|
|
|
start: function(event){
|
|
var options = this.options;
|
|
|
|
if (event.rightClick) return;
|
|
|
|
if (options.preventDefault) event.preventDefault();
|
|
if (options.stopPropagation) event.stopPropagation();
|
|
this.mouse.start = event.page;
|
|
|
|
this.fireEvent('beforeStart', this.element);
|
|
|
|
var limit = options.limit;
|
|
this.limit = {x: [], y: []};
|
|
|
|
var z, coordinates;
|
|
for (z in options.modifiers){
|
|
if (!options.modifiers[z]) continue;
|
|
|
|
var style = this.element.getStyle(options.modifiers[z]);
|
|
|
|
// Some browsers (IE and Opera) don't always return pixels.
|
|
if (style && !style.match(/px$/)){
|
|
if (!coordinates) coordinates = this.element.getCoordinates(this.element.getOffsetParent());
|
|
style = coordinates[options.modifiers[z]];
|
|
}
|
|
|
|
if (options.style) this.value.now[z] = (style || 0).toInt();
|
|
else this.value.now[z] = this.element[options.modifiers[z]];
|
|
|
|
if (options.invert) this.value.now[z] *= -1;
|
|
|
|
this.mouse.pos[z] = event.page[z] - this.value.now[z];
|
|
|
|
if (limit && limit[z]){
|
|
var i = 2;
|
|
while (i--){
|
|
var limitZI = limit[z][i];
|
|
if (limitZI || limitZI === 0) this.limit[z][i] = (typeof limitZI == 'function') ? limitZI() : limitZI;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (typeOf(this.options.grid) == 'number') this.options.grid = {
|
|
x: this.options.grid,
|
|
y: this.options.grid
|
|
};
|
|
|
|
var events = {
|
|
mousemove: this.bound.check,
|
|
mouseup: this.bound.cancel
|
|
};
|
|
events[this.selection] = this.bound.eventStop;
|
|
this.document.addEvents(events);
|
|
},
|
|
|
|
check: function(event){
|
|
if (this.options.preventDefault) event.preventDefault();
|
|
var distance = Math.round(Math.sqrt(Math.pow(event.page.x - this.mouse.start.x, 2) + Math.pow(event.page.y - this.mouse.start.y, 2)));
|
|
if (distance > this.options.snap){
|
|
this.cancel();
|
|
this.document.addEvents({
|
|
mousemove: this.bound.drag,
|
|
mouseup: this.bound.stop
|
|
});
|
|
this.fireEvent('start', [this.element, event]).fireEvent('snap', this.element);
|
|
}
|
|
},
|
|
|
|
drag: function(event){
|
|
var options = this.options;
|
|
|
|
if (options.preventDefault) event.preventDefault();
|
|
this.mouse.now = event.page;
|
|
|
|
for (var z in options.modifiers){
|
|
if (!options.modifiers[z]) continue;
|
|
this.value.now[z] = this.mouse.now[z] - this.mouse.pos[z];
|
|
|
|
if (options.invert) this.value.now[z] *= -1;
|
|
|
|
if (options.limit && this.limit[z]){
|
|
if ((this.limit[z][1] || this.limit[z][1] === 0) && (this.value.now[z] > this.limit[z][1])){
|
|
this.value.now[z] = this.limit[z][1];
|
|
} else if ((this.limit[z][0] || this.limit[z][0] === 0) && (this.value.now[z] < this.limit[z][0])){
|
|
this.value.now[z] = this.limit[z][0];
|
|
}
|
|
}
|
|
|
|
if (options.grid[z]) this.value.now[z] -= ((this.value.now[z] - (this.limit[z][0]||0)) % options.grid[z]);
|
|
|
|
if (options.style) this.element.setStyle(options.modifiers[z], this.value.now[z] + options.unit);
|
|
else this.element[options.modifiers[z]] = this.value.now[z];
|
|
}
|
|
|
|
this.fireEvent('drag', [this.element, event]);
|
|
},
|
|
|
|
cancel: function(event){
|
|
this.document.removeEvents({
|
|
mousemove: this.bound.check,
|
|
mouseup: this.bound.cancel
|
|
});
|
|
if (event){
|
|
this.document.removeEvent(this.selection, this.bound.eventStop);
|
|
this.fireEvent('cancel', this.element);
|
|
}
|
|
},
|
|
|
|
stop: function(event){
|
|
var events = {
|
|
mousemove: this.bound.drag,
|
|
mouseup: this.bound.stop
|
|
};
|
|
events[this.selection] = this.bound.eventStop;
|
|
this.document.removeEvents(events);
|
|
if (event) this.fireEvent('complete', [this.element, event]);
|
|
}
|
|
|
|
});
|
|
|
|
Element.implement({
|
|
|
|
makeResizable: function(options){
|
|
var drag = new Drag(this, Object.merge({
|
|
modifiers: {
|
|
x: 'width',
|
|
y: 'height'
|
|
}
|
|
}, options));
|
|
|
|
this.store('resizer', drag);
|
|
return drag.addEvent('drag', function(){
|
|
this.fireEvent('resize', drag);
|
|
}.bind(this));
|
|
}
|
|
|
|
});
|
|
|
|
|
|
/*
|
|
---
|
|
|
|
script: Drag.Move.js
|
|
|
|
name: Drag.Move
|
|
|
|
description: A Drag extension that provides support for the constraining of draggables to containers and droppables.
|
|
|
|
license: MIT-style license
|
|
|
|
authors:
|
|
- Valerio Proietti
|
|
- Tom Occhinno
|
|
- Jan Kassens
|
|
- Aaron Newton
|
|
- Scott Kyle
|
|
|
|
requires:
|
|
- Core/Element.Dimensions
|
|
- /Drag
|
|
|
|
provides: [Drag.Move]
|
|
|
|
...
|
|
*/
|
|
|
|
Drag.Move = new Class({
|
|
|
|
Extends: Drag,
|
|
|
|
options: {/*
|
|
onEnter: function(thisElement, overed){},
|
|
onLeave: function(thisElement, overed){},
|
|
onDrop: function(thisElement, overed, event){},*/
|
|
droppables: [],
|
|
container: false,
|
|
precalculate: false,
|
|
includeMargins: true,
|
|
checkDroppables: true
|
|
},
|
|
|
|
initialize: function(element, options){
|
|
this.parent(element, options);
|
|
element = this.element;
|
|
|
|
this.droppables = $$(this.options.droppables);
|
|
this.container = document.id(this.options.container);
|
|
|
|
if (this.container && typeOf(this.container) != 'element')
|
|
this.container = document.id(this.container.getDocument().body);
|
|
|
|
if (this.options.style){
|
|
if (this.options.modifiers.x == 'left' && this.options.modifiers.y == 'top'){
|
|
var parent = element.getOffsetParent(),
|
|
styles = element.getStyles('left', 'top');
|
|
if (parent && (styles.left == 'auto' || styles.top == 'auto')){
|
|
element.setPosition(element.getPosition(parent));
|
|
}
|
|
}
|
|
|
|
if (element.getStyle('position') == 'static') element.setStyle('position', 'absolute');
|
|
}
|
|
|
|
this.addEvent('start', this.checkDroppables, true);
|
|
this.overed = null;
|
|
},
|
|
|
|
start: function(event){
|
|
if (this.container) this.options.limit = this.calculateLimit();
|
|
|
|
if (this.options.precalculate){
|
|
this.positions = this.droppables.map(function(el){
|
|
return el.getCoordinates();
|
|
});
|
|
}
|
|
|
|
this.parent(event);
|
|
},
|
|
|
|
calculateLimit: function(){
|
|
var element = this.element,
|
|
container = this.container,
|
|
|
|
offsetParent = document.id(element.getOffsetParent()) || document.body,
|
|
containerCoordinates = container.getCoordinates(offsetParent),
|
|
elementMargin = {},
|
|
elementBorder = {},
|
|
containerMargin = {},
|
|
containerBorder = {},
|
|
offsetParentPadding = {};
|
|
|
|
['top', 'right', 'bottom', 'left'].each(function(pad){
|
|
elementMargin[pad] = element.getStyle('margin-' + pad).toInt();
|
|
elementBorder[pad] = element.getStyle('border-' + pad).toInt();
|
|
containerMargin[pad] = container.getStyle('margin-' + pad).toInt();
|
|
containerBorder[pad] = container.getStyle('border-' + pad).toInt();
|
|
offsetParentPadding[pad] = offsetParent.getStyle('padding-' + pad).toInt();
|
|
}, this);
|
|
|
|
var width = element.offsetWidth + elementMargin.left + elementMargin.right,
|
|
height = element.offsetHeight + elementMargin.top + elementMargin.bottom,
|
|
left = 0,
|
|
top = 0,
|
|
right = containerCoordinates.right - containerBorder.right - width,
|
|
bottom = containerCoordinates.bottom - containerBorder.bottom - height;
|
|
|
|
if (this.options.includeMargins){
|
|
left += elementMargin.left;
|
|
top += elementMargin.top;
|
|
} else {
|
|
right += elementMargin.right;
|
|
bottom += elementMargin.bottom;
|
|
}
|
|
|
|
if (element.getStyle('position') == 'relative'){
|
|
var coords = element.getCoordinates(offsetParent);
|
|
coords.left -= element.getStyle('left').toInt();
|
|
coords.top -= element.getStyle('top').toInt();
|
|
|
|
left -= coords.left;
|
|
top -= coords.top;
|
|
if (container.getStyle('position') != 'relative'){
|
|
left += containerBorder.left;
|
|
top += containerBorder.top;
|
|
}
|
|
right += elementMargin.left - coords.left;
|
|
bottom += elementMargin.top - coords.top;
|
|
|
|
if (container != offsetParent){
|
|
left += containerMargin.left + offsetParentPadding.left;
|
|
top += ((Browser.ie6 || Browser.ie7) ? 0 : containerMargin.top) + offsetParentPadding.top;
|
|
}
|
|
} else {
|
|
left -= elementMargin.left;
|
|
top -= elementMargin.top;
|
|
if (container != offsetParent){
|
|
left += containerCoordinates.left + containerBorder.left;
|
|
top += containerCoordinates.top + containerBorder.top;
|
|
}
|
|
}
|
|
|
|
return {
|
|
x: [left, right],
|
|
y: [top, bottom]
|
|
};
|
|
},
|
|
|
|
getDroppableCoordinates: function(element){
|
|
var position = element.getCoordinates();
|
|
if (element.getStyle('position') == 'fixed'){
|
|
var scroll = window.getScroll();
|
|
position.left += scroll.x;
|
|
position.right += scroll.x;
|
|
position.top += scroll.y;
|
|
position.bottom += scroll.y;
|
|
}
|
|
return position;
|
|
},
|
|
|
|
checkDroppables: function(){
|
|
var overed = this.droppables.filter(function(el, i){
|
|
el = this.positions ? this.positions[i] : this.getDroppableCoordinates(el);
|
|
var now = this.mouse.now;
|
|
return (now.x > el.left && now.x < el.right && now.y < el.bottom && now.y > el.top);
|
|
}, this).getLast();
|
|
|
|
if (this.overed != overed){
|
|
if (this.overed) this.fireEvent('leave', [this.element, this.overed]);
|
|
if (overed) this.fireEvent('enter', [this.element, overed]);
|
|
this.overed = overed;
|
|
}
|
|
},
|
|
|
|
drag: function(event){
|
|
this.parent(event);
|
|
if (this.options.checkDroppables && this.droppables.length) this.checkDroppables();
|
|
},
|
|
|
|
stop: function(event){
|
|
this.checkDroppables();
|
|
this.fireEvent('drop', [this.element, this.overed, event]);
|
|
this.overed = null;
|
|
return this.parent(event);
|
|
}
|
|
|
|
});
|
|
|
|
Element.implement({
|
|
|
|
makeDraggable: function(options){
|
|
var drag = new Drag.Move(this, options);
|
|
this.store('dragger', drag);
|
|
return drag;
|
|
}
|
|
|
|
});
|
|
|
|
|
|
/*
|
|
---
|
|
|
|
script: Sortables.js
|
|
|
|
name: Sortables
|
|
|
|
description: Class for creating a drag and drop sorting interface for lists of items.
|
|
|
|
license: MIT-style license
|
|
|
|
authors:
|
|
- Tom Occhino
|
|
|
|
requires:
|
|
- Core/Fx.Morph
|
|
- /Drag.Move
|
|
|
|
provides: [Sortables]
|
|
|
|
...
|
|
*/
|
|
|
|
var Sortables = new Class({
|
|
|
|
Implements: [Events, Options],
|
|
|
|
options: {/*
|
|
onSort: function(element, clone){},
|
|
onStart: function(element, clone){},
|
|
onComplete: function(element){},*/
|
|
opacity: 1,
|
|
clone: false,
|
|
revert: false,
|
|
handle: false,
|
|
dragOptions: {}
|
|
},
|
|
|
|
initialize: function(lists, options){
|
|
this.setOptions(options);
|
|
|
|
this.elements = [];
|
|
this.lists = [];
|
|
this.idle = true;
|
|
|
|
this.addLists($$(document.id(lists) || lists));
|
|
|
|
if (!this.options.clone) this.options.revert = false;
|
|
if (this.options.revert) this.effect = new Fx.Morph(null, Object.merge({
|
|
duration: 250,
|
|
link: 'cancel'
|
|
}, this.options.revert));
|
|
},
|
|
|
|
attach: function(){
|
|
this.addLists(this.lists);
|
|
return this;
|
|
},
|
|
|
|
detach: function(){
|
|
this.lists = this.removeLists(this.lists);
|
|
return this;
|
|
},
|
|
|
|
addItems: function(){
|
|
Array.flatten(arguments).each(function(element){
|
|
this.elements.push(element);
|
|
var start = element.retrieve('sortables:start', function(event){
|
|
this.start.call(this, event, element);
|
|
}.bind(this));
|
|
(this.options.handle ? element.getElement(this.options.handle) || element : element).addEvent('mousedown', start);
|
|
}, this);
|
|
return this;
|
|
},
|
|
|
|
addLists: function(){
|
|
Array.flatten(arguments).each(function(list){
|
|
this.lists.include(list);
|
|
this.addItems(list.getChildren());
|
|
}, this);
|
|
return this;
|
|
},
|
|
|
|
removeItems: function(){
|
|
return $$(Array.flatten(arguments).map(function(element){
|
|
this.elements.erase(element);
|
|
var start = element.retrieve('sortables:start');
|
|
(this.options.handle ? element.getElement(this.options.handle) || element : element).removeEvent('mousedown', start);
|
|
|
|
return element;
|
|
}, this));
|
|
},
|
|
|
|
removeLists: function(){
|
|
return $$(Array.flatten(arguments).map(function(list){
|
|
this.lists.erase(list);
|
|
this.removeItems(list.getChildren());
|
|
|
|
return list;
|
|
}, this));
|
|
},
|
|
|
|
getClone: function(event, element){
|
|
if (!this.options.clone) return new Element(element.tagName).inject(document.body);
|
|
if (typeOf(this.options.clone) == 'function') return this.options.clone.call(this, event, element, this.list);
|
|
var clone = element.clone(true).setStyles({
|
|
margin: 0,
|
|
position: 'absolute',
|
|
visibility: 'hidden',
|
|
width: element.getStyle('width')
|
|
}).addEvent('mousedown', function(event){
|
|
element.fireEvent('mousedown', event);
|
|
});
|
|
//prevent the duplicated radio inputs from unchecking the real one
|
|
if (clone.get('html').test('radio')){
|
|
clone.getElements('input[type=radio]').each(function(input, i){
|
|
input.set('name', 'clone_' + i);
|
|
if (input.get('checked')) element.getElements('input[type=radio]')[i].set('checked', true);
|
|
});
|
|
}
|
|
|
|
return clone.inject(this.list).setPosition(element.getPosition(element.getOffsetParent()));
|
|
},
|
|
|
|
getDroppables: function(){
|
|
var droppables = this.list.getChildren().erase(this.clone).erase(this.element);
|
|
if (!this.options.constrain) droppables.append(this.lists).erase(this.list);
|
|
return droppables;
|
|
},
|
|
|
|
insert: function(dragging, element){
|
|
var where = 'inside';
|
|
if (this.lists.contains(element)){
|
|
this.list = element;
|
|
this.drag.droppables = this.getDroppables();
|
|
} else {
|
|
where = this.element.getAllPrevious().contains(element) ? 'before' : 'after';
|
|
}
|
|
this.element.inject(element, where);
|
|
this.fireEvent('sort', [this.element, this.clone]);
|
|
},
|
|
|
|
start: function(event, element){
|
|
if (
|
|
!this.idle ||
|
|
event.rightClick ||
|
|
['button', 'input', 'a', 'textarea'].contains(event.target.get('tag'))
|
|
) return;
|
|
|
|
this.idle = false;
|
|
this.element = element;
|
|
this.opacity = element.getStyle('opacity');
|
|
this.list = element.getParent();
|
|
this.clone = this.getClone(event, element);
|
|
|
|
this.drag = new Drag.Move(this.clone, Object.merge({
|
|
|
|
droppables: this.getDroppables()
|
|
}, this.options.dragOptions)).addEvents({
|
|
onSnap: function(){
|
|
event.stop();
|
|
this.clone.setStyle('visibility', 'visible');
|
|
this.element.setStyle('opacity', this.options.opacity || 0);
|
|
this.fireEvent('start', [this.element, this.clone]);
|
|
}.bind(this),
|
|
onEnter: this.insert.bind(this),
|
|
onCancel: this.end.bind(this),
|
|
onComplete: this.end.bind(this)
|
|
});
|
|
|
|
this.clone.inject(this.element, 'before');
|
|
this.drag.start(event);
|
|
},
|
|
|
|
end: function(){
|
|
this.drag.detach();
|
|
this.element.setStyle('opacity', this.opacity);
|
|
if (this.effect){
|
|
var dim = this.element.getStyles('width', 'height'),
|
|
clone = this.clone,
|
|
pos = clone.computePosition(this.element.getPosition(this.clone.getOffsetParent()));
|
|
|
|
var destroy = function(){
|
|
this.removeEvent('cancel', destroy);
|
|
clone.destroy();
|
|
};
|
|
|
|
this.effect.element = clone;
|
|
this.effect.start({
|
|
top: pos.top,
|
|
left: pos.left,
|
|
width: dim.width,
|
|
height: dim.height,
|
|
opacity: 0.25
|
|
}).addEvent('cancel', destroy).chain(destroy);
|
|
} else {
|
|
this.clone.destroy();
|
|
}
|
|
this.reset();
|
|
},
|
|
|
|
reset: function(){
|
|
this.idle = true;
|
|
this.fireEvent('complete', this.element);
|
|
},
|
|
|
|
serialize: function(){
|
|
var params = Array.link(arguments, {
|
|
modifier: Type.isFunction,
|
|
index: function(obj){
|
|
return obj != null;
|
|
}
|
|
});
|
|
var serial = this.lists.map(function(list){
|
|
return list.getChildren().map(params.modifier || function(element){
|
|
return element.get('id');
|
|
}, this);
|
|
}, this);
|
|
|
|
var index = params.index;
|
|
if (this.lists.length == 1) index = 0;
|
|
return (index || index === 0) && index >= 0 && index < this.lists.length ? serial[index] : serial;
|
|
}
|
|
|
|
});
|
|
|
|
|
|
/*
|
|
---
|
|
|
|
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;
|
|
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 = {};
|
|
|
|
|
|
/*
|
|
---
|
|
|
|
script: Request.Periodical.js
|
|
|
|
name: Request.Periodical
|
|
|
|
description: Requests the same URL to pull data from a server but increases the intervals if no data is returned to reduce the load
|
|
|
|
license: MIT-style license
|
|
|
|
authors:
|
|
- Christoph Pojer
|
|
|
|
requires:
|
|
- Core/Request
|
|
- /MooTools.More
|
|
|
|
provides: [Request.Periodical]
|
|
|
|
...
|
|
*/
|
|
|
|
Request.implement({
|
|
|
|
options: {
|
|
initialDelay: 5000,
|
|
delay: 5000,
|
|
limit: 60000
|
|
},
|
|
|
|
startTimer: function(data){
|
|
var fn = function(){
|
|
if (!this.running) this.send({data: data});
|
|
};
|
|
this.lastDelay = this.options.initialDelay;
|
|
this.timer = fn.delay(this.lastDelay, this);
|
|
this.completeCheck = function(response){
|
|
clearTimeout(this.timer);
|
|
this.lastDelay = (response) ? this.options.delay : (this.lastDelay + this.options.delay).min(this.options.limit);
|
|
this.timer = fn.delay(this.lastDelay, this);
|
|
};
|
|
return this.addEvent('complete', this.completeCheck);
|
|
},
|
|
|
|
stopTimer: function(){
|
|
clearTimeout(this.timer);
|
|
return this.removeEvent('complete', this.completeCheck);
|
|
}
|
|
|
|
});
|
|
|