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 | 123 | options_for_select.join("\n") |
124 | 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 | 239 | protected |
127 | 240 | def self.next_id_number |
128 | 241 | if defined? @@id_num | ... | ... |
app/views/layouts/_javascript.rhtml
... | ... | @@ -2,7 +2,8 @@ |
2 | 2 | 'jquery.noconflict.js', 'jquery.cycle.all.min.js', 'thickbox.js', 'lightbox', 'colorbox', |
3 | 3 | 'jquery-ui-1.8.2.custom.min', 'jquery.scrollTo', 'jquery.form.js', 'jquery-validation/jquery.validate', |
4 | 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 | 8 | <% language = FastGettext.locale %> |
8 | 9 | <% %w{messages methods}.each do |type| %> | ... | ... |
... | ... | @@ -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 | 4293 | margin: 5px 0; |
4294 | 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 | 4304 | /* Categories block stuff */ |
4297 | 4305 | |
4298 | 4306 | .categories-block ul { | ... | ... |