├── .gitignore ├── package.json ├── demos ├── inputs.html ├── triggers.html ├── auto.html ├── range.html ├── index.md └── index.html ├── LICENSE ├── src ├── dzdatetimepicker.js ├── rangepicker.js ├── autohook.js ├── dzdatetimepicker.less ├── timepicker.js └── datepicker.js ├── dist ├── dzdatetimepicker.css.map ├── dzdatetimepicker.css ├── dzdatetimepicker-dist.js.map └── dzdatetimepicker-dist.js ├── README.md ├── prepros-6.config ├── .eslintrc └── prepros.config /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | README.html 3 | node_modules 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dzdatetimepicker", 3 | "version": "1.6.6", 4 | "description": "Functional, Extensible & Simple DateTime picker without any dependencies.", 5 | "main": "src/dzdatetimepicker.js", 6 | "dependencies": {}, 7 | "devDependencies": {}, 8 | "scripts": { 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/DZNS/DZDateTimePicker.git" 14 | }, 15 | "keywords": [ 16 | "picker", 17 | "date", 18 | "time", 19 | "html", 20 | "javascript", 21 | "fallback", 22 | "support", 23 | "es6" 24 | ], 25 | "author": "Nikhil Nigade (Dezine Zync Studios LLP.)", 26 | "license": "MIT", 27 | "bugs": { 28 | "url": "https://github.com/DZNS/DZDateTimePicker/issues" 29 | }, 30 | "homepage": "https://github.com/DZNS/DZDateTimePicker#readme" 31 | } 32 | -------------------------------------------------------------------------------- /demos/inputs.html: -------------------------------------------------------------------------------- 1 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Dezine Zync Studios 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 | -------------------------------------------------------------------------------- /demos/triggers.html: -------------------------------------------------------------------------------- 1 | 36 | 37 |
38 | 39 | 40 |
Date Trigger
41 | 42 | 43 |
Time Trigger
44 | 45 |
46 | 47 | -------------------------------------------------------------------------------- /demos/auto.html: -------------------------------------------------------------------------------- 1 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 33 |
34 | 42 |
43 | 44 |
45 | 46 | 47 | 52 | -------------------------------------------------------------------------------- /demos/range.html: -------------------------------------------------------------------------------- 1 | 35 | 36 |
37 | 38 |
39 |
Start
40 |
End
41 |
42 | 43 |
44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/dzdatetimepicker.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const findParent = (elem, id) => { 4 | 5 | const checker = i => i.getAttribute('id') === id || i.classList.contains(id) 6 | 7 | if(checker(elem)) 8 | return elem; 9 | 10 | while(elem.parentNode) { 11 | 12 | elem = elem.parentNode 13 | 14 | if(elem === document.body || elem === document) 15 | return undefined 16 | 17 | if(checker(elem)) 18 | return elem 19 | 20 | } 21 | 22 | return undefined 23 | }; 24 | 25 | const inputFocus = (evt) => { 26 | if(evt && evt.preventDefault) 27 | evt.preventDefault() 28 | evt.target.blur() 29 | return false 30 | }; 31 | 32 | const inputBlur = (evt) => { 33 | if(evt && evt.preventDefault) 34 | evt.preventDefault() 35 | return false 36 | }; 37 | 38 | const measure = (fn = function() {}) => new Promise((resolve, reject) => { 39 | window.requestAnimationFrame(() => { 40 | const retval = fn() 41 | resolve(retval) 42 | }) 43 | }); 44 | 45 | const mutate = (fn = function() {}) => new Promise((resolve, reject) => { 46 | window.requestAnimationFrame(() => { 47 | const retval = fn() 48 | resolve(retval) 49 | }) 50 | }); 51 | 52 | window.wait = window.wait || async function (milliseconds = 0) { 53 | return new Promise((resolve) => { 54 | setTimeout(() => { 55 | resolve(); 56 | }, milliseconds); 57 | }) 58 | }; 59 | 60 | // @prepros-append ./datepicker.js 61 | // @prepros-append ./timepicker.js 62 | // @prepros-append ./rangepicker.js 63 | // @prepros-append ./autohook.js 64 | -------------------------------------------------------------------------------- /src/rangepicker.js: -------------------------------------------------------------------------------- 1 | ((glob) => { 2 | class RangePicker { 3 | constructor(elem) { 4 | this.elem = elem 5 | this.initialized = false 6 | this.init() 7 | } 8 | 9 | init () { 10 | if (!this.elem) 11 | return 12 | 13 | if (this.initialized) 14 | return 15 | this.initialized = true 16 | 17 | let time = +new Date() 18 | 19 | this.startElem = this.elem.querySelector('.range-start') 20 | this.endElem = this.elem.querySelector('.range-end') 21 | 22 | this.startElem.setAttribute("type", "text") 23 | this.endElem.setAttribute("type", "text") 24 | 25 | this.startElem.classList.add('start'+time) 26 | this.endElem.classList.add('end'+time) 27 | 28 | this.startController = new DatePicker('start'+time) 29 | this.endController = new DatePicker('end'+time) 30 | 31 | this.startController.callback = this.callback.bind(this) 32 | this.endController.callback = this.startController.callback 33 | } 34 | 35 | callback() { 36 | let args = [...arguments] 37 | let elem = args[0] 38 | let val = args[1] 39 | 40 | let isStart = elem.classList.contains('range-start') 41 | 42 | if (isStart) 43 | this.start = val 44 | else 45 | this.end = val 46 | 47 | if (isStart) { 48 | // update the min-date of the end-range 49 | // this needs to be adjusted such that 50 | // the min-date also includes the selected date 51 | // for single day ranges. 52 | 53 | const selected = new Date(val); 54 | 55 | const newMax = new Date(selected.setDate(selected.getDate() - 1)); 56 | 57 | const month = DatePicker.zeroPaddedFormatMonth(newMax); 58 | const dateStr = DatePicker.zeroPaddedFormatDate(newMax); 59 | 60 | this.endElem.dataset.dateMin = `${newMax.getFullYear()}-${month}-${dateStr}` 61 | } 62 | 63 | } 64 | } 65 | 66 | if (glob.hasOwnProperty('exports')) 67 | glob.exports = Object.assign({}, glob.exports, RangePicker) 68 | else 69 | glob.RangePicker = RangePicker 70 | 71 | })(typeof module === "undefined" ? window : module); 72 | -------------------------------------------------------------------------------- /dist/dzdatetimepicker.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../src/dzdatetimepicker.less","../src/dzdatetimepicker.css"],"names":[],"mappings":"AAEA,MACI,6DAAA,AACA,6CAAA,AAEA,+CAAA,AACA,6CAAA,AACA,gDAAA,AAEA,+CAAA,AACA,6CAAA,AACA,0CAAA,CCFH,ADaD,6BACI,cAAA,CCVH,ADaD,uBACI,gBAAA,AAGA,YAAA,AACA,YAAA,AACA,cAAA,AAEA,mBAAA,AAEA,kBAAA,AAEA,kCAAA,AAEA,qHAAA,6GAAA,AAEA,kBAAA,AAEA,UAAA,AAEA,8BAAA,0BAAA,sBAAA,AACA,iCAAA,6BAAA,yBAAA,AACA,UAAA,AACA,+BAAA,AAEA,kEAAA,0DAAA,qDAAA,kDAAA,+EAAA,AACA,mBAAA,CCpBH,ADsBG,qCACI,2BAAA,uBAAA,mBAAA,AACA,UAAA,AACA,mBAAA,CCnBP,ADsBG,qCACI,WAAA,AACA,WAAA,AACA,YAAA,AACA,kBAAA,AACA,oBAAA,AACA,gCAAA,4BAAA,wBAAA,AAEA,UAAA,AAEA,kBAAA,AACA,SAAA,AACA,SAAA,AACA,iBAAA,AAEA,wCAAA,AACA,oDAAA,2CAAA,CCtBP,AD0BD,aAEI,UAAA,AACA,kBAAA,CCzBH,ADsBD,0BAMQ,kBAAA,CCzBP,ADmBD,4CAUQ,WAAA,AACA,YAAA,AACA,yBAAA,AACA,wBAAA,gBAAA,AAEA,UAAA,AAEA,cAAA,AACA,YAAA,AACA,YAAA,CC3BP,AD6BO,wDACI,cAAA,CC1BX,ADID,8DA0BY,qCAAA,CC1BX,ADAD,sBAgCQ,eAAA,CC7BP,ADHD,uBAqCQ,eAAA,AACA,gBAAA,AACA,oBAAA,oBAAA,aAAA,AACA,yBAAA,sBAAA,mBAAA,AACA,gDAAA,CC/BP,ADVD,0BA4CY,SAAA,AACA,UAAA,AACA,cAAA,CC/BX,ADfD,8BAkDY,gBAAA,CChCX,ADkCW,yCACI,eAAA,CChCf,ADrBD,sBA6DQ,WAAA,AACA,YAAA,AAEA,oBAAA,oBAAA,aAAA,AACA,qBAAA,iBAAA,AACA,yBAAA,sBAAA,kBAAA,CCtCP,AD5BD,0BAqEY,mBAAA,WAAA,OAAA,AACA,kBAAA,AACA,eAAA,AACA,gBAAA,AACA,4BAAA,CCtCX,ADnCD,uBA+EQ,WAAA,AACA,YAAA,AAEA,oBAAA,oBAAA,aAAA,AACA,mBAAA,cAAA,CC1CP,ADzCD,8BAuFY,mBAAA,kBAAA,cAAA,AACA,YAAA,AACA,qBAAA,AAEA,6BAAA,AACA,wBAAA,gBAAA,AACA,YAAA,AAEA,kBAAA,AACA,iBAAA,AACA,mBAAA,AACA,eAAA,AA9JI,qCAAA,6BAAA,AAiKJ,6BAAA,AAEA,kBAAA,AAEA,UAAA,AACA,oBAAA,AACA,eAAA,CChDX,ADmEW,oCACI,eAAA,AACA,wBAAA,CCjEf,ADmEe,2CApBA,WAAA,AACA,WAAA,AACA,YAAA,AACA,cAAA,AAEA,kBAAA,AACA,SAAA,AACA,QAAA,AAEA,WAAA,AAEA,mBAAA,AAEA,wCAAA,CChDf,AD6DW,oCAEI,4BAAA,AACA,eAAA,CC5Df,AD8De,2CA/BA,WAAA,AACA,WAAA,AACA,YAAA,AACA,cAAA,AAEA,kBAAA,AACA,SAAA,AACA,QAAA,AAEA,WAAA,AAEA,mBAAA,AAsBI,yCAAA,AACA,uBAAA,AACA,wCAAA,mCAAA,+BAAA,CCpDnB,ADwDmB,iDACI,wCAAA,CCtDvB,AD4DW,uCAEI,WAAA,CC3Df,AD6De,8CAlDA,WAAA,AACA,WAAA,AACA,YAAA,AACA,cAAA,AAEA,kBAAA,AACA,SAAA,AACA,QAAA,AAEA,WAAA,AAEA,mBAAA,AAEA,yCAAA,AAuCI,uBAAA,AACA,wCAAA,mCAAA,gCAAA,AACA,uCAAA,CClDnB,ADqDe,6CACI,4BAAA,CCnDnB,ADoDmB,oDACI,wCAAA,CClDvB,ADwDW,uCACI,oBAAA,AACA,WAAA,CCtDf,AD+DD,UACE,WAAA,AACA,WAAA,CC7DD,ADgED,mCACI,MAEI,8CAAA,AACA,+CAAA,AAEA,2BAAA,AACA,0BAAA,AACA,yBAAA,CChEL,ADuEC,uBACI,kHAAA,yGAAA,CCpEL,ADuEC,8DAIY,oCAAA,CCvEb,ADmEC,0BAUY,6BAAA,CC1Eb,ADgEC,8BAiBY,YAAA,AACA,wBAAA,eAAA,CC9Eb,ADkFiB,8CACI,sCAAA,CChFrB,ADmFiB,6CAEI,2BAAA,CClFrB,ADoFqB,oDACI,wCAAA,CClFzB,CACF"} -------------------------------------------------------------------------------- /demos/index.md: -------------------------------------------------------------------------------- 1 | # DZDateTimePicker 2 | Functional, Extensible & Simple Date-picker without any dependencies.. 3 | 4 | Demo: http://codepen.io/dezinezync/pen/jqvZYp 5 | 6 | ### Setup 7 | ```html 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | ``` 16 | 17 | ### Date Picker Usage 18 | You can initiate the date picker by wiring up a *trigger* element like so: 19 | ```html 20 | 21 | ``` 22 | 23 | The few important things to note are: 24 | - when `dzdatetimepicker.js` runs, it automatically finds elements with the class `date-trigger` and hooks on to them. No futher configuration is required. 25 | - You can set additional, *optional* dataset items like `date-max` and `date-min` to control the selectable items within a range. Both are optional, and you can use only one if desired. 26 | - the last parameter, `onset` is required if you need a callback when the user selects a date. This is optional, however, your implementation will require it if you need to update the UI. The implementation for this is intentionally left out. 27 | 28 | ### Timer Picker Usage 29 | You can initiate the time picker by wiring up a *trigger* element like so: 30 | ```html 31 |
Time Trigger
32 | ``` 33 | When the script loads, it automatically hooks on to elements with the class `timer-trigger`. No other configuration is necessary. Similar to the date picker, the last parameter, `onchange` is required if you need a callback when the user selects a date. This is optional, however, your implementation will require it if you need to update the UI. The implementation for this is intentionally left out. 34 | 35 | The callback, unlike the date picker, responds with an object in the following format: 36 | ```json 37 | { 38 | "string" : "14:26", 39 | "hours" : 14, 40 | "minutes" : 26 41 | } 42 | ``` 43 | 44 | ### Notes 45 | - Both the datepicker and timepicker automatically idenity `` elements. They hook on to the `focus` and `blur` events so the user can use the pickers to set the values directly. 46 | - If the pickers detect an `` element, the pickers will update the `value` attribute when the user updates their selection. 47 | - When not using an `` element, you can optionally set the attribute `data-date-val=""` and it'll be updated similarly. 48 | 49 | ### Todo 50 | - [x] Remove dependencies 51 | 52 | ### License 53 | DZDateTimePicker is licensed under the MIT License. Please refer to the LICENSE file for more information. 54 | 55 | ### Author 56 | Nikhil Nigade (Dezine Zync Studios) 57 | -------------------------------------------------------------------------------- /demos/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | index.md 5 | 6 | 7 |

DZDateTimePicker

8 |

Functional, Extensible & Simple Date-picker without any dependencies..

9 |

Demo: http://codepen.io/dezinezync/pen/jqvZYp

10 |

Setup

11 |
<!-- For Dev -->
12 | <script src="dzdatetimepicker.js"></script>
13 | <!-- For Production -->
14 | <script src="dzdtp.min.js"></script>
15 | 
16 | <!-- The stylesheet. You can include your own instead -->
17 | <link rel="stylesheet" href="dzdatetimepicker.css" />
18 | 
19 |

Date Picker Usage

20 |

You can initiate the date picker by wiring up a trigger element like so:

21 |
<button class="date-trigger" data-date-max="2016-05-09" data-date-min="2016-01-01" data-onset="didSetDate">Trigger</button>
22 | 
23 |

The few important things to note are:

24 | 29 |

Timer Picker Usage

30 |

You can initiate the time picker by wiring up a trigger element like so:

31 |
<div role="button" class="trigger timer-trigger" data-onchange="didSetTime">Time Trigger</div>
32 | 
33 |

When the script loads, it automatically hooks on to elements with the class timer-trigger. No other configuration is necessary. Similar to the date picker, the last parameter, onchange is required if you need a callback when the user selects a date. This is optional, however, your implementation will require it if you need to update the UI. The implementation for this is intentionally left out.

34 |

The callback, unlike the date picker, responds with an object in the following format:

35 |
{
36 |   "string" : "14:26",
37 |   "hours" : 14,
38 |   "minutes" : 26
39 | }
40 | 
41 |

Notes

42 | 47 |

Todo

48 | 51 |

License

52 |

DZDateTimePicker is licensed under the MIT License. Please refer to the LICENSE file for more information.

53 |

Author

54 |

Nikhil Nigade (Dezine Zync Studios)

55 | 56 | 57 | -------------------------------------------------------------------------------- /src/autohook.js: -------------------------------------------------------------------------------- 1 | ((glob) => { 2 | 3 | if (!glob) 4 | return; // exit early as we only wish to target the browser environment 5 | 6 | /* 7 | * we check early if the browser natively supports 8 | * input[type="date"], 9 | * input[type="time"], 10 | * input[type="datetime-local"] 11 | */ 12 | 13 | let checks = { 14 | 'date': false, 15 | 'time': false, 16 | 'datetime-local': false 17 | } 18 | 19 | let input = document.createElement("input") 20 | 21 | Object.keys(checks).forEach(key => { 22 | input.type = key 23 | // if the input type is the same as we set it, it is supported by the browser 24 | checks[key] = input.type === key 25 | }) 26 | 27 | const DATE_TIME_EXP = /([\d]{4}\-[\d]{2}\-[\d]{2})T([\d]{2}\:[\d]{2})/ 28 | 29 | const hookTime = () => { 30 | let inputs = Array.prototype.slice.call(document.querySelectorAll('input[type="time"]')) 31 | inputs.forEach(attachTimeTrigger) 32 | } 33 | 34 | const hookDate = () => { 35 | let inputs = Array.prototype.slice.call(document.querySelectorAll('input[type="date"]')) 36 | inputs.forEach(attachDateTrigger) 37 | } 38 | 39 | const hookDateTime = () => { 40 | /* 41 | * when datetime-local is not supported, 42 | * we split the current input into two separate inputs. 43 | * One for date, the other for time. 44 | * We set the original input elem to "hidden" and manipulate 45 | * it's value so the user still retains the name of that field in the form 46 | */ 47 | let inputs = Array.prototype.slice.call(document.querySelectorAll('input[type="datetime-local"]')) 48 | inputs.forEach(elem => { 49 | 50 | // create a reference for the parent node because we need it later 51 | const input = elem 52 | const container = input.parentNode 53 | const getTarget = () => container.querySelector("input[data-original='datetime-local']") 54 | 55 | let value = input.value, 56 | hasValue = value.trim().length > 0, 57 | date = null, 58 | time = null 59 | 60 | if (hasValue && DATE_TIME_EXP.test(value)) { 61 | date = value.replace(DATE_TIME_EXP, "$1") 62 | time = value.replace(DATE_TIME_EXP, "$2") 63 | } 64 | 65 | const dateChange = evt => { 66 | let target = getTarget() 67 | target.dataset.date = evt.target.value 68 | } 69 | 70 | const timeChange = evt => { 71 | let target = getTarget() 72 | target.dataset.time = evt.target.value 73 | } 74 | 75 | // define a custom getter for value which utilizes the above two dataset values 76 | input.__defineGetter__("value", function() { 77 | return ((this.dataset.date||"" )+ " " + (this.dataset.time||"")).trim() 78 | }) 79 | 80 | // set the type to hidden so it's still in the DOM, but not visible to the user 81 | input.type = "hidden" 82 | // set this custom dataset prop so we can query for it later 83 | input.dataset.original = "datetime-local" 84 | 85 | // create our new date input 86 | let inDate = document.createElement("input") 87 | inDate.type = checks.date ? "date" : "text" 88 | inDate.placeholder = "Date" 89 | inDate.oninput = dateChange; 90 | 91 | if (date) 92 | inDate.value = date 93 | 94 | // check if date-min and date-max are set 95 | let {dateMin, dateMax} = input.dataset 96 | if (dateMin) 97 | inDate.dataset.dateMin = dateMin 98 | if (dateMax) 99 | inDate.dataset.dateMax = dateMax 100 | 101 | // create our new time input 102 | let inTime = document.createElement("input") 103 | inTime.type = checks.time ? "time" : "text" 104 | inTime.placeholder = "Time" 105 | inTime.oninput = timeChange; 106 | 107 | if (time) 108 | inTime.value = time; 109 | 110 | [inDate, inTime].forEach(inp => { 111 | inp.__defineGetter__("required", function() { 112 | return input.required 113 | }) 114 | 115 | inp.__defineGetter__("validity", function() { 116 | return input.validity 117 | }) 118 | 119 | inp.__defineGetter__("pattern", function() { 120 | return input.pattern 121 | }) 122 | 123 | inp.__defineGetter__("validationMessage", function() { 124 | return input.validationMessage 125 | }) 126 | 127 | inp.__defineSetter__("validationMessage", function(val) { 128 | input.validationMessage = val 129 | }) 130 | }) 131 | 132 | // add them to the DOM after the OG 133 | container.insertAdjacentElement("beforeEnd", inDate) 134 | container.insertAdjacentElement("beforeEnd", inTime) 135 | 136 | // attach the triggers 137 | attachDateTrigger(inDate) 138 | attachTimeTrigger(inTime) 139 | }) 140 | } 141 | 142 | if (!checks.date) 143 | hookDate() 144 | if (!checks.time) 145 | hookTime() 146 | if (!checks['datetime-local']) 147 | hookDateTime() 148 | 149 | // expose functions to the window 150 | glob.hookDate = hookDate; 151 | glob.hookTime = hookTime; 152 | glob.hookDateTimer = hookDateTime; 153 | 154 | })(typeof module === "undefined" ? window : undefined); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DZDateTimePicker 2 | Functional, Extensible & Simple Date and Time picker without any dependencies. 3 | 4 | DZDateTimePicker also automatically adds support for: 5 | ```html 6 | input[type="date"] 7 | input[type="time"] 8 | input[type="datetime-local"] 9 | ``` 10 | if they are not supported natively. You don't have to do anything extra. The library will handle the setup for you. You simply have to query the `.value` of your original input elements and you're all set. 11 | 12 | ### Demos 13 | The related demos are in the `demo` folder of this repo. 14 | On a related note: 15 | - All source files are in the `src` directory. 16 | - All distribution files are in the `dist` directory (which you should use for production sites) 17 | 18 | ### Setup 19 | Via NPM 20 | ```sh 21 | npm install --save dzdatetimepicker 22 | ``` 23 | 24 | ```html 25 | 26 | 27 | 28 | 29 | ``` 30 | 31 | ### Date Picker Usage 32 | Simply, 33 | ```html 34 | 35 | ``` 36 | DZDateTimePicker will allow native browser implementations to take over if they exist. If they don't, the library will do it's own wiring for you. 37 | 38 | 39 | You can optionally initiate the date picker by wiring up a *trigger* element like so: 40 | ```html 41 | 47 | ``` 48 | 49 | The few important things to note are: 50 | - when `dzdatetimepicker-dsit.js` runs, it automatically finds elements with the class `date-trigger` and hooks on to them. No futher configuration is required. 51 | - You can set additional, *optional* dataset items like `date-max` and `date-min` to control the selectable items within a range. Both are optional, and you can use only one if desired. 52 | - the last parameter, `onset` is required if you need a callback when the user selects a date. This is optional, however, your implementation will require it if you need to update the UI. The implementation for this is intentionally left out. 53 | 54 | ### Timer Picker Usage 55 | Simply, 56 | ```html 57 | 58 | ``` 59 | 60 | You can optionally initiate the time picker by wiring up a *trigger* element like so: 61 | ```html 62 |
Time Trigger
67 | ``` 68 | When the script loads, it automatically hooks on to elements with the class `timer-trigger`. No other configuration is necessary. Similar to the date picker, the last parameter, `onchange` is required if you need a callback when the user selects a date. This is optional, however, your implementation will require it if you need to update the UI. The implementation for this is intentionally left out. 69 | 70 | The callback, unlike the date picker, responds with an object in the following format: 71 | ```json 72 | { 73 | "string" : "14:26", 74 | "hours" : 14, 75 | "minutes" : 26 76 | } 77 | ``` 78 | 79 | ### Range Picker Usage 80 | To setup a range picker, include the `rangepicker-dist.js` file along with the date-picker sources as mentioned above. Then you can can write simple markup as follows: 81 | ```html 82 |
83 | 84 |
Start
91 | 92 |
End
99 | 100 |
101 | ``` 102 | 103 | You can then initialise the range picker as follows: 104 | ```js 105 | const myRangePicker = new RangePicker(document.getElementById("range-picker")) 106 | ``` 107 | 108 | The `RangePicker` will then automatically handle all the setup for you and adjust the min-max ranges for the date picker based on the user's input. 109 | 110 | ### Notes 111 | - Both the datepicker and timepicker automatically idenity `` elements. They hook on to the `focus` and `blur` events so the user can use the pickers to set the values directly. 112 | - If the pickers detect an `` element, the pickers will update the `value` attribute when the user updates their selection. 113 | - When not using an `` element, you can optionally set the attribute `data-date-val=""` and it'll be updated similarly. 114 | 115 | ### Keyboard Navigation 116 | #### Date picker 117 | - `Tab`, `→` to move to the next date 118 | - `Shift + Tab`, `←` to move to the previous date 119 | - `Space` or `Enter` to confirm input 120 | - `Escape` to dismiss the datepicker 121 | - `Home` to go to the first date in the month 122 | - `End` to go to the last date in the month 123 | - `Page Up` to go to the previous month 124 | - `Page Down` to go to the next month 125 | 126 | #### Time picker 127 | - `Tab` to move to the next control 128 | - `Shift + Tab` to move to the previous control 129 | - `Enter` to confirm input 130 | - `Space` to confirm control input 131 | 132 | ### License 133 | DZDateTimePicker is licensed under the MIT License. Please refer to the LICENSE file for more information. 134 | 135 | ### Author 136 | Nikhil Nigade (Dezine Zync Studios) 137 | -------------------------------------------------------------------------------- /dist/dzdatetimepicker.css: -------------------------------------------------------------------------------- 1 | :root{--dzdp-color-border:var(--color-border, rgba(0, 0, 0, 0.12));--dzdp-color-base:var(--color-base, #ffffff);--dzdp-color-title:var(--color-title, #000000);--dzdp-color-text:var(--color-text, #0a0a0c);--dzdp-color-days:var(--color-subtext, #282828);--dzdp-hover-color:var(--color-base2, #eeeeee);--dzdp-color-blue:var(--color-blue, #007aff);--dzdp-color-red:var(--color-red, #ff3b30)}.date-trigger,.timer-trigger{cursor:pointer}#dz-calendar,#dz-timer{padding-top:8px;width:245px;height:auto;display:block;padding-bottom:8px;position:absolute;background:var(--dzdp-color-base);-webkit-box-shadow:0 2px 6px rgba(0,0,0,0.12), inset 0 0 0 1px var(--dzdp-color-border), 0 4px 21px rgba(0,0,0,0.08);box-shadow:0 2px 6px rgba(0,0,0,0.12), inset 0 0 0 1px var(--dzdp-color-border), 0 4px 21px rgba(0,0,0,0.08);border-radius:8px;z-index:3;-webkit-transform:scale(0.25);-ms-transform:scale(0.25);transform:scale(0.25);-webkit-transform-origin:50% top;-ms-transform-origin:50% top;transform-origin:50% top;opacity:0;will-change:transform, opacity;-webkit-transition:opacity 0.2s ease, -webkit-transform 0.2s ease;transition:opacity 0.2s ease, -webkit-transform 0.2s ease;-o-transition:transform 0.2s ease, opacity 0.2s ease;transition:transform 0.2s ease, opacity 0.2s ease;transition:transform 0.2s ease, opacity 0.2s ease, -webkit-transform 0.2s ease;pointer-events:none}#dz-calendar.active,#dz-timer.active{-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1);opacity:1;pointer-events:auto}#dz-calendar:before,#dz-timer:before{content:'';width:12px;height:12px;border-radius:2px;pointer-events:auto;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg);z-index:2;position:absolute;left:50%;top:-6px;margin-left:-6px;background-color:var(--dzdp-color-base);-webkit-box-shadow:-1px -1px 2px rgba(0, 0, 0, 0.2);box-shadow:-1px -1px 2px rgba(0, 0, 0, 0.2)}#dz-calendar{padding:0;padding-bottom:8px}#dz-calendar .buttons-bar{padding-bottom:8px}#dz-calendar #dz-next,#dz-calendar #dz-prev{width:24px;height:24px;background-color:inherit;-webkit-box-shadow:none;box-shadow:none;padding:0;display:block;border:none;outline:none}#dz-calendar #dz-next:hover,#dz-calendar #dz-prev:hover{cursor:pointer}#dz-calendar #dz-next svg path,#dz-calendar #dz-prev svg path{fill:var(--dzdp-color-blue)!important}#dz-calendar #dz-next{margin-left:8px}#dz-calendar .dz-title{font-size:13px;padding:8px 8px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;border-bottom:1px solid var(--dzdp-color-border)}#dz-calendar .dz-title h4{margin:0;padding:0;font-size:13px}#dz-calendar .dz-title button{margin-left:auto}#dz-calendar .dz-title button:last-child{margin-left:8px}#dz-calendar .dz-days{width:100%;height:24px;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:nowrap;flex-wrap:nowrap;-webkit-box-align:center;-ms-flex-align:center;align-items:center}#dz-calendar .dz-days>div{-webkit-box-flex:1;-ms-flex:1;flex:1;text-align:center;font-size:12px;font-weight:600;color:var(--dzdp-color-days)}#dz-calendar .dz-dates{width:100%;height:auto;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap}#dz-calendar .dz-dates>button{-webkit-box-flex:0;-ms-flex:0 0 34px;flex:0 0 34px;height:24px;display:inline-block;background-color:transparent;-webkit-box-shadow:none;box-shadow:none;border:none;text-align:center;line-height:24px;font-weight:normal;font-size:13px;-webkit-font-feature-settings:"tnum";font-feature-settings:"tnum";color:var(--dzdp-color-text);position:relative;padding:0;text-transform:none;border-radius:0}#dz-calendar .dz-dates>button:hover{cursor:pointer;color:var(--color-title)}#dz-calendar .dz-dates>button:hover:before{content:'';width:24px;height:24px;display:block;position:absolute;left:6px;top:0px;z-index:-1;border-radius:12px;background-color:var(--dzdp-hover-color)}#dz-calendar .dz-dates>button.today{color:var(--dzdp-color-red);font-weight:600}#dz-calendar .dz-dates>button.today:before{content:'';width:24px;height:24px;display:block;position:absolute;left:6px;top:0px;z-index:-1;border-radius:12px;background-color:var(--dzdp-hover-color);will-change:background;-webkit-transition:background 0.2s ease;-o-transition:background 0.2s ease;transition:background 0.2s ease}#dz-calendar .dz-dates>button.today:hover:before{background-color:var(--dzdp-hover-color)}#dz-calendar .dz-dates>button.selected{color:white}#dz-calendar .dz-dates>button.selected:before{content:'';width:24px;height:24px;display:block;position:absolute;left:6px;top:0px;z-index:-1;border-radius:12px;background-color:var(--dzdp-hover-color);will-change:background;-webkit-transition:background 0.2s ease;-o-transition:background 0.2s ease;transition:background 0.2s ease;background-color:var(--dzdp-color-blue)}#dz-calendar .dz-dates>button.selected:hover{color:var(--dzdp-color-blue)}#dz-calendar .dz-dates>button.selected:hover:before{background-color:var(--dzdp-hover-color)}#dz-calendar .dz-dates>button.disabled{pointer-events:none;opacity:0.5}#dz-timer{width:auto;padding:8px}@media (prefers-color-scheme:dark){:root{--dzdp-color-base:var(--color-base2, #2c2c30);--dzdp-hover-color:var(--color-base3, #323236);--dzdp-color-title:#ffffff;--dzdp-color-text:#f8f8fa;--dzdp-color-days:#c8c8c8}#dz-calendar,#dz-timer{-webkit-box-shadow:0 2px 6px rgba(0,0,0,0.12), inset 0 0 0 1px var(--dzdp-color-border), 0 4px 21px rgba(0,0,0,1);box-shadow:0 2px 6px rgba(0,0,0,0.12), inset 0 0 0 1px var(--dzdp-color-border), 0 4px 21px rgba(0,0,0,1)}#dz-calendar #dz-next svg path,#dz-calendar #dz-prev svg path{fill:var(--dzdp-color-red)!important}#dz-calendar .dz-title h4{color:var(--dzdp-color-title)}#dz-calendar .dz-dates button{border:none;-webkit-box-shadow:none;box-shadow:none}#dz-calendar .dz-dates button.selected:before{background-color:var(--dzdp-color-red)}#dz-calendar .dz-dates button.selected:hover{color:var(--dzdp-color-red)}#dz-calendar .dz-dates button.selected:hover:before{background-color:var(--dzdp-hover-color)}} 2 | /*# sourceMappingURL=dzdatetimepicker.css.map */ -------------------------------------------------------------------------------- /dist/dzdatetimepicker-dist.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../src/dzdatetimepicker.js","../src/datepicker.js","../src/timepicker.js","../src/rangepicker.js","../src/autohook.js"],"names":[],"mappings":"AAAA,a;;AAEA,kC;;AAEA,8E;;AAEA,mB;AACA,gB;;AAEA,0B;;AAEA,0B;;AAEA,mD;AACA,sB;;AAEA,qB;AACA,iB;;AAEA,G;;AAEA,kB;AACA,E;;AAEA,6B;AACA,+B;AACA,wB;AACA,mB;AACA,c;AACA,E;;AAEA,4B;AACA,+B;AACA,wB;AACA,c;AACA,E;;AAEA,0E;AACA,uC;AACA,uB;AACA,mB;AACA,I;AACA,G;;AAEA,yE;AACA,sC;AACA,uB;AACA,mB;AACA,I;AACA,G;;AAEA,gE;AACA,qC;AACA,0B;AACA,sB;AACA,yB;AACA,M;AACA,E;;AAEA,kC;AACA,kC;AACA,mC;AACA,gC;;AC9DA,Y;;AAEA,kR;AACA,kQ;;AAEA,oB;;AAEA,8B;AACA,oC;AACA,iB;AACA,K;;AAEA,Y;AACA,0B;AACA,oB;;AAEA,6B;;AAEA,uB;AACA,K;;AAEA,kB;;AAEA,kC;;AAEA,qC;AACA,8B;;AAEA,yC;AACA,+D;AACA,kE;;AAEA,8E;;AAEA,yE;AACA,2E;;AAEA,0D;AACA,gE;;AAEA,0C;;AAEA,yC;AACA,uC;;AAEA,uD;AACA,2F;;AAEA,mB;;AAEA,oB;;AAEA,O;;AAEA,kC;;AAEA,qC;AACA,8B;;AAEA,yC;AACA,+D;AACA,kE;;AAEA,0E;;AAEA,qE;AACA,2E;;AAEA,0D;AACA,gE;;AAEA,0C;;AAEA,qC;AACA,mC;;AAEA,uD;AACA,2F;;AAEA,mB;;AAEA,oB;;AAEA,O;;AAEA,iC;;AAEA,yC;;AAEA,oB;AACA,oD;AACA,+C;AACA,mD;AACA,sD;AACA,S;AACA,O;;AAEA,iC;AACA,6B;;AAEA,2C;;AAEA,6C;AACA,gC;AACA,iH;AACA,mB;AACA,wB;AACA,qB;AACA,S;;AAEA,6C;AACA,kC;AACA,uE;;AAEA,gC;AACA,mD;AACA,sD;AACA,wD;AACA,sC;;AAEA,wF;AACA,mB;AACA,wB;AACA,qB;AACA,S;;AAEA,4B;AACA,oD;AACA,qB;AACA,S;;AAEA,4B;AACA,oD;AACA,qB;AACA,S;;AAEA,4D;AACA,qB;;AAEA,6C;AACA,kF;AACA,oE;AACA,sE;AACA,S;;AAEA,4B;AACA,oB;AACA,mD;AACA,S;;AAEA,mB;AACA,O;;AAEA,kC;;AAEA,yC;AACA,iD;;AAEA,+D;AACA,+D;;AAEA,kD;AACA,c;AACA,kB;;AAEA,uC;AACA,2D;;AAEA,sC;AACA,4D;;AAEA,gE;;AAEA,8C;AACA,iC;AACA,qC;AACA,8D;AACA,c;AACA,yD;AACA,S;AACA,4C;AACA,2C;;AAEA,0B;AACA,yC;;AAEA,kD;;AAEA,O;;AAEA,+B;;AAEA,yC;AACA,qB;AACA,gB;;AAEA,0G;AACA,iC;AACA,kD;AACA,4D;AACA,U;;AAEA,O;;AAEA,4B;;AAEA,qC;;AAEA,mD;AACA,wC;;AAEA,iD;;AAEA,4C;AACA,4B;AACA,6B;AACA,iB;AACA,sB;AACA,S;;AAEA,sD;;AAEA,sB;AACA,0C;AACA,mC;AACA,S;;AAEA,sD;AACA,kC;AACA,gF;;AAEA,4B;;AAEA,0C;;AAEA,sB;AACA,iE;AACA,U;AACA,qB;AACA,2D;AACA,kC;AACA,gE;AACA,U;AACA,yB;AACA,wD;AACA,qC;;AAEA,2D;AACA,4C;;AAEA,4D;;AAEA,4D;;AAEA,oD;AACA,0C;AACA,uD;;AAEA,4C;;AAEA,sD;AACA,sD;;AAEA,0D;AACA,0D;;AAEA,+B;AACA,4C;AACA,6D;AACA,iD;AACA,uF;AACA,a;AACA,Y;AACA,U;AACA,qB;AACA,qB;;AAEA,sC;AACA,wB;AACA,gC;AACA,U;AACA,qB;AACA,U;AACA,gC;;AAEA,8G;AACA,+C;AACA,W;;AAEA,gC;;AAEA,mF;;AAEA,U;AACA,yB;AACA,uB;AACA,0B;AACA,W;AACA,wE;AACA,0E;AACA,U;AACA,yB;AACA,4B;AACA,mD;AACA,iB;AACA,U;AACA,uB;AACA,4B;AACA,U;;AAEA,oB;;AAEA,O;;AAEA,2G;AACA,qD;;AAEA,uC;AACA,wB;AACA,Q;AACA,uC;AACA,6D;AACA,yD;AACA,oD;AACA,qD;AACA,S;AACA,c;AACA,6D;AACA,S;AACA,O;;AAEA,kC;AACA,2B;AACA,Q;;AAEA,4C;;AAEA,K;;AAEA,mB;AACA,mD;AACA,K;;AAEA,wB;AACA,kD;AACA,4D;AACA,K;;AAEA,uB;AACA,gH;AACA,K;;AAEA,2B;AACA,sJ;AACA,K;;AAEA,+B;;AAEA,mC;AACA,iC;AACA,6D;AACA,mB;;AAEA,6B;AACA,oD;AACA,qB;AACA,O;;AAEA,2B;AACA,K;;AAEA,sB;;AAEA,2B;AACA,6B;;AAEA,+D;AACA,yC;AACA,2C;AACA,mD;;AAEA,2C;AACA,uC;;AAEA,kD;;AAEA,iB;AACA,mC;AACA,iB;AACA,mC;;AAEA,oB;AACA,0C;AACA,yC;AACA,2C;AACA,mD;;AAEA,mC;AACA,uC;;AAEA,gK;;AAEA,oC;;AAEA,yB;;AAEA,qC;AACA,qC;AACA,gC;AACA,S;;AAEA,8C;AACA,yC;AACA,mC;AACA,S;;AAEA,mE;AACA,iE;AACA,mC;AACA,S;;AAEA,mE;AACA,iE;AACA,mC;AACA,S;;AAEA,oC;;AAEA,sB;AACA,0B;AACA,2B;AACA,6B;AACA,4B;AACA,0B;AACA,4B;AACA,yB;AACA,S;;AAEA,6C;AACA,oE;AACA,mD;;AAEA,6E;AACA,kE;AACA,gD;AACA,yC;;AAEA,wB;AACA,sG;AACA,S;AACA,c;AACA,+I;AACA,S;;AAEA,Q;;AAEA,wB;;AAEA,mB;;AAEA,K;;AAEA,oB;;AAEA,2B;;AAEA,0G;AACA,0C;AACA,O;;AAEA,kC;AACA,gC;;AAEA,+C;AACA,oD;;AAEA,wI;AACA,8B;AACA,mL;AACA,sG;AACA,8F;AACA,c;AACA,8B;;AAEA,6B;AACA,qC;AACA,Q;;AAEA,uB;AACA,gC;AACA,a;;AAEA,mB;AACA,K;;AAEA,yC;;AAEA,yC;;AAEA,oB;AACA,e;AACA,oD;;AAEA,uB;AACA,+B;AACA,gF;AACA,yC;AACA,sC;AACA,O;;AAEA,oD;AACA,uB;AACA,wD;AACA,2C;;AAEA,sC;;AAEA,iC;AACA,wF;AACA,2C;AACA,O;;AAEA,K;;AAEA,oC;;AAEA,mC;AACA,4B;;AAEA,oB;;AAEA,sB;AACA,wC;AACA,6C;AACA,U;AACA,8B;AACA,qB;AACA,8C;AACA,qD;AACA,U;AACA,qB;AACA,4B;AACA,mF;AACA,W;;AAEA,kC;AACA,U;AACA,qB;AACA,2E;AACA,6E;AACA,U;AACA,uB;AACA,4B;AACA,U;;AAEA,O;;AAEA,kB;;AAEA,K;;AAEA,yC;;AAEA,sC;;AAEA,0C;AACA,2B;AACA,O;;AAEA,mB;;AAEA,K;;AAEA,wC;;AAEA,oC;AACA,kC;;AAEA,4C;AACA,+B;AACA,O;;AAEA,qB;;AAEA,K;;AAEA,G;;AAEA,0B;AACA,sC;AACA,+B;AACA,oC;AACA,M;;AAEA,Q;AACA,gC;AACA,sC;AACA,G;;AAEA,oD;;ACvlBA,Y;;AAEA,oB;;AAEA,mB;AACA,iB;AACA,K;;AAEA,Y;;AAEA,0B;AACA,oB;;AAEA,6B;AACA,uB;;AAEA,K;;AAEA,kB;;AAEA,iC;;AAEA,4C;AACA,sB;;AAEA,mC;;AAEA,iB;AACA,iD;AACA,4C;AACA,gD;AACA,gD;AACA,W;;AAEA,0E;;AAEA,O;;AAEA,iC;AACA,6B;;AAEA,2C;AACA,qB;;AAEA,4B;AACA,wD;AACA,uD;AACA,qD;AACA,kD;AACA,W;AACA,S;;AAEA,sE;AACA,iD;AACA,qC;;AAEA,qD;;AAEA,mB;AACA,O;;AAEA,+B;;AAEA,kC;AACA,mC;;AAEA,qD;AACA,uD;AACA,qD;;AAEA,sC;AACA,qB;;AAEA,uC;AACA,sB;;AAEA,8C;AACA,mD;AACA,qC;AACA,8D;AACA,c;AACA,yD;AACA,S;;AAEA,qD;AACA,mB;AACA,wC;AACA,iC;AACA,0B;AACA,U;;AAEA,O;;AAEA,qC;;AAEA,qC;;AAEA,qB;AACA,yC;AACA,4B;AACA,6B;AACA,iB;AACA,sB;AACA,S;;AAEA,qD;AACA,sB;AACA,uB;AACA,mC;AACA,S;;AAEA,gC;;AAEA,oC;;AAEA,sB;AACA,8D;AACA,U;AACA,qB;AACA,iC;;AAEA,iC;AACA,6E;AACA,iC;AACA,wC;AACA,yC;;AAEA,iC;AACA,uE;AACA,+C;AACA,2D;AACA,c;AACA,W;;AAEA,kC;AACA,U;AACA,qB;AACA,0B;AACA,wE;AACA,6D;AACA,Y;;AAEA,6D;AACA,U;AACA,yB;AACA,wD;AACA,kC;;AAEA,2D;AACA,2C;;AAEA,mD;AACA,6C;;AAEA,+B;AACA,yC;;AAEA,6D;AACA,iD;AACA,oF;AACA,a;AACA,Y;AACA,U;AACA,qB;AACA,+C;AACA,gD;AACA,wE;AACA,0E;AACA,U;AACA,uB;AACA,4B;AACA,U;;AAEA,oB;;AAEA,O;;AAEA,uC;AACA,wB;AACA,2D;AACA,uC;AACA,2D;AACA,yD;AACA,oD;AACA,qD;AACA,S;AACA,O;;AAEA,4F;;AAEA,kC;AACA,2B;AACA,Q;;AAEA,8C;;AAEA,K;;AAEA,gB;AACA,gD;AACA,K;;AAEA,qB;AACA,+C;AACA,4D;AACA,K;;AAEA,iB;;AAEA,wD;AACA,0C;AACA,+B;;AAEA,e;AACA,4B;AACA,mC;AACA,uB;;AAEA,0B;AACA,yB;AACA,O;;AAEA,uG;AACA,+B;;AAEA,4B;AACA,8C;AACA,mB;AACA,qB;AACA,wB;AACA,+B;AACA,iF;AACA,2D;AACA,oB;;AAEA,0B;AACA,iC;;AAEA,8B;AACA,4C;AACA,sB;AACA,wC;AACA,2B;AACA,sC;AACA,+E;AACA,yD;AACA,kB;;AAEA,e;AACA,0B;AACA,8B;AACA,+E;AACA,8E;AACA,kB;;AAEA,yB;AACA,a;;AAEA,mB;AACA,K;;AAEA,8B;AACA,mC;AACA,4B;;AAEA,iB;;AAEA,sB;AACA,0C;AACA,U;AACA,8B;AACA,qB;AACA,iC;AACA,8B;AACA,4C;AACA,U;AACA,uB;AACA,4B;AACA,U;;AAEA,O;;AAEA,uE;AACA,yE;;AAEA,kB;AACA,K;;AAEA,G;;AAEA,4B;AACA,sC;AACA,+B;AACA,oC;AACA,M;AACA,G;AACA,Q;AACA,gC;AACA,sC;AACA,G;;AAEA,oD;;AC7SA,Y;AACA,qB;AACA,uB;AACA,wB;AACA,gC;AACA,mB;AACA,K;;AAEA,a;AACA,qB;AACA,c;;AAEA,2B;AACA,c;AACA,6B;;AAEA,4B;;AAEA,8D;AACA,0D;;AAEA,iD;AACA,+C;AACA,M;AACA,gD;AACA,4C;;AAEA,yD;AACA,qD;;AAEA,8D;AACA,iE;AACA,K;;AAEA,gB;AACA,+B;AACA,wB;AACA,uB;;AAEA,0D;;AAEA,kB;AACA,wB;AACA,U;AACA,sB;;AAEA,oB;AACA,+C;AACA,8C;AACA,uD;AACA,iC;AACA,Q;AACA,uC;;AAEA,0E;;AAEA,+D;AACA,gE;AACA,Q;AACA,oF;AACA,O;;AAEA,K;AACA,G;;AAEA,qC;AACA,+D;AACA,M;AACA,kC;;AAEA,oD;;ACtEA,Y;;AAEA,Y;AACA,2E;;AAEA,I;AACA,qD;AACA,yB;AACA,yB;AACA,iC;AACA,K;;AAEA,gB;AACA,kB;AACA,kB;AACA,2B;AACA,G;;AAEA,6C;AACA,E;AACA,sC;AACA,oB;AACA,iF;AACA,qC;AACA,I;;AAEA,wE;;AAEA,0B;AACA,4F;AACA,qC;AACA,G;;AAEA,0B;AACA,4F;AACA,qC;AACA,G;;AAEA,8B;AACA,O;AACA,6C;AACA,4D;AACA,wC;AACA,gE;AACA,8E;AACA,O;AACA,sG;AACA,4B;AACA,M;AACA,wE;AACA,wB;AACA,wC;AACA,8F;;AAEA,8B;AACA,2C;AACA,oB;AACA,mB;AACA,M;AACA,kD;AACA,iD;AACA,iD;AACA,O;AACA,M;AACA,iC;AACA,gC;AACA,8C;AACA,O;;AAEA,iC;AACA,gC;AACA,8C;AACA,O;;AAEA,qF;AACA,kD;AACA,+E;AACA,Q;;AAEA,qF;AACA,2B;AACA,kE;AACA,+C;AACA,M;AACA,kC;AACA,kD;AACA,iD;AACA,iC;AACA,kC;;AAEA,e;AACA,2B;;AAEA,+C;AACA,4C;AACA,kB;AACA,wC;AACA,kB;AACA,wC;;AAEA,kC;AACA,kD;AACA,iD;AACA,iC;AACA,kC;;AAEA,e;AACA,4B;AACA,M;AACA,uC;AACA,qD;AACA,+B;AACA,U;;AAEA,qD;AACA,+B;AACA,U;;AAEA,oD;AACA,8B;AACA,U;;AAEA,8D;AACA,wC;AACA,U;;AAEA,iE;AACA,uC;AACA,U;AACA,Q;;AAEA,yC;AACA,0D;AACA,0D;;AAEA,4B;AACA,+B;AACA,+B;AACA,M;AACA,G;;AAEA,mB;AACA,c;AACA,mB;AACA,c;AACA,gC;AACA,kB;;AAEA,mC;AACA,2B;AACA,2B;AACA,oC;;AAEA,uD"} -------------------------------------------------------------------------------- /src/dzdatetimepicker.less: -------------------------------------------------------------------------------- 1 | /* DZDateTimePicker */ 2 | 3 | :root { 4 | --dzdp-color-border: var(--color-border, rgba(0,0,0,.12)); 5 | --dzdp-color-base: var(--color-base, rgba(255, 255, 255, 1)); 6 | 7 | --dzdp-color-title: var(--color-title, rgba(0, 0, 0, 1)); 8 | --dzdp-color-text: var(--color-text, rgba(10, 10, 12, 1)); 9 | --dzdp-color-days: var(--color-subtext, rgba(40, 40, 40, 1)); 10 | 11 | --dzdp-hover-color: var(--color-base2, rgba(238, 238, 238, 1)); 12 | --dzdp-color-blue: var(--color-blue, rgb(0, 122, 255)); 13 | --dzdp-color-red: var(--color-red, rgb(255, 59, 48)); 14 | } 15 | 16 | .hideText() { 17 | text-indent: 1000%; 18 | white-space: nowrap; 19 | overflow: hidden; 20 | } 21 | 22 | .monospaced() { font-feature-settings: "tnum"; } 23 | 24 | .date-trigger, .timer-trigger { 25 | cursor: pointer; 26 | } 27 | 28 | #dz-calendar, #dz-timer { 29 | padding-top: 8px; 30 | padding-bottom: 8px; 31 | 32 | width: 245px; 33 | height: auto; 34 | display: block; 35 | 36 | padding-bottom: 8px; 37 | 38 | position: absolute; 39 | 40 | background: var(--dzdp-color-base); 41 | 42 | box-shadow: ~"0 2px 6px rgba(0,0,0,0.12), inset 0 0 0 1px var(--dzdp-color-border), 0 4px 21px rgba(0,0,0,0.08)"; 43 | 44 | border-radius: 8px; 45 | 46 | z-index: 3; 47 | 48 | transform: scale(0.25); 49 | transform-origin: 50% top; 50 | opacity: 0; 51 | will-change: transform, opacity; 52 | 53 | transition: transform 0.2s ease, opacity 0.2s ease; 54 | pointer-events: none; 55 | 56 | &.active { 57 | transform: scale(1); 58 | opacity: 1; 59 | pointer-events: auto; 60 | } 61 | 62 | &:before { 63 | content: ''; 64 | width: 12px; 65 | height: 12px; 66 | border-radius: 2px; 67 | pointer-events: auto; 68 | transform: rotate(45deg); 69 | 70 | z-index: 2; 71 | 72 | position: absolute; 73 | left: 50%; 74 | top: -6px; 75 | margin-left: -6px; 76 | 77 | background-color: var(--dzdp-color-base); 78 | box-shadow: -1px -1px 2px rgba(0,0,0,.2); 79 | } 80 | } 81 | 82 | #dz-calendar { 83 | 84 | padding: 0; 85 | padding-bottom: 8px; 86 | 87 | .buttons-bar { 88 | padding-bottom: 8px; 89 | } 90 | 91 | #dz-prev, #dz-next { 92 | width: 24px; 93 | height: 24px; 94 | background-color: inherit; 95 | box-shadow: none; 96 | 97 | padding: 0; 98 | 99 | display: block; 100 | border: none; 101 | outline: none; 102 | 103 | &:hover { 104 | cursor: pointer; 105 | } 106 | 107 | svg path { 108 | fill: var(--dzdp-color-blue) !important; 109 | } 110 | 111 | } 112 | 113 | #dz-next { 114 | margin-left: 8px; 115 | } 116 | 117 | .dz-title { 118 | 119 | font-size: 13px; 120 | padding: 8px 8px; 121 | display: flex; 122 | align-items: center; 123 | border-bottom: 1px solid var(--dzdp-color-border); 124 | 125 | h4 { 126 | margin: 0; 127 | padding: 0; 128 | font-size: 13px; 129 | } 130 | 131 | button { 132 | margin-left: auto; 133 | 134 | &:last-child { 135 | margin-left: 8px; 136 | } 137 | 138 | } 139 | 140 | } 141 | 142 | .dz-days { 143 | width: 100%; 144 | height: 24px; 145 | 146 | display: flex; 147 | flex-wrap: nowrap; 148 | align-items: center; 149 | 150 | > div { 151 | flex: 1; 152 | text-align: center; 153 | font-size: 12px; 154 | font-weight: 600; 155 | color: var(--dzdp-color-days); 156 | } 157 | 158 | } 159 | 160 | .dz-dates { 161 | width: 100%; 162 | height: auto; 163 | 164 | display: flex; 165 | flex-wrap: wrap; 166 | 167 | > button { 168 | // width: 35px; 169 | flex: 0 0 34px; 170 | height: 24px; 171 | display: inline-block; 172 | 173 | background-color: transparent; 174 | box-shadow: none; 175 | border: none; 176 | 177 | text-align: center; 178 | line-height: 24px; 179 | font-weight: normal; 180 | font-size: 13px; 181 | .monospaced(); 182 | 183 | color: var(--dzdp-color-text); 184 | 185 | position: relative; 186 | 187 | padding: 0; 188 | text-transform: none; 189 | border-radius: 0; 190 | 191 | .onHover() { 192 | content: ''; 193 | width: 24px; 194 | height: 24px; 195 | display: block; 196 | 197 | position: absolute; 198 | left: 6px; 199 | top: 0px; 200 | 201 | z-index: -1; 202 | 203 | border-radius: 12px; 204 | 205 | background-color: var(--dzdp-hover-color); 206 | } 207 | 208 | &:hover { 209 | cursor: pointer; 210 | color: var(--color-title); 211 | 212 | &:before { 213 | .onHover(); 214 | } 215 | 216 | } 217 | 218 | &.today { 219 | 220 | color: var(--dzdp-color-red); 221 | font-weight: 600; 222 | 223 | &:before { 224 | .onHover(); 225 | background-color: var(--dzdp-hover-color); 226 | will-change: background; 227 | transition: background 0.2s ease; 228 | } 229 | 230 | &:hover { 231 | &:before { 232 | background-color: var(--dzdp-hover-color); 233 | } 234 | } 235 | 236 | } 237 | 238 | &.selected { 239 | 240 | color: white; 241 | 242 | &:before { 243 | .onHover(); 244 | will-change: background; 245 | transition: background 0.2s ease; 246 | background-color: var(--dzdp-color-blue); 247 | } 248 | 249 | &:hover { 250 | color: var(--dzdp-color-blue); 251 | &:before { 252 | background-color: var(--dzdp-hover-color); 253 | } 254 | } 255 | 256 | } 257 | 258 | &.disabled { 259 | pointer-events: none; 260 | opacity: 0.5; 261 | } 262 | 263 | } 264 | 265 | } 266 | 267 | } 268 | 269 | #dz-timer { 270 | width: auto; 271 | padding: 8px; 272 | } 273 | 274 | @media (prefers-color-scheme: dark) { 275 | :root { 276 | 277 | --dzdp-color-base: var(--color-base2, rgba(44, 44, 48, 1)); 278 | --dzdp-hover-color: var(--color-base3, rgba(50, 50, 54, 1)); 279 | 280 | --dzdp-color-title: rgba(255, 255, 255, 1); 281 | --dzdp-color-text: rgba(248, 248, 250, 1); 282 | --dzdp-color-days: rgba(200, 200, 200, 1); 283 | 284 | // --dzdp-hover-color: rgba(60, 60, 64, 1); 285 | // --dzdp-color-blue: rgb(10, 132, 255); 286 | // --dzdp-color-red: rgb(255, 69, 58); 287 | } 288 | 289 | #dz-calendar, #dz-timer { 290 | box-shadow: ~"0 2px 6px rgba(0,0,0,0.12), inset 0 0 0 1px var(--dzdp-color-border), 0 4px 21px rgba(0,0,0,1)"; 291 | } 292 | 293 | #dz-calendar { 294 | 295 | #dz-prev, #dz-next { 296 | svg path { 297 | fill: var(--dzdp-color-red) !important; 298 | } 299 | } 300 | 301 | .dz-title { 302 | h4 { 303 | color: var(--dzdp-color-title); 304 | } 305 | } 306 | 307 | .dz-dates { 308 | 309 | button { 310 | border: none; 311 | box-shadow: none; 312 | 313 | &.selected { 314 | 315 | &:before { 316 | background-color: var(--dzdp-color-red); 317 | } 318 | 319 | &:hover { 320 | 321 | color: var(--dzdp-color-red); 322 | 323 | &:before { 324 | background-color: var(--dzdp-hover-color); 325 | } 326 | 327 | } 328 | 329 | } 330 | 331 | } 332 | 333 | } 334 | 335 | } 336 | 337 | } 338 | -------------------------------------------------------------------------------- /src/timepicker.js: -------------------------------------------------------------------------------- 1 | ((glob) => { 2 | 3 | class TimePicker { 4 | 5 | constructor() { 6 | this.init() 7 | } 8 | 9 | init() { 10 | 11 | if(this.initialized) 12 | return false 13 | 14 | this.initialized = true 15 | this.setupHooks() 16 | 17 | } 18 | 19 | setupHooks() { 20 | 21 | this.bodyClick = (evt) => { 22 | 23 | if(evt.target.nodeName === 'SELECT') 24 | return false 25 | 26 | let timer = this.getTimer() 27 | 28 | if(timer) 29 | if(!timer.classList.contains('active')) 30 | document.body.removeChild(timer) 31 | else if(!this.isInTimer(evt.target)) { 32 | return this.cleanupTimer(evt, timer) 33 | } 34 | 35 | document.body.removeEventListener('click', this.bodyClick, false); 36 | 37 | } 38 | 39 | this.bodyInput = (evt) => { 40 | const {keyCode} = evt 41 | 42 | if (keyCode != 13 && keyCode != 27) 43 | return true 44 | 45 | if (keyCode == 27) { 46 | // user is dismissing by pressing the Esc. key 47 | // reset the value back to the original value 48 | if (this.hasOwnProperty("originalValue")) { 49 | this.source.value = this.originalValue 50 | } 51 | } 52 | 53 | // user has pressed the enter key. Assume to be a confirmation 54 | if (this.hasOwnProperty("originalValue")) 55 | delete [this.originalValue] 56 | 57 | this.cleanupTimer(undefined, this.getTimer()) 58 | 59 | return true 60 | } 61 | 62 | const didChange = () => { 63 | 64 | // let target = evt.target 65 | let timer = this.getTimer() 66 | 67 | let hours = parseInt(timer.children[0].value) 68 | let minutes = parseInt(timer.children[1].value) 69 | let shift = parseInt(timer.children[2].value) 70 | 71 | if(shift === 1 && hours != 12) 72 | hours += 12 73 | 74 | if(hours === 12 && shift === 0) 75 | hours = '00' 76 | 77 | if(this.source.nodeName === 'INPUT') { 78 | this.source.value = hours + ':' + minutes 79 | if ('InputEvent' in window) 80 | this.source.dispatchEvent(new InputEvent('input')) 81 | else 82 | this.source.dispatchEvent(new Event('input')) 83 | } 84 | 85 | let fn = window[this.source.dataset.onchange] 86 | if(fn) fn({ 87 | string: hours + ':' + minutes, 88 | hours: parseInt(hours), 89 | minutes: minutes 90 | }) 91 | 92 | } 93 | 94 | const triggerClick = (evt) => { 95 | 96 | let phantom = this.getTimer() 97 | 98 | if(phantom) { 99 | this.cleanupTimer(evt, phantom) 100 | setTimeout(() => { 101 | triggerClick(evt) 102 | }, 300) 103 | return false 104 | } 105 | 106 | let rect = evt.target.getBoundingClientRect() 107 | let center = { 108 | x: rect.left, 109 | y: rect.top + rect.height 110 | } 111 | 112 | this.source = evt.target 113 | 114 | let timer = this.drawTimer() 115 | 116 | mutate(() => { 117 | document.body.insertAdjacentHTML('beforeEnd', timer) 118 | }) 119 | .then(() => { 120 | timer = this.getTimer() 121 | 122 | // set the current time 123 | if(this.source.nodeName !== 'INPUT' || !this.source.value.length) { 124 | let date = new Date() 125 | let hours = date.getHours(), 126 | minutes = date.getMinutes() 127 | 128 | return mutate(() => { 129 | timer.children[0].value = hours > 12 ? hours - 12 : hours 130 | timer.children[1].value = minutes 131 | timer.children[2].value = hours >= 12 ? 1 : 0 132 | }) 133 | } 134 | 135 | return Promise.resolve() 136 | }) 137 | .then(() => { 138 | // add the hooks 139 | Array.prototype.slice.call(timer.children).forEach((item) => { 140 | item.addEventListener('change', didChange, false) 141 | }) 142 | 143 | return measure(() => timer.getBoundingClientRect()) 144 | }) 145 | .then(result => { 146 | // position the calendar near the origin point 147 | const timerRect = result 148 | 149 | // the width before showing = actual width * 0.25 150 | const width = timerRect.width * 4 151 | 152 | timer.style.left = (center.x - 16) + 'px' 153 | timer.style.top = (center.y) + 'px' 154 | 155 | return mutate(() => { 156 | timer.classList.add('active') 157 | 158 | this.source.setAttribute("aria-expanded", "true") 159 | if (this.source.hasAttribute("id")) { 160 | timer.setAttribute("aria-describedby", this.source.getAttribute("id")) 161 | } 162 | }) 163 | }) 164 | .then(() => { 165 | timer.querySelector("select").focus() 166 | this.originalValue = this.source.value 167 | document.body.addEventListener('click', this.bodyClick, false) 168 | document.body.addEventListener('keydown', this.bodyInput, false) 169 | }) 170 | .catch(err => { 171 | console.error(err) 172 | }) 173 | 174 | return false 175 | 176 | } 177 | 178 | const attachTrigger = (elem) => { 179 | if(!elem) return 180 | elem.addEventListener('click', triggerClick, false) 181 | if(elem.nodeName === "INPUT") { 182 | elem.addEventListener('focus', inputFocus, false) 183 | elem.addEventListener('blur', inputBlur, false) 184 | elem.setAttribute("aria-haspopup", "true") 185 | elem.setAttribute("aria-expanded", "false") 186 | } 187 | } 188 | 189 | let triggers = Array.prototype.slice.call(document.querySelectorAll('.timer-trigger')) 190 | 191 | triggers.forEach((item) => { 192 | attachTrigger(item) 193 | }) 194 | 195 | window.attachTimeTrigger = attachTrigger 196 | 197 | } 198 | 199 | getTimer() { 200 | return document.getElementById('dz-timer') 201 | } 202 | 203 | isInTimer(elem) { 204 | let parent = findParent(elem, 'dz-timer') 205 | return parent !== document.body && parent != undefined 206 | } 207 | 208 | drawTimer() { 209 | 210 | let val = null, hoursVal, minVal, shiftVal = false 211 | if(this.source.nodeName === 'INPUT') 212 | val = this.source.value 213 | 214 | if(val) { 215 | val = val.split(':') 216 | hoursVal = parseInt(val[0]) 217 | minVal = val[1] 218 | 219 | if(hoursVal >= 12) 220 | shiftVal = true 221 | } 222 | 223 | let markup = `` 258 | 259 | return markup 260 | } 261 | 262 | cleanupTimer(evt, timer) { 263 | if(evt && evt.preventDefault) 264 | evt.preventDefault() 265 | 266 | if(timer) { 267 | 268 | mutate(() => { 269 | timer.classList.remove('active') 270 | }) 271 | .then(() => wait(500)) 272 | .then(() => { 273 | this.source = undefined 274 | if(timer.parentNode) 275 | document.body.removeChild(timer) 276 | }) 277 | .catch(err => { 278 | console.error(err) 279 | }) 280 | 281 | } 282 | 283 | document.body.removeEventListener('click', this.bodyClick, false) 284 | document.body.removeEventListener('keydown', this.bodyInput, false) 285 | 286 | return false 287 | } 288 | 289 | } 290 | 291 | if(glob && glob.exports) { 292 | glob.exports = Object.assign({}, { 293 | 'TimePicker': TimePicker, 294 | 'timePicker': new TimePicker() 295 | }) 296 | } 297 | else { 298 | glob.TimePicker = TimePicker 299 | glob.timePicker = new TimePicker() 300 | } 301 | 302 | })(typeof module === "undefined" ? window : module); 303 | -------------------------------------------------------------------------------- /prepros-6.config: -------------------------------------------------------------------------------- 1 | { 2 | "name": "DZDateTimePicker", 3 | "firstRun": false, 4 | "exportConfig": true, 5 | "fileConfigs": [ 6 | { 7 | "path": "dzdatetimepicker.css", 8 | "configJson": "{\"autoCompile\":false,\"forceCompile\":false,\"customOutput\":\"\",\"sourceMap\":false,\"compiler-autoprefixer\":{\"enabled\":false},\"compiler-cssnext\":{\"enabled\":false},\"compiler-minify-css\":{\"enabled\":false},\"outputSuffix\":\"-dist\"}" 9 | }, 10 | { 11 | "path": "dzdatetimepicker.js", 12 | "configJson": "{\"autoCompile\":true,\"forceCompile\":false,\"customOutput\":\"\",\"sourceMap\":true,\"compiler-concat-js\":{\"enabled\":true},\"compiler-babel\":{\"enabled\":false},\"compiler-uglify-js\":{\"enabled\":false,\"mangle\":false},\"outputSuffix\":\"-dist\"}" 13 | }, 14 | { 15 | "path": "dzdtp.min.js", 16 | "configJson": "{\"autoCompile\":false,\"forceCompile\":false,\"customOutput\":\"\",\"sourceMap\":false,\"compiler-concat-js\":{\"enabled\":false},\"compiler-babel\":{\"enabled\":false},\"compiler-uglify-js\":{\"enabled\":false,\"mangle\":false},\"outputSuffix\":\"-dist\"}" 17 | }, 18 | { 19 | "path": "rangepicker.js", 20 | "configJson": "{\"autoCompile\":true,\"forceCompile\":false,\"customOutput\":\"\",\"sourceMap\":true,\"compiler-concat-js\":{\"enabled\":true},\"compiler-babel\":{\"enabled\":false},\"compiler-uglify-js\":{\"enabled\":false,\"mangle\":false},\"outputSuffix\":\"-dist\"}" 21 | }, 22 | { 23 | "path": "src/dzdatetimepicker.js", 24 | "configJson": "{\"autoCompile\":true,\"forceCompile\":false,\"customOutput\":\"dist/dzdatetimepicker-dist.js\",\"sourceMap\":true,\"compiler-concat-js\":{\"enabled\":true},\"compiler-babel\":{\"enabled\":false},\"compiler-uglify-js\":{\"enabled\":false,\"mangle\":false},\"outputSuffix\":\"-dist\"}" 25 | }, 26 | { 27 | "path": "src/dzdatetimepicker.less", 28 | "configJson": "{\"forceCompile\":false,\"customOutput\":\"dist/dzdatetimepicker.css\",\"autoCompile\":true,\"sourceMap\":true,\"compiler-less\":{\"enabled\":true},\"compiler-autoprefixer\":{\"enabled\":true},\"compiler-minify-css\":{\"enabled\":true}}" 29 | } 30 | ], 31 | "fileTree": { 32 | "expandedDirs": [ 33 | "src" 34 | ], 35 | "hideSystemFiles": true, 36 | "systemFiles": [ 37 | ".*", 38 | "desktop.ini", 39 | "prepros.config", 40 | "$RECYCLE.BIN", 41 | "prepros.cfg", 42 | "prepros-6.config", 43 | "Prepros Export" 44 | ], 45 | "hideUnwatchedFiles": false 46 | }, 47 | "imports": [ 48 | { 49 | "path": "src/dzdatetimepicker.js", 50 | "imports": [ 51 | "src/datepicker.js", 52 | "src/timepicker.js", 53 | "src/rangepicker.js", 54 | "src/autohook.js" 55 | ] 56 | } 57 | ], 58 | "projectView": { 59 | "selectedView": "file-tree" 60 | }, 61 | "fileWatcher": { 62 | "enabled": true, 63 | "watchedExtensions": [ 64 | "less", 65 | "sass", 66 | "scss", 67 | "styl", 68 | "md", 69 | "markdown", 70 | "coffee", 71 | "js", 72 | "jade", 73 | "haml", 74 | "slim", 75 | "ls", 76 | "html", 77 | "htm", 78 | "css", 79 | "rb", 80 | "php", 81 | "asp", 82 | "aspx", 83 | "cfm", 84 | "chm", 85 | "cms", 86 | "do", 87 | "erb", 88 | "jsp", 89 | "mhtml", 90 | "mspx", 91 | "pl", 92 | "py", 93 | "shtml", 94 | "cshtml", 95 | "cs", 96 | "vb", 97 | "vbs", 98 | "tpl", 99 | "ctp", 100 | "kit", 101 | "png", 102 | "jpg", 103 | "jpeg", 104 | "json", 105 | "ts", 106 | "pug" 107 | ] 108 | }, 109 | "pathFilters": [ 110 | "node_modules", 111 | ".*", 112 | "bower_components", 113 | "prepros.config", 114 | "Prepros Export", 115 | "prepros-6.config", 116 | "prepros.cfg", 117 | "wp-admin", 118 | "wp-includes" 119 | ], 120 | "server": { 121 | "port": 7879, 122 | "assignNewPortAutomatically": false, 123 | "enable": true, 124 | "proxy": { 125 | "enable": false, 126 | "url": "" 127 | } 128 | }, 129 | "browser-sync": { 130 | "enable": false, 131 | "clicks": true, 132 | "forms": true, 133 | "scroll": true 134 | }, 135 | "live-reload": { 136 | "enable": true, 137 | "animate": true, 138 | "delay": 0 139 | }, 140 | "ftp-deploy": { 141 | "connectionType": "ftp", 142 | "remotePath": "", 143 | "uploadTimeout": 20000, 144 | "uploadOnChange": false, 145 | "ftp": { 146 | "secure": false, 147 | "keepAlive": true, 148 | "host": "", 149 | "port": 21, 150 | "user": "", 151 | "password": "" 152 | }, 153 | "sftp": { 154 | "host": "", 155 | "port": 22, 156 | "usePrivateKey": false, 157 | "username": "", 158 | "password": "", 159 | "privateKey": "", 160 | "passphrase": "" 161 | }, 162 | "pathFilters": [ 163 | "config.rb", 164 | "prepros.config", 165 | "prepros-6.config", 166 | "node_modules", 167 | "Prepros Export", 168 | ".git", 169 | ".idea", 170 | ".sass-cache", 171 | ".hg", 172 | ".svn", 173 | ".cache", 174 | ".DS_Store", 175 | "*.sass", 176 | "*.scss", 177 | "*.less", 178 | "*.pug", 179 | "*.jade", 180 | "*.styl", 181 | "*.haml", 182 | "*.slim", 183 | "*.coffee", 184 | "*.ls", 185 | "*.kit", 186 | "*.ts" 187 | ], 188 | "history": [] 189 | }, 190 | "file-type-sass": "{\"compilers\":[\"node-sass\",\"autoprefixer\",\"minify-css\"]}", 191 | "file-type-less": "{\"compilers\":[\"less\",\"autoprefixer\",\"minify-css\"]}", 192 | "autoprefixer": { 193 | "browsers": "last 5 versions" 194 | }, 195 | "file-type-pug": "{\"compilers\":[\"pug\"]}", 196 | "file-type-css": "{\"compilers\":[\"autoprefixer\",\"cssnext\",\"minify-css\"]}", 197 | "file-type-javascript": "{\"compilers\":[\"concat-js\",\"babel\",\"uglify-js\"]}", 198 | "file-type-stylus": "{\"compilers\":[\"stylus\",\"autoprefixer\",\"minify-css\"]}", 199 | "file-type-markdown": "{\"compilers\":[\"markdown\"]}", 200 | "file-type-haml": "{\"compilers\":[\"haml\"]}", 201 | "file-type-slim": "{\"compilers\":[\"slim\"]}", 202 | "file-type-coffee-script": "{\"compilers\":[\"coffee-script\",\"uglify-js\"]}", 203 | "file-type-livescript": "{\"compilers\":[\"livescript\",\"uglify-js\"]}", 204 | "file-type-kit": "{\"compilers\":[\"kit\"]}", 205 | "uglify-js": { 206 | "ie8": false, 207 | "compress": { 208 | "sequences": true, 209 | "properties": true, 210 | "dead_code": true, 211 | "drop_debugger": true, 212 | "unsafe": false, 213 | "unsafe_comps": false, 214 | "unsafe_math": false, 215 | "unsafe_proto": false, 216 | "unsafe_regexp": false, 217 | "conditionals": true, 218 | "comparisons": true, 219 | "evaluate": true, 220 | "booleans": true, 221 | "loops": true, 222 | "unused": true, 223 | "toplevel": false, 224 | "top_retain": "", 225 | "hoist_funs": true, 226 | "hoist_vars": false, 227 | "if_return": true, 228 | "join_vars": true, 229 | "collapse_vars": true, 230 | "reduce_vars": true, 231 | "warnings": false, 232 | "negate_iife": true, 233 | "pure_getters": false, 234 | "pure_funcs": [], 235 | "drop_console": false, 236 | "expression": false, 237 | "keep_fargs": false, 238 | "keep_fnames": false, 239 | "passes": 1, 240 | "keep_infinity": false, 241 | "side_effects": true, 242 | "global_defs": [] 243 | }, 244 | "output": { 245 | "ascii_only": false, 246 | "beautify": false, 247 | "comments": "", 248 | "indent_level": 4, 249 | "indent_start": 0, 250 | "inline_script": false, 251 | "keep_quoted_props": false, 252 | "max_line_len": false, 253 | "preamble": "", 254 | "preserve_line": false, 255 | "quote_keys": false, 256 | "quote_style": 0, 257 | "semicolons": true, 258 | "shebang": true, 259 | "width": 80 260 | } 261 | }, 262 | "cssnext": { 263 | "customProperties": true, 264 | "applyRule": true, 265 | "calc": false, 266 | "nesting": true, 267 | "customMedia": true, 268 | "mediaQueriesRange": true, 269 | "customSelectors": true, 270 | "attributeCaseInsensitive": true, 271 | "colorRebeccapurple": true, 272 | "colorHwb": true, 273 | "colorGray": true, 274 | "colorHexAlpha": true, 275 | "colorFunction": true, 276 | "fontVariant": true, 277 | "filter": true, 278 | "initial": true, 279 | "rem": true, 280 | "pseudoElements": true, 281 | "pseudoClassMatches": true, 282 | "pseudoClassNot": true, 283 | "pseudoClassAnyLink": true, 284 | "colorRgba": true, 285 | "overflowWrap": true 286 | }, 287 | "file-type-typescript": "{\"compilers\":[\"typescript\",\"uglify-js\"]}", 288 | "babel": { 289 | "useBabelRc": true, 290 | "presets": { 291 | "babel-preset-es2015": true 292 | }, 293 | "plugins": { 294 | "babel-plugin-syntax-jsx": true, 295 | "babel-plugin-transform-react-jsx": true, 296 | "babel-plugin-transform-async-to-generator": true, 297 | "babel-plugin-transform-class-properties": true, 298 | "babel-plugin-transform-object-rest-spread": true 299 | } 300 | }, 301 | "file-type-png": "{\"compilers\":[\"png\"]}", 302 | "file-type-jpg": "{\"compilers\":[\"jpg\"]}" 303 | } -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | // http://eslint.org/docs/rules/ 3 | "parserOptions" : { 4 | "ecmaVersion": 6, 5 | "sourceType": "script" 6 | }, 7 | 8 | "ecmaFeatures": { 9 | "binaryLiterals": false, // enable binary literals 10 | "blockBindings": true, // enable let and const (aka block bindings) 11 | "defaultParams": false, // enable default function parameters 12 | "forOf": true, // enable for-of loops 13 | "generators": true, // enable generators 14 | "objectLiteralComputedProperties": false, // enable computed object literal property names 15 | "objectLiteralDuplicateProperties": false, // enable duplicate object literal properties in strict mode 16 | "objectLiteralShorthandMethods": true, // enable object literal shorthand methods 17 | "objectLiteralShorthandProperties": true, // enable object literal shorthand properties 18 | "octalLiterals": true, // enable octal literals 19 | "regexUFlag": false, // enable the regular expression u flag 20 | "regexYFlag": false, // enable the regular expression y flag 21 | "templateStrings": true, // enable template strings 22 | "unicodeCodePointEscapes": false, // enable code point escapes 23 | "jsx": true // enable JSX 24 | }, 25 | 26 | "env": { 27 | "browser": false, // browser global variables. 28 | "node": true, // Node.js global variables and Node.js-specific rules. 29 | "amd": false, // defines require() and define() as global variables as per the amd spec. 30 | "mocha": true, // adds all of the Mocha testing global variables. 31 | "jasmine": false, // adds all of the Jasmine testing global variables for version 1.3 and 2.0. 32 | "phantomjs": false, // phantomjs global variables. 33 | "jquery": false, // jquery global variables. 34 | "prototypejs": false, // prototypejs global variables. 35 | "shelljs": false, // shelljs global variables. 36 | }, 37 | 38 | "globals": { 39 | // e.g. "angular": true 40 | }, 41 | 42 | "plugins": [ 43 | // e.g. "react" (must run `npm install eslint-plugin-react` first) 44 | ], 45 | 46 | "rules": { 47 | ////////// Possible Errors ////////// 48 | 49 | "comma-dangle": 0, // allow trailing commas in object literals 50 | "no-cond-assign": 0, // disallow assignment in conditional expressions 51 | "no-console": 0, // disallow use of console (off by default in the node environment) 52 | "no-constant-condition": 0, // disallow use of constant expressions in conditions 53 | "no-control-regex": 0, // disallow control characters in regular expressions 54 | "no-debugger": 2, // disallow use of debugger 55 | "no-dupe-keys": 0, // disallow duplicate keys when creating object literals 56 | "no-empty": 0, // disallow empty statements 57 | "no-empty-character-class": 1,// disallow the use of empty character classes in regular expressions 58 | "no-ex-assign": 0, // disallow assigning to the exception in a catch block 59 | "no-extra-boolean-cast": 0, // disallow double-negation boolean casts in a boolean context 60 | "no-extra-parens": 0, // disallow unnecessary parentheses (off by default) 61 | "no-extra-semi": 1, // disallow unnecessary semicolons 62 | "no-func-assign": 0, // disallow overwriting functions written as function declarations 63 | "no-inner-declarations": 0, // disallow function or variable declarations in nested blocks 64 | "no-invalid-regexp": 0, // disallow invalid regular expression strings in the RegExp constructor 65 | "no-irregular-whitespace": 0, // disallow irregular whitespace outside of strings and comments 66 | "no-negated-in-lhs": 0, // disallow negation of the left operand of an in expression 67 | "no-obj-calls": 0, // disallow the use of object properties of the global object (Math and JSON) as functions 68 | "no-regex-spaces": 0, // disallow multiple spaces in a regular expression literal 69 | "no-reserved-keys": 0, // disallow reserved words being used as object literal keys (off by default) 70 | "no-sparse-arrays": 0, // disallow sparse arrays 71 | "no-unreachable": 1, // disallow unreachable statements after a return, throw, continue, or break statement 72 | "use-isnan": 0, // disallow comparisons with the value NaN 73 | "valid-jsdoc": 1, // Ensure JSDoc comments are valid (off by default) 74 | "valid-typeof": 0, // Ensure that the results of typeof are compared against a valid string 75 | 76 | 77 | ////////// Best Practices ////////// 78 | 79 | "block-scoped-var": 0, // treat var statements as if they were block scoped (off by default) 80 | "complexity": 0, // specify the maximum cyclomatic complexity allowed in a program (off by default) 81 | "consistent-return": 0, // require return statements to either always or never specify values 82 | "curly": 0, // specify curly brace conventions for all control statements 83 | "default-case": 0, // require default case in switch statements (off by default) 84 | "dot-notation": 0, // encourages use of dot notation whenever possible 85 | "eqeqeq": 0, // require the use of === and !== 86 | "guard-for-in": 0, // make sure for-in loops have an if statement (off by default) 87 | "no-alert": 0, // disallow the use of alert, confirm, and prompt 88 | "no-caller": 0, // disallow use of arguments.caller or arguments.callee 89 | "no-div-regex": 0, // disallow division operators explicitly at beginning of regular expression (off by default) 90 | "no-else-return": 0, // disallow else after a return in an if (off by default) 91 | "no-empty-label": 0, // disallow use of labels for anything other then loops and switches 92 | "no-eq-null": 0, // disallow comparisons to null without a type-checking operator (off by default) 93 | "no-eval": 2, // disallow use of eval() 94 | "no-extend-native": 0, // disallow adding to native types 95 | "no-extra-bind": 0, // disallow unnecessary function binding 96 | "no-fallthrough": 0, // disallow fallthrough of case statements 97 | "no-floating-decimal": 0, // disallow the use of leading or trailing decimal points in numeric literals (off by default) 98 | "no-implied-eval": 1, // disallow use of eval()-like methods 99 | "no-iterator": 0, // disallow usage of __iterator__ property 100 | "no-labels": 0, // disallow use of labeled statements 101 | "no-lone-blocks": 0, // disallow unnecessary nested blocks 102 | "no-loop-func": 0, // disallow creation of functions within loops 103 | "no-multi-spaces": 0, // disallow use of multiple spaces 104 | "no-multi-str": 0, // disallow use of multiline strings 105 | "no-native-reassign": 0, // disallow reassignments of native objects 106 | "no-new": 0, // disallow use of new operator when not part of the assignment or comparison 107 | "no-new-func": 0, // disallow use of new operator for Function object 108 | "no-new-wrappers": 0, // disallows creating new instances of String, Number, and Boolean 109 | "no-octal": 0, // disallow use of octal literals 110 | "no-octal-escape": 0, // disallow use of octal escape sequences in string literals, such as var foo = "Copyright \251"; 111 | "no-process-env": 0, // disallow use of process.env (off by default) 112 | "no-proto": 1, // disallow usage of __proto__ property 113 | "no-redeclare": 0, // disallow declaring the same variable more then once 114 | "no-return-assign": 0, // disallow use of assignment in return statement 115 | "no-script-url": 0, // disallow use of javascript: urls. 116 | "no-self-compare": 0, // disallow comparisons where both sides are exactly the same (off by default) 117 | "no-sequences": 0, // disallow use of comma operator 118 | "no-unused-expressions": 0, // disallow usage of expressions in statement position 119 | "no-void": 0, // disallow use of void operator (off by default) 120 | "no-warning-comments": 2, // disallow usage of configurable warning terms in comments, e.g. TODO or FIXME (off by default) 121 | "no-with": 0, // disallow use of the with statement 122 | "radix": 0, // require use of the second argument for parseInt() (off by default) 123 | "vars-on-top": 0, // requires to declare all vars on top of their containing scope (off by default) 124 | "wrap-iife": 0, // require immediate function invocation to be wrapped in parentheses (off by default) 125 | "yoda": 0, // require or disallow Yoda conditions 126 | 127 | 128 | ////////// Strict Mode ////////// 129 | 130 | "global-strict": 0, // (deprecated) require or disallow the "use strict" pragma in the global scope (off by default in the node environment) 131 | "no-extra-strict": 0, // (deprecated) disallow unnecessary use of "use strict"; when already in strict mode 132 | "strict": 0, // controls location of Use Strict Directives 133 | 134 | 135 | ////////// Variables ////////// 136 | 137 | "no-catch-shadow": 0, // disallow the catch clause parameter name being the same as a variable in the outer scope (off by default in the node environment) 138 | "no-delete-var": 0, // disallow deletion of variables 139 | "no-label-var": 0, // disallow labels that share a name with a variable 140 | "no-shadow": 0, // disallow declaration of variables already declared in the outer scope 141 | "no-shadow-restricted-names": 0, // disallow shadowing of names such as arguments 142 | "no-undef": 0, // disallow use of undeclared variables unless mentioned in a /*global */ block 143 | "no-undef-init": 0, // disallow use of undefined when initializing variables 144 | "no-undefined": 0, // disallow use of undefined variable (off by default) 145 | "no-unused-vars": 0, // disallow declaration of variables that are not used in the code 146 | "no-use-before-define": 0, // disallow use of variables before they are defined 147 | 148 | 149 | ////////// Node.js ////////// 150 | 151 | "handle-callback-err": 0, // enforces error handling in callbacks (off by default) (on by default in the node environment) 152 | "no-mixed-requires": 0, // disallow mixing regular variable and require declarations (off by default) (on by default in the node environment) 153 | "no-new-require": 0, // disallow use of new operator with the require function (off by default) (on by default in the node environment) 154 | "no-path-concat": 0, // disallow string concatenation with __dirname and __filename (off by default) (on by default in the node environment) 155 | "no-process-exit": 0, // disallow process.exit() (on by default in the node environment) 156 | "no-restricted-modules": 0, // restrict usage of specified node modules (off by default) 157 | "no-sync": 0, // disallow use of synchronous methods (off by default) 158 | 159 | 160 | ////////// Stylistic Issues ////////// 161 | 162 | "brace-style": [1,"stroustrup"],// enforce one true brace style (off by default) 163 | "camelcase": 1, // require camel case names 164 | "comma-spacing": 0, // enforce spacing before and after comma 165 | "comma-style": 0, // enforce one true comma style (off by default) 166 | "consistent-this": 0, // enforces consistent naming when capturing the current execution context (off by default) 167 | "eol-last": 0, // enforce newline at the end of file, with no multiple empty lines 168 | "func-names": 0, // require function expressions to have a name (off by default) 169 | "func-style": 0, // enforces use of function declarations or expressions (off by default) 170 | "key-spacing": 1, // enforces spacing between keys and values in object literal properties 171 | "max-nested-callbacks": 2, // specify the maximum depth callbacks can be nested (off by default) 172 | "new-cap": 1, // require a capital letter for constructors 173 | "new-parens": 0, // disallow the omission of parentheses when invoking a constructor with no arguments 174 | "no-array-constructor": 0, // disallow use of the Array constructor 175 | "no-inline-comments": 0, // disallow comments inline after code (off by default) 176 | "no-lonely-if": 1, // disallow if as the only statement in an else block (off by default) 177 | "no-mixed-spaces-and-tabs": 0, // disallow mixed spaces and tabs for indentation 178 | "no-multiple-empty-lines": 0, // disallow multiple empty lines (off by default) 179 | "no-nested-ternary": 0, // disallow nested ternary expressions (off by default) 180 | "no-new-object": 0, // disallow use of the Object constructor 181 | "semi-spacing": 1, // enforce consistent spacing before and after semicolons 182 | "no-spaced-func": 0, // disallow space between function identifier and application 183 | "no-ternary": 0, // disallow the use of ternary operators (off by default) 184 | "no-trailing-spaces": 0, // disallow trailing whitespace at the end of lines 185 | "no-underscore-dangle": 0, // disallow dangling underscores in identifiers 186 | "no-wrap-func": 0, // disallow wrapping of non-IIFE statements in parens 187 | "one-var": 0, // allow just one var statement per function (off by default) 188 | "operator-assignment": 0, // require assignment operator shorthand where possible or prohibit it entirely (off by default) 189 | "padded-blocks": 0, // enforce padding within blocks (off by default) 190 | "quote-props": 0, // require quotes around object literal property names (off by default) 191 | "quotes": 0, // specify whether double or single quotes should be used 192 | "semi": 0, // require or disallow use of semicolons instead of ASI 193 | "sort-vars": 0, // sort variables within the same declaration block (off by default) 194 | "space-after-function-name": 0, // require a space after function names (off by default) 195 | "space-after-keywords": 0, // require a space after certain keywords (off by default) 196 | "space-before-blocks": 0, // require or disallow space before blocks (off by default) 197 | "space-in-brackets": 0, // require or disallow spaces inside brackets (off by default) 198 | "space-in-parens": 0, // require or disallow spaces inside parentheses (off by default) 199 | "space-infix-ops": 0, // require spaces around operators 200 | "space-return-throw-case": 0, // require a space after return, throw, and case 201 | "space-unary-ops": 0, // Require or disallow spaces before/after unary operators (words on by default, nonwords off by default) 202 | "spaced-line-comment": 0, // require or disallow a space immediately following the // in a line comment (off by default) 203 | "wrap-regex": 0, // require regex literals to be wrapped in parentheses (off by default) 204 | 205 | 206 | ////////// ECMAScript 6 ////////// 207 | 208 | "no-var": 1, // require let or const instead of var (off by default) 209 | "generator-star": 0, // enforce the position of the * in generator functions (off by default) 210 | 211 | 212 | ////////// Legacy ////////// 213 | 214 | "max-depth": 2, // specify the maximum depth that blocks can be nested (off by default) 215 | "max-len": 0, // specify the maximum length of a line in your program (off by default) 216 | "max-params": 0, // limits the number of parameters that can be used in the function declaration. (off by default) 217 | "max-statements": 0, // specify the maximum number of statement allowed in a function (off by default) 218 | "no-bitwise": 0, // disallow use of bitwise operators (off by default) 219 | "no-plusplus": 0 // disallow use of unary operators, ++ and -- (off by default) 220 | } 221 | } -------------------------------------------------------------------------------- /src/datepicker.js: -------------------------------------------------------------------------------- 1 | ((glob) => { 2 | 3 | const prevSVG = ``; 4 | const nextSVG = ``; 5 | 6 | class DatePicker { 7 | 8 | constructor(customClass) { 9 | this.customClass = customClass 10 | this.init() 11 | } 12 | 13 | init() { 14 | if(this.initialized) 15 | return false 16 | 17 | this.initialized = true 18 | 19 | this.setupHooks() 20 | } 21 | 22 | setupHooks() { 23 | 24 | const prevClick = (evt) => { 25 | 26 | if(evt && evt.preventDefault) 27 | evt.preventDefault() 28 | 29 | let calendar = this.getCalendar() 30 | let currentString = calendar.dataset.current.split('-') 31 | let current = new Date(currentString[0], currentString[1]) 32 | 33 | let previous = new Date(current.getFullYear(), current.getMonth() - 1) 34 | 35 | let newDates = this.drawDates(this.getDaysArrayByMonth(previous)) 36 | let currentDates = document.querySelector('#dz-calendar .dz-dates') 37 | 38 | calendar.insertAdjacentHTML('beforeEnd', newDates) 39 | newDates = calendar.children[calendar.children.length-1] 40 | 41 | calendar.removeChild(currentDates) 42 | 43 | let year = previous.getFullYear() 44 | let month = previous.getMonth() 45 | 46 | calendar.dataset.current = `${year} - ${month}` 47 | calendar.children[0].children[0].innerHTML = `${this.getMonthName(month)}, ${year}` 48 | 49 | hookDates() 50 | 51 | return false 52 | 53 | } 54 | 55 | const nextClick = (evt) => { 56 | 57 | if(evt && evt.preventDefault) 58 | evt.preventDefault() 59 | 60 | let calendar = this.getCalendar() 61 | let currentString = calendar.dataset.current.split('-') 62 | let current = new Date(currentString[0], currentString[1]) 63 | 64 | let next = new Date(current.getFullYear(), current.getMonth() + 1) 65 | 66 | let newDates = this.drawDates(this.getDaysArrayByMonth(next)) 67 | let currentDates = document.querySelector('#dz-calendar .dz-dates') 68 | 69 | calendar.insertAdjacentHTML('beforeEnd', newDates) 70 | newDates = calendar.children[calendar.children.length-1] 71 | 72 | calendar.removeChild(currentDates) 73 | 74 | let year = next.getFullYear() 75 | let month = next.getMonth() 76 | 77 | calendar.dataset.current = `${year} - ${month}` 78 | calendar.children[0].children[0].innerHTML = `${this.getMonthName(month)}, ${year}` 79 | 80 | hookDates() 81 | 82 | return false 83 | 84 | } 85 | 86 | this.bodyClick = (evt) => { 87 | 88 | let calendar = this.getCalendar() 89 | 90 | if(calendar) 91 | if(!calendar.classList.contains('active')) 92 | document.body.removeChild(calendar) 93 | else if(!this.isInCalendar(evt.target)) { 94 | return this.cleanupCalendar(evt, calendar) 95 | } 96 | } 97 | 98 | this.bodyInput = (evt) => { 99 | const {keyCode} = evt 100 | 101 | const calendar = this.getCalendar() 102 | 103 | if (keyCode == 36 || keyCode == 35) { 104 | // pressed Home or End 105 | const elem = calendar.querySelector(`.dz-dates button:${keyCode == 36 ? 'first-child' : 'last-child'}`) 106 | if (elem) 107 | elem.focus() 108 | return true 109 | } 110 | 111 | if (keyCode >= 37 && keyCode <= 40) { 112 | // up or down arrow keys 113 | const current = Number(document.activeElement.innerHTML) || 0 114 | 115 | let expected = current 116 | if (keyCode == 40) expected += 7; // down 117 | else if (keyCode == 38) expected -= 7; // up 118 | else if (keyCode == 37) expected -= 1; // left 119 | else expected += 1; // right 120 | 121 | const elem = calendar.querySelector(`.dz-dates button:nth-child(${expected})`) 122 | if (elem) 123 | elem.focus() 124 | return true 125 | } 126 | 127 | if (keyCode == 33) { 128 | calendar.querySelector("#dz-prev").click() 129 | return true 130 | } 131 | 132 | if (keyCode == 34) { 133 | calendar.querySelector("#dz-next").click() 134 | return true 135 | } 136 | 137 | if (keyCode != 13 && keyCode != 27 || keyCode != 32) 138 | return true 139 | 140 | if (keyCode == 13 || keyCode == 32) { 141 | // user has pressed the enter or space key. Assume to be a confirmation 142 | document.activeElement.getAttribute("aria-label").click() 143 | // the above click will automatically clean up the calendar 144 | } 145 | 146 | if (keyCode == 27) { 147 | // esc key 148 | this.cleanupCalendar(evt, this.calendar); 149 | } 150 | 151 | return true 152 | } 153 | 154 | const dateClick = (evt) => { 155 | 156 | let calendar = this.getCalendar() 157 | let date = parseInt(evt.target.innerHTML) 158 | 159 | let currentString = calendar.dataset.current.split('-') 160 | date = new Date(currentString[0],currentString[1],date) 161 | 162 | let fn = window[this.source.dataset.onset] 163 | if(fn) 164 | fn(date) 165 | 166 | // zero pad the month if needed 167 | let month = DatePicker.zeroPaddedFormatMonth(date); 168 | 169 | // zero pad the date if needed 170 | let dateStr = DatePicker.zeroPaddedFormatDate(date); 171 | 172 | let val = [date.getFullYear(), month, dateStr].join('-') 173 | 174 | if(this.source.nodeName === 'INPUT') { 175 | this.source.value = val 176 | if ('InputEvent' in window) 177 | this.source.dispatchEvent(new InputEvent('input')) 178 | else 179 | this.source.dispatchEvent(new Event('input')) 180 | } 181 | else if(this.source.dataset.dateVal) 182 | this.source.dataset.dateVal = val 183 | 184 | if (this.callback) 185 | this.callback(this.source, val) 186 | 187 | return this.cleanupCalendar(evt, calendar) 188 | 189 | } 190 | 191 | const hookDates = () => { 192 | 193 | let calendar = this.getCalendar() 194 | if(!calendar) 195 | return 196 | 197 | let dates = Array.prototype.slice.call(document.querySelectorAll('#dz-calendar .dz-dates button')) 198 | dates.forEach((item) => { 199 | if(!item.classList.contains('disabled')) 200 | item.addEventListener('click', dateClick, false) 201 | }) 202 | 203 | } 204 | 205 | let fromFocus = false; 206 | 207 | const triggerClick = (evt) => { 208 | 209 | // check if calendar is already being shown 210 | let phantom = this.getCalendar() 211 | 212 | if(phantom && phantom != this.calendar) { 213 | 214 | this.cleanupCalendar(evt, phantom) 215 | setTimeout(() => { 216 | triggerClick(evt) 217 | }, 350) 218 | return false 219 | } 220 | 221 | let rect = evt.target.getBoundingClientRect(); 222 | 223 | let center = { 224 | x: rect.left + (rect.width / 2), 225 | y: rect.top + rect.height 226 | } 227 | 228 | let target = evt.target.nodeName === "INPUT" ? 229 | evt.target : 230 | findParent(evt.target, this.customClass || 'date-trigger') 231 | 232 | this.source = target 233 | 234 | let calendar = this.drawCalendar() 235 | 236 | mutate(() => { 237 | document.body.insertAdjacentHTML('beforeEnd', calendar) 238 | }) 239 | .then(() => { 240 | calendar = document.getElementById('dz-calendar') 241 | this.calendar = calendar 242 | return measure(() => calendar.getBoundingClientRect()) 243 | }) 244 | .then(result => { 245 | // position the calendar near the origin point 246 | const calendarRect = result 247 | 248 | // the width before showing = actual width * 0.25 249 | let width = calendarRect.width * 4 250 | 251 | calendar.style.left = (center.x - width/2) + 'px'; 252 | 253 | const targetRect = target.getBoundingClientRect(); 254 | 255 | // center.y + half of the pointer's height 256 | // 193 is height of the calendar 257 | calendar.style.top = (center.y + 36) + 'px'; 258 | 259 | console.debug(calendar.style.top); 260 | 261 | let prev = calendar.children[0].children[1]; 262 | let next = calendar.children[0].children[2]; 263 | 264 | prev.addEventListener('click', prevClick, false) 265 | next.addEventListener('click', nextClick, false) 266 | 267 | return mutate(() => { 268 | calendar.classList.add('active') 269 | this.source.setAttribute("aria-expanded", "true") 270 | if (this.source.hasAttribute("id")) { 271 | calendar.setAttribute("aria-describedby", this.source.getAttribute("id")) 272 | } 273 | }) 274 | }) 275 | .then(() => { 276 | hookDates() 277 | 278 | let fn = 'didShowDatePicker' 279 | if(window[fn]) 280 | window[fn](calendar) 281 | }) 282 | .then(() => { 283 | 284 | let date = new Date(); 285 | 286 | if (this.source.hasAttribute("value") && !!(this.source.value) && this.source.value.trim().length) { 287 | date = new Date(this.source.value); 288 | } 289 | 290 | date = date.getDate(); 291 | 292 | return measure(() => calendar.querySelector(`button:nth-child(${date})`)) 293 | 294 | }) 295 | .then(result => { 296 | if (result) { 297 | result.focus() 298 | } 299 | document.body.addEventListener('click', this.bodyClick, false) 300 | document.body.addEventListener('keydown', this.bodyInput, false) 301 | }) 302 | .then(result => { 303 | setTimeout(() => { 304 | this.repositionCalendarWithinViewport() 305 | }, 100) 306 | }) 307 | .catch(err => { 308 | console.error(err) 309 | }) 310 | 311 | return false 312 | 313 | } 314 | 315 | let triggers = document.querySelectorAll(this.customClass ? "." + this.customClass : '.date-trigger') 316 | triggers = Array.prototype.slice.call(triggers) 317 | 318 | const attachTrigger = (elem) => { 319 | if(!elem) return 320 | 321 | if(elem.nodeName === "INPUT") { 322 | elem.addEventListener('click', triggerClick, false) 323 | elem.addEventListener('blur', inputBlur, false) 324 | elem.setAttribute("aria-haspopup", "true") 325 | elem.setAttribute("aria-expanded", "false") 326 | } 327 | else { 328 | elem.addEventListener('click', triggerClick, false) 329 | } 330 | } 331 | 332 | triggers.forEach((item) => { 333 | attachTrigger(item) 334 | }) 335 | 336 | glob.attachDateTrigger = attachTrigger 337 | 338 | } 339 | 340 | getCalendar() { 341 | return document.getElementById("dz-calendar") 342 | } 343 | 344 | isInCalendar(elem) { 345 | let parent = findParent(elem, 'dz-calendar') 346 | return parent !== document.body && parent != undefined 347 | } 348 | 349 | getMonthName(idx) { 350 | return ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'].splice(idx, 1) 351 | } 352 | 353 | getFullMonthName(idx) { 354 | return ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'].splice(idx, 1) 355 | } 356 | 357 | getDaysArrayByMonth(date) { 358 | 359 | let year = date.getFullYear() 360 | let month = date.getMonth() 361 | let monthRange = new Date(year, month + 1, 0).getDate() 362 | let days = [] 363 | 364 | while(monthRange > 0) { 365 | days.push(new Date(year, month, monthRange)) 366 | monthRange--; 367 | } 368 | 369 | return days.reverse() 370 | } 371 | 372 | drawDates(dates) { 373 | 374 | let now = new Date(); 375 | let today = new Date(); 376 | 377 | if(this.source.nodeName === 'INPUT' && this.source.value) 378 | now = new Date(this.source.value) 379 | else if (this.source.dataset.dateVal) 380 | now = new Date(this.source.dataset.dateVal) 381 | 382 | let markup = `
` 383 | let calendar = this.getCalendar() 384 | 385 | let {dateMax, dateMin} = this.source.dataset 386 | 387 | if(dateMax) 388 | dateMax = new Date(dateMax) 389 | if(dateMin) 390 | dateMin = new Date(dateMin) 391 | 392 | let val = null 393 | if(this.source.nodeName === 'INPUT') 394 | val = new Date(this.source.value) 395 | else if (this.source.dataset.dateVal) 396 | val = new Date(this.source.dataset.dateVal) 397 | 398 | // find offset of first date. 399 | let offsetDay = dates[0].getDay() 400 | 401 | const dateEqual = (base, compare) => base.getDate() === compare.getDate() && base.getMonth() === compare.getMonth() && base.getYear() == compare.getYear() 402 | 403 | dates.forEach((date, idx) => { 404 | 405 | let classes = []; 406 | 407 | // check if the date is today 408 | if (dateEqual(today, date)) { 409 | classes.push('today'); 410 | } 411 | 412 | // check if this is the selected value 413 | if(val && dateEqual(date, val)) { 414 | classes.push('selected'); 415 | } 416 | 417 | // check if the date is within the min range, if one is set 418 | if(dateMin && (dateMin.getTime() - date.getTime()) > 0) { 419 | classes.push('disabled'); 420 | } 421 | 422 | // check if the date is within the max range, if one is set 423 | if(dateMax && (dateMax.getTime() - date.getTime()) < 0) { 424 | classes.push('disabled'); 425 | } 426 | 427 | classes = classes.join(' '); 428 | 429 | const days = { 430 | "Mon": "Monday", 431 | "Tue": "Tuesday", 432 | "Wed": "Wednesday", 433 | "Thu": "Thursday", 434 | "Fri": "Friday", 435 | "Sat": "Saturday", 436 | "Sun": "Sunday" 437 | } 438 | 439 | let ariaString = date.toDateString(); 440 | ariaString = [ariaString.substr(0,3), ariaString.substr(4)]; 441 | ariaString[0] = `${days[ariaString[0]]}, `; 442 | 443 | ariaString[1] = [ariaString[1].substr(0,3), ariaString[1].substr(4)]; 444 | ariaString[1][0] = this.getFullMonthName(date.getMonth()); 445 | ariaString[1] = ariaString[1].join(" "); 446 | ariaString = ariaString.join(""); 447 | 448 | if (idx !== 0) { 449 | markup += `` 450 | } 451 | else { 452 | markup += `` 453 | } 454 | 455 | }) 456 | 457 | markup += `
` 458 | 459 | return markup 460 | 461 | } 462 | 463 | drawCalendar() { 464 | 465 | let now = new Date(); 466 | 467 | if (this.source.hasAttribute("value") && !!(this.source.value) && this.source.value.trim().length) { 468 | now = new Date(this.source.value); 469 | } 470 | 471 | let year = now.getFullYear() 472 | let month = now.getMonth() 473 | 474 | let dates = this.getDaysArrayByMonth(now) 475 | let days = ['S', 'M', 'T', 'W', 'T', 'F', 'S'] 476 | 477 | let markup = `` 492 | 493 | return markup 494 | } 495 | 496 | repositionCalendarWithinViewport () { 497 | 498 | const calendar = this.getCalendar() 499 | 500 | if (!calendar) 501 | return; 502 | const rect = calendar.getBoundingClientRect(); 503 | 504 | if (rect.x < 0) { 505 | // move it to the right 506 | const left = rect.x - Number(calendar.style.left.replace("px", "")) - 8; 507 | calendar.style.left = left + "px" 508 | calendar.classList.add("zp-l") 509 | } 510 | 511 | if ((rect.x + rect.width) > glob.innerWidth) { 512 | // pull it back 513 | const right = glob.innerWidth - rect.width - 48; 514 | calendar.style.left = right + "px"; 515 | 516 | calendar.classList.add("zp-r") 517 | 518 | // reposition the pointer 519 | const beforeElem = calendar.parentNode.querySelector("#dz-calendar", ":before"); 520 | console.log(beforeElem.style.left); 521 | } 522 | 523 | } 524 | 525 | cleanupCalendar(evt, calendar) { 526 | 527 | if(evt && evt.preventDefault) 528 | evt.preventDefault() 529 | 530 | if(calendar) { 531 | 532 | mutate(() => { 533 | document.activeElement.blur(); 534 | calendar.classList.remove('active') 535 | }) 536 | .then(() => wait(300)) 537 | .then(() => { 538 | if (calendar && calendar.parentNode) 539 | calendar.parentNode.removeChild(calendar) 540 | }) 541 | .then(() => { 542 | if (this.source) { 543 | return mutate(() => this.source.setAttribute("aria-expanded", "false")) 544 | } 545 | 546 | return Promise.resolve() 547 | }) 548 | .then(() => { 549 | document.body.removeEventListener('click', this.bodyClick, false) 550 | document.body.removeEventListener('keydown', this.bodyInput, false) 551 | }) 552 | .catch(err => { 553 | console.error(err) 554 | }) 555 | 556 | } 557 | 558 | return false 559 | 560 | } 561 | 562 | static zeroPaddedFormatMonth (date) { 563 | 564 | let month = date.getMonth() + 1; 565 | 566 | if (month.toString().length === 1) { 567 | month = "0" + month 568 | } 569 | 570 | return month; 571 | 572 | } 573 | 574 | static zeroPaddedFormatDate (date) { 575 | 576 | // zero pad the date if needed 577 | let dateStr = date.getDate() 578 | 579 | if (dateStr.toString().length === 1) { 580 | dateStr = "0" + dateStr 581 | } 582 | 583 | return dateStr; 584 | 585 | } 586 | 587 | } 588 | 589 | if(glob && glob.exports) 590 | glob.exports = Object.assign({}, { 591 | 'DatePicker': DatePicker, 592 | 'datePicker': new DatePicker() 593 | }) 594 | 595 | else { 596 | glob.DatePicker = DatePicker 597 | glob.datePicker = new DatePicker() 598 | } 599 | 600 | })(typeof module === "undefined" ? window : module); 601 | -------------------------------------------------------------------------------- /prepros.config: -------------------------------------------------------------------------------- 1 | { 2 | "version": "7", 3 | "about": "This is a Prepros (https://prepros.io) configuration file. You can commit this file to a git repo to backup and sync project configurations.", 4 | "config": { 5 | "proxy": { 6 | "enable": false, 7 | "target": "", 8 | "useLocalAssets": false 9 | }, 10 | "reload": { 11 | "enable": true, 12 | "delay": 0, 13 | "animate": true, 14 | "afterUpload": false 15 | }, 16 | "sync": { 17 | "enable": false, 18 | "mouse": true, 19 | "keyboard": true, 20 | "form": true, 21 | "scroll": true 22 | }, 23 | "watcher": { 24 | "enable": true, 25 | "maxFiles": 2000, 26 | "usePolling": false, 27 | "pollingInterval": 500, 28 | "extensions": [ 29 | ".ls", 30 | ".html", 31 | ".htm", 32 | ".rb", 33 | ".php", 34 | ".asp", 35 | ".aspx", 36 | ".cfm", 37 | ".chm", 38 | ".cms", 39 | ".do", 40 | ".erb", 41 | ".jsp", 42 | ".mhtml", 43 | ".mspx", 44 | ".pl", 45 | ".py", 46 | ".shtml", 47 | ".cshtml", 48 | ".cs", 49 | ".vb", 50 | ".vbs", 51 | ".tpl", 52 | ".ctp", 53 | ".json" 54 | ], 55 | "ignore": { 56 | "patterns": [ 57 | "node_modules", 58 | ".*", 59 | "bower_components", 60 | "prepros.config", 61 | "Prepros Export", 62 | "prepros-6.config", 63 | "prepros.cfg", 64 | "wp-admin", 65 | "wp-includes" 66 | ], 67 | "exceptions": [] 68 | } 69 | }, 70 | "exporter": { 71 | "ignore": { 72 | "patterns": [ 73 | "config.rb", 74 | "prepros.config", 75 | "prepros-6.config", 76 | "node_modules", 77 | "Prepros Export", 78 | ".git", 79 | ".idea", 80 | ".sass-cache", 81 | ".hg", 82 | ".svn", 83 | ".cache", 84 | ".DS_Store", 85 | "*.sass", 86 | "*.scss", 87 | "*.less", 88 | "*.pug", 89 | "*.jade", 90 | "*.styl", 91 | "*.haml", 92 | "*.slim", 93 | "*.coffee", 94 | "*.ls", 95 | "*.kit", 96 | "*.ts" 97 | ], 98 | "exceptions": [] 99 | } 100 | }, 101 | "uploader": { 102 | "remotePath": "", 103 | "timeout": 20000, 104 | "autoUpload": false, 105 | "connectionType": "ftp", 106 | "history": [] 107 | }, 108 | "packages": { 109 | "createPackageLock": true 110 | }, 111 | "tasks": { 112 | "autoprefixer": { 113 | "cascade": true, 114 | "add": true, 115 | "remove": true, 116 | "supports": true, 117 | "flexbox": true, 118 | "grid": "autoplace", 119 | "browsers": [ 120 | "last 5 versions" 121 | ], 122 | "sourceMap": false 123 | }, 124 | "babel": { 125 | "sourceMap": false, 126 | "presets": { 127 | "@babel/preset-env": { 128 | "enable": true, 129 | "options": { 130 | "targets": [ 131 | "> 2%", 132 | "not dead" 133 | ], 134 | "preserveImports": false 135 | } 136 | }, 137 | "@babel/preset-react": true, 138 | "@babel/preset-flow": false 139 | }, 140 | "plugins": { 141 | "@babel/plugin-proposal-class-properties": false, 142 | "@babel/plugin-proposal-decorators": { 143 | "enable": false, 144 | "options": { 145 | "decoratorsBeforeExport": true 146 | } 147 | }, 148 | "@babel/plugin-proposal-export-namespace-from": false, 149 | "@babel/plugin-proposal-function-sent": false, 150 | "@babel/plugin-proposal-nullish-coalescing-operator": false, 151 | "@babel/plugin-proposal-numeric-separator": false, 152 | "@babel/plugin-proposal-optional-chaining": false, 153 | "@babel/plugin-proposal-private-methods": false, 154 | "@babel/plugin-proposal-throw-expressions": false 155 | }, 156 | "customPresets": [], 157 | "customPlugins": [] 158 | }, 159 | "bundle-js": { 160 | "sourceMap": false, 161 | "exclude": [ 162 | "node_modules", 163 | "bower_components" 164 | ], 165 | "devMode": true, 166 | "globals": [], 167 | "externals": [], 168 | "babel": { 169 | "enable": true, 170 | "options": { 171 | "sourceMap": false, 172 | "presets": { 173 | "@babel/preset-env": { 174 | "enable": true, 175 | "options": { 176 | "targets": [ 177 | "> 2%", 178 | "not dead" 179 | ], 180 | "preserveImports": false 181 | } 182 | }, 183 | "@babel/preset-react": true, 184 | "@babel/preset-flow": false 185 | }, 186 | "plugins": { 187 | "@babel/plugin-proposal-class-properties": false, 188 | "@babel/plugin-proposal-decorators": { 189 | "enable": false, 190 | "options": { 191 | "decoratorsBeforeExport": true 192 | } 193 | }, 194 | "@babel/plugin-proposal-export-namespace-from": false, 195 | "@babel/plugin-proposal-function-sent": false, 196 | "@babel/plugin-proposal-nullish-coalescing-operator": false, 197 | "@babel/plugin-proposal-numeric-separator": false, 198 | "@babel/plugin-proposal-optional-chaining": false, 199 | "@babel/plugin-proposal-private-methods": false, 200 | "@babel/plugin-proposal-throw-expressions": false 201 | }, 202 | "customPresets": [], 203 | "customPlugins": [] 204 | } 205 | }, 206 | "css": { 207 | "enable": true 208 | }, 209 | "fonts": { 210 | "enable": true 211 | } 212 | }, 213 | "coffeescript": { 214 | "header": false, 215 | "bare": false, 216 | "sourceMap": false 217 | }, 218 | "command": { 219 | "command": "", 220 | "rootDir": "" 221 | }, 222 | "concat-js": { 223 | "sourceMap": false, 224 | "rootDir": "" 225 | }, 226 | "copy": { 227 | "sourceMap": false 228 | }, 229 | "dart-sass": { 230 | "indentType": "space", 231 | "indentWidth": 2, 232 | "linefeed": "lf", 233 | "sourceMap": false 234 | }, 235 | "haml": { 236 | "doubleQuoteAttributes": true 237 | }, 238 | "jpg": { 239 | "quality": 90 240 | }, 241 | "less": { 242 | "javascriptEnabled": false, 243 | "strictImports": false, 244 | "insecure": false, 245 | "math": "always", 246 | "strictUnits": false, 247 | "dumpLineNumbers": false, 248 | "sourceMap": false 249 | }, 250 | "markdown": { 251 | "githubFlavored": true, 252 | "wrapWithHtml": false 253 | }, 254 | "minify-css": { 255 | "sourceMap": false 256 | }, 257 | "minify-html": { 258 | "caseSensitive": false, 259 | "collapseBooleanAttributes": true, 260 | "collapseInlineTagWhitespace": false, 261 | "collapseWhitespace": true, 262 | "conservativeCollapse": false, 263 | "decodeEntities": false, 264 | "html5": true, 265 | "includeAutoGeneratedTags": true, 266 | "keepClosingSlash": false, 267 | "minifyCSS": true, 268 | "minifyJS": true, 269 | "preserveLineBreaks": false, 270 | "preventAttributesEscaping": false, 271 | "processConditionalComments": false, 272 | "removeAttributeQuotes": false, 273 | "removeComments": true, 274 | "removeEmptyAttributes": false, 275 | "removeEmptyElement": false, 276 | "removeOptionalTags": false, 277 | "removeRedundantAttributes": false, 278 | "removeScriptTypeAttributes": false, 279 | "removeStyleLinkTypeAttributes": false, 280 | "removeTagWhitespace": false, 281 | "sortAttributes": false, 282 | "sortClassName": false, 283 | "useShortDoctype": true 284 | }, 285 | "minify-js": { 286 | "parse": { 287 | "bare_returns": false 288 | }, 289 | "compress": { 290 | "arrows": true, 291 | "arguments": false, 292 | "booleans": true, 293 | "booleans_as_integers": false, 294 | "collapse_vars": true, 295 | "comparisons": true, 296 | "computed_props": true, 297 | "conditionals": true, 298 | "dead_code": true, 299 | "directives": true, 300 | "drop_console": false, 301 | "drop_debugger": true, 302 | "evaluate": true, 303 | "expression": false, 304 | "global_defs": [], 305 | "hoist_funs": false, 306 | "hoist_props": true, 307 | "hoist_vars": false, 308 | "if_return": true, 309 | "inline": 3, 310 | "join_vars": true, 311 | "keep_fargs": true, 312 | "keep_infinity": false, 313 | "loops": true, 314 | "negate_iife": true, 315 | "properties": true, 316 | "pure_funcs": [], 317 | "pure_getters": false, 318 | "reduce_vars": true, 319 | "sequences": true, 320 | "side_effects": true, 321 | "switches": true, 322 | "top_retain": [], 323 | "typeofs": true, 324 | "unsafe": false, 325 | "unsafe_arrows": false, 326 | "unsafe_comps": false, 327 | "unsafe_Function": false, 328 | "unsafe_math": false, 329 | "unsafe_proto": false, 330 | "unsafe_regexp": false, 331 | "unsafe_undefined": false, 332 | "unused": true 333 | }, 334 | "mangle": { 335 | "eval": false, 336 | "reserved": [] 337 | }, 338 | "output": { 339 | "ascii_only": false, 340 | "braces": false, 341 | "comments": "none", 342 | "inline_script": true, 343 | "keep_numbers": false, 344 | "keep_quoted_props": false, 345 | "preamble": null, 346 | "quote_keys": false, 347 | "quote_style": 0, 348 | "semicolons": true, 349 | "shebang": true, 350 | "webkit": false, 351 | "wrap_iife": false, 352 | "wrap_func_args": true 353 | }, 354 | "sourceMap": false, 355 | "toplevel": false, 356 | "ie8": false, 357 | "keep_classnames": false, 358 | "keep_fnames": false, 359 | "safari10": false 360 | }, 361 | "node-sass": { 362 | "indentType": "space", 363 | "indentWidth": 2, 364 | "linefeed": "lf", 365 | "outputStyle": "expanded", 366 | "precision": 10, 367 | "sourceMap": false, 368 | "sourceComments": false 369 | }, 370 | "png": { 371 | "quality": 90 372 | }, 373 | "pug": { 374 | "pretty": true 375 | }, 376 | "slim": { 377 | "indent": "space", 378 | "indentSize": 2, 379 | "pretty": true 380 | }, 381 | "stylus": { 382 | "useNib": true, 383 | "sourceMap": false, 384 | "linenos": false 385 | }, 386 | "svg": { 387 | "cleanupAttrs": true, 388 | "removeDoctype": true, 389 | "removeXMLProcInst": true, 390 | "removeComments": true, 391 | "removeMetadata": true, 392 | "removeTitle": true, 393 | "removeDesc": true, 394 | "removeUselessDefs": true, 395 | "removeEditorsNSData": true, 396 | "removeEmptyAttrs": true, 397 | "removeHiddenElems": true, 398 | "removeEmptyText": true, 399 | "removeEmptyContainers": true, 400 | "removeViewBox": false, 401 | "cleanupEnableBackground": true, 402 | "convertStyleToAttrs": true, 403 | "convertColors": true, 404 | "convertPathData": true, 405 | "convertTransform": true, 406 | "removeUnknownsAndDefaults": true, 407 | "removeNonInheritableGroupAttrs": true, 408 | "removeUselessStrokeAndFill": true, 409 | "removeUnusedNS": true, 410 | "cleanupIDs": true, 411 | "cleanupNumericValues": true, 412 | "moveElemsAttrsToGroup": true, 413 | "moveGroupAttrsToElems": true, 414 | "collapseGroups": true, 415 | "removeRasterImages": false, 416 | "mergePaths": true, 417 | "convertShapeToPath": true, 418 | "sortAttrs": true, 419 | "removeDimensions": true 420 | }, 421 | "turf": { 422 | "rootDir": "" 423 | }, 424 | "typescript": { 425 | "allowJs": false, 426 | "allowSyntheticDefaultImports": true, 427 | "allowUmdGlobalAccess": false, 428 | "allowUnreachableCode": false, 429 | "allowUnusedLabels": false, 430 | "alwaysStrict": false, 431 | "charset": "utf8", 432 | "checkJs": false, 433 | "declaration": false, 434 | "disableSizeLimit": false, 435 | "downlevelIteration": false, 436 | "emitBOM": false, 437 | "emitDecoratorMetadata": false, 438 | "experimentalDecorators": false, 439 | "forceConsistentCasingInFileNames": false, 440 | "importHelpers": false, 441 | "jsx": "React", 442 | "keyofStringsOnly": false, 443 | "lib": [], 444 | "maxNodeModuleJsDepth": 0, 445 | "module": "ES2015", 446 | "moduleResolution": "NodeJs", 447 | "newLine": "LineFeed", 448 | "noFallthroughCasesInSwitch": false, 449 | "noImplicitAny": false, 450 | "noImplicitReturns": false, 451 | "noImplicitThis": false, 452 | "noStrictGenericChecks": false, 453 | "noUnusedLocals": false, 454 | "noUnusedParameters": false, 455 | "noImplicitUseStrict": false, 456 | "noLib": false, 457 | "noResolve": false, 458 | "preserveConstEnums": false, 459 | "jsxFactory": "React.createElement", 460 | "removeComments": false, 461 | "skipLibCheck": false, 462 | "sourceMap": false, 463 | "strict": false, 464 | "strictFunctionTypes": false, 465 | "strictBindCallApply": false, 466 | "strictNullChecks": false, 467 | "strictPropertyInitialization": false, 468 | "suppressExcessPropertyErrors": false, 469 | "suppressImplicitAnyIndexErrors": false, 470 | "target": "ES3", 471 | "resolveJsonModule": false, 472 | "esModuleInterop": false, 473 | "useDefineForClassFields": false 474 | } 475 | }, 476 | "fileTypes": { 477 | "sass": { 478 | "extensions": [ 479 | ".scss", 480 | ".sass" 481 | ], 482 | "autoCompile": true, 483 | "sourceMap": false, 484 | "tasks": [ 485 | { 486 | "task": "dart-sass", 487 | "enable": true 488 | }, 489 | { 490 | "task": "autoprefixer", 491 | "enable": true 492 | }, 493 | { 494 | "task": "minify-css", 495 | "enable": false 496 | } 497 | ], 498 | "output": { 499 | "extension": ".css", 500 | "type": "REPLACE_SEGMENTS", 501 | "segments": [ 502 | { 503 | "segment": "scss", 504 | "replaceWith": "css" 505 | }, 506 | { 507 | "segment": "sass", 508 | "replaceWith": "css" 509 | } 510 | ] 511 | } 512 | }, 513 | "less": { 514 | "extensions": [ 515 | ".less" 516 | ], 517 | "autoCompile": true, 518 | "sourceMap": false, 519 | "tasks": [ 520 | { 521 | "task": "less", 522 | "enable": true 523 | }, 524 | { 525 | "task": "autoprefixer", 526 | "enable": true 527 | }, 528 | { 529 | "task": "minify-css", 530 | "enable": false 531 | } 532 | ], 533 | "output": { 534 | "extension": ".css", 535 | "type": "REPLACE_SEGMENTS", 536 | "segments": [ 537 | { 538 | "segment": "less", 539 | "replaceWith": "css" 540 | } 541 | ] 542 | } 543 | }, 544 | "pug": { 545 | "extensions": [ 546 | ".pug", 547 | ".jade" 548 | ], 549 | "autoCompile": true, 550 | "tasks": [ 551 | { 552 | "task": "pug", 553 | "enable": true 554 | }, 555 | { 556 | "task": "minify-html", 557 | "enable": false 558 | } 559 | ], 560 | "output": { 561 | "extension": ".html", 562 | "type": "REPLACE_SEGMENTS", 563 | "segments": [ 564 | { 565 | "segment": "pug", 566 | "replaceWith": "html" 567 | } 568 | ] 569 | } 570 | }, 571 | "css": { 572 | "extensions": [ 573 | ".css" 574 | ], 575 | "autoCompile": false, 576 | "sourceMap": false, 577 | "tasks": [ 578 | { 579 | "task": "copy", 580 | "enable": true 581 | }, 582 | { 583 | "task": "autoprefixer", 584 | "enable": true 585 | }, 586 | { 587 | "task": "minify-css", 588 | "enable": true 589 | } 590 | ], 591 | "output": { 592 | "extension": ".css", 593 | "type": "SOURCE_RELATIVE", 594 | "relativePath": "", 595 | "suffix": "-dist", 596 | "alwaysSuffix": false 597 | } 598 | }, 599 | "javascript": { 600 | "extensions": [ 601 | ".js", 602 | ".jsx" 603 | ], 604 | "autoCompile": false, 605 | "sourceMap": false, 606 | "tasks": [ 607 | { 608 | "task": "copy", 609 | "enable": true 610 | }, 611 | { 612 | "task": "concat-js", 613 | "enable": false 614 | }, 615 | { 616 | "task": "babel", 617 | "enable": false 618 | }, 619 | { 620 | "task": "bundle-js", 621 | "enable": false 622 | }, 623 | { 624 | "task": "minify-js", 625 | "enable": true 626 | } 627 | ], 628 | "output": { 629 | "extension": ".js", 630 | "type": "SOURCE_RELATIVE", 631 | "relativePath": "", 632 | "suffix": "-dist", 633 | "alwaysSuffix": false 634 | } 635 | }, 636 | "stylus": { 637 | "extensions": [ 638 | ".styl" 639 | ], 640 | "autoCompile": true, 641 | "sourceMap": false, 642 | "tasks": [ 643 | { 644 | "task": "stylus", 645 | "enable": true 646 | }, 647 | { 648 | "task": "autoprefixer", 649 | "enable": true 650 | }, 651 | { 652 | "task": "minify-css", 653 | "enable": false 654 | } 655 | ], 656 | "output": { 657 | "extension": ".css", 658 | "type": "REPLACE_SEGMENTS", 659 | "segments": [ 660 | { 661 | "segment": "stylus", 662 | "replaceWith": "css" 663 | }, 664 | { 665 | "segment": "styl", 666 | "replaceWith": "css" 667 | } 668 | ] 669 | } 670 | }, 671 | "markdown": { 672 | "extensions": [ 673 | ".md", 674 | ".markdown", 675 | ".mkd" 676 | ], 677 | "autoCompile": false, 678 | "tasks": [ 679 | { 680 | "task": "markdown", 681 | "enable": true 682 | }, 683 | { 684 | "task": "minify-html", 685 | "enable": false 686 | } 687 | ], 688 | "output": { 689 | "extension": ".html", 690 | "type": "REPLACE_SEGMENTS", 691 | "segments": [ 692 | { 693 | "segment": "markdown", 694 | "replaceWith": "html" 695 | } 696 | ] 697 | } 698 | }, 699 | "haml": { 700 | "extensions": [ 701 | ".haml" 702 | ], 703 | "autoCompile": true, 704 | "tasks": [ 705 | { 706 | "task": "haml", 707 | "enable": true 708 | }, 709 | { 710 | "task": "minify-html", 711 | "enable": false 712 | } 713 | ], 714 | "output": { 715 | "extension": ".html", 716 | "type": "REPLACE_SEGMENTS", 717 | "segments": [ 718 | { 719 | "segment": "haml", 720 | "replaceWith": "html" 721 | } 722 | ] 723 | } 724 | }, 725 | "slim": { 726 | "extensions": [ 727 | ".slim" 728 | ], 729 | "autoCompile": true, 730 | "tasks": [ 731 | { 732 | "task": "slim", 733 | "enable": true 734 | }, 735 | { 736 | "task": "minify-html", 737 | "enable": false 738 | } 739 | ], 740 | "output": { 741 | "extension": ".html", 742 | "type": "REPLACE_SEGMENTS", 743 | "segments": [ 744 | { 745 | "segment": "slim", 746 | "replaceWith": "html" 747 | } 748 | ] 749 | } 750 | }, 751 | "coffeescript": { 752 | "extensions": [ 753 | ".coffee" 754 | ], 755 | "autoCompile": true, 756 | "sourceMap": false, 757 | "tasks": [ 758 | { 759 | "task": "coffeescript", 760 | "enable": true 761 | }, 762 | { 763 | "task": "babel", 764 | "enable": false 765 | }, 766 | { 767 | "task": "bundle-js", 768 | "enable": false 769 | }, 770 | { 771 | "task": "minify-js", 772 | "enable": false 773 | } 774 | ], 775 | "output": { 776 | "extension": ".js", 777 | "type": "REPLACE_SEGMENTS", 778 | "segments": [ 779 | { 780 | "segment": "coffee-script", 781 | "replaceWith": "js" 782 | }, 783 | { 784 | "segment": "coffeescript", 785 | "replaceWith": "js" 786 | }, 787 | { 788 | "segment": "coffee", 789 | "replaceWith": "js" 790 | } 791 | ] 792 | } 793 | }, 794 | "turf": { 795 | "extensions": [ 796 | ".turf", 797 | ".kit" 798 | ], 799 | "autoCompile": true, 800 | "tasks": [ 801 | { 802 | "task": "turf", 803 | "enable": true 804 | }, 805 | { 806 | "task": "minify-html", 807 | "enable": false 808 | } 809 | ], 810 | "output": { 811 | "extension": ".html", 812 | "type": "REPLACE_SEGMENTS", 813 | "segments": [ 814 | { 815 | "segment": "turf", 816 | "replaceWith": "html" 817 | } 818 | ] 819 | } 820 | }, 821 | "typescript": { 822 | "extensions": [ 823 | ".ts", 824 | ".tsx" 825 | ], 826 | "autoCompile": true, 827 | "sourceMap": false, 828 | "tasks": [ 829 | { 830 | "task": "typescript", 831 | "enable": true 832 | }, 833 | { 834 | "task": "babel", 835 | "enable": false 836 | }, 837 | { 838 | "task": "bundle-js", 839 | "enable": false 840 | }, 841 | { 842 | "task": "minify-js", 843 | "enable": false 844 | } 845 | ], 846 | "output": { 847 | "extension": ".js", 848 | "type": "REPLACE_SEGMENTS", 849 | "segments": [ 850 | { 851 | "segment": "typescript", 852 | "replaceWith": "js" 853 | }, 854 | { 855 | "segment": "ts", 856 | "replaceWith": "js" 857 | } 858 | ] 859 | } 860 | }, 861 | "jpg": { 862 | "extensions": [ 863 | ".jpg", 864 | ".jpeg" 865 | ], 866 | "tasks": [ 867 | { 868 | "task": "jpg", 869 | "enable": true 870 | } 871 | ], 872 | "output": { 873 | "extension": ".jpg", 874 | "type": "SOURCE_RELATIVE", 875 | "relativePath": "" 876 | } 877 | }, 878 | "png": { 879 | "extensions": [ 880 | ".png" 881 | ], 882 | "tasks": [ 883 | { 884 | "task": "png", 885 | "enable": true 886 | } 887 | ], 888 | "output": { 889 | "extension": ".png", 890 | "type": "SOURCE_RELATIVE", 891 | "relativePath": "" 892 | } 893 | }, 894 | "svg": { 895 | "extensions": [ 896 | ".svg" 897 | ], 898 | "tasks": [ 899 | { 900 | "task": "svg", 901 | "enable": true 902 | } 903 | ], 904 | "output": { 905 | "extension": ".svg", 906 | "type": "SOURCE_RELATIVE", 907 | "relativePath": "" 908 | } 909 | } 910 | }, 911 | "files": [ 912 | { 913 | "file": "dzdatetimepicker.css", 914 | "config": { 915 | "autoCompile": false, 916 | "sourceMap": false, 917 | "compileImported": false 918 | } 919 | }, 920 | { 921 | "file": "dzdatetimepicker.js", 922 | "config": { 923 | "autoCompile": true, 924 | "sourceMap": true, 925 | "compileImported": false 926 | } 927 | }, 928 | { 929 | "file": "dzdtp.min.js", 930 | "config": { 931 | "autoCompile": false, 932 | "sourceMap": false, 933 | "compileImported": false 934 | } 935 | }, 936 | { 937 | "file": "rangepicker.js", 938 | "config": { 939 | "autoCompile": true, 940 | "sourceMap": true, 941 | "compileImported": false 942 | } 943 | }, 944 | { 945 | "file": "src/dzdatetimepicker.js", 946 | "config": { 947 | "autoCompile": true, 948 | "sourceMap": true, 949 | "customOutput": "dist/dzdatetimepicker-dist.js", 950 | "tasks": { 951 | "concat-js": { 952 | "enable": true 953 | } 954 | } 955 | } 956 | }, 957 | { 958 | "file": "src/dzdatetimepicker.less", 959 | "config": { 960 | "sourceMap": true, 961 | "customOutput": "dist/dzdatetimepicker.css", 962 | "tasks": { 963 | "minify-css": { 964 | "enable": true 965 | } 966 | } 967 | } 968 | } 969 | ] 970 | } 971 | } 972 | -------------------------------------------------------------------------------- /dist/dzdatetimepicker-dist.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const findParent = (elem, id) => { 4 | 5 | const checker = i => i.getAttribute('id') === id || i.classList.contains(id) 6 | 7 | if(checker(elem)) 8 | return elem; 9 | 10 | while(elem.parentNode) { 11 | 12 | elem = elem.parentNode 13 | 14 | if(elem === document.body || elem === document) 15 | return undefined 16 | 17 | if(checker(elem)) 18 | return elem 19 | 20 | } 21 | 22 | return undefined 23 | }; 24 | 25 | const inputFocus = (evt) => { 26 | if(evt && evt.preventDefault) 27 | evt.preventDefault() 28 | evt.target.blur() 29 | return false 30 | }; 31 | 32 | const inputBlur = (evt) => { 33 | if(evt && evt.preventDefault) 34 | evt.preventDefault() 35 | return false 36 | }; 37 | 38 | const measure = (fn = function() {}) => new Promise((resolve, reject) => { 39 | window.requestAnimationFrame(() => { 40 | const retval = fn() 41 | resolve(retval) 42 | }) 43 | }); 44 | 45 | const mutate = (fn = function() {}) => new Promise((resolve, reject) => { 46 | window.requestAnimationFrame(() => { 47 | const retval = fn() 48 | resolve(retval) 49 | }) 50 | }); 51 | 52 | window.wait = window.wait || async function (milliseconds = 0) { 53 | return new Promise((resolve) => { 54 | setTimeout(() => { 55 | resolve(); 56 | }, milliseconds); 57 | }) 58 | }; 59 | 60 | // @prepros-append ./datepicker.js 61 | // @prepros-append ./timepicker.js 62 | // @prepros-append ./rangepicker.js 63 | // @prepros-append ./autohook.js 64 | 65 | ((glob) => { 66 | 67 | const prevSVG = ``; 68 | const nextSVG = ``; 69 | 70 | class DatePicker { 71 | 72 | constructor(customClass) { 73 | this.customClass = customClass 74 | this.init() 75 | } 76 | 77 | init() { 78 | if(this.initialized) 79 | return false 80 | 81 | this.initialized = true 82 | 83 | this.setupHooks() 84 | } 85 | 86 | setupHooks() { 87 | 88 | const prevClick = (evt) => { 89 | 90 | if(evt && evt.preventDefault) 91 | evt.preventDefault() 92 | 93 | let calendar = this.getCalendar() 94 | let currentString = calendar.dataset.current.split('-') 95 | let current = new Date(currentString[0], currentString[1]) 96 | 97 | let previous = new Date(current.getFullYear(), current.getMonth() - 1) 98 | 99 | let newDates = this.drawDates(this.getDaysArrayByMonth(previous)) 100 | let currentDates = document.querySelector('#dz-calendar .dz-dates') 101 | 102 | calendar.insertAdjacentHTML('beforeEnd', newDates) 103 | newDates = calendar.children[calendar.children.length-1] 104 | 105 | calendar.removeChild(currentDates) 106 | 107 | let year = previous.getFullYear() 108 | let month = previous.getMonth() 109 | 110 | calendar.dataset.current = `${year} - ${month}` 111 | calendar.children[0].children[0].innerHTML = `${this.getMonthName(month)}, ${year}` 112 | 113 | hookDates() 114 | 115 | return false 116 | 117 | } 118 | 119 | const nextClick = (evt) => { 120 | 121 | if(evt && evt.preventDefault) 122 | evt.preventDefault() 123 | 124 | let calendar = this.getCalendar() 125 | let currentString = calendar.dataset.current.split('-') 126 | let current = new Date(currentString[0], currentString[1]) 127 | 128 | let next = new Date(current.getFullYear(), current.getMonth() + 1) 129 | 130 | let newDates = this.drawDates(this.getDaysArrayByMonth(next)) 131 | let currentDates = document.querySelector('#dz-calendar .dz-dates') 132 | 133 | calendar.insertAdjacentHTML('beforeEnd', newDates) 134 | newDates = calendar.children[calendar.children.length-1] 135 | 136 | calendar.removeChild(currentDates) 137 | 138 | let year = next.getFullYear() 139 | let month = next.getMonth() 140 | 141 | calendar.dataset.current = `${year} - ${month}` 142 | calendar.children[0].children[0].innerHTML = `${this.getMonthName(month)}, ${year}` 143 | 144 | hookDates() 145 | 146 | return false 147 | 148 | } 149 | 150 | this.bodyClick = (evt) => { 151 | 152 | let calendar = this.getCalendar() 153 | 154 | if(calendar) 155 | if(!calendar.classList.contains('active')) 156 | document.body.removeChild(calendar) 157 | else if(!this.isInCalendar(evt.target)) { 158 | return this.cleanupCalendar(evt, calendar) 159 | } 160 | } 161 | 162 | this.bodyInput = (evt) => { 163 | const {keyCode} = evt 164 | 165 | const calendar = this.getCalendar() 166 | 167 | if (keyCode == 36 || keyCode == 35) { 168 | // pressed Home or End 169 | const elem = calendar.querySelector(`.dz-dates button:${keyCode == 36 ? 'first-child' : 'last-child'}`) 170 | if (elem) 171 | elem.focus() 172 | return true 173 | } 174 | 175 | if (keyCode >= 37 && keyCode <= 40) { 176 | // up or down arrow keys 177 | const current = Number(document.activeElement.innerHTML) || 0 178 | 179 | let expected = current 180 | if (keyCode == 40) expected += 7; // down 181 | else if (keyCode == 38) expected -= 7; // up 182 | else if (keyCode == 37) expected -= 1; // left 183 | else expected += 1; // right 184 | 185 | const elem = calendar.querySelector(`.dz-dates button:nth-child(${expected})`) 186 | if (elem) 187 | elem.focus() 188 | return true 189 | } 190 | 191 | if (keyCode == 33) { 192 | calendar.querySelector("#dz-prev").click() 193 | return true 194 | } 195 | 196 | if (keyCode == 34) { 197 | calendar.querySelector("#dz-next").click() 198 | return true 199 | } 200 | 201 | if (keyCode != 13 && keyCode != 27 || keyCode != 32) 202 | return true 203 | 204 | if (keyCode == 13 || keyCode == 32) { 205 | // user has pressed the enter or space key. Assume to be a confirmation 206 | document.activeElement.getAttribute("aria-label").click() 207 | // the above click will automatically clean up the calendar 208 | } 209 | 210 | if (keyCode == 27) { 211 | // esc key 212 | this.cleanupCalendar(evt, this.calendar); 213 | } 214 | 215 | return true 216 | } 217 | 218 | const dateClick = (evt) => { 219 | 220 | let calendar = this.getCalendar() 221 | let date = parseInt(evt.target.innerHTML) 222 | 223 | let currentString = calendar.dataset.current.split('-') 224 | date = new Date(currentString[0],currentString[1],date) 225 | 226 | let fn = window[this.source.dataset.onset] 227 | if(fn) 228 | fn(date) 229 | 230 | // zero pad the month if needed 231 | let month = DatePicker.zeroPaddedFormatMonth(date); 232 | 233 | // zero pad the date if needed 234 | let dateStr = DatePicker.zeroPaddedFormatDate(date); 235 | 236 | let val = [date.getFullYear(), month, dateStr].join('-') 237 | 238 | if(this.source.nodeName === 'INPUT') { 239 | this.source.value = val 240 | if ('InputEvent' in window) 241 | this.source.dispatchEvent(new InputEvent('input')) 242 | else 243 | this.source.dispatchEvent(new Event('input')) 244 | } 245 | else if(this.source.dataset.dateVal) 246 | this.source.dataset.dateVal = val 247 | 248 | if (this.callback) 249 | this.callback(this.source, val) 250 | 251 | return this.cleanupCalendar(evt, calendar) 252 | 253 | } 254 | 255 | const hookDates = () => { 256 | 257 | let calendar = this.getCalendar() 258 | if(!calendar) 259 | return 260 | 261 | let dates = Array.prototype.slice.call(document.querySelectorAll('#dz-calendar .dz-dates button')) 262 | dates.forEach((item) => { 263 | if(!item.classList.contains('disabled')) 264 | item.addEventListener('click', dateClick, false) 265 | }) 266 | 267 | } 268 | 269 | let fromFocus = false; 270 | 271 | const triggerClick = (evt) => { 272 | 273 | // check if calendar is already being shown 274 | let phantom = this.getCalendar() 275 | 276 | if(phantom && phantom != this.calendar) { 277 | 278 | this.cleanupCalendar(evt, phantom) 279 | setTimeout(() => { 280 | triggerClick(evt) 281 | }, 350) 282 | return false 283 | } 284 | 285 | let rect = evt.target.getBoundingClientRect(); 286 | 287 | let center = { 288 | x: rect.left + (rect.width / 2), 289 | y: rect.top + rect.height 290 | } 291 | 292 | let target = evt.target.nodeName === "INPUT" ? 293 | evt.target : 294 | findParent(evt.target, this.customClass || 'date-trigger') 295 | 296 | this.source = target 297 | 298 | let calendar = this.drawCalendar() 299 | 300 | mutate(() => { 301 | document.body.insertAdjacentHTML('beforeEnd', calendar) 302 | }) 303 | .then(() => { 304 | calendar = document.getElementById('dz-calendar') 305 | this.calendar = calendar 306 | return measure(() => calendar.getBoundingClientRect()) 307 | }) 308 | .then(result => { 309 | // position the calendar near the origin point 310 | const calendarRect = result 311 | 312 | // the width before showing = actual width * 0.25 313 | let width = calendarRect.width * 4 314 | 315 | calendar.style.left = (center.x - width/2) + 'px'; 316 | 317 | const targetRect = target.getBoundingClientRect(); 318 | 319 | // center.y + half of the pointer's height 320 | // 193 is height of the calendar 321 | calendar.style.top = (center.y + 36) + 'px'; 322 | 323 | console.debug(calendar.style.top); 324 | 325 | let prev = calendar.children[0].children[1]; 326 | let next = calendar.children[0].children[2]; 327 | 328 | prev.addEventListener('click', prevClick, false) 329 | next.addEventListener('click', nextClick, false) 330 | 331 | return mutate(() => { 332 | calendar.classList.add('active') 333 | this.source.setAttribute("aria-expanded", "true") 334 | if (this.source.hasAttribute("id")) { 335 | calendar.setAttribute("aria-describedby", this.source.getAttribute("id")) 336 | } 337 | }) 338 | }) 339 | .then(() => { 340 | hookDates() 341 | 342 | let fn = 'didShowDatePicker' 343 | if(window[fn]) 344 | window[fn](calendar) 345 | }) 346 | .then(() => { 347 | 348 | let date = new Date(); 349 | 350 | if (this.source.hasAttribute("value") && !!(this.source.value) && this.source.value.trim().length) { 351 | date = new Date(this.source.value); 352 | } 353 | 354 | date = date.getDate(); 355 | 356 | return measure(() => calendar.querySelector(`button:nth-child(${date})`)) 357 | 358 | }) 359 | .then(result => { 360 | if (result) { 361 | result.focus() 362 | } 363 | document.body.addEventListener('click', this.bodyClick, false) 364 | document.body.addEventListener('keydown', this.bodyInput, false) 365 | }) 366 | .then(result => { 367 | setTimeout(() => { 368 | this.repositionCalendarWithinViewport() 369 | }, 100) 370 | }) 371 | .catch(err => { 372 | console.error(err) 373 | }) 374 | 375 | return false 376 | 377 | } 378 | 379 | let triggers = document.querySelectorAll(this.customClass ? "." + this.customClass : '.date-trigger') 380 | triggers = Array.prototype.slice.call(triggers) 381 | 382 | const attachTrigger = (elem) => { 383 | if(!elem) return 384 | 385 | if(elem.nodeName === "INPUT") { 386 | elem.addEventListener('click', triggerClick, false) 387 | elem.addEventListener('blur', inputBlur, false) 388 | elem.setAttribute("aria-haspopup", "true") 389 | elem.setAttribute("aria-expanded", "false") 390 | } 391 | else { 392 | elem.addEventListener('click', triggerClick, false) 393 | } 394 | } 395 | 396 | triggers.forEach((item) => { 397 | attachTrigger(item) 398 | }) 399 | 400 | glob.attachDateTrigger = attachTrigger 401 | 402 | } 403 | 404 | getCalendar() { 405 | return document.getElementById("dz-calendar") 406 | } 407 | 408 | isInCalendar(elem) { 409 | let parent = findParent(elem, 'dz-calendar') 410 | return parent !== document.body && parent != undefined 411 | } 412 | 413 | getMonthName(idx) { 414 | return ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'].splice(idx, 1) 415 | } 416 | 417 | getFullMonthName(idx) { 418 | return ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'].splice(idx, 1) 419 | } 420 | 421 | getDaysArrayByMonth(date) { 422 | 423 | let year = date.getFullYear() 424 | let month = date.getMonth() 425 | let monthRange = new Date(year, month + 1, 0).getDate() 426 | let days = [] 427 | 428 | while(monthRange > 0) { 429 | days.push(new Date(year, month, monthRange)) 430 | monthRange--; 431 | } 432 | 433 | return days.reverse() 434 | } 435 | 436 | drawDates(dates) { 437 | 438 | let now = new Date(); 439 | let today = new Date(); 440 | 441 | if(this.source.nodeName === 'INPUT' && this.source.value) 442 | now = new Date(this.source.value) 443 | else if (this.source.dataset.dateVal) 444 | now = new Date(this.source.dataset.dateVal) 445 | 446 | let markup = `
` 447 | let calendar = this.getCalendar() 448 | 449 | let {dateMax, dateMin} = this.source.dataset 450 | 451 | if(dateMax) 452 | dateMax = new Date(dateMax) 453 | if(dateMin) 454 | dateMin = new Date(dateMin) 455 | 456 | let val = null 457 | if(this.source.nodeName === 'INPUT') 458 | val = new Date(this.source.value) 459 | else if (this.source.dataset.dateVal) 460 | val = new Date(this.source.dataset.dateVal) 461 | 462 | // find offset of first date. 463 | let offsetDay = dates[0].getDay() 464 | 465 | const dateEqual = (base, compare) => base.getDate() === compare.getDate() && base.getMonth() === compare.getMonth() && base.getYear() == compare.getYear() 466 | 467 | dates.forEach((date, idx) => { 468 | 469 | let classes = []; 470 | 471 | // check if the date is today 472 | if (dateEqual(today, date)) { 473 | classes.push('today'); 474 | } 475 | 476 | // check if this is the selected value 477 | if(val && dateEqual(date, val)) { 478 | classes.push('selected'); 479 | } 480 | 481 | // check if the date is within the min range, if one is set 482 | if(dateMin && (dateMin.getTime() - date.getTime()) > 0) { 483 | classes.push('disabled'); 484 | } 485 | 486 | // check if the date is within the max range, if one is set 487 | if(dateMax && (dateMax.getTime() - date.getTime()) < 0) { 488 | classes.push('disabled'); 489 | } 490 | 491 | classes = classes.join(' '); 492 | 493 | const days = { 494 | "Mon": "Monday", 495 | "Tue": "Tuesday", 496 | "Wed": "Wednesday", 497 | "Thu": "Thursday", 498 | "Fri": "Friday", 499 | "Sat": "Saturday", 500 | "Sun": "Sunday" 501 | } 502 | 503 | let ariaString = date.toDateString(); 504 | ariaString = [ariaString.substr(0,3), ariaString.substr(4)]; 505 | ariaString[0] = `${days[ariaString[0]]}, `; 506 | 507 | ariaString[1] = [ariaString[1].substr(0,3), ariaString[1].substr(4)]; 508 | ariaString[1][0] = this.getFullMonthName(date.getMonth()); 509 | ariaString[1] = ariaString[1].join(" "); 510 | ariaString = ariaString.join(""); 511 | 512 | if (idx !== 0) { 513 | markup += `` 514 | } 515 | else { 516 | markup += `` 517 | } 518 | 519 | }) 520 | 521 | markup += `
` 522 | 523 | return markup 524 | 525 | } 526 | 527 | drawCalendar() { 528 | 529 | let now = new Date(); 530 | 531 | if (this.source.hasAttribute("value") && !!(this.source.value) && this.source.value.trim().length) { 532 | now = new Date(this.source.value); 533 | } 534 | 535 | let year = now.getFullYear() 536 | let month = now.getMonth() 537 | 538 | let dates = this.getDaysArrayByMonth(now) 539 | let days = ['S', 'M', 'T', 'W', 'T', 'F', 'S'] 540 | 541 | let markup = `` 556 | 557 | return markup 558 | } 559 | 560 | repositionCalendarWithinViewport () { 561 | 562 | const calendar = this.getCalendar() 563 | 564 | if (!calendar) 565 | return; 566 | const rect = calendar.getBoundingClientRect(); 567 | 568 | if (rect.x < 0) { 569 | // move it to the right 570 | const left = rect.x - Number(calendar.style.left.replace("px", "")) - 8; 571 | calendar.style.left = left + "px" 572 | calendar.classList.add("zp-l") 573 | } 574 | 575 | if ((rect.x + rect.width) > glob.innerWidth) { 576 | // pull it back 577 | const right = glob.innerWidth - rect.width - 48; 578 | calendar.style.left = right + "px"; 579 | 580 | calendar.classList.add("zp-r") 581 | 582 | // reposition the pointer 583 | const beforeElem = calendar.parentNode.querySelector("#dz-calendar", ":before"); 584 | console.log(beforeElem.style.left); 585 | } 586 | 587 | } 588 | 589 | cleanupCalendar(evt, calendar) { 590 | 591 | if(evt && evt.preventDefault) 592 | evt.preventDefault() 593 | 594 | if(calendar) { 595 | 596 | mutate(() => { 597 | document.activeElement.blur(); 598 | calendar.classList.remove('active') 599 | }) 600 | .then(() => wait(300)) 601 | .then(() => { 602 | if (calendar && calendar.parentNode) 603 | calendar.parentNode.removeChild(calendar) 604 | }) 605 | .then(() => { 606 | if (this.source) { 607 | return mutate(() => this.source.setAttribute("aria-expanded", "false")) 608 | } 609 | 610 | return Promise.resolve() 611 | }) 612 | .then(() => { 613 | document.body.removeEventListener('click', this.bodyClick, false) 614 | document.body.removeEventListener('keydown', this.bodyInput, false) 615 | }) 616 | .catch(err => { 617 | console.error(err) 618 | }) 619 | 620 | } 621 | 622 | return false 623 | 624 | } 625 | 626 | static zeroPaddedFormatMonth (date) { 627 | 628 | let month = date.getMonth() + 1; 629 | 630 | if (month.toString().length === 1) { 631 | month = "0" + month 632 | } 633 | 634 | return month; 635 | 636 | } 637 | 638 | static zeroPaddedFormatDate (date) { 639 | 640 | // zero pad the date if needed 641 | let dateStr = date.getDate() 642 | 643 | if (dateStr.toString().length === 1) { 644 | dateStr = "0" + dateStr 645 | } 646 | 647 | return dateStr; 648 | 649 | } 650 | 651 | } 652 | 653 | if(glob && glob.exports) 654 | glob.exports = Object.assign({}, { 655 | 'DatePicker': DatePicker, 656 | 'datePicker': new DatePicker() 657 | }) 658 | 659 | else { 660 | glob.DatePicker = DatePicker 661 | glob.datePicker = new DatePicker() 662 | } 663 | 664 | })(typeof module === "undefined" ? window : module); 665 | 666 | ((glob) => { 667 | 668 | class TimePicker { 669 | 670 | constructor() { 671 | this.init() 672 | } 673 | 674 | init() { 675 | 676 | if(this.initialized) 677 | return false 678 | 679 | this.initialized = true 680 | this.setupHooks() 681 | 682 | } 683 | 684 | setupHooks() { 685 | 686 | this.bodyClick = (evt) => { 687 | 688 | if(evt.target.nodeName === 'SELECT') 689 | return false 690 | 691 | let timer = this.getTimer() 692 | 693 | if(timer) 694 | if(!timer.classList.contains('active')) 695 | document.body.removeChild(timer) 696 | else if(!this.isInTimer(evt.target)) { 697 | return this.cleanupTimer(evt, timer) 698 | } 699 | 700 | document.body.removeEventListener('click', this.bodyClick, false); 701 | 702 | } 703 | 704 | this.bodyInput = (evt) => { 705 | const {keyCode} = evt 706 | 707 | if (keyCode != 13 && keyCode != 27) 708 | return true 709 | 710 | if (keyCode == 27) { 711 | // user is dismissing by pressing the Esc. key 712 | // reset the value back to the original value 713 | if (this.hasOwnProperty("originalValue")) { 714 | this.source.value = this.originalValue 715 | } 716 | } 717 | 718 | // user has pressed the enter key. Assume to be a confirmation 719 | if (this.hasOwnProperty("originalValue")) 720 | delete [this.originalValue] 721 | 722 | this.cleanupTimer(undefined, this.getTimer()) 723 | 724 | return true 725 | } 726 | 727 | const didChange = () => { 728 | 729 | // let target = evt.target 730 | let timer = this.getTimer() 731 | 732 | let hours = parseInt(timer.children[0].value) 733 | let minutes = parseInt(timer.children[1].value) 734 | let shift = parseInt(timer.children[2].value) 735 | 736 | if(shift === 1 && hours != 12) 737 | hours += 12 738 | 739 | if(hours === 12 && shift === 0) 740 | hours = '00' 741 | 742 | if(this.source.nodeName === 'INPUT') { 743 | this.source.value = hours + ':' + minutes 744 | if ('InputEvent' in window) 745 | this.source.dispatchEvent(new InputEvent('input')) 746 | else 747 | this.source.dispatchEvent(new Event('input')) 748 | } 749 | 750 | let fn = window[this.source.dataset.onchange] 751 | if(fn) fn({ 752 | string: hours + ':' + minutes, 753 | hours: parseInt(hours), 754 | minutes: minutes 755 | }) 756 | 757 | } 758 | 759 | const triggerClick = (evt) => { 760 | 761 | let phantom = this.getTimer() 762 | 763 | if(phantom) { 764 | this.cleanupTimer(evt, phantom) 765 | setTimeout(() => { 766 | triggerClick(evt) 767 | }, 300) 768 | return false 769 | } 770 | 771 | let rect = evt.target.getBoundingClientRect() 772 | let center = { 773 | x: rect.left, 774 | y: rect.top + rect.height 775 | } 776 | 777 | this.source = evt.target 778 | 779 | let timer = this.drawTimer() 780 | 781 | mutate(() => { 782 | document.body.insertAdjacentHTML('beforeEnd', timer) 783 | }) 784 | .then(() => { 785 | timer = this.getTimer() 786 | 787 | // set the current time 788 | if(this.source.nodeName !== 'INPUT' || !this.source.value.length) { 789 | let date = new Date() 790 | let hours = date.getHours(), 791 | minutes = date.getMinutes() 792 | 793 | return mutate(() => { 794 | timer.children[0].value = hours > 12 ? hours - 12 : hours 795 | timer.children[1].value = minutes 796 | timer.children[2].value = hours >= 12 ? 1 : 0 797 | }) 798 | } 799 | 800 | return Promise.resolve() 801 | }) 802 | .then(() => { 803 | // add the hooks 804 | Array.prototype.slice.call(timer.children).forEach((item) => { 805 | item.addEventListener('change', didChange, false) 806 | }) 807 | 808 | return measure(() => timer.getBoundingClientRect()) 809 | }) 810 | .then(result => { 811 | // position the calendar near the origin point 812 | const timerRect = result 813 | 814 | // the width before showing = actual width * 0.25 815 | const width = timerRect.width * 4 816 | 817 | timer.style.left = (center.x - 16) + 'px' 818 | timer.style.top = (center.y) + 'px' 819 | 820 | return mutate(() => { 821 | timer.classList.add('active') 822 | 823 | this.source.setAttribute("aria-expanded", "true") 824 | if (this.source.hasAttribute("id")) { 825 | timer.setAttribute("aria-describedby", this.source.getAttribute("id")) 826 | } 827 | }) 828 | }) 829 | .then(() => { 830 | timer.querySelector("select").focus() 831 | this.originalValue = this.source.value 832 | document.body.addEventListener('click', this.bodyClick, false) 833 | document.body.addEventListener('keydown', this.bodyInput, false) 834 | }) 835 | .catch(err => { 836 | console.error(err) 837 | }) 838 | 839 | return false 840 | 841 | } 842 | 843 | const attachTrigger = (elem) => { 844 | if(!elem) return 845 | elem.addEventListener('click', triggerClick, false) 846 | if(elem.nodeName === "INPUT") { 847 | elem.addEventListener('focus', inputFocus, false) 848 | elem.addEventListener('blur', inputBlur, false) 849 | elem.setAttribute("aria-haspopup", "true") 850 | elem.setAttribute("aria-expanded", "false") 851 | } 852 | } 853 | 854 | let triggers = Array.prototype.slice.call(document.querySelectorAll('.timer-trigger')) 855 | 856 | triggers.forEach((item) => { 857 | attachTrigger(item) 858 | }) 859 | 860 | window.attachTimeTrigger = attachTrigger 861 | 862 | } 863 | 864 | getTimer() { 865 | return document.getElementById('dz-timer') 866 | } 867 | 868 | isInTimer(elem) { 869 | let parent = findParent(elem, 'dz-timer') 870 | return parent !== document.body && parent != undefined 871 | } 872 | 873 | drawTimer() { 874 | 875 | let val = null, hoursVal, minVal, shiftVal = false 876 | if(this.source.nodeName === 'INPUT') 877 | val = this.source.value 878 | 879 | if(val) { 880 | val = val.split(':') 881 | hoursVal = parseInt(val[0]) 882 | minVal = val[1] 883 | 884 | if(hoursVal >= 12) 885 | shiftVal = true 886 | } 887 | 888 | let markup = `` 923 | 924 | return markup 925 | } 926 | 927 | cleanupTimer(evt, timer) { 928 | if(evt && evt.preventDefault) 929 | evt.preventDefault() 930 | 931 | if(timer) { 932 | 933 | mutate(() => { 934 | timer.classList.remove('active') 935 | }) 936 | .then(() => wait(500)) 937 | .then(() => { 938 | this.source = undefined 939 | if(timer.parentNode) 940 | document.body.removeChild(timer) 941 | }) 942 | .catch(err => { 943 | console.error(err) 944 | }) 945 | 946 | } 947 | 948 | document.body.removeEventListener('click', this.bodyClick, false) 949 | document.body.removeEventListener('keydown', this.bodyInput, false) 950 | 951 | return false 952 | } 953 | 954 | } 955 | 956 | if(glob && glob.exports) { 957 | glob.exports = Object.assign({}, { 958 | 'TimePicker': TimePicker, 959 | 'timePicker': new TimePicker() 960 | }) 961 | } 962 | else { 963 | glob.TimePicker = TimePicker 964 | glob.timePicker = new TimePicker() 965 | } 966 | 967 | })(typeof module === "undefined" ? window : module); 968 | 969 | ((glob) => { 970 | class RangePicker { 971 | constructor(elem) { 972 | this.elem = elem 973 | this.initialized = false 974 | this.init() 975 | } 976 | 977 | init () { 978 | if (!this.elem) 979 | return 980 | 981 | if (this.initialized) 982 | return 983 | this.initialized = true 984 | 985 | let time = +new Date() 986 | 987 | this.startElem = this.elem.querySelector('.range-start') 988 | this.endElem = this.elem.querySelector('.range-end') 989 | 990 | this.startElem.setAttribute("type", "text") 991 | this.endElem.setAttribute("type", "text") 992 | 993 | this.startElem.classList.add('start'+time) 994 | this.endElem.classList.add('end'+time) 995 | 996 | this.startController = new DatePicker('start'+time) 997 | this.endController = new DatePicker('end'+time) 998 | 999 | this.startController.callback = this.callback.bind(this) 1000 | this.endController.callback = this.startController.callback 1001 | } 1002 | 1003 | callback() { 1004 | let args = [...arguments] 1005 | let elem = args[0] 1006 | let val = args[1] 1007 | 1008 | let isStart = elem.classList.contains('range-start') 1009 | 1010 | if (isStart) 1011 | this.start = val 1012 | else 1013 | this.end = val 1014 | 1015 | if (isStart) { 1016 | // update the min-date of the end-range 1017 | // this needs to be adjusted such that 1018 | // the min-date also includes the selected date 1019 | // for single day ranges. 1020 | 1021 | const selected = new Date(val); 1022 | 1023 | const newMax = new Date(selected.setDate(selected.getDate() - 1)); 1024 | 1025 | const month = DatePicker.zeroPaddedFormatMonth(newMax); 1026 | const dateStr = DatePicker.zeroPaddedFormatDate(newMax); 1027 | 1028 | this.endElem.dataset.dateMin = `${newMax.getFullYear()}-${month}-${dateStr}` 1029 | } 1030 | 1031 | } 1032 | } 1033 | 1034 | if (glob.hasOwnProperty('exports')) 1035 | glob.exports = Object.assign({}, glob.exports, RangePicker) 1036 | else 1037 | glob.RangePicker = RangePicker 1038 | 1039 | })(typeof module === "undefined" ? window : module); 1040 | 1041 | ((glob) => { 1042 | 1043 | if (!glob) 1044 | return; // exit early as we only wish to target the browser environment 1045 | 1046 | /* 1047 | * we check early if the browser natively supports 1048 | * input[type="date"], 1049 | * input[type="time"], 1050 | * input[type="datetime-local"] 1051 | */ 1052 | 1053 | let checks = { 1054 | 'date': false, 1055 | 'time': false, 1056 | 'datetime-local': false 1057 | } 1058 | 1059 | let input = document.createElement("input") 1060 | 1061 | Object.keys(checks).forEach(key => { 1062 | input.type = key 1063 | // if the input type is the same as we set it, it is supported by the browser 1064 | checks[key] = input.type === key 1065 | }) 1066 | 1067 | const DATE_TIME_EXP = /([\d]{4}\-[\d]{2}\-[\d]{2})T([\d]{2}\:[\d]{2})/ 1068 | 1069 | const hookTime = () => { 1070 | let inputs = Array.prototype.slice.call(document.querySelectorAll('input[type="time"]')) 1071 | inputs.forEach(attachTimeTrigger) 1072 | } 1073 | 1074 | const hookDate = () => { 1075 | let inputs = Array.prototype.slice.call(document.querySelectorAll('input[type="date"]')) 1076 | inputs.forEach(attachDateTrigger) 1077 | } 1078 | 1079 | const hookDateTime = () => { 1080 | /* 1081 | * when datetime-local is not supported, 1082 | * we split the current input into two separate inputs. 1083 | * One for date, the other for time. 1084 | * We set the original input elem to "hidden" and manipulate 1085 | * it's value so the user still retains the name of that field in the form 1086 | */ 1087 | let inputs = Array.prototype.slice.call(document.querySelectorAll('input[type="datetime-local"]')) 1088 | inputs.forEach(elem => { 1089 | 1090 | // create a reference for the parent node because we need it later 1091 | const input = elem 1092 | const container = input.parentNode 1093 | const getTarget = () => container.querySelector("input[data-original='datetime-local']") 1094 | 1095 | let value = input.value, 1096 | hasValue = value.trim().length > 0, 1097 | date = null, 1098 | time = null 1099 | 1100 | if (hasValue && DATE_TIME_EXP.test(value)) { 1101 | date = value.replace(DATE_TIME_EXP, "$1") 1102 | time = value.replace(DATE_TIME_EXP, "$2") 1103 | } 1104 | 1105 | const dateChange = evt => { 1106 | let target = getTarget() 1107 | target.dataset.date = evt.target.value 1108 | } 1109 | 1110 | const timeChange = evt => { 1111 | let target = getTarget() 1112 | target.dataset.time = evt.target.value 1113 | } 1114 | 1115 | // define a custom getter for value which utilizes the above two dataset values 1116 | input.__defineGetter__("value", function() { 1117 | return ((this.dataset.date||"" )+ " " + (this.dataset.time||"")).trim() 1118 | }) 1119 | 1120 | // set the type to hidden so it's still in the DOM, but not visible to the user 1121 | input.type = "hidden" 1122 | // set this custom dataset prop so we can query for it later 1123 | input.dataset.original = "datetime-local" 1124 | 1125 | // create our new date input 1126 | let inDate = document.createElement("input") 1127 | inDate.type = checks.date ? "date" : "text" 1128 | inDate.placeholder = "Date" 1129 | inDate.oninput = dateChange; 1130 | 1131 | if (date) 1132 | inDate.value = date 1133 | 1134 | // check if date-min and date-max are set 1135 | let {dateMin, dateMax} = input.dataset 1136 | if (dateMin) 1137 | inDate.dataset.dateMin = dateMin 1138 | if (dateMax) 1139 | inDate.dataset.dateMax = dateMax 1140 | 1141 | // create our new time input 1142 | let inTime = document.createElement("input") 1143 | inTime.type = checks.time ? "time" : "text" 1144 | inTime.placeholder = "Time" 1145 | inTime.oninput = timeChange; 1146 | 1147 | if (time) 1148 | inTime.value = time; 1149 | 1150 | [inDate, inTime].forEach(inp => { 1151 | inp.__defineGetter__("required", function() { 1152 | return input.required 1153 | }) 1154 | 1155 | inp.__defineGetter__("validity", function() { 1156 | return input.validity 1157 | }) 1158 | 1159 | inp.__defineGetter__("pattern", function() { 1160 | return input.pattern 1161 | }) 1162 | 1163 | inp.__defineGetter__("validationMessage", function() { 1164 | return input.validationMessage 1165 | }) 1166 | 1167 | inp.__defineSetter__("validationMessage", function(val) { 1168 | input.validationMessage = val 1169 | }) 1170 | }) 1171 | 1172 | // add them to the DOM after the OG 1173 | container.insertAdjacentElement("beforeEnd", inDate) 1174 | container.insertAdjacentElement("beforeEnd", inTime) 1175 | 1176 | // attach the triggers 1177 | attachDateTrigger(inDate) 1178 | attachTimeTrigger(inTime) 1179 | }) 1180 | } 1181 | 1182 | if (!checks.date) 1183 | hookDate() 1184 | if (!checks.time) 1185 | hookTime() 1186 | if (!checks['datetime-local']) 1187 | hookDateTime() 1188 | 1189 | // expose functions to the window 1190 | glob.hookDate = hookDate; 1191 | glob.hookTime = hookTime; 1192 | glob.hookDateTimer = hookDateTime; 1193 | 1194 | })(typeof module === "undefined" ? window : undefined); 1195 | 1196 | //# sourceMappingURL=dzdatetimepicker-dist.js.map --------------------------------------------------------------------------------