input-duration 3.1.0 → 3.2.0

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.
@@ -19,53 +19,115 @@
19
19
 
20
20
  <h1 class="page-title">Source: index.js</h1>
21
21
 
22
- <h1>Hi from bob</h1>Hi from bobQ!!!</h1>
23
22
 
24
23
 
25
24
 
26
-
25
+
26
+
27
27
  <section>
28
28
  <article>
29
29
  <pre class="prettyprint source linenums"><code>/**
30
30
  * This is jsdoc 'auto' documentation see https://jsdoc.app/
31
- *
31
+ * npm install -g jsdoc
32
+ * jsdoc index.js -d ./docs/
33
+ *
34
+ *
32
35
  * @fileoverview INPUT-DURATION
33
- * @file INPUT-DURATION
36
+ * @file INPUT-DURATION
34
37
  * @author Stephan Luis
35
38
  * @see &lt;a href="https://www.npmjs.com/package/input-duration">NPM input-duration&lt;/a>
36
39
  * @see &lt;a href="https://github.com/StephanLuis/input-duration">GitHub input-duration&lt;/a>
37
- * @copyright MIT License, Copyright (c) 2022
40
+ * @copyright MIT License, Copyright (c) 2022
41
+ * @version 2.2.8 (release)
38
42
  */
39
43
 
40
44
 
41
45
 
42
46
  /**
43
47
  * Class for the Input-Duration webcomponent
48
+ *
49
+ * Boolean attributes `no-hours`, `no-minutes`, `no-seconds`, and
50
+ * `no-microseconds` hide their respective fields. String attributes
51
+ * `hours-divider`, `minutes-divider`, `seconds-divider`, and
52
+ * `microseconds-divider` customize the separators; the last adds a suffix
53
+ * after milliseconds. Divider values are rendered as text.
54
+ *
55
+ * @example
56
+ * &lt;input-duration no-microseconds hours-divider="h " microseconds-divider="ms">&lt;/input-duration>
57
+ *
44
58
  * @class InputDuration
45
59
  * @extends HTMLElement
46
60
  */
47
61
 
48
62
  class InputDuration extends HTMLElement {
63
+ /**
64
+ * HTML attributes that update the component when changed.
65
+ *
66
+ * @static
67
+ * @returns {string[]} Observed value, visibility, and divider attributes.
68
+ */
69
+ static get observedAttributes() {
70
+ return [
71
+ 'value',
72
+ 'no-hours',
73
+ 'no-minutes',
74
+ 'no-seconds',
75
+ 'no-microseconds',
76
+ 'hours-divider',
77
+ 'minutes-divider',
78
+ 'seconds-divider',
79
+ 'microseconds-divider'
80
+ ];
81
+ }
82
+
49
83
  constructor() {
50
84
 
51
85
  super();
52
86
 
87
+ /**
88
+ * Shadow root containing this component's controls.
89
+ * @type {ShadowRoot}
90
+ */
53
91
  this.myElement = this.attachShadow({ mode: 'open' });
54
92
 
55
- // needed for setting inputs when value attribute is added to chronlyHMS
56
- // &lt;chronly-hms id="bobPrepop" value="99:09:09.999">&lt;/chronly-hms>
57
-
58
- this.value = this.getAttribute('value');
59
-
60
93
  this.boot();
61
94
 
62
95
  } // end constructor
63
96
 
97
+ /**
98
+ * Updates the rendered control when an observed attribute changes.
99
+ *
100
+ * @param {string} name - Changed attribute name.
101
+ * @param {?string} oldValue - Previous attribute value.
102
+ * @param {?string} newValue - New attribute value, or null when removed.
103
+ * @returns {void}
104
+ */
105
+ attributeChangedCallback(name, oldValue, newValue) {
106
+
107
+ if (oldValue === newValue) {
108
+ return;
109
+ }
110
+
111
+ if (name !== 'value') {
112
+ this.updateVisibleFields();
113
+ this.updateDividers();
114
+ return;
115
+ }
116
+
117
+ if (newValue === null) {
118
+ this.resetInputs();
119
+ } else if (this.isValidValue(newValue)) {
120
+ this.setInputValues(newValue);
121
+ } else {
122
+ this.warnInvalidValue(newValue);
123
+ }
124
+ }
125
+
64
126
 
65
127
  /**
66
128
  * get the input-duration value, pulls values from each input
67
- * so in js use var x = document.querySelector("#bobPrepop").value;
68
- * @return {duration}
129
+ * so in js use var x = document.querySelector("#bobPrepop").value;
130
+ * @returns {?string} Duration in `HH:mm:ss.SSS` format, or null before initialization.
69
131
  */
70
132
 
71
133
  get value() {
@@ -89,69 +151,84 @@ class InputDuration extends HTMLElement {
89
151
 
90
152
 
91
153
  /**
92
- * set the input-duration value
93
- * so in js use document.querySelector("#bobPrepop").value = "05:05:05.005"
94
- * @return {duration}
95
- * @param {duration} can be html attribute or set in js
154
+ * Sets the duration using the fixed `HH:mm:ss.SSS` format.
155
+ *
156
+ * @param {string} val - Duration string, such as `05:05:05.005`.
157
+ * @returns {void}
96
158
  */
97
159
 
98
160
  set value(val) {
99
161
 
100
162
  // for setting the value in js (like document.querySelector("#bobPrepop").value = "05:05:05.005")
101
- if (val) {
102
-
103
-
104
- console.log(val);
105
-
106
-
107
- if (/(^[0-9][0-9]):([0-5][0-9]):([0-5][0-9])\.([0-9][0-9][0-9]$)/.exec(val)) {
108
-
109
-
110
- // split val
111
-
112
- var timeArray = val.split(/[.:]+/);
113
-
114
- console.log('time array is ' + timeArray[0] + ':' + timeArray[1] + ':' + timeArray[2] + ':' + timeArray[3]);
115
-
116
- console.log('this.id = ' + this.id);
117
-
118
- setTimeout(() => {
119
-
120
- this.myElement.querySelector('input[name="startHours"]').value = timeArray[0];
121
- this.myElement.querySelector('input[name="startMinutes"]').value = timeArray[1];
122
- this.myElement.querySelector('input[name="startSeconds"]').value = timeArray[2];
123
- this.myElement.querySelector('input[name="startMilliSecs"]').value = timeArray[3];
124
-
125
- }, 0);
126
-
127
-
128
- this.setAttribute('value', val);
129
-
130
- }
131
-
132
- else {
133
-
134
- 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.`);
163
+ if (!val) {
164
+ this.resetInputs();
165
+ this.removeAttribute('value');
166
+ return;
167
+ }
135
168
 
136
- }
169
+ if (typeof val !== 'string' || !this.isValidValue(val)) {
170
+ this.warnInvalidValue(val);
171
+ return;
172
+ }
137
173
 
138
- // I think this is for empty string to clear value
139
- // gives a False bool and removes value from Webcomponent chronlyHMS
174
+ this.setInputValues(val);
140
175
 
141
- } else {
176
+ if (this.getAttribute('value') !== val) {
177
+ this.setAttribute('value', val);
178
+ }
179
+ }
142
180
 
143
- setTimeout(() => {
181
+ /**
182
+ * Checks whether a value follows the supported duration format and ranges.
183
+ *
184
+ * @param {*} val - Candidate value.
185
+ * @returns {boolean} Whether the value is valid `HH:mm:ss.SSS`.
186
+ */
187
+ isValidValue(val) {
188
+ return typeof val === 'string' &amp;&amp;
189
+ /^[0-9]{2}:[0-5][0-9]:[0-5][0-9]\.[0-9]{3}$/.test(val);
190
+ }
144
191
 
145
- this.myElement.querySelector('input[name="startHours"]').value = '00';
146
- this.myElement.querySelector('input[name="startMinutes"]').value = '00';
147
- this.myElement.querySelector('input[name="startSeconds"]').value = '00';
148
- this.myElement.querySelector('input[name="startMilliSecs"]').value = '000';
192
+ /**
193
+ * Copies a validated duration string into the four shadow inputs.
194
+ *
195
+ * @param {string} val - Valid duration in `HH:mm:ss.SSS` format.
196
+ * @returns {void}
197
+ */
198
+ setInputValues(val) {
199
+ const timeArray = val.split(/[.:]+/);
200
+ const inputNames = ['startHours', 'startMinutes', 'startSeconds', 'startMilliSecs'];
201
+
202
+ inputNames.forEach((name, index) => {
203
+ const input = this.myElement.querySelector(`input[name="${name}"]`);
204
+ input.value = timeArray[index];
205
+ input.oldValue = input.value;
206
+ });
207
+ }
149
208
 
150
- }, 0);
209
+ /**
210
+ * Resets all duration fields to zero.
211
+ *
212
+ * @returns {void}
213
+ */
214
+ resetInputs() {
215
+ const defaults = ['00', '00', '00', '000'];
216
+ const inputs = this.myElement.querySelectorAll('.timeCase input');
151
217
 
152
- this.removeAttribute('value');
218
+ inputs.forEach((input, index) => {
219
+ input.value = defaults[index];
220
+ input.oldValue = input.value;
221
+ });
222
+ }
153
223
 
154
- }
224
+ /**
225
+ * Reports a value that does not match the supported duration format.
226
+ *
227
+ * @param {*} val - Rejected value.
228
+ * @returns {void}
229
+ */
230
+ warnInvalidValue(val) {
231
+ 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.`);
155
232
  }
156
233
 
157
234
 
@@ -178,17 +255,13 @@ class InputDuration extends HTMLElement {
178
255
 
179
256
  /**
180
257
  * eventlistener that adds arrow key input of values (up/down) and place toggling (left/right) triggered by
181
- * the change event of the input
258
+ * the change event of the input
182
259
  * @method
183
260
  * @see boot()
184
261
  */
185
262
 
186
263
  addArrowKeyInput() {
187
264
 
188
- console.log('1 this: ' + this);
189
- console.log('1 this.myElement: ' + this.myElement);
190
- console.log('1 this.myElement active: ' + this.myElement);
191
-
192
265
  var mE = this.myElement;
193
266
 
194
267
  // Left and Right arrow key toggle between HMSmS
@@ -259,18 +332,20 @@ class InputDuration extends HTMLElement {
259
332
  var spanIn = document.createElement("div");
260
333
 
261
334
  spanIn.classList.add('timeCase');
335
+ spanIn.setAttribute('part', 'control');
262
336
 
263
337
  var template = document.createElement('template');
264
338
 
265
339
  template.innerHTML = `
266
- &lt;input type="number" class="sH D2 ts_digit" name="startHours" data-tp="1" min="-1" max="100" value="00" >
267
- &lt;span class="bds-h">:&lt;/span>
268
- &lt;input type="number" class="sM D2 ts_digit" name="startMinutes" data-tp="2" min="-1" max="60" value="00">
269
- &lt;span class="bds-m">:&lt;/span>
270
- &lt;input type="number" class="sS D2 ts_digit" name="startSeconds" data-tp="3" min="-1" max="60" value="00">
271
- &lt;span class="bds-s">.&lt;/span>
272
- &lt;input type="number" class="sMS D3 ts_digit" name="startMilliSecs" data-tp="4" min="-10" max="1010" step="10" value="000">
273
- &lt;div id="svgContainer">
340
+ &lt;input type="number" class="sH D2 ts_digit" part="field field-hours" name="startHours" data-tp="1" min="-1" max="100" value="00" >
341
+ &lt;span class="bds-h" part="divider divider-hours-minutes">:&lt;/span>
342
+ &lt;input type="number" class="sM D2 ts_digit" part="field field-minutes" name="startMinutes" data-tp="2" min="-1" max="60" value="00">
343
+ &lt;span class="bds-m" part="divider divider-minutes-seconds">:&lt;/span>
344
+ &lt;input type="number" class="sS D2 ts_digit" part="field field-seconds" name="startSeconds" data-tp="3" min="-1" max="60" value="00">
345
+ &lt;span class="bds-s" part="divider divider-seconds-milliseconds">.&lt;/span>
346
+ &lt;input type="number" class="sMS D3 ts_digit" part="field field-milliseconds" name="startMilliSecs" data-tp="4" min="-10" max="1010" step="10" value="000">
347
+ &lt;span class="bds-ms" part="divider divider-milliseconds-suffix" style="display: none">&lt;/span>
348
+ &lt;div id="svgContainer" part="icon">
274
349
  &lt;svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true"
275
350
  focusable="false" data-prefix="fal" data-icon="stopwatch" class="svg-inline--fa fa-stopwatch fa-w-14"
276
351
  role="img" viewBox="0 0 448 512">
@@ -278,82 +353,103 @@ class InputDuration extends HTMLElement {
278
353
  &lt;/svg>
279
354
  &lt;/div>
280
355
  &lt;style>
281
- *:focus {
282
- outline: none;
356
+ :host {
357
+ display: inline-block;
358
+ color: inherit;
359
+ font: inherit;
360
+ vertical-align: middle;
361
+ --input-duration-gap: 0.08em;
362
+ --input-duration-padding: 0.4em 0.55em;
363
+ --input-duration-border-color: #9aa6b2;
364
+ --input-duration-border-radius: 0.4em;
365
+ --input-duration-background: transparent;
366
+ --input-duration-color: inherit;
367
+ --input-duration-focus-color: #2196f3;
368
+ --input-duration-focus-outline: 3px solid #2196f3;
369
+ --input-duration-focus-outline-offset: 2px;
370
+ --input-duration-divider-color: currentColor;
371
+ --input-duration-divider-opacity: 0.7;
372
+ --input-duration-disabled-color: GrayText;
373
+ --input-duration-icon-color: inherit;
283
374
  }
284
375
 
285
-
286
- div.timeCase{
287
- display: inline-flex;
288
- flex-direction: row;
289
- max-width: 300px;
290
- padding: 3px;
291
- border-style: solid;
292
- border-width: 1px;
293
- border-radius: 2px;
376
+ .timeCase,
377
+ .timeCase[part~="control"] {
378
+ display: inline-flex;
379
+ align-items: center;
380
+ gap: var(--input-duration-gap);
381
+ max-width: 100%;
382
+ padding: var(--input-duration-padding);
383
+ border: 1px solid var(--input-duration-border-color);
384
+ border-radius: var(--input-duration-border-radius);
385
+ background: var(--input-duration-background);
386
+ color: var(--input-duration-color);
387
+ font-variant-numeric: tabular-nums;
388
+ line-height: 1.4;
389
+ white-space: nowrap;
294
390
  }
295
391
 
296
-
297
- /* Each input width set and blinking cursor 'caret' removed */
298
- div.timeCase input{
299
- caret-color: transparent;
300
- width: 15px;
301
- padding-top:1px;
392
+ .timeCase:focus-within {
393
+ border-color: var(--input-duration-focus-color);
394
+ outline: var(--input-duration-focus-outline);
395
+ outline-offset: var(--input-duration-focus-outline-offset);
302
396
  }
303
397
 
304
-
305
- div.timeCase .D3{
306
- width: 25px;
398
+ .timeCase input {
399
+ box-sizing: content-box;
400
+ width: 2ch;
401
+ min-width: 2ch;
402
+ margin: 0;
403
+ padding: 0;
404
+ border: 0;
405
+ outline: 0;
406
+ background: transparent;
407
+ color: inherit;
408
+ font: inherit;
409
+ font-variant-numeric: tabular-nums;
410
+ text-align: center;
411
+ caret-color: transparent;
412
+ appearance: textfield;
307
413
  }
308
414
 
309
-
310
- /* Hiding the up and down arrow */
311
- /*https://www.w3schools.com/howto/howto_css_hide_arrow_number.asp*/
312
- /* Chrome, Safari, Edge, Opera */
313
-
314
- input::-webkit-outer-spin-button,
315
- input::-webkit-inner-spin-button {
316
- -webkit-appearance: none;
317
- margin: 0;
415
+ .timeCase input.D3 {
416
+ width: 3ch;
417
+ min-width: 3ch;
318
418
  }
319
419
 
320
-
321
- /* Firefox */
322
-
323
- input[type=number] {
324
- /* -moz-appearance: textfield; */
325
- -moz-appearance: textarea;
326
- -webkit-appearance: textarea;
420
+ .timeCase input::-webkit-outer-spin-button,
421
+ .timeCase input::-webkit-inner-spin-button {
422
+ margin: 0;
423
+ appearance: none;
327
424
  }
328
425
 
329
-
330
- div.timeCase:focus-within {
331
- border: 2px solid black;
332
- padding: 2px;
426
+ .timeCase span {
427
+ color: var(--input-duration-divider-color);
428
+ opacity: var(--input-duration-divider-opacity);
333
429
  }
334
430
 
431
+ #svgContainer {
432
+ display: inline-flex;
433
+ width: 1em;
434
+ height: 1em;
435
+ flex: 0 0 auto;
436
+ align-items: center;
437
+ justify-content: center;
438
+ margin-left: 0.2em;
439
+ color: var(--input-duration-icon-color);
440
+ }
335
441
 
336
- .ts_digit {
337
- border: none;
338
- }
339
-
340
- /* between digit span */
341
- .bds{
342
- padding-bottom: 1px;
442
+ #svgContainer svg {
443
+ display: block;
444
+ width: 100%;
445
+ height: 100%;
343
446
  }
344
447
 
345
- #svgContainer {
346
- width: 12px;
347
- height: 12px;
348
- padding-top: 1px;
349
- padding-right: 2px;
350
- color: black;
351
- }
352
-
353
- *:disabled {
354
- background-color: grey;
355
- color: lightgrey;
356
- opacity: .6;
448
+ .timeCase input:disabled {
449
+ background: transparent;
450
+ color: var(--input-duration-disabled-color);
451
+ cursor: not-allowed;
452
+ opacity: 0.65;
357
453
  }
358
454
  &lt;/style> `
359
455
 
@@ -366,7 +462,7 @@ class InputDuration extends HTMLElement {
366
462
 
367
463
  /**
368
464
  * eventlistener that adds number looping for up and down keys triggered by
369
- * the change event of the input
465
+ * the change event of the input
370
466
  * @method
371
467
  * @see boot()
372
468
  */
@@ -432,7 +528,7 @@ class InputDuration extends HTMLElement {
432
528
 
433
529
 
434
530
  /**
435
- * eventlistener that adds number input for keyed values triggered by the keyup event
531
+ * eventlistener that filters number input and advances between fields
436
532
  * @method
437
533
  * @see boot()
438
534
  */
@@ -445,26 +541,13 @@ class InputDuration extends HTMLElement {
445
541
  // Digit input 0-9 (typed in by user)
446
542
 
447
543
  function setInputFilter(inputElement, inputFilter) {
448
- // this sets a listener and immediately updates the value of the input number (note: can update this from input text, like by removing setSelectionRange )
449
-
450
- console.log('inputElement: ' + inputElement);
451
- window.inputElement = inputElement;
452
-
453
- inputElement.addEventListener('keyup', function (event) {
454
-
455
- window.kue = event;
456
-
457
- if (/^([0-9]?)$/.test(event.key)) {
458
- if (inputFilter(this.value)) {
459
- this.oldValue = this.value;
460
- this.oldSelectionStart = this.selectionStart;
461
- this.oldSelectionEnd = this.selectionEnd;
462
- } else if (this.hasOwnProperty("oldValue")) {
463
- this.value = this.oldValue;
464
- // this.setSelectionRange(this.oldSelectionStart, this.oldSelectionEnd);
465
- } else {
466
- this.value = "";
467
- }
544
+ inputElement.oldValue = inputElement.value;
545
+
546
+ inputElement.addEventListener('input', function () {
547
+ if (inputFilter(this.value)) {
548
+ this.oldValue = this.value;
549
+ } else {
550
+ this.value = this.oldValue;
468
551
  }
469
552
  });
470
553
  }
@@ -478,7 +561,7 @@ class InputDuration extends HTMLElement {
478
561
  var newV = /^([0-9]?|[0-9][0-9]?)$/.test(value);
479
562
 
480
563
 
481
- if (value.length === 2) {
564
+ if (newV &amp;&amp; value.length === 2) {
482
565
 
483
566
  mE.querySelector('input.sM').focus();
484
567
  mE.querySelector('input.sM').select();
@@ -495,7 +578,7 @@ class InputDuration extends HTMLElement {
495
578
 
496
579
  var newV = /^([0-9]?|[0-5][0-9]?)$/.test(value);
497
580
 
498
- if (value > 5 || value.length === 2) {
581
+ if (newV &amp;&amp; (value > 5 || value.length === 2)) {
499
582
 
500
583
  mE.querySelector('input.sS').focus();
501
584
  mE.querySelector('input.sS').select();
@@ -511,7 +594,7 @@ class InputDuration extends HTMLElement {
511
594
 
512
595
  var newV = /^([0-9]?|[0-5][0-9]?)$/.test(value);
513
596
 
514
- if (value > 5 || value.length === 2) {
597
+ if (newV &amp;&amp; (value > 5 || value.length === 2)) {
515
598
 
516
599
  mE.querySelector('input.sMS').focus();
517
600
  mE.querySelector('input.sMS').select();
@@ -529,7 +612,7 @@ class InputDuration extends HTMLElement {
529
612
  var newV = /^([0-9]?|[0-9][0-9]?|[0-9][0-9][0-9]?)$/.test(value);
530
613
 
531
614
 
532
- if (value.length === 3) {
615
+ if (newV &amp;&amp; value.length === 3) {
533
616
 
534
617
  mE.querySelector('input.sMS').blur();
535
618
 
@@ -543,7 +626,7 @@ class InputDuration extends HTMLElement {
543
626
 
544
627
  /**
545
628
  * eventlistener that adds 0s to preface numbers less than 10 triggered by
546
- * the change event of the input
629
+ * the change event of the input
547
630
  * @method
548
631
  * @see boot()
549
632
  */
@@ -567,11 +650,11 @@ class InputDuration extends HTMLElement {
567
650
  }));
568
651
 
569
652
  }
570
-
653
+
571
654
 
572
655
  /**
573
656
  * eventlistener that adds click to activate input of values by the keyboard triggered by
574
- * the click event of the input
657
+ * the click event of the input
575
658
  * @method
576
659
  * @see boot()
577
660
  */
@@ -584,7 +667,7 @@ class InputDuration extends HTMLElement {
584
667
 
585
668
  /**
586
669
  * eventlistener that adds key filtering to stop letters (or other non-numerics) from being input triggered by
587
- * the keypress event of the input
670
+ * the keypress event of the input
588
671
  * @method
589
672
  * @see boot()
590
673
  */
@@ -606,25 +689,30 @@ class InputDuration extends HTMLElement {
606
689
  }
607
690
 
608
691
  /**
609
- * Stop event propigation from the timeCase up through the DOM so when keys
692
+ * Stop event propigation from the timeCase up through the DOM so when keys
610
693
  * are being used they don't affect other controls (like volume on plyr)
611
694
  * @method
612
695
  */
613
696
 
614
697
  removeEprop() {
615
-
616
- document.querySelector('input-duration').shadowRoot.querySelector('.timeCase')
617
- .addEventListener('keydown', function (event) { event.stopPropagation();});
698
+
699
+ var closure = this;
700
+
701
+ closure.shadowRoot.querySelector('.timeCase')
702
+ .addEventListener('keydown', function (event) { event.stopPropagation();});
703
+
704
+ // document.querySelectorAll('input-duration').forEach(x => x.shadowRoot.querySelector('.timeCase')
705
+ // .addEventListener('keydown', function (event) { event.stopPropagation();}));
618
706
 
619
707
  }
620
708
 
621
709
 
622
-
710
+
623
711
  // formatting and behaviour options
624
712
 
625
713
  /**
626
714
  * disables entire control => read-only
627
- * @method
715
+ * @method
628
716
  */
629
717
 
630
718
  disable() {
@@ -639,31 +727,228 @@ class InputDuration extends HTMLElement {
639
727
 
640
728
 
641
729
  /**
642
- * removes the hours, so the display is mm:ss.uuu
643
- * @method
730
+ * Hides the hours field and its adjacent divider.
731
+ * Sets the `no-hours` attribute.
732
+ *
733
+ * @returns {void}
644
734
  */
735
+ hideHours() {
736
+ this.setAttribute('no-hours', '');
737
+ }
645
738
 
739
+ /**
740
+ * Shows the hours field and its adjacent divider.
741
+ * Removes the `no-hours` attribute.
742
+ *
743
+ * @returns {void}
744
+ */
745
+ showHours() {
746
+ this.removeAttribute('no-hours');
747
+ }
748
+
749
+ /**
750
+ * Backward-compatible alias for {@link InputDuration#hideHours}.
751
+ *
752
+ * @returns {void}
753
+ */
646
754
  noHours() {
755
+ this.hideHours();
756
+ }
647
757
 
648
- var closure = this;
758
+ /**
759
+ * Hides the minutes field and its adjacent divider.
760
+ * Sets the `no-minutes` attribute.
761
+ *
762
+ * @returns {void}
763
+ */
764
+ hideMinutes() {
765
+ this.setAttribute('no-minutes', '');
766
+ }
767
+
768
+ /**
769
+ * Shows the minutes field and its adjacent divider.
770
+ * Removes the `no-minutes` attribute.
771
+ *
772
+ * @returns {void}
773
+ */
774
+ showMinutes() {
775
+ this.removeAttribute('no-minutes');
776
+ }
777
+
778
+ /**
779
+ * Backward-compatible alias for {@link InputDuration#hideMinutes}.
780
+ *
781
+ * @returns {void}
782
+ */
783
+ noMinutes() {
784
+ this.hideMinutes();
785
+ }
786
+
787
+ /**
788
+ * Hides the seconds field and its adjacent divider.
789
+ * Sets the `no-seconds` attribute.
790
+ *
791
+ * @returns {void}
792
+ */
793
+ hideSeconds() {
794
+ this.setAttribute('no-seconds', '');
795
+ }
796
+
797
+ /**
798
+ * Shows the seconds field and its adjacent divider.
799
+ * Removes the `no-seconds` attribute.
800
+ *
801
+ * @returns {void}
802
+ */
803
+ showSeconds() {
804
+ this.removeAttribute('no-seconds');
805
+ }
806
+
807
+ /**
808
+ * Backward-compatible alias for {@link InputDuration#hideSeconds}.
809
+ *
810
+ * @returns {void}
811
+ */
812
+ noSeconds() {
813
+ this.hideSeconds();
814
+ }
649
815
 
650
- // hide chronly hours inputs on page
816
+ /**
817
+ * Hides the milliseconds field and its adjacent divider or suffix.
818
+ * Sets the `no-microseconds` attribute.
819
+ *
820
+ * @returns {void}
821
+ */
822
+ hideMicroSeconds() {
823
+ this.setAttribute('no-microseconds', '');
824
+ }
651
825
 
652
- closure.shadowRoot.querySelectorAll(".timeCase input.sH").forEach(el => el.style.display = 'none');
826
+ /**
827
+ * Shows the milliseconds field and its adjacent divider or suffix.
828
+ * Removes the `no-microseconds` attribute.
829
+ *
830
+ * @returns {void}
831
+ */
832
+ showMicroSeconds() {
833
+ this.removeAttribute('no-microseconds');
834
+ }
653
835
 
836
+ /**
837
+ * Backward-compatible alias for {@link InputDuration#hideMicroSeconds}.
838
+ *
839
+ * @returns {void}
840
+ */
841
+ noMicroSeconds() {
842
+ this.hideMicroSeconds();
843
+ }
654
844
 
655
- // hide the hours colon on page
845
+ /**
846
+ * Replaces the hours/minutes separator.
847
+ * Also available through the `hours-divider` attribute.
848
+ *
849
+ * @param {string} text - Divider text to display.
850
+ * @returns {void}
851
+ */
852
+ setHoursDivider(text) {
853
+ this.setAttribute('hours-divider', text);
854
+ }
656
855
 
657
- closure.shadowRoot.querySelectorAll(".timeCase span.bds-h").forEach(el => el.style.display = 'none');
856
+ /**
857
+ * Replaces the minutes/seconds separator.
858
+ * Also available through the `minutes-divider` attribute.
859
+ *
860
+ * @param {string} text - Divider text to display.
861
+ * @returns {void}
862
+ */
863
+ setMinutesDivider(text) {
864
+ this.setAttribute('minutes-divider', text);
865
+ }
658
866
 
867
+ /**
868
+ * Replaces the seconds/milliseconds separator.
869
+ * Also available through the `seconds-divider` attribute.
870
+ *
871
+ * @param {string} text - Divider text to display.
872
+ * @returns {void}
873
+ */
874
+ setSecondsDivider(text) {
875
+ this.setAttribute('seconds-divider', text);
659
876
  }
660
- }
877
+
878
+ /**
879
+ * Sets a suffix to display after milliseconds.
880
+ * Also available through the `microseconds-divider` attribute.
881
+ *
882
+ * @param {string} text - Suffix text to display.
883
+ * @returns {void}
884
+ */
885
+ setMicroSecondsDivider(text) {
886
+ this.setAttribute('microseconds-divider', text);
887
+ }
888
+
889
+ /**
890
+ * Synchronizes field and divider visibility with the `no-*` attributes.
891
+ *
892
+ * @returns {void}
893
+ */
894
+ updateVisibleFields() {
895
+ const hiddenFields = {
896
+ 'no-hours': '.sH',
897
+ 'no-minutes': '.sM',
898
+ 'no-seconds': '.sS',
899
+ 'no-microseconds': '.sMS'
900
+ };
901
+ const hiddenDividers = {
902
+ '.bds-h': ['no-hours', 'no-minutes'],
903
+ '.bds-m': ['no-seconds'],
904
+ '.bds-s': ['no-microseconds'],
905
+ '.bds-ms': ['no-microseconds']
906
+ };
907
+
908
+ for (const [attribute, selector] of Object.entries(hiddenFields)) {
909
+ const field = this.myElement.querySelector(selector);
910
+ field.style.display = this.hasAttribute(attribute) ? 'none' : '';
911
+ }
912
+
913
+ for (const [selector, attributes] of Object.entries(hiddenDividers)) {
914
+ const divider = this.myElement.querySelector(selector);
915
+ const shouldHide = attributes.some(attribute => this.hasAttribute(attribute));
916
+ divider.style.display = shouldHide ? 'none' : '';
917
+ }
918
+ }
919
+
920
+ /**
921
+ * Synchronizes divider text with the corresponding divider attributes.
922
+ *
923
+ * @returns {void}
924
+ */
925
+ updateDividers() {
926
+ const dividers = {
927
+ 'hours-divider': ['.bds-h', ':'],
928
+ 'minutes-divider': ['.bds-m', ':'],
929
+ 'seconds-divider': ['.bds-s', '.'],
930
+ 'microseconds-divider': ['.bds-ms', '']
931
+ };
932
+
933
+ for (const [attribute, [selector, defaultText]] of Object.entries(dividers)) {
934
+ const divider = this.myElement.querySelector(selector);
935
+ const text = this.getAttribute(attribute) ?? defaultText;
936
+ divider.textContent = text;
937
+ if (selector === '.bds-ms') {
938
+ divider.style.display = text &amp;&amp; !this.hasAttribute('no-microseconds') ? '' : 'none';
939
+ }
940
+ }
941
+ }
942
+ }
661
943
  // end class
662
944
 
663
945
 
664
- export default customElements.define('input-duration', InputDuration);
946
+ customElements.define('input-duration', InputDuration);
947
+
948
+ export default InputDuration;
665
949
 
666
- // an option is to make all above an IIFE</code></pre>
950
+ // an option is to make all above an IIFE
951
+ </code></pre>
667
952
  </article>
668
953
  </section>
669
954
 
@@ -679,7 +964,7 @@ export default customElements.define('input-duration', InputDuration);
679
964
  <br class="clear">
680
965
 
681
966
  <footer>
682
- 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)
967
+ Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.5</a> on Thu Nov 05 2026 14:15:36 GMT+0000 (Coordinated Universal Time)
683
968
  </footer>
684
969
 
685
970
  <script> prettyPrint(); </script>