bhf 0.4.4 → 0.4.5
Sign up to get free protection for your applications and to get access to all the features.
- data/app/controllers/bhf/entries_controller.rb +1 -1
- data/app/views/bhf/entries/form/column/_date.haml +1 -1
- data/app/views/bhf/pages/_platform.haml +1 -1
- data/config/locales/en.yml +7 -1
- data/vendor/assets/javascripts/bhf/application.js +9 -23
- data/vendor/assets/javascripts/bhf/classes/Locale.de-DE.DatePicker.js +16 -0
- data/vendor/assets/javascripts/bhf/classes/Locale.en-US.DatePicker.js +19 -0
- data/vendor/assets/javascripts/bhf/classes/Picker.js +344 -0
- data/vendor/assets/javascripts/bhf/classes/Picker_Attach.js +161 -0
- data/vendor/assets/javascripts/bhf/classes/Picker_Date.js +668 -0
- data/vendor/assets/javascripts/bhf/mootools-more-1.4.0.1.js +1316 -178
- data/vendor/assets/stylesheets/bhf/application.css.sass +1 -1
- metadata +17 -13
- data/vendor/assets/javascripts/bhf/classes/Datepicker.js +0 -38
@@ -0,0 +1,161 @@
|
|
1
|
+
/*
|
2
|
+
---
|
3
|
+
name: Picker.Attach
|
4
|
+
description: Adds attach and detach methods to the Picker, to attach it to element events
|
5
|
+
authors: Arian Stolwijk
|
6
|
+
requires: [Picker, Core/Element.Event]
|
7
|
+
provides: Picker.Attach
|
8
|
+
...
|
9
|
+
*/
|
10
|
+
|
11
|
+
|
12
|
+
Picker.Attach = new Class({
|
13
|
+
|
14
|
+
Extends: Picker,
|
15
|
+
|
16
|
+
options: {/*
|
17
|
+
onAttached: function(event){},
|
18
|
+
|
19
|
+
toggleElements: null, // deprecated
|
20
|
+
toggle: null, // When set it deactivate toggling by clicking on the input */
|
21
|
+
togglesOnly: true, // set to false to always make calendar popup on input element, if true, it depends on the toggles elements set.
|
22
|
+
showOnInit: false, // overrides the Picker option
|
23
|
+
blockKeydown: true
|
24
|
+
},
|
25
|
+
|
26
|
+
initialize: function(attachTo, options){
|
27
|
+
this.parent(options);
|
28
|
+
|
29
|
+
this.attachedEvents = [];
|
30
|
+
this.attachedElements = [];
|
31
|
+
this.toggles = [];
|
32
|
+
this.inputs = [];
|
33
|
+
|
34
|
+
var documentEvent = function(event){
|
35
|
+
if (this.attachedElements.contains(event.target)) return;
|
36
|
+
this.close();
|
37
|
+
}.bind(this);
|
38
|
+
var document = this.picker.getDocument().addEvent('click', documentEvent);
|
39
|
+
|
40
|
+
var preventPickerClick = function(event){
|
41
|
+
event.stopPropagation();
|
42
|
+
return false;
|
43
|
+
};
|
44
|
+
this.picker.addEvent('click', preventPickerClick);
|
45
|
+
|
46
|
+
// Support for deprecated toggleElements
|
47
|
+
if (this.options.toggleElements) this.options.toggle = document.getElements(this.options.toggleElements);
|
48
|
+
|
49
|
+
this.attach(attachTo, this.options.toggle);
|
50
|
+
},
|
51
|
+
|
52
|
+
attach: function(attachTo, toggle){
|
53
|
+
if (typeOf(attachTo) == 'string') attachTo = document.id(attachTo);
|
54
|
+
if (typeOf(toggle) == 'string') toggle = document.id(toggle);
|
55
|
+
|
56
|
+
var elements = Array.from(attachTo),
|
57
|
+
toggles = Array.from(toggle),
|
58
|
+
allElements = [].append(elements).combine(toggles),
|
59
|
+
self = this;
|
60
|
+
|
61
|
+
var closeEvent = function(event){
|
62
|
+
var stopInput = self.options.blockKeydown
|
63
|
+
&& event.type == 'keydown'
|
64
|
+
&& !(['tab', 'esc'].contains(event.key)),
|
65
|
+
isCloseKey = event.type == 'keydown'
|
66
|
+
&& (['tab', 'esc'].contains(event.key)),
|
67
|
+
isA = event.target.get('tag') == 'a';
|
68
|
+
|
69
|
+
if (stopInput || isA) event.preventDefault();
|
70
|
+
if (isCloseKey || isA) self.close();
|
71
|
+
};
|
72
|
+
|
73
|
+
var getOpenEvent = function(element){
|
74
|
+
return function(event){
|
75
|
+
var tag = event.target.get('tag');
|
76
|
+
if (tag == 'input' && event.type == 'click' && !element.match(':focus') || (self.opened && self.input == element)) return;
|
77
|
+
if (tag == 'a') event.stop();
|
78
|
+
self.position(element);
|
79
|
+
self.open();
|
80
|
+
self.fireEvent('attached', [event, element]);
|
81
|
+
};
|
82
|
+
};
|
83
|
+
|
84
|
+
var getToggleEvent = function(open, close){
|
85
|
+
return function(event){
|
86
|
+
if (self.opened) close(event);
|
87
|
+
else open(event);
|
88
|
+
};
|
89
|
+
};
|
90
|
+
|
91
|
+
allElements.each(function(element){
|
92
|
+
|
93
|
+
// The events are already attached!
|
94
|
+
if (self.attachedElements.contains(element)) return;
|
95
|
+
|
96
|
+
var events = {},
|
97
|
+
tag = element.get('tag'),
|
98
|
+
openEvent = getOpenEvent(element),
|
99
|
+
// closeEvent does not have a depency on element
|
100
|
+
toggleEvent = getToggleEvent(openEvent, closeEvent);
|
101
|
+
|
102
|
+
if (tag == 'input'){
|
103
|
+
// Fix in order to use togglers only
|
104
|
+
if (!self.options.togglesOnly || !toggles.length){
|
105
|
+
events = {
|
106
|
+
focus: openEvent,
|
107
|
+
click: openEvent,
|
108
|
+
keydown: closeEvent
|
109
|
+
};
|
110
|
+
}
|
111
|
+
self.inputs.push(element);
|
112
|
+
} else {
|
113
|
+
if (toggles.contains(element)){
|
114
|
+
self.toggles.push(element);
|
115
|
+
events.click = toggleEvent
|
116
|
+
} else {
|
117
|
+
events.click = openEvent;
|
118
|
+
}
|
119
|
+
}
|
120
|
+
element.addEvents(events);
|
121
|
+
self.attachedElements.push(element);
|
122
|
+
self.attachedEvents.push(events);
|
123
|
+
});
|
124
|
+
return this;
|
125
|
+
},
|
126
|
+
|
127
|
+
detach: function(attachTo, toggle){
|
128
|
+
if (typeOf(attachTo) == 'string') attachTo = document.id(attachTo);
|
129
|
+
if (typeOf(toggle) == 'string') toggle = document.id(toggle);
|
130
|
+
|
131
|
+
var elements = Array.from(attachTo),
|
132
|
+
toggles = Array.from(toggle),
|
133
|
+
allElements = [].append(elements).combine(toggles),
|
134
|
+
self = this;
|
135
|
+
|
136
|
+
if (!allElements.length) allElements = self.attachedElements;
|
137
|
+
|
138
|
+
allElements.each(function(element){
|
139
|
+
var i = self.attachedElements.indexOf(element);
|
140
|
+
if (i < 0) return;
|
141
|
+
|
142
|
+
var events = self.attachedEvents[i];
|
143
|
+
element.removeEvents(events);
|
144
|
+
delete self.attachedEvents[i];
|
145
|
+
delete self.attachedElements[i];
|
146
|
+
|
147
|
+
var toggleIndex = self.toggles.indexOf(element);
|
148
|
+
if (toggleIndex != -1) delete self.toggles[toggleIndex];
|
149
|
+
|
150
|
+
var inputIndex = self.inputs.indexOf(element);
|
151
|
+
if (toggleIndex != -1) delete self.inputs[inputIndex];
|
152
|
+
});
|
153
|
+
return this;
|
154
|
+
},
|
155
|
+
|
156
|
+
destroy: function(){
|
157
|
+
this.detach();
|
158
|
+
return this.parent();
|
159
|
+
}
|
160
|
+
|
161
|
+
});
|
@@ -0,0 +1,668 @@
|
|
1
|
+
/*
|
2
|
+
---
|
3
|
+
name: Picker.Date
|
4
|
+
description: Creates a DatePicker, can be used for picking years/months/days and time, or all of them
|
5
|
+
authors: Arian Stolwijk
|
6
|
+
requires: [Picker, Picker.Attach, Locale.en-US.DatePicker, More/Locale, More/Date]
|
7
|
+
provides: Picker.Date
|
8
|
+
...
|
9
|
+
*/
|
10
|
+
|
11
|
+
|
12
|
+
(function(){
|
13
|
+
|
14
|
+
this.DatePicker = Picker.Date = new Class({
|
15
|
+
|
16
|
+
Extends: Picker.Attach,
|
17
|
+
|
18
|
+
options: {/*
|
19
|
+
onSelect: function(date){},
|
20
|
+
|
21
|
+
minDate: new Date('3/4/2010'), // Date object or a string
|
22
|
+
maxDate: new Date('3/4/2011'), // same as minDate
|
23
|
+
availableDates: {}, //
|
24
|
+
invertAvailable: false,
|
25
|
+
|
26
|
+
format: null,*/
|
27
|
+
|
28
|
+
timePicker: false,
|
29
|
+
timePickerOnly: false, // deprecated, use onlyView = 'time'
|
30
|
+
timeWheelStep: 1, // 10,15,20,30
|
31
|
+
|
32
|
+
yearPicker: true,
|
33
|
+
yearsPerPage: 20,
|
34
|
+
|
35
|
+
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
|
36
|
+
rtl: false,
|
37
|
+
|
38
|
+
startView: 'days', // allowed values: {time, days, months, years}
|
39
|
+
openLastView: false,
|
40
|
+
pickOnly: false, // 'years', 'months', 'days', 'time'
|
41
|
+
canAlwaysGoUp: ['months', 'days'],
|
42
|
+
updateAll : false, //whether or not to update all inputs when selecting a date
|
43
|
+
|
44
|
+
weeknumbers: false,
|
45
|
+
|
46
|
+
// if you like to use your own translations
|
47
|
+
months_abbr: null,
|
48
|
+
days_abbr: null,
|
49
|
+
years_title: function(date, options){
|
50
|
+
var year = date.get('year');
|
51
|
+
return year + '-' + (year + options.yearsPerPage - 1);
|
52
|
+
},
|
53
|
+
months_title: function(date, options){
|
54
|
+
return date.get('year');
|
55
|
+
},
|
56
|
+
days_title: function(date, options){
|
57
|
+
return date.format('%b %Y');
|
58
|
+
},
|
59
|
+
time_title: function(date, options){
|
60
|
+
return (options.pickOnly == 'time') ? Locale.get('DatePicker.select_a_time') : date.format('%d %B, %Y');
|
61
|
+
}
|
62
|
+
},
|
63
|
+
|
64
|
+
initialize: function(attachTo, options){
|
65
|
+
this.parent(attachTo, options);
|
66
|
+
|
67
|
+
this.setOptions(options);
|
68
|
+
options = this.options;
|
69
|
+
|
70
|
+
// If we only want to use one picker / backwards compatibility
|
71
|
+
['year', 'month', 'day', 'time'].some(function(what){
|
72
|
+
if (options[what + 'PickerOnly']){
|
73
|
+
options.pickOnly = what;
|
74
|
+
return true;
|
75
|
+
}
|
76
|
+
return false;
|
77
|
+
});
|
78
|
+
if (options.pickOnly){
|
79
|
+
options[options.pickOnly + 'Picker'] = true;
|
80
|
+
options.startView = options.pickOnly;
|
81
|
+
}
|
82
|
+
|
83
|
+
// backward compatibility for startView
|
84
|
+
var newViews = ['days', 'months', 'years'];
|
85
|
+
['month', 'year', 'decades'].some(function(what, i){
|
86
|
+
return (options.startView == what) && (options.startView = newViews[i]);
|
87
|
+
});
|
88
|
+
|
89
|
+
options.canAlwaysGoUp = options.canAlwaysGoUp ? Array.from(options.canAlwaysGoUp) : [];
|
90
|
+
|
91
|
+
// Set the min and max dates as Date objects
|
92
|
+
if (options.minDate){
|
93
|
+
if (!(options.minDate instanceof Date)) options.minDate = Date.parse(options.minDate);
|
94
|
+
options.minDate.clearTime();
|
95
|
+
}
|
96
|
+
if (options.maxDate){
|
97
|
+
if (!(options.maxDate instanceof Date)) options.maxDate = Date.parse(options.maxDate);
|
98
|
+
options.maxDate.clearTime();
|
99
|
+
}
|
100
|
+
|
101
|
+
if (!options.format){
|
102
|
+
options.format = (options.pickOnly != 'time') ? Locale.get('Date.shortDate') : '';
|
103
|
+
if (options.timePicker) options.format = (options.format) + (options.format ? ' ' : '') + Locale.get('Date.shortTime');
|
104
|
+
}
|
105
|
+
|
106
|
+
// Some link or input has fired an event!
|
107
|
+
this.addEvent('attached', function(event, element){
|
108
|
+
|
109
|
+
// This is where we store the selected date
|
110
|
+
if (!this.currentView || !options.openLastView) this.currentView = options.startView;
|
111
|
+
|
112
|
+
this.date = limitDate(new Date(), options.minDate, options.maxDate);
|
113
|
+
var tag = element.get('tag'), input;
|
114
|
+
if (tag == 'input') input = element;
|
115
|
+
else {
|
116
|
+
var index = this.toggles.indexOf(element);
|
117
|
+
if (this.inputs[index]) input = this.inputs[index];
|
118
|
+
}
|
119
|
+
this.getInputDate(input);
|
120
|
+
this.input = input;
|
121
|
+
this.setColumns(this.originalColumns);
|
122
|
+
}.bind(this), true);
|
123
|
+
|
124
|
+
},
|
125
|
+
|
126
|
+
getInputDate: function(input){
|
127
|
+
this.date = new Date();
|
128
|
+
if (!input) return;
|
129
|
+
var date = Date.parse(input.get('value'));
|
130
|
+
if (!date || !date.isValid()){
|
131
|
+
var storeDate = input.retrieve('datepicker:value');
|
132
|
+
if (storeDate) date = Date.parse(storeDate);
|
133
|
+
}
|
134
|
+
if (date && date != null && date.isValid()) this.date = date;
|
135
|
+
},
|
136
|
+
|
137
|
+
// Control the previous and next elements
|
138
|
+
|
139
|
+
constructPicker: function(){
|
140
|
+
this.parent();
|
141
|
+
|
142
|
+
if (!this.options.rtl){
|
143
|
+
this.previous = new Element('div.previous[html=«]').inject(this.header);
|
144
|
+
this.next = new Element('div.next[html=»]').inject(this.header);
|
145
|
+
} else {
|
146
|
+
this.next = new Element('div.previous[html=«]').inject(this.header);
|
147
|
+
this.previous = new Element('div.next[html=»]').inject(this.header);
|
148
|
+
}
|
149
|
+
},
|
150
|
+
|
151
|
+
hidePrevious: function(_next, _show){
|
152
|
+
this[_next ? 'next' : 'previous'].setStyle('display', _show ? 'block' : 'none');
|
153
|
+
return this;
|
154
|
+
},
|
155
|
+
|
156
|
+
showPrevious: function(_next){
|
157
|
+
return this.hidePrevious(_next, true);
|
158
|
+
},
|
159
|
+
|
160
|
+
setPreviousEvent: function(fn, _next){
|
161
|
+
this[_next ? 'next' : 'previous'].removeEvents('click');
|
162
|
+
if (fn) this[_next ? 'next' : 'previous'].addEvent('click', fn);
|
163
|
+
return this;
|
164
|
+
},
|
165
|
+
|
166
|
+
hideNext: function(){
|
167
|
+
return this.hidePrevious(true);
|
168
|
+
},
|
169
|
+
|
170
|
+
showNext: function(){
|
171
|
+
return this.showPrevious(true);
|
172
|
+
},
|
173
|
+
|
174
|
+
setNextEvent: function(fn){
|
175
|
+
return this.setPreviousEvent(fn, true);
|
176
|
+
},
|
177
|
+
|
178
|
+
setColumns: function(columns, view, date, viewFx){
|
179
|
+
var ret = this.parent(columns), method;
|
180
|
+
|
181
|
+
if ((view || this.currentView)
|
182
|
+
&& (method = 'render' + (view || this.currentView).capitalize())
|
183
|
+
&& this[method]
|
184
|
+
) this[method](date || this.date.clone(), viewFx);
|
185
|
+
|
186
|
+
return ret;
|
187
|
+
},
|
188
|
+
|
189
|
+
// Render the Pickers
|
190
|
+
|
191
|
+
renderYears: function(date, fx){
|
192
|
+
var options = this.options, pages = options.columns, perPage = options.yearsPerPage,
|
193
|
+
_columns = [], _dates = [];
|
194
|
+
this.dateElements = [];
|
195
|
+
|
196
|
+
// start neatly at interval (eg. 1980 instead of 1987)
|
197
|
+
date = date.clone().decrement('year', date.get('year') % perPage);
|
198
|
+
|
199
|
+
var iterateDate = date.clone().decrement('year', Math.floor((pages - 1) / 2) * perPage);
|
200
|
+
|
201
|
+
for (var i = pages; i--;){
|
202
|
+
var _date = iterateDate.clone();
|
203
|
+
_dates.push(_date);
|
204
|
+
_columns.push(renderers.years(
|
205
|
+
timesSelectors.years(options, _date.clone()),
|
206
|
+
options,
|
207
|
+
this.date.clone(),
|
208
|
+
this.dateElements,
|
209
|
+
function(date){
|
210
|
+
if (options.pickOnly == 'years') this.select(date);
|
211
|
+
else this.renderMonths(date, 'fade');
|
212
|
+
this.date = date;
|
213
|
+
}.bind(this)
|
214
|
+
));
|
215
|
+
iterateDate.increment('year', perPage);
|
216
|
+
}
|
217
|
+
|
218
|
+
this.setColumnsContent(_columns, fx);
|
219
|
+
this.setTitle(_dates, options.years_title);
|
220
|
+
|
221
|
+
// Set limits
|
222
|
+
var limitLeft = (options.minDate && date.get('year') <= options.minDate.get('year')),
|
223
|
+
limitRight = (options.maxDate && (date.get('year') + options.yearsPerPage) >= options.maxDate.get('year'));
|
224
|
+
this[(limitLeft ? 'hide' : 'show') + 'Previous']();
|
225
|
+
this[(limitRight ? 'hide' : 'show') + 'Next']();
|
226
|
+
|
227
|
+
this.setPreviousEvent(function(){
|
228
|
+
this.renderYears(date.decrement('year', perPage), 'left');
|
229
|
+
}.bind(this));
|
230
|
+
|
231
|
+
this.setNextEvent(function(){
|
232
|
+
this.renderYears(date.increment('year', perPage), 'right');
|
233
|
+
}.bind(this));
|
234
|
+
|
235
|
+
// We can't go up!
|
236
|
+
this.setTitleEvent(null);
|
237
|
+
|
238
|
+
this.currentView = 'years';
|
239
|
+
},
|
240
|
+
|
241
|
+
renderMonths: function(date, fx){
|
242
|
+
var options = this.options, years = options.columns, _columns = [], _dates = [],
|
243
|
+
iterateDate = date.clone().decrement('year', Math.floor((years - 1) / 2));
|
244
|
+
this.dateElements = [];
|
245
|
+
|
246
|
+
for (var i = years; i--;){
|
247
|
+
var _date = iterateDate.clone();
|
248
|
+
_dates.push(_date);
|
249
|
+
_columns.push(renderers.months(
|
250
|
+
timesSelectors.months(options, _date.clone()),
|
251
|
+
options,
|
252
|
+
this.date.clone(),
|
253
|
+
this.dateElements,
|
254
|
+
function(date){
|
255
|
+
if (options.pickOnly == 'months') this.select(date);
|
256
|
+
else this.renderDays(date, 'fade');
|
257
|
+
this.date = date;
|
258
|
+
}.bind(this)
|
259
|
+
));
|
260
|
+
iterateDate.increment('year', 1);
|
261
|
+
}
|
262
|
+
|
263
|
+
this.setColumnsContent(_columns, fx);
|
264
|
+
this.setTitle(_dates, options.months_title);
|
265
|
+
|
266
|
+
// Set limits
|
267
|
+
var year = date.get('year'),
|
268
|
+
limitLeft = (options.minDate && year <= options.minDate.get('year')),
|
269
|
+
limitRight = (options.maxDate && year >= options.maxDate.get('year'));
|
270
|
+
this[(limitLeft ? 'hide' : 'show') + 'Previous']();
|
271
|
+
this[(limitRight ? 'hide' : 'show') + 'Next']();
|
272
|
+
|
273
|
+
this.setPreviousEvent(function(){
|
274
|
+
this.renderMonths(date.decrement('year', years), 'left');
|
275
|
+
}.bind(this));
|
276
|
+
|
277
|
+
this.setNextEvent(function(){
|
278
|
+
this.renderMonths(date.increment('year', years), 'right');
|
279
|
+
}.bind(this));
|
280
|
+
|
281
|
+
var canGoUp = options.yearPicker && (options.pickOnly != 'months' || options.canAlwaysGoUp.contains('months'));
|
282
|
+
var titleEvent = (canGoUp) ? function(){
|
283
|
+
this.renderYears(date, 'fade');
|
284
|
+
}.bind(this) : null;
|
285
|
+
this.setTitleEvent(titleEvent);
|
286
|
+
|
287
|
+
this.currentView = 'months';
|
288
|
+
},
|
289
|
+
|
290
|
+
renderDays: function(date, fx){
|
291
|
+
var options = this.options, months = options.columns, _columns = [], _dates = [],
|
292
|
+
iterateDate = date.clone().decrement('month', Math.floor((months - 1) / 2));
|
293
|
+
this.dateElements = [];
|
294
|
+
|
295
|
+
for (var i = months; i--;){
|
296
|
+
_date = iterateDate.clone();
|
297
|
+
_dates.push(_date);
|
298
|
+
_columns.push(renderers.days(
|
299
|
+
timesSelectors.days(options, _date.clone()),
|
300
|
+
options,
|
301
|
+
this.date.clone(),
|
302
|
+
this.dateElements,
|
303
|
+
function(date){
|
304
|
+
if (options.pickOnly == 'days' || !options.timePicker) this.select(date)
|
305
|
+
else this.renderTime(date, 'fade');
|
306
|
+
this.date = date;
|
307
|
+
}.bind(this)
|
308
|
+
));
|
309
|
+
iterateDate.increment('month', 1);
|
310
|
+
}
|
311
|
+
|
312
|
+
this.setColumnsContent(_columns, fx);
|
313
|
+
this.setTitle(_dates, options.days_title);
|
314
|
+
|
315
|
+
var yearmonth = date.format('%Y%m').toInt(),
|
316
|
+
limitLeft = (options.minDate && yearmonth <= options.minDate.format('%Y%m')),
|
317
|
+
limitRight = (options.maxDate && yearmonth >= options.maxDate.format('%Y%m'));
|
318
|
+
this[(limitLeft ? 'hide' : 'show') + 'Previous']();
|
319
|
+
this[(limitRight ? 'hide' : 'show') + 'Next']();
|
320
|
+
|
321
|
+
this.setPreviousEvent(function(){
|
322
|
+
this.renderDays(date.decrement('month', months), 'left');
|
323
|
+
}.bind(this));
|
324
|
+
|
325
|
+
this.setNextEvent(function(){
|
326
|
+
this.renderDays(date.increment('month', months), 'right');
|
327
|
+
}.bind(this));
|
328
|
+
|
329
|
+
var canGoUp = options.pickOnly != 'days' || options.canAlwaysGoUp.contains('days');
|
330
|
+
var titleEvent = (canGoUp) ? function(){
|
331
|
+
this.renderMonths(date, 'fade');
|
332
|
+
}.bind(this) : null;
|
333
|
+
this.setTitleEvent(titleEvent);
|
334
|
+
|
335
|
+
this.currentView = 'days';
|
336
|
+
},
|
337
|
+
|
338
|
+
renderTime: function(date, fx){
|
339
|
+
var options = this.options;
|
340
|
+
this.setTitle(date, options.time_title);
|
341
|
+
|
342
|
+
var originalColumns = this.originalColumns = options.columns;
|
343
|
+
this.currentView = null; // otherwise you'd get crazy recursion
|
344
|
+
if (originalColumns != 1) this.setColumns(1);
|
345
|
+
|
346
|
+
this.setContent(renderers.time(
|
347
|
+
options,
|
348
|
+
date.clone(),
|
349
|
+
function(date){
|
350
|
+
this.select(date);
|
351
|
+
}.bind(this)
|
352
|
+
), fx);
|
353
|
+
|
354
|
+
// Hide « and » buttons
|
355
|
+
this.hidePrevious()
|
356
|
+
.hideNext()
|
357
|
+
.setPreviousEvent(null)
|
358
|
+
.setNextEvent(null);
|
359
|
+
|
360
|
+
var canGoUp = options.pickOnly != 'time' || options.canAlwaysGoUp.contains('time');
|
361
|
+
var titleEvent = (canGoUp) ? function(){
|
362
|
+
this.setColumns(originalColumns, 'days', date, 'fade');
|
363
|
+
}.bind(this) : null;
|
364
|
+
this.setTitleEvent(titleEvent);
|
365
|
+
|
366
|
+
this.currentView = 'time';
|
367
|
+
},
|
368
|
+
|
369
|
+
select: function(date, all){
|
370
|
+
this.date = date;
|
371
|
+
var formatted = date.format(this.options.format),
|
372
|
+
time = date.strftime(),
|
373
|
+
inputs = (!this.options.updateAll && !all && this.input) ? [this.input] : this.inputs;
|
374
|
+
|
375
|
+
inputs.each(function(input){
|
376
|
+
input.set('value', formatted).store('datepicker:value', time).fireEvent('change');
|
377
|
+
}, this);
|
378
|
+
|
379
|
+
this.fireEvent('select', [date].concat(inputs));
|
380
|
+
this.close();
|
381
|
+
return this;
|
382
|
+
}
|
383
|
+
|
384
|
+
});
|
385
|
+
|
386
|
+
|
387
|
+
// Renderers only output elements and calculate the limits!
|
388
|
+
|
389
|
+
var timesSelectors = {
|
390
|
+
|
391
|
+
years: function(options, date){
|
392
|
+
var times = [];
|
393
|
+
for (var i = 0; i < options.yearsPerPage; i++){
|
394
|
+
times.push(+date);
|
395
|
+
date.increment('year', 1);
|
396
|
+
}
|
397
|
+
return times;
|
398
|
+
},
|
399
|
+
|
400
|
+
months: function(options, date){
|
401
|
+
var times = [];
|
402
|
+
date.set('month', 0);
|
403
|
+
for (var i = 0; i <= 11; i++){
|
404
|
+
times.push(+date);
|
405
|
+
date.increment('month', 1);
|
406
|
+
}
|
407
|
+
return times;
|
408
|
+
},
|
409
|
+
|
410
|
+
days: function(options, date){
|
411
|
+
var times = [];
|
412
|
+
date.set('date', 1);
|
413
|
+
while (date.get('day') != options.startDay) date.set('date', date.get('date') - 1);
|
414
|
+
for (var i = 0; i < 42; i++){
|
415
|
+
times.push(+date);
|
416
|
+
date.increment('day', 1);
|
417
|
+
}
|
418
|
+
return times;
|
419
|
+
}
|
420
|
+
|
421
|
+
};
|
422
|
+
|
423
|
+
var renderers = {
|
424
|
+
|
425
|
+
years: function(years, options, currentDate, dateElements, fn){
|
426
|
+
var container = new Element('div.years'),
|
427
|
+
today = new Date(), element, classes;
|
428
|
+
|
429
|
+
years.each(function(_year, i){
|
430
|
+
var date = new Date(_year), year = date.get('year');
|
431
|
+
|
432
|
+
classes = '.year.year' + i;
|
433
|
+
if (year == today.get('year')) classes += '.today';
|
434
|
+
if (year == currentDate.get('year')) classes += '.selected';
|
435
|
+
element = new Element('div' + classes, {text: year}).inject(container);
|
436
|
+
|
437
|
+
dateElements.push({element: element, time: _year});
|
438
|
+
|
439
|
+
if (isUnavailable('year', date, options)) element.addClass('unavailable');
|
440
|
+
else element.addEvent('click', fn.pass(date));
|
441
|
+
});
|
442
|
+
|
443
|
+
return container;
|
444
|
+
},
|
445
|
+
|
446
|
+
months: function(months, options, currentDate, dateElements, fn){
|
447
|
+
var today = new Date(),
|
448
|
+
month = today.get('month'),
|
449
|
+
thisyear = today.get('year'),
|
450
|
+
selectedyear = currentDate.get('year'),
|
451
|
+
container = new Element('div.months'),
|
452
|
+
monthsAbbr = options.months_abbr || Locale.get('Date.months_abbr'),
|
453
|
+
element, classes;
|
454
|
+
|
455
|
+
months.each(function(_month, i){
|
456
|
+
var date = new Date(_month), year = date.get('year');
|
457
|
+
|
458
|
+
classes = '.month.month' + (i + 1);
|
459
|
+
if (i == month && year == thisyear) classes += '.today';
|
460
|
+
if (i == currentDate.get('month') && year == selectedyear) classes += '.selected';
|
461
|
+
element = new Element('div' + classes, {text: monthsAbbr[i]}).inject(container);
|
462
|
+
|
463
|
+
dateElements.push({element: element, time: _month});
|
464
|
+
|
465
|
+
if (isUnavailable('month', date, options)) element.addClass('unavailable');
|
466
|
+
else element.addEvent('click', fn.pass(date));
|
467
|
+
});
|
468
|
+
|
469
|
+
return container;
|
470
|
+
},
|
471
|
+
|
472
|
+
days: function(days, options, currentDate, dateElements, fn){
|
473
|
+
var month = new Date(days[14]).get('month'),
|
474
|
+
todayString = new Date().toDateString(),
|
475
|
+
currentString = currentDate.toDateString(),
|
476
|
+
weeknumbers = options.weeknumbers,
|
477
|
+
container = new Element('table.days' + (weeknumbers ? '.weeknumbers' : ''), {
|
478
|
+
role: 'grid', 'aria-labelledby': this.titleID
|
479
|
+
}),
|
480
|
+
header = new Element('thead').inject(container),
|
481
|
+
body = new Element('tbody').inject(container),
|
482
|
+
titles = new Element('tr.titles').inject(header),
|
483
|
+
localeDaysShort = options.days_abbr || Locale.get('Date.days_abbr'),
|
484
|
+
day, classes, element, weekcontainer, dateString,
|
485
|
+
where = options.rtl ? 'top' : 'bottom';
|
486
|
+
|
487
|
+
if (weeknumbers) new Element('th.title.day.weeknumber', {
|
488
|
+
text: Locale.get('DatePicker.week')
|
489
|
+
}).inject(titles);
|
490
|
+
|
491
|
+
for (day = options.startDay; day < (options.startDay + 7); day++){
|
492
|
+
new Element('th.title.day.day' + (day % 7), {
|
493
|
+
text: localeDaysShort[(day % 7)],
|
494
|
+
role: 'columnheader'
|
495
|
+
}).inject(titles, where);
|
496
|
+
}
|
497
|
+
|
498
|
+
days.each(function(_date, i){
|
499
|
+
var date = new Date(_date);
|
500
|
+
|
501
|
+
if (i % 7 == 0){
|
502
|
+
weekcontainer = new Element('tr.week.week' + (Math.floor(i / 7))).set('role', 'row').inject(body);
|
503
|
+
if (weeknumbers) new Element('th.day.weeknumber', {text: date.get('week'), scope: 'row', role: 'rowheader'}).inject(weekcontainer);
|
504
|
+
}
|
505
|
+
|
506
|
+
dateString = date.toDateString();
|
507
|
+
classes = '.day.day' + date.get('day');
|
508
|
+
if (dateString == todayString) classes += '.today';
|
509
|
+
if (date.get('month') != month) classes += '.otherMonth';
|
510
|
+
element = new Element('td' + classes, {text: date.getDate(), role: 'gridcell'}).inject(weekcontainer, where);
|
511
|
+
|
512
|
+
if (dateString == currentString) element.addClass('selected').set('aria-selected', 'true');
|
513
|
+
else element.set('aria-selected', 'false');
|
514
|
+
|
515
|
+
dateElements.push({element: element, time: _date});
|
516
|
+
|
517
|
+
if (isUnavailable('date', date, options)) element.addClass('unavailable');
|
518
|
+
else element.addEvent('click', fn.pass(date.clone()));
|
519
|
+
});
|
520
|
+
|
521
|
+
return container;
|
522
|
+
},
|
523
|
+
|
524
|
+
time: function(options, date, fn){
|
525
|
+
var container = new Element('div.time'),
|
526
|
+
// make sure that the minutes are timeWheelStep * k
|
527
|
+
initMinutes = (date.get('minutes') / options.timeWheelStep).round() * options.timeWheelStep
|
528
|
+
|
529
|
+
if (initMinutes >= 60) initMinutes = 0;
|
530
|
+
date.set('minutes', initMinutes);
|
531
|
+
|
532
|
+
var hoursInput = new Element('input.hour[type=text]', {
|
533
|
+
title: Locale.get('DatePicker.use_mouse_wheel'),
|
534
|
+
value: date.format('%H'),
|
535
|
+
events: {
|
536
|
+
click: function(event){
|
537
|
+
event.target.focus();
|
538
|
+
event.stop();
|
539
|
+
},
|
540
|
+
mousewheel: function(event){
|
541
|
+
event.stop();
|
542
|
+
hoursInput.focus();
|
543
|
+
var value = hoursInput.get('value').toInt();
|
544
|
+
value = (event.wheel > 0) ? ((value < 23) ? value + 1 : 0)
|
545
|
+
: ((value > 0) ? value - 1 : 23)
|
546
|
+
date.set('hours', value);
|
547
|
+
hoursInput.set('value', date.format('%H'));
|
548
|
+
}.bind(this)
|
549
|
+
},
|
550
|
+
maxlength: 2
|
551
|
+
}).inject(container);
|
552
|
+
|
553
|
+
var minutesInput = new Element('input.minutes[type=text]', {
|
554
|
+
title: Locale.get('DatePicker.use_mouse_wheel'),
|
555
|
+
value: date.format('%M'),
|
556
|
+
events: {
|
557
|
+
click: function(event){
|
558
|
+
event.target.focus();
|
559
|
+
event.stop();
|
560
|
+
},
|
561
|
+
mousewheel: function(event){
|
562
|
+
event.stop();
|
563
|
+
minutesInput.focus();
|
564
|
+
var value = minutesInput.get('value').toInt();
|
565
|
+
value = (event.wheel > 0) ? ((value < 59) ? (value + options.timeWheelStep) : 0)
|
566
|
+
: ((value > 0) ? (value - options.timeWheelStep) : (60 - options.timeWheelStep));
|
567
|
+
if (value >= 60) value = 0;
|
568
|
+
date.set('minutes', value);
|
569
|
+
minutesInput.set('value', date.format('%M'));
|
570
|
+
}.bind(this)
|
571
|
+
},
|
572
|
+
maxlength: 2
|
573
|
+
}).inject(container);
|
574
|
+
|
575
|
+
new Element('div.separator[text=:]').inject(container);
|
576
|
+
|
577
|
+
new Element('input.ok[type=submit]', {
|
578
|
+
value: Locale.get('DatePicker.time_confirm_button'),
|
579
|
+
events: {click: function(event){
|
580
|
+
event.stop();
|
581
|
+
date.set({
|
582
|
+
hours: hoursInput.get('value').toInt(),
|
583
|
+
minutes: minutesInput.get('value').toInt()
|
584
|
+
});
|
585
|
+
fn(date.clone());
|
586
|
+
}}
|
587
|
+
}).inject(container);
|
588
|
+
|
589
|
+
return container;
|
590
|
+
}
|
591
|
+
|
592
|
+
};
|
593
|
+
|
594
|
+
|
595
|
+
Picker.Date.defineRenderer = function(name, fn){
|
596
|
+
renderers[name] = fn;
|
597
|
+
return this;
|
598
|
+
};
|
599
|
+
|
600
|
+
var limitDate = function(date, min, max){
|
601
|
+
if (min && date < min) return min;
|
602
|
+
if (max && date > max) return max;
|
603
|
+
return date;
|
604
|
+
};
|
605
|
+
|
606
|
+
var isUnavailable = function(type, date, options){
|
607
|
+
var minDate = options.minDate,
|
608
|
+
maxDate = options.maxDate,
|
609
|
+
availableDates = options.availableDates,
|
610
|
+
year, month, day, ms;
|
611
|
+
|
612
|
+
if (!minDate && !maxDate && !availableDates) return false;
|
613
|
+
date.clearTime();
|
614
|
+
|
615
|
+
if (type == 'year'){
|
616
|
+
year = date.get('year');
|
617
|
+
return (
|
618
|
+
(minDate && year < minDate.get('year')) ||
|
619
|
+
(maxDate && year > maxDate.get('year')) ||
|
620
|
+
(
|
621
|
+
(availableDates != null && !options.invertAvailable) && (
|
622
|
+
availableDates[year] == null ||
|
623
|
+
Object.getLength(availableDates[year]) == 0 ||
|
624
|
+
Object.getLength(
|
625
|
+
Object.filter(availableDates[year], function(days){
|
626
|
+
return (days.length > 0);
|
627
|
+
})
|
628
|
+
) == 0
|
629
|
+
)
|
630
|
+
)
|
631
|
+
);
|
632
|
+
}
|
633
|
+
|
634
|
+
if (type == 'month'){
|
635
|
+
year = date.get('year');
|
636
|
+
month = date.get('month') + 1;
|
637
|
+
ms = date.format('%Y%m').toInt();
|
638
|
+
return (
|
639
|
+
(minDate && ms < minDate.format('%Y%m').toInt()) ||
|
640
|
+
(maxDate && ms > maxDate.format('%Y%m').toInt()) ||
|
641
|
+
(
|
642
|
+
(availableDates != null && !options.invertAvailable) && (
|
643
|
+
availableDates[year] == null ||
|
644
|
+
availableDates[year][month] == null ||
|
645
|
+
availableDates[year][month].length == 0
|
646
|
+
)
|
647
|
+
)
|
648
|
+
);
|
649
|
+
}
|
650
|
+
|
651
|
+
// type == 'date'
|
652
|
+
year = date.get('year');
|
653
|
+
month = date.get('month') + 1;
|
654
|
+
day = date.get('date');
|
655
|
+
|
656
|
+
var dateAllow = (minDate && date < minDate) || (maxDate && date > maxDate);
|
657
|
+
if (availableDates != null){
|
658
|
+
dateAllow = dateAllow
|
659
|
+
|| availableDates[year] == null
|
660
|
+
|| availableDates[year][month] == null
|
661
|
+
|| !availableDates[year][month].contains(day);
|
662
|
+
if (options.invertAvailable) dateAllow = !dateAllow;
|
663
|
+
}
|
664
|
+
|
665
|
+
return dateAllow;
|
666
|
+
};
|
667
|
+
|
668
|
+
})();
|