Fixes for e2e tests following the Vue 3 compat upgrade (#6837)

* clock, timeConductor and appActions fixes

* Ensure realtime uses upstream context when available
Eliminate ambiguity when looking for time conductor locator

* Fix log plot e2e tests

* Fix displayLayout e2e tests

* Specify global time conductor to fix issues with duplicate selectors with independent time contexts

* a11y: ARIA for conductor and independent time conductor

* a11y: fix label collisions, specify 'Menu' in label

* Add watch mode

* fix(e2e): update appActions and tests to use a11y locators for ITC

* Don't remove the itc popup from the DOM. Just show/hide it once it's added the first time.

* test(e2e): disable one imagery test due to known bug

* Add fixme to tagging tests, issue described in 6822

* Fix locator for time conductor popups

* Improve how time bounds are set in independent time conductor.
Fix tests for flexible layout and timestrip

* Fix some tests for itc for display layouts

* Fix Inspector tabs remounting on change

* fix autoscale test and snapshot

* Fix telemetry table test

* Fix timestrip test

* e2e: move test info annotations to within test

* 6826: Fixes padStart error due to using it on a number rather than a string

* fix(e2e): update snapshots

* fix(e2e): fix restricted notebook locator

* fix(restrictedNotebook): fix issue causing sections not to update on lock

* fix(restrictedNotebook): fix issue causing snapshots to not be able to be deleted from a locked page

- Using `this.$delete(arr, index)` does not update the `length` property on the underlying target object, so it can lead to bizarre issues where your array is of length 4 but it has 3 objects in it.

* fix: replace all instances of `$delete` with `Array.splice()` or `delete`

* fix(e2e): fix grand search test

* fix(#3117): can remove item from displayLayout via tree context menu while viewing another item

* fix: remove typo 

* Wait for background image to load

* fix(#6832): timelist events can tick down

* fix: ensure that menuitems have the raw objects so emits work

* fix: assign new arrays instead of editing state in-place

* refactor(timelist): use `getClock()` instead of `clock()`

* Revert "refactor(timelist): use `getClock()` instead of `clock()`"

This reverts commit d888553112.

* refactor(timelist): use new timeAPI

* Stop ticking when the independent time context is disabled (#6833)

* Turn off the clock ticket for independent time conductor when it is disabled

* Fix linting issues

---------

Co-authored-by: Khalid Adil <khalidadil29@gmail.com>

* test: update couchdb notebook test

* fix: codeQL warnings

* fix(tree-item): infinite spinner issue

- Using `indexOf()` with an object was failing due to some items in the tree being Proxy-wrapped and others not. So instead, use `findIndex()` with a predicate that compares the navigationPaths of both objects

* [Timer] Remove "refresh" call, it is not needed (#6841)

* removing an unneccessary refresh that waas causing many get requests
* lets just pretend this never happened

* fix(mct-tree): maintain reactivity of all tree items

* Hide change role button in the indicator in cases where there is only… (#6840)

Hide change role button in the indicator in cases where there is only a single role available for the current user

---------

Co-authored-by: Shefali <simplyrender@gmail.com>
Co-authored-by: Khalid Adil <khalidadil29@gmail.com>
Co-authored-by: John Hill <john.c.hill@nasa.gov>
Co-authored-by: David Tsay <david.e.tsay@nasa.gov>
Co-authored-by: Jamie V <jamie.j.vigliotta@nasa.gov>
This commit is contained in:
Jesse Mazzella
2023-07-27 19:06:41 -07:00
committed by GitHub
parent 4885c816dc
commit 16e1ac2529
96 changed files with 921 additions and 816 deletions

View File

@ -49,7 +49,11 @@
@panAxis="pan"
@zoomAxis="zoom"
/>
<div class="c-not-button c-not-button--compact c-compact-tc__gear icon-gear"></div>
<div
role="button"
class="c-not-button c-not-button--compact c-compact-tc__gear icon-gear"
aria-label="Time Conductor Settings"
></div>
<conductor-pop-up
v-if="showConductorPopup"

View File

@ -1,29 +1,38 @@
/***************************************************************************** * Open MCT Web,
Copyright (c) 2014-2023, United States Government * as represented by the Administrator of the
National Aeronautics and Space * Administration. All rights reserved. * * Open MCT Web is licensed
under the Apache License, Version 2.0 (the * "License"); you may not use this file except in
compliance with the License. * You may obtain a copy of the License at *
http://www.apache.org/licenses/LICENSE-2.0. * * Unless required by applicable law or agreed to in
writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific
language governing permissions and limitations * under the License. * * Open MCT Web includes source
code licensed under additional open source * licenses. See the Open Source Licenses file
(LICENSES.md) included with * this source code distribution or the Licensing information page
available * at runtime from the About dialog for additional information.
*****************************************************************************/
<!--
Open MCT, Copyright (c) 2014-2023, United States Government
as represented by the Administrator of the National Aeronautics and Space
Administration. All rights reserved.
Open MCT is licensed under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
Open MCT includes source code licensed under additional open source
licenses. See the Open Source Licenses file (LICENSES.md) included with
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<template>
<div v-if="readOnly === false" ref="clockButton" class="c-tc-input-popup__options">
<div class="c-menu-button c-ctrl-wrapper c-ctrl-wrapper--menus-left">
<button
class="c-button--menu js-clock-button"
:class="[buttonCssClass, selectedClock.cssClass]"
aria-label="Time Conductor Clock Menu"
@click.prevent.stop="showClocksMenu"
>
<span class="c-button__label">{{ selectedClock.name }}</span>
</button>
</div>
</div>
<div v-else class="c-compact-tc__setting-value__elem" :title="`Clock: ${selectedClock.name}`">
<div v-else class="c-compact-tc__setting-value__elem" aria-label="Time Conductor Clock">
{{ selectedClock.name }}
</div>
</template>

View File

@ -32,6 +32,7 @@
<div
class="c-compact-tc__setting-value u-fade-truncate--lg --no-sep"
:title="`Start bounds: ${formattedBounds.start}`"
aria-label="Start bounds"
>
{{ formattedBounds.start }}
</div>
@ -39,6 +40,7 @@
<div
class="c-compact-tc__setting-value u-fade-truncate--lg --no-sep"
:title="`End bounds: ${formattedBounds.end}`"
aria-label="End bounds"
>
{{ formattedBounds.end }}
</div>

View File

@ -25,13 +25,19 @@
<button
class="c-button--menu js-mode-button"
:class="[buttonCssClass, selectedMode.cssClass]"
aria-label="Time Conductor Mode Menu"
@click.prevent.stop="showModesMenu"
>
<span class="c-button__label">{{ selectedMode.name }}</span>
</button>
</div>
</div>
<div v-else class="c-compact-tc__setting-value__elem" :title="`Mode: ${selectedMode.name}`">
<div
v-else
role="button"
class="c-compact-tc__setting-value__elem"
aria-label="Time Conductor Mode"
>
{{ selectedMode.name }}
</div>
</template>

View File

@ -28,6 +28,7 @@
<button
class="c-button--menu c-time-system-button"
:class="[buttonCssClass]"
aria-label="Time Conductor Time System"
@click.prevent.stop="showTimeSystemMenu"
>
<span class="c-button__label">{{ selectedTimeSystem.name }}</span>

View File

@ -45,16 +45,21 @@
></div>
</div>
<div class="c-datetime-picker__calendar c-calendar">
<ul class="c-calendar__row--header l-cal-row">
<li v-for="day in ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa']" :key="day">
<div class="c-calendar__row--header l-cal-row">
<div
v-for="day in ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa']"
:key="day"
class="c-calendar-cell"
>
{{ day }}
</li>
</ul>
<ul v-for="(row, tableIndex) in table" :key="tableIndex" class="c-calendar__row--body">
<li
</div>
</div>
<div v-for="(row, tableIndex) in table" :key="tableIndex" class="c-calendar__row--body">
<div
v-for="(cell, rowIndex) in row"
:key="rowIndex"
:class="{ 'is-in-month': isInCurrentMonth(cell), selected: isSelected(cell) }"
class="c-calendar-cell"
@click="select(cell)"
>
<div class="c-calendar__day--prime">
@ -63,8 +68,8 @@
<div class="c-calendar__day--sub">
{{ cell.dayOfYear }}
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>

View File

@ -563,6 +563,10 @@
}
}
}
.pr-time-input input {
width: 3.5em; // Needed for Firefox
}
}
.c-compact-tc {

View File

@ -1,101 +1,107 @@
/******************************************************** PICKER */
.c-datetime-picker {
@include userSelectNone();
padding: $interiorMarginLg !important;
display: flex !important; // Override .c-menu display: block;
flex-direction: column;
> * + * {
margin-top: $interiorMargin;
}
@include userSelectNone();
padding: $interiorMarginLg !important;
display: flex !important; // Override .c-menu display: block;
flex-direction: column;
&__close-button {
display: none; // Only show when body.phone, see below.
}
> * + * {
margin-top: $interiorMargin;
}
&__pager {
flex: 0 0 auto;
}
&__close-button {
display: none; // Only show when body.phone, see below.
}
&__calendar {
border-top: 1px solid $colorInteriorBorder;
flex: 1 1 auto;
}
&__pager {
flex: 0 0 auto;
}
&__calendar {
border-top: 1px solid $colorInteriorBorder;
flex: 1 1 auto;
}
}
.c-pager {
display: grid;
grid-column-gap: $interiorMargin;
grid-template-rows: 1fr;
grid-template-columns: auto 1fr auto;
align-items: center;
display: grid;
grid-column-gap: $interiorMargin;
grid-template-rows: 1fr;
grid-template-columns: auto 1fr auto;
align-items: center;
.c-icon-button {
font-size: 0.8em;
}
.c-icon-button {
font-size: 0.8em;
}
&__month-year {
text-align: center;
}
&__month-year {
text-align: center;
}
}
/******************************************************** CALENDAR */
.c-calendar {
display: grid;
grid-template-columns: repeat(7, min-content);
grid-template-rows: auto;
grid-gap: 1px;
height: 100%;
$mutedOpacity: 0.5;
display: grid;
grid-template-columns: repeat(7, min-content);
grid-template-rows: auto;
grid-gap: 1px;
$mutedOpacity: 0.5;
ul {
display: contents;
&[class*='--header'] {
pointer-events: none;
li {
opacity: $mutedOpacity;
}
}
}
li {
display: flex;
flex-direction: column;
justify-content: center !important;
padding: $interiorMargin;
&.is-in-month {
background: $colorMenuElementHilite;
[class*="__row"] {
display: contents;
}
&.selected {
background: $colorKey;
color: $colorKeyFg;
}
}
.c-calendar__row--header {
pointer-events: none;
&__day {
&--sub {
opacity: $mutedOpacity;
font-size: 0.8em;
.c-calendar-cell {
opacity: $mutedOpacity;
}
}
.c-calendar-cell {
display: flex;
flex-direction: column;
align-items: center;
padding: $interiorMargin;
cursor: pointer;
@include hover {
background: $colorMenuHovBg;
}
&.is-in-month {
background: $colorMenuElementHilite;
}
&.selected {
background: $colorKey;
color: $colorKeyFg;
}
}
&__day {
&--sub {
opacity: $mutedOpacity;
font-size: 0.8em;
}
}
}
}
/******************************************************** MOBILE */
body.phone {
.c-datetime-picker {
&.c-menu {
@include modalFullScreen();
.c-datetime-picker {
&.c-menu {
@include modalFullScreen();
}
&__close-button {
display: flex;
justify-content: flex-end;
}
}
&__close-button {
display: flex;
justify-content: flex-end;
.c-calendar {
grid-template-columns: repeat(7, auto);
}
}
.c-calendar {
grid-template-columns: repeat(7, auto);
}
}

View File

@ -1,16 +1,24 @@
/***************************************************************************** * Open MCT Web,
Copyright (c) 2014-2023, United States Government * as represented by the Administrator of the
National Aeronautics and Space * Administration. All rights reserved. * * Open MCT Web is licensed
under the Apache License, Version 2.0 (the * "License"); you may not use this file except in
compliance with the License. * You may obtain a copy of the License at *
http://www.apache.org/licenses/LICENSE-2.0. * * Unless required by applicable law or agreed to in
writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific
language governing permissions and limitations * under the License. * * Open MCT Web includes source
code licensed under additional open source * licenses. See the Open Source Licenses file
(LICENSES.md) included with * this source code distribution or the Licensing information page
available * at runtime from the About dialog for additional information.
*****************************************************************************/
<!--
Open MCT, Copyright (c) 2014-2023, United States Government
as represented by the Administrator of the National Aeronautics and Space
Administration. All rights reserved.
Open MCT is licensed under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
Open MCT includes source code licensed under additional open source
licenses. See the Open Source Licenses file (LICENSES.md) included with
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<template>
<div ref="clockMenuButton" class="c-ctrl-wrapper c-ctrl-wrapper--menus-up">
<div class="c-menu-button c-ctrl-wrapper c-ctrl-wrapper--menus-left">
@ -18,6 +26,7 @@ available * at runtime from the About dialog for additional information.
v-if="selectedClock"
class="c-icon-button c-button--menu js-clock-button"
:class="[buttonCssClass, selectedClock.cssClass]"
aria-label="Independent Time Conductor Clock Menu"
@click.prevent.stop="showClocksMenu"
>
<span class="c-button__label">{{ selectedClock.name }}</span>
@ -48,7 +57,7 @@ export default {
}
}
},
data: function () {
data() {
const activeClock = this.getActiveClock();
return {

View File

@ -25,6 +25,7 @@
<button
class="c-icon-button c-button--menu js-mode-button"
:class="[buttonCssClass, selectedMode.cssClass]"
aria-label="Independent Time Conductor Mode Menu"
@click.prevent.stop="showModesMenu"
>
<span class="c-button__label">{{ selectedMode.name }}</span>

View File

@ -28,17 +28,17 @@
{ 'is-expanded': independentTCEnabled }
]"
>
<toggle-switch
<ToggleSwitch
id="independentTCToggle"
class="c-toggle-switch--mini"
:checked="independentTCEnabled"
:title="toggleTitle"
:name="toggleTitle"
@change="toggleIndependentTC"
/>
<ConductorModeIcon />
<conductor-inputs-fixed
<ConductorInputsFixed
v-if="showFixedInputs"
class="c-compact-tc__bounds--fixed"
:object-path="objectPath"
@ -46,7 +46,7 @@
:compact="true"
/>
<conductor-inputs-realtime
<ConductorInputsRealtime
v-if="showRealtimeInputs"
class="c-compact-tc__bounds--real-time"
:object-path="objectPath"
@ -55,10 +55,12 @@
/>
<div
v-if="independentTCEnabled"
role="button"
class="c-not-button c-not-button--compact c-compact-tc__gear icon-gear"
aria-label="Independent Time Conductor Settings"
></div>
<conductor-pop-up
<ConductorPopUp
v-if="showConductorPopup"
ref="conductorPopup"
:object-path="objectPath"
@ -145,7 +147,7 @@ export default {
},
computed: {
toggleTitle() {
return `${this.independentTCEnabled ? 'Disable' : 'Enable'} independent Time Conductor`;
return `${this.independentTCEnabled ? 'Disable' : 'Enable'} Independent Time Conductor`;
},
showFixedInputs() {
return this.isFixed && this.independentTCEnabled;

View File

@ -42,8 +42,11 @@ export default {
methods: {
initializePopup() {
this.conductorPopup = this.$refs.conductorPopup.$el;
document.body.appendChild(this.conductorPopup); // remove from container as it (and it's ancestors) have overflow:hidden
// we need to append it the first time since the popup has overflow:hidden
// then we show/hide based on the flag
if (this.conductorPopup.parentNode !== document.body) {
document.body.appendChild(this.conductorPopup);
}
this.$nextTick(() => {
window.addEventListener('resize', this.positionBox);
document.addEventListener('click', this.handleClickAway);
@ -97,11 +100,6 @@ export default {
if (!this.conductorPopup) {
return;
}
if (this.conductorPopup.parentNode === document.body) {
document.body.removeChild(this.conductorPopup);
}
this.showConductorPopup = false;
this.conductorPopup = null;
this.positionX = -10000; // reset it off screan

View File

@ -108,25 +108,27 @@ describe('time conductor', () => {
});
describe('in realtime mode', () => {
beforeEach((done) => {
beforeEach(async () => {
openmct.time.setClockOffsets({
start: -THIRTY_MINUTES,
end: THIRTY_SECONDS
});
const switcher = appHolder.querySelector('.is-fixed-mode');
const clickEvent = createMouseEvent('click');
switcher.dispatchEvent(clickEvent);
Vue.nextTick(() => {
const modeButton = switcher.querySelector('.c-tc-input-popup .c-button--menu');
const clickEvent1 = createMouseEvent('click');
modeButton.dispatchEvent(clickEvent1);
Vue.nextTick(() => {
const clockItem = document.querySelectorAll(
'.c-conductor__mode-menu .c-super-menu__menu li'
)[1];
const clickEvent2 = createMouseEvent('click');
clockItem.dispatchEvent(clickEvent2);
Vue.nextTick(() => {
done();
});
});
});
await Vue.nextTick();
const modeButton = switcher.querySelector('.c-tc-input-popup .c-button--menu');
const clickEvent1 = createMouseEvent('click');
modeButton.dispatchEvent(clickEvent1);
await Vue.nextTick();
const clockItem = document.querySelectorAll(
'.c-conductor__mode-menu .c-super-menu__menu li'
)[1];
const clickEvent2 = createMouseEvent('click');
clockItem.dispatchEvent(clickEvent2);
await Vue.nextTick();
await Vue.nextTick();
});
it('shows delta inputs', () => {

View File

@ -1,83 +1,94 @@
<template>
<form ref="fixedDeltaInput" class="c-tc-input-popup__input-grid">
<div class="pr-time-label"><em>Start</em> Date</div>
<div class="pr-time-label">Time Z</div>
<div class="pr-time-label"></div>
<div class="pr-time-label"><em>End</em> Date</div>
<div class="pr-time-label">Time Z</div>
<div class="pr-time-label"></div>
<form ref="fixedDeltaInput">
<div class="c-tc-input-popup__input-grid">
<div class="pr-time-label"><em>Start</em> Date</div>
<div class="pr-time-label">Time</div>
<div class="pr-time-label"></div>
<div class="pr-time-label"><em>End</em> Date</div>
<div class="pr-time-label">Time</div>
<div class="pr-time-label"></div>
<div class="pr-time-input pr-time-input--date pr-time-input--input-and-button">
<input
ref="startDate"
v-model="formattedBounds.start"
class="c-input--datetime"
type="text"
autocorrect="off"
spellcheck="false"
@change="validateAllBounds('startDate')"
/>
<date-picker
v-if="isUTCBased"
class="c-ctrl-wrapper--menus-left"
:default-date-time="formattedBounds.start"
:formatter="timeFormatter"
@date-selected="startDateSelected"
/>
</div>
<div class="pr-time-input pr-time-input--date pr-time-input--input-and-button">
<input
ref="startDate"
v-model="formattedBounds.start"
class="c-input--datetime"
type="text"
autocorrect="off"
spellcheck="false"
aria-label="Start date"
@change="validateAllBounds('startDate')"
/>
<date-picker
v-if="isUTCBased"
class="c-ctrl-wrapper--menus-left"
:default-date-time="formattedBounds.start"
:formatter="timeFormatter"
@date-selected="startDateSelected"
/>
</div>
<div class="pr-time-input pr-time-input--time">
<input
ref="startTime"
v-model="formattedBounds.startTime"
class="c-input--datetime"
type="text"
autocorrect="off"
spellcheck="false"
@change="validateAllBounds('startDate')"
/>
</div>
<div class="pr-time-input pr-time-input--time">
<input
ref="startTime"
v-model="formattedBounds.startTime"
class="c-input--datetime"
type="text"
autocorrect="off"
spellcheck="false"
aria-label="Start time"
@change="validateAllBounds('startDate')"
/>
</div>
<div class="pr-time-input pr-time-input__start-end-sep icon-arrows-right-left"></div>
<div class="pr-time-input pr-time-input__start-end-sep icon-arrows-right-left"></div>
<div class="pr-time-input pr-time-input--date pr-time-input--input-and-button">
<input
ref="endDate"
v-model="formattedBounds.end"
class="c-input--datetime"
type="text"
autocorrect="off"
spellcheck="false"
@change="validateAllBounds('endDate')"
/>
<date-picker
v-if="isUTCBased"
class="c-ctrl-wrapper--menus-left"
:default-date-time="formattedBounds.end"
:formatter="timeFormatter"
@date-selected="endDateSelected"
/>
</div>
<div class="pr-time-input pr-time-input--date pr-time-input--input-and-button">
<input
ref="endDate"
v-model="formattedBounds.end"
class="c-input--datetime"
type="text"
autocorrect="off"
spellcheck="false"
aria-label="End date"
@change="validateAllBounds('endDate')"
/>
<date-picker
v-if="isUTCBased"
class="c-ctrl-wrapper--menus-left"
:default-date-time="formattedBounds.end"
:formatter="timeFormatter"
@date-selected="endDateSelected"
/>
</div>
<div class="pr-time-input pr-time-input--time">
<input
ref="endTime"
v-model="formattedBounds.endTime"
class="c-input--datetime"
type="text"
autocorrect="off"
spellcheck="false"
@change="validateAllBounds('endDate')"
/>
</div>
<div class="pr-time-input pr-time-input--time">
<input
ref="endTime"
v-model="formattedBounds.endTime"
class="c-input--datetime"
type="text"
autocorrect="off"
spellcheck="false"
aria-label="End time"
@change="validateAllBounds('endDate')"
/>
</div>
<div class="pr-time-input pr-time-input--buttons">
<button
class="c-button c-button--major icon-check"
:disabled="isDisabled"
@click.prevent="submit"
></button>
<button class="c-button icon-x" @click.prevent="hide"></button>
<div class="pr-time-input pr-time-input--buttons">
<button
class="c-button c-button--major icon-check"
:disabled="isDisabled"
aria-label="Submit time bounds"
@click.prevent="submit"
></button>
<button
class="c-button icon-x"
aria-label="Discard time bounds"
@click.prevent="hide"
></button>
</div>
</div>
</form>
</template>

View File

@ -1,131 +1,143 @@
<template>
<form ref="deltaInput" class="c-tc-input-popup__input-grid">
<div class="pr-time-label icon-minus">Hrs</div>
<div class="pr-time-label">Mins</div>
<div class="pr-time-label">Secs</div>
<div class="pr-time-label"></div>
<div class="pr-time-label icon-plus">Hrs</div>
<div class="pr-time-label">Mins</div>
<div class="pr-time-label">Secs</div>
<div class="pr-time-label"></div>
<form ref="deltaInput">
<div class="c-tc-input-popup__input-grid">
<div class="pr-time-label icon-minus">Hrs</div>
<div class="pr-time-label">Mins</div>
<div class="pr-time-label">Secs</div>
<div class="pr-time-label"></div>
<div class="pr-time-label icon-plus">Hrs</div>
<div class="pr-time-label">Mins</div>
<div class="pr-time-label">Secs</div>
<div class="pr-time-label"></div>
<div class="pr-time-input">
<input
ref="startInputHrs"
v-model="startInputHrs"
class="pr-time-input__hrs"
step="1"
type="number"
min="0"
max="23"
title="Enter 0 - 23"
@change="validate()"
@keyup="validate()"
@focusin="selectAll($event)"
@focusout="format('startInputHrs')"
@wheel="increment($event, 'startInputHrs')"
/>
<b>:</b>
</div>
<div class="pr-time-input">
<input
ref="startInputMins"
v-model="startInputMins"
type="number"
class="pr-time-input__mins"
min="0"
max="59"
title="Enter 0 - 59"
step="1"
@change="validate()"
@keyup="validate()"
@focusin="selectAll($event)"
@focusout="format('startInputMins')"
@wheel="increment($event, 'startInputMins')"
/>
<b>:</b>
</div>
<div class="pr-time-input">
<input
ref="startInputSecs"
v-model="startInputSecs"
type="number"
class="pr-time-input__secs"
min="0"
max="59"
title="Enter 0 - 59"
step="1"
@change="validate()"
@keyup="validate()"
@focusin="selectAll($event)"
@focusout="format('startInputSecs')"
@wheel="increment($event, 'startInputSecs')"
/>
</div>
<div class="pr-time-input">
<input
ref="startInputHrs"
v-model="startInputHrs"
class="pr-time-input__hrs"
step="1"
type="number"
min="0"
max="23"
title="Enter 0 - 23"
aria-label="Start offset hours"
@change="validate()"
@keyup="validate()"
@focusin="selectAll($event)"
@focusout="format('startInputHrs')"
@wheel="increment($event, 'startInputHrs')"
/>
<b>:</b>
</div>
<div class="pr-time-input">
<input
ref="startInputMins"
v-model="startInputMins"
type="number"
class="pr-time-input__mins"
min="0"
max="59"
title="Enter 0 - 59"
step="1"
aria-label="Start offset minutes"
@change="validate()"
@keyup="validate()"
@focusin="selectAll($event)"
@focusout="format('startInputMins')"
@wheel="increment($event, 'startInputMins')"
/>
<b>:</b>
</div>
<div class="pr-time-input">
<input
ref="startInputSecs"
v-model="startInputSecs"
type="number"
class="pr-time-input__secs"
min="0"
max="59"
title="Enter 0 - 59"
step="1"
aria-label="Start offset seconds"
@change="validate()"
@keyup="validate()"
@focusin="selectAll($event)"
@focusout="format('startInputSecs')"
@wheel="increment($event, 'startInputSecs')"
/>
</div>
<div class="pr-time-input pr-time-input__start-end-sep icon-arrows-right-left"></div>
<div class="pr-time-input pr-time-input__start-end-sep icon-arrows-right-left"></div>
<div class="pr-time-input">
<input
ref="endInputHrs"
v-model="endInputHrs"
class="pr-time-input__hrs"
step="1"
type="number"
min="0"
max="23"
title="Enter 0 - 23"
@change="validate()"
@keyup="validate()"
@focusin="selectAll($event)"
@focusout="format('endInputHrs')"
@wheel="increment($event, 'endInputHrs')"
/>
<b>:</b>
</div>
<div class="pr-time-input">
<input
ref="endInputMins"
v-model="endInputMins"
type="number"
class="pr-time-input__mins"
min="0"
max="59"
title="Enter 0 - 59"
step="1"
@change="validate()"
@keyup="validate()"
@focusin="selectAll($event)"
@focusout="format('endInputMins')"
@wheel="increment($event, 'endInputMins')"
/>
<b>:</b>
</div>
<div class="pr-time-input">
<input
ref="endInputSecs"
v-model="endInputSecs"
type="number"
class="pr-time-input__secs"
min="0"
max="59"
title="Enter 0 - 59"
step="1"
@change="validate()"
@keyup="validate()"
@focusin="selectAll($event)"
@focusout="format('endInputSecs')"
@wheel="increment($event, 'endInputSecs')"
/>
</div>
<div class="pr-time-input">
<input
ref="endInputHrs"
v-model="endInputHrs"
class="pr-time-input__hrs"
step="1"
type="number"
min="0"
max="23"
title="Enter 0 - 23"
aria-label="End offset hours"
@change="validate()"
@keyup="validate()"
@focusin="selectAll($event)"
@focusout="format('endInputHrs')"
@wheel="increment($event, 'endInputHrs')"
/>
<b>:</b>
</div>
<div class="pr-time-input">
<input
ref="endInputMins"
v-model="endInputMins"
type="number"
class="pr-time-input__mins"
min="0"
max="59"
title="Enter 0 - 59"
step="1"
@change="validate()"
@keyup="validate()"
@focusin="selectAll($event)"
@focusout="format('endInputMins')"
@wheel="increment($event, 'endInputMins')"
/>
<b>:</b>
</div>
<div class="pr-time-input">
<input
ref="endInputSecs"
v-model="endInputSecs"
type="number"
class="pr-time-input__secs"
min="0"
max="59"
title="Enter 0 - 59"
step="1"
aria-label="End offset seconds"
@change="validate()"
@keyup="validate()"
@focusin="selectAll($event)"
@focusout="format('endInputSecs')"
@wheel="increment($event, 'endInputSecs')"
/>
</div>
<div class="pr-time-input pr-time-input--buttons">
<button
class="c-button c-button--major icon-check"
:disabled="isDisabled"
@click.prevent="submit"
></button>
<button class="c-button icon-x" @click.prevent="hide"></button>
<div class="pr-time-input pr-time-input--buttons">
<button
class="c-button c-button--major icon-check"
:disabled="isDisabled"
aria-label="Submit time offsets"
@click.prevent="submit"
></button>
<button
class="c-button icon-x"
aria-label="Discard time offsets"
@click.prevent="hide"
></button>
</div>
</div>
</form>
</template>
@ -167,7 +179,7 @@ export default {
methods: {
format(ref) {
const curVal = this[ref];
this[ref] = curVal.padStart(2, '0');
this[ref] = curVal.toString().padStart(2, '0');
},
validate() {
let disabled = false;
@ -226,25 +238,16 @@ export default {
[this.startInputHrs, this.startInputMins, this.startInputSecs] =
this.offsets.start.split(':');
[this.endInputHrs, this.endInputMins, this.endInputSecs] = this.offsets.end.split(':');
this.numberSelect('startInputHrs');
this.$nextTick(() => {
this.numberSelect('startInputHrs');
});
},
numberSelect(input) {
if (this.$refs[input] === undefined || this.$refs[input] === null) {
return;
}
this.$refs[input].focus();
// change to text, select, then change back to number
// number inputs do not support select()
this.$nextTick(() => {
if (this.$refs[input] === undefined) {
return;
}
this.$refs[input].setAttribute('type', 'text');
this.$refs[input].select();
this.$nextTick(() => {
this.$refs[input].setAttribute('type', 'number');
});
});
this.$refs[input].select();
},
selectAll($ev) {
$ev.target.select();