├── .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 |
45 |
46 |
47 |
52 |
--------------------------------------------------------------------------------
/demos/range.html:
--------------------------------------------------------------------------------
1 |
35 |
36 |
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 | Trigger
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 |
25 | when dzdatetimepicker.js runs, it automatically finds elements with the class date-trigger and hooks on to them. No futher configuration is required.
26 | 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.
27 | 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.
28 |
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 |
43 | Both the datepicker and timepicker automatically idenity <input> elements. They hook on to the focus and blur events so the user can use the pickers to set the values directly.
44 | If the pickers detect an <input> element, the pickers will update the value attribute when the user updates their selection.
45 | When not using an <input> element, you can optionally set the attribute data-date-val="" and it'll be updated similarly.
46 |
47 | Todo
48 |
49 | [x] Remove dependencies
50 |
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 | Trigger
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 = `
224 | `
225 |
226 | // draw hours dropdown
227 | let hours = Array.from(Array(13).keys())
228 | hours.shift()
229 | markup += hours
230 | .map((item) => {
231 | if(item === hoursVal)
232 | return `${item} `
233 | return `${item} `
234 | }).join(' ')
235 |
236 | markup += `
237 | `
238 |
239 | // draw minutes dropdown
240 | markup += Array.from(Array(60).keys())
241 | .map((item) => {
242 | if(item.toString().length === 1)
243 | item = '0' + item
244 | if(item.toString() === minVal)
245 | return `${item} `
246 | return `${item} `
247 | }).join(' ')
248 |
249 | // AM, PM
250 | markup += `
251 |
252 | AM
253 | PM
254 | `
255 |
256 | markup +=`
257 |
`
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 = `Previous Month `;
4 | const nextSVG = `Next Month `;
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 += `${date.getDate()} `
450 | }
451 | else {
452 | markup += `${date.getDate()} `
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 = `
478 |
479 |
${this.getMonthName(now.getMonth())}, ${now.getFullYear()}
480 | ${prevSVG}
481 | ${nextSVG}
482 |
483 |
`
484 |
485 | days.forEach((day) => {
486 | markup += `
${day}
`
487 | })
488 |
489 | markup += `
490 | ${this.drawDates(dates)}
491 |
`
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 = `Previous Month `;
68 | const nextSVG = `Next Month `;
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 += `${date.getDate()} `
514 | }
515 | else {
516 | markup += `${date.getDate()} `
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 = `
542 |
543 |
${this.getMonthName(now.getMonth())}, ${now.getFullYear()}
544 | ${prevSVG}
545 | ${nextSVG}
546 |
547 |
`
548 |
549 | days.forEach((day) => {
550 | markup += `
${day}
`
551 | })
552 |
553 | markup += `
554 | ${this.drawDates(dates)}
555 |
`
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 = `
889 | `
890 |
891 | // draw hours dropdown
892 | let hours = Array.from(Array(13).keys())
893 | hours.shift()
894 | markup += hours
895 | .map((item) => {
896 | if(item === hoursVal)
897 | return `${item} `
898 | return `${item} `
899 | }).join(' ')
900 |
901 | markup += `
902 | `
903 |
904 | // draw minutes dropdown
905 | markup += Array.from(Array(60).keys())
906 | .map((item) => {
907 | if(item.toString().length === 1)
908 | item = '0' + item
909 | if(item.toString() === minVal)
910 | return `${item} `
911 | return `${item} `
912 | }).join(' ')
913 |
914 | // AM, PM
915 | markup += `
916 |
917 | AM
918 | PM
919 | `
920 |
921 | markup +=`
922 |
`
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
--------------------------------------------------------------------------------