Sort out inputs, shortcut button
This commit is contained in:
parent
6ce8bba6b7
commit
0daef615c1
189
src/common/components/EditShortcutButton.vue
Normal file
189
src/common/components/EditShortcutButton.vue
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex flex-row">
|
||||||
|
<div
|
||||||
|
class="flex-grow button"
|
||||||
|
@click="editShortcut()"
|
||||||
|
|
||||||
|
>
|
||||||
|
<template v-if="!editing">
|
||||||
|
{{shortcutDisplay}}
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
{{currentKeypress ?? 'Press a key'}}
|
||||||
|
<input ref="input"
|
||||||
|
class="hidden-input"
|
||||||
|
@keyup.capture="keyup($event)"
|
||||||
|
@keydown.capture="keydown($event)"
|
||||||
|
@input.prevent=""
|
||||||
|
@blur="editing = false;"
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import KeyboardShortcutParser from '../js/KeyboardShortcutParser';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
shortcut: Object,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
currentKeypress: undefined,
|
||||||
|
currentKey: undefined,
|
||||||
|
editing: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
shortcutDisplay() {
|
||||||
|
if (!this.shortcut) {
|
||||||
|
return '(no shortcut)'
|
||||||
|
}
|
||||||
|
return KeyboardShortcutParser.parseShortcut(this.shortcut);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
editShortcut() {
|
||||||
|
this.editing = true;
|
||||||
|
this.currentKeypress = undefined;
|
||||||
|
this.currentKey = undefined;
|
||||||
|
|
||||||
|
// input doesn't exist now, but will exist on the next tick
|
||||||
|
this.$nextTick(()=> this.$refs.input.focus());
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Updates currently pressed keypress for display
|
||||||
|
*/
|
||||||
|
keydown(event) {
|
||||||
|
// event.repeat is set to 'true' when key is being held down, but not on
|
||||||
|
// first keydown. We don't need to process subsequent repeats of a keypress
|
||||||
|
// we already processed.
|
||||||
|
if (event.repeat) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const shortcut = KeyboardShortcutParser.generateShortcutFromKeypress(event);
|
||||||
|
const fixedShortcut = this.handleModifierKeypress(shortcut);
|
||||||
|
|
||||||
|
if (this.currentKey === undefined) {
|
||||||
|
this.currentKey = fixedShortcut;
|
||||||
|
} else {
|
||||||
|
// here's a fun fact. Keydown doesn't do modifier keys the way we want —
|
||||||
|
// notably, A-Z0-9 keys are returned without modifier state (all modifiers)
|
||||||
|
// are set to false in keydown events. That means we need to keep track of
|
||||||
|
// modifiers ourselves.
|
||||||
|
if (fixedShortcut.notModifier) {
|
||||||
|
this.currentKey.key = fixedShortcut.key;
|
||||||
|
this.currentKey.code = fixedShortcut.code;
|
||||||
|
} else {
|
||||||
|
this.currentKey = {
|
||||||
|
...fixedShortcut,
|
||||||
|
key: this.currentKey.key,
|
||||||
|
code: this.currentKey.code
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update display
|
||||||
|
this.currentKeypress = KeyboardShortcutParser.parseShortcut(this.currentKey);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Emits shortcutChanged when shortcut is considered changed
|
||||||
|
*/
|
||||||
|
keyup(event) {
|
||||||
|
const shortcut = KeyboardShortcutParser.generateShortcutFromKeypress(event);
|
||||||
|
const fixedShortcut = this.handleModifierKeypress(shortcut);
|
||||||
|
|
||||||
|
if (fixedShortcut.notModifier) {
|
||||||
|
this.editing = false;
|
||||||
|
this.$emit('shortcutChanged', this.currentKey);
|
||||||
|
console.log('emitted shortcut:', shortcut, 'raw event:', event);
|
||||||
|
} else {
|
||||||
|
// if none of the modifiers are pressed and if no other key is being held down,
|
||||||
|
// we need to reset label back to 'pls press key'
|
||||||
|
if (!fixedShortcut.altKey && !fixedShortcut.ctrlKey && !fixedShortcut.metaKey && !fixedShortcut.shiftKey && !fixedShortcut.code) {
|
||||||
|
this.currentKeypress = undefined;
|
||||||
|
this.currentKey = undefined;
|
||||||
|
} else {
|
||||||
|
this.currentKey = shortcut;
|
||||||
|
this.currentKeypress = KeyboardShortcutParser.parseShortcut(this.currentKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles current keypress if event.keyCode is a modifier key.
|
||||||
|
* Returns true if current event was a modifier key, false if
|
||||||
|
* if was a regular A-Z 0-9 key.
|
||||||
|
*/
|
||||||
|
handleModifierKeypress(event) {
|
||||||
|
const modifierPressed = event.type === 'keydown';
|
||||||
|
|
||||||
|
switch (event.code) {
|
||||||
|
case 'ShiftLeft':
|
||||||
|
case 'ShiftRight':
|
||||||
|
return {
|
||||||
|
...event,
|
||||||
|
key: '…',
|
||||||
|
code: null,
|
||||||
|
shiftKey: modifierPressed
|
||||||
|
}
|
||||||
|
case 'ControlLeft':
|
||||||
|
case 'ControlRight':
|
||||||
|
return {
|
||||||
|
...event,
|
||||||
|
key: '…',
|
||||||
|
code: null,
|
||||||
|
controlKey: modifierPressed
|
||||||
|
};
|
||||||
|
case 'MetaLeft':
|
||||||
|
case 'MetaRight':
|
||||||
|
return {
|
||||||
|
...event,
|
||||||
|
key: '…',
|
||||||
|
code: null,
|
||||||
|
metaKey: modifierPressed
|
||||||
|
};
|
||||||
|
case 'AltLeft':
|
||||||
|
case 'AltRight':
|
||||||
|
return {
|
||||||
|
...event,
|
||||||
|
key: '…',
|
||||||
|
code: null,
|
||||||
|
altKey: modifierPressed
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...event,
|
||||||
|
notModifier: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" src="../../csui/src/res-common/common.scss" scoped></style>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../csui/src/res-common/variables";
|
||||||
|
|
||||||
|
.center-text {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.dark {
|
||||||
|
opacity: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden-input {
|
||||||
|
position: absolute;
|
||||||
|
z-index: -9999;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,38 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="flex flex-column flex-center">
|
|
||||||
<template v-if="!editing">
|
|
||||||
<div class="flex flex-self-center">
|
|
||||||
{{label}}
|
|
||||||
</div>
|
|
||||||
<div class="flex dark flex-self-center">
|
|
||||||
<small>
|
|
||||||
{{shortcut ? `(${shortcut})` : ''}}
|
|
||||||
</small>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<div class="flex flex-row flex-center">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
label: String,
|
|
||||||
shortcut: String,
|
|
||||||
editing: Boolean,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.center-text {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
.dark {
|
|
||||||
opacity: 50%;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -21,6 +21,19 @@ class KeyboardShortcutParser {
|
|||||||
}
|
}
|
||||||
return shortcutCombo;
|
return shortcutCombo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static generateShortcutFromKeypress(event) {
|
||||||
|
return {
|
||||||
|
ctrlKey: event.ctrlKey,
|
||||||
|
shiftKey: event.altKey,
|
||||||
|
altKey: event.altKey,
|
||||||
|
code: event.code,
|
||||||
|
key: event.key,
|
||||||
|
keyup: true,
|
||||||
|
keydown: false,
|
||||||
|
type: event.type, // only needed for purposes of EditShortcutButton
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default KeyboardShortcutParser;
|
export default KeyboardShortcutParser;
|
@ -50,48 +50,58 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- EDIT MODE PANEL -->
|
<!-- EDIT MODE PANEL -->
|
||||||
|
<div class="sub-panel-content">
|
||||||
<div class="edit-action-area">
|
<div class="edit-action-area">
|
||||||
<div>
|
<div class="edit-action-area-header">
|
||||||
Editing options for <b>{{editModeOptions?.crop?.selected?.label}}</b>
|
Editing options for: <b>{{editModeOptions?.crop?.selected?.label}}</b>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Some options are only shown for type 4 (fixed) crops -->
|
<!-- Some options are only shown for type 4 (fixed) crops -->
|
||||||
<template v-if="editModeOptions?.crop?.selected.arguments.type === AspectRatioType.Fixed">
|
<template v-if="editModeOptions?.crop?.selected?.arguments?.type === AspectRatioType.Fixed">
|
||||||
<div>
|
<div class="field">
|
||||||
Label: -- todo --
|
<div class="label">
|
||||||
|
Ratio:
|
||||||
|
</div>
|
||||||
|
<div class="input">
|
||||||
|
<input v-model="editModeOptions.crop.selected.arguments.ratio">
|
||||||
|
</div>
|
||||||
|
<div class="hint">
|
||||||
|
You can enter a ratio in width:height format (e.g. "21:9" or "1:2.39"), or just the factor
|
||||||
|
(in this case, "1:2.39" would become "2.39" and "21:9" would become "2.33"). You should enter
|
||||||
|
your numbers without quote marks. Number will be converted to factor form on save.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<div class="label">
|
||||||
|
Label:
|
||||||
|
</div>
|
||||||
|
<div class="input">
|
||||||
|
<input v-model="editModeOptions.crop.selected.label">
|
||||||
|
</div>
|
||||||
|
<div class="hint">
|
||||||
|
Label for the button. You can make it say something other than ratio.
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
Ratio: -- todo --
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- editing keyboard shortcuts is always allowed -->
|
<!-- editing keyboard shortcuts is always allowed -->
|
||||||
<div>
|
<div class="field">
|
||||||
-- todo: edit keyboard shortcut --
|
<div class="label">Shortcut:</div>
|
||||||
|
<div class="">
|
||||||
|
<EditShortcutButton
|
||||||
|
:shortcut="editModeOptions?.crop?.selected?.shortcut"
|
||||||
|
@shortcutChanged="updateSelectedShortcut($event, 'crop')"
|
||||||
|
>
|
||||||
|
</EditShortcutButton>
|
||||||
|
</div>
|
||||||
|
<div class="hint">
|
||||||
|
<b>Note:</b> Your browser and OS already use certain key combinations that involve Ctrl and Meta (Windows) keys — and, to a lesser extent, Alt.
|
||||||
|
The extension doesn't (and cannot) check whether the keyboard shortcut you enter is actually free for you to use. The extension also won't override
|
||||||
|
any keyboard shortcuts defined by the site itself.
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
|
||||||
------------ <br/>>
|
|
||||||
present items:<br/>>
|
|
||||||
editModeOptions? {{!!editModeOptions}}<br/>
|
|
||||||
.crop? {{!!editModeOptions?.crop}}<br/>
|
|
||||||
.selected? {{!!editModeOptions?.crop?.selected}}<br/>
|
|
||||||
<br/>
|
|
||||||
selected action:<br/>{{editModeOptions?.crop?.selected}}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- <select class=""
|
|
||||||
:value="selectedAction"
|
|
||||||
@change="setAction($event.target.value)"
|
|
||||||
>
|
|
||||||
<option :value="undefined" selected disabled>Select ...</option>
|
|
||||||
<option v-for="(action, key) in ActionList"
|
|
||||||
:value="key"
|
|
||||||
:key="key"
|
|
||||||
>
|
|
||||||
{{action.name}}
|
|
||||||
</option>
|
|
||||||
</select> -->
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-row">
|
<div class="flex flex-row">
|
||||||
@ -297,6 +307,7 @@
|
|||||||
import Button from '../../../common/components/Button.vue'
|
import Button from '../../../common/components/Button.vue'
|
||||||
import KeyboardShortcutParser from '../../../common/js/KeyboardShortcutParser';
|
import KeyboardShortcutParser from '../../../common/js/KeyboardShortcutParser';
|
||||||
import ShortcutButton from '../../../common/components/ShortcutButton';
|
import ShortcutButton from '../../../common/components/ShortcutButton';
|
||||||
|
import EditShortcutButton from '../../../common/components/EditShortcutButton';
|
||||||
import ComputeActionsMixin from '../../../common/mixins/ComputeActionsMixin';
|
import ComputeActionsMixin from '../../../common/mixins/ComputeActionsMixin';
|
||||||
import ExecAction from '../ui-libs/ExecAction';
|
import ExecAction from '../ui-libs/ExecAction';
|
||||||
import BrowserDetect from '../../../ext/conf/BrowserDetect';
|
import BrowserDetect from '../../../ext/conf/BrowserDetect';
|
||||||
@ -319,7 +330,8 @@ export default {
|
|||||||
y: 0
|
y: 0
|
||||||
},
|
},
|
||||||
editMode: true,
|
editMode: true,
|
||||||
editModeOptions: {},
|
editModeOptions: {
|
||||||
|
},
|
||||||
resizerConfig: {
|
resizerConfig: {
|
||||||
crop: null,
|
crop: null,
|
||||||
stretch: null,
|
stretch: null,
|
||||||
@ -357,6 +369,7 @@ export default {
|
|||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
ShortcutButton,
|
ShortcutButton,
|
||||||
|
EditShortcutButton,
|
||||||
Button,
|
Button,
|
||||||
AlignmentOptionsControlComponent
|
AlignmentOptionsControlComponent
|
||||||
},
|
},
|
||||||
@ -521,6 +534,18 @@ export default {
|
|||||||
console.error(`[Ultrawidify] there's a problem with VideoSettings.vue::editAction():`, e);
|
console.error(`[Ultrawidify] there's a problem with VideoSettings.vue::editAction():`, e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
updateSelectedShortcut(shortcut, actionType) {
|
||||||
|
try {
|
||||||
|
if (!this.editModeOptions[actionType]?.selected) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
this.editModeOptions[actionType].selected.shortcut = shortcut
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`[Ultrawidify] there's a problem with VideoSettings.vue::updateShortcut():`, e);
|
||||||
|
}
|
||||||
|
},
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region comms and bus
|
//#region comms and bus
|
||||||
@ -588,4 +613,13 @@ export default {
|
|||||||
padding-bottom: 16px;
|
padding-bottom: 16px;
|
||||||
padding-top: 8px;
|
padding-top: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.edit-action-area {
|
||||||
|
background-color: rgba($blackBg,0.5);
|
||||||
|
padding: 0.5rem;
|
||||||
|
|
||||||
|
.edit-action-area-header {
|
||||||
|
border-bottom: 1px solid rgba(255,255,255,0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -3,3 +3,7 @@ $warning-color: #d6ba4a;
|
|||||||
$primary: rgb(255, 147, 85);
|
$primary: rgb(255, 147, 85);
|
||||||
$primaryBrighter: rgb(255, 174, 127);
|
$primaryBrighter: rgb(255, 174, 127);
|
||||||
$primaryBg: rgba(54, 31, 21, 0.5);
|
$primaryBg: rgba(54, 31, 21, 0.5);
|
||||||
|
|
||||||
|
$blackBg: rgb(11,11,11);
|
||||||
|
$normalTransparentOpacity: 0.5;
|
||||||
|
$hoverTransparentOpacity: 0.9;
|
||||||
|
@ -31,13 +31,18 @@ h1, h2, h3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
background-color: rgba(11,11,11,0.5);
|
background-color: rgba($blackBg, $normalTransparentOpacity);
|
||||||
|
|
||||||
|
padding: 0.5rem 2rem;
|
||||||
|
margin: 3px;
|
||||||
|
|
||||||
color: #aaa;
|
color: #aaa;
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
|
user-select: none !important;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
background-color: rgba(11,11,11,0.9);
|
background-color: rgba($blackBg, $hoverTransparentOpacity);
|
||||||
border-bottom: 1px solid rgba($primary, 0.5);
|
border-bottom: 1px solid rgba($primary, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,3 +56,47 @@ h1, h2, h3 {
|
|||||||
margin: 0.25rem;
|
margin: 0.25rem;
|
||||||
padding: 0.5rem 2rem;
|
padding: 0.5rem 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.field {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
padding-top: 0.5rem;
|
||||||
|
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
flex: 0 0 25%;
|
||||||
|
text-align: right;
|
||||||
|
padding-right: 1rem;
|
||||||
|
}
|
||||||
|
.input {
|
||||||
|
flex: 0 0 70%;
|
||||||
|
background-color: rgba($blackBg, $normalTransparentOpacity);
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-bottom: 1px solid rgba(255,255,255,0.5);
|
||||||
|
padding-top: 0.25rem;
|
||||||
|
padding-bottom: 0.25rem;
|
||||||
|
|
||||||
|
&:active, &:focus, &:focus-within {
|
||||||
|
border-bottom: 1px solid rgba($primary, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
width: 100%;
|
||||||
|
outline: none;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
background-color: transparent;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.hint {
|
||||||
|
padding-left: calc(25% + 1rem);
|
||||||
|
font-size: 0.8rem;
|
||||||
|
opacity: 0.7;
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -226,18 +226,16 @@ small {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
/*display: inline-block;*/
|
border: 1px solid transparent;
|
||||||
// padding-top: 8px;
|
padding: 0.5rem 2rem;
|
||||||
// padding-bottom: 3px;
|
|
||||||
//padding-left: 5px;
|
|
||||||
//padding-right: 5px;
|
|
||||||
border: 1px solid rgb(39, 39, 39);
|
|
||||||
margin-top: 3px;
|
margin-top: 3px;
|
||||||
margin-bottom: 3px;
|
margin-bottom: 3px;
|
||||||
|
|
||||||
color: $text-dim;
|
color: $text-dim;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
user-select: none;;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user