mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-08-04 05:21:21 +02:00
.devcontainer
.github
.vscode
build
client
assets
components
app
cards
content
controls
covers
modals
player
prompt
readers
stats
tables
ui
Btn.vue
Checkbox.vue
ContextMenuDropdown.vue
Dropdown.vue
EditableText.vue
FileInput.vue
IconBtn.vue
InputDropdown.vue
LibrariesDropdown.vue
LibraryIcon.vue
LoadingIndicator.vue
MediaIconPicker.vue
MultiSelect.vue
MultiSelectDropdown.vue
MultiSelectQueryInput.vue
QueryInput.vue
RangeInput.vue
ReadIconBtn.vue
RichTextEditor.vue
SelectInput.vue
TextInput.vue
TextInputWithLabel.vue
TextareaInput.vue
TextareaWithLabel.vue
TimePicker.vue
ToggleBtns.vue
ToggleSwitch.vue
Tooltip.vue
VueTrix.vue
widgets
cypress
layouts
middleware
mixins
pages
players
plugins
static
store
strings
cypress.config.js
nuxt.config.js
package-lock.json
package.json
tailwind.config.js
docs
images
server
test
.dockerignore
.editorconfig
.gitattributes
.gitignore
.prettierrc
Dockerfile
LICENSE
custom-metadata-provider-specification.yaml
docker-compose.yml
docker-template.xml
index.js
package-lock.json
package.json
prod.js
readme.md
213 lines
6.8 KiB
Vue
213 lines
6.8 KiB
Vue
<template>
|
|
<div tabindex="0" @focus="focusDigit('second0')" class="relative">
|
|
<div class="rounded text-gray-200 border w-full px-3 py-2" :class="focusedDigit ? 'bg-primary bg-opacity-50 border-gray-300' : 'bg-primary border-gray-600'" @click="clickInput" v-click-outside="clickOutsideObj">
|
|
<div class="flex items-center">
|
|
<template v-for="(digit, index) in digitDisplay">
|
|
<div v-if="digit == ':'" :key="index" class="px-px" @click.stop="clickMedian(index)">:</div>
|
|
<div v-else :key="index" class="px-px" :class="{ 'digit-focused': focusedDigit == digit }" @click.stop="focusDigit(digit)">{{ digits[digit] }}</div>
|
|
</template>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
props: {
|
|
value: [String, Number],
|
|
showThreeDigitHour: Boolean
|
|
},
|
|
data() {
|
|
return {
|
|
clickOutsideObj: {
|
|
handler: this.clickOutside,
|
|
events: ['mousedown'],
|
|
isActive: true
|
|
},
|
|
digitDisplay: ['hour1', 'hour0', ':', 'minute1', 'minute0', ':', 'second1', 'second0'],
|
|
focusedDigit: null,
|
|
digits: {
|
|
hour2: 0,
|
|
hour1: 0,
|
|
hour0: 0,
|
|
minute1: 0,
|
|
minute0: 0,
|
|
second1: 0,
|
|
second0: 0
|
|
},
|
|
isOver99Hours: false
|
|
}
|
|
},
|
|
watch: {
|
|
value: {
|
|
immediate: true,
|
|
handler() {
|
|
this.initDigits()
|
|
}
|
|
}
|
|
},
|
|
computed: {},
|
|
methods: {
|
|
initDigits() {
|
|
var totalSeconds = !this.value || isNaN(this.value) ? 0 : Number(this.value)
|
|
totalSeconds = Math.round(totalSeconds)
|
|
|
|
var minutes = Math.floor(totalSeconds / 60)
|
|
var seconds = totalSeconds - minutes * 60
|
|
var hours = Math.floor(minutes / 60)
|
|
minutes -= hours * 60
|
|
|
|
this.digits.second1 = seconds <= 9 ? 0 : Number(String(seconds)[0])
|
|
this.digits.second0 = seconds <= 9 ? seconds : Number(String(seconds)[1])
|
|
|
|
this.digits.minute1 = minutes <= 9 ? 0 : Number(String(minutes)[0])
|
|
this.digits.minute0 = minutes <= 9 ? minutes : Number(String(minutes)[1])
|
|
|
|
if (hours > 99) {
|
|
this.digits.hour2 = Number(String(hours)[0])
|
|
this.digits.hour1 = Number(String(hours)[1])
|
|
this.digits.hour0 = Number(String(hours)[2])
|
|
this.isOver99Hours = true
|
|
} else {
|
|
this.digits.hour1 = hours <= 9 ? 0 : Number(String(hours)[0])
|
|
this.digits.hour0 = hours <= 9 ? hours : Number(String(hours)[1])
|
|
this.isOver99Hours = this.showThreeDigitHour
|
|
}
|
|
|
|
if (this.isOver99Hours) {
|
|
this.digitDisplay = ['hour2', 'hour1', 'hour0', ':', 'minute1', 'minute0', ':', 'second1', 'second0']
|
|
} else {
|
|
this.digitDisplay = ['hour1', 'hour0', ':', 'minute1', 'minute0', ':', 'second1', 'second0']
|
|
}
|
|
},
|
|
updateSeconds() {
|
|
var seconds = this.digits.second0 + this.digits.second1 * 10
|
|
seconds += this.digits.minute0 * 60 + this.digits.minute1 * 600
|
|
seconds += this.digits.hour0 * 3600 + this.digits.hour1 * 36000
|
|
if (this.isOver99Hours) seconds += this.digits.hour2 * 360000
|
|
|
|
if (Number(this.value) !== seconds) {
|
|
this.$emit('input', seconds)
|
|
this.$emit('change', seconds)
|
|
}
|
|
},
|
|
clickMedian(index) {
|
|
// Click colon select digit to right
|
|
if (index >= 5) {
|
|
this.focusedDigit = 'second1'
|
|
} else {
|
|
this.focusedDigit = 'minute1'
|
|
}
|
|
},
|
|
clickOutside() {
|
|
this.removeFocus()
|
|
},
|
|
removeFocus() {
|
|
this.focusedDigit = null
|
|
this.removeListeners()
|
|
},
|
|
focusDigit(digit) {
|
|
if (this.focusedDigit == null || isNaN(this.focusedDigit)) this.initListeners()
|
|
this.focusedDigit = digit
|
|
},
|
|
clickInput() {
|
|
if (this.focusedDigit) return
|
|
this.focusDigit('second0')
|
|
},
|
|
shiftFocusLeft() {
|
|
if (!this.focusedDigit) return
|
|
if (this.focusedDigit.endsWith('2')) return
|
|
|
|
const isDigit1 = this.focusedDigit.endsWith('1')
|
|
if (!isDigit1) {
|
|
const digit1Key = this.focusedDigit.replace('0', '1')
|
|
this.focusedDigit = digit1Key
|
|
} else if (this.focusedDigit.startsWith('second')) {
|
|
this.focusedDigit = 'minute0'
|
|
} else if (this.focusedDigit.startsWith('minute')) {
|
|
this.focusedDigit = 'hour0'
|
|
} else if (this.isOver99Hours && this.focusedDigit.startsWith('hour')) {
|
|
this.focusedDigit = 'hour2'
|
|
}
|
|
},
|
|
shiftFocusRight() {
|
|
if (!this.focusedDigit) return
|
|
if (this.focusedDigit.endsWith('2')) {
|
|
// Must be hour2
|
|
this.focusedDigit = 'hour1'
|
|
return
|
|
}
|
|
const isDigit1 = this.focusedDigit.endsWith('1')
|
|
if (isDigit1) {
|
|
const digit0Key = this.focusedDigit.replace('1', '0')
|
|
this.focusedDigit = digit0Key
|
|
} else if (this.focusedDigit.startsWith('hour')) {
|
|
this.focusedDigit = 'minute1'
|
|
} else if (this.focusedDigit.startsWith('minute')) {
|
|
this.focusedDigit = 'second1'
|
|
}
|
|
},
|
|
increaseFocused() {
|
|
if (!this.focusedDigit) return
|
|
const isDigit1 = this.focusedDigit.endsWith('1')
|
|
const digit = Number(this.digits[this.focusedDigit])
|
|
if (isDigit1 && !this.focusedDigit.startsWith('hour')) this.digits[this.focusedDigit] = (digit + 1) % 6
|
|
else this.digits[this.focusedDigit] = (digit + 1) % 10
|
|
this.updateSeconds()
|
|
},
|
|
decreaseFocused() {
|
|
if (!this.focusedDigit) return
|
|
const isDigit1 = this.focusedDigit.endsWith('1')
|
|
const digit = Number(this.digits[this.focusedDigit])
|
|
if (isDigit1 && !this.focusedDigit.startsWith('hour')) this.digits[this.focusedDigit] = digit - 1 < 0 ? 5 : digit - 1
|
|
else this.digits[this.focusedDigit] = digit - 1 < 0 ? 9 : digit - 1
|
|
this.updateSeconds()
|
|
},
|
|
keydown(evt) {
|
|
if (!this.focusedDigit || !evt.key) return
|
|
|
|
if (evt.key === 'ArrowLeft') {
|
|
return this.shiftFocusLeft()
|
|
} else if (evt.key === 'ArrowRight') {
|
|
return this.shiftFocusRight()
|
|
} else if (evt.key === 'ArrowUp') {
|
|
return this.increaseFocused()
|
|
} else if (evt.key === 'ArrowDown') {
|
|
return this.decreaseFocused()
|
|
} else if (evt.key === 'Enter' || evt.key === 'Escape' || evt.key === 'Tab') {
|
|
return this.removeFocus()
|
|
}
|
|
|
|
if (isNaN(evt.key)) return
|
|
|
|
var digit = Number(evt.key)
|
|
const isDigit1 = this.focusedDigit.endsWith('1')
|
|
if (isDigit1 && !this.focusedDigit.startsWith('hour') && digit >= 6) {
|
|
digit = 5
|
|
}
|
|
|
|
this.digits[this.focusedDigit] = digit
|
|
|
|
this.updateSeconds()
|
|
this.shiftFocusRight()
|
|
},
|
|
initListeners() {
|
|
window.addEventListener('keydown', this.keydown)
|
|
},
|
|
removeListeners() {
|
|
window.removeEventListener('keydown', this.keydown)
|
|
}
|
|
},
|
|
mounted() {},
|
|
beforeDestroy() {
|
|
this.removeListeners()
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.digit-focused {
|
|
background-color: #555;
|
|
}
|
|
</style>
|