bootstrap-time 0.1.6-beta → 0.1.8-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -6
- package/dist/css/bootstrap-time.css +3 -27
- package/dist/css/bootstrap-time.min.css +1 -1
- package/dist/js/bootstrap-time.js +61 -43
- package/dist/js/bootstrap-time.min.js +1 -1
- package/package.json +2 -3
- package/src/js/bootstrap-time.js +61 -43
- package/src/scss/bootstrap-time.scss +3 -31
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ dist/ generated, do not edit
|
|
|
18
18
|
examples/ HTML that points at dist
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
`npm run build` compiles `src` into `dist`. Bootstrap
|
|
21
|
+
`npm run build` compiles `src` into `dist`. Bootstrap 5.3.8 or later 5.3 is required. The browser supplies the time field icon. Focus opens the clock and blur closes it.
|
|
22
22
|
|
|
23
23
|
## Usage
|
|
24
24
|
|
|
@@ -31,10 +31,9 @@ npm install bootstrap-time
|
|
|
31
31
|
Or load the published files from jsDelivr:
|
|
32
32
|
|
|
33
33
|
```html
|
|
34
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@
|
|
35
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-
|
|
36
|
-
<
|
|
37
|
-
<script src="https://cdn.jsdelivr.net/npm/bootstrap-time@0.1.6-beta/dist/js/bootstrap-time.min.js"></script>
|
|
34
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css">
|
|
35
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-time@0.1.8-beta/dist/css/bootstrap-time.min.css">
|
|
36
|
+
<script src="https://cdn.jsdelivr.net/npm/bootstrap-time@0.1.8-beta/dist/js/bootstrap-time.min.js"></script>
|
|
38
37
|
```
|
|
39
38
|
|
|
40
39
|
Local builds use the same paths under `dist/`:
|
|
@@ -44,10 +43,30 @@ Local builds use the same paths under `dist/`:
|
|
|
44
43
|
<script src="dist/js/bootstrap-time.min.js"></script>
|
|
45
44
|
```
|
|
46
45
|
|
|
47
|
-
|
|
46
|
+
Add `bs-time` to a time field. The script builds the clock and places it under that field, so it works in an existing Bootstrap form.
|
|
47
|
+
|
|
48
|
+
```html
|
|
49
|
+
<label class="form-label" for="time">Time</label>
|
|
50
|
+
<input type="time" class="form-control bs-time" id="time" step="60">
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Minute selection follows the input `step`, including when `step` changes: `60` allows every minute by clicking between the numbers, `900` enables only 00, 15, 30 and 45. See `examples/bootstrap-time.html`.
|
|
48
54
|
|
|
49
55
|
## Changelog
|
|
50
56
|
|
|
57
|
+
### 0.1.8-beta
|
|
58
|
+
|
|
59
|
+
- Requires Bootstrap 5.3.8 instead of Bootstrap 6.
|
|
60
|
+
- Removed the adorn button. The browser time icon stays, and focus and blur still open and close the clock.
|
|
61
|
+
|
|
62
|
+
### 0.2.0
|
|
63
|
+
|
|
64
|
+
- Stable release. Attach the clock to any field with class `bs-time`.
|
|
65
|
+
|
|
66
|
+
### 0.1.7-beta
|
|
67
|
+
|
|
68
|
+
- Attach the clock to any field with class `bs-time`.
|
|
69
|
+
|
|
51
70
|
### 0.1.6-beta
|
|
52
71
|
|
|
53
72
|
- The example starts on the current time.
|
|
@@ -1,29 +1,5 @@
|
|
|
1
1
|
.clock-picker {
|
|
2
2
|
position: relative;
|
|
3
|
-
width: 20rem;
|
|
4
|
-
}
|
|
5
|
-
.clock-picker input[type=time]::-webkit-calendar-picker-indicator {
|
|
6
|
-
display: none;
|
|
7
|
-
appearance: none;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
.clock-toggle {
|
|
11
|
-
pointer-events: auto;
|
|
12
|
-
width: 2.25rem;
|
|
13
|
-
height: 2.25rem;
|
|
14
|
-
margin: -0.25rem;
|
|
15
|
-
border: 0;
|
|
16
|
-
border-radius: 50%;
|
|
17
|
-
background: transparent;
|
|
18
|
-
color: var(--bs-form-adorn-icon-color, var(--bs-secondary-color));
|
|
19
|
-
}
|
|
20
|
-
.clock-toggle .bi {
|
|
21
|
-
font-size: 1rem;
|
|
22
|
-
line-height: 1;
|
|
23
|
-
}
|
|
24
|
-
.clock-toggle:hover, .clock-toggle:focus-visible {
|
|
25
|
-
background-color: var(--bs-bg-3);
|
|
26
|
-
color: var(--bs-body-color);
|
|
27
3
|
}
|
|
28
4
|
|
|
29
5
|
.clock-widget {
|
|
@@ -34,8 +10,8 @@
|
|
|
34
10
|
width: 20rem;
|
|
35
11
|
margin-top: 0.25rem;
|
|
36
12
|
padding: 0.25rem 0.5rem 1rem;
|
|
37
|
-
background-color: var(--bs-secondary-bg
|
|
38
|
-
color: var(--bs-
|
|
13
|
+
background-color: var(--bs-secondary-bg);
|
|
14
|
+
color: var(--bs-body-color);
|
|
39
15
|
}
|
|
40
16
|
|
|
41
17
|
.clock-arrows {
|
|
@@ -63,7 +39,7 @@
|
|
|
63
39
|
fill: currentColor;
|
|
64
40
|
}
|
|
65
41
|
.btn.clock-arrow:hover, .btn.clock-arrow:focus-visible {
|
|
66
|
-
background-color: var(--bs-bg
|
|
42
|
+
background-color: var(--bs-tertiary-bg);
|
|
67
43
|
color: var(--bs-body-color);
|
|
68
44
|
}
|
|
69
45
|
.btn.clock-arrow:disabled, .btn.clock-arrow:disabled:hover {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
.clock-picker{position:relative
|
|
1
|
+
.clock-picker{position:relative}.clock-widget{position:absolute;top:100%;left:0;z-index:5;width:20rem;margin-top:.25rem;padding:.25rem .5rem 1rem;background-color:var(--bs-secondary-bg);color:var(--bs-body-color)}.clock-arrows{display:flex;justify-content:flex-end;gap:.25rem}.btn.clock-arrow{display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;min-height:0;padding:0;border-radius:50%;background-color:rgba(0,0,0,0);color:var(--bs-body-color);text-decoration:none}.btn.clock-arrow svg{width:1.5rem;height:1.5rem;fill:currentColor}.btn.clock-arrow:hover,.btn.clock-arrow:focus-visible{background-color:var(--bs-tertiary-bg);color:var(--bs-body-color)}.btn.clock-arrow:disabled,.btn.clock-arrow:disabled:hover{background-color:rgba(0,0,0,0);color:var(--bs-secondary-color);opacity:.45}.clock{width:16rem;height:16rem;border-radius:50%;touch-action:none;cursor:pointer}.clock-hand{position:absolute;left:50%;bottom:50%;width:2px;height:var(--hand);transform-origin:center bottom;transform:translateX(-50%) rotate(var(--angle));transition:transform .3s ease,height .3s ease;border-radius:1px;pointer-events:none}.clock-knob{position:absolute;left:50%;top:0;width:2.25rem;height:2.25rem;border-radius:50%;transform:translate(-50%, -50%)}.clock-number{position:absolute;left:50%;top:50%;z-index:1;width:2.25rem;height:2.25rem;margin:-1.125rem;border:0;border-radius:50%;background:rgba(0,0,0,0);color:inherit;transform:rotate(var(--angle)) translateY(calc(var(--radius) * -1)) rotate(calc(var(--angle) * -1))}.clock-number[aria-pressed=true]{color:var(--bs-white, #fff)}.clock-number:disabled{opacity:.35;cursor:default}
|
|
@@ -7,20 +7,48 @@
|
|
|
7
7
|
|
|
8
8
|
var INNER_RADIUS = "4.6rem";
|
|
9
9
|
var OUTER_RADIUS = "6.4rem";
|
|
10
|
+
var LEFT = "M15.41 16.59 10.83 12l4.58-4.59L14 6l-6 6 6 6z";
|
|
11
|
+
var RIGHT = "M8.59 16.59 13.17 12 8.59 7.41 10 6l6 6-6 6z";
|
|
10
12
|
|
|
11
|
-
function
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
function svg(path) {
|
|
14
|
+
return '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="' + path + '"></path></svg>';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function mount(field) {
|
|
18
|
+
if (field.dataset.bsTime === "ready") return;
|
|
19
|
+
field.dataset.bsTime = "ready";
|
|
20
|
+
|
|
21
|
+
var host = field.closest(".form-control") || field;
|
|
22
|
+
var picker = host.closest(".clock-picker");
|
|
23
|
+
if (!picker) {
|
|
24
|
+
picker = document.createElement("div");
|
|
25
|
+
picker.className = "clock-picker";
|
|
26
|
+
host.parentNode.insertBefore(picker, host);
|
|
27
|
+
picker.append(host);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
var widget = picker.querySelector(".clock-widget");
|
|
31
|
+
if (!widget) {
|
|
32
|
+
widget = document.createElement("div");
|
|
33
|
+
widget.className = "clock-widget card bg-body-secondary";
|
|
34
|
+
widget.hidden = true;
|
|
35
|
+
widget.innerHTML =
|
|
36
|
+
'<div class="clock-arrows">' +
|
|
37
|
+
'<button class="btn btn-link clock-arrow clock-hour" type="button" aria-label="Uren">' + svg(LEFT) + "</button>" +
|
|
38
|
+
'<button class="btn btn-link clock-arrow clock-minute" type="button" aria-label="Minuten">' + svg(RIGHT) + "</button>" +
|
|
39
|
+
"</div>" +
|
|
40
|
+
'<div class="clock position-relative mx-auto bg-body-tertiary" role="group" aria-label="Kies een uur"></div>';
|
|
41
|
+
picker.append(widget);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
var clock = widget.querySelector(".clock");
|
|
45
|
+
var hourArrow = widget.querySelector(".clock-hour");
|
|
46
|
+
var minuteArrow = widget.querySelector(".clock-minute");
|
|
47
|
+
if (!clock || !hourArrow || !minuteArrow) return;
|
|
20
48
|
|
|
21
49
|
var now = new Date();
|
|
22
|
-
var initial =
|
|
23
|
-
?
|
|
50
|
+
var initial = field.value
|
|
51
|
+
? field.value.split(":")
|
|
24
52
|
: [now.getHours(), now.getMinutes()];
|
|
25
53
|
var hour = Number(initial[0]) || 0;
|
|
26
54
|
var minute = snapMinute(Number(initial[1]) || 0);
|
|
@@ -40,7 +68,7 @@
|
|
|
40
68
|
}
|
|
41
69
|
|
|
42
70
|
function minuteStep() {
|
|
43
|
-
var step = Number(
|
|
71
|
+
var step = Number(field.getAttribute("step") || field.step);
|
|
44
72
|
if (!step || step < 60) step = 60;
|
|
45
73
|
return Math.max(1, Math.round(step / 60));
|
|
46
74
|
}
|
|
@@ -78,7 +106,7 @@
|
|
|
78
106
|
}
|
|
79
107
|
|
|
80
108
|
function writeInput() {
|
|
81
|
-
|
|
109
|
+
field.value = pad(hour) + ":" + pad(minute);
|
|
82
110
|
}
|
|
83
111
|
|
|
84
112
|
function showMode(nextMode) {
|
|
@@ -131,20 +159,11 @@
|
|
|
131
159
|
}
|
|
132
160
|
|
|
133
161
|
function showWidget() {
|
|
134
|
-
if (!widget) return;
|
|
135
162
|
widget.hidden = false;
|
|
136
|
-
if (clockToggle) clockToggle.setAttribute("aria-pressed", "true");
|
|
137
163
|
}
|
|
138
164
|
|
|
139
165
|
function hideWidget() {
|
|
140
|
-
if (!widget) return;
|
|
141
166
|
widget.hidden = true;
|
|
142
|
-
if (clockToggle) clockToggle.setAttribute("aria-pressed", "false");
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function toggleWidget() {
|
|
146
|
-
if (widget && widget.hidden) showWidget();
|
|
147
|
-
else hideWidget();
|
|
148
167
|
}
|
|
149
168
|
|
|
150
169
|
function valueFromPoint(event) {
|
|
@@ -178,13 +197,11 @@
|
|
|
178
197
|
minuteArrow.addEventListener("click", function () {
|
|
179
198
|
showMode("minute");
|
|
180
199
|
});
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
if (!timeInput.value) return;
|
|
187
|
-
var parts = timeInput.value.split(":");
|
|
200
|
+
field.addEventListener("focus", showWidget);
|
|
201
|
+
field.addEventListener("blur", hideWidget);
|
|
202
|
+
field.addEventListener("input", function () {
|
|
203
|
+
if (!field.value) return;
|
|
204
|
+
var parts = field.value.split(":");
|
|
188
205
|
var nextHour = Number(parts[0]);
|
|
189
206
|
var nextMinute = Number(parts[1]);
|
|
190
207
|
if (nextMinute !== minute) mode = "minute";
|
|
@@ -194,48 +211,49 @@
|
|
|
194
211
|
updateArrows();
|
|
195
212
|
renderClock();
|
|
196
213
|
});
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
event.preventDefault();
|
|
202
|
-
});
|
|
203
|
-
}
|
|
214
|
+
picker.addEventListener("mousedown", function (event) {
|
|
215
|
+
if (event.target === field) return;
|
|
216
|
+
event.preventDefault();
|
|
217
|
+
});
|
|
204
218
|
document.addEventListener("mousedown", function (event) {
|
|
205
|
-
if (
|
|
219
|
+
if (picker.contains(event.target)) return;
|
|
206
220
|
hideWidget();
|
|
207
221
|
});
|
|
208
222
|
|
|
209
223
|
function applyStep() {
|
|
210
224
|
minute = snapMinute(minute);
|
|
211
|
-
|
|
225
|
+
field.value = pad(hour) + ":" + pad(minute);
|
|
212
226
|
renderClock();
|
|
213
227
|
}
|
|
214
228
|
|
|
215
229
|
var stepDescriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "step");
|
|
216
230
|
if (stepDescriptor && stepDescriptor.set) {
|
|
217
|
-
Object.defineProperty(
|
|
231
|
+
Object.defineProperty(field, "step", {
|
|
218
232
|
configurable: true,
|
|
219
233
|
get: function () {
|
|
220
|
-
return stepDescriptor.get.call(
|
|
234
|
+
return stepDescriptor.get.call(field);
|
|
221
235
|
},
|
|
222
236
|
set: function (value) {
|
|
223
|
-
stepDescriptor.set.call(
|
|
237
|
+
stepDescriptor.set.call(field, value);
|
|
224
238
|
applyStep();
|
|
225
239
|
}
|
|
226
240
|
});
|
|
227
241
|
}
|
|
228
|
-
new MutationObserver(applyStep).observe(
|
|
242
|
+
new MutationObserver(applyStep).observe(field, {
|
|
229
243
|
attributes: true,
|
|
230
244
|
attributeFilter: ["step"]
|
|
231
245
|
});
|
|
232
246
|
|
|
233
247
|
updateArrows();
|
|
234
|
-
|
|
248
|
+
if (!field.value) field.value = pad(hour) + ":" + pad(minute);
|
|
235
249
|
renderClock();
|
|
236
250
|
hideWidget();
|
|
237
251
|
}
|
|
238
252
|
|
|
253
|
+
function init() {
|
|
254
|
+
document.querySelectorAll(".bs-time").forEach(mount);
|
|
255
|
+
}
|
|
256
|
+
|
|
239
257
|
if (document.readyState === "loading") {
|
|
240
258
|
document.addEventListener("DOMContentLoaded", init);
|
|
241
259
|
} else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(){"use strict";var e="4.6rem",t="6.4rem";function n(){var
|
|
1
|
+
!function(){"use strict";var e="4.6rem",t="6.4rem";function n(e){return'<svg viewBox="0 0 24 24" aria-hidden="true"><path d="'+e+'"></path></svg>'}function r(r){if("ready"!==r.dataset.bsTime){r.dataset.bsTime="ready";var a=r.closest(".form-control")||r,o=a.closest(".clock-picker");o||((o=document.createElement("div")).className="clock-picker",a.parentNode.insertBefore(o,a),o.append(a));var u=o.querySelector(".clock-widget");u||((u=document.createElement("div")).className="clock-widget card bg-body-secondary",u.hidden=!0,u.innerHTML='<div class="clock-arrows"><button class="btn btn-link clock-arrow clock-hour" type="button" aria-label="Uren">'+n("M15.41 16.59 10.83 12l4.58-4.59L14 6l-6 6 6 6z")+'</button><button class="btn btn-link clock-arrow clock-minute" type="button" aria-label="Minuten">'+n("M8.59 16.59 13.17 12 8.59 7.41 10 6l6 6-6 6z")+'</button></div><div class="clock position-relative mx-auto bg-body-tertiary" role="group" aria-label="Kies een uur"></div>',o.append(u));var i=u.querySelector(".clock"),c=u.querySelector(".clock-hour"),l=u.querySelector(".clock-minute");if(i&&c&&l){var d=new Date,s=r.value?r.value.split(":"):[d.getHours(),d.getMinutes()],m=Number(s[0])||0,b=E(Number(s[1])||0),v="hour",p=150,f=document.createElement("div"),h=document.createElement("span");f.className="clock-hand bg-primary",h.className="clock-knob bg-primary",h.setAttribute("aria-hidden","true"),f.append(h),i.append(f),i.addEventListener("click",function(e){if(!e.target.closest(".clock-number")){var t=function(e){var t=i.getBoundingClientRect(),n=e.clientX-(t.left+t.width/2),r=e.clientY-(t.top+t.height/2),a=(180*Math.atan2(n,-r)/Math.PI+360)%360;if("minute"===v)return E(Math.round(a/6)%60);var o=Math.round(a/30)%12;return Math.hypot(n,r)<.32*t.width?0===o?0:o+12:0===o?12:o}(e);"minute"===v?b=t:(m=t,v="minute"),w(),L(),S()}}),c.addEventListener("click",function(){N("hour")}),l.addEventListener("click",function(){N("minute")}),r.addEventListener("focus",function(){u.hidden=!1}),r.addEventListener("blur",P),r.addEventListener("input",function(){if(r.value){var e=r.value.split(":"),t=Number(e[0]),n=Number(e[1]);n!==b?v="minute":t!==m&&(v="hour"),m=t,b=n,L(),S()}}),o.addEventListener("mousedown",function(e){e.target!==r&&e.preventDefault()}),document.addEventListener("mousedown",function(e){o.contains(e.target)||P()});var g=Object.getOwnPropertyDescriptor(HTMLInputElement.prototype,"step");g&&g.set&&Object.defineProperty(r,"step",{configurable:!0,get:function(){return g.get.call(r)},set:function(e){g.set.call(r,e),q()}}),new MutationObserver(q).observe(r,{attributes:!0,attributeFilter:["step"]}),L(),r.value||(r.value=y(m)+":"+y(b)),S(),P()}}function y(e){return String(e).padStart(2,"0")}function k(){var e=Number(r.getAttribute("step")||r.step);return(!e||e<60)&&(e=60),Math.max(1,Math.round(e/60))}function E(e){var t=k();return(Math.round(e/t)*t%60+60)%60}function M(){p+=((("hour"===v?m%12*30:6*b)-p)%360+540)%360-180,f.style.setProperty("--angle",p+"deg"),f.style.setProperty("--hand","hour"===v&&(0===m||m>12)?e:t)}function L(){c.disabled="hour"===v,l.disabled="minute"===v}function w(){r.value=y(m)+":"+y(b)}function N(e){v!==e&&(v=e,L(),S())}function S(){i.querySelectorAll(".clock-number").forEach(function(e){e.remove()}),i.setAttribute("aria-label","hour"===v?"Kies een uur":"Kies de minuten");var n="hour"===v?[12,1,2,3,4,5,6,7,8,9,10,11,0,13,14,15,16,17,18,19,20,21,22,23]:[0,5,10,15,20,25,30,35,40,45,50,55],r="hour"===v?m:b;M(),n.forEach(function(n,a){var o=document.createElement("button"),u="hour"===v&&a>=12,c=30*("hour"===v?a%12:a),l="minute"===v&&!function(e){return e%k()===0}(n);o.type="button",o.className="clock-number",o.textContent=0===n?"00":String(n),o.dataset.value=String(n),o.disabled=l,o.setAttribute("aria-pressed",l||n!==r?"false":"true"),o.style.setProperty("--angle",c+"deg"),o.style.setProperty("--radius",u?e:t),o.addEventListener("click",function(){o.disabled||("hour"===v?(m=n,v="minute"):b=n,w(),L(),S())}),i.append(o)})}function P(){u.hidden=!0}function q(){b=E(b),r.value=y(m)+":"+y(b),S()}}function a(){document.querySelectorAll(".bs-time").forEach(r)}"loading"===document.readyState?document.addEventListener("DOMContentLoaded",a):a()}();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bootstrap-time",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8-beta",
|
|
4
4
|
"description": "Time picker based on Bootstrap.",
|
|
5
5
|
"author": "M. de Ridder",
|
|
6
6
|
"license": "MIT",
|
|
@@ -60,7 +60,6 @@
|
|
|
60
60
|
"terser": "^5.44.0"
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
|
-
"bootstrap": ">=
|
|
64
|
-
"bootstrap-icons": "^1.13.2"
|
|
63
|
+
"bootstrap": ">=5.3.8 <6"
|
|
65
64
|
}
|
|
66
65
|
}
|
package/src/js/bootstrap-time.js
CHANGED
|
@@ -7,20 +7,48 @@
|
|
|
7
7
|
|
|
8
8
|
var INNER_RADIUS = "4.6rem";
|
|
9
9
|
var OUTER_RADIUS = "6.4rem";
|
|
10
|
+
var LEFT = "M15.41 16.59 10.83 12l4.58-4.59L14 6l-6 6 6 6z";
|
|
11
|
+
var RIGHT = "M8.59 16.59 13.17 12 8.59 7.41 10 6l6 6-6 6z";
|
|
10
12
|
|
|
11
|
-
function
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
function svg(path) {
|
|
14
|
+
return '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="' + path + '"></path></svg>';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function mount(field) {
|
|
18
|
+
if (field.dataset.bsTime === "ready") return;
|
|
19
|
+
field.dataset.bsTime = "ready";
|
|
20
|
+
|
|
21
|
+
var host = field.closest(".form-control") || field;
|
|
22
|
+
var picker = host.closest(".clock-picker");
|
|
23
|
+
if (!picker) {
|
|
24
|
+
picker = document.createElement("div");
|
|
25
|
+
picker.className = "clock-picker";
|
|
26
|
+
host.parentNode.insertBefore(picker, host);
|
|
27
|
+
picker.append(host);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
var widget = picker.querySelector(".clock-widget");
|
|
31
|
+
if (!widget) {
|
|
32
|
+
widget = document.createElement("div");
|
|
33
|
+
widget.className = "clock-widget card bg-body-secondary";
|
|
34
|
+
widget.hidden = true;
|
|
35
|
+
widget.innerHTML =
|
|
36
|
+
'<div class="clock-arrows">' +
|
|
37
|
+
'<button class="btn btn-link clock-arrow clock-hour" type="button" aria-label="Uren">' + svg(LEFT) + "</button>" +
|
|
38
|
+
'<button class="btn btn-link clock-arrow clock-minute" type="button" aria-label="Minuten">' + svg(RIGHT) + "</button>" +
|
|
39
|
+
"</div>" +
|
|
40
|
+
'<div class="clock position-relative mx-auto bg-body-tertiary" role="group" aria-label="Kies een uur"></div>';
|
|
41
|
+
picker.append(widget);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
var clock = widget.querySelector(".clock");
|
|
45
|
+
var hourArrow = widget.querySelector(".clock-hour");
|
|
46
|
+
var minuteArrow = widget.querySelector(".clock-minute");
|
|
47
|
+
if (!clock || !hourArrow || !minuteArrow) return;
|
|
20
48
|
|
|
21
49
|
var now = new Date();
|
|
22
|
-
var initial =
|
|
23
|
-
?
|
|
50
|
+
var initial = field.value
|
|
51
|
+
? field.value.split(":")
|
|
24
52
|
: [now.getHours(), now.getMinutes()];
|
|
25
53
|
var hour = Number(initial[0]) || 0;
|
|
26
54
|
var minute = snapMinute(Number(initial[1]) || 0);
|
|
@@ -40,7 +68,7 @@
|
|
|
40
68
|
}
|
|
41
69
|
|
|
42
70
|
function minuteStep() {
|
|
43
|
-
var step = Number(
|
|
71
|
+
var step = Number(field.getAttribute("step") || field.step);
|
|
44
72
|
if (!step || step < 60) step = 60;
|
|
45
73
|
return Math.max(1, Math.round(step / 60));
|
|
46
74
|
}
|
|
@@ -78,7 +106,7 @@
|
|
|
78
106
|
}
|
|
79
107
|
|
|
80
108
|
function writeInput() {
|
|
81
|
-
|
|
109
|
+
field.value = pad(hour) + ":" + pad(minute);
|
|
82
110
|
}
|
|
83
111
|
|
|
84
112
|
function showMode(nextMode) {
|
|
@@ -131,20 +159,11 @@
|
|
|
131
159
|
}
|
|
132
160
|
|
|
133
161
|
function showWidget() {
|
|
134
|
-
if (!widget) return;
|
|
135
162
|
widget.hidden = false;
|
|
136
|
-
if (clockToggle) clockToggle.setAttribute("aria-pressed", "true");
|
|
137
163
|
}
|
|
138
164
|
|
|
139
165
|
function hideWidget() {
|
|
140
|
-
if (!widget) return;
|
|
141
166
|
widget.hidden = true;
|
|
142
|
-
if (clockToggle) clockToggle.setAttribute("aria-pressed", "false");
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function toggleWidget() {
|
|
146
|
-
if (widget && widget.hidden) showWidget();
|
|
147
|
-
else hideWidget();
|
|
148
167
|
}
|
|
149
168
|
|
|
150
169
|
function valueFromPoint(event) {
|
|
@@ -178,13 +197,11 @@
|
|
|
178
197
|
minuteArrow.addEventListener("click", function () {
|
|
179
198
|
showMode("minute");
|
|
180
199
|
});
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
if (!timeInput.value) return;
|
|
187
|
-
var parts = timeInput.value.split(":");
|
|
200
|
+
field.addEventListener("focus", showWidget);
|
|
201
|
+
field.addEventListener("blur", hideWidget);
|
|
202
|
+
field.addEventListener("input", function () {
|
|
203
|
+
if (!field.value) return;
|
|
204
|
+
var parts = field.value.split(":");
|
|
188
205
|
var nextHour = Number(parts[0]);
|
|
189
206
|
var nextMinute = Number(parts[1]);
|
|
190
207
|
if (nextMinute !== minute) mode = "minute";
|
|
@@ -194,48 +211,49 @@
|
|
|
194
211
|
updateArrows();
|
|
195
212
|
renderClock();
|
|
196
213
|
});
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
event.preventDefault();
|
|
202
|
-
});
|
|
203
|
-
}
|
|
214
|
+
picker.addEventListener("mousedown", function (event) {
|
|
215
|
+
if (event.target === field) return;
|
|
216
|
+
event.preventDefault();
|
|
217
|
+
});
|
|
204
218
|
document.addEventListener("mousedown", function (event) {
|
|
205
|
-
if (
|
|
219
|
+
if (picker.contains(event.target)) return;
|
|
206
220
|
hideWidget();
|
|
207
221
|
});
|
|
208
222
|
|
|
209
223
|
function applyStep() {
|
|
210
224
|
minute = snapMinute(minute);
|
|
211
|
-
|
|
225
|
+
field.value = pad(hour) + ":" + pad(minute);
|
|
212
226
|
renderClock();
|
|
213
227
|
}
|
|
214
228
|
|
|
215
229
|
var stepDescriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "step");
|
|
216
230
|
if (stepDescriptor && stepDescriptor.set) {
|
|
217
|
-
Object.defineProperty(
|
|
231
|
+
Object.defineProperty(field, "step", {
|
|
218
232
|
configurable: true,
|
|
219
233
|
get: function () {
|
|
220
|
-
return stepDescriptor.get.call(
|
|
234
|
+
return stepDescriptor.get.call(field);
|
|
221
235
|
},
|
|
222
236
|
set: function (value) {
|
|
223
|
-
stepDescriptor.set.call(
|
|
237
|
+
stepDescriptor.set.call(field, value);
|
|
224
238
|
applyStep();
|
|
225
239
|
}
|
|
226
240
|
});
|
|
227
241
|
}
|
|
228
|
-
new MutationObserver(applyStep).observe(
|
|
242
|
+
new MutationObserver(applyStep).observe(field, {
|
|
229
243
|
attributes: true,
|
|
230
244
|
attributeFilter: ["step"]
|
|
231
245
|
});
|
|
232
246
|
|
|
233
247
|
updateArrows();
|
|
234
|
-
|
|
248
|
+
if (!field.value) field.value = pad(hour) + ":" + pad(minute);
|
|
235
249
|
renderClock();
|
|
236
250
|
hideWidget();
|
|
237
251
|
}
|
|
238
252
|
|
|
253
|
+
function init() {
|
|
254
|
+
document.querySelectorAll(".bs-time").forEach(mount);
|
|
255
|
+
}
|
|
256
|
+
|
|
239
257
|
if (document.readyState === "loading") {
|
|
240
258
|
document.addEventListener("DOMContentLoaded", init);
|
|
241
259
|
} else {
|
|
@@ -4,34 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
.clock-picker {
|
|
6
6
|
position: relative;
|
|
7
|
-
width: 20rem;
|
|
8
|
-
|
|
9
|
-
input[type="time"]::-webkit-calendar-picker-indicator {
|
|
10
|
-
display: none;
|
|
11
|
-
appearance: none;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
.clock-toggle {
|
|
16
|
-
pointer-events: auto;
|
|
17
|
-
width: 2.25rem;
|
|
18
|
-
height: 2.25rem;
|
|
19
|
-
margin: -0.25rem;
|
|
20
|
-
border: 0;
|
|
21
|
-
border-radius: 50%;
|
|
22
|
-
background: transparent;
|
|
23
|
-
color: var(--bs-form-adorn-icon-color, var(--bs-secondary-color));
|
|
24
|
-
|
|
25
|
-
.bi {
|
|
26
|
-
font-size: 1rem;
|
|
27
|
-
line-height: 1;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
&:hover,
|
|
31
|
-
&:focus-visible {
|
|
32
|
-
background-color: var(--bs-bg-3);
|
|
33
|
-
color: var(--bs-body-color);
|
|
34
|
-
}
|
|
35
7
|
}
|
|
36
8
|
|
|
37
9
|
.clock-widget {
|
|
@@ -42,8 +14,8 @@
|
|
|
42
14
|
width: 20rem;
|
|
43
15
|
margin-top: 0.25rem;
|
|
44
16
|
padding: 0.25rem 0.5rem 1rem;
|
|
45
|
-
background-color: var(--bs-secondary-bg
|
|
46
|
-
color: var(--bs-
|
|
17
|
+
background-color: var(--bs-secondary-bg);
|
|
18
|
+
color: var(--bs-body-color);
|
|
47
19
|
}
|
|
48
20
|
|
|
49
21
|
.clock-arrows {
|
|
@@ -73,7 +45,7 @@
|
|
|
73
45
|
|
|
74
46
|
&:hover,
|
|
75
47
|
&:focus-visible {
|
|
76
|
-
background-color: var(--bs-bg
|
|
48
|
+
background-color: var(--bs-tertiary-bg);
|
|
77
49
|
color: var(--bs-body-color);
|
|
78
50
|
}
|
|
79
51
|
|