Commit c0c8151c81f7daddd4bfe28bed13e8510ce0d425
1 parent
4398fe05
Exists in
master
and in
23 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 { | ... | ... |