From a2139ff85c533bb0c3b2b30a873c6349226814eb Mon Sep 17 00:00:00 2001 From: Enrique Erne Date: Mon, 23 Nov 2009 10:46:45 +0100 Subject: [PATCH 001/285] fixed .unavailable to not :hover --- datepicker.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/datepicker.css b/datepicker.css index 1c54ebb..355bcae 100644 --- a/datepicker.css +++ b/datepicker.css @@ -207,7 +207,8 @@ color: #fff !important; } -.datepicker .unavailable { +.datepicker .unavailable, +.datepicker .body .days .week .day.unavailable:hover { background: #edd !important; color: #b88 !important; cursor: default !important; From 99310c4211c3f03b34cc48a5b13c9f02176bbde2 Mon Sep 17 00:00:00 2001 From: Enrique Erne Date: Sun, 29 Nov 2009 13:41:11 +0100 Subject: [PATCH 002/285] fixed bug button previous month disappeared on the last month --- datepicker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datepicker.js b/datepicker.js index 9c08b52..735d9ce 100644 --- a/datepicker.js +++ b/datepicker.js @@ -418,7 +418,7 @@ var DatePicker = new Class({ e.addClass('unavailable'); if (available) { this.limit.right = true; - } else if (this.d.getMonth() == month) { + } else if (this.d.getMonth() < month) { this.limit.left = true; } } else { From 95f4f641d5b2f41b685fb2fd5961150e09ff7e6a Mon Sep 17 00:00:00 2001 From: Enrique Erne Date: Sun, 29 Nov 2009 15:00:14 +0100 Subject: [PATCH 003/285] very specific bug when month is processed before day (i.e. Y-m-d) bug only occured on 29th, 30th and 31th when setting month before day it fall to march. easy fix start unformat from absolute unix time zero --- datepicker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datepicker.js b/datepicker.js index 735d9ce..50fa5ee 100644 --- a/datepicker.js +++ b/datepicker.js @@ -647,7 +647,7 @@ var DatePicker = new Class({ }, unformat: function(t, format) { - var d = new Date(); + var d = new Date('January 1, 1970 00:00:00'); var a = {}; var c, m; t = t.toString(); From d9a6d9eeb3ee419590fb7c5f53b9763a30ac9d05 Mon Sep 17 00:00:00 2001 From: Enrique Erne Date: Sun, 29 Nov 2009 23:13:43 +0100 Subject: [PATCH 004/285] added onNext and onPrevious events --- datepicker.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/datepicker.js b/datepicker.js index 50fa5ee..8f251f1 100644 --- a/datepicker.js +++ b/datepicker.js @@ -73,7 +73,9 @@ var DatePicker = new Class({ // and some event hooks: onShow: $empty, // triggered when the datepicker pops up onClose: $empty, // triggered after the datepicker is closed (destroyed) - onSelect: $empty // triggered when a date is selected + onSelect: $empty, // triggered when a date is selected + onNext: $empty, // triggered when changing to next month + onPrevious: $empty // triggered when changing to previous month }, initialize: function(attachTo, options) { @@ -569,6 +571,7 @@ var DatePicker = new Class({ this.d.setMonth(this.d.getMonth() - 1); } this.render('left'); + this.options.onPrevious(); }, next: function() { @@ -580,6 +583,7 @@ var DatePicker = new Class({ this.d.setMonth(this.d.getMonth() + 1); } this.render('right'); + this.options.onNext(); }, close: function(e, force) { From 072959005bb9fed5a8582600b3ff172852baa2ce Mon Sep 17 00:00:00 2001 From: Ken Marfilla Date: Tue, 19 Jan 2010 19:28:57 +0800 Subject: [PATCH 005/285] now uses Date.parse internally --- datepicker.js | 79 +++++++-------------------------------------------- 1 file changed, 10 insertions(+), 69 deletions(-) diff --git a/datepicker.js b/datepicker.js index 9c08b52..e0cb506 100644 --- a/datepicker.js +++ b/datepicker.js @@ -89,10 +89,10 @@ var DatePicker = new Class({ formatMinMaxDates: function() { if (this.options.minDate && this.options.minDate.format) { - this.options.minDate = this.unformat(this.options.minDate.date, this.options.minDate.format); + this.options.minDate = this.unformat(this.options.minDate.date); } if (this.options.maxDate && this.options.maxDate.format) { - this.options.maxDate = this.unformat(this.options.maxDate.date, this.options.maxDate.format); + this.options.maxDate = this.unformat(this.options.maxDate.date); this.options.maxDate.setHours(23); this.options.maxDate.setMinutes(59); this.options.maxDate.setSeconds(59); @@ -120,7 +120,7 @@ var DatePicker = new Class({ // determine starting value(s) if ($chk(item.get('value'))) { - var init_clone_val = this.format(new Date(this.unformat(item.get('value'), this.options.inputOutputFormat)), this.options.format); + var init_clone_val = this.format(this.unformat(item.get('value')), this.options.format); } else if (!this.options.allowEmpty) { var init_clone_val = this.format(new Date(), this.options.format); } else { @@ -178,7 +178,7 @@ var DatePicker = new Class({ var init_visual_date, d = visual_input.getCoordinates(); if ($chk(original_input.get('value'))) { - init_visual_date = this.unformat(original_input.get('value'), this.options.inputOutputFormat).valueOf(); + init_visual_date = this.unformat(original_input.get('value')).valueOf(); } else { init_visual_date = new Date(); if ($chk(this.options.maxDate) && init_visual_date.valueOf() > this.options.maxDate.valueOf()) { @@ -646,74 +646,15 @@ var DatePicker = new Class({ return f; }, - unformat: function(t, format) { - var d = new Date(); - var a = {}; - var c, m; - t = t.toString(); + unformat: function(t) { + t = Date.parse(t); - for (var i = 0; i < format.length; i++) { - c = format.charAt(i); - switch(c) { - case '\\': r = null; i++; break; - case 'y': r = '[0-9]{2}'; break; - case 'Y': r = '[0-9]{4}'; break; - case 'm': r = '0[1-9]|1[012]'; break; - case 'n': r = '[1-9]|1[012]'; break; - case 'M': r = '[A-Za-z]{'+this.options.monthShort+'}'; break; - case 'F': r = '[A-Za-z]+'; break; - case 'd': r = '0[1-9]|[12][0-9]|3[01]'; break; - case 'j': r = '[1-9]|[12][0-9]|3[01]'; break; - case 'D': r = '[A-Za-z]{'+this.options.dayShort+'}'; break; - case 'l': r = '[A-Za-z]+'; break; - case 'G': - case 'H': - case 'g': - case 'h': r = '[0-9]{1,2}'; break; - case 'a': r = '(am|pm)'; break; - case 'A': r = '(AM|PM)'; break; - case 'i': - case 's': r = '[012345][0-9]'; break; - case 'U': r = '-?[0-9]+$'; break; - default: r = null; - } - - if ($chk(r)) { - m = t.match('^'+r); - if ($chk(m)) { - a[c] = m[0]; - t = t.substring(a[c].length); - } else { - if (this.options.debug) alert("Fatal Error in DatePicker\n\nUnexpected format at: '"+t+"' expected format character '"+c+"' (pattern '"+r+"')"); - return d; - } - } else { - t = t.substring(1); - } + if(isNaN(t.get('year'))) { + t = new Date(); } - for (c in a) { - var v = a[c]; - switch(c) { - case 'y': d.setFullYear(v < 30 ? 2000 + v.toInt() : 1900 + v.toInt()); break; // assume between 1930 - 2029 - case 'Y': d.setFullYear(v); break; - case 'm': - case 'n': d.setMonth(v - 1); break; - // FALL THROUGH NOTICE! "M" has no break, because "v" now is the full month (eg. 'February'), which will work with the next format "F": - case 'M': v = this.options.months.filter(function(item, index) { return item.substring(0,this.options.monthShort) == v }.bind(this))[0]; - case 'F': d.setMonth(this.options.months.indexOf(v)); break; - case 'd': - case 'j': d.setDate(v); break; - case 'G': - case 'H': d.setHours(v); break; - case 'g': - case 'h': if (a['a'] == 'pm' || a['A'] == 'PM') { d.setHours(v == 12 ? 0 : v.toInt() + 12); } else { d.setHours(v); } break; - case 'i': d.setMinutes(v); break; - case 's': d.setSeconds(v); break; - case 'U': d = new Date(v.toInt() * 1000); - } - }; + t = (t.get('year') < 1900) ? new Date() : t; - return d; + return t; } }); \ No newline at end of file From 3077fcd4c676b708dec6e68e95de2df524963c20 Mon Sep 17 00:00:00 2001 From: Ken Marfilla Date: Tue, 19 Jan 2010 19:31:43 +0800 Subject: [PATCH 006/285] now uses Date.format --- datepicker.js | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/datepicker.js b/datepicker.js index e0cb506..ef87955 100644 --- a/datepicker.js +++ b/datepicker.js @@ -614,36 +614,7 @@ var DatePicker = new Class({ }, format: function(t, format) { - var f = ''; - var h = t.getHours(); - var m = t.getMonth(); - - for (var i = 0; i < format.length; i++) { - switch(format.charAt(i)) { - case '\\': i++; f+= format.charAt(i); break; - case 'y': f += (100 + t.getYear() + '').substring(1); break - case 'Y': f += t.getFullYear(); break; - case 'm': f += this.leadZero(m + 1); break; - case 'n': f += (m + 1); break; - case 'M': f += this.options.months[m].substring(0,this.options.monthShort); break; - case 'F': f += this.options.months[m]; break; - case 'd': f += this.leadZero(t.getDate()); break; - case 'j': f += t.getDate(); break; - case 'D': f += this.options.days[t.getDay()].substring(0,this.options.dayShort); break; - case 'l': f += this.options.days[t.getDay()]; break; - case 'G': f += h; break; - case 'H': f += this.leadZero(h); break; - case 'g': f += (h % 12 ? h % 12 : 12); break; - case 'h': f += this.leadZero(h % 12 ? h % 12 : 12); break; - case 'a': f += (h > 11 ? 'pm' : 'am'); break; - case 'A': f += (h > 11 ? 'PM' : 'AM'); break; - case 'i': f += this.leadZero(t.getMinutes()); break; - case 's': f += this.leadZero(t.getSeconds()); break; - case 'U': f += Math.floor(t.valueOf() / 1000); break; - default: f += format.charAt(i); - } - } - return f; + return new Date(t).format(format); }, unformat: function(t) { From 782e0eae6392d35d1fccc28827c98e3f8db860d2 Mon Sep 17 00:00:00 2001 From: Ken Marfilla Date: Tue, 19 Jan 2010 19:33:02 +0800 Subject: [PATCH 007/285] set default of allowEmpty to true --- datepicker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datepicker.js b/datepicker.js index ef87955..3d28a01 100644 --- a/datepicker.js +++ b/datepicker.js @@ -59,7 +59,7 @@ var DatePicker = new Class({ yearPicker: true, yearsPerPage: 20, format: 'd-m-Y', - allowEmpty: false, + allowEmpty: true, inputOutputFormat: 'U', // default to unix timestamp animationDuration: 400, useFadeInOut: !Browser.Engine.trident, // dont animate fade-in/fade-out for IE From 8136d6d4dd8be2808a5b836433c88872f55e4913 Mon Sep 17 00:00:00 2001 From: Ken Marfilla Date: Tue, 19 Jan 2010 19:49:55 +0800 Subject: [PATCH 008/285] remove the need for visual input, implements Events --- datepicker.js | 68 ++++++++++++++++++++------------------------------- 1 file changed, 26 insertions(+), 42 deletions(-) diff --git a/datepicker.js b/datepicker.js index 3d28a01..bfd5f55 100644 --- a/datepicker.js +++ b/datepicker.js @@ -21,7 +21,7 @@ var DatePicker = new Class({ - Implements: Options, + Implements: [Options, Events], // working date, which we will keep modifying to render the calendars d: '', @@ -58,9 +58,8 @@ var DatePicker = new Class({ timePickerOnly: false, yearPicker: true, yearsPerPage: 20, - format: 'd-m-Y', + format: '%d-%m-%Y', allowEmpty: true, - inputOutputFormat: 'U', // default to unix timestamp animationDuration: 400, useFadeInOut: !Browser.Engine.trident, // dont animate fade-in/fade-out for IE startView: 'month', // allowed values: {time, month, year, decades} @@ -120,24 +119,15 @@ var DatePicker = new Class({ // determine starting value(s) if ($chk(item.get('value'))) { - var init_clone_val = this.format(this.unformat(item.get('value')), this.options.format); + var init_val = this.format(this.unformat(item.get('value')), this.options.format); } else if (!this.options.allowEmpty) { - var init_clone_val = this.format(new Date(), this.options.format); + var init_val = this.format(new Date(), this.options.format); } else { - var init_clone_val = ''; + var init_val = ''; } - // create clone - var display = item.getStyle('display'); - var clone = item - .setStyle('display', this.options.debug ? display : 'none') - .store('datepicker', true) // to prevent double attachment... - .clone() - .store('datepicker', true) // ...even for the clone (!) - .removeProperty('name') // secure clean (form)submission - .setStyle('display', display) - .set('value', init_clone_val) - .inject(item, 'after'); + + item.store('datepicker', true); // to prevent double attachment... // events if ($chk(this.options.toggleElements)) { @@ -145,20 +135,15 @@ var DatePicker = new Class({ .setStyle('cursor', 'pointer') .addEvents({ 'click': function(e) { - this.onFocus(item, clone); + this.onFocus(item); }.bind(this) }); - clone.addEvents({ - 'blur': function() { - item.set('value', clone.get('value')); - } }); } else { - clone.addEvents({ + item.addEvents({ 'keydown': function(e) { if (this.options.allowEmpty && (e.key == "delete" || e.key == "backspace")) { item.set('value', ''); - e.target.set('value', ''); this.close(null, true); } else if (e.key == "tab") { this.close(null, true); @@ -167,32 +152,31 @@ var DatePicker = new Class({ } }.bind(this), 'focus': function(e) { - this.onFocus(item, clone); + this.onFocus(item); }.bind(this) }); } }.bind(this)); }, - onFocus: function(original_input, visual_input) { - var init_visual_date, d = visual_input.getCoordinates(); + onFocus: function(input) { + var input_date, d = input.getCoordinates(); - if ($chk(original_input.get('value'))) { - init_visual_date = this.unformat(original_input.get('value')).valueOf(); + if ($chk(input.get('value'))) { + input_date = this.unformat(input.get('value')).valueOf(); } else { - init_visual_date = new Date(); - if ($chk(this.options.maxDate) && init_visual_date.valueOf() > this.options.maxDate.valueOf()) { - init_visual_date = new Date(this.options.maxDate.valueOf()); + input_date = new Date(); + if ($chk(this.options.maxDate) && input_date.valueOf() > this.options.maxDate.valueOf()) { + input_date = new Date(this.options.maxDate.valueOf()); } - if ($chk(this.options.minDate) && init_visual_date.valueOf() < this.options.minDate.valueOf()) { - init_visual_date = new Date(this.options.minDate.valueOf()); + if ($chk(this.options.minDate) && input_date.valueOf() < this.options.minDate.valueOf()) { + input_date = new Date(this.options.minDate.valueOf()); } } - this.show({ left: d.left + this.options.positionOffset.x, top: d.top + d.height + this.options.positionOffset.y }, init_visual_date); - this.input = original_input; - this.visual = visual_input; - this.options.onShow(); + this.show({ left: d.left + this.options.positionOffset.x, top: d.top + d.height + this.options.positionOffset.y }, input_date); + this.input = input; + this.fireEvent('show'); }, dateToObject: function(d) { @@ -597,15 +581,15 @@ var DatePicker = new Class({ destroy: function() { this.picker.destroy(); this.picker = null; - this.options.onClose(); + this.fireEvent('close'); }, select: function(values) { this.choice = $merge(this.choice, values); var d = this.dateFromObject(this.choice); - this.input.set('value', this.format(d, this.options.inputOutputFormat)); - this.visual.set('value', this.format(d, this.options.format)); - this.options.onSelect(d); + this.input.set('value', this.format(d, this.options.format)); + this.fireEvent('select', this, [d]); + this.close(null, true); }, From 528fe46dbc1f5f60f7f3840a2a24f687e52d3d7d Mon Sep 17 00:00:00 2001 From: Ken Marfilla Date: Tue, 19 Jan 2010 19:57:14 +0800 Subject: [PATCH 009/285] fixed syntax error from previous commit --- datepicker.js | 1 - 1 file changed, 1 deletion(-) diff --git a/datepicker.js b/datepicker.js index bfd5f55..e175bb1 100644 --- a/datepicker.js +++ b/datepicker.js @@ -138,7 +138,6 @@ var DatePicker = new Class({ this.onFocus(item); }.bind(this) }); - }); } else { item.addEvents({ 'keydown': function(e) { From e8c5364788dde24a2413fd231033b590059d404b Mon Sep 17 00:00:00 2001 From: Ken Marfilla Date: Tue, 19 Jan 2010 20:01:20 +0800 Subject: [PATCH 010/285] prevents positioning beyond the visible viewport --- datepicker.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/datepicker.js b/datepicker.js index e175bb1..3e15a53 100644 --- a/datepicker.js +++ b/datepicker.js @@ -218,9 +218,23 @@ var DatePicker = new Class({ this.choice = this.dateToObject(this.d); this.mode = (this.options.startView == 'time' && !this.options.timePicker) ? 'month' : this.options.startView; this.render(); - this.picker.setStyles(position); + this.position({x: position.left, y: position.top}); }, - + + position: function(p) { + var w = window.getSize(), + s = window.getScroll(), + d = this.picker.getSize(), + max_y = (w.y + s.y) - d.y, + max_x = (w.x + s.x) - d.x, + i = this.input.getCoordinates(); + + if(p.x > max_x) p.x = i.right - this.options.positionOffset.x - d.x; + if(p.y > max_y) p.y = i.top - this.options.positionOffset.y - d.y; + + this.picker.setStyles({left: p.x, top: p.y}); + }, + render: function(fx) { if (!$chk(this.picker)) { this.constructPicker(); From 004a3f80da1af88c5d866e568ac8a425f779c20e Mon Sep 17 00:00:00 2001 From: Ken Marfilla Date: Tue, 19 Jan 2010 20:07:11 +0800 Subject: [PATCH 011/285] fixed positioning bug --- datepicker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datepicker.js b/datepicker.js index 3e15a53..774360c 100644 --- a/datepicker.js +++ b/datepicker.js @@ -173,8 +173,8 @@ var DatePicker = new Class({ } } - this.show({ left: d.left + this.options.positionOffset.x, top: d.top + d.height + this.options.positionOffset.y }, input_date); this.input = input; + this.show({ left: d.left + this.options.positionOffset.x, top: d.top + d.height + this.options.positionOffset.y }, input_date); this.fireEvent('show'); }, From d453e947952f025d9ccc7586bfe95412ecc94848 Mon Sep 17 00:00:00 2001 From: Ken Marfilla Date: Tue, 19 Jan 2010 20:15:19 +0800 Subject: [PATCH 012/285] enable drag, can be disabled via draggable option --- datepicker.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/datepicker.js b/datepicker.js index 774360c..93ce50f 100644 --- a/datepicker.js +++ b/datepicker.js @@ -68,6 +68,7 @@ var DatePicker = new Class({ maxDate: null, // same as minDate debug: false, toggleElements: null, + draggable: true, // and some event hooks: onShow: $empty, // triggered when the datepicker pops up @@ -219,6 +220,11 @@ var DatePicker = new Class({ this.mode = (this.options.startView == 'time' && !this.options.timePicker) ? 'month' : this.options.startView; this.render(); this.position({x: position.left, y: position.top}); + + if(this.options.draggable) { + this.dragger = this.picker.makeDraggable(); + this.picker.setStyle('cursor', 'move'); + } }, position: function(p) { From 44cafaf5c8316a4bafaef8ad7cbedf25549e4611 Mon Sep 17 00:00:00 2001 From: Ken Marfilla Date: Tue, 19 Jan 2010 20:22:29 +0800 Subject: [PATCH 013/285] will now shim the picker in IE --- datepicker.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/datepicker.js b/datepicker.js index 93ce50f..04820d1 100644 --- a/datepicker.js +++ b/datepicker.js @@ -225,6 +225,31 @@ var DatePicker = new Class({ this.dragger = this.picker.makeDraggable(); this.picker.setStyle('cursor', 'move'); } + + if(Browser.Engine.trident) this.shim(); + }, + + shim: function() { + var coords = this.picker.setStyle('zIndex', 1000).getCoordinates(); + this.frame = new Element('iframe', { + src: 'javascript:false;document.write("");', + styles: { + position: 'absolute', + zIndex: 999, + height: coords.height, width: coords.width, + left: coords.left, top: coords.top + } + }).inject(document.body); + this.frame.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)'; + + this.addEvent('close', function() {this.destroy()}.bind(this.frame)); + + if(this.options.draggable) { + this.dragger.addEvent('drag', function() { + var coords = this.picker.getCoordinates(); + this.frame.setStyles({left: coords.left, top: coords.top}); + }.bind(this)); + } }, position: function(p) { From e22a66093f98608435737c2117b8efa05c31041c Mon Sep 17 00:00:00 2001 From: Chris Baxter Date: Mon, 1 Feb 2010 11:56:46 +0000 Subject: [PATCH 014/285] Amended date validation to handle 'Invalid date' --- datepicker.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/datepicker.js b/datepicker.js index 04820d1..7549dc7 100644 --- a/datepicker.js +++ b/datepicker.js @@ -1,4 +1,4 @@ -/** +/** * datepicker.js - MooTools Datepicker class * @version 1.16 * @@ -648,7 +648,7 @@ var DatePicker = new Class({ unformat: function(t) { t = Date.parse(t); - if(isNaN(t.get('year'))) { + if(!t.isValid()) { t = new Date(); } From f0af0d8aa63e57a2689c1c3276f531c56da9ba86 Mon Sep 17 00:00:00 2001 From: Chris Baxter Date: Mon, 1 Feb 2010 12:14:04 +0000 Subject: [PATCH 015/285] Added Date.defineParser to handle more date formats --- datepicker.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/datepicker.js b/datepicker.js index 7549dc7..ec0441b 100644 --- a/datepicker.js +++ b/datepicker.js @@ -120,7 +120,7 @@ var DatePicker = new Class({ // determine starting value(s) if ($chk(item.get('value'))) { - var init_val = this.format(this.unformat(item.get('value')), this.options.format); + var init_val = this.format(this.unformat(item.get('value'),this.options.format), this.options.format); } else if (!this.options.allowEmpty) { var init_val = this.format(new Date(), this.options.format); } else { @@ -163,7 +163,7 @@ var DatePicker = new Class({ var input_date, d = input.getCoordinates(); if ($chk(input.get('value'))) { - input_date = this.unformat(input.get('value')).valueOf(); + input_date = this.unformat(input.get('value'),this.options.format).valueOf(); } else { input_date = new Date(); if ($chk(this.options.maxDate) && input_date.valueOf() > this.options.maxDate.valueOf()) { @@ -645,7 +645,8 @@ var DatePicker = new Class({ return new Date(t).format(format); }, - unformat: function(t) { + unformat: function(t,format) { + Date.defineParser(format); t = Date.parse(t); if(!t.isValid()) { @@ -656,4 +657,4 @@ var DatePicker = new Class({ return t; } -}); \ No newline at end of file +}); From d1f0b15907dc9a71ffcccb1bb7dd74f0054c9e7c Mon Sep 17 00:00:00 2001 From: Chris Baxter Date: Mon, 1 Feb 2010 12:27:09 +0000 Subject: [PATCH 016/285] Changed format for minDate and maxDate to inputFormat to resolve conflict with MooTools Date.format function --- datepicker.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/datepicker.js b/datepicker.js index ec0441b..167f48a 100644 --- a/datepicker.js +++ b/datepicker.js @@ -88,11 +88,11 @@ var DatePicker = new Class({ }, formatMinMaxDates: function() { - if (this.options.minDate && this.options.minDate.format) { - this.options.minDate = this.unformat(this.options.minDate.date); + if (this.options.minDate && this.options.minDate.inputFormat) { //cbaxter changed minDate.format for minDate.inputFormat to address issues when implemented with MooTools.Date extension due to date.format() being confused with date.format string + this.options.minDate = this.unformat(this.options.minDate.date, this.options.minDate.inputFormat); } - if (this.options.maxDate && this.options.maxDate.format) { - this.options.maxDate = this.unformat(this.options.maxDate.date); + if (this.options.maxDate && this.options.maxDate.inputFormat) { + this.options.maxDate = this.unformat(this.options.maxDate.date, this.options.maxDate.inputFormat); this.options.maxDate.setHours(23); this.options.maxDate.setMinutes(59); this.options.maxDate.setSeconds(59); From 9ef5be1ced877dc67c50b73e299e0f14478efe6d Mon Sep 17 00:00:00 2001 From: Chris Baxter Date: Mon, 1 Feb 2010 12:30:18 +0000 Subject: [PATCH 017/285] Added check that MooTools More extension Drag.Move is included. Will now function without error if not included and incorrectly configured. --- datepicker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datepicker.js b/datepicker.js index 167f48a..b868a4b 100644 --- a/datepicker.js +++ b/datepicker.js @@ -221,7 +221,7 @@ var DatePicker = new Class({ this.render(); this.position({x: position.left, y: position.top}); - if(this.options.draggable) { + if(this.options.draggable && $type(this.picker.makeDraggable) == 'function') { this.dragger = this.picker.makeDraggable(); this.picker.setStyle('cursor', 'move'); } From 8f14a5e7d394d8898f36965d03a33d11ab299c1f Mon Sep 17 00:00:00 2001 From: Chris Baxter Date: Tue, 2 Feb 2010 14:10:00 +0000 Subject: [PATCH 018/285] Fixed bug with onPrevious and onNext when date > 29 was selected. As per issue 2 in original issue list --- datepicker.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/datepicker.js b/datepicker.js index b868a4b..77bc275 100644 --- a/datepicker.js +++ b/datepicker.js @@ -594,6 +594,7 @@ var DatePicker = new Class({ } else if (this.mode == 'year') { this.d.setFullYear(this.d.getFullYear() - 1); } else if (this.mode == 'month') { + this.d.setDate(1); this.d.setMonth(this.d.getMonth() - 1); } this.render('left'); @@ -605,6 +606,7 @@ var DatePicker = new Class({ } else if (this.mode == 'year') { this.d.setFullYear(this.d.getFullYear() + 1); } else if (this.mode == 'month') { + this.d.setDate(1); this.d.setMonth(this.d.getMonth() + 1); } this.render('right'); From c9e4cd6482ac54a70268f46be6c58330e795d040 Mon Sep 17 00:00:00 2001 From: Chris Baxter Date: Tue, 2 Feb 2010 17:22:15 +0000 Subject: [PATCH 019/285] Fix to the picker.previous visibility during on month display when minDate in use --- datepicker.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/datepicker.js b/datepicker.js index 77bc275..e521750 100644 --- a/datepicker.js +++ b/datepicker.js @@ -474,7 +474,15 @@ var DatePicker = new Class({ this.picker.getElement('.titleText').set('text', this.d.getFullYear()); this.d.setMonth(0); - + if ($chk(this.options.minDate) { + this.d.decrement('month',1) + this.d.set('date',this.d.get('lastdayofmonth')); + if (this.limited('month')) { + this.limit.left = true; + } + this.d.increment('month',1) + } + this.d.set('date',this.d.get('lastdayofmonth')) var i, e; var available = false; var container = new Element('div', { 'class': 'months' }).inject(this.newContents); @@ -499,7 +507,8 @@ var DatePicker = new Class({ this.render('fade'); }.bindWithEvent(this, i)); } - this.d.setMonth(i); + this.d.increment('month',1) + this.d.set('date',this.d.get('lastdayofmonth')) } if (!available) this.limit.right = true; }, From 8b0e843ecfd2521a7a3305620cb4c38125f20301 Mon Sep 17 00:00:00 2001 From: Chris Baxter Date: Tue, 2 Feb 2010 17:36:18 +0000 Subject: [PATCH 020/285] Correction to last commit --- datepicker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datepicker.js b/datepicker.js index e521750..6580cfd 100644 --- a/datepicker.js +++ b/datepicker.js @@ -474,7 +474,7 @@ var DatePicker = new Class({ this.picker.getElement('.titleText').set('text', this.d.getFullYear()); this.d.setMonth(0); - if ($chk(this.options.minDate) { + if ($chk(this.options.minDate)) { this.d.decrement('month',1) this.d.set('date',this.d.get('lastdayofmonth')); if (this.limited('month')) { From 414b6a3af6f8d74f79167e77e12d09143a36383b Mon Sep 17 00:00:00 2001 From: Chris Baxter Date: Tue, 2 Feb 2010 17:37:44 +0000 Subject: [PATCH 021/285] Update to correct picker.previous visibililty when minDate is in use --- datepicker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datepicker.js b/datepicker.js index 6580cfd..2a0270a 100644 --- a/datepicker.js +++ b/datepicker.js @@ -446,7 +446,7 @@ var DatePicker = new Class({ e.addClass('unavailable'); if (available) { this.limit.right = true; - } else if (this.d.getMonth() == month) { + } else { this.limit.left = true; } } else { From 419322b5efa842157e039da17c01dd4329d3ece6 Mon Sep 17 00:00:00 2001 From: Chris Baxter Date: Tue, 2 Feb 2010 18:46:54 +0000 Subject: [PATCH 022/285] Fix for picker coordinates were incorrect when main input is invisible (display none or type hidden) --- datepicker.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/datepicker.js b/datepicker.js index 2a0270a..9f3cd88 100644 --- a/datepicker.js +++ b/datepicker.js @@ -136,7 +136,7 @@ var DatePicker = new Class({ .setStyle('cursor', 'pointer') .addEvents({ 'click': function(e) { - this.onFocus(item); + this.onFocus(item,togglers[index]); }.bind(this) }); } else { @@ -159,8 +159,8 @@ var DatePicker = new Class({ }.bind(this)); }, - onFocus: function(input) { - var input_date, d = input.getCoordinates(); + onFocus: function(input,toggler) { + var input_date, d = ($defined(toggler) ? toggler:input).getCoordinates(); if ($chk(input.get('value'))) { input_date = this.unformat(input.get('value'),this.options.format).valueOf(); From edd07d5805524f382911d1042bc7b734ca6cddca Mon Sep 17 00:00:00 2001 From: Chris Baxter Date: Wed, 3 Feb 2010 12:33:27 +0000 Subject: [PATCH 023/285] Changed the fireEvent to return just the date object for onSelect as per original code --- datepicker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datepicker.js b/datepicker.js index 9f3cd88..ce18251 100644 --- a/datepicker.js +++ b/datepicker.js @@ -643,7 +643,7 @@ var DatePicker = new Class({ this.choice = $merge(this.choice, values); var d = this.dateFromObject(this.choice); this.input.set('value', this.format(d, this.options.format)); - this.fireEvent('select', this, [d]); + this.fireEvent('select', d); this.close(null, true); }, From 9a289bef34dc3f3faec2a45641bc87b6aac9d439 Mon Sep 17 00:00:00 2001 From: Chris Baxter Date: Wed, 3 Feb 2010 12:38:50 +0000 Subject: [PATCH 024/285] Fixed next month image not visible when maxDate between 1st->6th of next month --- datepicker.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/datepicker.js b/datepicker.js index ce18251..ec0062e 100644 --- a/datepicker.js +++ b/datepicker.js @@ -445,7 +445,9 @@ var DatePicker = new Class({ if (this.limited('date')) { e.addClass('unavailable'); if (available) { - this.limit.right = true; + if(month == this.d.getMonth() || this.d.getDate() == 1) { + this.limit.right = true; + } } else { this.limit.left = true; } From 6cb985ffbacd1a6f6cc48f4885a0a987e558b8f1 Mon Sep 17 00:00:00 2001 From: Arian Date: Tue, 23 Feb 2010 15:02:15 +0100 Subject: [PATCH 025/285] Make it ready for the mootools forge --- README.md | 16 ++++++++++++++ datepicker.css => Source/datepicker.css | 0 datepicker.js => Source/datepicker.js | 20 ++++++++++++++++++ .../datepicker_dashboard}/buttons.png | Bin .../datepicker_dashboard.css | 0 .../datepicker_dashboard}/frame.png | Bin .../datepicker_jqui}/arrows.png | Bin .../datepicker_jqui}/datepicker_jqui.css | 0 .../datepicker_jqui}/frame.png | Bin .../datepicker_vista}/buttons.png | Bin .../datepicker_vista}/datepicker_vista.css | 0 .../datepicker_vista}/days.png | Bin .../datepicker_vista}/frame.png | Bin .../datepicker_vista}/months.png | Bin .../datepicker_vista}/years.png | Bin package.yml | 7 ++++++ screenshot.png | Bin 0 -> 14423 bytes 17 files changed, 43 insertions(+) create mode 100644 README.md rename datepicker.css => Source/datepicker.css (100%) rename datepicker.js => Source/datepicker.js (99%) rename {datepicker_dashboard => Source/datepicker_dashboard}/buttons.png (100%) rename {datepicker_dashboard => Source/datepicker_dashboard}/datepicker_dashboard.css (100%) rename {datepicker_dashboard => Source/datepicker_dashboard}/frame.png (100%) rename {datepicker_jqui => Source/datepicker_jqui}/arrows.png (100%) rename {datepicker_jqui => Source/datepicker_jqui}/datepicker_jqui.css (100%) rename {datepicker_jqui => Source/datepicker_jqui}/frame.png (100%) rename {datepicker_vista => Source/datepicker_vista}/buttons.png (100%) rename {datepicker_vista => Source/datepicker_vista}/datepicker_vista.css (100%) rename {datepicker_vista => Source/datepicker_vista}/days.png (100%) rename {datepicker_vista => Source/datepicker_vista}/frame.png (100%) rename {datepicker_vista => Source/datepicker_vista}/months.png (100%) rename {datepicker_vista => Source/datepicker_vista}/years.png (100%) create mode 100644 package.yml create mode 100644 screenshot.png diff --git a/README.md b/README.md new file mode 100644 index 0000000..e545f39 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +MooTools-DatePicker +=============== + +Smoothly animating, very configurable and easy to install. +No Ajax, pure Javascript. 4 skins available out of the box. + +![Screenshot](http://github.com/arian/mootools-datepicker/raw/master/screenshot.png) + +How to use +---------- + + #JS + new DatePicker(input-target-selector [, options-object]); + +where the input-target-selector naturally is a MooTools selector (eg. .datepickers or #great_picker). The datepicker will be effective for all selected input elements. Usage examples are given at the bottom of this document. + diff --git a/datepicker.css b/Source/datepicker.css similarity index 100% rename from datepicker.css rename to Source/datepicker.css diff --git a/datepicker.js b/Source/datepicker.js similarity index 99% rename from datepicker.js rename to Source/datepicker.js index 9c08b52..1f01b3d 100644 --- a/datepicker.js +++ b/Source/datepicker.js @@ -1,3 +1,23 @@ +/* +--- +description: MooTools Datepicker class + +authors: + - MonkeyPhysics.com + +license: + - Attribution-Share Alike 3.0 Unported + +requires: + core/1.2.4: '*' + +provides: + - [DatePicker] + +... +*/ + + /** * datepicker.js - MooTools Datepicker class * @version 1.16 diff --git a/datepicker_dashboard/buttons.png b/Source/datepicker_dashboard/buttons.png similarity index 100% rename from datepicker_dashboard/buttons.png rename to Source/datepicker_dashboard/buttons.png diff --git a/datepicker_dashboard/datepicker_dashboard.css b/Source/datepicker_dashboard/datepicker_dashboard.css similarity index 100% rename from datepicker_dashboard/datepicker_dashboard.css rename to Source/datepicker_dashboard/datepicker_dashboard.css diff --git a/datepicker_dashboard/frame.png b/Source/datepicker_dashboard/frame.png similarity index 100% rename from datepicker_dashboard/frame.png rename to Source/datepicker_dashboard/frame.png diff --git a/datepicker_jqui/arrows.png b/Source/datepicker_jqui/arrows.png similarity index 100% rename from datepicker_jqui/arrows.png rename to Source/datepicker_jqui/arrows.png diff --git a/datepicker_jqui/datepicker_jqui.css b/Source/datepicker_jqui/datepicker_jqui.css similarity index 100% rename from datepicker_jqui/datepicker_jqui.css rename to Source/datepicker_jqui/datepicker_jqui.css diff --git a/datepicker_jqui/frame.png b/Source/datepicker_jqui/frame.png similarity index 100% rename from datepicker_jqui/frame.png rename to Source/datepicker_jqui/frame.png diff --git a/datepicker_vista/buttons.png b/Source/datepicker_vista/buttons.png similarity index 100% rename from datepicker_vista/buttons.png rename to Source/datepicker_vista/buttons.png diff --git a/datepicker_vista/datepicker_vista.css b/Source/datepicker_vista/datepicker_vista.css similarity index 100% rename from datepicker_vista/datepicker_vista.css rename to Source/datepicker_vista/datepicker_vista.css diff --git a/datepicker_vista/days.png b/Source/datepicker_vista/days.png similarity index 100% rename from datepicker_vista/days.png rename to Source/datepicker_vista/days.png diff --git a/datepicker_vista/frame.png b/Source/datepicker_vista/frame.png similarity index 100% rename from datepicker_vista/frame.png rename to Source/datepicker_vista/frame.png diff --git a/datepicker_vista/months.png b/Source/datepicker_vista/months.png similarity index 100% rename from datepicker_vista/months.png rename to Source/datepicker_vista/months.png diff --git a/datepicker_vista/years.png b/Source/datepicker_vista/years.png similarity index 100% rename from datepicker_vista/years.png rename to Source/datepicker_vista/years.png diff --git a/package.yml b/package.yml new file mode 100644 index 0000000..0c46ea0 --- /dev/null +++ b/package.yml @@ -0,0 +1,7 @@ +name: MooTools-DatePicker +author: astolwijk +current: 1.16 +category: Widgets +tags: [Datepicker,Calendar] +demo: http://www.monkeyphysics.com/mootools/script/2/datepicker +docs: http://www.monkeyphysics.com/mootools/script/2/datepicker \ No newline at end of file diff --git a/screenshot.png b/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..4299e9467495608c03a985ec849619b105fc0553 GIT binary patch literal 14423 zcma*OWmH>H*ELF^P@uRw1TXHc!QI{6i@TNL?rz147brmsMFRwPhvE*!otr-IbKm=o z@7K*3**V!GIcLjRYt6aVJkhGkGN{Nz$S^Q4sB*HB>M$_xQlQ5}h_KLB>FY%l^y8ho zx(pDeZk*&0`US~FR?i&<<|FpM_dA%JJOXIv2M;+VsSnGr_^AA3Tud=EFfbG_a+2bj zKFg>1-iA0b#9*5{zY;16DKXU;`1r+m+gV8^bEUZQE+T((1!MmcB8ySt5?b2Zg?_A$ z8PxOdJJiI*{V-Migg09oy$$wWwsA1odJF1Z?gQS2z$6_L!h%g#E7@(?8(0Ju?_pp} zg_BgFA732b{hv)EJalCL8q>1IaK?$mCMv}25$Q73ML#dX=KCQd;YiohIbs3}#j+E< z4l3=~Y9GIVxa>S9qn-Sq)`?lnrmY=}3bKwXy=T6Oy=k(bo4Y&P@g&1^ejP8aQI->3 z{<SkTaY5&e7kn&#!Zx49?Ro45qFahWnR!DmjqPTf$vGiE zh{?RlJND0$J7FCApyFBApR-eZY5TUL1@*V$x+k}h#5v`s!uqnJ0WDGnFSTzQqp~j= zz_~i{gzbZqT9qnS7|UZq0IDvYmU_{Yw&hD(=l0mAHR;n%nT0^=^vA3AeAmZ_wOH6Y zqy_F|jn4NIZzE)Zo}nBzXXhlsrfq(!e>$vkMq=WqEMhaeIPCX@5dgIAD+b%Wa6E(Q z#3<56$hNV<3`uGYFY*>^_z0T^mU9nC)@W8-T}QcENt{9vQj#Fy38j)4X8gv-}Iw zSo4Msy4@L8{0SBi*0F1M(!Y?KQwgE=+V}<0XU6(s>!p!J@5v<77sn>-ja%zSrPJ=9oC#sAq|iI_`$IZffNQy1Niu1AitXx!Spu*y_1W_hX{V}l8|G7wth;wN30Ak$L#y!Fcg4N(Y7_V$Ri&6%wy)!XQDG6FB&SA;Y>uQbmE8)@dfjC>m!We zSD~wgszvAuxE7$z16J3NH?(szRxw$7XI7eK?#o&#MvYUVfX?fFvNb_IWK67fZ(DJx zv@8sDiV%%LyN^%5zo6`a3g(8iu>+aJ=Q>)RPr?9<3X#F&n7Mf#fg0pir$~NyjP1d` zEF28b*O4|*`!Qs}9ub-6&=#oa6a?pvIG1xO{e7eC6m1Hs(t1AFqfr=hquSm^ljd*hK>6k9dlSd<>!7;l7O0$xr*rX5kTOXyX4Wp8 zHthX4YoaY~Tfo|bIRZe@%7ovI77~DALqF4i$PT~Hb2@h&*pc69Uks9}Us!VvZsAo+ z#N^mB62;aS1carnWuBsR|KN7HBX$lfv=oz_+}g#grOceee2D%Il)m54>uNV0axp18 zA5t4sQkdvKIeyNX7an;&RFWYQde|UkQOs=@F3*#SVoqG*IZcJ+?_s4?@ICxF9vEk+aOXp)sRTGfB z+k#XelAkVoL)9WItMPg?CMR%^&Qhxhp%Bf$?IDs|)R4tYoK_5U52Rr|-mu@n zFg!f$}qu!N9PJ2^TVSRO|#O6uw@CRPBpZ?b;cpn0TY=3RA*86s}wfWpUKYRS? z>&U=pkH7zWVn2K&PJRk09(dQ3_|{T4q!N@M=n*`lam?l>>A;Tll;8u_I^`;@xU#@i zWxg_6QgL9WER6nRgTH)2_{X9`efcL52z(nWniz1xEGc_JME~YLU}{pPS=VScWudn; zYa!ZwD%}_k7R~qA9m{tx2GJx9-EE&jNP_N7wMx;hnC-tZc7yh~O)@iTJK?}o$R8qbhxixx=t z&hGinQ@dGz6^^TdxU< zp8Pc<6~}OqfPuLNL2=x-7ATOr2IY|Nh4ZL(z)UhVBzPKB-nl7x1lmaJWvpGFE~J)^ zCCQgjBb98HN9j`AZl9vCGno3Ga>gr}`GUN;SHp-X5{?ETYLK=ZZKPUJ}b0`Z0kC$X52kq6LQ_B>xiskRqV3y z+<^!p#1TDDmv0h9Uv=9(mhPJcxzp1Xm*S5qG|<;Vj^joN&&hLM@a0rQYZ3;6(B#cSsC5I;rwH_db3h>YVah@G#t-Z)4_FutJlu||lX+@7x_On^}w_YQ}^2-DCxQNA~2Qo3&7;^{W>A zJL0DaE!sV``}1EDk!w6*Rgyc*jhAekU!^{;KR04#wL<%kNLj)r4V-^9yKWCwYS6|b z=jOfk6cviv()3%|fW2?;?(WXH{uuICsJyi4TZXKP1MT7n0R4m`c9pe1yYh=fl%aHxQ#y0o->l8Z%=8kg352@V@w`HHkU z^f(&jiY)ctJ1f~0KhDSSXHcAcIPJ{O$jHF^MOCwvnJ9ho9Zzoy8&5YtKt4YC@HL!X zs~e4{IXFD+J`7&?6iNtl?#BGH6t3z@M&L^pPsSKA-D9*-EQ zK&?z`eEr!qM^3x@`{!#NncJ;M*dieBE5l!Y!`EJj*gQPQhutF2Y^4inO;-2A$;oSs z)q4zGgdzuX;^Z4X?l08AuBQP}ek9OsZ0bjT24S69=L`FT#Qm{INl9m>r$jbup7VPJN!uguwBt|GGJ#Hgu?^*c&2G8~JV3V4`%GoZ4L@AJXYnQODY zLN8LK$3cdNeJ7VPR`UF=I<1zWr`Rs17mzB)N82j#idq#PMY<DA`T)dy6SDL zfu4>4MZXr**r;AHqlRO}kzK``Nc&aKxLWkB_SaHY_#zYgdvPJp%|X|^hiG+)#44Q9 zs&m7aN(&a2pkvL^{g?ssO3f-&dQApgNFztKB4zUI*}*#~{Hk1<w&=Xcm6-Ud^ux8HQQy@PzRYQwakpc!=CaHFReZ^caqnN%{+dyBxYUU6Y z7WU-igc>Vamip__`>Jnt`jwg)nVEESbh#gz_Rfgou%WXMhdOw6qImsU?dm!CGWFD9 zNi|JnWo2Jqez^f>C3nhfc^2uMk_gK5lHTzFDy zQc_X~p*^-->NxNt@QC5SN=^F$=^qUZ>>E7L6PKy8qre?kLoa5NWc!LbCB(49H*U&i zX=Mey$ys=Kv}?5`%DOiB`1m{yCe1c~hZq|h%a>sRpd+V`DYk1zdbNe)3SQ!PTkK~; zQJQgUBLS2y9LGyPv)r)(OxGF}Stl10EI+Lq$ zePc(_Fg9kvK^AX<2}|lR#Xt_{4k~^(2D@ax6Cx%o`ri2B9n~rwo2=uk!H>)5j)Ipv z;&l0U5G=3twFor-r)B_1g}+)v(777)1gnJiUFNsFzrpkuD>a${nxmg9k>$o*+?r;>}t+amIcIV6^KudBWxhW!;a66Zq_7+1~hcU z^k5Zdvi*1>?xVqY;&{sUmI`}x`F}Jc0MB)QhLkj9;6JBv{RkuWPg*V%3%5~ctZ-K! zbtS1d00!eKk;<3PkMHduTErQkl<-Pw*lZtAJiy^r2P&4#KF1UDLcJXPDV`-nz;3g* z#_M!BpU>4C>bwdH3gYL>7-%y+k`ip0NeLNZrsi89q3nZ*B^ASxfr&QJ-)U03L#dr_ za0NyyKD1I%gST56kQA0A5NmM!iCi(Qqct-KerulPOzOR@KTw7JZZ*utxD zl~tYvv@gx*hEGf`CR=_yAd{1bs`_}~V?JZrNKoV&JGvCJwU_QKCDe1|U%t=eNbVWs{G5Oh2v;ZwIe$;EscjYV?{w z&Kq6UV>yGTE`QA3Mv*S^_O;>nJn_gUgY(BxZDl@h(8DhOF);-z871sD(GqCuSi&&w1uy)ubG*dwzhUC zWj`3){jir?A|0>a?qN4WKvz6+Ra{vzJQCR_J-yeU%vO%6v44#d5>5?7M! zQ4~|*s;j=q(d1FNSTV9*w9UAtdh@?(5d8$qX4Tmi?vq-G#RLvzDcEY})ke)u4uQDm zsjdH!5gDmMhWWgad26N*b|y$3QJ-azi3GdTtdg>SPiCbzhzYO|6?7P;49*BJdeut(dW;4 z>Z0T=^R(Ponvc;%6_r#-gQSAG_y8bcgCEXynX5Av_lnw&&x~qo{Bh7t>59{_Qg<+> z8kfdKELt^zKdjFN<+FQs%h*TEl)yR!NiF$`r-Ve^XMY!AroG+ud)jJYQPn}2O;_J0 z5DmNTAOG|<>17bEMNwR)UyusAOb%6cI`7wdLXF(k_=3gOz@0;LAGj_rAnjguTIAHr z%OZfQl%+yO6Fa7kGQ$bcS*PS*0(@pIOid~J*kbWn zy*xd+gVoj4{_O7VZf%)^E+R6V=eTS_m+=D%bKc(Ly)cY(0EJ;G4B~s9AFjsU*aSI_ zJp|&VIoHbdgn5h1DHzXaxi$BHk8x?*P;vUw5ioG<0hC z40>O-L1gaYfqzeZu5>J%u2pi+;~(t5=9a5}qqt-}UB9?e;*OmZ{fypAfUSP6L#Gt@ ztM;o{d+VCXt49+Gc3A(L$#FMgoNnud?RcnCM*mDoC8mvxSE1FF;oazl_5=_?43tB$ zm~{g#ms-(2`&hj&h2nNFJ@(?VCrpHNBH`CgMT-pxODerN@O``Nx)@u%$wo+4NKC{Z z&Hwgf4sjYwy|vBZKN!~jSg^xnWtu;^l!4d@=+TFZvI@#6OHS0Oa3=P|MIfo{|o z_=7)~nRgX?`m2rfxZwdxqaT9`^gIfPsuBWZBY&8#?>=5sk1<4WsclTGWziq=yU%5b z;}@f^mK1u4*lpabEriK*-(UN+4HbneMq&bG=i5!9@)}N;e(jz|HXZowsxcx3dWHAT9vwaTh4KX`CVmIeYw|;i~sSm?z55RIhykN zjc%jH_i9;F^6Bu{I7SQTBurOE@<&w|eZS-8@dz62Z|*ZaitbO?O>4v%iz~~wz}Ss6 z6CdG)FsFSc)z4TT=03;Q_AKbMe|fwy87JGM+`L2OF)9ykHtUN(CFTjZvC|Q3?4b+d z^iDeNQ*NCEw3_hRZN+y!F2cH5@dk?&kwdfBalFe*A2ESZsvy)W=2jO@4obP@=1d!5 z;WP*EI~WHtYOFA&dZoX~CS0~E#q4+Ie19X2^o^@edZk_s@wg76r-&W5LXRKxxDSfM z93L)tjPo3Px27zS*ylG4PGtrPxDzW?cTWrP7Mzpre>SX#wlNok_QP1tSUvI@>|UNo zC@fGP9BHv-wFf`u`c?*lm9yH~$6j}dDN#bqMB4DZbu>Bfv81pceMrY!9UOh~l%i2t zEMfc%v=iB%&iP#LLf|^wdC$|D(4|Fj@7(x#gTax%7}XD#^y`#aKX1y$^RNNi77b%c z#VAeb_v|WE+q~uT+V31AHQc$vqX*E8o;>hqE9_g#we54hpYM;Yq+4z@H#xu=bN3u_ zjGyZ^@vl3$h^kb0y@Zl12mQEQL3N-7=?H|~-eg=xZ-=17sm}lSXE`-w8uQJP1CW>D z+y->5kAT3VO2+SRtwF}>uz+OugO$Ggt=CqgdA1unxp=gp{e8!biKpH{xUpplX#<1X```z&M&!#wu&`Sy6jok(wdF$E%s=4~WmHJe}d zq<;NoC=k{;c3c>bmc&lmPWf=3pj&_U1SXXYWb5LxHf|N4INYaG2{=N$|I25lp#1_!2m;=JgEEgzj+vB%0X!9h4Hhk?;GNmAinL97 ze;_tPi`Wx&PZQdDl!9z~F5xd{zYp+RpMrHs*tT^&fWYZBf23~a1N%Nkv^vsKDF zz(*y6F1NUbv7`;gYwOFzPU}8Va@XpqjaOef5gw6Gf38cEn5 z{{Bd3VCXxW5nY16!KI5A!5pp2!ADI`@$GyM@2cB>CBFiU!eMpd$IC@e|4r%K*@<=x zNlQNky9gz} zElV_n(pE*e#N+HYJ_RItpzO0$|tC-Y5C18QPbq|3;aYSN>JZeTv{G|J6%t9U0 zYO?iL+K<1}I;{{5P4aKu)?c@?pAAxlJO+ldo(TP6(Q5h9225N_duF=N{4blxHJBY2 z7A;+T&Se#MqHoTn;(6;~VDQ)eX#o&E`5H7U2nnx zolajBhB)+hNz4$*YVhTnMah1EYx!cM9Y@H>m>Q6R`sQ$BgI|=V&}4>-rvCi!V}G$aAWcaFdY~y_0qDxq+(sbv@5t*)7j|b*Z;-D z0?VA0$$VaUEqCm$_dW9?%9T8NB2%a*x>$2XwP$Th&1XXk2M32&3`f`yqAyAm*B~Nt zL*Jl0Qt=^8<%C<2p#1ghrbGJzOa}CShRO5)gH(SPf`M6TB>N9>{-0x(-LLKcfFI*O z&e_Mv_8-W%>2X(on%Dhm?QqO|ZDaMMC5Q%g6{385yR=*7gBjAckoZ@?+1c4S*zn!C z8}6A|nAn~pNGg8$`HL3|OJh1!nfY*A?BXUB%QxYXg_4$s<*R%)bl}I&jX}gnuw% zWLn)*`sg(9xWdzWyV*R+k=#|pY-&?IzXx@WTGSaHFld<{J*q4M;;JN@d z$af6FgL=v_|MMj!l4V`sXzvN|4sb4&u-tw?!#}|%ggRiKKQNz{!CF z2MtM1K7$88M{bP*ae?90MpHMX$U%vY(K-|JM-X;JH06!(YK@ zJY*tyj=v+)sQ#1#&fgFF4E%AR*FI)~p0s)Ef(xhmm?0;nhybSXM#!rAdbG27a3Gj& zUF4?chS0&n=j?)eZ?$z_B;Z?SR+7&R;pX|?Hhm)#Yo-5>P}-6-X~d~A!t{h5=G?*C z)IA$|1gJri!e;iw(%NPwzTQQD_4*k6ETlQ$oHVreD)7*BpZvrsMRH#=_YzP$e$7Ou zpEI(YKx;+Mb4W-S^KR_jpV%_}v%YNqpJjKWTu>!VT6b4G!4_Eu5tuKUwwp>U5B{ic6iI{|> zP8$uW)$|M+6dH&qW$8jP%we)DyVnTXTcV$h3ul=j9Ci=^xrnfrin2Gty_Q|kyX82d zPyF1RQj}XAI=)4wmU@NB-s7izs=JB{pSYW@Yf^EP3~NbRVc!6goE4L4lL`V z@tc2a5kL!LO#u&X*ORT~-@nrf3g*gSu)H1Aq{Dd?C}mk$X4g>7fK9f2?_v#9kVQEL zQZ3>RKU4(#tmtv)F@LLkx(!^e&5sj@uewGMx-e=66NORrd^eT6i}L&vrzjs*uhm8PzOII`m(XG6DMZq z6*Sd-SI%Wi^vnF)o^0~azW-&k{ZhBq(c>qSZnX-QrGs^{Z>l}>jko%5Bbfc%W z&K)?vbz+kf7pA%Ref|+v!J1w?Q5Wz+#nN>ye*uYv8u2L~Di2Qe=`;h#KQaPw6NGGIsSDk^7A8!-Z*GLtKiKax54NgY*dG{F%tn!urnHWG`h&-M4SAx z{^q)BTvmw&eHJ63!2TnbCqHdnD*-iW>B3+4Ai#}zG(>yCe9Xa2uf42{3eBk4XK zUhG?djr>Q!z47qc?NFQyr*j&TN7jNGy>52tiKoVb67;4JrJu?T0m-4yNNee>T}@cxH{qBX;kv z4(Gqo8ihO!rEkaZo;UP&YizOyD7O$FgYus}r;cB=qsy86mNIOp1@`-&dE33udCgy? z%7j{=7eO~_mmU{M27j{`F-PPclBuyKfrbwtA|`B#Sd{9|!v(pNbnTHQrvq$slN5B) zBRZ+lKrq|>r~)C*Mp%C>cnmFi&8zN9(`FT0EiZ8lz_OtzOYsYapDDc;Uus?E;&ZHfDW4ApR9EFv7PiQYOPpp)MAJ zUf9gBzukm{^tUDWFwpO@*g-$&Aqr~kiAo8H9iFBaH-5x1a{qUP#|8xcGxfVAa?)T2 zm4oEy>Lch)CzB^2Ut>lPFCAevdY&9+?R=Au=J0og<1N&TAhhS(%ptUHA^LQ}c@??Y z0zdl=w4rTgR+N~Sn46m$8XBs}5Kh@>Ut{4uvE1x1_V$gws-}iXR8*9c6Pp3u_V?8T zKotj?SkKE%q?RjEMNI#|wfVq=lR}L&0^c}iJ0g`*Dn|k(YAjy+efo*Q$Ru{HYMy&gCa|dP@ZM7woJI{MVp~`dvwsW^m?`jJTR# za*td*s#HiQ?W1?rD25FJ!_lq|-<=_5M{TU9$04P}oiV4Wn14+RxDrPM00{-0Ux>|x z9eO+g#vO3;p_z?->ucS}84cxqPDFr(-lw+!vJ+&#O)4JhF->y1sAboxfd0=Jnh#OjvTe{p z542>&jRB=jo#Nz!Bw!1$tJ528L4xxCn|X%j9f(F8qlyyFdV*^)aM(Jpk`Ywi+Ruk4 zf_ApwRD~00M9dSnboZ#Vt2KQeqqJfz8WI;n&GH82ROa?Y5XE(k>fx?TEc74=f$N5|5t;2&-M5`{t_`5h9qY?iT_Z#jWDb%yAK34LE z^B)aGq@w)3ysTIC{G_m^~1Y zUDEyUZo7a5hBsQ^T+<-kO>Cdi>R5SPrXgz`5txF`UsFG(U&ImL#)F~IM5KJD-k-0Y z4g(ldAi8Gg(YVkbyX-f*HrvJ0lt=&pG$k(neSCc6Dwkg3DNsKB=MuKU`Lv$$}c zWwU&P=uqf=!R1Nc)B48Ci8m2&j|(Jq^?_apGcq$#*Jxn?EK}n}(j{UpSdd_;A2p=E+e~c978T74Xu0Je;LNF0~iwfni6OOBe zf12`TqJ>IT1zQ=fQXtGe{+(jGf3{`a5I!o%7Gh)jt2itX zm$qP3uQQQ@Isx@ROXHDqlarPq_%8AV+-kJrTV}94b~jwoh@5_KbU!xp<4GXqVTj3! z$_FE;8Mg419(QW#)_BCZzX_t!`1xZ;E@x@uFt!Mmw|r%RTdN~oTgD;p5PW`rTwL)R zw9szI&#kTG%iP+?k=3fE2-Y!3=HdL)1s@|ZV(_?F#hF5HBLlf6XaZ*b9>0B@ULCEW z6rSiJ2dG8ymq;9YbuqBljdtX!eY0U6mbcvB9oeI{|6@b2IdI}6EFlT1gpVJ4m! z95Oa##a1r1Et9uo@=rXZFHX#UHoVq1G!M9ogW97SPJB5WL?g3)cxDz-(Q2hQSKSkc z(He|40`;=!+Y&Gc(HYShO4U5$>6PqOKds`UF`~j3CEZJB=d~>vws`9ke~9dl-;lT) zzXA%51nqDg;cDl}t->&*Wht7pQZzsHT^;cS%7uSR4`pK2VO3p>j>E+{|4ae!^wK$K z98q$adB_&MY-XK zL77y^cIfq|X()2al4f4^;`8p`A%dgk3A_^}C&eO`J>U)|?PX$At+Ip#QeaII!S!i?sCm@O zfe?y*!daTQ+NRE;UERLhSk0dbiQ;+HX@_s~RvP;5OkXW+bVN3RXm z;-ZmYhu-5izvoB;<1u;<_RqdIlHgvVNoHDEx16m0rO^rPq6lvZ!RFCYH@ESZGb@ra zcc8;grNja#kd(p$x1-0Y3rEFJ^~O48itl2F{te zbi?fV*@n;xC*$Ir4SzPpvTUR>L_mmBt}+_YNbg=hp(n~GOw6dBFjWTA>vC!5LUfb? zEKVlweRllJ^6zP=Khu+F0_x(D`1u)e8#h&XC1WIEK_$WFiu&-f1W*YlS1O%K-Q)Rw zVQ>P*a;Gn6;e4nrlO}!td*J&|6uJ?+E0jnn)EL0hn(zwdbQ7T7Vk5s%vi{})1r_Ee zZ#U|>f%vsrj75FI$$pgr`D$jI8Y`ZPGmsVOP1hwEShK*;J`eSAgym%c^alx)B5 z(Xa=mFBH3H;vt{0!uTaz_ts9_us;u-|0O8-05ahyn);@(5#Mbv9_1*sa^Eq8=t!@q zFjlz$3?XtInZ}+TA@GI#J}O*gwjm;t3FH+C{p(YiS~2^)9~ogDa5**fA|S$r15s9D z<#IvoW^sSWn(*5U&ALc~#|Q}tLFr>M?p&Okn|qeCv#V@rX{oNR{`E_Eqh;=2hRF!@ z1wV4RQA=0%V0(LeZ*OmNlOkQdD9SVm5k~3t!EuOHYvrA&gL~)an`t27~c9nRk) z^G@t2B{PS!_MSmOUE0;@!VUK#{?4gGiIdl-ovZa~~MbaSx&ctQvdPYMq)e%42 zpX%j7Y4T;p^^pwkUkRa-qb>une>lpvkp=^?RQ(gA5v9*G&QpLC?1~j#`baGdlSQ{D zm!esznUIhG69OGsq!;vLs{|EV`;jDRsZkalC?CJ7lnhelfJ`}t^+*@-TwX|#H z?4^h8@rbFV{nNe0b18A6^tl@5$D$DbO3qzL@wJI=hRj=>f1r$dRB_IY1yW-PM}9Dv zn;652{x{!$ayLt3xOcyplWL_M__ekM*iib|m>}Ao%{jBU!hYV`?n@&ET0?uWRl#oq zhE{Lq4V`Ua)sG Date: Tue, 23 Feb 2010 15:16:02 +0100 Subject: [PATCH 026/285] Comment the events in the options object (since it is no good practice anymore) --- Source/datepicker.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/datepicker.js b/Source/datepicker.js index 1f01b3d..ebdd087 100644 --- a/Source/datepicker.js +++ b/Source/datepicker.js @@ -88,12 +88,12 @@ var DatePicker = new Class({ minDate: null, // { date: '[date-string]', format: '[date-string-interpretation-format]' } maxDate: null, // same as minDate debug: false, - toggleElements: null, + toggleElements: null/*, // and some event hooks: onShow: $empty, // triggered when the datepicker pops up onClose: $empty, // triggered after the datepicker is closed (destroyed) - onSelect: $empty // triggered when a date is selected + onSelect: $empty // triggered when a date is selected*/ }, initialize: function(attachTo, options) { From 11f4e01a4382cba5847a62c8bb7a911381240482 Mon Sep 17 00:00:00 2001 From: Arian Date: Tue, 23 Feb 2010 15:32:16 +0100 Subject: [PATCH 027/285] Replace $$() and $() functions for resp document.getElements and document.id --- Source/datepicker.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Source/datepicker.js b/Source/datepicker.js index ebdd087..e0dc5db 100644 --- a/Source/datepicker.js +++ b/Source/datepicker.js @@ -131,10 +131,9 @@ var DatePicker = new Class({ }.bind(this) }); }; - + // attach functionality to the inputs - $$(this.attachTo).each(function(item, index) { - + document.getElements(this.attachTo).each(function(item, index) { // never double attach if (item.retrieve('datepicker')) return; @@ -603,7 +602,7 @@ var DatePicker = new Class({ }, close: function(e, force) { - if (!$(this.picker)) return; + if (!document.id(this.picker)) return; var clickOutside = ($chk(e) && e.target != this.picker && !this.picker.hasChild(e.target) && e.target != this.visual); if (force || clickOutside) { if (this.options.useFadeInOut) { From 780abe3039e8fde259cf4aa5e8d849a03fc3b0e3 Mon Sep 17 00:00:00 2001 From: Arian Date: Tue, 23 Feb 2010 15:38:15 +0100 Subject: [PATCH 028/285] Add a demo --- Test/index.html | 71 + Test/mootools-1.2.4-core.js | 4329 +++++++++++++++++++++++++++++++++++ Test/style.css | 121 + 3 files changed, 4521 insertions(+) create mode 100644 Test/index.html create mode 100644 Test/mootools-1.2.4-core.js create mode 100644 Test/style.css diff --git a/Test/index.html b/Test/index.html new file mode 100644 index 0000000..4075321 --- /dev/null +++ b/Test/index.html @@ -0,0 +1,71 @@ + + + + + +MooTools Datepicker + + + + + + + + + + + + + + + + + +

MooTools Datepicker

+ +

+ Smoothly animating, very configurable and easy to install. No Ajax, pure Javascript. +

+ +

+ More information and the original: Monkey Physics +

+ + +

Demo and Examples

+ +

+
+ +

+ +

+
+ +

+ +

+
+ +

+ +

+
+ +

+ + + diff --git a/Test/mootools-1.2.4-core.js b/Test/mootools-1.2.4-core.js new file mode 100644 index 0000000..0098571 --- /dev/null +++ b/Test/mootools-1.2.4-core.js @@ -0,0 +1,4329 @@ +/* +--- + +script: Core.js + +description: The core of MooTools, contains all the base functions and the Native and Hash implementations. Required by all the other scripts. + +license: MIT-style license. + +copyright: Copyright (c) 2006-2008 [Valerio Proietti](http://mad4milk.net/). + +authors: The MooTools production team (http://mootools.net/developers/) + +inspiration: +- Class implementation inspired by [Base.js](http://dean.edwards.name/weblog/2006/03/base/) Copyright (c) 2006 Dean Edwards, [GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php) +- Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php) + +provides: [Mootools, Native, Hash.base, Array.each, $util] + +... +*/ + +var MooTools = { + 'version': '1.2.4', + 'build': '0d9113241a90b9cd5643b926795852a2026710d4' +}; + +var Native = function(options){ + options = options || {}; + var name = options.name; + var legacy = options.legacy; + var protect = options.protect; + var methods = options.implement; + var generics = options.generics; + var initialize = options.initialize; + var afterImplement = options.afterImplement || function(){}; + var object = initialize || legacy; + generics = generics !== false; + + object.constructor = Native; + object.$family = {name: 'native'}; + if (legacy && initialize) object.prototype = legacy.prototype; + object.prototype.constructor = object; + + if (name){ + var family = name.toLowerCase(); + object.prototype.$family = {name: family}; + Native.typize(object, family); + } + + var add = function(obj, name, method, force){ + if (!protect || force || !obj.prototype[name]) obj.prototype[name] = method; + if (generics) Native.genericize(obj, name, protect); + afterImplement.call(obj, name, method); + return obj; + }; + + object.alias = function(a1, a2, a3){ + if (typeof a1 == 'string'){ + var pa1 = this.prototype[a1]; + if ((a1 = pa1)) return add(this, a2, a1, a3); + } + for (var a in a1) this.alias(a, a1[a], a2); + return this; + }; + + object.implement = function(a1, a2, a3){ + if (typeof a1 == 'string') return add(this, a1, a2, a3); + for (var p in a1) add(this, p, a1[p], a2); + return this; + }; + + if (methods) object.implement(methods); + + return object; +}; + +Native.genericize = function(object, property, check){ + if ((!check || !object[property]) && typeof object.prototype[property] == 'function') object[property] = function(){ + var args = Array.prototype.slice.call(arguments); + return object.prototype[property].apply(args.shift(), args); + }; +}; + +Native.implement = function(objects, properties){ + for (var i = 0, l = objects.length; i < l; i++) objects[i].implement(properties); +}; + +Native.typize = function(object, family){ + if (!object.type) object.type = function(item){ + return ($type(item) === family); + }; +}; + +(function(){ + var natives = {'Array': Array, 'Date': Date, 'Function': Function, 'Number': Number, 'RegExp': RegExp, 'String': String}; + for (var n in natives) new Native({name: n, initialize: natives[n], protect: true}); + + var types = {'boolean': Boolean, 'native': Native, 'object': Object}; + for (var t in types) Native.typize(types[t], t); + + var generics = { + 'Array': ["concat", "indexOf", "join", "lastIndexOf", "pop", "push", "reverse", "shift", "slice", "sort", "splice", "toString", "unshift", "valueOf"], + 'String': ["charAt", "charCodeAt", "concat", "indexOf", "lastIndexOf", "match", "replace", "search", "slice", "split", "substr", "substring", "toLowerCase", "toUpperCase", "valueOf"] + }; + for (var g in generics){ + for (var i = generics[g].length; i--;) Native.genericize(natives[g], generics[g][i], true); + } +})(); + +var Hash = new Native({ + + name: 'Hash', + + initialize: function(object){ + if ($type(object) == 'hash') object = $unlink(object.getClean()); + for (var key in object) this[key] = object[key]; + return this; + } + +}); + +Hash.implement({ + + forEach: function(fn, bind){ + for (var key in this){ + if (this.hasOwnProperty(key)) fn.call(bind, this[key], key, this); + } + }, + + getClean: function(){ + var clean = {}; + for (var key in this){ + if (this.hasOwnProperty(key)) clean[key] = this[key]; + } + return clean; + }, + + getLength: function(){ + var length = 0; + for (var key in this){ + if (this.hasOwnProperty(key)) length++; + } + return length; + } + +}); + +Hash.alias('forEach', 'each'); + +Array.implement({ + + forEach: function(fn, bind){ + for (var i = 0, l = this.length; i < l; i++) fn.call(bind, this[i], i, this); + } + +}); + +Array.alias('forEach', 'each'); + +function $A(iterable){ + if (iterable.item){ + var l = iterable.length, array = new Array(l); + while (l--) array[l] = iterable[l]; + return array; + } + return Array.prototype.slice.call(iterable); +}; + +function $arguments(i){ + return function(){ + return arguments[i]; + }; +}; + +function $chk(obj){ + return !!(obj || obj === 0); +}; + +function $clear(timer){ + clearTimeout(timer); + clearInterval(timer); + return null; +}; + +function $defined(obj){ + return (obj != undefined); +}; + +function $each(iterable, fn, bind){ + var type = $type(iterable); + ((type == 'arguments' || type == 'collection' || type == 'array') ? Array : Hash).each(iterable, fn, bind); +}; + +function $empty(){}; + +function $extend(original, extended){ + for (var key in (extended || {})) original[key] = extended[key]; + return original; +}; + +function $H(object){ + return new Hash(object); +}; + +function $lambda(value){ + return ($type(value) == 'function') ? value : function(){ + return value; + }; +}; + +function $merge(){ + var args = Array.slice(arguments); + args.unshift({}); + return $mixin.apply(null, args); +}; + +function $mixin(mix){ + for (var i = 1, l = arguments.length; i < l; i++){ + var object = arguments[i]; + if ($type(object) != 'object') continue; + for (var key in object){ + var op = object[key], mp = mix[key]; + mix[key] = (mp && $type(op) == 'object' && $type(mp) == 'object') ? $mixin(mp, op) : $unlink(op); + } + } + return mix; +}; + +function $pick(){ + for (var i = 0, l = arguments.length; i < l; i++){ + if (arguments[i] != undefined) return arguments[i]; + } + return null; +}; + +function $random(min, max){ + return Math.floor(Math.random() * (max - min + 1) + min); +}; + +function $splat(obj){ + var type = $type(obj); + return (type) ? ((type != 'array' && type != 'arguments') ? [obj] : obj) : []; +}; + +var $time = Date.now || function(){ + return +new Date; +}; + +function $try(){ + for (var i = 0, l = arguments.length; i < l; i++){ + try { + return arguments[i](); + } catch(e){} + } + return null; +}; + +function $type(obj){ + if (obj == undefined) return false; + if (obj.$family) return (obj.$family.name == 'number' && !isFinite(obj)) ? false : obj.$family.name; + if (obj.nodeName){ + switch (obj.nodeType){ + case 1: return 'element'; + case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace'; + } + } else if (typeof obj.length == 'number'){ + if (obj.callee) return 'arguments'; + else if (obj.item) return 'collection'; + } + return typeof obj; +}; + +function $unlink(object){ + var unlinked; + switch ($type(object)){ + case 'object': + unlinked = {}; + for (var p in object) unlinked[p] = $unlink(object[p]); + break; + case 'hash': + unlinked = new Hash(object); + break; + case 'array': + unlinked = []; + for (var i = 0, l = object.length; i < l; i++) unlinked[i] = $unlink(object[i]); + break; + default: return object; + } + return unlinked; +}; + + +/* +--- + +script: Browser.js + +description: The Browser Core. Contains Browser initialization, Window and Document, and the Browser Hash. + +license: MIT-style license. + +requires: +- /Native +- /$util + +provides: [Browser, Window, Document, $exec] + +... +*/ + +var Browser = $merge({ + + Engine: {name: 'unknown', version: 0}, + + Platform: {name: (window.orientation != undefined) ? 'ipod' : (navigator.platform.match(/mac|win|linux/i) || ['other'])[0].toLowerCase()}, + + Features: {xpath: !!(document.evaluate), air: !!(window.runtime), query: !!(document.querySelector)}, + + Plugins: {}, + + Engines: { + + presto: function(){ + return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925)); + }, + + trident: function(){ + return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? ((document.querySelectorAll) ? 6 : 5) : 4); + }, + + webkit: function(){ + return (navigator.taintEnabled) ? false : ((Browser.Features.xpath) ? ((Browser.Features.query) ? 525 : 420) : 419); + }, + + gecko: function(){ + return (!document.getBoxObjectFor && window.mozInnerScreenX == null) ? false : ((document.getElementsByClassName) ? 19 : 18); + } + + } + +}, Browser || {}); + +Browser.Platform[Browser.Platform.name] = true; + +Browser.detect = function(){ + + for (var engine in this.Engines){ + var version = this.Engines[engine](); + if (version){ + this.Engine = {name: engine, version: version}; + this.Engine[engine] = this.Engine[engine + version] = true; + break; + } + } + + return {name: engine, version: version}; + +}; + +Browser.detect(); + +Browser.Request = function(){ + return $try(function(){ + return new XMLHttpRequest(); + }, function(){ + return new ActiveXObject('MSXML2.XMLHTTP'); + }, function(){ + return new ActiveXObject('Microsoft.XMLHTTP'); + }); +}; + +Browser.Features.xhr = !!(Browser.Request()); + +Browser.Plugins.Flash = (function(){ + var version = ($try(function(){ + return navigator.plugins['Shockwave Flash'].description; + }, function(){ + return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version'); + }) || '0 r0').match(/\d+/g); + return {version: parseInt(version[0] || 0 + '.' + version[1], 10) || 0, build: parseInt(version[2], 10) || 0}; +})(); + +function $exec(text){ + if (!text) return text; + if (window.execScript){ + window.execScript(text); + } else { + var script = document.createElement('script'); + script.setAttribute('type', 'text/javascript'); + script[(Browser.Engine.webkit && Browser.Engine.version < 420) ? 'innerText' : 'text'] = text; + document.head.appendChild(script); + document.head.removeChild(script); + } + return text; +}; + +Native.UID = 1; + +var $uid = (Browser.Engine.trident) ? function(item){ + return (item.uid || (item.uid = [Native.UID++]))[0]; +} : function(item){ + return item.uid || (item.uid = Native.UID++); +}; + +var Window = new Native({ + + name: 'Window', + + legacy: (Browser.Engine.trident) ? null: window.Window, + + initialize: function(win){ + $uid(win); + if (!win.Element){ + win.Element = $empty; + if (Browser.Engine.webkit) win.document.createElement("iframe"); //fixes safari 2 + win.Element.prototype = (Browser.Engine.webkit) ? window["[[DOMElement.prototype]]"] : {}; + } + win.document.window = win; + return $extend(win, Window.Prototype); + }, + + afterImplement: function(property, value){ + window[property] = Window.Prototype[property] = value; + } + +}); + +Window.Prototype = {$family: {name: 'window'}}; + +new Window(window); + +var Document = new Native({ + + name: 'Document', + + legacy: (Browser.Engine.trident) ? null: window.Document, + + initialize: function(doc){ + $uid(doc); + doc.head = doc.getElementsByTagName('head')[0]; + doc.html = doc.getElementsByTagName('html')[0]; + if (Browser.Engine.trident && Browser.Engine.version <= 4) $try(function(){ + doc.execCommand("BackgroundImageCache", false, true); + }); + if (Browser.Engine.trident) doc.window.attachEvent('onunload', function(){ + doc.window.detachEvent('onunload', arguments.callee); + doc.head = doc.html = doc.window = null; + }); + return $extend(doc, Document.Prototype); + }, + + afterImplement: function(property, value){ + document[property] = Document.Prototype[property] = value; + } + +}); + +Document.Prototype = {$family: {name: 'document'}}; + +new Document(document); + + +/* +--- + +script: Array.js + +description: Contains Array Prototypes like each, contains, and erase. + +license: MIT-style license. + +requires: +- /$util +- /Array.each + +provides: [Array] + +... +*/ + +Array.implement({ + + every: function(fn, bind){ + for (var i = 0, l = this.length; i < l; i++){ + if (!fn.call(bind, this[i], i, this)) return false; + } + return true; + }, + + filter: function(fn, bind){ + var results = []; + for (var i = 0, l = this.length; i < l; i++){ + if (fn.call(bind, this[i], i, this)) results.push(this[i]); + } + return results; + }, + + clean: function(){ + return this.filter($defined); + }, + + indexOf: function(item, from){ + var len = this.length; + for (var i = (from < 0) ? Math.max(0, len + from) : from || 0; i < len; i++){ + if (this[i] === item) return i; + } + return -1; + }, + + map: function(fn, bind){ + var results = []; + for (var i = 0, l = this.length; i < l; i++) results[i] = fn.call(bind, this[i], i, this); + return results; + }, + + some: function(fn, bind){ + for (var i = 0, l = this.length; i < l; i++){ + if (fn.call(bind, this[i], i, this)) return true; + } + return false; + }, + + associate: function(keys){ + var obj = {}, length = Math.min(this.length, keys.length); + for (var i = 0; i < length; i++) obj[keys[i]] = this[i]; + return obj; + }, + + link: function(object){ + var result = {}; + for (var i = 0, l = this.length; i < l; i++){ + for (var key in object){ + if (object[key](this[i])){ + result[key] = this[i]; + delete object[key]; + break; + } + } + } + return result; + }, + + contains: function(item, from){ + return this.indexOf(item, from) != -1; + }, + + extend: function(array){ + for (var i = 0, j = array.length; i < j; i++) this.push(array[i]); + return this; + }, + + getLast: function(){ + return (this.length) ? this[this.length - 1] : null; + }, + + getRandom: function(){ + return (this.length) ? this[$random(0, this.length - 1)] : null; + }, + + include: function(item){ + if (!this.contains(item)) this.push(item); + return this; + }, + + combine: function(array){ + for (var i = 0, l = array.length; i < l; i++) this.include(array[i]); + return this; + }, + + erase: function(item){ + for (var i = this.length; i--; i){ + if (this[i] === item) this.splice(i, 1); + } + return this; + }, + + empty: function(){ + this.length = 0; + return this; + }, + + flatten: function(){ + var array = []; + for (var i = 0, l = this.length; i < l; i++){ + var type = $type(this[i]); + if (!type) continue; + array = array.concat((type == 'array' || type == 'collection' || type == 'arguments') ? Array.flatten(this[i]) : this[i]); + } + return array; + }, + + hexToRgb: function(array){ + if (this.length != 3) return null; + var rgb = this.map(function(value){ + if (value.length == 1) value += value; + return value.toInt(16); + }); + return (array) ? rgb : 'rgb(' + rgb + ')'; + }, + + rgbToHex: function(array){ + if (this.length < 3) return null; + if (this.length == 4 && this[3] == 0 && !array) return 'transparent'; + var hex = []; + for (var i = 0; i < 3; i++){ + var bit = (this[i] - 0).toString(16); + hex.push((bit.length == 1) ? '0' + bit : bit); + } + return (array) ? hex : '#' + hex.join(''); + } + +}); + + +/* +--- + +script: Function.js + +description: Contains Function Prototypes like create, bind, pass, and delay. + +license: MIT-style license. + +requires: +- /Native +- /$util + +provides: [Function] + +... +*/ + +Function.implement({ + + extend: function(properties){ + for (var property in properties) this[property] = properties[property]; + return this; + }, + + create: function(options){ + var self = this; + options = options || {}; + return function(event){ + var args = options.arguments; + args = (args != undefined) ? $splat(args) : Array.slice(arguments, (options.event) ? 1 : 0); + if (options.event) args = [event || window.event].extend(args); + var returns = function(){ + return self.apply(options.bind || null, args); + }; + if (options.delay) return setTimeout(returns, options.delay); + if (options.periodical) return setInterval(returns, options.periodical); + if (options.attempt) return $try(returns); + return returns(); + }; + }, + + run: function(args, bind){ + return this.apply(bind, $splat(args)); + }, + + pass: function(args, bind){ + return this.create({bind: bind, arguments: args}); + }, + + bind: function(bind, args){ + return this.create({bind: bind, arguments: args}); + }, + + bindWithEvent: function(bind, args){ + return this.create({bind: bind, arguments: args, event: true}); + }, + + attempt: function(args, bind){ + return this.create({bind: bind, arguments: args, attempt: true})(); + }, + + delay: function(delay, bind, args){ + return this.create({bind: bind, arguments: args, delay: delay})(); + }, + + periodical: function(periodical, bind, args){ + return this.create({bind: bind, arguments: args, periodical: periodical})(); + } + +}); + + +/* +--- + +script: Number.js + +description: Contains Number Prototypes like limit, round, times, and ceil. + +license: MIT-style license. + +requires: +- /Native +- /$util + +provides: [Number] + +... +*/ + +Number.implement({ + + limit: function(min, max){ + return Math.min(max, Math.max(min, this)); + }, + + round: function(precision){ + precision = Math.pow(10, precision || 0); + return Math.round(this * precision) / precision; + }, + + times: function(fn, bind){ + for (var i = 0; i < this; i++) fn.call(bind, i, this); + }, + + toFloat: function(){ + return parseFloat(this); + }, + + toInt: function(base){ + return parseInt(this, base || 10); + } + +}); + +Number.alias('times', 'each'); + +(function(math){ + var methods = {}; + math.each(function(name){ + if (!Number[name]) methods[name] = function(){ + return Math[name].apply(null, [this].concat($A(arguments))); + }; + }); + Number.implement(methods); +})(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']); + + +/* +--- + +script: String.js + +description: Contains String Prototypes like camelCase, capitalize, test, and toInt. + +license: MIT-style license. + +requires: +- /Native + +provides: [String] + +... +*/ + +String.implement({ + + test: function(regex, params){ + return ((typeof regex == 'string') ? new RegExp(regex, params) : regex).test(this); + }, + + contains: function(string, separator){ + return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : this.indexOf(string) > -1; + }, + + trim: function(){ + return this.replace(/^\s+|\s+$/g, ''); + }, + + clean: function(){ + return this.replace(/\s+/g, ' ').trim(); + }, + + camelCase: function(){ + return this.replace(/-\D/g, function(match){ + return match.charAt(1).toUpperCase(); + }); + }, + + hyphenate: function(){ + return this.replace(/[A-Z]/g, function(match){ + return ('-' + match.charAt(0).toLowerCase()); + }); + }, + + capitalize: function(){ + return this.replace(/\b[a-z]/g, function(match){ + return match.toUpperCase(); + }); + }, + + escapeRegExp: function(){ + return this.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1'); + }, + + toInt: function(base){ + return parseInt(this, base || 10); + }, + + toFloat: function(){ + return parseFloat(this); + }, + + hexToRgb: function(array){ + var hex = this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/); + return (hex) ? hex.slice(1).hexToRgb(array) : null; + }, + + rgbToHex: function(array){ + var rgb = this.match(/\d{1,3}/g); + return (rgb) ? rgb.rgbToHex(array) : null; + }, + + stripScripts: function(option){ + var scripts = ''; + var text = this.replace(/]*>([\s\S]*?)<\/script>/gi, function(){ + scripts += arguments[1] + '\n'; + return ''; + }); + if (option === true) $exec(scripts); + else if ($type(option) == 'function') option(scripts, text); + return text; + }, + + substitute: function(object, regexp){ + return this.replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){ + if (match.charAt(0) == '\\') return match.slice(1); + return (object[name] != undefined) ? object[name] : ''; + }); + } + +}); + + +/* +--- + +script: Hash.js + +description: Contains Hash Prototypes. Provides a means for overcoming the JavaScript practical impossibility of extending native Objects. + +license: MIT-style license. + +requires: +- /Hash.base + +provides: [Hash] + +... +*/ + +Hash.implement({ + + has: Object.prototype.hasOwnProperty, + + keyOf: function(value){ + for (var key in this){ + if (this.hasOwnProperty(key) && this[key] === value) return key; + } + return null; + }, + + hasValue: function(value){ + return (Hash.keyOf(this, value) !== null); + }, + + extend: function(properties){ + Hash.each(properties || {}, function(value, key){ + Hash.set(this, key, value); + }, this); + return this; + }, + + combine: function(properties){ + Hash.each(properties || {}, function(value, key){ + Hash.include(this, key, value); + }, this); + return this; + }, + + erase: function(key){ + if (this.hasOwnProperty(key)) delete this[key]; + return this; + }, + + get: function(key){ + return (this.hasOwnProperty(key)) ? this[key] : null; + }, + + set: function(key, value){ + if (!this[key] || this.hasOwnProperty(key)) this[key] = value; + return this; + }, + + empty: function(){ + Hash.each(this, function(value, key){ + delete this[key]; + }, this); + return this; + }, + + include: function(key, value){ + if (this[key] == undefined) this[key] = value; + return this; + }, + + map: function(fn, bind){ + var results = new Hash; + Hash.each(this, function(value, key){ + results.set(key, fn.call(bind, value, key, this)); + }, this); + return results; + }, + + filter: function(fn, bind){ + var results = new Hash; + Hash.each(this, function(value, key){ + if (fn.call(bind, value, key, this)) results.set(key, value); + }, this); + return results; + }, + + every: function(fn, bind){ + for (var key in this){ + if (this.hasOwnProperty(key) && !fn.call(bind, this[key], key)) return false; + } + return true; + }, + + some: function(fn, bind){ + for (var key in this){ + if (this.hasOwnProperty(key) && fn.call(bind, this[key], key)) return true; + } + return false; + }, + + getKeys: function(){ + var keys = []; + Hash.each(this, function(value, key){ + keys.push(key); + }); + return keys; + }, + + getValues: function(){ + var values = []; + Hash.each(this, function(value){ + values.push(value); + }); + return values; + }, + + toQueryString: function(base){ + var queryString = []; + Hash.each(this, function(value, key){ + if (base) key = base + '[' + key + ']'; + var result; + switch ($type(value)){ + case 'object': result = Hash.toQueryString(value, key); break; + case 'array': + var qs = {}; + value.each(function(val, i){ + qs[i] = val; + }); + result = Hash.toQueryString(qs, key); + break; + default: result = key + '=' + encodeURIComponent(value); + } + if (value != undefined) queryString.push(result); + }); + + return queryString.join('&'); + } + +}); + +Hash.alias({keyOf: 'indexOf', hasValue: 'contains'}); + + +/* +--- + +script: Event.js + +description: Contains the Event Class, to make the event object cross-browser. + +license: MIT-style license. + +requires: +- /Window +- /Document +- /Hash +- /Array +- /Function +- /String + +provides: [Event] + +... +*/ + +var Event = new Native({ + + name: 'Event', + + initialize: function(event, win){ + win = win || window; + var doc = win.document; + event = event || win.event; + if (event.$extended) return event; + this.$extended = true; + var type = event.type; + var target = event.target || event.srcElement; + while (target && target.nodeType == 3) target = target.parentNode; + + if (type.test(/key/)){ + var code = event.which || event.keyCode; + var key = Event.Keys.keyOf(code); + if (type == 'keydown'){ + var fKey = code - 111; + if (fKey > 0 && fKey < 13) key = 'f' + fKey; + } + key = key || String.fromCharCode(code).toLowerCase(); + } else if (type.match(/(click|mouse|menu)/i)){ + doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body; + var page = { + x: event.pageX || event.clientX + doc.scrollLeft, + y: event.pageY || event.clientY + doc.scrollTop + }; + var client = { + x: (event.pageX) ? event.pageX - win.pageXOffset : event.clientX, + y: (event.pageY) ? event.pageY - win.pageYOffset : event.clientY + }; + if (type.match(/DOMMouseScroll|mousewheel/)){ + var wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3; + } + var rightClick = (event.which == 3) || (event.button == 2); + var related = null; + if (type.match(/over|out/)){ + switch (type){ + case 'mouseover': related = event.relatedTarget || event.fromElement; break; + case 'mouseout': related = event.relatedTarget || event.toElement; + } + if (!(function(){ + while (related && related.nodeType == 3) related = related.parentNode; + return true; + }).create({attempt: Browser.Engine.gecko})()) related = false; + } + } + + return $extend(this, { + event: event, + type: type, + + page: page, + client: client, + rightClick: rightClick, + + wheel: wheel, + + relatedTarget: related, + target: target, + + code: code, + key: key, + + shift: event.shiftKey, + control: event.ctrlKey, + alt: event.altKey, + meta: event.metaKey + }); + } + +}); + +Event.Keys = new Hash({ + 'enter': 13, + 'up': 38, + 'down': 40, + 'left': 37, + 'right': 39, + 'esc': 27, + 'space': 32, + 'backspace': 8, + 'tab': 9, + 'delete': 46 +}); + +Event.implement({ + + stop: function(){ + return this.stopPropagation().preventDefault(); + }, + + stopPropagation: function(){ + if (this.event.stopPropagation) this.event.stopPropagation(); + else this.event.cancelBubble = true; + return this; + }, + + preventDefault: function(){ + if (this.event.preventDefault) this.event.preventDefault(); + else this.event.returnValue = false; + return this; + } + +}); + + +/* +--- + +script: Class.js + +description: Contains the Class Function for easily creating, extending, and implementing reusable Classes. + +license: MIT-style license. + +requires: +- /$util +- /Native +- /Array +- /String +- /Function +- /Number +- /Hash + +provides: [Class] + +... +*/ + +function Class(params){ + + if (params instanceof Function) params = {initialize: params}; + + var newClass = function(){ + Object.reset(this); + if (newClass._prototyping) return this; + this._current = $empty; + var value = (this.initialize) ? this.initialize.apply(this, arguments) : this; + delete this._current; delete this.caller; + return value; + }.extend(this); + + newClass.implement(params); + + newClass.constructor = Class; + newClass.prototype.constructor = newClass; + + return newClass; + +}; + +Function.prototype.protect = function(){ + this._protected = true; + return this; +}; + +Object.reset = function(object, key){ + + if (key == null){ + for (var p in object) Object.reset(object, p); + return object; + } + + delete object[key]; + + switch ($type(object[key])){ + case 'object': + var F = function(){}; + F.prototype = object[key]; + var i = new F; + object[key] = Object.reset(i); + break; + case 'array': object[key] = $unlink(object[key]); break; + } + + return object; + +}; + +new Native({name: 'Class', initialize: Class}).extend({ + + instantiate: function(F){ + F._prototyping = true; + var proto = new F; + delete F._prototyping; + return proto; + }, + + wrap: function(self, key, method){ + if (method._origin) method = method._origin; + + return function(){ + if (method._protected && this._current == null) throw new Error('The method "' + key + '" cannot be called.'); + var caller = this.caller, current = this._current; + this.caller = current; this._current = arguments.callee; + var result = method.apply(this, arguments); + this._current = current; this.caller = caller; + return result; + }.extend({_owner: self, _origin: method, _name: key}); + + } + +}); + +Class.implement({ + + implement: function(key, value){ + + if ($type(key) == 'object'){ + for (var p in key) this.implement(p, key[p]); + return this; + } + + var mutator = Class.Mutators[key]; + + if (mutator){ + value = mutator.call(this, value); + if (value == null) return this; + } + + var proto = this.prototype; + + switch ($type(value)){ + + case 'function': + if (value._hidden) return this; + proto[key] = Class.wrap(this, key, value); + break; + + case 'object': + var previous = proto[key]; + if ($type(previous) == 'object') $mixin(previous, value); + else proto[key] = $unlink(value); + break; + + case 'array': + proto[key] = $unlink(value); + break; + + default: proto[key] = value; + + } + + return this; + + } + +}); + +Class.Mutators = { + + Extends: function(parent){ + + this.parent = parent; + this.prototype = Class.instantiate(parent); + + this.implement('parent', function(){ + var name = this.caller._name, previous = this.caller._owner.parent.prototype[name]; + if (!previous) throw new Error('The method "' + name + '" has no parent.'); + return previous.apply(this, arguments); + }.protect()); + + }, + + Implements: function(items){ + $splat(items).each(function(item){ + if (item instanceof Function) item = Class.instantiate(item); + this.implement(item); + }, this); + + } + +}; + + +/* +--- + +script: Class.Extras.js + +description: Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks. + +license: MIT-style license. + +requires: +- /Class + +provides: [Chain, Events, Options] + +... +*/ + +var Chain = new Class({ + + $chain: [], + + chain: function(){ + this.$chain.extend(Array.flatten(arguments)); + return this; + }, + + callChain: function(){ + return (this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false; + }, + + clearChain: function(){ + this.$chain.empty(); + return this; + } + +}); + +var Events = new Class({ + + $events: {}, + + addEvent: function(type, fn, internal){ + type = Events.removeOn(type); + if (fn != $empty){ + this.$events[type] = this.$events[type] || []; + this.$events[type].include(fn); + if (internal) fn.internal = true; + } + return this; + }, + + addEvents: function(events){ + for (var type in events) this.addEvent(type, events[type]); + return this; + }, + + fireEvent: function(type, args, delay){ + type = Events.removeOn(type); + if (!this.$events || !this.$events[type]) return this; + this.$events[type].each(function(fn){ + fn.create({'bind': this, 'delay': delay, 'arguments': args})(); + }, this); + return this; + }, + + removeEvent: function(type, fn){ + type = Events.removeOn(type); + if (!this.$events[type]) return this; + if (!fn.internal) this.$events[type].erase(fn); + return this; + }, + + removeEvents: function(events){ + var type; + if ($type(events) == 'object'){ + for (type in events) this.removeEvent(type, events[type]); + return this; + } + if (events) events = Events.removeOn(events); + for (type in this.$events){ + if (events && events != type) continue; + var fns = this.$events[type]; + for (var i = fns.length; i--; i) this.removeEvent(type, fns[i]); + } + return this; + } + +}); + +Events.removeOn = function(string){ + return string.replace(/^on([A-Z])/, function(full, first){ + return first.toLowerCase(); + }); +}; + +var Options = new Class({ + + setOptions: function(){ + this.options = $merge.run([this.options].extend(arguments)); + if (!this.addEvent) return this; + for (var option in this.options){ + if ($type(this.options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue; + this.addEvent(option, this.options[option]); + delete this.options[option]; + } + return this; + } + +}); + + +/* +--- + +script: Element.js + +description: One of the most important items in MooTools. Contains the dollar function, the dollars function, and an handful of cross-browser, time-saver methods to let you easily work with HTML Elements. + +license: MIT-style license. + +requires: +- /Window +- /Document +- /Array +- /String +- /Function +- /Number +- /Hash + +provides: [Element, Elements, $, $$, Iframe] + +... +*/ + +var Element = new Native({ + + name: 'Element', + + legacy: window.Element, + + initialize: function(tag, props){ + var konstructor = Element.Constructors.get(tag); + if (konstructor) return konstructor(props); + if (typeof tag == 'string') return document.newElement(tag, props); + return document.id(tag).set(props); + }, + + afterImplement: function(key, value){ + Element.Prototype[key] = value; + if (Array[key]) return; + Elements.implement(key, function(){ + var items = [], elements = true; + for (var i = 0, j = this.length; i < j; i++){ + var returns = this[i][key].apply(this[i], arguments); + items.push(returns); + if (elements) elements = ($type(returns) == 'element'); + } + return (elements) ? new Elements(items) : items; + }); + } + +}); + +Element.Prototype = {$family: {name: 'element'}}; + +Element.Constructors = new Hash; + +var IFrame = new Native({ + + name: 'IFrame', + + generics: false, + + initialize: function(){ + var params = Array.link(arguments, {properties: Object.type, iframe: $defined}); + var props = params.properties || {}; + var iframe = document.id(params.iframe); + var onload = props.onload || $empty; + delete props.onload; + props.id = props.name = $pick(props.id, props.name, iframe ? (iframe.id || iframe.name) : 'IFrame_' + $time()); + iframe = new Element(iframe || 'iframe', props); + var onFrameLoad = function(){ + var host = $try(function(){ + return iframe.contentWindow.location.host; + }); + if (!host || host == window.location.host){ + var win = new Window(iframe.contentWindow); + new Document(iframe.contentWindow.document); + $extend(win.Element.prototype, Element.Prototype); + } + onload.call(iframe.contentWindow, iframe.contentWindow.document); + }; + var contentWindow = $try(function(){ + return iframe.contentWindow; + }); + ((contentWindow && contentWindow.document.body) || window.frames[props.id]) ? onFrameLoad() : iframe.addListener('load', onFrameLoad); + return iframe; + } + +}); + +var Elements = new Native({ + + initialize: function(elements, options){ + options = $extend({ddup: true, cash: true}, options); + elements = elements || []; + if (options.ddup || options.cash){ + var uniques = {}, returned = []; + for (var i = 0, l = elements.length; i < l; i++){ + var el = document.id(elements[i], !options.cash); + if (options.ddup){ + if (uniques[el.uid]) continue; + uniques[el.uid] = true; + } + if (el) returned.push(el); + } + elements = returned; + } + return (options.cash) ? $extend(elements, this) : elements; + } + +}); + +Elements.implement({ + + filter: function(filter, bind){ + if (!filter) return this; + return new Elements(Array.filter(this, (typeof filter == 'string') ? function(item){ + return item.match(filter); + } : filter, bind)); + } + +}); + +Document.implement({ + + newElement: function(tag, props){ + if (Browser.Engine.trident && props){ + ['name', 'type', 'checked'].each(function(attribute){ + if (!props[attribute]) return; + tag += ' ' + attribute + '="' + props[attribute] + '"'; + if (attribute != 'checked') delete props[attribute]; + }); + tag = '<' + tag + '>'; + } + return document.id(this.createElement(tag)).set(props); + }, + + newTextNode: function(text){ + return this.createTextNode(text); + }, + + getDocument: function(){ + return this; + }, + + getWindow: function(){ + return this.window; + }, + + id: (function(){ + + var types = { + + string: function(id, nocash, doc){ + id = doc.getElementById(id); + return (id) ? types.element(id, nocash) : null; + }, + + element: function(el, nocash){ + $uid(el); + if (!nocash && !el.$family && !(/^object|embed$/i).test(el.tagName)){ + var proto = Element.Prototype; + for (var p in proto) el[p] = proto[p]; + }; + return el; + }, + + object: function(obj, nocash, doc){ + if (obj.toElement) return types.element(obj.toElement(doc), nocash); + return null; + } + + }; + + types.textnode = types.whitespace = types.window = types.document = $arguments(0); + + return function(el, nocash, doc){ + if (el && el.$family && el.uid) return el; + var type = $type(el); + return (types[type]) ? types[type](el, nocash, doc || document) : null; + }; + + })() + +}); + +if (window.$ == null) Window.implement({ + $: function(el, nc){ + return document.id(el, nc, this.document); + } +}); + +Window.implement({ + + $$: function(selector){ + if (arguments.length == 1 && typeof selector == 'string') return this.document.getElements(selector); + var elements = []; + var args = Array.flatten(arguments); + for (var i = 0, l = args.length; i < l; i++){ + var item = args[i]; + switch ($type(item)){ + case 'element': elements.push(item); break; + case 'string': elements.extend(this.document.getElements(item, true)); + } + } + return new Elements(elements); + }, + + getDocument: function(){ + return this.document; + }, + + getWindow: function(){ + return this; + } + +}); + +Native.implement([Element, Document], { + + getElement: function(selector, nocash){ + return document.id(this.getElements(selector, true)[0] || null, nocash); + }, + + getElements: function(tags, nocash){ + tags = tags.split(','); + var elements = []; + var ddup = (tags.length > 1); + tags.each(function(tag){ + var partial = this.getElementsByTagName(tag.trim()); + (ddup) ? elements.extend(partial) : elements = partial; + }, this); + return new Elements(elements, {ddup: ddup, cash: !nocash}); + } + +}); + +(function(){ + +var collected = {}, storage = {}; +var props = {input: 'checked', option: 'selected', textarea: (Browser.Engine.webkit && Browser.Engine.version < 420) ? 'innerHTML' : 'value'}; + +var get = function(uid){ + return (storage[uid] || (storage[uid] = {})); +}; + +var clean = function(item, retain){ + if (!item) return; + var uid = item.uid; + if (Browser.Engine.trident){ + if (item.clearAttributes){ + var clone = retain && item.cloneNode(false); + item.clearAttributes(); + if (clone) item.mergeAttributes(clone); + } else if (item.removeEvents){ + item.removeEvents(); + } + if ((/object/i).test(item.tagName)){ + for (var p in item){ + if (typeof item[p] == 'function') item[p] = $empty; + } + Element.dispose(item); + } + } + if (!uid) return; + collected[uid] = storage[uid] = null; +}; + +var purge = function(){ + Hash.each(collected, clean); + if (Browser.Engine.trident) $A(document.getElementsByTagName('object')).each(clean); + if (window.CollectGarbage) CollectGarbage(); + collected = storage = null; +}; + +var walk = function(element, walk, start, match, all, nocash){ + var el = element[start || walk]; + var elements = []; + while (el){ + if (el.nodeType == 1 && (!match || Element.match(el, match))){ + if (!all) return document.id(el, nocash); + elements.push(el); + } + el = el[walk]; + } + return (all) ? new Elements(elements, {ddup: false, cash: !nocash}) : null; +}; + +var attributes = { + 'html': 'innerHTML', + 'class': 'className', + 'for': 'htmlFor', + 'defaultValue': 'defaultValue', + 'text': (Browser.Engine.trident || (Browser.Engine.webkit && Browser.Engine.version < 420)) ? 'innerText' : 'textContent' +}; +var bools = ['compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked', 'disabled', 'readonly', 'multiple', 'selected', 'noresize', 'defer']; +var camels = ['value', 'type', 'defaultValue', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan', 'frameBorder', 'maxLength', 'readOnly', 'rowSpan', 'tabIndex', 'useMap']; + +bools = bools.associate(bools); + +Hash.extend(attributes, bools); +Hash.extend(attributes, camels.associate(camels.map(String.toLowerCase))); + +var inserters = { + + before: function(context, element){ + if (element.parentNode) element.parentNode.insertBefore(context, element); + }, + + after: function(context, element){ + if (!element.parentNode) return; + var next = element.nextSibling; + (next) ? element.parentNode.insertBefore(context, next) : element.parentNode.appendChild(context); + }, + + bottom: function(context, element){ + element.appendChild(context); + }, + + top: function(context, element){ + var first = element.firstChild; + (first) ? element.insertBefore(context, first) : element.appendChild(context); + } + +}; + +inserters.inside = inserters.bottom; + +Hash.each(inserters, function(inserter, where){ + + where = where.capitalize(); + + Element.implement('inject' + where, function(el){ + inserter(this, document.id(el, true)); + return this; + }); + + Element.implement('grab' + where, function(el){ + inserter(document.id(el, true), this); + return this; + }); + +}); + +Element.implement({ + + set: function(prop, value){ + switch ($type(prop)){ + case 'object': + for (var p in prop) this.set(p, prop[p]); + break; + case 'string': + var property = Element.Properties.get(prop); + (property && property.set) ? property.set.apply(this, Array.slice(arguments, 1)) : this.setProperty(prop, value); + } + return this; + }, + + get: function(prop){ + var property = Element.Properties.get(prop); + return (property && property.get) ? property.get.apply(this, Array.slice(arguments, 1)) : this.getProperty(prop); + }, + + erase: function(prop){ + var property = Element.Properties.get(prop); + (property && property.erase) ? property.erase.apply(this) : this.removeProperty(prop); + return this; + }, + + setProperty: function(attribute, value){ + var key = attributes[attribute]; + if (value == undefined) return this.removeProperty(attribute); + if (key && bools[attribute]) value = !!value; + (key) ? this[key] = value : this.setAttribute(attribute, '' + value); + return this; + }, + + setProperties: function(attributes){ + for (var attribute in attributes) this.setProperty(attribute, attributes[attribute]); + return this; + }, + + getProperty: function(attribute){ + var key = attributes[attribute]; + var value = (key) ? this[key] : this.getAttribute(attribute, 2); + return (bools[attribute]) ? !!value : (key) ? value : value || null; + }, + + getProperties: function(){ + var args = $A(arguments); + return args.map(this.getProperty, this).associate(args); + }, + + removeProperty: function(attribute){ + var key = attributes[attribute]; + (key) ? this[key] = (key && bools[attribute]) ? false : '' : this.removeAttribute(attribute); + return this; + }, + + removeProperties: function(){ + Array.each(arguments, this.removeProperty, this); + return this; + }, + + hasClass: function(className){ + return this.className.contains(className, ' '); + }, + + addClass: function(className){ + if (!this.hasClass(className)) this.className = (this.className + ' ' + className).clean(); + return this; + }, + + removeClass: function(className){ + this.className = this.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1'); + return this; + }, + + toggleClass: function(className){ + return this.hasClass(className) ? this.removeClass(className) : this.addClass(className); + }, + + adopt: function(){ + Array.flatten(arguments).each(function(element){ + element = document.id(element, true); + if (element) this.appendChild(element); + }, this); + return this; + }, + + appendText: function(text, where){ + return this.grab(this.getDocument().newTextNode(text), where); + }, + + grab: function(el, where){ + inserters[where || 'bottom'](document.id(el, true), this); + return this; + }, + + inject: function(el, where){ + inserters[where || 'bottom'](this, document.id(el, true)); + return this; + }, + + replaces: function(el){ + el = document.id(el, true); + el.parentNode.replaceChild(this, el); + return this; + }, + + wraps: function(el, where){ + el = document.id(el, true); + return this.replaces(el).grab(el, where); + }, + + getPrevious: function(match, nocash){ + return walk(this, 'previousSibling', null, match, false, nocash); + }, + + getAllPrevious: function(match, nocash){ + return walk(this, 'previousSibling', null, match, true, nocash); + }, + + getNext: function(match, nocash){ + return walk(this, 'nextSibling', null, match, false, nocash); + }, + + getAllNext: function(match, nocash){ + return walk(this, 'nextSibling', null, match, true, nocash); + }, + + getFirst: function(match, nocash){ + return walk(this, 'nextSibling', 'firstChild', match, false, nocash); + }, + + getLast: function(match, nocash){ + return walk(this, 'previousSibling', 'lastChild', match, false, nocash); + }, + + getParent: function(match, nocash){ + return walk(this, 'parentNode', null, match, false, nocash); + }, + + getParents: function(match, nocash){ + return walk(this, 'parentNode', null, match, true, nocash); + }, + + getSiblings: function(match, nocash){ + return this.getParent().getChildren(match, nocash).erase(this); + }, + + getChildren: function(match, nocash){ + return walk(this, 'nextSibling', 'firstChild', match, true, nocash); + }, + + getWindow: function(){ + return this.ownerDocument.window; + }, + + getDocument: function(){ + return this.ownerDocument; + }, + + getElementById: function(id, nocash){ + var el = this.ownerDocument.getElementById(id); + if (!el) return null; + for (var parent = el.parentNode; parent != this; parent = parent.parentNode){ + if (!parent) return null; + } + return document.id(el, nocash); + }, + + getSelected: function(){ + return new Elements($A(this.options).filter(function(option){ + return option.selected; + })); + }, + + getComputedStyle: function(property){ + if (this.currentStyle) return this.currentStyle[property.camelCase()]; + var computed = this.getDocument().defaultView.getComputedStyle(this, null); + return (computed) ? computed.getPropertyValue([property.hyphenate()]) : null; + }, + + toQueryString: function(){ + var queryString = []; + this.getElements('input, select, textarea', true).each(function(el){ + if (!el.name || el.disabled || el.type == 'submit' || el.type == 'reset' || el.type == 'file') return; + var value = (el.tagName.toLowerCase() == 'select') ? Element.getSelected(el).map(function(opt){ + return opt.value; + }) : ((el.type == 'radio' || el.type == 'checkbox') && !el.checked) ? null : el.value; + $splat(value).each(function(val){ + if (typeof val != 'undefined') queryString.push(el.name + '=' + encodeURIComponent(val)); + }); + }); + return queryString.join('&'); + }, + + clone: function(contents, keepid){ + contents = contents !== false; + var clone = this.cloneNode(contents); + var clean = function(node, element){ + if (!keepid) node.removeAttribute('id'); + if (Browser.Engine.trident){ + node.clearAttributes(); + node.mergeAttributes(element); + node.removeAttribute('uid'); + if (node.options){ + var no = node.options, eo = element.options; + for (var j = no.length; j--;) no[j].selected = eo[j].selected; + } + } + var prop = props[element.tagName.toLowerCase()]; + if (prop && element[prop]) node[prop] = element[prop]; + }; + + if (contents){ + var ce = clone.getElementsByTagName('*'), te = this.getElementsByTagName('*'); + for (var i = ce.length; i--;) clean(ce[i], te[i]); + } + + clean(clone, this); + return document.id(clone); + }, + + destroy: function(){ + Element.empty(this); + Element.dispose(this); + clean(this, true); + return null; + }, + + empty: function(){ + $A(this.childNodes).each(function(node){ + Element.destroy(node); + }); + return this; + }, + + dispose: function(){ + return (this.parentNode) ? this.parentNode.removeChild(this) : this; + }, + + hasChild: function(el){ + el = document.id(el, true); + if (!el) return false; + if (Browser.Engine.webkit && Browser.Engine.version < 420) return $A(this.getElementsByTagName(el.tagName)).contains(el); + return (this.contains) ? (this != el && this.contains(el)) : !!(this.compareDocumentPosition(el) & 16); + }, + + match: function(tag){ + return (!tag || (tag == this) || (Element.get(this, 'tag') == tag)); + } + +}); + +Native.implement([Element, Window, Document], { + + addListener: function(type, fn){ + if (type == 'unload'){ + var old = fn, self = this; + fn = function(){ + self.removeListener('unload', fn); + old(); + }; + } else { + collected[this.uid] = this; + } + if (this.addEventListener) this.addEventListener(type, fn, false); + else this.attachEvent('on' + type, fn); + return this; + }, + + removeListener: function(type, fn){ + if (this.removeEventListener) this.removeEventListener(type, fn, false); + else this.detachEvent('on' + type, fn); + return this; + }, + + retrieve: function(property, dflt){ + var storage = get(this.uid), prop = storage[property]; + if (dflt != undefined && prop == undefined) prop = storage[property] = dflt; + return $pick(prop); + }, + + store: function(property, value){ + var storage = get(this.uid); + storage[property] = value; + return this; + }, + + eliminate: function(property){ + var storage = get(this.uid); + delete storage[property]; + return this; + } + +}); + +window.addListener('unload', purge); + +})(); + +Element.Properties = new Hash; + +Element.Properties.style = { + + set: function(style){ + this.style.cssText = style; + }, + + get: function(){ + return this.style.cssText; + }, + + erase: function(){ + this.style.cssText = ''; + } + +}; + +Element.Properties.tag = { + + get: function(){ + return this.tagName.toLowerCase(); + } + +}; + +Element.Properties.html = (function(){ + var wrapper = document.createElement('div'); + + var translations = { + table: [1, '', '
'], + select: [1, ''], + tbody: [2, '', '
'], + tr: [3, '', '
'] + }; + translations.thead = translations.tfoot = translations.tbody; + + var html = { + set: function(){ + var html = Array.flatten(arguments).join(''); + var wrap = Browser.Engine.trident && translations[this.get('tag')]; + if (wrap){ + var first = wrapper; + first.innerHTML = wrap[1] + html + wrap[2]; + for (var i = wrap[0]; i--;) first = first.firstChild; + this.empty().adopt(first.childNodes); + } else { + this.innerHTML = html; + } + } + }; + + html.erase = html.set; + + return html; +})(); + +if (Browser.Engine.webkit && Browser.Engine.version < 420) Element.Properties.text = { + get: function(){ + if (this.innerText) return this.innerText; + var temp = this.ownerDocument.newElement('div', {html: this.innerHTML}).inject(this.ownerDocument.body); + var text = temp.innerText; + temp.destroy(); + return text; + } +}; + + +/* +--- + +script: Element.Event.js + +description: Contains Element methods for dealing with events. This file also includes mouseenter and mouseleave custom Element Events. + +license: MIT-style license. + +requires: +- /Element +- /Event + +provides: [Element.Event] + +... +*/ + +Element.Properties.events = {set: function(events){ + this.addEvents(events); +}}; + +Native.implement([Element, Window, Document], { + + addEvent: function(type, fn){ + var events = this.retrieve('events', {}); + events[type] = events[type] || {'keys': [], 'values': []}; + if (events[type].keys.contains(fn)) return this; + events[type].keys.push(fn); + var realType = type, custom = Element.Events.get(type), condition = fn, self = this; + if (custom){ + if (custom.onAdd) custom.onAdd.call(this, fn); + if (custom.condition){ + condition = function(event){ + if (custom.condition.call(this, event)) return fn.call(this, event); + return true; + }; + } + realType = custom.base || realType; + } + var defn = function(){ + return fn.call(self); + }; + var nativeEvent = Element.NativeEvents[realType]; + if (nativeEvent){ + if (nativeEvent == 2){ + defn = function(event){ + event = new Event(event, self.getWindow()); + if (condition.call(self, event) === false) event.stop(); + }; + } + this.addListener(realType, defn); + } + events[type].values.push(defn); + return this; + }, + + removeEvent: function(type, fn){ + var events = this.retrieve('events'); + if (!events || !events[type]) return this; + var pos = events[type].keys.indexOf(fn); + if (pos == -1) return this; + events[type].keys.splice(pos, 1); + var value = events[type].values.splice(pos, 1)[0]; + var custom = Element.Events.get(type); + if (custom){ + if (custom.onRemove) custom.onRemove.call(this, fn); + type = custom.base || type; + } + return (Element.NativeEvents[type]) ? this.removeListener(type, value) : this; + }, + + addEvents: function(events){ + for (var event in events) this.addEvent(event, events[event]); + return this; + }, + + removeEvents: function(events){ + var type; + if ($type(events) == 'object'){ + for (type in events) this.removeEvent(type, events[type]); + return this; + } + var attached = this.retrieve('events'); + if (!attached) return this; + if (!events){ + for (type in attached) this.removeEvents(type); + this.eliminate('events'); + } else if (attached[events]){ + while (attached[events].keys[0]) this.removeEvent(events, attached[events].keys[0]); + attached[events] = null; + } + return this; + }, + + fireEvent: function(type, args, delay){ + var events = this.retrieve('events'); + if (!events || !events[type]) return this; + events[type].keys.each(function(fn){ + fn.create({'bind': this, 'delay': delay, 'arguments': args})(); + }, this); + return this; + }, + + cloneEvents: function(from, type){ + from = document.id(from); + var fevents = from.retrieve('events'); + if (!fevents) return this; + if (!type){ + for (var evType in fevents) this.cloneEvents(from, evType); + } else if (fevents[type]){ + fevents[type].keys.each(function(fn){ + this.addEvent(type, fn); + }, this); + } + return this; + } + +}); + +Element.NativeEvents = { + click: 2, dblclick: 2, mouseup: 2, mousedown: 2, contextmenu: 2, //mouse buttons + mousewheel: 2, DOMMouseScroll: 2, //mouse wheel + mouseover: 2, mouseout: 2, mousemove: 2, selectstart: 2, selectend: 2, //mouse movement + keydown: 2, keypress: 2, keyup: 2, //keyboard + focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, //form elements + load: 1, unload: 1, beforeunload: 2, resize: 1, move: 1, DOMContentLoaded: 1, readystatechange: 1, //window + error: 1, abort: 1, scroll: 1 //misc +}; + +(function(){ + +var $check = function(event){ + var related = event.relatedTarget; + if (related == undefined) return true; + if (related === false) return false; + return ($type(this) != 'document' && related != this && related.prefix != 'xul' && !this.hasChild(related)); +}; + +Element.Events = new Hash({ + + mouseenter: { + base: 'mouseover', + condition: $check + }, + + mouseleave: { + base: 'mouseout', + condition: $check + }, + + mousewheel: { + base: (Browser.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel' + } + +}); + +})(); + + +/* +--- + +script: Element.Style.js + +description: Contains methods for interacting with the styles of Elements in a fashionable way. + +license: MIT-style license. + +requires: +- /Element + +provides: [Element.Style] + +... +*/ + +Element.Properties.styles = {set: function(styles){ + this.setStyles(styles); +}}; + +Element.Properties.opacity = { + + set: function(opacity, novisibility){ + if (!novisibility){ + if (opacity == 0){ + if (this.style.visibility != 'hidden') this.style.visibility = 'hidden'; + } else { + if (this.style.visibility != 'visible') this.style.visibility = 'visible'; + } + } + if (!this.currentStyle || !this.currentStyle.hasLayout) this.style.zoom = 1; + if (Browser.Engine.trident) this.style.filter = (opacity == 1) ? '' : 'alpha(opacity=' + opacity * 100 + ')'; + this.style.opacity = opacity; + this.store('opacity', opacity); + }, + + get: function(){ + return this.retrieve('opacity', 1); + } + +}; + +Element.implement({ + + setOpacity: function(value){ + return this.set('opacity', value, true); + }, + + getOpacity: function(){ + return this.get('opacity'); + }, + + setStyle: function(property, value){ + switch (property){ + case 'opacity': return this.set('opacity', parseFloat(value)); + case 'float': property = (Browser.Engine.trident) ? 'styleFloat' : 'cssFloat'; + } + property = property.camelCase(); + if ($type(value) != 'string'){ + var map = (Element.Styles.get(property) || '@').split(' '); + value = $splat(value).map(function(val, i){ + if (!map[i]) return ''; + return ($type(val) == 'number') ? map[i].replace('@', Math.round(val)) : val; + }).join(' '); + } else if (value == String(Number(value))){ + value = Math.round(value); + } + this.style[property] = value; + return this; + }, + + getStyle: function(property){ + switch (property){ + case 'opacity': return this.get('opacity'); + case 'float': property = (Browser.Engine.trident) ? 'styleFloat' : 'cssFloat'; + } + property = property.camelCase(); + var result = this.style[property]; + if (!$chk(result)){ + result = []; + for (var style in Element.ShortStyles){ + if (property != style) continue; + for (var s in Element.ShortStyles[style]) result.push(this.getStyle(s)); + return result.join(' '); + } + result = this.getComputedStyle(property); + } + if (result){ + result = String(result); + var color = result.match(/rgba?\([\d\s,]+\)/); + if (color) result = result.replace(color[0], color[0].rgbToHex()); + } + if (Browser.Engine.presto || (Browser.Engine.trident && !$chk(parseInt(result, 10)))){ + if (property.test(/^(height|width)$/)){ + var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom'], size = 0; + values.each(function(value){ + size += this.getStyle('border-' + value + '-width').toInt() + this.getStyle('padding-' + value).toInt(); + }, this); + return this['offset' + property.capitalize()] - size + 'px'; + } + if ((Browser.Engine.presto) && String(result).test('px')) return result; + if (property.test(/(border(.+)Width|margin|padding)/)) return '0px'; + } + return result; + }, + + setStyles: function(styles){ + for (var style in styles) this.setStyle(style, styles[style]); + return this; + }, + + getStyles: function(){ + var result = {}; + Array.flatten(arguments).each(function(key){ + result[key] = this.getStyle(key); + }, this); + return result; + } + +}); + +Element.Styles = new Hash({ + left: '@px', top: '@px', bottom: '@px', right: '@px', + width: '@px', height: '@px', maxWidth: '@px', maxHeight: '@px', minWidth: '@px', minHeight: '@px', + backgroundColor: 'rgb(@, @, @)', backgroundPosition: '@px @px', color: 'rgb(@, @, @)', + fontSize: '@px', letterSpacing: '@px', lineHeight: '@px', clip: 'rect(@px @px @px @px)', + margin: '@px @px @px @px', padding: '@px @px @px @px', border: '@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)', + borderWidth: '@px @px @px @px', borderStyle: '@ @ @ @', borderColor: 'rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)', + zIndex: '@', 'zoom': '@', fontWeight: '@', textIndent: '@px', opacity: '@' +}); + +Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, borderStyle: {}, borderColor: {}}; + +['Top', 'Right', 'Bottom', 'Left'].each(function(direction){ + var Short = Element.ShortStyles; + var All = Element.Styles; + ['margin', 'padding'].each(function(style){ + var sd = style + direction; + Short[style][sd] = All[sd] = '@px'; + }); + var bd = 'border' + direction; + Short.border[bd] = All[bd] = '@px @ rgb(@, @, @)'; + var bdw = bd + 'Width', bds = bd + 'Style', bdc = bd + 'Color'; + Short[bd] = {}; + Short.borderWidth[bdw] = Short[bd][bdw] = All[bdw] = '@px'; + Short.borderStyle[bds] = Short[bd][bds] = All[bds] = '@'; + Short.borderColor[bdc] = Short[bd][bdc] = All[bdc] = 'rgb(@, @, @)'; +}); + + +/* +--- + +script: Element.Dimensions.js + +description: Contains methods to work with size, scroll, or positioning of Elements and the window object. + +license: MIT-style license. + +credits: +- Element positioning based on the [qooxdoo](http://qooxdoo.org/) code and smart browser fixes, [LGPL License](http://www.gnu.org/licenses/lgpl.html). +- Viewport dimensions based on [YUI](http://developer.yahoo.com/yui/) code, [BSD License](http://developer.yahoo.com/yui/license.html). + +requires: +- /Element + +provides: [Element.Dimensions] + +... +*/ + +(function(){ + +Element.implement({ + + scrollTo: function(x, y){ + if (isBody(this)){ + this.getWindow().scrollTo(x, y); + } else { + this.scrollLeft = x; + this.scrollTop = y; + } + return this; + }, + + getSize: function(){ + if (isBody(this)) return this.getWindow().getSize(); + return {x: this.offsetWidth, y: this.offsetHeight}; + }, + + getScrollSize: function(){ + if (isBody(this)) return this.getWindow().getScrollSize(); + return {x: this.scrollWidth, y: this.scrollHeight}; + }, + + getScroll: function(){ + if (isBody(this)) return this.getWindow().getScroll(); + return {x: this.scrollLeft, y: this.scrollTop}; + }, + + getScrolls: function(){ + var element = this, position = {x: 0, y: 0}; + while (element && !isBody(element)){ + position.x += element.scrollLeft; + position.y += element.scrollTop; + element = element.parentNode; + } + return position; + }, + + getOffsetParent: function(){ + var element = this; + if (isBody(element)) return null; + if (!Browser.Engine.trident) return element.offsetParent; + while ((element = element.parentNode) && !isBody(element)){ + if (styleString(element, 'position') != 'static') return element; + } + return null; + }, + + getOffsets: function(){ + if (this.getBoundingClientRect){ + var bound = this.getBoundingClientRect(), + html = document.id(this.getDocument().documentElement), + htmlScroll = html.getScroll(), + elemScrolls = this.getScrolls(), + elemScroll = this.getScroll(), + isFixed = (styleString(this, 'position') == 'fixed'); + + return { + x: bound.left.toInt() + elemScrolls.x - elemScroll.x + ((isFixed) ? 0 : htmlScroll.x) - html.clientLeft, + y: bound.top.toInt() + elemScrolls.y - elemScroll.y + ((isFixed) ? 0 : htmlScroll.y) - html.clientTop + }; + } + + var element = this, position = {x: 0, y: 0}; + if (isBody(this)) return position; + + while (element && !isBody(element)){ + position.x += element.offsetLeft; + position.y += element.offsetTop; + + if (Browser.Engine.gecko){ + if (!borderBox(element)){ + position.x += leftBorder(element); + position.y += topBorder(element); + } + var parent = element.parentNode; + if (parent && styleString(parent, 'overflow') != 'visible'){ + position.x += leftBorder(parent); + position.y += topBorder(parent); + } + } else if (element != this && Browser.Engine.webkit){ + position.x += leftBorder(element); + position.y += topBorder(element); + } + + element = element.offsetParent; + } + if (Browser.Engine.gecko && !borderBox(this)){ + position.x -= leftBorder(this); + position.y -= topBorder(this); + } + return position; + }, + + getPosition: function(relative){ + if (isBody(this)) return {x: 0, y: 0}; + var offset = this.getOffsets(), + scroll = this.getScrolls(); + var position = { + x: offset.x - scroll.x, + y: offset.y - scroll.y + }; + var relativePosition = (relative && (relative = document.id(relative))) ? relative.getPosition() : {x: 0, y: 0}; + return {x: position.x - relativePosition.x, y: position.y - relativePosition.y}; + }, + + getCoordinates: function(element){ + if (isBody(this)) return this.getWindow().getCoordinates(); + var position = this.getPosition(element), + size = this.getSize(); + var obj = { + left: position.x, + top: position.y, + width: size.x, + height: size.y + }; + obj.right = obj.left + obj.width; + obj.bottom = obj.top + obj.height; + return obj; + }, + + computePosition: function(obj){ + return { + left: obj.x - styleNumber(this, 'margin-left'), + top: obj.y - styleNumber(this, 'margin-top') + }; + }, + + setPosition: function(obj){ + return this.setStyles(this.computePosition(obj)); + } + +}); + + +Native.implement([Document, Window], { + + getSize: function(){ + if (Browser.Engine.presto || Browser.Engine.webkit){ + var win = this.getWindow(); + return {x: win.innerWidth, y: win.innerHeight}; + } + var doc = getCompatElement(this); + return {x: doc.clientWidth, y: doc.clientHeight}; + }, + + getScroll: function(){ + var win = this.getWindow(), doc = getCompatElement(this); + return {x: win.pageXOffset || doc.scrollLeft, y: win.pageYOffset || doc.scrollTop}; + }, + + getScrollSize: function(){ + var doc = getCompatElement(this), min = this.getSize(); + return {x: Math.max(doc.scrollWidth, min.x), y: Math.max(doc.scrollHeight, min.y)}; + }, + + getPosition: function(){ + return {x: 0, y: 0}; + }, + + getCoordinates: function(){ + var size = this.getSize(); + return {top: 0, left: 0, bottom: size.y, right: size.x, height: size.y, width: size.x}; + } + +}); + +// private methods + +var styleString = Element.getComputedStyle; + +function styleNumber(element, style){ + return styleString(element, style).toInt() || 0; +}; + +function borderBox(element){ + return styleString(element, '-moz-box-sizing') == 'border-box'; +}; + +function topBorder(element){ + return styleNumber(element, 'border-top-width'); +}; + +function leftBorder(element){ + return styleNumber(element, 'border-left-width'); +}; + +function isBody(element){ + return (/^(?:body|html)$/i).test(element.tagName); +}; + +function getCompatElement(element){ + var doc = element.getDocument(); + return (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body; +}; + +})(); + +//aliases +Element.alias('setPosition', 'position'); //compatability + +Native.implement([Window, Document, Element], { + + getHeight: function(){ + return this.getSize().y; + }, + + getWidth: function(){ + return this.getSize().x; + }, + + getScrollTop: function(){ + return this.getScroll().y; + }, + + getScrollLeft: function(){ + return this.getScroll().x; + }, + + getScrollHeight: function(){ + return this.getScrollSize().y; + }, + + getScrollWidth: function(){ + return this.getScrollSize().x; + }, + + getTop: function(){ + return this.getPosition().y; + }, + + getLeft: function(){ + return this.getPosition().x; + } + +}); + + +/* +--- + +script: Selectors.js + +description: Adds advanced CSS-style querying capabilities for targeting HTML Elements. Includes pseudo selectors. + +license: MIT-style license. + +requires: +- /Element + +provides: [Selectors] + +... +*/ + +Native.implement([Document, Element], { + + getElements: function(expression, nocash){ + expression = expression.split(','); + var items, local = {}; + for (var i = 0, l = expression.length; i < l; i++){ + var selector = expression[i], elements = Selectors.Utils.search(this, selector, local); + if (i != 0 && elements.item) elements = $A(elements); + items = (i == 0) ? elements : (items.item) ? $A(items).concat(elements) : items.concat(elements); + } + return new Elements(items, {ddup: (expression.length > 1), cash: !nocash}); + } + +}); + +Element.implement({ + + match: function(selector){ + if (!selector || (selector == this)) return true; + var tagid = Selectors.Utils.parseTagAndID(selector); + var tag = tagid[0], id = tagid[1]; + if (!Selectors.Filters.byID(this, id) || !Selectors.Filters.byTag(this, tag)) return false; + var parsed = Selectors.Utils.parseSelector(selector); + return (parsed) ? Selectors.Utils.filter(this, parsed, {}) : true; + } + +}); + +var Selectors = {Cache: {nth: {}, parsed: {}}}; + +Selectors.RegExps = { + id: (/#([\w-]+)/), + tag: (/^(\w+|\*)/), + quick: (/^(\w+|\*)$/), + splitter: (/\s*([+>~\s])\s*([a-zA-Z#.*:\[])/g), + combined: (/\.([\w-]+)|\[(\w+)(?:([!*^$~|]?=)(["']?)([^\4]*?)\4)?\]|:([\w-]+)(?:\(["']?(.*?)?["']?\)|$)/g) +}; + +Selectors.Utils = { + + chk: function(item, uniques){ + if (!uniques) return true; + var uid = $uid(item); + if (!uniques[uid]) return uniques[uid] = true; + return false; + }, + + parseNthArgument: function(argument){ + if (Selectors.Cache.nth[argument]) return Selectors.Cache.nth[argument]; + var parsed = argument.match(/^([+-]?\d*)?([a-z]+)?([+-]?\d*)?$/); + if (!parsed) return false; + var inta = parseInt(parsed[1], 10); + var a = (inta || inta === 0) ? inta : 1; + var special = parsed[2] || false; + var b = parseInt(parsed[3], 10) || 0; + if (a != 0){ + b--; + while (b < 1) b += a; + while (b >= a) b -= a; + } else { + a = b; + special = 'index'; + } + switch (special){ + case 'n': parsed = {a: a, b: b, special: 'n'}; break; + case 'odd': parsed = {a: 2, b: 0, special: 'n'}; break; + case 'even': parsed = {a: 2, b: 1, special: 'n'}; break; + case 'first': parsed = {a: 0, special: 'index'}; break; + case 'last': parsed = {special: 'last-child'}; break; + case 'only': parsed = {special: 'only-child'}; break; + default: parsed = {a: (a - 1), special: 'index'}; + } + + return Selectors.Cache.nth[argument] = parsed; + }, + + parseSelector: function(selector){ + if (Selectors.Cache.parsed[selector]) return Selectors.Cache.parsed[selector]; + var m, parsed = {classes: [], pseudos: [], attributes: []}; + while ((m = Selectors.RegExps.combined.exec(selector))){ + var cn = m[1], an = m[2], ao = m[3], av = m[5], pn = m[6], pa = m[7]; + if (cn){ + parsed.classes.push(cn); + } else if (pn){ + var parser = Selectors.Pseudo.get(pn); + if (parser) parsed.pseudos.push({parser: parser, argument: pa}); + else parsed.attributes.push({name: pn, operator: '=', value: pa}); + } else if (an){ + parsed.attributes.push({name: an, operator: ao, value: av}); + } + } + if (!parsed.classes.length) delete parsed.classes; + if (!parsed.attributes.length) delete parsed.attributes; + if (!parsed.pseudos.length) delete parsed.pseudos; + if (!parsed.classes && !parsed.attributes && !parsed.pseudos) parsed = null; + return Selectors.Cache.parsed[selector] = parsed; + }, + + parseTagAndID: function(selector){ + var tag = selector.match(Selectors.RegExps.tag); + var id = selector.match(Selectors.RegExps.id); + return [(tag) ? tag[1] : '*', (id) ? id[1] : false]; + }, + + filter: function(item, parsed, local){ + var i; + if (parsed.classes){ + for (i = parsed.classes.length; i--; i){ + var cn = parsed.classes[i]; + if (!Selectors.Filters.byClass(item, cn)) return false; + } + } + if (parsed.attributes){ + for (i = parsed.attributes.length; i--; i){ + var att = parsed.attributes[i]; + if (!Selectors.Filters.byAttribute(item, att.name, att.operator, att.value)) return false; + } + } + if (parsed.pseudos){ + for (i = parsed.pseudos.length; i--; i){ + var psd = parsed.pseudos[i]; + if (!Selectors.Filters.byPseudo(item, psd.parser, psd.argument, local)) return false; + } + } + return true; + }, + + getByTagAndID: function(ctx, tag, id){ + if (id){ + var item = (ctx.getElementById) ? ctx.getElementById(id, true) : Element.getElementById(ctx, id, true); + return (item && Selectors.Filters.byTag(item, tag)) ? [item] : []; + } else { + return ctx.getElementsByTagName(tag); + } + }, + + search: function(self, expression, local){ + var splitters = []; + + var selectors = expression.trim().replace(Selectors.RegExps.splitter, function(m0, m1, m2){ + splitters.push(m1); + return ':)' + m2; + }).split(':)'); + + var items, filtered, item; + + for (var i = 0, l = selectors.length; i < l; i++){ + + var selector = selectors[i]; + + if (i == 0 && Selectors.RegExps.quick.test(selector)){ + items = self.getElementsByTagName(selector); + continue; + } + + var splitter = splitters[i - 1]; + + var tagid = Selectors.Utils.parseTagAndID(selector); + var tag = tagid[0], id = tagid[1]; + + if (i == 0){ + items = Selectors.Utils.getByTagAndID(self, tag, id); + } else { + var uniques = {}, found = []; + for (var j = 0, k = items.length; j < k; j++) found = Selectors.Getters[splitter](found, items[j], tag, id, uniques); + items = found; + } + + var parsed = Selectors.Utils.parseSelector(selector); + + if (parsed){ + filtered = []; + for (var m = 0, n = items.length; m < n; m++){ + item = items[m]; + if (Selectors.Utils.filter(item, parsed, local)) filtered.push(item); + } + items = filtered; + } + + } + + return items; + + } + +}; + +Selectors.Getters = { + + ' ': function(found, self, tag, id, uniques){ + var items = Selectors.Utils.getByTagAndID(self, tag, id); + for (var i = 0, l = items.length; i < l; i++){ + var item = items[i]; + if (Selectors.Utils.chk(item, uniques)) found.push(item); + } + return found; + }, + + '>': function(found, self, tag, id, uniques){ + var children = Selectors.Utils.getByTagAndID(self, tag, id); + for (var i = 0, l = children.length; i < l; i++){ + var child = children[i]; + if (child.parentNode == self && Selectors.Utils.chk(child, uniques)) found.push(child); + } + return found; + }, + + '+': function(found, self, tag, id, uniques){ + while ((self = self.nextSibling)){ + if (self.nodeType == 1){ + if (Selectors.Utils.chk(self, uniques) && Selectors.Filters.byTag(self, tag) && Selectors.Filters.byID(self, id)) found.push(self); + break; + } + } + return found; + }, + + '~': function(found, self, tag, id, uniques){ + while ((self = self.nextSibling)){ + if (self.nodeType == 1){ + if (!Selectors.Utils.chk(self, uniques)) break; + if (Selectors.Filters.byTag(self, tag) && Selectors.Filters.byID(self, id)) found.push(self); + } + } + return found; + } + +}; + +Selectors.Filters = { + + byTag: function(self, tag){ + return (tag == '*' || (self.tagName && self.tagName.toLowerCase() == tag)); + }, + + byID: function(self, id){ + return (!id || (self.id && self.id == id)); + }, + + byClass: function(self, klass){ + return (self.className && self.className.contains && self.className.contains(klass, ' ')); + }, + + byPseudo: function(self, parser, argument, local){ + return parser.call(self, argument, local); + }, + + byAttribute: function(self, name, operator, value){ + var result = Element.prototype.getProperty.call(self, name); + if (!result) return (operator == '!='); + if (!operator || value == undefined) return true; + switch (operator){ + case '=': return (result == value); + case '*=': return (result.contains(value)); + case '^=': return (result.substr(0, value.length) == value); + case '$=': return (result.substr(result.length - value.length) == value); + case '!=': return (result != value); + case '~=': return result.contains(value, ' '); + case '|=': return result.contains(value, '-'); + } + return false; + } + +}; + +Selectors.Pseudo = new Hash({ + + // w3c pseudo selectors + + checked: function(){ + return this.checked; + }, + + empty: function(){ + return !(this.innerText || this.textContent || '').length; + }, + + not: function(selector){ + return !Element.match(this, selector); + }, + + contains: function(text){ + return (this.innerText || this.textContent || '').contains(text); + }, + + 'first-child': function(){ + return Selectors.Pseudo.index.call(this, 0); + }, + + 'last-child': function(){ + var element = this; + while ((element = element.nextSibling)){ + if (element.nodeType == 1) return false; + } + return true; + }, + + 'only-child': function(){ + var prev = this; + while ((prev = prev.previousSibling)){ + if (prev.nodeType == 1) return false; + } + var next = this; + while ((next = next.nextSibling)){ + if (next.nodeType == 1) return false; + } + return true; + }, + + 'nth-child': function(argument, local){ + argument = (argument == undefined) ? 'n' : argument; + var parsed = Selectors.Utils.parseNthArgument(argument); + if (parsed.special != 'n') return Selectors.Pseudo[parsed.special].call(this, parsed.a, local); + var count = 0; + local.positions = local.positions || {}; + var uid = $uid(this); + if (!local.positions[uid]){ + var self = this; + while ((self = self.previousSibling)){ + if (self.nodeType != 1) continue; + count ++; + var position = local.positions[$uid(self)]; + if (position != undefined){ + count = position + count; + break; + } + } + local.positions[uid] = count; + } + return (local.positions[uid] % parsed.a == parsed.b); + }, + + // custom pseudo selectors + + index: function(index){ + var element = this, count = 0; + while ((element = element.previousSibling)){ + if (element.nodeType == 1 && ++count > index) return false; + } + return (count == index); + }, + + even: function(argument, local){ + return Selectors.Pseudo['nth-child'].call(this, '2n+1', local); + }, + + odd: function(argument, local){ + return Selectors.Pseudo['nth-child'].call(this, '2n', local); + }, + + selected: function(){ + return this.selected; + }, + + enabled: function(){ + return (this.disabled === false); + } + +}); + + +/* +--- + +script: DomReady.js + +description: Contains the custom event domready. + +license: MIT-style license. + +requires: +- /Element.Event + +provides: [DomReady] + +... +*/ + +Element.Events.domready = { + + onAdd: function(fn){ + if (Browser.loaded) fn.call(this); + } + +}; + +(function(){ + + var domready = function(){ + if (Browser.loaded) return; + Browser.loaded = true; + window.fireEvent('domready'); + document.fireEvent('domready'); + }; + + window.addEvent('load', domready); + + if (Browser.Engine.trident){ + var temp = document.createElement('div'); + (function(){ + ($try(function(){ + temp.doScroll(); // Technique by Diego Perini + return document.id(temp).inject(document.body).set('html', 'temp').dispose(); + })) ? domready() : arguments.callee.delay(50); + })(); + } else if (Browser.Engine.webkit && Browser.Engine.version < 525){ + (function(){ + (['loaded', 'complete'].contains(document.readyState)) ? domready() : arguments.callee.delay(50); + })(); + } else { + document.addEvent('DOMContentLoaded', domready); + } + +})(); + + +/* +--- + +script: JSON.js + +description: JSON encoder and decoder. + +license: MIT-style license. + +See Also: + +requires: +- /Array +- /String +- /Number +- /Function +- /Hash + +provides: [JSON] + +... +*/ + +var JSON = new Hash(this.JSON && { + stringify: JSON.stringify, + parse: JSON.parse +}).extend({ + + $specialChars: {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'}, + + $replaceChars: function(chr){ + return JSON.$specialChars[chr] || '\\u00' + Math.floor(chr.charCodeAt() / 16).toString(16) + (chr.charCodeAt() % 16).toString(16); + }, + + encode: function(obj){ + switch ($type(obj)){ + case 'string': + return '"' + obj.replace(/[\x00-\x1f\\"]/g, JSON.$replaceChars) + '"'; + case 'array': + return '[' + String(obj.map(JSON.encode).clean()) + ']'; + case 'object': case 'hash': + var string = []; + Hash.each(obj, function(value, key){ + var json = JSON.encode(value); + if (json) string.push(JSON.encode(key) + ':' + json); + }); + return '{' + string + '}'; + case 'number': case 'boolean': return String(obj); + case false: return 'null'; + } + return null; + }, + + decode: function(string, secure){ + if ($type(string) != 'string' || !string.length) return null; + if (secure && !(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(string.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''))) return null; + return eval('(' + string + ')'); + } + +}); + +Native.implement([Hash, Array, String, Number], { + + toJSON: function(){ + return JSON.encode(this); + } + +}); + + +/* +--- + +script: Cookie.js + +description: Class for creating, reading, and deleting browser Cookies. + +license: MIT-style license. + +credits: +- Based on the functions by Peter-Paul Koch (http://quirksmode.org). + +requires: +- /Options + +provides: [Cookie] + +... +*/ + +var Cookie = new Class({ + + Implements: Options, + + options: { + path: false, + domain: false, + duration: false, + secure: false, + document: document + }, + + initialize: function(key, options){ + this.key = key; + this.setOptions(options); + }, + + write: function(value){ + value = encodeURIComponent(value); + if (this.options.domain) value += '; domain=' + this.options.domain; + if (this.options.path) value += '; path=' + this.options.path; + if (this.options.duration){ + var date = new Date(); + date.setTime(date.getTime() + this.options.duration * 24 * 60 * 60 * 1000); + value += '; expires=' + date.toGMTString(); + } + if (this.options.secure) value += '; secure'; + this.options.document.cookie = this.key + '=' + value; + return this; + }, + + read: function(){ + var value = this.options.document.cookie.match('(?:^|;)\\s*' + this.key.escapeRegExp() + '=([^;]*)'); + return (value) ? decodeURIComponent(value[1]) : null; + }, + + dispose: function(){ + new Cookie(this.key, $merge(this.options, {duration: -1})).write(''); + return this; + } + +}); + +Cookie.write = function(key, value, options){ + return new Cookie(key, options).write(value); +}; + +Cookie.read = function(key){ + return new Cookie(key).read(); +}; + +Cookie.dispose = function(key, options){ + return new Cookie(key, options).dispose(); +}; + + +/* +--- + +script: Swiff.js + +description: Wrapper for embedding SWF movies. Supports External Interface Communication. + +license: MIT-style license. + +credits: +- Flash detection & Internet Explorer + Flash Player 9 fix inspired by SWFObject. + +requires: +- /Options +- /$util + +provides: [Swiff] + +... +*/ + +var Swiff = new Class({ + + Implements: [Options], + + options: { + id: null, + height: 1, + width: 1, + container: null, + properties: {}, + params: { + quality: 'high', + allowScriptAccess: 'always', + wMode: 'transparent', + swLiveConnect: true + }, + callBacks: {}, + vars: {} + }, + + toElement: function(){ + return this.object; + }, + + initialize: function(path, options){ + this.instance = 'Swiff_' + $time(); + + this.setOptions(options); + options = this.options; + var id = this.id = options.id || this.instance; + var container = document.id(options.container); + + Swiff.CallBacks[this.instance] = {}; + + var params = options.params, vars = options.vars, callBacks = options.callBacks; + var properties = $extend({height: options.height, width: options.width}, options.properties); + + var self = this; + + for (var callBack in callBacks){ + Swiff.CallBacks[this.instance][callBack] = (function(option){ + return function(){ + return option.apply(self.object, arguments); + }; + })(callBacks[callBack]); + vars[callBack] = 'Swiff.CallBacks.' + this.instance + '.' + callBack; + } + + params.flashVars = Hash.toQueryString(vars); + if (Browser.Engine.trident){ + properties.classid = 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000'; + params.movie = path; + } else { + properties.type = 'application/x-shockwave-flash'; + properties.data = path; + } + var build = ''; + } + build += ''; + this.object = ((container) ? container.empty() : new Element('div')).set('html', build).firstChild; + }, + + replaces: function(element){ + element = document.id(element, true); + element.parentNode.replaceChild(this.toElement(), element); + return this; + }, + + inject: function(element){ + document.id(element, true).appendChild(this.toElement()); + return this; + }, + + remote: function(){ + return Swiff.remote.apply(Swiff, [this.toElement()].extend(arguments)); + } + +}); + +Swiff.CallBacks = {}; + +Swiff.remote = function(obj, fn){ + var rs = obj.CallFunction('' + __flash__argumentsToXML(arguments, 2) + ''); + return eval(rs); +}; + + +/* +--- + +script: Fx.js + +description: Contains the basic animation logic to be extended by all other Fx Classes. + +license: MIT-style license. + +requires: +- /Chain +- /Events +- /Options + +provides: [Fx] + +... +*/ + +var Fx = new Class({ + + Implements: [Chain, Events, Options], + + options: { + /* + onStart: $empty, + onCancel: $empty, + onComplete: $empty, + */ + fps: 50, + unit: false, + duration: 500, + link: 'ignore' + }, + + initialize: function(options){ + this.subject = this.subject || this; + this.setOptions(options); + this.options.duration = Fx.Durations[this.options.duration] || this.options.duration.toInt(); + var wait = this.options.wait; + if (wait === false) this.options.link = 'cancel'; + }, + + getTransition: function(){ + return function(p){ + return -(Math.cos(Math.PI * p) - 1) / 2; + }; + }, + + step: function(){ + var time = $time(); + if (time < this.time + this.options.duration){ + var delta = this.transition((time - this.time) / this.options.duration); + this.set(this.compute(this.from, this.to, delta)); + } else { + this.set(this.compute(this.from, this.to, 1)); + this.complete(); + } + }, + + set: function(now){ + return now; + }, + + compute: function(from, to, delta){ + return Fx.compute(from, to, delta); + }, + + check: function(){ + if (!this.timer) return true; + switch (this.options.link){ + case 'cancel': this.cancel(); return true; + case 'chain': this.chain(this.caller.bind(this, arguments)); return false; + } + return false; + }, + + start: function(from, to){ + if (!this.check(from, to)) return this; + this.from = from; + this.to = to; + this.time = 0; + this.transition = this.getTransition(); + this.startTimer(); + this.onStart(); + return this; + }, + + complete: function(){ + if (this.stopTimer()) this.onComplete(); + return this; + }, + + cancel: function(){ + if (this.stopTimer()) this.onCancel(); + return this; + }, + + onStart: function(){ + this.fireEvent('start', this.subject); + }, + + onComplete: function(){ + this.fireEvent('complete', this.subject); + if (!this.callChain()) this.fireEvent('chainComplete', this.subject); + }, + + onCancel: function(){ + this.fireEvent('cancel', this.subject).clearChain(); + }, + + pause: function(){ + this.stopTimer(); + return this; + }, + + resume: function(){ + this.startTimer(); + return this; + }, + + stopTimer: function(){ + if (!this.timer) return false; + this.time = $time() - this.time; + this.timer = $clear(this.timer); + return true; + }, + + startTimer: function(){ + if (this.timer) return false; + this.time = $time() - this.time; + this.timer = this.step.periodical(Math.round(1000 / this.options.fps), this); + return true; + } + +}); + +Fx.compute = function(from, to, delta){ + return (to - from) * delta + from; +}; + +Fx.Durations = {'short': 250, 'normal': 500, 'long': 1000}; + + +/* +--- + +script: Fx.CSS.js + +description: Contains the CSS animation logic. Used by Fx.Tween, Fx.Morph, Fx.Elements. + +license: MIT-style license. + +requires: +- /Fx +- /Element.Style + +provides: [Fx.CSS] + +... +*/ + +Fx.CSS = new Class({ + + Extends: Fx, + + //prepares the base from/to object + + prepare: function(element, property, values){ + values = $splat(values); + var values1 = values[1]; + if (!$chk(values1)){ + values[1] = values[0]; + values[0] = element.getStyle(property); + } + var parsed = values.map(this.parse); + return {from: parsed[0], to: parsed[1]}; + }, + + //parses a value into an array + + parse: function(value){ + value = $lambda(value)(); + value = (typeof value == 'string') ? value.split(' ') : $splat(value); + return value.map(function(val){ + val = String(val); + var found = false; + Fx.CSS.Parsers.each(function(parser, key){ + if (found) return; + var parsed = parser.parse(val); + if ($chk(parsed)) found = {value: parsed, parser: parser}; + }); + found = found || {value: val, parser: Fx.CSS.Parsers.String}; + return found; + }); + }, + + //computes by a from and to prepared objects, using their parsers. + + compute: function(from, to, delta){ + var computed = []; + (Math.min(from.length, to.length)).times(function(i){ + computed.push({value: from[i].parser.compute(from[i].value, to[i].value, delta), parser: from[i].parser}); + }); + computed.$family = {name: 'fx:css:value'}; + return computed; + }, + + //serves the value as settable + + serve: function(value, unit){ + if ($type(value) != 'fx:css:value') value = this.parse(value); + var returned = []; + value.each(function(bit){ + returned = returned.concat(bit.parser.serve(bit.value, unit)); + }); + return returned; + }, + + //renders the change to an element + + render: function(element, property, value, unit){ + element.setStyle(property, this.serve(value, unit)); + }, + + //searches inside the page css to find the values for a selector + + search: function(selector){ + if (Fx.CSS.Cache[selector]) return Fx.CSS.Cache[selector]; + var to = {}; + Array.each(document.styleSheets, function(sheet, j){ + var href = sheet.href; + if (href && href.contains('://') && !href.contains(document.domain)) return; + var rules = sheet.rules || sheet.cssRules; + Array.each(rules, function(rule, i){ + if (!rule.style) return; + var selectorText = (rule.selectorText) ? rule.selectorText.replace(/^\w+/, function(m){ + return m.toLowerCase(); + }) : null; + if (!selectorText || !selectorText.test('^' + selector + '$')) return; + Element.Styles.each(function(value, style){ + if (!rule.style[style] || Element.ShortStyles[style]) return; + value = String(rule.style[style]); + to[style] = (value.test(/^rgb/)) ? value.rgbToHex() : value; + }); + }); + }); + return Fx.CSS.Cache[selector] = to; + } + +}); + +Fx.CSS.Cache = {}; + +Fx.CSS.Parsers = new Hash({ + + Color: { + parse: function(value){ + if (value.match(/^#[0-9a-f]{3,6}$/i)) return value.hexToRgb(true); + return ((value = value.match(/(\d+),\s*(\d+),\s*(\d+)/))) ? [value[1], value[2], value[3]] : false; + }, + compute: function(from, to, delta){ + return from.map(function(value, i){ + return Math.round(Fx.compute(from[i], to[i], delta)); + }); + }, + serve: function(value){ + return value.map(Number); + } + }, + + Number: { + parse: parseFloat, + compute: Fx.compute, + serve: function(value, unit){ + return (unit) ? value + unit : value; + } + }, + + String: { + parse: $lambda(false), + compute: $arguments(1), + serve: $arguments(0) + } + +}); + + +/* +--- + +script: Fx.Tween.js + +description: Formerly Fx.Style, effect to transition any CSS property for an element. + +license: MIT-style license. + +requires: +- /Fx.CSS + +provides: [Fx.Tween, Element.fade, Element.highlight] + +... +*/ + +Fx.Tween = new Class({ + + Extends: Fx.CSS, + + initialize: function(element, options){ + this.element = this.subject = document.id(element); + this.parent(options); + }, + + set: function(property, now){ + if (arguments.length == 1){ + now = property; + property = this.property || this.options.property; + } + this.render(this.element, property, now, this.options.unit); + return this; + }, + + start: function(property, from, to){ + if (!this.check(property, from, to)) return this; + var args = Array.flatten(arguments); + this.property = this.options.property || args.shift(); + var parsed = this.prepare(this.element, this.property, args); + return this.parent(parsed.from, parsed.to); + } + +}); + +Element.Properties.tween = { + + set: function(options){ + var tween = this.retrieve('tween'); + if (tween) tween.cancel(); + return this.eliminate('tween').store('tween:options', $extend({link: 'cancel'}, options)); + }, + + get: function(options){ + if (options || !this.retrieve('tween')){ + if (options || !this.retrieve('tween:options')) this.set('tween', options); + this.store('tween', new Fx.Tween(this, this.retrieve('tween:options'))); + } + return this.retrieve('tween'); + } + +}; + +Element.implement({ + + tween: function(property, from, to){ + this.get('tween').start(arguments); + return this; + }, + + fade: function(how){ + var fade = this.get('tween'), o = 'opacity', toggle; + how = $pick(how, 'toggle'); + switch (how){ + case 'in': fade.start(o, 1); break; + case 'out': fade.start(o, 0); break; + case 'show': fade.set(o, 1); break; + case 'hide': fade.set(o, 0); break; + case 'toggle': + var flag = this.retrieve('fade:flag', this.get('opacity') == 1); + fade.start(o, (flag) ? 0 : 1); + this.store('fade:flag', !flag); + toggle = true; + break; + default: fade.start(o, arguments); + } + if (!toggle) this.eliminate('fade:flag'); + return this; + }, + + highlight: function(start, end){ + if (!end){ + end = this.retrieve('highlight:original', this.getStyle('background-color')); + end = (end == 'transparent') ? '#fff' : end; + } + var tween = this.get('tween'); + tween.start('background-color', start || '#ffff88', end).chain(function(){ + this.setStyle('background-color', this.retrieve('highlight:original')); + tween.callChain(); + }.bind(this)); + return this; + } + +}); + + +/* +--- + +script: Fx.Morph.js + +description: Formerly Fx.Styles, effect to transition any number of CSS properties for an element using an object of rules, or CSS based selector rules. + +license: MIT-style license. + +requires: +- /Fx.CSS + +provides: [Fx.Morph] + +... +*/ + +Fx.Morph = new Class({ + + Extends: Fx.CSS, + + initialize: function(element, options){ + this.element = this.subject = document.id(element); + this.parent(options); + }, + + set: function(now){ + if (typeof now == 'string') now = this.search(now); + for (var p in now) this.render(this.element, p, now[p], this.options.unit); + return this; + }, + + compute: function(from, to, delta){ + var now = {}; + for (var p in from) now[p] = this.parent(from[p], to[p], delta); + return now; + }, + + start: function(properties){ + if (!this.check(properties)) return this; + if (typeof properties == 'string') properties = this.search(properties); + var from = {}, to = {}; + for (var p in properties){ + var parsed = this.prepare(this.element, p, properties[p]); + from[p] = parsed.from; + to[p] = parsed.to; + } + return this.parent(from, to); + } + +}); + +Element.Properties.morph = { + + set: function(options){ + var morph = this.retrieve('morph'); + if (morph) morph.cancel(); + return this.eliminate('morph').store('morph:options', $extend({link: 'cancel'}, options)); + }, + + get: function(options){ + if (options || !this.retrieve('morph')){ + if (options || !this.retrieve('morph:options')) this.set('morph', options); + this.store('morph', new Fx.Morph(this, this.retrieve('morph:options'))); + } + return this.retrieve('morph'); + } + +}; + +Element.implement({ + + morph: function(props){ + this.get('morph').start(props); + return this; + } + +}); + + +/* +--- + +script: Fx.Transitions.js + +description: Contains a set of advanced transitions to be used with any of the Fx Classes. + +license: MIT-style license. + +credits: +- Easing Equations by Robert Penner, , modified and optimized to be used with MooTools. + +requires: +- /Fx + +provides: [Fx.Transitions] + +... +*/ + +Fx.implement({ + + getTransition: function(){ + var trans = this.options.transition || Fx.Transitions.Sine.easeInOut; + if (typeof trans == 'string'){ + var data = trans.split(':'); + trans = Fx.Transitions; + trans = trans[data[0]] || trans[data[0].capitalize()]; + if (data[1]) trans = trans['ease' + data[1].capitalize() + (data[2] ? data[2].capitalize() : '')]; + } + return trans; + } + +}); + +Fx.Transition = function(transition, params){ + params = $splat(params); + return $extend(transition, { + easeIn: function(pos){ + return transition(pos, params); + }, + easeOut: function(pos){ + return 1 - transition(1 - pos, params); + }, + easeInOut: function(pos){ + return (pos <= 0.5) ? transition(2 * pos, params) / 2 : (2 - transition(2 * (1 - pos), params)) / 2; + } + }); +}; + +Fx.Transitions = new Hash({ + + linear: $arguments(0) + +}); + +Fx.Transitions.extend = function(transitions){ + for (var transition in transitions) Fx.Transitions[transition] = new Fx.Transition(transitions[transition]); +}; + +Fx.Transitions.extend({ + + Pow: function(p, x){ + return Math.pow(p, x[0] || 6); + }, + + Expo: function(p){ + return Math.pow(2, 8 * (p - 1)); + }, + + Circ: function(p){ + return 1 - Math.sin(Math.acos(p)); + }, + + Sine: function(p){ + return 1 - Math.sin((1 - p) * Math.PI / 2); + }, + + Back: function(p, x){ + x = x[0] || 1.618; + return Math.pow(p, 2) * ((x + 1) * p - x); + }, + + Bounce: function(p){ + var value; + for (var a = 0, b = 1; 1; a += b, b /= 2){ + if (p >= (7 - 4 * a) / 11){ + value = b * b - Math.pow((11 - 6 * a - 11 * p) / 4, 2); + break; + } + } + return value; + }, + + Elastic: function(p, x){ + return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x[0] || 1) / 3); + } + +}); + +['Quad', 'Cubic', 'Quart', 'Quint'].each(function(transition, i){ + Fx.Transitions[transition] = new Fx.Transition(function(p){ + return Math.pow(p, [i + 2]); + }); +}); + + +/* +--- + +script: Request.js + +description: Powerful all purpose Request Class. Uses XMLHTTPRequest. + +license: MIT-style license. + +requires: +- /Element +- /Chain +- /Events +- /Options +- /Browser + +provides: [Request] + +... +*/ + +var Request = new Class({ + + Implements: [Chain, Events, Options], + + options: {/* + onRequest: $empty, + onComplete: $empty, + onCancel: $empty, + onSuccess: $empty, + onFailure: $empty, + onException: $empty,*/ + url: '', + data: '', + headers: { + 'X-Requested-With': 'XMLHttpRequest', + 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' + }, + async: true, + format: false, + method: 'post', + link: 'ignore', + isSuccess: null, + emulation: true, + urlEncoded: true, + encoding: 'utf-8', + evalScripts: false, + evalResponse: false, + noCache: false + }, + + initialize: function(options){ + this.xhr = new Browser.Request(); + this.setOptions(options); + this.options.isSuccess = this.options.isSuccess || this.isSuccess; + this.headers = new Hash(this.options.headers); + }, + + onStateChange: function(){ + if (this.xhr.readyState != 4 || !this.running) return; + this.running = false; + this.status = 0; + $try(function(){ + this.status = this.xhr.status; + }.bind(this)); + this.xhr.onreadystatechange = $empty; + if (this.options.isSuccess.call(this, this.status)){ + this.response = {text: this.xhr.responseText, xml: this.xhr.responseXML}; + this.success(this.response.text, this.response.xml); + } else { + this.response = {text: null, xml: null}; + this.failure(); + } + }, + + isSuccess: function(){ + return ((this.status >= 200) && (this.status < 300)); + }, + + processScripts: function(text){ + if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) return $exec(text); + return text.stripScripts(this.options.evalScripts); + }, + + success: function(text, xml){ + this.onSuccess(this.processScripts(text), xml); + }, + + onSuccess: function(){ + this.fireEvent('complete', arguments).fireEvent('success', arguments).callChain(); + }, + + failure: function(){ + this.onFailure(); + }, + + onFailure: function(){ + this.fireEvent('complete').fireEvent('failure', this.xhr); + }, + + setHeader: function(name, value){ + this.headers.set(name, value); + return this; + }, + + getHeader: function(name){ + return $try(function(){ + return this.xhr.getResponseHeader(name); + }.bind(this)); + }, + + check: function(){ + if (!this.running) return true; + switch (this.options.link){ + case 'cancel': this.cancel(); return true; + case 'chain': this.chain(this.caller.bind(this, arguments)); return false; + } + return false; + }, + + send: function(options){ + if (!this.check(options)) return this; + this.running = true; + + var type = $type(options); + if (type == 'string' || type == 'element') options = {data: options}; + + var old = this.options; + options = $extend({data: old.data, url: old.url, method: old.method}, options); + var data = options.data, url = String(options.url), method = options.method.toLowerCase(); + + switch ($type(data)){ + case 'element': data = document.id(data).toQueryString(); break; + case 'object': case 'hash': data = Hash.toQueryString(data); + } + + if (this.options.format){ + var format = 'format=' + this.options.format; + data = (data) ? format + '&' + data : format; + } + + if (this.options.emulation && !['get', 'post'].contains(method)){ + var _method = '_method=' + method; + data = (data) ? _method + '&' + data : _method; + method = 'post'; + } + + if (this.options.urlEncoded && method == 'post'){ + var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : ''; + this.headers.set('Content-type', 'application/x-www-form-urlencoded' + encoding); + } + + if (this.options.noCache){ + var noCache = 'noCache=' + new Date().getTime(); + data = (data) ? noCache + '&' + data : noCache; + } + + var trimPosition = url.lastIndexOf('/'); + if (trimPosition > -1 && (trimPosition = url.indexOf('#')) > -1) url = url.substr(0, trimPosition); + + if (data && method == 'get'){ + url = url + (url.contains('?') ? '&' : '?') + data; + data = null; + } + + this.xhr.open(method.toUpperCase(), url, this.options.async); + + this.xhr.onreadystatechange = this.onStateChange.bind(this); + + this.headers.each(function(value, key){ + try { + this.xhr.setRequestHeader(key, value); + } catch (e){ + this.fireEvent('exception', [key, value]); + } + }, this); + + this.fireEvent('request'); + this.xhr.send(data); + if (!this.options.async) this.onStateChange(); + return this; + }, + + cancel: function(){ + if (!this.running) return this; + this.running = false; + this.xhr.abort(); + this.xhr.onreadystatechange = $empty; + this.xhr = new Browser.Request(); + this.fireEvent('cancel'); + return this; + } + +}); + +(function(){ + +var methods = {}; +['get', 'post', 'put', 'delete', 'GET', 'POST', 'PUT', 'DELETE'].each(function(method){ + methods[method] = function(){ + var params = Array.link(arguments, {url: String.type, data: $defined}); + return this.send($extend(params, {method: method})); + }; +}); + +Request.implement(methods); + +})(); + +Element.Properties.send = { + + set: function(options){ + var send = this.retrieve('send'); + if (send) send.cancel(); + return this.eliminate('send').store('send:options', $extend({ + data: this, link: 'cancel', method: this.get('method') || 'post', url: this.get('action') + }, options)); + }, + + get: function(options){ + if (options || !this.retrieve('send')){ + if (options || !this.retrieve('send:options')) this.set('send', options); + this.store('send', new Request(this.retrieve('send:options'))); + } + return this.retrieve('send'); + } + +}; + +Element.implement({ + + send: function(url){ + var sender = this.get('send'); + sender.send({data: this, url: url || sender.options.url}); + return this; + } + +}); + + +/* +--- + +script: Request.HTML.js + +description: Extends the basic Request Class with additional methods for interacting with HTML responses. + +license: MIT-style license. + +requires: +- /Request +- /Element + +provides: [Request.HTML] + +... +*/ + +Request.HTML = new Class({ + + Extends: Request, + + options: { + update: false, + append: false, + evalScripts: true, + filter: false + }, + + processHTML: function(text){ + var match = text.match(/]*>([\s\S]*?)<\/body>/i); + text = (match) ? match[1] : text; + + var container = new Element('div'); + + return $try(function(){ + var root = '' + text + '', doc; + if (Browser.Engine.trident){ + doc = new ActiveXObject('Microsoft.XMLDOM'); + doc.async = false; + doc.loadXML(root); + } else { + doc = new DOMParser().parseFromString(root, 'text/xml'); + } + root = doc.getElementsByTagName('root')[0]; + if (!root) return null; + for (var i = 0, k = root.childNodes.length; i < k; i++){ + var child = Element.clone(root.childNodes[i], true, true); + if (child) container.grab(child); + } + return container; + }) || container.set('html', text); + }, + + success: function(text){ + var options = this.options, response = this.response; + + response.html = text.stripScripts(function(script){ + response.javascript = script; + }); + + var temp = this.processHTML(response.html); + + response.tree = temp.childNodes; + response.elements = temp.getElements('*'); + + if (options.filter) response.tree = response.elements.filter(options.filter); + if (options.update) document.id(options.update).empty().set('html', response.html); + else if (options.append) document.id(options.append).adopt(temp.getChildren()); + if (options.evalScripts) $exec(response.javascript); + + this.onSuccess(response.tree, response.elements, response.html, response.javascript); + } + +}); + +Element.Properties.load = { + + set: function(options){ + var load = this.retrieve('load'); + if (load) load.cancel(); + return this.eliminate('load').store('load:options', $extend({data: this, link: 'cancel', update: this, method: 'get'}, options)); + }, + + get: function(options){ + if (options || ! this.retrieve('load')){ + if (options || !this.retrieve('load:options')) this.set('load', options); + this.store('load', new Request.HTML(this.retrieve('load:options'))); + } + return this.retrieve('load'); + } + +}; + +Element.implement({ + + load: function(){ + this.get('load').send(Array.link(arguments, {data: Object.type, url: String.type})); + return this; + } + +}); + + +/* +--- + +script: Request.JSON.js + +description: Extends the basic Request Class with additional methods for sending and receiving JSON data. + +license: MIT-style license. + +requires: +- /Request JSON + +provides: [Request.HTML] + +... +*/ + +Request.JSON = new Class({ + + Extends: Request, + + options: { + secure: true + }, + + initialize: function(options){ + this.parent(options); + this.headers.extend({'Accept': 'application/json', 'X-Request': 'JSON'}); + }, + + success: function(text){ + this.response.json = JSON.decode(text, this.options.secure); + this.onSuccess(this.response.json, text); + } + +}); diff --git a/Test/style.css b/Test/style.css new file mode 100644 index 0000000..6f35686 --- /dev/null +++ b/Test/style.css @@ -0,0 +1,121 @@ +html { + background: #666; +} + +body { + margin: 20px 10%; + font-family: Tahoma,Geneva,Kalimati,sans-serif; + font-size: 0.8em; + background: #FFF; + padding: 20px; + border: 1px solid #111; + -moz-border-radius: 20px; + -webkit-border-radius: 20px; +} + +::selection { + background: #fd9800; + color: #2d77e0; +} +::-moz-selection { + background: #fd9800; + color: #2d77e0; +} + +a { + color: #2d77e0; + padding: 1px 3px; +} + +a:hover { + background: #2d77e0; + color: white; +} + +p,h2 { + background: #f5f5f5; + padding: 5px; +} + +h1 { + color: #2d77e0; + font-size: 2em; + text-shadow: 0 1px rgba(0, 0, 0, 0.5); + margin: 0; +} + +h2 { + -webkit-box-shadow: 1px 1px 5px #CCC; + -moz-box-shadow: 1px 1px 5px #DDD; + box-shadow: 1px 1px 5px #333; + border: 1px solid #CCC; + font-size: 1.6em; + margin: 30px 0 10px 0; + background: #E9E9E9; +} + +h2.subtitle { + margin: 0 0 30px 20px; + padding: 0; + border: 0; + background: none; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +h3 { + font-size: 1.2em; +} + +h2, h3 { + color: #fd9800; + text-shadow: 1px 1px rgba(0, 0, 0, 0.5); +} + +code { + border: 1px solid #CCC; + background: #EEE; + padding: 1px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + border-radius: 3px; + font-size: 1.2em; +} + +.docs { + margin-right: 240px; +} + +.docs h3 { + background: #E9E9E9; + border-bottom: 1px solid #CCC; + padding: 5px; + font-size: 1.4em; + text-shadow: 0 1px rgba(255, 255, 255, 0.8); + color: #111; + margin: 0; + font-weight: normal; +} + +.docs .section { + background: white 3px 3px no-repeat; + padding: 5px; + border-bottom: 1px solid #DDD; +} + +.docs h4 { + margin: 10px 0; +} + +pre { + background: #f5f5f5; + padding: 10px; +} + +#overview { + float: right; + width: 200px; + border-left: 1px solid #DDD; + padding: 10px; +} From 36925d756a77085cac12928583ca5038dfeabdb6 Mon Sep 17 00:00:00 2001 From: arian Date: Fri, 19 Mar 2010 13:15:58 +0100 Subject: [PATCH 029/285] Remove merging line --- Source/datepicker.js | 1 - 1 file changed, 1 deletion(-) diff --git a/Source/datepicker.js b/Source/datepicker.js index 38dfd12..1f05ac7 100644 --- a/Source/datepicker.js +++ b/Source/datepicker.js @@ -1,4 +1,3 @@ -<<<<<<< HEAD:Source/datepicker.js /* --- description: MooTools Datepicker class From 4b4a329b588f69465af1c2d7c4e2d261d0a3f8dc Mon Sep 17 00:00:00 2001 From: arian Date: Fri, 19 Mar 2010 13:33:57 +0100 Subject: [PATCH 030/285] Add mootools more (Native/Date) to the tests --- Test/index.html | 8 +- Test/mootools-1.2.4.4-more.js | 672 ++++++++++++++++++++++++++++++++++ 2 files changed, 679 insertions(+), 1 deletion(-) create mode 100644 Test/mootools-1.2.4.4-more.js diff --git a/Test/index.html b/Test/index.html index 4075321..b0dfce0 100644 --- a/Test/index.html +++ b/Test/index.html @@ -13,6 +13,7 @@ + @@ -148,8 +155,8 @@

Demo and Examples

-Click to attach the datpicker to this field
-Click to detach the datpicker from this field
+Click to attach the datepicker to this field
+Click to detach the datepicker from this field
Show datepicker (after you attached it)

@@ -172,5 +179,12 @@

Demo and Examples

+ +

+
+ +

+ + From 8be337c7b14ae65a3df02802ccbd5d3c33a5068b Mon Sep 17 00:00:00 2001 From: Arian Date: Wed, 15 Sep 2010 22:31:06 +0200 Subject: [PATCH 131/285] * Code cleanups * Date:isValid is already in Date -more --- Source/datepicker.js | 78 +++++++++++++++++++++++++------------------- Test/index.html | 5 +++ 2 files changed, 49 insertions(+), 34 deletions(-) diff --git a/Source/datepicker.js b/Source/datepicker.js index 02fd6cc..c8eda3d 100644 --- a/Source/datepicker.js +++ b/Source/datepicker.js @@ -115,8 +115,8 @@ var DatePicker = new Class({ }, initialize: function(attachTo, options){ + // Localization var localeGet = MooTools.lang.get; - // MooTools.lang this.setOptions({ days: localeGet('Date', 'days'), months: localeGet('Date', 'months'), @@ -125,9 +125,9 @@ var DatePicker = new Class({ timeConfirmButton: localeGet('DatePicker', 'time_confirm_button') }); - var oldFormat = this.options.format; + var defaultFormat = this.options.format; this.setOptions(options); - if (this.options.timePicker && this.options.format == oldFormat){ + if (this.options.timePicker && this.options.format == defaultFormat){ var timeFormat = localeGet('Date', 'shortTime'); this.options.format = this.options.timePickerOnly ? timeFormat : this.options.format + ' ' + timeFormat; } @@ -159,7 +159,7 @@ var DatePicker = new Class({ attach: function(attachTo, toggle){ //don't bother trying to attach when not set - if (!attachTo) return; + if (!attachTo) return this; // toggle the datepicker through a separate element? if (toggle){ @@ -177,7 +177,7 @@ var DatePicker = new Class({ } }.bind(this) }); - }; + } // see what is being attached and get an array suitable for it var elems = $type(attachTo) == 'array' ? attachTo : [document.id(attachTo)]; @@ -237,7 +237,7 @@ var DatePicker = new Class({ var toggler = item.retrieve('datepicker:toggler'); var events = item.retrieve('datepicker:events'); // Detach the Events - (toggler ? toggler : item).removeEvents(events); + (toggler || item).removeEvents(events); }); return this; @@ -261,6 +261,7 @@ var DatePicker = new Class({ } } if (!this.d.isValid()) this.d = new Date(); + // Min/max date if (this.options.maxDate && this.options.maxDate.isValid() && this.d > this.options.maxDate) this.d = this.options.maxDate.clone(); @@ -268,10 +269,10 @@ var DatePicker = new Class({ this.d = this.options.minDate.clone(); this.input = input; - var d = (toggler ? document.id(toggler) : input).getCoordinates(); + var inputCoords = (document.id(toggler) || input).getCoordinates(); var position = { - left: d.left + this.options.positionOffset.x, - top: d.top + d.height + this.options.positionOffset.y + left: inputCoords.left + this.options.positionOffset.x, + top: inputCoords.top + inputCoords.height + this.options.positionOffset.y }; this.fireEvent('show'); @@ -279,7 +280,10 @@ var DatePicker = new Class({ this.choice = this.d.toObject(); this.mode = (this.options.startView == 'time' && !this.options.timePicker) ? 'month' : this.options.startView; this.render(); - this.position({x: position.left, y: position.top}); + this.position({ + x: position.left, + y: position.top + }); if (this.options.draggable && $type(this.picker.makeDraggable) == 'function'){ this.dragger = this.picker.makeDraggable(); @@ -292,12 +296,16 @@ var DatePicker = new Class({ }, close: function(e, force){ - if (!document.id(this.picker)) return; + if (!document.id(this.picker)) return this; if ($type(e) != 'event') force = true; + var clickOutside = e && e.target != this.picker && !this.picker.hasChild(e.target); if (force || clickOutside){ if (this.options.useFadeInOut){ - this.picker.set('tween', {duration: this.options.animationDuration / 2, onComplete: this.destroy.bind(this)}).tween('opacity', 1, 0); + this.picker.set('tween', { + duration: this.options.animationDuration / 2, + onComplete: this.destroy.bind(this) + }).fade(0); } else { this.destroy(); } @@ -319,7 +327,7 @@ var DatePicker = new Class({ left: coords.left, top: coords.top } }).inject(document.body); - this.frame.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)'; + frame.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)'; this.addEvent('close', function(){frame.destroy()}); @@ -331,18 +339,21 @@ var DatePicker = new Class({ } }, - position: function(p){ - var w = window.getSize(), - s = window.getScroll(), - d = this.picker.getSize(), - max_y = (w.y + s.y) - d.y, - max_x = (w.x + s.x) - d.x, - i = this.input.getCoordinates(); + position: function(position){ + var size = window.getSize(), + scroll = window.getScroll(), + pickerSize = this.picker.getSize(), + max_y = (size.y + scroll.y) - pickerSize.y, + max_x = (size.x + scroll.x) - pickerSize.x, + inputCoords = this.input.getCoordinates(); - if (p.x > max_x) p.x = i.right - this.options.positionOffset.x - d.x; - if (p.y > max_y) p.y = i.top - this.options.positionOffset.y - d.y; + if (position.x > max_x) position.x = inputCoords.right - this.options.positionOffset.x - pickerSize.x; + if (position.y > max_y) position.y = inputCoords.top - this.options.positionOffset.y - pickerSize.y; - this.picker.setStyles({left: p.x, top: p.y}); + this.picker.setStyles({ + left: position.x, + top: position.y + }); }, render: function(fx){ @@ -350,9 +361,9 @@ var DatePicker = new Class({ this.constructPicker(); } else { // swap contents so we can fill the newContents again and animate - var o = this.oldContents; + var old = this.oldContents; this.oldContents = this.newContents; - this.newContents = o; + this.newContents = old; this.newContents.empty(); } @@ -383,9 +394,7 @@ var DatePicker = new Class({ // if ever the opacity is set to '0' it was only to have us fade it in here // refer to the constructPicker() function, which instantiates the picker at opacity 0 when fading is desired - if (this.picker.getStyle('opacity') == 0){ - this.picker.tween('opacity', 0, 1); - } + if (this.picker.getStyle('opacity') == 0) this.picker.fade(1); // animate if (fx) this.fx(fx); @@ -408,9 +417,14 @@ var DatePicker = new Class({ }, constructPicker: function(){ - this.picker = new Element('div', {'class': this.options.pickerClass}).inject(document.body); + this.picker = new Element('div', { + 'class': this.options.pickerClass + }).inject(document.body); + if (this.options.useFadeInOut){ - this.picker.setStyle('opacity', 0).set('tween', {duration: this.options.animationDuration}); + this.picker.setStyle('opacity', 0).set('tween', { + duration: this.options.animationDuration + }); } var h = new Element('div', {'class': 'header'}).inject(this.picker); @@ -734,10 +748,6 @@ Date.implement({ minutes: this.getMinutes(), seconds: this.getSeconds() }; - }, - - isValid: function(){ - return !isNaN(this); } }); diff --git a/Test/index.html b/Test/index.html index 45d6d93..4104f3e 100644 --- a/Test/index.html +++ b/Test/index.html @@ -138,6 +138,11 @@

Demo and Examples

+

+
+ +

+


From f678fa103df02bf32821ba86bae81645fe8a3f5c Mon Sep 17 00:00:00 2001 From: chemiX Date: Fri, 13 Aug 2010 17:14:03 +0200 Subject: [PATCH 132/285] fix rounded minutes when timeWheelStep > 1 ex.: now if have time 11:58 and wheel step is 10 return 12:00 not 11:60 --- Source/datepicker.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/Source/datepicker.js b/Source/datepicker.js index c8eda3d..a672574 100644 --- a/Source/datepicker.js +++ b/Source/datepicker.js @@ -449,8 +449,18 @@ var DatePicker = new Class({ this.picker.getElement('.titleText').set('html', this.options.timePickerOnly ? this.options.selectTimeTitle : this.d.format('%d %B, %Y')); - new Element('input', {type: 'text', 'class': 'hour', 'title': MooTools.lang.get('DatePicker', 'use_mouse_wheel')}) - .set('value', this.leadZero(this.d.getHours())) + // Init Values for minutes & hours + var initMinutes = (this.d.getMinutes() / this.options.timeWheelStep).round() * this.options.timeWheelStep, + initHours = this.d.getHours(); + + if (initMinutes >= 60){ + initMinutes = 0; + initHours = initHours + 1; + if (initHours > 23) initHours = 0; + } + + new Element('input', { type: 'text', 'class': 'hour', 'title': MooTools.lang.get('DatePicker', 'use_mouse_wheel')}) + .set('value', this.leadZero(initHours) ) .addEvents({ click: function(e){ e.target.focus(); @@ -471,8 +481,8 @@ var DatePicker = new Class({ .set('maxlength', 2) .inject(container); - new Element('input', {type: 'text', 'class': 'minutes', 'title': MooTools.lang.get('DatePicker', 'use_mouse_wheel')}) - .set('value', this.leadZero((this.d.getMinutes() / this.options.timeWheelStep).round() * this.options.timeWheelStep)) + new Element('input', { type: 'text', 'class': 'minutes', 'title': MooTools.lang.get('DatePicker', 'use_mouse_wheel')}) + .set('value', this.leadZero(initMinutes)) .addEvents({ click: function(e){ e.target.focus(); From c88aa4126b8d997a9ffc1b5ba3ad9a7a4cefaf47 Mon Sep 17 00:00:00 2001 From: chemiX Date: Fri, 13 Aug 2010 17:15:26 +0200 Subject: [PATCH 133/285] better czech translation --- Source/datepicker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/datepicker.js b/Source/datepicker.js index a672574..7ea2f21 100644 --- a/Source/datepicker.js +++ b/Source/datepicker.js @@ -805,5 +805,5 @@ MooTools.lang.set('nl-NL', 'DatePicker', { MooTools.lang.set('cs-CZ', 'DatePicker', { select_a_time: 'Vyberte čas', use_mouse_wheel: 'Použijte kolečko myši k rychlé změně hodnoty', - time_confirm_button: 'Potvrď' + time_confirm_button: 'Zvolte čas' }); From 308c7ee391315c2464dc6ae570d78281ed3530eb Mon Sep 17 00:00:00 2001 From: chemiX Date: Fri, 13 Aug 2010 17:21:42 +0200 Subject: [PATCH 134/285] fix first select date, when use repeatly open and close (not select date) dialog before update : when you select first datetime and then open dialog and close and open dialog again, selected date was be misch mash value (selected date was last date from calendar table [next mont and last day from table]) --- Source/datepicker.js | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/Source/datepicker.js b/Source/datepicker.js index 7ea2f21..9b6b73a 100644 --- a/Source/datepicker.js +++ b/Source/datepicker.js @@ -460,7 +460,7 @@ var DatePicker = new Class({ } new Element('input', { type: 'text', 'class': 'hour', 'title': MooTools.lang.get('DatePicker', 'use_mouse_wheel')}) - .set('value', this.leadZero(initHours) ) + .set('value', this.leadZero(initHours)) .addEvents({ click: function(e){ e.target.focus(); @@ -523,17 +523,19 @@ var DatePicker = new Class({ this.picker.getElement('.titleText').set('html', this.options.months[month] + ' ' + this.d.getFullYear()); - this.d.setDate(1); - while (this.d.getDay() != this.options.startDay){ - this.d.setDate(this.d.getDate() - 1); - } + var date = this.d.clone(); + + date.setDate(1); + while (date.getDay() != this.options.startDay) + date.setDate(date.getDate() - 1); + var container = new Element('div', {'class': 'days'}).inject(this.newContents); var titles = new Element('div', {'class': 'titles'}).inject(container); - var d, i, classes, e, weekcontainer; + var day, i, classes, e, weekcontainer; - for (d = this.options.startDay; d < (this.options.startDay + 7); d++){ - new Element('div', {'class': 'title day day' + (d % 7)}).set('text', this.options.days[(d % 7)].substring(0, this.options.dayShort)).inject(titles); + for (day = this.options.startDay; day < (this.options.startDay + 7); day++){ + new Element('div', {'class': 'title day day' + (day % 7)}).set('text', this.options.days[(day % 7)].substring(0, this.options.dayShort)).inject(titles); } var available = false; @@ -543,20 +545,20 @@ var DatePicker = new Class({ for (i = 0; i < 42; i++){ classes = []; classes.push('day'); - classes.push('day' + this.d.getDay()); - if (this.d.toDateString() == t) classes.push('today'); - if (this.d.toDateString() == currentChoice) classes.push('selected'); - if (this.d.getMonth() != month) classes.push('otherMonth'); + classes.push('day' + date.getDay()); + if (date.toDateString() == t) classes.push('today'); + if (date.toDateString() == currentChoice) classes.push('selected'); + if (date.getMonth() != month) classes.push('otherMonth'); if (i % 7 == 0){ weekcontainer = new Element('div', {'class': 'week week' + (Math.floor(i / 7))}).inject(container); } - e = new Element('div', {'class': classes.join(' ')}).set('text', this.d.getDate()).inject(weekcontainer); + e = new Element('div', {'class': classes.join(' ')}).set('text', date.getDate()).inject(weekcontainer); if (this.limited('date')){ e.addClass('unavailable'); if (available){ - if (month == this.d.getMonth() || this.d.getDate() == 1){ + if (month == date.getMonth() || date.getDate() == 1){ this.limit.right = true; } } else { @@ -566,16 +568,16 @@ var DatePicker = new Class({ available = true; e.addEvent('click', function(d){ if (this.options.timePicker){ - this.d.setDate(d.day); - this.d.setMonth(d.month); + date.setDate(d.day); + date.setMonth(d.month); this.mode = 'time'; this.render('fade'); } else { this.select(d); } - }.pass([{day: this.d.getDate(), month: this.d.getMonth(), year: this.d.getFullYear()}], this)); + }.pass([{day: date.getDate(), month: date.getMonth(), year: date.getFullYear()}], this)); } - this.d.setDate(this.d.getDate() + 1); + date.setDate(date.getDate() + 1); } if (!available) this.limit.right = true; }, From 31089356a1969c4d234fee6767cdaeeb47a9ba78 Mon Sep 17 00:00:00 2001 From: chemiX Date: Fri, 13 Aug 2010 17:23:55 +0200 Subject: [PATCH 135/285] add input call event "onChange" when new value selected --- Source/datepicker.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/datepicker.js b/Source/datepicker.js index 9b6b73a..bf7fa03 100644 --- a/Source/datepicker.js +++ b/Source/datepicker.js @@ -738,6 +738,7 @@ var DatePicker = new Class({ this.input.set('value', d.format(this.options.format)) .store('datepicker:value', d.strftime()); this.fireEvent('select', d); + this.input.fireEvent('change'); // call input onChange event this.close(null, true); }, From c4ab4d464e4a576ac6f63ac3c2c092dec91c6700 Mon Sep 17 00:00:00 2001 From: Arian Date: Mon, 20 Sep 2010 23:34:44 +0200 Subject: [PATCH 136/285] Fix #5 - The datepicker closed/flickered when another input element was focussed --- Source/datepicker.js | 53 ++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/Source/datepicker.js b/Source/datepicker.js index bf7fa03..25dfc8a 100644 --- a/Source/datepicker.js +++ b/Source/datepicker.js @@ -152,7 +152,14 @@ var DatePicker = new Class({ } document.addEvent('mousedown', function(event){ - this.close.call(this, event); + if ( + !(this.elems && this.elems.contains(event.target)) && + this.picker && + event.target != this.picker && + !this.picker.hasChild(event.target) + ){ + this.close.call(this); + } }.bind(this)); }, @@ -173,14 +180,14 @@ var DatePicker = new Class({ !target.hasClass('minutes') && !target.hasClass('ok') ){ - this.close(null, true); + this.close(); } }.bind(this) }); } // see what is being attached and get an array suitable for it - var elems = $type(attachTo) == 'array' ? attachTo : [document.id(attachTo)]; + var elems = this.elems = $type(attachTo) == 'array' ? attachTo : [document.id(attachTo)]; // attach functionality to the inputs elems.each(function(item, index){ @@ -192,12 +199,10 @@ var DatePicker = new Class({ // events if (toggle && togglers){ var self = this; - var events = { - 'click': function(e){ - if (e) e.stop(); - self.show(item, togglers[index]); - } - }; + var events = {'click': function(e){ + if (e) e.stop(); + self.show(item, togglers[index]); + }}; var toggler = togglers[index] .setStyle('cursor', 'pointer') .addEvents(events); @@ -209,9 +214,9 @@ var DatePicker = new Class({ // prevent the user from typing in the field if (this.options.allowEmpty && (e.key == 'delete' || e.key == 'backspace')){ item.set('value', ''); - this.close(null, true); + this.close(); } else if (e.key == 'tab'){ - this.close(null, true); + this.close(); } else { e.stop(); } @@ -295,20 +300,16 @@ var DatePicker = new Class({ return this; }, - close: function(e, force){ + close: function(){ if (!document.id(this.picker)) return this; - if ($type(e) != 'event') force = true; - - var clickOutside = e && e.target != this.picker && !this.picker.hasChild(e.target); - if (force || clickOutside){ - if (this.options.useFadeInOut){ - this.picker.set('tween', { - duration: this.options.animationDuration / 2, - onComplete: this.destroy.bind(this) - }).fade(0); - } else { - this.destroy(); - } + + if (this.options.useFadeInOut){ + this.picker.set('tween', { + duration: this.options.animationDuration / 2, + onComplete: this.destroy.bind(this) + }).fade(0); + } else { + this.destroy(); } return this; @@ -432,7 +433,7 @@ var DatePicker = new Class({ new Element('div', {'class': 'previous'}).addEvent('click', this.previous.bind(this)).set('text', '«').inject(h); new Element('div', {'class': 'next'}).addEvent('click', this.next.bind(this)).set('text', '»').inject(h); new Element('div', {'class': 'closeButton'}).addEvent('click', function(event){ - this.close.call(this, event, true); + this.close.call(this); }.bind(this)).set('text', 'x').inject(h); new Element('span', {'class': 'titleText'}).addEvent('click', this.zoomOut.bind(this)).inject(titlecontainer); @@ -740,7 +741,7 @@ var DatePicker = new Class({ this.fireEvent('select', d); this.input.fireEvent('change'); // call input onChange event - this.close(null, true); + this.close(); }, leadZero: function(v){ From 833fc3de36eac1d6770b33e84f9ab32bcfc73fec Mon Sep 17 00:00:00 2001 From: Arian Date: Tue, 21 Sep 2010 00:28:53 +0200 Subject: [PATCH 137/285] Fixing behaviour when tabbing trough the input fields --- Source/datepicker.js | 52 ++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/Source/datepicker.js b/Source/datepicker.js index 25dfc8a..ec0a89e 100644 --- a/Source/datepicker.js +++ b/Source/datepicker.js @@ -171,19 +171,17 @@ var DatePicker = new Class({ // toggle the datepicker through a separate element? if (toggle){ var togglers = $type(toggle) == 'array' ? toggle : [document.id(toggle)]; - document.addEvents({ - 'keydown': function(e){ - var target = document.id(e.target); - if ( - e.key == 'tab' && - !target.hasClass('hour') && - !target.hasClass('minutes') && - !target.hasClass('ok') - ){ - this.close(); - } - }.bind(this) - }); + document.addEvent('keydown', function(event){ + var target = document.id(event.target); + if ( + event.key == 'tab' && + !target.hasClass('hour') && + !target.hasClass('minutes') && + !target.hasClass('ok') + ){ + this.close(); + } + }.bind(this)); } // see what is being attached and get an array suitable for it @@ -199,7 +197,7 @@ var DatePicker = new Class({ // events if (toggle && togglers){ var self = this; - var events = {'click': function(e){ + var events = {click: function(e){ if (e) e.stop(); self.show(item, togglers[index]); }}; @@ -210,7 +208,7 @@ var DatePicker = new Class({ .store('datepicker:events', events); } else { var events = { - 'keydown': function(e){ + keydown: function(e){ // prevent the user from typing in the field if (this.options.allowEmpty && (e.key == 'delete' || e.key == 'backspace')){ item.set('value', ''); @@ -221,7 +219,8 @@ var DatePicker = new Class({ e.stop(); } }.bind(this), - 'focus': this.show.pass(item, this) + focus: this.show.pass(item, this), + click: this.show.pass(item, this) }; item.addEvents(events).store('datepicker:events', events); @@ -284,6 +283,7 @@ var DatePicker = new Class({ this.today = new Date(); this.choice = this.d.toObject(); this.mode = (this.options.startView == 'time' && !this.options.timePicker) ? 'month' : this.options.startView; + this.render(); this.position({ x: position.left, @@ -303,14 +303,8 @@ var DatePicker = new Class({ close: function(){ if (!document.id(this.picker)) return this; - if (this.options.useFadeInOut){ - this.picker.set('tween', { - duration: this.options.animationDuration / 2, - onComplete: this.destroy.bind(this) - }).fade(0); - } else { - this.destroy(); - } + if (this.options.useFadeInOut) this.picker.fade(0); + else this.destroy(); return this; }, @@ -393,9 +387,7 @@ var DatePicker = new Class({ // restore working date this.d = startDate; - // if ever the opacity is set to '0' it was only to have us fade it in here - // refer to the constructPicker() function, which instantiates the picker at opacity 0 when fading is desired - if (this.picker.getStyle('opacity') == 0) this.picker.fade(1); + this.picker.fade(1); // animate if (fx) this.fx(fx); @@ -424,7 +416,11 @@ var DatePicker = new Class({ if (this.options.useFadeInOut){ this.picker.setStyle('opacity', 0).set('tween', { - duration: this.options.animationDuration + duration: this.options.animationDuration, + link: 'cancel', + onComplete: function(){ + if (this.picker.getStyle('opacity') < 1) this.destroy(); + }.bind(this) }); } From 9770ebf94a1ad915c564276c2263db4190d90ace Mon Sep 17 00:00:00 2001 From: Arian Date: Tue, 21 Sep 2010 00:39:37 +0200 Subject: [PATCH 138/285] Tagging 1.50 beta 5, all serious bugs are squashed --- package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.yml b/package.yml index 2013a86..6ba58c4 100644 --- a/package.yml +++ b/package.yml @@ -1,6 +1,6 @@ name: MooTools-DatePicker author: astolwijk -current: 1.50b4 +current: 1.50b5 category: Widgets tags: [Datepicker,Calendar] demo: http://www.aryweb.nl/projects/mootools-datepicker/ From ed6ae50205189171b0cd883c284140cff61fa7f2 Mon Sep 17 00:00:00 2001 From: Nathan Wright Date: Wed, 29 Sep 2010 12:30:53 -0700 Subject: [PATCH 139/285] Fix date change when the date and time pickers are used in combination I'm not sure if it's necessary to alter the date var, or if altering just this.d is sufficient. Taking the safer approach and leaving date as-is. --- Source/datepicker.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/datepicker.js b/Source/datepicker.js index ec0a89e..f21827c 100644 --- a/Source/datepicker.js +++ b/Source/datepicker.js @@ -567,6 +567,8 @@ var DatePicker = new Class({ if (this.options.timePicker){ date.setDate(d.day); date.setMonth(d.month); + this.d.setDate(d.day); + this.d.setMonth(d.month); this.mode = 'time'; this.render('fade'); } else { From 2840358d618231b6f0c67d8154f703aed279c73b Mon Sep 17 00:00:00 2001 From: Arian Date: Fri, 8 Oct 2010 17:19:19 +0200 Subject: [PATCH 140/285] Add test for commit ed6ae502051891, fixes #17 and #20 --- Test/index.html | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Test/index.html b/Test/index.html index 4104f3e..0581f34 100644 --- a/Test/index.html +++ b/Test/index.html @@ -98,6 +98,11 @@ timePickerOnly: true }); + // Date and Time + new DatePicker('dateandtime',{ + timePicker: true + }); + // Date object as max/minDate new DatePicker('date_object_options', { minDate: new Date('03/05/2010'), @@ -184,6 +189,10 @@

Demo and Examples

+

+
+ +


From 4ac02811302d54ad6887f065f27e769493e5144a Mon Sep 17 00:00:00 2001 From: Arian Date: Fri, 8 Oct 2010 19:26:10 +0200 Subject: [PATCH 141/285] Remove two unnecessary lines + add Chemix to the Authors --- Source/datepicker.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Source/datepicker.js b/Source/datepicker.js index f21827c..2f31d34 100644 --- a/Source/datepicker.js +++ b/Source/datepicker.js @@ -11,6 +11,7 @@ authors: - MadmanMonty (Chris Baxter) - marfillaster (Ken Marfilla) - eerne (Enrique Erne) + - Chemix license: - MIT License @@ -565,8 +566,6 @@ var DatePicker = new Class({ available = true; e.addEvent('click', function(d){ if (this.options.timePicker){ - date.setDate(d.day); - date.setMonth(d.month); this.d.setDate(d.day); this.d.setMonth(d.month); this.mode = 'time'; From aaf555f6bbe7c720b34cde3c4a4070d315ac8fa0 Mon Sep 17 00:00:00 2001 From: Arian Date: Sat, 16 Oct 2010 11:07:30 +0200 Subject: [PATCH 142/285] Add newline at the add of the package.yml file --- package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.yml b/package.yml index 6ba58c4..de56712 100644 --- a/package.yml +++ b/package.yml @@ -10,4 +10,4 @@ license: MIT web: "[aryweb.nl/projects/mootools-datepicker](http://www.aryweb.nl/projects/mootools-datepicker/)" description: MooTools Datepicker class sources: - - "Source/datepicker.js" \ No newline at end of file + - "Source/datepicker.js" From 155947d66a743f6024217f9b7bfb6e30c7234db2 Mon Sep 17 00:00:00 2001 From: Kyle Dodson Date: Fri, 15 Oct 2010 13:32:45 -0700 Subject: [PATCH 143/285] Upgrade to Mootools 1.3 (dropping support for Mootools 1.2) using notes at http://github.com/mootools/mootools-core/wiki/Upgrade-from-1.2-to-1.3 --- Source/datepicker.js | 52 +- Test/index.html | 4 +- Test/mootools-1.2.4-core.js | 4329 ------------- Test/mootools-1.3-core.js | 5367 +++++++++++++++++ ....4-more.js => mootools-1.3.0.1rc1-more.js} | 851 ++- 5 files changed, 5923 insertions(+), 4680 deletions(-) delete mode 100644 Test/mootools-1.2.4-core.js create mode 100644 Test/mootools-1.3-core.js rename Test/{mootools-1.2.4.4-more.js => mootools-1.3.0.1rc1-more.js} (58%) diff --git a/Source/datepicker.js b/Source/datepicker.js index 2f31d34..08fe385 100644 --- a/Source/datepicker.js +++ b/Source/datepicker.js @@ -88,7 +88,7 @@ var DatePicker = new Class({ yearsPerPage: 20, allowEmpty: true, animationDuration: 400, - useFadeInOut: !Browser.Engine.trident, // dont animate fade-in/fade-out for IE + useFadeInOut: !Browser.ie, // dont animate fade-in/fade-out for IE startView: 'month', // allowed values: {time, month, year, decades} positionOffset: {x: 0, y: 0}, /*minDate: null, // Date object or a string @@ -108,28 +108,27 @@ var DatePicker = new Class({ // and some event hooks: - onShow: $empty, // triggered when the datepicker pops up - onClose: $empty, // triggered after the datepicker is closed (destroyed) - onSelect: $empty, // triggered when a date is selected - onNext: $empty, // triggered when changing to next month - onPrevious: $empty // triggered when changing to previous month */ + onShow: function(){}, // triggered when the datepicker pops up + onClose: function(){}, // triggered after the datepicker is closed (destroyed) + onSelect: function(){}, // triggered when a date is selected + onNext: function(){}, // triggered when changing to next month + onPrevious: function(){} // triggered when changing to previous month */ }, initialize: function(attachTo, options){ // Localization - var localeGet = MooTools.lang.get; this.setOptions({ - days: localeGet('Date', 'days'), - months: localeGet('Date', 'months'), - format: localeGet('Date', 'shortDate'), - selectTimeTitle: localeGet('DatePicker', 'select_a_time'), - timeConfirmButton: localeGet('DatePicker', 'time_confirm_button') + days: Locale.get('Date.days'), + months: Locale.get('Date.months'), + format: Locale.get('Date.shortDate'), + selectTimeTitle: Locale.get('DatePicker.select_a_time'), + timeConfirmButton: Locale.get('DatePicker.time_confirm_button') }); var defaultFormat = this.options.format; this.setOptions(options); if (this.options.timePicker && this.options.format == defaultFormat){ - var timeFormat = localeGet('Date', 'shortTime'); + var timeFormat = Locale.get('Date.shortTime'); this.options.format = this.options.timePickerOnly ? timeFormat : this.options.format + ' ' + timeFormat; } @@ -157,7 +156,7 @@ var DatePicker = new Class({ !(this.elems && this.elems.contains(event.target)) && this.picker && event.target != this.picker && - !this.picker.hasChild(event.target) + !(this.picker.contains(event.target) && event.target != this.picker) ){ this.close.call(this); } @@ -171,7 +170,7 @@ var DatePicker = new Class({ // toggle the datepicker through a separate element? if (toggle){ - var togglers = $type(toggle) == 'array' ? toggle : [document.id(toggle)]; + var togglers = typeOf(toggle) == 'array' ? toggle : [document.id(toggle)]; document.addEvent('keydown', function(event){ var target = document.id(event.target); if ( @@ -186,7 +185,8 @@ var DatePicker = new Class({ } // see what is being attached and get an array suitable for it - var elems = this.elems = $type(attachTo) == 'array' ? attachTo : [document.id(attachTo)]; + var elemsType = typeOf(attachTo); + var elems = this.elems = elemsType == 'array' || elemsType == 'elements' ? attachTo : [document.id(attachTo)]; // attach functionality to the inputs elems.each(function(item, index){ @@ -232,7 +232,7 @@ var DatePicker = new Class({ }, detach: function(detach){ - var elems = $type(detach) == 'array' ? detach : [document.id(detach)]; + var elems = typeOf(detach) == 'array' ? detach : [document.id(detach)]; elems.each(function(item){ // Only when the datepicker is attached @@ -291,12 +291,12 @@ var DatePicker = new Class({ y: position.top }); - if (this.options.draggable && $type(this.picker.makeDraggable) == 'function'){ + if (this.options.draggable && typeOf(this.picker.makeDraggable) == 'function'){ this.dragger = this.picker.makeDraggable(); this.picker.setStyle('cursor', 'move'); } - if (Browser.Engine.trident) this.shim(); + if (Browser.ie) this.shim(); return this; }, @@ -457,7 +457,7 @@ var DatePicker = new Class({ if (initHours > 23) initHours = 0; } - new Element('input', { type: 'text', 'class': 'hour', 'title': MooTools.lang.get('DatePicker', 'use_mouse_wheel')}) + new Element('input', { type: 'text', 'class': 'hour', 'title': Locale.get('DatePicker.use_mouse_wheel')}) .set('value', this.leadZero(initHours)) .addEvents({ click: function(e){ @@ -479,7 +479,7 @@ var DatePicker = new Class({ .set('maxlength', 2) .inject(container); - new Element('input', { type: 'text', 'class': 'minutes', 'title': MooTools.lang.get('DatePicker', 'use_mouse_wheel')}) + new Element('input', { type: 'text', 'class': 'minutes', 'title': Locale.get('DatePicker.use_mouse_wheel')}) .set('value', this.leadZero(initMinutes)) .addEvents({ click: function(e){ @@ -509,7 +509,7 @@ var DatePicker = new Class({ .addEvents({ click: function(e){ e.stop(); - this.select($merge(this.d.toObject(), {hours: this.picker.getElement('.hour').get('value').toInt(), minutes: this.picker.getElement('.minutes').get('value').toInt()})); + this.select(Object.merge({}, this.d.toObject(), {hours: this.picker.getElement('.hour').get('value').toInt(), minutes: this.picker.getElement('.minutes').get('value').toInt()})); }.bind(this) }) .set('maxlength', 2) @@ -731,7 +731,7 @@ var DatePicker = new Class({ }, select: function(values){ - this.choice = $merge(this.choice, values); + this.choice = Object.merge({}, this.choice, values); var d = Date.fromObject(this.choice); this.input.set('value', d.format(this.options.format)) .store('datepicker:value', d.strftime()); @@ -791,19 +791,19 @@ Date.extend({ * Translation * */ -MooTools.lang.set('en-US', 'DatePicker', { +Locale.define('en-US', 'DatePicker', { select_a_time: 'Select a time', use_mouse_wheel: 'Use the mouse wheel to quickly change value', time_confirm_button: 'OK' }); -MooTools.lang.set('nl-NL', 'DatePicker', { +Locale.define('nl-NL', 'DatePicker', { select_a_time: 'Selecteer een tijd', use_mouse_wheel: 'Gebruik uw scrollwiel om door de tijd te scrollen', time_confirm_button: 'OK' }); -MooTools.lang.set('cs-CZ', 'DatePicker', { +Locale.define('cs-CZ', 'DatePicker', { select_a_time: 'Vyberte čas', use_mouse_wheel: 'Použijte kolečko myši k rychlé změně hodnoty', time_confirm_button: 'Zvolte čas' diff --git a/Test/index.html b/Test/index.html index 0581f34..c8f8d5a 100644 --- a/Test/index.html +++ b/Test/index.html @@ -12,8 +12,8 @@ - - + + - + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + +

Localized Date Picker

+ +

+ This datepicker should parse the date as february 8th 1991 (dd-mm-yyyy). And should format it that way when it is ready. + The month and day names should be localized as well. +

+ +

+ Inputs: + +

+ + + + \ No newline at end of file From 90d5ecca1e88458d2b84e4b010b81d8646f5720e Mon Sep 17 00:00:00 2001 From: Arian Date: Mon, 8 Nov 2010 11:27:33 +0100 Subject: [PATCH 170/285] Make sture when the timeWheelStep option is set, the minutes are always n*timeWheelStep + add time parsers to Date to parse times with Date.defineParsers --- Source/Picker.Date.js | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/Source/Picker.Date.js b/Source/Picker.Date.js index 0657e08..3d6a387 100644 --- a/Source/Picker.Date.js +++ b/Source/Picker.Date.js @@ -472,9 +472,11 @@ var renderers = { time: function(options, date, currentDate, fn){ var container = new Element('div.time'), - // Init Values for minutes & hours - initMinutes = date.get('minutes'), - initHours = date.get('hours'); + // make sure that the minutes are timeWheelStep * k + initMinutes = (date.get('minutes') / options.timeWheelStep).round() * options.timeWheelStep + + if (initMinutes >= 60) initMinutes = 0; + date.set('minutes', initMinutes); var hoursInput = new Element('input.hour[type=text]', { title: Locale.get('DatePicker.use_mouse_wheel'), @@ -488,8 +490,8 @@ var renderers = { event.stop(); hoursInput.focus(); var value = hoursInput.get('value').toInt(); - if (event.wheel > 0) value = (value < 23) ? value + 1 : 0; - else value = (value > 0) ? value - 1 : 23; + value = (event.wheel > 0) ? ((value < 23) ? value + 1 : 0) + : ((value > 0) ? value - 1 : 23) date.set('hours', value); hoursInput.set('value', date.format('%H')); }.bind(this) @@ -509,9 +511,9 @@ var renderers = { event.stop(); minutesInput.focus(); var value = minutesInput.get('value').toInt(); - if (event.wheel > 0) value = (value < 59) ? (value + options.timeWheelStep) : 0; - else value = (value > 0) ? (value - options.timeWheelStep) : (60 - options.timeWheelStep); - if (value == 60) value = 0; + value = (event.wheel > 0) ? ((value < 59) ? (value + options.timeWheelStep) : 0) + : ((value > 0) ? (value - options.timeWheelStep) : (60 - options.timeWheelStep)); + if (value >= 60) value = 0; date.set('minutes', value); minutesInput.set('value', date.format('%M')); }.bind(this) @@ -581,4 +583,12 @@ var isLimited = function(type, date, minDate, maxDate){ }; + +// Parse times +Date.defineParsers( + '%H:%M%p', // "11:05pm" + '%H:%M %p', // "11:05 pm" + '%H:%M' // "11:05" +); + })(); From 7367ef92a2b47c7fc59343f38281b61470d0572b Mon Sep 17 00:00:00 2001 From: Arian Date: Mon, 8 Nov 2010 11:28:13 +0100 Subject: [PATCH 171/285] Add timepicker test --- Test/timepicker.html | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 Test/timepicker.html diff --git a/Test/timepicker.html b/Test/timepicker.html new file mode 100644 index 0000000..ccd0469 --- /dev/null +++ b/Test/timepicker.html @@ -0,0 +1,44 @@ + + + + + Picker.Date Timepicker + + + + + + + + + + + + + + +

TimePicker

+ +

+ This test shows a timepicker only. It should parse the current time (11:05 AM) and it should format it that way.
+ You should not be able to go up by clicking the picker title. The title should say a localized string "select a time"
+ You should be able to change the hours and minutes with your scrollweel. The minutes should go in steps of 5. +

+ +

+ Inputs: + +

+ + + + \ No newline at end of file From ce7d3fa53fcbcf7168783ab469bfecf1daf276fd Mon Sep 17 00:00:00 2001 From: Arian Date: Mon, 8 Nov 2010 11:47:28 +0100 Subject: [PATCH 172/285] Add a MonthPicker Test --- Source/Picker.js | 2 +- Test/monthpicker.html | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 Test/monthpicker.html diff --git a/Source/Picker.js b/Source/Picker.js index 9957dde..84205ab 100644 --- a/Source/Picker.js +++ b/Source/Picker.js @@ -63,12 +63,12 @@ var Picker = new Class({ // Build the body of the picker var body = this.body = new Element('div.body').inject(picker); - // oldContents and newContents are used to slide from the old content to a new one. var bodysize = this.bodysize = body.getSize(); this.pickersize = picker.getSize(); picker.setStyle('display', 'none'); + // oldContents and newContents are used to slide from the old content to a new one. var slider = this.slider = new Element('div.slider', { styles: { position: 'absolute', diff --git a/Test/monthpicker.html b/Test/monthpicker.html new file mode 100644 index 0000000..2369800 --- /dev/null +++ b/Test/monthpicker.html @@ -0,0 +1,43 @@ + + + + + Picker.Date Monthpicker + + + + + + + + + + + + + + +

MonthPicker

+ +

+ This test shows a monthpicker only. It should parse the default month (December) and it should format it that way.
+ You can go up to the years picker, but you cannot pick a specific day. +

+ +

+ Inputs: + +

+ + + + \ No newline at end of file From 595844e668f1f03f4e2798faa499bb14632a8184 Mon Sep 17 00:00:00 2001 From: Arian Date: Mon, 8 Nov 2010 11:53:56 +0100 Subject: [PATCH 173/285] this.date should not be able to modify by one of the renderers + add a yearpicker test --- Source/Picker.Date.js | 2 +- Test/yearpicker.html | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 Test/yearpicker.html diff --git a/Source/Picker.Date.js b/Source/Picker.Date.js index 3d6a387..ae0a7dd 100644 --- a/Source/Picker.Date.js +++ b/Source/Picker.Date.js @@ -102,7 +102,7 @@ this.DatePicker = Picker.Date = new Class({ var view = this.currentView, cap = view.capitalize(); if (this['render' + cap]){ - this['render' + cap](this.date); + this['render' + cap](this.date.clone()); this.currentView = view; } }.bind(this)); diff --git a/Test/yearpicker.html b/Test/yearpicker.html new file mode 100644 index 0000000..44ffeec --- /dev/null +++ b/Test/yearpicker.html @@ -0,0 +1,42 @@ + + + + + Picker.Date YearPicker + + + + + + + + + + + + + + +

YearPicker

+ +

+ This test shows a yearpicker only. It should parse the default year (2010) and it should format it that way. +

+ +

+ Inputs: + +

+ + + + \ No newline at end of file From 73259b90500936be20fa26eeec55503cdc7fe35b Mon Sep 17 00:00:00 2001 From: Arian Date: Mon, 8 Nov 2010 13:22:04 +0100 Subject: [PATCH 174/285] Better default dateformat option - only date if timepicker = false, date and time if timepicker = true and only time if pickOnly = time --- Source/Picker.Date.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Source/Picker.Date.js b/Source/Picker.Date.js index ae0a7dd..224d240 100644 --- a/Source/Picker.Date.js +++ b/Source/Picker.Date.js @@ -69,7 +69,10 @@ this.DatePicker = Picker.Date = new Class({ this.options.maxDate = Date.parse(options.maxDate).increment('day', 1); } - if (!options.format) options.format = Locale.get('Date.' + ((options.pickOnly == 'time') ? 'shortTime' : 'shortDate')); + if (!options.format){ + if (options.pickOnly != 'time') options.format = Locale.get('Date.shortDate'); + if (options.timePicker) options.format = options.format + (options.format ? ' ' : '') + Locale.get('Date.shortTime'); + } // This is where we store the selected date this.date = limitDate(new Date(), options.minDate, options.maxDate); From f0f3494362836c2b7244cbc9e3260cd7f2d03b75 Mon Sep 17 00:00:00 2001 From: Arian Date: Mon, 8 Nov 2010 13:29:43 +0100 Subject: [PATCH 175/285] Never let the picker fall outside the screen, so the use does not have to scroll to see the Picker --- Source/Picker.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Source/Picker.js b/Source/Picker.js index 84205ab..f36a96a 100644 --- a/Source/Picker.js +++ b/Source/Picker.js @@ -183,17 +183,19 @@ var Picker = new Class({ y = elementCoords.top; } var offset = this.options.positionOffset, - scrollSize = document.getScrollSize(), + scroll = document.getScroll(), + size = document.getSize(), pickersize = this.pickersize; + var position = { left: x + offset.x, top: y + offset.y }; + if ((position.left + pickersize.x) > (size.x + scroll.x)) position.left = (size.x + scroll.x) - pickersize.x; + if ((position.top + pickersize.y) > (size.y + scroll.y)) position.top = (size.y + scroll.y) - pickersize.y; if (position.left < 0) position.left = 0; if (position.top < 0) position.top = 0; - if ((position.left + pickersize.x) > scrollSize.x) position.left = scrollSize.x - pickersize.x; - if ((position.top + pickersize.y) > scrollSize.y) position.top = scrollSize.y - pickersize.y; this.picker.setStyles(position); if (this.shim) this.shim.position(); From 4b659cb0a7ccdf7e4cfec71538c8a33abf6bd6e3 Mon Sep 17 00:00:00 2001 From: Arian Date: Mon, 8 Nov 2010 13:37:53 +0100 Subject: [PATCH 176/285] Update package.yml and YAML headers a bit --- Source/Picker.Date.js | 12 ++++++------ Source/Picker.js | 2 +- package.yml | 11 ++++++++--- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/Source/Picker.Date.js b/Source/Picker.Date.js index 224d240..b7621ff 100644 --- a/Source/Picker.Date.js +++ b/Source/Picker.Date.js @@ -1,9 +1,9 @@ /* --- name: Picker.Date -description: Creates a Datepicker +description: Creates a DatePicker, can be used for picking years/months/days and time, or all of them authors: Arian Stolwijk -requires: [Picker.Attach, Locale.en-US.DatePicker, More/Locale, More/Date] +requires: [Picker, Picker.Attach, Locale.en-US.DatePicker, More/Locale, More/Date] provides: Picker.Date ... */ @@ -15,10 +15,10 @@ this.DatePicker = Picker.Date = new Class({ Extends: Picker.Attach, - options: { -// minDate: new Date('3/4/2010'), // Date object or a string -// maxDate: new Date('3/4/2011'), // same as minDate -// format: null, + options: {/* + minDate: new Date('3/4/2010'), // Date object or a string + maxDate: new Date('3/4/2011'), // same as minDate + format: null,*/ timePicker: false, timePickerOnly: false, // deprecated, use onlyView = 'time' diff --git a/Source/Picker.js b/Source/Picker.js index f36a96a..bdfc684 100644 --- a/Source/Picker.js +++ b/Source/Picker.js @@ -1,7 +1,7 @@ /* --- name: Picker -description: Creates a Picker +description: Creates a Picker, which can be used for anything authors: Arian Stolwijk requires: [Core/Element.Dimensions, Core/Fx.Tween, Core/Fx.Transitions] provides: Picker diff --git a/package.yml b/package.yml index dfa7cb9..9cce948 100644 --- a/package.yml +++ b/package.yml @@ -1,8 +1,8 @@ name: MooTools-DatePicker author: astolwijk -current: 1.61 +current: 2.0 category: Widgets -tags: [Datepicker,Calendar] +tags: [Datepicker, Calendar, Picker] demo: http://www.aryweb.nl/projects/mootools-datepicker/ docs: http://github.com/arian/mootools-datepicker/blob/master/README.md copyright: "© [MonkeyPhysics.com](http://monkeyphysics.com)" @@ -11,4 +11,9 @@ web: "[aryweb.nl/projects/mootools-datepicker](http://www.aryweb.nl/projects/moo description: MooTools Datepicker class sources: - - "Source/datepicker.js" + - "Source/Picker.js" + - "Source/Picker.Attach.js" + - "Source/Picker.Date.js" + - "Source/Locale.en-US.DatePicker.js" + - "Source/Locale.cs-CZ.DatePicker.js" + - "Source/Locale.nl-NL.DatePicker.js" From d4b5b1e5c9b4566dc4c083a233a497d02b68ae05 Mon Sep 17 00:00:00 2001 From: Arian Date: Mon, 8 Nov 2010 20:26:28 +0100 Subject: [PATCH 177/285] Fix where the mouse pointer could disappear above the title --- Source/Picker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Picker.js b/Source/Picker.js index bdfc684..fda128c 100644 --- a/Source/Picker.js +++ b/Source/Picker.js @@ -268,7 +268,7 @@ var Picker = new Class({ setTitleEvent: function(fn){ this.titleText.removeEvents('click'); if (fn) this.titleText.addEvent('click', fn); - this.titleText.setStyle('cursor', fn ? 'pointer' : 'none'); + this.titleText.setStyle('cursor', fn ? 'pointer' : ''); return this; } From dfe5ee5bbfcac5c8f88f2f8e54a1af6dc66501a8 Mon Sep 17 00:00:00 2001 From: Arian Date: Mon, 8 Nov 2010 20:33:31 +0100 Subject: [PATCH 178/285] Fix the format correctly, if pickView = time --- Source/Picker.Date.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Picker.Date.js b/Source/Picker.Date.js index b7621ff..514496c 100644 --- a/Source/Picker.Date.js +++ b/Source/Picker.Date.js @@ -70,8 +70,8 @@ this.DatePicker = Picker.Date = new Class({ } if (!options.format){ - if (options.pickOnly != 'time') options.format = Locale.get('Date.shortDate'); - if (options.timePicker) options.format = options.format + (options.format ? ' ' : '') + Locale.get('Date.shortTime'); + options.format = (options.pickOnly != 'time') ? Locale.get('Date.shortDate') : ''; + if (options.timePicker) options.format = (options.format) + (options.format ? ' ' : '') + Locale.get('Date.shortTime'); } // This is where we store the selected date From ebc4c411bdd737dcf68638872b5f07adedc75caa Mon Sep 17 00:00:00 2001 From: Arian Date: Tue, 9 Nov 2010 12:25:30 +0100 Subject: [PATCH 179/285] Improve the Position method where Chrome sometimes failed to get the right pickersize --- Source/Picker.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Source/Picker.js b/Source/Picker.js index fda128c..c2fc44c 100644 --- a/Source/Picker.js +++ b/Source/Picker.js @@ -64,8 +64,6 @@ var Picker = new Class({ var body = this.body = new Element('div.body').inject(picker); var bodysize = this.bodysize = body.getSize(); - - this.pickersize = picker.getSize(); picker.setStyle('display', 'none'); // oldContents and newContents are used to slide from the old content to a new one. @@ -182,22 +180,24 @@ var Picker = new Class({ : elementCoords.right y = elementCoords.top; } + var offset = this.options.positionOffset, scroll = document.getScroll(), size = document.getSize(), - pickersize = this.pickersize; + pickersize = this.picker.getSize(); - var position = { - left: x + offset.x, - top: y + offset.y - }; + x += offset.x; + y += offset.y; - if ((position.left + pickersize.x) > (size.x + scroll.x)) position.left = (size.x + scroll.x) - pickersize.x; - if ((position.top + pickersize.y) > (size.y + scroll.y)) position.top = (size.y + scroll.y) - pickersize.y; - if (position.left < 0) position.left = 0; - if (position.top < 0) position.top = 0; + if ((x + pickersize.x) > (size.x + scroll.x)) x = (size.x + scroll.x) - pickersize.x; + if ((y + pickersize.y) > (size.y + scroll.y)) y = (size.y + scroll.y) - pickersize.y; + if (x < 0) x = 0; + if (y < 0) y = 0; - this.picker.setStyles(position); + this.picker.setStyles({ + left: x, + top: y + }); if (this.shim) this.shim.position(); return this; }, From 40a5cdcaf46f32d8ddcb3a9fcfd774d367d49338 Mon Sep 17 00:00:00 2001 From: Arian Date: Tue, 9 Nov 2010 12:54:54 +0100 Subject: [PATCH 180/285] Another improvement for Chrome, where it set the body height to 0px sometimes --- Source/Picker.js | 54 ++++++++++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/Source/Picker.js b/Source/Picker.js index c2fc44c..c4cf730 100644 --- a/Source/Picker.js +++ b/Source/Picker.js @@ -40,7 +40,7 @@ var Picker = new Class({ var picker = this.picker = new Element('div', { 'class': options.pickerClass, - styles: {opacity: 0, left: 0, top: 0} + styles: {left: 0, top: 0} }).inject(options.inject || document.body); if (options.useFadeInOut){ @@ -63,17 +63,12 @@ var Picker = new Class({ // Build the body of the picker var body = this.body = new Element('div.body').inject(picker); - var bodysize = this.bodysize = body.getSize(); - picker.setStyle('display', 'none'); - // oldContents and newContents are used to slide from the old content to a new one. var slider = this.slider = new Element('div.slider', { styles: { position: 'absolute', top: 0, - left: 0, - width: 2 * bodysize.x, - height: bodysize.y + left: 0 } }).set('tween', { duration: options.animationDuration, @@ -83,10 +78,7 @@ var Picker = new Class({ this.oldContents = new Element('div', { styles: { position: 'absolute', - top: 0, - left: bodysize.x, - width: bodysize.x, - height: bodysize.y + top: 0 } }).inject(slider); @@ -94,9 +86,7 @@ var Picker = new Class({ styles: { position: 'absolute', top: 0, - left: 0, - width: bodysize.x, - height: bodysize.y + left: 0 } }).inject(slider); @@ -121,6 +111,11 @@ var Picker = new Class({ if (shim) shim.hide(); }, true); + // Hide the picker + picker.setStyles({ + display: 'none', + opacity: 0 + }); }, open: function(noFx){ @@ -171,21 +166,21 @@ var Picker = new Class({ }, position: function(x, y){ + var offset = this.options.positionOffset, + scroll = document.getScroll(), + size = document.getSize(), + pickersize = this.picker.getSize(); + if (typeOf(x) == 'element'){ var element = x, where = y || this.options.pickerPosition; var elementCoords = element.getCoordinates(); - x = (where == 'left') ? x = elementCoords.left - this.bodysize.x + x = (where == 'left') ? x = elementCoords.left - this.pickersize.x : elementCoords.right y = elementCoords.top; } - var offset = this.options.positionOffset, - scroll = document.getScroll(), - size = document.getSize(), - pickersize = this.picker.getSize(); - x += offset.x; y += offset.y; @@ -202,6 +197,23 @@ var Picker = new Class({ return this; }, + setBodySize: function(){ + var bodysize = this.bodysize = this.body.getSize(); + this.slider.setStyles({ + width: 2 * bodysize.x, + height: bodysize.y + }); + this.oldContents.setStyles({ + left: bodysize.x, + width: bodysize.x, + height: bodysize.y + }); + this.newContents.setStyles({ + width: bodysize.x, + height: bodysize.y + }); + }, + setContent: function(){ var content = Array.from(arguments), fx; @@ -218,6 +230,8 @@ var Picker = new Class({ if (['string', 'number'].contains(type)) this.newContents.set('text', content); else this.newContents.adopt(content); + this.setBodySize(); + if (fx){ this.fx(fx); } else { From d0907563963391022780905665b15f97064bdbab Mon Sep 17 00:00:00 2001 From: Arian Date: Tue, 9 Nov 2010 13:25:43 +0100 Subject: [PATCH 181/285] Be sure the `canAlwaysGoUp` option will get an array, even when it is set to false or null --- Source/Picker.Date.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Picker.Date.js b/Source/Picker.Date.js index 514496c..b2ea33a 100644 --- a/Source/Picker.Date.js +++ b/Source/Picker.Date.js @@ -60,6 +60,8 @@ this.DatePicker = Picker.Date = new Class({ } }); + options.canAlwaysGoUp = options.canAlwaysGoUp ? Array.from(options.canAlwaysGoUp) : []; + // Set the min and max dates as Date objects if (options.minDate && (!(options.minDate instanceof Date))){ options.minDate = Date.parse(options.minDate); From 6353c1592fbac1eb6f95ece457c6d07e0c3390e0 Mon Sep 17 00:00:00 2001 From: Arian Date: Tue, 9 Nov 2010 13:26:13 +0100 Subject: [PATCH 182/285] Add a Intro page for the tests, that will show them in a IFrame + some other nice new demos! --- Test/events.html | 61 ++++++++++++++++++++++++++++++++++++ Test/full.html | 43 ++++++++++++++++++++++++++ Test/index.html | 72 +++++++++++++++++++++++++++++++++++++++++++ Test/legacy.html | 5 ++- Test/monthpicker.html | 3 +- Test/picker.date.html | 3 +- Test/picker.html | 2 +- Test/themes.html | 70 +++++++++++++++++++++++++++++++++++++++++ Test/timepicker.html | 4 +-- 9 files changed, 254 insertions(+), 9 deletions(-) create mode 100644 Test/events.html create mode 100644 Test/full.html create mode 100644 Test/index.html create mode 100644 Test/themes.html diff --git a/Test/events.html b/Test/events.html new file mode 100644 index 0000000..1a4131f --- /dev/null +++ b/Test/events.html @@ -0,0 +1,61 @@ + + + + + DatePicker Events + + + + + + + + + + + + + + + + +

DatePicker Events

+ +

+ This shows the different Events DatePicker fires. You can use the onSelect event if you want to + display the selected date elsewhere for example. +

+ +
 
+ +

+ Inputs: + +

+ + + + \ No newline at end of file diff --git a/Test/full.html b/Test/full.html new file mode 100644 index 0000000..0dc18dd --- /dev/null +++ b/Test/full.html @@ -0,0 +1,43 @@ + + + + + Full Date and TimePicker + + + + + + + + + + + + + + +

Full Date and TimePicker

+ +

+ This is a demo of a all the pickers, including years, months, days and time.
+ You should begin at the days view, but you can click the title to go up to months and years.
+ If you've selected a day, you should see the timepicker. +

+ +

+ Inputs: + +

+ + + + \ No newline at end of file diff --git a/Test/index.html b/Test/index.html new file mode 100644 index 0000000..d7c2da4 --- /dev/null +++ b/Test/index.html @@ -0,0 +1,72 @@ + + + + + MooTools DatePicker + + + + + + + +
+ +

MooTools DatePicker Demos

+ +

+ Select one of the pickers you would like to see. The demo will load in the iframe. +

+ + + +
+ +
+ +
+ + + \ No newline at end of file diff --git a/Test/legacy.html b/Test/legacy.html index c7f8c77..207d430 100644 --- a/Test/legacy.html +++ b/Test/legacy.html @@ -1,11 +1,10 @@ - - + + MooTools Datepicker - diff --git a/Test/monthpicker.html b/Test/monthpicker.html index 2369800..bd8c727 100644 --- a/Test/monthpicker.html +++ b/Test/monthpicker.html @@ -17,7 +17,8 @@ window.addEvent('domready', function(){ myPicker = new Picker.Date($$('input'), { pickOnly: 'months', - format: '%B' + format: '%B', + canAlwaysGoUp: false }); }); diff --git a/Test/picker.date.html b/Test/picker.date.html index 4044a21..8dee092 100644 --- a/Test/picker.date.html +++ b/Test/picker.date.html @@ -18,8 +18,7 @@ myPicker = new Picker.Date($$('a.open, input'), { toggle: $$('.toggle'), - positionOffset: {x: -10, y: 20}, - timePickerOnly: true + positionOffset: {x: -10, y: 20} }); $('open').addEvent('click', function(e){ diff --git a/Test/picker.html b/Test/picker.html index c13cf14..689e61a 100644 --- a/Test/picker.html +++ b/Test/picker.html @@ -14,7 +14,7 @@ window.addEvent('domready', function(){ // sorry for the global, but this is easier debugging with the console! - myPicker = new Picker(); + myPicker = new Picker().position(200, 200); $('open').addEvent('click', function(e){ e.stop(); diff --git a/Test/themes.html b/Test/themes.html new file mode 100644 index 0000000..e198ac7 --- /dev/null +++ b/Test/themes.html @@ -0,0 +1,70 @@ + + + + + DatePicker Themes + + + + + + + + + + + + + + + + + +

DatePicker Themes

+ +

+ This demo shows you the current four supported themes. It is just a simple option of setting the picker classname to another CSS class. +

+ +

+ Dashboard:
+ +

+ +

+ jQuery UI:
+ +

+ + +

+ Vista:
+ +

+ +

+ Default:
+ +

+ + + \ No newline at end of file diff --git a/Test/timepicker.html b/Test/timepicker.html index ccd0469..5ea75ae 100644 --- a/Test/timepicker.html +++ b/Test/timepicker.html @@ -29,14 +29,14 @@

TimePicker

- This test shows a timepicker only. It should parse the current time (11:05 AM) and it should format it that way.
+ This test shows a timepicker only. It should parse the current time (11:05AM) and it should format it that way.
You should not be able to go up by clicking the picker title. The title should say a localized string "select a time"
You should be able to change the hours and minutes with your scrollweel. The minutes should go in steps of 5.

Inputs: - +

From eaccfee675658620523e7e883de653c9472169ef Mon Sep 17 00:00:00 2001 From: Arian Date: Tue, 9 Nov 2010 13:36:56 +0100 Subject: [PATCH 183/285] Add a Min/Max Date Demo --- Test/index.html | 1 + Test/minmaxdate.html | 50 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 Test/minmaxdate.html diff --git a/Test/index.html b/Test/index.html index d7c2da4..7f8df1c 100644 --- a/Test/index.html +++ b/Test/index.html @@ -49,6 +49,7 @@

MooTools DatePicker Demos

  • Month Picker
  • Year Picker
  • Localization
  • +
  • Min/Max Date option
  • DatePicker 1.6 tests
  • Standalone Picker
  • Picker with events
  • diff --git a/Test/minmaxdate.html b/Test/minmaxdate.html new file mode 100644 index 0000000..1b2f586 --- /dev/null +++ b/Test/minmaxdate.html @@ -0,0 +1,50 @@ + + + + + Min and Max Dates + + + + + + + + + + + + + + +

    Min and Max dates

    + +

    + This demo shows the minDate and maxDate options. You can set the to a certain date so the user + cannot select a date outside that limits. The limits are set to and . +

    + +

    + Input: + +

    + + + + \ No newline at end of file From c2d3a8fd2962d0c132bd09630a3af0e01798d252 Mon Sep 17 00:00:00 2001 From: arian Date: Tue, 9 Nov 2010 17:23:14 +0100 Subject: [PATCH 184/285] Remove the maxlength option of the Submit button of the timePicker --- Source/Picker.Date.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Source/Picker.Date.js b/Source/Picker.Date.js index b2ea33a..01be168 100644 --- a/Source/Picker.Date.js +++ b/Source/Picker.Date.js @@ -539,8 +539,7 @@ var renderers = { }); fn(date); }.bind(this) - }, - maxlength: 2 + } }).inject(container); return {content: container}; From be0c066c10fcf18a239c64238ed5d81ea97276c0 Mon Sep 17 00:00:00 2001 From: arian Date: Tue, 9 Nov 2010 18:26:29 +0100 Subject: [PATCH 185/285] Hide the Picker element right away, to prevent flickering --- Source/Picker.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Source/Picker.js b/Source/Picker.js index c4cf730..2314bdd 100644 --- a/Source/Picker.js +++ b/Source/Picker.js @@ -40,7 +40,12 @@ var Picker = new Class({ var picker = this.picker = new Element('div', { 'class': options.pickerClass, - styles: {left: 0, top: 0} + styles: { + left: 0, + top: 0, + display: 'none', + opacity: 0 + } }).inject(options.inject || document.body); if (options.useFadeInOut){ @@ -111,11 +116,6 @@ var Picker = new Class({ if (shim) shim.hide(); }, true); - // Hide the picker - picker.setStyles({ - display: 'none', - opacity: 0 - }); }, open: function(noFx){ From 0809972f2deea7e13d135c1a593314c950b6ad53 Mon Sep 17 00:00:00 2001 From: arian Date: Tue, 9 Nov 2010 18:29:10 +0100 Subject: [PATCH 186/285] Update the Test/Demos with a nice layout --- Test/events.html | 2 + Test/full.html | 8 ++- Test/index.html | 30 +++------ Test/legacy.html | 14 +---- Test/locale.html | 1 + Test/minmaxdate.html | 3 +- Test/monthpicker.html | 1 + Test/picker.attach.html | 1 + Test/picker.date.html | 1 + Test/picker.html | 1 + Test/style.css | 134 +++++++++++++++++++++------------------- Test/themes.html | 9 +-- Test/timepicker.html | 1 + Test/yearpicker.html | 1 + 14 files changed, 100 insertions(+), 107 deletions(-) diff --git a/Test/events.html b/Test/events.html index 1a4131f..6aa0aae 100644 --- a/Test/events.html +++ b/Test/events.html @@ -10,6 +10,7 @@ + + - +
    @@ -40,6 +19,9 @@

    MooTools DatePicker Demos

    +

    + You should be able to edit this text. The text of the above input fields + should not be editable.
    + +

    \ No newline at end of file From 42c3b8f1167cf9a7ab020778bfe8faac7f623d69 Mon Sep 17 00:00:00 2001 From: Arian Date: Sun, 24 Apr 2011 22:06:58 +0200 Subject: [PATCH 220/285] Fix some double defined variables, unused code, a typo and some tests --- Source/Picker.Date.js | 30 +++++++++++------------------- Test/locale.html | 4 +++- Test/select.html | 6 ++++-- 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/Source/Picker.Date.js b/Source/Picker.Date.js index fd0d2a4..aae7cd8 100644 --- a/Source/Picker.Date.js +++ b/Source/Picker.Date.js @@ -335,8 +335,7 @@ this.DatePicker = Picker.Date = new Class({ var renderers = { years: function(options, date, currentDate, fn){ - var limit = {left: false, right: false}, - container = new Element('div.years'), + var container = new Element('div.years'), today = new Date(), year, element, classes; @@ -360,12 +359,11 @@ var renderers = { months: function(options, date, currentDate, fn){ var today = new Date(), month = today.get('month'), - limit = {left: false, right: false}, thisyear = (date.get('year') == today.get('year')), selectedyear = (date.get('year') == currentDate.get('year')), container = new Element('div.months'), months = options.months_abbr || Locale.get('Date.months_abbr'), - elelement, classes; + element, classes; date.set('month', 0); if (options.minDate){ @@ -395,7 +393,6 @@ var renderers = { days: function(options, date, currentDate, fn){ var month = date.get('month'), - limit = {left: false, right: false}, todayString = new Date().toDateString(), currentString = currentDate.toDateString(), container = new Element('div.days'), @@ -521,13 +518,14 @@ var limitDate = function(date, min, max){ var isUnavailable = function(type, date, options){ var minDate = options.minDate, maxDate = options.maxDate, - availableDates = options.availableDates; + availableDates = options.availableDates, + year, month, day, ms; if (!minDate && !maxDate && !availableDates) return false; date.clearTime(); if (type == 'year'){ - var year = date.get('year'); + year = date.get('year'); return ( (minDate && year < minDate.get('year')) || (maxDate && year > maxDate.get('year')) || @@ -546,9 +544,9 @@ var isUnavailable = function(type, date, options){ } if (type == 'month'){ - var year = date.get('year'), - month = date.get('month') + 1, - ms = date.format('%Y%m').toInt(); + year = date.get('year'); + month = date.get('month') + 1; + ms = date.format('%Y%m').toInt(); return ( (minDate && ms < minDate.format('%Y%m').toInt()) || (maxDate && ms > maxDate.format('%Y%m').toInt()) || @@ -563,9 +561,9 @@ var isUnavailable = function(type, date, options){ } // type == 'date' - var year = date.get('year'), - month = date.get('month') + 1, - day = date.get('date'); + year = date.get('year'); + month = date.get('month') + 1; + day = date.get('date'); return ( (minDate && date < minDate) || (maxDate && date > maxDate) || @@ -579,10 +577,4 @@ var isUnavailable = function(type, date, options){ ); }; - -// Parse times -Date.defineParsers( - '%H:%M( ?%p)?' // "11:05pm", "11:05 am" and "11:05" -); - })(); diff --git a/Test/locale.html b/Test/locale.html index 6b4e2c5..9faa185 100644 --- a/Test/locale.html +++ b/Test/locale.html @@ -19,7 +19,9 @@ Locale.use('nl-NL'); window.addEvent('domready', function(){ - myPicker = new Picker.Date('locale'); + myPicker = new Picker.Date('locale', { + timePicker: true + }); myPicker2 = new Picker.Date('abbr', { months_abbr: ['ja', 'fe', 'ma', 'ap', 'me', 'jn', 'jl', 'au', 'ok', 'se', 'no', 'de'], diff --git a/Test/select.html b/Test/select.html index a6b1d5e..f91e5a5 100644 --- a/Test/select.html +++ b/Test/select.html @@ -24,8 +24,10 @@ format : '%b %d, %y' }); - $('click').addEvent('click',function(){ - pick.select(Date.parse('Nov 12, 12')); + $('click').addEvent('click',function(event){ + event.stop(); + var date = Date.parse('Nov 12, 2012'); + pick.select(date); }); }); From 1a442c317f13908b4855a2bf55389e69735b9d53 Mon Sep 17 00:00:00 2001 From: Arian Date: Sun, 24 Apr 2011 22:15:44 +0200 Subject: [PATCH 221/285] And... 2.0.3! --- package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.yml b/package.yml index 3d15639..c9405c7 100644 --- a/package.yml +++ b/package.yml @@ -1,6 +1,6 @@ name: MooTools-DatePicker author: astolwijk -current: 2.0.2 +current: 2.0.3 category: Widgets tags: [Datepicker, Calendar, Picker] demo: http://www.aryweb.nl/projects/mootools-datepicker/ From e1fe6f761363e75a842a9299e8ee9dd7c1b79531 Mon Sep 17 00:00:00 2001 From: Arian Date: Thu, 2 Jun 2011 12:59:20 +0200 Subject: [PATCH 222/285] 2.0.4! Improved closing/toggling behavior, fixes #48 --- Source/Picker.Attach.js | 21 +++++++++++---------- package.yml | 2 +- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Source/Picker.Attach.js b/Source/Picker.Attach.js index b445d1d..948496b 100644 --- a/Source/Picker.Attach.js +++ b/Source/Picker.Attach.js @@ -58,14 +58,15 @@ Picker.Attach = new Class({ self = this; var closeEvent = function(event){ - if (self.options.blockKeydown && event.type == 'keydown' && !(['tab', 'esc'].contains(event.key))){ - event.preventDefault(); - return; - } - if (event.target.get('tag') == 'a') event.stop(); - if (!(event.type == 'keydown' && !self.options.blockKeydown)){ - self.close(); - } + var stopInput = self.options.blockKeydown + && event.type == 'keydown' + && !(['tab', 'esc'].contains(event.key)), + isCloseKey = event.type == 'keydown' + && (['tab', 'esc'].contains(event.key)), + isA = event.target.get('tag') == 'a'; + + if (stopInput || isA) event.preventDefault(); + if (isCloseKey || isA) self.close(); }; var getOpenEvent = function(element){ @@ -84,7 +85,7 @@ Picker.Attach = new Class({ }; }; - allElements.each(function(element, i){ + allElements.each(function(element){ // The events are already attached! if (self.attachedElements.contains(element)) return; @@ -152,7 +153,7 @@ Picker.Attach = new Class({ destroy: function(){ this.detach(); - this.parent(); + return this.parent(); } }); diff --git a/package.yml b/package.yml index c9405c7..2cd1a5c 100644 --- a/package.yml +++ b/package.yml @@ -1,6 +1,6 @@ name: MooTools-DatePicker author: astolwijk -current: 2.0.3 +current: 2.0.4 category: Widgets tags: [Datepicker, Calendar, Picker] demo: http://www.aryweb.nl/projects/mootools-datepicker/ From 9a569c25c4a3ad6a6d10f229917ee6dc1bf0b115 Mon Sep 17 00:00:00 2001 From: Arian Date: Fri, 8 Jul 2011 14:06:09 +0100 Subject: [PATCH 223/285] Multi Column DatePicker! --- Source/Picker.Date.js | 172 +++++++++++++++++++++++++++--------------- Source/Picker.js | 62 ++++++++++++--- Source/datepicker.css | 48 +++++++++++- Test/columns.html | 39 ++++++++++ Test/index.html | 1 + Test/range.html | 53 +++++++++++++ 6 files changed, 301 insertions(+), 74 deletions(-) create mode 100644 Test/columns.html create mode 100644 Test/range.html diff --git a/Source/Picker.Date.js b/Source/Picker.Date.js index aae7cd8..f127e1b 100644 --- a/Source/Picker.Date.js +++ b/Source/Picker.Date.js @@ -41,14 +41,20 @@ this.DatePicker = Picker.Date = new Class({ months_abbr: null, days_abbr: null, years_title: function(date, options){ - var year = date.get('year'); - return year + '-' + (year + options.yearsPerPage - 1); + return Array.from(date).map(function(_date, i){ + var year = _date.get('year'); + return new Element('div.column', {text: year + '-' + (year + options.yearsPerPage - 1)}).addClass('column_' + (i + 1)); + }); }, months_title: function(date, options){ - return date.get('year'); + return Array.from(date).map(function(_date, i){ + return new Element('div.column', {text: _date.get('year')}).addClass('column_' + (i + 1)); + }); }, days_title: function(date, options){ - return date.format('%b %Y'); + return Array.from(date).map(function(_date, i){ + return new Element('div.column', {text: _date.format('%b %Y')}).addClass('column_' + (i + 1)); + }); }, time_title: function(date, options){ return (options.pickOnly == 'time') ? Locale.get('DatePicker.select_a_time') : date.format('%d %B, %Y'); @@ -129,12 +135,7 @@ this.DatePicker = Picker.Date = new Class({ // Start rendering the default view. this.currentView = options.startView; this.addEvent('open', function(){ - var view = this.currentView, - cap = view.capitalize(); - if (this['render' + cap]){ - this['render' + cap](this.date.clone()); - this.currentView = view; - } + this.setColumns(this.originalColumns); }.bind(this)); }, @@ -148,18 +149,18 @@ this.DatePicker = Picker.Date = new Class({ this.next = new Element('div.next[html=»]').inject(this.header); }, - hidePrevious: function($next, $show){ - this[$next ? 'next' : 'previous'].setStyle('display', $show ? 'block' : 'none'); + hidePrevious: function(_next, _show){ + this[_next ? 'next' : 'previous'].setStyle('display', _show ? 'block' : 'none'); return this; }, - showPrevious: function($next){ - return this.hidePrevious($next, true); + showPrevious: function(_next){ + return this.hidePrevious(_next, true); }, - setPreviousEvent: function(fn, $next){ - this[$next ? 'next' : 'previous'].removeEvents('click'); - if (fn) this[$next ? 'next' : 'previous'].addEvent('click', fn); + setPreviousEvent: function(fn, _next){ + this[_next ? 'next' : 'previous'].removeEvents('click'); + if (fn) this[_next ? 'next' : 'previous'].addEvent('click', fn); return this; }, @@ -175,26 +176,46 @@ this.DatePicker = Picker.Date = new Class({ return this.setPreviousEvent(fn, true); }, + setColumns: function(columns, tween, view, date, viewFx){ + var ret = this.parent(columns, tween), method; + + if ((view || this.currentView) + && (method = 'render' + (view || this.currentView).capitalize()) + && this[method] + ) this[method](date || this.date.clone(), viewFx); + + return ret; + }, + // Render the Pickers renderYears: function(date, fx){ - - var options = this.options; + var options = this.options, pages = options.columns, perPage = options.yearsPerPage, + _columns = [], _dates = []; // start neatly at interval (eg. 1980 instead of 1987) - while (date.get('year') % options.yearsPerPage > 0) date.decrement('year', 1); - - this.setTitle(options.years_title(date, options)); + date = date.clone().decrement('year', date.get('year') % perPage); + + var iterateDate = date.clone().decrement('year', Math.floor((pages - 1) / 2) * perPage); + + for (var i = pages; i--;){ + var _date = iterateDate.clone(); + _dates.push(_date); + _columns.push(renderers.years( + options, + _date.clone(), + this.date.clone(), + function(date){ + if (options.pickOnly == 'years') this.select(date); + else this.renderMonths(date, 'fade'); + this.date = date; + }.bind(this) + )); + iterateDate.increment('year', perPage); + } - this.setContent(renderers.years( - options, - date.clone(), - this.date.clone(), - function(date){ - if (options.pickOnly == 'years') this.select(date); - else this.renderMonths(date, 'fade'); - }.bind(this) - ), fx); + this.setColumnsContent(_columns, fx); + this.setTitle(options.years_title(_dates, options)); // Set limits var limitLeft = (options.minDate && date.get('year') <= options.minDate.get('year')), @@ -203,30 +224,41 @@ this.DatePicker = Picker.Date = new Class({ this[(limitRight ? 'hide' : 'show') + 'Next'](); this.setPreviousEvent(function(){ - this.renderYears(date.decrement('year', options.yearsPerPage), 'left'); + this.renderYears(date.decrement('year', perPage), 'left'); }.bind(this)); this.setNextEvent(function(){ - this.renderYears(date.increment('year', options.yearsPerPage), 'right'); + this.renderYears(date.increment('year', perPage), 'right'); }.bind(this)); // We can't go up! this.setTitleEvent(null); + + this.currentView = 'years'; }, renderMonths: function(date, fx){ - var options = this.options; - this.setTitle(options.months_title(date, options)); + var options = this.options, years = options.columns, _columns = [], _dates = [], + iterateDate = date.clone().decrement('year', Math.floor((years - 1) / 2)); + + for (var i = years; i--;){ + var _date = iterateDate.clone(); + _dates.push(_date); + _columns.push(renderers.months( + options, + _date.clone(), + this.date.clone(), + function(date){ + if (options.pickOnly == 'months') this.select(date); + else this.renderDays(date, 'fade'); + this.date = date; + }.bind(this) + )); + iterateDate.increment('year', 1); + } - this.setContent(renderers.months( - options, - date.clone(), - this.date.clone(), - function(date){ - if (options.pickOnly == 'months') this.select(date); - else this.renderDays(date, 'fade'); - }.bind(this) - ), fx); + this.setColumnsContent(_columns, fx); + this.setTitle(options.months_title(_dates, options)); // Set limits var year = date.get('year'), @@ -236,11 +268,11 @@ this.DatePicker = Picker.Date = new Class({ this[(limitRight ? 'hide' : 'show') + 'Next'](); this.setPreviousEvent(function(){ - this.renderMonths(date.decrement('year', 1), 'left'); + this.renderMonths(date.decrement('year', years), 'left'); }.bind(this)); this.setNextEvent(function(){ - this.renderMonths(date.increment('year', 1), 'right'); + this.renderMonths(date.increment('year', years), 'right'); }.bind(this)); var canGoUp = options.yearPicker && (options.pickOnly != 'months' || options.canAlwaysGoUp.contains('months')); @@ -248,21 +280,32 @@ this.DatePicker = Picker.Date = new Class({ this.renderYears(date, 'fade'); }.bind(this) : null; this.setTitleEvent(titleEvent); + + this.currentView = 'months'; }, renderDays: function(date, fx){ - var options = this.options; - this.setTitle(options.days_title(date, options)); + var options = this.options, months = options.columns, _columns = [], _dates = [], + iterateDate = date.clone().decrement('month', Math.floor((months - 1) / 2)); + + for (var i = months; i--;){ + _date = iterateDate.clone(); + _dates.push(_date); + _columns.push(renderers.days( + options, + _date.clone(), + this.date.clone(), + function(date){ + if (options.pickOnly == 'days' || !options.timePicker) this.select(date) + else this.renderTime(date, 'fade'); + this.date = date; + }.bind(this) + )); + iterateDate.increment('month', 1); + } - this.setContent(renderers.days( - options, - date.clone(), - this.date.clone(), - function(date){ - if (options.pickOnly == 'days' || !options.timePicker) this.select(date) - else this.renderTime(date, 'fade'); - }.bind(this) - ), fx); + this.setColumnsContent(_columns, fx); + this.setTitle(options.days_title(_dates, options)); var yearmonth = date.format('%Y%m').toInt(), limitLeft = (options.minDate && yearmonth <= options.minDate.format('%Y%m')), @@ -271,11 +314,11 @@ this.DatePicker = Picker.Date = new Class({ this[(limitRight ? 'hide' : 'show') + 'Next'](); this.setPreviousEvent(function(){ - this.renderDays(date.decrement('month', 1), 'left'); + this.renderDays(date.decrement('month', months), 'left'); }.bind(this)); this.setNextEvent(function(){ - this.renderDays(date.increment('month', 1), 'right'); + this.renderDays(date.increment('month', months), 'right'); }.bind(this)); var canGoUp = options.pickOnly != 'days' || options.canAlwaysGoUp.contains('days'); @@ -283,12 +326,18 @@ this.DatePicker = Picker.Date = new Class({ this.renderMonths(date, 'fade'); }.bind(this) : null; this.setTitleEvent(titleEvent); + + this.currentView = 'days'; }, renderTime: function(date, fx){ var options = this.options; this.setTitle(options.time_title(date, options)); + var originalColumns = this.originalColumns = options.columns; + this.currentView = null; // otherwise you'd get crazy recursion + this.setColumns(1, true); + this.setContent(renderers.time( options, date.clone(), @@ -306,9 +355,11 @@ this.DatePicker = Picker.Date = new Class({ var canGoUp = options.pickOnly != 'time' || options.canAlwaysGoUp.contains('time'); var titleEvent = (canGoUp) ? function(){ - this.renderDays(date, 'fade'); + this.setColumns(originalColumns, true, 'days', date, 'fade'); }.bind(this) : null; this.setTitleEvent(titleEvent); + + this.currentView = 'time'; }, select: function(date, all){ @@ -508,7 +559,6 @@ Picker.Date.defineRenderer = function(name, fn){ return this; }; - var limitDate = function(date, min, max){ if (min && date < min) return min; if (max && date > max) return max; diff --git a/Source/Picker.js b/Source/Picker.js index bea0eac..08bc66d 100644 --- a/Source/Picker.js +++ b/Source/Picker.js @@ -26,7 +26,8 @@ var Picker = new Class({ positionOffset: {x: 0, y: 0}, pickerPosition: 'bottom', draggable: true, - showOnInit: true + showOnInit: true, + columns: 1 }, initialize: function(options){ @@ -47,6 +48,7 @@ var Picker = new Class({ opacity: 0 } }).inject(options.inject || document.body); + picker.addClass('column_' + options.columns); if (options.useFadeInOut){ picker.set('tween', { @@ -95,6 +97,9 @@ var Picker = new Class({ } }).inject(slider); + this.originalColumns = options.columns; + this.setColumns(options.columns); + // IFrameShim for select fields in IE var shim = this.shim = window['IframeShim'] ? new IframeShim(picker) : null; @@ -203,6 +208,7 @@ var Picker = new Class({ setBodySize: function(){ var bodysize = this.bodysize = this.body.getSize(); + this.slider.setStyles({ width: 2 * bodysize.x, height: bodysize.y @@ -218,11 +224,50 @@ var Picker = new Class({ }); }, - setContent: function(){ - var content = Array.from(arguments), fx; + setColumnContent: function(column, content){ + var columnElement = this.columns[column]; + if (!columnElement) return this; + + var type = typeOf(content); + if (['string', 'number'].contains(type)) columnElement.set('text', content); + else columnElement.empty().adopt(content); + + return this; + }, + + setColumnsContent: function(content, fx){ + var old = this.columns; + this.columns = this.newColumns; + this.newColumns = old; + + content.forEach(function(_content, i){ + this.setColumnContent(i, _content); + }, this); + return this.setContent(null, fx); + }, + + setColumns: function(columns, tween){ - if (['right', 'left', 'fade'].contains(content[1])) fx = content[1]; - if (content.length == 1 || fx) content = content[0]; + var _columns = this.columns = new Elements, _newColumns = this.newColumns = new Elements; + for (var i = columns; i--;){ + _columns.push(new Element('div.column').addClass('column_' + (columns - i))); + _newColumns.push(new Element('div.column').addClass('column_' + (columns - i))); + } + + var oldClass = 'column_' + this.options.columns, newClass = 'column_' + columns; + var picker = this.picker.setStyle('width', null).removeClass(oldClass).addClass(newClass); + if (tween){ + var newWidth = picker.getStyle('width'); + picker.removeClass(newClass).addClass(oldClass); + picker.tween('width', newWidth); + picker.removeClass(oldClass).addClass(newClass); + } + this.options.columns = columns; + return this; + }, + + setContent: function(content, fx){ + if (content) return this.setColumnsContent([content], fx); // swap contents so we can fill the newContents again and animate var old = this.oldContents; @@ -230,9 +275,7 @@ var Picker = new Class({ this.newContents = old; this.newContents.empty(); - var type = typeOf(content); - if (['string', 'number'].contains(type)) this.newContents.set('text', content); - else this.newContents.adopt(content); + this.newContents.adopt(this.columns); this.setBodySize(); @@ -277,7 +320,8 @@ var Picker = new Class({ }, setTitle: function(text){ - this.titleText.set('text', text); + if (!(/(elements|array)/.test(typeOf(text)))) text = new Element('div.column', {text: text}).addClass('column_1'); + this.titleText.empty().adopt(text); return this; }, diff --git a/Source/datepicker.css b/Source/datepicker.css index fcfaae9..b37de10 100644 --- a/Source/datepicker.css +++ b/Source/datepicker.css @@ -10,6 +10,22 @@ z-index: 3003; } +.datepicker.column_2 { + width: 393px; +} + +.datepicker.column_3 { + width: 592px; +} + +.datepicker.column_4 { + width: 791px; +} + +.datepicker.column_5 { + width: 990px; +} + /* header ********************************************************/ .datepicker .header { @@ -18,17 +34,19 @@ height: 21px; padding-top: 4px; margin-bottom: 3px; + overflow: hidden; } .datepicker .header .title { text-align: center; padding-top: 1px; - margin: 0px 42px 0 20px; + position: absolute; + color: #fff; + font-weight: bold; + width: 99999px; } .datepicker .header .titleText { - color: #fff; - font-weight: bold; } .datepicker .header .next, .datepicker .header .previous, @@ -58,12 +76,34 @@ position: relative; top: 0px; left: 0px; - width: 194px; border-right: 2px solid #fff; height: 193px; overflow: hidden; } +/* Columns */ + +.datepicker .body .column { + float: left; + width: 194px; + min-height: 193px; + margin-left: 5px; +} + +.datepicker .body .column.column_1 { + margin-left: 0; +} + +.datepicker .titleText .column { + float: left; + width: 194px; + margin-left: 5px; +} + +.datepicker .titleText .column.column_1 { + margin-left: 0; +} + /* time ********************************************************/ .datepicker .time { diff --git a/Test/columns.html b/Test/columns.html new file mode 100644 index 0000000..136f9e6 --- /dev/null +++ b/Test/columns.html @@ -0,0 +1,39 @@ + + + + + Full Date and TimePicker + + + + + + + + + + + + + + + + +

    Multiple Columns

    + +

    + Inputs:
    + +

    + + + + + diff --git a/Test/index.html b/Test/index.html index da94679..11f289b 100644 --- a/Test/index.html +++ b/Test/index.html @@ -25,6 +25,7 @@

    Demos & Tests

    • Full Date and Time Picker
    • DatePicker Themes
    • +
    • Multiple Columns
    • DatePicker Events
    • Date Picker
    • Time Picker
    • diff --git a/Test/range.html b/Test/range.html new file mode 100644 index 0000000..afa25ba --- /dev/null +++ b/Test/range.html @@ -0,0 +1,53 @@ + + + + + Full Date and TimePicker + + + + + + + + + + + + + + + + + +

      Multiv

      + +

      + This is a demo of a all the pickers, including years, months, days and time.
      + You should begin at the days view, but you can click the title to go up to months and years.
      + If you've selected a day, you should see the timepicker. +

      + +

      + Inputs:
      + +

      + +

      + Empty default value:
      + +

      + + + \ No newline at end of file From fd15f5876f98be2bb0aa6380aa5ab2dfcd267d28 Mon Sep 17 00:00:00 2001 From: Arian Date: Fri, 8 Jul 2011 15:01:15 +0100 Subject: [PATCH 224/285] Prevent the Picker from fireing the onAttachedEvent twice when clicking an input --- Source/Picker.Attach.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Source/Picker.Attach.js b/Source/Picker.Attach.js index 948496b..88a3a45 100644 --- a/Source/Picker.Attach.js +++ b/Source/Picker.Attach.js @@ -71,7 +71,9 @@ Picker.Attach = new Class({ var getOpenEvent = function(element){ return function(event){ - if (event.target.get('tag') == 'a') event.stop(); + var tag = event.target.get('tag'); + if (tag == 'input' && event.type == 'click') return; + if (tag == 'a') event.stop(); self.fireEvent('attachedEvent', [event, element]); self.position(element); self.open(); From ad32f13a8d295dfdc5870d2f4a77de6a58c72230 Mon Sep 17 00:00:00 2001 From: Arian Date: Fri, 8 Jul 2011 15:08:19 +0100 Subject: [PATCH 225/285] Fix Close Button --- Source/Picker.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Picker.js b/Source/Picker.js index 08bc66d..bb20099 100644 --- a/Source/Picker.js +++ b/Source/Picker.js @@ -60,13 +60,13 @@ var Picker = new Class({ // Build the header var header = this.header = new Element('div.header').inject(picker); + var title = this.title = new Element('div.title').inject(header); + this.titleText = new Element('div.titleText').inject(title); + this.closeButton = new Element('div.closeButton[text=x]') .addEvent('click', this.close.pass(false, this)) .inject(header); - var title = this.title = new Element('div.title').inject(header); - this.titleText = new Element('div.titleText').inject(title); - // Build the body of the picker var body = this.body = new Element('div.body').inject(picker); From 843f64a47d54f729699e4da6053f51352aa838de Mon Sep 17 00:00:00 2001 From: Arian Date: Fri, 8 Jul 2011 17:51:03 +0100 Subject: [PATCH 226/285] Add Possibility to add a footer --- Source/Picker.js | 8 +++++++- Source/datepicker.css | 16 ++++++++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/Source/Picker.js b/Source/Picker.js index bb20099..68ef766 100644 --- a/Source/Picker.js +++ b/Source/Picker.js @@ -27,7 +27,8 @@ var Picker = new Class({ pickerPosition: 'bottom', draggable: true, showOnInit: true, - columns: 1 + columns: 1, + footer: false }, initialize: function(options){ @@ -70,6 +71,11 @@ var Picker = new Class({ // Build the body of the picker var body = this.body = new Element('div.body').inject(picker); + if (options.footer){ + this.footer = new Element('div.footer').inject(picker); + picker.addClass('footer'); + } + // oldContents and newContents are used to slide from the old content to a new one. var slider = this.slider = new Element('div.slider', { styles: { diff --git a/Source/datepicker.css b/Source/datepicker.css index b37de10..98e2ca8 100644 --- a/Source/datepicker.css +++ b/Source/datepicker.css @@ -76,7 +76,6 @@ position: relative; top: 0px; left: 0px; - border-right: 2px solid #fff; height: 193px; overflow: hidden; } @@ -104,6 +103,19 @@ margin-left: 0; } +/* Footer */ + +.datepicker.footer { + height: 280px; +} + +.datepicker .footer { + margin-top: 3px; + padding: 15px 5px; + height: 26px; + +} + /* time ********************************************************/ .datepicker .time { @@ -260,4 +272,4 @@ .datepicker .years .year:hover { background: #5D6E95 !important; color: #fff !important; -} \ No newline at end of file +} From 61ccc95a07291bd4934487a2f5424b2db9bbaa73 Mon Sep 17 00:00:00 2001 From: Arian Date: Fri, 8 Jul 2011 17:52:43 +0100 Subject: [PATCH 227/285] Split the renderers into the selected dates and the actual DOM operations --- Source/Picker.Date.js | 134 +++++++++++++++++++++++------------------- 1 file changed, 74 insertions(+), 60 deletions(-) diff --git a/Source/Picker.Date.js b/Source/Picker.Date.js index f127e1b..4cf32c8 100644 --- a/Source/Picker.Date.js +++ b/Source/Picker.Date.js @@ -83,11 +83,7 @@ this.DatePicker = Picker.Date = new Class({ // backward compatibility for startView var newViews = ['days', 'months', 'years']; ['month', 'year', 'decades'].some(function(what, i){ - if (options.startView == what){ - options.startView = newViews[i]; - return true; - } - return false; + return (options.startView == what) && (options.startView = newViews[i]); }); options.canAlwaysGoUp = options.canAlwaysGoUp ? Array.from(options.canAlwaysGoUp) : []; @@ -113,21 +109,12 @@ this.DatePicker = Picker.Date = new Class({ // Some link or input has fired an event! this.addEvent('attachedEvent', function(event, element){ var tag = element.get('tag'), input; - if (tag == 'input'){ - input = element; - } else { + if (tag == 'input') input = element; + else { var index = this.toggles.indexOf(element); if (this.inputs[index]) input = this.inputs[index]; } - this.date = new Date(); - if (input){ - var date = Date.parse(input.get('value')); - if (date == null || !date.isValid()){ - var storeDate = input.retrieve('datepicker:value'); - if (storeDate) date = Date.parse(storeDate); - } - if (date != null && date.isValid()) this.date = date; - } + this.getInputDate(input); this.input = input; }.bind(this), true); @@ -140,6 +127,17 @@ this.DatePicker = Picker.Date = new Class({ }, + getInputDate: function(input){ + this.date = new Date(); + if (!input) return; + var date = Date.parse(input.get('value')); + if (date == null || !date.isValid()){ + var storeDate = input.retrieve('datepicker:value'); + if (storeDate) date = Date.parse(storeDate); + } + if (date != null && date.isValid()) this.date = date; + }, + // Control the previous and next elements constructPicker: function(){ @@ -202,8 +200,8 @@ this.DatePicker = Picker.Date = new Class({ var _date = iterateDate.clone(); _dates.push(_date); _columns.push(renderers.years( + timesSelectors.years(options, _date.clone()), options, - _date.clone(), this.date.clone(), function(date){ if (options.pickOnly == 'years') this.select(date); @@ -245,8 +243,8 @@ this.DatePicker = Picker.Date = new Class({ var _date = iterateDate.clone(); _dates.push(_date); _columns.push(renderers.months( + timesSelectors.months(options, _date.clone()), options, - _date.clone(), this.date.clone(), function(date){ if (options.pickOnly == 'months') this.select(date); @@ -292,8 +290,8 @@ this.DatePicker = Picker.Date = new Class({ _date = iterateDate.clone(); _dates.push(_date); _columns.push(renderers.days( + timesSelectors.days(options, _date.clone()), options, - _date.clone(), this.date.clone(), function(date){ if (options.pickOnly == 'days' || !options.timePicker) this.select(date) @@ -383,15 +381,48 @@ this.DatePicker = Picker.Date = new Class({ // Renderers only output elements and calculate the limits! +var timesSelectors = { + + years: function(options, date){ + var times = []; + for (var i = 0; i < options.yearsPerPage; i++){ + times.push(+date); + date.increment('year', 1); + } + return times; + }, + + months: function(options, date){ + var times = []; + date.set('month', 0); + for (var i = 0; i <= 11; i++){ + times.push(+date); + date.increment('month', 1); + } + return times; + }, + + days: function(options, date){ + var times = []; + date.set('date', 1); + while (date.get('day') != options.startDay) date.set('date', date.get('date') - 1); + for (var i = 0; i < 42; i++){ + times.push(+date); + date.increment('day', 1); + } + return times; + } + +}; + var renderers = { - years: function(options, date, currentDate, fn){ + years: function(years, options, currentDate, fn){ var container = new Element('div.years'), - today = new Date(), - year, element, classes; + today = new Date(), element, classes; - for (var i = 0; i < options.yearsPerPage; i++){ - year = date.get('year'); + years.each(function(_year, i){ + var date = new Date(_year), year = date.get('year'); classes = '.year.year' + i; if (year == today.get('year')) classes += '.today'; @@ -399,51 +430,38 @@ var renderers = { element = new Element('div' + classes, {text: year}).inject(container); if (isUnavailable('year', date, options)) element.addClass('unavailable'); - else element.addEvent('click', fn.pass(date.clone())); - - date.increment('year', 1); - } + else element.addEvent('click', fn.pass(date)); + }); return container; }, - months: function(options, date, currentDate, fn){ + months: function(months, options, currentDate, fn){ var today = new Date(), month = today.get('month'), - thisyear = (date.get('year') == today.get('year')), - selectedyear = (date.get('year') == currentDate.get('year')), + thisyear = today.get('year'), + selectedyear = currentDate.get('year'), container = new Element('div.months'), - months = options.months_abbr || Locale.get('Date.months_abbr'), + monthsAbbr = options.months_abbr || Locale.get('Date.months_abbr'), element, classes; - date.set('month', 0); - if (options.minDate){ - date.decrement('month', 1); - date.set('date', date.get('lastdayofmonth')); - date.increment('month', 1); - } - - date.set('date', date.get('lastdayofmonth')); - - for (var i = 0; i <= 11; i++){ + months.each(function(_month, i){ + var date = new Date(_month), year = date.get('year'); classes = '.month.month' + (i + 1); - if (i == month && thisyear) classes += '.today'; - if (i == currentDate.get('month') && selectedyear) classes += '.selected'; - element = new Element('div' + classes, {text: months[i]}).inject(container); + if (i == month && year == thisyear) classes += '.today'; + if (i == currentDate.get('month') && year == selectedyear) classes += '.selected'; + element = new Element('div' + classes, {text: monthsAbbr[i]}).inject(container); if (isUnavailable('month', date, options)) element.addClass('unavailable'); - else element.addEvent('click', fn.pass(date.clone())); - - date.increment('month', 1); - date.set('date', date.get('lastdayofmonth')); - } + else element.addEvent('click', fn.pass(date)); + }); return container; }, - days: function(options, date, currentDate, fn){ - var month = date.get('month'), + days: function(days, options, currentDate, fn){ + var month = new Date(days[14]).get('month'), todayString = new Date().toDateString(), currentString = currentDate.toDateString(), container = new Element('div.days'), @@ -451,16 +469,14 @@ var renderers = { localeDaysShort = options.days_abbr || Locale.get('Date.days_abbr'), day, classes, element, weekcontainer, dateString; - date.setDate(1); - while (date.getDay() != options.startDay) date.setDate(date.getDate() - 1); - for (day = options.startDay; day < (options.startDay + 7); day++){ new Element('div.title.day.day' + (day % 7), { text: localeDaysShort[(day % 7)] }).inject(titles); } - for (var i = 0; i < 42; i++){ + days.each(function(_date, i){ + var date = new Date(_date); if (i % 7 == 0){ weekcontainer = new Element('div.week.week' + (Math.floor(i / 7))).inject(container); @@ -476,9 +492,7 @@ var renderers = { if (isUnavailable('date', date, options)) element.addClass('unavailable'); else element.addEvent('click', fn.pass(date.clone())); - - date.increment('day', 1); - } + }); return container; }, From 716491bc2ba937a4446257cb24289cfcdfcb71a5 Mon Sep 17 00:00:00 2001 From: Arian Date: Fri, 8 Jul 2011 17:53:08 +0100 Subject: [PATCH 228/285] Initial start for Picker.Date.Range --- Source/Locale.en-US.DatePicker.js | 3 +- Source/Locale.nl-NL.DatePicker.js | 3 +- Source/Picker.Date.Range.js | 126 ++++++++++++++++++++++++++++++ Test/range.html | 49 ++++++------ Test/style.css | 3 +- 5 files changed, 154 insertions(+), 30 deletions(-) create mode 100644 Source/Picker.Date.Range.js diff --git a/Source/Locale.en-US.DatePicker.js b/Source/Locale.en-US.DatePicker.js index 26e72e6..64db73c 100644 --- a/Source/Locale.en-US.DatePicker.js +++ b/Source/Locale.en-US.DatePicker.js @@ -12,5 +12,6 @@ provides: Locale.en-US.DatePicker Locale.define('en-US', 'DatePicker', { select_a_time: 'Select a time', use_mouse_wheel: 'Use the mouse wheel to quickly change value', - time_confirm_button: 'OK' + time_confirm_button: 'OK', + apply_range: 'Apply' }); diff --git a/Source/Locale.nl-NL.DatePicker.js b/Source/Locale.nl-NL.DatePicker.js index 3e5f69e..f77e3fa 100644 --- a/Source/Locale.nl-NL.DatePicker.js +++ b/Source/Locale.nl-NL.DatePicker.js @@ -12,5 +12,6 @@ provides: Locale.nl-NL.DatePicker Locale.define('nl-NL', 'DatePicker', { select_a_time: 'Selecteer een tijd', use_mouse_wheel: 'Gebruik uw scrollwiel om door de tijd te scrollen', - time_confirm_button: 'OK' + time_confirm_button: 'OK', + apply_range: 'OK' }); diff --git a/Source/Picker.Date.Range.js b/Source/Picker.Date.Range.js new file mode 100644 index 0000000..e26e832 --- /dev/null +++ b/Source/Picker.Date.Range.js @@ -0,0 +1,126 @@ +/* +--- +name: Picker.Date.Range +description: Select a Range of Dates +authors: Arian Stolwijk +requires: [Picker, Picker.Date] +provides: Picker.Date.Range +... +*/ + +Picker.Date.Range = new Class({ + + Extends: Picker.Date, + + options: { + getStartEndDate: function(input){ + return input.get('value').split('-').map(function(date){ + var parsed = Date.parse(date); + return parsed.isValid() ? parsed : null; + }).clean(); + }, + setStartEndDate: function(input, dates){ + input.set('value', dates.join(' - ')); + }, + footer: true + }, + + getInputDate: function(input){ + this.date = new Date(); + if (!input) return; + + var dates = input.retrieve('datepicker:value'); + if (!dates || !dates.every(function(date){ + return Date.isValid(date); + })){ + + dates = this.options.getStartEndDate(input); + if (!dates.every(function(date){ + return Date.isValid(date); + })) dates = [new Date]; + + } + + if (dates.length == 1) this.date = dates[0]; + else if (dates.length == 2){ + + this.date = new Date((+dates[0] + +dates[1]) / 2); + + this.startDate = dates[0]; + this.endDate = dates[1]; + + } + }, + + constructPicker: function(){ + this.parent(); + var footer = this.footer, self = this; + if (!footer) return; + + var startInput = this.startInput = new Element('input', {events: { + click: function(){ + startInput.focus(); + }, + blur: self.updateRangeSelection + }}).inject(footer); + + new Element('span', {text: ' - '}); + + var endInput = this.endInput = new Element('input', {events: { + click: function(){ + endInput.focus(); + }, + blur: self.updateRangeSelection + }}).inject(footer); + + var apply = this.applyButton = new Element('button', { + text: Locale.get('DatePicker.apply_range'), + events: {click: function(){ + console.log('yo'); + self.selectRange(); + }} + }).inject(footer); + + }, + + select: function(date){ + if (this.startDate && !this.endDate && date > this.startDate) this.endDate = date; + else { + this.startDate = date; + this.endDate = null; + } + + var formattedFirst = this.startDate.format(this.options.format) + formattedEnd = this.endDate && this.endDate.format(this.options.format) || ''; + + this.startInput.set('value', formattedFirst); + this.endInput.set('value', formattedEnd); + }, + + selectRange: function(){ + this.date = this.startDate; + + var dates = [this.startDate, this.endDate], input = this.input; + + input.store('datepicker:value', dates.map(function(date){ + return date.strftime(); + })); + + this.options.setStartEndDate(input, [ + this.startInput.get('value'), + this.endInput.get('value') + ]); + + this.fireEvent('select', dates); + this.close(); + input.blur(); + return this; + }, + + updateRangeSelection: function(){ + + } + +}); + + diff --git a/Test/range.html b/Test/range.html index afa25ba..952584f 100644 --- a/Test/range.html +++ b/Test/range.html @@ -9,45 +9,40 @@ - + - - - + -

      Multiv

      - -

      - This is a demo of a all the pickers, including years, months, days and time.
      - You should begin at the days view, but you can click the title to go up to months and years.
      - If you've selected a day, you should see the timepicker. -

      +

      Range

      Inputs:
      - +

      -

      - Empty default value:
      - -

      + + \ No newline at end of file diff --git a/Test/style.css b/Test/style.css index bf431ba..033e729 100644 --- a/Test/style.css +++ b/Test/style.css @@ -9,12 +9,13 @@ body { font-family: Tahoma,Geneva,Kalimati,sans-serif; font-size: 0.8em; - padding: 0; + padding: 20px; margin: 0; } body.viewer { background: #EEE; + padding: 0; } ::selection { From 4e1b23d08a02cb462d9198b8c42a771afd3504ee Mon Sep 17 00:00:00 2001 From: Arian Date: Mon, 11 Jul 2011 12:23:08 +0100 Subject: [PATCH 229/285] Picker.Date.Range: Select all dates in the selected range by adding a CSS class --- Source/Picker.Date.Range.js | 50 +++++++++++++++++++++++++------------ Source/Picker.Date.js | 22 +++++++++++----- Source/datepicker.css | 4 +++ Test/range.html | 3 ++- 4 files changed, 56 insertions(+), 23 deletions(-) diff --git a/Source/Picker.Date.Range.js b/Source/Picker.Date.Range.js index e26e832..1ce77e1 100644 --- a/Source/Picker.Date.Range.js +++ b/Source/Picker.Date.Range.js @@ -41,7 +41,7 @@ Picker.Date.Range = new Class({ } - if (dates.length == 1) this.date = dates[0]; + if (dates.length == 1) this.date = this.startDate = this.endDate = dates[0]; else if (dates.length == 2){ this.date = new Date((+dates[0] + +dates[1]) / 2); @@ -57,32 +57,39 @@ Picker.Date.Range = new Class({ var footer = this.footer, self = this; if (!footer) return; - var startInput = this.startInput = new Element('input', {events: { + var events = { + blur: self.updateRangeSelection.pass([], self), + keydown: function(event){ + if (event.key == 'enter') self.selectRange(); + } + }; + + var startInput = this.startInput = new Element('input', {events: Object.merge(events, { click: function(){ startInput.focus(); - }, - blur: self.updateRangeSelection - }}).inject(footer); + } + })}).inject(footer); new Element('span', {text: ' - '}); - var endInput = this.endInput = new Element('input', {events: { + var endInput = this.endInput = new Element('input', {events: Object.merge(events, { click: function(){ endInput.focus(); - }, - blur: self.updateRangeSelection - }}).inject(footer); + } + })}).inject(footer); - var apply = this.applyButton = new Element('button', { + this.applyButton = new Element('button', { text: Locale.get('DatePicker.apply_range'), - events: {click: function(){ - console.log('yo'); - self.selectRange(); - }} + events: {click: self.selectRange.pass([], self)} }).inject(footer); }, + renderDays: function(){ + this.parent.apply(this, arguments); + this.updateRangeSelection(); + }, + select: function(date){ if (this.startDate && !this.endDate && date > this.startDate) this.endDate = date; else { @@ -95,6 +102,8 @@ Picker.Date.Range = new Class({ this.startInput.set('value', formattedFirst); this.endInput.set('value', formattedEnd); + + this.updateRangeSelection(this.startDate, this.endDate); }, selectRange: function(){ @@ -117,8 +126,17 @@ Picker.Date.Range = new Class({ return this; }, - updateRangeSelection: function(){ - + updateRangeSelection: function(start, end){ + if (!start) start = ((start = Date.parse(this.startInput.get('value'))) && start.isValid() && start) || this.startDate; + if (!end) end = ((end = Date.parse(this.endInput.get('value'))) && end.isValid() && end) || this.endDate || start; + + if (this.dateElements) for (var i = this.dateElements.length; i--;){ + var el = this.dateElements[i]; + if (el.time >= start && el.time <= end) el.element.addClass('selected'); + else el.element.removeClass('selected'); + } + + return this; } }); diff --git a/Source/Picker.Date.js b/Source/Picker.Date.js index 4cf32c8..1b82ebc 100644 --- a/Source/Picker.Date.js +++ b/Source/Picker.Date.js @@ -190,6 +190,7 @@ this.DatePicker = Picker.Date = new Class({ renderYears: function(date, fx){ var options = this.options, pages = options.columns, perPage = options.yearsPerPage, _columns = [], _dates = []; + this.dateElements = []; // start neatly at interval (eg. 1980 instead of 1987) date = date.clone().decrement('year', date.get('year') % perPage); @@ -203,6 +204,7 @@ this.DatePicker = Picker.Date = new Class({ timesSelectors.years(options, _date.clone()), options, this.date.clone(), + this.dateElements, function(date){ if (options.pickOnly == 'years') this.select(date); else this.renderMonths(date, 'fade'); @@ -238,6 +240,7 @@ this.DatePicker = Picker.Date = new Class({ renderMonths: function(date, fx){ var options = this.options, years = options.columns, _columns = [], _dates = [], iterateDate = date.clone().decrement('year', Math.floor((years - 1) / 2)); + this.dateElements = []; for (var i = years; i--;){ var _date = iterateDate.clone(); @@ -246,6 +249,7 @@ this.DatePicker = Picker.Date = new Class({ timesSelectors.months(options, _date.clone()), options, this.date.clone(), + this.dateElements, function(date){ if (options.pickOnly == 'months') this.select(date); else this.renderDays(date, 'fade'); @@ -285,6 +289,7 @@ this.DatePicker = Picker.Date = new Class({ renderDays: function(date, fx){ var options = this.options, months = options.columns, _columns = [], _dates = [], iterateDate = date.clone().decrement('month', Math.floor((months - 1) / 2)); + this.dateElements = []; for (var i = months; i--;){ _date = iterateDate.clone(); @@ -293,6 +298,7 @@ this.DatePicker = Picker.Date = new Class({ timesSelectors.days(options, _date.clone()), options, this.date.clone(), + this.dateElements, function(date){ if (options.pickOnly == 'days' || !options.timePicker) this.select(date) else this.renderTime(date, 'fade'); @@ -385,6 +391,7 @@ var timesSelectors = { years: function(options, date){ var times = []; + date.clearTime(); for (var i = 0; i < options.yearsPerPage; i++){ times.push(+date); date.increment('year', 1); @@ -394,7 +401,7 @@ var timesSelectors = { months: function(options, date){ var times = []; - date.set('month', 0); + date.clearTime().set('month', 0); for (var i = 0; i <= 11; i++){ times.push(+date); date.increment('month', 1); @@ -404,7 +411,7 @@ var timesSelectors = { days: function(options, date){ var times = []; - date.set('date', 1); + date.clearTime().set('date', 1); while (date.get('day') != options.startDay) date.set('date', date.get('date') - 1); for (var i = 0; i < 42; i++){ times.push(+date); @@ -417,7 +424,7 @@ var timesSelectors = { var renderers = { - years: function(years, options, currentDate, fn){ + years: function(years, options, currentDate, dateElements, fn){ var container = new Element('div.years'), today = new Date(), element, classes; @@ -428,6 +435,7 @@ var renderers = { if (year == today.get('year')) classes += '.today'; if (year == currentDate.get('year')) classes += '.selected'; element = new Element('div' + classes, {text: year}).inject(container); + dateElements.push({element: element, time: _year}); if (isUnavailable('year', date, options)) element.addClass('unavailable'); else element.addEvent('click', fn.pass(date)); @@ -436,7 +444,7 @@ var renderers = { return container; }, - months: function(months, options, currentDate, fn){ + months: function(months, options, currentDate, dateElements, fn){ var today = new Date(), month = today.get('month'), thisyear = today.get('year'), @@ -452,6 +460,7 @@ var renderers = { if (i == month && year == thisyear) classes += '.today'; if (i == currentDate.get('month') && year == selectedyear) classes += '.selected'; element = new Element('div' + classes, {text: monthsAbbr[i]}).inject(container); + dateElements.push({element: element, time: _month}); if (isUnavailable('month', date, options)) element.addClass('unavailable'); else element.addEvent('click', fn.pass(date)); @@ -460,7 +469,7 @@ var renderers = { return container; }, - days: function(days, options, currentDate, fn){ + days: function(days, options, currentDate, dateElements, fn){ var month = new Date(days[14]).get('month'), todayString = new Date().toDateString(), currentString = currentDate.toDateString(), @@ -489,6 +498,7 @@ var renderers = { if (date.get('month') != month) classes += '.otherMonth'; element = new Element('div' + classes, {text: date.getDate()}).inject(weekcontainer); + dateElements.push({element: element, time: _date}); if (isUnavailable('date', date, options)) element.addClass('unavailable'); else element.addEvent('click', fn.pass(date.clone())); @@ -497,7 +507,7 @@ var renderers = { return container; }, - time: function(options, date, currentDate, fn){ + time: function(options, date, fn){ var container = new Element('div.time'), // make sure that the minutes are timeWheelStep * k initMinutes = (date.get('minutes') / options.timeWheelStep).round() * options.timeWheelStep diff --git a/Source/datepicker.css b/Source/datepicker.css index 98e2ca8..e0fd068 100644 --- a/Source/datepicker.css +++ b/Source/datepicker.css @@ -260,6 +260,10 @@ color: #fff !important; } +.datepicker .days .otherMonth.selected { + background: #bbbfc8 !important; +} + .datepicker .unavailable, .datepicker .body .days .week .day.unavailable:hover { background: #edd !important; diff --git a/Test/range.html b/Test/range.html index 952584f..a685fb8 100644 --- a/Test/range.html +++ b/Test/range.html @@ -22,7 +22,8 @@

      Range

      Inputs:
      - +
      +

      From 5fa714ccf21961544810362645209eec845496fb Mon Sep 17 00:00:00 2001 From: Arian Date: Tue, 12 Jul 2011 16:17:20 +0100 Subject: [PATCH 235/285] Fire the attached event and rename it from "attachedEvent" to "attached", it was a stupid name because it was obvious that it is an event --- Source/Picker.Attach.js | 4 ++-- Source/Picker.Date.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Picker.Attach.js b/Source/Picker.Attach.js index 8aea726..73e41b6 100644 --- a/Source/Picker.Attach.js +++ b/Source/Picker.Attach.js @@ -14,7 +14,7 @@ Picker.Attach = new Class({ Extends: Picker, options: {/* - onAttachedEvent: function(event){}, + onAttached: function(event){}, toggleElements: null, // deprecated toggle: null, // When set it deactivate toggling by clicking on the input */ @@ -74,9 +74,9 @@ Picker.Attach = new Class({ var tag = event.target.get('tag'); if (tag == 'input' && event.type == 'click' && !element.match(':focus')) return; if (tag == 'a') event.stop(); - self.fireEvent('attachedEvent', [event, element]); self.position(element); self.open(); + self.fireEvent('attached', [event, element]); }; }; diff --git a/Source/Picker.Date.js b/Source/Picker.Date.js index 1b6c730..7b51d72 100644 --- a/Source/Picker.Date.js +++ b/Source/Picker.Date.js @@ -107,7 +107,7 @@ this.DatePicker = Picker.Date = new Class({ this.currentView = options.startView; // Some link or input has fired an event! - this.addEvent('attachedEvent', function(event, element){ + this.addEvent('attached', function(event, element){ this.date = limitDate(new Date(), options.minDate, options.maxDate); var tag = element.get('tag'), input; if (tag == 'input') input = element; From 42c77ac91585780e6bb085aba925aa3dba83009e Mon Sep 17 00:00:00 2001 From: Arian Date: Tue, 12 Jul 2011 17:23:43 +0100 Subject: [PATCH 236/285] Remove the setColumns tween argument, was too buggy and broke the timepicker with the recent changes --- Source/Picker.Attach.js | 2 +- Source/Picker.Date.js | 8 ++++---- Source/Picker.js | 11 +++-------- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/Source/Picker.Attach.js b/Source/Picker.Attach.js index 73e41b6..2106214 100644 --- a/Source/Picker.Attach.js +++ b/Source/Picker.Attach.js @@ -72,7 +72,7 @@ Picker.Attach = new Class({ var getOpenEvent = function(element){ return function(event){ var tag = event.target.get('tag'); - if (tag == 'input' && event.type == 'click' && !element.match(':focus')) return; + if (tag == 'input' && event.type == 'click' && !element.match(':focus') || (self.opened && self.input == element)) return; if (tag == 'a') event.stop(); self.position(element); self.open(); diff --git a/Source/Picker.Date.js b/Source/Picker.Date.js index 7b51d72..54dedff 100644 --- a/Source/Picker.Date.js +++ b/Source/Picker.Date.js @@ -169,8 +169,8 @@ this.DatePicker = Picker.Date = new Class({ return this.setPreviousEvent(fn, true); }, - setColumns: function(columns, tween, view, date, viewFx){ - var ret = this.parent(columns, tween), method; + setColumns: function(columns, view, date, viewFx){ + var ret = this.parent(columns), method; if ((view || this.currentView) && (method = 'render' + (view || this.currentView).capitalize()) @@ -335,7 +335,7 @@ this.DatePicker = Picker.Date = new Class({ var originalColumns = this.originalColumns = options.columns; this.currentView = null; // otherwise you'd get crazy recursion - this.setColumns(1, true); + if (originalColumns != 1) this.setColumns(1); this.setContent(renderers.time( options, @@ -353,7 +353,7 @@ this.DatePicker = Picker.Date = new Class({ var canGoUp = options.pickOnly != 'time' || options.canAlwaysGoUp.contains('time'); var titleEvent = (canGoUp) ? function(){ - this.setColumns(originalColumns, true, 'days', date, 'fade'); + this.setColumns(originalColumns, 'days', date, 'fade'); }.bind(this) : null; this.setTitleEvent(titleEvent); diff --git a/Source/Picker.js b/Source/Picker.js index 68ef766..097a453 100644 --- a/Source/Picker.js +++ b/Source/Picker.js @@ -252,7 +252,7 @@ var Picker = new Class({ return this.setContent(null, fx); }, - setColumns: function(columns, tween){ + setColumns: function(columns){ var _columns = this.columns = new Elements, _newColumns = this.newColumns = new Elements; for (var i = columns; i--;){ @@ -261,13 +261,8 @@ var Picker = new Class({ } var oldClass = 'column_' + this.options.columns, newClass = 'column_' + columns; - var picker = this.picker.setStyle('width', null).removeClass(oldClass).addClass(newClass); - if (tween){ - var newWidth = picker.getStyle('width'); - picker.removeClass(newClass).addClass(oldClass); - picker.tween('width', newWidth); - picker.removeClass(oldClass).addClass(newClass); - } + this.picker.removeClass(oldClass).addClass(newClass); + this.options.columns = columns; return this; }, From 81cda82bf86a01005b924c52b6d866774d7da0b8 Mon Sep 17 00:00:00 2001 From: Arian Date: Wed, 13 Jul 2011 11:35:36 +0100 Subject: [PATCH 237/285] Make the _title options backward compatible or like it used to be --- Source/Picker.Date.js | 22 ++++++++-------------- Source/Picker.js | 12 +++++++++--- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Source/Picker.Date.js b/Source/Picker.Date.js index 54dedff..c3cb907 100644 --- a/Source/Picker.Date.js +++ b/Source/Picker.Date.js @@ -41,20 +41,14 @@ this.DatePicker = Picker.Date = new Class({ months_abbr: null, days_abbr: null, years_title: function(date, options){ - return Array.from(date).map(function(_date, i){ - var year = _date.get('year'); - return new Element('div.column', {text: year + '-' + (year + options.yearsPerPage - 1)}).addClass('column_' + (i + 1)); - }); + var year = date.get('year'); + return year + '-' + (year + options.yearsPerPage - 1); }, months_title: function(date, options){ - return Array.from(date).map(function(_date, i){ - return new Element('div.column', {text: _date.get('year')}).addClass('column_' + (i + 1)); - }); + return date.get('year'); }, days_title: function(date, options){ - return Array.from(date).map(function(_date, i){ - return new Element('div.column', {text: _date.format('%b %Y')}).addClass('column_' + (i + 1)); - }); + return date.format('%b %Y'); }, time_title: function(date, options){ return (options.pickOnly == 'time') ? Locale.get('DatePicker.select_a_time') : date.format('%d %B, %Y'); @@ -210,7 +204,7 @@ this.DatePicker = Picker.Date = new Class({ } this.setColumnsContent(_columns, fx); - this.setTitle(options.years_title(_dates, options)); + this.setTitle(_dates, options.years_title); // Set limits var limitLeft = (options.minDate && date.get('year') <= options.minDate.get('year')), @@ -255,7 +249,7 @@ this.DatePicker = Picker.Date = new Class({ } this.setColumnsContent(_columns, fx); - this.setTitle(options.months_title(_dates, options)); + this.setTitle(_dates, options.months_title); // Set limits var year = date.get('year'), @@ -304,7 +298,7 @@ this.DatePicker = Picker.Date = new Class({ } this.setColumnsContent(_columns, fx); - this.setTitle(options.days_title(_dates, options)); + this.setTitle(_dates, options.days_title); var yearmonth = date.format('%Y%m').toInt(), limitLeft = (options.minDate && yearmonth <= options.minDate.format('%Y%m')), @@ -331,7 +325,7 @@ this.DatePicker = Picker.Date = new Class({ renderTime: function(date, fx){ var options = this.options; - this.setTitle(options.time_title(date, options)); + this.setTitle(date, options.time_title); var originalColumns = this.originalColumns = options.columns; this.currentView = null; // otherwise you'd get crazy recursion diff --git a/Source/Picker.js b/Source/Picker.js index 097a453..35f663d 100644 --- a/Source/Picker.js +++ b/Source/Picker.js @@ -320,9 +320,15 @@ var Picker = new Class({ return this.picker; }, - setTitle: function(text){ - if (!(/(elements|array)/.test(typeOf(text)))) text = new Element('div.column', {text: text}).addClass('column_1'); - this.titleText.empty().adopt(text); + setTitle: function(content, fn){ + if (!fn) fn = Function.from; + this.titleText.empty().adopt( + Array.from(content).map(function(item, i){ + return typeOf(item) == 'element' + ? item + : new Element('div.column', {text: fn(item, this.options)}).addClass('column_' + (i + 1)); + }, this) + ); return this; }, From 4d5cf2cfaef05904e08685c130e389f7275fadbc Mon Sep 17 00:00:00 2001 From: Arian Date: Wed, 13 Jul 2011 12:06:08 +0100 Subject: [PATCH 238/285] Some code cleanup: * Inline the added open/hide events logic which belonged in the open/close methods * Cleanup Picker.Date.Range startInput and endInput click events * Remove some ugly whitespace --- Source/Picker.Attach.js | 1 - Source/Picker.Date.Range.js | 14 ++------------ Source/Picker.js | 33 ++++++++++++--------------------- 3 files changed, 14 insertions(+), 34 deletions(-) diff --git a/Source/Picker.Attach.js b/Source/Picker.Attach.js index 2106214..3bfd2da 100644 --- a/Source/Picker.Attach.js +++ b/Source/Picker.Attach.js @@ -148,7 +148,6 @@ Picker.Attach = new Class({ var inputIndex = self.inputs.indexOf(element); if (toggleIndex != -1) delete self.inputs[inputIndex]; - }); return this; }, diff --git a/Source/Picker.Date.Range.js b/Source/Picker.Date.Range.js index 0441efd..0fe5f2b 100644 --- a/Source/Picker.Date.Range.js +++ b/Source/Picker.Date.Range.js @@ -64,19 +64,9 @@ Picker.Date.Range = new Class({ } }; - var startInput = this.startInput = new Element('input', {events: Object.merge(events, { - click: function(){ - startInput.focus(); - } - })}).inject(footer); - + var startInput = this.startInput = new Element('input', {events: events}).inject(footer); new Element('span', {text: ' - '}).inject(footer); - - var endInput = this.endInput = new Element('input', {events: Object.merge(events, { - click: function(){ - endInput.focus(); - } - })}).inject(footer); + var endInput = this.endInput = new Element('input', {events: events}).inject(footer); this.applyButton = new Element('button.apply', { text: Locale.get('DatePicker.apply_range'), diff --git a/Source/Picker.js b/Source/Picker.js index 35f663d..107346e 100644 --- a/Source/Picker.js +++ b/Source/Picker.js @@ -116,29 +116,18 @@ var Picker = new Class({ } : null); picker.setStyle('cursor', 'move'); } - - this.addEvent('open', function(){ - picker.setStyle('display', 'block'); - if (shim) shim.show(); - }, true); - - this.addEvent('hide', function(){ - picker.setStyle('display', 'none'); - if (shim) shim.hide(); - }, true); - }, open: function(noFx){ if (this.opened == true) return this; this.opened = true; + var picker = this.picker.setStyle('display', 'block'); + if (this.shim) this.shim.show(); this.fireEvent('open'); if (this.options.useFadeInOut && !noFx){ - this.picker.fade('in').get('tween').chain(function(){ - this.fireEvent('show'); - }.bind(this)); + picker.fade('in').get('tween').chain(this.fireEvent.pass('show', this)); } else { - this.picker.setStyle('opacity', 1); + picker.setStyle('opacity', 1); this.fireEvent('show'); } return this; @@ -152,13 +141,16 @@ var Picker = new Class({ if (this.opened == false) return this; this.opened = false; this.fireEvent('close'); + var self = this, picker = this.picker, hide = function(){ + picker.setStyle('display', 'none'); + if (self.shim) self.shim.hide(); + self.fireEvent('hide'); + }; if (this.options.useFadeInOut && !noFx){ - this.picker.fade('out').get('tween').chain(function(){ - this.fireEvent('hide'); - }.bind(this)); + picker.fade('out').get('tween').chain(hide); } else { - this.picker.setStyle('opacity', 0); - this.fireEvent('hide'); + picker.setStyle('opacity', 0); + hide(); } return this; }, @@ -253,7 +245,6 @@ var Picker = new Class({ }, setColumns: function(columns){ - var _columns = this.columns = new Elements, _newColumns = this.newColumns = new Elements; for (var i = columns; i--;){ _columns.push(new Element('div.column').addClass('column_' + (columns - i))); From 95ab51c5c2f80b0bbcda9493c76bf3098ae5d9ad Mon Sep 17 00:00:00 2001 From: Arian Date: Thu, 14 Jul 2011 11:12:51 +0100 Subject: [PATCH 239/285] Add Spanish translations (thanks juanparati) --- README.md | 7 ++++--- Source/Locale.es-ES-DatePicker.js | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 Source/Locale.es-ES-DatePicker.js diff --git a/README.md b/README.md index 3f43e48..ecc7797 100644 --- a/README.md +++ b/README.md @@ -63,14 +63,15 @@ Just include the file in your page with a script tag to use the translations. Currently the following languages are supported -- en-US +- cs-CZ - de-DE +- en-US +- es-ES - fr-FR - it-IT - nl-NL -- cs-CZ -- ru-RU - pl-PL +- ru-RU You can set the current language with: diff --git a/Source/Locale.es-ES-DatePicker.js b/Source/Locale.es-ES-DatePicker.js new file mode 100644 index 0000000..627f17c --- /dev/null +++ b/Source/Locale.es-ES-DatePicker.js @@ -0,0 +1,16 @@ +/* +--- +name: Locale.es-ES.DatePicker +description: Spanish Language File for DatePicker +authors: Juan Lago D. +requires: [More/Locale] +provides: Locale.es-ES.DatePicker +... +*/ + + +Locale.define('es-ES', 'DatePicker', { + select_a_time: 'Selecciona una fecha', + use_mouse_wheel: 'Utiliza la rueda del raton para cambiar rapidamente de valor', + time_confirm_button: 'OK' +}); From 6a4699ec37568a2fb0ec83a6d9c6c34d39cd0cb6 Mon Sep 17 00:00:00 2001 From: Arian Date: Thu, 14 Jul 2011 11:30:56 +0100 Subject: [PATCH 240/285] Add an invertAvailable option that inverts the availableDates option (thanks juanparati!) --- README.md | 1 + Source/Picker.Date.js | 28 +++++++++++++++------------- Test/minmaxdate.html | 38 ++++++++++++++++++++++++++++++++------ 3 files changed, 48 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index ecc7797..f203e7c 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,7 @@ All the options of the Picker and Picker.Attach classes, and: - minDate: (*Date instance*, *string*, defaults to `null`) Minimum date allowed to pick. Blocks anything before. - maxDate: (*Date instance*, *string*, defaults to `null`) Maximum date allowed to pick. Blocks anything after. - availableDates: (*object*, defaults to `null`) When only a few dates should be selectable. An object like `{2011: {1: [19, 29, 31], 3: [5, 19, 24]}}` with all the dates (year -> months -> days). +- invertAvailable: (*boolean*, defaults to `false`) Invert the `availableDates` option. - format: (*string*, defaults to the default localized format) The format to output into the input field. Uses [Date.format](http://mootools.net/docs/more/Types/Date#Date:format) - timePicker: (*boolean*, defaults to 1 `false`) Enable/disable timepicker functionality. Hours/Minutes values can be changed using the scrollwheel. - timeWheelStep: (*number*, defaults to `1`) The number of minutes the minutes field will change in the timepicker when using the scrollwheel, for example 5, 10, 15. The value will always be k * timeWheelStep. diff --git a/Source/Picker.Date.js b/Source/Picker.Date.js index c3cb907..9befea4 100644 --- a/Source/Picker.Date.js +++ b/Source/Picker.Date.js @@ -21,6 +21,8 @@ this.DatePicker = Picker.Date = new Class({ minDate: new Date('3/4/2010'), // Date object or a string maxDate: new Date('3/4/2011'), // same as minDate availableDates: {}, // + invertAvailable: false, + format: null,*/ timePicker: false, @@ -591,7 +593,7 @@ var isUnavailable = function(type, date, options){ (minDate && year < minDate.get('year')) || (maxDate && year > maxDate.get('year')) || ( - (availableDates != null) && ( + (availableDates != null && !options.invertAvailable) && ( availableDates[year] == null || Object.getLength(availableDates[year]) == 0 || Object.getLength( @@ -612,7 +614,7 @@ var isUnavailable = function(type, date, options){ (minDate && ms < minDate.format('%Y%m').toInt()) || (maxDate && ms > maxDate.format('%Y%m').toInt()) || ( - (availableDates != null) && ( + (availableDates != null && !options.invertAvailable) && ( availableDates[year] == null || availableDates[year][month] == null || availableDates[year][month].length == 0 @@ -625,17 +627,17 @@ var isUnavailable = function(type, date, options){ year = date.get('year'); month = date.get('month') + 1; day = date.get('date'); - return ( - (minDate && date < minDate) || - (maxDate && date > maxDate) || - ( - (availableDates != null) && ( - availableDates[year] == null || - availableDates[year][month] == null || - !availableDates[year][month].contains(day) - ) - ) - ); + + var dateAllow = (minDate && date < minDate) || (minDate && date > maxDate); + if (availableDates != null){ + dateAllow = dateAllow + || availableDates[year] == null + || availableDates[year][month] == null + || !availableDates[year][month].contains(day); + if (options.invertAvailable) dateAllow = !dateAllow; + } + + return dateAllow; }; })(); diff --git a/Test/minmaxdate.html b/Test/minmaxdate.html index 1991ecf..7e356e4 100644 --- a/Test/minmaxdate.html +++ b/Test/minmaxdate.html @@ -41,16 +41,39 @@ startView: 'days', yearPicker: false, minDate: '2011-1-19', - maxDate: '2011-3-24', + maxDate: '2011-10-24', availableDates: { 2011: { 1: [19, 29, 31], - 2: [14], - 3: [5, 19, 24] + 3: [5, 19, 24], + 7: [6, 8, 20], + 8: [29], + 9: [15, 20], + 10:[2] } } }); + new Picker.Date('myInput4', { + pickerClass: 'datepicker_vista', + format: '%Y-%m-%d', + startView: 'days', + yearPicker: false, + minDate: '2011-1-19', + maxDate: '2011-10-24', + availableDates: { + 2011: { + 1: [19, 29, 31], + 3: [5, 19, 24], + 7: [6, 8, 20], + 8: [29], + 9: [15, 20], + 10:[2] + } + }, + invertAvailable: true + }); + }); @@ -59,6 +82,7 @@ +

      Min and Max dates

      @@ -78,8 +102,10 @@

      Min and Max dates

      Input (only a few dates are available):

      - - +

      + Input (invert previously available dates):
      + +

      - \ No newline at end of file + From fd966b6b283d3159aac2c24427e551ed0a827dcf Mon Sep 17 00:00:00 2001 From: Arian Date: Thu, 14 Jul 2011 11:46:50 +0100 Subject: [PATCH 241/285] Update MooTools to 1.3.2 --- Test/mootools-core.js | 142 +++++++++------- Test/mootools-more.js | 371 +++++++++++++++++++++--------------------- 2 files changed, 269 insertions(+), 244 deletions(-) diff --git a/Test/mootools-core.js b/Test/mootools-core.js index e12939c..d35fd1d 100644 --- a/Test/mootools-core.js +++ b/Test/mootools-core.js @@ -33,8 +33,8 @@ provides: [Core, MooTools, Type, typeOf, instanceOf, Native] (function(){ this.MooTools = { - version: '1.3.1', - build: 'af48c8d589f43f32212f9bb8ff68a127e6a3ba6c' + version: '1.3.2', + build: 'c9f1ff10e9e7facb65e9481049ed1b450959d587' }; // typeOf, instanceOf @@ -398,7 +398,7 @@ String.extend('uniqueID', function(){ -}).call(this); +})(); /* @@ -419,13 +419,7 @@ provides: Array Array.implement({ - invoke: function(methodName){ - var args = Array.slice(arguments, 1); - return this.map(function(item){ - return item[methodName].apply(item, args); - }); - }, - + /**/ every: function(fn, bind){ for (var i = 0, l = this.length; i < l; i++){ if ((i in this) && !fn.call(bind, this[i], i, this)) return false; @@ -441,12 +435,6 @@ Array.implement({ return results; }, - clean: function(){ - return this.filter(function(item){ - return item != null; - }); - }, - indexOf: function(item, from){ var len = this.length; for (var i = (from < 0) ? Math.max(0, len + from) : from || 0; i < len; i++){ @@ -469,6 +457,20 @@ Array.implement({ } return false; }, + /**/ + + clean: function(){ + return this.filter(function(item){ + return item != null; + }); + }, + + invoke: function(methodName){ + var args = Array.slice(arguments, 1); + return this.map(function(item){ + return item[methodName].apply(item, args); + }); + }, associate: function(keys){ var obj = {}, length = Math.min(this.length, keys.length); @@ -748,6 +750,7 @@ Function.implement({ return null; }, + /**/ bind: function(bind){ var self = this, args = (arguments.length > 1) ? Array.slice(arguments, 1) : null; @@ -758,6 +761,7 @@ Function.implement({ return self.apply(bind, args || arguments); }; }, + /**/ pass: function(args, bind){ var self = this; @@ -806,7 +810,7 @@ Object.extend({ var results = {}; for (var i = 0, l = keys.length; i < l; i++){ var k = keys[i]; - results[k] = object[k]; + if (k in object) results[k] = object[k]; } return results; }, @@ -821,9 +825,10 @@ Object.extend({ filter: function(object, fn, bind){ var results = {}; - Object.each(object, function(value, key){ - if (fn.call(bind, value, key, object)) results[key] = value; - }); + for (var key in object){ + var value = object[key]; + if (hasOwnProperty.call(object, key) && fn.call(bind, value, key, object)) results[key] = value; + } return results; }, @@ -1063,12 +1068,13 @@ Document.mirror(function(name, method){ }); document.html = document.documentElement; -document.head = document.getElementsByTagName('head')[0]; +if (!document.head) document.head = document.getElementsByTagName('head')[0]; if (document.execCommand) try { document.execCommand("BackgroundImageCache", false, true); } catch (e){} +/**/ if (this.attachEvent && !this.addEventListener){ var unloadEvent = function(){ this.detachEvent('onunload', unloadEvent); @@ -1100,10 +1106,11 @@ try { }; }); } +/**/ -}).call(this); +})(); /* @@ -1353,7 +1360,7 @@ Class.Mutators = { } }; -}).call(this); +})(); /* @@ -1474,7 +1481,7 @@ this.Options = new Class({ }); -}).call(this); +})(); /* @@ -2040,17 +2047,28 @@ local.search = function(context, expression, append, first){ /**/ querySelector: if (context.querySelectorAll) { - if (!this.isHTMLDocument || this.brokenMixedCaseQSA || qsaFailExpCache[expression] || - (this.brokenCheckedQSA && expression.indexOf(':checked') > -1) || - (this.brokenEmptyAttributeQSA && reEmptyAttribute.test(expression)) || Slick.disableQSA) break querySelector; - - var _expression = expression; + if (!this.isHTMLDocument + || qsaFailExpCache[expression] + //TODO: only skip when expression is actually mixed case + || this.brokenMixedCaseQSA + || (this.brokenCheckedQSA && expression.indexOf(':checked') > -1) + || (this.brokenEmptyAttributeQSA && reEmptyAttribute.test(expression)) + || (!contextIsDocument //Abort when !contextIsDocument and... + // there are multiple expressions in the selector + // since we currently only fix non-document rooted QSA for single expression selectors + && expression.indexOf(',') > -1 + ) + || Slick.disableQSA + ) break querySelector; + + var _expression = expression, _context = context; if (!contextIsDocument){ // non-document rooted QSA // credits to Andrew Dupont - var currentId = context.getAttribute('id'), slickid = 'slickid__'; - context.setAttribute('id', slickid); + var currentId = _context.getAttribute('id'), slickid = 'slickid__'; + _context.setAttribute('id', slickid); _expression = '#' + slickid + ' ' + _expression; + context = _context.parentNode; } try { @@ -2061,8 +2079,9 @@ local.search = function(context, expression, append, first){ break querySelector; } finally { if (!contextIsDocument){ - if (currentId) context.setAttribute('id', currentId); - else context.removeAttribute('id'); + if (currentId) _context.setAttribute('id', currentId); + else _context.removeAttribute('id'); + context = _context; } } @@ -2700,8 +2719,10 @@ var Element = function(tag, props){ var attributes = parsed.attributes; if (attributes) for (var i = 0, l = attributes.length; i < l; i++){ var attr = attributes[i]; - if (attr.value != null && attr.operator == '=' && props[attr.key] == null) - props[attr.key] = attr.value; + if (props[attr.key] != null) continue; + + if (attr.value != null && attr.operator == '=') props[attr.key] = attr.value; + else if (!attr.value && !attr.operator) props[attr.key] = true; } if (parsed.classList && props['class'] == null) props['class'] = parsed.classList.join(' '); @@ -3358,11 +3379,12 @@ if (!document.createElement('div').contains) Element.implement(contains); }); -// IE purge +/**/ if (window.attachEvent && !window.addEventListener) window.addListener('unload', function(){ Object.each(collected, clean); if (window.CollectGarbage) CollectGarbage(); }); +/**/ })(); @@ -3394,6 +3416,7 @@ Element.Properties.tag = { }; +/**/ (function(maxLength){ if (maxLength != null) Element.Properties.maxlength = Element.Properties.maxLength = { get: function(){ @@ -3402,7 +3425,9 @@ Element.Properties.tag = { } }; })(document.createElement('input').getAttribute('maxLength')); +/**/ +/**/ Element.Properties.html = (function(){ var tableTest = Function.attempt(function(){ @@ -3439,6 +3464,7 @@ Element.Properties.html = (function(){ return html; })(); +/**/ /* @@ -3473,7 +3499,8 @@ var setOpacity = function(element, opacity){ if (hasOpacity){ element.style.opacity = opacity; } else { - opacity = (opacity == 1) ? '' : 'alpha(opacity=' + opacity * 100 + ')'; + opacity = (opacity * 100).limit(0, 100).round(); + opacity = (opacity == 100) ? '' : 'alpha(opacity=' + opacity + ')'; var filter = element.style.filter || element.getComputedStyle('filter') || ''; element.style.filter = reAlpha.test(filter) ? filter.replace(reAlpha, opacity) : filter + opacity; } @@ -3619,7 +3646,7 @@ Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, bor Short.borderColor[bdc] = Short[bd][bdc] = All[bdc] = 'rgb(@, @, @)'; }); -}).call(this); +})(); /* @@ -3792,7 +3819,7 @@ Element.Events = { -}).call(this); +})(); /* @@ -4038,7 +4065,7 @@ function getCompatElement(element){ return (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body; } -}).call(this); +})(); //aliases Element.alias({position: 'setPosition'}); //compatability @@ -4258,7 +4285,7 @@ var pullInstance = function(fps){ } }; -}).call(this); +})(); /* @@ -4726,12 +4753,7 @@ var ready, checks = [], shouldPoll, timer, - isFramed = true; - -// Thanks to Rich Dougherty -try { - isFramed = window.frameElement != null; -} catch(e){} + testElement = document.createElement('div'); var domready = function(){ clearTimeout(timer); @@ -4748,7 +4770,6 @@ var check = function(){ domready(); return true; } - return false; }; @@ -4759,19 +4780,23 @@ var poll = function(){ document.addListener('DOMContentLoaded', domready); +/**/ // doScroll technique by Diego Perini http://javascript.nwbox.com/IEContentLoaded/ -var testElement = document.createElement('div'); -if (testElement.doScroll && !isFramed){ - checks.push(function(){ - try { - testElement.doScroll(); - return true; - } catch (e){} - - return false; - }); +// testElement.doScroll() throws when the DOM is not ready, only in the top window +var doScrollWorks = function(){ + try { + testElement.doScroll(); + return true; + } catch (e){} + return false; +} +// If doScroll works already, it can't be used to determine domready +// e.g. in an iframe +if (testElement.doScroll && !doScrollWorks()){ + checks.push(doScrollWorks); shouldPoll = true; } +/**/ if (document.readyState) checks.push(function(){ var state = document.readyState; @@ -4800,7 +4825,6 @@ Element.Events.load = { domready(); delete Element.Events.load; } - return true; } }; diff --git a/Test/mootools-more.js b/Test/mootools-more.js index ddc607d..72df8d8 100644 --- a/Test/mootools-more.js +++ b/Test/mootools-more.js @@ -20,6 +20,7 @@ authors: - Tim Wienk - Christoph Pojer - Aaron Newton + - Jacob Thornton requires: - Core/MooTools @@ -30,8 +31,8 @@ provides: [MooTools.More] */ MooTools.More = { - 'version': '1.3.1.1', - 'build': '0292a3af1eea242b817fecf9daa127417d10d4ce' + 'version': '1.3.2.1', + 'build': 'e586bcd2496e9b22acfde32e12f84d49ce09e59d' }; @@ -100,7 +101,7 @@ Object.extend({ }); -}).call(this); +})(); /* @@ -268,7 +269,7 @@ Locale.Set = new Class({ -}).call(this); +})(); /* @@ -907,7 +908,7 @@ Locale.addEvent('change', function(language){ if (Locale.get('Date')) recompile(language); }).fireEvent('change', Locale.getCurrent()); -}).call(this); +})(); /* @@ -1021,12 +1022,6 @@ var Drag = new Class({ var limit = options.limit; this.limit = {x: [], y: []}; - var styles = this.element.getStyles('left', 'right', 'top', 'bottom'); - this._invert = { - x: options.modifiers.x == 'left' && styles.left == 'auto' && !isNaN(styles.right.toInt()) && (options.modifiers.x = 'right'), - y: options.modifiers.y == 'top' && styles.top == 'auto' && !isNaN(styles.bottom.toInt()) && (options.modifiers.y = 'bottom') - }; - var z, coordinates; for (z in options.modifiers){ if (!options.modifiers[z]) continue; @@ -1043,7 +1038,6 @@ var Drag = new Class({ else this.value.now[z] = this.element[options.modifiers[z]]; if (options.invert) this.value.now[z] *= -1; - if (this._invert[z]) this.value.now[z] *= -1; this.mouse.pos[z] = event.page[z] - this.value.now[z]; @@ -1093,7 +1087,6 @@ var Drag = new Class({ this.value.now[z] = this.mouse.now[z] - this.mouse.pos[z]; if (options.invert) this.value.now[z] *= -1; - if (this._invert[z]) this.value.now[z] *= -1; if (options.limit && this.limit[z]){ if ((this.limit[z][1] || this.limit[z][1] === 0) && (this.value.now[z] > this.limit[z][1])){ @@ -1207,10 +1200,9 @@ Drag.Move = new Class({ this.container = document.id(this.container.getDocument().body); if (this.options.style){ - if (this.options.modifiers.x == "left" && this.options.modifiers.y == "top"){ - var parentStyles, - parent = element.getOffsetParent(); - var styles = element.getStyles('left', 'top'); + if (this.options.modifiers.x == 'left' && this.options.modifiers.y == 'top'){ + var parent = element.getOffsetParent(), + styles = element.getStyles('left', 'top'); if (parent && (styles.left == 'auto' || styles.top == 'auto')){ element.setPosition(element.getPosition(parent)); } @@ -1520,7 +1512,7 @@ Element.implement({ }); -}).call(this); +})(); /* @@ -1536,219 +1528,228 @@ license: MIT-style license authors: - Aaron Newton + - Jacob Thornton requires: + - Core/Options - Core/Element.Dimensions - - /Element.Measure + - Element.Measure provides: [Element.Position] ... */ -(function(){ +(function(original){ -var original = Element.prototype.position; +var local = Element.Position = { -Element.implement({ + options: {/* + edge: false, + returnPos: false, + minimum: {x: 0, y: 0}, + maximum: {x: 0, y: 0}, + relFixedPosition: false, + ignoreMargins: false, + ignoreScroll: false, + allowNegative: false,*/ + relativeTo: document.body, + position: { + x: 'center', //left, center, right + y: 'center' //top, center, bottom + }, + offset: {x: 0, y: 0} + }, - position: function(options){ - //call original position if the options are x/y values - if (options && (options.x != null || options.y != null)){ - return original ? original.apply(this, arguments) : this; - } + getOptions: function(element, options){ + options = Object.merge({}, local.options, options); + local.setPositionOption(options); + local.setEdgeOption(options); + local.setOffsetOption(element, options); + local.setDimensionsOption(element, options); + return options; + }, - Object.each(options || {}, function(v, k){ - if (v == null) delete options[k]; - }); + setPositionOption: function(options){ + options.position = local.getCoordinateFromValue(options.position); + }, - options = Object.merge({ - // minimum: { x: 0, y: 0 }, - // maximum: { x: 0, y: 0}, - relativeTo: document.body, - position: { - x: 'center', //left, center, right - y: 'center' //top, center, bottom - }, - offset: {x: 0, y: 0}/*, - edge: false, - returnPos: false, - relFixedPosition: false, - ignoreMargins: false, - ignoreScroll: false, - allowNegative: false*/ - }, options); + setEdgeOption: function(options){ + var edgeOption = local.getCoordinateFromValue(options.edge); + options.edge = edgeOption ? edgeOption : + (options.position.x == 'center' && options.position.y == 'center') ? {x: 'center', y: 'center'} : + {x: 'left', y: 'top'}; + }, - //compute the offset of the parent positioned element if this element is in one + setOffsetOption: function(element, options){ var parentOffset = {x: 0, y: 0}, - parentPositioned = false; + offsetParent = element.measure(function(){ + return document.id(this.getOffsetParent()); + }), + parentScroll = offsetParent.getScroll(); + + if (!offsetParent || offsetParent == element.getDocument().body) return; + parentOffset = offsetParent.measure(function(){ + var position = this.getPosition(); + if (this.getStyle('position') == 'fixed'){ + var scroll = window.getScroll(); + position.x += scroll.x; + position.y += scroll.y; + } + return position; + }); + + options.offset = { + parentPositioned: offsetParent != document.id(options.relativeTo), + x: options.offset.x - parentOffset.x + parentScroll.x, + y: options.offset.y - parentOffset.y + parentScroll.y + }; + }, - /* dollar around getOffsetParent should not be necessary, but as it does not return - * a mootools extended element in IE, an error occurs on the call to expose. See: - * http://mootools.lighthouseapp.com/projects/2706/tickets/333-element-getoffsetparent-inconsistency-between-ie-and-other-browsers */ - var offsetParent = this.measure(function(){ - return document.id(this.getOffsetParent()); + setDimensionsOption: function(element, options){ + options.dimensions = element.getDimensions({ + computeSize: true, + styles: ['padding', 'border', 'margin'] }); - if (offsetParent && offsetParent != this.getDocument().body){ - parentOffset = offsetParent.measure(function(){ - return this.getPosition(); - }); - parentPositioned = offsetParent != document.id(options.relativeTo); - options.offset.x = options.offset.x - parentOffset.x; - options.offset.y = options.offset.y - parentOffset.y; - } + }, - //upperRight, bottomRight, centerRight, upperLeft, bottomLeft, centerLeft - //topRight, topLeft, centerTop, centerBottom, center - var fixValue = function(option){ - if (typeOf(option) != 'string') return option; - option = option.toLowerCase(); - var val = {}; - - if (option.test('left')){ - val.x = 'left'; - } else if (option.test('right')){ - val.x = 'right'; - } else { - val.x = 'center'; - } + getPosition: function(element, options){ + var position = {}; + options = local.getOptions(element, options); + var relativeTo = document.id(options.relativeTo) || document.body; - if (option.test('upper') || option.test('top')){ - val.y = 'top'; - } else if (option.test('bottom')){ - val.y = 'bottom'; - } else { - val.y = 'center'; - } + local.setPositionCoordinates(options, position, relativeTo); + if (options.edge) local.toEdge(position, options); - return val; - }; + var offset = options.offset; + position.left = ((position.x >= 0 || offset.parentPositioned || options.allowNegative) ? position.x : 0).toInt(); + position.top = ((position.y >= 0 || offset.parentPositioned || options.allowNegative) ? position.y : 0).toInt(); - options.edge = fixValue(options.edge); - options.position = fixValue(options.position); - if (!options.edge){ - if (options.position.x == 'center' && options.position.y == 'center') options.edge = {x:'center', y:'center'}; - else options.edge = {x:'left', y:'top'}; - } + local.toMinMax(position, options); - this.setStyle('position', 'absolute'); - var rel = document.id(options.relativeTo) || document.body, - calc = rel == document.body ? window.getScroll() : rel.getPosition(), - top = calc.y, left = calc.x; + if (options.relFixedPosition || relativeTo.getStyle('position') == 'fixed') local.toRelFixedPosition(relativeTo, position); + if (options.ignoreScroll) local.toIgnoreScroll(relativeTo, position); + if (options.ignoreMargins) local.toIgnoreMargins(position, options); - var dim = this.getDimensions({ - computeSize: true, - styles:['padding', 'border','margin'] - }); + position.left = Math.ceil(position.left); + position.top = Math.ceil(position.top); + delete position.x; + delete position.y; - var pos = {}, - prefY = options.offset.y, - prefX = options.offset.x, + return position; + }, + + setPositionCoordinates: function(options, position, relativeTo){ + var offsetY = options.offset.y, + offsetX = options.offset.x, + calc = (relativeTo == document.body) ? window.getScroll() : relativeTo.getPosition(), + top = calc.y, + left = calc.x, winSize = window.getSize(); - switch (options.position.x){ - case 'left': - pos.x = left + prefX; - break; - case 'right': - pos.x = left + prefX + rel.offsetWidth; - break; - default: //center - pos.x = left + ((rel == document.body ? winSize.x : rel.offsetWidth)/2) + prefX; - break; + switch(options.position.x){ + case 'left': position.x = left + offsetX; break; + case 'right': position.x = left + offsetX + relativeTo.offsetWidth; break; + default: position.x = left + ((relativeTo == document.body ? winSize.x : relativeTo.offsetWidth) / 2) + offsetX; break; } - switch (options.position.y){ - case 'top': - pos.y = top + prefY; - break; - case 'bottom': - pos.y = top + prefY + rel.offsetHeight; - break; - default: //center - pos.y = top + ((rel == document.body ? winSize.y : rel.offsetHeight)/2) + prefY; - break; + switch(options.position.y){ + case 'top': position.y = top + offsetY; break; + case 'bottom': position.y = top + offsetY + relativeTo.offsetHeight; break; + default: position.y = top + ((relativeTo == document.body ? winSize.y : relativeTo.offsetHeight) / 2) + offsetY; break; } + }, - if (options.edge){ - var edgeOffset = {}; - - switch (options.edge.x){ - case 'left': - edgeOffset.x = 0; - break; - case 'right': - edgeOffset.x = -dim.x-dim.computedRight-dim.computedLeft; - break; - default: //center - edgeOffset.x = -(dim.totalWidth/2); - break; - } + toMinMax: function(position, options){ + var xy = {left: 'x', top: 'y'}, value; + ['minimum', 'maximum'].each(function(minmax){ + ['left', 'top'].each(function(lr){ + value = options[minmax] ? options[minmax][xy[lr]] : null; + if (value != null && ((minmax == 'minimum') ? position[lr] < value : position[lr] > value)) position[lr] = value; + }); + }); + }, - switch (options.edge.y){ - case 'top': - edgeOffset.y = 0; - break; - case 'bottom': - edgeOffset.y = -dim.y-dim.computedTop-dim.computedBottom; - break; - default: //center - edgeOffset.y = -(dim.totalHeight/2); - break; - } + toRelFixedPosition: function(relativeTo, position){ + var winScroll = window.getScroll(); + position.top += winScroll.y; + position.left += winScroll.x; + }, - pos.x += edgeOffset.x; - pos.y += edgeOffset.y; - } + toIgnoreScroll: function(relativeTo, position){ + var relScroll = relativeTo.getScroll(); + position.top -= relScroll.y; + position.left -= relScroll.x; + }, - pos = { - left: ((pos.x >= 0 || parentPositioned || options.allowNegative) ? pos.x : 0).toInt(), - top: ((pos.y >= 0 || parentPositioned || options.allowNegative) ? pos.y : 0).toInt() - }; + toIgnoreMargins: function(position, options){ + position.left += options.edge.x == 'right' + ? options.dimensions['margin-right'] + : (options.edge.x != 'center' + ? -options.dimensions['margin-left'] + : -options.dimensions['margin-left'] + ((options.dimensions['margin-right'] + options.dimensions['margin-left']) / 2)); - var xy = {left: 'x', top: 'y'}; + position.top += options.edge.y == 'bottom' + ? options.dimensions['margin-bottom'] + : (options.edge.y != 'center' + ? -options.dimensions['margin-top'] + : -options.dimensions['margin-top'] + ((options.dimensions['margin-bottom'] + options.dimensions['margin-top']) / 2)); + }, - ['minimum', 'maximum'].each(function(minmax){ - ['left', 'top'].each(function(lr){ - var val = options[minmax] ? options[minmax][xy[lr]] : null; - if (val != null && ((minmax == 'minimum') ? pos[lr] < val : pos[lr] > val)) pos[lr] = val; - }); - }); + toEdge: function(position, options){ + var edgeOffset = {}, + dimensions = options.dimensions, + edge = options.edge; - if (rel.getStyle('position') == 'fixed' || options.relFixedPosition){ - var winScroll = window.getScroll(); - pos.top+= winScroll.y; - pos.left+= winScroll.x; + switch(edge.x){ + case 'left': edgeOffset.x = 0; break; + case 'right': edgeOffset.x = -dimensions.x - dimensions.computedRight - dimensions.computedLeft; break; + // center + default: edgeOffset.x = -(Math.round(dimensions.totalWidth / 2)); break; } - if (options.ignoreScroll){ - var relScroll = rel.getScroll(); - pos.top -= relScroll.y; - pos.left -= relScroll.x; + + switch(edge.y){ + case 'top': edgeOffset.y = 0; break; + case 'bottom': edgeOffset.y = -dimensions.y - dimensions.computedTop - dimensions.computedBottom; break; + // center + default: edgeOffset.y = -(Math.round(dimensions.totalHeight / 2)); break; } - if (options.ignoreMargins){ - pos.left += ( - options.edge.x == 'right' ? dim['margin-right'] : - options.edge.x == 'center' ? -dim['margin-left'] + ((dim['margin-right'] + dim['margin-left'])/2) : - - dim['margin-left'] - ); - pos.top += ( - options.edge.y == 'bottom' ? dim['margin-bottom'] : - options.edge.y == 'center' ? -dim['margin-top'] + ((dim['margin-bottom'] + dim['margin-top'])/2) : - - dim['margin-top'] - ); + position.x += edgeOffset.x; + position.y += edgeOffset.y; + }, + + getCoordinateFromValue: function(option){ + if (typeOf(option) != 'string') return option; + option = option.toLowerCase(); + + return { + x: option.test('left') ? 'left' + : (option.test('right') ? 'right' : 'center'), + y: option.test(/upper|top/) ? 'top' + : (option.test('bottom') ? 'bottom' : 'center') + }; + } + +}; + +Element.implement({ + + position: function(options){ + if (options && (options.x != null || options.y != null)) { + return (original ? original.apply(this, arguments) : this); } + var position = this.setStyle('position', 'absolute').calculatePosition(options); + return (options && options.returnPos) ? position : this.setStyles(position); + }, - pos.left = Math.ceil(pos.left); - pos.top = Math.ceil(pos.top); - if (options.returnPos) return pos; - else this.setStyles(pos); - return this; + calculatePosition: function(options){ + return local.getPosition(this, options); } }); -}).call(this); +})(Element.prototype.position); /* From dd8614aff58fea687193bc1bae695e12608f6cd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rouven=20We=C3=9Fling?= Date: Tue, 12 Jul 2011 17:22:17 +0200 Subject: [PATCH 242/285] Optimize images --- Source/datepicker_dashboard/buttons.png | Bin 696 -> 638 bytes Source/datepicker_dashboard/frame.png | Bin 1954 -> 1319 bytes Source/datepicker_jqui/arrows.png | Bin 352 -> 247 bytes Source/datepicker_jqui/frame.png | Bin 1053 -> 771 bytes Source/datepicker_vista/buttons.png | Bin 758 -> 700 bytes Source/datepicker_vista/days.png | Bin 530 -> 459 bytes Source/datepicker_vista/frame.png | Bin 1929 -> 1487 bytes Source/datepicker_vista/months.png | Bin 682 -> 617 bytes Source/datepicker_vista/years.png | Bin 673 -> 608 bytes screenshot.png | Bin 14423 -> 12793 bytes 10 files changed, 0 insertions(+), 0 deletions(-) diff --git a/Source/datepicker_dashboard/buttons.png b/Source/datepicker_dashboard/buttons.png index 66e24e37c6cb4c8fcffae249e908b6ee1ac5e91a..8de1438de6b687fdece07fe241ccfab08a9b678c 100644 GIT binary patch delta 297 zcmV+^0oMMw1^xt(Be7UN0e=TcL_t(|+O^TwP6AO72H?ZYF1_s1dq)&S5$wHzT>%9I zu>kV^ufWA@&Ps?mn&901nJ<~l4EtV&AHyG+m3OQY{~3% z!|TzIO$Oi$K(=XND*$hg5W6E4b-@$^SCm5bwg~Y2wM@)C!`u|Yoe@B+tO|xU_TeNB vr6<7(Id6gW;_A8JARbqqy@1+&nfvP}!(14{qpoky00000NkvXXu0mjf9&n99 delta 354 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 X-=RFmirX?400000NkvXXu0mjf4W@&K diff --git a/Source/datepicker_jqui/frame.png b/Source/datepicker_jqui/frame.png index 7e727782a86f318281bcb24137457e4f1529b557..c8187afb189289524d11f9d10947bb7c8cd13e30 100644 GIT binary patch delta 707 zcmbQs(abhMl7pFnfgvPU+GnDoc|F7b0G|+7pukNc!2SF8A3uKlt5>gHzkdDZ&6~Gx-@beI?*04sA3l8e`0?YXPoF;bGkl)H{do${=c#<3 zrwM+ZDgJqu)aUhnpEm@2{`~n%{RY1;8w0;=3i|N@#}efqOH_VNXZkgh`S(VP-y1Fe0MRCkKbx)oY_|Ec#qQ5mhrg>7|E^Z~ zyGH%*TCKn9bpNh5_`AXA??%&qbD94wVE?y>=ig%fe@g`aEfx8z+J+`{DD2BauHC7#NE@T^vIyZoRz` z?RVHfq~+m9)y}LHRf77pN&mAKi?C#Q$f`e6Oysxy@}28XW}oe}xiK8QJ?jc*t@<2W zRk=xP$GqP%kG^f)$`!C%z9`2pXz$aUg5SB%OI|Im&o`-;En_P_@iSR^QTL?0<4dyq zFPQwZ_6)qVVYOMmqw$(1O)1eIk=+h%jHkP_E^WT~cKZK`j7%&X0(UwS{Mk6F`2gJ}Q42s9F?yVijXqId#WGfOu> yezRP0Rs3<2;R#F2-JDY%JxS^aV@=iiDn3Of=F2b9=xxA=VeoYIb6Mw<&;$UenPUq8 literal 1053 zcmeAS@N?(olHy`uVBq!ia0vp^2Z4AQ2OE$~-u$`_NU@|l`Z_W&T)T0_Kf(yemn?CO zC<)F_D=AMbN@Z|N$xljE@XSq2PYp^D?*#T|l2rkc&}S~#Vy;mo#W z8RE-=dnWCC^2K)Y1hp+2e}Dd0S8&K@($&L1f6tj|yiDV?k=x>nUM@BB`?O!KkaM1! zyX>*2)jk=%_Sr{|9Xs~(%ahFg_v7D{SY6C9>+Oh|eg65zy?bRJfBcbJ^{Y_3cBicb z&$Qil*S(z3`bz#++9TXsF)_2-|Lj|{IkJ3_08W$^B2#!|6k?ST}KoDdI8t$jEXBxmbW{9{8tdgIbCHwE_-S~Z-W%-s-&3~^Sd%EsrAh+vg*|kf*uVy#&eqQ-_^KN!~ zYaz#9&hy*1jrl7QMz3h1NRf zesB8o{MO1jv$?+3FRXbn=YPMi0+Z1l7QJ?XM&AYw7bNseWVdnfK{W=!1`dVI9DMbC zPApFz)Z1A~1{{Wx)p zznM>W)U3BluJ6&FFE8)-@!|E2pC2sOxZkt5c2S2D_mx!UCB^ktn#n=m#Gn8CI6L8` zlZbg;-^pKRXY7gSulRfD%Zm1LKleS`rH;NTXRoh$eM9_M_x>wiU&=ZwOY2pfxVQhk zM6)l063B%PEDB5lj2#Rv43!1PC1xMsfN;Qa3i0oR6NDugkrX~TUCWfiq>Rv|)KIh2 zzri9-wz`0PFt4@20YKc2I4 SUAuw#o59o7&t;ucLK6TC1-YC6 diff --git a/Source/datepicker_vista/buttons.png b/Source/datepicker_vista/buttons.png index 3b392cb2571b82a06f03e164e7147e8933a30fa2..a26e8fadadabb0fbc4afbfd8feb9c7f2a6c6878d 100644 GIT binary patch delta 320 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 diff --git a/Source/datepicker_vista/months.png b/Source/datepicker_vista/months.png index c125b8279cdef5b32fd7f79ed8a69537d29a7c8e..0a1585b6ad4c6c244c2ac1e342ecb2a09e0234e6 100644 GIT binary patch delta 300 zcmV+{0n`4f1?dEkBe7T~0e=cfL_t(|+MUZ&VgykX1kmai+qUg=_t>^F6YhT-sV&?( z{|By>Zo{UXZaKt~-H%tBk8U!CNbcS)7eUZ@w(A7Iu>!z_f^R{=cckDuRPfy>_zo0& z;|jiW1>dBCZ(qT;q2QZU@LenT&J=uC3ceEs-@1bDQ~?B;7rRV=NPq3luJ(f%im7*- zR1x2B&2j}cm2%TzOatdP5}r+>;X6e8b>G?e^?nrb!joMgjgjbBe7T~0e=BWL_t(|+I`AXVgykD1i+pb+s4LrGF;nMc>impFYvm) z3ntU*!=m5H7{p7-_Pa$pS&AbXJ_^GKe(z4``M|jZ;8J2(kQk06hDC{CUSfzz4Eqwp zvBYp7G3-eUw-Up;#Bd`qtV#^m62pbWuqH8_NPs_n6~;cI?vv2{LVp~c(TByTgFl#5 zeE^F=J!LRK3XE5)I2M(fXAm~hp0V)KjSxZkUML4}vkyYng)=8PaAqWi6^UV1Vpx(G zP9=s7iD6S>n3fo(B!)?e;Y?!Kl^C`ph8>CFN@7@+7!D`xjxM pS$wl7HVZ#6`CQeps2Jw*<{v2pvc6LD?Ro$J002ovPDHLkV1lN!fD`}# delta 355 zcmV-p0i6Ee1fd0xBQpR5XF*Lt007q5)K6G40000PbVXQnQ*UN;cVTj606}DLVr3vn zZDD6+Qe|Oed2z{QJh34u0e=liL_t(|+Jw`^VZ=ZHLs5Cc%*@Oj(|VbiA=rN#Q3IpA z^FQb!m~^uTi(WHr5ET=xH;Y!H7$G)z5C$>$-CLpS17{MKTu2P&BnAf(gL#R;ti<3* zVz4VQIFuOdNep%*1~(FeRf)m1#9&!sa3wJ~ml&)_42~thAH4`8AAhmVqtN+8g!b^= zV%WwnOtRLuJ*!_!8jSq|#;cYci*nU727yu~*vc7reBb@*M002ovPDHLkV1oS; Bk+T2* diff --git a/screenshot.png b/screenshot.png index 4299e9467495608c03a985ec849619b105fc0553..69be6cd9396f885433aa32b3193381a1fb5b9022 100644 GIT binary patch literal 12793 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 W$ER%S1Nln_l#GO;c!j8;-~R&YvB2&C literal 14423 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 Date: Thu, 14 Jul 2011 15:01:38 +0100 Subject: [PATCH 243/285] Add another example how you can use the range picker with an hidden input field --- Test/range.html | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/Test/range.html b/Test/range.html index 84bf520..1a2a921 100644 --- a/Test/range.html +++ b/Test/range.html @@ -2,7 +2,7 @@ - Full Date and TimePicker + Date Range Picker @@ -27,14 +27,29 @@

      Range

      +

      + Hidden input:
      + Select Range +

      + From 2c1980519296193302be771970ac459327a3b23a Mon Sep 17 00:00:00 2001 From: Arian Date: Mon, 25 Jul 2011 12:31:19 +0100 Subject: [PATCH 244/285] Range: use the stored dates correctly --- Source/Picker.Date.Range.js | 8 +++----- package.yml | 1 + 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Source/Picker.Date.Range.js b/Source/Picker.Date.Range.js index 0fe5f2b..8217471 100644 --- a/Source/Picker.Date.Range.js +++ b/Source/Picker.Date.Range.js @@ -29,15 +29,15 @@ Picker.Date.Range = new Class({ if (!input) return; var dates = input.retrieve('datepicker:value'); - if (!dates || !dates.length || !dates.every(function(date){ - return Date.isValid(date); + if (dates && dates.length) dates = dates.map(Date.parse); + if (!dates || !dates.length || dates.some(function(date){ + return !Date.isValid(date); })){ dates = this.options.getStartEndDate(input); if (!dates.length || !dates.every(function(date){ return Date.isValid(date); })) dates = [this.date]; } - if (dates.length == 1) this.date = this.startDate = this.endDate = dates[0]; else if (dates.length == 2){ this.date = this.startDate = dates[0]; @@ -132,5 +132,3 @@ Picker.Date.Range = new Class({ } }); - - diff --git a/package.yml b/package.yml index 2cd1a5c..a15ae8e 100644 --- a/package.yml +++ b/package.yml @@ -14,6 +14,7 @@ sources: - "Source/Picker.js" - "Source/Picker.Attach.js" - "Source/Picker.Date.js" + - "Source/Picker.Date.Range.js" - "Source/Locale.en-US.DatePicker.js" - "Source/Locale.cs-CZ.DatePicker.js" - "Source/Locale.de-DE.DatePicker.js" From 5cd7b6b1370963398adb6b68d4941755d54d77ce Mon Sep 17 00:00:00 2001 From: Arian Date: Mon, 25 Jul 2011 13:11:21 +0100 Subject: [PATCH 245/285] Always open the startView by default, fixes #53 --- Source/Picker.Date.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Source/Picker.Date.js b/Source/Picker.Date.js index 9befea4..7a69c88 100644 --- a/Source/Picker.Date.js +++ b/Source/Picker.Date.js @@ -35,6 +35,7 @@ this.DatePicker = Picker.Date = new Class({ startDay: 1, // Sunday (0) through Saturday (6) - be aware that this may affect your layout, since the days on the right might have a different margin startView: 'days', // allowed values: {time, days, months, years} + openLastView: false, pickOnly: false, // 'years', 'months', 'days', 'time' canAlwaysGoUp: ['months', 'days'], updateAll : false, //whether or not to update all inputs when selecting a date @@ -99,11 +100,12 @@ this.DatePicker = Picker.Date = new Class({ if (options.timePicker) options.format = (options.format) + (options.format ? ' ' : '') + Locale.get('Date.shortTime'); } - // This is where we store the selected date - this.currentView = options.startView; - // Some link or input has fired an event! this.addEvent('attached', function(event, element){ + + // This is where we store the selected date + if (!this.currentView || !options.openLastView) this.currentView = options.startView; + this.date = limitDate(new Date(), options.minDate, options.maxDate); var tag = element.get('tag'), input; if (tag == 'input') input = element; From 19fbd660a6728ac7a281524d338703f60d1d1b16 Mon Sep 17 00:00:00 2001 From: Arian Date: Mon, 25 Jul 2011 13:13:00 +0100 Subject: [PATCH 246/285] Range: Change the `setStartEndDate` a bit so it does all the formatting of the input field and set the default number of columns to 3 --- Source/Picker.Date.Range.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Source/Picker.Date.Range.js b/Source/Picker.Date.Range.js index 8217471..80e8902 100644 --- a/Source/Picker.Date.Range.js +++ b/Source/Picker.Date.Range.js @@ -20,9 +20,12 @@ Picker.Date.Range = new Class({ }).clean(); }, setStartEndDate: function(input, dates){ - input.set('value', dates.join(' - ')); + input.set('value', dates.map(function(date){ + return date.format(this.options.format); + }, this).join(' - ')); }, - footer: true + footer: true, + columns: 3 }, getInputDate: function(input){ @@ -33,7 +36,7 @@ Picker.Date.Range = new Class({ if (!dates || !dates.length || dates.some(function(date){ return !Date.isValid(date); })){ - dates = this.options.getStartEndDate(input); + dates = this.options.getStartEndDate.call(this, input); if (!dates.length || !dates.every(function(date){ return Date.isValid(date); })) dates = [this.date]; @@ -101,10 +104,7 @@ Picker.Date.Range = new Class({ return date.strftime(); })); - this.options.setStartEndDate(input, [ - this.startInput.get('value'), - this.endInput.get('value') - ]); + this.options.setStartEndDate.call(this, input, dates); this.fireEvent('select', dates); this.close(); From 47c6c5cf240d2ba71f76fdb4a7d7a0ebbf7c1b29 Mon Sep 17 00:00:00 2001 From: Arian Date: Mon, 25 Jul 2011 13:13:09 +0100 Subject: [PATCH 247/285] Update README --- README.md | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f203e7c..b44c670 100644 --- a/README.md +++ b/README.md @@ -106,6 +106,7 @@ All the options of the Picker and Picker.Attach classes, and: - yearPicker: (*boolean*, defaults to `true`) Enable/disable yearpicker functionality. Makes it much easier to change years. - yearPerPage: (*number*, defaults to `20`) Amount of years to show in the year-picking view. Be aware that this may affect your layout. - startView: (*string*, defaults to `days`) The view that will be showed when the picker opens. The options are `time`, `days`, `months` and `years` +- openLastView: (*boolean*, defaults to `false`) Opens the last opened view after the picker is opened again, instead of the `startView` - pickOnly: (*string*, defaults to `false`) If you just want to pick a year, month, day or time. The options are `time`, `days`, `months` and `years` - canAlwaysGoUp: (*array*, defaults to `['months', 'days']`) The views where you can click the title to go up. The options are `time`, `days`, `months` and `years` - updateAll (*boolean*, defaults to `false`) whether or not to update all inputs when selecting a date @@ -143,7 +144,6 @@ All the options of the Picker and Picker.Attach classes, and: } }); - Picker.Date method: select -------------------------- @@ -163,6 +163,28 @@ Selects a date manually. - Picker.Date instance. +Class: Picker.Date.Range +------------------------ + +The range picker can be used to select date ranges, with a start date and a end date. + +### Syntax: + + #JS + var dp = new Picker.Date.Range([element, options]); + +### Arguments: + +#### Options: + +All `Picker.Date` options plus: + +- getStartEndDate: (*function*) Parses the two dates in the input field to `Date` instances. Signature: `function(input)` +- setStartEndDate: (*function*) Formats the dates and sets the input field value. Signature: `function(input, dates)` +- columns: (*number*, defaults to `3`) Number of columns +- footer: (*boolean*, defaults to `true`) Creates an extra footer element + + Class: Picker.Attach -------------------- @@ -227,6 +249,8 @@ This is a generic Picker Class, which is used for the basic things, like positio - positionOffset: (*object*, defaults to `{x: 0, y: 0}`) Allows you to tweak the position at which the datepicker appears, relative to the input element. Formatted as an object with x and y properties. Values can be negative. - pickerPosition: (*string*, defaults to `bottom`) If the picker is positioned relative to an element, you can choose to position it top, bottom, left or right. - draggable: (*boolean*, defaults to `true`) Will make the picker draggable, if Drag from MooTools More is included. +- columns: (*number*, defaults to `1`) Number of columns +- footer: (*boolean*, defaults to `false`) Creates an extra footer element #### Events: From 2b5d603f09e18d589eb90f4df898797d9cfd7656 Mon Sep 17 00:00:00 2001 From: Arian Date: Mon, 25 Jul 2011 14:26:41 +0100 Subject: [PATCH 248/285] Fixes #58 - Fires the onchange event after a date is selected --- Source/Picker.Date.Range.js | 6 ++---- Source/Picker.Date.js | 3 +-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Source/Picker.Date.Range.js b/Source/Picker.Date.Range.js index 80e8902..28b8664 100644 --- a/Source/Picker.Date.Range.js +++ b/Source/Picker.Date.Range.js @@ -100,15 +100,13 @@ Picker.Date.Range = new Class({ this.date = this.startDate; var dates = [this.startDate, this.endDate], input = this.input; + this.options.setStartEndDate.call(this, input, dates); input.store('datepicker:value', dates.map(function(date){ return date.strftime(); - })); - - this.options.setStartEndDate.call(this, input, dates); + })).fireEvent('change'); this.fireEvent('select', dates); this.close(); - input.blur(); return this; }, diff --git a/Source/Picker.Date.js b/Source/Picker.Date.js index 7a69c88..50376c6 100644 --- a/Source/Picker.Date.js +++ b/Source/Picker.Date.js @@ -365,8 +365,7 @@ this.DatePicker = Picker.Date = new Class({ inputs = (!this.options.updateAll && !all && this.input) ? [this.input] : this.inputs; inputs.each(function(input){ - input.set('value', formatted) - .store('datepicker:value', time) + input.set('value', formatted).store('datepicker:value', time).fireEvent('change'); }, this); this.fireEvent('select', date); From 311d9e0e9bd9b9105c9d40e356c59a3952c0ff49 Mon Sep 17 00:00:00 2001 From: Arian Date: Mon, 25 Jul 2011 14:42:08 +0100 Subject: [PATCH 249/285] Fixes #57 - Pass the input field as argument to the select event --- Source/Picker.Date.Range.js | 2 +- Source/Picker.Date.js | 2 +- Test/events.html | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Source/Picker.Date.Range.js b/Source/Picker.Date.Range.js index 28b8664..1e31b43 100644 --- a/Source/Picker.Date.Range.js +++ b/Source/Picker.Date.Range.js @@ -105,7 +105,7 @@ Picker.Date.Range = new Class({ return date.strftime(); })).fireEvent('change'); - this.fireEvent('select', dates); + this.fireEvent('select', dates, input); this.close(); return this; }, diff --git a/Source/Picker.Date.js b/Source/Picker.Date.js index 50376c6..0b70c30 100644 --- a/Source/Picker.Date.js +++ b/Source/Picker.Date.js @@ -368,7 +368,7 @@ this.DatePicker = Picker.Date = new Class({ input.set('value', formatted).store('datepicker:value', time).fireEvent('change'); }, this); - this.fireEvent('select', date); + this.fireEvent('select', [date].concat(inputs)); this.close(); return this; } diff --git a/Test/events.html b/Test/events.html index 6aa0aae..ca383bb 100644 --- a/Test/events.html +++ b/Test/events.html @@ -33,7 +33,8 @@ onClose: function(){ debug.tween('#AAA'); }, - onSelect: function(date){ + onSelect: function(date, input){ + input.highlight(); debug.set('text', date.format('%c')); } }); From 1a5fa614dcb75eea20ec41be0b7deeefb51a7987 Mon Sep 17 00:00:00 2001 From: Arian Date: Mon, 25 Jul 2011 15:00:01 +0100 Subject: [PATCH 250/285] Testcase for #39 - could not reproduce --- Test/picker.position.html | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Test/picker.position.html b/Test/picker.position.html index 8cc2cb5..ccf01ff 100644 --- a/Test/picker.position.html +++ b/Test/picker.position.html @@ -21,10 +21,11 @@ @@ -67,6 +80,10 @@

      Position the Picker

      Open Close Toggle +

      From 8eaaade715ef471ff45a83dfb6b66d608305ae86 Mon Sep 17 00:00:00 2001 From: Arian Date: Mon, 25 Jul 2011 15:09:36 +0100 Subject: [PATCH 251/285] =?UTF-8?q?Testcase=20for=20#28,=20seems=20to=20be?= =?UTF-8?q?=20fixed.=20The=20=C2=BB=20disappeared=20sometimes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Test/minmaxdate.html | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Test/minmaxdate.html b/Test/minmaxdate.html index 7e356e4..4f717d7 100644 --- a/Test/minmaxdate.html +++ b/Test/minmaxdate.html @@ -74,6 +74,13 @@ invertAvailable: true }); + new Picker.Date('myInput5', { + yearPicker: false, + draggable: false, + format: '%e %b %Y', + allowEmpty: false, + maxDate: Date.parse(' 6 Dec 2010') + }); }); @@ -106,6 +113,10 @@

      Min and Max dates

      Input (invert previously available dates):

      +

      + Input with only maxDate:
      + +

      From a26a1557914dc58374add4e72fe8308c8f8fa640 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rouven=20We=C3=9Fling?= Date: Mon, 18 Jul 2011 23:15:58 +0200 Subject: [PATCH 252/285] Improve accessiblity. Change all the day views to use tables instead of divs. Add support for WAI-ARIA. Based on WAI-ARIA 1.0 Authoring Practices Working Draft. http://www.w3.org/TR/2010/WD-wai-aria-practices-20100916/ --- Source/Picker.Date.js | 21 ++++++++++++------- Source/Picker.js | 15 ++++++++++--- Source/datepicker.css | 9 ++++++++ .../datepicker_dashboard.css | 10 +++++++++ Source/datepicker_jqui/datepicker_jqui.css | 9 ++++++++ Source/datepicker_vista/datepicker_vista.css | 9 ++++++++ 6 files changed, 63 insertions(+), 10 deletions(-) diff --git a/Source/Picker.Date.js b/Source/Picker.Date.js index 0b70c30..e94b654 100644 --- a/Source/Picker.Date.js +++ b/Source/Picker.Date.js @@ -425,6 +425,7 @@ var renderers = { if (year == today.get('year')) classes += '.today'; if (year == currentDate.get('year')) classes += '.selected'; element = new Element('div' + classes, {text: year}).inject(container); + dateElements.push({element: element, time: _year}); if (isUnavailable('year', date, options)) element.addClass('unavailable'); @@ -450,6 +451,7 @@ var renderers = { if (i == month && year == thisyear) classes += '.today'; if (i == currentDate.get('month') && year == selectedyear) classes += '.selected'; element = new Element('div' + classes, {text: monthsAbbr[i]}).inject(container); + dateElements.push({element: element, time: _month}); if (isUnavailable('month', date, options)) element.addClass('unavailable'); @@ -463,14 +465,17 @@ var renderers = { var month = new Date(days[14]).get('month'), todayString = new Date().toDateString(), currentString = currentDate.toDateString(), - container = new Element('div.days'), - titles = new Element('div.titles').inject(container), + container = new Element('table.days', {role: 'grid', 'aria-labelledby': this.titleId}), + header = new Element('thead').inject(container), + body = new Element('tbody').inject(container), + titles = new Element('tr.titles').inject(header), localeDaysShort = options.days_abbr || Locale.get('Date.days_abbr'), day, classes, element, weekcontainer, dateString; for (day = options.startDay; day < (options.startDay + 7); day++){ - new Element('div.title.day.day' + (day % 7), { - text: localeDaysShort[(day % 7)] + new Element('th.title.day.day' + (day % 7), { + text: localeDaysShort[(day % 7)], + role: 'columnheader' }).inject(titles); } @@ -478,16 +483,18 @@ var renderers = { var date = new Date(_date); if (i % 7 == 0){ - weekcontainer = new Element('div.week.week' + (Math.floor(i / 7))).inject(container); + weekcontainer = new Element('tr.week.week' + (Math.floor(i / 7))).set('role', 'row').inject(body); } dateString = date.toDateString(); classes = '.day.day' + date.get('day'); if (dateString == todayString) classes += '.today'; - if (dateString == currentString) classes += '.selected'; if (date.get('month') != month) classes += '.otherMonth'; + element = new Element('td' + classes, {text: date.getDate(), role: 'gridcell'}).inject(weekcontainer); + + if (dateString == currentString) element.addClass('selected').set('aria-selected', 'true'); + else element.set('aria-selected', 'false'); - element = new Element('div' + classes, {text: date.getDate()}).inject(weekcontainer); dateElements.push({element: element, time: _date}); if (isUnavailable('date', date, options)) element.addClass('unavailable'); diff --git a/Source/Picker.js b/Source/Picker.js index 107346e..72d860e 100644 --- a/Source/Picker.js +++ b/Source/Picker.js @@ -62,9 +62,16 @@ var Picker = new Class({ var header = this.header = new Element('div.header').inject(picker); var title = this.title = new Element('div.title').inject(header); - this.titleText = new Element('div.titleText').inject(title); - - this.closeButton = new Element('div.closeButton[text=x]') + this.titleId = 'pickertitle-'+String.uniqueID(); + this.titleText = new Element('div', { + role: 'heading', + 'class': 'titleText', + id: this.titleId, + 'aria-live': 'assertive', + 'aria-atomic': 'true' + }).inject(title); + + this.closeButton = new Element('div.closeButton[text=x][role=button]') .addEvent('click', this.close.pass(false, this)) .inject(header); @@ -122,6 +129,7 @@ var Picker = new Class({ if (this.opened == true) return this; this.opened = true; var picker = this.picker.setStyle('display', 'block'); + picker.set('aria-hidden', 'false'); if (this.shim) this.shim.show(); this.fireEvent('open'); if (this.options.useFadeInOut && !noFx){ @@ -143,6 +151,7 @@ var Picker = new Class({ this.fireEvent('close'); var self = this, picker = this.picker, hide = function(){ picker.setStyle('display', 'none'); + picker.set('aria-hidden', 'true'); if (self.shim) self.shim.hide(); self.fireEvent('hide'); }; diff --git a/Source/datepicker.css b/Source/datepicker.css index fc573a4..b6ae4cc 100644 --- a/Source/datepicker.css +++ b/Source/datepicker.css @@ -276,3 +276,12 @@ background: #5D6E95 !important; color: #fff !important; } + +.datepicker_dashboard table { + border-spacing: 0; +} + +.datepicker_dashboard th, +.datepicker_dashboard td { + padding: 0; +} diff --git a/Source/datepicker_dashboard/datepicker_dashboard.css b/Source/datepicker_dashboard/datepicker_dashboard.css index 3b8f06f..760910d 100644 --- a/Source/datepicker_dashboard/datepicker_dashboard.css +++ b/Source/datepicker_dashboard/datepicker_dashboard.css @@ -130,6 +130,7 @@ padding-top: 1px; height: 14px; margin: 0 1px 1px 0; + font-weight: normal; } .datepicker_dashboard .days .titles { height: 15px; @@ -243,3 +244,12 @@ cursor: default !important; text-decoration: line-through; } + +.datepicker_dashboard table { + border-spacing: 0; +} + +.datepicker_dashboard th, +.datepicker_dashboard td { + padding: 0; +} diff --git a/Source/datepicker_jqui/datepicker_jqui.css b/Source/datepicker_jqui/datepicker_jqui.css index 2d12d5b..1aa369b 100644 --- a/Source/datepicker_jqui/datepicker_jqui.css +++ b/Source/datepicker_jqui/datepicker_jqui.css @@ -278,3 +278,12 @@ color: #ccc !important; border: 1px solid #ccc !important; } + +.datepicker_dashboard table { + border-spacing: 0; +} + +.datepicker_dashboard th, +.datepicker_dashboard td { + padding: 0; +} diff --git a/Source/datepicker_vista/datepicker_vista.css b/Source/datepicker_vista/datepicker_vista.css index ae02e6f..6f379ed 100644 --- a/Source/datepicker_vista/datepicker_vista.css +++ b/Source/datepicker_vista/datepicker_vista.css @@ -245,3 +245,12 @@ color: #fbb !important; cursor: default !important; } + +.datepicker_dashboard table { + border-spacing: 0; +} + +.datepicker_dashboard th, +.datepicker_dashboard td { + padding: 0; +} From 7f76b92e89df91f515f9af7b65f3c1aba673bb4a Mon Sep 17 00:00:00 2001 From: Arian Date: Mon, 25 Jul 2011 13:30:49 +0100 Subject: [PATCH 253/285] Some cleanups for the aria changes --- Source/Picker.Date.js | 2 +- Source/Picker.js | 14 ++++++-------- Source/datepicker.css | 6 +++--- Source/datepicker_jqui/datepicker_jqui.css | 6 +++--- Source/datepicker_vista/datepicker_vista.css | 6 +++--- 5 files changed, 16 insertions(+), 18 deletions(-) diff --git a/Source/Picker.Date.js b/Source/Picker.Date.js index e94b654..69ba278 100644 --- a/Source/Picker.Date.js +++ b/Source/Picker.Date.js @@ -465,7 +465,7 @@ var renderers = { var month = new Date(days[14]).get('month'), todayString = new Date().toDateString(), currentString = currentDate.toDateString(), - container = new Element('table.days', {role: 'grid', 'aria-labelledby': this.titleId}), + container = new Element('table.days', {role: 'grid', 'aria-labelledby': this.titleID}), header = new Element('thead').inject(container), body = new Element('tbody').inject(container), titles = new Element('tr.titles').inject(header), diff --git a/Source/Picker.js b/Source/Picker.js index 72d860e..7917f8d 100644 --- a/Source/Picker.js +++ b/Source/Picker.js @@ -62,14 +62,14 @@ var Picker = new Class({ var header = this.header = new Element('div.header').inject(picker); var title = this.title = new Element('div.title').inject(header); - this.titleId = 'pickertitle-'+String.uniqueID(); + var titleID = this.titleID = 'pickertitle-' + String.uniqueID(); this.titleText = new Element('div', { - role: 'heading', + 'role': 'heading', 'class': 'titleText', - id: this.titleId, + 'id': titleID, 'aria-live': 'assertive', 'aria-atomic': 'true' - }).inject(title); + }).inject(title); this.closeButton = new Element('div.closeButton[text=x][role=button]') .addEvent('click', this.close.pass(false, this)) @@ -128,8 +128,7 @@ var Picker = new Class({ open: function(noFx){ if (this.opened == true) return this; this.opened = true; - var picker = this.picker.setStyle('display', 'block'); - picker.set('aria-hidden', 'false'); + var picker = this.picker.setStyle('display', 'block').set('aria-hidden', 'false') if (this.shim) this.shim.show(); this.fireEvent('open'); if (this.options.useFadeInOut && !noFx){ @@ -150,8 +149,7 @@ var Picker = new Class({ this.opened = false; this.fireEvent('close'); var self = this, picker = this.picker, hide = function(){ - picker.setStyle('display', 'none'); - picker.set('aria-hidden', 'true'); + picker.setStyle('display', 'none').set('aria-hidden', 'true'); if (self.shim) self.shim.hide(); self.fireEvent('hide'); }; diff --git a/Source/datepicker.css b/Source/datepicker.css index b6ae4cc..35fd2e2 100644 --- a/Source/datepicker.css +++ b/Source/datepicker.css @@ -277,11 +277,11 @@ color: #fff !important; } -.datepicker_dashboard table { +.datepicker table { border-spacing: 0; } -.datepicker_dashboard th, -.datepicker_dashboard td { +.datepicker th, +.datepicker td { padding: 0; } diff --git a/Source/datepicker_jqui/datepicker_jqui.css b/Source/datepicker_jqui/datepicker_jqui.css index 1aa369b..902db5b 100644 --- a/Source/datepicker_jqui/datepicker_jqui.css +++ b/Source/datepicker_jqui/datepicker_jqui.css @@ -279,11 +279,11 @@ border: 1px solid #ccc !important; } -.datepicker_dashboard table { +.datepicker_jqui table { border-spacing: 0; } -.datepicker_dashboard th, -.datepicker_dashboard td { +.datepicker_jqui th, +.datepicker_jqui td { padding: 0; } diff --git a/Source/datepicker_vista/datepicker_vista.css b/Source/datepicker_vista/datepicker_vista.css index 6f379ed..9276730 100644 --- a/Source/datepicker_vista/datepicker_vista.css +++ b/Source/datepicker_vista/datepicker_vista.css @@ -246,11 +246,11 @@ cursor: default !important; } -.datepicker_dashboard table { +.datepicker_vista table { border-spacing: 0; } -.datepicker_dashboard th, -.datepicker_dashboard td { +.datepicker_vista th, +.datepicker_vista td { padding: 0; } From 78c58ddbdbbea8c8dfba790b713136eefff7aade Mon Sep 17 00:00:00 2001 From: Arian Date: Mon, 25 Jul 2011 15:44:12 +0100 Subject: [PATCH 254/285] Fixes #7 - Add support for weeknumbers in the `days` view --- README.md | 1 + Source/Locale.en-US.DatePicker.js | 3 ++- Source/Locale.nl-NL.DatePicker.js | 3 ++- Source/Picker.Date.js | 11 ++++++++- Source/datepicker.css | 11 +++++++++ Test/index.html | 1 + Test/weeknumbers.html | 37 +++++++++++++++++++++++++++++++ 7 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 Test/weeknumbers.html diff --git a/README.md b/README.md index b44c670..77de52a 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,7 @@ All the options of the Picker and Picker.Attach classes, and: - pickOnly: (*string*, defaults to `false`) If you just want to pick a year, month, day or time. The options are `time`, `days`, `months` and `years` - canAlwaysGoUp: (*array*, defaults to `['months', 'days']`) The views where you can click the title to go up. The options are `time`, `days`, `months` and `years` - updateAll (*boolean*, defaults to `false`) whether or not to update all inputs when selecting a date +- weeknumbers (*boolean*, defaults to `false`) display weeknumbers for the `days` view - months_abbr: (*array*) An array with the month name abbreviations. If nothing is set, it will automatically use MooTools Locale to get the abbreviations - days_abbr: (*array*) An array with the day name abbreviations. If nothing is set, it will automatically use MooTools Locale to get the abbreviations - years_title: (*function*, defaults to a function which returns `year + '-' + (year + options.yearsPerPage - 1)`) A function that returns the title for the yearpicker with as arguments the date object and the options object. diff --git a/Source/Locale.en-US.DatePicker.js b/Source/Locale.en-US.DatePicker.js index 17e6f33..fc69c25 100644 --- a/Source/Locale.en-US.DatePicker.js +++ b/Source/Locale.en-US.DatePicker.js @@ -14,5 +14,6 @@ Locale.define('en-US', 'DatePicker', { use_mouse_wheel: 'Use the mouse wheel to quickly change value', time_confirm_button: 'OK', apply_range: 'Apply', - cancel: 'Cancel' + cancel: 'Cancel', + week: 'Wk' }); diff --git a/Source/Locale.nl-NL.DatePicker.js b/Source/Locale.nl-NL.DatePicker.js index 6eab7f2..471fd72 100644 --- a/Source/Locale.nl-NL.DatePicker.js +++ b/Source/Locale.nl-NL.DatePicker.js @@ -14,5 +14,6 @@ Locale.define('nl-NL', 'DatePicker', { use_mouse_wheel: 'Gebruik uw scrollwiel om door de tijd te scrollen', time_confirm_button: 'OK', apply_range: 'OK', - cancel: 'Annuleer' + cancel: 'Annuleer', + week: 'W' }); diff --git a/Source/Picker.Date.js b/Source/Picker.Date.js index 69ba278..ff57df5 100644 --- a/Source/Picker.Date.js +++ b/Source/Picker.Date.js @@ -40,6 +40,8 @@ this.DatePicker = Picker.Date = new Class({ canAlwaysGoUp: ['months', 'days'], updateAll : false, //whether or not to update all inputs when selecting a date + weeknumbers: false, + // if you like to use your own translations months_abbr: null, days_abbr: null, @@ -465,13 +467,19 @@ var renderers = { var month = new Date(days[14]).get('month'), todayString = new Date().toDateString(), currentString = currentDate.toDateString(), - container = new Element('table.days', {role: 'grid', 'aria-labelledby': this.titleID}), + weeknumbers = options.weeknumbers, + container = new Element('table.days' + (weeknumbers ? '.weeknumbers' : ''), { + role: 'grid', 'aria-labelledby': this.titleID + }), header = new Element('thead').inject(container), body = new Element('tbody').inject(container), titles = new Element('tr.titles').inject(header), localeDaysShort = options.days_abbr || Locale.get('Date.days_abbr'), day, classes, element, weekcontainer, dateString; + if (weeknumbers) new Element('th.title.day.weeknumber', { + text: Locale.get('DatePicker.week') + }).inject(titles); for (day = options.startDay; day < (options.startDay + 7); day++){ new Element('th.title.day.day' + (day % 7), { text: localeDaysShort[(day % 7)], @@ -484,6 +492,7 @@ var renderers = { if (i % 7 == 0){ weekcontainer = new Element('tr.week.week' + (Math.floor(i / 7))).set('role', 'row').inject(body); + if (weeknumbers) new Element('td.day.weeknumber', {text: date.get('week')}).inject(weekcontainer); } dateString = date.toDateString(); diff --git a/Source/datepicker.css b/Source/datepicker.css index 35fd2e2..e182958 100644 --- a/Source/datepicker.css +++ b/Source/datepicker.css @@ -277,6 +277,17 @@ color: #fff !important; } +.datepicker .days.weeknumbers .day { + width: 22px; +} + +.datepicker .days.weeknumbers .day.weeknumber, +.datepicker .days.weeknumbers .day.weeknumber:hover { + color: #AAA !important; + width: 16px !important; + background: #EEE !important; +} + .datepicker table { border-spacing: 0; } diff --git a/Test/index.html b/Test/index.html index ff38c13..28881bc 100644 --- a/Test/index.html +++ b/Test/index.html @@ -31,6 +31,7 @@

      Demos & Tests

    • Time Picker
    • Month Picker
    • Year Picker
    • +
    • Weeknumbers
    • Ranges
    • Localization
    • Min/Max Date option
    • diff --git a/Test/weeknumbers.html b/Test/weeknumbers.html new file mode 100644 index 0000000..5ffa5c0 --- /dev/null +++ b/Test/weeknumbers.html @@ -0,0 +1,37 @@ + + + + + Full Date and TimePicker + + + + + + + + + + + + + + + +

      Multiple Columns

      + +

      + Inputs:
      + +

      + + + + + From 510ca67bdd2a70d14d7c7b5d232f6be579258d10 Mon Sep 17 00:00:00 2001 From: Arian Date: Mon, 25 Jul 2011 15:49:20 +0100 Subject: [PATCH 255/285] Fix weeknumbers test title --- Test/weeknumbers.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Test/weeknumbers.html b/Test/weeknumbers.html index 5ffa5c0..44dd40e 100644 --- a/Test/weeknumbers.html +++ b/Test/weeknumbers.html @@ -18,7 +18,7 @@ -

      Multiple Columns

      +

      Weeknumbers

      Inputs:
      From 638de1e0534e26c11f992264333a09c9188df936 Mon Sep 17 00:00:00 2001 From: Arian Date: Mon, 25 Jul 2011 15:49:47 +0100 Subject: [PATCH 256/285] Version bumb --- package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.yml b/package.yml index a15ae8e..58033b4 100644 --- a/package.yml +++ b/package.yml @@ -1,6 +1,6 @@ name: MooTools-DatePicker author: astolwijk -current: 2.0.4 +current: 2.1.0 category: Widgets tags: [Datepicker, Calendar, Picker] demo: http://www.aryweb.nl/projects/mootools-datepicker/ From b2ca29de30b53ce4cbac1d7523598b603184dad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rouven=20We=C3=9Fling?= Date: Thu, 28 Jul 2011 13:20:18 +0200 Subject: [PATCH 257/285] Accessibility improvement for the week number. --- Source/Picker.Date.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Picker.Date.js b/Source/Picker.Date.js index ff57df5..4f56553 100644 --- a/Source/Picker.Date.js +++ b/Source/Picker.Date.js @@ -492,7 +492,7 @@ var renderers = { if (i % 7 == 0){ weekcontainer = new Element('tr.week.week' + (Math.floor(i / 7))).set('role', 'row').inject(body); - if (weeknumbers) new Element('td.day.weeknumber', {text: date.get('week')}).inject(weekcontainer); + if (weeknumbers) new Element('th.day.weeknumber', {text: date.get('week'), scope: 'row', role: 'rowheader'}).inject(weekcontainer); } dateString = date.toDateString(); From b389c6065aaa90bc2da74d05bde593cc6b608327 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rouven=20We=C3=9Fling?= Date: Thu, 28 Jul 2011 13:33:17 +0200 Subject: [PATCH 258/285] Add RTL support to the days view. --- Source/Picker.Date.js | 18 +++++++++++++----- Test/rtl.html | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 5 deletions(-) create mode 100644 Test/rtl.html diff --git a/Source/Picker.Date.js b/Source/Picker.Date.js index 4f56553..ad8cef0 100644 --- a/Source/Picker.Date.js +++ b/Source/Picker.Date.js @@ -33,6 +33,7 @@ this.DatePicker = Picker.Date = new Class({ yearsPerPage: 20, startDay: 1, // Sunday (0) through Saturday (6) - be aware that this may affect your layout, since the days on the right might have a different margin + rtl: false, startView: 'days', // allowed values: {time, days, months, years} openLastView: false, @@ -138,8 +139,13 @@ this.DatePicker = Picker.Date = new Class({ constructPicker: function(){ this.parent(); - this.previous = new Element('div.previous[html=«]').inject(this.header); - this.next = new Element('div.next[html=»]').inject(this.header); + if (!this.options.rtl){ + this.previous = new Element('div.previous[html=«]').inject(this.header); + this.next = new Element('div.next[html=»]').inject(this.header); + } else { + this.next = new Element('div.previous[html=«]').inject(this.header); + this.previous = new Element('div.next[html=»]').inject(this.header); + } }, hidePrevious: function(_next, _show){ @@ -475,16 +481,18 @@ var renderers = { body = new Element('tbody').inject(container), titles = new Element('tr.titles').inject(header), localeDaysShort = options.days_abbr || Locale.get('Date.days_abbr'), - day, classes, element, weekcontainer, dateString; + day, classes, element, weekcontainer, dateString + where = options.rtl ? 'top' : 'bottom'; if (weeknumbers) new Element('th.title.day.weeknumber', { text: Locale.get('DatePicker.week') }).inject(titles); + for (day = options.startDay; day < (options.startDay + 7); day++){ new Element('th.title.day.day' + (day % 7), { text: localeDaysShort[(day % 7)], role: 'columnheader' - }).inject(titles); + }).inject(titles, where); } days.each(function(_date, i){ @@ -499,7 +507,7 @@ var renderers = { classes = '.day.day' + date.get('day'); if (dateString == todayString) classes += '.today'; if (date.get('month') != month) classes += '.otherMonth'; - element = new Element('td' + classes, {text: date.getDate(), role: 'gridcell'}).inject(weekcontainer); + element = new Element('td' + classes, {text: date.getDate(), role: 'gridcell'}).inject(weekcontainer, where); if (dateString == currentString) element.addClass('selected').set('aria-selected', 'true'); else element.set('aria-selected', 'false'); diff --git a/Test/rtl.html b/Test/rtl.html new file mode 100644 index 0000000..9779c10 --- /dev/null +++ b/Test/rtl.html @@ -0,0 +1,38 @@ + + + + + Full Date and TimePicker + + + + + + + + + + + + + + + +

      RTL

      + +

      + Inputs:
      + +

      + + + + + From 75f909335b773e4b604725c36709ea6e3be2cdb6 Mon Sep 17 00:00:00 2001 From: Arian Stolwijk Date: Thu, 28 Jul 2011 14:26:03 +0200 Subject: [PATCH 259/285] Fix syntax error. --- Source/Picker.Date.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Picker.Date.js b/Source/Picker.Date.js index ad8cef0..fda87ec 100644 --- a/Source/Picker.Date.js +++ b/Source/Picker.Date.js @@ -481,7 +481,7 @@ var renderers = { body = new Element('tbody').inject(container), titles = new Element('tr.titles').inject(header), localeDaysShort = options.days_abbr || Locale.get('Date.days_abbr'), - day, classes, element, weekcontainer, dateString + day, classes, element, weekcontainer, dateString, where = options.rtl ? 'top' : 'bottom'; if (weeknumbers) new Element('th.title.day.weeknumber', { From cfdcd305d94a2c99d1b9ae727acda0f9f79ff535 Mon Sep 17 00:00:00 2001 From: Arian Stolwijk Date: Fri, 29 Jul 2011 12:13:15 +0200 Subject: [PATCH 260/285] Fixes #60 - French Typo --- Source/Locale.fr-FR.DatePicker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Locale.fr-FR.DatePicker.js b/Source/Locale.fr-FR.DatePicker.js index 3f4c1d1..c66957d 100644 --- a/Source/Locale.fr-FR.DatePicker.js +++ b/Source/Locale.fr-FR.DatePicker.js @@ -11,6 +11,6 @@ provides: Locale.fr-FR.DatePicker Locale.define('fr-FR', 'DatePicker', { select_a_time: 'Choisir l\'heure', - use_mouse_wheel: 'Utiliser la molette pour changer l\'heure rapiedment', + use_mouse_wheel: 'Utiliser la molette pour changer l\'heure rapidement', time_confirm_button: 'OK' }); From 80411b226e534d51d4123f3cdfc0a10e11b5b124 Mon Sep 17 00:00:00 2001 From: Abric Armand Date: Fri, 29 Jul 2011 20:54:36 +0300 Subject: [PATCH 261/285] Update FR language. --- Source/Locale.fr-FR.DatePicker.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Source/Locale.fr-FR.DatePicker.js b/Source/Locale.fr-FR.DatePicker.js index c66957d..dae4c44 100644 --- a/Source/Locale.fr-FR.DatePicker.js +++ b/Source/Locale.fr-FR.DatePicker.js @@ -2,15 +2,17 @@ --- name: Locale.fr-FR.DatePicker description: French Language File for DatePicker -authors: ["Arian Stolwijk", "charlouze"] +authors: ["Arian Stolwijk", "charlouze", "Abric Armand"] requires: [More/Locale] provides: Locale.fr-FR.DatePicker ... */ - Locale.define('fr-FR', 'DatePicker', { select_a_time: 'Choisir l\'heure', use_mouse_wheel: 'Utiliser la molette pour changer l\'heure rapidement', time_confirm_button: 'OK' -}); + apply_range: 'Appliquer', + cancel: 'Annuler', + week: 'Sem' +}); \ No newline at end of file From 751ea2f435c17580e27369404cf04b054a097d8e Mon Sep 17 00:00:00 2001 From: Jonnathan Soares Date: Fri, 29 Jul 2011 16:04:32 -0300 Subject: [PATCH 262/285] Add Portuguese translation --- Source/Locale.pt-BR.DatePicker.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 Source/Locale.pt-BR.DatePicker.js diff --git a/Source/Locale.pt-BR.DatePicker.js b/Source/Locale.pt-BR.DatePicker.js new file mode 100644 index 0000000..97d5f8e --- /dev/null +++ b/Source/Locale.pt-BR.DatePicker.js @@ -0,0 +1,19 @@ +/* +--- +name: Locale.pt-BR.DatePicker +description: Portuguese Language File for DatePicker +authors: Jonnathan Soares +requires: [More/Locale] +provides: Locale.pt-BR.DatePicker +... +*/ + + +Locale.define('pt-BR', 'DatePicker', { + select_a_time: 'Selecione uma hora', + use_mouse_wheel: 'Use a roda do mouse para rapidamente trocar de valor', + time_confirm_button: 'OK', + apply_range: 'Aplicar', + cancel: 'Cancelar', + week: 'Sem.' +}); From 4efee6a9198d9cc9e37d29b543685300887a614c Mon Sep 17 00:00:00 2001 From: Arian Stolwijk Date: Sat, 30 Jul 2011 04:48:34 +0200 Subject: [PATCH 263/285] Add Brazil Portuguese to the supported languages --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 77de52a..f4eac46 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,7 @@ Currently the following languages are supported - it-IT - nl-NL - pl-PL +- pt-BR - ru-RU You can set the current language with: From af178f1a9982af59d38069a95275aaacf0e2a170 Mon Sep 17 00:00:00 2001 From: Arian Stolwijk Date: Sat, 30 Jul 2011 05:09:15 +0200 Subject: [PATCH 264/285] newline --- Source/Locale.fr-FR.DatePicker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Locale.fr-FR.DatePicker.js b/Source/Locale.fr-FR.DatePicker.js index dae4c44..863a1d7 100644 --- a/Source/Locale.fr-FR.DatePicker.js +++ b/Source/Locale.fr-FR.DatePicker.js @@ -15,4 +15,4 @@ Locale.define('fr-FR', 'DatePicker', { apply_range: 'Appliquer', cancel: 'Annuler', week: 'Sem' -}); \ No newline at end of file +}); From e7f494b055c27af0a5c942a60a005d19a703765f Mon Sep 17 00:00:00 2001 From: Arian Date: Thu, 18 Aug 2011 15:38:31 +0200 Subject: [PATCH 265/285] Add the togglesOnly option to Picker.Attach so when the toggle option is set, you can still open/close the picker with the input focus/blur events Credits to Koen Cuelenaere / http://dalicon.com --- README.md | 1 + Source/Picker.Attach.js | 5 +++-- Test/toggler.html | 16 ++++++++++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f4eac46..466165e 100644 --- a/README.md +++ b/README.md @@ -202,6 +202,7 @@ This class adds a outerclick as well to close the Picker if you click outside th #### Options: - toggle: (*element*, *string*, *array*) A collection of elements which will toggle the picker when such a link is clicked. +- togglesOnly: (*boolean, defaults to `true`) If the `toggle` option is set, this option determines if the focus/blur events on the input fields are still added as well. - blockKeydown: (*boolean*, defaults to `true`) Whether it should block keydown events, so the user can type into the input field or not. ### Picker.Attach Method: attach diff --git a/Source/Picker.Attach.js b/Source/Picker.Attach.js index 3bfd2da..900159e 100644 --- a/Source/Picker.Attach.js +++ b/Source/Picker.Attach.js @@ -18,6 +18,7 @@ Picker.Attach = new Class({ toggleElements: null, // deprecated toggle: null, // When set it deactivate toggling by clicking on the input */ + togglesOnly: true, // set to false to always make calendar popup on input element, if true, it depends on the toggles elements set. showOnInit: false, // overrides the Picker option blockKeydown: true }, @@ -97,10 +98,10 @@ Picker.Attach = new Class({ openEvent = getOpenEvent(element), // closeEvent does not have a depency on element toggleEvent = getToggleEvent(openEvent, closeEvent); - + if (tag == 'input'){ // Fix in order to use togglers only - if (!toggles.length){ + if (!self.options.togglesOnly || !toggles.length){ events = { focus: openEvent, click: openEvent, diff --git a/Test/toggler.html b/Test/toggler.html index 29e0449..43b0005 100644 --- a/Test/toggler.html +++ b/Test/toggler.html @@ -21,6 +21,11 @@ toggle: $$('.myLink') }); + new Picker.Date($$('.myInput2'), { + toggle: $$('.myLink2'), + togglesOnly: false + }); + }); @@ -44,5 +49,16 @@

      Toggled by a link

      toggler

      +

      For these inputs it's both the input field and the toggle link

      + +

      + Input3:
      + toggler +

      + +

      + Input4:
      + toggler +

      From a31a482af32420e061318df0efdeeabbc3f5ca45 Mon Sep 17 00:00:00 2001 From: Arian Stolwijk Date: Sun, 21 Aug 2011 16:38:21 +0300 Subject: [PATCH 266/285] Fixes #68 - add missing comma in French Locale. --- Source/Locale.fr-FR.DatePicker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Locale.fr-FR.DatePicker.js b/Source/Locale.fr-FR.DatePicker.js index 863a1d7..f523685 100644 --- a/Source/Locale.fr-FR.DatePicker.js +++ b/Source/Locale.fr-FR.DatePicker.js @@ -11,7 +11,7 @@ provides: Locale.fr-FR.DatePicker Locale.define('fr-FR', 'DatePicker', { select_a_time: 'Choisir l\'heure', use_mouse_wheel: 'Utiliser la molette pour changer l\'heure rapidement', - time_confirm_button: 'OK' + time_confirm_button: 'OK', apply_range: 'Appliquer', cancel: 'Annuler', week: 'Sem' From efbeea4055be3648793b8a9eeb485b5f898a22b5 Mon Sep 17 00:00:00 2001 From: Amitay Horwitz Date: Tue, 20 Sep 2011 00:12:51 +0300 Subject: [PATCH 267/285] Added Hebrew locale --- Source/Locale.he-IL.DatePicker.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 Source/Locale.he-IL.DatePicker.js diff --git a/Source/Locale.he-IL.DatePicker.js b/Source/Locale.he-IL.DatePicker.js new file mode 100644 index 0000000..9d5297d --- /dev/null +++ b/Source/Locale.he-IL.DatePicker.js @@ -0,0 +1,19 @@ +/* +--- +name: Locale.he-IL.DatePicker +description: Hebrew Language File for DatePicker +authors: Amitay Horwitz +requires: [More/Locale] +provides: Locale.he-IL.DatePicker +... +*/ + + +Locale.define('he-IL', 'DatePicker', { + select_a_time: 'בחר זמן', + use_mouse_wheel: 'השתמש בגלגלת העכבר לשינוי מהיר', + time_confirm_button: 'אישור', + apply_range: 'החל', + cancel: 'ביטול', + week: 'שבוע' +}); From 0271f31f2b4540bad46adfdd76dc41e60df81330 Mon Sep 17 00:00:00 2001 From: Amitay Horwitz Date: Tue, 20 Sep 2011 00:13:55 +0300 Subject: [PATCH 268/285] Fixed unclickable dates bug --- Source/Picker.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Source/Picker.js b/Source/Picker.js index 7917f8d..d209c19 100644 --- a/Source/Picker.js +++ b/Source/Picker.js @@ -95,18 +95,18 @@ var Picker = new Class({ transition: Fx.Transitions.Quad.easeInOut }).inject(body); - this.oldContents = new Element('div', { + this.newContents = new Element('div', { styles: { position: 'absolute', - top: 0 + top: 0, + left: 0 } }).inject(slider); - this.newContents = new Element('div', { + this.oldContents = new Element('div', { styles: { position: 'absolute', - top: 0, - left: 0 + top: 0 } }).inject(slider); From 33c59543b99a3f22a2ce7f9aa16a891a2f38a8a7 Mon Sep 17 00:00:00 2001 From: Amitay Horwitz Date: Tue, 20 Sep 2011 18:54:17 +0300 Subject: [PATCH 269/285] Added Hebrew to the locale list in the readme file --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 466165e..772ddf1 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,7 @@ Currently the following languages are supported - pl-PL - pt-BR - ru-RU +- he-IL You can set the current language with: From ba3bedbcd3296191c73cd4f6df394431467651ed Mon Sep 17 00:00:00 2001 From: Arian Date: Wed, 21 Sep 2011 16:12:28 +0200 Subject: [PATCH 270/285] =?UTF-8?q?Fix=20some=20stylistic=20things=20(tabs?= =?UTF-8?q?=20=E2=86=92=20spaces,=20alphabetical=20locale=20list).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- Source/Picker.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 772ddf1..89beeba 100644 --- a/README.md +++ b/README.md @@ -68,12 +68,12 @@ Currently the following languages are supported - en-US - es-ES - fr-FR +- he-IL - it-IT - nl-NL - pl-PL - pt-BR - ru-RU -- he-IL You can set the current language with: diff --git a/Source/Picker.js b/Source/Picker.js index d209c19..45b2acc 100644 --- a/Source/Picker.js +++ b/Source/Picker.js @@ -95,7 +95,7 @@ var Picker = new Class({ transition: Fx.Transitions.Quad.easeInOut }).inject(body); - this.newContents = new Element('div', { + this.newContents = new Element('div', { styles: { position: 'absolute', top: 0, From 6597e9c0374fe535d6e5b1a3ffa4d238643af1f8 Mon Sep 17 00:00:00 2001 From: Arian Date: Wed, 21 Sep 2011 16:18:09 +0200 Subject: [PATCH 271/285] Update Tests to MooTools 1.4 --- Test/mootools-core.js | 809 +++++++++++++++++++++++------------------- Test/mootools-more.js | 41 +-- 2 files changed, 468 insertions(+), 382 deletions(-) diff --git a/Test/mootools-core.js b/Test/mootools-core.js index d35fd1d..d0f87f9 100644 --- a/Test/mootools-core.js +++ b/Test/mootools-core.js @@ -33,8 +33,8 @@ provides: [Core, MooTools, Type, typeOf, instanceOf, Native] (function(){ this.MooTools = { - version: '1.3.2', - build: 'c9f1ff10e9e7facb65e9481049ed1b450959d587' + version: '1.4.0', + build: 'a15e35b4dbd12e8d86d9b50aa67a27e8e0071ea3' }; // typeOf, instanceOf @@ -265,7 +265,7 @@ var force = function(name, object, methods){ force('String', String, [ 'charAt', 'charCodeAt', 'concat', 'indexOf', 'lastIndexOf', 'match', 'quote', 'replace', 'search', - 'slice', 'split', 'substr', 'substring', 'toLowerCase', 'toUpperCase' + 'slice', 'split', 'substr', 'substring', 'trim', 'toLowerCase', 'toUpperCase' ])('Array', Array, [ 'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice', 'indexOf', 'lastIndexOf', 'filter', 'forEach', 'every', 'map', 'some', 'reduce', 'reduceRight' @@ -421,7 +421,7 @@ Array.implement({ /**/ every: function(fn, bind){ - for (var i = 0, l = this.length; i < l; i++){ + for (var i = 0, l = this.length >>> 0; i < l; i++){ if ((i in this) && !fn.call(bind, this[i], i, this)) return false; } return true; @@ -429,30 +429,30 @@ Array.implement({ filter: function(fn, bind){ var results = []; - for (var i = 0, l = this.length; i < l; i++){ + for (var i = 0, l = this.length >>> 0; i < l; i++){ if ((i in this) && fn.call(bind, this[i], i, this)) results.push(this[i]); } return results; }, indexOf: function(item, from){ - var len = this.length; - for (var i = (from < 0) ? Math.max(0, len + from) : from || 0; i < len; i++){ + var length = this.length >>> 0; + for (var i = (from < 0) ? Math.max(0, length + from) : from || 0; i < length; i++){ if (this[i] === item) return i; } return -1; }, map: function(fn, bind){ - var results = []; - for (var i = 0, l = this.length; i < l; i++){ + var length = this.length >>> 0, results = Array(length); + for (var i = 0; i < length; i++){ if (i in this) results[i] = fn.call(bind, this[i], i, this); } return results; }, some: function(fn, bind){ - for (var i = 0, l = this.length; i < l; i++){ + for (var i = 0, l = this.length >>> 0; i < l; i++){ if ((i in this) && fn.call(bind, this[i], i, this)) return true; } return false; @@ -596,37 +596,37 @@ String.implement({ }, contains: function(string, separator){ - return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : this.indexOf(string) > -1; + return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : String(this).indexOf(string) > -1; }, trim: function(){ - return this.replace(/^\s+|\s+$/g, ''); + return String(this).replace(/^\s+|\s+$/g, ''); }, clean: function(){ - return this.replace(/\s+/g, ' ').trim(); + return String(this).replace(/\s+/g, ' ').trim(); }, camelCase: function(){ - return this.replace(/-\D/g, function(match){ + return String(this).replace(/-\D/g, function(match){ return match.charAt(1).toUpperCase(); }); }, hyphenate: function(){ - return this.replace(/[A-Z]/g, function(match){ + return String(this).replace(/[A-Z]/g, function(match){ return ('-' + match.charAt(0).toLowerCase()); }); }, capitalize: function(){ - return this.replace(/\b[a-z]/g, function(match){ + return String(this).replace(/\b[a-z]/g, function(match){ return match.toUpperCase(); }); }, escapeRegExp: function(){ - return this.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1'); + return String(this).replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1'); }, toInt: function(base){ @@ -638,17 +638,17 @@ String.implement({ }, hexToRgb: function(array){ - var hex = this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/); + var hex = String(this).match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/); return (hex) ? hex.slice(1).hexToRgb(array) : null; }, rgbToHex: function(array){ - var rgb = this.match(/\d{1,3}/g); + var rgb = String(this).match(/\d{1,3}/g); return (rgb) ? rgb.rgbToHex(array) : null; }, substitute: function(object, regexp){ - return this.replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){ + return String(this).replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){ if (match.charAt(0) == '\\') return match.slice(1); return (object[name] != null) ? object[name] : ''; }); @@ -750,18 +750,26 @@ Function.implement({ return null; }, - /**/ - bind: function(bind){ + /**/ + bind: function(that){ var self = this, - args = (arguments.length > 1) ? Array.slice(arguments, 1) : null; - - return function(){ - if (!args && !arguments.length) return self.call(bind); - if (args && arguments.length) return self.apply(bind, args.concat(Array.from(arguments))); - return self.apply(bind, args || arguments); + args = arguments.length > 1 ? Array.slice(arguments, 1) : null, + F = function(){}; + + var bound = function(){ + var context = that, length = arguments.length; + if (this instanceof bound){ + F.prototype = self.prototype; + context = new F; + } + var result = (!args && !length) + ? self.call(context) + : self.apply(context, args && length ? args.concat(Array.slice(arguments)) : args || arguments); + return context == that ? result : context; }; + return bound; }, - /**/ + /**/ pass: function(args, bind){ var self = this; @@ -1118,7 +1126,7 @@ try { name: Event -description: Contains the Event Class, to make the event object cross-browser. +description: Contains the Event Type, to make the event object cross-browser. license: MIT-style license. @@ -1129,52 +1137,54 @@ provides: Event ... */ -var Event = new Type('Event', function(event, win){ +(function() { + +var _keys = {}; + +var DOMEvent = this.DOMEvent = new Type('DOMEvent', function(event, win){ if (!win) win = window; - var doc = win.document; event = event || win.event; if (event.$extended) return event; + this.event = event; this.$extended = true; - var type = event.type, - target = event.target || event.srcElement, - page = {}, - client = {}, - related = null, - rightClick, wheel, code, key; + this.shift = event.shiftKey; + this.control = event.ctrlKey; + this.alt = event.altKey; + this.meta = event.metaKey; + var type = this.type = event.type; + var target = event.target || event.srcElement; while (target && target.nodeType == 3) target = target.parentNode; + this.target = document.id(target); - if (type.indexOf('key') != -1){ - code = event.which || event.keyCode; - key = Object.keyOf(Event.Keys, code); + if (type.indexOf('key') == 0){ + var code = this.code = (event.which || event.keyCode); + this.key = _keys[code]; if (type == 'keydown'){ - var fKey = code - 111; - if (fKey > 0 && fKey < 13) key = 'f' + fKey; + if (code > 111 && code < 124) this.key = 'f' + (code - 111); + else if (code > 95 && code < 106) this.key = code - 96; } - if (!key) key = String.fromCharCode(code).toLowerCase(); - } else if ((/click|mouse|menu/i).test(type)){ + if (this.key == null) this.key = String.fromCharCode(code).toLowerCase(); + } else if (type == 'click' || type == 'dblclick' || type == 'contextmenu' || type.indexOf('mouse') == 0){ + var doc = win.document; doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body; - page = { + this.page = { x: (event.pageX != null) ? event.pageX : event.clientX + doc.scrollLeft, y: (event.pageY != null) ? event.pageY : event.clientY + doc.scrollTop }; - client = { + this.client = { x: (event.pageX != null) ? event.pageX - win.pageXOffset : event.clientX, y: (event.pageY != null) ? event.pageY - win.pageYOffset : event.clientY }; - if ((/DOMMouseScroll|mousewheel/).test(type)){ - wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3; - } - rightClick = (event.which == 3) || (event.button == 2); - if ((/over|out/).test(type)){ - related = event.relatedTarget || event[(type == 'mouseover' ? 'from' : 'to') + 'Element']; - var testRelated = function(){ - while (related && related.nodeType == 3) related = related.parentNode; - return true; - }; - var hasRelated = (Browser.firefox2) ? testRelated.attempt() : testRelated(); - related = (hasRelated) ? related : null; + if (type == 'DOMMouseScroll' || type == 'mousewheel') + this.wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3; + + this.rightClick = (event.which == 3 || event.button == 2); + if (type == 'mouseover' || type == 'mouseout'){ + var related = event.relatedTarget || event[(type == 'mouseover' ? 'from' : 'to') + 'Element']; + while (related && related.nodeType == 3) related = related.parentNode; + this.relatedTarget = document.id(related); } - } else if ((/gesture|touch/i).test(type)){ + } else if (type.indexOf('touch') == 0 || type.indexOf('gesture') == 0){ // Hotfixed 0xc2a0 char to normal space this.rotation = event.rotation; this.scale = event.scale; this.targetTouches = event.targetTouches; @@ -1182,53 +1192,19 @@ var Event = new Type('Event', function(event, win){ var touches = this.touches = event.touches; if (touches && touches[0]){ var touch = touches[0]; - page = {x: touch.pageX, y: touch.pageY}; - client = {x: touch.clientX, y: touch.clientY}; + this.page = {x: touch.pageX, y: touch.pageY}; + this.client = {x: touch.clientX, y: touch.clientY}; } } - return Object.append(this, { - event: event, - type: type, - - page: page, - client: client, - rightClick: rightClick, - - wheel: wheel, - - relatedTarget: document.id(related), - target: document.id(target), - - code: code, - key: key, - - shift: event.shiftKey, - control: event.ctrlKey, - alt: event.altKey, - meta: event.metaKey - }); + if (!this.client) this.client = {}; + if (!this.page) this.page = {}; }); -Event.Keys = { - 'enter': 13, - 'up': 38, - 'down': 40, - 'left': 37, - 'right': 39, - 'esc': 27, - 'space': 32, - 'backspace': 8, - 'tab': 9, - 'delete': 46 -}; - - - -Event.implement({ +DOMEvent.implement({ stop: function(){ - return this.stopPropagation().preventDefault(); + return this.preventDefault().stopPropagation(); }, stopPropagation: function(){ @@ -1245,6 +1221,25 @@ Event.implement({ }); +DOMEvent.defineKey = function(code, key){ + _keys[code] = key; + return this; +}; + +DOMEvent.defineKeys = DOMEvent.defineKey.overloadSetter(true); + +DOMEvent.defineKeys({ + '38': 'up', '40': 'down', '37': 'left', '39': 'right', + '27': 'esc', '32': 'space', '8': 'backspace', '9': 'tab', + '46': 'delete', '13': 'enter' +}); + +})(); + + + + + /* --- @@ -2280,7 +2275,7 @@ local.matchNode = function(node, selector){ if (!parsed) return true; // simple (single) selectors - var expressions = parsed.expressions, reversedExpressions, simpleExpCounter = 0, i; + var expressions = parsed.expressions, simpleExpCounter = 0, i; for (i = 0; (currentExpression = expressions[i]); i++){ if (currentExpression.length == 1){ var exp = currentExpression[0]; @@ -2575,7 +2570,7 @@ for (var p in pseudos) local['pseudo:' + p] = pseudos[p]; // attributes methods -local.attributeGetters = { +var attributeGetters = local.attributeGetters = { 'class': function(){ return this.getAttribute('class') || this.className; @@ -2600,15 +2595,22 @@ local.attributeGetters = { 'type': function(){ return this.getAttribute('type'); + }, + + 'maxlength': function(){ + var attributeNode = this.getAttributeNode('maxLength'); + return (attributeNode && attributeNode.specified) ? attributeNode.nodeValue : null; } }; +attributeGetters.MAXLENGTH = attributeGetters.maxLength = attributeGetters.maxlength; + // Slick var Slick = local.Slick = (this.Slick || {}); -Slick.version = '1.1.5'; +Slick.version = '1.1.6'; // Slick finder @@ -2630,9 +2632,15 @@ Slick.contains = function(container, node){ // Slick attribute getter Slick.getAttribute = function(node, name){ + local.setDocument(node); return local.getAttribute(node, name); }; +Slick.hasAttribute = function(node, name){ + local.setDocument(node); + return local.hasAttribute(node, name); +}; + // Slick matcher Slick.match = function(node, selector){ @@ -2697,7 +2705,7 @@ description: One of the most important items in MooTools. Contains the dollar fu license: MIT-style license. -requires: [Window, Document, Array, String, Function, Number, Slick.Parser, Slick.Finder] +requires: [Window, Document, Array, String, Function, Object, Number, Slick.Parser, Slick.Finder] provides: [Element, Elements, $, $$, Iframe, Selectors] @@ -2717,8 +2725,8 @@ var Element = function(tag, props){ if (parsed.id && props.id == null) props.id = parsed.id; var attributes = parsed.attributes; - if (attributes) for (var i = 0, l = attributes.length; i < l; i++){ - var attr = attributes[i]; + if (attributes) for (var attr, i = 0, l = attributes.length; i < l; i++){ + attr = attributes[i]; if (props[attr.key] != null) continue; if (attr.value != null && attr.operator == '=') props[attr.key] = attr.value; @@ -2862,9 +2870,9 @@ var splice = Array.prototype.splice, object = {'0': 0, '1': 1, length: 2}; splice.call(object, 1, 1); if (object[1] == 1) Elements.implement('splice', function(){ var length = this.length; - splice.apply(this, arguments); + var result = splice.apply(this, arguments); while (length >= this.length) delete this[length--]; - return this; + return result; }.protect()); Elements.implement(Array.prototype); @@ -2984,6 +2992,79 @@ Window.implement({ }); +var contains = {contains: function(element){ + return Slick.contains(this, element); +}}; + +if (!document.contains) Document.implement(contains); +if (!document.createElement('div').contains) Element.implement(contains); + + + +// tree walking + +var injectCombinator = function(expression, combinator){ + if (!expression) return combinator; + + expression = Object.clone(Slick.parse(expression)); + + var expressions = expression.expressions; + for (var i = expressions.length; i--;) + expressions[i][0].combinator = combinator; + + return expression; +}; + +Object.forEach({ + getNext: '~', + getPrevious: '!~', + getParent: '!' +}, function(combinator, method){ + Element.implement(method, function(expression){ + return this.getElement(injectCombinator(expression, combinator)); + }); +}); + +Object.forEach({ + getAllNext: '~', + getAllPrevious: '!~', + getSiblings: '~~', + getChildren: '>', + getParents: '!' +}, function(combinator, method){ + Element.implement(method, function(expression){ + return this.getElements(injectCombinator(expression, combinator)); + }); +}); + +Element.implement({ + + getFirst: function(expression){ + return document.id(Slick.search(this, injectCombinator(expression, '>'))[0]); + }, + + getLast: function(expression){ + return document.id(Slick.search(this, injectCombinator(expression, '>')).getLast()); + }, + + getWindow: function(){ + return this.ownerDocument.window; + }, + + getDocument: function(){ + return this.ownerDocument; + }, + + getElementById: function(id){ + return document.id(Slick.find(this, '#' + ('' + id).replace(/(\W)/g, '\\$1'))); + }, + + match: function(expression){ + return !expression || Slick.match(this, expression); + } + +}); + if (window.$$ == null) Window.implement('$$', function(selector){ @@ -2996,48 +3077,7 @@ if (window.$$ == null) Window.implement('$$', function(selector){ (function(){ -var collected = {}, storage = {}; -var formProps = {input: 'checked', option: 'selected', textarea: 'value'}; - -var get = function(uid){ - return (storage[uid] || (storage[uid] = {})); -}; - -var clean = function(item){ - var uid = item.uid; - if (item.removeEvents) item.removeEvents(); - if (item.clearAttributes) item.clearAttributes(); - if (uid != null){ - delete collected[uid]; - delete storage[uid]; - } - return item; -}; - -var camels = ['defaultValue', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan', 'frameBorder', 'maxLength', 'readOnly', - 'rowSpan', 'tabIndex', 'useMap' -]; -var bools = ['compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked', 'disabled', 'readOnly', 'multiple', 'selected', - 'noresize', 'defer', 'defaultChecked' -]; - var attributes = { - 'html': 'innerHTML', - 'class': 'className', - 'for': 'htmlFor', - 'text': (function(){ - var temp = document.createElement('div'); - return (temp.textContent == null) ? 'innerText' : 'textContent'; - })() -}; -var readOnly = ['type']; -var expandos = ['value', 'defaultValue']; -var uriAttrs = /^(?:href|src|usemap)$/i; - -bools = bools.associate(bools); -camels = camels.associate(camels.map(String.toLowerCase)); -readOnly = readOnly.associate(readOnly); - -Object.append(attributes, expandos.associate(expandos)); +// Inserters var inserters = { @@ -3065,42 +3105,84 @@ inserters.inside = inserters.bottom; -var injectCombinator = function(expression, combinator){ - if (!expression) return combinator; +// getProperty / setProperty - expression = Object.clone(Slick.parse(expression)); +var propertyGetters = {}, propertySetters = {}; - var expressions = expression.expressions; - for (var i = expressions.length; i--;) - expressions[i][0].combinator = combinator; +// properties - return expression; -}; +var properties = {}; +Array.forEach([ + 'type', 'value', 'defaultValue', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan', + 'frameBorder', 'readOnly', 'rowSpan', 'tabIndex', 'useMap' +], function(property){ + properties[property.toLowerCase()] = property; +}); -Element.implement({ +Object.append(properties, { + 'html': 'innerHTML', + 'text': (function(){ + var temp = document.createElement('div'); + return (temp.innerText == null) ? 'textContent' : 'innerText'; + })() +}); - set: function(prop, value){ - var property = Element.Properties[prop]; - (property && property.set) ? property.set.call(this, value) : this.setProperty(prop, value); - }.overloadSetter(), +Object.forEach(properties, function(real, key){ + propertySetters[key] = function(node, value){ + node[real] = value; + }; + propertyGetters[key] = function(node){ + return node[real]; + }; +}); - get: function(prop){ - var property = Element.Properties[prop]; - return (property && property.get) ? property.get.apply(this) : this.getProperty(prop); - }.overloadGetter(), +// Booleans - erase: function(prop){ - var property = Element.Properties[prop]; - (property && property.erase) ? property.erase.apply(this) : this.removeProperty(prop); - return this; +var bools = [ + 'compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked', + 'disabled', 'readOnly', 'multiple', 'selected', 'noresize', + 'defer', 'defaultChecked', 'autofocus', 'controls', 'autoplay', + 'loop' +]; + +var booleans = {}; +Array.forEach(bools, function(bool){ + var lower = bool.toLowerCase(); + booleans[lower] = bool; + propertySetters[lower] = function(node, value){ + node[bool] = !!value; + }; + propertyGetters[lower] = function(node){ + return !!node[bool]; + }; +}); + +// Special cases + +Object.append(propertySetters, { + + 'class': function(node, value){ + ('className' in node) ? node.className = value : node.setAttribute('class', value); + }, + + 'for': function(node, value){ + ('htmlFor' in node) ? node.htmlFor = value : node.setAttribute('for', value); }, - setProperty: function(attribute, value){ - attribute = camels[attribute] || attribute; - if (value == null) return this.removeProperty(attribute); - var key = attributes[attribute]; - (key) ? this[key] = value : - (bools[attribute]) ? this[attribute] = !!value : this.setAttribute(attribute, '' + value); + 'style': function(node, value){ + (node.style) ? node.style.cssText = value : node.setAttribute('style', value); + } + +}); + +/* getProperty, setProperty */ + +Element.implement({ + + setProperty: function(name, value){ + var setter = propertySetters[name.toLowerCase()]; + if (setter) setter(this, value); + else this.setAttribute(name, value); return this; }, @@ -3109,13 +3191,11 @@ Element.implement({ return this; }, - getProperty: function(attribute){ - attribute = camels[attribute] || attribute; - var key = attributes[attribute] || readOnly[attribute]; - return (key) ? this[key] : - (bools[attribute]) ? !!this[attribute] : - (uriAttrs.test(attribute) ? this.getAttribute(attribute, 2) : - (key = this.getAttributeNode(attribute)) ? key.nodeValue : null) || null; + getProperty: function(name){ + var getter = propertyGetters[name.toLowerCase()]; + if (getter) return getter(this); + var result = Slick.getAttribute(this, name); + return (!result && !Slick.hasAttribute(this, name)) ? null : result; }, getProperties: function(){ @@ -3123,11 +3203,10 @@ Element.implement({ return args.map(this.getProperty, this).associate(args); }, - removeProperty: function(attribute){ - attribute = camels[attribute] || attribute; - var key = attributes[attribute]; - (key) ? this[key] = '' : - (bools[attribute]) ? this[attribute] = false : this.removeAttribute(attribute); + removeProperty: function(name){ + name = name.toLowerCase(); + if (booleans[name]) this.setProperty(name, false); + this.removeAttribute(name); return this; }, @@ -3136,6 +3215,22 @@ Element.implement({ return this; }, + set: function(prop, value){ + var property = Element.Properties[prop]; + (property && property.set) ? property.set.call(this, value) : this.setProperty(prop, value); + }.overloadSetter(), + + get: function(prop){ + var property = Element.Properties[prop]; + return (property && property.get) ? property.get.apply(this) : this.getProperty(prop); + }.overloadGetter(), + + erase: function(prop){ + var property = Element.Properties[prop]; + (property && property.erase) ? property.erase.apply(this) : this.removeProperty(prop); + return this; + }, + hasClass: function(className){ return this.className.clean().contains(className, ' '); }, @@ -3194,58 +3289,6 @@ Element.implement({ return this.replaces(el).grab(el, where); }, - getPrevious: function(expression){ - return document.id(Slick.find(this, injectCombinator(expression, '!~'))); - }, - - getAllPrevious: function(expression){ - return Slick.search(this, injectCombinator(expression, '!~'), new Elements); - }, - - getNext: function(expression){ - return document.id(Slick.find(this, injectCombinator(expression, '~'))); - }, - - getAllNext: function(expression){ - return Slick.search(this, injectCombinator(expression, '~'), new Elements); - }, - - getFirst: function(expression){ - return document.id(Slick.search(this, injectCombinator(expression, '>'))[0]); - }, - - getLast: function(expression){ - return document.id(Slick.search(this, injectCombinator(expression, '>')).getLast()); - }, - - getParent: function(expression){ - return document.id(Slick.find(this, injectCombinator(expression, '!'))); - }, - - getParents: function(expression){ - return Slick.search(this, injectCombinator(expression, '!'), new Elements); - }, - - getSiblings: function(expression){ - return Slick.search(this, injectCombinator(expression, '~~'), new Elements); - }, - - getChildren: function(expression){ - return Slick.search(this, injectCombinator(expression, '>'), new Elements); - }, - - getWindow: function(){ - return this.ownerDocument.window; - }, - - getDocument: function(){ - return this.ownerDocument; - }, - - getElementById: function(id){ - return document.id(Slick.find(this, '#' + ('' + id).replace(/(\W)/g, '\\$1'))); - }, - getSelected: function(){ this.selectedIndex; // Safari 3.2.1 return new Elements(Array.from(this.options).filter(function(option){ @@ -3269,7 +3312,30 @@ Element.implement({ }); }); return queryString.join('&'); - }, + } + +}); + +var collected = {}, storage = {}; + +var get = function(uid){ + return (storage[uid] || (storage[uid] = {})); +}; + +var clean = function(item){ + var uid = item.uid; + if (item.removeEvents) item.removeEvents(); + if (item.clearAttributes) item.clearAttributes(); + if (uid != null){ + delete collected[uid]; + delete storage[uid]; + } + return item; +}; + +var formProps = {input: 'checked', option: 'selected', textarea: 'value'}; + +Element.implement({ destroy: function(){ var children = clean(this).getElementsByTagName('*'); @@ -3287,55 +3353,44 @@ Element.implement({ return (this.parentNode) ? this.parentNode.removeChild(this) : this; }, - match: function(expression){ - return !expression || Slick.match(this, expression); - } + clone: function(contents, keepid){ + contents = contents !== false; + var clone = this.cloneNode(contents), ce = [clone], te = [this], i; -}); - -var cleanClone = function(node, element, keepid){ - if (!keepid) node.setAttributeNode(document.createAttribute('id')); - if (node.clearAttributes){ - node.clearAttributes(); - node.mergeAttributes(element); - node.removeAttribute('uid'); - if (node.options){ - var no = node.options, eo = element.options; - for (var i = no.length; i--;) no[i].selected = eo[i].selected; + if (contents){ + ce.append(Array.from(clone.getElementsByTagName('*'))); + te.append(Array.from(this.getElementsByTagName('*'))); } - } - var prop = formProps[element.tagName.toLowerCase()]; - if (prop && element[prop]) node[prop] = element[prop]; -}; - -Element.implement('clone', function(contents, keepid){ - contents = contents !== false; - var clone = this.cloneNode(contents), i; + for (i = ce.length; i--;){ + var node = ce[i], element = te[i]; + if (!keepid) node.removeAttribute('id'); + /**/ + if (node.clearAttributes){ + node.clearAttributes(); + node.mergeAttributes(element); + node.removeAttribute('uid'); + if (node.options){ + var no = node.options, eo = element.options; + for (var j = no.length; j--;) no[j].selected = eo[j].selected; + } + } + /**/ + var prop = formProps[element.tagName.toLowerCase()]; + if (prop && element[prop]) node[prop] = element[prop]; + } - if (contents){ - var ce = clone.getElementsByTagName('*'), te = this.getElementsByTagName('*'); - for (i = ce.length; i--;) cleanClone(ce[i], te[i], keepid); + /**/ + if (Browser.ie){ + var co = clone.getElementsByTagName('object'), to = this.getElementsByTagName('object'); + for (i = co.length; i--;) co[i].outerHTML = to[i].outerHTML; + } + /**/ + return document.id(clone); } - cleanClone(clone, this, keepid); - - if (Browser.ie){ - var co = clone.getElementsByTagName('object'), to = this.getElementsByTagName('object'); - for (i = co.length; i--;) co[i].outerHTML = to[i].outerHTML; - } - return document.id(clone); }); -var contains = {contains: function(element){ - return Slick.contains(this, element); -}}; - -if (!document.contains) Document.implement(contains); -if (!document.createElement('div').contains) Element.implement(contains); - - - [Element, Window, Document].invoke('implement', { addListener: function(type, fn){ @@ -3386,8 +3441,6 @@ if (window.attachEvent && !window.addEventListener) window.addListener('unload', }); /**/ -})(); - Element.Properties = {}; @@ -3416,17 +3469,6 @@ Element.Properties.tag = { }; -/**/ -(function(maxLength){ - if (maxLength != null) Element.Properties.maxlength = Element.Properties.maxLength = { - get: function(){ - var maxlength = this.getAttribute('maxLength'); - return maxlength == maxLength ? null : maxlength; - } - }; -})(document.createElement('input').getAttribute('maxLength')); -/**/ - /**/ Element.Properties.html = (function(){ @@ -3445,10 +3487,26 @@ Element.Properties.html = (function(){ }; translations.thead = translations.tfoot = translations.tbody; + /**/ + // technique by jdbarlett - http://jdbartlett.com/innershiv/ + wrapper.innerHTML = ''; + var HTML5Test = wrapper.childNodes.length == 1; + if (!HTML5Test){ + var tags = 'abbr article aside audio canvas datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video'.split(' '), + fragment = document.createDocumentFragment(), l = tags.length; + while (l--) fragment.createElement(tags[l]); + fragment.appendChild(wrapper); + } + /**/ + var html = { - set: function(){ - var html = Array.flatten(arguments).join(''); + set: function(html){ + if (typeOf(html) == 'array') html = html.join(''); + var wrap = (!tableTest && translations[this.get('tag')]); + /**/ + if (!wrap && !HTML5Test) wrap = [0, '', '']; + /**/ if (wrap){ var first = wrapper; first.innerHTML = wrap[1] + html + wrap[2]; @@ -3466,6 +3524,40 @@ Element.Properties.html = (function(){ })(); /**/ +/**/ +var testForm = document.createElement('form'); +testForm.innerHTML = ''; + +if (testForm.firstChild.value != 's') Element.Properties.value = { + + set: function(value){ + var tag = this.get('tag'); + if (tag != 'select') return this.setProperty('value', value); + var options = this.getElements('option'); + for (var i = 0; i < options.length; i++){ + var option = options[i], + attr = option.getAttributeNode('value'), + optionValue = (attr && attr.specified) ? option.value : option.get('text'); + if (optionValue == value) return option.selected = true; + } + }, + + get: function(){ + var option = this, tag = option.get('tag'); + + if (tag != 'select' && tag != 'option') return this.getProperty('value'); + + if (tag == 'select' && !(option = option.getSelected()[0])) return ''; + + var attr = option.getAttributeNode('value'); + return (attr && attr.specified) ? option.value : option.get('text'); + } + +}; +/**/ + +})(); + /* --- @@ -3491,41 +3583,38 @@ Element.Properties.styles = {set: function(styles){ this.setStyles(styles); }}; -var hasOpacity = (html.style.opacity != null); -var reAlpha = /alpha\(opacity=([\d.]+)\)/i; +var hasOpacity = (html.style.opacity != null), + hasFilter = (html.style.filter != null), + reAlpha = /alpha\(opacity=([\d.]+)\)/i; -var setOpacity = function(element, opacity){ - if (!element.currentStyle || !element.currentStyle.hasLayout) element.style.zoom = 1; - if (hasOpacity){ - element.style.opacity = opacity; - } else { - opacity = (opacity * 100).limit(0, 100).round(); - opacity = (opacity == 100) ? '' : 'alpha(opacity=' + opacity + ')'; - var filter = element.style.filter || element.getComputedStyle('filter') || ''; - element.style.filter = reAlpha.test(filter) ? filter.replace(reAlpha, opacity) : filter + opacity; - } +var setVisibility = function(element, opacity){ + element.store('$opacity', opacity); + element.style.visibility = opacity > 0 ? 'visible' : 'hidden'; }; -Element.Properties.opacity = { - - set: function(opacity){ - var visibility = this.style.visibility; - if (opacity == 0 && visibility != 'hidden') this.style.visibility = 'hidden'; - else if (opacity != 0 && visibility != 'visible') this.style.visibility = 'visible'; - - setOpacity(this, opacity); - }, - - get: (hasOpacity) ? function(){ - var opacity = this.style.opacity || this.getComputedStyle('opacity'); - return (opacity == '') ? 1 : opacity; - } : function(){ - var opacity, filter = (this.style.filter || this.getComputedStyle('filter')); - if (filter) opacity = filter.match(reAlpha); - return (opacity == null || filter == null) ? 1 : (opacity[1] / 100); - } - -}; +var setOpacity = (hasOpacity ? function(element, opacity){ + element.style.opacity = opacity; +} : (hasFilter ? function(element, opacity){ + if (!element.currentStyle || !element.currentStyle.hasLayout) element.style.zoom = 1; + opacity = (opacity * 100).limit(0, 100).round(); + opacity = (opacity == 100) ? '' : 'alpha(opacity=' + opacity + ')'; + var filter = element.style.filter || element.getComputedStyle('filter') || ''; + element.style.filter = reAlpha.test(filter) ? filter.replace(reAlpha, opacity) : filter + opacity; +} : setVisibility)); + +var getOpacity = (hasOpacity ? function(element){ + var opacity = element.style.opacity || element.getComputedStyle('opacity'); + return (opacity == '') ? 1 : opacity.toFloat(); +} : (hasFilter ? function(element){ + var filter = (element.style.filter || element.getComputedStyle('filter')), + opacity; + if (filter) opacity = filter.match(reAlpha); + return (opacity == null || filter == null) ? 1 : (opacity[1] / 100); +} : function(element){ + var opacity = element.retrieve('$opacity'); + if (opacity == null) opacity = (element.style.visibility == 'hidden' ? 0 : 1); + return opacity; +})); var floatName = (html.style.cssFloat == null) ? 'styleFloat' : 'cssFloat'; @@ -3538,21 +3627,12 @@ Element.implement({ return (computed) ? computed.getPropertyValue((property == floatName) ? 'float' : property.hyphenate()) : null; }, - setOpacity: function(value){ - setOpacity(this, value); - return this; - }, - - getOpacity: function(){ - return this.get('opacity'); - }, - setStyle: function(property, value){ - switch (property){ - case 'opacity': return this.set('opacity', parseFloat(value)); - case 'float': property = floatName; + if (property == 'opacity'){ + setOpacity(this, parseFloat(value)); + return this; } - property = property.camelCase(); + property = (property == 'float' ? floatName : property).camelCase(); if (typeOf(value) != 'string'){ var map = (Element.Styles[property] || '@').split(' '); value = Array.from(value).map(function(val, i){ @@ -3567,11 +3647,8 @@ Element.implement({ }, getStyle: function(property){ - switch (property){ - case 'opacity': return this.get('opacity'); - case 'float': property = floatName; - } - property = property.camelCase(); + if (property == 'opacity') return getOpacity(this); + property = (property == 'float' ? floatName : property).camelCase(); var result = this.style[property]; if (!result || property == 'zIndex'){ result = []; @@ -3628,6 +3705,8 @@ Element.Styles = { + + Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, borderStyle: {}, borderColor: {}}; ['Top', 'Right', 'Bottom', 'Left'].each(function(direction){ @@ -3683,14 +3762,14 @@ Element.Properties.events = {set: function(events){ condition = fn, self = this; if (custom){ - if (custom.onAdd) custom.onAdd.call(this, fn); + if (custom.onAdd) custom.onAdd.call(this, fn, type); if (custom.condition){ condition = function(event){ - if (custom.condition.call(this, event)) return fn.call(this, event); + if (custom.condition.call(this, event, type)) return fn.call(this, event); return true; }; } - realType = custom.base || realType; + if (custom.base) realType = Function.from(custom.base).call(this, type); } var defn = function(){ return fn.call(self); @@ -3699,7 +3778,7 @@ Element.Properties.events = {set: function(events){ if (nativeEvent){ if (nativeEvent == 2){ defn = function(event){ - event = new Event(event, self.getWindow()); + event = new DOMEvent(event, self.getWindow()); if (condition.call(self, event) === false) event.stop(); }; } @@ -3720,8 +3799,8 @@ Element.Properties.events = {set: function(events){ delete list.values[index]; var custom = Element.Events[type]; if (custom){ - if (custom.onRemove) custom.onRemove.call(this, fn); - type = custom.base || type; + if (custom.onRemove) custom.onRemove.call(this, fn, type); + if (custom.base) type = Function.from(custom.base).call(this, type); } return (Element.NativeEvents[type]) ? this.removeListener(type, value, arguments[2]) : this; }, @@ -3787,7 +3866,7 @@ Element.NativeEvents = { orientationchange: 2, // mobile touchstart: 2, touchmove: 2, touchend: 2, touchcancel: 2, // touch gesturestart: 2, gesturechange: 2, gestureend: 2, // gesture - focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, //form elements + focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, paste: 2, oninput: 2, //form elements load: 2, unload: 1, beforeunload: 2, resize: 1, move: 1, DOMContentLoaded: 1, readystatechange: 1, //window error: 1, abort: 1, scroll: 1 //misc }; @@ -3817,6 +3896,21 @@ Element.Events = { }; +/**/ +if (!window.addEventListener){ + Element.NativeEvents.propertychange = 2; + Element.Events.change = { + base: function(){ + var type = this.type; + return (this.get('tag') == 'input' && (type == 'radio' || type == 'checkbox')) ? 'propertychange' : 'change' + }, + condition: function(event){ + return !!(this.type != 'radio' || this.checked); + } + } +} +/**/ + })(); @@ -3961,7 +4055,6 @@ Element.implement({ }, getPosition: function(relative){ - if (isBody(this)) return {x: 0, y: 0}; var offset = this.getOffsets(), scroll = this.getScrolls(); var position = { @@ -4513,7 +4606,7 @@ Element.implement({ case 'show': fade.set(o, 1); break; case 'hide': fade.set(o, 0); break; case 'toggle': - var flag = this.retrieve('fade:flag', this.get('opacity') == 1); + var flag = this.retrieve('fade:flag', this.getStyle('opacity') == 1); fade.start(o, (flag) ? 0 : 1); this.store('fade:flag', !flag); toggle = true; @@ -4789,7 +4882,7 @@ var doScrollWorks = function(){ return true; } catch (e){} return false; -} +}; // If doScroll works already, it can't be used to determine domready // e.g. in an iframe if (testElement.doScroll && !doScrollWorks()){ diff --git a/Test/mootools-more.js b/Test/mootools-more.js index 72df8d8..dcc5528 100644 --- a/Test/mootools-more.js +++ b/Test/mootools-more.js @@ -31,8 +31,8 @@ provides: [MooTools.More] */ MooTools.More = { - 'version': '1.3.2.1', - 'build': 'e586bcd2496e9b22acfde32e12f84d49ce09e59d' + 'version': '1.4.0.1', + 'build': 'a4244edf2aa97ac8a196fc96082dd35af1abab87' }; @@ -551,19 +551,19 @@ Date.implement({ }, isValid: function(date){ - return !isNaN((date || this).valueOf()); + if (!date) date = this; + return typeOf(date) == 'date' && !isNaN(date.valueOf()); }, - format: function(f){ + format: function(format){ if (!this.isValid()) return 'invalid date'; - if (!f) f = '%x %X'; - var formatLower = f.toLowerCase(); - if (formatters[formatLower]) return formatters[formatLower](this); // it's a formatter! - f = formats[formatLower] || f; // replace short-hand with actual format + if (!format) format = '%x %X'; + if (typeof format == 'string') format = formats[format.toLowerCase()] || format; + if (typeof format == 'function') return format(this); var d = this; - return f.replace(/%([a-z%])/gi, + return format.replace(/%([a-z%])/gi, function($0, $1){ switch ($1){ case 'a': return Date.getMsg('days_abbr')[d.get('day')]; @@ -610,18 +610,15 @@ Date.implement({ strftime: 'format' }); -var formats = { - db: '%Y-%m-%d %H:%M:%S', - compact: '%Y%m%dT%H%M%S', - 'short': '%d %b %H:%M', - 'long': '%B %d, %Y %H:%M' -}; - // The day and month abbreviations are standardized, so we cannot use simply %a and %b because they will get localized var rfcDayAbbr = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], rfcMonthAbbr = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; -var formatters = { +var formats = { + db: '%Y-%m-%d %H:%M:%S', + compact: '%Y%m%dT%H%M%S', + 'short': '%d %b %H:%M', + 'long': '%B %d, %Y %H:%M', rfc822: function(date){ return rfcDayAbbr[date.get('day')] + date.format(', %d ') + rfcMonthAbbr[date.get('month')] + date.format(' %Y %H:%M:%S %Z'); }, @@ -641,7 +638,6 @@ var formatters = { } }; - var parsePatterns = [], nativeParse = Date.parse; @@ -753,11 +749,6 @@ Date.extend({ return this; }, - defineFormats: function(formats){ - for (var name in formats) Date.defineFormat(name, formats[name]); - return this; - }, - defineParser: function(pattern){ @@ -776,6 +767,8 @@ Date.extend({ return this; } +}).extend({ + defineFormats: Date.defineFormat.overloadSetter() }); var regexOf = function(type){ @@ -1736,7 +1729,7 @@ var local = Element.Position = { Element.implement({ position: function(options){ - if (options && (options.x != null || options.y != null)) { + if (options && (options.x != null || options.y != null)){ return (original ? original.apply(this, arguments) : this); } var position = this.setStyle('position', 'absolute').calculatePosition(options); From 0768c575d52e9231543f59815328524e8102a67a Mon Sep 17 00:00:00 2001 From: Arian Date: Wed, 21 Sep 2011 16:20:38 +0200 Subject: [PATCH 272/285] MooTools Datepicker 2.1.1! --- package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.yml b/package.yml index 58033b4..8c0447d 100644 --- a/package.yml +++ b/package.yml @@ -1,6 +1,6 @@ name: MooTools-DatePicker author: astolwijk -current: 2.1.0 +current: 2.1.1 category: Widgets tags: [Datepicker, Calendar, Picker] demo: http://www.aryweb.nl/projects/mootools-datepicker/ From f2621e5a672e62323a964b440b2fdb7e9eea42be Mon Sep 17 00:00:00 2001 From: Arian Stolwijk Date: Sun, 6 Nov 2011 21:10:22 +0100 Subject: [PATCH 273/285] Fixes #86 - Fix maxDate option when the minDate option was not used, in the isUnavailable function. --- Source/Picker.Date.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Picker.Date.js b/Source/Picker.Date.js index fda87ec..9166c32 100644 --- a/Source/Picker.Date.js +++ b/Source/Picker.Date.js @@ -653,7 +653,7 @@ var isUnavailable = function(type, date, options){ month = date.get('month') + 1; day = date.get('date'); - var dateAllow = (minDate && date < minDate) || (minDate && date > maxDate); + var dateAllow = (minDate && date < minDate) || (maxDate && date > maxDate); if (availableDates != null){ dateAllow = dateAllow || availableDates[year] == null From d3a230995340f46da6f7ec68efbc52119c7c92b7 Mon Sep 17 00:00:00 2001 From: Arian Date: Tue, 15 Nov 2011 12:24:50 +0100 Subject: [PATCH 274/285] Update to MooTools 1.4.1 --- .gitignore | 1 + Test/mootools-core.js | 56 ++++++++++++++++++++++++++----------------- Test/mootools-more.js | 11 +++++---- 3 files changed, 41 insertions(+), 27 deletions(-) diff --git a/.gitignore b/.gitignore index 0f6221c..30c9f5c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ *.tmp* +*~ diff --git a/Test/mootools-core.js b/Test/mootools-core.js index d0f87f9..74540cb 100644 --- a/Test/mootools-core.js +++ b/Test/mootools-core.js @@ -33,8 +33,8 @@ provides: [Core, MooTools, Type, typeOf, instanceOf, Native] (function(){ this.MooTools = { - version: '1.4.0', - build: 'a15e35b4dbd12e8d86d9b50aa67a27e8e0071ea3' + version: '1.4.1', + build: 'd1fb25710e3c5482a219ab9dc675a4e0ad2176b6' }; // typeOf, instanceOf @@ -167,7 +167,7 @@ var Type = this.Type = function(name, object){ object.prototype.$family = (function(){ return lower; }).hide(); - + } } @@ -1164,7 +1164,7 @@ var DOMEvent = this.DOMEvent = new Type('DOMEvent', function(event, win){ else if (code > 95 && code < 106) this.key = code - 96; } if (this.key == null) this.key = String.fromCharCode(code).toLowerCase(); - } else if (type == 'click' || type == 'dblclick' || type == 'contextmenu' || type.indexOf('mouse') == 0){ + } else if (type == 'click' || type == 'dblclick' || type == 'contextmenu' || type == 'DOMMouseScroll' || type.indexOf('mouse') == 0){ var doc = win.document; doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body; this.page = { @@ -1184,7 +1184,7 @@ var DOMEvent = this.DOMEvent = new Type('DOMEvent', function(event, win){ while (related && related.nodeType == 3) related = related.parentNode; this.relatedTarget = document.id(related); } - } else if (type.indexOf('touch') == 0 || type.indexOf('gesture') == 0){ // Hotfixed 0xc2a0 char to normal space + } else if (type.indexOf('touch') == 0 || type.indexOf('gesture') == 0){ this.rotation = event.rotation; this.scale = event.scale; this.targetTouches = event.targetTouches; @@ -1409,7 +1409,7 @@ this.Events = new Class({ addEvent: function(type, fn, internal){ type = removeOn(type); - + this.$events[type] = (this.$events[type] || []).include(fn); if (internal) fn.internal = true; @@ -3123,7 +3123,7 @@ Object.append(properties, { 'html': 'innerHTML', 'text': (function(){ var temp = document.createElement('div'); - return (temp.innerText == null) ? 'textContent' : 'innerText'; + return (temp.textContent == null) ? 'innerText': 'textContent'; })() }); @@ -3180,7 +3180,15 @@ Object.append(propertySetters, { Element.implement({ setProperty: function(name, value){ - var setter = propertySetters[name.toLowerCase()]; + var lower = name.toLowerCase(); + if (value == null){ + if (!booleans[lower]){ + this.removeAttribute(name); + return this; + } + value = false; + } + var setter = propertySetters[lower]; if (setter) setter(this, value); else this.setAttribute(name, value); return this; @@ -3204,10 +3212,7 @@ Element.implement({ }, removeProperty: function(name){ - name = name.toLowerCase(); - if (booleans[name]) this.setProperty(name, false); - this.removeAttribute(name); - return this; + return this.setProperty(name, null); }, removeProperties: function(){ @@ -3866,7 +3871,7 @@ Element.NativeEvents = { orientationchange: 2, // mobile touchstart: 2, touchmove: 2, touchend: 2, touchcancel: 2, // touch gesturestart: 2, gesturechange: 2, gestureend: 2, // gesture - focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, paste: 2, oninput: 2, //form elements + focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, paste: 2, input: 2, //form elements load: 2, unload: 1, beforeunload: 2, resize: 1, move: 1, DOMContentLoaded: 1, readystatechange: 1, //window error: 1, abort: 1, scroll: 1 //misc }; @@ -4593,27 +4598,33 @@ Element.Properties.tween = { Element.implement({ tween: function(property, from, to){ - this.get('tween').start(arguments); + this.get('tween').start(property, from, to); return this; }, fade: function(how){ - var fade = this.get('tween'), o = 'opacity', toggle; - how = [how, 'toggle'].pick(); + var fade = this.get('tween'), method, to, toggle; + if (how == null) how = 'toggle'; switch (how){ - case 'in': fade.start(o, 1); break; - case 'out': fade.start(o, 0); break; - case 'show': fade.set(o, 1); break; - case 'hide': fade.set(o, 0); break; + case 'in': method = 'start'; to = 1; break; + case 'out': method = 'start'; to = 0; break; + case 'show': method = 'set'; to = 1; break; + case 'hide': method = 'set'; to = 0; break; case 'toggle': var flag = this.retrieve('fade:flag', this.getStyle('opacity') == 1); - fade.start(o, (flag) ? 0 : 1); + method = 'start'; + to = flag ? 0 : 1; this.store('fade:flag', !flag); toggle = true; break; - default: fade.start(o, arguments); + default: method = 'start'; to = how; } if (!toggle) this.eliminate('fade:flag'); + fade[method]('opacity', to); + if (method == 'set' || to != 0) this.setStyle('visibility', to == 0 ? 'hidden' : 'visible'); + else fade.chain(function(){ + this.element.setStyle('visibility', 'hidden'); + }); return this; }, @@ -4928,3 +4939,4 @@ window.addEvent('load', function(){ }); })(window, document); + diff --git a/Test/mootools-more.js b/Test/mootools-more.js index dcc5528..2824883 100644 --- a/Test/mootools-more.js +++ b/Test/mootools-more.js @@ -1,5 +1,5 @@ // MooTools: the javascript framework. -// Load this file's selection again by visiting: http://mootools.net/more/ea71e7d3aab3551fe45865dbb054a052 +// Load this file's selection again by visiting: http://mootools.net/more/ea71e7d3aab3551fe45865dbb054a052 // Or build this file again with packager using: packager build More/Date More/Drag More/Drag.Move More/IframeShim /* --- @@ -155,7 +155,7 @@ var Locale = this.Locale = { if (set) locale.define(set, key, value); - + if (!current) current = locale; @@ -170,7 +170,7 @@ var Locale = this.Locale = { this.fireEvent('change', locale); - + } return this; @@ -749,7 +749,7 @@ Date.extend({ return this; }, - + defineParser: function(pattern){ parsePatterns.push((pattern.re && pattern.handler) ? pattern : build(pattern)); @@ -1455,7 +1455,7 @@ Element.implement({ }, getComputedSize: function(options){ - + options = Object.merge({ styles: ['padding','border'], @@ -1915,3 +1915,4 @@ var IframeShim = new Class({ window.addEvent('load', function(){ IframeShim.ready = true; }); + From f53f674629acee2d3a6a96c5a76e7d7a922c5901 Mon Sep 17 00:00:00 2001 From: Arian Date: Tue, 15 Nov 2011 12:27:35 +0100 Subject: [PATCH 275/285] Fixes #84 - Picker hides after opening for the 2nd time This is a bug in mootools 1.4.1: https://github.com/mootools/mootools-core/issues/2116 --- Source/Picker.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Source/Picker.js b/Source/Picker.js index 45b2acc..398a559 100644 --- a/Source/Picker.js +++ b/Source/Picker.js @@ -128,11 +128,15 @@ var Picker = new Class({ open: function(noFx){ if (this.opened == true) return this; this.opened = true; - var picker = this.picker.setStyle('display', 'block').set('aria-hidden', 'false') + var self = this, + picker = this.picker.setStyle('display', 'block').set('aria-hidden', 'false') if (this.shim) this.shim.show(); this.fireEvent('open'); if (this.options.useFadeInOut && !noFx){ - picker.fade('in').get('tween').chain(this.fireEvent.pass('show', this)); + picker.get('tween').start('opacity', 1).chain(function(){ + self.fireEvent('show'); + this.callChain(); + }); } else { picker.setStyle('opacity', 1); this.fireEvent('show'); @@ -154,7 +158,7 @@ var Picker = new Class({ self.fireEvent('hide'); }; if (this.options.useFadeInOut && !noFx){ - picker.fade('out').get('tween').chain(hide); + picker.get('tween').start('opacity', 0).chain(hide); } else { picker.setStyle('opacity', 0); hide(); From dca19ccc66d81fad5f49f9d8f650c00d951e5ea8 Mon Sep 17 00:00:00 2001 From: Werner Mollentze Date: Thu, 1 Dec 2011 19:49:40 +0200 Subject: [PATCH 276/285] Add Afrikaans translations --- Source/Locale.af-ZA.DatePicker.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 Source/Locale.af-ZA.DatePicker.js diff --git a/Source/Locale.af-ZA.DatePicker.js b/Source/Locale.af-ZA.DatePicker.js new file mode 100644 index 0000000..7395543 --- /dev/null +++ b/Source/Locale.af-ZA.DatePicker.js @@ -0,0 +1,19 @@ +/* +--- +name: Locale.af-ZA.DatePicker +description: Afrikaans Language File for DatePicker +authors: Werner Mollentze +requires: [More/Locale] +provides: Locale.af-ZA.DatePicker +... +*/ + + +Locale.define('af-ZA', 'DatePicker', { + select_a_time: 'Kies \'n tyd', + use_mouse_wheel: 'Gebruik die muiswiel om vinnig \'n waarde te verander', + time_confirm_button: 'OK', + apply_range: 'OK', + cancel: 'Kanseleer', + week: 'Wk' +}); From 1054b7cc6ef081ed6cfdcdf89d4e839cfd118ef1 Mon Sep 17 00:00:00 2001 From: Arian Stolwijk Date: Thu, 1 Dec 2011 19:07:08 +0100 Subject: [PATCH 277/285] Add Afrikaans to the supported languages in the readme. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 89beeba..3759445 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,7 @@ Just include the file in your page with a script tag to use the translations. Currently the following languages are supported +- af-ZA - cs-CZ - de-DE - en-US From cd3a084761c52236743e3adcb9470efbff4881cd Mon Sep 17 00:00:00 2001 From: ccerrillo Date: Tue, 17 Jan 2012 11:22:58 +0100 Subject: [PATCH 278/285] added some missing spanish translations --- Source/Locale.es-ES-DatePicker.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Source/Locale.es-ES-DatePicker.js b/Source/Locale.es-ES-DatePicker.js index 627f17c..d52fdfc 100644 --- a/Source/Locale.es-ES-DatePicker.js +++ b/Source/Locale.es-ES-DatePicker.js @@ -2,7 +2,7 @@ --- name: Locale.es-ES.DatePicker description: Spanish Language File for DatePicker -authors: Juan Lago D. +authors: ["Juan Lago D.", "Carlos Cerrillo"] requires: [More/Locale] provides: Locale.es-ES.DatePicker ... @@ -12,5 +12,8 @@ provides: Locale.es-ES.DatePicker Locale.define('es-ES', 'DatePicker', { select_a_time: 'Selecciona una fecha', use_mouse_wheel: 'Utiliza la rueda del raton para cambiar rapidamente de valor', - time_confirm_button: 'OK' + time_confirm_button: 'OK', + apply_range: 'Aplicar', + cancel: 'Cancelar', + week: 'S' }); From c9017aadd21dde35525b0a84f43ae9b2481ab198 Mon Sep 17 00:00:00 2001 From: ccerrillo Date: Tue, 17 Jan 2012 11:23:19 +0100 Subject: [PATCH 279/285] romoved spaces --- Source/Locale.es-ES-DatePicker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Locale.es-ES-DatePicker.js b/Source/Locale.es-ES-DatePicker.js index d52fdfc..e05dca4 100644 --- a/Source/Locale.es-ES-DatePicker.js +++ b/Source/Locale.es-ES-DatePicker.js @@ -15,5 +15,5 @@ Locale.define('es-ES', 'DatePicker', { time_confirm_button: 'OK', apply_range: 'Aplicar', cancel: 'Cancelar', - week: 'S' + week: 'S' }); From e0dfb76a3764e727ce3d94b0855b9bbe8c5811e3 Mon Sep 17 00:00:00 2001 From: Leon Date: Thu, 8 Dec 2011 13:58:58 +0100 Subject: [PATCH 280/285] Added Swedish translation --- Source/Locale.sv-SE.DatePicker.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 Source/Locale.sv-SE.DatePicker.js diff --git a/Source/Locale.sv-SE.DatePicker.js b/Source/Locale.sv-SE.DatePicker.js new file mode 100644 index 0000000..1c11034 --- /dev/null +++ b/Source/Locale.sv-SE.DatePicker.js @@ -0,0 +1,19 @@ +/* +--- +name: Locale.sv-SE.DatePicker +description: Swedish Language File for DatePicker +authors: Leon Radley +requires: [More/Locale] +provides: Locale.sv-SE.DatePicker +... +*/ + + +Locale.define('sv-SE', 'DatePicker', { + select_a_time: 'Välj en tid', + use_mouse_wheel: 'Scrolla för att snabbt ändra värde', + time_confirm_button: 'OK', + apply_range: 'Välj', + cancel: 'Avbryt', + week: 'v.' +}); From 42917bd3f3333020b94126e34a4396569a90aec8 Mon Sep 17 00:00:00 2001 From: Leon Date: Thu, 8 Dec 2011 16:11:28 +0100 Subject: [PATCH 281/285] Added Minimal theme --- .../datepicker_minimal/datepicker_minimal.css | 208 ++++++++++++++++++ Test/themes.html | 25 +-- 2 files changed, 219 insertions(+), 14 deletions(-) create mode 100644 Source/datepicker_minimal/datepicker_minimal.css diff --git a/Source/datepicker_minimal/datepicker_minimal.css b/Source/datepicker_minimal/datepicker_minimal.css new file mode 100644 index 0000000..b232d0b --- /dev/null +++ b/Source/datepicker_minimal/datepicker_minimal.css @@ -0,0 +1,208 @@ +/* + Minimal Theme + Author: Leon Radley (github.com/leon) + + Selected: #95adb8 + Hover: #c6d2d8 + Current: #f60 +*/ +.datepicker_minimal { + position: absolute; + border: 1px solid #ddd; + font-size: 11px; + width: 220px; + height: 200px; + background: #fff; + line-height: normal; + z-index: 3003; + border-radius: 2px; + -webkit-border-radius: 2px; + -moz-border-radius: 2px; +} + .datepicker_minimal th, + .datepicker_minimal td { + margin: 0; + padding: 0; + } + .datepicker_minimal .selected { + background: #95adb8 !important; + color: #fff !important; + } + + .datepicker_minimal .unavailable, + .datepicker_minimal .day.unavailable:hover { + background: #edd !important; + color: #b88 !important; + cursor: default !important; + } + + .datepicker_minimal td.day:hover, + .datepicker_minimal .month:hover, + .datepicker_minimal .year:hover { + background: #c6d2d8 !important; + color: #222 !important; + } + +/* + Header +*/ +.datepicker_minimal .header { + position: relative; + background: #333; + height: 25px; +} + .datepicker_minimal .header .title { + margin: 0 50px; + text-align: center; + line-height: 25px; + } + .datepicker_minimal .header .titleText { + color: #fff; + font-weight: bold; + } + .datepicker_minimal .header .next, + .datepicker_minimal .header .previous, + .datepicker_minimal .header .closeButton { + position: absolute; + top: 0; + width: 25px; + height: 25px; + line-height: 25px; + text-align: center; + color: #fff; + cursor: pointer; + } + .datepicker_minimal .header .previous { + left: 0; + } + .datepicker_minimal .header .next { + right: 25px; + } + .datepicker_minimal .header .closeButton { + right: 0; + } + +/* + Body +*/ +.datepicker_minimal .body { + position: relative; + top: 0; + left: 0; + width: 100%; + height: 175px; + overflow: hidden; +} + .datepicker_minimal .body .column { + height: 100%; + } + +/* + Days +*/ +.datepicker_minimal .days { + width: 100%; + border: 0; + border-spacing: 0; +} + .datepicker_minimal .days .title { + font-weight: bold; + color: #444; + cursor: default; + width: 14.2857142857143%; /* 100/7 */ + } + .datepicker_minimal .days.weeknumbers .title { + width: 12.5%; + } + .datepicker_minimal .days .otherMonth { + background: #eee; + color: #aaa; + } + .datepicker_minimal .day { + cursor: pointer; + text-align: center; + overflow: hidden; + line-height: 25px; + } + .datepicker_minimal .today { + color: #f60; + font-weight: bold; + } + .datepicker_minimal .day0 { + margin-right: 0; + } + .datepicker_minimal .days .week5 .day { + margin-bottom: 0; + } + +/* + Months +*/ +.datepicker_minimal .months { + height: 100%; +} + .datepicker_minimal .month { + float: left; + display: inline; + width: 33.33333333%; + line-height: 44px; + cursor: pointer; + vertical-align: middle; + text-align: center; + overflow: hidden; + } + +/* + Years +*/ +.datepicker_minimal .years { + height: 100%; +} + .datepicker_minimal .year { + float: left; + display: inline; + width: 25%; + line-height: 35px; + cursor: pointer; + text-align: center; + overflow: hidden; + } + +/* + Time +*/ +.datepicker_minimal .time { + width: 100%; + height: 100%; + background: #fff; +} + .datepicker_minimal .time .hour, + .datepicker_minimal .time .separator, + .datepicker_minimal .time .minutes { + position: absolute; + top: 50px; + width: 50px; + border: 1px dashed #ddd; + font-size: 32px; + text-align: center; + } + .datepicker_minimal .time .hour { + left: 40px; + } + .datepicker_minimal .time .separator { + background: transparent; + border: 0px; + width: 10px; + left: 100px; + } + + .datepicker_minimal .time .minutes { + left: 120px; + } + .datepicker_minimal .time .ok { + position: absolute; + top: 105px; + width: 136px; + left: 40px; + font-size: 20px; + } diff --git a/Test/themes.html b/Test/themes.html index f25ab44..bcb2a51 100644 --- a/Test/themes.html +++ b/Test/themes.html @@ -15,6 +15,7 @@ + - -

      DatePicker Themes

      - +

      This demo shows you the current four supported themes. It is just a simple option of setting the picker classname to another CSS class.

      - This demo shows you the current four supported themes. It is just a simple option of setting the picker classname to another CSS class. +
      +

      -


      -


      - -


      -

      -
      - +
      +

      -


      From c4e179a66c6c24e54a7e2926948372ab9e7774f0 Mon Sep 17 00:00:00 2001 From: Leon Date: Tue, 20 Dec 2011 15:00:37 +0100 Subject: [PATCH 282/285] Made time choose button work in IE 9 --- Source/Picker.Date.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/Picker.Date.js b/Source/Picker.Date.js index 9166c32..8b4558e 100644 --- a/Source/Picker.Date.js +++ b/Source/Picker.Date.js @@ -574,7 +574,8 @@ var renderers = { new Element('div.separator[text=:]').inject(container); - new Element('input.ok[type=submit]', { + new Element('input.ok', { + 'type': 'input', value: Locale.get('DatePicker.time_confirm_button'), events: {click: function(event){ event.stop(); From 46d166a51c630fbee920ab64606d3f7b46affd3a Mon Sep 17 00:00:00 2001 From: Arian Date: Fri, 20 Jan 2012 19:05:09 +0100 Subject: [PATCH 283/285] Add Swedish to the README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3759445..496b952 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,7 @@ Currently the following languages are supported - pl-PL - pt-BR - ru-RU +- sv-SE You can set the current language with: From 80515062e3290d0dcedb78b0954dc0fa8e5b0025 Mon Sep 17 00:00:00 2001 From: Artem Godlevskyy Date: Sat, 30 Jun 2012 18:49:20 +0300 Subject: [PATCH 284/285] Added ukrainian locale file --- Source/Locale.uk-UA.DatePicker.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 Source/Locale.uk-UA.DatePicker.js diff --git a/Source/Locale.uk-UA.DatePicker.js b/Source/Locale.uk-UA.DatePicker.js new file mode 100644 index 0000000..b73055a --- /dev/null +++ b/Source/Locale.uk-UA.DatePicker.js @@ -0,0 +1,19 @@ +/* +--- +name: Locale.en-US.DatePicker +description: English Language File for DatePicker +authors: Arian Stolwijk +requires: [More/Locale] +provides: Locale.en-US.DatePicker +... +*/ + + +Locale.define('uk-UA', 'DatePicker', { + select_a_time: 'Встановіть час', + use_mouse_wheel: 'Використовуйте прокрутку для швидкої зміни значення', + time_confirm_button: 'Гаразд', + apply_range: 'Застосувати', + cancel: 'Скасувати', + week: 'Т-нь' +}); From e35fa19a206035bf1b2adcd3e3228888a9139401 Mon Sep 17 00:00:00 2001 From: Artem Godlevskyy Date: Sat, 30 Jun 2012 18:51:43 +0300 Subject: [PATCH 285/285] Ukrainian locale mentioned in README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 496b952..47486c1 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,7 @@ Currently the following languages are supported - pt-BR - ru-RU - sv-SE +- uk-UA You can set the current language with: