input-duration 2.2.27 → 3.0.1
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/.github/workflows/manualTriggersEcho0.yml +1 -1
- package/README.md +41 -68
- package/docs/index.html +260 -171
- package/docs/index.js.html +1 -1
- package/index.js +142 -139
- package/package.json +16 -6
- package/.github/workflows/commitToBSEndToEnd.yml +0 -51
- package/.github/workflows/devVersionAndRelease.yml +0 -66
- package/.github/workflows/npm-bump.yml +0 -47
package/README.md
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
*** Thanks for checking out the Best-README-Template. If you have a suggestion
|
|
5
5
|
*** that would make this better, please fork the repo and create a pull request
|
|
6
6
|
*** or simply open an issue with the tag "enhancement".
|
|
7
|
+
*** Don't forget to give the project a star!
|
|
8
|
+
*** Thanks again! Now go create something AMAZING! :D
|
|
7
9
|
-->
|
|
8
10
|
|
|
9
11
|
|
|
@@ -17,16 +19,6 @@
|
|
|
17
19
|
*** https://www.markdownguide.org/basic-syntax/#reference-style-links
|
|
18
20
|
-->
|
|
19
21
|
|
|
20
|
-
Live BrowserStack Test Results:
|
|
21
|
-
|
|
22
|
-

|
|
23
|
-
|
|
24
|
-

|
|
25
|
-
|
|
26
|
-
- this can be updated with https://shields.io/
|
|
27
|
-
|
|
28
|
-
Remove these:
|
|
29
|
-
|
|
30
22
|
[![npm bundle size][npm-bundle-size]][npm-bundle-size]
|
|
31
23
|
[![Contributors][contributors-shield]][contributors-url]
|
|
32
24
|
[![Forks][forks-shield]][forks-url]
|
|
@@ -47,15 +39,22 @@ Remove these:
|
|
|
47
39
|
|
|
48
40
|
|
|
49
41
|
<a href="https://github.com/StephanLuis/input-duration">
|
|
50
|
-
<h3 align="center">Input-Duration --
|
|
42
|
+
<h3 align="center">Input-Duration -- JavaScript duration input</h3> <img src="readme/logo.svg" alt="Logo" width="90" height="90">
|
|
51
43
|
</a>
|
|
52
44
|
|
|
53
45
|
|
|
54
46
|
|
|
55
|
-
<p align="center">A
|
|
47
|
+
<p align="center">A compact duration input with a fixed, locale-independent display for hours, minutes, seconds, and milliseconds.</p>
|
|
56
48
|
</div>
|
|
57
49
|
|
|
58
|
-
|
|
50
|
+
Use `input-duration` when users need to enter a duration rather than a time of day: for example, a countdown, elapsed-time limit, or media offset. Its displayed value uses `HH:mm:ss.SSS` on every locale, without a locale-specific AM/PM presentation, and supports durations greater than 24 hours (currently up to 99 hours) with millisecond values, such as `30:00:00.125`.
|
|
51
|
+
|
|
52
|
+
HTML's built-in `<input type="time">` is for choosing a time of day, not entering elapsed time. HTML does not provide a native duration input with a fixed `HH:mm:ss.SSS` format or support for values over 24 hours; this web component fills that gap.
|
|
53
|
+
|
|
54
|
+
The component supplies its own segmented layout instead of the browser's native time-picker UI, so the displayed format does not change with browser or locale. It is built from native number inputs, however, so details such as the on-screen keyboard and interaction can still vary by device and browser; this is consistency of the value's presentation, not a guarantee of pixel-identical rendering. Milliseconds can be entered as three digits; the input's step controls increment in 10 ms intervals.
|
|
55
|
+
|
|
56
|
+
The control's styles are scoped inside its Shadow DOM, so global styles and resets from Tailwind or other CSS libraries do not leak into its internal layout. The control inherits its font and text color from its surrounding page.
|
|
57
|
+
<br>
|
|
59
58
|
<p>
|
|
60
59
|
<div>
|
|
61
60
|
</div>
|
|
@@ -65,6 +64,8 @@ Remove these:
|
|
|
65
64
|
</a> ·
|
|
66
65
|
<a href="https://6mxpg2.csb.app/" target="_blank">Demo</a>
|
|
67
66
|
·
|
|
67
|
+
<a href="https://stephanluis.github.io/input-duration/" target="_blank">Live demo</a>
|
|
68
|
+
·
|
|
68
69
|
<a href="https://stephanluis.github.io/input-duration/" target="_blank">Docs</a>
|
|
69
70
|
·
|
|
70
71
|
<a href="https://github.com/StephanLuis/input-duration/issues">Bugs</a>
|
|
@@ -72,17 +73,28 @@ Remove these:
|
|
|
72
73
|
<a href="https://github.com/StephanLuis/input-duration/issues">Request Feature</a>
|
|
73
74
|
</p>
|
|
74
75
|
</div>
|
|
75
|
-
Ok, what about mobile?? Yep, input-duration works on all popular operating system / browser combinations.
|
|
76
|
-
<br/>
|
|
77
76
|
</div>
|
|
78
77
|
<br/>
|
|
79
78
|
|
|
80
|
-
<h2>
|
|
79
|
+
<h2>Fixed-format duration input</h2>
|
|
80
|
+
|
|
81
|
+
`input-duration` is intended for touch and keyboard use. The HTML structure and displayed field order are controlled by the component; device-specific input and keyboard behavior remains native to the browser.
|
|
81
82
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
<h2>Bob is rescued by INPUT-DURATION!</h2>
|
|
84
|
+
|
|
85
|
+
The goal is a small JavaScript duration input that gives countdowns and elapsed-time entry a predictable displayed format across browser and locale settings, while retaining native numeric inputs for editing.
|
|
86
|
+
|
|
87
|
+
<i>Does this lose any functionality?</i> No! `document.querySelector('#bob').value` has a getter and setter, so values can be set and retrieved from JavaScript or the HTML attribute.
|
|
88
|
+
|
|
89
|
+
<img src="readme/safariBad.png" alt="Example comparing a native time input with input-duration" width="80%"/>
|
|
90
|
+
|
|
91
|
+
Native time inputs are useful when the user is choosing a time on a clock. A duration is different: `30:00:00.125` means thirty hours, not 6 AM the next day. Keeping those concepts separate avoids date, timezone, and 12/24-hour display concerns when collecting a duration.
|
|
92
|
+
|
|
93
|
+
Here's why:
|
|
94
|
+
* Enter durations independently of a calendar date or time of day.
|
|
95
|
+
* Keep a fixed `HH:mm:ss.SSS` display regardless of locale-specific clock conventions.
|
|
96
|
+
* Represent durations beyond 24 hours (up to 99 hours in the current implementation).
|
|
97
|
+
* Read and set the value from JavaScript using the component's `.value` property.
|
|
86
98
|
|
|
87
99
|
<!-- TABLE OF CONTENTS -->
|
|
88
100
|
<details>
|
|
@@ -103,7 +115,7 @@ Remove these:
|
|
|
103
115
|
</li>
|
|
104
116
|
<li><a href="#usage">Usage</a></li>
|
|
105
117
|
<li><a href="#roadmap">Roadmap</a></li>
|
|
106
|
-
<li><a href="#
|
|
118
|
+
<li><a href="#cross-browser-testing">Cross-browser testing</a></li>
|
|
107
119
|
<li><a href="#contributing">Contributing</a></li>
|
|
108
120
|
<li><a href="#license">License</a></li>
|
|
109
121
|
<li><a href="#contact">Contact</a></li>
|
|
@@ -115,50 +127,16 @@ Remove these:
|
|
|
115
127
|
|
|
116
128
|
<!-- ABOUT THE PROJECT -->
|
|
117
129
|
## About The Project
|
|
118
|
-
|
|
130
|
+
|
|
131
|
+
HTML's `<input type="time">` represents a time of day. Browsers may localize its visible control (for example, showing a 12-hour clock with AM/PM), even though its value is standardized. It also cannot represent a duration longer than a day.
|
|
132
|
+
|
|
133
|
+
`input-duration` is for duration values, not appointments or clock times. Its separate numeric fields present hours, minutes, seconds, and milliseconds in a fixed `HH:mm:ss.SSS` format. This avoids locale-dependent time-of-day presentation while allowing durations beyond 24 hours and millisecond values in a compact control.
|
|
119
134
|
|
|
120
135
|
<!-- [![Product Name Screen Shot][product-screenshot]](https://example.com) -->
|
|
121
136
|
|
|
122
137
|
<img src="readme/codeDrawing.png" alt="drawing" width="60%"/>
|
|
123
138
|
|
|
124
139
|
<!-- [![HTML Screen Shot][html-screenshot]](https://example.com) -->
|
|
125
|
-
*note input-duration needs closing tag!
|
|
126
|
-
|
|
127
|
-
<h3> Bob is rescued by INPUT-DURATION! </h3>
|
|
128
|
-
|
|
129
|
-
The objective is a minimised javascript plugin that reproduces the behaviour of the input type=time on Chrome. This way at least two of the major browsers are supported, Safari and Chrome, on desktop and mobile operating systems.
|
|
130
|
-
|
|
131
|
-
<i>Does this loose any functionality?</i> No! document.querySelector('#bob').value has a getter and setter! So values can be set and retrieved by ID or attribute in HTML.
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
<img src="readme/safariBad.png" alt="drawing" width="80%"/>
|
|
136
|
-
<!-- [![Safari Screen Shot][safari-screenshot]](https://example.com) -->
|
|
137
|
-
|
|
138
|
-
Yes! It seems CRAZY in 2022 that there is not a native 'time only' input for HTML. What I mean is there is no user input control for time rendered independantly of date or time of day. Yea, crazy, but now input-duration is a javascript plugin that creates a UX input control for a value of time simply as hours, minutes, seconds --<b>only</b>! <br> Ever thought, why is it difficult to 'code' a countdown timer? Why can't it be done with one control? Just look at google's timer and other coundown timers! All use multiple inputs, usually designed for integers.
|
|
139
|
-
|
|
140
|
-
The very worst is Safari on desktop and mobile, which undermine any input type=time coding efforts and update the input based on OS settings! Shouldn't a user be able to 'scientifically' specify a period of time with one control? <br> Maybe it's just me, but the chrome / google timer is 14 separate elements ... those guys must be paid by the hour. The closest HTML5 input type- time when configured with UX for hours to millisecs is very finicky and is rendered differently on Chrome than Safari. <b>Mobile</b> is different from laptop<br> ... so I've simplified that!
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
There were a few plugins that remediated the lack of continuity, but even those controls treated time as a date (ex 24hr max). So it seems the current state is the most relable UX is multi input type number. The worst example is the Google countdown timer. That way is wrong because time is a basic unit that should be separate from calendar complexities. That got me thinking, why isn't there an input control for it implemented across browsers?? I needed one, so coded input-duration.
|
|
149
|
-
|
|
150
|
-
Here's why:
|
|
151
|
-
* Time is hours minutes and seconds (and millisecs) and needn't be associated with part of a day or a date
|
|
152
|
-
* The date association breaks UX and is varied with browser implementation
|
|
153
|
-
* I found no other crossbrowser solution
|
|
154
|
-
* I thought this would be a great open source project
|
|
155
|
-
* End use of number inputs (standard hack) for use with time
|
|
156
|
-
|
|
157
|
-
Of course, this is functional but in it's infancy. Maybe, with some contribution this is a project that can inspire change to the HTML spec.
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
Feel free to vote for WhatWG inclusion of a into the HTML spec! (link comming soon)
|
|
161
|
-
|
|
162
140
|
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
163
141
|
|
|
164
142
|
|
|
@@ -279,14 +257,9 @@ See the [open issues](https://github.com/StephanLuis/input-duration/issues) for
|
|
|
279
257
|
<p align="right">(<a href="#top">back to top</a>)</p>
|
|
280
258
|
|
|
281
259
|
<!-- TESTSTATUS -->
|
|
282
|
-
##
|
|
260
|
+
## Cross-browser testing
|
|
283
261
|
|
|
284
|
-
|
|
285
|
-

|
|
286
|
-

|
|
287
|
-

|
|
288
|
-

|
|
289
|
-

|
|
262
|
+
The browser and device results linked below are historical and should not be treated as verification against current browser versions. The local regression suite checks component behavior, but current cross-browser rendering and interaction still need to be tested.
|
|
290
263
|
|
|
291
264
|
[Tests & Live Status](https://github.com/StephanLuis/BrowserStackSelenium/blob/main/input-duration/README.md)
|
|
292
265
|
|
|
@@ -296,6 +269,8 @@ See the [open issues](https://github.com/StephanLuis/input-duration/issues) for
|
|
|
296
269
|
|
|
297
270
|
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.
|
|
298
271
|
|
|
272
|
+
Run the local regression tests with `npm test`.
|
|
273
|
+
|
|
299
274
|
If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement".
|
|
300
275
|
Don't forget to give the project a star! Thanks again!
|
|
301
276
|
|
|
@@ -350,8 +325,6 @@ Resources I've found helpful and would like to give credit to:
|
|
|
350
325
|
<!-- https://www.markdownguide.org/basic-syntax/#reference-style-links -->
|
|
351
326
|
|
|
352
327
|
|
|
353
|
-
|
|
354
|
-
|
|
355
328
|
[contributors-shield]: https://img.shields.io/github/contributors/StephanLuis/input-duration?style=for-the-badge
|
|
356
329
|
[contributors-url]: https://github.com/StephanLuis/input-duration/graphs/contributors
|
|
357
330
|
[forks-shield]: https://img.shields.io/github/forks/StephanLuis/input-duration?style=for-the-badge
|
package/docs/index.html
CHANGED
|
@@ -1,177 +1,266 @@
|
|
|
1
|
-
<!
|
|
1
|
+
<!doctype html>
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8">
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
<
|
|
8
|
-
<
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<meta name="description" content="A tiny demo of why a time-of-day input is not the same thing as a duration input.">
|
|
7
|
+
<title>Time is not a duration — input-duration</title>
|
|
8
|
+
<style>
|
|
9
|
+
:root {
|
|
10
|
+
color-scheme: light;
|
|
11
|
+
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
12
|
+
color: #17201c;
|
|
13
|
+
background: #f5f7f3;
|
|
14
|
+
font-synthesis: none;
|
|
15
|
+
text-rendering: optimizeLegibility;
|
|
16
|
+
--green: #176b4a;
|
|
17
|
+
--muted: #64716a;
|
|
18
|
+
--line: #dce4dd;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
* {
|
|
22
|
+
box-sizing: border-box;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
body {
|
|
26
|
+
min-width: 320px;
|
|
27
|
+
margin: 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
main {
|
|
31
|
+
width: min(100% - 40px, 960px);
|
|
32
|
+
margin: 0 auto;
|
|
33
|
+
padding: 48px 0 32px;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
header {
|
|
37
|
+
max-width: 720px;
|
|
38
|
+
margin: 0 auto 34px;
|
|
39
|
+
text-align: center;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.eyebrow {
|
|
43
|
+
margin: 0 0 14px;
|
|
44
|
+
color: var(--green);
|
|
45
|
+
font-size: .78rem;
|
|
46
|
+
font-weight: 750;
|
|
47
|
+
letter-spacing: .12em;
|
|
48
|
+
text-transform: uppercase;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
h1 {
|
|
52
|
+
margin: 0;
|
|
53
|
+
font-size: clamp(2.35rem, 7vw, 4.5rem);
|
|
54
|
+
letter-spacing: -.065em;
|
|
55
|
+
line-height: 1.02;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.intro {
|
|
59
|
+
max-width: 610px;
|
|
60
|
+
margin: 20px auto 0;
|
|
61
|
+
color: var(--muted);
|
|
62
|
+
font-size: 1.08rem;
|
|
63
|
+
line-height: 1.6;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.scenario {
|
|
67
|
+
display: inline-block;
|
|
68
|
+
margin-top: 20px;
|
|
69
|
+
padding: 10px 15px;
|
|
70
|
+
border: 1px solid #d6e8dc;
|
|
71
|
+
border-radius: 999px;
|
|
72
|
+
background: #eaf4ed;
|
|
73
|
+
color: #25513b;
|
|
74
|
+
font-size: .95rem;
|
|
75
|
+
font-weight: 650;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.comparison {
|
|
79
|
+
display: grid;
|
|
80
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
81
|
+
gap: 18px;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
article {
|
|
85
|
+
display: flex;
|
|
86
|
+
min-height: 300px;
|
|
87
|
+
flex-direction: column;
|
|
88
|
+
align-items: flex-start;
|
|
89
|
+
padding: 26px;
|
|
90
|
+
border: 1px solid var(--line);
|
|
91
|
+
border-radius: 18px;
|
|
92
|
+
background: #fff;
|
|
93
|
+
box-shadow: 0 12px 32px rgb(23 32 28 / 5%);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
article.duration {
|
|
97
|
+
border-color: #b7d9c4;
|
|
98
|
+
box-shadow: 0 12px 32px rgb(23 107 74 / 9%);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.card-label {
|
|
102
|
+
margin: 0 0 8px;
|
|
103
|
+
color: var(--muted);
|
|
104
|
+
font-size: .76rem;
|
|
105
|
+
font-weight: 750;
|
|
106
|
+
letter-spacing: .1em;
|
|
107
|
+
text-transform: uppercase;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
h2 {
|
|
111
|
+
margin: 0;
|
|
112
|
+
font-size: 1.45rem;
|
|
113
|
+
letter-spacing: -.03em;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.card-copy {
|
|
117
|
+
min-height: 52px;
|
|
118
|
+
margin: 10px 0 20px;
|
|
119
|
+
color: var(--muted);
|
|
120
|
+
line-height: 1.5;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.field {
|
|
124
|
+
display: flex;
|
|
125
|
+
min-height: 54px;
|
|
126
|
+
align-items: center;
|
|
127
|
+
margin: 0 0 18px;
|
|
128
|
+
padding: 8px 12px;
|
|
129
|
+
border: 1px solid #bdc9c0;
|
|
130
|
+
border-radius: 10px;
|
|
131
|
+
background: #fff;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
input[type="time"] {
|
|
135
|
+
width: 100%;
|
|
136
|
+
border: 0;
|
|
137
|
+
background: transparent;
|
|
138
|
+
color: inherit;
|
|
139
|
+
font: inherit;
|
|
140
|
+
font-size: 1.2rem;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
input[type="time"]:focus-visible {
|
|
144
|
+
outline: 2px solid var(--green);
|
|
145
|
+
outline-offset: 3px;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
input-duration {
|
|
149
|
+
display: block;
|
|
150
|
+
max-width: 100%;
|
|
151
|
+
font-size: 1.2rem;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.result {
|
|
155
|
+
margin: auto 0 0;
|
|
156
|
+
color: #33463a;
|
|
157
|
+
font-size: .94rem;
|
|
158
|
+
line-height: 1.5;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.result strong {
|
|
162
|
+
color: #a23e2c;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.duration .result strong {
|
|
166
|
+
color: var(--green);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
footer {
|
|
170
|
+
margin-top: 28px;
|
|
171
|
+
color: var(--muted);
|
|
172
|
+
font-size: .92rem;
|
|
173
|
+
line-height: 1.6;
|
|
174
|
+
text-align: center;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
a {
|
|
178
|
+
color: var(--green);
|
|
179
|
+
font-weight: 650;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
@media (max-width: 650px) {
|
|
183
|
+
main {
|
|
184
|
+
width: min(100% - 28px, 480px);
|
|
185
|
+
padding-top: 34px;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.comparison {
|
|
189
|
+
grid-template-columns: 1fr;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
article {
|
|
193
|
+
min-height: 270px;
|
|
194
|
+
padding: 22px;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
</style>
|
|
14
198
|
</head>
|
|
15
|
-
|
|
16
199
|
<body>
|
|
17
|
-
|
|
18
|
-
<
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
<dt class="tag-author">Author:</dt>
|
|
92
|
-
<dd class="tag-author">
|
|
93
|
-
<ul>
|
|
94
|
-
<li>Stephan Luis</li>
|
|
95
|
-
</ul>
|
|
96
|
-
</dd>
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
<dt class="tag-copyright">Copyright:</dt>
|
|
101
|
-
<dd class="tag-copyright"><ul class="dummy"><li>MIT License, Copyright (c) 2022</li></ul></dd>
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
<dt class="tag-source">Source:</dt>
|
|
110
|
-
<dd class="tag-source"><ul class="dummy"><li>
|
|
111
|
-
<a href="index.js.html">index.js</a>, <a href="index.js.html#line1">line 1</a>
|
|
112
|
-
</li></ul></dd>
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
<dt class="tag-see">See:</dt>
|
|
119
|
-
<dd class="tag-see">
|
|
120
|
-
<ul>
|
|
121
|
-
<li><a href="https://www.npmjs.com/package/input-duration">NPM input-duration</a></li>
|
|
122
|
-
|
|
123
|
-
<li><a href="https://github.com/StephanLuis/input-duration">GitHub input-duration</a></li>
|
|
124
|
-
</ul>
|
|
125
|
-
</dd>
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
</dl>
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
</div>
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
</article>
|
|
156
|
-
|
|
157
|
-
</section>
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
</div>
|
|
163
|
-
|
|
164
|
-
<nav>
|
|
165
|
-
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="InputDuration.html">InputDuration</a></li></ul>
|
|
166
|
-
</nav>
|
|
167
|
-
|
|
168
|
-
<br class="clear">
|
|
169
|
-
|
|
170
|
-
<footer>
|
|
171
|
-
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a> on Fri Sep 29 2023 11:02:59 GMT+0000 (GMT)
|
|
172
|
-
</footer>
|
|
173
|
-
|
|
174
|
-
<script> prettyPrint(); </script>
|
|
175
|
-
<script src="scripts/linenumber.js"> </script>
|
|
200
|
+
<main>
|
|
201
|
+
<header>
|
|
202
|
+
<p class="eyebrow">A small input, a very different question</p>
|
|
203
|
+
<h1>Time is not a duration.</h1>
|
|
204
|
+
<p class="intro">You need to set a maintenance window. It’ll take 30 hours. Surely a time picker can handle that?</p>
|
|
205
|
+
<p class="scenario">The task: run for 30 hours</p>
|
|
206
|
+
</header>
|
|
207
|
+
|
|
208
|
+
<section class="comparison" aria-label="Compare a time-of-day input with a duration input">
|
|
209
|
+
<article>
|
|
210
|
+
<p class="card-label">The time picker</p>
|
|
211
|
+
<h2>“What time is it?”</h2>
|
|
212
|
+
<p class="card-copy">HTML's built-in time input asks for a time of day—not an elapsed duration. The clock has other plans.</p>
|
|
213
|
+
<label class="field" for="clock-time">
|
|
214
|
+
<input id="clock-time" type="time" value="06:00" step="60">
|
|
215
|
+
</label>
|
|
216
|
+
<p class="result" id="clock-result" aria-live="polite">06:00 is a time of day—not how long the task takes.</p>
|
|
217
|
+
</article>
|
|
218
|
+
|
|
219
|
+
<article class="duration">
|
|
220
|
+
<p class="card-label">The duration input</p>
|
|
221
|
+
<h2>“How long does it take?”</h2>
|
|
222
|
+
<p class="card-copy">HTML has no built-in duration input. This one handles 30 hours, with a fixed HH:mm:ss.SSS display.</p>
|
|
223
|
+
<input-duration id="duration" role="group" aria-label="Duration in hours, minutes, seconds, and milliseconds" value="30:00:00.000"></input-duration>
|
|
224
|
+
<p class="result" id="duration-result" aria-live="polite"><strong>30:00:00.000</strong> — a 30-hour duration, exactly as requested.</p>
|
|
225
|
+
</article>
|
|
226
|
+
</section>
|
|
227
|
+
|
|
228
|
+
<footer>
|
|
229
|
+
Native HTML time inputs are for times of day; HTML has no built-in control for entering a duration like 30:00:00.000.
|
|
230
|
+
That's the gap <a href="InputDuration.html">input-duration</a> fills. Read the
|
|
231
|
+
<a href="https://github.com/StephanLuis/input-duration">source on GitHub</a>.
|
|
232
|
+
</footer>
|
|
233
|
+
</main>
|
|
234
|
+
<script type="module">
|
|
235
|
+
import '../index.js';
|
|
236
|
+
|
|
237
|
+
const clockInput = document.querySelector('#clock-time');
|
|
238
|
+
const clockResult = document.querySelector('#clock-result');
|
|
239
|
+
const durationInput = document.querySelector('#duration');
|
|
240
|
+
const durationResult = document.querySelector('#duration-result');
|
|
241
|
+
|
|
242
|
+
clockInput.addEventListener('input', () => {
|
|
243
|
+
clockResult.textContent = clockInput.value
|
|
244
|
+
? `${clockInput.value} is a time of day—not how long the task takes.`
|
|
245
|
+
: 'No time picked. Still not a duration.';
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
const updateDurationResult = () => {
|
|
249
|
+
const value = durationInput.value;
|
|
250
|
+
if (/^[0-9]{2}:[0-5][0-9]:[0-5][0-9]\.[0-9]{3}$/.test(value)) {
|
|
251
|
+
const formattedValue = document.createElement('strong');
|
|
252
|
+
formattedValue.textContent = value;
|
|
253
|
+
durationResult.replaceChildren(
|
|
254
|
+
formattedValue,
|
|
255
|
+
document.createTextNode(' — a duration, exactly as requested.')
|
|
256
|
+
);
|
|
257
|
+
} else {
|
|
258
|
+
durationResult.textContent = 'Keep going—finish entering the duration.';
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
durationInput.addEventListener('input', updateDurationResult);
|
|
263
|
+
durationInput.addEventListener('change', updateDurationResult);
|
|
264
|
+
</script>
|
|
176
265
|
</body>
|
|
177
|
-
</html>
|
|
266
|
+
</html>
|
package/docs/index.js.html
CHANGED
package/index.js
CHANGED
|
@@ -6,12 +6,11 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @fileoverview INPUT-DURATION
|
|
8
8
|
* @file INPUT-DURATION
|
|
9
|
-
* @author Stephan Luis
|
|
9
|
+
* @author Stephan Luis
|
|
10
10
|
* @see <a href="https://www.npmjs.com/package/input-duration">NPM input-duration</a>
|
|
11
11
|
* @see <a href="https://github.com/StephanLuis/input-duration">GitHub input-duration</a>
|
|
12
|
-
* @copyright MIT License, Copyright (c)
|
|
13
|
-
* @version 2.2.
|
|
14
|
-
* fake update to check CI , 16 Dec, 6x
|
|
12
|
+
* @copyright MIT License, Copyright (c) 2022
|
|
13
|
+
* @version 2.2.8 (release)
|
|
15
14
|
*/
|
|
16
15
|
|
|
17
16
|
|
|
@@ -23,21 +22,35 @@
|
|
|
23
22
|
*/
|
|
24
23
|
|
|
25
24
|
class InputDuration extends HTMLElement {
|
|
25
|
+
static get observedAttributes() {
|
|
26
|
+
return ['value'];
|
|
27
|
+
}
|
|
28
|
+
|
|
26
29
|
constructor() {
|
|
27
30
|
|
|
28
31
|
super();
|
|
29
32
|
|
|
30
33
|
this.myElement = this.attachShadow({ mode: 'open' });
|
|
31
34
|
|
|
32
|
-
// needed for setting inputs when value attribute is added to chronlyHMS
|
|
33
|
-
// <chronly-hms id="bobPrepop" value="99:09:09.999"></chronly-hms>
|
|
34
|
-
|
|
35
|
-
this.value = this.getAttribute('value');
|
|
36
|
-
|
|
37
35
|
this.boot();
|
|
38
36
|
|
|
39
37
|
} // end constructor
|
|
40
38
|
|
|
39
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
40
|
+
|
|
41
|
+
if (name !== 'value' || oldValue === newValue) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (newValue === null) {
|
|
46
|
+
this.resetInputs();
|
|
47
|
+
} else if (this.isValidValue(newValue)) {
|
|
48
|
+
this.setInputValues(newValue);
|
|
49
|
+
} else {
|
|
50
|
+
this.warnInvalidValue(newValue);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
41
54
|
|
|
42
55
|
/**
|
|
43
56
|
* get the input-duration value, pulls values from each input
|
|
@@ -75,60 +88,52 @@ class InputDuration extends HTMLElement {
|
|
|
75
88
|
set value(val) {
|
|
76
89
|
|
|
77
90
|
// for setting the value in js (like document.querySelector("#bobPrepop").value = "05:05:05.005")
|
|
78
|
-
if (val) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (/(^[0-9][0-9]):([0-5][0-9]):([0-5][0-9])\.([0-9][0-9][0-9]$)/.exec(val)) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
// split val
|
|
88
|
-
|
|
89
|
-
var timeArray = val.split(/[.:]+/);
|
|
90
|
-
|
|
91
|
-
console.log('time array is ' + timeArray[0] + ':' + timeArray[1] + ':' + timeArray[2] + ':' + timeArray[3]);
|
|
92
|
-
|
|
93
|
-
console.log('this.id = ' + this.id);
|
|
94
|
-
|
|
95
|
-
setTimeout(() => {
|
|
96
|
-
|
|
97
|
-
this.myElement.querySelector('input[name="startHours"]').value = timeArray[0];
|
|
98
|
-
this.myElement.querySelector('input[name="startMinutes"]').value = timeArray[1];
|
|
99
|
-
this.myElement.querySelector('input[name="startSeconds"]').value = timeArray[2];
|
|
100
|
-
this.myElement.querySelector('input[name="startMilliSecs"]').value = timeArray[3];
|
|
101
|
-
|
|
102
|
-
}, 0);
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
this.setAttribute('value', val);
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
else {
|
|
91
|
+
if (!val) {
|
|
92
|
+
this.resetInputs();
|
|
93
|
+
this.removeAttribute('value');
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
110
96
|
|
|
111
|
-
|
|
97
|
+
if (typeof val !== 'string' || !this.isValidValue(val)) {
|
|
98
|
+
this.warnInvalidValue(val);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
112
101
|
|
|
113
|
-
|
|
102
|
+
this.setInputValues(val);
|
|
114
103
|
|
|
115
|
-
|
|
116
|
-
|
|
104
|
+
if (this.getAttribute('value') !== val) {
|
|
105
|
+
this.setAttribute('value', val);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
117
108
|
|
|
118
|
-
|
|
109
|
+
isValidValue(val) {
|
|
110
|
+
return typeof val === 'string' &&
|
|
111
|
+
/^[0-9]{2}:[0-5][0-9]:[0-5][0-9]\.[0-9]{3}$/.test(val);
|
|
112
|
+
}
|
|
119
113
|
|
|
120
|
-
|
|
114
|
+
setInputValues(val) {
|
|
115
|
+
const timeArray = val.split(/[.:]+/);
|
|
116
|
+
const inputNames = ['startHours', 'startMinutes', 'startSeconds', 'startMilliSecs'];
|
|
121
117
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
118
|
+
inputNames.forEach((name, index) => {
|
|
119
|
+
const input = this.myElement.querySelector(`input[name="${name}"]`);
|
|
120
|
+
input.value = timeArray[index];
|
|
121
|
+
input.oldValue = input.value;
|
|
122
|
+
});
|
|
123
|
+
}
|
|
126
124
|
|
|
127
|
-
|
|
125
|
+
resetInputs() {
|
|
126
|
+
const defaults = ['00', '00', '00', '000'];
|
|
127
|
+
const inputs = this.myElement.querySelectorAll('.timeCase input');
|
|
128
128
|
|
|
129
|
-
|
|
129
|
+
inputs.forEach((input, index) => {
|
|
130
|
+
input.value = defaults[index];
|
|
131
|
+
input.oldValue = input.value;
|
|
132
|
+
});
|
|
133
|
+
}
|
|
130
134
|
|
|
131
|
-
|
|
135
|
+
warnInvalidValue(val) {
|
|
136
|
+
console.warn(`The specified value ${val} does not conform to the required format. The format is "HH:mm:ss.SSS" where HH is 00-99, mm is 00-59, ss is 00-59, and SSS is 000-999.`);
|
|
132
137
|
}
|
|
133
138
|
|
|
134
139
|
|
|
@@ -162,10 +167,6 @@ class InputDuration extends HTMLElement {
|
|
|
162
167
|
|
|
163
168
|
addArrowKeyInput() {
|
|
164
169
|
|
|
165
|
-
console.log('1 this: ' + this);
|
|
166
|
-
console.log('1 this.myElement: ' + this.myElement);
|
|
167
|
-
console.log('1 this.myElement active: ' + this.myElement);
|
|
168
|
-
|
|
169
170
|
var mE = this.myElement;
|
|
170
171
|
|
|
171
172
|
// Left and Right arrow key toggle between HMSmS
|
|
@@ -255,82 +256,89 @@ class InputDuration extends HTMLElement {
|
|
|
255
256
|
</svg>
|
|
256
257
|
</div>
|
|
257
258
|
<style>
|
|
258
|
-
|
|
259
|
-
|
|
259
|
+
:host {
|
|
260
|
+
display: inline-block;
|
|
261
|
+
color: inherit;
|
|
262
|
+
font: inherit;
|
|
263
|
+
vertical-align: middle;
|
|
260
264
|
}
|
|
261
265
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
266
|
+
.timeCase {
|
|
267
|
+
display: inline-flex;
|
|
268
|
+
align-items: center;
|
|
269
|
+
gap: 0.08em;
|
|
270
|
+
max-width: 100%;
|
|
271
|
+
padding: 0.4em 0.55em;
|
|
272
|
+
border: 1px solid #9aa6b2;
|
|
273
|
+
border-radius: 0.4em;
|
|
274
|
+
background: transparent;
|
|
275
|
+
color: inherit;
|
|
276
|
+
font-variant-numeric: tabular-nums;
|
|
277
|
+
line-height: 1.4;
|
|
278
|
+
white-space: nowrap;
|
|
271
279
|
}
|
|
272
280
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
width: 15px;
|
|
278
|
-
padding-top:1px;
|
|
281
|
+
.timeCase:focus-within {
|
|
282
|
+
border-color: #176b4a;
|
|
283
|
+
outline: 3px solid #176b4a;
|
|
284
|
+
outline-offset: 2px;
|
|
279
285
|
}
|
|
280
286
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
287
|
+
.timeCase input {
|
|
288
|
+
box-sizing: content-box;
|
|
289
|
+
width: 2ch;
|
|
290
|
+
min-width: 2ch;
|
|
291
|
+
margin: 0;
|
|
292
|
+
padding: 0;
|
|
293
|
+
border: 0;
|
|
294
|
+
outline: 0;
|
|
295
|
+
background: transparent;
|
|
296
|
+
color: inherit;
|
|
297
|
+
font: inherit;
|
|
298
|
+
font-variant-numeric: tabular-nums;
|
|
299
|
+
text-align: center;
|
|
300
|
+
caret-color: transparent;
|
|
301
|
+
appearance: textfield;
|
|
284
302
|
}
|
|
285
303
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
/* Chrome, Safari, Edge, Opera */
|
|
290
|
-
|
|
291
|
-
input::-webkit-outer-spin-button,
|
|
292
|
-
input::-webkit-inner-spin-button {
|
|
293
|
-
-webkit-appearance: none;
|
|
294
|
-
margin: 0;
|
|
304
|
+
.timeCase input.D3 {
|
|
305
|
+
width: 3ch;
|
|
306
|
+
min-width: 3ch;
|
|
295
307
|
}
|
|
296
308
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
/* -moz-appearance: textfield; */
|
|
302
|
-
-moz-appearance: textarea;
|
|
303
|
-
-webkit-appearance: textarea;
|
|
309
|
+
.timeCase input::-webkit-outer-spin-button,
|
|
310
|
+
.timeCase input::-webkit-inner-spin-button {
|
|
311
|
+
margin: 0;
|
|
312
|
+
appearance: none;
|
|
304
313
|
}
|
|
305
314
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
padding: 2px;
|
|
315
|
+
.timeCase span {
|
|
316
|
+
color: currentColor;
|
|
317
|
+
opacity: 0.7;
|
|
310
318
|
}
|
|
311
319
|
|
|
320
|
+
#svgContainer {
|
|
321
|
+
display: inline-flex;
|
|
322
|
+
width: 1em;
|
|
323
|
+
height: 1em;
|
|
324
|
+
flex: 0 0 auto;
|
|
325
|
+
align-items: center;
|
|
326
|
+
justify-content: center;
|
|
327
|
+
margin-left: 0.2em;
|
|
328
|
+
color: inherit;
|
|
329
|
+
}
|
|
312
330
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
/* between digit span */
|
|
318
|
-
.bds{
|
|
319
|
-
padding-bottom: 1px;
|
|
331
|
+
#svgContainer svg {
|
|
332
|
+
display: block;
|
|
333
|
+
width: 100%;
|
|
334
|
+
height: 100%;
|
|
320
335
|
}
|
|
321
336
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
color: black;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
*:disabled {
|
|
331
|
-
background-color: grey;
|
|
332
|
-
color: lightgrey;
|
|
333
|
-
opacity: .6;
|
|
337
|
+
.timeCase input:disabled {
|
|
338
|
+
background: transparent;
|
|
339
|
+
color: GrayText;
|
|
340
|
+
cursor: not-allowed;
|
|
341
|
+
opacity: 0.65;
|
|
334
342
|
}
|
|
335
343
|
</style> `
|
|
336
344
|
|
|
@@ -422,26 +430,19 @@ class InputDuration extends HTMLElement {
|
|
|
422
430
|
// Digit input 0-9 (typed in by user)
|
|
423
431
|
|
|
424
432
|
function setInputFilter(inputElement, inputFilter) {
|
|
425
|
-
|
|
433
|
+
inputElement.oldValue = inputElement.value;
|
|
426
434
|
|
|
427
|
-
|
|
428
|
-
|
|
435
|
+
inputElement.addEventListener('input', function () {
|
|
436
|
+
if (inputFilter(this.value)) {
|
|
437
|
+
this.oldValue = this.value;
|
|
438
|
+
} else {
|
|
439
|
+
this.value = this.oldValue;
|
|
440
|
+
}
|
|
441
|
+
});
|
|
429
442
|
|
|
430
443
|
inputElement.addEventListener('keyup', function (event) {
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
if (/^([0-9]?)$/.test(event.key)) {
|
|
435
|
-
if (inputFilter(this.value)) {
|
|
436
|
-
this.oldValue = this.value;
|
|
437
|
-
this.oldSelectionStart = this.selectionStart;
|
|
438
|
-
this.oldSelectionEnd = this.selectionEnd;
|
|
439
|
-
} else if (this.hasOwnProperty("oldValue")) {
|
|
440
|
-
this.value = this.oldValue;
|
|
441
|
-
// this.setSelectionRange(this.oldSelectionStart, this.oldSelectionEnd);
|
|
442
|
-
} else {
|
|
443
|
-
this.value = "";
|
|
444
|
-
}
|
|
444
|
+
if (/^[0-9]$/.test(event.key)) {
|
|
445
|
+
inputFilter(this.value);
|
|
445
446
|
}
|
|
446
447
|
});
|
|
447
448
|
}
|
|
@@ -455,7 +456,7 @@ class InputDuration extends HTMLElement {
|
|
|
455
456
|
var newV = /^([0-9]?|[0-9][0-9]?)$/.test(value);
|
|
456
457
|
|
|
457
458
|
|
|
458
|
-
if (value.length === 2) {
|
|
459
|
+
if (newV && value.length === 2) {
|
|
459
460
|
|
|
460
461
|
mE.querySelector('input.sM').focus();
|
|
461
462
|
mE.querySelector('input.sM').select();
|
|
@@ -472,7 +473,7 @@ class InputDuration extends HTMLElement {
|
|
|
472
473
|
|
|
473
474
|
var newV = /^([0-9]?|[0-5][0-9]?)$/.test(value);
|
|
474
475
|
|
|
475
|
-
if (value > 5 || value.length === 2) {
|
|
476
|
+
if (newV && (value > 5 || value.length === 2)) {
|
|
476
477
|
|
|
477
478
|
mE.querySelector('input.sS').focus();
|
|
478
479
|
mE.querySelector('input.sS').select();
|
|
@@ -488,7 +489,7 @@ class InputDuration extends HTMLElement {
|
|
|
488
489
|
|
|
489
490
|
var newV = /^([0-9]?|[0-5][0-9]?)$/.test(value);
|
|
490
491
|
|
|
491
|
-
if (value > 5 || value.length === 2) {
|
|
492
|
+
if (newV && (value > 5 || value.length === 2)) {
|
|
492
493
|
|
|
493
494
|
mE.querySelector('input.sMS').focus();
|
|
494
495
|
mE.querySelector('input.sMS').select();
|
|
@@ -506,7 +507,7 @@ class InputDuration extends HTMLElement {
|
|
|
506
507
|
var newV = /^([0-9]?|[0-9][0-9]?|[0-9][0-9][0-9]?)$/.test(value);
|
|
507
508
|
|
|
508
509
|
|
|
509
|
-
if (value.length === 3) {
|
|
510
|
+
if (newV && value.length === 3) {
|
|
510
511
|
|
|
511
512
|
mE.querySelector('input.sMS').blur();
|
|
512
513
|
|
|
@@ -643,6 +644,8 @@ class InputDuration extends HTMLElement {
|
|
|
643
644
|
// end class
|
|
644
645
|
|
|
645
646
|
|
|
646
|
-
|
|
647
|
+
customElements.define('input-duration', InputDuration);
|
|
648
|
+
|
|
649
|
+
export default InputDuration;
|
|
647
650
|
|
|
648
651
|
// an option is to make all above an IIFE
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "input-duration",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"author": "Stephan Luis <stephan@learnsense.org>",
|
|
5
|
-
"description": "
|
|
6
|
-
"browser": "
|
|
5
|
+
"description": "A JavaScript web component for entering durations up to 99 hours in a fixed HH:mm:ss.SSS format, with millisecond precision for countdown timers and elapsed time.",
|
|
6
|
+
"browser": "./index.js",
|
|
7
7
|
"module": "index.js",
|
|
8
8
|
"main": "index.js",
|
|
9
9
|
"type": "module",
|
|
10
10
|
"scripts": {
|
|
11
|
-
"test": "
|
|
11
|
+
"test": "node --test Tests/inputDuration.test.js",
|
|
12
12
|
"build": "webpack && date '+%T'",
|
|
13
13
|
"devbuild": "webpack --mode=development && date '+%T'",
|
|
14
14
|
"start": "python3 -m http.server"
|
|
@@ -18,19 +18,29 @@
|
|
|
18
18
|
"url": "git+https://github.com/StephanLuis/input-duration.git"
|
|
19
19
|
},
|
|
20
20
|
"license": "ISC",
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"jsdom": "^26.1.0"
|
|
23
|
+
},
|
|
21
24
|
"bugs": {
|
|
22
25
|
"url": "https://github.com/StephanLuis/input-duration/issues"
|
|
23
26
|
},
|
|
24
27
|
"homepage": "https://github.com/StephanLuis/input-duration#readme",
|
|
25
28
|
"keywords": [
|
|
29
|
+
"javascript",
|
|
30
|
+
"duration input",
|
|
31
|
+
"time duration",
|
|
32
|
+
"countdown timer",
|
|
33
|
+
"elapsed time",
|
|
34
|
+
"millisecond",
|
|
35
|
+
"time input",
|
|
36
|
+
"web component",
|
|
26
37
|
"vanilla js",
|
|
27
38
|
"input",
|
|
28
39
|
"time",
|
|
29
40
|
"duration",
|
|
30
|
-
"webcomponent",
|
|
31
41
|
"hour",
|
|
32
42
|
"minute",
|
|
33
43
|
"second",
|
|
34
|
-
"
|
|
44
|
+
"milliseconds"
|
|
35
45
|
]
|
|
36
46
|
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# triggered on commit to rep
|
|
2
|
-
# triggers specific workflow in curl enpoint (that workflow needs workflow_disptach)
|
|
3
|
-
|
|
4
|
-
name: CommitToBSEndToEnd
|
|
5
|
-
|
|
6
|
-
# Controls when the action will run. Workflow runs when manually triggered using the UI
|
|
7
|
-
# or API.
|
|
8
|
-
on: push
|
|
9
|
-
|
|
10
|
-
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
|
11
|
-
jobs:
|
|
12
|
-
bump-pub:
|
|
13
|
-
runs-on: ubuntu-latest
|
|
14
|
-
steps:
|
|
15
|
-
- uses: actions/checkout@v3
|
|
16
|
-
- uses: actions/setup-node@v3
|
|
17
|
-
with:
|
|
18
|
-
node-version: 16
|
|
19
|
-
registry-url: https://registry.npmjs.org/
|
|
20
|
-
- run: npm ci
|
|
21
|
-
|
|
22
|
-
# bumps minor version
|
|
23
|
-
- run: echo "Token ${{ secrets.GITHUB_TOKEN }}"
|
|
24
|
-
- run: echo "Repo ${{ github.repository }}"
|
|
25
|
-
- run: echo "Head ${{ github.head_ref }}"
|
|
26
|
-
- run: npm version patch
|
|
27
|
-
- run: git push "https://${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}"
|
|
28
|
-
|
|
29
|
-
# publishes with credentials
|
|
30
|
-
- run: npm publish
|
|
31
|
-
env:
|
|
32
|
-
NODE_AUTH_TOKEN: ${{secrets.npm_token}}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
trigger-BStest:
|
|
38
|
-
runs-on: ubuntu-latest
|
|
39
|
-
steps:
|
|
40
|
-
|
|
41
|
-
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
|
42
|
-
- name: Trigger Tests
|
|
43
|
-
|
|
44
|
-
run: |
|
|
45
|
-
curl -L \
|
|
46
|
-
-X POST \
|
|
47
|
-
-H "Accept: application/vnd.github+json" \
|
|
48
|
-
-u "StephanLuis:${{secrets.PAT_KEY}}" \
|
|
49
|
-
-H "X-GitHub-Api-Version: 2022-11-28" \
|
|
50
|
-
https://api.github.com/repos/StephanLuis/BrowserStackSelenium/actions/workflows/78546395/dispatches \
|
|
51
|
-
-d '{"ref":"main"}'
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
name: Dev Version and Release
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
|
|
6
|
-
# exclude push for these files / dir
|
|
7
|
-
paths:
|
|
8
|
-
- '**.js'
|
|
9
|
-
- '!**.config.js'
|
|
10
|
-
- '!.github/**'
|
|
11
|
-
- '!Competitors/**'
|
|
12
|
-
- '!docs/**'
|
|
13
|
-
- '!readme/**'
|
|
14
|
-
|
|
15
|
-
env:
|
|
16
|
-
node_version: lts/*
|
|
17
|
-
new_version: patch
|
|
18
|
-
|
|
19
|
-
concurrency: # prevent concurrent releases
|
|
20
|
-
group: npm-bump
|
|
21
|
-
cancel-in-progress: true
|
|
22
|
-
|
|
23
|
-
jobs:
|
|
24
|
-
version_and_release:
|
|
25
|
-
runs-on: ubuntu-latest
|
|
26
|
-
outputs:
|
|
27
|
-
tagName: ${{ steps.npm-bump.outputs.release_tag }}
|
|
28
|
-
steps:
|
|
29
|
-
- uses: actions/checkout@v3
|
|
30
|
-
with:
|
|
31
|
-
# fetch full history so things like auto-changelog work properly
|
|
32
|
-
fetch-depth: 0
|
|
33
|
-
- name: Use Node.js ${{ env.node_version }}
|
|
34
|
-
uses: actions/setup-node@v3
|
|
35
|
-
with:
|
|
36
|
-
node-version: ${{ env.node_version }}
|
|
37
|
-
# setting a registry enables the NODE_AUTH_TOKEN env variable where we can set an npm token. REQUIRED
|
|
38
|
-
registry-url: 'https://registry.npmjs.org'
|
|
39
|
-
- run: npm i
|
|
40
|
-
- run: npm test
|
|
41
|
-
|
|
42
|
-
# https://github.com/marketplace/actions/npm-bump
|
|
43
|
-
- name: Version and publish to npm
|
|
44
|
-
id: npm-bump
|
|
45
|
-
uses: bcomnes/npm-bump@v2
|
|
46
|
-
with:
|
|
47
|
-
git_email: stephan@learnsense.org
|
|
48
|
-
git_username: ${{ github.actor }}
|
|
49
|
-
newversion: ${{ env.new_version }}
|
|
50
|
-
publish_cmd: npm publish --tag dev
|
|
51
|
-
push_version_commit: true # if your prePublishOnly step pushes git commits, you can omit this input or set it to false.
|
|
52
|
-
github_token: ${{ secrets.GITHUB_TOKEN }} # built in actions token. Passed tp gh-release if in use.
|
|
53
|
-
npm_token: ${{ secrets.NPM_TOKEN }} # user set secret token generated at npm
|
|
54
|
-
- run: echo ${{ steps.npm-bump.outputs.release_tag }}
|
|
55
|
-
|
|
56
|
-
# Trigger tests on BrowserStackSelenium repo
|
|
57
|
-
- name: Test
|
|
58
|
-
|
|
59
|
-
run: |
|
|
60
|
-
curl -L \
|
|
61
|
-
-X POST \
|
|
62
|
-
-H "Accept: application/vnd.github+json" \
|
|
63
|
-
-u "StephanLuis:${{secrets.PAT_KEY}}" \
|
|
64
|
-
-H "X-GitHub-Api-Version: 2022-11-28" \
|
|
65
|
-
https://api.github.com/repos/StephanLuis/BrowserStackSelenium/actions/workflows/79764882/dispatches \
|
|
66
|
-
-d '{"ref":"main"}'
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
# second commit
|
|
2
|
-
# from https://github.com/marketplace/actions/npm-bump
|
|
3
|
-
name: NPM Version and Release (npm-bump.yml)
|
|
4
|
-
|
|
5
|
-
on:
|
|
6
|
-
workflow_dispatch:
|
|
7
|
-
inputs:
|
|
8
|
-
newversion:
|
|
9
|
-
description: 'Semantic Version Bump Type (major minor patch)'
|
|
10
|
-
required: true
|
|
11
|
-
|
|
12
|
-
env:
|
|
13
|
-
node_version: lts/*
|
|
14
|
-
|
|
15
|
-
concurrency: # prevent concurrent releases
|
|
16
|
-
group: npm-bump
|
|
17
|
-
cancel-in-progress: true
|
|
18
|
-
|
|
19
|
-
jobs:
|
|
20
|
-
version_and_release:
|
|
21
|
-
runs-on: ubuntu-latest
|
|
22
|
-
outputs:
|
|
23
|
-
tagName: ${{ steps.npm-bump.outputs.release_tag }}
|
|
24
|
-
steps:
|
|
25
|
-
- uses: actions/checkout@v3
|
|
26
|
-
with:
|
|
27
|
-
# fetch full history so things like auto-changelog work properly
|
|
28
|
-
fetch-depth: 0
|
|
29
|
-
- name: Use Node.js ${{ env.node_version }}
|
|
30
|
-
uses: actions/setup-node@v3
|
|
31
|
-
with:
|
|
32
|
-
node-version: ${{ env.node_version }}
|
|
33
|
-
# setting a registry enables the NODE_AUTH_TOKEN env variable where we can set an npm token. REQUIRED
|
|
34
|
-
registry-url: 'https://registry.npmjs.org'
|
|
35
|
-
- run: npm i
|
|
36
|
-
- run: npm test
|
|
37
|
-
- name: Version and publish to npm
|
|
38
|
-
id: npm-bump
|
|
39
|
-
uses: bcomnes/npm-bump@v2
|
|
40
|
-
with:
|
|
41
|
-
git_email: bcomnes@gmail.com
|
|
42
|
-
git_username: ${{ github.actor }}
|
|
43
|
-
newversion: ${{ github.event.inputs.newversion }}
|
|
44
|
-
push_version_commit: true # if your prePublishOnly step pushes git commits, you can omit this input or set it to false.
|
|
45
|
-
github_token: ${{ secrets.GITHUB_TOKEN }} # built in actions token. Passed tp gh-release if in use.
|
|
46
|
-
npm_token: ${{ secrets.NPM_TOKEN }} # user set secret token generated at npm
|
|
47
|
-
- run: echo ${{ steps.npm-bump.outputs.release_tag }}
|