Author: eallen
Date: 2009-10-22 10:37:50 -0400 (Thu, 22 Oct 2009)
New Revision: 3679
Modified:
mgmt/trunk/wooly/python/wooly/pages.strings
mgmt/trunk/wooly/resources/mootools.js
Log:
Combining mootools.js and mootools-more.js to prevent mootools-more.js from being loaded
before mootools.js. This was causing an error and the page would render without and styles
applied.
Modified: mgmt/trunk/wooly/python/wooly/pages.strings
===================================================================
--- mgmt/trunk/wooly/python/wooly/pages.strings 2009-10-22 14:27:01 UTC (rev 3678)
+++ mgmt/trunk/wooly/python/wooly/pages.strings 2009-10-22 14:37:50 UTC (rev 3679)
@@ -14,7 +14,6 @@
<!--[if lte IE 7]><link rel="stylesheet" type="text/css"
href="resource?name=ielte7.css"/><![endif]-->
<script type="text/javascript"
src="resource?name=mootools.js"> </script>
- <script type="text/javascript"
src="resource?name=mootools-more.js"> </script>
<script type="text/javascript"
src="resource?name=wooly.js"> </script>
<script type="text/javascript" src="resource?name=app.js">
</script>
<script type="text/javascript" src="{base_name}.js">
</script>
Modified: mgmt/trunk/wooly/resources/mootools.js
===================================================================
--- mgmt/trunk/wooly/resources/mootools.js 2009-10-22 14:27:01 UTC (rev 3678)
+++ mgmt/trunk/wooly/resources/mootools.js 2009-10-22 14:37:50 UTC (rev 3679)
@@ -3902,4 +3902,3010 @@
return this;
}
+});
+
+//MooTools More, <
http://mootools.net/more>. Copyright (c) 2006-2009 Aaron Newton
<
http://clientcide.com/>, Valerio Proietti <
http://mad4milk.net> & the
MooTools team <
http://mootools.net/developers>, MIT Style License.
+
+MooTools.More = {
+ 'version': '1.2.3.1'
+};
+
+/*
+Script: MooTools.Lang.js
+ Provides methods for localization.
+
+ License:
+ MIT-style license.
+
+ Authors:
+ Aaron Newton
+*/
+
+(function(){
+
+ var data = {
+ language: 'en-US',
+ languages: {
+ 'en-US': {}
+ },
+ cascades: ['en-US']
+ };
+
+ var cascaded;
+
+ MooTools.lang = new Events();
+
+ $extend(MooTools.lang, {
+
+ setLanguage: function(lang){
+ if (!data.languages[lang]) return this;
+ data.language = lang;
+ this.load();
+ this.fireEvent('langChange', lang);
+ return this;
+ },
+
+ load: function() {
+ var langs = this.cascade(this.getCurrentLanguage());
+ cascaded = {};
+ $each(langs, function(set, setName){
+ cascaded[setName] = this.lambda(set);
+ }, this);
+ },
+
+ getCurrentLanguage: function(){
+ return data.language;
+ },
+
+ addLanguage: function(lang){
+ data.languages[lang] = data.languages[lang] || {};
+ return this;
+ },
+
+ cascade: function(lang){
+ var cascades = (data.languages[lang] || {}).cascades || [];
+ cascades.combine(data.cascades);
+ cascades.erase(lang).push(lang);
+ var langs = cascades.map(function(lng){
+ return data.languages[lng];
+ }, this);
+ return $merge.apply(this, langs);
+ },
+
+ lambda: function(set) {
+ (set || {}).get = function(key, args){
+ return $lambda(set[key]).apply(this, $splat(args));
+ };
+ return set;
+ },
+
+ get: function(set, key, args){
+ if (cascaded && cascaded[set]) return (key ? cascaded[set].get(key,
args) : cascaded[set]);
+ },
+
+ set: function(lang, set, members){
+ this.addLanguage(lang);
+ langData = data.languages[lang];
+ if (!langData[set]) langData[set] = {};
+ $extend(langData[set], members);
+ if (lang == this.getCurrentLanguage()){
+ this.load();
+ this.fireEvent('langChange', lang);
+ }
+ return this;
+ },
+
+ list: function(){
+ return Hash.getKeys(data.languages);
+ }
+
+ });
+
+})();
+
+/*
+Script: Log.js
+ Provides basic logging functionality for plugins to implement.
+
+ License:
+ MIT-style license.
+
+ Authors:
+ Guillermo Rauch
+*/
+
+var Log = new Class({
+
+ log: function(){
+ Log.logger.call(this, arguments);
+ }
+
+});
+
+Log.logged = [];
+
+Log.logger = function(){
+ if(window.console && console.log) console.log.apply(console, arguments);
+ else Log.logged.push(arguments);
+};
+
+/*
+Script: Class.Binds.js
+ Automagically binds specified methods in a class to the instance of the class.
+
+ License:
+ MIT-style license.
+
+ Authors:
+ Aaron Newton
+*/
+
+Class.Mutators.Binds = function(binds){
+ return binds;
+};
+
+Class.Mutators.initialize = function(initialize){
+ return function(){
+ $splat(this.Binds).each(function(name){
+ var original = this[name];
+ if (original) this[name] = original.bind(this);
+ }, this);
+ return initialize.apply(this, arguments);
+ };
+};
+
+/*
+Script: Class.Occlude.js
+ Prevents a class from being applied to a DOM element twice.
+
+ License:
+ MIT-style license.
+
+ Authors:
+ Aaron Newton
+*/
+
+Class.Occlude = new Class({
+
+ occlude: function(property, element){
+ element = document.id(element || this.element);
+ var instance = element.retrieve(property || this.property);
+ if (instance && !$defined(this.occluded)){
+ this.occluded = instance;
+ } else {
+ this.occluded = false;
+ element.store(property || this.property, this);
+ }
+ return this.occluded;
+ }
+
+});
+
+/*
+Script: Date.js
+ 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
+
+*/
+
+(function(){
+
+if (!Date.now) Date.now = $time;
+
+Date.Methods = {};
+
+['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'].each(function(method){
+ Date.Methods[method.toLowerCase()] = method;
+});
+
+$each({
+ ms: 'Milliseconds',
+ year: 'FullYear',
+ min: 'Minutes',
+ mo: 'Month',
+ sec: 'Seconds',
+ hr: 'Hours'
+}, function(value, key){
+ Date.Methods[key] = value;
+});
+
+var zeroize = function(what, length){
+ return new Array(length - what.toString().length + 1).join('0') + what;
+};
+
+Date.implement({
+
+ set: function(prop, value){
+ switch ($type(prop)){
+ case 'object':
+ for (var p in prop) this.set(p, prop[p]);
+ break;
+ case 'string':
+ prop = prop.toLowerCase();
+ var m = Date.Methods;
+ if (m[prop]) this['set' + m[prop]](value);
+ }
+ return this;
+ },
+
+ get: function(prop){
+ prop = prop.toLowerCase();
+ var m = Date.Methods;
+ if (m[prop]) return this['get' + m[prop]]();
+ return null;
+ },
+
+ clone: function(){
+ return new Date(this.get('time'));
+ },
+
+ increment: function(interval, times){
+ interval = interval || 'day';
+ times = $pick(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 * $pick(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(d, resolution){
+ resolution = resolution || 'day';
+ if ($type(d) == 'string') d = Date.parse(d);
+
+ switch (resolution){
+ case 'year':
+ return d.get('year') - this.get('year');
+ case 'month':
+ var months = (d.get('year') - this.get('year')) * 12;
+ return months + d.get('mo') - this.get('mo');
+ default:
+ var diff = d.get('time') - this.get('time');
+ if (Date.units[resolution]() > diff.abs()) return 0;
+ return ((d.get('time') - this.get('time')) /
Date.units[resolution]()).round();
+ }
+
+ return null;
+ },
+
+ 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();
+ },
+
+ getWeek: function(){
+ return (this.get('dayofyear') / 7).ceil();
+ },
+
+ 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) ? '-' : '+') + zeroize((off.abs() /
60).floor(), 2) + zeroize(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 !!(date || this).valueOf();
+ },
+
+ format: function(f){
+ if (!this.isValid()) return 'invalid date';
+ f = f || '%x %X';
+ f = formats[f.toLowerCase()] || f; // replace short-hand with actual format
+ var d = this;
+ return f.replace(/%([a-z%])/gi,
+ function($1, $2){
+ switch ($2){
+ case 'a': return
Date.getMsg('days')[d.get('day')].substr(0, 3);
+ case 'A': return
Date.getMsg('days')[d.get('day')];
+ case 'b': return
Date.getMsg('months')[d.get('month')].substr(0, 3);
+ case 'B': return
Date.getMsg('months')[d.get('month')];
+ case 'c': return d.toString();
+ case 'd': return zeroize(d.get('date'), 2);
+ case 'H': return zeroize(d.get('hr'), 2);
+ case 'I': return ((d.get('hr') % 12) || 12);
+ case 'j': return zeroize(d.get('dayofyear'), 3);
+ case 'm': return zeroize((d.get('mo') + 1), 2);
+ case 'M': return zeroize(d.get('min'), 2);
+ case 'o': return d.get('ordinal');
+ case 'p': return Date.getMsg(d.get('ampm'));
+ case 'S': return zeroize(d.get('seconds'), 2);
+ case 'U': return zeroize(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 'T': return d.get('GMTOffset');
+ case 'Z': return d.get('Timezone');
+ }
+ return $2;
+ }
+ );
+ },
+
+ toISOString: function(){
+ return this.format('iso8601');
+ }
+
+});
+
+Date.alias('diff', 'compare');
+Date.alias('format', 'strftime');
+
+var formats = {
+ db: '%Y-%m-%d %H:%M:%S',
+ compact: '%Y%m%dT%H%M%S',
+ iso8601: '%Y-%m-%dT%H:%M:%S%T',
+ rfc822: '%a, %d %b %Y %H:%M:%S %Z',
+ 'short': '%d %b %H:%M',
+ 'long': '%B %d, %Y %H:%M'
+};
+
+var nativeParse = Date.parse;
+
+var parseWord = function(type, word, num){
+ var ret = -1;
+ var translated = Date.getMsg(type + 's');
+
+ switch ($type(word)){
+ case 'object':
+ ret = translated[word.get(type)];
+ break;
+ case 'number':
+ ret = translated[month - 1];
+ if (!ret) throw new Error('Invalid ' + type + ' index: ' +
index);
+ 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;
+};
+
+
+Date.extend({
+
+ getMsg: function(key, args) {
+ return MooTools.lang.get('Date', key, args);
+ },
+
+ units: {
+ ms: $lambda(1),
+ second: $lambda(1000),
+ minute: $lambda(60000),
+ hour: $lambda(3600000),
+ day: $lambda(86400000),
+ week: $lambda(608400000),
+ month: function(month, year){
+ var d = new Date;
+ return Date.daysInMonth($pick(month, d.get('mo')), $pick(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 new Date(year, 1, 29).get('date') == 29;
+ },
+
+ parse: function(from){
+ var t = $type(from);
+ if (t == 'number') return new Date(from);
+ if (t != 'string') return from;
+ from = from.clean();
+ if (!from.length) return null;
+
+ var parsed;
+ Date.parsePatterns.some(function(pattern){
+ var r = pattern.re.exec(from);
+ return (r) ? (parsed = pattern.handler(r)) : false;
+ });
+
+ return parsed || new Date(nativeParse(from));
+ },
+
+ 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'));
+ return new Date(utcSeconds);
+ },
+
+ orderIndex: function(unit){
+ return Date.getMsg('dateOrder').indexOf(unit) + 1;
+ },
+
+ defineFormat: function(name, format){
+ formats[name] = format;
+ },
+
+ defineFormats: function(formats){
+ for (var name in formats) Date.defineFormat(name, formats[f]);
+ },
+
+ parsePatterns: [],
+
+ defineParser: function(pattern){
+ Date.parsePatterns.push( pattern.re && pattern.handler ? pattern :
build(pattern) );
+ },
+
+ defineParsers: function(){
+ Array.flatten(arguments).each(Date.defineParser);
+ },
+
+ define2DigitYearStart: function(year){
+ yr_start = year % 100;
+ yr_base = year - yr_start;
+ }
+
+});
+
+var yr_base = 1900;
+var yr_start = 70;
+
+var replacers = function(key){
+ switch(key){
+ case 'x': // iso8601 covers yyyy-mm-dd, so just check if month is first
+ return (Date.orderIndex('month') == 1) ?
'%m[.-/]%d([.-/]%y)?' : '%d[.-/]%m([.-/]%y)?';
+ case 'X':
+ return '%H([.:]%M)?([.:]%S([.:]%s)?)?\\s?%p?\\s?%T?';
+ case 'o':
+ return '[^\\d\\s]*';
+ }
+ return null;
+};
+
+var keys = {
+ a: /[a-z]{3,}/,
+ 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+/,
+ p: /[ap]\.?m\.?/,
+ y: /\d{2}|\d{4}/,
+ Y: /\d{4}/,
+ T: /Z|[+-]\d{2}(?::?\d{2})?/
+};
+
+keys.B = keys.b = keys.A = keys.a;
+keys.m = keys.I;
+keys.S = keys.M;
+
+var lang;
+
+var build = function(format){
+ if (!lang) return {format: format}; // wait until language is set
+
+ var parsed = [null];
+
+ var re = (format.source || format) // allow format to be regex
+ .replace(/%([a-z])/gi,
+ function($1, $2){
+ return replacers($2) || $1;
+ }
+ ).replace(/\((?!\?)/g, '(?:') // make all groups non-capturing
+ .replace(/ (?!\?|\*)/g, ',? ') // be forgiving with spaces and commas
+ .replace(/%([a-z%])/gi,
+ function($1, $2){
+ var p = keys[$2];
+ if (!p) return $2;
+ parsed.push($2);
+ return '(' + p.source + ')';
+ }
+ );
+
+ return {
+ format: format,
+ re: new RegExp('^' + re + '$', 'i'),
+ handler: function(bits){
+ var date = new Date().clearTime();
+ for (var i = 1; i < parsed.length; i++)
+ date = handle.call(date, parsed[i], bits[i]);
+ return date;
+ }
+ };
+};
+
+var handle = function(key, value){
+ if (!value){
+ if (key == 'm' || key == 'd') value = 1;
+ else 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 += yr_base + (value < yr_start ? 100 : 0);
+ return this.set('year', value);
+ case 'T':
+ 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 * 1) - 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
+ '%b %Y' // "December 1999"
+);
+
+MooTools.lang.addEvent('langChange', function(language){
+ if (!MooTools.lang.get('Date')) return;
+
+ lang = language;
+ Date.parsePatterns.each(function(pattern, i){
+ if (pattern.format) Date.parsePatterns[i] = build(pattern.format);
+ });
+
+}).fireEvent('langChange', MooTools.lang.getCurrentLanguage());
+
+})();
+
+/*
+Script: Element.Forms.js
+ Extends the Element native object to include methods useful in managing inputs.
+
+ License:
+ MIT-style license.
+
+ Authors:
+ Aaron Newton
+
+*/
+
+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 ($defined(this.selectionStart)) 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 dup = range.duplicate();
+ if (this.type == 'text') {
+ pos.start = 0 - dup.moveStart('character', -100000);
+ pos.end = pos.start + range.text.length;
+ } else {
+ var value = this.get('value');
+ var offset = value.length - value.match(/[\n\r]*$/)[0].length;
+ dup.moveToElementText(this);
+ dup.setEndPoint('StartToEnd', range);
+ pos.end = offset - dup.text.length;
+ dup.setEndPoint('StartToStart', range);
+ pos.start = offset - dup.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 ($pick(select, true)) this.selectRange(pos.start, pos.start + value.length);
+ else this.setCaretPosition(pos.start + value.length);
+ return this;
+ },
+
+ insertAroundCursor: function(options, select){
+ options = $extend({
+ 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 ($pick(select, true)) this.selectRange(selStart, selStart +
current.length);
+ else this.setCaretPosition(selStart + text.length);
+ }
+ return this;
+ }
+
+});
+
+/*
+Script: Element.Measure.js
+ Extends the Element native object to include methods useful in measuring dimensions.
+
+ 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
+
+*/
+
+Element.implement({
+
+ measure: function(fn){
+ var vis = function(el) {
+ return !!(!el || el.offsetHeight || el.offsetWidth);
+ };
+ if (vis(this)) return fn.apply(this);
+ var parent = this.getParent(),
+ toMeasure = [],
+ restorers = [];
+ while (!vis(parent) && parent != document.body) {
+ toMeasure.push(parent.expose());
+ parent = parent.getParent();
+ }
+ var restore = this.expose();
+ var result = fn.apply(this);
+ restore();
+ toMeasure.each(function(restore){
+ restore();
+ });
+ return result;
+ },
+
+ expose: function(){
+ if (this.getStyle('display') != 'none') return $empty;
+ 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 = $merge({computeSize: false},options);
+ var dim = {};
+ var getSize = function(el, options){
+ return (options.computeSize)?el.getComputedSize(options):el.getSize();
+ };
+ if (this.getStyle('display') == 'none'){
+ dim = this.measure(function(){
+ return getSize(this, options);
+ });
+ } else {
+ try { //safari sometimes crashes here, so catch it
+ dim = getSize(this, options);
+ }catch(e){}
+ }
+ return $chk(dim.x) ? $extend(dim, {width: dim.x, height: dim.y}) : $extend(dim,
{x: dim.width, y: dim.height});
+ },
+
+ getComputedSize: function(options){
+ options = $merge({
+ styles: ['padding','border'],
+ plains: {
+ height: ['top','bottom'],
+ width: ['left','right']
+ },
+ mode: 'both'
+ }, options);
+ var size = {width: 0,height: 0};
+ switch (options.mode){
+ case 'vertical':
+ delete size.width;
+ delete options.plains.width;
+ break;
+ case 'horizontal':
+ delete size.height;
+ delete options.plains.height;
+ break;
+ }
+ var getStyles = [];
+ //this function might be useful in other places; perhaps it should be outside
this function?
+ $each(options.plains, function(plain, key){
+ plain.each(function(edge){
+ options.styles.each(function(style){
+ getStyles.push((style == 'border') ? style + '-' +
edge + '-' + 'width' : style + '-' + edge);
+ });
+ });
+ });
+ var styles = {};
+ getStyles.each(function(style){ styles[style] = this.getComputedStyle(style); },
this);
+ var subtracted = [];
+ $each(options.plains, function(plain, key){ //keys: width, height, plains:
['left', 'right'], ['top','bottom']
+ var capitalized = key.capitalize();
+ size['total' + capitalized] = 0;
+ size['computed' + capitalized] = 0;
+ plain.each(function(edge){ //top, left, right, bottom
+ size['computed' + edge.capitalize()] = 0;
+ getStyles.each(function(style, i){ //padding, border, etc.
+ //'padding-left'.test('left')
size['totalWidth'] = size['width'] + [padding-left]
+ if (style.test(edge)){
+ styles[style] = styles[style].toInt() || 0;
//styles['padding-left'] = 5;
+ size['total' + capitalized] = size['total' +
capitalized] + styles[style];
+ size['computed' + edge.capitalize()] =
size['computed' + edge.capitalize()] + styles[style];
+ }
+ //if width != width (so, padding-left, for instance), then subtract
that from the total
+ if (style.test(edge) && key != style &&
+ (style.test('border') || style.test('padding'))
&& !subtracted.contains(style)){
+ subtracted.push(style);
+ size['computed' + capitalized] = size['computed'
+ capitalized]-styles[style];
+ }
+ });
+ });
+ });
+
+ ['Width', 'Height'].each(function(value){
+ var lower = value.toLowerCase();
+ if(!$chk(size[lower])) return;
+
+ size[lower] = size[lower] + this['offset' + value] +
size['computed' + value];
+ size['total' + value] = size[lower] + size['total' + value];
+ delete size['computed' + value];
+ }, this);
+
+ return $extend(styles, size);
+ }
+
+});
+
+/*
+Script: Element.Pin.js
+ Extends the Element native object to include the pin method useful for fixed
positioning for elements.
+
+ License:
+ MIT-style license.
+
+ Authors:
+ Aaron Newton
+*/
+
+(function(){
+ var supportsPositionFixed = false;
+ window.addEvent('domready', function(){
+ var test = new Element('div').setStyles({
+ position: 'fixed',
+ top: 0,
+ right: 0
+ }).inject(document.body);
+ supportsPositionFixed = (test.offsetTop === 0);
+ test.dispose();
+ });
+
+ Element.implement({
+
+ pin: function(enable){
+ if (this.getStyle('display') == 'none') return null;
+
+ var p;
+ if (enable !== false){
+ p = this.getPosition();
+ if (!this.retrieve('pinned')){
+ var pos = {
+ top: p.y - window.getScroll().y,
+ left: p.x - window.getScroll().x
+ };
+ if (supportsPositionFixed){
+ this.setStyle('position',
'fixed').setStyles(pos);
+ } else {
+ this.store('pinnedByJS', true);
+ this.setStyles({
+ position: 'absolute',
+ top: p.y,
+ left: p.x
+ });
+ this.store('scrollFixer', (function(){
+ if (this.retrieve('pinned'))
+ this.setStyles({
+ top: pos.top.toInt() + window.getScroll().y,
+ left: pos.left.toInt() + window.getScroll().x
+ });
+ }).bind(this));
+ window.addEvent('scroll',
this.retrieve('scrollFixer'));
+ }
+ this.store('pinned', true);
+ }
+ } else {
+ var op;
+ if (!Browser.Engine.trident){
+ if (this.getParent().getComputedStyle('position') !=
'static') op = this.getParent();
+ else op = this.getParent().getOffsetParent();
+ }
+ p = this.getPosition(op);
+ this.store('pinned', false);
+ var reposition;
+ if (supportsPositionFixed &&
!this.retrieve('pinnedByJS')){
+ reposition = {
+ top: p.y + window.getScroll().y,
+ left: p.x + window.getScroll().x
+ };
+ } else {
+ this.store('pinnedByJS', false);
+ window.removeEvent('scroll',
this.retrieve('scrollFixer'));
+ reposition = {
+ top: p.y,
+ left: p.x
+ };
+ }
+ this.setStyles($merge(reposition, {position: 'absolute'}));
+ }
+ return this.addClass('isPinned');
+ },
+
+ unpin: function(){
+ return this.pin(false).removeClass('isPinned');
+ },
+
+ togglepin: function(){
+ this.pin(!this.retrieve('pinned'));
+ }
+
+ });
+
+})();
+
+/*
+Script: Element.Position.js
+ Extends the Element native object to include methods useful positioning elements
relative to others.
+
+ License:
+ MIT-style license.
+
+ Authors:
+ Aaron Newton
+*/
+
+(function(){
+
+var original = Element.prototype.position;
+
+Element.implement({
+
+ position: function(options){
+ //call original position if the options are x/y values
+ if (options && ($defined(options.x) || $defined(options.y))) return
original ? original.apply(this, arguments) : this;
+ $each(options||{}, function(v, k){ if (!$defined(v)) delete options[k]; });
+ options = $merge({
+ relativeTo: document.body,
+ position: {
+ x: 'center', //left, center, right
+ y: 'center' //top, center, bottom
+ },
+ edge: false,
+ offset: {x: 0, y: 0},
+ returnPos: false,
+ relFixedPosition: false,
+ ignoreMargins: false,
+ allowNegative: false
+ }, options);
+ //compute the offset of the parent positioned element if this element is in one
+ var parentOffset = {x: 0, y: 0};
+ var parentPositioned = false;
+ /* dollar around getOffsetParent should not be necessary, but as it does not
return
+ * a mootools extended element in IE, an error occurs on the call to expose.
See:
+ *
http://mootools.lighthouseapp.com/projects/2706/tickets/333-element-getof...
*/
+ var offsetParent = this.measure(function(){
+ return document.id(this.getOffsetParent());
+ });
+ if (offsetParent && offsetParent != this.getDocument().body){
+ parentOffset = offsetParent.measure(function(){
+ return this.getPosition();
+ });
+ parentPositioned = true;
+ options.offset.x = options.offset.x - parentOffset.x;
+ options.offset.y = options.offset.y - parentOffset.y;
+ }
+ //upperRight, bottomRight, centerRight, upperLeft, bottomLeft, centerLeft
+ //topRight, topLeft, centerTop, centerBottom, center
+ var fixValue = function(option){
+ if ($type(option) != 'string') return option;
+ option = option.toLowerCase();
+ var val = {};
+ if (option.test('left')) val.x = 'left';
+ else if (option.test('right')) val.x = 'right';
+ else val.x = 'center';
+ if (option.test('upper') || option.test('top')) val.y =
'top';
+ else if (option.test('bottom')) val.y = 'bottom';
+ else val.y = 'center';
+ return val;
+ };
+ options.edge = fixValue(options.edge);
+ options.position = fixValue(options.position);
+ if (!options.edge){
+ if (options.position.x == 'center' && options.position.y ==
'center') options.edge = {x:'center', y:'center'};
+ else options.edge = {x:'left', y:'top'};
+ }
+
+ this.setStyle('position', 'absolute');
+ var rel = document.id(options.relativeTo) || document.body;
+ var calc = rel == document.body ? window.getScroll() : rel.getPosition();
+ var top = calc.y;
+ var left = calc.x;
+
+ if (Browser.Engine.trident){
+ var scrolls = rel.getScrolls();
+ top += scrolls.y;
+ left += scrolls.x;
+ }
+
+ var dim = this.getDimensions({computeSize: true, styles:['padding',
'border','margin']});
+ if (options.ignoreMargins){
+ options.offset.x = options.offset.x - dim['margin-left'];
+ options.offset.y = options.offset.y - dim['margin-top'];
+ }
+ var pos = {};
+ var prefY = options.offset.y;
+ var prefX = options.offset.x;
+ var winSize = window.getSize();
+ switch(options.position.x){
+ case 'left':
+ pos.x = left + prefX;
+ break;
+ case 'right':
+ pos.x = left + prefX + rel.offsetWidth;
+ break;
+ default: //center
+ pos.x = left + ((rel == document.body ? winSize.x : rel.offsetWidth)/2) +
prefX;
+ break;
+ }
+ switch(options.position.y){
+ case 'top':
+ pos.y = top + prefY;
+ break;
+ case 'bottom':
+ pos.y = top + prefY + rel.offsetHeight;
+ break;
+ default: //center
+ pos.y = top + ((rel == document.body ? winSize.y : rel.offsetHeight)/2) +
prefY;
+ break;
+ }
+
+ if (options.edge){
+ var edgeOffset = {};
+
+ switch(options.edge.x){
+ case 'left':
+ edgeOffset.x = 0;
+ break;
+ case 'right':
+ edgeOffset.x = -dim.x-dim.computedRight-dim.computedLeft;
+ break;
+ default: //center
+ edgeOffset.x = -(dim.x/2);
+ break;
+ }
+ switch(options.edge.y){
+ case 'top':
+ edgeOffset.y = 0;
+ break;
+ case 'bottom':
+ edgeOffset.y = -dim.y-dim.computedTop-dim.computedBottom;
+ break;
+ default: //center
+ edgeOffset.y = -(dim.y/2);
+ break;
+ }
+ pos.x = pos.x + edgeOffset.x;
+ pos.y = pos.y + edgeOffset.y;
+ }
+ pos = {
+ left: ((pos.x >= 0 || parentPositioned || options.allowNegative) ? pos.x :
0).toInt(),
+ top: ((pos.y >= 0 || parentPositioned || options.allowNegative) ? pos.y :
0).toInt()
+ };
+ if (rel.getStyle('position') == 'fixed' ||
options.relFixedPosition){
+ var winScroll = window.getScroll();
+ pos.top = pos.top.toInt() + winScroll.y;
+ pos.left = pos.left.toInt() + winScroll.x;
+ }
+
+ if (options.returnPos) return pos;
+ else this.setStyles(pos);
+ return this;
+ }
+
+});
+
+})();
+
+/*
+Script: Element.Shortcuts.js
+ Extends the Element native object to include some shortcut methods.
+
+ License:
+ MIT-style license.
+
+ Authors:
+ Aaron Newton
+
+*/
+
+Element.implement({
+
+ isDisplayed: function(){
+ return this.getStyle('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
+ if ('none' != this.getStyle('display')) d =
this.getStyle('display');
+ } catch(e){}
+
+ return this.store('originalDisplay', d ||
'block').setStyle('display', 'none');
+ },
+
+ show: function(display){
+ return this.setStyle('display', display ||
this.retrieve('originalDisplay') || 'block');
+ },
+
+ swapClass: function(remove, add){
+ return this.removeClass(remove).addClass(add);
+ }
+
+});
+
+
+/*
+Script: FormValidator.js
+ A css-class based form validation system.
+
+ License:
+ MIT-style license.
+
+ Authors:
+ Aaron Newton
+*/
+var InputValidator = new Class({
+
+ Implements: [Options],
+
+ options: {
+ errorMsg: 'Validation failed.',
+ test: function(field){return true;}
+ },
+
+ initialize: function(className, options){
+ this.setOptions(options);
+ this.className = className;
+ },
+
+ test: function(field, props){
+ if (document.id(field)) return this.options.test(document.id(field),
props||this.getProps(field));
+ else return false;
+ },
+
+ getError: function(field, props){
+ var err = this.options.errorMsg;
+ if ($type(err) == 'function') err = err(document.id(field),
props||this.getProps(field));
+ return err;
+ },
+
+ getProps: function(field){
+ if (!document.id(field)) return {};
+ return field.get('validatorProps');
+ }
+
+});
+
+Element.Properties.validatorProps = {
+
+ set: function(props){
+ return this.eliminate('validatorProps').store('validatorProps',
props);
+ },
+
+ get: function(props){
+ if (props) this.set(props);
+ if (this.retrieve('validatorProps')) return
this.retrieve('validatorProps');
+ if (this.getProperty('validatorProps')){
+ try {
+ this.store('validatorProps',
JSON.decode(this.getProperty('validatorProps')));
+ }catch(e){
+ return {};
+ }
+ } else {
+ var vals = this.get('class').split('
').filter(function(cls){
+ return cls.test(':');
+ });
+ if (!vals.length){
+ this.store('validatorProps', {});
+ } else {
+ props = {};
+ vals.each(function(cls){
+ var split = cls.split(':');
+ if (split[1]) {
+ try {
+ props[split[0]] = JSON.decode(split[1]);
+ } catch(e) {}
+ }
+ });
+ this.store('validatorProps', props);
+ }
+ }
+ return this.retrieve('validatorProps');
+ }
+
+};
+
+var FormValidator = new Class({
+
+ Implements:[Options, Events],
+
+ Binds: ['onSubmit'],
+
+ options: {/*
+ onFormValidate: $empty(isValid, form, event),
+ onElementValidate: $empty(isValid, field, className, warn),
+ onElementPass: $empty(field),
+ onElementFail: $empty(field, validatorsFailed) */
+ fieldSelectors: 'input, select, textarea',
+ ignoreHidden: true,
+ useTitles: false,
+ evaluateOnSubmit: true,
+ evaluateFieldsOnBlur: true,
+ evaluateFieldsOnChange: true,
+ serial: true,
+ stopOnFailure: true,
+ warningPrefix: function(){
+ return FormValidator.getMsg('warningPrefix') || 'Warning: ';
+ },
+ errorPrefix: function(){
+ return FormValidator.getMsg('errorPrefix') || 'Error: ';
+ }
+ },
+
+ initialize: function(form, options){
+ this.setOptions(options);
+ this.element = document.id(form);
+ this.element.store('validator', this);
+ this.warningPrefix = $lambda(this.options.warningPrefix)();
+ this.errorPrefix = $lambda(this.options.errorPrefix)();
+ if (this.options.evaluateOnSubmit) this.element.addEvent('submit',
this.onSubmit);
+ if (this.options.evaluateFieldsOnBlur || this.options.evaluateFieldsOnChange)
this.watchFields(this.getFields());
+ },
+
+ toElement: function(){
+ return this.element;
+ },
+
+ getFields: function(){
+ return (this.fields = this.element.getElements(this.options.fieldSelectors));
+ },
+
+ watchFields: function(fields){
+ fields.each(function(el){
+ if (this.options.evaluateFieldsOnBlur)
+ el.addEvent('blur', this.validationMonitor.pass([el, false],
this));
+ if (this.options.evaluateFieldsOnChange)
+ el.addEvent('change', this.validationMonitor.pass([el, true],
this));
+ }, this);
+ },
+
+ validationMonitor: function(){
+ $clear(this.timer);
+ this.timer = this.validateField.delay(50, this, arguments);
+ },
+
+ onSubmit: function(event){
+ if (!this.validate(event) && event) event.preventDefault();
+ else this.reset();
+ },
+
+ reset: function(){
+ this.getFields().each(this.resetField, this);
+ return this;
+ },
+
+ validate: function(event){
+ var result = this.getFields().map(function(field){
+ return this.validateField(field, true);
+ }, this).every(function(v){ return v;});
+ this.fireEvent('formValidate', [result, this.element, event]);
+ if (this.options.stopOnFailure && !result && event)
event.preventDefault();
+ return result;
+ },
+
+ validateField: function(field, force){
+ if (this.paused) return true;
+ field = document.id(field);
+ var passed = !field.hasClass('validation-failed');
+ var failed, warned;
+ if (this.options.serial && !force){
+ failed = this.element.getElement('.validation-failed');
+ warned = this.element.getElement('.warning');
+ }
+ if (field && (!failed || force ||
field.hasClass('validation-failed') || (failed &&
!this.options.serial))){
+ var validators = field.className.split(' ').some(function(cn){
+ return this.getValidator(cn);
+ }, this);
+ var validatorsFailed = [];
+ field.className.split(' ').each(function(className){
+ if (className && !this.test(className, field))
validatorsFailed.include(className);
+ }, this);
+ passed = validatorsFailed.length === 0;
+ if (validators && !field.hasClass('warnOnly')){
+ if (passed){
+
field.addClass('validation-passed').removeClass('validation-failed');
+ this.fireEvent('elementPass', field);
+ } else {
+
field.addClass('validation-failed').removeClass('validation-passed');
+ this.fireEvent('elementFail', [field, validatorsFailed]);
+ }
+ }
+ if (!warned){
+ var warnings = field.className.split(' ').some(function(cn){
+ if (cn.test('^warn-') || field.hasClass('warnOnly'))
+ return this.getValidator(cn.replace(/^warn-/,''));
+ else return null;
+ }, this);
+ field.removeClass('warning');
+ var warnResult = field.className.split(' ').map(function(cn){
+ if (cn.test('^warn-') || field.hasClass('warnOnly'))
+ return this.test(cn.replace(/^warn-/,''), field, true);
+ else return null;
+ }, this);
+ }
+ }
+ return passed;
+ },
+
+ test: function(className, field, warn){
+ var validator = this.getValidator(className);
+ field = document.id(field);
+ if (field.hasClass('ignoreValidation')) return true;
+ warn = $pick(warn, false);
+ if (field.hasClass('warnOnly')) warn = true;
+ var isValid = validator ? validator.test(field) : true;
+ if (validator && this.isVisible(field))
this.fireEvent('elementValidate', [isValid, field, className, warn]);
+ if (warn) return true;
+ return isValid;
+ },
+
+ isVisible : function(field){
+ if (!this.options.ignoreHidden) return true;
+ while(field != document.body){
+ if (document.id(field).getStyle('display') == 'none') return
false;
+ field = field.getParent();
+ }
+ return true;
+ },
+
+ resetField: function(field){
+ field = document.id(field);
+ if (field){
+ field.className.split(' ').each(function(className){
+ if (className.test('^warn-')) className =
className.replace(/^warn-/, '');
+ field.removeClass('validation-failed');
+ field.removeClass('warning');
+ field.removeClass('validation-passed');
+ }, this);
+ }
+ return this;
+ },
+
+ stop: function(){
+ this.paused = true;
+ return this;
+ },
+
+ start: function(){
+ this.paused = false;
+ return this;
+ },
+
+ ignoreField: function(field, warn){
+ field = document.id(field);
+ if (field){
+ this.enforceField(field);
+ if (warn) field.addClass('warnOnly');
+ else field.addClass('ignoreValidation');
+ }
+ return this;
+ },
+
+ enforceField: function(field){
+ field = document.id(field);
+ if (field)
field.removeClass('warnOnly').removeClass('ignoreValidation');
+ return this;
+ }
+
+});
+
+FormValidator.getMsg = function(key){
+ return MooTools.lang.get('FormValidator', key);
+};
+
+FormValidator.adders = {
+
+ validators:{},
+
+ add : function(className, options){
+ this.validators[className] = new InputValidator(className, options);
+ //if this is a class (this method is used by instances of FormValidator and the
FormValidator namespace)
+ //extend these validators into it
+ //this allows validators to be global and/or per instance
+ if (!this.initialize){
+ this.implement({
+ validators: this.validators
+ });
+ }
+ },
+
+ addAllThese : function(validators){
+ $A(validators).each(function(validator){
+ this.add(validator[0], validator[1]);
+ }, this);
+ },
+
+ getValidator: function(className){
+ return this.validators[className.split(':')[0]];
+ }
+
+};
+
+$extend(FormValidator, FormValidator.adders);
+
+FormValidator.implement(FormValidator.adders);
+
+FormValidator.add('IsEmpty', {
+
+ errorMsg: false,
+ test: function(element){
+ if (element.type == 'select-one' || element.type == 'select')
+ return !(element.selectedIndex >= 0 &&
element.options[element.selectedIndex].value != '');
+ else
+ return ((element.get('value') == null) ||
(element.get('value').length == 0));
+ }
+
+});
+
+FormValidator.addAllThese([
+
+ ['required', {
+ errorMsg: function(){
+ return FormValidator.getMsg('required');
+ },
+ test: function(element){
+ return !FormValidator.getValidator('IsEmpty').test(element);
+ }
+ }],
+
+ ['minLength', {
+ errorMsg: function(element, props){
+ if ($type(props.minLength))
+ return
FormValidator.getMsg('minLength').substitute({minLength:props.minLength,length:element.get('value').length
});
+ else return '';
+ },
+ test: function(element, props){
+ if ($type(props.minLength)) return (element.get('value').length >=
$pick(props.minLength, 0));
+ else return true;
+ }
+ }],
+
+ ['maxLength', {
+ errorMsg: function(element, props){
+ //props is {maxLength:10}
+ if ($type(props.maxLength))
+ return
FormValidator.getMsg('maxLength').substitute({maxLength:props.maxLength,length:element.get('value').length
});
+ else return '';
+ },
+ test: function(element, props){
+ //if the value is <= than the maxLength value, element passes test
+ return (element.get('value').length <= $pick(props.maxLength,
10000));
+ }
+ }],
+
+ ['validate-integer', {
+ errorMsg: FormValidator.getMsg.pass('integer'),
+ test: function(element){
+ return FormValidator.getValidator('IsEmpty').test(element) ||
(/^(-?[1-9]\d*|0)$/).test(element.get('value'));
+ }
+ }],
+
+ ['validate-numeric', {
+ errorMsg: FormValidator.getMsg.pass('numeric'),
+ test: function(element){
+ return FormValidator.getValidator('IsEmpty').test(element) ||
+
(/^-?(?:0$0(?=\d*\.)|[1-9]|0)\d*(\.\d+)?$/).test(element.get('value'));
+ }
+ }],
+
+ ['validate-digits', {
+ errorMsg: FormValidator.getMsg.pass('digits'),
+ test: function(element){
+ return FormValidator.getValidator('IsEmpty').test(element) ||
(/^[\d() .:\-\+#]+$/.test(element.get('value')));
+ }
+ }],
+
+ ['validate-alpha', {
+ errorMsg: FormValidator.getMsg.pass('alpha'),
+ test: function(element){
+ return FormValidator.getValidator('IsEmpty').test(element) ||
(/^[a-zA-Z]+$/).test(element.get('value'));
+ }
+ }],
+
+ ['validate-alphanum', {
+ errorMsg: FormValidator.getMsg.pass('alphanum'),
+ test: function(element){
+ return FormValidator.getValidator('IsEmpty').test(element) ||
!(/\W/).test(element.get('value'));
+ }
+ }],
+
+ ['validate-date', {
+ errorMsg: function(element, props){
+ if (Date.parse){
+ var format = props.dateFormat || '%x';
+ return FormValidator.getMsg('dateSuchAs').substitute({date: new
Date().format(format)});
+ } else {
+ return FormValidator.getMsg('dateInFormatMDY');
+ }
+ },
+ test: function(element, props){
+ if (FormValidator.getValidator('IsEmpty').test(element)) return
true;
+ var d;
+ if (Date.parse){
+ var format = props.dateFormat || '%x';
+ d = Date.parse(element.get('value'));
+ var formatted = d.format(format);
+ if (formatted != 'invalid date') element.set('value',
formatted);
+ return !isNaN(d);
+ } else {
+ var regex = /^(\d{2})\/(\d{2})\/(\d{4})$/;
+ if (!regex.test(element.get('value'))) return false;
+ d = new Date(element.get('value').replace(regex,
'$1/$2/$3'));
+ return (parseInt(RegExp.$1, 10) == (1 + d.getMonth())) &&
+ (parseInt(RegExp.$2, 10) == d.getDate()) &&
+ (parseInt(RegExp.$3, 10) == d.getFullYear());
+ }
+ }
+ }],
+
+ ['validate-email', {
+ errorMsg: FormValidator.getMsg.pass('email'),
+ test: function(element){
+ return FormValidator.getValidator('IsEmpty').test(element) ||
(/^[A-Z0-9._%+-]+(a)[A-Z0-9.-]+\.[A-Z]{2,4}$/i).test(element.get('value'));
+ }
+ }],
+
+ ['validate-url', {
+ errorMsg: FormValidator.getMsg.pass('url'),
+ test: function(element){
+ return FormValidator.getValidator('IsEmpty').test(element) ||
(/^(https?|ftp|rmtp|mms):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)(:(\d+))?\/?/i).test(element.get('value'));
+ }
+ }],
+
+ ['validate-currency-dollar', {
+ errorMsg: FormValidator.getMsg.pass('currencyDollar'),
+ test: function(element){
+ // [$]1[##][,###]+[.##]
+ // [$]1###+[.##]
+ // [$]0.##
+ // [$].##
+ return FormValidator.getValidator('IsEmpty').test(element) ||
(/^\$?\-?([1-9]{1}[0-9]{0,2}(\,[0-9]{3})*(\.[0-9]{0,2})?|[1-9]{1}\d*(\.[0-9]{0,2})?|0(\.[0-9]{0,2})?|(\.[0-9]{1,2})?)$/).test(element.get('value'));
+ }
+ }],
+
+ ['validate-one-required', {
+ errorMsg: FormValidator.getMsg.pass('oneRequired'),
+ test: function(element, props){
+ var p = document.id(props['validate-one-required']) ||
element.parentNode;
+ return p.getElements('input').some(function(el){
+ if (['checkbox',
'radio'].contains(el.get('type'))) return el.get('checked');
+ return el.get('value');
+ });
+ }
+ }]
+
+]);
+
+Element.Properties.validator = {
+
+ set: function(options){
+ var validator = this.retrieve('validator');
+ if (validator) validator.setOptions(options);
+ return this.store('validator:options');
+ },
+
+ get: function(options){
+ if (options || !this.retrieve('validator')){
+ if (options || !this.retrieve('validator:options'))
this.set('validator', options);
+ this.store('validator', new FormValidator(this,
this.retrieve('validator:options')));
+ }
+ return this.retrieve('validator');
+ }
+
+};
+
+Element.implement({
+
+ validate: function(options){
+ this.set('validator', options);
+ return this.get('validator', options).validate();
+ }
+
+});
+
+/*
+Script: Fx.Elements.js
+ Effect to change any number of CSS properties of any number of Elements.
+
+ License:
+ MIT-style license.
+
+ Authors:
+ Valerio Proietti
+*/
+
+Fx.Elements = new Class({
+
+ Extends: Fx.CSS,
+
+ initialize: function(elements, options){
+ this.elements = this.subject = $$(elements);
+ this.parent(options);
+ },
+
+ compute: function(from, to, delta){
+ var now = {};
+ for (var i in from){
+ var iFrom = from[i], iTo = to[i], iNow = now[i] = {};
+ for (var p in iFrom) iNow[p] = this.parent(iFrom[p], iTo[p], delta);
+ }
+ return now;
+ },
+
+ set: function(now){
+ for (var i in now){
+ var iNow = now[i];
+ for (var p in iNow) this.render(this.elements[i], p, iNow[p],
this.options.unit);
+ }
+ return this;
+ },
+
+ start: function(obj){
+ if (!this.check(obj)) return this;
+ var from = {}, to = {};
+ for (var i in obj){
+ var iProps = obj[i], iFrom = from[i] = {}, iTo = to[i] = {};
+ for (var p in iProps){
+ var parsed = this.prepare(this.elements[i], p, iProps[p]);
+ iFrom[p] = parsed.from;
+ iTo[p] = parsed.to;
+ }
+ }
+ return this.parent(from, to);
+ }
+
+});
+
+/*
+Script: Fx.Accordion.js
+ An Fx.Elements extension which allows you to easily create accordion type controls.
+
+ License:
+ MIT-style license.
+
+ Authors:
+ Valerio Proietti
+*/
+
+var Accordion = Fx.Accordion = new Class({
+
+ Extends: Fx.Elements,
+
+ options: {/*
+ onActive: $empty(toggler, section),
+ onBackground: $empty(toggler, section),*/
+ display: 0,
+ show: false,
+ height: true,
+ width: false,
+ opacity: true,
+ fixedHeight: false,
+ fixedWidth: false,
+ wait: false,
+ alwaysHide: false,
+ trigger: 'click',
+ initialDisplayFx: true
+ },
+
+ initialize: function(){
+ var params = Array.link(arguments, {'container': Element.type,
'options': Object.type, 'togglers': $defined, 'elements':
$defined});
+ this.parent(params.elements, params.options);
+ this.togglers = $$(params.togglers);
+ this.container = document.id(params.container);
+ this.previous = -1;
+ if (this.options.alwaysHide) this.options.wait = true;
+ if ($chk(this.options.show)){
+ this.options.display = false;
+ this.previous = this.options.show;
+ }
+ if (this.options.start){
+ this.options.display = false;
+ this.options.show = false;
+ }
+ this.effects = {};
+ if (this.options.opacity) this.effects.opacity = 'fullOpacity';
+ if (this.options.width) this.effects.width = this.options.fixedWidth ?
'fullWidth' : 'offsetWidth';
+ if (this.options.height) this.effects.height = this.options.fixedHeight ?
'fullHeight' : 'scrollHeight';
+ for (var i = 0, l = this.togglers.length; i < l; i++)
this.addSection(this.togglers[i], this.elements[i]);
+ this.elements.each(function(el, i){
+ if (this.options.show === i){
+ this.fireEvent('active', [this.togglers[i], el]);
+ } else {
+ for (var fx in this.effects) el.setStyle(fx, 0);
+ }
+ }, this);
+ if ($chk(this.options.display)) this.display(this.options.display,
this.options.initialDisplayFx);
+ },
+
+ addSection: function(toggler, element){
+ toggler = document.id(toggler);
+ element = document.id(element);
+ var test = this.togglers.contains(toggler);
+ this.togglers.include(toggler);
+ this.elements.include(element);
+ var idx = this.togglers.indexOf(toggler);
+ toggler.addEvent(this.options.trigger, this.display.bind(this, idx));
+ if (this.options.height) element.setStyles({'padding-top': 0,
'border-top': 'none', 'padding-bottom': 0,
'border-bottom': 'none'});
+ if (this.options.width) element.setStyles({'padding-left': 0,
'border-left': 'none', 'padding-right': 0, 'border-right':
'none'});
+ element.fullOpacity = 1;
+ if (this.options.fixedWidth) element.fullWidth = this.options.fixedWidth;
+ if (this.options.fixedHeight) element.fullHeight = this.options.fixedHeight;
+ element.setStyle('overflow', 'hidden');
+ if (!test){
+ for (var fx in this.effects) element.setStyle(fx, 0);
+ }
+ return this;
+ },
+
+ display: function(index, useFx){
+ useFx = $pick(useFx, true);
+ index = ($type(index) == 'element') ? this.elements.indexOf(index) :
index;
+ if ((this.timer && this.options.wait) || (index === this.previous
&& !this.options.alwaysHide)) return this;
+ this.previous = index;
+ var obj = {};
+ this.elements.each(function(el, i){
+ obj[i] = {};
+ var hide = (i != index) || (this.options.alwaysHide &&
(el.offsetHeight > 0));
+ this.fireEvent(hide ? 'background' : 'active',
[this.togglers[i], el]);
+ for (var fx in this.effects) obj[i][fx] = hide ? 0 : el[this.effects[fx]];
+ }, this);
+ return useFx ? this.start(obj) : this.set(obj);
+ }
+
+});
+
+/*
+Script: Fx.Move.js
+ Defines Fx.Move, a class that works with Element.Position.js to transition an element
from one location to another.
+
+ License:
+ MIT-style license.
+
+ Authors:
+ Aaron Newton
+
+*/
+
+Fx.Move = new Class({
+
+ Extends: Fx.Morph,
+
+ options: {
+ relativeTo: document.body,
+ position: 'center',
+ edge: false,
+ offset: {x: 0, y: 0}
+ },
+
+ start: function(destination){
+ return this.parent(this.element.position($merge(this.options, destination,
{returnPos: true})));
+ }
+
+});
+
+Element.Properties.move = {
+
+ set: function(options){
+ var morph = this.retrieve('move');
+ if (morph) morph.cancel();
+ return this.eliminate('move').store('move:options',
$extend({link: 'cancel'}, options));
+ },
+
+ get: function(options){
+ if (options || !this.retrieve('move')){
+ if (options || !this.retrieve('move:options'))
this.set('move', options);
+ this.store('move', new Fx.Move(this,
this.retrieve('move:options')));
+ }
+ return this.retrieve('move');
+ }
+
+};
+
+Element.implement({
+
+ move: function(options){
+ this.get('move').start(options);
+ return this;
+ }
+
+});
+
+
+/*
+Script: Fx.Reveal.js
+ Defines Fx.Reveal, a class that shows and hides elements with a transition.
+
+ License:
+ MIT-style license.
+
+ Authors:
+ Aaron Newton
+
+*/
+
+Fx.Reveal = new Class({
+
+ Extends: Fx.Morph,
+
+ options: {/*
+ onShow: $empty(thisElement),
+ onHide: $empty(thisElement),
+ onComplete: $empty(thisElement),
+ heightOverride: null,
+ widthOverride: null, */
+ styles: ['padding', 'border', 'margin'],
+ transitionOpacity: !Browser.Engine.trident4,
+ mode: 'vertical',
+ display: 'block',
+ hideInputs: Browser.Engine.trident ? 'select, input, textarea, object,
embed' : false
+ },
+
+ dissolve: function(){
+ try {
+ if (!this.hiding && !this.showing){
+ if (this.element.getStyle('display') != 'none'){
+ this.hiding = true;
+ this.showing = false;
+ this.hidden = true;
+ var startStyles = this.element.getComputedSize({
+ styles: this.options.styles,
+ mode: this.options.mode
+ });
+ var setToAuto = (this.element.style.height ===
''||this.element.style.height == 'auto');
+ this.element.setStyle('display', 'block');
+ if (this.options.transitionOpacity) startStyles.opacity = 1;
+ var zero = {};
+ $each(startStyles, function(style, name){
+ zero[name] = [style, 0];
+ }, this);
+ var overflowBefore = this.element.getStyle('overflow');
+ this.element.setStyle('overflow', 'hidden');
+ var hideThese = this.options.hideInputs ?
this.element.getElements(this.options.hideInputs) : null;
+ this.$chain.unshift(function(){
+ if (this.hidden){
+ this.hiding = false;
+ $each(startStyles, function(style, name){
+ startStyles[name] = style;
+ }, this);
+ this.element.setStyles($merge({display: 'none',
overflow: overflowBefore}, startStyles));
+ if (setToAuto){
+ if (['vertical',
'both'].contains(this.options.mode)) this.element.style.height = '';
+ if (['width',
'both'].contains(this.options.mode)) this.element.style.width = '';
+ }
+ if (hideThese) hideThese.setStyle('visibility',
'visible');
+ }
+ this.fireEvent('hide', this.element);
+ this.callChain();
+ }.bind(this));
+ if (hideThese) hideThese.setStyle('visibility',
'hidden');
+ this.start(zero);
+ } else {
+ this.callChain.delay(10, this);
+ this.fireEvent('complete', this.element);
+ this.fireEvent('hide', this.element);
+ }
+ } else if (this.options.link == 'chain'){
+ this.chain(this.dissolve.bind(this));
+ } else if (this.options.link == 'cancel' && !this.hiding){
+ this.cancel();
+ this.dissolve();
+ }
+ } catch(e){
+ this.hiding = false;
+ this.element.setStyle('display', 'none');
+ this.callChain.delay(10, this);
+ this.fireEvent('complete', this.element);
+ this.fireEvent('hide', this.element);
+ }
+ return this;
+ },
+
+ reveal: function(){
+ try {
+ if (!this.showing && !this.hiding){
+ if (this.element.getStyle('display') == 'none' ||
+ this.element.getStyle('visiblity') == 'hidden' ||
+ this.element.getStyle('opacity') == 0){
+ this.showing = true;
+ this.hiding = false;
+ this.hidden = false;
+ var setToAuto, startStyles;
+ //toggle display, but hide it
+ this.element.measure(function(){
+ setToAuto = (this.element.style.height === '' ||
this.element.style.height == 'auto');
+ //create the styles for the opened/visible state
+ startStyles = this.element.getComputedSize({
+ styles: this.options.styles,
+ mode: this.options.mode
+ });
+ }.bind(this));
+ $each(startStyles, function(style, name){
+ startStyles[name] = style;
+ });
+ //if we're overridding height/width
+ if ($chk(this.options.heightOverride)) startStyles.height =
this.options.heightOverride.toInt();
+ if ($chk(this.options.widthOverride)) startStyles.width =
this.options.widthOverride.toInt();
+ if (this.options.transitionOpacity) {
+ this.element.setStyle('opacity', 0);
+ startStyles.opacity = 1;
+ }
+ //create the zero state for the beginning of the transition
+ var zero = {
+ height: 0,
+ display: this.options.display
+ };
+ $each(startStyles, function(style, name){ zero[name] = 0; });
+ var overflowBefore = this.element.getStyle('overflow');
+ //set to zero
+ this.element.setStyles($merge(zero, {overflow: 'hidden'}));
+ //hide inputs
+ var hideThese = this.options.hideInputs ?
this.element.getElements(this.options.hideInputs) : null;
+ if (hideThese) hideThese.setStyle('visibility',
'hidden');
+ //start the effect
+ this.start(startStyles);
+ this.$chain.unshift(function(){
+ this.element.setStyle('overflow', overflowBefore);
+ if (!this.options.heightOverride && setToAuto){
+ if (['vertical',
'both'].contains(this.options.mode)) this.element.style.height = '';
+ if (['width',
'both'].contains(this.options.mode)) this.element.style.width = '';
+ }
+ if (!this.hidden) this.showing = false;
+ if (hideThese) hideThese.setStyle('visibility',
'visible');
+ this.callChain();
+ this.fireEvent('show', this.element);
+ }.bind(this));
+ } else {
+ this.callChain();
+ this.fireEvent('complete', this.element);
+ this.fireEvent('show', this.element);
+ }
+ } else if (this.options.link == 'chain'){
+ this.chain(this.reveal.bind(this));
+ } else if (this.options.link == 'cancel' && !this.showing){
+ this.cancel();
+ this.reveal();
+ }
+ } catch(e){
+ this.element.setStyles({
+ display: this.options.display,
+ visiblity: 'visible',
+ opacity: 1
+ });
+ this.showing = false;
+ this.callChain.delay(10, this);
+ this.fireEvent('complete', this.element);
+ this.fireEvent('show', this.element);
+ }
+ return this;
+ },
+
+ toggle: function(){
+ if (this.element.getStyle('display') == 'none' ||
+ this.element.getStyle('visiblity') == 'hidden' ||
+ this.element.getStyle('opacity') == 0){
+ this.reveal();
+ } else {
+ this.dissolve();
+ }
+ return this;
+ }
+
+});
+
+Element.Properties.reveal = {
+
+ set: function(options){
+ var reveal = this.retrieve('reveal');
+ if (reveal) reveal.cancel();
+ return this.eliminate('reveal').store('reveal:options',
$extend({link: 'cancel'}, options));
+ },
+
+ get: function(options){
+ if (options || !this.retrieve('reveal')){
+ if (options || !this.retrieve('reveal:options'))
this.set('reveal', options);
+ this.store('reveal', new Fx.Reveal(this,
this.retrieve('reveal:options')));
+ }
+ return this.retrieve('reveal');
+ }
+
+};
+
+Element.Properties.dissolve = Element.Properties.reveal;
+
+Element.implement({
+
+ reveal: function(options){
+ this.get('reveal', options).reveal();
+ return this;
+ },
+
+ dissolve: function(options){
+ this.get('reveal', options).dissolve();
+ return this;
+ },
+
+ nix: function(){
+ var params = Array.link(arguments, {destroy: Boolean.type, options:
Object.type});
+ this.get('reveal', params.options).dissolve().chain(function(){
+ this[params.destroy ? 'destroy' : 'dispose']();
+ }.bind(this));
+ return this;
+ },
+
+ wink: function(){
+ var params = Array.link(arguments, {duration: Number.type, options:
Object.type});
+ var reveal = this.get('reveal', params.options);
+ reveal.reveal().chain(function(){
+ (function(){
+ reveal.dissolve();
+ }).delay(params.duration || 2000);
+ });
+ }
+
+
+});
+
+/*
+Script: Fx.Scroll.js
+ Effect to smoothly scroll any element, including the window.
+
+ License:
+ MIT-style license.
+
+ Authors:
+ Valerio Proietti
+*/
+
+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);
+ var cancel = this.cancel.bind(this, false);
+
+ if ($type(this.element) != 'element') this.element =
document.id(this.element.getDocument().body);
+
+ var stopper = this.element;
+
+ if (this.options.wheelStops){
+ 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);
+ this.element.scrollTo(now[0], now[1]);
+ },
+
+ 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 offsetSize = this.element.getSize(), scrollSize =
this.element.getScrollSize();
+ var scroll = this.element.getScroll(), values = {x: x, y: y};
+ for (var z in values){
+ var max = scrollSize[z] - offsetSize[z];
+ if ($chk(values[z])) values[z] = ($type(values[z]) == 'number') ?
values[z].limit(0, max) : max;
+ else values[z] = scroll[z];
+ values[z] += this.options.offset[z];
+ }
+ return this.parent([scroll.x, scroll.y], [values.x, values.y]);
+ },
+
+ toTop: function(){
+ return this.start(false, 0);
+ },
+
+ toLeft: function(){
+ return this.start(0, false);
+ },
+
+ toRight: function(){
+ return this.start('right', false);
+ },
+
+ toBottom: function(){
+ return this.start(false, 'bottom');
+ },
+
+ toElement: function(el){
+ var position = document.id(el).getPosition(this.element);
+ return this.start(position.x, position.y);
+ },
+
+ scrollIntoView: function(el, axes, offset){
+ axes = axes ? $splat(axes) : ['x','y'];
+ var to = {};
+ el = document.id(el);
+ var pos = el.getPosition(this.element);
+ var size = el.getSize();
+ var scroll = this.element.getScroll();
+ var containerSize = this.element.getSize();
+ var edge = {
+ x: pos.x + size.x,
+ y: pos.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 (pos[axis] < scroll[axis]) to[axis] = pos[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;
+ }
+
+});
+
+
+/*
+Script: Fx.Slide.js
+ Effect to slide an element in and out of view.
+
+ License:
+ MIT-style license.
+
+ Authors:
+ Valerio Proietti
+*/
+
+Fx.Slide = new Class({
+
+ Extends: Fx,
+
+ options: {
+ mode: 'vertical'
+ },
+
+ initialize: function(element, options){
+ this.addEvent('complete', function(){
+ this.open = (this.wrapper['offset' + this.layout.capitalize()] !=
0);
+ if (this.open && Browser.Engine.webkit419)
this.element.dispose().inject(this.wrapper);
+ }, true);
+ this.element = this.subject = document.id(element);
+ this.parent(options);
+ var wrapper = this.element.retrieve('wrapper');
+ this.wrapper = wrapper || new Element('div', {
+ styles: $extend(this.element.getStyles('margin', 'position'),
{overflow: 'hidden'})
+ }).wraps(this.element);
+ this.element.store('wrapper', this.wrapper).setStyle('margin',
0);
+ this.now = [];
+ this.open = 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();
+ var layout = this.wrapper.getStyle(this.layout).toInt();
+ var caseIn = [[margin, layout], [0, this.offset]];
+ var caseOut = [[margin, layout], [-this.offset, 0]];
+ var 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){
+ var slide = this.retrieve('slide');
+ if (slide) slide.cancel();
+ return this.eliminate('slide').store('slide:options',
$extend({link: 'cancel'}, options));
+ },
+
+ get: function(options){
+ if (options || !this.retrieve('slide')){
+ if (options || !this.retrieve('slide:options'))
this.set('slide', options);
+ this.store('slide', new Fx.Slide(this,
this.retrieve('slide:options')));
+ }
+ return this.retrieve('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: Fx.SmoothScroll.js
+ Class for creating a smooth scrolling effect to all internal links on the page.
+
+ License:
+ MIT-style license.
+
+ Authors:
+ Valerio Proietti
+*/
+
+var SmoothScroll = Fx.SmoothScroll = new Class({
+
+ Extends: Fx.Scroll,
+
+ initialize: function(options, context){
+ context = context || document;
+ this.doc = context.getDocument();
+ var win = context.getWindow();
+ this.parent(this.doc, options);
+ this.links = this.options.links ? $$(this.options.links) : $$(this.doc.links);
+ var location = win.location.href.match(/^[^#]*/)[0] + '#';
+ this.links.each(function(link){
+ if (link.href.indexOf(location) != 0) {return;}
+ var anchor = link.href.substr(location.length);
+ if (anchor) this.useLink(link, anchor);
+ }, this);
+ if (!Browser.Engine.webkit419) {
+ this.addEvent('complete', function(){
+ win.location.hash = this.anchor;
+ }, true);
+ }
+ },
+
+ useLink: function(link, anchor){
+ var el;
+ link.addEvent('click', function(event){
+ if (el !== false && !el) el = document.id(anchor) ||
this.doc.getElement('a[name=' + anchor + ']');
+ if (el) {
+ event.preventDefault();
+ this.anchor = anchor;
+ this.toElement(el);
+ link.blur();
+ }
+ }.bind(this));
+ }
+
+});
+
+/*
+Script: Drag.js
+ 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
+*/
+
+var Drag = new Class({
+
+ Implements: [Events, Options],
+
+ options: {/*
+ onBeforeStart: $empty(thisElement),
+ onStart: $empty(thisElement, event),
+ onSnap: $empty(thisElement)
+ onDrag: $empty(thisElement, event),
+ onCancel: $empty(thisElement),
+ onComplete: $empty(thisElement, event),*/
+ snap: 6,
+ unit: 'px',
+ grid: false,
+ style: true,
+ limit: false,
+ handle: false,
+ invert: false,
+ preventDefault: false,
+ modifiers: {x: 'left', y: 'top'}
+ },
+
+ initialize: function(){
+ var params = Array.link(arguments, {'options': Object.type,
'element': $defined});
+ this.element = document.id(params.element);
+ this.document = this.element.getDocument();
+ this.setOptions(params.options || {});
+ var htype = $type(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.Engine.trident) ? 'selectstart' :
'mousedown';
+
+ 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: $lambda(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){
+ if (this.options.preventDefault) event.preventDefault();
+ this.mouse.start = event.page;
+ this.fireEvent('beforeStart', this.element);
+ var limit = this.options.limit;
+ this.limit = {x: [], y: []};
+ for (var z in this.options.modifiers){
+ if (!this.options.modifiers[z]) continue;
+ if (this.options.style) this.value.now[z] =
this.element.getStyle(this.options.modifiers[z]).toInt();
+ else this.value.now[z] = this.element[this.options.modifiers[z]];
+ if (this.options.invert) this.value.now[z] *= -1;
+ this.mouse.pos[z] = event.page[z] - this.value.now[z];
+ if (limit && limit[z]){
+ for (var i = 2; i--; i){
+ if ($chk(limit[z][i])) this.limit[z][i] = $lambda(limit[z][i])();
+ }
+ }
+ }
+ if ($type(this.options.grid) == 'number') this.options.grid = {x:
this.options.grid, y: this.options.grid};
+ this.document.addEvents({mousemove: this.bound.check, mouseup:
this.bound.cancel});
+ this.document.addEvent(this.selection, this.bound.eventStop);
+ },
+
+ 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){
+ if (this.options.preventDefault) event.preventDefault();
+ this.mouse.now = event.page;
+ for (var z in this.options.modifiers){
+ if (!this.options.modifiers[z]) continue;
+ this.value.now[z] = this.mouse.now[z] - this.mouse.pos[z];
+ if (this.options.invert) this.value.now[z] *= -1;
+ if (this.options.limit && this.limit[z]){
+ if ($chk(this.limit[z][1]) && (this.value.now[z] >
this.limit[z][1])){
+ this.value.now[z] = this.limit[z][1];
+ } else if ($chk(this.limit[z][0]) && (this.value.now[z] <
this.limit[z][0])){
+ this.value.now[z] = this.limit[z][0];
+ }
+ }
+ if (this.options.grid[z]) this.value.now[z] -= ((this.value.now[z] -
(this.limit[z][0]||0)) % this.options.grid[z]);
+ if (this.options.style) this.element.setStyle(this.options.modifiers[z],
this.value.now[z] + this.options.unit);
+ else this.element[this.options.modifiers[z]] = this.value.now[z];
+ }
+ this.fireEvent('drag', [this.element, event]);
+ },
+
+ cancel: function(event){
+ this.document.removeEvent('mousemove', this.bound.check);
+ this.document.removeEvent('mouseup', this.bound.cancel);
+ if (event){
+ this.document.removeEvent(this.selection, this.bound.eventStop);
+ this.fireEvent('cancel', this.element);
+ }
+ },
+
+ stop: function(event){
+ this.document.removeEvent(this.selection, this.bound.eventStop);
+ this.document.removeEvent('mousemove', this.bound.drag);
+ this.document.removeEvent('mouseup', this.bound.stop);
+ if (event) this.fireEvent('complete', [this.element, event]);
+ }
+
+});
+
+Element.implement({
+
+ makeResizable: function(options){
+ var drag = new Drag(this, $merge({modifiers: {x: 'width', y:
'height'}}, options));
+ this.store('resizer', drag);
+ return drag.addEvent('drag', function(){
+ this.fireEvent('resize', drag);
+ }.bind(this));
+ }
+
+});
+
+
+/*
+Script: Slider.js
+ Class for creating horizontal and vertical slider controls.
+
+ License:
+ MIT-style license.
+
+ Authors:
+ Valerio Proietti
+*/
+
+var Slider = new Class({
+
+ Implements: [Events, Options],
+
+ Binds: ['clickedElement', 'draggedKnob', 'scrolledElement'],
+
+ options: {
+ onTick: function(position){
+ if (this.options.snap) position = this.toPosition(this.step);
+ this.knob.setStyle(this.property, position);
+ },
+ snap: false,
+ offset: 0,
+ range: false,
+ wheel: false,
+ steps: 100,
+ mode: 'horizontal'
+ },
+
+ initialize: function(element, knob, options){
+ this.setOptions(options);
+ this.element = document.id(element);
+ this.knob = document.id(knob);
+ this.previousChange = this.previousEnd = this.step = -1;
+ var offset, limit = {}, modifiers = {'x': false, 'y': false};
+ switch (this.options.mode){
+ case 'vertical':
+ this.axis = 'y';
+ this.property = 'top';
+ offset = 'offsetHeight';
+ break;
+ case 'horizontal':
+ this.axis = 'x';
+ this.property = 'left';
+ offset = 'offsetWidth';
+ }
+ this.half = this.knob[offset] / 2;
+ this.full = this.element[offset] - this.knob[offset] + (this.options.offset *
2);
+ this.min = $chk(this.options.range[0]) ? this.options.range[0] : 0;
+ this.max = $chk(this.options.range[1]) ? this.options.range[1] :
this.options.steps;
+ this.range = this.max - this.min;
+ this.steps = this.options.steps || this.full;
+ this.stepSize = Math.abs(this.range) / this.steps;
+ this.stepWidth = this.stepSize * this.full / Math.abs(this.range) ;
+
+ this.knob.setStyle('position',
'relative').setStyle(this.property, - this.options.offset);
+ modifiers[this.axis] = this.property;
+ limit[this.axis] = [- this.options.offset, this.full - this.options.offset];
+
+ this.bound = {
+ clickedElement: this.clickedElement.bind(this),
+ scrolledElement: this.scrolledElement.bindWithEvent(this),
+ draggedKnob: this.draggedKnob.bind(this)
+ };
+
+ var dragOptions = {
+ snap: 0,
+ limit: limit,
+ modifiers: modifiers,
+ onDrag: this.bound.draggedKnob,
+ onStart: this.bound.draggedKnob,
+ onBeforeStart: (function(){
+ this.isDragging = true;
+ }).bind(this),
+ onComplete: function(){
+ this.isDragging = false;
+ this.draggedKnob();
+ this.end();
+ }.bind(this)
+ };
+ if (this.options.snap){
+ dragOptions.grid = Math.ceil(this.stepWidth);
+ dragOptions.limit[this.axis][1] = this.full;
+ }
+
+ this.drag = new Drag(this.knob, dragOptions);
+ this.attach();
+ },
+
+ attach: function(){
+ this.element.addEvent('mousedown', this.bound.clickedElement);
+
+ // keep track from firing the 'mousedown' event if the knob has been
hovored
+ this.knob.addEvent('mouseenter',function(){
+ this.element.removeEvents('mousedown');
+ }.bind(this));
+ this.knob.addEvent('mouseleave',function(){
+ this.element.addEvent('mousedown', this.clickedElement.bind(this));
+ }.bind(this));
+
+ if (this.options.wheel) this.element.addEvent('mousewheel',
this.bound.scrolledElement);
+ this.drag.attach();
+ return this;
+ },
+
+ detach: function(){
+ this.element.removeEvent('mousedown', this.bound.clickedElement);
+ this.element.removeEvent('mousewheel', this.bound.scrolledElement);
+ this.drag.detach();
+ return this;
+ },
+
+ set: function(step, check){
+ if (arguments.length == 1)
+ check = true;
+ if (!((this.range > 0) ^ (step < this.min))) step = this.min;
+ if (!((this.range > 0) ^ (step > this.max))) step = this.max;
+
+ this.step = Math.round(step);
+ if (check)
+ this.checkStep();
+ this.fireEvent('tick', this.toPosition(this.step));
+ this.end();
+ return this;
+ },
+
+ clickedElement: function(event){
+ if (this.isDragging || event.target == this.knob) return;
+
+ var dir = this.range < 0 ? -1 : 1;
+ var position = event.page[this.axis] - this.element.getPosition()[this.axis] -
this.half;
+ position = position.limit(-this.options.offset, this.full -this.options.offset);
+
+ this.step = Math.round(this.min + dir * this.toStep(position));
+ this.checkStep();
+ this.fireEvent('tick', position);
+ this.end();
+ },
+
+ scrolledElement: function(event){
+ var mode = (this.options.mode == 'horizontal') ? (event.wheel < 0) :
(event.wheel > 0);
+ this.set(mode ? this.step - this.stepSize : this.step + this.stepSize);
+ event.stop();
+ },
+
+ draggedKnob: function(){
+ var dir = this.range < 0 ? -1 : 1;
+ var position = this.drag.value.now[this.axis];
+ position = position.limit(-this.options.offset, this.full -this.options.offset);
+ this.step = Math.round(this.min + dir * this.toStep(position));
+ this.checkStep();
+ },
+
+ checkStep: function(){
+ if (this.previousChange != this.step){
+ this.previousChange = this.step;
+ this.fireEvent('change', this.step);
+ }
+ },
+
+ end: function(){
+ if (this.previousEnd !== this.step){
+ this.previousEnd = this.step;
+ this.fireEvent('complete', this.step + '');
+ }
+ },
+
+ toStep: function(position){
+ var step = (position + this.options.offset) * this.stepSize / this.full *
this.steps;
+ return this.options.steps ? Math.round(step -= step % this.stepSize) : step;
+ },
+
+ toPosition: function(step){
+ return (this.full * Math.abs(this.min - step)) / (this.steps * this.stepSize) -
this.options.offset;
+ }
+
+});
+
+/*
+Script: Tips.js
+ Class for creating nice tips that follow the mouse cursor when hovering an element.
+
+ License:
+ MIT-style license.
+
+ Authors:
+ Valerio Proietti
+ Christoph Pojer
+*/
+
+var Tips = new Class({
+
+ Implements: [Events, Options],
+
+ options: {
+ onShow: function(tip){
+ tip.setStyle('visibility', 'visible');
+ },
+ onHide: function(tip){
+ tip.setStyle('visibility', 'hidden');
+ },
+ title: 'title',
+ text: function(el){
+ return el.get('rel') || el.get('href');
+ },
+ showDelay: 100,
+ hideDelay: 100,
+ className: null,
+ offset: {x: 16, y: 16},
+ fixed: false
+ },
+
+ initialize: function(){
+ var params = Array.link(arguments, {options: Object.type, elements: $defined});
+ if (params.options && params.options.offsets) params.options.offset =
params.options.offsets;
+ this.setOptions(params.options);
+ this.container = new Element('div', {'class': 'tip'});
+ this.tip = this.getTip();
+
+ if (params.elements) this.attach(params.elements);
+ },
+
+ getTip: function(){
+ return new Element('div', {
+ 'class': this.options.className,
+ styles: {
+ visibility: 'hidden',
+ display: 'none',
+ position: 'absolute',
+ top: 0,
+ left: 0
+ }
+ }).adopt(
+ new Element('div', {'class': 'tip-top'}),
+ this.container,
+ new Element('div', {'class': 'tip-bottom'})
+ ).inject(document.body);
+ },
+
+ attach: function(elements){
+ var read = function(option, element){
+ if (option == null) return '';
+ return $type(option) == 'function' ? option(element) :
element.get(option);
+ };
+ $$(elements).each(function(element){
+ var title = read(this.options.title, element);
+ element.erase('title').store('tip:native',
title).retrieve('tip:title', title);
+ element.retrieve('tip:text', read(this.options.text, element));
+
+ var events = ['enter', 'leave'];
+ if (!this.options.fixed) events.push('move');
+
+ events.each(function(value){
+ element.addEvent('mouse' + value, element.retrieve('tip:'
+ value, this['element' + value.capitalize()].bindWithEvent(this, element)));
+ }, this);
+ }, this);
+
+ return this;
+ },
+
+ detach: function(elements){
+ $$(elements).each(function(element){
+ ['enter', 'leave', 'move'].each(function(value){
+ element.removeEvent('mouse' + value,
element.retrieve('tip:' + value) || $empty);
+ });
+
+
element.eliminate('tip:enter').eliminate('tip:leave').eliminate('tip:move');
+
+ if ($type(this.options.title) == 'string' &&
this.options.title == 'title'){
+ var original = element.retrieve('tip:native');
+ if (original) element.set('title', original);
+ }
+ }, this);
+
+ return this;
+ },
+
+ elementEnter: function(event, element){
+ $A(this.container.childNodes).each(Element.dispose);
+
+ ['title', 'text'].each(function(value){
+ var content = element.retrieve('tip:' + value);
+ if (!content) return;
+
+ this[value + 'Element'] = new Element('div',
{'class': 'tip-' + value}).inject(this.container);
+ this.fill(this[value + 'Element'], content);
+ }, this);
+
+ this.timer = $clear(this.timer);
+ this.timer = this.show.delay(this.options.showDelay, this, element);
+ this.tip.setStyle('display', 'block');
+ this.position((!this.options.fixed) ? event : {page: element.getPosition()});
+ },
+
+ elementLeave: function(event, element){
+ $clear(this.timer);
+ this.tip.setStyle('display', 'none');
+ this.timer = this.hide.delay(this.options.hideDelay, this, element);
+ },
+
+ elementMove: function(event){
+ this.position(event);
+ },
+
+ position: function(event){
+ var size = window.getSize(), scroll = window.getScroll(),
+ tip = {x: this.tip.offsetWidth, y: this.tip.offsetHeight},
+ props = {x: 'left', y: 'top'},
+ obj = {};
+
+ for (var z in props){
+ obj[props[z]] = event.page[z] + this.options.offset[z];
+ if ((obj[props[z]] + tip[z] - scroll[z]) > size[z]) obj[props[z]] =
event.page[z] - this.options.offset[z] - tip[z];
+ }
+
+ this.tip.setStyles(obj);
+ },
+
+ fill: function(element, contents){
+ if(typeof contents == 'string') element.set('html', contents);
+ else element.adopt(contents);
+ },
+
+ show: function(el){
+ this.fireEvent('show', [this.tip, el]);
+ },
+
+ hide: function(el){
+ this.fireEvent('hide', [this.tip, el]);
+ }
+
+});
+
+/*
+Script: Date.English.US.js
+ Date messages for US English.
+
+ License:
+ MIT-style license.
+
+ Authors:
+ Aaron Newton
+
+*/
+
+MooTools.lang.set('en-US', 'Date', {
+
+ months: ['January', 'February', 'March', 'April',
'May', 'June', 'July', 'August', 'September',
'October', 'November', 'December'],
+ days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday',
'Thursday', 'Friday', 'Saturday'],
+ //culture's date order: MM/DD/YYYY
+ dateOrder: ['month', 'date', 'year'],
+ shortDate: '%m/%d/%Y',
+ shortTime: '%I:%M%p',
+ AM: 'AM',
+ PM: 'PM',
+
+ /* 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',
+ 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'
+
+});
+
+/*
+Script: FormValidator.English.js
+ Date messages for English.
+
+ License:
+ MIT-style license.
+
+ Authors:
+ Aaron Newton
+
+*/
+
+MooTools.lang.set('en-US', 'FormValidator', {
+
+ required:'This field is required.',
+ minLength:'Please enter at least {minLength} characters (you entered {length}
characters).',
+ maxLength:'Please enter no more than {maxLength} characters (you entered {length}
characters).',
+ integer:'Please enter an integer in this field. Numbers with decimals (e.g. 1.25)
are not permitted.',
+ numeric:'Please enter only numeric values in this field (i.e. "1" or
"1.1" or "-1" or "-1.1").',
+ digits:'Please use numbers and punctuation only in this field (for example, a
phone number with dashes or dots is permitted).',
+ alpha:'Please use letters only (a-z) with in this field. No spaces or other
characters are allowed.',
+ alphanum:'Please use only letters (a-z) or numbers (0-9) only in this field. No
spaces or other characters are allowed.',
+ dateSuchAs:'Please enter a valid date such as {date}',
+ dateInFormatMDY:'Please enter a valid date such as MM/DD/YYYY (i.e.
"12/31/1999")',
+ email:'Please enter a valid email address. For example
"fred(a)domain.com".',
+ url:'Please enter a valid URL such as
http://www.google.com.';,
+ currencyDollar:'Please enter a valid $ amount. For example $100.00 .',
+ oneRequired:'Please enter something for at least one of these inputs.',
+ errorPrefix: 'Error: ',
+ warningPrefix: 'Warning: ',
+
+ //FormValidator.Extras
+
+ noSpace: 'There can be no spaces in this input.',
+ reqChkByNode: 'No items are selected.',
+ requiredChk: 'This field is required.',
+ reqChkByName: 'Please select a {label}.',
+ match: 'This field needs to match the {matchName} field',
+ startDate: 'the start date',
+ endDate: 'the end date',
+ currendDate: 'the current date',
+ afterDate: 'The date should be the same or after {label}.',
+ beforeDate: 'The date should be the same or before {label}.',
+ startMonth: 'Please select a start month',
+ sameMonth: 'These two dates must be in the same month - you must change one or
the other.'
+
});
\ No newline at end of file