Index: trunk/extensions/Contest/Contest.i18n.php |
— | — | @@ -85,6 +85,7 @@ |
86 | 86 | 'contest-edit-help' => 'Help page', |
87 | 87 | 'contest-edit-signup' => 'Signup email page', |
88 | 88 | 'contest-edit-reminder' => 'Reminder email page', |
| 89 | + 'contest-edit-end' => 'Contest end', |
89 | 90 | 'contest-edit-exists-already' => 'Note: you are editing an already existing contest, not creating a new one.', |
90 | 91 | 'contest-edit-submit' => 'Submit', |
91 | 92 | |
Index: trunk/extensions/Contest/specials/SpecialEditContest.php |
— | — | @@ -205,9 +205,22 @@ |
206 | 206 | 'label-message' => 'contest-edit-reminder', |
207 | 207 | ); |
208 | 208 | |
| 209 | + $fields['end'] = array ( |
| 210 | + 'type' => 'text', |
| 211 | + 'label-message' => 'contest-edit-end', |
| 212 | + 'id' => 'contest-edit-end', |
| 213 | + 'size' => 15 |
| 214 | + ); |
| 215 | + |
209 | 216 | if ( $contest !== false ) { |
210 | 217 | foreach ( $fields as $name => $data ) { |
211 | | - $fields[$name]['default'] = $contest->getField( $name ); |
| 218 | + $default = $contest->getField( $name ); |
| 219 | + |
| 220 | + if ( $name == 'end' ) { |
| 221 | + $default = wfTimestamp( TS_DB, $default ); |
| 222 | + } |
| 223 | + |
| 224 | + $fields[$name]['default'] = $default; |
212 | 225 | } |
213 | 226 | } |
214 | 227 | |
— | — | @@ -247,6 +260,10 @@ |
248 | 261 | $matches = array(); |
249 | 262 | |
250 | 263 | if ( preg_match( '/contest-(.+)/', $name, $matches ) ) { |
| 264 | + if ( $matches[1] == 'end' ) { |
| 265 | + $value = wfTimestamp( TS_MW, strtotime( $value ) ); |
| 266 | + } |
| 267 | + |
251 | 268 | $fields[$matches[1]] = $value; |
252 | 269 | } |
253 | 270 | } |
Index: trunk/extensions/Contest/Contest.php |
— | — | @@ -151,8 +151,12 @@ |
152 | 152 | |
153 | 153 | $wgResourceModules['contest.special.editcontest'] = $moduleTemplate + array( |
154 | 154 | 'scripts' => array( |
155 | | - 'contest.special.editcontest.js' |
| 155 | + 'jquery-ui-timepicker-addon.js', |
| 156 | + 'contest.special.editcontest.js', |
156 | 157 | ), |
| 158 | + 'styles' => array( |
| 159 | + 'jquery-ui-timepicker-addon.css', |
| 160 | + ), |
157 | 161 | 'messages' => array( |
158 | 162 | 'contest-edit-delete', |
159 | 163 | 'contest-edit-add-first', |
— | — | @@ -163,7 +167,9 @@ |
164 | 168 | 'contest-edit-challenge-oneline', |
165 | 169 | ), |
166 | 170 | 'dependencies' => array( |
167 | | - 'jquery.ui.button' |
| 171 | + 'jquery.ui.button', |
| 172 | + 'jquery.ui.slider', |
| 173 | + 'jquery.ui.datepicker' |
168 | 174 | ) |
169 | 175 | ); |
170 | 176 | |
Index: trunk/extensions/Contest/includes/ContestUtils.php |
— | — | @@ -53,6 +53,11 @@ |
54 | 54 | |
55 | 55 | $article = new Article( $title, 0 ); |
56 | 56 | |
| 57 | + // Looks like the LinkEnd hook can be used here instead of replaceRelativeLinks. |
| 58 | + // The hook could just turn relative urls into absolute ones in a nice way, |
| 59 | + // but would reauire setting some global such as $isContestEmailParse to true |
| 60 | + // before the parse call and to false afterwards, which also is not very nice. |
| 61 | + |
57 | 62 | global $wgParser; |
58 | 63 | return $wgParser->parse( |
59 | 64 | self::replaceRelativeLinks( $article->fetchContent() ), |
Index: trunk/extensions/Contest/includes/Contest.class.php |
— | — | @@ -115,7 +115,7 @@ |
116 | 116 | 'id' => 'id', |
117 | 117 | 'name' => 'str', |
118 | 118 | 'status' => 'int', |
119 | | - 'end' => 'int', |
| 119 | + 'end' => 'str', // TS_MW |
120 | 120 | |
121 | 121 | 'rules_page' => 'str', |
122 | 122 | 'opportunities' => 'str', |
Index: trunk/extensions/Contest/resources/jquery-ui-timepicker-addon.js |
— | — | @@ -0,0 +1,1276 @@ |
| 2 | +/* |
| 3 | +* jQuery timepicker addon |
| 4 | +* By: Trent Richardson [http://trentrichardson.com] |
| 5 | +* Version 0.9.7 |
| 6 | +* Last Modified: 10/02/2011 |
| 7 | +* |
| 8 | +* Copyright 2011 Trent Richardson |
| 9 | +* Dual licensed under the MIT and GPL licenses. |
| 10 | +* http://trentrichardson.com/Impromptu/GPL-LICENSE.txt |
| 11 | +* http://trentrichardson.com/Impromptu/MIT-LICENSE.txt |
| 12 | +* |
| 13 | +* HERES THE CSS: |
| 14 | +* .ui-timepicker-div .ui-widget-header { margin-bottom: 8px; } |
| 15 | +* .ui-timepicker-div dl { text-align: left; } |
| 16 | +* .ui-timepicker-div dl dt { height: 25px; } |
| 17 | +* .ui-timepicker-div dl dd { margin: -25px 10px 10px 65px; } |
| 18 | +* .ui-timepicker-div td { font-size: 90%; } |
| 19 | +* .ui-tpicker-grid-label { background: none; border: none; margin: 0; padding: 0; } |
| 20 | +*/ |
| 21 | + |
| 22 | +(function($) { |
| 23 | + |
| 24 | +$.extend($.ui, { timepicker: { version: "0.9.7" } }); |
| 25 | + |
| 26 | +/* Time picker manager. |
| 27 | + Use the singleton instance of this class, $.timepicker, to interact with the time picker. |
| 28 | + Settings for (groups of) time pickers are maintained in an instance object, |
| 29 | + allowing multiple different settings on the same page. */ |
| 30 | + |
| 31 | +function Timepicker() { |
| 32 | + this.regional = []; // Available regional settings, indexed by language code |
| 33 | + this.regional[''] = { // Default regional settings |
| 34 | + currentText: 'Now', |
| 35 | + closeText: 'Done', |
| 36 | + ampm: false, |
| 37 | + amNames: ['AM', 'A'], |
| 38 | + pmNames: ['PM', 'P'], |
| 39 | + timeFormat: 'hh:mm tt', |
| 40 | + timeSuffix: '', |
| 41 | + timeOnlyTitle: 'Choose Time', |
| 42 | + timeText: 'Time', |
| 43 | + hourText: 'Hour', |
| 44 | + minuteText: 'Minute', |
| 45 | + secondText: 'Second', |
| 46 | + millisecText: 'Millisecond', |
| 47 | + timezoneText: 'Time Zone' |
| 48 | + }; |
| 49 | + this._defaults = { // Global defaults for all the datetime picker instances |
| 50 | + showButtonPanel: true, |
| 51 | + timeOnly: false, |
| 52 | + showHour: true, |
| 53 | + showMinute: true, |
| 54 | + showSecond: false, |
| 55 | + showMillisec: false, |
| 56 | + showTimezone: false, |
| 57 | + showTime: true, |
| 58 | + stepHour: 0.05, |
| 59 | + stepMinute: 0.05, |
| 60 | + stepSecond: 0.05, |
| 61 | + stepMillisec: 0.5, |
| 62 | + hour: 0, |
| 63 | + minute: 0, |
| 64 | + second: 0, |
| 65 | + millisec: 0, |
| 66 | + timezone: '+0000', |
| 67 | + hourMin: 0, |
| 68 | + minuteMin: 0, |
| 69 | + secondMin: 0, |
| 70 | + millisecMin: 0, |
| 71 | + hourMax: 23, |
| 72 | + minuteMax: 59, |
| 73 | + secondMax: 59, |
| 74 | + millisecMax: 999, |
| 75 | + minDateTime: null, |
| 76 | + maxDateTime: null, |
| 77 | + onSelect: null, |
| 78 | + hourGrid: 0, |
| 79 | + minuteGrid: 0, |
| 80 | + secondGrid: 0, |
| 81 | + millisecGrid: 0, |
| 82 | + alwaysSetTime: true, |
| 83 | + separator: ' ', |
| 84 | + altFieldTimeOnly: true, |
| 85 | + showTimepicker: true, |
| 86 | + timezoneIso8609: false, |
| 87 | + timezoneList: null |
| 88 | + }; |
| 89 | + $.extend(this._defaults, this.regional['']); |
| 90 | +} |
| 91 | + |
| 92 | +$.extend(Timepicker.prototype, { |
| 93 | + $input: null, |
| 94 | + $altInput: null, |
| 95 | + $timeObj: null, |
| 96 | + inst: null, |
| 97 | + hour_slider: null, |
| 98 | + minute_slider: null, |
| 99 | + second_slider: null, |
| 100 | + millisec_slider: null, |
| 101 | + timezone_select: null, |
| 102 | + hour: 0, |
| 103 | + minute: 0, |
| 104 | + second: 0, |
| 105 | + millisec: 0, |
| 106 | + timezone: '+0000', |
| 107 | + hourMinOriginal: null, |
| 108 | + minuteMinOriginal: null, |
| 109 | + secondMinOriginal: null, |
| 110 | + millisecMinOriginal: null, |
| 111 | + hourMaxOriginal: null, |
| 112 | + minuteMaxOriginal: null, |
| 113 | + secondMaxOriginal: null, |
| 114 | + millisecMaxOriginal: null, |
| 115 | + ampm: '', |
| 116 | + formattedDate: '', |
| 117 | + formattedTime: '', |
| 118 | + formattedDateTime: '', |
| 119 | + timezoneList: null, |
| 120 | + |
| 121 | + /* Override the default settings for all instances of the time picker. |
| 122 | + @param settings object - the new settings to use as defaults (anonymous object) |
| 123 | + @return the manager object */ |
| 124 | + setDefaults: function(settings) { |
| 125 | + extendRemove(this._defaults, settings || {}); |
| 126 | + return this; |
| 127 | + }, |
| 128 | + |
| 129 | + //######################################################################## |
| 130 | + // Create a new Timepicker instance |
| 131 | + //######################################################################## |
| 132 | + _newInst: function($input, o) { |
| 133 | + var tp_inst = new Timepicker(), |
| 134 | + inlineSettings = {}; |
| 135 | + |
| 136 | + for (var attrName in this._defaults) { |
| 137 | + var attrValue = $input.attr('time:' + attrName); |
| 138 | + if (attrValue) { |
| 139 | + try { |
| 140 | + inlineSettings[attrName] = eval(attrValue); |
| 141 | + } catch (err) { |
| 142 | + inlineSettings[attrName] = attrValue; |
| 143 | + } |
| 144 | + } |
| 145 | + } |
| 146 | + tp_inst._defaults = $.extend({}, this._defaults, inlineSettings, o, { |
| 147 | + beforeShow: function(input, dp_inst) { |
| 148 | + if ($.isFunction(o.beforeShow)) |
| 149 | + o.beforeShow(input, dp_inst, tp_inst); |
| 150 | + }, |
| 151 | + onChangeMonthYear: function(year, month, dp_inst) { |
| 152 | + // Update the time as well : this prevents the time from disappearing from the $input field. |
| 153 | + tp_inst._updateDateTime(dp_inst); |
| 154 | + if ($.isFunction(o.onChangeMonthYear)) |
| 155 | + o.onChangeMonthYear.call($input[0], year, month, dp_inst, tp_inst); |
| 156 | + }, |
| 157 | + onClose: function(dateText, dp_inst) { |
| 158 | + if (tp_inst.timeDefined === true && $input.val() != '') |
| 159 | + tp_inst._updateDateTime(dp_inst); |
| 160 | + if ($.isFunction(o.onClose)) |
| 161 | + o.onClose.call($input[0], dateText, dp_inst, tp_inst); |
| 162 | + }, |
| 163 | + timepicker: tp_inst // add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker'); |
| 164 | + }); |
| 165 | + tp_inst.amNames = $.map(tp_inst._defaults.amNames, function(val) { return val.toUpperCase() }); |
| 166 | + tp_inst.pmNames = $.map(tp_inst._defaults.pmNames, function(val) { return val.toUpperCase() }); |
| 167 | + |
| 168 | + if (tp_inst._defaults.timezoneList === null) { |
| 169 | + var timezoneList = []; |
| 170 | + for (var i = -11; i <= 12; i++) |
| 171 | + timezoneList.push((i >= 0 ? '+' : '-') + ('0' + Math.abs(i).toString()).slice(-2) + '00'); |
| 172 | + if (tp_inst._defaults.timezoneIso8609) |
| 173 | + timezoneList = $.map(timezoneList, function(val) { |
| 174 | + return val == '+0000' ? 'Z' : (val.substring(0, 3) + ':' + val.substring(3)); |
| 175 | + }); |
| 176 | + tp_inst._defaults.timezoneList = timezoneList; |
| 177 | + } |
| 178 | + |
| 179 | + tp_inst.hour = tp_inst._defaults.hour; |
| 180 | + tp_inst.minute = tp_inst._defaults.minute; |
| 181 | + tp_inst.second = tp_inst._defaults.second; |
| 182 | + tp_inst.millisec = tp_inst._defaults.millisec; |
| 183 | + tp_inst.ampm = ''; |
| 184 | + tp_inst.$input = $input; |
| 185 | + |
| 186 | + if (o.altField) |
| 187 | + tp_inst.$altInput = $(o.altField) |
| 188 | + .css({ cursor: 'pointer' }) |
| 189 | + .focus(function(){ $input.trigger("focus"); }); |
| 190 | + |
| 191 | + if(tp_inst._defaults.minDate==0 || tp_inst._defaults.minDateTime==0) |
| 192 | + { |
| 193 | + tp_inst._defaults.minDate=new Date(); |
| 194 | + } |
| 195 | + if(tp_inst._defaults.maxDate==0 || tp_inst._defaults.maxDateTime==0) |
| 196 | + { |
| 197 | + tp_inst._defaults.maxDate=new Date(); |
| 198 | + } |
| 199 | + |
| 200 | + // datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime.. |
| 201 | + if(tp_inst._defaults.minDate !== undefined && tp_inst._defaults.minDate instanceof Date) |
| 202 | + tp_inst._defaults.minDateTime = new Date(tp_inst._defaults.minDate.getTime()); |
| 203 | + if(tp_inst._defaults.minDateTime !== undefined && tp_inst._defaults.minDateTime instanceof Date) |
| 204 | + tp_inst._defaults.minDate = new Date(tp_inst._defaults.minDateTime.getTime()); |
| 205 | + if(tp_inst._defaults.maxDate !== undefined && tp_inst._defaults.maxDate instanceof Date) |
| 206 | + tp_inst._defaults.maxDateTime = new Date(tp_inst._defaults.maxDate.getTime()); |
| 207 | + if(tp_inst._defaults.maxDateTime !== undefined && tp_inst._defaults.maxDateTime instanceof Date) |
| 208 | + tp_inst._defaults.maxDate = new Date(tp_inst._defaults.maxDateTime.getTime()); |
| 209 | + return tp_inst; |
| 210 | + }, |
| 211 | + |
| 212 | + //######################################################################## |
| 213 | + // add our sliders to the calendar |
| 214 | + //######################################################################## |
| 215 | + _addTimePicker: function(dp_inst) { |
| 216 | + var currDT = (this.$altInput && this._defaults.altFieldTimeOnly) ? |
| 217 | + this.$input.val() + ' ' + this.$altInput.val() : |
| 218 | + this.$input.val(); |
| 219 | + |
| 220 | + this.timeDefined = this._parseTime(currDT); |
| 221 | + this._limitMinMaxDateTime(dp_inst, false); |
| 222 | + this._injectTimePicker(); |
| 223 | + }, |
| 224 | + |
| 225 | + //######################################################################## |
| 226 | + // parse the time string from input value or _setTime |
| 227 | + //######################################################################## |
| 228 | + _parseTime: function(timeString, withDate) { |
| 229 | + var regstr = this._defaults.timeFormat.toString() |
| 230 | + .replace(/h{1,2}/ig, '(\\d?\\d)') |
| 231 | + .replace(/m{1,2}/ig, '(\\d?\\d)') |
| 232 | + .replace(/s{1,2}/ig, '(\\d?\\d)') |
| 233 | + .replace(/l{1}/ig, '(\\d?\\d?\\d)') |
| 234 | + .replace(/t{1,2}/ig, this._getPatternAmpm()) |
| 235 | + .replace(/z{1}/ig, '(z|[-+]\\d\\d:?\\d\\d)?') |
| 236 | + .replace(/\s/g, '\\s?') + this._defaults.timeSuffix + '$', |
| 237 | + order = this._getFormatPositions(), |
| 238 | + ampm = '', |
| 239 | + treg; |
| 240 | + |
| 241 | + if (!this.inst) this.inst = $.datepicker._getInst(this.$input[0]); |
| 242 | + |
| 243 | + if (withDate || !this._defaults.timeOnly) { |
| 244 | + // the time should come after x number of characters and a space. |
| 245 | + // x = at least the length of text specified by the date format |
| 246 | + var dp_dateFormat = $.datepicker._get(this.inst, 'dateFormat'); |
| 247 | + // escape special regex characters in the seperator |
| 248 | + var specials = new RegExp("[.*+?|()\\[\\]{}\\\\]", "g"); |
| 249 | + regstr = '.{' + dp_dateFormat.length + ',}' + this._defaults.separator.replace(specials, "\\$&") + regstr; |
| 250 | + } |
| 251 | + |
| 252 | + treg = timeString.match(new RegExp(regstr, 'i')); |
| 253 | + |
| 254 | + if (treg) { |
| 255 | + if (order.t !== -1) { |
| 256 | + if (treg[order.t] === undefined || treg[order.t].length === 0) { |
| 257 | + ampm = ''; |
| 258 | + this.ampm = ''; |
| 259 | + } else { |
| 260 | + ampm = $.inArray(treg[order.t].toUpperCase(), this.amNames) !== -1 ? 'AM' : 'PM'; |
| 261 | + this.ampm = this._defaults[ampm == 'AM' ? 'amNames' : 'pmNames'][0]; |
| 262 | + } |
| 263 | + } |
| 264 | + |
| 265 | + if (order.h !== -1) { |
| 266 | + if (ampm == 'AM' && treg[order.h] == '12') |
| 267 | + this.hour = 0; // 12am = 0 hour |
| 268 | + else if (ampm == 'PM' && treg[order.h] != '12') |
| 269 | + this.hour = (parseFloat(treg[order.h]) + 12).toFixed(0); // 12pm = 12 hour, any other pm = hour + 12 |
| 270 | + else this.hour = Number(treg[order.h]); |
| 271 | + } |
| 272 | + |
| 273 | + if (order.m !== -1) this.minute = Number(treg[order.m]); |
| 274 | + if (order.s !== -1) this.second = Number(treg[order.s]); |
| 275 | + if (order.l !== -1) this.millisec = Number(treg[order.l]); |
| 276 | + if (order.z !== -1 && treg[order.z] !== undefined) { |
| 277 | + var tz = treg[order.z].toUpperCase(); |
| 278 | + switch (tz.length) { |
| 279 | + case 1: // Z |
| 280 | + tz = this._defaults.timezoneIso8609 ? 'Z' : '+0000'; |
| 281 | + break; |
| 282 | + case 5: // +hhmm |
| 283 | + if (this._defaults.timezoneIso8609) |
| 284 | + tz = tz.substring(1) == '0000' |
| 285 | + ? 'Z' |
| 286 | + : tz.substring(0, 3) + ':' + tz.substring(3); |
| 287 | + break; |
| 288 | + case 6: // +hh:mm |
| 289 | + if (!this._defaults.timezoneIso8609) |
| 290 | + tz = tz == 'Z' || tz.substring(1) == '00:00' |
| 291 | + ? '+0000' |
| 292 | + : tz.replace(/:/, ''); |
| 293 | + else if (tz.substring(1) == '00:00') |
| 294 | + tz = 'Z'; |
| 295 | + break; |
| 296 | + } |
| 297 | + this.timezone = tz; |
| 298 | + } |
| 299 | + |
| 300 | + return true; |
| 301 | + |
| 302 | + } |
| 303 | + return false; |
| 304 | + }, |
| 305 | + |
| 306 | + //######################################################################## |
| 307 | + // pattern for standard and localized AM/PM markers |
| 308 | + //######################################################################## |
| 309 | + _getPatternAmpm: function() { |
| 310 | + var markers = []; |
| 311 | + o = this._defaults; |
| 312 | + if (o.amNames) |
| 313 | + $.merge(markers, o.amNames); |
| 314 | + if (o.pmNames) |
| 315 | + $.merge(markers, o.pmNames); |
| 316 | + markers = $.map(markers, function(val) { return val.replace(/[.*+?|()\[\]{}\\]/g, '\\$&') }); |
| 317 | + return '(' + markers.join('|') + ')?'; |
| 318 | + }, |
| 319 | + |
| 320 | + //######################################################################## |
| 321 | + // figure out position of time elements.. cause js cant do named captures |
| 322 | + //######################################################################## |
| 323 | + _getFormatPositions: function() { |
| 324 | + var finds = this._defaults.timeFormat.toLowerCase().match(/(h{1,2}|m{1,2}|s{1,2}|l{1}|t{1,2}|z)/g), |
| 325 | + orders = { h: -1, m: -1, s: -1, l: -1, t: -1, z: -1 }; |
| 326 | + |
| 327 | + if (finds) |
| 328 | + for (var i = 0; i < finds.length; i++) |
| 329 | + if (orders[finds[i].toString().charAt(0)] == -1) |
| 330 | + orders[finds[i].toString().charAt(0)] = i + 1; |
| 331 | + |
| 332 | + return orders; |
| 333 | + }, |
| 334 | + |
| 335 | + //######################################################################## |
| 336 | + // generate and inject html for timepicker into ui datepicker |
| 337 | + //######################################################################## |
| 338 | + _injectTimePicker: function() { |
| 339 | + var $dp = this.inst.dpDiv, |
| 340 | + o = this._defaults, |
| 341 | + tp_inst = this, |
| 342 | + // Added by Peter Medeiros: |
| 343 | + // - Figure out what the hour/minute/second max should be based on the step values. |
| 344 | + // - Example: if stepMinute is 15, then minMax is 45. |
| 345 | + hourMax = (o.hourMax - ((o.hourMax - o.hourMin) % o.stepHour)).toFixed(0), |
| 346 | + minMax = (o.minuteMax - ((o.minuteMax - o.minuteMin) % o.stepMinute)).toFixed(0), |
| 347 | + secMax = (o.secondMax - ((o.secondMax - o.secondMin) % o.stepSecond)).toFixed(0), |
| 348 | + millisecMax = (o.millisecMax - ((o.millisecMax - o.millisecMin) % o.stepMillisec)).toFixed(0), |
| 349 | + dp_id = this.inst.id.toString().replace(/([^A-Za-z0-9_])/g, ''); |
| 350 | + |
| 351 | + // Prevent displaying twice |
| 352 | + //if ($dp.find("div#ui-timepicker-div-"+ dp_id).length === 0) { |
| 353 | + if ($dp.find("div#ui-timepicker-div-"+ dp_id).length === 0 && o.showTimepicker) { |
| 354 | + var noDisplay = ' style="display:none;"', |
| 355 | + html = '<div class="ui-timepicker-div" id="ui-timepicker-div-' + dp_id + '"><dl>' + |
| 356 | + '<dt class="ui_tpicker_time_label" id="ui_tpicker_time_label_' + dp_id + '"' + |
| 357 | + ((o.showTime) ? '' : noDisplay) + '>' + o.timeText + '</dt>' + |
| 358 | + '<dd class="ui_tpicker_time" id="ui_tpicker_time_' + dp_id + '"' + |
| 359 | + ((o.showTime) ? '' : noDisplay) + '></dd>' + |
| 360 | + '<dt class="ui_tpicker_hour_label" id="ui_tpicker_hour_label_' + dp_id + '"' + |
| 361 | + ((o.showHour) ? '' : noDisplay) + '>' + o.hourText + '</dt>', |
| 362 | + hourGridSize = 0, |
| 363 | + minuteGridSize = 0, |
| 364 | + secondGridSize = 0, |
| 365 | + millisecGridSize = 0, |
| 366 | + size; |
| 367 | + |
| 368 | + // Hours |
| 369 | + if (o.showHour && o.hourGrid > 0) { |
| 370 | + html += '<dd class="ui_tpicker_hour">' + |
| 371 | + '<div id="ui_tpicker_hour_' + dp_id + '"' + ((o.showHour) ? '' : noDisplay) + '></div>' + |
| 372 | + '<div style="padding-left: 1px"><table class="ui-tpicker-grid-label"><tr>'; |
| 373 | + |
| 374 | + for (var h = o.hourMin; h <= hourMax; h += parseInt(o.hourGrid,10)) { |
| 375 | + hourGridSize++; |
| 376 | + var tmph = (o.ampm && h > 12) ? h-12 : h; |
| 377 | + if (tmph < 10) tmph = '0' + tmph; |
| 378 | + if (o.ampm) { |
| 379 | + if (h == 0) tmph = 12 +'a'; |
| 380 | + else if (h < 12) tmph += 'a'; |
| 381 | + else tmph += 'p'; |
| 382 | + } |
| 383 | + html += '<td>' + tmph + '</td>'; |
| 384 | + } |
| 385 | + |
| 386 | + html += '</tr></table></div>' + |
| 387 | + '</dd>'; |
| 388 | + } else html += '<dd class="ui_tpicker_hour" id="ui_tpicker_hour_' + dp_id + '"' + |
| 389 | + ((o.showHour) ? '' : noDisplay) + '></dd>'; |
| 390 | + |
| 391 | + html += '<dt class="ui_tpicker_minute_label" id="ui_tpicker_minute_label_' + dp_id + '"' + |
| 392 | + ((o.showMinute) ? '' : noDisplay) + '>' + o.minuteText + '</dt>'; |
| 393 | + |
| 394 | + // Minutes |
| 395 | + if (o.showMinute && o.minuteGrid > 0) { |
| 396 | + html += '<dd class="ui_tpicker_minute ui_tpicker_minute_' + o.minuteGrid + '">' + |
| 397 | + '<div id="ui_tpicker_minute_' + dp_id + '"' + |
| 398 | + ((o.showMinute) ? '' : noDisplay) + '></div>' + |
| 399 | + '<div style="padding-left: 1px"><table class="ui-tpicker-grid-label"><tr>'; |
| 400 | + |
| 401 | + for (var m = o.minuteMin; m <= minMax; m += parseInt(o.minuteGrid,10)) { |
| 402 | + minuteGridSize++; |
| 403 | + html += '<td>' + ((m < 10) ? '0' : '') + m + '</td>'; |
| 404 | + } |
| 405 | + |
| 406 | + html += '</tr></table></div>' + |
| 407 | + '</dd>'; |
| 408 | + } else html += '<dd class="ui_tpicker_minute" id="ui_tpicker_minute_' + dp_id + '"' + |
| 409 | + ((o.showMinute) ? '' : noDisplay) + '></dd>'; |
| 410 | + |
| 411 | + // Seconds |
| 412 | + html += '<dt class="ui_tpicker_second_label" id="ui_tpicker_second_label_' + dp_id + '"' + |
| 413 | + ((o.showSecond) ? '' : noDisplay) + '>' + o.secondText + '</dt>'; |
| 414 | + |
| 415 | + if (o.showSecond && o.secondGrid > 0) { |
| 416 | + html += '<dd class="ui_tpicker_second ui_tpicker_second_' + o.secondGrid + '">' + |
| 417 | + '<div id="ui_tpicker_second_' + dp_id + '"' + |
| 418 | + ((o.showSecond) ? '' : noDisplay) + '></div>' + |
| 419 | + '<div style="padding-left: 1px"><table><tr>'; |
| 420 | + |
| 421 | + for (var s = o.secondMin; s <= secMax; s += parseInt(o.secondGrid,10)) { |
| 422 | + secondGridSize++; |
| 423 | + html += '<td>' + ((s < 10) ? '0' : '') + s + '</td>'; |
| 424 | + } |
| 425 | + |
| 426 | + html += '</tr></table></div>' + |
| 427 | + '</dd>'; |
| 428 | + } else html += '<dd class="ui_tpicker_second" id="ui_tpicker_second_' + dp_id + '"' + |
| 429 | + ((o.showSecond) ? '' : noDisplay) + '></dd>'; |
| 430 | + |
| 431 | + // Milliseconds |
| 432 | + html += '<dt class="ui_tpicker_millisec_label" id="ui_tpicker_millisec_label_' + dp_id + '"' + |
| 433 | + ((o.showMillisec) ? '' : noDisplay) + '>' + o.millisecText + '</dt>'; |
| 434 | + |
| 435 | + if (o.showMillisec && o.millisecGrid > 0) { |
| 436 | + html += '<dd class="ui_tpicker_millisec ui_tpicker_millisec_' + o.millisecGrid + '">' + |
| 437 | + '<div id="ui_tpicker_millisec_' + dp_id + '"' + |
| 438 | + ((o.showMillisec) ? '' : noDisplay) + '></div>' + |
| 439 | + '<div style="padding-left: 1px"><table><tr>'; |
| 440 | + |
| 441 | + for (var l = o.millisecMin; l <= millisecMax; l += parseInt(o.millisecGrid,10)) { |
| 442 | + millisecGridSize++; |
| 443 | + html += '<td>' + ((l < 10) ? '0' : '') + s + '</td>'; |
| 444 | + } |
| 445 | + |
| 446 | + html += '</tr></table></div>' + |
| 447 | + '</dd>'; |
| 448 | + } else html += '<dd class="ui_tpicker_millisec" id="ui_tpicker_millisec_' + dp_id + '"' + |
| 449 | + ((o.showMillisec) ? '' : noDisplay) + '></dd>'; |
| 450 | + |
| 451 | + // Timezone |
| 452 | + html += '<dt class="ui_tpicker_timezone_label" id="ui_tpicker_timezone_label_' + dp_id + '"' + |
| 453 | + ((o.showTimezone) ? '' : noDisplay) + '>' + o.timezoneText + '</dt>'; |
| 454 | + html += '<dd class="ui_tpicker_timezone" id="ui_tpicker_timezone_' + dp_id + '"' + |
| 455 | + ((o.showTimezone) ? '' : noDisplay) + '></dd>'; |
| 456 | + |
| 457 | + html += '</dl></div>'; |
| 458 | + $tp = $(html); |
| 459 | + |
| 460 | + // if we only want time picker... |
| 461 | + if (o.timeOnly === true) { |
| 462 | + $tp.prepend( |
| 463 | + '<div class="ui-widget-header ui-helper-clearfix ui-corner-all">' + |
| 464 | + '<div class="ui-datepicker-title">' + o.timeOnlyTitle + '</div>' + |
| 465 | + '</div>'); |
| 466 | + $dp.find('.ui-datepicker-header, .ui-datepicker-calendar').hide(); |
| 467 | + } |
| 468 | + |
| 469 | + this.hour_slider = $tp.find('#ui_tpicker_hour_'+ dp_id).slider({ |
| 470 | + orientation: "horizontal", |
| 471 | + value: this.hour, |
| 472 | + min: o.hourMin, |
| 473 | + max: hourMax, |
| 474 | + step: o.stepHour, |
| 475 | + slide: function(event, ui) { |
| 476 | + tp_inst.hour_slider.slider( "option", "value", ui.value); |
| 477 | + tp_inst._onTimeChange(); |
| 478 | + } |
| 479 | + }); |
| 480 | + |
| 481 | + // Updated by Peter Medeiros: |
| 482 | + // - Pass in Event and UI instance into slide function |
| 483 | + this.minute_slider = $tp.find('#ui_tpicker_minute_'+ dp_id).slider({ |
| 484 | + orientation: "horizontal", |
| 485 | + value: this.minute, |
| 486 | + min: o.minuteMin, |
| 487 | + max: minMax, |
| 488 | + step: o.stepMinute, |
| 489 | + slide: function(event, ui) { |
| 490 | + // update the global minute slider instance value with the current slider value |
| 491 | + tp_inst.minute_slider.slider( "option", "value", ui.value); |
| 492 | + tp_inst._onTimeChange(); |
| 493 | + } |
| 494 | + }); |
| 495 | + |
| 496 | + this.second_slider = $tp.find('#ui_tpicker_second_'+ dp_id).slider({ |
| 497 | + orientation: "horizontal", |
| 498 | + value: this.second, |
| 499 | + min: o.secondMin, |
| 500 | + max: secMax, |
| 501 | + step: o.stepSecond, |
| 502 | + slide: function(event, ui) { |
| 503 | + tp_inst.second_slider.slider( "option", "value", ui.value); |
| 504 | + tp_inst._onTimeChange(); |
| 505 | + } |
| 506 | + }); |
| 507 | + |
| 508 | + this.millisec_slider = $tp.find('#ui_tpicker_millisec_'+ dp_id).slider({ |
| 509 | + orientation: "horizontal", |
| 510 | + value: this.millisec, |
| 511 | + min: o.millisecMin, |
| 512 | + max: millisecMax, |
| 513 | + step: o.stepMillisec, |
| 514 | + slide: function(event, ui) { |
| 515 | + tp_inst.millisec_slider.slider( "option", "value", ui.value); |
| 516 | + tp_inst._onTimeChange(); |
| 517 | + } |
| 518 | + }); |
| 519 | + |
| 520 | + this.timezone_select = $tp.find('#ui_tpicker_timezone_'+ dp_id).append('<select></select>').find("select"); |
| 521 | + $.fn.append.apply(this.timezone_select, |
| 522 | + $.map(o.timezoneList, function(val, idx) { |
| 523 | + return $("<option />") |
| 524 | + .val(typeof val == "object" ? val.value : val) |
| 525 | + .text(typeof val == "object" ? val.label : val); |
| 526 | + }) |
| 527 | + ); |
| 528 | + this.timezone_select.val((typeof this.timezone != "undefined" && this.timezone != null && this.timezone != "") ? this.timezone : o.timezone); |
| 529 | + this.timezone_select.change(function() { |
| 530 | + tp_inst._onTimeChange(); |
| 531 | + }); |
| 532 | + |
| 533 | + // Add grid functionality |
| 534 | + if (o.showHour && o.hourGrid > 0) { |
| 535 | + size = 100 * hourGridSize * o.hourGrid / (hourMax - o.hourMin); |
| 536 | + |
| 537 | + $tp.find(".ui_tpicker_hour table").css({ |
| 538 | + width: size + "%", |
| 539 | + marginLeft: (size / (-2 * hourGridSize)) + "%", |
| 540 | + borderCollapse: 'collapse' |
| 541 | + }).find("td").each( function(index) { |
| 542 | + $(this).click(function() { |
| 543 | + var h = $(this).html(); |
| 544 | + if(o.ampm) { |
| 545 | + var ap = h.substring(2).toLowerCase(), |
| 546 | + aph = parseInt(h.substring(0,2), 10); |
| 547 | + if (ap == 'a') { |
| 548 | + if (aph == 12) h = 0; |
| 549 | + else h = aph; |
| 550 | + } else if (aph == 12) h = 12; |
| 551 | + else h = aph + 12; |
| 552 | + } |
| 553 | + tp_inst.hour_slider.slider("option", "value", h); |
| 554 | + tp_inst._onTimeChange(); |
| 555 | + tp_inst._onSelectHandler(); |
| 556 | + }).css({ |
| 557 | + cursor: 'pointer', |
| 558 | + width: (100 / hourGridSize) + '%', |
| 559 | + textAlign: 'center', |
| 560 | + overflow: 'hidden' |
| 561 | + }); |
| 562 | + }); |
| 563 | + } |
| 564 | + |
| 565 | + if (o.showMinute && o.minuteGrid > 0) { |
| 566 | + size = 100 * minuteGridSize * o.minuteGrid / (minMax - o.minuteMin); |
| 567 | + $tp.find(".ui_tpicker_minute table").css({ |
| 568 | + width: size + "%", |
| 569 | + marginLeft: (size / (-2 * minuteGridSize)) + "%", |
| 570 | + borderCollapse: 'collapse' |
| 571 | + }).find("td").each(function(index) { |
| 572 | + $(this).click(function() { |
| 573 | + tp_inst.minute_slider.slider("option", "value", $(this).html()); |
| 574 | + tp_inst._onTimeChange(); |
| 575 | + tp_inst._onSelectHandler(); |
| 576 | + }).css({ |
| 577 | + cursor: 'pointer', |
| 578 | + width: (100 / minuteGridSize) + '%', |
| 579 | + textAlign: 'center', |
| 580 | + overflow: 'hidden' |
| 581 | + }); |
| 582 | + }); |
| 583 | + } |
| 584 | + |
| 585 | + if (o.showSecond && o.secondGrid > 0) { |
| 586 | + $tp.find(".ui_tpicker_second table").css({ |
| 587 | + width: size + "%", |
| 588 | + marginLeft: (size / (-2 * secondGridSize)) + "%", |
| 589 | + borderCollapse: 'collapse' |
| 590 | + }).find("td").each(function(index) { |
| 591 | + $(this).click(function() { |
| 592 | + tp_inst.second_slider.slider("option", "value", $(this).html()); |
| 593 | + tp_inst._onTimeChange(); |
| 594 | + tp_inst._onSelectHandler(); |
| 595 | + }).css({ |
| 596 | + cursor: 'pointer', |
| 597 | + width: (100 / secondGridSize) + '%', |
| 598 | + textAlign: 'center', |
| 599 | + overflow: 'hidden' |
| 600 | + }); |
| 601 | + }); |
| 602 | + } |
| 603 | + |
| 604 | + if (o.showMillisec && o.millisecGrid > 0) { |
| 605 | + $tp.find(".ui_tpicker_millisec table").css({ |
| 606 | + width: size + "%", |
| 607 | + marginLeft: (size / (-2 * millisecGridSize)) + "%", |
| 608 | + borderCollapse: 'collapse' |
| 609 | + }).find("td").each(function(index) { |
| 610 | + $(this).click(function() { |
| 611 | + tp_inst.millisec_slider.slider("option", "value", $(this).html()); |
| 612 | + tp_inst._onTimeChange(); |
| 613 | + tp_inst._onSelectHandler(); |
| 614 | + }).css({ |
| 615 | + cursor: 'pointer', |
| 616 | + width: (100 / millisecGridSize) + '%', |
| 617 | + textAlign: 'center', |
| 618 | + overflow: 'hidden' |
| 619 | + }); |
| 620 | + }); |
| 621 | + } |
| 622 | + |
| 623 | + var $buttonPanel = $dp.find('.ui-datepicker-buttonpane'); |
| 624 | + if ($buttonPanel.length) $buttonPanel.before($tp); |
| 625 | + else $dp.append($tp); |
| 626 | + |
| 627 | + this.$timeObj = $tp.find('#ui_tpicker_time_'+ dp_id); |
| 628 | + |
| 629 | + if (this.inst !== null) { |
| 630 | + var timeDefined = this.timeDefined; |
| 631 | + this._onTimeChange(); |
| 632 | + this.timeDefined = timeDefined; |
| 633 | + } |
| 634 | + |
| 635 | + //Emulate datepicker onSelect behavior. Call on slidestop. |
| 636 | + var onSelectDelegate = function() { |
| 637 | + tp_inst._onSelectHandler(); |
| 638 | + }; |
| 639 | + this.hour_slider.bind('slidestop',onSelectDelegate); |
| 640 | + this.minute_slider.bind('slidestop',onSelectDelegate); |
| 641 | + this.second_slider.bind('slidestop',onSelectDelegate); |
| 642 | + this.millisec_slider.bind('slidestop',onSelectDelegate); |
| 643 | + } |
| 644 | + }, |
| 645 | + |
| 646 | + //######################################################################## |
| 647 | + // This function tries to limit the ability to go outside the |
| 648 | + // min/max date range |
| 649 | + //######################################################################## |
| 650 | + _limitMinMaxDateTime: function(dp_inst, adjustSliders){ |
| 651 | + var o = this._defaults, |
| 652 | + dp_date = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay); |
| 653 | + |
| 654 | + if(!this._defaults.showTimepicker) return; // No time so nothing to check here |
| 655 | + |
| 656 | + if($.datepicker._get(dp_inst, 'minDateTime') !== null && $.datepicker._get(dp_inst, 'minDateTime') !== undefined && dp_date){ |
| 657 | + var minDateTime = $.datepicker._get(dp_inst, 'minDateTime'), |
| 658 | + minDateTimeDate = new Date(minDateTime.getFullYear(), minDateTime.getMonth(), minDateTime.getDate(), 0, 0, 0, 0); |
| 659 | + |
| 660 | + if(this.hourMinOriginal === null || this.minuteMinOriginal === null || this.secondMinOriginal === null || this.millisecMinOriginal === null){ |
| 661 | + this.hourMinOriginal = o.hourMin; |
| 662 | + this.minuteMinOriginal = o.minuteMin; |
| 663 | + this.secondMinOriginal = o.secondMin; |
| 664 | + this.millisecMinOriginal = o.millisecMin; |
| 665 | + } |
| 666 | + |
| 667 | + if(dp_inst.settings.timeOnly || minDateTimeDate.getTime() == dp_date.getTime()) { |
| 668 | + this._defaults.hourMin = minDateTime.getHours(); |
| 669 | + if (this.hour <= this._defaults.hourMin) { |
| 670 | + this.hour = this._defaults.hourMin; |
| 671 | + this._defaults.minuteMin = minDateTime.getMinutes(); |
| 672 | + if (this.minute <= this._defaults.minuteMin) { |
| 673 | + this.minute = this._defaults.minuteMin; |
| 674 | + this._defaults.secondMin = minDateTime.getSeconds(); |
| 675 | + } else if (this.second <= this._defaults.secondMin){ |
| 676 | + this.second = this._defaults.secondMin; |
| 677 | + this._defaults.millisecMin = minDateTime.getMilliseconds(); |
| 678 | + } else { |
| 679 | + if(this.millisec < this._defaults.millisecMin) |
| 680 | + this.millisec = this._defaults.millisecMin; |
| 681 | + this._defaults.millisecMin = this.millisecMinOriginal; |
| 682 | + } |
| 683 | + } else { |
| 684 | + this._defaults.minuteMin = this.minuteMinOriginal; |
| 685 | + this._defaults.secondMin = this.secondMinOriginal; |
| 686 | + this._defaults.millisecMin = this.millisecMinOriginal; |
| 687 | + } |
| 688 | + }else{ |
| 689 | + this._defaults.hourMin = this.hourMinOriginal; |
| 690 | + this._defaults.minuteMin = this.minuteMinOriginal; |
| 691 | + this._defaults.secondMin = this.secondMinOriginal; |
| 692 | + this._defaults.millisecMin = this.millisecMinOriginal; |
| 693 | + } |
| 694 | + } |
| 695 | + |
| 696 | + if($.datepicker._get(dp_inst, 'maxDateTime') !== null && $.datepicker._get(dp_inst, 'maxDateTime') !== undefined && dp_date){ |
| 697 | + var maxDateTime = $.datepicker._get(dp_inst, 'maxDateTime'), |
| 698 | + maxDateTimeDate = new Date(maxDateTime.getFullYear(), maxDateTime.getMonth(), maxDateTime.getDate(), 0, 0, 0, 0); |
| 699 | + |
| 700 | + if(this.hourMaxOriginal === null || this.minuteMaxOriginal === null || this.secondMaxOriginal === null){ |
| 701 | + this.hourMaxOriginal = o.hourMax; |
| 702 | + this.minuteMaxOriginal = o.minuteMax; |
| 703 | + this.secondMaxOriginal = o.secondMax; |
| 704 | + this.millisecMaxOriginal = o.millisecMax; |
| 705 | + } |
| 706 | + |
| 707 | + if(dp_inst.settings.timeOnly || maxDateTimeDate.getTime() == dp_date.getTime()){ |
| 708 | + this._defaults.hourMax = maxDateTime.getHours(); |
| 709 | + if (this.hour >= this._defaults.hourMax) { |
| 710 | + this.hour = this._defaults.hourMax; |
| 711 | + this._defaults.minuteMax = maxDateTime.getMinutes(); |
| 712 | + if (this.minute >= this._defaults.minuteMax) { |
| 713 | + this.minute = this._defaults.minuteMax; |
| 714 | + this._defaults.secondMax = maxDateTime.getSeconds(); |
| 715 | + } else if (this.second >= this._defaults.secondMax) { |
| 716 | + this.second = this._defaults.secondMax; |
| 717 | + this._defaults.millisecMax = maxDateTime.getMilliseconds(); |
| 718 | + } else { |
| 719 | + if(this.millisec > this._defaults.millisecMax) this.millisec = this._defaults.millisecMax; |
| 720 | + this._defaults.millisecMax = this.millisecMaxOriginal; |
| 721 | + } |
| 722 | + } else { |
| 723 | + this._defaults.minuteMax = this.minuteMaxOriginal; |
| 724 | + this._defaults.secondMax = this.secondMaxOriginal; |
| 725 | + this._defaults.millisecMax = this.millisecMaxOriginal; |
| 726 | + } |
| 727 | + }else{ |
| 728 | + this._defaults.hourMax = this.hourMaxOriginal; |
| 729 | + this._defaults.minuteMax = this.minuteMaxOriginal; |
| 730 | + this._defaults.secondMax = this.secondMaxOriginal; |
| 731 | + this._defaults.millisecMax = this.millisecMaxOriginal; |
| 732 | + } |
| 733 | + } |
| 734 | + |
| 735 | + if(adjustSliders !== undefined && adjustSliders === true){ |
| 736 | + var hourMax = (this._defaults.hourMax - ((this._defaults.hourMax - this._defaults.hourMin) % this._defaults.stepHour)).toFixed(0), |
| 737 | + minMax = (this._defaults.minuteMax - ((this._defaults.minuteMax - this._defaults.minuteMin) % this._defaults.stepMinute)).toFixed(0), |
| 738 | + secMax = (this._defaults.secondMax - ((this._defaults.secondMax - this._defaults.secondMin) % this._defaults.stepSecond)).toFixed(0), |
| 739 | + millisecMax = (this._defaults.millisecMax - ((this._defaults.millisecMax - this._defaults.millisecMin) % this._defaults.stepMillisec)).toFixed(0); |
| 740 | + |
| 741 | + if(this.hour_slider) |
| 742 | + this.hour_slider.slider("option", { min: this._defaults.hourMin, max: hourMax }).slider('value', this.hour); |
| 743 | + if(this.minute_slider) |
| 744 | + this.minute_slider.slider("option", { min: this._defaults.minuteMin, max: minMax }).slider('value', this.minute); |
| 745 | + if(this.second_slider) |
| 746 | + this.second_slider.slider("option", { min: this._defaults.secondMin, max: secMax }).slider('value', this.second); |
| 747 | + if(this.millisec_slider) |
| 748 | + this.millisec_slider.slider("option", { min: this._defaults.millisecMin, max: millisecMax }).slider('value', this.millisec); |
| 749 | + } |
| 750 | + |
| 751 | + }, |
| 752 | + |
| 753 | + |
| 754 | + //######################################################################## |
| 755 | + // when a slider moves, set the internal time... |
| 756 | + // on time change is also called when the time is updated in the text field |
| 757 | + //######################################################################## |
| 758 | + _onTimeChange: function() { |
| 759 | + var hour = (this.hour_slider) ? this.hour_slider.slider('value') : false, |
| 760 | + minute = (this.minute_slider) ? this.minute_slider.slider('value') : false, |
| 761 | + second = (this.second_slider) ? this.second_slider.slider('value') : false, |
| 762 | + millisec = (this.millisec_slider) ? this.millisec_slider.slider('value') : false, |
| 763 | + timezone = (this.timezone_select) ? this.timezone_select.val() : false, |
| 764 | + o = this._defaults; |
| 765 | + |
| 766 | + if (typeof(hour) == 'object') hour = false; |
| 767 | + if (typeof(minute) == 'object') minute = false; |
| 768 | + if (typeof(second) == 'object') second = false; |
| 769 | + if (typeof(millisec) == 'object') millisec = false; |
| 770 | + if (typeof(timezone) == 'object') timezone = false; |
| 771 | + |
| 772 | + if (hour !== false) hour = parseInt(hour,10); |
| 773 | + if (minute !== false) minute = parseInt(minute,10); |
| 774 | + if (second !== false) second = parseInt(second,10); |
| 775 | + if (millisec !== false) millisec = parseInt(millisec,10); |
| 776 | + |
| 777 | + var ampm = o[hour < 12 ? 'amNames' : 'pmNames'][0]; |
| 778 | + |
| 779 | + // If the update was done in the input field, the input field should not be updated. |
| 780 | + // If the update was done using the sliders, update the input field. |
| 781 | + var hasChanged = (hour != this.hour || minute != this.minute |
| 782 | + || second != this.second || millisec != this.millisec |
| 783 | + || (this.ampm.length > 0 |
| 784 | + && (hour < 12) != ($.inArray(this.ampm.toUpperCase(), this.amNames) !== -1)) |
| 785 | + || timezone != this.timezone); |
| 786 | + |
| 787 | + if (hasChanged) { |
| 788 | + |
| 789 | + if (hour !== false)this.hour = hour; |
| 790 | + if (minute !== false) this.minute = minute; |
| 791 | + if (second !== false) this.second = second; |
| 792 | + if (millisec !== false) this.millisec = millisec; |
| 793 | + if (timezone !== false) this.timezone = timezone; |
| 794 | + |
| 795 | + if (!this.inst) this.inst = $.datepicker._getInst(this.$input[0]); |
| 796 | + |
| 797 | + this._limitMinMaxDateTime(this.inst, true); |
| 798 | + } |
| 799 | + if (o.ampm) this.ampm = ampm; |
| 800 | + |
| 801 | + this._formatTime(); |
| 802 | + if (this.$timeObj) this.$timeObj.text(this.formattedTime + o.timeSuffix); |
| 803 | + this.timeDefined = true; |
| 804 | + if (hasChanged) this._updateDateTime(); |
| 805 | + }, |
| 806 | + |
| 807 | + //######################################################################## |
| 808 | + // call custom onSelect. |
| 809 | + // bind to sliders slidestop, and grid click. |
| 810 | + //######################################################################## |
| 811 | + _onSelectHandler: function() { |
| 812 | + var onSelect = this._defaults.onSelect; |
| 813 | + var inputEl = this.$input ? this.$input[0] : null; |
| 814 | + if (onSelect && inputEl) { |
| 815 | + onSelect.apply(inputEl, [this.formattedDateTime, this]); |
| 816 | + } |
| 817 | + }, |
| 818 | + |
| 819 | + //######################################################################## |
| 820 | + // format the time all pretty... |
| 821 | + //######################################################################## |
| 822 | + _formatTime: function(time, format, ampm) { |
| 823 | + if (ampm == undefined) ampm = this._defaults.ampm; |
| 824 | + time = time || { hour: this.hour, minute: this.minute, second: this.second, millisec: this.millisec, ampm: this.ampm, timezone: this.timezone }; |
| 825 | + var tmptime = (format || this._defaults.timeFormat).toString(); |
| 826 | + |
| 827 | + var hour = parseInt(time.hour, 10); |
| 828 | + if (ampm) { |
| 829 | + if (!$.inArray(time.ampm.toUpperCase(), this.amNames) !== -1) |
| 830 | + hour = hour % 12; |
| 831 | + if (hour === 0) |
| 832 | + hour = 12; |
| 833 | + } |
| 834 | + tmptime = tmptime.replace(/(?:hh?|mm?|ss?|[tT]{1,2}|[lz])/g, function(match) { |
| 835 | + switch (match.toLowerCase()) { |
| 836 | + case 'hh': return ('0' + hour).slice(-2); |
| 837 | + case 'h': return hour; |
| 838 | + case 'mm': return ('0' + time.minute).slice(-2); |
| 839 | + case 'm': return time.minute; |
| 840 | + case 'ss': return ('0' + time.second).slice(-2); |
| 841 | + case 's': return time.second; |
| 842 | + case 'l': return ('00' + time.millisec).slice(-3); |
| 843 | + case 'z': return time.timezone; |
| 844 | + case 't': case 'tt': |
| 845 | + if (ampm) { |
| 846 | + var _ampm = time.ampm; |
| 847 | + if (match.length == 1) |
| 848 | + _ampm = _ampm.charAt(0); |
| 849 | + return match.charAt(0) == 'T' ? _ampm.toUpperCase() : _ampm.toLowerCase(); |
| 850 | + } |
| 851 | + return ''; |
| 852 | + } |
| 853 | + }); |
| 854 | + |
| 855 | + if (arguments.length) return tmptime; |
| 856 | + else this.formattedTime = tmptime; |
| 857 | + }, |
| 858 | + |
| 859 | + //######################################################################## |
| 860 | + // update our input with the new date time.. |
| 861 | + //######################################################################## |
| 862 | + _updateDateTime: function(dp_inst) { |
| 863 | + dp_inst = this.inst || dp_inst, |
| 864 | + dt = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay), |
| 865 | + dateFmt = $.datepicker._get(dp_inst, 'dateFormat'), |
| 866 | + formatCfg = $.datepicker._getFormatConfig(dp_inst), |
| 867 | + timeAvailable = dt !== null && this.timeDefined; |
| 868 | + this.formattedDate = $.datepicker.formatDate(dateFmt, (dt === null ? new Date() : dt), formatCfg); |
| 869 | + var formattedDateTime = this.formattedDate; |
| 870 | + if (dp_inst.lastVal !== undefined && (dp_inst.lastVal.length > 0 && this.$input.val().length === 0)) |
| 871 | + return; |
| 872 | + |
| 873 | + if (this._defaults.timeOnly === true) { |
| 874 | + formattedDateTime = this.formattedTime; |
| 875 | + } else if (this._defaults.timeOnly !== true && (this._defaults.alwaysSetTime || timeAvailable)) { |
| 876 | + formattedDateTime += this._defaults.separator + this.formattedTime + this._defaults.timeSuffix; |
| 877 | + } |
| 878 | + |
| 879 | + this.formattedDateTime = formattedDateTime; |
| 880 | + |
| 881 | + if(!this._defaults.showTimepicker) { |
| 882 | + this.$input.val(this.formattedDate); |
| 883 | + } else if (this.$altInput && this._defaults.altFieldTimeOnly === true) { |
| 884 | + this.$altInput.val(this.formattedTime); |
| 885 | + this.$input.val(this.formattedDate); |
| 886 | + } else if(this.$altInput) { |
| 887 | + this.$altInput.val(formattedDateTime); |
| 888 | + this.$input.val(formattedDateTime); |
| 889 | + } else { |
| 890 | + this.$input.val(formattedDateTime); |
| 891 | + } |
| 892 | + |
| 893 | + this.$input.trigger("change"); |
| 894 | + } |
| 895 | + |
| 896 | +}); |
| 897 | + |
| 898 | +$.fn.extend({ |
| 899 | + //######################################################################## |
| 900 | + // shorthand just to use timepicker.. |
| 901 | + //######################################################################## |
| 902 | + timepicker: function(o) { |
| 903 | + o = o || {}; |
| 904 | + var tmp_args = arguments; |
| 905 | + |
| 906 | + if (typeof o == 'object') tmp_args[0] = $.extend(o, { timeOnly: true }); |
| 907 | + |
| 908 | + return $(this).each(function() { |
| 909 | + $.fn.datetimepicker.apply($(this), tmp_args); |
| 910 | + }); |
| 911 | + }, |
| 912 | + |
| 913 | + //######################################################################## |
| 914 | + // extend timepicker to datepicker |
| 915 | + //######################################################################## |
| 916 | + datetimepicker: function(o) { |
| 917 | + o = o || {}; |
| 918 | + var $input = this, |
| 919 | + tmp_args = arguments; |
| 920 | + |
| 921 | + if (typeof(o) == 'string'){ |
| 922 | + if(o == 'getDate') |
| 923 | + return $.fn.datepicker.apply($(this[0]), tmp_args); |
| 924 | + else |
| 925 | + return this.each(function() { |
| 926 | + var $t = $(this); |
| 927 | + $t.datepicker.apply($t, tmp_args); |
| 928 | + }); |
| 929 | + } |
| 930 | + else |
| 931 | + return this.each(function() { |
| 932 | + var $t = $(this); |
| 933 | + $t.datepicker($.timepicker._newInst($t, o)._defaults); |
| 934 | + }); |
| 935 | + } |
| 936 | +}); |
| 937 | + |
| 938 | +//######################################################################## |
| 939 | +// the bad hack :/ override datepicker so it doesnt close on select |
| 940 | +// inspired: http://stackoverflow.com/questions/1252512/jquery-datepicker-prevent-closing-picker-when-clicking-a-date/1762378#1762378 |
| 941 | +//######################################################################## |
| 942 | +$.datepicker._base_selectDate = $.datepicker._selectDate; |
| 943 | +$.datepicker._selectDate = function (id, dateStr) { |
| 944 | + var inst = this._getInst($(id)[0]), |
| 945 | + tp_inst = this._get(inst, 'timepicker'); |
| 946 | + |
| 947 | + if (tp_inst) { |
| 948 | + tp_inst._limitMinMaxDateTime(inst, true); |
| 949 | + inst.inline = inst.stay_open = true; |
| 950 | + //This way the onSelect handler called from calendarpicker get the full dateTime |
| 951 | + this._base_selectDate(id, dateStr); |
| 952 | + inst.inline = inst.stay_open = false; |
| 953 | + this._notifyChange(inst); |
| 954 | + this._updateDatepicker(inst); |
| 955 | + } |
| 956 | + else this._base_selectDate(id, dateStr); |
| 957 | +}; |
| 958 | + |
| 959 | +//############################################################################################# |
| 960 | +// second bad hack :/ override datepicker so it triggers an event when changing the input field |
| 961 | +// and does not redraw the datepicker on every selectDate event |
| 962 | +//############################################################################################# |
| 963 | +$.datepicker._base_updateDatepicker = $.datepicker._updateDatepicker; |
| 964 | +$.datepicker._updateDatepicker = function(inst) { |
| 965 | + |
| 966 | + // don't popup the datepicker if there is another instance already opened |
| 967 | + var input = inst.input[0]; |
| 968 | + if($.datepicker._curInst && |
| 969 | + $.datepicker._curInst != inst && |
| 970 | + $.datepicker._datepickerShowing && |
| 971 | + $.datepicker._lastInput != input) { |
| 972 | + return; |
| 973 | + } |
| 974 | + |
| 975 | + if (typeof(inst.stay_open) !== 'boolean' || inst.stay_open === false) { |
| 976 | + |
| 977 | + this._base_updateDatepicker(inst); |
| 978 | + |
| 979 | + // Reload the time control when changing something in the input text field. |
| 980 | + var tp_inst = this._get(inst, 'timepicker'); |
| 981 | + if(tp_inst) tp_inst._addTimePicker(inst); |
| 982 | + } |
| 983 | +}; |
| 984 | + |
| 985 | +//####################################################################################### |
| 986 | +// third bad hack :/ override datepicker so it allows spaces and colon in the input field |
| 987 | +//####################################################################################### |
| 988 | +$.datepicker._base_doKeyPress = $.datepicker._doKeyPress; |
| 989 | +$.datepicker._doKeyPress = function(event) { |
| 990 | + var inst = $.datepicker._getInst(event.target), |
| 991 | + tp_inst = $.datepicker._get(inst, 'timepicker'); |
| 992 | + |
| 993 | + if (tp_inst) { |
| 994 | + if ($.datepicker._get(inst, 'constrainInput')) { |
| 995 | + var ampm = tp_inst._defaults.ampm, |
| 996 | + dateChars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')), |
| 997 | + datetimeChars = tp_inst._defaults.timeFormat.toString() |
| 998 | + .replace(/[hms]/g, '') |
| 999 | + .replace(/TT/g, ampm ? 'APM' : '') |
| 1000 | + .replace(/Tt/g, ampm ? 'AaPpMm' : '') |
| 1001 | + .replace(/tT/g, ampm ? 'AaPpMm' : '') |
| 1002 | + .replace(/T/g, ampm ? 'AP' : '') |
| 1003 | + .replace(/tt/g, ampm ? 'apm' : '') |
| 1004 | + .replace(/t/g, ampm ? 'ap' : '') + |
| 1005 | + " " + |
| 1006 | + tp_inst._defaults.separator + |
| 1007 | + tp_inst._defaults.timeSuffix + |
| 1008 | + (tp_inst._defaults.showTimezone ? tp_inst._defaults.timezoneList.join('') : '') + |
| 1009 | + (tp_inst._defaults.amNames.join('')) + |
| 1010 | + (tp_inst._defaults.pmNames.join('')) + |
| 1011 | + dateChars, |
| 1012 | + chr = String.fromCharCode(event.charCode === undefined ? event.keyCode : event.charCode); |
| 1013 | + return event.ctrlKey || (chr < ' ' || !dateChars || datetimeChars.indexOf(chr) > -1); |
| 1014 | + } |
| 1015 | + } |
| 1016 | + |
| 1017 | + return $.datepicker._base_doKeyPress(event); |
| 1018 | +}; |
| 1019 | + |
| 1020 | +//####################################################################################### |
| 1021 | +// Override key up event to sync manual input changes. |
| 1022 | +//####################################################################################### |
| 1023 | +$.datepicker._base_doKeyUp = $.datepicker._doKeyUp; |
| 1024 | +$.datepicker._doKeyUp = function (event) { |
| 1025 | + var inst = $.datepicker._getInst(event.target), |
| 1026 | + tp_inst = $.datepicker._get(inst, 'timepicker'); |
| 1027 | + |
| 1028 | + if (tp_inst) { |
| 1029 | + if (tp_inst._defaults.timeOnly && (inst.input.val() != inst.lastVal)) { |
| 1030 | + try { |
| 1031 | + $.datepicker._updateDatepicker(inst); |
| 1032 | + } |
| 1033 | + catch (err) { |
| 1034 | + $.datepicker.log(err); |
| 1035 | + } |
| 1036 | + } |
| 1037 | + } |
| 1038 | + |
| 1039 | + return $.datepicker._base_doKeyUp(event); |
| 1040 | +}; |
| 1041 | + |
| 1042 | +//####################################################################################### |
| 1043 | +// override "Today" button to also grab the time. |
| 1044 | +//####################################################################################### |
| 1045 | +$.datepicker._base_gotoToday = $.datepicker._gotoToday; |
| 1046 | +$.datepicker._gotoToday = function(id) { |
| 1047 | + var inst = this._getInst($(id)[0]), |
| 1048 | + $dp = inst.dpDiv; |
| 1049 | + this._base_gotoToday(id); |
| 1050 | + var now = new Date(); |
| 1051 | + var tp_inst = this._get(inst, 'timepicker'); |
| 1052 | + if (tp_inst._defaults.showTimezone && tp_inst.timezone_select) { |
| 1053 | + var tzoffset = now.getTimezoneOffset(); // If +0100, returns -60 |
| 1054 | + var tzsign = tzoffset > 0 ? '-' : '+'; |
| 1055 | + tzoffset = Math.abs(tzoffset); |
| 1056 | + var tzmin = tzoffset % 60 |
| 1057 | + tzoffset = tzsign + ('0' + (tzoffset - tzmin) / 60).slice(-2) + ('0' + tzmin).slice(-2); |
| 1058 | + if (tp_inst._defaults.timezoneIso8609) |
| 1059 | + tzoffset = tzoffset.substring(0, 3) + ':' + tzoffset.substring(3); |
| 1060 | + tp_inst.timezone_select.val(tzoffset); |
| 1061 | + } |
| 1062 | + this._setTime(inst, now); |
| 1063 | + $( '.ui-datepicker-today', $dp).click(); |
| 1064 | +}; |
| 1065 | + |
| 1066 | +//####################################################################################### |
| 1067 | +// Disable & enable the Time in the datetimepicker |
| 1068 | +//####################################################################################### |
| 1069 | +$.datepicker._disableTimepickerDatepicker = function(target, date, withDate) { |
| 1070 | + var inst = this._getInst(target), |
| 1071 | + tp_inst = this._get(inst, 'timepicker'); |
| 1072 | + $(target).datepicker('getDate'); // Init selected[Year|Month|Day] |
| 1073 | + if (tp_inst) { |
| 1074 | + tp_inst._defaults.showTimepicker = false; |
| 1075 | + tp_inst._updateDateTime(inst); |
| 1076 | + } |
| 1077 | +}; |
| 1078 | + |
| 1079 | +$.datepicker._enableTimepickerDatepicker = function(target, date, withDate) { |
| 1080 | + var inst = this._getInst(target), |
| 1081 | + tp_inst = this._get(inst, 'timepicker'); |
| 1082 | + $(target).datepicker('getDate'); // Init selected[Year|Month|Day] |
| 1083 | + if (tp_inst) { |
| 1084 | + tp_inst._defaults.showTimepicker = true; |
| 1085 | + tp_inst._addTimePicker(inst); // Could be disabled on page load |
| 1086 | + tp_inst._updateDateTime(inst); |
| 1087 | + } |
| 1088 | +}; |
| 1089 | + |
| 1090 | +//####################################################################################### |
| 1091 | +// Create our own set time function |
| 1092 | +//####################################################################################### |
| 1093 | +$.datepicker._setTime = function(inst, date) { |
| 1094 | + var tp_inst = this._get(inst, 'timepicker'); |
| 1095 | + if (tp_inst) { |
| 1096 | + var defaults = tp_inst._defaults, |
| 1097 | + // calling _setTime with no date sets time to defaults |
| 1098 | + hour = date ? date.getHours() : defaults.hour, |
| 1099 | + minute = date ? date.getMinutes() : defaults.minute, |
| 1100 | + second = date ? date.getSeconds() : defaults.second, |
| 1101 | + millisec = date ? date.getMilliseconds() : defaults.millisec; |
| 1102 | + |
| 1103 | + //check if within min/max times.. |
| 1104 | + if ((hour < defaults.hourMin || hour > defaults.hourMax) || (minute < defaults.minuteMin || minute > defaults.minuteMax) || (second < defaults.secondMin || second > defaults.secondMax) || (millisec < defaults.millisecMin || millisec > defaults.millisecMax)) { |
| 1105 | + hour = defaults.hourMin; |
| 1106 | + minute = defaults.minuteMin; |
| 1107 | + second = defaults.secondMin; |
| 1108 | + millisec = defaults.millisecMin; |
| 1109 | + } |
| 1110 | + |
| 1111 | + tp_inst.hour = hour; |
| 1112 | + tp_inst.minute = minute; |
| 1113 | + tp_inst.second = second; |
| 1114 | + tp_inst.millisec = millisec; |
| 1115 | + |
| 1116 | + if (tp_inst.hour_slider) tp_inst.hour_slider.slider('value', hour); |
| 1117 | + if (tp_inst.minute_slider) tp_inst.minute_slider.slider('value', minute); |
| 1118 | + if (tp_inst.second_slider) tp_inst.second_slider.slider('value', second); |
| 1119 | + if (tp_inst.millisec_slider) tp_inst.millisec_slider.slider('value', millisec); |
| 1120 | + |
| 1121 | + tp_inst._onTimeChange(); |
| 1122 | + tp_inst._updateDateTime(inst); |
| 1123 | + } |
| 1124 | +}; |
| 1125 | + |
| 1126 | +//####################################################################################### |
| 1127 | +// Create new public method to set only time, callable as $().datepicker('setTime', date) |
| 1128 | +//####################################################################################### |
| 1129 | +$.datepicker._setTimeDatepicker = function(target, date, withDate) { |
| 1130 | + var inst = this._getInst(target), |
| 1131 | + tp_inst = this._get(inst, 'timepicker'); |
| 1132 | + |
| 1133 | + if (tp_inst) { |
| 1134 | + this._setDateFromField(inst); |
| 1135 | + var tp_date; |
| 1136 | + if (date) { |
| 1137 | + if (typeof date == "string") { |
| 1138 | + tp_inst._parseTime(date, withDate); |
| 1139 | + tp_date = new Date(); |
| 1140 | + tp_date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec); |
| 1141 | + } |
| 1142 | + else tp_date = new Date(date.getTime()); |
| 1143 | + if (tp_date.toString() == 'Invalid Date') tp_date = undefined; |
| 1144 | + this._setTime(inst, tp_date); |
| 1145 | + } |
| 1146 | + } |
| 1147 | + |
| 1148 | +}; |
| 1149 | + |
| 1150 | +//####################################################################################### |
| 1151 | +// override setDate() to allow setting time too within Date object |
| 1152 | +//####################################################################################### |
| 1153 | +$.datepicker._base_setDateDatepicker = $.datepicker._setDateDatepicker; |
| 1154 | +$.datepicker._setDateDatepicker = function(target, date) { |
| 1155 | + var inst = this._getInst(target), |
| 1156 | + tp_date = (date instanceof Date) ? new Date(date.getTime()) : date; |
| 1157 | + |
| 1158 | + this._updateDatepicker(inst); |
| 1159 | + this._base_setDateDatepicker.apply(this, arguments); |
| 1160 | + this._setTimeDatepicker(target, tp_date, true); |
| 1161 | +}; |
| 1162 | + |
| 1163 | +//####################################################################################### |
| 1164 | +// override getDate() to allow getting time too within Date object |
| 1165 | +//####################################################################################### |
| 1166 | +$.datepicker._base_getDateDatepicker = $.datepicker._getDateDatepicker; |
| 1167 | +$.datepicker._getDateDatepicker = function(target, noDefault) { |
| 1168 | + var inst = this._getInst(target), |
| 1169 | + tp_inst = this._get(inst, 'timepicker'); |
| 1170 | + |
| 1171 | + if (tp_inst) { |
| 1172 | + this._setDateFromField(inst, noDefault); |
| 1173 | + var date = this._getDate(inst); |
| 1174 | + if (date && tp_inst._parseTime($(target).val(), tp_inst.timeOnly)) date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec); |
| 1175 | + return date; |
| 1176 | + } |
| 1177 | + return this._base_getDateDatepicker(target, noDefault); |
| 1178 | +}; |
| 1179 | + |
| 1180 | +//####################################################################################### |
| 1181 | +// override parseDate() because UI 1.8.14 throws an error about "Extra characters" |
| 1182 | +// An option in datapicker to ignore extra format characters would be nicer. |
| 1183 | +//####################################################################################### |
| 1184 | +$.datepicker._base_parseDate = $.datepicker.parseDate; |
| 1185 | +$.datepicker.parseDate = function(format, value, settings) { |
| 1186 | + var date; |
| 1187 | + try { |
| 1188 | + date = this._base_parseDate(format, value, settings); |
| 1189 | + } catch (err) { |
| 1190 | + // Hack! The error message ends with a colon, a space, and |
| 1191 | + // the "extra" characters. We rely on that instead of |
| 1192 | + // attempting to perfectly reproduce the parsing algorithm. |
| 1193 | + date = this._base_parseDate(format, value.substring(0,value.length-(err.length-err.indexOf(':')-2)), settings); |
| 1194 | + } |
| 1195 | + return date; |
| 1196 | +}; |
| 1197 | + |
| 1198 | +//####################################################################################### |
| 1199 | +// override formatDate to set date with time to the input |
| 1200 | +//####################################################################################### |
| 1201 | +$.datepicker._base_formatDate=$.datepicker._formatDate; |
| 1202 | +$.datepicker._formatDate = function(inst, day, month, year){ |
| 1203 | + var tp_inst = this._get(inst, 'timepicker'); |
| 1204 | + if(tp_inst) |
| 1205 | + { |
| 1206 | + if(day) |
| 1207 | + var b = this._base_formatDate(inst, day, month, year); |
| 1208 | + tp_inst._updateDateTime(); |
| 1209 | + return tp_inst.$input.val(); |
| 1210 | + } |
| 1211 | + return this._base_formatDate(inst); |
| 1212 | +} |
| 1213 | + |
| 1214 | +//####################################################################################### |
| 1215 | +// override options setter to add time to maxDate(Time) and minDate(Time). MaxDate |
| 1216 | +//####################################################################################### |
| 1217 | +$.datepicker._base_optionDatepicker = $.datepicker._optionDatepicker; |
| 1218 | +$.datepicker._optionDatepicker = function(target, name, value) { |
| 1219 | + var inst = this._getInst(target), |
| 1220 | + tp_inst = this._get(inst, 'timepicker'); |
| 1221 | + if (tp_inst) { |
| 1222 | + var min,max,onselect; |
| 1223 | + if (typeof name == 'string') { // if min/max was set with the string |
| 1224 | + if (name==='minDate' || name==='minDateTime' ) |
| 1225 | + min = value; |
| 1226 | + else if (name==='maxDate' || name==='maxDateTime') |
| 1227 | + max = value; |
| 1228 | + else if (name==='onSelect') |
| 1229 | + onselect=value; |
| 1230 | + } else if (typeof name == 'object') { //if min/max was set with the JSON |
| 1231 | + if(name.minDate) |
| 1232 | + min = name.minDate; |
| 1233 | + else if (name.minDateTime) |
| 1234 | + min = name.minDateTime; |
| 1235 | + else if (name.maxDate) |
| 1236 | + max = name.maxDate; |
| 1237 | + else if (name.maxDateTime) |
| 1238 | + max = name.maxDateTime; |
| 1239 | + } |
| 1240 | + if(min){ //if min was set |
| 1241 | + if(min==0) |
| 1242 | + min=new Date(); |
| 1243 | + else |
| 1244 | + min= new Date(min); |
| 1245 | + |
| 1246 | + tp_inst._defaults.minDate = min; |
| 1247 | + tp_inst._defaults.minDateTime = min; |
| 1248 | + } else if (max){ //if max was set |
| 1249 | + if(max==0) |
| 1250 | + max=new Date(); |
| 1251 | + else |
| 1252 | + max= new Date(max); |
| 1253 | + tp_inst._defaults.maxDate = max; |
| 1254 | + tp_inst._defaults.maxDateTime = max; |
| 1255 | + } |
| 1256 | + else if (onselect) |
| 1257 | + tp_inst._defaults.onSelect=onselect; |
| 1258 | + } |
| 1259 | + this._base_optionDatepicker(target, name, value); |
| 1260 | +}; |
| 1261 | + |
| 1262 | +//####################################################################################### |
| 1263 | +// jQuery extend now ignores nulls! |
| 1264 | +//####################################################################################### |
| 1265 | +function extendRemove(target, props) { |
| 1266 | + $.extend(target, props); |
| 1267 | + for (var name in props) |
| 1268 | + if (props[name] === null || props[name] === undefined) |
| 1269 | + target[name] = props[name]; |
| 1270 | + return target; |
| 1271 | +} |
| 1272 | + |
| 1273 | +$.timepicker = new Timepicker(); // singleton instance |
| 1274 | +$.timepicker.version = "0.9.7"; |
| 1275 | + |
| 1276 | +})(jQuery); |
| 1277 | + |
Index: trunk/extensions/Contest/resources/contest.special.editcontest.js |
— | — | @@ -159,6 +159,11 @@ |
160 | 160 | } ); |
161 | 161 | } ); |
162 | 162 | |
| 163 | + $( '#contest-edit-end' ).datetimepicker( { |
| 164 | + minDate: new Date(), |
| 165 | + dateFormat: 'yy-mm-dd' |
| 166 | + } ); |
| 167 | + |
163 | 168 | } ); |
164 | 169 | |
165 | 170 | })( window.jQuery, window.mediaWiki ); |
Index: trunk/extensions/Contest/resources/jquery-ui-timepicker-addon.css |
— | — | @@ -0,0 +1,6 @@ |
| 2 | +/* css for timepicker */ |
| 3 | +.ui-timepicker-div .ui-widget-header{ margin-bottom: 8px; } |
| 4 | +.ui-timepicker-div dl{ text-align: left; } |
| 5 | +.ui-timepicker-div dl dt{ height: 25px; } |
| 6 | +.ui-timepicker-div dl dd{ margin: -25px 0 10px 65px; } |
| 7 | +.ui-timepicker-div td { font-size: 90%; } |
\ No newline at end of file |