1// MooTools: the javascript framework. 2// Load this file's selection again by visiting: http://mootools.net/more/d06b1fcc692893a712456d0658524080 3// Or build this file again with packager using: packager build More/More More/Array.Extras More/Date More/Date.Extras More/String.Extras More/String.QueryString More/Hash More/Hash.Extras More/Element.Forms More/Elements.From More/Element.Event.Pseudos More/Element.Event.Pseudos.Keys More/Element.Measure More/Element.Pin More/Element.Position More/Element.Shortcuts More/Form.Request More/Form.Request.Append More/Form.Validator More/Form.Validator.Inline More/Form.Validator.Extras More/OverText More/Fx.Elements More/Fx.Accordion More/Fx.Move More/Fx.Scroll More/Fx.Slide More/Fx.SmoothScroll More/Fx.Sort More/Assets More/Hash.Cookie More/Keyboard More/Keyboard.Extras More/Scroller More/Tips 4/* 5--- 6 7script: More.js 8 9name: More 10 11description: MooTools More 12 13license: MIT-style license 14 15authors: 16 - Guillermo Rauch 17 - Thomas Aylott 18 - Scott Kyle 19 - Arian Stolwijk 20 - Tim Wienk 21 - Christoph Pojer 22 - Aaron Newton 23 - Jacob Thornton 24 25requires: 26 - Core/MooTools 27 28provides: [MooTools.More] 29 30... 31*/ 32 33MooTools.More = { 34 'version': '1.4.0.1', 35 'build': 'a4244edf2aa97ac8a196fc96082dd35af1abab87' 36}; 37 38 39/* 40--- 41 42script: Array.Extras.js 43 44name: Array.Extras 45 46description: Extends the Array native object to include useful methods to work with arrays. 47 48license: MIT-style license 49 50authors: 51 - Christoph Pojer 52 - Sebastian Markbåge 53 54requires: 55 - Core/Array 56 - MooTools.More 57 58provides: [Array.Extras] 59 60... 61*/ 62 63(function(nil){ 64 65Array.implement({ 66 67 min: function(){ 68 return Math.min.apply(null, this); 69 }, 70 71 max: function(){ 72 return Math.max.apply(null, this); 73 }, 74 75 average: function(){ 76 return this.length ? this.sum() / this.length : 0; 77 }, 78 79 sum: function(){ 80 var result = 0, l = this.length; 81 if (l){ 82 while (l--) result += this[l]; 83 } 84 return result; 85 }, 86 87 unique: function(){ 88 return [].combine(this); 89 }, 90 91 shuffle: function(){ 92 for (var i = this.length; i && --i;){ 93 var temp = this[i], r = Math.floor(Math.random() * ( i + 1 )); 94 this[i] = this[r]; 95 this[r] = temp; 96 } 97 return this; 98 }, 99 100 reduce: function(fn, value){ 101 for (var i = 0, l = this.length; i < l; i++){ 102 if (i in this) value = value === nil ? this[i] : fn.call(null, value, this[i], i, this); 103 } 104 return value; 105 }, 106 107 reduceRight: function(fn, value){ 108 var i = this.length; 109 while (i--){ 110 if (i in this) value = value === nil ? this[i] : fn.call(null, value, this[i], i, this); 111 } 112 return value; 113 } 114 115}); 116 117})(); 118 119 120/* 121--- 122 123script: Object.Extras.js 124 125name: Object.Extras 126 127description: Extra Object generics, like getFromPath which allows a path notation to child elements. 128 129license: MIT-style license 130 131authors: 132 - Aaron Newton 133 134requires: 135 - Core/Object 136 - /MooTools.More 137 138provides: [Object.Extras] 139 140... 141*/ 142 143(function(){ 144 145var defined = function(value){ 146 return value != null; 147}; 148 149var hasOwnProperty = Object.prototype.hasOwnProperty; 150 151Object.extend({ 152 153 getFromPath: function(source, parts){ 154 if (typeof parts == 'string') parts = parts.split('.'); 155 for (var i = 0, l = parts.length; i < l; i++){ 156 if (hasOwnProperty.call(source, parts[i])) source = source[parts[i]]; 157 else return null; 158 } 159 return source; 160 }, 161 162 cleanValues: function(object, method){ 163 method = method || defined; 164 for (var key in object) if (!method(object[key])){ 165 delete object[key]; 166 } 167 return object; 168 }, 169 170 erase: function(object, key){ 171 if (hasOwnProperty.call(object, key)) delete object[key]; 172 return object; 173 }, 174 175 run: function(object){ 176 var args = Array.slice(arguments, 1); 177 for (var key in object) if (object[key].apply){ 178 object[key].apply(object, args); 179 } 180 return object; 181 } 182 183}); 184 185})(); 186 187 188/* 189--- 190 191script: Locale.js 192 193name: Locale 194 195description: Provides methods for localization. 196 197license: MIT-style license 198 199authors: 200 - Aaron Newton 201 - Arian Stolwijk 202 203requires: 204 - Core/Events 205 - /Object.Extras 206 - /MooTools.More 207 208provides: [Locale, Lang] 209 210... 211*/ 212 213(function(){ 214 215var current = null, 216 locales = {}, 217 inherits = {}; 218 219var getSet = function(set){ 220 if (instanceOf(set, Locale.Set)) return set; 221 else return locales[set]; 222}; 223 224var Locale = this.Locale = { 225 226 define: function(locale, set, key, value){ 227 var name; 228 if (instanceOf(locale, Locale.Set)){ 229 name = locale.name; 230 if (name) locales[name] = locale; 231 } else { 232 name = locale; 233 if (!locales[name]) locales[name] = new Locale.Set(name); 234 locale = locales[name]; 235 } 236 237 if (set) locale.define(set, key, value); 238 239 /*<1.2compat>*/ 240 if (set == 'cascade') return Locale.inherit(name, key); 241 /*</1.2compat>*/ 242 243 if (!current) current = locale; 244 245 return locale; 246 }, 247 248 use: function(locale){ 249 locale = getSet(locale); 250 251 if (locale){ 252 current = locale; 253 254 this.fireEvent('change', locale); 255 256 /*<1.2compat>*/ 257 this.fireEvent('langChange', locale.name); 258 /*</1.2compat>*/ 259 } 260 261 return this; 262 }, 263 264 getCurrent: function(){ 265 return current; 266 }, 267 268 get: function(key, args){ 269 return (current) ? current.get(key, args) : ''; 270 }, 271 272 inherit: function(locale, inherits, set){ 273 locale = getSet(locale); 274 275 if (locale) locale.inherit(inherits, set); 276 return this; 277 }, 278 279 list: function(){ 280 return Object.keys(locales); 281 } 282 283}; 284 285Object.append(Locale, new Events); 286 287Locale.Set = new Class({ 288 289 sets: {}, 290 291 inherits: { 292 locales: [], 293 sets: {} 294 }, 295 296 initialize: function(name){ 297 this.name = name || ''; 298 }, 299 300 define: function(set, key, value){ 301 var defineData = this.sets[set]; 302 if (!defineData) defineData = {}; 303 304 if (key){ 305 if (typeOf(key) == 'object') defineData = Object.merge(defineData, key); 306 else defineData[key] = value; 307 } 308 this.sets[set] = defineData; 309 310 return this; 311 }, 312 313 get: function(key, args, _base){ 314 var value = Object.getFromPath(this.sets, key); 315 if (value != null){ 316 var type = typeOf(value);
317 if (type == 'function') value = value.apply(null, Array.from(args)); 318 else if (type == 'object') value = Object.clone(value); 319 return value; 320 } 321 322 // get value of inherited locales 323 var index = key.indexOf('.'), 324 set = index < 0 ? key : key.substr(0, index), 325 names = (this.inherits.sets[set] || []).combine(this.inherits.locales).include('en-US'); 326 if (!_base) _base = []; 327 328 for (var i = 0, l = names.length; i < l; i++){ 329 if (_base.contains(names[i])) continue; 330 _base.include(names[i]); 331 332 var locale = locales[names[i]]; 333 if (!locale) continue; 334 335 value = locale.get(key, args, _base); 336 if (value != null) return value; 337 } 338 339 return ''; 340 }, 341 342 inherit: function(names, set){ 343 names = Array.from(names); 344 345 if (set && !this.inherits.sets[set]) this.inherits.sets[set] = []; 346 347 var l = names.length; 348 while (l--) (set ? this.inherits.sets[set] : this.inherits.locales).unshift(names[l]); 349 350 return this; 351 } 352 353}); 354 355/*<1.2compat>*/ 356var lang = MooTools.lang = {}; 357 358Object.append(lang, Locale, { 359 setLanguage: Locale.use, 360 getCurrentLanguage: function(){ 361 var current = Locale.getCurrent(); 362 return (current) ? current.name : null; 363 }, 364 set: function(){ 365 Locale.define.apply(this, arguments); 366 return this; 367 }, 368 get: function(set, key, args){ 369 if (key) set += '.' + key; 370 return Locale.get(set, args); 371 } 372}); 373/*</1.2compat>*/ 374 375})(); 376 377 378/* 379--- 380 381name: Locale.en-US.Date 382 383description: Date messages for US English. 384 385license: MIT-style license 386 387authors: 388 - Aaron Newton 389 390requires: 391 - /Locale 392 393provides: [Locale.en-US.Date] 394 395... 396*/ 397 398Locale.define('en-US', 'Date', { 399 400 months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], 401 months_abbr: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], 402 days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], 403 days_abbr: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], 404 405 // Culture's date order: MM/DD/YYYY 406 dateOrder: ['month', 'date', 'year'], 407 shortDate: '%m/%d/%Y', 408 shortTime: '%I:%M%p', 409 AM: 'AM', 410 PM: 'PM', 411 firstDayOfWeek: 0, 412 413 // Date.Extras 414 ordinal: function(dayOfMonth){ 415 // 1st, 2nd, 3rd, etc. 416 return (dayOfMonth > 3 && dayOfMonth < 21) ? 'th' : ['th', 'st', 'nd', 'rd', 'th'][Math.min(dayOfMonth % 10, 4)]; 417 }, 418 419 lessThanMinuteAgo: 'less than a minute ago', 420 minuteAgo: 'about a minute ago', 421 minutesAgo: '{delta} minutes ago', 422 hourAgo: 'about an hour ago', 423 hoursAgo: 'about {delta} hours ago', 424 dayAgo: '1 day ago', 425 daysAgo: '{delta} days ago', 426 weekAgo: '1 week ago', 427 weeksAgo: '{delta} weeks ago', 428 monthAgo: '1 month ago', 429 monthsAgo: '{delta} months ago', 430 yearAgo: '1 year ago', 431 yearsAgo: '{delta} years ago', 432 433 lessThanMinuteUntil: 'less than a minute from now', 434 minuteUntil: 'about a minute from now', 435 minutesUntil: '{delta} minutes from now', 436 hourUntil: 'about an hour from now', 437 hoursUntil: 'about {delta} hours from now', 438 dayUntil: '1 day from now', 439 daysUntil: '{delta} days from now', 440 weekUntil: '1 week from now', 441 weeksUntil: '{delta} weeks from now', 442 monthUntil: '1 month from now', 443 monthsUntil: '{delta} months from now', 444 yearUntil: '1 year from now', 445 yearsUntil: '{delta} years from now' 446 447}); 448 449 450/* 451--- 452 453script: Date.js 454 455name: Date 456 457description: Extends the Date native object to include methods useful in managing dates. 458 459license: MIT-style license 460 461authors: 462 - Aaron Newton
463 - Nicholas Barthelemy - https://svn.nbarthelemy.com/date-js/ 464 - Harald Kirshner - mail [at] digitarald.de; http://digitarald.de 465 - Scott Kyle - scott [at] appden.com; http://appden.com 466 467requires: 468 - Core/Array 469 - Core/String 470 - Core/Number 471 - MooTools.More 472 - Locale 473 - Locale.en-US.Date 474 475provides: [Date] 476 477... 478*/ 479 480(function(){ 481 482var Date = this.Date; 483 484var DateMethods = Date.Methods = { 485 ms: 'Milliseconds', 486 year: 'FullYear', 487 min: 'Minutes', 488 mo: 'Month', 489 sec: 'Seconds', 490 hr: 'Hours' 491}; 492 493['Date', 'Day', 'FullYear', 'Hours', 'Milliseconds', 'Minutes', 'Month', 'Seconds', 'Time', 'TimezoneOffset', 494 'Week', 'Timezone', 'GMTOffset', 'DayOfYear', 'LastMonth', 'LastDayOfMonth', 'UTCDate', 'UTCDay', 'UTCFullYear', 495 'AMPM', 'Ordinal', 'UTCHours', 'UTCMilliseconds', 'UTCMinutes', 'UTCMonth', 'UTCSeconds', 'UTCMilliseconds'].each(function(method){ 496 Date.Methods[method.toLowerCase()] = method; 497}); 498 499var pad = function(n, digits, string){ 500 if (digits == 1) return n; 501 return n < Math.pow(10, digits - 1) ? (string || '0') + pad(n, digits - 1, string) : n; 502}; 503 504Date.implement({ 505 506 set: function(prop, value){ 507 prop = prop.toLowerCase(); 508 var method = DateMethods[prop] && 'set' + DateMethods[prop]; 509 if (method && this[method]) this[method](value); 510 return this; 511 }.overloadSetter(), 512 513 get: function(prop){ 514 prop = prop.toLowerCase(); 515 var method = DateMethods[prop] && 'get' + DateMethods[prop]; 516 if (method && this[method]) return this[method](); 517 return null; 518 }.overloadGetter(), 519 520 clone: function(){ 521 return new Date(this.get('time')); 522 }, 523 524 increment: function(interval, times){ 525 interval = interval || 'day'; 526 times = times != null ? times : 1; 527 528 switch (interval){ 529 case 'year': 530 return this.increment('month', times * 12); 531 case 'month': 532 var d = this.get('date'); 533 this.set('date', 1).set('mo', this.get('mo') + times); 534 return this.set('date', d.min(this.get('lastdayofmonth'))); 535 case 'week': 536 return this.increment('day', times * 7); 537 case 'day': 538 return this.set('date', this.get('date') + times); 539 } 540 541 if (!Date.units[interval]) throw new Error(interval + ' is not a supported interval'); 542 543 return this.set('time', this.get('time') + times * Date.units[interval]()); 544 }, 545 546 decrement: function(interval, times){ 547 return this.increment(interval, -1 * (times != null ? times : 1)); 548 }, 549 550 isLeapYear: function(){ 551 return Date.isLeapYear(this.get('year')); 552 }, 553 554 clearTime: function(){ 555 return this.set({hr: 0, min: 0, sec: 0, ms: 0}); 556 }, 557 558 diff: function(date, resolution){ 559 if (typeOf(date) == 'string') date = Date.parse(date); 560 561 return ((date - this) / Date.units[resolution || 'day'](3, 3)).round(); // non-leap year, 30-day month 562 }, 563 564 getLastDayOfMonth: function(){ 565 return Date.daysInMonth(this.get('mo'), this.get('year')); 566 }, 567 568 getDayOfYear: function(){ 569 return (Date.UTC(this.get('year'), this.get('mo'), this.get('date') + 1) 570 - Date.UTC(this.get('year'), 0, 1)) / Date.units.day(); 571 }, 572 573 setDay: function(day, firstDayOfWeek){ 574 if (firstDayOfWeek == null){ 575 firstDayOfWeek = Date.getMsg('firstDayOfWeek'); 576 if (firstDayOfWeek === '') firstDayOfWeek = 1; 577 } 578 579 day = (7 + Date.parseDay(day, true) - firstDayOfWeek) % 7; 580 var currentDay = (7 + this.get('day') - firstDayOfWeek) % 7; 581 582 return this.increment('day', day - currentDay); 583 }, 584 585 getWeek: function(firstDayOfWeek){ 586 if (firstDayOfWeek == null){ 587 firstDayOfWeek = Date.getMsg('firstDayOfWeek'); 588 if (firstDayOfWeek === '') firstDayOfWeek = 1; 589 } 590 591 var date = this, 592 dayOfWeek = (7 + date.get('day') - firstDayOfWeek) % 7, 593 dividend = 0, 594 firstDayOfYear; 595 596 if (firstDayOfWeek == 1){ 597 // ISO-8601, week belongs to year that has the most days of the week (i.e. has the thursday of the week) 598 var month = date.get('month'), 599 startOfWeek = date.get('date') - dayOfWeek; 600 601 if (month == 11 && startOfWeek > 28) return 1; // Week 1 of next year 602 603 if (month == 0 && startOfWeek < -2){ 604 // Use a date from last year to determine the week 605 date = new Date(date).decrement('day', dayOfWeek); 606 dayOfWeek = 0; 607 } 608 609 firstDayOfYear = new Date(date.get('year'), 0, 1).get('day') || 7; 610 if (firstDayOfYear > 4) dividend = -7; // First week of the year is not week 1 611 } else { 612 // In other cultures the first week of the year is always week 1 and the last week always 53 or 54. 613 // Days in the same week can have a different weeknumber if the week spreads across two years. 614 firstDayOfYear = new Date(date.get('year'), 0, 1).get('day'); 615 } 616 617 dividend += date.get('dayofyear'); 618 dividend += 6 - dayOfWeek; // Add days so we calculate the current date's week as a full week 619 dividend += (7 + firstDayOfYear - firstDayOfWeek) % 7; // Make up for first week of the year not being a full week 620 621 return (dividend / 7); 622 }, 623 624 getOrdinal: function(day){ 625 return Date.getMsg('ordinal', day || this.get('date')); 626 }, 627 628 getTimezone: function(){ 629 return this.toString() 630 .replace(/^.*? ([A-Z]{3}).[0-9]{4}.*$/, '$1') 631 .replace(/^.*?\(([A-Z])[a-z]+ ([A-Z])[a-z]+ ([A-Z])[a-z]+\)$/, '$1$2$3'); 632 }, 633 634 getGMTOffset: function(){ 635 var off = this.get('timezoneOffset'); 636 return ((off > 0) ? '-' : '+') + pad((off.abs() / 60).floor(), 2) + pad(off % 60, 2); 637 }, 638 639 setAMPM: function(ampm){ 640 ampm = ampm.toUpperCase(); 641 var hr = this.get('hr'); 642 if (hr >
642 11 && ampm == 'AM') return this.decrement('hour', 12); 643 else if (hr < 12 && ampm == 'PM') return this.increment('hour', 12); 644 return this; 645 }, 646 647 getAMPM: function(){ 648 return (this.get('hr') < 12) ? 'AM' : 'PM'; 649 }, 650 651 parse: function(str){ 652 this.set('time', Date.parse(str)); 653 return this; 654 }, 655 656 isValid: function(date){ 657 if (!date) date = this; 658 return typeOf(date) == 'date' && !isNaN(date.valueOf()); 659 }, 660 661 format: function(format){ 662 if (!this.isValid()) return 'invalid date'; 663 664 if (!format) format = '%x %X'; 665 if (typeof format == 'string') format = formats[format.toLowerCase()] || format; 666 if (typeof format == 'function') return format(this); 667 668 var d = this; 669 return format.replace(/%([a-z%])/gi, 670 function($0, $1){ 671 switch ($1){ 672 case 'a': return Date.getMsg('days_abbr')[d.get('day')]; 673 case 'A': return Date.getMsg('days')[d.get('day')]; 674 case 'b': return Date.getMsg('months_abbr')[d.get('month')]; 675 case 'B': return Date.getMsg('months')[d.get('month')]; 676 case 'c': return d.format('%a %b %d %H:%M:%S %Y'); 677 case 'd': return pad(d.get('date'), 2); 678 case 'e': return pad(d.get('date'), 2, ' '); 679 case 'H': return pad(d.get('hr'), 2); 680 case 'I': return pad((d.get('hr') % 12) || 12, 2); 681 case 'j': return pad(d.get('dayofyear'), 3); 682 case 'k': return pad(d.get('hr'), 2, ' '); 683 case 'l': return pad((d.get('hr') % 12) || 12, 2, ' '); 684 case 'L': return pad(d.get('ms'), 3); 685 case 'm': return pad((d.get('mo') + 1), 2); 686 case 'M': return pad(d.get('min'), 2); 687 case 'o': return d.get('ordinal'); 688 case 'p': return Date.getMsg(d.get('ampm')); 689 case 's': return Math.round(d / 1000); 690 case 'S': return pad(d.get('seconds'), 2); 691 case 'T': return d.format('%H:%M:%S'); 692 case 'U': return pad(d.get('week'), 2); 693 case 'w': return d.get('day'); 694 case 'x': return d.format(Date.getMsg('shortDate')); 695 case 'X': return d.format(Date.getMsg('shortTime')); 696 case 'y': return d.get('year').toString().substr(2); 697 case 'Y': return d.get('year'); 698 case 'z': return d.get('GMTOffset'); 699 case 'Z': return d.get('Timezone'); 700 } 701 return $1; 702 } 703 ); 704 }, 705 706 toISOString: function(){ 707 return this.format('iso8601'); 708 } 709 710}).alias({ 711 toJSON: 'toISOString', 712 compare: 'diff', 713 strftime: 'format' 714}); 715 716// The day and month abbreviations are standardized, so we cannot use simply %a and %b because they will get localized 717var rfcDayAbbr = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], 718 rfcMonthAbbr = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; 719 720var formats = { 721 db: '%Y-%m-%d %H:%M:%S', 722 compact: '%Y%m%dT%H%M%S', 723 'short': '%d %b %H:%M', 724 'long': '%B %d, %Y %H:%M', 725 rfc822: function(date){ 726 return rfcDayAbbr[date.get('day')] + date.format(', %d ') + rfcMonthAbbr[date.get('month')] + date.format(' %Y %H:%M:%S %Z'); 727 }, 728 rfc2822: function(date){ 729 return rfcDayAbbr[date.get('day')] + date.format(', %d ') + rfcMonthAbbr[date.get('month')] + date.format(' %Y %H:%M:%S %z'); 730 }, 731 iso8601: function(date){ 732 return ( 733 date.getUTCFullYear() + '-' + 734 pad(date.getUTCMonth() + 1, 2) + '-' + 735 pad(date.getUTCDate(), 2) + 'T' + 736 pad(date.getUTCHours(), 2) + ':' + 737 pad(date.getUTCMinutes(), 2) + ':' + 738 pad(date.getUTCSeconds(), 2) + '.' + 739 pad(date.getUTCMilliseconds(), 3) + 'Z' 740 ); 741 } 742}; 743 744var parsePatterns = [], 745 nativeParse = Date.parse; 746 747var parseWord = function(type, word, num){ 748 var ret = -1, 749 translated = Date.getMsg(type + 's'); 750 switch (typeOf(word)){ 751 case 'object': 752 ret = translated[word.get(type)]; 753 break; 754 case 'number': 755 ret = translated[word]; 756 if (!ret) throw new Error('Invalid ' + type + ' index: ' + word); 757 break; 758 case 'string': 759 var match = translated.filter(function(name){ 760 return this.test(name); 761 }, new RegExp('^' + word, 'i')); 762 if (!match.length) throw new Error('Invalid ' + type + ' string'); 763 if (match.length > 1) throw new Error('Ambiguous ' + type); 764 ret = match[0]; 765 } 766 767 return (num) ? translated.indexOf(ret) : ret; 768}; 769 770var startCentury = 1900, 771 startYear = 70; 772 773Date.extend({ 774 775 getMsg: function(key, args){ 776 return Locale.get('Date.' + key, args); 777 }, 778 779 units: { 780 ms: Function.from(1), 781 second: Function.from(1000), 782 minute: Function.from(60000), 783 hour: Function.from(3600000), 784 day: Function.from(86400000), 785 week: Function.from(608400000), 786 month: function(month, year){ 787 var d = new Date; 788 return Date.daysInMonth(month != null ? month : d.get('mo'), year != null ? year : d.get('year')) * 86400000; 789 }, 790 year: function(year){
791 year = year || new Date().get('year'); 792 return Date.isLeapYear(year) ? 31622400000 : 31536000000; 793 } 794 }, 795 796 daysInMonth: function(month, year){ 797 return [31, Date.isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]; 798 }, 799 800 isLeapYear: function(year){ 801 return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0); 802 }, 803 804 parse: function(from){ 805 var t = typeOf(from); 806 if (t == 'number') return new Date(from); 807 if (t != 'string') return from; 808 from = from.clean(); 809 if (!from.length) return null; 810 811 var parsed; 812 parsePatterns.some(function(pattern){ 813 var bits = pattern.re.exec(from); 814 return (bits) ? (parsed = pattern.handler(bits)) : false; 815 }); 816 817 if (!(parsed && parsed.isValid())){ 818 parsed = new Date(nativeParse(from)); 819 if (!(parsed && parsed.isValid())) parsed = new Date(from.toInt()); 820 } 821 return parsed; 822 }, 823 824 parseDay: function(day, num){ 825 return parseWord('day', day, num); 826 }, 827 828 parseMonth: function(month, num){ 829 return parseWord('month', month, num); 830 }, 831 832 parseUTC: function(value){ 833 var localDate = new Date(value); 834 var utcSeconds = Date.UTC( 835 localDate.get('year'), 836 localDate.get('mo'), 837 localDate.get('date'), 838 localDate.get('hr'), 839 localDate.get('min'), 840 localDate.get('sec'), 841 localDate.get('ms') 842 ); 843 return new Date(utcSeconds); 844 }, 845 846 orderIndex: function(unit){ 847 return Date.getMsg('dateOrder').indexOf(unit) + 1; 848 }, 849 850 defineFormat: function(name, format){ 851 formats[name] = format; 852 return this; 853 }, 854 855 //<1.2compat> 856 parsePatterns: parsePatterns, 857 //</1.2compat> 858 859 defineParser: function(pattern){ 860 parsePatterns.push((pattern.re && pattern.handler) ? pattern : build(pattern)); 861 return this; 862 }, 863 864 defineParsers: function(){ 865 Array.flatten(arguments).each(Date.defineParser); 866 return this; 867 }, 868 869 define2DigitYearStart: function(year){ 870 startYear = year % 100; 871 startCentury = year - startYear; 872 return this; 873 } 874 875}).extend({ 876 defineFormats: Date.defineFormat.overloadSetter() 877}); 878 879var regexOf = function(type){ 880 return new RegExp('(?:' + Date.getMsg(type).map(function(name){ 881 return name.substr(0, 3); 882 }).join('|') + ')[a-z]*'); 883}; 884 885var replacers = function(key){ 886 switch (key){ 887 case 'T': 888 return '%H:%M:%S'; 889 case 'x': // iso8601 covers yyyy-mm-dd, so just check if month is first 890 return ((Date.orderIndex('month') == 1) ? '%m[-./]%d' : '%d[-./]%m') + '([-./]%y)?'; 891 case 'X': 892 return '%H([.:]%M)?([.:]%S([.:]%s)?)? ?%p? ?%z?'; 893 } 894 return null; 895}; 896 897var keys = { 898 d: /[0-2]?[0-9]|3[01]/, 899 H: /[01]?[0-9]|2[0-3]/, 900 I: /0?[1-9]|1[0-2]/, 901 M: /[0-5]?\d/, 902 s: /\d+/, 903 o: /[a-z]*/, 904 p: /[ap]\.?m\.?/, 905 y: /\d{2}|\d{4}/, 906 Y: /\d{4}/, 907 z: /Z|[+-]\d{2}(?::?\d{2})?/ 908}; 909 910keys.m = keys.I; 911keys.S = keys.M; 912 913var currentLanguage; 914 915var recompile = function(language){ 916 currentLanguage = language; 917 918 keys.a = keys.A = regexOf('days'); 919 keys.b = keys.B = regexOf('months'); 920 921 parsePatterns.each(function(pattern, i){ 922 if (pattern.format) parsePatterns[i] = build(pattern.format); 923 }); 924}; 925 926var build = function(format){ 927 if (!currentLanguage) return {format: format}; 928 929 var parsed = []; 930 var re = (format.source || format) // allow format to be regex 931 .replace(/%([a-z])/gi, 932 function($0, $1){ 933 return replacers($1) || $0; 934 } 935 ).replace(/\((?!\?)/g, '(?:') // make all groups non-capturing 936 .replace(/ (?!\?|\*)/g, ',? ') // be forgiving with spaces and commas 937 .replace(/%([a-z%])/gi, 938 function($0, $1){ 939 var p = keys[$1]; 940 if (!p) return $1; 941 parsed.push($1); 942 return '(' + p.source + ')'; 943 } 944 ).replace(/\[a-z\]/gi, '[a-z\\u00c0-\\uffff;\&]'); // handle unicode words 945 946 return { 947 format: format, 948 re: new RegExp('^' + re + '$', 'i'), 949 handler: function(bits){ 950 bits = bits.slice(1).associate(parsed); 951 var date = new Date().clearTime(), 952 year = bits.y || bits.Y; 953 954 if (year != null) handle.call(date, 'y', year); // need to start in the right year 955 if ('d' in bits) handle.call(date, 'd', 1); 956 if ('m' in bits || bits.b || bits.B) handle.call(date, 'm', 1); 957 958 for (var key in bits) handle.call(date, key, bits[key]); 959 return date; 960 } 961 }; 962}; 963 964var handle = function(key, value){ 965 if (!value) return this; 966 967 switch (key){ 968 case 'a': case 'A': return this.set('day', Date.parseDay(value, true)); 969 case 'b': case 'B': return this.set('mo', Date.parseMonth(value, true)); 970 case 'd': return this.set('date', value); 971 case 'H': case 'I': return this.set('hr', value); 972 case 'm': return this.set('mo', value - 1); 973 case 'M': return this.set('min', value); 974 case 'p': return this.set('ampm', value.replace(/\./g, '')); 975 case 'S': return this.set('sec', value); 976 case 's': return this.set('ms', ('0.' + value) * 1000); 977 case 'w': return this.set('day', value); 978 case 'Y': return this.set('year', value); 979 case 'y': 980 value = +value; 981 if (value < 100) value += startCentury + (value < startYear ? 100 : 0); 982 return this.set('year', value); 983 case 'z': 984 if (value == 'Z') value = '+00'; 985 var offset = value.match(/([+-])(\d{2}):?(\d{2})?/); 986 offset = (offset[1] + '1') * (offset[2] * 60 + (+offset[3] || 0)) + this.getTimezoneOffset(); 987 return this.set('time', this - offset * 60000); 988 } 989 990 return this; 991}; 992 993Date.defineParsers( 994 '%Y([-./]%m([-./]%d((T| )%X)?)?)?', // "1999-12-31", "1999-12-31 11:59pm", "1999-12-31 23:59:59", ISO8601 995 '%Y%m%d(T%H(%M%S?)?)?', // "19991231", "19991231T1159", compact 996 '%x( %X)?', // "12/31", "12.31.99", "12-31-1999", "12/31/2008 11:59 PM" 997 '%d%o( %b( %Y)?)?( %X)?', // "31st", "31st December", "31 Dec 1999", "31 Dec 1999 11:59pm" 998 '%b( %d%o)?( %Y)?( %X)?', // Same as above with month and day switched 999 '%Y %b( %d%o( %X)?)?', // Same as above with year coming first 1000 '%o %b %d %X %z %Y', // "Thu Oct 22 08:11:23 +0000 2009" 1001 '%T', // %H:%M:%S 1002 '%H:%M( ?%p)?' // "11:05pm", "11:05 am" and "11:05" 1003); 1004 1005Locale.addEvent('change', function(language){ 1006 if (Locale.get('Date')) recompile(language); 1007}).fireEvent('change', Locale.getCurrent()); 1008 1009})(); 1010 1011 1012/* 1013--- 1014 1015script: Date.Extras.js 1016 1017name: Date.Extras 1018 1019description: Extends the Date native object to include extra methods (on to
1019p of those in Date.js). 1020 1021license: MIT-style license 1022 1023authors: 1024 - Aaron Newton 1025 - Scott Kyle 1026 1027requires: 1028 - /Date 1029 1030provides: [Date.Extras] 1031 1032... 1033*/ 1034 1035Date.implement({ 1036 1037 timeDiffInWords: function(to){ 1038 return Date.distanceOfTimeInWords(this, to || new Date); 1039 }, 1040 1041 timeDiff: function(to, separator){ 1042 if (to == null) to = new Date; 1043 var delta = ((to - this) / 1000).floor().abs(); 1044 1045 var vals = [], 1046 durations = [60, 60, 24, 365, 0], 1047 names = ['s', 'm', 'h', 'd', 'y'], 1048 value, duration; 1049 1050 for (var item = 0; item < durations.length; item++){ 1051 if (item && !delta) break; 1052 value = delta; 1053 if ((duration = durations[item])){ 1054 value = (delta % duration); 1055 delta = (delta / duration).floor(); 1056 } 1057 vals.unshift(value + (names[item] || '')); 1058 } 1059 1060 return vals.join(separator || ':'); 1061 } 1062 1063}).extend({ 1064 1065 distanceOfTimeInWords: function(from, to){ 1066 return Date.getTimePhrase(((to - from) / 1000).toInt()); 1067 }, 1068 1069 getTimePhrase: function(delta){ 1070 var suffix = (delta < 0) ? 'Until' : 'Ago'; 1071 if (delta < 0) delta *= -1; 1072 1073 var units = { 1074 minute: 60, 1075 hour: 60, 1076 day: 24, 1077 week: 7, 1078 month: 52 / 12, 1079 year: 12, 1080 eon: Infinity 1081 }; 1082 1083 var msg = 'lessThanMinute'; 1084 1085 for (var unit in units){ 1086 var interval = units[unit]; 1087 if (delta < 1.5 * interval){ 1088 if (delta > 0.75 * interval) msg = unit; 1089 break; 1090 } 1091 delta /= interval; 1092 msg = unit + 's'; 1093 } 1094 1095 delta = delta.round(); 1096 return Date.getMsg(msg + suffix, delta).substitute({delta: delta}); 1097 } 1098 1099}).defineParsers( 1100 1101 { 1102 // "today", "tomorrow", "yesterday" 1103 re: /^(?:tod|tom|yes)/i, 1104 handler: function(bits){ 1105 var d = new Date().clearTime(); 1106 switch (bits[0]){ 1107 case 'tom': return d.increment(); 1108 case 'yes': return d.decrement(); 1109 default: return d; 1110 } 1111 } 1112 }, 1113 1114 { 1115 // "next Wednesday", "last Thursday" 1116 re: /^(next|last) ([a-z]+)$/i, 1117 handler: function(bits){ 1118 var d = new Date().clearTime(); 1119 var day = d.getDay(); 1120 var newDay = Date.parseDay(bits[2], true); 1121 var addDays = newDay - day; 1122 if (newDay <= day) addDays += 7; 1123 if (bits[1] == 'last') addDays -= 7; 1124 return d.set('date', d.getDate() + addDays); 1125 } 1126 } 1127 1128).alias('timeAgoInWords', 'timeDiffInWords'); 1129 1130 1131/* 1132--- 1133 1134script: String.Extras.js 1135 1136name: String.Extras 1137 1138description: Extends the String native object to include methods useful in managing various kinds of strings (query strings, urls, html, etc). 1139 1140license: MIT-style license 1141 1142authors: 1143 - Aaron Newton 1144 - Guillermo Rauch 1145 - Christopher Pitt 1146 1147requires: 1148 - Core/String 1149 - Core/Array 1150 - MooTools.More 1151 1152provides: [String.Extras] 1153 1154... 1155*/ 1156 1157(function(){ 1158 1159var special = { 1160 'a': /[à áâãäåÄÄ ]/g, 1161 'A': /[ÃÃÃÃÃà ÄÄ]/g, 1162 'c': /[ÄÄç]/g, 1163 'C': /[ÄÄÃ]/g, 1164 'd': /[ÄÄ]/g, 1165 'D': /[ÄÃ]/g, 1166 'e': /[èéêëÄÄ]/g, 1167 'E': /[ÃÃÃÃÄÄ]/g, 1168 'g': /[Ä]/g, 1169 'G': /[Ä]/g, 1170 'i': /[ìÃîï]/g, 1171 'I': /[ÃÃÃÃ]/g, 1172 'l': /[ĺľÅ]/g, 1173 'L': /[ĹĽÅ]/g, 1174 'n': /[ñÅÅ]/g, 1175 'N': /[ÃÅÅ]/g, 1176 'o': /[òóôõöøÅ]/g, 1177 'O': /[ÃÃÃÃÃÃ]/g, 1178 'r': /[ÅÅ]/g, 1179 'R': /[ÅÅ]/g, 1180 's': /[ššÅ]/g, 1181 'S': /[Å ÅÅ]/g, 1182 't': /[ťţ]/g, 1183 'T': /[ŤŢ]/g, 1184 'ue': /[ü]/g, 1185 'UE': /[Ã]/g, 1186 'u': /[ùúûůµ]/g, 1187 'U': /[ÃÃÃÅ®]/g, 1188 'y': /[ÿý]/g, 1189 'Y': /[ŸÃ]/g, 1190 'z': /[žźż]/g, 1191 'Z': /[ŽŹŻ]/g, 1192 'th': /[þ]/g, 1193 'TH': /[Ã]/g, 1194 'dh': /[ð]/g, 1195 'DH': /[Ã]/g, 1196 'ss': /[Ã]/g, 1197 'oe': /[Å]/g, 1198 'OE': /[Å]/g, 1199 'ae': /[æ]/g, 1200 'AE': /[Ã]/g 1201}, 1202 1203tidy = { 1204 ' ': /[\xa0\u2002\u2003\u2009]/g, 1205 '*': /[\xb7]/g, 1206 '\'': /[\u2018\u2019]/g, 1207 '"': /[\u201c\u201d]/g, 1208 '...': /[\u2026]/g, 1209 '-': /[\u2013]/g, 1210// '--': /[\u2014]/g, 1211 '»': /[\uFFFD]/g 1212}; 1213 1214var walk = function(string, replacements){ 1215 var result = string, key; 1216 for (key in replacements) result = result.replace(replacements[key], key); 1217 return result; 1218}; 1219 1220var getRegexForTag = function(tag, contents){ 1221 tag = tag || ''; 1222 var regstr = contents ? "<" + tag + "(?!\\w)[^>]*>([\\s\\S]*?)<\/" + tag + "(?!\\w)>" : "<\/?" + tag + "([^>]+)?>", 1223 reg = new RegExp(regstr, "gi"); 1224 return reg; 1225}; 1226 1227String.implement({ 1228 1229 standardize: function(){ 1230 return walk(this, special); 1231 }, 1232 1233 repeat: function(times){ 1234 return new Array(times + 1).join(this); 1235 }, 1236 1237 pad: function(length, str, direction){ 1238 if (this.length >= length) return this; 1239 1240 var pad = (str == null ? ' ' : '' + str) 1241 .repeat(length - this.length) 1242 .substr(0, length - this.length); 1243 1244 if (!direction || direction == 'right') return this + pad; 1245 if (direction == 'left') return pad + this; 1246 1247 return pad.substr(0, (pad.length / 2).floor()) + this + pad.substr(0, (pad.length / 2).ceil()); 1248 }, 1249 1250 getTags: function(tag, contents){ 1251 return this.match(getRegexForTag(tag, contents)) || []; 1252 }, 1253 1254 stripTags: function(tag, contents){ 1255 return this.replace(getRegexForTag(tag, contents), ''); 1256 }, 1257 1258 tidy: function(){ 1259 return walk(this, tidy); 1260 }, 1261 1262 truncate: function(max, trail, atChar){ 1263 var string = this; 1264 if (trail == null && arguments.length == 1) trail = 'â¦'; 1265 if (string.length > max){ 1266 string = string.substring(0, max); 1267 if (atChar){ 1268 var index = string.lastIndexOf(atChar); 1269 if (index != -1) string = string.substr(0, index); 1270 }
1271 if (trail) string += trail; 1272 } 1273 return string; 1274 } 1275 1276}); 1277 1278})(); 1279 1280 1281/* 1282--- 1283 1284script: String.QueryString.js 1285 1286name: String.QueryString 1287 1288description: Methods for dealing with URI query strings. 1289 1290license: MIT-style license 1291 1292authors: 1293 - Sebastian Markbåge 1294 - Aaron Newton 1295 - Lennart Pilon 1296 - Valerio Proietti 1297 1298requires: 1299 - Core/Array 1300 - Core/String 1301 - /MooTools.More 1302 1303provides: [String.QueryString] 1304 1305... 1306*/ 1307 1308String.implement({ 1309 1310 parseQueryString: function(decodeKeys, decodeValues){ 1311 if (decodeKeys == null) decodeKeys = true; 1312 if (decodeValues == null) decodeValues = true; 1313 1314 var vars = this.split(/[&;]/), 1315 object = {}; 1316 if (!vars.length) return object; 1317 1318 vars.each(function(val){ 1319 var index = val.indexOf('=') + 1, 1320 value = index ? val.substr(index) : '', 1321 keys = index ? val.substr(0, index - 1).match(/([^\]\[]+|(\B)(?=\]))/g) : [val], 1322 obj = object; 1323 if (!keys) return; 1324 if (decodeValues) value = decodeURIComponent(value); 1325 keys.each(function(key, i){ 1326 if (decodeKeys) key = decodeURIComponent(key); 1327 var current = obj[key]; 1328 1329 if (i < keys.length - 1) obj = obj[key] = current || {}; 1330 else if (typeOf(current) == 'array') current.push(value); 1331 else obj[key] = current != null ? [current, value] : value; 1332 }); 1333 }); 1334 1335 return object; 1336 }, 1337 1338 cleanQueryString: function(method){ 1339 return this.split('&').filter(function(val){ 1340 var index = val.indexOf('='), 1341 key = index < 0 ? '' : val.substr(0, index), 1342 value = val.substr(index + 1); 1343 1344 return method ? method.call(null, key, value) : (value || value === 0); 1345 }).join('&'); 1346 } 1347 1348}); 1349 1350 1351/* 1352--- 1353 1354name: Hash 1355 1356description: Contains Hash Prototypes. Provides a means for overcoming the JavaScript practical impossibility of extending native Objects. 1357 1358license: MIT-style license. 1359 1360requires: 1361 - Core/Object 1362 - /MooTools.More 1363 1364provides: [Hash] 1365 1366... 1367*/ 1368 1369(function(){ 1370 1371if (this.Hash) return; 1372 1373var Hash = this.Hash = new Type('Hash', function(object){ 1374 if (typeOf(object) == 'hash') object = Object.clone(object.getClean()); 1375 for (var key in object) this[key] = object[key]; 1376 return this; 1377}); 1378 1379this.$H = function(object){ 1380 return new Hash(object); 1381}; 1382 1383Hash.implement({ 1384 1385 forEach: function(fn, bind){ 1386 Object.forEach(this, fn, bind); 1387 }, 1388 1389 getClean: function(){ 1390 var clean = {}; 1391 for (var key in this){ 1392 if (this.hasOwnProperty(key)) clean[key] = this[key]; 1393 } 1394 return clean; 1395 }, 1396 1397 getLength: function(){ 1398 var length = 0; 1399 for (var key in this){ 1400 if (this.hasOwnProperty(key)) length++; 1401 } 1402 return length; 1403 } 1404 1405}); 1406 1407Hash.alias('each', 'forEach'); 1408 1409Hash.implement({ 1410 1411 has: Object.prototype.hasOwnProperty, 1412 1413 keyOf: function(value){ 1414 return Object.keyOf(this, value); 1415 }, 1416 1417 hasValue: function(value){ 1418 return Object.contains(this, value); 1419 }, 1420 1421 extend: function(properties){ 1422 Hash.each(properties || {}, function(value, key){ 1423 Hash.set(this, key, value); 1424 }, this); 1425 return this; 1426 }, 1427 1428 combine: function(properties){ 1429 Hash.each(properties || {}, function(value, key){ 1430 Hash.include(this, key, value); 1431 }, this); 1432 return this; 1433 }, 1434 1435 erase: function(key){ 1436 if (this.hasOwnProperty(key)) delete this[key]; 1437 return this; 1438 }, 1439 1440 get: function(key){ 1441 return (this.hasOwnProperty(key)) ? this[key] : null; 1442 }, 1443 1444 set: function(key, value){ 1445 if (!this[key] || this.hasOwnProperty(key)) this[key] = value; 1446 return this; 1447 }, 1448 1449 empty: function(){ 1450 Hash.each(this, function(value, key){ 1451 delete this[key]; 1452 }, this); 1453 return this; 1454 }, 1455 1456 include: function(key, value){ 1457 if (this[key] == undefined) this[key] = value; 1458 return this; 1459 }, 1460 1461 map: function(fn, bind){ 1462 return new Hash(Object.map(this, fn, bind)); 1463 }, 1464 1465 filter: function(fn, bind){ 1466 return new Hash(Object.filter(this, fn, bind)); 1467 }, 1468 1469 every: function(fn, bind){ 1470 return Object.every(this, fn, bind); 1471 }, 1472 1473 some: function(fn, bind){ 1474 return Object.some(this, fn, bind); 1475 }, 1476 1477 getKeys: function(){ 1478 return Object.keys(this); 1479 }, 1480 1481 getValues: function(){ 1482 return Object.values(this); 1483 }, 1484 1485 toQueryString: function(base){ 1486 return Object.toQueryString(this, base); 1487 } 1488 1489}); 1490 1491Hash.alias({indexOf: 'keyOf', contains: 'hasValue'}); 1492 1493 1494})(); 1495 1496 1497 1498/* 1499--- 1500 1501script: Hash.Extras.js 1502 1503name: Hash.Extras 1504 1505description: Extends the Hash Type to include getFromPath which allows a path notation to child elements. 1506 1507license: MIT-style license 1508 1509authors: 1510 - Aaron Newton 1511 1512requires: 1513 - /Hash 1514 - /Object.Extras 1515 1516provides: [Hash.Extras] 1517 1518... 1519*/ 1520 1521Hash.implement({ 1522 1523 getFromPath: function(notation){ 1524 return Object.getFromPath(this, notation); 1525 }, 1526 1527 cleanValues: function(method){ 1528 return new Hash(Object.cleanValues(this, method)); 1529 }, 1530 1531 run: function(){ 1532 Object.run(arguments); 1533 } 1534 1535}); 1536 1537 1538/* 1539--- 1540 1541script: Element.Forms.js 1542 1543name: Element.Forms 1544 1545description: Extends the Element native object to include methods useful in managing inputs. 1546 1547license: MIT-style license 1548 1549authors: 1550 - Aaron Newton 1551 1552requires: 1553 - Core/Element 1554 - /String.Extras
1555 - /MooTools.More 1556 1557provides: [Element.Forms] 1558 1559... 1560*/ 1561 1562Element.implement({ 1563 1564 tidy: function(){ 1565 this.set('value', this.get('value').tidy()); 1566 }, 1567 1568 getTextInRange: function(start, end){ 1569 return this.get('value').substring(start, end); 1570 }, 1571 1572 getSelectedText: function(){ 1573 if (this.setSelectionRange) return this.getTextInRange(this.getSelectionStart(), this.getSelectionEnd()); 1574 return document.selection.createRange().text; 1575 }, 1576 1577 getSelectedRange: function(){ 1578 if (this.selectionStart != null){ 1579 return { 1580 start: this.selectionStart, 1581 end: this.selectionEnd 1582 }; 1583 } 1584 1585 var pos = { 1586 start: 0, 1587 end: 0 1588 }; 1589 var range = this.getDocument().selection.createRange(); 1590 if (!range || range.parentElement() != this) return pos; 1591 var duplicate = range.duplicate(); 1592 1593 if (this.type == 'text'){ 1594 pos.start = 0 - duplicate.moveStart('character', -100000); 1595 pos.end = pos.start + range.text.length; 1596 } else { 1597 var value = this.get('value'); 1598 var offset = value.length; 1599 duplicate.moveToElementText(this); 1600 duplicate.setEndPoint('StartToEnd', range); 1601 if (duplicate.text.length) offset -= value.match(/[\n\r]*$/)[0].length; 1602 pos.end = offset - duplicate.text.length; 1603 duplicate.setEndPoint('StartToStart', range); 1604 pos.start = offset - duplicate.text.length; 1605 } 1606 return pos; 1607 }, 1608 1609 getSelectionStart: function(){ 1610 return this.getSelectedRange().start; 1611 }, 1612 1613 getSelectionEnd: function(){ 1614 return this.getSelectedRange().end; 1615 }, 1616 1617 setCaretPosition: function(pos){ 1618 if (pos == 'end') pos = this.get('value').length; 1619 this.selectRange(pos, pos); 1620 return this; 1621 }, 1622 1623 getCaretPosition: function(){ 1624 return this.getSelectedRange().start; 1625 }, 1626 1627 selectRange: function(start, end){ 1628 if (this.setSelectionRange){ 1629 this.focus(); 1630 this.setSelectionRange(start, end); 1631 } else { 1632 var value = this.get('value'); 1633 var diff = value.substr(start, end - start).replace(/\r/g, '').length; 1634 start = value.substr(0, start).replace(/\r/g, '').length; 1635 var range = this.createTextRange(); 1636 range.collapse(true); 1637 range.moveEnd('character', start + diff); 1638 range.moveStart('character', start); 1639 range.select(); 1640 } 1641 return this; 1642 }, 1643 1644 insertAtCursor: function(value, select){ 1645 var pos = this.getSelectedRange(); 1646 var text = this.get('value'); 1647 this.set('value', text.substring(0, pos.start) + value + text.substring(pos.end, text.length)); 1648 if (select !== false) this.selectRange(pos.start, pos.start + value.length); 1649 else this.setCaretPosition(pos.start + value.length); 1650 return this; 1651 }, 1652 1653 insertAroundCursor: function(options, select){ 1654 options = Object.append({ 1655 before: '', 1656 defaultMiddle: '', 1657 after: '' 1658 }, options); 1659 1660 var value = this.getSelectedText() || options.defaultMiddle; 1661 var pos = this.getSelectedRange(); 1662 var text = this.get('value'); 1663 1664 if (pos.start == pos.end){ 1665 this.set('value', text.substring(0, pos.start) + options.before + value + options.after + text.substring(pos.end, text.length)); 1666 this.selectRange(pos.start + options.before.length, pos.end + options.before.length + value.length); 1667 } else { 1668 var current = text.substring(pos.start, pos.end); 1669 this.set('value', text.substring(0, pos.start) + options.before + current + options.after + text.substring(pos.end, text.length)); 1670 var selStart = pos.start + options.before.length; 1671 if (select !== false) this.selectRange(selStart, selStart + current.length); 1672 else this.setCaretPosition(selStart + text.length); 1673 } 1674 return this; 1675 } 1676 1677}); 1678 1679 1680/* 1681--- 1682 1683script: Elements.From.js 1684 1685name: Elements.From 1686 1687description: Returns a collection of elements from a string of html. 1688 1689license: MIT-style license 1690 1691authors: 1692 - Aaron Newton 1693 1694requires: 1695 - Core/String 1696 - Core/Element 1697 - /MooTools.More 1698 1699provides: [Elements.from, Elements.From] 1700 1701... 1702*/ 1703 1704Elements.from = function(text, excludeScripts){ 1705 if (excludeScripts || excludeScripts == null) text = text.stripScripts(); 1706 1707 var container, match = text.match(/^\s*<(t[dhr]|tbody|tfoot|thead)/i); 1708 1709 if (match){ 1710 container = new Element('table'); 1711 var tag = match[1].toLowerCase(); 1712 if (['td', 'th', 'tr'].contains(tag)){ 1713 container = new Element('tbody').inject(container); 1714 if (tag != 'tr') container = new Element('tr').inject(container); 1715 } 1716 } 1717 1718 return (container || new Element('div')).set('html', text).getChildren(); 1719}; 1720 1721 1722/* 1723--- 1724 1725name: Events.Pseudos 1726 1727description: Adds the functionality to add pseudo events 1728 1729license: MIT-style license 1730 1731authors: 1732 - Arian Stolwijk 1733 1734requires: [Core/Class.Extras, Core/Slick.Parser, More/MooTools.More] 1735 1736provides: [Events.Pseudos] 1737 1738... 1739*/ 1740 1741(function(){ 1742 1743Events.Pseudos = function(pseudos, addEvent, removeEvent){ 1744 1745 var storeKey = '_monitorEvents:'; 1746 1747 var storageOf = function(object){ 1748 return { 1749 store: object.store ? function(key, value){ 1750 object.store(storeKey + key, value); 1751 } : function(key, value){ 1752 (object._monitorEvents || (object._monitorEvents = {}))[key] = value; 1753 }, 1754 retrieve: object.retrieve ? function(key, dflt){ 1755 return object.retrieve(storeKey + key, dflt); 1756 } : function(key, dflt){ 1757 if (!object._monitorEvents) return dflt; 1758 return object._monitorEvents[key] || dflt; 1759 } 1760 }; 1761 }; 1762 1763 var splitType = function(type){ 1764 if (type.indexOf(':') == -1 || !pseudos) return null; 1765 1766 var parsed = Slick.parse(type).expressions[0][0], 1767 parsedPseudos = parsed.pseudos, 1768 l = parsedPseudos.length, 1769 splits = []; 1770 1771 while (l--){ 1772 var pseudo = parsedPseudos[l].key, 1773 listener = pseudos[pseudo]; 1774 if (listener != null) splits.push({ 1775 event: parsed.tag, 1776 value: parsedPseudos[l].value, 1777 pseudo: pseudo, 1778 original: type, 1779 listener: listener 1780 }); 1781 } 1782 return splits.length ? splits : null; 1783 }; 1784 1785 return { 1786 1787 addEvent: function(type, fn, internal){ 1788 var split = splitType(type); 1789 if (!split) return addEvent.call(this, type, fn, internal); 1790 1791 var storage = storageOf(this), 1792 events = storage.retrieve(type, []), 1793 eventType = split[0].event, 1794 args = Array.slice(arguments, 2), 1795 stack = fn, 1796 self = this; 1797 1798 split.each(function(item){ 1799 var listener = item.listener, 1800 stackFn = stack; 1801 if (listener == false) eventType += ':' + item.pseudo + '(' + item.value + ')'; 1802 else stack = function(){ 1803 listener.call(self, item, stackFn, arguments, stack); 1804 }; 1805 }); 1806 1807 events.include({type: eventType, event: fn, monitor: stack}); 1808 storage.store(type, events); 1809 1810 if (type != eventType) addEvent.apply(this, [type, fn].concat(args)); 1811 return addEvent.apply(this, [eventType, stack].concat(args)); 1812 }, 1813
1814 removeEvent: function(type, fn){ 1815 var split = splitType(type); 1816 if (!split) return removeEvent.call(this, type, fn); 1817 1818 var storage = storageOf(this), 1819 events = storage.retrieve(type); 1820 if (!events) return this; 1821 1822 var args = Array.slice(arguments, 2); 1823 1824 removeEvent.apply(this, [type, fn].concat(args)); 1825 events.each(function(monitor, i){ 1826 if (!fn || monitor.event == fn) removeEvent.apply(this, [monitor.type, monitor.monitor].concat(args)); 1827 delete events[i]; 1828 }, this); 1829 1830 storage.store(type, events); 1831 return this; 1832 } 1833 1834 }; 1835 1836}; 1837 1838var pseudos = { 1839 1840 once: function(split, fn, args, monitor){ 1841 fn.apply(this, args); 1842 this.removeEvent(split.event, monitor) 1843 .removeEvent(split.original, fn); 1844 }, 1845 1846 throttle: function(split, fn, args){ 1847 if (!fn._throttled){ 1848 fn.apply(this, args); 1849 fn._throttled = setTimeout(function(){ 1850 fn._throttled = false; 1851 }, split.value || 250); 1852 } 1853 }, 1854 1855 pause: function(split, fn, args){ 1856 clearTimeout(fn._pause); 1857 fn._pause = fn.delay(split.value || 250, this, args); 1858 } 1859 1860}; 1861 1862Events.definePseudo = function(key, listener){ 1863 pseudos[key] = listener; 1864 return this; 1865}; 1866 1867Events.lookupPseudo = function(key){ 1868 return pseudos[key]; 1869}; 1870 1871var proto = Events.prototype; 1872Events.implement(Events.Pseudos(pseudos, proto.addEvent, proto.removeEvent)); 1873 1874['Request', 'Fx'].each(function(klass){ 1875 if (this[klass]) this[klass].implement(Events.prototype); 1876}); 1877 1878})(); 1879 1880 1881/* 1882--- 1883 1884name: Element.Event.Pseudos 1885 1886description: Adds the functionality to add pseudo events for Elements 1887 1888license: MIT-style license 1889 1890authors: 1891 - Arian Stolwijk 1892 1893requires: [Core/Element.Event, Core/Element.Delegation, Events.Pseudos] 1894 1895provides: [Element.Event.Pseudos, Element.Delegation] 1896 1897... 1898*/ 1899 1900(function(){ 1901 1902var pseudos = {relay: false}, 1903 copyFromEvents = ['once', 'throttle', 'pause'], 1904 count = copyFromEvents.length; 1905 1906while (count--) pseudos[copyFromEvents[count]] = Events.lookupPseudo(copyFromEvents[count]); 1907 1908DOMEvent.definePseudo = function(key, listener){ 1909 pseudos[key] = listener; 1910 return this; 1911}; 1912 1913var proto = Element.prototype; 1914[Element, Window, Document].invoke('implement', Events.Pseudos(pseudos, proto.addEvent, proto.removeEvent)); 1915 1916})(); 1917 1918 1919/* 1920--- 1921 1922name: Element.Event.Pseudos.Keys 1923 1924description: Adds functionality fire events if certain keycombinations are pressed 1925 1926license: MIT-style license 1927 1928authors: 1929 - Arian Stolwijk 1930 1931requires: [Element.Event.Pseudos] 1932 1933provides: [Element.Event.Pseudos.Keys] 1934 1935... 1936*/ 1937 1938(function(){ 1939 1940var keysStoreKey = '$moo:keys-pressed', 1941 keysKeyupStoreKey = '$moo:keys-keyup'; 1942 1943 1944DOMEvent.definePseudo('keys', function(split, fn, args){ 1945 1946 var event = args[0], 1947 keys = [], 1948 pressed = this.retrieve(keysStoreKey, []); 1949 1950 keys.append(split.value.replace('++', function(){ 1951 keys.push('+'); // shift++ and shift+++a 1952 return ''; 1953 }).split('+')); 1954 1955 pressed.include(event.key); 1956 1957 if (keys.every(function(key){ 1958 return pressed.contains(key); 1959 })) fn.apply(this, args); 1960 1961 this.store(keysStoreKey, pressed); 1962 1963 if (!this.retrieve(keysKeyupStoreKey)){ 1964 var keyup = function(event){ 1965 (function(){ 1966 pressed = this.retrieve(keysStoreKey, []).erase(event.key); 1967 this.store(keysStoreKey, pressed); 1968 }).delay(0, this); // Fix for IE 1969 }; 1970 this.store(keysKeyupStoreKey, keyup).addEvent('keyup', keyup); 1971 } 1972 1973}); 1974 1975DOMEvent.defineKeys({ 1976 '16': 'shift', 1977 '17': 'control', 1978 '18': 'alt', 1979 '20': 'capslock', 1980 '33': 'pageup', 1981 '34': 'pagedown', 1982 '35': 'end', 1983 '36': 'home', 1984 '144': 'numlock', 1985 '145': 'scrolllock', 1986 '186': ';', 1987 '187': '=', 1988 '188': ',', 1989 '190': '.', 1990 '191': '/', 1991 '192': '`', 1992 '219': '[', 1993 '220': '\\', 1994 '221': ']', 1995 '222': "'", 1996 '107': '+' 1997}).defineKey(Browser.firefox ? 109 : 189, '-'); 1998 1999})(); 2000 2001 2002/* 2003--- 2004 2005script: Element.Measure.js 2006 2007name: Element.Measure 2008 2009description: Extends the Element native object to include methods useful in measuring dimensions. 2010 2011credits: "Element.measure / .expose methods by Daniel Steigerwald License: MIT-style license. Copyright: Copyright (c) 2008 Daniel Steigerwald, daniel.steigerwald.cz" 2012 2013license: MIT-style license 2014 2015authors: 2016 - Aaron Newton 2017 2018requires: 2019 - Core/Element.Style 2020 - Core/Element.Dimensions
2021 - /MooTools.More 2022 2023provides: [Element.Measure] 2024 2025... 2026*/ 2027 2028(function(){ 2029 2030var getStylesList = function(styles, planes){ 2031 var list = []; 2032 Object.each(planes, function(directions){ 2033 Object.each(directions, function(edge){ 2034 styles.each(function(style){ 2035 list.push(style + '-' + edge + (style == 'border' ? '-width' : '')); 2036 }); 2037 }); 2038 }); 2039 return list; 2040}; 2041 2042var calculateEdgeSize = function(edge, styles){ 2043 var total = 0; 2044 Object.each(styles, function(value, style){ 2045 if (style.test(edge)) total = total + value.toInt(); 2046 }); 2047 return total; 2048}; 2049 2050var isVisible = function(el){ 2051 return !!(!el || el.offsetHeight || el.offsetWidth); 2052}; 2053 2054 2055Element.implement({ 2056 2057 measure: function(fn){ 2058 if (isVisible(this)) return fn.call(this); 2059 var parent = this.getParent(), 2060 toMeasure = []; 2061 while (!isVisible(parent) && parent != document.body){ 2062 toMeasure.push(parent.expose()); 2063 parent = parent.getParent(); 2064 } 2065 var restore = this.expose(), 2066 result = fn.call(this); 2067 restore(); 2068 toMeasure.each(function(restore){ 2069 restore(); 2070 }); 2071 return result; 2072 }, 2073 2074 expose: function(){ 2075 if (this.getStyle('display') != 'none') return function(){}; 2076 var before = this.style.cssText; 2077 this.setStyles({ 2078 display: 'block', 2079 position: 'absolute', 2080 visibility: 'hidden' 2081 }); 2082 return function(){ 2083 this.style.cssText = before; 2084 }.bind(this); 2085 }, 2086 2087 getDimensions: function(options){ 2088 options = Object.merge({computeSize: false}, options); 2089 var dim = {x: 0, y: 0}; 2090 2091 var getSize = function(el, options){ 2092 return (options.computeSize) ? el.getComputedSize(options) : el.getSize(); 2093 }; 2094 2095 var parent = this.getParent('body'); 2096 2097 if (parent && this.getStyle('display') == 'none'){ 2098 dim = this.measure(function(){ 2099 return getSize(this, options); 2100 }); 2101 } else if (parent){ 2102 try { //safari sometimes crashes here, so catch it 2103 dim = getSize(this, options); 2104 }catch(e){} 2105 } 2106 2107 return Object.append(dim, (dim.x || dim.x === 0) ? { 2108 width: dim.x, 2109 height: dim.y 2110 } : { 2111 x: dim.width, 2112 y: dim.height 2113 } 2114 ); 2115 }, 2116 2117 getComputedSize: function(options){ 2118 //<1.2compat> 2119 //legacy support for my stupid spelling error 2120 if (options && options.plains) options.planes = options.plains; 2121 //</1.2compat> 2122 2123 options = Object.merge({ 2124 styles: ['padding','border'], 2125 planes: { 2126 height: ['top','bottom'], 2127 width: ['left','right'] 2128 }, 2129 mode: 'both' 2130 }, options); 2131 2132 var styles = {}, 2133 size = {width: 0, height: 0}, 2134 dimensions; 2135 2136 if (options.mode == 'vertical'){ 2137 delete size.width; 2138 delete options.planes.width; 2139 } else if (options.mode == 'horizontal'){ 2140 delete size.height; 2141 delete options.planes.height; 2142 } 2143 2144 getStylesList(options.styles, options.planes).each(function(style){ 2145 styles[style] = this.getStyle(style).toInt(); 2146 }, this); 2147 2148 Object.each(options.planes, function(edges, plane){ 2149 2150 var capitalized = plane.capitalize(), 2151 style = this.getStyle(plane); 2152 2153 if (style == 'auto' && !dimensions) dimensions = this.getDimensions(); 2154 2155 style = styles[plane] = (style == 'auto') ? dimensions[plane] : style.toInt(); 2156 size['total' + capitalized] = style; 2157 2158 edges.each(function(edge){ 2159 var edgesize = calculateEdgeSize(edge, styles); 2160 size['computed' + edge.capitalize()] = edgesize; 2161 size['total' + capitalized] += edgesize; 2162 }); 2163 2164 }, this); 2165 2166 return Object.append(size, styles); 2167 } 2168 2169}); 2170 2171})(); 2172 2173 2174/* 2175--- 2176 2177script: Element.Pin.js 2178 2179name: Element.Pin 2180 2181description: Extends the Element native object to include the pin method useful for fixed positioning for elements. 2182 2183license: MIT-style license 2184 2185authors: 2186 - Aaron Newton 2187 2188requires: 2189 - Core/Element.Event 2190 - Core/Element.Dimensions 2191 - Core/Element.Style 2192 - /MooTools.More 2193 2194provides: [Element.Pin] 2195 2196... 2197*/ 2198 2199(function(){ 2200 var supportsPositionFixed = false, 2201 supportTested = false; 2202 2203 var testPositionFixed = function(){ 2204 var test = new Element('div').setStyles({ 2205 position: 'fixed', 2206 top: 0, 2207 right: 0 2208 }).inject(document.body); 2209 supportsPositionFixed = (test.offsetTop === 0); 2210 test.dispose(); 2211 supportTested = true; 2212 }; 2213 2214 Element.implement({ 2215 2216 pin: function(enable, forceScroll){ 2217 if (!supportTested) testPositionFixed(); 2218 if (this.getStyle('display') == 'none') return this; 2219 2220 var pinnedPosition, 2221 scroll = window.getScroll(), 2222 parent, 2223 scrollFixer; 2224 2225 if (enable !== false){ 2226 pinnedPosition = this.getPosition(supportsPositionFixed ? document.body : this.getOffsetParent()); 2227 if (!this.retrieve('pin:_pinned')){ 2228 var currentPosition = { 2229 top: pinnedPosition.y - scroll.y, 2230 left: pinnedPosition.x - scroll.x 2231 }; 2232 2233 if (supportsPositionFixed && !forceScroll){ 2234 this.setStyle('position', 'fixed').setStyles(currentPosition); 2235 } else { 2236 2237 parent = this.getOffsetParent(); 2238 var position = this.getPosition(parent),
2239 styles = this.getStyles('left', 'top'); 2240 2241 if (parent && styles.left == 'auto' || styles.top == 'auto') this.setPosition(position); 2242 if (this.getStyle('position') == 'static') this.setStyle('position', 'absolute'); 2243 2244 position = { 2245 x: styles.left.toInt() - scroll.x, 2246 y: styles.top.toInt() - scroll.y 2247 }; 2248 2249 scrollFixer = function(){ 2250 if (!this.retrieve('pin:_pinned')) return; 2251 var scroll = window.getScroll(); 2252 this.setStyles({ 2253 left: position.x + scroll.x, 2254 top: position.y + scroll.y 2255 }); 2256 }.bind(this); 2257 2258 this.store('pin:_scrollFixer', scrollFixer); 2259 window.addEvent('scroll', scrollFixer); 2260 } 2261 this.store('pin:_pinned', true); 2262 } 2263 2264 } else { 2265 if (!this.retrieve('pin:_pinned')) return this; 2266 2267 parent = this.getParent(); 2268 var offsetParent = (parent.getComputedStyle('position') != 'static' ? parent : parent.getOffsetParent()); 2269 2270 pinnedPosition = this.getPosition(offsetParent); 2271 2272 this.store('pin:_pinned', false); 2273 scrollFixer = this.retrieve('pin:_scrollFixer'); 2274 if (!scrollFixer){ 2275 this.setStyles({ 2276 position: 'absolute', 2277 top: pinnedPosition.y + scroll.y, 2278 left: pinnedPosition.x + scroll.x 2279 }); 2280 } else { 2281 this.store('pin:_scrollFixer', null); 2282 window.removeEvent('scroll', scrollFixer); 2283 } 2284 this.removeClass('isPinned'); 2285 } 2286 return this; 2287 }, 2288 2289 unpin: function(){ 2290 return this.pin(false); 2291 }, 2292 2293 togglePin: function(){ 2294 return this.pin(!this.retrieve('pin:_pinned')); 2295 } 2296 2297 }); 2298 2299//<1.2compat> 2300Element.alias('togglepin', 'togglePin'); 2301//</1.2compat> 2302 2303})(); 2304 2305 2306/* 2307--- 2308 2309script: Element.Position.js 2310 2311name: Element.Position 2312 2313description: Extends the Element native object to include methods useful positioning elements relative to others. 2314 2315license: MIT-style license 2316 2317authors: 2318 - Aaron Newton 2319 - Jacob Thornton 2320 2321requires: 2322 - Core/Options 2323 - Core/Element.Dimensions 2324 - Element.Measure 2325 2326provides: [Element.Position] 2327 2328... 2329*/ 2330 2331(function(original){ 2332 2333var local = Element.Position = { 2334 2335 options: {/* 2336 edge: false, 2337 returnPos: false, 2338 minimum: {x: 0, y: 0}, 2339 maximum: {x: 0, y: 0}, 2340 relFixedPosition: false, 2341 ignoreMargins: false, 2342 ignoreScroll: false, 2343 allowNegative: false,*/ 2344 relativeTo: document.body, 2345 position: { 2346 x: 'center', //left, center, right 2347 y: 'center' //top, center, bottom 2348 }, 2349 offset: {x: 0, y: 0} 2350 }, 2351 2352 getOptions: function(element, options){ 2353 options = Object.merge({}, local.options, options); 2354 local.setPositionOption(options); 2355 local.setEdgeOption(options); 2356 local.setOffsetOption(element, options); 2357 local.setDimensionsOption(element, options); 2358 return options; 2359 }, 2360 2361 setPositionOption: function(options){ 2362 options.position = local.getCoordinateFromValue(options.position); 2363 }, 2364 2365 setEdgeOption: function(options){ 2366 var edgeOption = local.getCoordinateFromValue(options.edge); 2367 options.edge = edgeOption ? edgeOption : 2368 (options.position.x == 'center' && options.position.y == 'center') ? {x: 'center', y: 'center'} : 2369 {x: 'left', y: 'top'}; 2370 }, 2371 2372 setOffsetOption: function(element, options){ 2373 var parentOffset = {x: 0, y: 0}, 2374 offsetParent = element.measure(function(){ 2375 return document.id(this.getOffsetParent()); 2376 }), 2377 parentScroll = offsetParent.getScroll(); 2378 2379 if (!offsetParent || offsetParent == element.getDocument().body) return; 2380 parentOffset = offsetParent.measure(function(){ 2381 var position = this.getPosition(); 2382 if (this.getStyle('position') == 'fixed'){ 2383 var scroll = window.getScroll(); 2384 position.x += scroll.x; 2385 position.y += scroll.y; 2386 } 2387 return position; 2388 }); 2389 2390 options.offset = { 2391 parentPositioned: offsetParent != document.id(options.relativeTo), 2392 x: options.offset.x - parentOffset.x + parentScroll.x, 2393 y: options.offset.y - parentOffset.y + parentScroll.y 2394 }; 2395 }, 2396 2397 setDimensionsOption: function(element, options){ 2398 options.dimensions = element.getDimensions({ 2399 computeSize: true, 2400 styles: ['padding', 'border', 'margin'] 2401 }); 2402 }, 2403 2404 getPosition: function(element, options){ 2405 var position = {}; 2406 options = local.getOptions(element, options); 2407 var relativeTo = document.id(options.relativeTo) || document.body; 2408 2409 local.setPositionCoordinates(options, position, relativeTo); 2410 if (options.edge) local.toEdge(position, options); 2411 2412 var offset = options.offset; 2413 position.left = ((position.x >= 0 || offset.parentPositioned || options.allowNegative) ? position.x : 0).toInt(); 2414 position.top = ((position.y >= 0 || offset.parentPositioned || options.allowNegative) ? position.y : 0).toInt(); 2415 2416 local.toMinMax(position, options); 2417 2418 if (options.relFixedPosition || relativeTo.getStyle('position') == 'fixed') local.toRelFixedPosition(relativeTo, position); 2419 if (options.ignoreScroll) local.toIgnoreScroll(relativeTo, position); 2420 if (options.ignoreMargins) local.toIgnoreMargins(position, options); 2421
2422 position.left = Math.ceil(position.left); 2423 position.top = Math.ceil(position.top); 2424 delete position.x; 2425 delete position.y; 2426 2427 return position; 2428 }, 2429 2430 setPositionCoordinates: function(options, position, relativeTo){ 2431 var offsetY = options.offset.y, 2432 offsetX = options.offset.x, 2433 calc = (relativeTo == document.body) ? window.getScroll() : relativeTo.getPosition(), 2434 top = calc.y, 2435 left = calc.x, 2436 winSize = window.getSize(); 2437 2438 switch(options.position.x){ 2439 case 'left': position.x = left + offsetX; break; 2440 case 'right': position.x = left + offsetX + relativeTo.offsetWidth; break; 2441 default: position.x = left + ((relativeTo == document.body ? winSize.x : relativeTo.offsetWidth) / 2) + offsetX; break; 2442 } 2443 2444 switch(options.position.y){ 2445 case 'top': position.y = top + offsetY; break; 2446 case 'bottom': position.y = top + offsetY + relativeTo.offsetHeight; break; 2447 default: position.y = top + ((relativeTo == document.body ? winSize.y : relativeTo.offsetHeight) / 2) + offsetY; break; 2448 } 2449 }, 2450 2451 toMinMax: function(position, options){ 2452 var xy = {left: 'x', top: 'y'}, value; 2453 ['minimum', 'maximum'].each(function(minmax){ 2454 ['left', 'top'].each(function(lr){ 2455 value = options[minmax] ? options[minmax][xy[lr]] : null; 2456 if (value != null && ((minmax == 'minimum') ? position[lr] < value : position[lr] > value)) position[lr] = value; 2457 }); 2458 }); 2459 }, 2460 2461 toRelFixedPosition: function(relativeTo, position){ 2462 var winScroll = window.getScroll(); 2463 position.top += winScroll.y; 2464 position.left += winScroll.x; 2465 }, 2466 2467 toIgnoreScroll: function(relativeTo, position){ 2468 var relScroll = relativeTo.getScroll(); 2469 position.top -= relScroll.y; 2470 position.left -= relScroll.x; 2471 }, 2472 2473 toIgnoreMargins: function(position, options){ 2474 position.left += options.edge.x == 'right' 2475 ? options.dimensions['margin-right'] 2476 : (options.edge.x != 'center' 2477 ? -options.dimensions['margin-left'] 2478 : -options.dimensions['margin-left'] + ((options.dimensions['margin-right'] + options.dimensions['margin-left']) / 2)); 2479 2480 position.top += options.edge.y == 'bottom' 2481 ? options.dimensions['margin-bottom'] 2482 : (options.edge.y != 'center' 2483 ? -options.dimensions['margin-top'] 2484 : -options.dimensions['margin-top'] + ((options.dimensions['margin-bottom'] + options.dimensions['margin-top']) / 2)); 2485 }, 2486 2487 toEdge: function(position, options){ 2488 var edgeOffset = {}, 2489 dimensions = options.dimensions, 2490 edge = options.edge; 2491 2492 switch(edge.x){ 2493 case 'left': edgeOffset.x = 0; break; 2494 case 'right': edgeOffset.x = -dimensions.x - dimensions.computedRight - dimensions.computedLeft; break; 2495 // center 2496 default: edgeOffset.x = -(Math.round(dimensions.totalWidth / 2)); break; 2497 } 2498 2499 switch(edge.y){ 2500 case 'top': edgeOffset.y = 0; break; 2501 case 'bottom': edgeOffset.y = -dimensions.y - dimensions.computedTop - dimensions.computedBottom; break; 2502 // center 2503 default: edgeOffset.y = -(Math.round(dimensions.totalHeight / 2)); break; 2504 } 2505 2506 position.x += edgeOffset.x; 2507 position.y += edgeOffset.y; 2508 }, 2509 2510 getCoordinateFromValue: function(option){ 2511 if (typeOf(option) != 'string') return option; 2512 option = option.toLowerCase(); 2513 2514 return { 2515 x: option.test('left') ? 'left' 2516 : (option.test('right') ? 'right' : 'center'), 2517 y: option.test(/upper|top/) ? 'top' 2518 : (option.test('bottom') ? 'bottom' : 'center') 2519 }; 2520 } 2521 2522}; 2523 2524Element.implement({ 2525 2526 position: function(options){ 2527 if (options && (options.x != null || options.y != null)){ 2528 return (original ? original.apply(this, arguments) : this); 2529 } 2530 var position = this.setStyle('position', 'absolute').calculatePosition(options); 2531 return (options && options.returnPos) ? position : this.setStyles(position); 2532 }, 2533 2534 calculatePosition: function(options){ 2535 return local.getPosition(this, options); 2536 } 2537 2538}); 2539 2540})(Element.prototype.position); 2541 2542 2543/* 2544--- 2545 2546script: Element.Shortcuts.js 2547 2548name: Element.Shortcuts 2549 2550description: Extends the Element native object to include some shortcut methods. 2551 2552license: MIT-style license 2553 2554authors: 2555 - Aaron Newton 2556 2557requires: 2558 - Core/Element.Style 2559 - /MooTools.More 2560 2561provides: [Element.Shortcuts] 2562 2563... 2564*/ 2565 2566Element.implement({ 2567 2568 isDisplayed: function(){
2569 return this.getStyle('display') != 'none'; 2570 }, 2571 2572 isVisible: function(){ 2573 var w = this.offsetWidth, 2574 h = this.offsetHeight; 2575 return (w == 0 && h == 0) ? false : (w > 0 && h > 0) ? true : this.style.display != 'none'; 2576 }, 2577 2578 toggle: function(){ 2579 return this[this.isDisplayed() ? 'hide' : 'show'](); 2580 }, 2581 2582 hide: function(){ 2583 var d; 2584 try { 2585 //IE fails here if the element is not in the dom 2586 d = this.getStyle('display'); 2587 } catch(e){} 2588 if (d == 'none') return this; 2589 return this.store('element:_originalDisplay', d || '').setStyle('display', 'none'); 2590 }, 2591 2592 show: function(display){ 2593 if (!display && this.isDisplayed()) return this; 2594 display = display || this.retrieve('element:_originalDisplay') || 'block'; 2595 return this.setStyle('display', (display == 'none') ? 'block' : display); 2596 }, 2597 2598 swapClass: function(remove, add){ 2599 return this.removeClass(remove).addClass(add); 2600 } 2601 2602}); 2603 2604Document.implement({ 2605 2606 clearSelection: function(){ 2607 if (window.getSelection){ 2608 var selection = window.getSelection(); 2609 if (selection && selection.removeAllRanges) selection.removeAllRanges(); 2610 } else if (document.selection && document.selection.empty){ 2611 try { 2612 //IE fails here if selected element is not in dom 2613 document.selection.empty(); 2614 } catch(e){} 2615 } 2616 } 2617 2618}); 2619 2620 2621/* 2622--- 2623 2624script: Class.Binds.js 2625 2626name: Class.Binds 2627 2628description: Automagically binds specified methods in a class to the instance of the class. 2629 2630license: MIT-style license 2631 2632authors: 2633 - Aaron Newton 2634 2635requires: 2636 - Core/Class 2637 - /MooTools.More 2638 2639provides: [Class.Binds] 2640 2641... 2642*/ 2643 2644Class.Mutators.Binds = function(binds){ 2645 if (!this.prototype.initialize) this.implement('initialize', function(){}); 2646 return Array.from(binds).concat(this.prototype.Binds || []); 2647}; 2648 2649Class.Mutators.initialize = function(initialize){ 2650 return function(){ 2651 Array.from(this.Binds).each(function(name){ 2652 var original = this[name]; 2653 if (original) this[name] = original.bind(this); 2654 }, this); 2655 return initialize.apply(this, arguments); 2656 }; 2657}; 2658 2659 2660/* 2661--- 2662 2663script: Class.Occlude.js 2664 2665name: Class.Occlude 2666 2667description: Prevents a class from being applied to a DOM element twice. 2668 2669license: MIT-style license. 2670 2671authors: 2672 - Aaron Newton 2673 2674requires: 2675 - Core/Class 2676 - Core/Element 2677 - /MooTools.More 2678 2679provides: [Class.Occlude] 2680 2681... 2682*/ 2683 2684Class.Occlude = new Class({ 2685 2686 occlude: function(property, element){ 2687 element = document.id(element || this.element); 2688 var instance = element.retrieve(property || this.property); 2689 if (instance && !this.occluded) 2690 return (this.occluded = instance); 2691 2692 this.occluded = false; 2693 element.store(property || this.property, this); 2694 return this.occluded; 2695 } 2696 2697}); 2698 2699 2700/* 2701--- 2702 2703script: Class.Refactor.js 2704 2705name: Class.Refactor 2706 2707description: Extends a class onto itself with new property, preserving any items attached to the class's namespace. 2708 2709license: MIT-style license 2710 2711authors: 2712 - Aaron Newton 2713 2714requires: 2715 - Core/Class 2716 - /MooTools.More 2717 2718# Some modules declare themselves dependent on Class.Refactor 2719provides: [Class.refactor, Class.Refactor] 2720 2721... 2722*/ 2723 2724Class.refactor = function(original, refactors){ 2725 2726 Object.each(refactors, function(item, name){ 2727 var origin = original.prototype[name]; 2728 origin = (origin && origin.$origin) || origin || function(){}; 2729 original.implement(name, (typeof item == 'function') ? function(){ 2730 var old = this.previous; 2731 this.previous = origin; 2732 var value = item.apply(this, arguments); 2733 this.previous = old; 2734 return value; 2735 } : item); 2736 }); 2737 2738 return original; 2739 2740}; 2741 2742 2743/* 2744--- 2745 2746script: IframeShim.js 2747 2748name: IframeShim 2749 2750description: Defines IframeShim, a class for obscuring select lists and flash objects in IE. 2751 2752license: MIT-style license 2753 2754authors: 2755 - Aaron Newton 2756 2757requires: 2758 - Core/Element.Event 2759 - Core/Element.Style 2760 - Core/Options 2761 - Core/Events 2762 - /Element.Position 2763 - /Class.Occlude 2764 2765provides: [IframeShim] 2766 2767... 2768*/ 2769 2770var IframeShim = new Class({ 2771 2772 Implements: [Options, Events, Class.Occlude], 2773 2774 options: { 2775 className: 'iframeShim', 2776 src: 'javascript:false;document.write("");', 2777 display: false, 2778 zIndex: null, 2779 margin: 0, 2780 offset: {x: 0, y: 0}, 2781 browsers: (Browser.ie6 || (Browser.firefox && Browser.version < 3 && Browser.Platform.mac)) 2782 },
2783 2784 property: 'IframeShim', 2785 2786 initialize: function(element, options){ 2787 this.element = document.id(element); 2788 if (this.occlude()) return this.occluded; 2789 this.setOptions(options); 2790 this.makeShim(); 2791 return this; 2792 }, 2793 2794 makeShim: function(){ 2795 if (this.options.browsers){ 2796 var zIndex = this.element.getStyle('zIndex').toInt(); 2797 2798 if (!zIndex){ 2799 zIndex = 1; 2800 var pos = this.element.getStyle('position'); 2801 if (pos == 'static' || !pos) this.element.setStyle('position', 'relative'); 2802 this.element.setStyle('zIndex', zIndex); 2803 } 2804 zIndex = ((this.options.zIndex != null || this.options.zIndex === 0) && zIndex > this.options.zIndex) ? this.options.zIndex : zIndex - 1; 2805 if (zIndex < 0) zIndex = 1; 2806 this.shim = new Element('iframe', { 2807 src: this.options.src, 2808 scrolling: 'no', 2809 frameborder: 0, 2810 styles: { 2811 zIndex: zIndex, 2812 position: 'absolute', 2813 border: 'none', 2814 filter: 'progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)' 2815 }, 2816 'class': this.options.className 2817 }).store('IframeShim', this); 2818 var inject = (function(){ 2819 this.shim.inject(this.element, 'after'); 2820 this[this.options.display ? 'show' : 'hide'](); 2821 this.fireEvent('inject'); 2822 }).bind(this); 2823 if (!IframeShim.ready) window.addEvent('load', inject); 2824 else inject(); 2825 } else { 2826 this.position = this.hide = this.show = this.dispose = Function.from(this); 2827 } 2828 }, 2829 2830 position: function(){ 2831 if (!IframeShim.ready || !this.shim) return this; 2832 var size = this.element.measure(function(){ 2833 return this.getSize(); 2834 }); 2835 if (this.options.margin != undefined){ 2836 size.x = size.x - (this.options.margin * 2); 2837 size.y = size.y - (this.options.margin * 2); 2838 this.options.offset.x += this.options.margin; 2839 this.options.offset.y += this.options.margin; 2840 } 2841 this.shim.set({width: size.x, height: size.y}).position({ 2842 relativeTo: this.element, 2843 offset: this.options.offset 2844 }); 2845 return this; 2846 }, 2847 2848 hide: function(){ 2849 if (this.shim) this.shim.setStyle('display', 'none'); 2850 return this; 2851 }, 2852 2853 show: function(){ 2854 if (this.shim) this.shim.setStyle('display', 'block'); 2855 return this.position(); 2856 }, 2857 2858 dispose: function(){ 2859 if (this.shim) this.shim.dispose(); 2860 return this; 2861 }, 2862 2863 destroy: function(){ 2864 if (this.shim) this.shim.destroy(); 2865 return this; 2866 } 2867 2868}); 2869 2870window.addEvent('load', function(){ 2871 IframeShim.ready = true; 2872}); 2873 2874 2875/* 2876--- 2877 2878script: Mask.js 2879 2880name: Mask 2881 2882description: Creates a mask element to cover another. 2883 2884license: MIT-style license 2885 2886authors: 2887 - Aaron Newton 2888 2889requires: 2890 - Core/Options 2891 - Core/Events 2892 - Core/Element.Event 2893 - /Class.Binds 2894 - /Element.Position 2895 - /IframeShim 2896 2897provides: [Mask] 2898 2899... 2900*/ 2901 2902var Mask = new Class({ 2903 2904 Implements: [Options, Events], 2905 2906 Binds: ['position'], 2907 2908 options: {/* 2909 onShow: function(){}, 2910 onHide: function(){}, 2911 onDestroy: function(){}, 2912 onClick: function(event){}, 2913 inject: { 2914 where: 'after', 2915 target: null, 2916 }, 2917 hideOnClick: false, 2918 id: null, 2919 destroyOnHide: false,*/ 2920 style: {}, 2921 'class': 'mask', 2922 maskMargins: false, 2923 useIframeShim: true, 2924 iframeShimOptions: {} 2925 }, 2926 2927 initialize: function(target, options){ 2928 this.target = document.id(target) || document.id(document.body); 2929 this.target.store('mask', this); 2930 this.setOptions(options); 2931 this.render(); 2932 this.inject(); 2933 }, 2934 2935 render: function(){ 2936 this.element = new Element('div', { 2937 'class': this.options['class'], 2938 id: this.options.id || 'mask-' + String.uniqueID(), 2939 styles: Object.merge({}, this.options.style, { 2940 display: 'none' 2941 }), 2942 events: { 2943 click: function(event){ 2944 this.fireEvent('click', event); 2945 if (this.options.hideOnClick) this.hide(); 2946 }.bind(this) 2947 } 2948 }); 2949 2950 this.hidden = true; 2951 }, 2952 2953 toElement: function(){ 2954 return this.element; 2955 }, 2956 2957 inject: function(target, where){ 2958 where = where || (this.options.inject ? this.options.inject.where : '') || this.target == document.body ? 'inside' : 'after'; 2959 target = target || (this.options.inject && this.options.inject.target) || this.target; 2960 2961 this.element.inject(target, where); 2962 2963 if (this.options.useIframeShim){ 2964 this.shim = new IframeShim(this.element, this.options.iframeShimOptions); 2965 2966 this.addEvents({ 2967 show: this.shim.show.bind(this.shim), 2968 hide: this.shim.hide.bind(this.shim), 2969 destroy: this.shim.destroy.bind(this.shim) 2970 }); 2971 } 2972 }, 2973 2974 position: function(){ 2975 this.resize(this.options.width, this.options.height); 2976 2977 this.element.position({ 2978 relativeTo: this.target, 2979 position: 'topLeft', 2980 ignoreMargins: !this.options.maskMargins, 2981 ignoreScroll: this.target == document.body 2982 }); 2983 2984 return this; 2985 }, 2986 2987 resize: function(x, y){ 2988 var opt = { 2989 styles: ['padding', 'border'] 2990 }; 2991 if (this.options.maskMargins) opt.styles.push('margin'); 2992 2993 var dim = this.target.getComputedSize(opt); 2994 if (this.target == document.body){ 2995 this.element.setStyles({width: 0, height: 0}); 2996 var win = window.getScrollSize(); 2997 if (dim.totalHeight < win.y) dim.totalHeight = win.y; 2998 if (dim.totalWidth < win.x) dim.totalWidth = win.x; 2999 } 3000 this.element.setStyles({ 3001 width: Array.pick([x, dim.totalWidth, dim.x]), 3002 height: Array.pick([y, dim.totalHeight, dim.y]) 3003 }); 3004 3005 return this; 3006 }, 3007 3008 show: function(){ 3009 if (!this.hidden) return this; 3010 3011 window.addEvent('resize', this.position); 3012 this.position(); 3013 this.showMask.apply(this, arguments); 3014 3015 return this; 3016 }, 3017 3018 showMask: function(){ 3019 this.element.setStyle('display', 'block'); 3020 this.hidden = false;
3021 this.fireEvent('show'); 3022 }, 3023 3024 hide: function(){ 3025 if (this.hidden) return this; 3026 3027 window.removeEvent('resize', this.position); 3028 this.hideMask.apply(this, arguments); 3029 if (this.options.destroyOnHide) return this.destroy(); 3030 3031 return this; 3032 }, 3033 3034 hideMask: function(){ 3035 this.element.setStyle('display', 'none'); 3036 this.hidden = true; 3037 this.fireEvent('hide'); 3038 }, 3039 3040 toggle: function(){ 3041 this[this.hidden ? 'show' : 'hide'](); 3042 }, 3043 3044 destroy: function(){ 3045 this.hide(); 3046 this.element.destroy(); 3047 this.fireEvent('destroy'); 3048 this.target.eliminate('mask'); 3049 } 3050 3051}); 3052 3053Element.Properties.mask = { 3054 3055 set: function(options){ 3056 var mask = this.retrieve('mask'); 3057 if (mask) mask.destroy(); 3058 return this.eliminate('mask').store('mask:options', options); 3059 }, 3060 3061 get: function(){ 3062 var mask = this.retrieve('mask'); 3063 if (!mask){ 3064 mask = new Mask(this, this.retrieve('mask:options')); 3065 this.store('mask', mask); 3066 } 3067 return mask; 3068 } 3069 3070}; 3071 3072Element.implement({ 3073 3074 mask: function(options){ 3075 if (options) this.set('mask', options); 3076 this.get('mask').show(); 3077 return this; 3078 }, 3079 3080 unmask: function(){ 3081 this.get('mask').hide(); 3082 return this; 3083 } 3084 3085}); 3086 3087 3088/* 3089--- 3090 3091script: Spinner.js 3092 3093name: Spinner 3094 3095description: Adds a semi-transparent overlay over a dom element with a spinnin ajax icon. 3096 3097license: MIT-style license 3098 3099authors: 3100 - Aaron Newton 3101 3102requires: 3103 - Core/Fx.Tween 3104 - Core/Request 3105 - /Class.refactor 3106 - /Mask 3107 3108provides: [Spinner] 3109 3110... 3111*/ 3112 3113var Spinner = new Class({ 3114 3115 Extends: Mask, 3116 3117 Implements: Chain, 3118 3119 options: {/* 3120 message: false,*/ 3121 'class': 'spinner', 3122 containerPosition: {}, 3123 content: { 3124 'class': 'spinner-content' 3125 }, 3126 messageContainer: { 3127 'class': 'spinner-msg' 3128 }, 3129 img: { 3130 'class': 'spinner-img' 3131 }, 3132 fxOptions: { 3133 link: 'chain' 3134 } 3135 }, 3136 3137 initialize: function(target, options){ 3138 this.target = document.id(target) || document.id(document.body); 3139 this.target.store('spinner', this); 3140 this.setOptions(options); 3141 this.render(); 3142 this.inject(); 3143 3144 // Add this to events for when noFx is true; parent methods handle hide/show. 3145 var deactivate = function(){ this.active = false; }.bind(this); 3146 this.addEvents({ 3147 hide: deactivate, 3148 show: deactivate 3149 }); 3150 }, 3151 3152 render: function(){ 3153 this.parent(); 3154 3155 this.element.set('id', this.options.id || 'spinner-' + String.uniqueID()); 3156 3157 this.content = document.id(this.options.content) || new Element('div', this.options.content); 3158 this.content.inject(this.element); 3159 3160 if (this.options.message){ 3161 this.msg = document.id(this.options.message) || new Element('p', this.options.messageContainer).appendText(this.options.message); 3162 this.msg.inject(this.content); 3163 } 3164 3165 if (this.options.img){ 3166 this.img = document.id(this.options.img) || new Element('div', this.options.img); 3167 this.img.inject(this.content); 3168 } 3169 3170 this.element.set('tween', this.options.fxOptions); 3171 }, 3172 3173 show: function(noFx){ 3174 if (this.active) return this.chain(this.show.bind(this)); 3175 if (!this.hidden){ 3176 this.callChain.delay(20, this); 3177 return this; 3178 } 3179 3180 this.active = true; 3181 3182 return this.parent(noFx); 3183 }, 3184 3185 showMask: function(noFx){ 3186 var pos = function(){ 3187 this.content.position(Object.merge({ 3188 relativeTo: this.element 3189 }, this.options.containerPosition)); 3190 }.bind(this); 3191 3192 if (noFx){ 3193 this.parent(); 3194 pos(); 3195 } else { 3196 if (!this.options.style.opacity) this.options.style.opacity = this.element.getStyle('opacity').toFloat(); 3197 this.element.setStyles({ 3198 display: 'block', 3199 opacity: 0 3200 }).tween('opacity', this.options.style.opacity); 3201 pos(); 3202 this.hidden = false; 3203 this.fireEvent('show'); 3204 this.callChain(); 3205 } 3206 }, 3207 3208 hide: function(noFx){ 3209 if (this.active) return this.chain(this.hide.bind(this)); 3210 if (this.hidden){ 3211 this.callChain.delay(20, this); 3212 return this; 3213 } 3214 this.active = true; 3215 return this.parent(noFx); 3216 }, 3217 3218 hideMask: function(noFx){ 3219 if (noFx) return this.parent(); 3220 this.element.tween('opacity', 0).get('tween').chain(function(){ 3221 this.element.setStyle('display', 'none'); 3222 this.hidden = true; 3223 this.fireEvent('hide'); 3224 this.callChain(); 3225 }.bind(this)); 3226 }, 3227 3228 destroy: function(){ 3229 this.content.destroy(); 3230 this.parent(); 3231 this.target.eliminate('spinner'); 3232 } 3233 3234}); 3235
3236Request = Class.refactor(Request, { 3237 3238 options: { 3239 useSpinner: false, 3240 spinnerOptions: {}, 3241 spinnerTarget: false 3242 }, 3243 3244 initialize: function(options){ 3245 this._send = this.send; 3246 this.send = function(options){ 3247 var spinner = this.getSpinner(); 3248 if (spinner) spinner.chain(this._send.pass(options, this)).show(); 3249 else this._send(options); 3250 return this; 3251 }; 3252 this.previous(options); 3253 }, 3254 3255 getSpinner: function(){ 3256 if (!this.spinner){ 3257 var update = document.id(this.options.spinnerTarget) || document.id(this.options.update); 3258 if (this.options.useSpinner && update){ 3259 update.set('spinner', this.options.spinnerOptions); 3260 var spinner = this.spinner = update.get('spinner'); 3261 ['complete', 'exception', 'cancel'].each(function(event){ 3262 this.addEvent(event, spinner.hide.bind(spinner)); 3263 }, this); 3264 } 3265 } 3266 return this.spinner; 3267 } 3268 3269}); 3270 3271Element.Properties.spinner = { 3272 3273 set: function(options){ 3274 var spinner = this.retrieve('spinner'); 3275 if (spinner) spinner.destroy(); 3276 return this.eliminate('spinner').store('spinner:options', options); 3277 }, 3278 3279 get: function(){ 3280 var spinner = this.retrieve('spinner'); 3281 if (!spinner){ 3282 spinner = new Spinner(this, this.retrieve('spinner:options')); 3283 this.store('spinner', spinner); 3284 } 3285 return spinner; 3286 } 3287 3288}; 3289 3290Element.implement({ 3291 3292 spin: function(options){ 3293 if (options) this.set('spinner', options); 3294 this.get('spinner').show(); 3295 return this; 3296 }, 3297 3298 unspin: function(){ 3299 this.get('spinner').hide(); 3300 return this; 3301 } 3302 3303}); 3304 3305 3306/* 3307--- 3308 3309script: Form.Request.js 3310 3311name: Form.Request 3312 3313description: Handles the basic functionality of submitting a form and updating a dom element with the result. 3314 3315license: MIT-style license 3316 3317authors: 3318 - Aaron Newton 3319 3320requires: 3321 - Core/Request.HTML 3322 - /Class.Binds 3323 - /Class.Occlude 3324 - /Spinner 3325 - /String.QueryString 3326 - /Element.Delegation 3327 3328provides: [Form.Request] 3329 3330... 3331*/ 3332 3333if (!window.Form) window.Form = {}; 3334 3335(function(){ 3336 3337 Form.Request = new Class({ 3338 3339 Binds: ['onSubmit', 'onFormValidate'], 3340 3341 Implements: [Options, Events, Class.Occlude], 3342 3343 options: {/* 3344 onFailure: function(){}, 3345 onSuccess: function(){}, // aliased to onComplete, 3346 onSend: function(){}*/ 3347 requestOptions: { 3348 evalScripts: true, 3349 useSpinner: true, 3350 emulation: false, 3351 link: 'ignore' 3352 }, 3353 sendButtonClicked: true, 3354 extraData: {}, 3355 resetForm: true 3356 }, 3357 3358 property: 'form.request', 3359 3360 initialize: function(form, target, options){ 3361 this.element = document.id(form); 3362 if (this.occlude()) return this.occluded; 3363 this.setOptions(options) 3364 .setTarget(target) 3365 .attach(); 3366 }, 3367 3368 setTarget: function(target){ 3369 this.target = document.id(target); 3370 if (!this.request){ 3371 this.makeRequest(); 3372 } else { 3373 this.request.setOptions({ 3374 update: this.target 3375 }); 3376 } 3377 return this; 3378 }, 3379 3380 toElement: function(){ 3381 return this.element; 3382 }, 3383 3384 makeRequest: function(){ 3385 var self = this; 3386 this.request = new Request.HTML(Object.merge({ 3387 update: this.target, 3388 emulation: false, 3389 spinnerTarget: this.element, 3390 method: this.element.get('method') || 'post' 3391 }, this.options.requestOptions)).addEvents({ 3392 success: function(tree, elements, html, javascript){ 3393 ['complete', 'success'].each(function(evt){ 3394 self.fireEvent(evt, [self.target, tree, elements, html, javascript]); 3395 }); 3396 }, 3397 failure: function(){ 3398 self.fireEvent('complete', arguments).fireEvent('failure', arguments); 3399 }, 3400 exception: function(){ 3401 self.fireEvent('failure', arguments); 3402 } 3403 }); 3404 return this.attachReset(); 3405 }, 3406 3407 attachReset: function(){ 3408 if (!this.options.resetForm) return this; 3409 this.request.addEvent('success', function(){ 3410 Function.attempt(function(){ 3411 this.element.reset(); 3412 }.bind(this)); 3413 if (window.OverText) OverText.update(); 3414 }.bind(this)); 3415 return this; 3416 }, 3417 3418 attach: function(attach){ 3419 var method = (attach != false) ? 'addEvent' : 'removeEvent'; 3420 this.element[method]('click:relay(button, input[type=submit])', this.saveClickedButton.bind(this)); 3421 3422 var fv = this.element.retrieve('validator'); 3423 if (fv) fv[method]('onFormValidate', this.onFormValidate); 3424 else this.element[method]('submit', this.onSubmit); 3425 3426 return this; 3427 }, 3428 3429 detach: function(){ 3430 return this.attach(false); 3431 }, 3432 3433 //public method 3434 enable: function(){ 3435 return this.attach(); 3436 }, 3437 3438 //public method 3439 disable: function(){ 3440 return this.detach(); 3441 }, 3442
3443 onFormValidate: function(valid, form, event){ 3444 //if there's no event, then this wasn't a submit event 3445 if (!event) return; 3446 var fv = this.element.retrieve('validator'); 3447 if (valid || (fv && !fv.options.stopOnFailure)){ 3448 event.stop(); 3449 this.send(); 3450 } 3451 }, 3452 3453 onSubmit: function(event){ 3454 var fv = this.element.retrieve('validator'); 3455 if (fv){ 3456 //form validator was created after Form.Request 3457 this.element.removeEvent('submit', this.onSubmit); 3458 fv.addEvent('onFormValidate', this.onFormValidate); 3459 this.element.validate(); 3460 return; 3461 } 3462 if (event) event.stop(); 3463 this.send(); 3464 }, 3465 3466 saveClickedButton: function(event, target){ 3467 var targetName = target.get('name'); 3468 if (!targetName || !this.options.sendButtonClicked) return; 3469 this.options.extraData[targetName] = target.get('value') || true; 3470 this.clickedCleaner = function(){ 3471 delete this.options.extraData[targetName]; 3472 this.clickedCleaner = function(){}; 3473 }.bind(this); 3474 }, 3475 3476 clickedCleaner: function(){}, 3477 3478 send: function(){ 3479 var str = this.element.toQueryString().trim(), 3480 data = Object.toQueryString(this.options.extraData); 3481 3482 if (str) str += "&" + data; 3483 else str = data; 3484 3485 this.fireEvent('send', [this.element, str.parseQueryString()]); 3486 this.request.send({ 3487 data: str, 3488 url: this.options.requestOptions.url || this.element.get('action') 3489 }); 3490 this.clickedCleaner(); 3491 return this; 3492 } 3493 3494 }); 3495 3496 Element.implement('formUpdate', function(update, options){ 3497 var fq = this.retrieve('form.request'); 3498 if (!fq){
3499 fq = new Form.Request(this, update, options); 3500 } else { 3501 if (update) fq.setTarget(update); 3502 if (options) fq.setOptions(options).makeRequest(); 3503 } 3504 fq.send(); 3505 return this; 3506 }); 3507 3508})(); 3509 3510 3511/* 3512--- 3513 3514script: Fx.Reveal.js 3515 3516name: Fx.Reveal 3517 3518description: Defines Fx.Reveal, a class that shows and hides elements with a transition. 3519 3520license: MIT-style license 3521 3522authors: 3523 - Aaron Newton 3524 3525requires: 3526 - Core/Fx.Morph 3527 - /Element.Shortcuts 3528 - /Element.Measure 3529 3530provides: [Fx.Reveal] 3531 3532... 3533*/ 3534 3535(function(){ 3536 3537 3538var hideTheseOf = function(object){ 3539 var hideThese = object.options.hideInputs; 3540 if (window.OverText){ 3541 var otClasses = [null]; 3542 OverText.each(function(ot){ 3543 otClasses.include('.' + ot.options.labelClass); 3544 }); 3545 if (otClasses) hideThese += otClasses.join(', '); 3546 } 3547 return (hideThese) ? object.element.getElements(hideThese) : null; 3548}; 3549 3550 3551Fx.Reveal = new Class({ 3552 3553 Extends: Fx.Morph, 3554 3555 options: {/* 3556 onShow: function(thisElement){}, 3557 onHide: function(thisElement){}, 3558 onComplete: function(thisElement){}, 3559 heightOverride: null, 3560 widthOverride: null,*/ 3561 link: 'cancel', 3562 styles: ['padding', 'border', 'margin'], 3563 transitionOpacity: !Browser.ie6, 3564 mode: 'vertical', 3565 display: function(){ 3566 return this.element.get('tag') != 'tr' ? 'block' : 'table-row'; 3567 }, 3568 opacity: 1, 3569 hideInputs: Browser.ie ? 'select, input, textarea, object, embed' : null 3570 }, 3571 3572 dissolve: function(){ 3573 if (!this.hiding && !this.showing){ 3574 if (this.element.getStyle('display') != 'none'){ 3575 this.hiding = true; 3576 this.showing = false; 3577 this.hidden = true; 3578 this.cssText = this.element.style.cssText; 3579 3580 var startStyles = this.element.getComputedSize({ 3581 styles: this.options.styles, 3582 mode: this.options.mode 3583 }); 3584 if (this.options.transitionOpacity) startStyles.opacity = this.options.opacity; 3585 3586 var zero = {}; 3587 Object.each(startStyles, function(style, name){ 3588 zero[name] = [style, 0]; 3589 }); 3590 3591 this.element.setStyles({ 3592 display: Function.from(this.options.display).call(this), 3593 overflow: 'hidden' 3594 }); 3595 3596 var hideThese = hideTheseOf(this); 3597 if (hideThese) hideThese.setStyle('visibility', 'hidden'); 3598 3599 this.$chain.unshift(function(){ 3600 if (this.hidden){ 3601 this.hiding = false; 3602 this.element.style.cssText = this.cssText; 3603 this.element.setStyle('display', 'none'); 3604 if (hideThese) hideThese.setStyle('visibility', 'visible'); 3605 } 3606 this.fireEvent('hide', this.element); 3607 this.callChain(); 3608 }.bind(this)); 3609 3610 this.start(zero); 3611 } else { 3612 this.callChain.delay(10, this); 3613 this.fireEvent('complete', this.element); 3614 this.fireEvent('hide', this.element); 3615 } 3616 } else if (this.options.link == 'chain'){ 3617 this.chain(this.dissolve.bind(this)); 3618 } else if (this.options.link == 'cancel' && !this.hiding){ 3619 this.cancel(); 3620 this.dissolve(); 3621 } 3622 return this; 3623 }, 3624 3625 reveal: function(){ 3626 if (!this.showing && !this.hiding){ 3627 if (this.element.getStyle('display') == 'none'){ 3628 this.hiding = false; 3629 this.showing = true; 3630 this.hidden = false; 3631 this.cssText = this.element.style.cssText; 3632 3633 var startStyles; 3634 this.element.measure(function(){ 3635 startStyles = this.element.getComputedSize({ 3636 styles: this.options.styles, 3637 mode: this.options.mode 3638 }); 3639 }.bind(this)); 3640 if (this.options.heightOverride != null) startStyles.height = this.options.heightOverride.toInt(); 3641 if (this.options.widthOverride != null) startStyles.width = this.options.widthOverride.toInt(); 3642 if (this.options.transitionOpacity){ 3643 this.element.setStyle('opacity', 0); 3644 startStyles.opacity = this.options.opacity; 3645 } 3646 3647 var zero = { 3648 height: 0, 3649 display: Function.from(this.options.display).call(this) 3650 }; 3651 Object.each(startStyles, function(style, name){ 3652 zero[name] = 0; 3653 }); 3654 zero.overflow = 'hidden'; 3655 3656 this.element.setStyles(zero); 3657 3658 var hideThese = hideTheseOf(this); 3659 if (hideThese) hideThese.setStyle('visibility', 'hidden'); 3660 3661 this.$chain.unshift(function(){ 3662 this.element.style.cssText = this.cssText; 3663 this.element.setStyle('display', Function.from(this.options.display).call(this)); 3664 if (!this.hidden) this.showing = false;
3665 if (hideThese) hideThese.setStyle('visibility', 'visible'); 3666 this.callChain(); 3667 this.fireEvent('show', this.element); 3668 }.bind(this)); 3669 3670 this.start(startStyles); 3671 } else { 3672 this.callChain(); 3673 this.fireEvent('complete', this.element); 3674 this.fireEvent('show', this.element); 3675 } 3676 } else if (this.options.link == 'chain'){ 3677 this.chain(this.reveal.bind(this)); 3678 } else if (this.options.link == 'cancel' && !this.showing){ 3679 this.cancel(); 3680 this.reveal(); 3681 } 3682 return this; 3683 }, 3684 3685 toggle: function(){ 3686 if (this.element.getStyle('display') == 'none'){ 3687 this.reveal(); 3688 } else { 3689 this.dissolve(); 3690 } 3691 return this; 3692 }, 3693 3694 cancel: function(){ 3695 this.parent.apply(this, arguments); 3696 if (this.cssText != null) this.element.style.cssText = this.cssText; 3697 this.hiding = false; 3698 this.showing = false; 3699 return this; 3700 } 3701 3702}); 3703 3704Element.Properties.reveal = { 3705 3706 set: function(options){ 3707 this.get('reveal').cancel().setOptions(options); 3708 return this; 3709 }, 3710 3711 get: function(){ 3712 var reveal = this.retrieve('reveal'); 3713 if (!reveal){ 3714 reveal = new Fx.Reveal(this); 3715 this.store('reveal', reveal); 3716 } 3717 return reveal; 3718 } 3719 3720}; 3721 3722Element.Properties.dissolve = Element.Properties.reveal; 3723 3724Element.implement({ 3725 3726 reveal: function(options){ 3727 this.get('reveal').setOptions(options).reveal(); 3728 return this; 3729 }, 3730 3731 dissolve: function(options){ 3732 this.get('reveal').setOptions(options).dissolve(); 3733 return this; 3734 }, 3735 3736 nix: function(options){ 3737 var params = Array.link(arguments, {destroy: Type.isBoolean, options: Type.isObject}); 3738 this.get('reveal').setOptions(options).dissolve().chain(function(){ 3739 this[params.destroy ? 'destroy' : 'dispose'](); 3740 }.bind(this)); 3741 return this; 3742 }, 3743 3744 wink: function(){ 3745 var params = Array.link(arguments, {duration: Type.isNumber, options: Type.isObject}); 3746 var reveal = this.get('reveal').setOptions(params.options); 3747 reveal.reveal().chain(function(){ 3748 (function(){ 3749 reveal.dissolve(); 3750 }).delay(params.duration || 2000); 3751 }); 3752 } 3753 3754}); 3755 3756})(); 3757 3758 3759/* 3760--- 3761 3762script: Form.Request.Append.js 3763 3764name: Form.Request.Append 3765 3766description: Handles the basic functionality of submitting a form and updating a dom element with the result. The result is appended to the DOM element instead of replacing its contents. 3767 3768license: MIT-style license 3769 3770authors: 3771 - Aaron Newton 3772 3773requires: 3774 - /Form.Request 3775 - /Fx.Reveal 3776 - /Elements.from 3777 3778provides: [Form.Request.Append] 3779 3780... 3781*/ 3782 3783Form.Request.Append = new Class({ 3784 3785 Extends: Form.Request, 3786 3787 options: { 3788 //onBeforeEffect: function(){}, 3789 useReveal: true, 3790 revealOptions: {}, 3791 inject: 'bottom' 3792 }, 3793 3794 makeRequest: function(){ 3795 this.request = new Request.HTML(Object.merge({ 3796 url: this.element.get('action'), 3797 method: this.element.get('method') || 'post', 3798 spinnerTarget: this.element 3799 }, this.options.requestOptions, { 3800 evalScripts: false 3801 }) 3802 ).addEvents({ 3803 success: function(tree, elements, html, javascript){ 3804 var container; 3805 var kids = Elements.from(html); 3806 if (kids.length == 1){ 3807 container = kids[0]; 3808 } else { 3809 container = new Element('div', { 3810 styles: { 3811 display: 'none' 3812 } 3813 }).adopt(kids); 3814 } 3815 container.inject(this.target, this.options.inject); 3816 if (this.options.requestOptions.evalScripts) Browser.exec(javascript); 3817 this.fireEvent('beforeEffect', container); 3818 var finish = function(){ 3819 this.fireEvent('success', [container, this.target, tree, elements, html, javascript]); 3820 }.bind(this); 3821 if (this.options.useReveal){ 3822 container.set('reveal', this.options.revealOptions).get('reveal').chain(finish); 3823 container.reveal(); 3824 } else { 3825 finish(); 3826 } 3827 }.bind(this), 3828 failure: function(xhr){ 3829 this.fireEvent('failure', xhr); 3830 }.bind(this) 3831 }); 3832 this.attachReset(); 3833 } 3834 3835}); 3836 3837 3838/* 3839--- 3840 3841name: Locale.en-US.Form.Validator 3842 3843description: Form Validator messages for English. 3844 3845license: MIT-style license 3846 3847authors: 3848 - Aaron Newton 3849 3850requires: 3851 - /Locale 3852 3853provides: [Locale.en-US.Form.Validator] 3854 3855... 3856*/ 3857 3858Locale.define('en-US', 'FormValidator', { 3859 3860 required: 'This field is required.', 3861 length: 'Please enter {length} characters (you entered {elLength} characters)', 3862 minLength: 'Please enter at least {minLength} characters (you entered {length} characters).', 3863 maxLength: 'Please enter no more than {maxLength} characters (you entered {length} characters).', 3864 integer: 'Please enter an integer in this field. Numbers with decimals (e.g. 1.25) are not permitted.', 3865 numeric: 'Please enter only numeric values in this field (i.e. "1" or "1.1" or "-1" or "-1.1").', 3866 digits: 'Please use numbers and punctuation only in this field (for example, a phone number with dashes or dots is permitted).', 3867 alpha: 'Please use only letters (a-z) within this field. No spaces or other characters are allowed.', 3868 alphanum: 'Please use only letters (a-z) or numbers (0-9) in this field. No spaces or other characters are allowed.', 3869 dateSuchAs: 'Please enter a valid date such as {date}', 3870 dateInFormatMDY: 'Please enter a valid date such as MM/DD/YYYY (i.e. "12/31/1999")', 3871 email: 'Please enter a valid email address. For example "[email protected]".', 3872 url: 'Please enter a valid URL such as http://www.example.com.', 3873 currencyDollar: 'Please enter a valid $ amount. For example $100.00 .', 3874 oneRequired: 'Please enter something for at least one of these inputs.', 3875 errorPrefix: 'Error: ', 3876 warningPrefix: 'Warning: ', 3877 3878 // Form.Validator.Extras 3879 noSpace: 'There can be no spaces in this input.', 3880 reqChkByNode: 'No items are selected.', 3881 requiredChk: 'This field is required.', 3882 reqChkByName: 'Please select a {label}.', 3883 match: 'This field needs to match the {matchName} field', 3884 startDate: 'the start date', 3885 endDate: 'the end date', 3886 currendDate: 'the current date', 3887 afterDate: 'The date should be the same or after {label}.', 3888 beforeDate: 'The date should be the same or before {label}.', 3889 startMonth: 'Please select a start month', 3890 sameMonth: 'These two dates must be in the same month - you must change one or the other.',
3891 creditcard: 'The credit card number entered is invalid. Please check the number and try again. {length} digits entered.' 3892 3893}); 3894 3895 3896/* 3897--- 3898 3899script: Form.Validator.js 3900 3901name: Form.Validator 3902 3903description: A css-class based form validation system. 3904 3905license: MIT-style license 3906 3907authors: 3908 - Aaron Newton 3909 3910requires: 3911 - Core/Options 3912 - Core/Events 3913 - Core/Slick.Finder 3914 - Core/Element.Event 3915 - Core/Element.Style 3916 - Core/JSON 3917 - /Locale 3918 - /Class.Binds 3919 - /Date 3920 - /Element.Forms 3921 - /Locale.en-US.Form.Validator 3922 - /Element.Shortcuts 3923 3924provides: [Form.Validator, InputValidator, FormValidator.BaseValidators] 3925 3926... 3927*/ 3928if (!window.Form) window.Form = {}; 3929 3930var InputValidator = this.InputValidator = new Class({ 3931 3932 Implements: [Options], 3933 3934 options: { 3935 errorMsg: 'Validation failed.', 3936 test: Function.from(true) 3937 }, 3938 3939 initialize: function(className, options){ 3940 this.setOptions(options); 3941 this.className = className; 3942 }, 3943 3944 test: function(field, props){ 3945 field = document.id(field); 3946 return (field) ? this.options.test(field, props || this.getProps(field)) : false; 3947 }, 3948 3949 getError: function(field, props){ 3950 field = document.id(field); 3951 var err = this.options.errorMsg; 3952 if (typeOf(err) == 'function') err = err(field, props || this.getProps(field)); 3953 return err; 3954 }, 3955 3956 getProps: function(field){ 3957 field = document.id(field); 3958 return (field) ? field.get('validatorProps') : {}; 3959 } 3960 3961}); 3962 3963Element.Properties.validators = { 3964 3965 get: function(){ 3966 return (this.get('data-validators') || this.className).clean().split(' '); 3967 } 3968 3969}; 3970 3971Element.Properties.validatorProps = { 3972 3973 set: function(props){ 3974 return this.eliminate('$moo:validatorProps').store('$moo:validatorProps', props); 3975 }, 3976 3977 get: function(props){ 3978 if (props) this.set(props); 3979 if (this.retrieve('$moo:validatorProps')) return this.retrieve('$moo:validatorProps'); 3980 if (this.getProperty('data-validator-properties') || this.getProperty('validatorProps')){ 3981 try { 3982 this.store('$moo:validatorProps', JSON.decode(this.getProperty('validatorProps') || this.getProperty('data-validator-properties'))); 3983 }catch(e){ 3984 return {}; 3985 } 3986 } else { 3987 var vals = this.get('validators').filter(function(cls){ 3988 return cls.test(':'); 3989 }); 3990 if (!vals.length){ 3991 this.store('$moo:validatorProps', {}); 3992 } else { 3993 props = {}; 3994 vals.each(function(cls){ 3995 var split = cls.split(':'); 3996 if (split[1]){ 3997 try { 3998 props[split[0]] = JSON.decode(split[1]); 3999 } catch(e){} 4000 } 4001 }); 4002 this.store('$moo:validatorProps', props); 4003 } 4004 } 4005 return this.retrieve('$moo:validatorProps'); 4006 } 4007 4008}; 4009 4010Form.Validator = new Class({ 4011 4012 Implements: [Options, Events], 4013 4014 Binds: ['onSubmit'], 4015 4016 options: {/* 4017 onFormValidate: function(isValid, form, event){}, 4018 onElementValidate: function(isValid, field, className, warn){}, 4019 onElementPass: function(field){}, 4020 onElementFail: function(field, validatorsFailed){}, */ 4021 fieldSelectors: 'input, select, textarea', 4022 ignoreHidden: true, 4023 ignoreDisabled: true, 4024 useTitles: false, 4025 evaluateOnSubmit: true, 4026 evaluateFieldsOnBlur: true, 4027 evaluateFieldsOnChange: true, 4028 serial: true, 4029 stopOnFailure: true, 4030 warningPrefix: function(){ 4031 return Form.Validator.getMsg('warningPrefix') || 'Warning: '; 4032 }, 4033 errorPrefix: function(){ 4034 return Form.Validator.getMsg('errorPrefix') || 'Error: '; 4035 } 4036 }, 4037 4038 initialize: function(form, options){ 4039 this.setOptions(options); 4040 this.element = document.id(form); 4041 this.element.store('validator', this); 4042 this.warningPrefix = Function.from(this.options.warningPrefix)(); 4043 this.errorPrefix = Function.from(this.options.errorPrefix)(); 4044 if (this.options.evaluateOnSubmit) this.element.addEvent('submit', this.onSubmit); 4045 if (this.options.evaluateFieldsOnBlur || this.options.evaluateFieldsOnChange) this.watchFields(this.getFields()); 4046 }, 4047 4048 toElement: function(){ 4049 return this.element; 4050 }, 4051 4052 getFields: function(){ 4053 return (this.fields = this.element.getElements(this.options.fieldSelectors)); 4054 }, 4055 4056 watchFields: function(fields){ 4057 fields.each(function(el){ 4058 if (this.options.evaluateFieldsOnBlur) 4059 el.addEvent('blur', this.validationMonitor.pass([el, false], this)); 4060 if (this.options.evaluateFieldsOnChange) 4061 el.addEvent('change', this.validationMonitor.pass([el, true], this)); 4062 }, this); 4063 }, 4064 4065 validationMonitor: function(){ 4066 clearTimeout(this.timer); 4067 this.timer = this.validateField.delay(50, this, arguments); 4068 }, 4069 4070 onSubmit: function(event){ 4071 if (this.validate(event)) this.reset(); 4072 }, 4073 4074 reset: function(){ 4075 this.getFields().each(this.resetField, this); 4076 return this; 4077 }, 4078 4079 validate: function(event){ 4080 var result = this.getFields().map(function(field){ 4081 return this.validateField(field, true); 4082 }, this).every(function(v){ 4083 return v; 4084 }); 4085 this.fireEvent('formValidate', [result, this.element, event]); 4086 if (this.options.stopOnFailure && !result && event) event.preventDefault(); 4087 return result; 4088 }, 4089 4090 validateField: function(field, force){ 4091 if (this.paused) return true; 4092 field = document.id(field); 4093 var passed = !field.hasClass('validation-failed'); 4094 var failed, warned; 4095 if (this.options.serial && !force){ 4096 failed = this.element.getElement('.validation-failed'); 4097 warned = this.element.getElement('.warning'); 4098 } 4099 if (field && (!failed || force || field.hasClass('validation-failed') || (failed && !this.options.serial))){
4100 var validationTypes = field.get('validators'); 4101 var validators = validationTypes.some(function(cn){ 4102 return this.getValidator(cn); 4103 }, this); 4104 var validatorsFailed = []; 4105 validationTypes.each(function(className){ 4106 if (className && !this.test(className, field)) validatorsFailed.include(className); 4107 }, this); 4108 passed = validatorsFailed.length === 0; 4109 if (validators && !this.hasValidator(field, 'warnOnly')){ 4110 if (passed){ 4111 field.addClass('validation-passed').removeClass('validation-failed'); 4112 this.fireEvent('elementPass', [field]); 4113 } else { 4114 field.addClass('validation-failed').removeClass('validation-passed'); 4115 this.fireEvent('elementFail', [field, validatorsFailed]); 4116 } 4117 } 4118 if (!warned){ 4119 var warnings = validationTypes.some(function(cn){ 4120 if (cn.test('^warn')) 4121 return this.getValidator(cn.replace(/^warn-/,'')); 4122 else return null; 4123 }, this); 4124 field.removeClass('warning'); 4125 var warnResult = validationTypes.map(function(cn){ 4126 if (cn.test('^warn')) 4127 return this.test(cn.replace(/^warn-/,''), field, true); 4128 else return null; 4129 }, this); 4130 } 4131 } 4132 return passed; 4133 }, 4134 4135 test: function(className, field, warn){ 4136 field = document.id(field); 4137 if ((this.options.ignoreHidden && !field.isVisible()) || (this.options.ignoreDisabled && field.get('disabled'))) return true; 4138 var validator = this.getValidator(className); 4139 if (warn != null) warn = false; 4140 if (this.hasValidator(field, 'warnOnly')) warn = true; 4141 var isValid = this.hasValidator(field, 'ignoreValidation') || (validator ? validator.test(field) : true); 4142 if (validator && field.isVisible()) this.fireEvent('elementValidate', [isValid, field, className, warn]); 4143 if (warn) return true; 4144 return isValid; 4145 }, 4146 4147 hasValidator: function(field, value){ 4148 return field.get('validators').contains(value); 4149 }, 4150 4151 resetField: function(field){ 4152 field = document.id(field); 4153 if (field){ 4154 field.get('validators').each(function(className){ 4155 if (className.test('^warn-')) className = className.replace(/^warn-/, ''); 4156 field.removeClass('validation-failed'); 4157 field.removeClass('warning'); 4158 field.removeClass('validation-passed'); 4159 }, this); 4160 } 4161 return this; 4162 }, 4163 4164 stop: function(){ 4165 this.paused = true; 4166 return this; 4167 }, 4168 4169 start: function(){ 4170 this.paused = false; 4171 return this; 4172 }, 4173 4174 ignoreField: function(field, warn){ 4175 field = document.id(field); 4176 if (field){ 4177 this.enforceField(field); 4178 if (warn) field.addClass('warnOnly'); 4179 else field.addClass('ignoreValidation'); 4180 } 4181 return this; 4182 }, 4183 4184 enforceField: function(field){ 4185 field = document.id(field); 4186 if (field) field.removeClass('warnOnly').removeClass('ignoreValidation'); 4187 return this; 4188 } 4189 4190}); 4191 4192Form.Validator.getMsg = function(key){ 4193 return Locale.get('FormValidator.' + key); 4194}; 4195 4196Form.Validator.adders = { 4197 4198 validators:{}, 4199 4200 add : function(className, options){ 4201 this.validators[className] = new InputValidator(className, options); 4202 //if this is a class (this method is used by instances of Form.Validator and the Form.Validator namespace) 4203 //extend these validators into it 4204 //this allows validators to be global and/or per instance 4205 if (!this.initialize){ 4206 this.implement({ 4207 validators: this.validators 4208 }); 4209 } 4210 }, 4211 4212 addAllThese : function(validators){ 4213 Array.from(validators).each(function(validator){ 4214 this.add(validator[0], validator[1]); 4215 }, this); 4216 }, 4217 4218 getValidator: function(className){ 4219 return this.validators[className.split(':')[0]]; 4220 } 4221 4222}; 4223 4224Object.append(Form.Validator, Form.Validator.adders); 4225 4226Form.Validator.implement(Form.Validator.adders); 4227 4228Form.Validator.add('IsEmpty', { 4229 4230 errorMsg: false, 4231 test: function(element){ 4232 if (element.type == 'select-one' || element.type == 'select') 4233 return !(element.selectedIndex >= 0 && element.options[element.selectedIndex].value != ''); 4234 else 4235 return ((element.get('value') == null) || (element.get('value').length == 0)); 4236 } 4237 4238}); 4239 4240Form.Validator.addAllThese([ 4241 4242 ['required', { 4243 errorMsg: function(){ 4244 return Form.Validator.getMsg('required'); 4245 }, 4246 test: function(element){ 4247 return !Form.Validator.getValidator('IsEmpty').test(element); 4248 } 4249 }], 4250 4251 ['length', { 4252 errorMsg: function(element, props){ 4253 if (typeOf(props.length) != 'null') 4254 return Form.Validator.getMsg('length').substitute({length: props.length, elLength: element.get('value').length}); 4255 else return ''; 4256 }, 4257 test: function(element, props){ 4258 if (typeOf(props.length) != 'null') return (element.get('value').length == props.length || element.get('value').length == 0); 4259 else return true; 4260 } 4261 }], 4262 4263 ['minLength', { 4264 errorMsg: function(element, props){ 4265 if (typeOf(props.minLength) != 'null') 4266 return Form.Validator.getMsg('minLength').substitute({minLength: props.minLength, length: element.get('value').length}); 4267 else return ''; 4268 }, 4269 test: function(element, props){ 4270 if (typeOf(props.minLength) != 'null') return (element.get('value').length >= (props.minLength || 0)); 4271 else return true; 4272 } 4273 }], 4274 4275 ['maxLength', { 4276 errorMsg: function(element, props){ 4277 //props is {maxLength:10} 4278 if (typeOf(props.maxLength) != 'null') 4279 return Form.Validator.getMsg('maxLength').substitute({maxLength: props.maxLength, length: element.get('value').length}); 4280 else return ''; 4281 }, 4282 test: function(element, props){ 4283 return element.get('value').length <= (props.maxLength || 10000); 4284 } 4285 }], 4286 4287 ['validate-integer', { 4288 errorMsg: Form.Validator.getMsg.pass('integer'), 4289 test: function(element){ 4290 return Form.Validator.getValidator('IsEmpty').test(element) || (/^(-?[1-9]\d*|0)$/).test(element.get('value')); 4291 } 4292 }], 4293 4294 ['validate-numeric', { 4295 errorMsg: Form.Validator.getMsg.pass('numeric'), 4296 test: function(element){ 4297 return Form.Validator.getValidator('IsEmpty').test(element) || 4298 (/^-?(?:0$0(?=\d*\.)|[1-9]|0)\d*(\.\d+)?$/).test(element.get('value')); 4299 } 4300 }], 4301 4302 ['validate-digits', { 4303 errorMsg: Form.Validator.getMsg.pass('digits'), 4304 test: function(element){ 4305 return Form.Validator.getValidator('IsEmpty').test(element) || (/^[\d() .:\-\+#]+$/.test(element.get('value'))); 4306 } 4307 }], 4308 4309 ['validate-alpha', {
4310 errorMsg: Form.Validator.getMsg.pass('alpha'), 4311 test: function(element){ 4312 return Form.Validator.getValidator('IsEmpty').test(element) || (/^[a-zA-Z]+$/).test(element.get('value')); 4313 } 4314 }], 4315 4316 ['validate-alphanum', { 4317 errorMsg: Form.Validator.getMsg.pass('alphanum'), 4318 test: function(element){ 4319 return Form.Validator.getValidator('IsEmpty').test(element) || !(/\W/).test(element.get('value')); 4320 } 4321 }], 4322 4323 ['validate-date', { 4324 errorMsg: function(element, props){ 4325 if (Date.parse){ 4326 var format = props.dateFormat || '%x'; 4327 return Form.Validator.getMsg('dateSuchAs').substitute({date: new Date().format(format)}); 4328 } else { 4329 return Form.Validator.getMsg('dateInFormatMDY'); 4330 } 4331 }, 4332 test: function(element, props){ 4333 if (Form.Validator.getValidator('IsEmpty').test(element)) return true; 4334 var dateLocale = Locale.getCurrent().sets.Date, 4335 dateNouns = new RegExp([dateLocale.days, dateLocale.days_abbr, dateLocale.months, dateLocale.months_abbr].flatten().join('|'), 'i'), 4336 value = element.get('value'), 4337 wordsInValue = value.match(/[a-z]+/gi); 4338 4339 if (wordsInValue && !wordsInValue.every(dateNouns.exec, dateNouns)) return false; 4340 4341 var date = Date.parse(value), 4342 format = props.dateFormat || '%x', 4343 formatted = date.format(format); 4344 4345 if (formatted != 'invalid date') element.set('value', formatted); 4346 return date.isValid(); 4347 } 4348 }], 4349 4350 ['validate-email', { 4351 errorMsg: Form.Validator.getMsg.pass('email'), 4352 test: function(element){ 4353 /* 4354 var chars = "[a-z0-9!#$%&'*+/=?^_`{|}~-]", 4355 local = '(?:' + chars + '\\.?){0,63}' + chars, 4356 4357 label = '[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?', 4358 hostname = '(?:' + label + '\\.)*' + label; 4359 4360 octet = '(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)', 4361 ipv4 = '\\[(?:' + octet + '\\.){3}' + octet + '\\]', 4362 4363 domain = '(?:' + hostname + '|' + ipv4 + ')'; 4364 4365 var regex = new RegExp('^' + local + '@' + domain + '$', 'i'); 4366 */ 4367 return Form.Validator.getValidator('IsEmpty').test(element) || (/^(?:[a-z0-9!#$%&'*+\/=?^_`{|}~-]\.?){0,63}[a-z0-9!#$%&'*+\/=?^_`{|}~-]@(?:(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)*[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\])$/i).test(element.get('value')); 4368 } 4369 }], 4370 4371 ['validate-url', { 4372 errorMsg: Form.Validator.getMsg.pass('url'), 4373 test: function(element){ 4374 return Form.Validator.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')); 4375 } 4376 }], 4377 4378 ['validate-currency-dollar', { 4379 errorMsg: Form.Validator.getMsg.pass('currencyDollar'), 4380 test: function(element){ 4381 return Form.Validator.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')); 4382 } 4383 }], 4384 4385 ['validate-one-required', { 4386 errorMsg: Form.Validator.getMsg.pass('oneRequired'), 4387 test: function(element, props){ 4388 var p = document.id(props['validate-one-required']) || element.getParent(props['validate-one-required']); 4389 return p.getElements('input').some(function(el){ 4390 if (['checkbox', 'radio'].contains(el.get('type'))) return el.get('checked'); 4391 return el.get('value'); 4392 }); 4393 } 4394 }] 4395 4396]); 4397 4398Element.Properties.validator = { 4399 4400 set: function(options){ 4401 this.get('validator').setOptions(options); 4402 }, 4403 4404 get: function(){ 4405 var validator = this.retrieve('validator'); 4406 if (!validator){ 4407 validator = new Form.Validator(this); 4408 this.store('validator', validator); 4409 } 4410 return validator; 4411 } 4412 4413}; 4414 4415Element.implement({ 4416 4417 validate: function(options){ 4418 if (options) this.set('validator', options); 4419 return this.get('validator').validate(); 4420 } 4421 4422}); 4423 4424 4425//<1.2compat> 4426//legacy 4427var FormValidator = Form.Validator; 4428//</1.2compat> 4429 4430 4431 4432 4433/* 4434--- 4435 4436script: Form.Validator.Inline.js 4437 4438name: Form.Validator.Inline 4439 4440description: Extends Form.Validator to add inline messages. 4441 4442license: MIT-style license 4443 4444authors: 4445 - Aaron Newton 4446 4447requires: 4448 - /Form.Validator 4449 4450provides: [Form.Validator.Inline] 4451 4452... 4453*/ 4454 4455Form.Validator.Inline = new Class({ 4456 4457 Extends: Form.Validator, 4458 4459 options: { 4460 showError: function(errorElement){ 4461 if (errorElement.reveal) errorElement.reveal(); 4462 else errorElement.setStyle('display', 'block'); 4463 }, 4464 hideError: function(errorElement){
4465 if (errorElement.dissolve) errorElement.dissolve(); 4466 else errorElement.setStyle('display', 'none'); 4467 }, 4468 scrollToErrorsOnSubmit: true, 4469 scrollToErrorsOnBlur: false, 4470 scrollToErrorsOnChange: false, 4471 scrollFxOptions: { 4472 transition: 'quad:out', 4473 offset: { 4474 y: -20 4475 } 4476 } 4477 }, 4478 4479 initialize: function(form, options){ 4480 this.parent(form, options); 4481 this.addEvent('onElementValidate', function(isValid, field, className, warn){ 4482 var validator = this.getValidator(className); 4483 if (!isValid && validator.getError(field)){ 4484 if (warn) field.addClass('warning'); 4485 var advice = this.makeAdvice(className, field, validator.getError(field), warn); 4486 this.insertAdvice(advice, field); 4487 this.showAdvice(className, field); 4488 } else { 4489 this.hideAdvice(className, field); 4490 } 4491 }); 4492 }, 4493 4494 makeAdvice: function(className, field, error, warn){ 4495 var errorMsg = (warn) ? this.warningPrefix : this.errorPrefix; 4496 errorMsg += (this.options.useTitles) ? field.title || error:error; 4497 var cssClass = (warn) ? 'warning-advice' : 'validation-advice'; 4498 var advice = this.getAdvice(className, field); 4499 if (advice){ 4500 advice = advice.set('html', errorMsg); 4501 } else { 4502 advice = new Element('div', { 4503 html: errorMsg, 4504 styles: { display: 'none' }, 4505 id: 'advice-' + className.split(':')[0] + '-' + this.getFieldId(field) 4506 }).addClass(cssClass); 4507 } 4508 field.store('$moo:advice-' + className, advice); 4509 return advice; 4510 }, 4511 4512 getFieldId : function(field){ 4513 return field.id ? field.id : field.id = 'input_' + field.name; 4514 }, 4515 4516 showAdvice: function(className, field){ 4517 var advice = this.getAdvice(className, field); 4518 if ( 4519 advice && 4520 !field.retrieve('$moo:' + this.getPropName(className)) && 4521 ( 4522 advice.getStyle('display') == 'none' || 4523 advice.getStyle('visiblity') == 'hidden' || 4524 advice.getStyle('opacity') == 0 4525 ) 4526 ){ 4527 field.store('$moo:' + this.getPropName(className), true); 4528 this.options.showError(advice); 4529 this.fireEvent('showAdvice', [field, advice, className]); 4530 } 4531 }, 4532 4533 hideAdvice: function(className, field){ 4534 var advice = this.getAdvice(className, field); 4535 if (advice && field.retrieve('$moo:' + this.getPropName(className))){ 4536 field.store('$moo:' + this.getPropName(className), false); 4537 this.options.hideError(advice); 4538 this.fireEvent('hideAdvice', [field, advice, className]); 4539 } 4540 }, 4541 4542 getPropName: function(className){ 4543 return 'advice' + className; 4544 }, 4545 4546 resetField: function(field){ 4547 field = document.id(field); 4548 if (!field) return this; 4549 this.parent(field); 4550 field.get('validators').each(function(className){ 4551 this.hideAdvice(className, field); 4552 }, this); 4553 return this; 4554 }, 4555 4556 getAllAdviceMessages: function(field, force){ 4557 var advice = []; 4558 if (field.hasClass('ignoreValidation') && !force) return advice; 4559 var validators = field.get('validators').some(function(cn){ 4560 var warner = cn.test('^warn-') || field.hasClass('warnOnly'); 4561 if (warner) cn = cn.replace(/^warn-/, ''); 4562 var validator = this.getValidator(cn); 4563 if (!validator) return; 4564 advice.push({ 4565 message: validator.getError(field), 4566 warnOnly: warner, 4567 passed: validator.test(), 4568 validator: validator 4569 }); 4570 }, this); 4571 return advice; 4572 }, 4573 4574 getAdvice: function(className, field){ 4575 return field.retrieve('$moo:advice-' + className); 4576 }, 4577 4578 insertAdvice: function(advice, field){ 4579 //Check for error position prop 4580 var props = field.get('validatorProps'); 4581 //Build advice 4582 if (!props.msgPos || !document.id(props.msgPos)){ 4583 if (field.type && field.type.toLowerCase() == 'radio') field.getParent().adopt(advice); 4584 else advice.inject(document.id(field), 'after'); 4585 } else { 4586 document.id(props.msgPos).grab(advice); 4587 } 4588 }, 4589 4590 validateField: function(field, force, scroll){ 4591 var result = this.parent(field, force); 4592 if (((this.options.scrollToErrorsOnSubmit && scroll == null) || scroll) && !result){ 4593 var failed = document.id(this).getElement('.validation-failed'); 4594 var par = document.id(this).getParent(); 4595 while (par != document.body && par.getScrollSize().y == par.getSize().y){ 4596 par = par.getParent(); 4597 } 4598 var fx = par.retrieve('$moo:fvScroller'); 4599 if (!fx && window.Fx && Fx.Scroll){ 4600 fx = new Fx.Scroll(par, this.options.scrollFxOptions); 4601 par.store('$moo:fvScroller', fx); 4602 } 4603 if (failed){ 4604 if (fx) fx.toElement(failed);
4605 else par.scrollTo(par.getScroll().x, failed.getPosition(par).y - 20); 4606 } 4607 } 4608 return result; 4609 }, 4610 4611 watchFields: function(fields){ 4612 fields.each(function(el){ 4613 if (this.options.evaluateFieldsOnBlur){ 4614 el.addEvent('blur', this.validationMonitor.pass([el, false, this.options.scrollToErrorsOnBlur], this)); 4615 } 4616 if (this.options.evaluateFieldsOnChange){ 4617 el.addEvent('change', this.validationMonitor.pass([el, true, this.options.scrollToErrorsOnChange], this)); 4618 } 4619 }, this); 4620 } 4621 4622}); 4623 4624 4625/* 4626--- 4627 4628script: Form.Validator.Extras.js 4629 4630name: Form.Validator.Extras 4631 4632description: Additional validators for the Form.Validator class. 4633 4634license: MIT-style license 4635 4636authors: 4637 - Aaron Newton 4638 4639requires: 4640 - /Form.Validator 4641 4642provides: [Form.Validator.Extras] 4643 4644... 4645*/ 4646Form.Validator.addAllThese([ 4647 4648 ['validate-enforce-oncheck', { 4649 test: function(element, props){ 4650 var fv = element.getParent('form').retrieve('validator'); 4651 if (!fv) return true; 4652 (props.toEnforce || document.id(props.enforceChildrenOf).getElements('input, select, textarea')).map(function(item){ 4653 if (element.checked){ 4654 fv.enforceField(item); 4655 } else { 4656 fv.ignoreField(item); 4657 fv.resetField(item); 4658 } 4659 }); 4660 return true; 4661 } 4662 }], 4663 4664 ['validate-ignore-oncheck', { 4665 test: function(element, props){ 4666 var fv = element.getParent('form').retrieve('validator'); 4667 if (!fv) return true; 4668 (props.toIgnore || document.id(props.ignoreChildrenOf).getElements('input, select, textarea')).each(function(item){ 4669 if (element.checked){ 4670 fv.ignoreField(item); 4671 fv.resetField(item); 4672 } else { 4673 fv.enforceField(item); 4674 } 4675 }); 4676 return true; 4677 } 4678 }], 4679 4680 ['validate-nospace', { 4681 errorMsg: function(){ 4682 return Form.Validator.getMsg('noSpace'); 4683 }, 4684 test: function(element, props){ 4685 return !element.get('value').test(/\s/); 4686 } 4687 }], 4688 4689 ['validate-toggle-oncheck', { 4690 test: function(element, props){ 4691 var fv = element.getParent('form').retrieve('validator'); 4692 if (!fv) return true; 4693 var eleArr = props.toToggle || document.id(props.toToggleChildrenOf).getElements('input, select, textarea'); 4694 if (!element.checked){ 4695 eleArr.each(function(item){ 4696 fv.ignoreField(item); 4697 fv.resetField(item); 4698 }); 4699 } else { 4700 eleArr.each(function(item){ 4701 fv.enforceField(item); 4702 }); 4703 } 4704 return true; 4705 } 4706 }], 4707 4708 ['validate-reqchk-bynode', { 4709 errorMsg: function(){ 4710 return Form.Validator.getMsg('reqChkByNode'); 4711 }, 4712 test: function(element, props){ 4713 return (document.id(props.nodeId).getElements(props.selector || 'input[type=checkbox], input[type=radio]')).some(function(item){ 4714 return item.checked; 4715 }); 4716 } 4717 }], 4718 4719 ['validate-required-check', { 4720 errorMsg: function(element, props){ 4721 return props.useTitle ? element.get('title') : Form.Validator.getMsg('requiredChk'); 4722 }, 4723 test: function(element, props){ 4724 return !!element.checked; 4725 } 4726 }], 4727 4728 ['validate-reqchk-byname', { 4729 errorMsg: function(element, props){ 4730 return Form.Validator.getMsg('reqChkByName').substitute({label: props.label || element.get('type')}); 4731 }, 4732 test: function(element, props){ 4733 var grpName = props.groupName || element.get('name'); 4734 var oneCheckedItem = $$(document.getElementsByName(grpName)).some(function(item, index){ 4735 return item.checked; 4736 }); 4737 var fv = element.getParent('form').retrieve('validator'); 4738 if (oneCheckedItem && fv) fv.resetField(element); 4739 return oneCheckedItem; 4740 } 4741 }], 4742 4743 ['validate-match', { 4744 errorMsg: function(element, props){ 4745 return Form.Validator.getMsg('match').substitute({matchName: props.matchName || document.id(props.matchInput).get('name')}); 4746 }, 4747 test: function(element, props){ 4748 var eleVal = element.get('value'); 4749 var matchVal = document.id(props.matchInput) && document.id(props.matchInput).get('value'); 4750 return eleVal && matchVal ? eleVal == matchVal : true; 4751 } 4752 }], 4753 4754 ['validate-after-date', { 4755 errorMsg: function(element, props){ 4756 return Form.Validator.getMsg('afterDate').substitute({ 4757 label: props.afterLabel || (props.afterElement ? Form.Validator.getMsg('startDate') : Form.Validator.getMsg('currentDate')) 4758 }); 4759 }, 4760 test: function(element, props){ 4761 var start = document.id(props.afterElement) ? Date.parse(document.id(props.afterElement).get('value')) : new Date(); 4762 var end = Date.parse(element.get('value')); 4763 return end && start ? end >= start : true; 4764 } 4765 }], 4766
4767 ['validate-before-date', { 4768 errorMsg: function(element, props){ 4769 return Form.Validator.getMsg('beforeDate').substitute({ 4770 label: props.beforeLabel || (props.beforeElement ? Form.Validator.getMsg('endDate') : Form.Validator.getMsg('currentDate')) 4771 }); 4772 }, 4773 test: function(element, props){ 4774 var start = Date.parse(element.get('value')); 4775 var end = document.id(props.beforeElement) ? Date.parse(document.id(props.beforeElement).get('value')) : new Date(); 4776 return end && start ? end >= start : true; 4777 } 4778 }], 4779 4780 ['validate-custom-required', { 4781 errorMsg: function(){ 4782 return Form.Validator.getMsg('required'); 4783 }, 4784 test: function(element, props){ 4785 return element.get('value') != props.emptyValue; 4786 } 4787 }], 4788 4789 ['validate-same-month', { 4790 errorMsg: function(element, props){ 4791 var startMo = document.id(props.sameMonthAs) && document.id(props.sameMonthAs).get('value'); 4792 var eleVal = element.get('value'); 4793 if (eleVal != '') return Form.Validator.getMsg(startMo ? 'sameMonth' : 'startMonth'); 4794 }, 4795 test: function(element, props){ 4796 var d1 = Date.parse(element.get('value')); 4797 var d2 = Date.parse(document.id(props.sameMonthAs) && document.id(props.sameMonthAs).get('value')); 4798 return d1 && d2 ? d1.format('%B') == d2.format('%B') : true; 4799 } 4800 }], 4801 4802 4803 ['validate-cc-num', { 4804 errorMsg: function(element){ 4805 var ccNum = element.get('value').replace(/[^0-9]/g, ''); 4806 return Form.Validator.getMsg('creditcard').substitute({length: ccNum.length}); 4807 }, 4808 test: function(element){ 4809 // required is a different test 4810 if (Form.Validator.getValidator('IsEmpty').test(element)) return true; 4811 4812 // Clean number value 4813 var ccNum = element.get('value'); 4814 ccNum = ccNum.replace(/[^0-9]/g, ''); 4815 4816 var valid_type = false;
4817 4818 if (ccNum.test(/^4[0-9]{12}([0-9]{3})?$/)) valid_type = 'Visa'; 4819 else if (ccNum.test(/^5[1-5]([0-9]{14})$/)) valid_type = 'Master Card'; 4820 else if (ccNum.test(/^3[47][0-9]{13}$/)) valid_type = 'American Express'; 4821 else if (ccNum.test(/^6011[0-9]{12}$/)) valid_type = 'Discover'; 4822 4823 if (valid_type){ 4824 var sum = 0; 4825 var cur = 0; 4826 4827 for (var i=ccNum.length-1; i>=0; --i){ 4828 cur = ccNum.charAt(i).toInt(); 4829 if (cur == 0) continue; 4830 4831 if ((ccNum.length-i) % 2 == 0) cur += cur; 4832 if (cur > 9){ 4833 cur = cur.toString().charAt(0).toInt() + cur.toString().charAt(1).toInt(); 4834 } 4835 4836 sum += cur; 4837 } 4838 if ((sum % 10) == 0) return true; 4839 } 4840 4841 var chunks = ''; 4842 while (ccNum != ''){ 4843 chunks += ' ' + ccNum.substr(0,4); 4844 ccNum = ccNum.substr(4); 4845 } 4846 4847 element.getParent('form').retrieve('validator').ignoreField(element); 4848 element.set('value', chunks.clean()); 4849 element.getParent('form').retrieve('validator').enforceField(element); 4850 return false; 4851 } 4852 }] 4853 4854 4855]); 4856 4857 4858/* 4859--- 4860 4861script: OverText.js 4862 4863name: OverText 4864 4865description: Shows text over an input that disappears when the user clicks into it. The text remains hidden if the user adds a value. 4866 4867license: MIT-style license 4868 4869authors: 4870 - Aaron Newton 4871 4872requires: 4873 - Core/Options 4874 - Core/Events 4875 - Core/Element.Event 4876 - Class.Binds 4877 - Class.Occlude 4878 - Element.Position 4879 - Element.Shortcuts 4880 4881provides: [OverText] 4882 4883... 4884*/ 4885 4886var OverText = new Class({ 4887 4888 Implements: [Options, Events, Class.Occlude], 4889 4890 Binds: ['reposition', 'assert', 'focus', 'hide'], 4891 4892 options: {/* 4893 textOverride: null, 4894 onFocus: function(){}, 4895 onTextHide: function(textEl, inputEl){}, 4896 onTextShow: function(textEl, inputEl){}, */ 4897 element: 'label', 4898 labelClass: 'overTxtLabel', 4899 positionOptions: { 4900 position: 'upperLeft', 4901 edge: 'upperLeft', 4902 offset: { 4903 x: 4, 4904 y: 2 4905 } 4906 }, 4907 poll: false, 4908 pollInterval: 250, 4909 wrap: false 4910 }, 4911 4912 property: 'OverText', 4913 4914 initialize: function(element, options){ 4915 element = this.element = document.id(element); 4916 4917 if (this.occlude()) return this.occluded; 4918 this.setOptions(options); 4919 4920 this.attach(element); 4921 OverText.instances.push(this); 4922 4923 if (this.options.poll) this.poll(); 4924 }, 4925 4926 toElement: function(){ 4927 return this.element; 4928 }, 4929 4930 attach: function(){ 4931 var element = this.element, 4932 options = this.options, 4933 value = options.textOverride || element.get('alt') || element.get('title'); 4934 4935 if (!value) return this; 4936 4937 var text = this.text = new Element(options.element, { 4938 'class': options.labelClass, 4939 styles: { 4940 lineHeight: 'normal', 4941 position: 'absolute', 4942 cursor: 'text' 4943 }, 4944 html: value, 4945 events: { 4946 click: this.hide.pass(options.element == 'label', this) 4947 } 4948 }).inject(element, 'after'); 4949 4950 if (options.element == 'label'){ 4951 if (!element.get('id')) element.set('id', 'input_' + String.uniqueID()); 4952 text.set('for', element.get('id')); 4953 } 4954 4955 if (options.wrap){ 4956 this.textHolder = new Element('div.overTxtWrapper', { 4957 styles: { 4958 lineHeight: 'normal', 4959 position: 'relative' 4960 } 4961 }).grab(text).inject(element, 'before'); 4962 } 4963 4964 return this.enable(); 4965 }, 4966 4967 destroy: function(){ 4968 this.element.eliminate(this.property); // Class.Occlude storage 4969 this.disable(); 4970 if (this.text) this.text.destroy(); 4971 if (this.textHolder) this.textHolder.destroy(); 4972 return this; 4973 }, 4974 4975 disable: function(){ 4976 this.element.removeEvents({ 4977 focus: this.focus, 4978 blur: this.assert, 4979 change: this.assert 4980 }); 4981 window.removeEvent('resize', this.reposition); 4982 this.hide(true, true); 4983 return this; 4984 }, 4985 4986 enable: function(){ 4987 this.element.addEvents({ 4988 focus: this.focus, 4989 blur: this.assert, 4990 change: this.assert 4991 }); 4992 window.addEvent('resize', this.reposition); 4993 this.reposition(); 4994 return this; 4995 }, 4996 4997 wrap: function(){ 4998 if (this.options.element == 'label'){ 4999 if (!this.element.get('id')) this.element.set('id', 'input_' + String.uniqueID()); 5000 this.text.set('for', this.element.get('id')); 5001 } 5002 }, 5003 5004 startPolling: function(){ 5005 this.pollingPaused = false; 5006 return this.poll(); 5007 }, 5008 5009 poll: function(stop){ 5010 //start immediately 5011 //pause on focus 5012 //resumeon blur 5013 if (this.poller && !stop) return this; 5014 if (stop){ 5015 clearInterval(this.poller); 5016 } else { 5017 this.poller = (function(){ 5018 if (!this.pollingPaused) this.assert(true); 5019 }).periodical(this.options.pollInterval, this); 5020 } 5021 5022 return this; 5023 }, 5024 5025 stopPolling: function(){ 5026 this.pollingPaused = true; 5027 return this.poll(true); 5028 }, 5029 5030 focus: function(){ 5031 if (this.text && (!this.text.isDisplayed() || this.element.get('disabled'))) return this; 5032 return this.hide(); 5033 }, 5034 5035 hide: function(suppressFocus, force){ 5036 if (this.text && (this.text.isDisplayed() && (!this.element.get('disabled') || force))){ 5037 this.text.hide(); 5038 this.fireEvent('textHide', [this.text, this.element]); 5039 this.pollingPaused = true; 5040 if (!suppressFocus){
5041 try { 5042 this.element.fireEvent('focus'); 5043 this.element.focus(); 5044 } catch(e){} //IE barfs if you call focus on hidden elements 5045 } 5046 } 5047 return this; 5048 }, 5049 5050 show: function(){ 5051 if (this.text && !this.text.isDisplayed()){ 5052 this.text.show(); 5053 this.reposition(); 5054 this.fireEvent('textShow', [this.text, this.element]); 5055 this.pollingPaused = false; 5056 } 5057 return this; 5058 }, 5059 5060 test: function(){ 5061 return !this.element.get('value'); 5062 }, 5063 5064 assert: function(suppressFocus){ 5065 return this[this.test() ? 'show' : 'hide'](suppressFocus); 5066 }, 5067 5068 reposition: function(){ 5069 this.assert(true); 5070 if (!this.element.isVisible()) return this.stopPolling().hide(); 5071 if (this.text && this.test()){ 5072 this.text.position(Object.merge(this.options.positionOptions, { 5073 relativeTo: this.element 5074 })); 5075 } 5076 return this; 5077 } 5078 5079}); 5080 5081OverText.instances = []; 5082 5083Object.append(OverText, { 5084 5085 each: function(fn){ 5086 return OverText.instances.each(function(ot, i){ 5087 if (ot.element && ot.text) fn.call(OverText, ot, i); 5088 }); 5089 }, 5090 5091 update: function(){ 5092 5093 return OverText.each(function(ot){ 5094 return ot.reposition(); 5095 }); 5096 5097 }, 5098 5099 hideAll: function(){ 5100 5101 return OverText.each(function(ot){ 5102 return ot.hide(true, true); 5103 }); 5104 5105 }, 5106 5107 showAll: function(){ 5108 return OverText.each(function(ot){ 5109 return ot.show(); 5110 }); 5111 } 5112 5113}); 5114 5115 5116 5117/* 5118--- 5119 5120script: Fx.Elements.js 5121 5122name: Fx.Elements 5123 5124description: Effect to change any number of CSS properties of any number of Elements. 5125 5126license: MIT-style license 5127 5128authors: 5129 - Valerio Proietti 5130 5131requires: 5132 - Core/Fx.CSS 5133 - /MooTools.More 5134 5135provides: [Fx.Elements] 5136 5137... 5138*/ 5139 5140Fx.Elements = new Class({ 5141 5142 Extends: Fx.CSS, 5143 5144 initialize: function(elements, options){ 5145 this.elements = this.subject = $$(elements); 5146 this.parent(options); 5147 }, 5148 5149 compute: function(from, to, delta){ 5150 var now = {}; 5151 5152 for (var i in from){ 5153 var iFrom = from[i], iTo = to[i], iNow = now[i] = {}; 5154 for (var p in iFrom) iNow[p] = this.parent(iFrom[p], iTo[p], delta); 5155 } 5156 5157 return now; 5158 }, 5159 5160 set: function(now){ 5161 for (var i in now){ 5162 if (!this.elements[i]) continue; 5163 5164 var iNow = now[i]; 5165 for (var p in iNow) this.render(this.elements[i], p, iNow[p], this.options.unit); 5166 } 5167 5168 return this; 5169 }, 5170 5171 start: function(obj){ 5172 if (!this.check(obj)) return this; 5173 var from = {}, to = {}; 5174 5175 for (var i in obj){ 5176 if (!this.elements[i]) continue; 5177 5178 var iProps = obj[i], iFrom = from[i] = {}, iTo = to[i] = {}; 5179 5180 for (var p in iProps){ 5181 var parsed = this.prepare(this.elements[i], p, iProps[p]); 5182 iFrom[p] = parsed.from; 5183 iTo[p] = parsed.to; 5184 } 5185 } 5186 5187 return this.parent(from, to); 5188 } 5189 5190}); 5191 5192 5193/* 5194--- 5195 5196script: Fx.Accordion.js 5197 5198name: Fx.Accordion 5199 5200description: An Fx.Elements extension which allows you to easily create accordion type controls. 5201 5202license: MIT-style license 5203 5204authors: 5205 - Valerio Proietti 5206 5207requires: 5208 - Core/Element.Event 5209 - /Fx.Elements 5210 5211provides: [Fx.Accordion] 5212 5213... 5214*/ 5215 5216Fx.Accordion = new Class({ 5217 5218 Extends: Fx.Elements, 5219 5220 options: {/* 5221 onActive: function(toggler, section){}, 5222 onBackground: function(toggler, section){},*/ 5223 fixedHeight: false, 5224 fixedWidth: false, 5225 display: 0, 5226 show: false, 5227 height: true, 5228 width: false, 5229 opacity: true, 5230 alwaysHide: false, 5231 trigger: 'click', 5232 initialDisplayFx: true, 5233 resetHeight: true 5234 }, 5235 5236 initialize: function(){ 5237 var defined = function(obj){ 5238 return obj != null; 5239 }; 5240 5241 var params = Array.link(arguments, { 5242 'container': Type.isElement, //deprecated 5243 'options': Type.isObject, 5244 'togglers': defined, 5245 'elements': defined 5246 }); 5247 this.parent(params.elements, params.options); 5248 5249 var options = this.options, 5250 togglers = this.togglers = $$(params.togglers); 5251 5252 this.previous = -1; 5253 this.internalChain = new Chain(); 5254 5255 if (options.alwaysHide) this.options.link = 'chain'; 5256 5257 if (options.show || this.options.show === 0){ 5258 options.display = false; 5259 this.previous = options.show; 5260 } 5261 5262 if (options.start){ 5263 options.display = false; 5264 options.show = false; 5265 } 5266 5267 var effects = this.effects = {}; 5268 5269 if (options.opacity) effects.opacity = 'fullOpacity'; 5270 if (options.width) effects.width = options.fixedWidth ? 'fullWidth' : 'offsetWidth'; 5271 if (options.height) effects.height = options.fixedHeight ? 'fullHeight' : 'scrollHeight';
5272 5273 for (var i = 0, l = togglers.length; i < l; i++) this.addSection(togglers[i], this.elements[i]); 5274 5275 this.elements.each(function(el, i){ 5276 if (options.show === i){ 5277 this.fireEvent('active', [togglers[i], el]); 5278 } else { 5279 for (var fx in effects) el.setStyle(fx, 0); 5280 } 5281 }, this); 5282 5283 if (options.display || options.display === 0 || options.initialDisplayFx === false){ 5284 this.display(options.display, options.initialDisplayFx); 5285 } 5286 5287 if (options.fixedHeight !== false) options.resetHeight = false; 5288 this.addEvent('complete', this.internalChain.callChain.bind(this.internalChain)); 5289 }, 5290 5291 addSection: function(toggler, element){ 5292 toggler = document.id(toggler); 5293 element = document.id(element); 5294 this.togglers.include(toggler); 5295 this.elements.include(element); 5296 5297 var togglers = this.togglers, 5298 options = this.options, 5299 test = togglers.contains(toggler), 5300 idx = togglers.indexOf(toggler), 5301 displayer = this.display.pass(idx, this); 5302 5303 toggler.store('accordion:display', displayer) 5304 .addEvent(options.trigger, displayer); 5305 5306 if (options.height) element.setStyles({'padding-top': 0, 'border-top': 'none', 'padding-bottom': 0, 'border-bottom': 'none'}); 5307 if (options.width) element.setStyles({'padding-left': 0, 'border-left': 'none', 'padding-right': 0, 'border-right': 'none'}); 5308 5309 element.fullOpacity = 1; 5310 if (options.fixedWidth) element.fullWidth = options.fixedWidth; 5311 if (options.fixedHeight) element.fullHeight = options.fixedHeight; 5312 element.setStyle('overflow', 'hidden'); 5313 5314 if (!test) for (var fx in this.effects){ 5315 element.setStyle(fx, 0); 5316 } 5317 return this; 5318 }, 5319 5320 removeSection: function(toggler, displayIndex){ 5321 var togglers = this.togglers, 5322 idx = togglers.indexOf(toggler), 5323 element = this.elements[idx]; 5324 5325 var remover = function(){ 5326 togglers.erase(toggler); 5327 this.elements.erase(element); 5328 this.detach(toggler); 5329 }.bind(this); 5330 5331 if (this.now == idx || displayIndex != null){ 5332 this.display(displayIndex != null ? displayIndex : (idx - 1 >= 0 ? idx - 1 : 0)).chain(remover); 5333 } else { 5334 remover(); 5335 } 5336 return this; 5337 }, 5338 5339 detach: function(toggler){ 5340 var remove = function(toggler){ 5341 toggler.removeEvent(this.options.trigger, toggler.retrieve('accordion:display')); 5342 }.bind(this); 5343 5344 if (!toggler) this.togglers.each(remove); 5345 else remove(toggler); 5346 return this; 5347 }, 5348 5349 display: function(index, useFx){ 5350 if (!this.check(index, useFx)) return this; 5351 5352 var obj = {}, 5353 elements = this.elements, 5354 options = this.options, 5355 effects = this.effects; 5356 5357 if (useFx == null) useFx = true; 5358 if (typeOf(index) == 'element') index = elements.indexOf(index); 5359 if (index == this.previous && !options.alwaysHide) return this; 5360 5361 if (options.resetHeight){ 5362 var prev = elements[this.previous]; 5363 if (prev && !this.selfHidden){ 5364 for (var fx in effects) prev.setStyle(fx, prev[effects[fx]]); 5365 } 5366 } 5367 5368 if ((this.timer && options.link == 'chain') || (index === this.previous && !options.alwaysHide)) return this; 5369 5370 this.previous = index; 5371 this.selfHidden = false; 5372 5373 elements.each(function(el, i){ 5374 obj[i] = {}; 5375 var hide; 5376 if (i != index){ 5377 hide = true; 5378 } else if (options.alwaysHide && ((el.offsetHeight > 0 && options.height) || el.offsetWidth > 0 && options.width)){ 5379 hide = true; 5380 this.selfHidden = true; 5381 } 5382 this.fireEvent(hide ? 'background' : 'active', [this.togglers[i], el]); 5383 for (var fx in effects) obj[i][fx] = hide ? 0 : el[effects[fx]]; 5384 if (!useFx && !hide && options.resetHeight) obj[i].height = 'auto'; 5385 }, this); 5386 5387 this.internalChain.clearChain(); 5388 this.internalChain.chain(function(){ 5389 if (options.resetHeight && !this.selfHidden){ 5390 var el = elements[index]; 5391 if (el) el.setStyle('height', 'auto'); 5392 } 5393 }.bind(this)); 5394 5395 return useFx ? this.start(obj) : this.set(obj).internalChain.callChain(); 5396 } 5397 5398}); 5399 5400/*<1.2compat>*/ 5401/* 5402 Compatibility with 1.2.0 5403*/ 5404var Accordion = new Class({ 5405 5406 Extends: Fx.Accordion, 5407 5408 initialize: function(){ 5409 this.parent.apply(this, arguments); 5410 var params = Array.link(arguments, {'container': Type.isElement}); 5411 this.container = params.container; 5412 }, 5413 5414 addSection: function(toggler, element, pos){ 5415 toggler = document.id(toggler); 5416 element = document.id(element); 5417 5418 var test = this.togglers.contains(toggler); 5419 var len = this.togglers.length; 5420 if (len && (!test || pos)){ 5421 pos = pos != null ? pos : len - 1; 5422 toggler.inject(this.togglers[pos], 'before'); 5423 element.inject(toggler, 'after'); 5424 } else if (this.container && !test){ 5425 toggler.inject(this.container); 5426 element.inject(this.container); 5427 } 5428 return this.parent.apply(this, arguments); 5429 } 5430 5431}); 5432/*</1.2compat>*/ 5433 5434 5435/* 5436--- 5437 5438script: Fx.Move.js 5439 5440name: Fx.Move 5441 5442description: Defines Fx.Move, a class that works with Element.Position.js to transition an element from one location to another. 5443 5444license: MIT-style license 5445 5446authors: 5447 - Aaron Newton 5448 5449requires: 5450 - Core/Fx.Morph 5451 - /Element.Position 5452 5453provides: [Fx.Move] 5454 5455... 5456*/ 5457 5458Fx.Move = new Class({ 5459 5460 Extends: Fx.Morph, 5461 5462 options: { 5463 relativeTo: document.body, 5464 position: 'center', 5465 edge: false, 5466 offset: {x: 0, y: 0} 5467 }, 5468 5469 start: function(destination){ 5470 var element = this.element, 5471 topLeft = element.getStyles('top', 'left'); 5472 if (topLeft.top == 'auto' || topLeft.left == 'auto'){ 5473 element.setPosition(element.getPosition(element.getOffsetParent())); 5474 } 5475 return this.parent(element.position(Object.merge({}, this.options, destination, {returnPos: true}))); 5476 } 5477 5478}); 5479 5480Element.Properties.move = { 5481 5482 set: function(options){ 5483 this.get('move').cancel().setOptions(options); 5484 return this; 5485 }, 5486 5487 get: function(){ 5488 var move = this.retrieve('move'); 5489 if (!move){ 5490 move = new Fx.Move(this, {link: 'cancel'}); 5491 this.store('move', move); 5492 } 5493 return move; 5494 } 5495 5496}; 5497 5498Element.implement({ 5499 5500 move: function(options){ 5501 this.get('move').start(options); 5502 return this; 5503 } 5504 5505}); 5506 5507 5508/* 5509--- 5510 5511script: Fx.Scroll.js 5512 5513name: Fx.Scroll 5514 5515description: Effect to smoothly scroll any element, including the window. 5516 5517license: MIT-style license 5518 5519authors: 5520 - Valerio Proietti 5521 5522requires: 5523 - Core/Fx 5524 - Core/Element.Event 5525 - Core/Element.Dimensions
5526 - /MooTools.More 5527 5528provides: [Fx.Scroll] 5529 5530... 5531*/ 5532 5533(function(){ 5534 5535Fx.Scroll = new Class({ 5536 5537 Extends: Fx, 5538 5539 options: { 5540 offset: {x: 0, y: 0}, 5541 wheelStops: true 5542 }, 5543 5544 initialize: function(element, options){ 5545 this.element = this.subject = document.id(element); 5546 this.parent(options); 5547 5548 if (typeOf(this.element) != 'element') this.element = document.id(this.element.getDocument().body); 5549 5550 if (this.options.wheelStops){ 5551 var stopper = this.element, 5552 cancel = this.cancel.pass(false, this); 5553 this.addEvent('start', function(){ 5554 stopper.addEvent('mousewheel', cancel); 5555 }, true); 5556 this.addEvent('complete', function(){ 5557 stopper.removeEvent('mousewheel', cancel); 5558 }, true); 5559 } 5560 }, 5561 5562 set: function(){ 5563 var now = Array.flatten(arguments); 5564 if (Browser.firefox) now = [Math.round(now[0]), Math.round(now[1])]; // not needed anymore in newer firefox versions 5565 this.element.scrollTo(now[0], now[1]); 5566 return this; 5567 }, 5568 5569 compute: function(from, to, delta){ 5570 return [0, 1].map(function(i){ 5571 return Fx.compute(from[i], to[i], delta); 5572 }); 5573 }, 5574 5575 start: function(x, y){ 5576 if (!this.check(x, y)) return this; 5577 var scroll = this.element.getScroll(); 5578 return this.parent([scroll.x, scroll.y], [x, y]); 5579 }, 5580 5581 calculateScroll: function(x, y){ 5582 var element = this.element, 5583 scrollSize = element.getScrollSize(), 5584 scroll = element.getScroll(), 5585 size = element.getSize(), 5586 offset = this.options.offset, 5587 values = {x: x, y: y}; 5588 5589 for (var z in values){ 5590 if (!values[z] && values[z] !== 0) values[z] = scroll[z]; 5591 if (typeOf(values[z]) != 'number') values[z] = scrollSize[z] - size[z]; 5592 values[z] += offset[z]; 5593 } 5594 5595 return [values.x, values.y]; 5596 }, 5597 5598 toTop: function(){ 5599 return this.start.apply(this, this.calculateScroll(false, 0)); 5600 }, 5601 5602 toLeft: function(){ 5603 return this.start.apply(this, this.calculateScroll(0, false)); 5604 }, 5605 5606 toRight: function(){ 5607 return this.start.apply(this, this.calculateScroll('right', false)); 5608 }, 5609 5610 toBottom: function(){ 5611 return this.start.apply(this, this.calculateScroll(false, 'bottom')); 5612 }, 5613 5614 toElement: function(el, axes){ 5615 axes = axes ? Array.from(axes) : ['x', 'y']; 5616 var scroll = isBody(this.element) ? {x: 0, y: 0} : this.element.getScroll(); 5617 var position = Object.map(document.id(el).getPosition(this.element), function(value, axis){ 5618 return axes.contains(axis) ? value + scroll[axis] : false; 5619 }); 5620 return this.start.apply(this, this.calculateScroll(position.x, position.y)); 5621 }, 5622 5623 toElementEdge: function(el, axes, offset){ 5624 axes = axes ? Array.from(axes) : ['x', 'y']; 5625 el = document.id(el); 5626 var to = {}, 5627 position = el.getPosition(this.element), 5628 size = el.getSize(), 5629 scroll = this.element.getScroll(), 5630 containerSize = this.element.getSize(), 5631 edge = { 5632 x: position.x + size.x, 5633 y: position.y + size.y 5634 }; 5635 5636 ['x', 'y'].each(function(axis){ 5637 if (axes.contains(axis)){ 5638 if (edge[axis] > scroll[axis] + containerSize[axis]) to[axis] = edge[axis] - containerSize[axis]; 5639 if (position[axis] < scroll[axis]) to[axis] = position[axis]; 5640 } 5641 if (to[axis] == null) to[axis] = scroll[axis]; 5642 if (offset && offset[axis]) to[axis] = to[axis] + offset[axis]; 5643 }, this); 5644 5645 if (to.x != scroll.x || to.y != scroll.y) this.start(to.x, to.y); 5646 return this; 5647 }, 5648 5649 toElementCenter: function(el, axes, offset){ 5650 axes = axes ? Array.from(axes) : ['x', 'y']; 5651 el = document.id(el); 5652 var to = {}, 5653 position = el.getPosition(this.element), 5654 size = el.getSize(), 5655 scroll = this.element.getScroll(), 5656 containerSize = this.element.getSize(); 5657 5658 ['x', 'y'].each(function(axis){ 5659 if (axes.contains(axis)){ 5660 to[axis] = position[axis] - (containerSize[axis] - size[axis]) / 2; 5661 } 5662 if (to[axis] == null) to[axis] = scroll[axis]; 5663 if (offset && offset[axis]) to[axis] = to[axis] + offset[axis]; 5664 }, this); 5665 5666 if (to.x != scroll.x || to.y != scroll.y) this.start(to.x, to.y); 5667 return this; 5668 } 5669 5670}); 5671 5672//<1.2compat> 5673Fx.Scroll.implement({ 5674 scrollToCenter: function(){ 5675 return this.toElementCenter.apply(this, arguments); 5676 }, 5677 scrollIntoView: function(){ 5678 return this.toElementEdge.apply(this, arguments); 5679 } 5680}); 5681//</1.2compat> 5682 5683function isBody(element){ 5684 return (/^(?:body|html)$/i).test(element.tagName); 5685} 5686 5687})(); 5688 5689 5690/* 5691--- 5692 5693script: Fx.Slide.js 5694 5695name: Fx.Slide 5696 5697description: Effect to slide an element in and out of view. 5698 5699license: MIT-style license 5700 5701authors: 5702 - Valerio Proietti 5703 5704requires: 5705 - Core/Fx 5706 - Core/Element.Style 5707 - /MooTools.More 5708 5709provides: [Fx.Slide] 5710 5711... 5712*/ 5713 5714Fx.Slide = new Class({ 5715 5716 Extends: Fx, 5717 5718 options: { 5719 mode: 'vertical', 5720 wrapper: false, 5721 hideOverflow: true, 5722 resetHeight: false 5723 }, 5724 5725 initialize: function(element, options){ 5726 element = this.element = this.subject = document.id(element); 5727 this.parent(options); 5728 options = this.options; 5729 5730 var wrapper = element.retrieve('wrapper'), 5731 styles = element.getStyles('margin', 'position', 'overflow'); 5732 5733 if (options.hideOverflow) styles = Object.append(styles, {overflow: 'hidden'}); 5734 if (options.wrapper) wrapper = document.id(options.wrapper).setStyles(styles); 5735 5736 if (!wrapper) wrapper = new Element('div', { 5737 styles: styles 5738 }).wraps(element); 5739 5740 element.store('wrapper', wrapper).setStyle('margin', 0); 5741 if (element.getStyle('overflow') == 'visible') element.setStyle('overflow', 'hidden'); 5742 5743 this.now = []; 5744 this.open = true; 5745 this.wrapper = wrapper; 5746 5747 this.addEvent('complete', function(){ 5748 this.open = (wrapper['offset' + this.layout.capitalize()] != 0); 5749 if (this.open && this.options.resetHeight) wrapper.setStyle('height', ''); 5750 }, true); 5751 }, 5752 5753 vertical: function(){ 5754 this.margin = 'margin-top'; 5755 this.layout = 'height';
5756 this.offset = this.element.offsetHeight; 5757 }, 5758 5759 horizontal: function(){ 5760 this.margin = 'margin-left'; 5761 this.layout = 'width'; 5762 this.offset = this.element.offsetWidth; 5763 }, 5764 5765 set: function(now){ 5766 this.element.setStyle(this.margin, now[0]); 5767 this.wrapper.setStyle(this.layout, now[1]); 5768 return this; 5769 }, 5770 5771 compute: function(from, to, delta){ 5772 return [0, 1].map(function(i){ 5773 return Fx.compute(from[i], to[i], delta); 5774 }); 5775 }, 5776 5777 start: function(how, mode){ 5778 if (!this.check(how, mode)) return this; 5779 this[mode || this.options.mode](); 5780 5781 var margin = this.element.getStyle(this.margin).toInt(), 5782 layout = this.wrapper.getStyle(this.layout).toInt(), 5783 caseIn = [[margin, layout], [0, this.offset]], 5784 caseOut = [[margin, layout], [-this.offset, 0]], 5785 start; 5786 5787 switch (how){ 5788 case 'in': start = caseIn; break; 5789 case 'out': start = caseOut; break; 5790 case 'toggle': start = (layout == 0) ? caseIn : caseOut; 5791 } 5792 return this.parent(start[0], start[1]); 5793 }, 5794 5795 slideIn: function(mode){ 5796 return this.start('in', mode); 5797 }, 5798 5799 slideOut: function(mode){ 5800 return this.start('out', mode); 5801 }, 5802 5803 hide: function(mode){ 5804 this[mode || this.options.mode](); 5805 this.open = false; 5806 return this.set([-this.offset, 0]); 5807 }, 5808 5809 show: function(mode){ 5810 this[mode || this.options.mode](); 5811 this.open = true; 5812 return this.set([0, this.offset]); 5813 }, 5814 5815 toggle: function(mode){ 5816 return this.start('toggle', mode); 5817 } 5818 5819}); 5820 5821Element.Properties.slide = { 5822 5823 set: function(options){ 5824 this.get('slide').cancel().setOptions(options); 5825 return this; 5826 }, 5827 5828 get: function(){ 5829 var slide = this.retrieve('slide'); 5830 if (!slide){ 5831 slide = new Fx.Slide(this, {link: 'cancel'}); 5832 this.store('slide', slide); 5833 } 5834 return slide; 5835 } 5836 5837}; 5838 5839Element.implement({ 5840 5841 slide: function(how, mode){ 5842 how = how || 'toggle'; 5843 var slide = this.get('slide'), toggle; 5844 switch (how){ 5845 case 'hide': slide.hide(mode); break; 5846 case 'show': slide.show(mode); break; 5847 case 'toggle': 5848 var flag = this.retrieve('slide:flag', slide.open); 5849 slide[flag ? 'slideOut' : 'slideIn'](mode); 5850 this.store('slide:flag', !flag); 5851 toggle = true; 5852 break; 5853 default: slide.start(how, mode); 5854 } 5855 if (!toggle) this.eliminate('slide:flag'); 5856 return this; 5857 } 5858 5859}); 5860 5861 5862/* 5863--- 5864 5865script: Fx.SmoothScroll.js 5866 5867name: Fx.SmoothScroll 5868 5869description: Class for creating a smooth scrolling effect to all internal links on the page. 5870 5871license: MIT-style license 5872 5873authors: 5874 - Valerio Proietti 5875 5876requires: 5877 - Core/Slick.Finder 5878 - /Fx.Scroll 5879 5880provides: [Fx.SmoothScroll] 5881 5882... 5883*/ 5884 5885/*<1.2compat>*/var SmoothScroll = /*</1.2compat>*/Fx.SmoothScroll = new Class({ 5886 5887 Extends: Fx.Scroll, 5888 5889 options: { 5890 axes: ['x', 'y'] 5891 }, 5892 5893 initialize: function(options, context){ 5894 context = context || document; 5895 this.doc = context.getDocument(); 5896 this.parent(this.doc, options); 5897 5898 var win = context.getWindow(), 5899 location = win.location.href.match(/^[^#]*/)[0] + '#', 5900 links = $$(this.options.links || this.doc.links); 5901 5902 links.each(function(link){ 5903 if (link.href.indexOf(location) != 0) return; 5904 var anchor = link.href.substr(location.length); 5905 if (anchor) this.useLink(link, anchor); 5906 }, this); 5907 5908 this.addEvent('complete', function(){ 5909 win.location.hash = this.anchor; 5910 this.element.scrollTo(this.to[0], this.to[1]); 5911 }, true); 5912 }, 5913 5914 useLink: function(link, anchor){ 5915 5916 link.addEvent('click', function(event){ 5917 var el = document.id(anchor) || this.doc.getElement('a[name=' + anchor + ']'); 5918 if (!el) return; 5919 5920 event.preventDefault(); 5921 this.toElement(el, this.options.axes).chain(function(){ 5922 this.fireEvent('scrolledTo', [link, el]); 5923 }.bind(this)); 5924 5925 this.anchor = anchor; 5926 5927 }.bind(this)); 5928 5929 return this; 5930 } 5931}); 5932 5933 5934/* 5935--- 5936 5937script: Fx.Sort.js 5938 5939name: Fx.Sort 5940 5941description: Defines Fx.Sort, a class that reorders lists with a transition. 5942 5943license: MIT-style license 5944 5945authors: 5946 - Aaron Newton 5947 5948requires: 5949 - Core/Element.Dimensions 5950 - /Fx.Elements 5951 - /Element.Measure 5952 5953provides: [Fx.Sort] 5954 5955... 5956*/ 5957 5958Fx.Sort = new Class({ 5959 5960 Extends: Fx.Elements, 5961 5962 options: { 5963 mode: 'vertical' 5964 }, 5965 5966 initialize: function(elements, options){ 5967 this.parent(elements, options); 5968 this.elements.each(function(el){ 5969 if (el.getStyle('position') == 'static') el.setStyle('position', 'relative'); 5970 }); 5971 this.setDefaultOrder(); 5972 }, 5973 5974 setDefaultOrder: function(){ 5975 this.currentOrder = this.elements.map(function(el, index){ 5976 return index; 5977 }); 5978 }, 5979 5980 sort: function(){ 5981 if (!this.check(arguments)) return this; 5982 var newOrder = Array.flatten(arguments); 5983 5984 var top = 0, 5985 left = 0, 5986 next = {}, 5987 zero = {}, 5988 vert = this.options.mode == 'vertical'; 5989 5990 var current = this.elements.map(function(el, index){ 5991 var size = el.getComputedSize({styles: ['border', 'padding', 'margin']}); 5992 var val; 5993 if (vert){ 5994 val = { 5995 top: top, 5996 margin: size['margin-top'], 5997 height: size.totalHeight 5998 }; 5999 top += val.height - size['margin-top']; 6000 } else { 6001 val = { 6002 left: left, 6003 margin: size['margin-left'], 6004 width: size.totalWidth 6005 }; 6006 left += val.width; 6007 } 6008 var plane = vert ? 'top' : 'left'; 6009 zero[index] = {}; 6010 var start = el.getStyle(plane).toInt(); 6011 zero[index][plane] = start || 0; 6012 return val; 6013 }, this); 6014 6015 this.set(zero); 6016 newOrder = newOrder.map(function(i){ return i.toInt(); }); 6017 if (newOrder.length != this.elements.length){ 6018 this.currentOrder.each(function(index){ 6019 if (!newOrder.contains(index)) newOrder.push(index); 6020 }); 6021 if (newOrder.length > this.elements.length) 6022 newOrder.splice(this.elements.length-1, newOrder.length - this.elements.length); 6023 } 6024 var margin = 0; 6025 top = left = 0; 6026 newOrder.each(function(item){ 6027 var newPos = {}; 6028 if (vert){ 6029 newPos.top = top - current[item].top - margin; 6030 top += current[item].height; 6031 } else { 6032 newPos.left = left - current[item].left; 6033 left += current[item].width; 6034 } 6035 margin = margin + current[item].margin; 6036 next[item]=newPos; 6037 }, this); 6038 var mapped = {}; 6039 Array.clone(newOrder).sort().each(function(index){ 6040 mapped[index] = next[index]; 6041 }); 6042 this.start(mapped); 6043 this.currentOrder = newOrder; 6044 6045 return this; 6046 }, 6047 6048 rearrangeDOM: function(newOrder){ 6049 newOrder = newOrder || this.currentOrder; 6050 var parent = this.elements[0].getParent(); 6051 var rearranged = []; 6052 this.elements.setStyle('opacity', 0); 6053 //move each element and store the new default order 6054 newOrder.each(function(index){ 6055 rearranged.push(this.elements[index].inject(parent).setStyles({ 6056 top: 0, 6057 left: 0 6058 })); 6059 }, this); 6060 this.elements.setStyle('opacity', 1); 6061 this.elements = $$(rearranged); 6062 this.setDefaultOrder(); 6063 return this; 6064 }, 6065 6066 getDefaultOrder: function(){ 6067 return this.elements.map(function(el, index){ 6068 return index; 6069 }); 6070 }, 6071 6072 getCurrentOrder: function(){ 6073 return this.currentOrder; 6074 }, 6075 6076 forward: function(){ 6077 return this.sort(this.getDefaultOrder()); 6078 }, 6079 6080 backward: function(){ 6081 return this.sort(this.getDefaultOrder().reverse()); 6082 }, 6083 6084 reverse: function(){ 6085 return this.sort(this.currentOrder.reverse()); 6086 }, 6087 6088 sortByElements: function(elements){ 6089 return this.sort(elements.map(function(el){ 6090 return this.elements.indexOf(el); 6091 }, this)); 6092 }, 6093 6094 swap: function(one, two){ 6095 if (typeOf(one) == 'element') one = this.elements.indexOf(one); 6096 if (typeOf(two) == 'element') two = this.elements.indexOf(two); 6097 6098 var newOrder = Array.clone(this.currentOrder); 6099 newOrder[this.currentOrder.indexOf(one)] = two; 6100 newOrder[this.currentOrder.indexOf(two)] = one; 6101 6102 return this.sort(newOrder); 6103 } 6104 6105}); 6106 6107 6108/* 6109--- 6110 6111script: Assets.js 6112 6113name: Assets 6114 6115description: Provides methods to dynamically load JavaScript, CSS, and Image files into the document. 6116 6117license: MIT-style license 6118 6119authors: 6120 - Valerio Proietti 6121 6122requires: 6123 - Core/Element.Event 6124 - /MooTools.More 6125 6126provides: [Assets] 6127 6128... 6129*/ 6130 6131var Asset = { 6132 6133 javascript: function(source, properties){ 6134 if (!properties) properties = {}; 6135 6136 var script = new Element('script', {src: source, type: 'text/javascript'}), 6137 doc = properties.document || document, 6138 load = properties.onload || properties.onLoad; 6139 6140 delete properties.onload; 6141 delete properties.onLoad; 6142 delete properties.document; 6143 6144 if (load){ 6145 if (typeof script.onreadystatechange != 'undefined'){ 6146 script.addEvent('readystatechange', function(){ 6147 if (['loaded', 'complete'].contains(this.readyState)) load.call(this); 6148 }); 6149 } else { 6150 script.addEvent('load', load); 6151 } 6152 } 6153 6154 return script.set(properties).inject(doc.head); 6155 }, 6156 6157 css: function(source, properties){ 6158 if (!properties) properties = {}; 6159 6160 var link = new Element('link', { 6161 rel: 'stylesheet', 6162 media: 'screen', 6163 type: 'text/css', 6164 href: source 6165 }); 6166 6167 var load = properties.onload || properties.onLoad, 6168 doc = properties.document || document; 6169 6170 delete properties.onload; 6171 delete properties.onLoad; 6172 delete properties.document; 6173 6174 if (load) link.addEvent('load', load); 6175 return link.set(properties).inject(doc.head); 6176 }, 6177 6178 image: function(source, properties){ 6179 if (!properties) properties = {}; 6180 6181 var image = new Image(), 6182 element = document.id(image) || new Element('img'); 6183 6184 ['load', 'abort', 'error'].each(function(name){ 6185 var type = 'on' + name, 6186 cap = 'on' + name.capitalize(), 6187 event = properties[type] || properties[cap] || function(){}; 6188 6189 delete properties[cap]; 6190 delete properties[type]; 6191 6192 image[type] = function(){ 6193 if (!image) return; 6194 if (!element.parentNode){ 6195 element.width = image.width; 6196 element.height = image.height; 6197 } 6198 image = image.onload = image.onabort = image.onerror = null; 6199 event.delay(1, element, element); 6200 element.fireEvent(name, element, 1); 6201 }; 6202 }); 6203 6204 image.src = element.src = source; 6205 if (image && image.complete) image.onload.delay(1); 6206 return element.set(properties); 6207 }, 6208 6209 images: function(sources, options){ 6210 sources = Array.from(sources); 6211 6212 var fn = function(){}, 6213 counter = 0; 6214 6215 options = Object.merge({ 6216 onComplete: fn, 6217 onProgress: fn, 6218 onError: fn, 6219 properties: {} 6220 }, options); 6221 6222 return new Elements(sources.map(function(source, index){ 6223 return Asset.image(source, Object.append(options.properties, { 6224 onload: function(){ 6225 counter++; 6226 options.onProgress.call(this, counter, index, source); 6227 if (counter == sources.length) options.onComplete(); 6228 }, 6229 onerror: function(){ 6230 counter++; 6231 options.onError.call(this, counter, index, source); 6232 if (counter == sources.length) options.onComplete(); 6233 } 6234 })); 6235 })); 6236 } 6237 6238}; 6239 6240 6241/* 6242--- 6243 6244script: Hash.Cookie.js 6245 6246name: Hash.Cookie 6247 6248description: Class for creating, reading, and deleting Cookies in JSON format. 6249 6250license: MIT-style license 6251 6252authors: 6253 - Valerio Proietti 6254 - Aaron Newton 6255 6256requires: 6257 - Core/Cookie 6258 - Core/JSON
6259 - /MooTools.More 6260 - /Hash 6261 6262provides: [Hash.Cookie] 6263 6264... 6265*/ 6266 6267Hash.Cookie = new Class({ 6268 6269 Extends: Cookie, 6270 6271 options: { 6272 autoSave: true 6273 }, 6274 6275 initialize: function(name, options){ 6276 this.parent(name, options); 6277 this.load(); 6278 }, 6279 6280 save: function(){ 6281 var value = JSON.encode(this.hash); 6282 if (!value || value.length > 4096) return false; //cookie would be truncated! 6283 if (value == '{}') this.dispose(); 6284 else this.write(value); 6285 return true; 6286 }, 6287 6288 load: function(){ 6289 this.hash = new Hash(JSON.decode(this.read(), true)); 6290 return this; 6291 } 6292 6293}); 6294 6295Hash.each(Hash.prototype, function(method, name){ 6296 if (typeof method == 'function') Hash.Cookie.implement(name, function(){ 6297 var value = method.apply(this.hash, arguments); 6298 if (this.options.autoSave) this.save(); 6299 return value; 6300 }); 6301}); 6302 6303 6304/* 6305--- 6306 6307script: Keyboard.js 6308 6309name: Keyboard 6310 6311description: KeyboardEvents used to intercept events on a class for keyboard and format modifiers in a specific order so as to make alt+shift+c the same as shift+alt+c. 6312 6313license: MIT-style license 6314 6315authors: 6316 - Perrin Westrich 6317 - Aaron Newton 6318 - Scott Kyle 6319 6320requires: 6321 - Core/Events 6322 - Core/Options 6323 - Core/Element.Event 6324 - Element.Event.Pseudos.Keys 6325 6326provides: [Keyboard] 6327 6328... 6329*/ 6330 6331(function(){ 6332 6333 var Keyboard = this.Keyboard = new Class({ 6334 6335 Extends: Events, 6336 6337 Implements: [Options], 6338 6339 options: {/* 6340 onActivate: function(){}, 6341 onDeactivate: function(){},*/ 6342 defaultEventType: 'keydown', 6343 active: false, 6344 manager: null, 6345 events: {}, 6346 nonParsedEvents: ['activate', 'deactivate', 'onactivate', 'ondeactivate', 'changed', 'onchanged'] 6347 }, 6348 6349 initialize: function(options){ 6350 if (options && options.manager){ 6351 this._manager = options.manager; 6352 delete options.manager; 6353 } 6354 this.setOptions(options); 6355 this._setup(); 6356 }, 6357 6358 addEvent: function(type, fn, internal){ 6359 return this.parent(Keyboard.parse(type, this.options.defaultEventType, this.options.nonParsedEvents), fn, internal); 6360 }, 6361 6362 removeEvent: function(type, fn){ 6363 return this.parent(Keyboard.parse(type, this.options.defaultEventType, this.options.nonParsedEvents), fn); 6364 }, 6365 6366 toggleActive: function(){ 6367 return this[this.isActive() ? 'deactivate' : 'activate'](); 6368 }, 6369 6370 activate: function(instance){ 6371 if (instance){ 6372 if (instance.isActive()) return this; 6373 //if we're stealing focus, store the last keyboard to have it so the relinquish command works 6374 if (this._activeKB && instance != this._activeKB){ 6375 this.previous = this._activeKB; 6376 this.previous.fireEvent('deactivate'); 6377 } 6378 //if we're enabling a child, assign it so that events are now passed to it 6379 this._activeKB = instance.fireEvent('activate'); 6380 Keyboard.manager.fireEvent('changed'); 6381 } else if (this._manager){ 6382 //else we're enabling ourselves, we must ask our parent to do it for us 6383 this._manager.activate(this); 6384 } 6385 return this; 6386 }, 6387 6388 isActive: function(){ 6389 return this._manager ? (this._manager._activeKB == this) : (Keyboard.manager == this); 6390 }, 6391 6392 deactivate: function(instance){ 6393 if (instance){ 6394 if (instance === this._activeKB){ 6395 this._activeKB = null; 6396 instance.fireEvent('deactivate'); 6397 Keyboard.manager.fireEvent('changed'); 6398 } 6399 } else if (this._manager){ 6400 this._manager.deactivate(this); 6401 } 6402 return this; 6403 }, 6404 6405 relinquish: function(){ 6406 if (this.isActive() && this._manager && this._manager.previous) this._manager.activate(this._manager.previous); 6407 else this.deactivate(); 6408 return this; 6409 }, 6410 6411 //management logic 6412 manage: function(instance){ 6413 if (instance._manager) instance._manager.drop(instance); 6414 this._instances.push(instance); 6415 instance._manager = this; 6416 if (!this._activeKB) this.activate(instance); 6417 return this; 6418 }, 6419 6420 drop: function(instance){ 6421 instance.relinquish(); 6422 this._instances.erase(instance); 6423 if (this._activeKB == instance){ 6424 if (this.previous && this._instances.contains(this.previous)) this.activate(this.previous); 6425 else this._activeKB = this._instances[0]; 6426 } 6427 return this; 6428 }, 6429 6430 trace: function(){ 6431 Keyboard.trace(this); 6432 }, 6433 6434 each: function(fn){ 6435 Keyboard.each(this, fn); 6436 }, 6437 6438 /* 6439 PRIVATE METHODS 6440 */ 6441 6442 _instances: [], 6443 6444 _disable: function(instance){ 6445 if (this._activeKB == instance) this._activeKB = null; 6446 }, 6447 6448 _setup: function(){ 6449 this.addEvents(this.options.events); 6450 //if this is the root manager, nothing manages it 6451 if (Keyboard.manager && !this._manager) Keyboard.manager.manage(this); 6452 if (this.options.active) this.activate(); 6453 else this.relinquish(); 6454 }, 6455 6456 _handle: function(event, type){ 6457 //Keyboard.stop(event) prevents key propagation 6458 if (event.preventKeyboardPropagation) return; 6459 6460 var bubbles = !!this._manager; 6461 if (bubbles && this._activeKB){ 6462 this._activeKB._handle(event, type); 6463 if (event.preventKeyboardPropagation) return; 6464 } 6465 this.fireEvent(type, event); 6466 6467 if (!bubbles && this._activeKB) this._activeKB._handle(event, type); 6468 } 6469 6470 }); 6471 6472 var parsed = {}; 6473 var modifiers = ['shift', 'control', 'alt', 'meta']; 6474 var regex = /^(?:shift|control|ctrl|alt|meta)$/; 6475 6476 Keyboard.parse = function(type, eventType, ignore){ 6477 if (ignore && ignore.contains(type.toLowerCase())) return type; 6478 6479 type = type.toLowerCase().replace(/^(keyup|keydown):/, function($0, $1){ 6480 eventType = $1; 6481 return ''; 6482 }); 6483 6484 if (!parsed[type]){ 6485 var key, mods = {}; 6486 type.split('+').each(function(part){ 6487 if (regex.test(part)) mods[part] = true; 6488 else key = part;
6489 }); 6490 6491 mods.control = mods.control || mods.ctrl; // allow both control and ctrl 6492 6493 var keys = []; 6494 modifiers.each(function(mod){ 6495 if (mods[mod]) keys.push(mod); 6496 }); 6497 6498 if (key) keys.push(key); 6499 parsed[type] = keys.join('+'); 6500 } 6501 6502 return eventType + ':keys(' + parsed[type] + ')'; 6503 }; 6504 6505 Keyboard.each = function(keyboard, fn){ 6506 var current = keyboard || Keyboard.manager; 6507 while (current){ 6508 fn.run(current); 6509 current = current._activeKB; 6510 } 6511 }; 6512 6513 Keyboard.stop = function(event){ 6514 event.preventKeyboardPropagation = true; 6515 }; 6516 6517 Keyboard.manager = new Keyboard({ 6518 active: true 6519 }); 6520 6521 Keyboard.trace = function(keyboard){ 6522 keyboard = keyboard || Keyboard.manager; 6523 var hasConsole = window.console && console.log; 6524 if (hasConsole) console.log('the following items have focus: '); 6525 Keyboard.each(keyboard, function(current){ 6526 if (hasConsole) console.log(document.id(current.widget) || current.wiget || current); 6527 }); 6528 }; 6529 6530 var handler = function(event){ 6531 var keys = []; 6532 modifiers.each(function(mod){ 6533 if (event[mod]) keys.push(mod); 6534 }); 6535 6536 if (!regex.test(event.key)) keys.push(event.key); 6537 Keyboard.manager._handle(event, event.type + ':keys(' + keys.join('+') + ')'); 6538 }; 6539 6540 document.addEvents({ 6541 'keyup': handler, 6542 'keydown': handler 6543 }); 6544 6545})(); 6546 6547 6548/* 6549--- 6550 6551script: Keyboard.Extras.js 6552 6553name: Keyboard.Extras 6554 6555description: Enhances Keyboard by adding the ability to name and describe keyboard shortcuts, and the ability to grab shortcuts by name and bind the shortcut to different keys. 6556 6557license: MIT-style license 6558 6559authors: 6560 - Perrin Westrich 6561 6562requires: 6563 - /Keyboard 6564 - /MooTools.More 6565 6566provides: [Keyboard.Extras] 6567 6568... 6569*/ 6570Keyboard.prototype.options.nonParsedEvents.combine(['rebound', 'onrebound']); 6571 6572Keyboard.implement({ 6573 6574 /* 6575 shortcut should be in the format of: 6576 { 6577 'keys': 'shift+s', // the default to add as an event. 6578 'description': 'blah blah blah', // a brief description of the functionality. 6579 'handler': function(){} // the event handler to run when keys are pressed. 6580 } 6581 */ 6582 addShortcut: function(name, shortcut){ 6583 this._shortcuts = this._shortcuts || []; 6584 this._shortcutIndex = this._shortcutIndex || {}; 6585 6586 shortcut.getKeyboard = Function.from(this); 6587 shortcut.name = name; 6588 this._shortcutIndex[name] = shortcut; 6589 this._shortcuts.push(shortcut); 6590 if (shortcut.keys) this.addEvent(shortcut.keys, shortcut.handler); 6591 return this; 6592 }, 6593 6594 addShortcuts: function(obj){ 6595 for (var name in obj) this.addShortcut(name, obj[name]); 6596 return this; 6597 }, 6598 6599 removeShortcut: function(name){ 6600 var shortcut = this.getShortcut(name); 6601 if (shortcut && shortcut.keys){ 6602 this.removeEvent(shortcut.keys, shortcut.handler); 6603 delete this._shortcutIndex[name]; 6604 this._shortcuts.erase(shortcut); 6605 } 6606 return this; 6607 }, 6608 6609 removeShortcuts: function(names){ 6610 names.each(this.removeShortcut, this); 6611 return this; 6612 }, 6613 6614 getShortcuts: function(){ 6615 return this._shortcuts || []; 6616 }, 6617 6618 getShortcut: function(name){ 6619 return (this._shortcutIndex || {})[name]; 6620 } 6621 6622}); 6623 6624Keyboard.rebind = function(newKeys, shortcuts){ 6625 Array.from(shortcuts).each(function(shortcut){ 6626 shortcut.getKeyboard().removeEvent(shortcut.keys, shortcut.handler); 6627 shortcut.getKeyboard().addEvent(newKeys, shortcut.handler); 6628 shortcut.keys = newKeys; 6629 shortcut.getKeyboard().fireEvent('rebound'); 6630 }); 6631}; 6632 6633 6634Keyboard.getActiveShortcuts = function(keyboard){ 6635 var activeKBS = [], activeSCS = []; 6636 Keyboard.each(keyboard, [].push.bind(activeKBS)); 6637 activeKBS.each(function(kb){ activeSCS.extend(kb.getShortcuts()); }); 6638 return activeSCS; 6639}; 6640 6641Keyboard.getShortcut = function(name, keyboard, opts){ 6642 opts = opts || {}; 6643 var shortcuts = opts.many ? [] : null, 6644 set = opts.many ? function(kb){ 6645 var shortcut = kb.getShortcut(name); 6646 if (shortcut) shortcuts.push(shortcut); 6647 } : function(kb){ 6648 if (!shortcuts) shortcuts = kb.getShortcut(name); 6649 }; 6650 Keyboard.each(keyboard, set); 6651 return shortcuts; 6652}; 6653 6654Keyboard.getShortcuts = function(name, keyboard){ 6655 return Keyboard.getShortcut(name, keyboard, { many: true }); 6656}; 6657 6658 6659/* 6660--- 6661 6662script: Scroller.js 6663 6664name: Scroller 6665 6666description: Class which scrolls the contents of any Element (including the window) when the mouse reaches the Element's boundaries. 6667 6668license: MIT-style license 6669 6670authors: 6671 - Valerio Proietti 6672 6673requires: 6674 - Core/Events 6675 - Core/Options 6676 - Core/Element.Event 6677 - Core/Element.Dimensions 6678 - MooTools.More 6679 6680provides: [Scroller] 6681 6682... 6683*/ 6684 6685var Scroller = new Class({ 6686 6687 Implements: [Events, Options], 6688 6689 options: { 6690 area: 20, 6691 velocity: 1, 6692 onChange: function(x, y){ 6693 this.element.scrollTo(x, y); 6694 }, 6695 fps: 50 6696 }, 6697 6698 initialize: function(element, options){ 6699 this.setOptions(options); 6700 this.element = document.id(element); 6701 this.docBody = document.id(this.element.getDocument().body); 6702 this.listener = (typeOf(this.element) != 'element') ? this.docBody : this.element; 6703 this.timer = null; 6704 this.bound = { 6705 attach: this.attach.bind(this), 6706 detach: this.detach.bind(this), 6707 getCoords: this.getCoords.bind(this) 6708 }; 6709 }, 6710 6711 start: function(){ 6712 this.listener.addEvents({ 6713 mouseover: this.bound.attach, 6714 mouseleave: this.bound.detach 6715 }); 6716 return this; 6717 }, 6718 6719 stop: function(){ 6720 this.listener.removeEvents({ 6721 mouseover: this.bound.attach, 6722 mouseleave: this.bound.detach 6723 }); 6724 this.detach(); 6725 this.timer = clearInterval(this.timer); 6726 return this; 6727 }, 6728 6729 attach: function(){ 6730 this.listener.addEvent('mousemove', this.bound.getCoords); 6731 }, 6732 6733 detach: function(){ 6734 this.listener.removeEvent('mousemove', this.bound.getCoords); 6735 this.timer = clearInterval(this.timer); 6736 }, 6737 6738 getCoords: function(event){ 6739 this.page = (this.listener.get('tag') == 'body') ? event.client : event.page; 6740 if (!this.timer) this.timer = this.scroll.periodical(Math.round(1000 / this.options.fps), this); 6741 }, 6742 6743 scroll: function(){ 6744 var size = this.element.getSize(), 6745 scroll = this.element.getScroll(), 6746 pos = this.element != this.docBody ? this.element.getOffsets() : {x: 0, y:0}, 6747 scrollSize = this.element.getScrollSize(), 6748 change = {x: 0, y: 0}, 6749 top = this.options.area.top || this.options.area, 6750 bottom = this.options.area.bottom || this.options.area; 6751 for (var z in this.page){ 6752 if (this.page[z] < (top + pos[z]) && scroll[z] != 0){ 6753 change[z] = (this.page[z] - top - pos[z]) * this.options.velocity; 6754 } else if (this.page[z] + bottom > (size[z] + pos[z]) && scroll[z] + size[z] != scrollSize[z]){ 6755 change[z] = (this.page[z] - size[z] + bottom - pos[z]) * this.options.velocity; 6756 } 6757 change[z] = change[z].round(); 6758 } 6759 if (change.y || change.x) this.fireEvent('change', [scroll.x + change.x, scroll.y + change.y]); 6760 } 6761 6762}); 6763 6764 6765/* 6766--- 6767 6768script: Tips.js 6769 6770name: Tips 6771 6772description: Class for creating nice tips that follow the mouse
6772cursor when hovering an element. 6773 6774license: MIT-style license 6775 6776authors: 6777 - Valerio Proietti 6778 - Christoph Pojer 6779 - Luis Merino 6780 6781requires: 6782 - Core/Options 6783 - Core/Events 6784 - Core/Element.Event 6785 - Core/Element.Style 6786 - Core/Element.Dimensions 6787 - /MooTools.More 6788 6789provides: [Tips] 6790 6791... 6792*/ 6793 6794(function(){ 6795 6796var read = function(option, element){ 6797 return (option) ? (typeOf(option) == 'function' ? option(element) : element.get(option)) : ''; 6798}; 6799 6800this.Tips = new Class({ 6801 6802 Implements: [Events, Options], 6803 6804 options: {/* 6805 id: null, 6806 onAttach: function(element){}, 6807 onDetach: function(element){}, 6808 onBound: function(coords){},*/ 6809 onShow: function(){ 6810 this.tip.setStyle('display', 'block'); 6811 }, 6812 onHide: function(){ 6813 this.tip.setStyle('display', 'none'); 6814 }, 6815 title: 'title', 6816 text: function(element){ 6817 return element.get('rel') || element.get('href'); 6818 }, 6819 showDelay: 100, 6820 hideDelay: 100, 6821 className: 'tip-wrap', 6822 offset: {x: 16, y: 16}, 6823 windowPadding: {x:0, y:0}, 6824 fixed: false, 6825 waiAria: true 6826 }, 6827 6828 initialize: function(){ 6829 var params = Array.link(arguments, { 6830 options: Type.isObject, 6831 elements: function(obj){ 6832 return obj != null; 6833 } 6834 }); 6835 this.setOptions(params.options); 6836 if (params.elements) this.attach(params.elements); 6837 this.container = new Element('div', {'class': 'tip'}); 6838 6839 if (this.options.id){ 6840 this.container.set('id', this.options.id); 6841 if (this.options.waiAria) this.attachWaiAria(); 6842 } 6843 }, 6844 6845 toElement: function(){ 6846 if (this.tip) return this.tip; 6847 6848 this.tip = new Element('div', { 6849 'class': this.options.className, 6850 styles: { 6851 position: 'absolute', 6852 top: 0, 6853 left: 0 6854 } 6855 }).adopt( 6856 new Element('div', {'class': 'tip-top'}), 6857 this.container, 6858 new Element('div', {'class': 'tip-bottom'}) 6859 ); 6860 6861 return this.tip; 6862 }, 6863 6864 attachWaiAria: function(){ 6865 var id = this.options.id; 6866 this.container.set('role', 'tooltip'); 6867 6868 if (!this.waiAria){ 6869 this.waiAria = { 6870 show: function(element){ 6871 if (id) element.set('aria-describedby', id); 6872 this.container.set('aria-hidden', 'false'); 6873 }, 6874 hide: function(element){ 6875 if (id) element.erase('aria-describedby'); 6876 this.container.set('aria-hidden', 'true'); 6877 } 6878 }; 6879 } 6880 this.addEvents(this.waiAria); 6881 }, 6882 6883 detachWaiAria: function(){ 6884 if (this.waiAria){ 6885 this.container.erase('role'); 6886 this.container.erase('aria-hidden'); 6887 this.removeEvents(this.waiAria); 6888 } 6889 }, 6890 6891 attach: function(elements){ 6892 $$(elements).each(function(element){ 6893 var title = read(this.options.title, element), 6894 text = read(this.options.text, element); 6895 6896 element.set('title', '').store('tip:native', title).retrieve('tip:title', title); 6897 element.retrieve('tip:text', text); 6898 this.fireEvent('attach', [element]); 6899 6900 var events = ['enter', 'leave']; 6901 if (!this.options.fixed) events.push('move'); 6902 6903 events.each(function(value){ 6904 var event = element.retrieve('tip:' + value); 6905 if (!event) event = function(event){ 6906 this['element' + value.capitalize()].apply(this, [event, element]); 6907 }.bind(this); 6908 6909 element.store('tip:' + value, event).addEvent('mouse' + value, event); 6910 }, this); 6911 }, this); 6912 6913 return this; 6914 }, 6915 6916 detach: function(elements){ 6917 $$(elements).each(function(element){ 6918 ['enter', 'leave', 'move'].each(function(value){ 6919 element.removeEvent('mouse' + value, element.retrieve('tip:' + value)).eliminate('tip:' + value); 6920 }); 6921 6922 this.fireEvent('detach', [element]); 6923 6924 if (this.options.title == 'title'){ // This is necessary to check if we can revert the title 6925 var original = element.retrieve('tip:native'); 6926 if (original) element.set('title', original); 6927 } 6928 }, this); 6929 6930 return this; 6931 }, 6932 6933 elementEnter: function(event, element){ 6934 clearTimeout(this.timer); 6935 this.timer = (function(){ 6936 this.container.empty(); 6937 6938 ['title', 'text'].each(function(value){ 6939 var content = element.retrieve('tip:' + value); 6940 var div = this['_' + value + 'Element'] = new Element('div', { 6941 'class': 'tip-' + value 6942 }).inject(this.container); 6943 if (content) this.fill(div, content); 6944 }, this); 6945 this.show(element); 6946 this.position((this.options.fixed) ? {page: element.getPosition()} : event); 6947 }).delay(this.options.showDelay, this); 6948 }, 6949 6950 elementLeave: function(event, element){ 6951 clearTimeout(this.timer); 6952 this.timer = this.hide.delay(this.options.hideDelay, this, element); 6953 this.fireForParent(event, element); 6954 }, 6955 6956 setTitle: function(title){ 6957 if (this._titleElement){ 6958 this._titleElement.empty(); 6959 this.fill(this._titleElement, title); 6960 } 6961 return this; 6962 }, 6963 6964 setText: function(text){ 6965 if (this._textElement){ 6966 this._textElement.empty(); 6967 this.fill(this._textElement, text); 6968 } 6969 return this; 6970 }, 6971 6972 fireForParent: function(event, element){ 6973 element = element.getParent(); 6974 if (!element || element == document.body) return; 6975 if (element.retrieve('tip:enter')) element.fireEvent('mouseenter', event); 6976 else this.fireForParent(event, element); 6977 }, 6978 6979 elementMove: function(event, element){ 6980 this.position(event); 6981 }, 6982 6983 position: function(event){ 6984 if (!this.tip) document.id(this); 6985 6986 var size = window.getSize(), scroll = window.getScroll(), 6987 tip = {x: this.tip.offsetWidth, y: this.tip.offsetHeight}, 6988 props = {x: 'left', y: 'top'}, 6989 bounds = {y: false, x2: false, y2: false, x: false}, 6990 obj = {}; 6991 6992 for (var z in props){ 6993 obj[props[z]] = event.page[z] + this.options.offset[z]; 6994 if (obj[props[z]] < 0) bounds[z] = true; 6995 if ((obj[props[z]] + tip[z] - scroll[z]) > size[z] - this.options.windowPadding[z]){ 6996 obj[props[z]] = event.page[z] - this.options.offset[z] - tip[z]; 6997 bounds[z+'2'] = true; 6998 } 6999 } 7000 7001 this.fireEvent('bound', bounds); 7002 this.tip.setStyles(obj); 7003 }, 7004 7005 fill: function(element, contents){ 7006 if (typeof contents == 'string') element.set('html', contents); 7007 else element.adopt(contents); 7008 }, 7009 7010 show: function(element){ 7011 if (!this.tip) document.id(this); 7012 if (!this.tip.getParent()) this.tip.inject(document.body); 7013 this.fireEvent('show', [this.tip, element]); 7014 }, 7015 7016 hide: function(element){ 7017 if (!this.tip) document.id(this); 7018 this.fireEvent('hide', [this.tip, element]); 7019 } 7020 7021}); 7022 7023})(); 7024
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.