├── LICENSE ├── README.md ├── index.html ├── jquery-clock-timepicker.js ├── jquery-clock-timepicker.min.js ├── package-lock.json └── package.json /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Andreas Marc Loeber 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Clock Timepicker Plugin for jQuery 2 | ================================== 3 | 4 | jquery-clock-timepicker screenshot 5 | 6 | [See a demo here](https://plugins.slyweb.ch/jquery-clock-timepicker) 7 | 8 | A free jQuery Plug-in to select the time with a clock inspired by the Android time picker. This plugin works on Desktop and Mobile phones. 9 | 10 | 11 | Requirements 12 | ------------ 13 | * [jQuery](https://jquery.com/) 14 | 15 | Note: You need the regular version of jQuery as the slim version does not include effects, which this library requires. 16 | 17 | 18 | Installation 19 | ------------ 20 | 21 | Install from [NPM](https://www.npmjs.com/package/jquery-clock-timepicker) as ```jquery-clock-timepicker```. 22 | 23 | ```npm install jquery-clock-timepicker``` 24 | 25 | 26 | Usage 27 | ----- 28 | 29 | ```javascript 30 | $('.your-time-field').clockTimePicker(options); 31 | ``` 32 | 33 | Include the file `jquery-clock-timepicker.min.js` in your page. There is no need of a CSS file. 34 | 35 | The Plug-in is customizable through the optional ```options``` object passed to the jQuery method, i.e. 36 | 37 | ```javascript 38 | $('.your-time-field').clockTimePicker({ 39 | duration: true, 40 | durationNegative: true, 41 | precision: 5, 42 | i18n: { 43 | cancelButton: 'Abbrechen' 44 | }, 45 | onAdjust: function(newVal, oldVal) { 46 | //... 47 | } 48 | }); 49 | ``` 50 | 51 | It is also possible to configure the ClockTimePicker element by using data attributes of the DOM element, i.e. 52 | 53 | ```html 54 | 55 | ``` 56 | 57 | You can combine the configuration by JavaScript and by the DOM data attributes. For example, you can use the JavaScript configuration to make a standard configuration 58 | for all your ClockTimePicker elements on the site and use the DOM data attributes to change configuration for individual elements. The data attributes have precedence 59 | over the JavaScript settings. 60 | 61 | If you want to set new options at runtime (after an input element already has been intialized), just call the function again with all desired options. 62 | 63 | If you want to dispose/destroy an initialized clock time picker element, please use the following code: 64 | 65 | ```javascript 66 | $('.your-time-field').clockTimePicker('dispose'); 67 | ``` 68 | 69 | If you want to change the value programmatically at runtime on an already initialized clock time picker element, use the following code: 70 | 71 | ```javascript 72 | $('.your-time-field').clockTimePicker('value', '08:00'); 73 | ``` 74 | 75 | Use the following code to show or hide a clock time picker programmatically: 76 | 77 | ```javascript 78 | $('.your-time-field').clockTimePicker('show'); 79 | $('.your-time-field').clockTimePicker('hide'); 80 | ``` 81 | 82 | 83 | 84 | Options 85 | ------- 86 | 87 | - **afternoonHoursInOuterCircle** 88 | Set this option to true to display the afternoon hours in the outer circle instead of the inner circle. 89 | *default: false* 90 | 91 | - **alwaysSelectHoursFirst** 92 | By default, if you click on the minutes part of your input field, the popup is opened to directly select the minutes. If you set this option to true, popup is always opened to select hours first before selecting the minutes. 93 | *default: false* 94 | 95 | - **autosize** 96 | Set this to true, if the width of the input field should be automatically adjusted to its content. 97 | *default: false* 98 | 99 | - **colors.buttonTextColor** 100 | The text color of the buttons display on the mobile phone. 101 | *default: '#0797FF'* 102 | 103 | - **colors.clockFaceColor** 104 | The color of the clock face. 105 | *default: '#EEEEEE'* 106 | 107 | - **colors.clockInnerCircleTextColor** 108 | The text color of the numbers displayed in the inner circle. 109 | *default: '#888888'* 110 | 111 | - **colors.clockInnerCircleUnselectableTextColor** 112 | The text color of the unselectable numbers displayed in the inner circle. (only used in combination with ```minimum``` and ```maximum``` option) 113 | *default: '#888888'* 114 | 115 | - **colors.clockOuterCircleTextColor** 116 | The text color of the numbers displayed in the outer circle. 117 | *default: '#000000'* 118 | 119 | - **colors.clockOuterCircleUnselectableTextColor** 120 | The text color of the unselectable numbers displayed in the outer circle. (only used in combination with ```minimum``` and ```maximum``` option) 121 | *default: '#000000'* 122 | 123 | - **colors.hoverCircleColor** 124 | The color of the circle when hovering over an hour or minute. 125 | *default: '#DDDDDD'* 126 | 127 | - **colors.popupBackgroundColor** 128 | The background color of the popup. 129 | *default: '#FFFFFF'* 130 | 131 | - **colors.popupHeaderBackgroundColor** 132 | The background color of the popup header displayed only on the mobile phone. 133 | *default: '#0797FF'* 134 | 135 | - **colors.popupHeaderTextColor** 136 | The text color of the popup header displayed only on the mobile phone. 137 | *default: '#FFFFFF'* 138 | 139 | - **colors.selectorColor** 140 | The color of the time selector. 141 | *default: '#0797FF'* 142 | 143 | - **colors.selectorNumberColor** 144 | The text color of the number that is selected. 145 | *default: '#FFFFFF'* 146 | 147 | - **contextmenu** 148 | If true, the browser's or a custom context menu is shown on right click. 149 | If false, the right click behaves like the left click and the clock is shown. 150 | *default: false* 151 | 152 | - **duration** 153 | If true, the hours can be greater than 23. 154 | *default: false* 155 | 156 | - **durationNegative** 157 | If true, the duration can be negative. This settings only has effect if the setting **duration** is set to true. 158 | *default: false* 159 | 160 | - **fonts.buttonFontSize** 161 | The font size of the buttons. These buttons are only displayed in the mobile version. 162 | *default: 20* 163 | 164 | - **fonts.clockInnerCircleFontSize** 165 | The font size of the numbers that are displayed in the inner circle. 166 | *default: 12* 167 | 168 | - **fonts.clockOuterCircleFontSize** 169 | The font size of the numbers that are displayed in the outer circle. 170 | *default: 14* 171 | 172 | - **fonts.fontFamily** 173 | The font family used to display the numbers. 174 | *default: 'Arial'* 175 | 176 | - **hideUnselectableNumbers** 177 | Set this option to true if you want to completely hide the unselectable numbers (in case you're using ```minimum``` and ```maximum``` option). 178 | *default: false* 179 | 180 | - **i18n.cancelButton** 181 | The name of the button to cancel the time change. Only displayed on mobile phones. 182 | *default: 'Cancel'* 183 | 184 | - **i18n.okButton** 185 | The name of the button to confirm the time change. Only displayed on mobile phones. 186 | *default: 'OK'* 187 | 188 | - **maximum** 189 | With this option you can define the maximum duration/time. Syntax: hh:mm, i.e. 8:30, 12:00, 24:00, 100:00, ... 190 | *default: '23:59'* 191 | 192 | - **minimum** 193 | With this option you can define the minimum duration/time. Syntax: hh:mm, i.e. 06:00, -10:00, -15:45, ... 194 | *default: '-23:59'* 195 | 196 | - **modeSwitchSpeed** 197 | The speed in milliseconds of the switch animation when changing between hour and minute selection. 198 | *default: 500* 199 | 200 | - **onlyShowClockOnMobile** 201 | If true, the clock time picker is not shown on Desktop version. 202 | *default: false* 203 | 204 | - **onAdjust** 205 | Called when the time value is been adjusting. Compared to onChange this function is called each time when the value is changing, also while dragging the time selector... 206 | *default: function(newValue, oldValue) {}* 207 | 208 | - **onChange** 209 | Called when the time value has been changed. This function is called when the input field is loosing its focus. 210 | *default: function(newValue, oldValue) {}* 211 | 212 | - **onClose** 213 | Called when timepicker popup has been closed. 214 | *default: function() {}* 215 | 216 | - **onModeSwitch** 217 | Called when timepicker is switching between hour and minute selection mode. Argument *selectionMode* is "HOUR" or "MINUTE". 218 | *default: function(selectionMode) {}* 219 | 220 | - **onOpen** 221 | Called when timepicker popup has been opened. 222 | *default: function() {}* 223 | 224 | - **popupWidthOnDesktop** 225 | The width of the popup in the Desktop version in pixels. On the mobile phone the width is automatically calculated. 226 | *default: 200* 227 | 228 | - **precision** 229 | When setting the precision to i.e. 5, user may only choose time in 5 minutes steps (8:00, 8:05, 8:10, ...). Valid values for precision are: 1, 5, 10, 15, 30, 60. 230 | *default: 1* 231 | 232 | - **required** 233 | If this option is set to true, a user cannot empty the field by hitting delete or backspace. 234 | *default: false* 235 | 236 | - **separator** 237 | The separator separating the hour and the minute parts. 238 | *default: :* 239 | 240 | - **useDurationPlusSign** 241 | If set to true, positive durations use the plus sign (+) as a prefix. 242 | *default: false* 243 | 244 | - **vibrate** 245 | If this is activated the mobile phone vibrates while changing the time. 246 | *default: true* 247 | 248 | 249 | 250 | Help 251 | ---- 252 | 253 | Submit a [GitHub Issues request](https://github.com/loebi-ch/jquery-clock-timepicker/issues/new). 254 | 255 | 256 | 257 | Changelog 258 | --------- 259 | 260 | **Version 2.6.4** 261 | - for loop variable i declared with let. 262 | 263 | **Version 2.6.3** 264 | - Made disturbing blinking cursor transparent, so it's not visible anymore. 265 | 266 | **Version 2.6.2** 267 | - New configuration setting ```contextmenu``` added. See above in the Options section for explanation. Closes pull request #43. 268 | 269 | **Version 2.6.1** 270 | - jQuery version notice included in README.md 271 | - ClockTimePicker's version number included as query parameter when loading ```jquery-clock-timepicker.min.js``` in index.html to solve browser caching issue for new released versions. 272 | 273 | **Version 2.6.0** 274 | - Minified JavaScript without eval() to solve issue #34. 275 | - Setting HTML value attribute upon time change. 276 | - Get value by calling ```$('.your-time-field').clockTimePicker('value');``` or ```$('.your-time-field').clockTimePicker('val');``` 277 | - Set value by calling ```$('.your-time-field').clockTimePicker('value', '08:00');``` or ```$('.your-time-field').clockTimePicker('val', '08:00');``` 278 | 279 | **Version 2.5.0** 280 | - Don't open clock canvas when setting value programmatically with ```$('.your-time-field').clockTimePicker('value', '08:00');``` 281 | - New function to show clock canvas programmatically with ```$('.your-time-field').clockTimePicker('show');``` 282 | - New function to hide clock canvas programmatically with ```$('.your-time-field').clockTimePicker('hide');``` 283 | 284 | **Version 2.4.0** 285 | - Position popup "fixed" instead of "absolute" to prevent popup from cut-off in containers with overflow: hidden. 286 | - Slow down scroll wheel event so that the clock timepicker doesn't spin uncontrollable when using touchpad. 287 | - Update to jQuery 3.5 288 | 289 | **Version 2.3.5** 290 | - Issue #29 fixed. 291 | - Blur input element on enter. 292 | 293 | **Version 2.3.4** 294 | - Method ```onInputElementKeyUp``` completely refactored to simplify and to solve issue #21. 295 | - Arrow keys and +/- sign behavior refactored. No wheelspin anymore, stop at ```minimum``` and ```maximum``` values. 296 | - Bugfix for bluring input element when switching from one clock timepicker element to another one. 297 | 298 | **Version 2.3.3** 299 | - Issue #14 fixed by inserting code Yauheni-Butski proposed. 300 | - Issue #28 fixed by changing code as proposed by Yauheni-Butski. 301 | 302 | **Version 2.3.2** 303 | - Issue #22 fixed. Using div and spans instead of input element on mobile phones to prevent context menu and cursors to show up. 304 | - Issue #23 fixed. Rounding problem on initialization solved when using option ```precision```. 305 | - Issue #25 fixed. New option ```alwaysSelectHoursFirst``` inserted. 306 | 307 | **Version 2.3.1** 308 | - Bugfix for entering durations with keyboard when ```useDurationPlusSign``` is set to ```true``` 309 | - Removed unwanted Console.log 310 | 311 | **Version 2.3.0** 312 | - Issue #15 solved. 313 | - Feature request #17 implemented: Showing unselectable numbers when using ```minimum``` and ```maximum``` options. 314 | - Hide unselectable numbers completely by using ```hideUnselectableNumbers``` option. 315 | - Configure text colors for unselectable numbers with new options ```clockInnerCircleUnselectableTextColor``` and ```clockOuterCircleUnselectableTextColor```. 316 | - Feature request #18 implemented: Use of data attributes to configure ClockTimePicker element. 317 | - Bugfix for wrong hovering when using ```afternoonHoursInOuterCircle``` (Issue #16). 318 | 319 | **Version 2.2.5** 320 | - Fixed a converting bug when switching between minus and plus sign. 321 | 322 | **Version 2.2.4** 323 | - Hide example console output that was deployed in version 2.2.3 by mistake. 324 | 325 | **Version 2.2.3** 326 | - Option ```useDurationPlusSign``` implemented. 327 | 328 | **Version 2.2.2** 329 | - Issue #12 fixed. 330 | 331 | **Version 2.2.1** 332 | - Issue #9 perfectionated to select hour/minute part with mouse click. 333 | - Parse number settings as integer to prevent errors in calculations in case that a string is passed. 334 | - Pull request #11 from reclaimingmytime inserted. 335 | 336 | **Version 2.2.0** 337 | - Issue #7 fixed. Now this plugin works in both portrait and landscape mode on the mobile phone. 338 | 339 | **Version 2.1.10** 340 | - Bluring issues fixed. 341 | 342 | **Version 2.1.9** 343 | - Directly select minute when clicking inside the minute part. 344 | - Bluring issues fixed. 345 | - Issue #9 perfectionated to select hour/minute part with mouse click. 346 | - Autosizing adjusted so that jquery-clock-timepicker works together with sortablejs. 347 | - Hide time picker when deleting content with delete or backspace. 348 | - Show 00:00 when focusing an empty timepicker. 349 | 350 | **Version 2.1.8** 351 | - Fixed an issue with overlapping popup when input element has a top margin. 352 | 353 | **Version 2.1.7** 354 | - Issue #9 fixed. Better approach to select hour/minute part with mouse click. 355 | 356 | **Version 2.1.6** 357 | - Bugfix when entering time/duration with keyboard on an empty input field. 358 | - Bugfix for keys "+" and "-" in 2.1.5 leaded to another bug with negative duration fields. Corrected in this version. 359 | 360 | **Version 2.1.5** 361 | - Precision 60 bugfix: In some cases the time picker switched to minute mode although precision 60 was set. 362 | - Bugfix for keys "+" and "-" to adjust value in correct direction: + = plus, - = minus. 363 | 364 | **Version 2.1.4** 365 | - Added function to set value on an already initialized clock time picker element at runtime. 366 | 367 | **Version 2.1.3** 368 | - Support for keypad with num lock. 369 | 370 | **Version 2.1.2** 371 | - Call event functions with call() using the element as context so that you can use $(this) inside the callback function to access the element. 372 | 373 | **Version 2.1.1** 374 | - Bugfix: Sign button clickable on mobile phone 375 | 376 | **Version 2.1.0** 377 | - Make it possible to dispose an already initialized clock time picker element. 378 | - Changed the default value for the option ```autosize``` from true to false. 379 | - New option ```required``` added: If you don't want the user to empty the input element, you can set this option to true. 380 | - New event ```onAddjust``` added: This option is called on each adjustment of the value, including dragging the timeselector. 381 | - Sign button +/- implemented in canvas instead of an HTML element to prevent styling issues depending on different global CSS layouts. 382 | - Selection of hour and minute part with the mouse improved (now also taking account of input element's padding). 383 | - Key handling improved for backspace, delete and minus key. 384 | - Arrow keys up and down switched. 385 | - Context menu on right click disabled. 386 | - Implementation of ```maximum``` and ```minimum``` option. 387 | 388 | **Version 2.0.0** 389 | - Event management completeley refactored so that one can use the input's default onchange event. 390 | 391 | **Version 1.x** 392 | - No changelog available for the first versions of this jQuery component. 393 | 394 | 395 | - - - 396 | 397 | This software is made available under the open source MIT License. © 2022 [Andreas Loeber](http://github.com/loebi-ch) and [contributors](https://github.com/loebi-ch/jquery-clock-timepicker/graphs/contributors) 398 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | jQuery Clock Time Picker 6 | 7 | 8 | 25 | 38 | 39 | 40 |
41 |

jQuery Clock Time Picker v2.6.4

42 |

NPM package "jquery-clock-timepicker"

43 |

A free jQuery Plug-in to select the time with a clock inspired by the Android time picker. This plugin works on Desktop and Mobile phones.

44 |

Install with NPM or download it directly from GitHub:
https://github.com/loebi-ch/jquery-clock-timepicker

45 |

The manual can be found on GitHub.

46 |

Examples

47 |

(with the most important settings. Of course, you can combine these different settings...)

48 |

49 | Standard time picker
50 | (no settings specified)
51 | 52 |

53 |

54 | Required time picker
55 | { required: true }
56 | 57 |

58 |

59 | Time picker with different separator
60 | { seperator: '.' }
61 | 62 |

63 |

64 | Time picker with precision
65 | 66 | 67 | 71 | 75 | 79 | 83 | 87 | 88 |
68 | { precision: 5 }
69 | 70 |
72 | { precision: 10 }
73 | 74 |
76 | { precision: 15 }
77 | 78 |
80 | { precision: 30 }
81 | 82 |
84 | { precision: 60 }
85 | 86 |
89 |

90 |

91 | Time picker - show clock picker only on mobile phones
92 | { onlyShowClockOnMobile: true }
93 | 94 |

95 |

96 | Duration picker
97 | { duration: true, maximum: '80:00' }
98 | 99 |

100 |

101 | Duration picker that allows to select negative durations
102 | { duration: true, durationNegative: true }
103 | 104 |

105 |

106 | Duration picker with minimum and maximum
107 | { duration: true, minimum: '1:00', maximum: '5:30' }
108 | 109 |

110 |

111 | Negative duration picker with minimum and maximum
112 | { duration: true, durationNegative: true, minimum: '-5:00', maximum: '5:00', precision: 5 }
113 | 114 |

115 |

116 | Find more settings in the README on GitHub.
117 | If you miss settings, please feel free to submit a GitHub issue request. 118 |

119 |
120 | 121 | -------------------------------------------------------------------------------- /jquery-clock-timepicker.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Andreas Loeber 3 | * Plugin: jquery-clock-timerpicker 4 | * Version: 2.6.4 5 | */ 6 | (function($) { 7 | 8 | $.fn.clockTimePicker = function(options, _value) { 9 | if (typeof options == 'string' && (options == 'value' || options == 'val') && !_value) return $(this).val(); 10 | 11 | /************************************************************************************************ 12 | DEFAULT SETTINGS (CAN BE OVERRIDDEN WITH THE OPTIONS ARGUMENT) 13 | ************************************************************************************************/ 14 | var settings = $.extend(true, { 15 | afternoonHoursInOuterCircle: false, 16 | alwaysSelectHoursFirst: false, 17 | autosize: false, 18 | contextmenu: false, 19 | colors: { 20 | buttonTextColor: '#0797FF', 21 | clockFaceColor: '#EEEEEE', 22 | clockInnerCircleTextColor: '#888888', 23 | clockInnerCircleUnselectableTextColor: '#CCCCCC', 24 | clockOuterCircleTextColor: '#000000', 25 | clockOuterCircleUnselectableTextColor: '#CCCCCC', 26 | hoverCircleColor: '#DDDDDD', 27 | popupBackgroundColor: '#FFFFFF', 28 | popupHeaderBackgroundColor: '#0797FF', 29 | popupHeaderTextColor: '#FFFFFF', 30 | selectorColor: '#0797FF', 31 | selectorNumberColor: '#FFFFFF', 32 | signButtonColor: '#FFFFFF', 33 | signButtonBackgroundColor: '#0797FF' 34 | }, 35 | duration: false, 36 | durationNegative: false, 37 | fonts: { 38 | fontFamily: 'Arial', 39 | clockOuterCircleFontSize: 14, 40 | clockInnerCircleFontSize: 12, 41 | buttonFontSize: 20 42 | }, 43 | hideUnselectableNumbers: false, 44 | i18n: { 45 | okButton: 'OK', 46 | cancelButton: 'Cancel' 47 | }, 48 | maximum: '23:59', 49 | minimum: '-23:59', 50 | modeSwitchSpeed: 500, 51 | onlyShowClockOnMobile: false, 52 | onAdjust: function(newVal, oldVal) { /*console.log('Value adjusted from ' + oldVal + ' to ' + newVal + '.');*/ }, 53 | onChange: function(newVal, oldVal) { /*console.log('Value changed from ' + oldVal + ' to ' + newVal + '.');*/ }, 54 | onClose: function() { }, 55 | onModeSwitch: function() { }, 56 | onOpen: function() { }, 57 | popupWidthOnDesktop: 200, 58 | precision: 1, 59 | required: false, 60 | separator: ':', 61 | useDurationPlusSign: false, 62 | vibrate: true 63 | }, typeof options == 'object' ? options : {}); 64 | 65 | 66 | /************************************************************************************************ 67 | DYNAMICALLY INSERT CSS CODE FOR SELECTION ON MOBILE 68 | ************************************************************************************************/ 69 | var css = '.clock-timepicker input { caret-color: transparent; }'; 70 | if (isMobile()) css += ' .clock-timepicker input::selection { background:rgba(255,255,255,0.6); } .clock-timepicker input::-moz-selection { background:rgba(255,255,255,0.6); }'; 71 | function cssAlreadyInitialized() { 72 | var cssFound = false; 73 | $('head style').each(function() { 74 | if ($(this).text() == css) { 75 | cssFound = true; 76 | return false; 77 | } 78 | }); 79 | if (cssFound) return true; 80 | else return false; 81 | } 82 | if (!cssAlreadyInitialized()) { 83 | var style = document.createElement('style'); 84 | style.type = 'text/css'; 85 | if (style.styleSheet) style.styleSheet.cssText = css; 86 | else style.appendChild(document.createTextNode(css)); 87 | (document.head || document.getElementsByTagName('head')[0]).appendChild(style); 88 | } 89 | 90 | //for each selected element 91 | return this.each(function() { 92 | 93 | var element = $(this); 94 | 95 | //Adjust settings by data attributes 96 | var dataOptions = {}, _data = element.data(); 97 | for (var dataOption in _data) { 98 | if (settings.hasOwnProperty(dataOption)) { 99 | settings[dataOption] = _data[dataOption]; 100 | } 101 | } 102 | 103 | //Validate settings 104 | validateSettings(); 105 | 106 | //VIBRATION API 107 | if (!('vibrate' in navigator)) settings.vibrate = false; 108 | 109 | if (typeof options == 'string') { 110 | if (!$(this).parent().hasClass('clock-timepicker')) console.log('%c[jquery-clock-timepicker] Before calling a function, please initialize the ClockTimePicker!', 'color:red'); 111 | else { 112 | options = options.toLowerCase(); 113 | if (options == 'dispose') disposeTimePicker($(this)); 114 | else if (options == 'value' || options == 'val') { 115 | $(this).val(formatTime(_value)); 116 | var mobileInput = $(this).parent().find('.clock-timepicker-mobile-input'); 117 | if (mobileInput.length > 0) mobileInput.val(formatTime(_value)); 118 | } 119 | else if (options == 'show') { 120 | $(this).parent().find('canvas:first').trigger('keydown'); 121 | } 122 | else if (options == 'hide') { 123 | $(this).parent().find('.clock-timepicker-popup').css('display', 'none'); 124 | $(this).blur(); 125 | } 126 | else console.log('%c[jquery-clock-timepicker] Invalid option passed to clockTimePicker: ' + options, 'color:red'); 127 | } 128 | return; 129 | } else { 130 | if ($(this).parent().hasClass('clock-timepicker')) disposeTimePicker($(this)); 131 | } 132 | 133 | 134 | 135 | /************************************************************************************************ 136 | INITIALIZE VARIABLES 137 | ************************************************************************************************/ 138 | element.val(formatTime(element.val())); 139 | if (isMobile()) element.prop('readonly', true); 140 | var oldValue = element.val(); 141 | var enteredDigits = ''; 142 | var selectionMode = 'HOUR'; //2 modes: 'HOUR' or 'MINUTE' 143 | var isDragging = false; 144 | var touchSignButton = false; 145 | var popupWidth = isMobile() ? $(document).width() - 80 : settings.popupWidthOnDesktop; 146 | var canvasSize = popupWidth - (isMobile() ? 50 : 20); 147 | var clockRadius = parseInt(canvasSize / 2); 148 | var clockCenterX = parseInt(canvasSize / 2); 149 | var clockCenterY = parseInt(canvasSize / 2); 150 | var clockOuterRadius = clockRadius - 16; 151 | var clockInnerRadius = clockOuterRadius - 29; 152 | var isTimeChanged = false; 153 | var lastMouseWheelTimestamp = 0; 154 | 155 | 156 | 157 | /************************************************************************************************ 158 | INITIALIZE A NEW PARENT ELEMENT THAT ENCAPSULATES THE INPUT FIELD 159 | ************************************************************************************************/ 160 | element.wrap('
'); 161 | 162 | 163 | 164 | /************************************************************************************************ 165 | TEMPORARY AUTOSIZE ELEMENT 166 | ************************************************************************************************/ 167 | var tempAutosizeElement = $('
'); 168 | tempAutosizeElement.css('position', 'absolute') 169 | .css('opacity', 0) 170 | .css('display', 'none') 171 | .css('top', parseInt(element.css('margin-top')) + 'px') 172 | .css('left', '0px') 173 | .css('font-size', element.css('font-size')) 174 | .css('font-family', element.css('font-family')) 175 | .css('font-weight', element.css('font-weight')) 176 | .css('line-height', element.css('line-height')); 177 | element.parent().append(tempAutosizeElement); 178 | element.css('min-width', element.outerWidth()); 179 | autosize(); 180 | 181 | 182 | 183 | /************************************************************************************************ 184 | INITIALIZE THE DIV TO DARKEN THE WEBSITE WHILE CHOOSING A TIME 185 | ************************************************************************************************/ 186 | var background; 187 | if (isMobile()) { 188 | background = $('
'); 189 | background.css('zIndex', 99998) 190 | .css('display', 'none') 191 | .css('position', 'fixed') 192 | .css('top', '0px') 193 | .css('left', '0px') 194 | .css('width', '100%') 195 | .css('height', '100%') 196 | .css('backgroundColor', 'rgba(0,0,0,0.6)'); 197 | element.parent().append(background); 198 | 199 | function onBackgroundTouchMove(event) { 200 | event.preventDefault(); 201 | } 202 | background.off('touchmove', onBackgroundTouchMove); 203 | background.on('touchmove', onBackgroundTouchMove); 204 | 205 | function onBackgroundClick(event) { 206 | event.preventDefault(); 207 | event.stopImmediatePropagation(); 208 | if (selectionMode == 'HOUR') selectHourOnInputElement(); 209 | else selectMinuteOnInputElement(); 210 | return false; 211 | } 212 | background.off('click', onBackgroundClick); 213 | background.on('click', onBackgroundClick); 214 | } 215 | 216 | 217 | 218 | /************************************************************************************************ 219 | INITIALIZE POPUP 220 | ************************************************************************************************/ 221 | var popup = $('
'); 222 | popup.css('display', 'none') 223 | .css('zIndex', 99999) 224 | .css('cursor', 'default') 225 | .css('position', 'fixed') 226 | .css('width', popupWidth + 'px') 227 | .css('backgroundColor', settings.colors.popupBackgroundColor) 228 | .css('box-shadow', '0 4px 20px 0px rgba(0, 0, 0, 0.14)') 229 | .css('border-radius', '5px') 230 | .css('overflow', 'hidden') 231 | .css('user-select', 'none'); 232 | popup.on('contextmenu', function() { return false; }); 233 | if (isMobile()) { 234 | popup.css('left', '40px') 235 | .css('top', '40px'); 236 | 237 | window.addEventListener("orientationchange", function() { 238 | setTimeout(function() { 239 | adjustMobilePopupDimensionAndPosition(); 240 | repaintClock(); 241 | }, 500); 242 | }); 243 | 244 | function onPopupTouchMove(event) { 245 | event.preventDefault(); 246 | } 247 | popup.off('touchmove', onPopupTouchMove); 248 | popup.on('touchmove', onPopupTouchMove); 249 | 250 | function onPopupClick(event) { 251 | event.stopImmediatePropagation(); 252 | if (selectionMode == 'HOUR') selectHourOnInputElement(); 253 | else selectMinuteOnInputElement(); 254 | return false; 255 | } 256 | popup.off('click', onPopupClick); 257 | popup.on('click', onPopupClick); 258 | } 259 | element.parent().append(popup); 260 | 261 | 262 | 263 | /************************************************************************************************ 264 | DESKTOP VERSION: A CLICK OUTSIDE OF THE POPUP SHOULD CLOSE THE TIME PICKER 265 | ************************************************************************************************/ 266 | if (!isMobile()) { 267 | function onWindowClick(event) { 268 | if (popup.css('display') != 'none' && !($(event.target)[0] == inputElement[0] || $.contains(inputElement.parent()[0], $(event.target)[0]))) { 269 | hideTimePicker(); 270 | } 271 | } 272 | $(window).off('click.clockTimePicker', onWindowClick); 273 | $(window).on('click.clockTimePicker', onWindowClick); 274 | } 275 | 276 | 277 | 278 | /************************************************************************************************ 279 | INITIALIZE INPUT ELEMENT 280 | ************************************************************************************************/ 281 | var inputElement = element; 282 | if (isMobile()) { 283 | 284 | inputElement = $('
'); 285 | inputElement.css('width', '100%') 286 | .css('fontFamily', settings.fonts.fontFamily) 287 | .css('fontSize', '40px') 288 | .css('padding', '10px 0px') 289 | .css('textAlign', 'center') 290 | .css('color', settings.colors.popupHeaderTextColor) 291 | .css('backgroundColor', settings.colors.popupHeaderBackgroundColor); 292 | var inputElementHours = $(''); 293 | inputElement.append(inputElementHours); 294 | var inputElementSeparator = $(''); 295 | inputElementSeparator.html(settings.separator); 296 | inputElement.append(inputElementSeparator); 297 | var inputElementMinutes = $(''); 298 | inputElement.append(inputElementMinutes); 299 | popup.append(inputElement); 300 | 301 | } 302 | if (element.attr('autocomplete')) element.attr('data-autocomplete-orig', element.attr('autocomplete')); 303 | element.prop('autocomplete', 'off'); 304 | if (element.attr('autocorrect')) element.attr('data-autocorrect-orig', element.attr('autocorrect')); 305 | element.prop('autocorrect', 'off'); 306 | if (element.attr('autocapitalize')) element.attr('data-autocapitalize-orig', element.attr('autocapitalize')); 307 | element.prop('autocapitalize', 'off'); 308 | if (element.attr('spellcheck')) element.attr('data-spellcheck-orig', element.attr('spellcheck')); 309 | element.prop('spellcheck', false); 310 | inputElement.on('drag.clockTimePicker dragend.clockTimePicker dragover.clockTimePicker dragenter.clockTimePicker dragstart.clockTimePicker dragleave.clockTimePicker drop.clockTimePicker selectstart.clockTimePicker contextmenu.clockTimePicker', onInputElementDragSelectContextMenu); 311 | inputElement.on('mousedown.clockTimePicker', onInputElementMouseDown); 312 | inputElement.on('keyup.clockTimePicker', onInputElementKeyUp); 313 | inputElement.on('keydown.clockTimePicker', onInputElementKeyDown); 314 | element.on('mousewheel.clockTimePicker', onInputElementMouseWheel); 315 | element.on('focus.clockTimePicker', onInputElementFocus); 316 | 317 | 318 | 319 | /************************************************************************************************ 320 | INITIALIZE CLOCK CANVASES 321 | ************************************************************************************************/ 322 | var canvasHolder = $('
'); 323 | canvasHolder.css('position', 'relative') 324 | .css('width', canvasSize + 'px') 325 | .css('height', canvasSize + 'px') 326 | .css('margin', '10px ' + (isMobile() ? 25 : 10) + 'px'); 327 | popup.append(canvasHolder); 328 | var clockHourCanvas = $(''); 329 | clockHourCanvas.css('cursor', 'default') 330 | .css('position', 'absolute') 331 | .css('top', '0px') 332 | .css('left', '0px'); 333 | clockHourCanvas.attr('width', canvasSize); 334 | clockHourCanvas.attr('height', canvasSize); 335 | registerDraggingEventsOnCanvas(clockHourCanvas); 336 | canvasHolder.append(clockHourCanvas); 337 | var clockMinuteCanvas = $(''); 338 | clockMinuteCanvas.css('cursor', 'default') 339 | .css('position', 'absolute') 340 | .css('top', '0px') 341 | .css('left', '0px') 342 | .css('display', 'none'); 343 | clockMinuteCanvas.attr('width', canvasSize); 344 | clockMinuteCanvas.attr('height', canvasSize); 345 | registerDraggingEventsOnCanvas(clockMinuteCanvas); 346 | canvasHolder.append(clockMinuteCanvas); 347 | 348 | 349 | 350 | /************************************************************************************************ 351 | INITIALIZE BUTTON AREA 352 | ************************************************************************************************/ 353 | if (isMobile()) { 354 | var buttonArea = $('
'); 355 | buttonArea.css('text-align', 'right') 356 | .css('padding', '15px 30px'); 357 | settings.fonts.fontFamily = settings.fonts.fontFamily.replace(/\"/g, "").replace(/\'/g, ""); //Prevents quotes in font to interfere 358 | var buttonHtml = ''; 359 | var cancelButton = $(buttonHtml); 360 | cancelButton.html(settings.i18n.cancelButton); 361 | cancelButton.on('click', function() { 362 | hideTimePicker(); 363 | }); 364 | buttonArea.append(cancelButton); 365 | var okButton = $(buttonHtml); 366 | okButton.html(settings.i18n.okButton); 367 | okButton.on('click', function() { 368 | if (isMobile()) element.val(getInputElementValue()); 369 | if (settings.vibrate) navigator.vibrate(10); 370 | hideTimePicker(); 371 | }); 372 | buttonArea.append(okButton); 373 | popup.append(buttonArea); 374 | } 375 | 376 | 377 | 378 | /************************************************************************************************ 379 | BLUR ALL 380 | ************************************************************************************************/ 381 | function blurAll() { 382 | if (document.activeElement != inputElement.get(0)) return; 383 | var tmp = document.createElement("input"); 384 | element.parent().get(0).appendChild(tmp); 385 | tmp.focus(); 386 | element.parent().get(0).removeChild(tmp); 387 | } 388 | 389 | 390 | 391 | /************************************************************************************************ 392 | REGISTER DRAGGING EVENT LISTENERS ON CANVASES 393 | ************************************************************************************************/ 394 | function registerDraggingEventsOnCanvas(canvas) { 395 | 396 | //Mouse Drag Events for Desktop Version 397 | if (!isMobile()) { 398 | canvas.on('mousedown', function(event) { 399 | var x = event.pageX - $(this).offset().left; 400 | var y = event.pageY - $(this).offset().top; 401 | processTimeSelection(x, y); 402 | isDragging = true; 403 | }); 404 | canvas.on('mouseup', function(event) { 405 | isDragging = false; 406 | var x = event.pageX - $(this).offset().left; 407 | var y = event.pageY - $(this).offset().top; 408 | var selectorLength = Math.sqrt(Math.pow(Math.abs(x - clockCenterX), 2) + Math.pow(Math.abs(y - clockCenterY), 2)); 409 | if (settings.duration && settings.durationNegative && selectorLength <= 20) { 410 | var oldVal = getInputElementValue(); 411 | if (oldVal.match(/^-/)) { 412 | newVal = oldVal.substring(1); 413 | } else { 414 | newVal = '-' + oldVal.replace(/^(-|\+)/, ''); 415 | } 416 | if (settings.minimum && !isTimeSmallerOrEquals(settings.minimum, newVal)) newVal = formatTime(settings.minimum); 417 | if (settings.maximum && !isTimeSmallerOrEquals(newVal, settings.maximum)) newVal = formatTime(settings.maximum); 418 | setInputElementValue(formatTime(newVal)); 419 | repaintClock(); 420 | element.attr('value', newVal.replace(/^\+/, '')); 421 | settings.onAdjust.call(element.get(0), newVal.replace(/^\+/, ''), oldVal.replace(/^\+/, '')); 422 | if (selectionMode == 'HOUR') selectHourOnInputElement(); 423 | else selectMinuteOnInputElement(); 424 | return; 425 | } 426 | if (!processTimeSelection(x, y, true)) { 427 | if (settings.precision == 60) { 428 | hideTimePicker(); 429 | } else if (selectionMode == 'HOUR') { 430 | switchToMinuteMode(); 431 | selectMinuteOnInputElement(); 432 | } else { 433 | hideTimePicker(); 434 | } 435 | return false; 436 | } 437 | if (selectionMode == 'MINUTE' || settings.precision == 60) { 438 | hideTimePicker(); 439 | } 440 | else { 441 | switchToMinuteMode(); 442 | selectMinuteOnInputElement(); 443 | } 444 | }); 445 | canvas.on('mousemove', function(event) { 446 | var x = event.pageX - $(this).offset().left; 447 | var y = event.pageY - $(this).offset().top; 448 | processTimeSelection(x, y); 449 | }); 450 | canvas.on('mouseleave', function(event) { 451 | if (selectionMode == 'HOUR') repaintClockHourCanvas(); 452 | else repaintClockMinuteCanvas(); 453 | }); 454 | 455 | canvas.on('mousewheel', function(event) { 456 | processMouseWheelEvent(event); 457 | }); 458 | } 459 | 460 | //Touch Events for Mobile Version 461 | else { 462 | canvas.on('touchstart', function(event) { 463 | event.preventDefault(); 464 | var x = event.originalEvent.touches[0].pageX - $(this).offset().left; 465 | var y = event.originalEvent.touches[0].pageY - $(this).offset().top; 466 | var selectorLength = Math.sqrt(Math.pow(Math.abs(x - clockCenterX), 2) + Math.pow(Math.abs(y - clockCenterY), 2)); 467 | if (settings.duration && settings.durationNegative && selectorLength <= 20) { 468 | touchSignButton = true; 469 | var oldVal = getInputElementValue(); 470 | if (oldVal.match(/^-/)) { 471 | newVal = oldVal.substring(1); 472 | } else { 473 | newVal = '-' + oldVal.replace(/^(-|\+)/, ''); 474 | } 475 | if (settings.minimum && !isTimeSmallerOrEquals(settings.minimum, newVal)) newVal = formatTime(settings.minimum); 476 | if (settings.maximum && !isTimeSmallerOrEquals(newVal, settings.maximum)) newVal = formatTime(settings.maximum); 477 | setInputElementValue(formatTime(newVal)); 478 | repaintClock(); 479 | element.attr('value', newVal.replace(/^\+/, '')); 480 | settings.onAdjust.call(element.get(0), newVal.replace(/^\+/, ''), oldVal.replace(/^\+/, '')); 481 | if (selectionMode == 'HOUR') selectHourOnInputElement(); 482 | else selectMinuteOnInputElement(); 483 | return; 484 | } 485 | isDragging = true; 486 | processTimeSelection(x, y); 487 | }); 488 | canvas.on('touchend', function(event) { 489 | event.preventDefault(); 490 | isDragging = false; 491 | if (!touchSignButton && settings.precision != 60) { 492 | switchToMinuteMode(); 493 | selectMinuteOnInputElement(); 494 | } 495 | touchSignButton = false; 496 | }); 497 | canvas.on('touchmove', function(event) { 498 | event.preventDefault(); 499 | if (isDragging) { 500 | var x = event.originalEvent.touches[0].pageX - $(this).offset().left; 501 | var y = event.originalEvent.touches[0].pageY - $(this).offset().top; 502 | processTimeSelection(x, y); 503 | } 504 | }); 505 | } 506 | 507 | canvas.on('keydown', function(event) { 508 | event.preventDefault(); 509 | processTimeSelection(); 510 | switchToHourMode(); 511 | selectHourOnInputElement(); 512 | oldValue = getInputElementValue(); 513 | }); 514 | } 515 | 516 | 517 | 518 | /************************************************************************************************ 519 | PROCESSES LEFT OR RIGHT MOUSE CLICK AND SINGLE TAP ON MOBILE PHONES 520 | ************************************************************************************************/ 521 | function processClick(event) { 522 | var popupVisible = popup.css('display') != 'none'; 523 | if (!getInputElementValue()) { 524 | setInputElementValue(formatTime('00:00')); 525 | switchToHourMode(!popupVisible); 526 | selectHourOnInputElement(); 527 | } 528 | else if (settings.precision == 60) { 529 | switchToHourMode(!popupVisible); 530 | selectHourOnInputElement(); 531 | } 532 | else { 533 | var textDirection = inputElement.css('direction'); 534 | if (!textDirection) textDirection = 'ltr'; 535 | var textAlignment = inputElement.css('text-align'); 536 | if (!textAlignment) textAlignment = 'left'; 537 | var elementWidth = inputElement.innerWidth(); 538 | var elementPaddingLeft = parseFloat(inputElement.css('padding-left')); 539 | var elementPaddingRight = parseFloat(inputElement.css('padding-right')); 540 | var elementInnerWidth = elementWidth - elementPaddingLeft - elementPaddingRight; 541 | tempAutosizeElement.css('display', 'inline-block'); 542 | tempAutosizeElement.html(getInputElementValue()); 543 | var textWidth = tempAutosizeElement.innerWidth(); 544 | tempAutosizeElement.html(settings.separator); 545 | var textCenter = tempAutosizeElement.innerWidth() / 2; 546 | tempAutosizeElement.html(getInputElementValue().replace(new RegExp(settings.separator + '[0-9]+$'), '')); 547 | textCenter += tempAutosizeElement.innerWidth(); 548 | tempAutosizeElement.css('display', 'none'); 549 | var inputElementCenter = elementWidth / 2; 550 | if (textAlignment == 'left' || textAlignment == 'justify' || (textDirection == 'ltr' && textAlignment == 'start') || (textDirection == 'rtl' && textAlignment == 'end')) { 551 | inputElementCenter = Math.floor(elementPaddingLeft + textCenter); 552 | } 553 | else if (textAlignment == 'center') { 554 | inputElementCenter = Math.floor(elementPaddingLeft + ((elementInnerWidth - textWidth) / 2) + textCenter); 555 | } 556 | else if (textAlignment == 'right' || (textDirection == 'ltr' && textAlignment == 'end') || (textDirection == 'rtl' && textAlignment == 'start')) { 557 | inputElementCenter = Math.floor(elementPaddingLeft + elementInnerWidth - (textWidth - textCenter)); 558 | } 559 | if (event.offsetX >= inputElementCenter - 2 && (popupVisible || !settings.alwaysSelectHoursFirst)) { 560 | if (selectionMode == 'HOUR' && settings.vibrate) navigator.vibrate(10); 561 | switchToMinuteMode(!popupVisible); 562 | selectMinuteOnInputElement(); 563 | } else { 564 | if (selectionMode == 'MINUTE' && settings.vibrate) navigator.vibrate(10); 565 | switchToHourMode(!popupVisible); 566 | selectHourOnInputElement(); 567 | } 568 | } 569 | if (!popupVisible) showTimePicker(); 570 | } 571 | 572 | 573 | 574 | /************************************************************************************************ 575 | PROCESSES THE MOUSE WHEEL EVENT AND INCREASES OR DECREASES HOURS OR MINUTES 576 | ************************************************************************************************/ 577 | function processMouseWheelEvent(event) { 578 | var e = window.event || event; 579 | event.preventDefault(); 580 | if (new Date().getTime() - lastMouseWheelTimestamp < 100) return; 581 | lastMouseWheelTimestamp = new Date().getTime(); 582 | var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail))); 583 | (new RegExp('^(-|\\+)?([0-9]+)(.([0-9]{1,2}))?$')).test(getInputElementValue()); 584 | var negative = settings.duration && settings.durationNegative && RegExp.$1 == '-' ? true : false; 585 | var h = parseInt(RegExp.$2); 586 | if (negative) h = -h; 587 | var m = RegExp.$4 ? parseInt(RegExp.$4) : 0; 588 | if (selectionMode == 'HOUR') { 589 | if (settings.duration && settings.durationNegative && h == 0 && !negative && delta == -1) negative = true; 590 | else if (settings.duration && settings.durationNegative && h == 0 && negative && delta == 1) negative = false; 591 | else h += delta; 592 | if (h == -1) { 593 | if (!settings.duration) h = 23; 594 | else if (!settings.durationNegative) h = 0; 595 | } 596 | if (h == 24 && !settings.duration) h = 0; 597 | } else { 598 | m += (delta * settings.precision); 599 | if (m < 0) m = 60 + m; 600 | if (m >= 60) m = m - 60; 601 | } 602 | var oldVal = getInputElementValue(); 603 | var newVal = (h < 10 && !settings.duration ? '0': '') + (negative && h == 0 ? '-' + h : h) + settings.separator + (m < 10 ? '0' : '') + m; 604 | var isMinMaxFullfilled = true; 605 | if (settings.maximum && !isTimeSmallerOrEquals(newVal, settings.maximum)) isMinMaxFullfilled = false; 606 | if (settings.minimum && !isTimeSmallerOrEquals(settings.minimum, newVal)) isMinMaxFullfilled = false; 607 | if (!isMinMaxFullfilled && selectionMode == 'HOUR') { 608 | if (delta > 0) newVal = formatTime(settings.maximum); 609 | else newVal = formatTime(settings.minimum); 610 | isMinMaxFullfilled = true; 611 | } 612 | if (isMinMaxFullfilled) { 613 | setInputElementValue(formatTime(newVal)); 614 | autosize(); 615 | repaintClock(); 616 | if (selectionMode == 'HOUR') selectHourOnInputElement(); 617 | else selectMinuteOnInputElement(); 618 | if (newVal != oldVal) { 619 | element.attr('value', newVal.replace(/^\+/, '')); 620 | settings.onAdjust.call(element.get(0), newVal.replace(/^\+/, ''), oldVal.replace(/^\+/, '')); 621 | } 622 | } 623 | } 624 | 625 | 626 | 627 | /************************************************************************************************ 628 | CONVERTS A CLICK / TOUCH IN THE CANVAS TO A TIME AND SETS THE NEW VALUE 629 | ************************************************************************************************/ 630 | function processTimeSelection(x, y, clicked) { 631 | var selectorAngle = (360 * Math.atan((y - clockCenterY)/(x - clockCenterX)) / (2 * Math.PI)) + 90; 632 | var selectorLength = Math.sqrt(Math.pow(Math.abs(x - clockCenterX), 2) + Math.pow(Math.abs(y - clockCenterY), 2)); 633 | var hour = 0; 634 | var min = 0; 635 | var negative = false; 636 | if ((new RegExp('^(-|\\+)?([0-9]+).([0-9]{2})$')).test(getInputElementValue())) { 637 | negative = settings.duration && settings.durationNegative && RegExp.$1 == '-' ? true : false; 638 | hour = parseInt(RegExp.$2); 639 | min = parseInt(RegExp.$3); 640 | } 641 | if (selectionMode == 'HOUR') { 642 | selectorAngle = Math.round(selectorAngle / 30); 643 | var h = -1; 644 | if (selectorLength < clockRadius + 10 && selectorLength > clockRadius - 28) { 645 | if (x - clockCenterX >= 0) { 646 | if (selectorAngle == 0) h = 12; 647 | else h = selectorAngle; 648 | } 649 | else if (x - clockCenterX < 0) { 650 | h = selectorAngle + 6; 651 | } 652 | } else if (selectorLength < clockRadius - 28 && selectorLength > clockRadius - 65) { 653 | if (x - clockCenterX >= 0) { 654 | if (selectorAngle != 0) h = selectorAngle + 12; 655 | else h = 0; 656 | } 657 | else if (x - clockCenterX < 0) { 658 | h = selectorAngle + 18; 659 | if (h == 24) h = 0; 660 | } 661 | } 662 | if (settings.afternoonHoursInOuterCircle) { 663 | h = h + (h >= 12 ? -12 : 12); 664 | } 665 | if (h > -1) { 666 | var newVal = (negative ? '-' : '') +(h < 10 && !settings.duration ? '0' : '') + h + settings.separator + (min < 10 ? '0' : '') + min; 667 | if (isDragging || clicked) { 668 | var isMinMaxFullfilled = true; 669 | if (settings.maximum && !isTimeSmallerOrEquals(newVal, settings.maximum)) isMinMaxFullfilled = false; 670 | if (settings.minimum && !isTimeSmallerOrEquals(settings.minimum, newVal)) isMinMaxFullfilled = false; 671 | if (!isMinMaxFullfilled) { 672 | if (settings.maximum && isTimeSmallerOrEquals((negative ? '-' : '') +(h < 10 && !settings.duration ? '0' : '') + h + settings.separator + '00', settings.maximum)) { 673 | newVal = formatTime(settings.maximum); 674 | isMinMaxFullfilled = true; 675 | } 676 | if (settings.minimum && !isTimeSmallerOrEquals(settings.minimum, (negative ? '-' : '') +(h < 10 && !settings.duration ? '0' : '') + h + settings.separator + '00')) { 677 | newVal = formatTime(settings.minimum); 678 | isMinMaxFullfilled = true; 679 | } 680 | } 681 | if (isMinMaxFullfilled) { 682 | var oldVal = getInputElementValue(); 683 | if (newVal != oldVal) { 684 | if (settings.vibrate) navigator.vibrate(10); 685 | element.attr('value', newVal.replace(/^\+/, '')); 686 | settings.onAdjust.call(element.get(0), newVal.replace(/^\+/, ''), oldVal.replace(/^\+/, '')); 687 | } 688 | setInputElementValue(formatTime(newVal)); 689 | autosize(); 690 | } 691 | } 692 | isTimeChanged = true; 693 | repaintClockHourCanvas(h == 0 ? 24 : h, settings.duration && settings.durationNegative && selectorLength <= 12); 694 | return true; 695 | } 696 | else { 697 | repaintClockHourCanvas(null, settings.duration && settings.durationNegative && selectorLength <= 12); 698 | return false; 699 | } 700 | } 701 | else if (selectionMode == 'MINUTE') { 702 | selectorAngle = Math.round(selectorAngle / 6); 703 | var m = -1; 704 | if (selectorLength < clockRadius + 10 && selectorLength > clockRadius - 40) { 705 | if (x - clockCenterX >= 0) { 706 | m = selectorAngle; 707 | } else if (x - clockCenterX < 0) { 708 | m = selectorAngle + 30; 709 | if (m == 60) m = 0; 710 | } 711 | } 712 | if (m > -1) { 713 | if (settings.precision != 1) { 714 | var f = Math.floor(m / settings.precision); 715 | m = f * settings.precision + (Math.round((m - f * settings.precision) / settings.precision) == 1 ? settings.precision : 0); 716 | if (m >= 60) m = 0; 717 | } 718 | var newVal = (negative ? '-' : '') + (hour < 10 && !settings.duration ? '0' : '') + hour + settings.separator + (m < 10 ? '0' : '') + m; 719 | var isMinMaxFullfilled = true; 720 | if (settings.maximum && !isTimeSmallerOrEquals(newVal, settings.maximum)) isMinMaxFullfilled = false; 721 | if (settings.minimum && !isTimeSmallerOrEquals(settings.minimum, newVal)) isMinMaxFullfilled = false; 722 | if ((isDragging || clicked) && isMinMaxFullfilled) { 723 | var oldVal = getInputElementValue(); 724 | if (newVal != oldVal) { 725 | if (settings.vibrate) navigator.vibrate(10); 726 | element.attr('value', newVal.replace(/^\+/, '')); 727 | settings.onAdjust.call(element.get(0), newVal.replace(/^\+/, ''), oldVal.replace(/^\+/, '')); 728 | } 729 | setInputElementValue(formatTime(newVal)); 730 | } 731 | isTimeChanged = true; 732 | repaintClockMinuteCanvas(m == 0 ? 60 : m, settings.duration && settings.durationNegative && selectorLength <= 12); 733 | return true; 734 | } 735 | else { 736 | repaintClockMinuteCanvas(null, settings.duration && settings.durationNegative && selectorLength <= 12); 737 | return false; 738 | } 739 | } 740 | } 741 | 742 | 743 | 744 | /************************************************************************************************ 745 | REPAINTS THE CORRESPONDING CLOCK CANVAS DEPENDING ON CURRENT SELECTION MODE 746 | ************************************************************************************************/ 747 | function repaintClock() { 748 | if (selectionMode == 'HOUR') { 749 | repaintClockHourCanvas(); 750 | } else { 751 | repaintClockMinuteCanvas(); 752 | } 753 | } 754 | 755 | 756 | 757 | /************************************************************************************************ 758 | REPAINTS THE SIGN BUTTON (used by repaintClockHourCanvas and repaintClockMinuteCanvas) 759 | ************************************************************************************************/ 760 | function repaintSignButton(ctx, hover) { 761 | ctx.beginPath(); 762 | ctx.arc(clockCenterX, clockCenterY, 12, 0, 2 * Math.PI, false); 763 | ctx.fillStyle = settings.colors.signButtonBackgroundColor; 764 | ctx.fill(); 765 | if (hover) { 766 | ctx.beginPath(); 767 | ctx.arc(clockCenterX, clockCenterY, 14, 0, 2 * Math.PI, false); 768 | ctx.strokeStyle = settings.colors.signButtonBackgroundColor; 769 | ctx.stroke(); 770 | } 771 | ctx.beginPath(); 772 | ctx.moveTo(clockCenterX - 6, clockCenterY); 773 | ctx.lineTo(clockCenterX + 6, clockCenterY); 774 | ctx.lineWidth = 2; 775 | ctx.strokeStyle = settings.colors.signButtonColor; 776 | ctx.stroke(); 777 | if (!getInputElementValue().match(/^-/)) { 778 | ctx.beginPath(); 779 | ctx.moveTo(clockCenterX, clockCenterY - 6); 780 | ctx.lineTo(clockCenterX, clockCenterY + 6); 781 | ctx.lineWidth = 2; 782 | ctx.strokeStyle = settings.colors.signButtonColor; 783 | ctx.stroke(); 784 | } 785 | } 786 | 787 | 788 | 789 | /************************************************************************************************ 790 | REPAINTS THE CLOCK HOUR CANVAS 791 | ************************************************************************************************/ 792 | function repaintClockHourCanvas(hoverHour, hoverSign) { 793 | 794 | var ctx = clockHourCanvas.get(0).getContext('2d'); 795 | (new RegExp('^(-|\\+)?([0-9]+).([0-9]{1,2})$')).test(getInputElementValue()); 796 | var negative = RegExp.$1 == '-' ? true : false; 797 | var hour = parseInt(RegExp.$2); 798 | 799 | ctx.clearRect(0, 0, canvasSize, canvasSize); 800 | 801 | if (hour >= 24) { 802 | popup.css('visibility', 'hidden'); 803 | return; 804 | } else { 805 | if (!settings.onlyShowClockOnMobile) popup.css('visibility', 'visible'); 806 | } 807 | 808 | if (hour == 0) hour = 24; 809 | if (!getInputElementValue()) hour = -1; 810 | 811 | //Paint clock circle 812 | ctx.beginPath(); 813 | ctx.arc(clockCenterX, clockCenterY, clockRadius, 0, 2 * Math.PI, false); 814 | ctx.fillStyle = settings.colors.clockFaceColor; 815 | ctx.fill(); 816 | 817 | //Paint hover (if available) 818 | if (!isMobile() && hoverHour) { 819 | var isMinMaxFullfilled = true; 820 | if (settings.maximum && !isTimeSmallerOrEquals((negative ? '-' : '') + (hoverHour == 24 ? '00' : hoverHour) + ':00', settings.maximum)) isMinMaxFullfilled = false; 821 | if (settings.minimum && !isTimeSmallerOrEquals(settings.minimum, (negative ? '-' : '') + (hoverHour == 24 ? '00' : hoverHour) + ':00', true)) isMinMaxFullfilled = false; 822 | if (isMinMaxFullfilled) { 823 | ctx.beginPath(); 824 | ctx.arc(clockCenterX + Math.cos(Math.PI / 6 * ((hoverHour % 12) - 3)) * (hoverHour > 12 ? (settings.afternoonHoursInOuterCircle ? clockOuterRadius : clockInnerRadius) : (settings.afternoonHoursInOuterCircle ? clockInnerRadius : clockOuterRadius)), 825 | clockCenterY + Math.sin(Math.PI / 6 * ((hoverHour % 12) - 3)) * (hoverHour > 12 ? (settings.afternoonHoursInOuterCircle ? clockOuterRadius : clockInnerRadius) : (settings.afternoonHoursInOuterCircle ? clockInnerRadius : clockOuterRadius)), 826 | 15, 0, 2 * Math.PI, false); 827 | ctx.fillStyle = settings.colors.hoverCircleColor; 828 | ctx.fill(); 829 | } 830 | } 831 | 832 | //Paint hour selector 833 | ctx.beginPath(); 834 | ctx.arc(clockCenterX, clockCenterY, 3, 0, 2 * Math.PI, false); 835 | ctx.fillStyle = settings.colors.selectorColor; 836 | ctx.fill(); 837 | if (hour > -1 && (!settings.maximum || hour == 24 || isTimeSmallerOrEquals(hour, settings.maximum))) { 838 | ctx.beginPath(); 839 | ctx.moveTo(clockCenterX, clockCenterY); 840 | ctx.lineTo(clockCenterX + Math.cos(Math.PI / 6 * ((hour % 12) - 3)) * (hour > 12 ? (settings.afternoonHoursInOuterCircle ? clockOuterRadius : clockInnerRadius) : (settings.afternoonHoursInOuterCircle ? clockInnerRadius : clockOuterRadius)), 841 | clockCenterY + Math.sin(Math.PI / 6 * ((hour % 12) - 3)) * (hour > 12 ? (settings.afternoonHoursInOuterCircle ? clockOuterRadius : clockInnerRadius) : (settings.afternoonHoursInOuterCircle ? clockInnerRadius : clockOuterRadius))); 842 | ctx.lineWidth = 1; 843 | ctx.strokeStyle = settings.colors.selectorColor; 844 | ctx.stroke(); 845 | ctx.beginPath(); 846 | ctx.arc(clockCenterX + Math.cos(Math.PI / 6 * ((hour % 12) - 3)) * (hour > 12 ? (settings.afternoonHoursInOuterCircle ? clockOuterRadius : clockInnerRadius) : (settings.afternoonHoursInOuterCircle ? clockInnerRadius : clockOuterRadius)), 847 | clockCenterY + Math.sin(Math.PI / 6 * ((hour % 12) - 3)) * (hour > 12 ? (settings.afternoonHoursInOuterCircle ? clockOuterRadius : clockInnerRadius) : (settings.afternoonHoursInOuterCircle ? clockInnerRadius : clockOuterRadius)), 848 | 15, 0, 2 * Math.PI, false); 849 | ctx.fillStyle = settings.colors.selectorColor; 850 | ctx.fill(); 851 | } 852 | 853 | //Paint hour numbers in outer circle 854 | ctx.font = settings.fonts.clockOuterCircleFontSize + 'px ' + settings.fonts.fontFamily; 855 | for(let i = 1; i <= 12; i++) { 856 | var angle = Math.PI / 6 * (i - 3); 857 | var s = i; 858 | if (settings.afternoonHoursInOuterCircle) { 859 | s = i + 12; 860 | if (hour == i + 12) ctx.fillStyle = settings.colors.selectorNumberColor; 861 | else ctx.fillStyle = settings.colors.clockInnerCircleTextColor; 862 | if (s == 24) s = '00'; 863 | } else { 864 | if (hour == i) ctx.fillStyle = settings.colors.selectorNumberColor; 865 | else ctx.fillStyle = settings.colors.clockOuterCircleTextColor; 866 | } 867 | if ((!settings.maximum || isTimeSmallerOrEquals((negative ? '-' : '') + s + ':00', settings.maximum)) && 868 | (!settings.minimum || isTimeSmallerOrEquals(settings.minimum, (negative ? '-' : '') + s + ':00', true))) { 869 | ctx.fillText(s, 870 | clockCenterX + Math.cos(angle) * clockOuterRadius - (ctx.measureText(s).width / 2), 871 | clockCenterY + Math.sin(angle) * clockOuterRadius + (settings.fonts.clockOuterCircleFontSize / 3)); 872 | } 873 | else if (!settings.hideUnselectableNumbers) { 874 | ctx.fillStyle = settings.colors.clockOuterCircleUnselectableTextColor; 875 | ctx.fillText(s, 876 | clockCenterX + Math.cos(angle) * clockOuterRadius - (ctx.measureText(s).width / 2), 877 | clockCenterY + Math.sin(angle) * clockOuterRadius + (settings.fonts.clockOuterCircleFontSize / 3)); 878 | } 879 | } 880 | 881 | //Paint hour numbers in inner circle 882 | ctx.font = settings.fonts.clockInnerCircleFontSize + 'px ' + settings.fonts.fontFamily; 883 | for(let i = 1; i <= 12; i++) { 884 | var angle = Math.PI / 6 * (i - 3); 885 | var s = i; 886 | if (!settings.afternoonHoursInOuterCircle) { 887 | s = i + 12; 888 | if (hour == i + 12) ctx.fillStyle = settings.colors.selectorNumberColor; 889 | else ctx.fillStyle = settings.colors.clockInnerCircleTextColor; 890 | if (s == 24) s = '00'; 891 | } else { 892 | if (hour == i) ctx.fillStyle = settings.colors.selectorNumberColor; 893 | else ctx.fillStyle = settings.colors.clockOuterCircleTextColor; 894 | } 895 | if ((!settings.maximum || isTimeSmallerOrEquals((negative ? '-' : '') + s + ':00', settings.maximum)) && 896 | (!settings.minimum || isTimeSmallerOrEquals(settings.minimum, (negative ? '-' : '') + s + ':00', true))) { 897 | ctx.fillText(s, 898 | clockCenterX + Math.cos(angle) * clockInnerRadius - (ctx.measureText(s).width / 2), 899 | clockCenterY + Math.sin(angle) * clockInnerRadius + (settings.fonts.clockInnerCircleFontSize / 3)); 900 | } 901 | else if (!settings.hideUnselectableNumbers) { 902 | ctx.fillStyle = settings.colors.clockInnerCircleUnselectableTextColor; 903 | ctx.fillText(s, 904 | clockCenterX + Math.cos(angle) * clockInnerRadius - (ctx.measureText(s).width / 2), 905 | clockCenterY + Math.sin(angle) * clockInnerRadius + (settings.fonts.clockInnerCircleFontSize / 3)); 906 | } 907 | } 908 | 909 | if (settings.duration && settings.durationNegative) repaintSignButton(ctx, hoverSign); 910 | } 911 | 912 | 913 | 914 | /************************************************************************************************ 915 | REPAINTS THE CLOCK MINUTE CANVAS 916 | ************************************************************************************************/ 917 | function repaintClockMinuteCanvas(hoverMinute, hoverSign) { 918 | 919 | var ctx = clockMinuteCanvas.get(0).getContext('2d'); 920 | (new RegExp('^(-|\\+)?([0-9]+).([0-9]{1,2})$')).test(getInputElementValue()); 921 | var negative = RegExp.$1 == '-' ? true : false; 922 | var hour = parseInt(RegExp.$2); 923 | var min = parseInt(RegExp.$3); 924 | if (!getInputElementValue()) min = -1; 925 | 926 | if (!settings.onlyShowClockOnMobile) popup.css('visibility', 'visible'); 927 | 928 | //Paint clock circle 929 | ctx.clearRect(0, 0, canvasSize, canvasSize); 930 | ctx.beginPath(); 931 | ctx.arc(clockCenterX, clockCenterY, clockRadius, 0, 2 * Math.PI, false); 932 | ctx.fillStyle = settings.colors.clockFaceColor; 933 | ctx.fill(); 934 | 935 | //Paint hover (if available) 936 | if (!isMobile() && hoverMinute) { 937 | if (hoverMinute == 60) hoverMinute = 0; 938 | var isMinMaxFullfilled = true; 939 | if (settings.maximum && !isTimeSmallerOrEquals((negative ? '-' : '') + hour + ':' + (hoverMinute < 10 ? '0' : '') + hoverMinute, settings.maximum)) isMinMaxFullfilled = false; 940 | if (settings.minimum && !isTimeSmallerOrEquals(settings.minimum, (negative ? '-' : '') + hour + ':' + (hoverMinute < 10 ? '0' : '') + hoverMinute)) isMinMaxFullfilled = false; 941 | if (isMinMaxFullfilled) { 942 | ctx.beginPath(); 943 | ctx.arc(clockCenterX + Math.cos(Math.PI / 6 * ((hoverMinute / 5) - 3)) * clockOuterRadius, 944 | clockCenterY + Math.sin(Math.PI / 6 * ((hoverMinute / 5) - 3)) * clockOuterRadius, 945 | 15, 0, 2 * Math.PI, false); 946 | ctx.fillStyle = settings.colors.hoverCircleColor; 947 | ctx.fill(); 948 | } 949 | } 950 | 951 | //Paint minute selector 952 | ctx.beginPath(); 953 | ctx.arc(clockCenterX, clockCenterY, 3, 0, 2 * Math.PI, false); 954 | ctx.fillStyle = settings.colors.selectorColor; 955 | ctx.fill(); 956 | if (min > -1 && (!settings.maximum || isTimeSmallerOrEquals(hour + ':' + min, settings.maximum)) && (!settings.minimum || isTimeSmallerOrEquals(settings.minimum, hour + ':' + min))) { 957 | ctx.beginPath(); 958 | ctx.moveTo(clockCenterX, clockCenterY); 959 | ctx.lineTo(clockCenterX + Math.cos(Math.PI / 6 * ((min / 5) - 3)) * clockOuterRadius, 960 | clockCenterY + Math.sin(Math.PI / 6 * ((min / 5) - 3)) * clockOuterRadius); 961 | ctx.lineWidth = 1; 962 | ctx.strokeStyle = settings.colors.selectorColor; 963 | ctx.stroke(); 964 | ctx.beginPath(); 965 | ctx.arc(clockCenterX + Math.cos(Math.PI / 6 * ((min / 5) - 3)) * clockOuterRadius, 966 | clockCenterY + Math.sin(Math.PI / 6 * ((min / 5) - 3)) * clockOuterRadius, 967 | 15, 0, 2 * Math.PI, false); 968 | ctx.fillStyle = settings.colors.selectorColor; 969 | ctx.fill(); 970 | } 971 | 972 | //Paint minute numbers 00 - 55 973 | ctx.font = settings.fonts.clockOuterCircleFontSize + 'px ' + settings.fonts.fontFamily; 974 | for(let i = 1; i <= 12; i++) { 975 | if (Math.floor(i * 5 / settings.precision) != i * 5 / settings.precision) continue; 976 | var angle = Math.PI / 6 * (i - 3); 977 | if (min == i * 5 || (min == 0 && i == 12)) ctx.fillStyle = settings.colors.selectorNumberColor; 978 | else ctx.fillStyle = settings.colors.clockOuterCircleTextColor; 979 | var s = i * 5 == 5 ? '05' : i * 5; 980 | if (s == 60) s = '00'; 981 | var isMinMaxFullfilled = true; 982 | if (settings.maximum && !isTimeSmallerOrEquals((negative ? '-' : '') + hour + ':' + s, settings.maximum)) isMinMaxFullfilled = false; 983 | if (settings.minimum && !isTimeSmallerOrEquals(settings.minimum, (negative ? '-' : '') + hour + ':' + s)) isMinMaxFullfilled = false; 984 | if (isMinMaxFullfilled) { 985 | ctx.fillText(s, 986 | clockCenterX + Math.cos(angle) * clockOuterRadius - (ctx.measureText(s).width / 2), 987 | clockCenterY + Math.sin(angle) * clockOuterRadius + (settings.fonts.clockOuterCircleFontSize / 3)); 988 | } 989 | else if (!settings.hideUnselectableNumbers) { 990 | ctx.fillStyle = settings.colors.clockOuterCircleUnselectableTextColor; 991 | ctx.fillText(s, 992 | clockCenterX + Math.cos(angle) * clockOuterRadius - (ctx.measureText(s).width / 2), 993 | clockCenterY + Math.sin(angle) * clockOuterRadius + (settings.fonts.clockOuterCircleFontSize / 3)); 994 | } 995 | } 996 | 997 | //For numbers not dividable by 5 paint a little white dot in the selector circle 998 | if (min > -1 && min % 5 != 0) { 999 | ctx.beginPath(); 1000 | ctx.arc(clockCenterX + Math.cos(Math.PI / 6 * ((min / 5) - 3)) * clockOuterRadius, 1001 | clockCenterY + Math.sin(Math.PI / 6 * ((min / 5) - 3)) * clockOuterRadius, 1002 | 2, 0, 2 * Math.PI, false); 1003 | ctx.fillStyle = 'white'; 1004 | ctx.fill(); 1005 | } 1006 | 1007 | if (settings.duration && settings.durationNegative) repaintSignButton(ctx, hoverSign); 1008 | } 1009 | 1010 | 1011 | /************************************************************************************************ 1012 | ADJUST POPUP DIMENSION AND POSITION (FOR MOBILE PHONES) 1013 | ************************************************************************************************/ 1014 | function adjustMobilePopupDimensionAndPosition() { 1015 | 1016 | var popupHeight; 1017 | 1018 | //Landscape mode 1019 | if (window.innerHeight < 400) { 1020 | popupWidth = window.innerHeight - 60; 1021 | popup.css('width', popupWidth + 200 + 'px'); 1022 | inputElement.css('position', 'absolute') 1023 | .css('left', '0px') 1024 | .css('top', '0px') 1025 | .css('width', '200px') 1026 | .css('height', popupWidth + 20 + 'px'); 1027 | canvasHolder.css('margin', '10px 25px 0px 230px'); 1028 | popupHeight = popupWidth + parseInt(canvasHolder.css('margin-top')) + parseInt(canvasHolder.css('margin-bottom')); 1029 | } 1030 | //Normal mode (enough space for normal popup) 1031 | else { 1032 | popupWidth = window.innerWidth - 80; 1033 | if (popupWidth > 300) popupWidth = 300; 1034 | popup.css('width', popupWidth + 'px'); 1035 | inputElement.css('position', 'static') 1036 | .css('width', '100%') 1037 | .css('height', 'auto'); 1038 | canvasHolder.css('margin', '10px 25px 10px 25px'); 1039 | popupHeight = popupWidth + parseInt(canvasHolder.css('margin-top')) + parseInt(canvasHolder.css('margin-bottom')) + 65; 1040 | } 1041 | 1042 | //Align popup in the middle of the screen 1043 | popup.css('left', parseInt(($('body').prop('clientWidth') - popup.outerWidth()) / 2) + 'px'); 1044 | popup.css('top', parseInt((window.innerHeight - popupHeight) / 2) + 'px'); 1045 | 1046 | canvasSize = popupWidth - 50; 1047 | clockRadius = parseInt(canvasSize / 2); 1048 | clockCenterX = parseInt(canvasSize / 2); 1049 | clockCenterY = parseInt(canvasSize / 2); 1050 | clockOuterRadius = clockRadius - 16; 1051 | clockInnerRadius = clockOuterRadius - 29; 1052 | canvasHolder.css('width', canvasSize + 'px'); 1053 | canvasHolder.css('height', canvasSize + 'px'); 1054 | 1055 | var dpr = window.devicePixelRatio || 1; 1056 | var hourCanvas = clockHourCanvas.get(0); 1057 | var minuteCanvas = clockMinuteCanvas.get(0); 1058 | hourCanvas.width = canvasSize * dpr; 1059 | hourCanvas.height = canvasSize * dpr; 1060 | minuteCanvas.width = canvasSize * dpr; 1061 | minuteCanvas.height = canvasSize * dpr; 1062 | var hourCtx = hourCanvas.getContext('2d'); 1063 | var minuteCtx = minuteCanvas.getContext('2d'); 1064 | hourCtx.scale(dpr, dpr); 1065 | minuteCtx.scale(dpr, dpr); 1066 | 1067 | clockHourCanvas.css('width', canvasSize); 1068 | clockHourCanvas.css('height', canvasSize); 1069 | clockMinuteCanvas.css('width', canvasSize); 1070 | clockMinuteCanvas.css('height', canvasSize); 1071 | } 1072 | 1073 | 1074 | /************************************************************************************************ 1075 | SHOWS THE TIME PICKER 1076 | ************************************************************************************************/ 1077 | function showTimePicker() { 1078 | if (!element.val()) setInputElementValue(formatTime('00:00')); 1079 | else setInputElementValue(formatTime(element.val())); 1080 | if (!isMobile() && settings.onlyShowClockOnMobile) popup.css('visibility', 'hidden'); 1081 | if (isMobile()) adjustMobilePopupDimensionAndPosition(); 1082 | popup.css('display', 'block'); 1083 | repaintClock(); 1084 | if (isMobile()) { 1085 | if (background) background.stop().css('opacity', 0).css('display', 'block').animate({opacity: 1}, 300); 1086 | } else { 1087 | positionPopup(); 1088 | $(window).on('scroll.clockTimePicker', _ => { 1089 | positionPopup(); 1090 | }); 1091 | } 1092 | settings.onOpen.call(element.get(0)); 1093 | } 1094 | 1095 | function positionPopup() { 1096 | var top = element.offset().top - $(window).scrollTop() + element.outerHeight(); 1097 | if (top + popup.outerHeight() > window.innerHeight) { 1098 | var newTop = element.offset().top - $(window).scrollTop() - popup.outerHeight(); 1099 | if (newTop >= 0) top = newTop; 1100 | } 1101 | var left = element.offset().left - $(window).scrollLeft() - parseInt((popup.outerWidth() - element.outerWidth()) / 2); 1102 | popup.css('left', left + 'px').css('top', top + 'px'); 1103 | } 1104 | 1105 | 1106 | 1107 | /************************************************************************************************ 1108 | HIDES THE TIME PICKER 1109 | ************************************************************************************************/ 1110 | function hideTimePicker() { 1111 | $(window).off('scroll.clockTimePicker'); 1112 | var newValue = formatTime(element.val()); 1113 | enteredDigits = ''; 1114 | popup.css('display', 'none'); 1115 | if (isMobile()) { 1116 | background.stop().animate({opacity: 0}, 300, function() { background.css('display', 'none'); }); 1117 | } else { 1118 | element.val(newValue); 1119 | } 1120 | blurAll(); 1121 | if (!isTimeChanged && !oldValue && newValue.match(new RegExp('^0+' + settings.separator + '00$'))) { 1122 | setInputElementValue(''); 1123 | } 1124 | else if (oldValue != newValue) { 1125 | if ('createEvent' in document) { 1126 | var evt = document.createEvent('HTMLEvents'); 1127 | evt.initEvent('change', true, false); 1128 | element.get(0).dispatchEvent(evt); 1129 | } 1130 | else { 1131 | var evt = document.createEventObject(); 1132 | evt.eventType = 'click'; 1133 | element.get(0).fireEvent('onchange', evt); 1134 | } 1135 | settings.onChange.call(element.get(0), newValue.replace(/^\+/, ''), oldValue.replace(/^\+/, '')); 1136 | oldValue = newValue; 1137 | } 1138 | settings.onClose.call(element.get(0)); 1139 | isTimeChanged = false; 1140 | } 1141 | 1142 | 1143 | 1144 | /************************************************************************************************ 1145 | SWITCH FROM MINUTE SELECTION MODE TO HOUR SELECTION MODE 1146 | ************************************************************************************************/ 1147 | function switchToHourMode(surpressAnimation) { 1148 | if (selectionMode == 'HOUR') return; 1149 | enteredDigits = ''; 1150 | repaintClockHourCanvas(); 1151 | if (surpressAnimation) { 1152 | clockMinuteCanvas.css('display', 'none'); 1153 | } 1154 | else { 1155 | clockMinuteCanvas.css('zIndex', 2).stop().animate({opacity: 0, zoom:'80%', left:'10%', top:'10%'}, settings.modeSwitchSpeed, function() { 1156 | clockMinuteCanvas.css('display', 'none'); 1157 | }); 1158 | } 1159 | clockHourCanvas.stop().css('zoom', '100%') 1160 | .css('left', '0px') 1161 | .css('top', '0px') 1162 | .css('display', 'block') 1163 | .css('opacity', 1) 1164 | .css('zIndex', 1); 1165 | selectionMode = 'HOUR'; 1166 | settings.onModeSwitch.call(element.get(0), selectionMode); 1167 | } 1168 | 1169 | 1170 | 1171 | /************************************************************************************************ 1172 | SWITCH FROM HOUR SELECTION MODE TO MINUTE SELECTION MODE 1173 | ************************************************************************************************/ 1174 | function switchToMinuteMode(surpressAnimation) { 1175 | if (selectionMode == 'MINUTE') return; 1176 | enteredDigits = ''; 1177 | repaintClockMinuteCanvas(); 1178 | clockMinuteCanvas.stop().css('display', 'block') 1179 | .css('zoom', '80%') 1180 | .css('left', '10%') 1181 | .css('top', '10%') 1182 | .css('opacity', 0) 1183 | .css('zIndex', 1); 1184 | if (surpressAnimation) { 1185 | clockMinuteCanvas.css('opacity', 1) 1186 | .css('zoom', '100%') 1187 | .css('left', '0px') 1188 | .css('top', '0px'); 1189 | } 1190 | else { 1191 | clockMinuteCanvas.animate({opacity: 1, zoom:'100%', left:'0px', top:'0px'}); 1192 | } 1193 | selectionMode = 'MINUTE'; 1194 | settings.onModeSwitch.call(element.get(0), selectionMode); 1195 | } 1196 | 1197 | 1198 | 1199 | /************************************************************************************************ 1200 | SELECT HOUR ON INPUT ELEMENT 1201 | ************************************************************************************************/ 1202 | function selectHourOnInputElement() { 1203 | inputElement.focus(); 1204 | setTimeout(function() { 1205 | if (isMobile()) { 1206 | $('.clock-timepicker-mobile-time-hours').css('backgroundColor', 'rgba(255, 255, 255, 0.6)'); 1207 | $('.clock-timepicker-mobile-time-minutes').css('backgroundColor', 'inherit'); 1208 | } else { 1209 | inputElement.get(0).setSelectionRange(0, getInputElementValue().indexOf(settings.separator)); 1210 | } 1211 | }, 1); 1212 | } 1213 | 1214 | 1215 | 1216 | /************************************************************************************************ 1217 | SELECT MINUTE ON INPUT ELEMENT 1218 | ************************************************************************************************/ 1219 | function selectMinuteOnInputElement() { 1220 | inputElement.focus(); 1221 | setTimeout(function() { 1222 | if (isMobile()) { 1223 | $('.clock-timepicker-mobile-time-hours').css('backgroundColor', 'inherit'); 1224 | $('.clock-timepicker-mobile-time-minutes').css('backgroundColor', 'rgba(255, 255, 255, 0.6)'); 1225 | } else { 1226 | inputElement.get(0).setSelectionRange(getInputElementValue().indexOf(settings.separator) + 1, getInputElementValue().length); 1227 | } 1228 | }, 1); 1229 | } 1230 | 1231 | 1232 | 1233 | /************************************************************************************************ 1234 | AUTOSIZE INPUT ELEMENT 1235 | ************************************************************************************************/ 1236 | function autosize() { 1237 | if (!settings.autosize || isMobile()) return; 1238 | tempAutosizeElement.html(element.val()); 1239 | tempAutosizeElement.css('display', 'inline-block'); 1240 | element.css('width', tempAutosizeElement.outerWidth() + 5 + parseInt(element.css('padding-left')) + parseInt(element.css('padding-right')) + 'px'); 1241 | tempAutosizeElement.css('display', 'none'); 1242 | } 1243 | 1244 | 1245 | 1246 | /************************************************************************************************ 1247 | FORMATS THE TIME 1248 | ************************************************************************************************/ 1249 | function formatTime(time) { 1250 | if (time == '') { 1251 | if (settings.required) return settings.duration ? '0:00' : '00:00'; 1252 | else return time; 1253 | } 1254 | if ((new RegExp('^(-|\\+)?([0-9]+)(.([0-9]{1,2})?)?$', 'i')).test(time)) { 1255 | var hour = parseInt(RegExp.$2); 1256 | var min = parseInt(RegExp.$4); 1257 | if (!min) min = 0; 1258 | var negative = settings.duration && settings.durationNegative && RegExp.$1 == '-' ? true : false; 1259 | if (hour >= 24 && !settings.duration) hour = hour % 24; 1260 | if (min >= 60) min = min % 60; 1261 | if (settings.precision != 1) { 1262 | var f = Math.floor(min / settings.precision); 1263 | min = f * settings.precision + (Math.round((min - f * settings.precision) / settings.precision) == 1 ? settings.precision : 0); 1264 | if (min == 60) { 1265 | min = 0; 1266 | hour++; 1267 | if (hour == 24 && !settings.duration) hour = 0; 1268 | } 1269 | } 1270 | time = (negative ? '-' : '') + (hour < 10 && !settings.duration ? '0' : '') + hour + settings.separator + (RegExp.$3 ? (min < 10 ? '0' : '') + min : '00'); 1271 | } 1272 | else if ((new RegExp('^(-|\\+)?.([0-9]{1,2})')).test(time)) { 1273 | var min = parseInt(RegExp.$2); 1274 | var negative = settings.duration && settings.durationNegative && RegExp.$1 == '-' ? true : false; 1275 | if (min >= 60) min = min % 60; 1276 | time = (negative && min > 0 ? '-' : '') + '0' + (!settings.duration ? '0' : '') + settings.separator + (min < 10 ? '0' : '') + min; 1277 | } 1278 | else { 1279 | time = '0' + (!settings.duration ? '0' : '') + settings.separator + '00'; 1280 | } 1281 | return (settings.duration && settings.useDurationPlusSign && !time.match(/^\-/) && !time.match(/^0+:00$/) ? '+' : '') + time; 1282 | } 1283 | 1284 | 1285 | 1286 | /************************************************************************************************ 1287 | DISPOSES AN INITIALIZED CLOCK TIME PICKER 1288 | ************************************************************************************************/ 1289 | function disposeTimePicker(element) { 1290 | element.parent().find('.clock-timepicker-autosize').remove(); 1291 | element.parent().find('.clock-timepicker-background').remove(); 1292 | element.parent().find('.clock-timepicker-popup').remove(); 1293 | element.unwrap(); 1294 | element.off('drag.clockTimePicker dragend.clockTimePicker dragover.clockTimePicker dragenter.clockTimePicker dragstart.clockTimePicker dragleave.clockTimePicker drop.clockTimePicker selectstart.clockTimePicker contextmenu.clockTimePicker'); 1295 | element.off('mousedown.clockTimePicker'); 1296 | element.off('keyup.clockTimePicker'); 1297 | element.off('keydown.clockTimePicker'); 1298 | element.off('mousewheel.clockTimePicker'); 1299 | element.off('focus.clockTimePicker'); 1300 | if (element.attr('data-autocomplete-orig')) { 1301 | element.attr('autocomplete', element.attr('data-autocomplete-orig')); 1302 | element.removeAttr('data-autocomplete-orig'); 1303 | } else element.removeAttr('autocomplete'); 1304 | if (element.attr('data-autocorrect-orig')) { 1305 | element.attr('autocorrect', element.attr('data-autocorrect-orig')); 1306 | element.removeAttr('data-autocorrect-orig'); 1307 | } else element.removeAttr('autocorrect'); 1308 | if (element.attr('data-autocapitalize-orig')) { 1309 | element.attr('autocapitalize', element.attr('data-autocapitalize-orig')); 1310 | element.removeAttr('data-autocapitalize-orig'); 1311 | } else element.removeAttr('autocapitalize'); 1312 | if (element.attr('data-spellcheck-orig')) { 1313 | element.attr('spellcheck', element.attr('data-spellcheck-orig')); 1314 | element.removeAttr('data-spellcheck-orig'); 1315 | } else element.removeAttr('spellcheck'); 1316 | } 1317 | 1318 | 1319 | 1320 | /************************************************************************************************ 1321 | ELEMENT EVENTS 1322 | ************************************************************************************************/ 1323 | function onInputElementMouseWheel(event) { 1324 | if (element.is(":focus")) processMouseWheelEvent(event); 1325 | } 1326 | 1327 | 1328 | function onInputElementFocus(event) { 1329 | if (isMobile()) { 1330 | showTimePicker(); 1331 | switchToHourMode(true); 1332 | selectHourOnInputElement(); 1333 | } else { 1334 | setTimeout(function() { 1335 | if (popup.css('display') == 'none') onInputElementMouseDown(event); 1336 | }, 50); 1337 | } 1338 | } 1339 | 1340 | 1341 | function onInputElementDragSelectContextMenu(event) { 1342 | if (!settings.contextmenu || event.which == 1) { 1343 | event.stopImmediatePropagation(); 1344 | event.preventDefault(); 1345 | return false; 1346 | } 1347 | } 1348 | 1349 | 1350 | function onInputElementMouseDown(event) { 1351 | if (!settings.contextmenu || event.which == 1) { 1352 | processClick(event); 1353 | event.stopImmediatePropagation(); 1354 | event.stopPropagation(); 1355 | event.preventDefault(); 1356 | return false; 1357 | } 1358 | } 1359 | 1360 | 1361 | function onInputElementKeyDown(event) { 1362 | //TABULATOR 1363 | if (event.keyCode == 9) { 1364 | hideTimePicker(); 1365 | } 1366 | //ENTER 1367 | else if (event.keyCode == 13) { 1368 | hideTimePicker(); 1369 | } 1370 | //ESC 1371 | else if (event.keyCode == 27) { 1372 | setInputElementValue(formatTime(oldValue)); 1373 | hideTimePicker(); 1374 | } 1375 | //BACKSPACE OR DELETE 1376 | else if (event.keyCode == 8 || event.keyCode == 46) { 1377 | enteredDigits = ''; 1378 | if (!getInputElementValue()) return false; 1379 | var oldVal = getInputElementValue(); 1380 | var newVal; 1381 | event.preventDefault(); 1382 | (new RegExp('^(-|\\+)?([0-9]+)(.([0-9]{1,2}))?$')).test(getInputElementValue()); 1383 | var negative = settings.duration && settings.durationNegative && RegExp.$1 == '-' ? true : false; 1384 | var h = parseInt(RegExp.$2); 1385 | var m = RegExp.$4 ? parseInt(RegExp.$4) : 0; 1386 | if (selectionMode == 'HOUR') { 1387 | if (h == 0) { 1388 | newVal = settings.required ? (!settings.duration ? '0' : '') +'0' + settings.separator + '00' : ''; 1389 | } else { 1390 | newVal = (!settings.duration ? '0' : '') + '0' + settings.separator + (m < 10 ? '0' : '') + m; 1391 | } 1392 | setInputElementValue(formatTime(newVal)); 1393 | if (!newVal) { 1394 | hideTimePicker(); 1395 | } else { 1396 | selectHourOnInputElement(); 1397 | } 1398 | if (oldVal != newVal) { 1399 | element.attr('value', newVal.replace(/^\+/, '')); 1400 | settings.onAdjust.call(element.get(0), newVal.replace(/^\+/, ''), oldVal.replace(/^\+/, '')); 1401 | } 1402 | } else { 1403 | if (m == 0) { 1404 | if (h == 0 && !settings.required) { 1405 | setInputElementValue(''); 1406 | if (oldVal != '') { 1407 | element.attr('value', ''); 1408 | settings.onAdjust.call(element.get(0), '', oldVal.replace(/^\+/, '')); 1409 | } 1410 | hideTimePicker(); 1411 | } else { 1412 | switchToHourMode(); 1413 | selectHourOnInputElement(); 1414 | } 1415 | } else { 1416 | newVal = (negative ? '-' : '') + (h < 10 && !settings.duration ? '0' : '') + h + settings.separator + '00'; 1417 | setInputElementValue(formatTime(newVal)); 1418 | selectMinuteOnInputElement(); 1419 | if (oldVal != newVal) { 1420 | element.attr('value', newVal.replace(/^\+/, '')); 1421 | settings.onAdjust.call(element.get(0), newVal.replace(/^\+/, ''), oldVal.replace(/^\+/, '')); 1422 | } 1423 | } 1424 | } 1425 | autosize(); 1426 | } 1427 | //ARROW LEFT OR HOME 1428 | else if ((event.keyCode == 36 || event.keyCode == 37) && getInputElementValue() != '') { 1429 | setInputElementValue(formatTime(getInputElementValue())); 1430 | if (selectionMode != 'HOUR') { 1431 | selectHourOnInputElement(); 1432 | switchToHourMode(); 1433 | } else { 1434 | event.preventDefault(); 1435 | event.stopPropagation(); 1436 | } 1437 | } 1438 | //ARROW RIGHT OR END 1439 | else if ((event.keyCode == 35 || event.keyCode == 39) && getInputElementValue() != '') { 1440 | setInputElementValue(formatTime(getInputElementValue())); 1441 | if (settings.precision != 60 && selectionMode != 'MINUTE') { 1442 | selectMinuteOnInputElement(); 1443 | switchToMinuteMode(); 1444 | } else { 1445 | event.preventDefault(); 1446 | event.stopPropagation(); 1447 | } 1448 | } 1449 | //COLON OR DOT 1450 | else if (event.keyCode == 190 || event.key == settings.separator) { 1451 | event.preventDefault(); 1452 | if (getInputElementValue().length == 0) setInputElementValue('0'); 1453 | setInputElementValue(formatTime(getInputElementValue())); 1454 | if (settings.precision != 60) { 1455 | selectMinuteOnInputElement(); 1456 | if (selectionMode != 'MINUTE') switchToMinuteMode(); 1457 | } else { 1458 | selectHourOnInputElement(); 1459 | } 1460 | } 1461 | //"+" SIGN 1462 | else if (event.key == '+' && settings.duration && settings.durationNegative) { 1463 | event.preventDefault(); 1464 | var oldVal = getInputElementValue(); 1465 | if (oldVal[0] == '-') { 1466 | var newVal = oldVal.substring(1); 1467 | setInputElementValue(formatTime(newVal)); 1468 | element.attr('value', newVal); 1469 | settings.onAdjust.call(element.get(0), newVal, oldVal); 1470 | autosize(); 1471 | repaintClock(); 1472 | if (selectionMode == 'HOUR') selectHourOnInputElement(); 1473 | else selectMinuteOnInputElement(); 1474 | } 1475 | } 1476 | //"-" SIGN 1477 | else if (event.key == '-' && settings.duration && settings.durationNegative) { 1478 | event.preventDefault(); 1479 | var oldVal = getInputElementValue().replace(/^\+/, ''); 1480 | if (oldVal[0] != '-') { 1481 | var newVal = '-' + oldVal; 1482 | setInputElementValue(formatTime(newVal)); 1483 | element.attr('value', newVal); 1484 | settings.onAdjust.call(element.get(0), newVal, oldVal); 1485 | autosize(); 1486 | repaintClock(); 1487 | if (selectionMode == 'HOUR') selectHourOnInputElement(); 1488 | else selectMinuteOnInputElement(); 1489 | } 1490 | } 1491 | //ARROW UP OR "+" SIGN, ARROW DOWN OR "-" SIGN 1492 | else if (event.keyCode == 38 || event.key == '+' || event.keyCode == 40 || event.key == '-') { 1493 | event.preventDefault(); 1494 | var oldVal = getInputElementValue(); 1495 | (new RegExp('^(-|\\+)?([0-9]+)(.([0-9]{1,2}))?$')).test(oldVal); 1496 | var h = parseInt(RegExp.$2); 1497 | if (settings.duration && settings.durationNegative && RegExp.$1 == '-') h = -h; 1498 | var m = RegExp.$4 ? parseInt(RegExp.$4) : 0; 1499 | if (selectionMode == 'HOUR') h += event.keyCode == 38 || event.key == '+' ? 1 : -1; 1500 | else { 1501 | m += (event.keyCode == 38 || event.key == '+' ? 1 : -1) * settings.precision; 1502 | if (m < 0) m = 0; 1503 | else if (m > 59) m = 60 - settings.precision; 1504 | } 1505 | var min = settings.minimum; 1506 | if ((!settings.duration || !settings.durationNegative) && min[0] == '-') min = '0:00'; 1507 | var max = settings.maximum; 1508 | if (settings.precision != 1) { 1509 | var minPart = parseInt(max.replace(/^(\+|-)?[0-9]+./, '')); 1510 | max = max.replace(/.[0-9]+$/, '') + settings.separator + (minPart - (minPart % settings.precision)); 1511 | } 1512 | var newVal = (h < 0 ? '-' : '') + (h < 10 && !settings.duration ? '0': '') + Math.abs(h) + settings.separator + (m < 10 ? '0' : '') + m; 1513 | if (selectionMode == 'HOUR') { 1514 | if (!isTimeSmallerOrEquals(newVal, max)) newVal = max; 1515 | else if (!isTimeSmallerOrEquals(min, newVal)) newVal = min; 1516 | } 1517 | if (oldVal != newVal) { 1518 | setInputElementValue(formatTime(newVal)); 1519 | element.attr('value', newVal.replace(/^\+/, '')); 1520 | settings.onAdjust.call(element.get(0), newVal.replace(/^\+/, ''), oldVal.replace(/^\+/, '')); 1521 | autosize(); 1522 | repaintClock(); 1523 | if (selectionMode == 'HOUR') selectHourOnInputElement(); 1524 | else selectMinuteOnInputElement(); 1525 | } 1526 | } 1527 | else { 1528 | event.preventDefault(); 1529 | event.stopPropagation(); 1530 | event.stopImmediatePropagation(); 1531 | return false; 1532 | } 1533 | } 1534 | 1535 | 1536 | function onInputElementKeyUp(event) { 1537 | if (event.shiftKey || event.ctrlKey || event.altKey || !event.key.match(/^[0-9]{1}$/)) return; 1538 | var hourPart = getInputElementValue().replace(/.[0-9]+$/, ''); 1539 | var minPart = getInputElementValue().replace(/^(\+|-)?[0-9]+./, ''); 1540 | var isNegative = getInputElementValue()[0] == '-'; 1541 | var oldVal = getInputElementValue(); 1542 | enteredDigits += event.key; 1543 | var newVal = (selectionMode == 'HOUR' ? (isNegative ? '-' : '') + (!settings.duration && enteredDigits.length == 1 ? '0' : '') + enteredDigits : hourPart) + settings.separator + (selectionMode == 'HOUR' ? minPart : (enteredDigits.length == 1 ? '0' : '') + enteredDigits); 1544 | if (isTimeSmallerOrEquals(newVal, settings.minimum)) newVal = settings.minimum; 1545 | if (isTimeSmallerOrEquals(settings.maximum, newVal)) newVal = settings.maximum; 1546 | newVal = formatTime(newVal); 1547 | setInputElementValue(newVal); 1548 | isTimeChanged = true; 1549 | var nextPossibleVal = (selectionMode == 'HOUR' ? (isNegative ? '-' : '') + (enteredDigits + '0') : hourPart) + settings.separator + (selectionMode == 'HOUR' ? '00' : (enteredDigits + '0')); 1550 | if ((selectionMode == 'MINUTE' && (enteredDigits.length == 2 || parseInt(enteredDigits + '0') >= 60)) || (selectionMode == 'HOUR' && !settings.duration && enteredDigits.length == 2) || (isNegative ? !isTimeSmallerOrEquals(settings.minimum, nextPossibleVal) : !isTimeSmallerOrEquals(nextPossibleVal, settings.maximum))) { 1551 | enteredDigits = ''; 1552 | if (selectionMode == 'HOUR') { 1553 | if (settings.precision == 60 || (newVal == settings.maximum && settings.maximum.match(/00$/)) || (settings.minimum[0] == '-' && newVal == settings.minimum && settings.minimum.match(/00$/))) { 1554 | hideTimePicker(); 1555 | return; 1556 | } 1557 | else { 1558 | switchToMinuteMode(); 1559 | selectMinuteOnInputElement(); 1560 | return; 1561 | } 1562 | } else { 1563 | hideTimePicker(); 1564 | return; 1565 | } 1566 | } 1567 | if (selectionMode == 'HOUR') selectHourOnInputElement(); 1568 | else selectMinuteOnInputElement(); 1569 | if (newVal != oldVal) { 1570 | element.attr('value', newVal.replace(/^\+/, '')); 1571 | settings.onAdjust.call(element.get(0), newVal.replace(/^\+/, ''), oldVal.replace(/^\+/, '')); 1572 | } 1573 | autosize(); 1574 | repaintClock(); 1575 | } 1576 | 1577 | 1578 | function getInputElementValue() { 1579 | if (isMobile()) { 1580 | return $('.clock-timepicker-mobile-time-hours').html() + settings.separator + $('.clock-timepicker-mobile-time-minutes').html(); 1581 | } 1582 | else { 1583 | return inputElement.val(); 1584 | } 1585 | } 1586 | 1587 | 1588 | function setInputElementValue(value) { 1589 | if (isMobile()) { 1590 | if (value.match(/^(-|\\+)?([0-9]{1,2}).([0-9]{1,2})$/)) { 1591 | var hours = RegExp.$1 + (!settings.duration && RegExp.$2.length == 1 ? '0' : '') + RegExp.$2; 1592 | var minutes = (RegExp.$3.length == 1 ? '0' : '') + RegExp.$3; 1593 | $('.clock-timepicker-mobile-time-hours').html(hours); 1594 | $('.clock-timepicker-mobile-time-minutes').html(minutes); 1595 | } 1596 | } 1597 | else { 1598 | inputElement.val(value); 1599 | } 1600 | } 1601 | }); 1602 | 1603 | /************************************************************************************************ 1604 | CHECKS IF THE DEVICE IS A MOBILE 1605 | ************************************************************************************************/ 1606 | function isMobile() { 1607 | var check = false; 1608 | (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera); 1609 | return check; 1610 | } 1611 | 1612 | /************************************************************************************************ 1613 | FUNCTION TO COMPARE TWO TIMES 1614 | ************************************************************************************************/ 1615 | function isTimeSmallerOrEquals(time1, time2, doNotInvolveMinutePart) { 1616 | var regex = '^(-|\\+)?([0-9]+)(.([0-9]{1,2}))?$'; 1617 | (new RegExp(regex, 'i')).test(time1); 1618 | var t1 = parseInt(RegExp.$2) * 60; 1619 | if (RegExp.$4 && !doNotInvolveMinutePart) t1 += parseInt(RegExp.$4); 1620 | if (RegExp.$1 == '-') t1 *= -1; 1621 | (new RegExp(regex, 'i')).test(time2); 1622 | var t2 = parseInt(RegExp.$2) * 60; 1623 | if (RegExp.$4 && !doNotInvolveMinutePart) t2 += parseInt(RegExp.$4); 1624 | if (RegExp.$1 == '-') t2 *= -1; 1625 | if (t1 <= t2) return true; 1626 | else return false; 1627 | } 1628 | 1629 | function validateSettings() { 1630 | settings.precision = parseInt(settings.precision); 1631 | settings.modeSwitchSpeed = parseInt(settings.modeSwitchSpeed); 1632 | settings.popupWidthOnDesktop = parseInt(settings.popupWidthOnDesktop); 1633 | settings.fonts.clockOuterCircleFontSize = parseInt(settings.fonts.clockOuterCircleFontSize); 1634 | settings.fonts.clockInnerCircleFontSize = parseInt(settings.fonts.clockInnerCircleFontSize); 1635 | settings.fonts.buttonFontSize = parseInt(settings.fonts.buttonFontSize); 1636 | 1637 | if (settings.precision != 1 && settings.precision != 5 && settings.precision != 10 && settings.precision != 15 && settings.precision != 30 && settings.precision != 60) { 1638 | console.error('%c[jquery-clock-timepicker] Invalid precision specified: ' + settings.precision + '! Precision has to be 1, 5, 10, 15, 30 or 60. For now, the precision has been set back to: 1', 'color:orange'); 1639 | settings.precision = 1; 1640 | } 1641 | if (!settings.separator || ('' + settings.separator).match(/[0-9]+/)) { 1642 | console.error('%c[jquery-clock-timepicker] Invalid separator specified: ' + (settings.separator ? settings.separator : '(empty)') + '! The separator cannot be empty nor can it contain any decimals. For now, the separator has been set back to a colon (:).', 'color:orange'); 1643 | settings.separator = ':'; 1644 | } 1645 | if (settings.durationNegative && !settings.duration) { 1646 | console.log('%c[jquery-clock-timepicker] durationNegative is set to true, but this has no effect because duration is false!', 'color:orange'); 1647 | } 1648 | if (settings.maximum && !settings.maximum.match(/^-?[0-9]+:[0-9]{2}$/)) { 1649 | console.log('%c[jquery-clock-timepicker] Invalid time format for option "maximum": ' + settings.maximum + '! Maximum not used...', 'color:orange'); 1650 | settings.maximum = null; 1651 | } 1652 | if (settings.minimum && !settings.minimum.match(/^-?[0-9]+:[0-9]{2}$/)) { 1653 | console.log('%c[jquery-clock-timepicker] Invalid time format for option "minimum": ' + settings.minimum + '! Minimum not used...', 'color:orange'); 1654 | settings.minimum = null; 1655 | } 1656 | if (settings.minimum && settings.maximum && (settings.minimum == settings.maximum || !isTimeSmallerOrEquals(settings.minimum, settings.maximum))) { 1657 | console.log('%c[jquery-clock-timepicker] Option "minimum" must be smaller than the option "maximum"!', 'color:orange'); 1658 | settings.minimum = null; 1659 | } 1660 | } 1661 | }; 1662 | }(jQuery)); 1663 | -------------------------------------------------------------------------------- /jquery-clock-timepicker.min.js: -------------------------------------------------------------------------------- 1 | !function(e){e.fn.clockTimePicker=function(t,o){if("string"==typeof t&&("value"==t||"val"==t)&&!o)return e(this).val();var i,r=e.extend(!0,{afternoonHoursInOuterCircle:!1,alwaysSelectHoursFirst:!1,autosize:!1,contextmenu:!1,colors:{buttonTextColor:"#0797FF",clockFaceColor:"#EEEEEE",clockInnerCircleTextColor:"#888888",clockInnerCircleUnselectableTextColor:"#CCCCCC",clockOuterCircleTextColor:"#000000",clockOuterCircleUnselectableTextColor:"#CCCCCC",hoverCircleColor:"#DDDDDD",popupBackgroundColor:"#FFFFFF",popupHeaderBackgroundColor:"#0797FF",popupHeaderTextColor:"#FFFFFF",selectorColor:"#0797FF",selectorNumberColor:"#FFFFFF",signButtonColor:"#FFFFFF",signButtonBackgroundColor:"#0797FF"},duration:!1,durationNegative:!1,fonts:{fontFamily:"Arial",clockOuterCircleFontSize:14,clockInnerCircleFontSize:12,buttonFontSize:20},hideUnselectableNumbers:!1,i18n:{okButton:"OK",cancelButton:"Cancel"},maximum:"23:59",minimum:"-23:59",modeSwitchSpeed:500,onlyShowClockOnMobile:!1,onAdjust:function(e,t){},onChange:function(e,t){},onClose:function(){},onModeSwitch:function(){},onOpen:function(){},popupWidthOnDesktop:200,precision:1,required:!1,separator:":",useDurationPlusSign:!1,vibrate:!0},"object"==typeof t?t:{}),a=".clock-timepicker input { caret-color: transparent; }";if(n()&&(a+=" .clock-timepicker input::selection { background:rgba(255,255,255,0.6); } .clock-timepicker input::-moz-selection { background:rgba(255,255,255,0.6); }"),i=!1,e("head style").each(function(){if(e(this).text()==a)return i=!0,!1}),!i){var c=document.createElement("style");c.type="text/css",c.styleSheet?c.styleSheet.cssText=a:c.appendChild(document.createTextNode(a)),(document.head||document.getElementsByTagName("head")[0]).appendChild(c)}return this.each(function(){var i,a=e(this),c=a.data();for(var s in c)r.hasOwnProperty(s)&&(r[s]=c[s]);if(r.precision=parseInt(r.precision),r.modeSwitchSpeed=parseInt(r.modeSwitchSpeed),r.popupWidthOnDesktop=parseInt(r.popupWidthOnDesktop),r.fonts.clockOuterCircleFontSize=parseInt(r.fonts.clockOuterCircleFontSize),r.fonts.clockInnerCircleFontSize=parseInt(r.fonts.clockInnerCircleFontSize),r.fonts.buttonFontSize=parseInt(r.fonts.buttonFontSize),1!=r.precision&&5!=r.precision&&10!=r.precision&&15!=r.precision&&30!=r.precision&&60!=r.precision&&(console.error("%c[jquery-clock-timepicker] Invalid precision specified: "+r.precision+"! Precision has to be 1, 5, 10, 15, 30 or 60. For now, the precision has been set back to: 1","color:orange"),r.precision=1),(!r.separator||(""+r.separator).match(/[0-9]+/))&&(console.error("%c[jquery-clock-timepicker] Invalid separator specified: "+(r.separator?r.separator:"(empty)")+"! The separator cannot be empty nor can it contain any decimals. For now, the separator has been set back to a colon (:).","color:orange"),r.separator=":"),r.durationNegative&&!r.duration&&console.log("%c[jquery-clock-timepicker] durationNegative is set to true, but this has no effect because duration is false!","color:orange"),r.maximum&&!r.maximum.match(/^-?[0-9]+:[0-9]{2}$/)&&(console.log('%c[jquery-clock-timepicker] Invalid time format for option "maximum": '+r.maximum+"! Maximum not used...","color:orange"),r.maximum=null),r.minimum&&!r.minimum.match(/^-?[0-9]+:[0-9]{2}$/)&&(console.log('%c[jquery-clock-timepicker] Invalid time format for option "minimum": '+r.minimum+"! Minimum not used...","color:orange"),r.minimum=null),r.minimum&&r.maximum&&(r.minimum==r.maximum||!l(r.minimum,r.maximum))&&(console.log('%c[jquery-clock-timepicker] Option "minimum" must be smaller than the option "maximum"!',"color:orange"),r.minimum=null),"vibrate"in navigator||(r.vibrate=!1),"string"==typeof t){if(e(this).parent().hasClass("clock-timepicker")){if("dispose"==(t=t.toLowerCase()))ec(e(this));else if("value"==t||"val"==t){e(this).val(ea(o));var m=e(this).parent().find(".clock-timepicker-mobile-input");m.length>0&&m.val(ea(o))}else"show"==t?e(this).parent().find("canvas:first").trigger("keydown"):"hide"==t?(e(this).parent().find(".clock-timepicker-popup").css("display","none"),e(this).blur()):console.log("%c[jquery-clock-timepicker] Invalid option passed to clockTimePicker: "+t,"color:red")}else console.log("%c[jquery-clock-timepicker] Before calling a function, please initialize the ClockTimePicker!","color:red");return}e(this).parent().hasClass("clock-timepicker")&&ec(e(this)),a.val(ea(a.val())),n()&&a.prop("readonly",!0);var u=a.val(),p="",$="HOUR",d=!1,f=!1,k=n()?e(document).width()-80:r.popupWidthOnDesktop,g=k-(n()?50:20),v=parseInt(g/2),h=parseInt(g/2),_=parseInt(g/2),x=v-16,b=x-29,y=!1,C=0;a.wrap('
');var w=e('
');if(w.css("position","absolute").css("opacity",0).css("display","none").css("top",parseInt(a.css("margin-top"))+"px").css("left","0px").css("font-size",a.css("font-size")).css("font-family",a.css("font-family")).css("font-weight",a.css("font-weight")).css("line-height",a.css("line-height")),a.parent().append(w),a.css("min-width",a.outerWidth()),er(),n()){function P(e){e.preventDefault()}function T(e){return e.preventDefault(),e.stopImmediatePropagation(),"HOUR"==$?eo():ei(),!1}(i=e('
')).css("zIndex",99998).css("display","none").css("position","fixed").css("top","0px").css("left","0px").css("width","100%").css("height","100%").css("backgroundColor","rgba(0,0,0,0.6)"),a.parent().append(i),i.off("touchmove",P),i.on("touchmove",P),i.off("click",T),i.on("click",T)}var I=e('
');if(I.css("display","none").css("zIndex",99999).css("cursor","default").css("position","fixed").css("width",k+"px").css("backgroundColor",r.colors.popupBackgroundColor).css("box-shadow","0 4px 20px 0px rgba(0, 0, 0, 0.14)").css("border-radius","5px").css("overflow","hidden").css("user-select","none"),I.on("contextmenu",function(){return!1}),n()){function O(e){e.preventDefault()}function S(e){return e.stopImmediatePropagation(),"HOUR"==$?eo():ei(),!1}I.css("left","40px").css("top","40px"),window.addEventListener("orientationchange",function(){setTimeout(function(){J(),Y()},500)}),I.off("touchmove",O),I.on("touchmove",O),I.off("click",S),I.on("click",S)}if(a.parent().append(I),!n()){function F(t){"none"==I.css("display")||e(t.target)[0]==H[0]||e.contains(H.parent()[0],e(t.target)[0])||Z()}e(window).off("click.clockTimePicker",F),e(window).on("click.clockTimePicker",F)}var H=a;if(n()){(H=e('
')).css("width","100%").css("fontFamily",r.fonts.fontFamily).css("fontSize","40px").css("padding","10px 0px").css("textAlign","center").css("color",r.colors.popupHeaderTextColor).css("backgroundColor",r.colors.popupHeaderBackgroundColor);var z=e('');H.append(z);var U=e("");U.html(r.separator),H.append(U);var N=e('');H.append(N),I.append(H)}a.attr("autocomplete")&&a.attr("data-autocomplete-orig",a.attr("autocomplete")),a.prop("autocomplete","off"),a.attr("autocorrect")&&a.attr("data-autocorrect-orig",a.attr("autocorrect")),a.prop("autocorrect","off"),a.attr("autocapitalize")&&a.attr("data-autocapitalize-orig",a.attr("autocapitalize")),a.prop("autocapitalize","off"),a.attr("spellcheck")&&a.attr("data-spellcheck-orig",a.attr("spellcheck")),a.prop("spellcheck",!1),H.on("drag.clockTimePicker dragend.clockTimePicker dragover.clockTimePicker dragenter.clockTimePicker dragstart.clockTimePicker dragleave.clockTimePicker drop.clockTimePicker selectstart.clockTimePicker contextmenu.clockTimePicker",function e(t){if(!r.contextmenu||1==t.which)return t.stopImmediatePropagation(),t.preventDefault(),!1}),H.on("mousedown.clockTimePicker",en),H.on("keyup.clockTimePicker",function e(t){if(!t.shiftKey&&!t.ctrlKey&&!t.altKey&&t.key.match(/^[0-9]{1}$/)){var o=el().replace(/.[0-9]+$/,""),i=el().replace(/^(\+|-)?[0-9]+./,""),c="-"==el()[0],n=el();p+=t.key;var s=("HOUR"==$?(c?"-":"")+(r.duration||1!=p.length?"":"0")+p:o)+r.separator+("HOUR"==$?i:(1==p.length?"0":"")+p);l(s,r.minimum)&&(s=r.minimum),l(r.maximum,s)&&(s=r.maximum),s=ea(s),es(s),y=!0;var m=("HOUR"==$?(c?"-":"")+p+"0":o)+r.separator+("HOUR"==$?"00":p+"0");if("MINUTE"==$&&(2==p.length||parseInt(p+"0")>=60)||"HOUR"==$&&!r.duration&&2==p.length||(c?!l(r.minimum,m):!l(m,r.maximum))){if(p="","HOUR"==$){if(60==r.precision||s==r.maximum&&r.maximum.match(/00$/)||"-"==r.minimum[0]&&s==r.minimum&&r.minimum.match(/00$/)){Z();return}et(),ei();return}Z();return}"HOUR"==$?eo():ei(),s!=n&&(a.attr("value",s.replace(/^\+/,"")),r.onAdjust.call(a.get(0),s.replace(/^\+/,""),n.replace(/^\+/,""))),er(),Y()}}),H.on("keydown.clockTimePicker",function e(t){if(9==t.keyCode)Z();else if(13==t.keyCode)Z();else if(27==t.keyCode)es(ea(u)),Z();else if(8==t.keyCode||46==t.keyCode){if(p="",!el())return!1;var o,i=el();t.preventDefault(),RegExp("^(-|\\+)?([0-9]+)(.([0-9]{1,2}))?$").test(el());var c=!!r.duration&&!!r.durationNegative&&"-"==RegExp.$1,n=parseInt(RegExp.$2),s=RegExp.$4?parseInt(RegExp.$4):0;"HOUR"==$?(es(ea(o=0==n?r.required?(r.duration?"":"0")+"0"+r.separator+"00":"":(r.duration?"":"0")+"0"+r.separator+(s<10?"0":"")+s)),o?eo():Z(),i!=o&&(a.attr("value",o.replace(/^\+/,"")),r.onAdjust.call(a.get(0),o.replace(/^\+/,""),i.replace(/^\+/,"")))):0==s?0!=n||r.required?(ee(),eo()):(es(""),""!=i&&(a.attr("value",""),r.onAdjust.call(a.get(0),"",i.replace(/^\+/,""))),Z()):(es(ea(o=(c?"-":"")+(n<10&&!r.duration?"0":"")+n+r.separator+"00")),ei(),i!=o&&(a.attr("value",o.replace(/^\+/,"")),r.onAdjust.call(a.get(0),o.replace(/^\+/,""),i.replace(/^\+/,"")))),er()}else if((36==t.keyCode||37==t.keyCode)&&""!=el())es(ea(el())),"HOUR"!=$?(eo(),ee()):(t.preventDefault(),t.stopPropagation());else if((35==t.keyCode||39==t.keyCode)&&""!=el())es(ea(el())),60!=r.precision&&"MINUTE"!=$?(ei(),et()):(t.preventDefault(),t.stopPropagation());else if(190==t.keyCode||t.key==r.separator)t.preventDefault(),0==el().length&&es("0"),es(ea(el())),60!=r.precision?(ei(),"MINUTE"!=$&&et()):eo();else if("+"==t.key&&r.duration&&r.durationNegative){t.preventDefault();var i=el();if("-"==i[0]){var o=i.substring(1);es(ea(o)),a.attr("value",o),r.onAdjust.call(a.get(0),o,i),er(),Y(),"HOUR"==$?eo():ei()}}else if("-"==t.key&&r.duration&&r.durationNegative){t.preventDefault();var i=el().replace(/^\+/,"");if("-"!=i[0]){var o="-"+i;es(ea(o)),a.attr("value",o),r.onAdjust.call(a.get(0),o,i),er(),Y(),"HOUR"==$?eo():ei()}}else{if(38!=t.keyCode&&"+"!=t.key&&40!=t.keyCode&&"-"!=t.key)return t.preventDefault(),t.stopPropagation(),t.stopImmediatePropagation(),!1;t.preventDefault();var i=el();RegExp("^(-|\\+)?([0-9]+)(.([0-9]{1,2}))?$").test(i);var n=parseInt(RegExp.$2);r.duration&&r.durationNegative&&"-"==RegExp.$1&&(n=-n);var s=RegExp.$4?parseInt(RegExp.$4):0;"HOUR"==$?n+=38==t.keyCode||"+"==t.key?1:-1:(s+=(38==t.keyCode||"+"==t.key?1:-1)*r.precision)<0?s=0:s>59&&(s=60-r.precision);var m=r.minimum;r.duration&&r.durationNegative||"-"!=m[0]||(m="0:00");var d=r.maximum;if(1!=r.precision){var f=parseInt(d.replace(/^(\+|-)?[0-9]+./,""));d=d.replace(/.[0-9]+$/,"")+r.separator+(f-f%r.precision)}var o=(n<0?"-":"")+(n<10&&!r.duration?"0":"")+Math.abs(n)+r.separator+(s<10?"0":"")+s;"HOUR"!=$||(l(o,d)?l(m,o)||(o=m):o=d),i!=o&&(es(ea(o)),a.attr("value",o.replace(/^\+/,"")),r.onAdjust.call(a.get(0),o.replace(/^\+/,""),i.replace(/^\+/,"")),er(),Y(),"HOUR"==$?eo():ei())}}),a.on("mousewheel.clockTimePicker",function e(t){a.is(":focus")&&M(t)}),a.on("focus.clockTimePicker",function e(t){n()?(Q(),ee(!0),eo()):setTimeout(function(){"none"==I.css("display")&&en(t)},50)});var R=e("
");R.css("position","relative").css("width",g+"px").css("height",g+"px").css("margin","10px "+(n()?25:10)+"px"),I.append(R);var D=e('');D.css("cursor","default").css("position","absolute").css("top","0px").css("left","0px"),D.attr("width",g),D.attr("height",g),W(D),R.append(D);var E=e('');if(E.css("cursor","default").css("position","absolute").css("top","0px").css("left","0px").css("display","none"),E.attr("width",g),E.attr("height",g),W(E),R.append(E),n()){var j=e("
");j.css("text-align","right").css("padding","15px 30px"),r.fonts.fontFamily=r.fonts.fontFamily.replace(/\"/g,"").replace(/\'/g,"");var A='',q=e(A);q.html(r.i18n.cancelButton),q.on("click",function(){Z()}),j.append(q);var B=e(A);B.html(r.i18n.okButton),B.on("click",function(){n()&&a.val(el()),r.vibrate&&navigator.vibrate(10),Z()}),j.append(B),I.append(j)}function W(t){n()?(t.on("touchstart",function(t){t.preventDefault();var o=t.originalEvent.touches[0].pageX-e(this).offset().left,i=t.originalEvent.touches[0].pageY-e(this).offset().top,c=Math.sqrt(Math.pow(Math.abs(o-h),2)+Math.pow(Math.abs(i-_),2));if(r.duration&&r.durationNegative&&c<=20){f=!0;var n=el();newVal=n.match(/^-/)?n.substring(1):"-"+n.replace(/^(-|\+)/,""),r.minimum&&!l(r.minimum,newVal)&&(newVal=ea(r.minimum)),r.maximum&&!l(newVal,r.maximum)&&(newVal=ea(r.maximum)),es(ea(newVal)),Y(),a.attr("value",newVal.replace(/^\+/,"")),r.onAdjust.call(a.get(0),newVal.replace(/^\+/,""),n.replace(/^\+/,"")),"HOUR"==$?eo():ei();return}d=!0,X(o,i)}),t.on("touchend",function(e){e.preventDefault(),d=!1,f||60==r.precision||(et(),ei()),f=!1}),t.on("touchmove",function(t){if(t.preventDefault(),d){var o=t.originalEvent.touches[0].pageX-e(this).offset().left,i=t.originalEvent.touches[0].pageY-e(this).offset().top;X(o,i)}})):(t.on("mousedown",function(t){var o=t.pageX-e(this).offset().left,i=t.pageY-e(this).offset().top;X(o,i),d=!0}),t.on("mouseup",function(t){d=!1;var o=t.pageX-e(this).offset().left,i=t.pageY-e(this).offset().top,c=Math.sqrt(Math.pow(Math.abs(o-h),2)+Math.pow(Math.abs(i-_),2));if(r.duration&&r.durationNegative&&c<=20){var n=el();newVal=n.match(/^-/)?n.substring(1):"-"+n.replace(/^(-|\+)/,""),r.minimum&&!l(r.minimum,newVal)&&(newVal=ea(r.minimum)),r.maximum&&!l(newVal,r.maximum)&&(newVal=ea(r.maximum)),es(ea(newVal)),Y(),a.attr("value",newVal.replace(/^\+/,"")),r.onAdjust.call(a.get(0),newVal.replace(/^\+/,""),n.replace(/^\+/,"")),"HOUR"==$?eo():ei();return}if(!X(o,i,!0))return 60==r.precision?Z():"HOUR"==$?(et(),ei()):Z(),!1;"MINUTE"==$||60==r.precision?Z():(et(),ei())}),t.on("mousemove",function(t){var o=t.pageX-e(this).offset().left,i=t.pageY-e(this).offset().top;X(o,i)}),t.on("mouseleave",function(e){"HOUR"==$?L():G()}),t.on("mousewheel",function(e){M(e)})),t.on("keydown",function(e){e.preventDefault(),X(),ee(),eo(),u=el()})}function M(e){var t=window.event||e;if(e.preventDefault(),!(new Date().getTime()-C<100)){C=new Date().getTime();var o=Math.max(-1,Math.min(1,t.wheelDelta||-t.detail));RegExp("^(-|\\+)?([0-9]+)(.([0-9]{1,2}))?$").test(el());var i=!!r.duration&&!!r.durationNegative&&"-"==RegExp.$1,c=parseInt(RegExp.$2);i&&(c=-c);var n=RegExp.$4?parseInt(RegExp.$4):0;"HOUR"==$?(r.duration&&r.durationNegative&&0==c&&!i&&-1==o?i=!0:r.duration&&r.durationNegative&&0==c&&i&&1==o?i=!1:c+=o,-1!=c||(r.duration?r.durationNegative||(c=0):c=23),24!=c||r.duration||(c=0)):((n+=o*r.precision)<0&&(n=60+n),n>=60&&(n-=60));var s=el(),m=(c<10&&!r.duration?"0":"")+(i&&0==c?"-"+c:c)+r.separator+(n<10?"0":"")+n,u=!0;r.maximum&&!l(m,r.maximum)&&(u=!1),r.minimum&&!l(r.minimum,m)&&(u=!1),u||"HOUR"!=$||(m=o>0?ea(r.maximum):ea(r.minimum),u=!0),u&&(es(ea(m)),er(),Y(),"HOUR"==$?eo():ei(),m!=s&&(a.attr("value",m.replace(/^\+/,"")),r.onAdjust.call(a.get(0),m.replace(/^\+/,""),s.replace(/^\+/,""))))}}function X(e,t,o){var i=360*Math.atan((t-_)/(e-h))/(2*Math.PI)+90,c=Math.sqrt(Math.pow(Math.abs(e-h),2)+Math.pow(Math.abs(t-_),2)),n=0,s=0,m=!1;if(RegExp("^(-|\\+)?([0-9]+).([0-9]{2})$").test(el())&&(m=!!r.duration&&!!r.durationNegative&&"-"==RegExp.$1,n=parseInt(RegExp.$2),s=parseInt(RegExp.$3)),"HOUR"==$){i=Math.round(i/30);var u=-1;if(cv-28?e-h>=0?u=0==i?12:i:e-h<0&&(u=i+6):cv-65&&(e-h>=0?u=0!=i?i+12:0:e-h<0&&24==(u=i+18)&&(u=0)),r.afternoonHoursInOuterCircle&&(u+=u>=12?-12:12),!(u>-1))return L(null,r.duration&&r.durationNegative&&c<=12),!1;var p=(m?"-":"")+(u<10&&!r.duration?"0":"")+u+r.separator+(s<10?"0":"")+s;if(d||o){var f=!0;if(r.maximum&&!l(p,r.maximum)&&(f=!1),r.minimum&&!l(r.minimum,p)&&(f=!1),f||(r.maximum&&l((m?"-":"")+(u<10&&!r.duration?"0":"")+u+r.separator+"00",r.maximum)&&(p=ea(r.maximum),f=!0),!r.minimum||l(r.minimum,(m?"-":"")+(u<10&&!r.duration?"0":"")+u+r.separator+"00")||(p=ea(r.minimum),f=!0)),f){var k=el();p!=k&&(r.vibrate&&navigator.vibrate(10),a.attr("value",p.replace(/^\+/,"")),r.onAdjust.call(a.get(0),p.replace(/^\+/,""),k.replace(/^\+/,""))),es(ea(p)),er()}}return y=!0,L(0==u?24:u,r.duration&&r.durationNegative&&c<=12),!0}if("MINUTE"==$){i=Math.round(i/6);var g=-1;if(cv-40&&(e-h>=0?g=i:e-h<0&&60==(g=i+30)&&(g=0)),!(g>-1))return G(null,r.duration&&r.durationNegative&&c<=12),!1;if(1!=r.precision){var x=Math.floor(g/r.precision);(g=x*r.precision+(1==Math.round((g-x*r.precision)/r.precision)?r.precision:0))>=60&&(g=0)}var p=(m?"-":"")+(n<10&&!r.duration?"0":"")+n+r.separator+(g<10?"0":"")+g,f=!0;if(r.maximum&&!l(p,r.maximum)&&(f=!1),r.minimum&&!l(r.minimum,p)&&(f=!1),(d||o)&&f){var k=el();p!=k&&(r.vibrate&&navigator.vibrate(10),a.attr("value",p.replace(/^\+/,"")),r.onAdjust.call(a.get(0),p.replace(/^\+/,""),k.replace(/^\+/,""))),es(ea(p))}return y=!0,G(0==g?60:g,r.duration&&r.durationNegative&&c<=12),!0}}function Y(){"HOUR"==$?L():G()}function K(e,t){e.beginPath(),e.arc(h,_,12,0,2*Math.PI,!1),e.fillStyle=r.colors.signButtonBackgroundColor,e.fill(),t&&(e.beginPath(),e.arc(h,_,14,0,2*Math.PI,!1),e.strokeStyle=r.colors.signButtonBackgroundColor,e.stroke()),e.beginPath(),e.moveTo(h-6,_),e.lineTo(h+6,_),e.lineWidth=2,e.strokeStyle=r.colors.signButtonColor,e.stroke(),el().match(/^-/)||(e.beginPath(),e.moveTo(h,_-6),e.lineTo(h,_+6),e.lineWidth=2,e.strokeStyle=r.colors.signButtonColor,e.stroke())}function L(e,t){var o=D.get(0).getContext("2d");RegExp("^(-|\\+)?([0-9]+).([0-9]{1,2})$").test(el());var i="-"==RegExp.$1,a=parseInt(RegExp.$2);if(o.clearRect(0,0,g,g),a>=24){I.css("visibility","hidden");return}if(r.onlyShowClockOnMobile||I.css("visibility","visible"),0==a&&(a=24),el()||(a=-1),o.beginPath(),o.arc(h,_,v,0,2*Math.PI,!1),o.fillStyle=r.colors.clockFaceColor,o.fill(),!n()&&e){var c=!0;r.maximum&&!l((i?"-":"")+(24==e?"00":e)+":00",r.maximum)&&(c=!1),r.minimum&&!l(r.minimum,(i?"-":"")+(24==e?"00":e)+":00",!0)&&(c=!1),c&&(o.beginPath(),o.arc(h+Math.cos(Math.PI/6*(e%12-3))*(e>12?r.afternoonHoursInOuterCircle?x:b:r.afternoonHoursInOuterCircle?b:x),_+Math.sin(Math.PI/6*(e%12-3))*(e>12?r.afternoonHoursInOuterCircle?x:b:r.afternoonHoursInOuterCircle?b:x),15,0,2*Math.PI,!1),o.fillStyle=r.colors.hoverCircleColor,o.fill())}o.beginPath(),o.arc(h,_,3,0,2*Math.PI,!1),o.fillStyle=r.colors.selectorColor,o.fill(),a>-1&&(!r.maximum||24==a||l(a,r.maximum))&&(o.beginPath(),o.moveTo(h,_),o.lineTo(h+Math.cos(Math.PI/6*(a%12-3))*(a>12?r.afternoonHoursInOuterCircle?x:b:r.afternoonHoursInOuterCircle?b:x),_+Math.sin(Math.PI/6*(a%12-3))*(a>12?r.afternoonHoursInOuterCircle?x:b:r.afternoonHoursInOuterCircle?b:x)),o.lineWidth=1,o.strokeStyle=r.colors.selectorColor,o.stroke(),o.beginPath(),o.arc(h+Math.cos(Math.PI/6*(a%12-3))*(a>12?r.afternoonHoursInOuterCircle?x:b:r.afternoonHoursInOuterCircle?b:x),_+Math.sin(Math.PI/6*(a%12-3))*(a>12?r.afternoonHoursInOuterCircle?x:b:r.afternoonHoursInOuterCircle?b:x),15,0,2*Math.PI,!1),o.fillStyle=r.colors.selectorColor,o.fill()),o.font=r.fonts.clockOuterCircleFontSize+"px "+r.fonts.fontFamily;for(let s=1;s<=12;s++){var m=Math.PI/6*(s-3),u=s;r.afternoonHoursInOuterCircle?(u=s+12,a==s+12?o.fillStyle=r.colors.selectorNumberColor:o.fillStyle=r.colors.clockInnerCircleTextColor,24==u&&(u="00")):a==s?o.fillStyle=r.colors.selectorNumberColor:o.fillStyle=r.colors.clockOuterCircleTextColor,(!r.maximum||l((i?"-":"")+u+":00",r.maximum))&&(!r.minimum||l(r.minimum,(i?"-":"")+u+":00",!0))?o.fillText(u,h+Math.cos(m)*x-o.measureText(u).width/2,_+Math.sin(m)*x+r.fonts.clockOuterCircleFontSize/3):r.hideUnselectableNumbers||(o.fillStyle=r.colors.clockOuterCircleUnselectableTextColor,o.fillText(u,h+Math.cos(m)*x-o.measureText(u).width/2,_+Math.sin(m)*x+r.fonts.clockOuterCircleFontSize/3))}o.font=r.fonts.clockInnerCircleFontSize+"px "+r.fonts.fontFamily;for(let p=1;p<=12;p++){var m=Math.PI/6*(p-3),u=p;r.afternoonHoursInOuterCircle?a==p?o.fillStyle=r.colors.selectorNumberColor:o.fillStyle=r.colors.clockOuterCircleTextColor:(u=p+12,a==p+12?o.fillStyle=r.colors.selectorNumberColor:o.fillStyle=r.colors.clockInnerCircleTextColor,24==u&&(u="00")),(!r.maximum||l((i?"-":"")+u+":00",r.maximum))&&(!r.minimum||l(r.minimum,(i?"-":"")+u+":00",!0))?o.fillText(u,h+Math.cos(m)*b-o.measureText(u).width/2,_+Math.sin(m)*b+r.fonts.clockInnerCircleFontSize/3):r.hideUnselectableNumbers||(o.fillStyle=r.colors.clockInnerCircleUnselectableTextColor,o.fillText(u,h+Math.cos(m)*b-o.measureText(u).width/2,_+Math.sin(m)*b+r.fonts.clockInnerCircleFontSize/3))}r.duration&&r.durationNegative&&K(o,t)}function G(e,t){var o=E.get(0).getContext("2d");RegExp("^(-|\\+)?([0-9]+).([0-9]{1,2})$").test(el());var i="-"==RegExp.$1,a=parseInt(RegExp.$2),c=parseInt(RegExp.$3);if(el()||(c=-1),r.onlyShowClockOnMobile||I.css("visibility","visible"),o.clearRect(0,0,g,g),o.beginPath(),o.arc(h,_,v,0,2*Math.PI,!1),o.fillStyle=r.colors.clockFaceColor,o.fill(),!n()&&e){60==e&&(e=0);var s=!0;r.maximum&&!l((i?"-":"")+a+":"+(e<10?"0":"")+e,r.maximum)&&(s=!1),r.minimum&&!l(r.minimum,(i?"-":"")+a+":"+(e<10?"0":"")+e)&&(s=!1),s&&(o.beginPath(),o.arc(h+Math.cos(Math.PI/6*(e/5-3))*x,_+Math.sin(Math.PI/6*(e/5-3))*x,15,0,2*Math.PI,!1),o.fillStyle=r.colors.hoverCircleColor,o.fill())}o.beginPath(),o.arc(h,_,3,0,2*Math.PI,!1),o.fillStyle=r.colors.selectorColor,o.fill(),c>-1&&(!r.maximum||l(a+":"+c,r.maximum))&&(!r.minimum||l(r.minimum,a+":"+c))&&(o.beginPath(),o.moveTo(h,_),o.lineTo(h+Math.cos(Math.PI/6*(c/5-3))*x,_+Math.sin(Math.PI/6*(c/5-3))*x),o.lineWidth=1,o.strokeStyle=r.colors.selectorColor,o.stroke(),o.beginPath(),o.arc(h+Math.cos(Math.PI/6*(c/5-3))*x,_+Math.sin(Math.PI/6*(c/5-3))*x,15,0,2*Math.PI,!1),o.fillStyle=r.colors.selectorColor,o.fill()),o.font=r.fonts.clockOuterCircleFontSize+"px "+r.fonts.fontFamily;for(let m=1;m<=12;m++)if(Math.floor(5*m/r.precision)==5*m/r.precision){var u=Math.PI/6*(m-3);c==5*m||0==c&&12==m?o.fillStyle=r.colors.selectorNumberColor:o.fillStyle=r.colors.clockOuterCircleTextColor;var p=5*m==5?"05":5*m;60==p&&(p="00");var s=!0;r.maximum&&!l((i?"-":"")+a+":"+p,r.maximum)&&(s=!1),r.minimum&&!l(r.minimum,(i?"-":"")+a+":"+p)&&(s=!1),s?o.fillText(p,h+Math.cos(u)*x-o.measureText(p).width/2,_+Math.sin(u)*x+r.fonts.clockOuterCircleFontSize/3):r.hideUnselectableNumbers||(o.fillStyle=r.colors.clockOuterCircleUnselectableTextColor,o.fillText(p,h+Math.cos(u)*x-o.measureText(p).width/2,_+Math.sin(u)*x+r.fonts.clockOuterCircleFontSize/3))}c>-1&&c%5!=0&&(o.beginPath(),o.arc(h+Math.cos(Math.PI/6*(c/5-3))*x,_+Math.sin(Math.PI/6*(c/5-3))*x,2,0,2*Math.PI,!1),o.fillStyle="white",o.fill()),r.duration&&r.durationNegative&&K(o,t)}function J(){window.innerHeight<400?(k=window.innerHeight-60,I.css("width",k+200+"px"),H.css("position","absolute").css("left","0px").css("top","0px").css("width","200px").css("height",k+20+"px"),R.css("margin","10px 25px 0px 230px"),t=k+parseInt(R.css("margin-top"))+parseInt(R.css("margin-bottom"))):((k=window.innerWidth-80)>300&&(k=300),I.css("width",k+"px"),H.css("position","static").css("width","100%").css("height","auto"),R.css("margin","10px 25px 10px 25px"),t=k+parseInt(R.css("margin-top"))+parseInt(R.css("margin-bottom"))+65),I.css("left",parseInt((e("body").prop("clientWidth")-I.outerWidth())/2)+"px"),I.css("top",parseInt((window.innerHeight-t)/2)+"px"),v=parseInt((g=k-50)/2),h=parseInt(g/2),_=parseInt(g/2),b=(x=v-16)-29,R.css("width",g+"px"),R.css("height",g+"px");var t,o=window.devicePixelRatio||1,i=D.get(0),r=E.get(0);i.width=g*o,i.height=g*o,r.width=g*o,r.height=g*o;var a=i.getContext("2d"),c=r.getContext("2d");a.scale(o,o),c.scale(o,o),D.css("width",g),D.css("height",g),E.css("width",g),E.css("height",g)}function Q(){a.val()?es(ea(a.val())):es(ea("00:00")),!n()&&r.onlyShowClockOnMobile&&I.css("visibility","hidden"),n()&&J(),I.css("display","block"),Y(),n()?i&&i.stop().css("opacity",0).css("display","block").animate({opacity:1},300):(V(),e(window).on("scroll.clockTimePicker",e=>{V()})),r.onOpen.call(a.get(0))}function V(){var t=a.offset().top-e(window).scrollTop()+a.outerHeight();if(t+I.outerHeight()>window.innerHeight){var o=a.offset().top-e(window).scrollTop()-I.outerHeight();o>=0&&(t=o)}var i=a.offset().left-e(window).scrollLeft()-parseInt((I.outerWidth()-a.outerWidth())/2);I.css("left",i+"px").css("top",t+"px")}function Z(){e(window).off("scroll.clockTimePicker");var t=ea(a.val());if(p="",I.css("display","none"),n()?i.stop().animate({opacity:0},300,function(){i.css("display","none")}):a.val(t),!function e(){if(document.activeElement==H.get(0)){var t=document.createElement("input");a.parent().get(0).appendChild(t),t.focus(),a.parent().get(0).removeChild(t)}}(),!y&&!u&&t.match(RegExp("^0+"+r.separator+"00$")))es("");else if(u!=t){if("createEvent"in document){var o=document.createEvent("HTMLEvents");o.initEvent("change",!0,!1),a.get(0).dispatchEvent(o)}else{var o=document.createEventObject();o.eventType="click",a.get(0).fireEvent("onchange",o)}r.onChange.call(a.get(0),t.replace(/^\+/,""),u.replace(/^\+/,"")),u=t}r.onClose.call(a.get(0)),y=!1}function ee(e){"HOUR"!=$&&(p="",L(),e?E.css("display","none"):E.css("zIndex",2).stop().animate({opacity:0,zoom:"80%",left:"10%",top:"10%"},r.modeSwitchSpeed,function(){E.css("display","none")}),D.stop().css("zoom","100%").css("left","0px").css("top","0px").css("display","block").css("opacity",1).css("zIndex",1),$="HOUR",r.onModeSwitch.call(a.get(0),$))}function et(e){"MINUTE"!=$&&(p="",G(),E.stop().css("display","block").css("zoom","80%").css("left","10%").css("top","10%").css("opacity",0).css("zIndex",1),e?E.css("opacity",1).css("zoom","100%").css("left","0px").css("top","0px"):E.animate({opacity:1,zoom:"100%",left:"0px",top:"0px"}),$="MINUTE",r.onModeSwitch.call(a.get(0),$))}function eo(){H.focus(),setTimeout(function(){n()?(e(".clock-timepicker-mobile-time-hours").css("backgroundColor","rgba(255, 255, 255, 0.6)"),e(".clock-timepicker-mobile-time-minutes").css("backgroundColor","inherit")):H.get(0).setSelectionRange(0,el().indexOf(r.separator))},1)}function ei(){H.focus(),setTimeout(function(){n()?(e(".clock-timepicker-mobile-time-hours").css("backgroundColor","inherit"),e(".clock-timepicker-mobile-time-minutes").css("backgroundColor","rgba(255, 255, 255, 0.6)")):H.get(0).setSelectionRange(el().indexOf(r.separator)+1,el().length)},1)}function er(){!r.autosize||n()||(w.html(a.val()),w.css("display","inline-block"),a.css("width",w.outerWidth()+5+parseInt(a.css("padding-left"))+parseInt(a.css("padding-right"))+"px"),w.css("display","none"))}function ea(e){if(""==e)return r.required?r.duration?"0:00":"00:00":e;if(RegExp("^(-|\\+)?([0-9]+)(.([0-9]{1,2})?)?$","i").test(e)){var t=parseInt(RegExp.$2),o=parseInt(RegExp.$4);o||(o=0);var i=!!r.duration&&!!r.durationNegative&&"-"==RegExp.$1;if(t>=24&&!r.duration&&(t%=24),o>=60&&(o%=60),1!=r.precision){var a=Math.floor(o/r.precision);60!=(o=a*r.precision+(1==Math.round((o-a*r.precision)/r.precision)?r.precision:0))||(o=0,24!=++t||r.duration||(t=0))}e=(i?"-":"")+(t<10&&!r.duration?"0":"")+t+r.separator+(RegExp.$3?(o<10?"0":"")+o:"00")}else if(RegExp("^(-|\\+)?.([0-9]{1,2})").test(e)){var o=parseInt(RegExp.$2),i=!!r.duration&&!!r.durationNegative&&"-"==RegExp.$1;o>=60&&(o%=60),e=(i&&o>0?"-":"")+"0"+(r.duration?"":"0")+r.separator+(o<10?"0":"")+o}else e="0"+(r.duration?"":"0")+r.separator+"00";return(r.duration&&r.useDurationPlusSign&&!e.match(/^\-/)&&!e.match(/^0+:00$/)?"+":"")+e}function ec(e){e.parent().find(".clock-timepicker-autosize").remove(),e.parent().find(".clock-timepicker-background").remove(),e.parent().find(".clock-timepicker-popup").remove(),e.unwrap(),e.off("drag.clockTimePicker dragend.clockTimePicker dragover.clockTimePicker dragenter.clockTimePicker dragstart.clockTimePicker dragleave.clockTimePicker drop.clockTimePicker selectstart.clockTimePicker contextmenu.clockTimePicker"),e.off("mousedown.clockTimePicker"),e.off("keyup.clockTimePicker"),e.off("keydown.clockTimePicker"),e.off("mousewheel.clockTimePicker"),e.off("focus.clockTimePicker"),e.attr("data-autocomplete-orig")?(e.attr("autocomplete",e.attr("data-autocomplete-orig")),e.removeAttr("data-autocomplete-orig")):e.removeAttr("autocomplete"),e.attr("data-autocorrect-orig")?(e.attr("autocorrect",e.attr("data-autocorrect-orig")),e.removeAttr("data-autocorrect-orig")):e.removeAttr("autocorrect"),e.attr("data-autocapitalize-orig")?(e.attr("autocapitalize",e.attr("data-autocapitalize-orig")),e.removeAttr("data-autocapitalize-orig")):e.removeAttr("autocapitalize"),e.attr("data-spellcheck-orig")?(e.attr("spellcheck",e.attr("data-spellcheck-orig")),e.removeAttr("data-spellcheck-orig")):e.removeAttr("spellcheck")}function en(e){if(!r.contextmenu||1==e.which)return!function e(t){var o="none"!=I.css("display");if(el()){if(60==r.precision)ee(!o),eo();else{var i=H.css("direction");i||(i="ltr");var a=H.css("text-align");a||(a="left");var c=H.innerWidth(),n=parseFloat(H.css("padding-left")),l=parseFloat(H.css("padding-right")),s=c-n-l;w.css("display","inline-block"),w.html(el());var m=w.innerWidth();w.html(r.separator);var u=w.innerWidth()/2;w.html(el().replace(RegExp(r.separator+"[0-9]+$"),"")),u+=w.innerWidth(),w.css("display","none");var p=c/2;"left"==a||"justify"==a||"ltr"==i&&"start"==a||"rtl"==i&&"end"==a?p=Math.floor(n+u):"center"==a?p=Math.floor(n+(s-m)/2+u):("right"==a||"ltr"==i&&"end"==a||"rtl"==i&&"start"==a)&&(p=Math.floor(n+s-(m-u))),t.offsetX>=p-2&&(o||!r.alwaysSelectHoursFirst)?("HOUR"==$&&r.vibrate&&navigator.vibrate(10),et(!o),ei()):("MINUTE"==$&&r.vibrate&&navigator.vibrate(10),ee(!o),eo())}}else es(ea("00:00")),ee(!o),eo();o||Q()}(e),e.stopImmediatePropagation(),e.stopPropagation(),e.preventDefault(),!1}function el(){return n()?e(".clock-timepicker-mobile-time-hours").html()+r.separator+e(".clock-timepicker-mobile-time-minutes").html():H.val()}function es(t){if(n()){if(t.match(/^(-|\\+)?([0-9]{1,2}).([0-9]{1,2})$/)){var o=RegExp.$1+(r.duration||1!=RegExp.$2.length?"":"0")+RegExp.$2,i=(1==RegExp.$3.length?"0":"")+RegExp.$3;e(".clock-timepicker-mobile-time-hours").html(o),e(".clock-timepicker-mobile-time-minutes").html(i)}}else H.val(t)}});function n(){var e,t=!1;return e=navigator.userAgent||navigator.vendor||window.opera,(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(e)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(e.substr(0,4)))&&(t=!0),t}function l(e,t,o){var i="^(-|\\+)?([0-9]+)(.([0-9]{1,2}))?$";RegExp(i,"i").test(e);var r=60*parseInt(RegExp.$2);RegExp.$4&&!o&&(r+=parseInt(RegExp.$4)),"-"==RegExp.$1&&(r*=-1),RegExp(i,"i").test(t);var a=60*parseInt(RegExp.$2);return RegExp.$4&&!o&&(a+=parseInt(RegExp.$4)),"-"==RegExp.$1&&(a*=-1),r<=a}}}(jQuery); -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-clock-timepicker", 3 | "version": "2.5.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "jquery-clock-timepicker", 9 | "version": "2.5.0", 10 | "license": "MIT", 11 | "dependencies": { 12 | "jquery": "~>3.5.0" 13 | } 14 | }, 15 | "node_modules/jquery": { 16 | "version": "3.5.1", 17 | "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.5.1.tgz", 18 | "integrity": "sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg==" 19 | } 20 | }, 21 | "dependencies": { 22 | "jquery": { 23 | "version": "3.5.1", 24 | "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.5.1.tgz", 25 | "integrity": "sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg==" 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-clock-timepicker", 3 | "version": "2.6.4", 4 | "author": { 5 | "name": "Andreas Loeber", 6 | "url": "https://github.com/loebi-ch" 7 | }, 8 | "license": "MIT", 9 | "dependencies": { 10 | "jquery": "~>3.5.0" 11 | }, 12 | "main": "jquery-clock-timepicker.min.js", 13 | "description": "A free jQuery Plug-in to select the time with a clock inspired by the Android time picker. This plugin works on Desktop and Mobile phones.", 14 | "keywords": [ 15 | "clock", 16 | "time", 17 | "picker", 18 | "jquery", 19 | "android", 20 | "responsive", 21 | "mobile" 22 | ], 23 | "homepage": "https://github.com/loebi-ch/jquery-clock-timepicker", 24 | "scripts": { 25 | "test": "echo \"Error: no test specified\" && exit 1" 26 | }, 27 | "repository": { 28 | "type": "git", 29 | "url": "https://github.com/loebi-ch/jquery-clock-timepicker.git" 30 | }, 31 | "bugs": { 32 | "url": "https://github.com/loebi-ch/jquery-clock-timepicker/issues" 33 | } 34 | } 35 | --------------------------------------------------------------------------------