bhf 0.4.4 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
})();
|