Commit c0c8151c81f7daddd4bfe28bed13e8510ce0d425
1 parent
4398fe05
Exists in
master
and in
28 other branches
Including a helper for jquery datetime fields
Showing
4 changed files
with
1653 additions
and
1 deletions
Show diff stats
app/helpers/forms_helper.rb
@@ -123,6 +123,119 @@ module FormsHelper | @@ -123,6 +123,119 @@ module FormsHelper | ||
123 | options_for_select.join("\n") | 123 | options_for_select.join("\n") |
124 | end | 124 | end |
125 | 125 | ||
126 | + def date_field(name, value, format = '%Y-%m-%d', datepicker_options = {}, html_options = {}) | ||
127 | + datepicker_options[:disabled] ||= false | ||
128 | + datepicker_options[:alt_field] ||= '' | ||
129 | + datepicker_options[:alt_format] ||= '' | ||
130 | + datepicker_options[:append_text] ||= '' | ||
131 | + datepicker_options[:auto_size] ||= false | ||
132 | + datepicker_options[:button_image] ||= '' | ||
133 | + datepicker_options[:button_image_only] ||= false | ||
134 | + datepicker_options[:button_text] ||= '...' | ||
135 | + datepicker_options[:calculate_week] ||= 'jQuery.datepicker.iso8601Week' | ||
136 | + datepicker_options[:change_month] ||= false | ||
137 | + datepicker_options[:change_year] ||= false | ||
138 | + datepicker_options[:close_text] ||= _('Done') | ||
139 | + datepicker_options[:constrain_input] ||= true | ||
140 | + datepicker_options[:current_text] ||= _('Today') | ||
141 | + datepicker_options[:date_format] ||= 'mm/dd/yy' | ||
142 | + datepicker_options[:day_names] ||= [_('Sunday'), _('Monday'), _('Tuesday'), _('Wednesday'), _('Thursday'), _('Friday'), _('Saturday')] | ||
143 | + datepicker_options[:day_names_min] ||= [_('Su'), _('Mo'), _('Tu'), _('We'), _('Th'), _('Fr'), _('Sa')] | ||
144 | + datepicker_options[:day_names_short] ||= [_('Sun'), _('Mon'), _('Tue'), _('Wed'), _('Thu'), _('Fri'), _('Sat')] | ||
145 | + datepicker_options[:default_date] ||= nil | ||
146 | + datepicker_options[:duration] ||= 'normal' | ||
147 | + datepicker_options[:first_day] ||= 0 | ||
148 | + datepicker_options[:goto_current] ||= false | ||
149 | + datepicker_options[:hide_if_no_prev_next] ||= false | ||
150 | + datepicker_options[:is_rtl] ||= false | ||
151 | + datepicker_options[:max_date] ||= nil | ||
152 | + datepicker_options[:min_date] ||= nil | ||
153 | + datepicker_options[:month_names] ||= [_('January'), _('February'), _('March'), _('April'), _('May'), _('June'), _('July'), _('August'), _('September'), _('October'), _('November'), _('December')] | ||
154 | + datepicker_options[:month_names_short] ||= [_('Jan'), _('Feb'), _('Mar'), _('Apr'), _('May'), _('Jun'), _('Jul'), _('Aug'), _('Sep'), _('Oct'), _('Nov'), _('Dec')] | ||
155 | + datepicker_options[:navigation_as_date_format] ||= false | ||
156 | + datepicker_options[:next_text] ||= _('Next') | ||
157 | + datepicker_options[:number_of_months] ||= 1 | ||
158 | + datepicker_options[:prev_text] ||= _('Prev') | ||
159 | + datepicker_options[:select_other_months] ||= false | ||
160 | + datepicker_options[:short_year_cutoff] ||= '+10' | ||
161 | + datepicker_options[:show_button_panel] ||= false | ||
162 | + datepicker_options[:show_current_at_pos] ||= 0 | ||
163 | + datepicker_options[:show_month_after_year] ||= false | ||
164 | + datepicker_options[:show_on] ||= 'focus' | ||
165 | + datepicker_options[:show_options] ||= {} | ||
166 | + datepicker_options[:show_other_months] ||= false | ||
167 | + datepicker_options[:show_week] ||= false | ||
168 | + datepicker_options[:step_months] ||= 1 | ||
169 | + datepicker_options[:week_header] ||= _('Wk') | ||
170 | + datepicker_options[:year_range] ||= 'c-10:c+10' | ||
171 | + datepicker_options[:year_suffix] ||= '' | ||
172 | + | ||
173 | + element_id = html_options[:id] || 'datepicker-date' | ||
174 | + value = value.strftime(format) if value.present? | ||
175 | + method = datepicker_options[:time] ? 'datetimepicker' : 'datepicker' | ||
176 | + result = text_field_tag(name, value, html_options) | ||
177 | + result += | ||
178 | + " | ||
179 | + <script type='text/javascript'> | ||
180 | + jQuery('##{element_id}').#{method}({ | ||
181 | + disabled: #{datepicker_options[:disabled].to_json}, | ||
182 | + altField: #{datepicker_options[:alt_field].to_json}, | ||
183 | + altFormat: #{datepicker_options[:alt_format].to_json}, | ||
184 | + appendText: #{datepicker_options[:append_text].to_json}, | ||
185 | + autoSize: #{datepicker_options[:auto_size].to_json}, | ||
186 | + buttonImage: #{datepicker_options[:button_image].to_json}, | ||
187 | + buttonImageOnly: #{datepicker_options[:button_image_only].to_json}, | ||
188 | + buttonText: #{datepicker_options[:button_text].to_json}, | ||
189 | + calculateWeek: #{datepicker_options[:calculate_week].to_json}, | ||
190 | + changeMonth: #{datepicker_options[:change_month].to_json}, | ||
191 | + changeYear: #{datepicker_options[:change_year].to_json}, | ||
192 | + closeText: #{datepicker_options[:close_text].to_json}, | ||
193 | + constrainInput: #{datepicker_options[:constrain_input].to_json}, | ||
194 | + currentText: #{datepicker_options[:current_text].to_json}, | ||
195 | + dateFormat: #{datepicker_options[:date_format].to_json}, | ||
196 | + dayNames: #{datepicker_options[:day_names].to_json}, | ||
197 | + dayNamesMin: #{datepicker_options[:day_names_min].to_json}, | ||
198 | + dayNamesShort: #{datepicker_options[:day_names_short].to_json}, | ||
199 | + defaultDate: #{datepicker_options[:default_date].to_json}, | ||
200 | + duration: #{datepicker_options[:duration].to_json}, | ||
201 | + firstDay: #{datepicker_options[:first_day].to_json}, | ||
202 | + gotoCurrent: #{datepicker_options[:goto_current].to_json}, | ||
203 | + hideIfNoPrevNext: #{datepicker_options[:hide_if_no_prev_next].to_json}, | ||
204 | + isRTL: #{datepicker_options[:is_rtl].to_json}, | ||
205 | + maxDate: #{datepicker_options[:max_date].to_json}, | ||
206 | + minDate: #{datepicker_options[:min_date].to_json}, | ||
207 | + monthNames: #{datepicker_options[:month_names].to_json}, | ||
208 | + monthNamesShort: #{datepicker_options[:month_names_short].to_json}, | ||
209 | + navigationAsDateFormat: #{datepicker_options[:navigation_as_date_format].to_json}, | ||
210 | + nextText: #{datepicker_options[:next_text].to_json}, | ||
211 | + numberOfMonths: #{datepicker_options[:number_of_months].to_json}, | ||
212 | + prevText: #{datepicker_options[:prev_text].to_json}, | ||
213 | + selectOtherMonths: #{datepicker_options[:select_other_months].to_json}, | ||
214 | + shortYearCutoff: #{datepicker_options[:short_year_cutoff].to_json}, | ||
215 | + showButtonPanel: #{datepicker_options[:show_button_panel].to_json}, | ||
216 | + showCurrentAtPos: #{datepicker_options[:show_current_at_pos].to_json}, | ||
217 | + showMonthAfterYear: #{datepicker_options[:show_month_after_year].to_json}, | ||
218 | + showOn: #{datepicker_options[:show_on].to_json}, | ||
219 | + showOptions: #{datepicker_options[:show_options].to_json}, | ||
220 | + showOtherMonths: #{datepicker_options[:show_other_months].to_json}, | ||
221 | + showWeek: #{datepicker_options[:show_week].to_json}, | ||
222 | + stepMonths: #{datepicker_options[:step_months].to_json}, | ||
223 | + weekHeader: #{datepicker_options[:week_header].to_json}, | ||
224 | + yearRange: #{datepicker_options[:year_range].to_json}, | ||
225 | + yearSuffix: #{datepicker_options[:year_suffix].to_json} | ||
226 | + }) | ||
227 | + </script> | ||
228 | + " | ||
229 | + result | ||
230 | + end | ||
231 | + | ||
232 | + def date_range_field(from_name, to_name, from_value, to_value, format = '%Y-%m-%d', datepicker_options = {}, html_options = {}) | ||
233 | + from_id = html_options[:from_id] || 'datepicker-from-date' | ||
234 | + to_id = html_options[:to_id] || 'datepicker-to-date' | ||
235 | + return _('From') +' '+ date_field(from_name, from_value, format, datepicker_options, html_options.merge({:id => from_id})) + | ||
236 | + ' ' + _('until') +' '+ date_field(to_name, to_value, format, datepicker_options, html_options.merge({:id => to_id})) | ||
237 | + end | ||
238 | + | ||
126 | protected | 239 | protected |
127 | def self.next_id_number | 240 | def self.next_id_number |
128 | if defined? @@id_num | 241 | if defined? @@id_num |
app/views/layouts/_javascript.rhtml
@@ -2,7 +2,8 @@ | @@ -2,7 +2,8 @@ | ||
2 | 'jquery.noconflict.js', 'jquery.cycle.all.min.js', 'thickbox.js', 'lightbox', 'colorbox', | 2 | 'jquery.noconflict.js', 'jquery.cycle.all.min.js', 'thickbox.js', 'lightbox', 'colorbox', |
3 | 'jquery-ui-1.8.2.custom.min', 'jquery.scrollTo', 'jquery.form.js', 'jquery-validation/jquery.validate', | 3 | 'jquery-ui-1.8.2.custom.min', 'jquery.scrollTo', 'jquery.form.js', 'jquery-validation/jquery.validate', |
4 | 'jquery.cookie', 'jquery.ba-bbq.min.js', 'reflection', 'jquery.tokeninput', | 4 | 'jquery.cookie', 'jquery.ba-bbq.min.js', 'reflection', 'jquery.tokeninput', |
5 | -'add-and-join', 'report-abuse', 'catalog', 'manage-products', :cache => 'cache-general' %> | 5 | +'add-and-join', 'report-abuse', 'catalog', 'manage-products', |
6 | +'jquery-ui-timepicker-addon', :cache => 'cache-general' %> | ||
6 | 7 | ||
7 | <% language = FastGettext.locale %> | 8 | <% language = FastGettext.locale %> |
8 | <% %w{messages methods}.each do |type| %> | 9 | <% %w{messages methods}.each do |type| %> |
@@ -0,0 +1,1530 @@ | @@ -0,0 +1,1530 @@ | ||
1 | +/* | ||
2 | +* jQuery timepicker addon | ||
3 | +* By: Trent Richardson [http://trentrichardson.com] | ||
4 | +* Version 1.0.1 | ||
5 | +* Last Modified: 07/01/2012 | ||
6 | +* | ||
7 | +* Copyright 2012 Trent Richardson | ||
8 | +* You may use this project under MIT or GPL licenses. | ||
9 | +* http://trentrichardson.com/Impromptu/GPL-LICENSE.txt | ||
10 | +* http://trentrichardson.com/Impromptu/MIT-LICENSE.txt | ||
11 | +* | ||
12 | +* HERES THE CSS: | ||
13 | +* .ui-timepicker-div .ui-widget-header { margin-bottom: 8px; } | ||
14 | +* .ui-timepicker-div dl { text-align: left; } | ||
15 | +* .ui-timepicker-div dl dt { height: 25px; margin-bottom: -25px; } | ||
16 | +* .ui-timepicker-div dl dd { margin: 0 10px 10px 65px; } | ||
17 | +* .ui-timepicker-div td { font-size: 90%; } | ||
18 | +* .ui-tpicker-grid-label { background: none; border: none; margin: 0; padding: 0; } | ||
19 | +*/ | ||
20 | + | ||
21 | +/*jslint evil: true, maxlen: 300, white: false, undef: false, nomen: false, onevar: false */ | ||
22 | + | ||
23 | +(function($) { | ||
24 | + | ||
25 | +// Prevent "Uncaught RangeError: Maximum call stack size exceeded" | ||
26 | +$.ui.timepicker = $.ui.timepicker || {}; | ||
27 | +if ($.ui.timepicker.version) { | ||
28 | + return; | ||
29 | +} | ||
30 | + | ||
31 | +$.extend($.ui, { timepicker: { version: "1.0.1" } }); | ||
32 | + | ||
33 | +/* Time picker manager. | ||
34 | + Use the singleton instance of this class, $.timepicker, to interact with the time picker. | ||
35 | + Settings for (groups of) time pickers are maintained in an instance object, | ||
36 | + allowing multiple different settings on the same page. */ | ||
37 | + | ||
38 | +function Timepicker() { | ||
39 | + this.regional = []; // Available regional settings, indexed by language code | ||
40 | + this.regional[''] = { // Default regional settings | ||
41 | + currentText: 'Now', | ||
42 | + closeText: 'Done', | ||
43 | + ampm: false, | ||
44 | + amNames: ['AM', 'A'], | ||
45 | + pmNames: ['PM', 'P'], | ||
46 | + timeFormat: 'hh:mm tt', | ||
47 | + timeSuffix: '', | ||
48 | + timeOnlyTitle: 'Choose Time', | ||
49 | + timeText: 'Time', | ||
50 | + hourText: 'Hour', | ||
51 | + minuteText: 'Minute', | ||
52 | + secondText: 'Second', | ||
53 | + millisecText: 'Millisecond', | ||
54 | + timezoneText: 'Time Zone' | ||
55 | + }; | ||
56 | + this._defaults = { // Global defaults for all the datetime picker instances | ||
57 | + showButtonPanel: true, | ||
58 | + timeOnly: false, | ||
59 | + showHour: true, | ||
60 | + showMinute: true, | ||
61 | + showSecond: false, | ||
62 | + showMillisec: false, | ||
63 | + showTimezone: false, | ||
64 | + showTime: true, | ||
65 | + stepHour: 1, | ||
66 | + stepMinute: 1, | ||
67 | + stepSecond: 1, | ||
68 | + stepMillisec: 1, | ||
69 | + hour: 0, | ||
70 | + minute: 0, | ||
71 | + second: 0, | ||
72 | + millisec: 0, | ||
73 | + timezone: null, | ||
74 | + useLocalTimezone: false, | ||
75 | + defaultTimezone: "+0000", | ||
76 | + hourMin: 0, | ||
77 | + minuteMin: 0, | ||
78 | + secondMin: 0, | ||
79 | + millisecMin: 0, | ||
80 | + hourMax: 23, | ||
81 | + minuteMax: 59, | ||
82 | + secondMax: 59, | ||
83 | + millisecMax: 999, | ||
84 | + minDateTime: null, | ||
85 | + maxDateTime: null, | ||
86 | + onSelect: null, | ||
87 | + hourGrid: 0, | ||
88 | + minuteGrid: 0, | ||
89 | + secondGrid: 0, | ||
90 | + millisecGrid: 0, | ||
91 | + alwaysSetTime: true, | ||
92 | + separator: ' ', | ||
93 | + altFieldTimeOnly: true, | ||
94 | + showTimepicker: true, | ||
95 | + timezoneIso8601: false, | ||
96 | + timezoneList: null, | ||
97 | + addSliderAccess: false, | ||
98 | + sliderAccessArgs: null | ||
99 | + }; | ||
100 | + $.extend(this._defaults, this.regional['']); | ||
101 | +} | ||
102 | + | ||
103 | +$.extend(Timepicker.prototype, { | ||
104 | + $input: null, | ||
105 | + $altInput: null, | ||
106 | + $timeObj: null, | ||
107 | + inst: null, | ||
108 | + hour_slider: null, | ||
109 | + minute_slider: null, | ||
110 | + second_slider: null, | ||
111 | + millisec_slider: null, | ||
112 | + timezone_select: null, | ||
113 | + hour: 0, | ||
114 | + minute: 0, | ||
115 | + second: 0, | ||
116 | + millisec: 0, | ||
117 | + timezone: null, | ||
118 | + defaultTimezone: "+0000", | ||
119 | + hourMinOriginal: null, | ||
120 | + minuteMinOriginal: null, | ||
121 | + secondMinOriginal: null, | ||
122 | + millisecMinOriginal: null, | ||
123 | + hourMaxOriginal: null, | ||
124 | + minuteMaxOriginal: null, | ||
125 | + secondMaxOriginal: null, | ||
126 | + millisecMaxOriginal: null, | ||
127 | + ampm: '', | ||
128 | + formattedDate: '', | ||
129 | + formattedTime: '', | ||
130 | + formattedDateTime: '', | ||
131 | + timezoneList: null, | ||
132 | + | ||
133 | + /* Override the default settings for all instances of the time picker. | ||
134 | + @param settings object - the new settings to use as defaults (anonymous object) | ||
135 | + @return the manager object */ | ||
136 | + setDefaults: function(settings) { | ||
137 | + extendRemove(this._defaults, settings || {}); | ||
138 | + return this; | ||
139 | + }, | ||
140 | + | ||
141 | + //######################################################################## | ||
142 | + // Create a new Timepicker instance | ||
143 | + //######################################################################## | ||
144 | + _newInst: function($input, o) { | ||
145 | + var tp_inst = new Timepicker(), | ||
146 | + inlineSettings = {}; | ||
147 | + | ||
148 | + for (var attrName in this._defaults) { | ||
149 | + var attrValue = $input.attr('time:' + attrName); | ||
150 | + if (attrValue) { | ||
151 | + try { | ||
152 | + inlineSettings[attrName] = eval(attrValue); | ||
153 | + } catch (err) { | ||
154 | + inlineSettings[attrName] = attrValue; | ||
155 | + } | ||
156 | + } | ||
157 | + } | ||
158 | + tp_inst._defaults = $.extend({}, this._defaults, inlineSettings, o, { | ||
159 | + beforeShow: function(input, dp_inst) { | ||
160 | + if ($.isFunction(o.beforeShow)) { | ||
161 | + return o.beforeShow(input, dp_inst, tp_inst); | ||
162 | + } | ||
163 | + }, | ||
164 | + onChangeMonthYear: function(year, month, dp_inst) { | ||
165 | + // Update the time as well : this prevents the time from disappearing from the $input field. | ||
166 | + tp_inst._updateDateTime(dp_inst); | ||
167 | + if ($.isFunction(o.onChangeMonthYear)) { | ||
168 | + o.onChangeMonthYear.call($input[0], year, month, dp_inst, tp_inst); | ||
169 | + } | ||
170 | + }, | ||
171 | + onClose: function(dateText, dp_inst) { | ||
172 | + if (tp_inst.timeDefined === true && $input.val() !== '') { | ||
173 | + tp_inst._updateDateTime(dp_inst); | ||
174 | + } | ||
175 | + if ($.isFunction(o.onClose)) { | ||
176 | + o.onClose.call($input[0], dateText, dp_inst, tp_inst); | ||
177 | + } | ||
178 | + }, | ||
179 | + timepicker: tp_inst // add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker'); | ||
180 | + }); | ||
181 | + tp_inst.amNames = $.map(tp_inst._defaults.amNames, function(val) { return val.toUpperCase(); }); | ||
182 | + tp_inst.pmNames = $.map(tp_inst._defaults.pmNames, function(val) { return val.toUpperCase(); }); | ||
183 | + | ||
184 | + if (tp_inst._defaults.timezoneList === null) { | ||
185 | + var timezoneList = []; | ||
186 | + for (var i = -11; i <= 12; i++) { | ||
187 | + timezoneList.push((i >= 0 ? '+' : '-') + ('0' + Math.abs(i).toString()).slice(-2) + '00'); | ||
188 | + } | ||
189 | + if (tp_inst._defaults.timezoneIso8601) { | ||
190 | + timezoneList = $.map(timezoneList, function(val) { | ||
191 | + return val == '+0000' ? 'Z' : (val.substring(0, 3) + ':' + val.substring(3)); | ||
192 | + }); | ||
193 | + } | ||
194 | + tp_inst._defaults.timezoneList = timezoneList; | ||
195 | + } | ||
196 | + | ||
197 | + tp_inst.timezone = tp_inst._defaults.timezone; | ||
198 | + tp_inst.hour = tp_inst._defaults.hour; | ||
199 | + tp_inst.minute = tp_inst._defaults.minute; | ||
200 | + tp_inst.second = tp_inst._defaults.second; | ||
201 | + tp_inst.millisec = tp_inst._defaults.millisec; | ||
202 | + tp_inst.ampm = ''; | ||
203 | + tp_inst.$input = $input; | ||
204 | + | ||
205 | + if (o.altField) { | ||
206 | + tp_inst.$altInput = $(o.altField) | ||
207 | + .css({ cursor: 'pointer' }) | ||
208 | + .focus(function(){ $input.trigger("focus"); }); | ||
209 | + } | ||
210 | + | ||
211 | + if(tp_inst._defaults.minDate===0 || tp_inst._defaults.minDateTime===0) | ||
212 | + { | ||
213 | + tp_inst._defaults.minDate=new Date(); | ||
214 | + } | ||
215 | + if(tp_inst._defaults.maxDate===0 || tp_inst._defaults.maxDateTime===0) | ||
216 | + { | ||
217 | + tp_inst._defaults.maxDate=new Date(); | ||
218 | + } | ||
219 | + | ||
220 | + // datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime.. | ||
221 | + if(tp_inst._defaults.minDate !== undefined && tp_inst._defaults.minDate instanceof Date) { | ||
222 | + tp_inst._defaults.minDateTime = new Date(tp_inst._defaults.minDate.getTime()); | ||
223 | + } | ||
224 | + if(tp_inst._defaults.minDateTime !== undefined && tp_inst._defaults.minDateTime instanceof Date) { | ||
225 | + tp_inst._defaults.minDate = new Date(tp_inst._defaults.minDateTime.getTime()); | ||
226 | + } | ||
227 | + if(tp_inst._defaults.maxDate !== undefined && tp_inst._defaults.maxDate instanceof Date) { | ||
228 | + tp_inst._defaults.maxDateTime = new Date(tp_inst._defaults.maxDate.getTime()); | ||
229 | + } | ||
230 | + if(tp_inst._defaults.maxDateTime !== undefined && tp_inst._defaults.maxDateTime instanceof Date) { | ||
231 | + tp_inst._defaults.maxDate = new Date(tp_inst._defaults.maxDateTime.getTime()); | ||
232 | + } | ||
233 | + return tp_inst; | ||
234 | + }, | ||
235 | + | ||
236 | + //######################################################################## | ||
237 | + // add our sliders to the calendar | ||
238 | + //######################################################################## | ||
239 | + _addTimePicker: function(dp_inst) { | ||
240 | + var currDT = (this.$altInput && this._defaults.altFieldTimeOnly) ? | ||
241 | + this.$input.val() + ' ' + this.$altInput.val() : | ||
242 | + this.$input.val(); | ||
243 | + | ||
244 | + this.timeDefined = this._parseTime(currDT); | ||
245 | + this._limitMinMaxDateTime(dp_inst, false); | ||
246 | + this._injectTimePicker(); | ||
247 | + }, | ||
248 | + | ||
249 | + //######################################################################## | ||
250 | + // parse the time string from input value or _setTime | ||
251 | + //######################################################################## | ||
252 | + _parseTime: function(timeString, withDate) { | ||
253 | + if (!this.inst) { | ||
254 | + this.inst = $.datepicker._getInst(this.$input[0]); | ||
255 | + } | ||
256 | + | ||
257 | + if (withDate || !this._defaults.timeOnly) | ||
258 | + { | ||
259 | + var dp_dateFormat = $.datepicker._get(this.inst, 'dateFormat'); | ||
260 | + try { | ||
261 | + var parseRes = parseDateTimeInternal(dp_dateFormat, this._defaults.timeFormat, timeString, $.datepicker._getFormatConfig(this.inst), this._defaults); | ||
262 | + if (!parseRes.timeObj) { return false; } | ||
263 | + $.extend(this, parseRes.timeObj); | ||
264 | + } catch (err) | ||
265 | + { | ||
266 | + return false; | ||
267 | + } | ||
268 | + return true; | ||
269 | + } | ||
270 | + else | ||
271 | + { | ||
272 | + var timeObj = $.datepicker.parseTime(this._defaults.timeFormat, timeString, this._defaults); | ||
273 | + if(!timeObj) { return false; } | ||
274 | + $.extend(this, timeObj); | ||
275 | + return true; | ||
276 | + } | ||
277 | + }, | ||
278 | + | ||
279 | + //######################################################################## | ||
280 | + // generate and inject html for timepicker into ui datepicker | ||
281 | + //######################################################################## | ||
282 | + _injectTimePicker: function() { | ||
283 | + var $dp = this.inst.dpDiv, | ||
284 | + o = this._defaults, | ||
285 | + tp_inst = this, | ||
286 | + // Added by Peter Medeiros: | ||
287 | + // - Figure out what the hour/minute/second max should be based on the step values. | ||
288 | + // - Example: if stepMinute is 15, then minMax is 45. | ||
289 | + hourMax = parseInt((o.hourMax - ((o.hourMax - o.hourMin) % o.stepHour)) ,10), | ||
290 | + minMax = parseInt((o.minuteMax - ((o.minuteMax - o.minuteMin) % o.stepMinute)) ,10), | ||
291 | + secMax = parseInt((o.secondMax - ((o.secondMax - o.secondMin) % o.stepSecond)) ,10), | ||
292 | + millisecMax = parseInt((o.millisecMax - ((o.millisecMax - o.millisecMin) % o.stepMillisec)) ,10), | ||
293 | + dp_id = this.inst.id.toString().replace(/([^A-Za-z0-9_])/g, ''); | ||
294 | + | ||
295 | + // Prevent displaying twice | ||
296 | + //if ($dp.find("div#ui-timepicker-div-"+ dp_id).length === 0) { | ||
297 | + if ($dp.find("div#ui-timepicker-div-"+ dp_id).length === 0 && o.showTimepicker) { | ||
298 | + var noDisplay = ' style="display:none;"', | ||
299 | + html = '<div class="ui-timepicker-div" id="ui-timepicker-div-' + dp_id + '"><dl>' + | ||
300 | + '<dt class="ui_tpicker_time_label" id="ui_tpicker_time_label_' + dp_id + '"' + | ||
301 | + ((o.showTime) ? '' : noDisplay) + '>' + o.timeText + '</dt>' + | ||
302 | + '<dd class="ui_tpicker_time" id="ui_tpicker_time_' + dp_id + '"' + | ||
303 | + ((o.showTime) ? '' : noDisplay) + '></dd>' + | ||
304 | + '<dt class="ui_tpicker_hour_label" id="ui_tpicker_hour_label_' + dp_id + '"' + | ||
305 | + ((o.showHour) ? '' : noDisplay) + '>' + o.hourText + '</dt>', | ||
306 | + hourGridSize = 0, | ||
307 | + minuteGridSize = 0, | ||
308 | + secondGridSize = 0, | ||
309 | + millisecGridSize = 0, | ||
310 | + size = null; | ||
311 | + | ||
312 | + // Hours | ||
313 | + html += '<dd class="ui_tpicker_hour"><div id="ui_tpicker_hour_' + dp_id + '"' + | ||
314 | + ((o.showHour) ? '' : noDisplay) + '></div>'; | ||
315 | + if (o.showHour && o.hourGrid > 0) { | ||
316 | + html += '<div style="padding-left: 1px"><table class="ui-tpicker-grid-label"><tr>'; | ||
317 | + | ||
318 | + for (var h = o.hourMin; h <= hourMax; h += parseInt(o.hourGrid,10)) { | ||
319 | + hourGridSize++; | ||
320 | + var tmph = (o.ampm && h > 12) ? h-12 : h; | ||
321 | + if (tmph < 10) { tmph = '0' + tmph; } | ||
322 | + if (o.ampm) { | ||
323 | + if (h === 0) { | ||
324 | + tmph = 12 +'a'; | ||
325 | + } else { | ||
326 | + if (h < 12) { tmph += 'a'; } | ||
327 | + else { tmph += 'p'; } | ||
328 | + } | ||
329 | + } | ||
330 | + html += '<td>' + tmph + '</td>'; | ||
331 | + } | ||
332 | + | ||
333 | + html += '</tr></table></div>'; | ||
334 | + } | ||
335 | + html += '</dd>'; | ||
336 | + | ||
337 | + // Minutes | ||
338 | + html += '<dt class="ui_tpicker_minute_label" id="ui_tpicker_minute_label_' + dp_id + '"' + | ||
339 | + ((o.showMinute) ? '' : noDisplay) + '>' + o.minuteText + '</dt>'+ | ||
340 | + '<dd class="ui_tpicker_minute"><div id="ui_tpicker_minute_' + dp_id + '"' + | ||
341 | + ((o.showMinute) ? '' : noDisplay) + '></div>'; | ||
342 | + | ||
343 | + if (o.showMinute && o.minuteGrid > 0) { | ||
344 | + html += '<div style="padding-left: 1px"><table class="ui-tpicker-grid-label"><tr>'; | ||
345 | + | ||
346 | + for (var m = o.minuteMin; m <= minMax; m += parseInt(o.minuteGrid,10)) { | ||
347 | + minuteGridSize++; | ||
348 | + html += '<td>' + ((m < 10) ? '0' : '') + m + '</td>'; | ||
349 | + } | ||
350 | + | ||
351 | + html += '</tr></table></div>'; | ||
352 | + } | ||
353 | + html += '</dd>'; | ||
354 | + | ||
355 | + // Seconds | ||
356 | + html += '<dt class="ui_tpicker_second_label" id="ui_tpicker_second_label_' + dp_id + '"' + | ||
357 | + ((o.showSecond) ? '' : noDisplay) + '>' + o.secondText + '</dt>'+ | ||
358 | + '<dd class="ui_tpicker_second"><div id="ui_tpicker_second_' + dp_id + '"'+ | ||
359 | + ((o.showSecond) ? '' : noDisplay) + '></div>'; | ||
360 | + | ||
361 | + if (o.showSecond && o.secondGrid > 0) { | ||
362 | + html += '<div style="padding-left: 1px"><table><tr>'; | ||
363 | + | ||
364 | + for (var s = o.secondMin; s <= secMax; s += parseInt(o.secondGrid,10)) { | ||
365 | + secondGridSize++; | ||
366 | + html += '<td>' + ((s < 10) ? '0' : '') + s + '</td>'; | ||
367 | + } | ||
368 | + | ||
369 | + html += '</tr></table></div>'; | ||
370 | + } | ||
371 | + html += '</dd>'; | ||
372 | + | ||
373 | + // Milliseconds | ||
374 | + html += '<dt class="ui_tpicker_millisec_label" id="ui_tpicker_millisec_label_' + dp_id + '"' + | ||
375 | + ((o.showMillisec) ? '' : noDisplay) + '>' + o.millisecText + '</dt>'+ | ||
376 | + '<dd class="ui_tpicker_millisec"><div id="ui_tpicker_millisec_' + dp_id + '"'+ | ||
377 | + ((o.showMillisec) ? '' : noDisplay) + '></div>'; | ||
378 | + | ||
379 | + if (o.showMillisec && o.millisecGrid > 0) { | ||
380 | + html += '<div style="padding-left: 1px"><table><tr>'; | ||
381 | + | ||
382 | + for (var l = o.millisecMin; l <= millisecMax; l += parseInt(o.millisecGrid,10)) { | ||
383 | + millisecGridSize++; | ||
384 | + html += '<td>' + ((l < 10) ? '0' : '') + l + '</td>'; | ||
385 | + } | ||
386 | + | ||
387 | + html += '</tr></table></div>'; | ||
388 | + } | ||
389 | + html += '</dd>'; | ||
390 | + | ||
391 | + // Timezone | ||
392 | + html += '<dt class="ui_tpicker_timezone_label" id="ui_tpicker_timezone_label_' + dp_id + '"' + | ||
393 | + ((o.showTimezone) ? '' : noDisplay) + '>' + o.timezoneText + '</dt>'; | ||
394 | + html += '<dd class="ui_tpicker_timezone" id="ui_tpicker_timezone_' + dp_id + '"' + | ||
395 | + ((o.showTimezone) ? '' : noDisplay) + '></dd>'; | ||
396 | + | ||
397 | + html += '</dl></div>'; | ||
398 | + var $tp = $(html); | ||
399 | + | ||
400 | + // if we only want time picker... | ||
401 | + if (o.timeOnly === true) { | ||
402 | + $tp.prepend( | ||
403 | + '<div class="ui-widget-header ui-helper-clearfix ui-corner-all">' + | ||
404 | + '<div class="ui-datepicker-title">' + o.timeOnlyTitle + '</div>' + | ||
405 | + '</div>'); | ||
406 | + $dp.find('.ui-datepicker-header, .ui-datepicker-calendar').hide(); | ||
407 | + } | ||
408 | + | ||
409 | + this.hour_slider = $tp.find('#ui_tpicker_hour_'+ dp_id).slider({ | ||
410 | + orientation: "horizontal", | ||
411 | + value: this.hour, | ||
412 | + min: o.hourMin, | ||
413 | + max: hourMax, | ||
414 | + step: o.stepHour, | ||
415 | + slide: function(event, ui) { | ||
416 | + tp_inst.hour_slider.slider( "option", "value", ui.value); | ||
417 | + tp_inst._onTimeChange(); | ||
418 | + } | ||
419 | + }); | ||
420 | + | ||
421 | + | ||
422 | + // Updated by Peter Medeiros: | ||
423 | + // - Pass in Event and UI instance into slide function | ||
424 | + this.minute_slider = $tp.find('#ui_tpicker_minute_'+ dp_id).slider({ | ||
425 | + orientation: "horizontal", | ||
426 | + value: this.minute, | ||
427 | + min: o.minuteMin, | ||
428 | + max: minMax, | ||
429 | + step: o.stepMinute, | ||
430 | + slide: function(event, ui) { | ||
431 | + tp_inst.minute_slider.slider( "option", "value", ui.value); | ||
432 | + tp_inst._onTimeChange(); | ||
433 | + } | ||
434 | + }); | ||
435 | + | ||
436 | + this.second_slider = $tp.find('#ui_tpicker_second_'+ dp_id).slider({ | ||
437 | + orientation: "horizontal", | ||
438 | + value: this.second, | ||
439 | + min: o.secondMin, | ||
440 | + max: secMax, | ||
441 | + step: o.stepSecond, | ||
442 | + slide: function(event, ui) { | ||
443 | + tp_inst.second_slider.slider( "option", "value", ui.value); | ||
444 | + tp_inst._onTimeChange(); | ||
445 | + } | ||
446 | + }); | ||
447 | + | ||
448 | + this.millisec_slider = $tp.find('#ui_tpicker_millisec_'+ dp_id).slider({ | ||
449 | + orientation: "horizontal", | ||
450 | + value: this.millisec, | ||
451 | + min: o.millisecMin, | ||
452 | + max: millisecMax, | ||
453 | + step: o.stepMillisec, | ||
454 | + slide: function(event, ui) { | ||
455 | + tp_inst.millisec_slider.slider( "option", "value", ui.value); | ||
456 | + tp_inst._onTimeChange(); | ||
457 | + } | ||
458 | + }); | ||
459 | + | ||
460 | + this.timezone_select = $tp.find('#ui_tpicker_timezone_'+ dp_id).append('<select></select>').find("select"); | ||
461 | + $.fn.append.apply(this.timezone_select, | ||
462 | + $.map(o.timezoneList, function(val, idx) { | ||
463 | + return $("<option />") | ||
464 | + .val(typeof val == "object" ? val.value : val) | ||
465 | + .text(typeof val == "object" ? val.label : val); | ||
466 | + }) | ||
467 | + ); | ||
468 | + if (typeof(this.timezone) != "undefined" && this.timezone !== null && this.timezone !== "") { | ||
469 | + var local_date = new Date(this.inst.selectedYear, this.inst.selectedMonth, this.inst.selectedDay, 12); | ||
470 | + var local_timezone = timeZoneString(local_date); | ||
471 | + if (local_timezone == this.timezone) { | ||
472 | + selectLocalTimeZone(tp_inst); | ||
473 | + } else { | ||
474 | + this.timezone_select.val(this.timezone); | ||
475 | + } | ||
476 | + } else { | ||
477 | + if (typeof(this.hour) != "undefined" && this.hour !== null && this.hour !== "") { | ||
478 | + this.timezone_select.val(o.defaultTimezone); | ||
479 | + } else { | ||
480 | + selectLocalTimeZone(tp_inst); | ||
481 | + } | ||
482 | + } | ||
483 | + this.timezone_select.change(function() { | ||
484 | + tp_inst._defaults.useLocalTimezone = false; | ||
485 | + tp_inst._onTimeChange(); | ||
486 | + }); | ||
487 | + | ||
488 | + // Add grid functionality | ||
489 | + if (o.showHour && o.hourGrid > 0) { | ||
490 | + size = 100 * hourGridSize * o.hourGrid / (hourMax - o.hourMin); | ||
491 | + | ||
492 | + $tp.find(".ui_tpicker_hour table").css({ | ||
493 | + width: size + "%", | ||
494 | + marginLeft: (size / (-2 * hourGridSize)) + "%", | ||
495 | + borderCollapse: 'collapse' | ||
496 | + }).find("td").each( function(index) { | ||
497 | + $(this).click(function() { | ||
498 | + var h = $(this).html(); | ||
499 | + if(o.ampm) { | ||
500 | + var ap = h.substring(2).toLowerCase(), | ||
501 | + aph = parseInt(h.substring(0,2), 10); | ||
502 | + if (ap == 'a') { | ||
503 | + if (aph == 12) { h = 0; } | ||
504 | + else { h = aph; } | ||
505 | + } else if (aph == 12) { h = 12; } | ||
506 | + else { h = aph + 12; } | ||
507 | + } | ||
508 | + tp_inst.hour_slider.slider("option", "value", h); | ||
509 | + tp_inst._onTimeChange(); | ||
510 | + tp_inst._onSelectHandler(); | ||
511 | + }).css({ | ||
512 | + cursor: 'pointer', | ||
513 | + width: (100 / hourGridSize) + '%', | ||
514 | + textAlign: 'center', | ||
515 | + overflow: 'hidden' | ||
516 | + }); | ||
517 | + }); | ||
518 | + } | ||
519 | + | ||
520 | + if (o.showMinute && o.minuteGrid > 0) { | ||
521 | + size = 100 * minuteGridSize * o.minuteGrid / (minMax - o.minuteMin); | ||
522 | + $tp.find(".ui_tpicker_minute table").css({ | ||
523 | + width: size + "%", | ||
524 | + marginLeft: (size / (-2 * minuteGridSize)) + "%", | ||
525 | + borderCollapse: 'collapse' | ||
526 | + }).find("td").each(function(index) { | ||
527 | + $(this).click(function() { | ||
528 | + tp_inst.minute_slider.slider("option", "value", $(this).html()); | ||
529 | + tp_inst._onTimeChange(); | ||
530 | + tp_inst._onSelectHandler(); | ||
531 | + }).css({ | ||
532 | + cursor: 'pointer', | ||
533 | + width: (100 / minuteGridSize) + '%', | ||
534 | + textAlign: 'center', | ||
535 | + overflow: 'hidden' | ||
536 | + }); | ||
537 | + }); | ||
538 | + } | ||
539 | + | ||
540 | + if (o.showSecond && o.secondGrid > 0) { | ||
541 | + $tp.find(".ui_tpicker_second table").css({ | ||
542 | + width: size + "%", | ||
543 | + marginLeft: (size / (-2 * secondGridSize)) + "%", | ||
544 | + borderCollapse: 'collapse' | ||
545 | + }).find("td").each(function(index) { | ||
546 | + $(this).click(function() { | ||
547 | + tp_inst.second_slider.slider("option", "value", $(this).html()); | ||
548 | + tp_inst._onTimeChange(); | ||
549 | + tp_inst._onSelectHandler(); | ||
550 | + }).css({ | ||
551 | + cursor: 'pointer', | ||
552 | + width: (100 / secondGridSize) + '%', | ||
553 | + textAlign: 'center', | ||
554 | + overflow: 'hidden' | ||
555 | + }); | ||
556 | + }); | ||
557 | + } | ||
558 | + | ||
559 | + if (o.showMillisec && o.millisecGrid > 0) { | ||
560 | + $tp.find(".ui_tpicker_millisec table").css({ | ||
561 | + width: size + "%", | ||
562 | + marginLeft: (size / (-2 * millisecGridSize)) + "%", | ||
563 | + borderCollapse: 'collapse' | ||
564 | + }).find("td").each(function(index) { | ||
565 | + $(this).click(function() { | ||
566 | + tp_inst.millisec_slider.slider("option", "value", $(this).html()); | ||
567 | + tp_inst._onTimeChange(); | ||
568 | + tp_inst._onSelectHandler(); | ||
569 | + }).css({ | ||
570 | + cursor: 'pointer', | ||
571 | + width: (100 / millisecGridSize) + '%', | ||
572 | + textAlign: 'center', | ||
573 | + overflow: 'hidden' | ||
574 | + }); | ||
575 | + }); | ||
576 | + } | ||
577 | + | ||
578 | + var $buttonPanel = $dp.find('.ui-datepicker-buttonpane'); | ||
579 | + if ($buttonPanel.length) { $buttonPanel.before($tp); } | ||
580 | + else { $dp.append($tp); } | ||
581 | + | ||
582 | + this.$timeObj = $tp.find('#ui_tpicker_time_'+ dp_id); | ||
583 | + | ||
584 | + if (this.inst !== null) { | ||
585 | + var timeDefined = this.timeDefined; | ||
586 | + this._onTimeChange(); | ||
587 | + this.timeDefined = timeDefined; | ||
588 | + } | ||
589 | + | ||
590 | + //Emulate datepicker onSelect behavior. Call on slidestop. | ||
591 | + var onSelectDelegate = function() { | ||
592 | + tp_inst._onSelectHandler(); | ||
593 | + }; | ||
594 | + this.hour_slider.bind('slidestop',onSelectDelegate); | ||
595 | + this.minute_slider.bind('slidestop',onSelectDelegate); | ||
596 | + this.second_slider.bind('slidestop',onSelectDelegate); | ||
597 | + this.millisec_slider.bind('slidestop',onSelectDelegate); | ||
598 | + | ||
599 | + // slideAccess integration: http://trentrichardson.com/2011/11/11/jquery-ui-sliders-and-touch-accessibility/ | ||
600 | + if (this._defaults.addSliderAccess){ | ||
601 | + var sliderAccessArgs = this._defaults.sliderAccessArgs; | ||
602 | + setTimeout(function(){ // fix for inline mode | ||
603 | + if($tp.find('.ui-slider-access').length === 0){ | ||
604 | + $tp.find('.ui-slider:visible').sliderAccess(sliderAccessArgs); | ||
605 | + | ||
606 | + // fix any grids since sliders are shorter | ||
607 | + var sliderAccessWidth = $tp.find('.ui-slider-access:eq(0)').outerWidth(true); | ||
608 | + if(sliderAccessWidth){ | ||
609 | + $tp.find('table:visible').each(function(){ | ||
610 | + var $g = $(this), | ||
611 | + oldWidth = $g.outerWidth(), | ||
612 | + oldMarginLeft = $g.css('marginLeft').toString().replace('%',''), | ||
613 | + newWidth = oldWidth - sliderAccessWidth, | ||
614 | + newMarginLeft = ((oldMarginLeft * newWidth)/oldWidth) + '%'; | ||
615 | + | ||
616 | + $g.css({ width: newWidth, marginLeft: newMarginLeft }); | ||
617 | + }); | ||
618 | + } | ||
619 | + } | ||
620 | + },0); | ||
621 | + } | ||
622 | + // end slideAccess integration | ||
623 | + | ||
624 | + } | ||
625 | + }, | ||
626 | + | ||
627 | + //######################################################################## | ||
628 | + // This function tries to limit the ability to go outside the | ||
629 | + // min/max date range | ||
630 | + //######################################################################## | ||
631 | + _limitMinMaxDateTime: function(dp_inst, adjustSliders){ | ||
632 | + var o = this._defaults, | ||
633 | + dp_date = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay); | ||
634 | + | ||
635 | + if(!this._defaults.showTimepicker) { return; } // No time so nothing to check here | ||
636 | + | ||
637 | + if($.datepicker._get(dp_inst, 'minDateTime') !== null && $.datepicker._get(dp_inst, 'minDateTime') !== undefined && dp_date){ | ||
638 | + var minDateTime = $.datepicker._get(dp_inst, 'minDateTime'), | ||
639 | + minDateTimeDate = new Date(minDateTime.getFullYear(), minDateTime.getMonth(), minDateTime.getDate(), 0, 0, 0, 0); | ||
640 | + | ||
641 | + if(this.hourMinOriginal === null || this.minuteMinOriginal === null || this.secondMinOriginal === null || this.millisecMinOriginal === null){ | ||
642 | + this.hourMinOriginal = o.hourMin; | ||
643 | + this.minuteMinOriginal = o.minuteMin; | ||
644 | + this.secondMinOriginal = o.secondMin; | ||
645 | + this.millisecMinOriginal = o.millisecMin; | ||
646 | + } | ||
647 | + | ||
648 | + if(dp_inst.settings.timeOnly || minDateTimeDate.getTime() == dp_date.getTime()) { | ||
649 | + this._defaults.hourMin = minDateTime.getHours(); | ||
650 | + if (this.hour <= this._defaults.hourMin) { | ||
651 | + this.hour = this._defaults.hourMin; | ||
652 | + this._defaults.minuteMin = minDateTime.getMinutes(); | ||
653 | + if (this.minute <= this._defaults.minuteMin) { | ||
654 | + this.minute = this._defaults.minuteMin; | ||
655 | + this._defaults.secondMin = minDateTime.getSeconds(); | ||
656 | + } else if (this.second <= this._defaults.secondMin){ | ||
657 | + this.second = this._defaults.secondMin; | ||
658 | + this._defaults.millisecMin = minDateTime.getMilliseconds(); | ||
659 | + } else { | ||
660 | + if(this.millisec < this._defaults.millisecMin) { | ||
661 | + this.millisec = this._defaults.millisecMin; | ||
662 | + } | ||
663 | + this._defaults.millisecMin = this.millisecMinOriginal; | ||
664 | + } | ||
665 | + } else { | ||
666 | + this._defaults.minuteMin = this.minuteMinOriginal; | ||
667 | + this._defaults.secondMin = this.secondMinOriginal; | ||
668 | + this._defaults.millisecMin = this.millisecMinOriginal; | ||
669 | + } | ||
670 | + }else{ | ||
671 | + this._defaults.hourMin = this.hourMinOriginal; | ||
672 | + this._defaults.minuteMin = this.minuteMinOriginal; | ||
673 | + this._defaults.secondMin = this.secondMinOriginal; | ||
674 | + this._defaults.millisecMin = this.millisecMinOriginal; | ||
675 | + } | ||
676 | + } | ||
677 | + | ||
678 | + if($.datepicker._get(dp_inst, 'maxDateTime') !== null && $.datepicker._get(dp_inst, 'maxDateTime') !== undefined && dp_date){ | ||
679 | + var maxDateTime = $.datepicker._get(dp_inst, 'maxDateTime'), | ||
680 | + maxDateTimeDate = new Date(maxDateTime.getFullYear(), maxDateTime.getMonth(), maxDateTime.getDate(), 0, 0, 0, 0); | ||
681 | + | ||
682 | + if(this.hourMaxOriginal === null || this.minuteMaxOriginal === null || this.secondMaxOriginal === null){ | ||
683 | + this.hourMaxOriginal = o.hourMax; | ||
684 | + this.minuteMaxOriginal = o.minuteMax; | ||
685 | + this.secondMaxOriginal = o.secondMax; | ||
686 | + this.millisecMaxOriginal = o.millisecMax; | ||
687 | + } | ||
688 | + | ||
689 | + if(dp_inst.settings.timeOnly || maxDateTimeDate.getTime() == dp_date.getTime()){ | ||
690 | + this._defaults.hourMax = maxDateTime.getHours(); | ||
691 | + if (this.hour >= this._defaults.hourMax) { | ||
692 | + this.hour = this._defaults.hourMax; | ||
693 | + this._defaults.minuteMax = maxDateTime.getMinutes(); | ||
694 | + if (this.minute >= this._defaults.minuteMax) { | ||
695 | + this.minute = this._defaults.minuteMax; | ||
696 | + this._defaults.secondMax = maxDateTime.getSeconds(); | ||
697 | + } else if (this.second >= this._defaults.secondMax) { | ||
698 | + this.second = this._defaults.secondMax; | ||
699 | + this._defaults.millisecMax = maxDateTime.getMilliseconds(); | ||
700 | + } else { | ||
701 | + if(this.millisec > this._defaults.millisecMax) { this.millisec = this._defaults.millisecMax; } | ||
702 | + this._defaults.millisecMax = this.millisecMaxOriginal; | ||
703 | + } | ||
704 | + } else { | ||
705 | + this._defaults.minuteMax = this.minuteMaxOriginal; | ||
706 | + this._defaults.secondMax = this.secondMaxOriginal; | ||
707 | + this._defaults.millisecMax = this.millisecMaxOriginal; | ||
708 | + } | ||
709 | + }else{ | ||
710 | + this._defaults.hourMax = this.hourMaxOriginal; | ||
711 | + this._defaults.minuteMax = this.minuteMaxOriginal; | ||
712 | + this._defaults.secondMax = this.secondMaxOriginal; | ||
713 | + this._defaults.millisecMax = this.millisecMaxOriginal; | ||
714 | + } | ||
715 | + } | ||
716 | + | ||
717 | + if(adjustSliders !== undefined && adjustSliders === true){ | ||
718 | + var hourMax = parseInt((this._defaults.hourMax - ((this._defaults.hourMax - this._defaults.hourMin) % this._defaults.stepHour)) ,10), | ||
719 | + minMax = parseInt((this._defaults.minuteMax - ((this._defaults.minuteMax - this._defaults.minuteMin) % this._defaults.stepMinute)) ,10), | ||
720 | + secMax = parseInt((this._defaults.secondMax - ((this._defaults.secondMax - this._defaults.secondMin) % this._defaults.stepSecond)) ,10), | ||
721 | + millisecMax = parseInt((this._defaults.millisecMax - ((this._defaults.millisecMax - this._defaults.millisecMin) % this._defaults.stepMillisec)) ,10); | ||
722 | + | ||
723 | + if(this.hour_slider) { | ||
724 | + this.hour_slider.slider("option", { min: this._defaults.hourMin, max: hourMax }).slider('value', this.hour); | ||
725 | + } | ||
726 | + if(this.minute_slider) { | ||
727 | + this.minute_slider.slider("option", { min: this._defaults.minuteMin, max: minMax }).slider('value', this.minute); | ||
728 | + } | ||
729 | + if(this.second_slider){ | ||
730 | + this.second_slider.slider("option", { min: this._defaults.secondMin, max: secMax }).slider('value', this.second); | ||
731 | + } | ||
732 | + if(this.millisec_slider) { | ||
733 | + this.millisec_slider.slider("option", { min: this._defaults.millisecMin, max: millisecMax }).slider('value', this.millisec); | ||
734 | + } | ||
735 | + } | ||
736 | + | ||
737 | + }, | ||
738 | + | ||
739 | + | ||
740 | + //######################################################################## | ||
741 | + // when a slider moves, set the internal time... | ||
742 | + // on time change is also called when the time is updated in the text field | ||
743 | + //######################################################################## | ||
744 | + _onTimeChange: function() { | ||
745 | + var hour = (this.hour_slider) ? this.hour_slider.slider('value') : false, | ||
746 | + minute = (this.minute_slider) ? this.minute_slider.slider('value') : false, | ||
747 | + second = (this.second_slider) ? this.second_slider.slider('value') : false, | ||
748 | + millisec = (this.millisec_slider) ? this.millisec_slider.slider('value') : false, | ||
749 | + timezone = (this.timezone_select) ? this.timezone_select.val() : false, | ||
750 | + o = this._defaults; | ||
751 | + | ||
752 | + if (typeof(hour) == 'object') { hour = false; } | ||
753 | + if (typeof(minute) == 'object') { minute = false; } | ||
754 | + if (typeof(second) == 'object') { second = false; } | ||
755 | + if (typeof(millisec) == 'object') { millisec = false; } | ||
756 | + if (typeof(timezone) == 'object') { timezone = false; } | ||
757 | + | ||
758 | + if (hour !== false) { hour = parseInt(hour,10); } | ||
759 | + if (minute !== false) { minute = parseInt(minute,10); } | ||
760 | + if (second !== false) { second = parseInt(second,10); } | ||
761 | + if (millisec !== false) { millisec = parseInt(millisec,10); } | ||
762 | + | ||
763 | + var ampm = o[hour < 12 ? 'amNames' : 'pmNames'][0]; | ||
764 | + | ||
765 | + // If the update was done in the input field, the input field should not be updated. | ||
766 | + // If the update was done using the sliders, update the input field. | ||
767 | + var hasChanged = (hour != this.hour || minute != this.minute || | ||
768 | + second != this.second || millisec != this.millisec || | ||
769 | + (this.ampm.length > 0 && | ||
770 | + (hour < 12) != ($.inArray(this.ampm.toUpperCase(), this.amNames) !== -1)) || | ||
771 | + timezone != this.timezone); | ||
772 | + | ||
773 | + if (hasChanged) { | ||
774 | + | ||
775 | + if (hour !== false) { this.hour = hour; } | ||
776 | + if (minute !== false) { this.minute = minute; } | ||
777 | + if (second !== false) { this.second = second; } | ||
778 | + if (millisec !== false) { this.millisec = millisec; } | ||
779 | + if (timezone !== false) { this.timezone = timezone; } | ||
780 | + | ||
781 | + if (!this.inst) { this.inst = $.datepicker._getInst(this.$input[0]); } | ||
782 | + | ||
783 | + this._limitMinMaxDateTime(this.inst, true); | ||
784 | + } | ||
785 | + if (o.ampm) { this.ampm = ampm; } | ||
786 | + | ||
787 | + //this._formatTime(); | ||
788 | + this.formattedTime = $.datepicker.formatTime(this._defaults.timeFormat, this, this._defaults); | ||
789 | + if (this.$timeObj) { this.$timeObj.text(this.formattedTime + o.timeSuffix); } | ||
790 | + this.timeDefined = true; | ||
791 | + if (hasChanged) { this._updateDateTime(); } | ||
792 | + }, | ||
793 | + | ||
794 | + //######################################################################## | ||
795 | + // call custom onSelect. | ||
796 | + // bind to sliders slidestop, and grid click. | ||
797 | + //######################################################################## | ||
798 | + _onSelectHandler: function() { | ||
799 | + var onSelect = this._defaults.onSelect; | ||
800 | + var inputEl = this.$input ? this.$input[0] : null; | ||
801 | + if (onSelect && inputEl) { | ||
802 | + onSelect.apply(inputEl, [this.formattedDateTime, this]); | ||
803 | + } | ||
804 | + }, | ||
805 | + | ||
806 | + //######################################################################## | ||
807 | + // left for any backwards compatibility | ||
808 | + //######################################################################## | ||
809 | + _formatTime: function(time, format) { | ||
810 | + time = time || { hour: this.hour, minute: this.minute, second: this.second, millisec: this.millisec, ampm: this.ampm, timezone: this.timezone }; | ||
811 | + var tmptime = (format || this._defaults.timeFormat).toString(); | ||
812 | + | ||
813 | + tmptime = $.datepicker.formatTime(tmptime, time, this._defaults); | ||
814 | + | ||
815 | + if (arguments.length) { return tmptime; } | ||
816 | + else { this.formattedTime = tmptime; } | ||
817 | + }, | ||
818 | + | ||
819 | + //######################################################################## | ||
820 | + // update our input with the new date time.. | ||
821 | + //######################################################################## | ||
822 | + _updateDateTime: function(dp_inst) { | ||
823 | + dp_inst = this.inst || dp_inst; | ||
824 | + var dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)), | ||
825 | + dateFmt = $.datepicker._get(dp_inst, 'dateFormat'), | ||
826 | + formatCfg = $.datepicker._getFormatConfig(dp_inst), | ||
827 | + timeAvailable = dt !== null && this.timeDefined; | ||
828 | + this.formattedDate = $.datepicker.formatDate(dateFmt, (dt === null ? new Date() : dt), formatCfg); | ||
829 | + var formattedDateTime = this.formattedDate; | ||
830 | + // remove following lines to force every changes in date picker to change the input value | ||
831 | + // Bug descriptions: when an input field has a default value, and click on the field to pop up the date picker. | ||
832 | + // If the user manually empty the value in the input field, the date picker will never change selected value. | ||
833 | + //if (dp_inst.lastVal !== undefined && (dp_inst.lastVal.length > 0 && this.$input.val().length === 0)) { | ||
834 | + // return; | ||
835 | + //} | ||
836 | + | ||
837 | + if (this._defaults.timeOnly === true) { | ||
838 | + formattedDateTime = this.formattedTime; | ||
839 | + } else if (this._defaults.timeOnly !== true && (this._defaults.alwaysSetTime || timeAvailable)) { | ||
840 | + formattedDateTime += this._defaults.separator + this.formattedTime + this._defaults.timeSuffix; | ||
841 | + } | ||
842 | + | ||
843 | + this.formattedDateTime = formattedDateTime; | ||
844 | + | ||
845 | + if(!this._defaults.showTimepicker) { | ||
846 | + this.$input.val(this.formattedDate); | ||
847 | + } else if (this.$altInput && this._defaults.altFieldTimeOnly === true) { | ||
848 | + this.$altInput.val(this.formattedTime); | ||
849 | + this.$input.val(this.formattedDate); | ||
850 | + } else if(this.$altInput) { | ||
851 | + this.$altInput.val(formattedDateTime); | ||
852 | + this.$input.val(formattedDateTime); | ||
853 | + } else { | ||
854 | + this.$input.val(formattedDateTime); | ||
855 | + } | ||
856 | + | ||
857 | + this.$input.trigger("change"); | ||
858 | + } | ||
859 | + | ||
860 | +}); | ||
861 | + | ||
862 | +$.fn.extend({ | ||
863 | + //######################################################################## | ||
864 | + // shorthand just to use timepicker.. | ||
865 | + //######################################################################## | ||
866 | + timepicker: function(o) { | ||
867 | + o = o || {}; | ||
868 | + var tmp_args = arguments; | ||
869 | + | ||
870 | + if (typeof o == 'object') { tmp_args[0] = $.extend(o, { timeOnly: true }); } | ||
871 | + | ||
872 | + return $(this).each(function() { | ||
873 | + $.fn.datetimepicker.apply($(this), tmp_args); | ||
874 | + }); | ||
875 | + }, | ||
876 | + | ||
877 | + //######################################################################## | ||
878 | + // extend timepicker to datepicker | ||
879 | + //######################################################################## | ||
880 | + datetimepicker: function(o) { | ||
881 | + o = o || {}; | ||
882 | + var tmp_args = arguments; | ||
883 | + | ||
884 | + if (typeof(o) == 'string'){ | ||
885 | + if(o == 'getDate') { | ||
886 | + return $.fn.datepicker.apply($(this[0]), tmp_args); | ||
887 | + } | ||
888 | + else { | ||
889 | + return this.each(function() { | ||
890 | + var $t = $(this); | ||
891 | + $t.datepicker.apply($t, tmp_args); | ||
892 | + }); | ||
893 | + } | ||
894 | + } | ||
895 | + else { | ||
896 | + return this.each(function() { | ||
897 | + var $t = $(this); | ||
898 | + $t.datepicker($.timepicker._newInst($t, o)._defaults); | ||
899 | + }); | ||
900 | + } | ||
901 | + } | ||
902 | +}); | ||
903 | + | ||
904 | +$.datepicker.parseDateTime = function(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) { | ||
905 | + var parseRes = parseDateTimeInternal(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings); | ||
906 | + if (parseRes.timeObj) | ||
907 | + { | ||
908 | + var t = parseRes.timeObj; | ||
909 | + parseRes.date.setHours(t.hour, t.minute, t.second, t.millisec); | ||
910 | + } | ||
911 | + | ||
912 | + return parseRes.date; | ||
913 | +}; | ||
914 | + | ||
915 | +$.datepicker.parseTime = function(timeFormat, timeString, options) { | ||
916 | + | ||
917 | + //######################################################################## | ||
918 | + // pattern for standard and localized AM/PM markers | ||
919 | + //######################################################################## | ||
920 | + var getPatternAmpm = function(amNames, pmNames) { | ||
921 | + var markers = []; | ||
922 | + if (amNames) { | ||
923 | + $.merge(markers, amNames); | ||
924 | + } | ||
925 | + if (pmNames) { | ||
926 | + $.merge(markers, pmNames); | ||
927 | + } | ||
928 | + markers = $.map(markers, function(val) { return val.replace(/[.*+?|()\[\]{}\\]/g, '\\$&'); }); | ||
929 | + return '(' + markers.join('|') + ')?'; | ||
930 | + }; | ||
931 | + | ||
932 | + //######################################################################## | ||
933 | + // figure out position of time elements.. cause js cant do named captures | ||
934 | + //######################################################################## | ||
935 | + var getFormatPositions = function( timeFormat ) { | ||
936 | + var finds = timeFormat.toLowerCase().match(/(h{1,2}|m{1,2}|s{1,2}|l{1}|t{1,2}|z)/g), | ||
937 | + orders = { h: -1, m: -1, s: -1, l: -1, t: -1, z: -1 }; | ||
938 | + | ||
939 | + if (finds) { | ||
940 | + for (var i = 0; i < finds.length; i++) { | ||
941 | + if (orders[finds[i].toString().charAt(0)] == -1) { | ||
942 | + orders[finds[i].toString().charAt(0)] = i + 1; | ||
943 | + } | ||
944 | + } | ||
945 | + } | ||
946 | + return orders; | ||
947 | + }; | ||
948 | + | ||
949 | + var o = extendRemove(extendRemove({}, $.timepicker._defaults), options || {}); | ||
950 | + | ||
951 | + var regstr = '^' + timeFormat.toString() | ||
952 | + .replace(/h{1,2}/ig, '(\\d?\\d)') | ||
953 | + .replace(/m{1,2}/ig, '(\\d?\\d)') | ||
954 | + .replace(/s{1,2}/ig, '(\\d?\\d)') | ||
955 | + .replace(/l{1}/ig, '(\\d?\\d?\\d)') | ||
956 | + .replace(/t{1,2}/ig, getPatternAmpm(o.amNames, o.pmNames)) | ||
957 | + .replace(/z{1}/ig, '(z|[-+]\\d\\d:?\\d\\d)?') | ||
958 | + .replace(/\s/g, '\\s?') + o.timeSuffix + '$', | ||
959 | + order = getFormatPositions(timeFormat), | ||
960 | + ampm = '', | ||
961 | + treg; | ||
962 | + | ||
963 | + treg = timeString.match(new RegExp(regstr, 'i')); | ||
964 | + | ||
965 | + var resTime = {hour: 0, minute: 0, second: 0, millisec: 0}; | ||
966 | + | ||
967 | + if (treg) { | ||
968 | + if (order.t !== -1) { | ||
969 | + if (treg[order.t] === undefined || treg[order.t].length === 0) { | ||
970 | + ampm = ''; | ||
971 | + resTime.ampm = ''; | ||
972 | + } else { | ||
973 | + ampm = $.inArray(treg[order.t], o.amNames) !== -1 ? 'AM' : 'PM'; | ||
974 | + resTime.ampm = o[ampm == 'AM' ? 'amNames' : 'pmNames'][0]; | ||
975 | + } | ||
976 | + } | ||
977 | + | ||
978 | + if (order.h !== -1) { | ||
979 | + if (ampm == 'AM' && treg[order.h] == '12') { | ||
980 | + resTime.hour = 0; // 12am = 0 hour | ||
981 | + } else { | ||
982 | + if (ampm == 'PM' && treg[order.h] != '12') { | ||
983 | + resTime.hour = parseInt(treg[order.h],10) + 12; // 12pm = 12 hour, any other pm = hour + 12 | ||
984 | + } | ||
985 | + else { resTime.hour = Number(treg[order.h]); } | ||
986 | + } | ||
987 | + } | ||
988 | + | ||
989 | + if (order.m !== -1) { resTime.minute = Number(treg[order.m]); } | ||
990 | + if (order.s !== -1) { resTime.second = Number(treg[order.s]); } | ||
991 | + if (order.l !== -1) { resTime.millisec = Number(treg[order.l]); } | ||
992 | + if (order.z !== -1 && treg[order.z] !== undefined) { | ||
993 | + var tz = treg[order.z].toUpperCase(); | ||
994 | + switch (tz.length) { | ||
995 | + case 1: // Z | ||
996 | + tz = o.timezoneIso8601 ? 'Z' : '+0000'; | ||
997 | + break; | ||
998 | + case 5: // +hhmm | ||
999 | + if (o.timezoneIso8601) { | ||
1000 | + tz = tz.substring(1) == '0000' ? | ||
1001 | + 'Z' : | ||
1002 | + tz.substring(0, 3) + ':' + tz.substring(3); | ||
1003 | + } | ||
1004 | + break; | ||
1005 | + case 6: // +hh:mm | ||
1006 | + if (!o.timezoneIso8601) { | ||
1007 | + tz = tz == 'Z' || tz.substring(1) == '00:00' ? | ||
1008 | + '+0000' : | ||
1009 | + tz.replace(/:/, ''); | ||
1010 | + } else { | ||
1011 | + if (tz.substring(1) == '00:00') { | ||
1012 | + tz = 'Z'; | ||
1013 | + } | ||
1014 | + } | ||
1015 | + break; | ||
1016 | + } | ||
1017 | + resTime.timezone = tz; | ||
1018 | + } | ||
1019 | + | ||
1020 | + | ||
1021 | + return resTime; | ||
1022 | + } | ||
1023 | + | ||
1024 | + return false; | ||
1025 | +}; | ||
1026 | + | ||
1027 | +//######################################################################## | ||
1028 | +// format the time all pretty... | ||
1029 | +// format = string format of the time | ||
1030 | +// time = a {}, not a Date() for timezones | ||
1031 | +// options = essentially the regional[].. amNames, pmNames, ampm | ||
1032 | +//######################################################################## | ||
1033 | +$.datepicker.formatTime = function(format, time, options) { | ||
1034 | + options = options || {}; | ||
1035 | + options = $.extend($.timepicker._defaults, options); | ||
1036 | + time = $.extend({hour:0, minute:0, second:0, millisec:0, timezone:'+0000'}, time); | ||
1037 | + | ||
1038 | + var tmptime = format; | ||
1039 | + var ampmName = options.amNames[0]; | ||
1040 | + | ||
1041 | + var hour = parseInt(time.hour, 10); | ||
1042 | + if (options.ampm) { | ||
1043 | + if (hour > 11){ | ||
1044 | + ampmName = options.pmNames[0]; | ||
1045 | + if(hour > 12) { | ||
1046 | + hour = hour % 12; | ||
1047 | + } | ||
1048 | + } | ||
1049 | + if (hour === 0) { | ||
1050 | + hour = 12; | ||
1051 | + } | ||
1052 | + } | ||
1053 | + tmptime = tmptime.replace(/(?:hh?|mm?|ss?|[tT]{1,2}|[lz])/g, function(match) { | ||
1054 | + switch (match.toLowerCase()) { | ||
1055 | + case 'hh': return ('0' + hour).slice(-2); | ||
1056 | + case 'h': return hour; | ||
1057 | + case 'mm': return ('0' + time.minute).slice(-2); | ||
1058 | + case 'm': return time.minute; | ||
1059 | + case 'ss': return ('0' + time.second).slice(-2); | ||
1060 | + case 's': return time.second; | ||
1061 | + case 'l': return ('00' + time.millisec).slice(-3); | ||
1062 | + case 'z': return time.timezone; | ||
1063 | + case 't': case 'tt': | ||
1064 | + if (options.ampm) { | ||
1065 | + if (match.length == 1) { | ||
1066 | + ampmName = ampmName.charAt(0); | ||
1067 | + } | ||
1068 | + return match.charAt(0) == 'T' ? ampmName.toUpperCase() : ampmName.toLowerCase(); | ||
1069 | + } | ||
1070 | + return ''; | ||
1071 | + } | ||
1072 | + }); | ||
1073 | + | ||
1074 | + tmptime = $.trim(tmptime); | ||
1075 | + return tmptime; | ||
1076 | +}; | ||
1077 | + | ||
1078 | +//######################################################################## | ||
1079 | +// the bad hack :/ override datepicker so it doesnt close on select | ||
1080 | +// inspired: http://stackoverflow.com/questions/1252512/jquery-datepicker-prevent-closing-picker-when-clicking-a-date/1762378#1762378 | ||
1081 | +//######################################################################## | ||
1082 | +$.datepicker._base_selectDate = $.datepicker._selectDate; | ||
1083 | +$.datepicker._selectDate = function (id, dateStr) { | ||
1084 | + var inst = this._getInst($(id)[0]), | ||
1085 | + tp_inst = this._get(inst, 'timepicker'); | ||
1086 | + | ||
1087 | + if (tp_inst) { | ||
1088 | + tp_inst._limitMinMaxDateTime(inst, true); | ||
1089 | + inst.inline = inst.stay_open = true; | ||
1090 | + //This way the onSelect handler called from calendarpicker get the full dateTime | ||
1091 | + this._base_selectDate(id, dateStr); | ||
1092 | + inst.inline = inst.stay_open = false; | ||
1093 | + this._notifyChange(inst); | ||
1094 | + this._updateDatepicker(inst); | ||
1095 | + } | ||
1096 | + else { this._base_selectDate(id, dateStr); } | ||
1097 | +}; | ||
1098 | + | ||
1099 | +//############################################################################################# | ||
1100 | +// second bad hack :/ override datepicker so it triggers an event when changing the input field | ||
1101 | +// and does not redraw the datepicker on every selectDate event | ||
1102 | +//############################################################################################# | ||
1103 | +$.datepicker._base_updateDatepicker = $.datepicker._updateDatepicker; | ||
1104 | +$.datepicker._updateDatepicker = function(inst) { | ||
1105 | + | ||
1106 | + // don't popup the datepicker if there is another instance already opened | ||
1107 | + var input = inst.input[0]; | ||
1108 | + if($.datepicker._curInst && | ||
1109 | + $.datepicker._curInst != inst && | ||
1110 | + $.datepicker._datepickerShowing && | ||
1111 | + $.datepicker._lastInput != input) { | ||
1112 | + return; | ||
1113 | + } | ||
1114 | + | ||
1115 | + if (typeof(inst.stay_open) !== 'boolean' || inst.stay_open === false) { | ||
1116 | + | ||
1117 | + this._base_updateDatepicker(inst); | ||
1118 | + | ||
1119 | + // Reload the time control when changing something in the input text field. | ||
1120 | + var tp_inst = this._get(inst, 'timepicker'); | ||
1121 | + if(tp_inst) { | ||
1122 | + tp_inst._addTimePicker(inst); | ||
1123 | + | ||
1124 | + if (tp_inst._defaults.useLocalTimezone) { //checks daylight saving with the new date. | ||
1125 | + var date = new Date(inst.selectedYear, inst.selectedMonth, inst.selectedDay, 12); | ||
1126 | + selectLocalTimeZone(tp_inst, date); | ||
1127 | + tp_inst._onTimeChange(); | ||
1128 | + } | ||
1129 | + } | ||
1130 | + } | ||
1131 | +}; | ||
1132 | + | ||
1133 | +//####################################################################################### | ||
1134 | +// third bad hack :/ override datepicker so it allows spaces and colon in the input field | ||
1135 | +//####################################################################################### | ||
1136 | +$.datepicker._base_doKeyPress = $.datepicker._doKeyPress; | ||
1137 | +$.datepicker._doKeyPress = function(event) { | ||
1138 | + var inst = $.datepicker._getInst(event.target), | ||
1139 | + tp_inst = $.datepicker._get(inst, 'timepicker'); | ||
1140 | + | ||
1141 | + if (tp_inst) { | ||
1142 | + if ($.datepicker._get(inst, 'constrainInput')) { | ||
1143 | + var ampm = tp_inst._defaults.ampm, | ||
1144 | + dateChars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')), | ||
1145 | + datetimeChars = tp_inst._defaults.timeFormat.toString() | ||
1146 | + .replace(/[hms]/g, '') | ||
1147 | + .replace(/TT/g, ampm ? 'APM' : '') | ||
1148 | + .replace(/Tt/g, ampm ? 'AaPpMm' : '') | ||
1149 | + .replace(/tT/g, ampm ? 'AaPpMm' : '') | ||
1150 | + .replace(/T/g, ampm ? 'AP' : '') | ||
1151 | + .replace(/tt/g, ampm ? 'apm' : '') | ||
1152 | + .replace(/t/g, ampm ? 'ap' : '') + | ||
1153 | + " " + | ||
1154 | + tp_inst._defaults.separator + | ||
1155 | + tp_inst._defaults.timeSuffix + | ||
1156 | + (tp_inst._defaults.showTimezone ? tp_inst._defaults.timezoneList.join('') : '') + | ||
1157 | + (tp_inst._defaults.amNames.join('')) + | ||
1158 | + (tp_inst._defaults.pmNames.join('')) + | ||
1159 | + dateChars, | ||
1160 | + chr = String.fromCharCode(event.charCode === undefined ? event.keyCode : event.charCode); | ||
1161 | + return event.ctrlKey || (chr < ' ' || !dateChars || datetimeChars.indexOf(chr) > -1); | ||
1162 | + } | ||
1163 | + } | ||
1164 | + | ||
1165 | + return $.datepicker._base_doKeyPress(event); | ||
1166 | +}; | ||
1167 | + | ||
1168 | +//####################################################################################### | ||
1169 | +// Override key up event to sync manual input changes. | ||
1170 | +//####################################################################################### | ||
1171 | +$.datepicker._base_doKeyUp = $.datepicker._doKeyUp; | ||
1172 | +$.datepicker._doKeyUp = function (event) { | ||
1173 | + var inst = $.datepicker._getInst(event.target), | ||
1174 | + tp_inst = $.datepicker._get(inst, 'timepicker'); | ||
1175 | + | ||
1176 | + if (tp_inst) { | ||
1177 | + if (tp_inst._defaults.timeOnly && (inst.input.val() != inst.lastVal)) { | ||
1178 | + try { | ||
1179 | + $.datepicker._updateDatepicker(inst); | ||
1180 | + } | ||
1181 | + catch (err) { | ||
1182 | + $.datepicker.log(err); | ||
1183 | + } | ||
1184 | + } | ||
1185 | + } | ||
1186 | + | ||
1187 | + return $.datepicker._base_doKeyUp(event); | ||
1188 | +}; | ||
1189 | + | ||
1190 | +//####################################################################################### | ||
1191 | +// override "Today" button to also grab the time. | ||
1192 | +//####################################################################################### | ||
1193 | +$.datepicker._base_gotoToday = $.datepicker._gotoToday; | ||
1194 | +$.datepicker._gotoToday = function(id) { | ||
1195 | + var inst = this._getInst($(id)[0]), | ||
1196 | + $dp = inst.dpDiv; | ||
1197 | + this._base_gotoToday(id); | ||
1198 | + var tp_inst = this._get(inst, 'timepicker'); | ||
1199 | + selectLocalTimeZone(tp_inst); | ||
1200 | + var now = new Date(); | ||
1201 | + this._setTime(inst, now); | ||
1202 | + $( '.ui-datepicker-today', $dp).click(); | ||
1203 | +}; | ||
1204 | + | ||
1205 | +//####################################################################################### | ||
1206 | +// Disable & enable the Time in the datetimepicker | ||
1207 | +//####################################################################################### | ||
1208 | +$.datepicker._disableTimepickerDatepicker = function(target) { | ||
1209 | + var inst = this._getInst(target); | ||
1210 | + if (!inst) { return; } | ||
1211 | + | ||
1212 | + var tp_inst = this._get(inst, 'timepicker'); | ||
1213 | + $(target).datepicker('getDate'); // Init selected[Year|Month|Day] | ||
1214 | + if (tp_inst) { | ||
1215 | + tp_inst._defaults.showTimepicker = false; | ||
1216 | + tp_inst._updateDateTime(inst); | ||
1217 | + } | ||
1218 | +}; | ||
1219 | + | ||
1220 | +$.datepicker._enableTimepickerDatepicker = function(target) { | ||
1221 | + var inst = this._getInst(target); | ||
1222 | + if (!inst) { return; } | ||
1223 | + | ||
1224 | + var tp_inst = this._get(inst, 'timepicker'); | ||
1225 | + $(target).datepicker('getDate'); // Init selected[Year|Month|Day] | ||
1226 | + if (tp_inst) { | ||
1227 | + tp_inst._defaults.showTimepicker = true; | ||
1228 | + tp_inst._addTimePicker(inst); // Could be disabled on page load | ||
1229 | + tp_inst._updateDateTime(inst); | ||
1230 | + } | ||
1231 | +}; | ||
1232 | + | ||
1233 | +//####################################################################################### | ||
1234 | +// Create our own set time function | ||
1235 | +//####################################################################################### | ||
1236 | +$.datepicker._setTime = function(inst, date) { | ||
1237 | + var tp_inst = this._get(inst, 'timepicker'); | ||
1238 | + if (tp_inst) { | ||
1239 | + var defaults = tp_inst._defaults, | ||
1240 | + // calling _setTime with no date sets time to defaults | ||
1241 | + hour = date ? date.getHours() : defaults.hour, | ||
1242 | + minute = date ? date.getMinutes() : defaults.minute, | ||
1243 | + second = date ? date.getSeconds() : defaults.second, | ||
1244 | + millisec = date ? date.getMilliseconds() : defaults.millisec; | ||
1245 | + //check if within min/max times.. | ||
1246 | + // correct check if within min/max times. | ||
1247 | + // Rewritten by Scott A. Woodward | ||
1248 | + var hourEq = hour === defaults.hourMin, | ||
1249 | + minuteEq = minute === defaults.minuteMin, | ||
1250 | + secondEq = second === defaults.secondMin; | ||
1251 | + var reset = false; | ||
1252 | + if(hour < defaults.hourMin || hour > defaults.hourMax) | ||
1253 | + reset = true; | ||
1254 | + else if( (minute < defaults.minuteMin || minute > defaults.minuteMax) && hourEq) | ||
1255 | + reset = true; | ||
1256 | + else if( (second < defaults.secondMin || second > defaults.secondMax ) && hourEq && minuteEq) | ||
1257 | + reset = true; | ||
1258 | + else if( (millisec < defaults.millisecMin || millisec > defaults.millisecMax) && hourEq && minuteEq && secondEq) | ||
1259 | + reset = true; | ||
1260 | + if(reset) { | ||
1261 | + hour = defaults.hourMin; | ||
1262 | + minute = defaults.minuteMin; | ||
1263 | + second = defaults.secondMin; | ||
1264 | + millisec = defaults.millisecMin; | ||
1265 | + } | ||
1266 | + tp_inst.hour = hour; | ||
1267 | + tp_inst.minute = minute; | ||
1268 | + tp_inst.second = second; | ||
1269 | + tp_inst.millisec = millisec; | ||
1270 | + if (tp_inst.hour_slider) tp_inst.hour_slider.slider('value', hour); | ||
1271 | + if (tp_inst.minute_slider) tp_inst.minute_slider.slider('value', minute); | ||
1272 | + if (tp_inst.second_slider) tp_inst.second_slider.slider('value', second); | ||
1273 | + if (tp_inst.millisec_slider) tp_inst.millisec_slider.slider('value', millisec); | ||
1274 | + | ||
1275 | + tp_inst._onTimeChange(); | ||
1276 | + tp_inst._updateDateTime(inst); | ||
1277 | + } | ||
1278 | +}; | ||
1279 | + | ||
1280 | +//####################################################################################### | ||
1281 | +// Create new public method to set only time, callable as $().datepicker('setTime', date) | ||
1282 | +//####################################################################################### | ||
1283 | +$.datepicker._setTimeDatepicker = function(target, date, withDate) { | ||
1284 | + var inst = this._getInst(target); | ||
1285 | + if (!inst) { return; } | ||
1286 | + | ||
1287 | + var tp_inst = this._get(inst, 'timepicker'); | ||
1288 | + | ||
1289 | + if (tp_inst) { | ||
1290 | + this._setDateFromField(inst); | ||
1291 | + var tp_date; | ||
1292 | + if (date) { | ||
1293 | + if (typeof date == "string") { | ||
1294 | + tp_inst._parseTime(date, withDate); | ||
1295 | + tp_date = new Date(); | ||
1296 | + tp_date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec); | ||
1297 | + } | ||
1298 | + else { tp_date = new Date(date.getTime()); } | ||
1299 | + if (tp_date.toString() == 'Invalid Date') { tp_date = undefined; } | ||
1300 | + this._setTime(inst, tp_date); | ||
1301 | + } | ||
1302 | + } | ||
1303 | + | ||
1304 | +}; | ||
1305 | + | ||
1306 | +//####################################################################################### | ||
1307 | +// override setDate() to allow setting time too within Date object | ||
1308 | +//####################################################################################### | ||
1309 | +$.datepicker._base_setDateDatepicker = $.datepicker._setDateDatepicker; | ||
1310 | +$.datepicker._setDateDatepicker = function(target, date) { | ||
1311 | + var inst = this._getInst(target); | ||
1312 | + if (!inst) { return; } | ||
1313 | + | ||
1314 | + var tp_date = (date instanceof Date) ? new Date(date.getTime()) : date; | ||
1315 | + | ||
1316 | + this._updateDatepicker(inst); | ||
1317 | + this._base_setDateDatepicker.apply(this, arguments); | ||
1318 | + this._setTimeDatepicker(target, tp_date, true); | ||
1319 | +}; | ||
1320 | + | ||
1321 | +//####################################################################################### | ||
1322 | +// override getDate() to allow getting time too within Date object | ||
1323 | +//####################################################################################### | ||
1324 | +$.datepicker._base_getDateDatepicker = $.datepicker._getDateDatepicker; | ||
1325 | +$.datepicker._getDateDatepicker = function(target, noDefault) { | ||
1326 | + var inst = this._getInst(target); | ||
1327 | + if (!inst) { return; } | ||
1328 | + | ||
1329 | + var tp_inst = this._get(inst, 'timepicker'); | ||
1330 | + | ||
1331 | + if (tp_inst) { | ||
1332 | + this._setDateFromField(inst, noDefault); | ||
1333 | + var date = this._getDate(inst); | ||
1334 | + if (date && tp_inst._parseTime($(target).val(), tp_inst.timeOnly)) { date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec); } | ||
1335 | + return date; | ||
1336 | + } | ||
1337 | + return this._base_getDateDatepicker(target, noDefault); | ||
1338 | +}; | ||
1339 | + | ||
1340 | +//####################################################################################### | ||
1341 | +// override parseDate() because UI 1.8.14 throws an error about "Extra characters" | ||
1342 | +// An option in datapicker to ignore extra format characters would be nicer. | ||
1343 | +//####################################################################################### | ||
1344 | +$.datepicker._base_parseDate = $.datepicker.parseDate; | ||
1345 | +$.datepicker.parseDate = function(format, value, settings) { | ||
1346 | + var splitRes = splitDateTime(format, value, settings); | ||
1347 | + return $.datepicker._base_parseDate(format, splitRes[0], settings); | ||
1348 | +}; | ||
1349 | + | ||
1350 | +//####################################################################################### | ||
1351 | +// override formatDate to set date with time to the input | ||
1352 | +//####################################################################################### | ||
1353 | +$.datepicker._base_formatDate = $.datepicker._formatDate; | ||
1354 | +$.datepicker._formatDate = function(inst, day, month, year){ | ||
1355 | + var tp_inst = this._get(inst, 'timepicker'); | ||
1356 | + if(tp_inst) { | ||
1357 | + tp_inst._updateDateTime(inst); | ||
1358 | + return tp_inst.$input.val(); | ||
1359 | + } | ||
1360 | + return this._base_formatDate(inst); | ||
1361 | +}; | ||
1362 | + | ||
1363 | +//####################################################################################### | ||
1364 | +// override options setter to add time to maxDate(Time) and minDate(Time). MaxDate | ||
1365 | +//####################################################################################### | ||
1366 | +$.datepicker._base_optionDatepicker = $.datepicker._optionDatepicker; | ||
1367 | +$.datepicker._optionDatepicker = function(target, name, value) { | ||
1368 | + var inst = this._getInst(target); | ||
1369 | + if (!inst) { return null; } | ||
1370 | + | ||
1371 | + var tp_inst = this._get(inst, 'timepicker'); | ||
1372 | + if (tp_inst) { | ||
1373 | + var min = null, max = null, onselect = null; | ||
1374 | + if (typeof name == 'string') { // if min/max was set with the string | ||
1375 | + if (name === 'minDate' || name === 'minDateTime' ) { | ||
1376 | + min = value; | ||
1377 | + } | ||
1378 | + else { | ||
1379 | + if (name === 'maxDate' || name === 'maxDateTime') { | ||
1380 | + max = value; | ||
1381 | + } | ||
1382 | + else { | ||
1383 | + if (name === 'onSelect') { | ||
1384 | + onselect = value; | ||
1385 | + } | ||
1386 | + } | ||
1387 | + } | ||
1388 | + } else { | ||
1389 | + if (typeof name == 'object') { //if min/max was set with the JSON | ||
1390 | + if (name.minDate) { | ||
1391 | + min = name.minDate; | ||
1392 | + } else { | ||
1393 | + if (name.minDateTime) { | ||
1394 | + min = name.minDateTime; | ||
1395 | + } else { | ||
1396 | + if (name.maxDate) { | ||
1397 | + max = name.maxDate; | ||
1398 | + } else { | ||
1399 | + if (name.maxDateTime) { | ||
1400 | + max = name.maxDateTime; | ||
1401 | + } | ||
1402 | + } | ||
1403 | + } | ||
1404 | + } | ||
1405 | + } | ||
1406 | + } | ||
1407 | + if(min) { //if min was set | ||
1408 | + if (min === 0) { | ||
1409 | + min = new Date(); | ||
1410 | + } else { | ||
1411 | + min = new Date(min); | ||
1412 | + } | ||
1413 | + | ||
1414 | + tp_inst._defaults.minDate = min; | ||
1415 | + tp_inst._defaults.minDateTime = min; | ||
1416 | + } else if (max) { //if max was set | ||
1417 | + if(max===0) { | ||
1418 | + max=new Date(); | ||
1419 | + } else { | ||
1420 | + max= new Date(max); | ||
1421 | + } | ||
1422 | + tp_inst._defaults.maxDate = max; | ||
1423 | + tp_inst._defaults.maxDateTime = max; | ||
1424 | + } else if (onselect) { | ||
1425 | + tp_inst._defaults.onSelect = onselect; | ||
1426 | + } | ||
1427 | + } | ||
1428 | + if (value === undefined) { | ||
1429 | + return this._base_optionDatepicker(target, name); | ||
1430 | + } | ||
1431 | + return this._base_optionDatepicker(target, name, value); | ||
1432 | +}; | ||
1433 | + | ||
1434 | +//####################################################################################### | ||
1435 | +// jQuery extend now ignores nulls! | ||
1436 | +//####################################################################################### | ||
1437 | +function extendRemove(target, props) { | ||
1438 | + $.extend(target, props); | ||
1439 | + for (var name in props) { | ||
1440 | + if (props[name] === null || props[name] === undefined) { | ||
1441 | + target[name] = props[name]; | ||
1442 | + } | ||
1443 | + } | ||
1444 | + return target; | ||
1445 | +} | ||
1446 | + | ||
1447 | +//####################################################################################### | ||
1448 | +// Splits datetime string into date ans time substrings. | ||
1449 | +// Throws exception when date can't be parsed | ||
1450 | +// If only date is present, time substring eill be '' | ||
1451 | +//####################################################################################### | ||
1452 | +var splitDateTime = function(dateFormat, dateTimeString, dateSettings) | ||
1453 | +{ | ||
1454 | + try { | ||
1455 | + var date = $.datepicker._base_parseDate(dateFormat, dateTimeString, dateSettings); | ||
1456 | + } catch (err) { | ||
1457 | + if (err.indexOf(":") >= 0) { | ||
1458 | + // Hack! The error message ends with a colon, a space, and | ||
1459 | + // the "extra" characters. We rely on that instead of | ||
1460 | + // attempting to perfectly reproduce the parsing algorithm. | ||
1461 | + var dateStringLength = dateTimeString.length-(err.length-err.indexOf(':')-2); | ||
1462 | + var timeString = dateTimeString.substring(dateStringLength); | ||
1463 | + | ||
1464 | + return [dateTimeString.substring(0, dateStringLength), dateTimeString.substring(dateStringLength)]; | ||
1465 | + | ||
1466 | + } else { | ||
1467 | + throw err; | ||
1468 | + } | ||
1469 | + } | ||
1470 | + return [dateTimeString, '']; | ||
1471 | +}; | ||
1472 | + | ||
1473 | +//####################################################################################### | ||
1474 | +// Internal function to parse datetime interval | ||
1475 | +// Returns: {date: Date, timeObj: Object}, where | ||
1476 | +// date - parsed date without time (type Date) | ||
1477 | +// timeObj = {hour: , minute: , second: , millisec: } - parsed time. Optional | ||
1478 | +//####################################################################################### | ||
1479 | +var parseDateTimeInternal = function(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) | ||
1480 | +{ | ||
1481 | + var date; | ||
1482 | + var splitRes = splitDateTime(dateFormat, dateTimeString, dateSettings); | ||
1483 | + date = $.datepicker._base_parseDate(dateFormat, splitRes[0], dateSettings); | ||
1484 | + if (splitRes[1] !== '') | ||
1485 | + { | ||
1486 | + var timeString = splitRes[1]; | ||
1487 | + var separator = timeSettings && timeSettings.separator ? timeSettings.separator : $.timepicker._defaults.separator; | ||
1488 | + if ( timeString.indexOf(separator) !== 0) { | ||
1489 | + throw 'Missing time separator'; | ||
1490 | + } | ||
1491 | + timeString = timeString.substring(separator.length); | ||
1492 | + var parsedTime = $.datepicker.parseTime(timeFormat, timeString, timeSettings); | ||
1493 | + if (parsedTime === null) { | ||
1494 | + throw 'Wrong time format'; | ||
1495 | + } | ||
1496 | + return {date: date, timeObj: parsedTime}; | ||
1497 | + } else { | ||
1498 | + return {date: date}; | ||
1499 | + } | ||
1500 | +}; | ||
1501 | + | ||
1502 | +//####################################################################################### | ||
1503 | +// Internal function to set timezone_select to the local timezone | ||
1504 | +//####################################################################################### | ||
1505 | +var selectLocalTimeZone = function(tp_inst, date) | ||
1506 | +{ | ||
1507 | + if (tp_inst && tp_inst.timezone_select) { | ||
1508 | + tp_inst._defaults.useLocalTimezone = true; | ||
1509 | + var now = typeof date !== 'undefined' ? date : new Date(); | ||
1510 | + var tzoffset = timeZoneString(now); | ||
1511 | + if (tp_inst._defaults.timezoneIso8601) { | ||
1512 | + tzoffset = tzoffset.substring(0, 3) + ':' + tzoffset.substring(3); | ||
1513 | + } | ||
1514 | + tp_inst.timezone_select.val(tzoffset); | ||
1515 | + } | ||
1516 | +}; | ||
1517 | + | ||
1518 | +// Input: Date Object | ||
1519 | +// Output: String with timezone offset, e.g. '+0100' | ||
1520 | +var timeZoneString = function(date) | ||
1521 | +{ | ||
1522 | + var off = date.getTimezoneOffset() * -10100 / 60; | ||
1523 | + var timezone = (off >= 0 ? '+' : '-') + Math.abs(off).toString().substr(1); | ||
1524 | + return timezone; | ||
1525 | +}; | ||
1526 | + | ||
1527 | +$.timepicker = new Timepicker(); // singleton instance | ||
1528 | +$.timepicker.version = "1.0.1"; | ||
1529 | + | ||
1530 | +})(jQuery); |
public/stylesheets/application.css
@@ -4293,6 +4293,14 @@ h1#agenda-title { | @@ -4293,6 +4293,14 @@ h1#agenda-title { | ||
4293 | margin: 5px 0; | 4293 | margin: 5px 0; |
4294 | padding: 5px; | 4294 | padding: 5px; |
4295 | } | 4295 | } |
4296 | + | ||
4297 | +.ui-timepicker-div .ui-widget-header { margin-bottom: 8px; } | ||
4298 | +.ui-timepicker-div dl { text-align: left; } | ||
4299 | +.ui-timepicker-div dl dt { height: 25px; margin-bottom: -25px; } | ||
4300 | +.ui-timepicker-div dl dd { margin: 0 10px 10px 65px; } | ||
4301 | +.ui-timepicker-div td { font-size: 90%; } | ||
4302 | +.ui-tpicker-grid-label { background: none; border: none; margin: 0; padding: 0; } | ||
4303 | + | ||
4296 | /* Categories block stuff */ | 4304 | /* Categories block stuff */ |
4297 | 4305 | ||
4298 | .categories-block ul { | 4306 | .categories-block ul { |