1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-10-14 06:51:58 +00:00
* Added: Backup and Restore now supports backing up any binary data stored in FFZ settings, creating a `zip` file rather than a `json` file.
* Fixed: Remove dead code from the `clear-settings` menu component.
* Changed: Update the theme mapping to include missing elements.
* Changed: Data Management > Storage >> Provider now indicates if a provider supports storing binary data.
* Changed: Update the link-parsing regex to match Twitch. Currently under limited roll-out while ensuring the implementation is bug-free.
* API Added: `setting-hotkey` now functions as would be expected and can be used.
* API Changed: A setting's `onUIChange` method now has the Vue component as its second argument, for getting any necessary state from the settings UI.
* API Changed: Providers now sanity check the format of Blobs before storing them.
This commit is contained in:
SirStendec 2021-02-10 16:53:10 -05:00
parent 5412a928a1
commit 2c5937c8af
20 changed files with 574 additions and 138 deletions

View file

@ -0,0 +1,171 @@
<template lang="html">
<div class="ffz--key-widget">
<div class="tw-relative tw-full-width tw-mg-05">
<div
ref="input"
v-bind="$attrs"
class="default-dimmable tw-block tw-border-radius-medium tw-font-size-6 tw-full-width tw-input tw-pd-l-1 tw-pd-r-3 tw-pd-y-05 tw-mg-y-05"
tabindex="0"
@click="startRecording"
@keydown="onKey"
@keyup="onKeyUp"
@blur="cancelRecording"
>
<template v-if="active">
{{ t('setting.record-key', 'Press a Key') }}
</template>
<template v-else-if="value == null">
{{ t('setting.unset', 'Unset') }}
</template>
<template v-else>
{{ value }}
</template>
</div>
<button
class="ffz-button--hollow ffz-clear-key tw-absolute tw-top-0 tw-bottom-0 tw-right-0 tw-border-l tw-z-default tw-pd-x-1 tw-tooltip__container"
@click="clear"
>
<figure class="ffz-i-trash" />
<div class="tw-tooltip tw-tooltip--down tw-tooltip--align-right">
{{ t('setting.clear', 'Clear') }}
</div>
</button>
</div>
</div>
</template>
<script>
import {KEYS} from 'utilities/constants';
const IGNORE_KEYS = [
KEYS.Shift,
KEYS.Control,
KEYS.Alt,
KEYS.Meta
];
const BAD_KEYS = [
KEYS.Escape,
KEYS.Tab
];
const KEYS_MAP = {
Backquote: '`',
Comma: ',',
Period: '.',
Slash: '/',
Semicolon: ';',
Quote: "'",
BracketLeft: '[',
BracketRight: ']',
Backslash: '\\',
Minus: '-',
Equal: '=',
ArrowLeft: 'left',
ArrowRight: 'right',
ArrowUp: 'up',
ArrowDown: 'down'
};
for(const num of [1,2,3,4,5,6,7,8,9,0])
KEYS_MAP[`Digit${num}`] = `${num}`;
for(const letter of 'abcdefghijklmnopqrstuvwxyz')
KEYS_MAP[`Key${letter.toUpperCase()}`] = letter;
export default {
props: {
value: String
},
data() {
return {
active: false
}
},
methods: {
onKey(e) {
if ( this.active )
this.record(e);
},
onKeyUp(e) {
if ( this.active )
this.finishRecording(e);
else {
const key = e.keyCode || e.which;
if ( key === KEYS.Enter || key === KEYS.Space )
this.startRecording(e);
}
},
stop(e) {
e.preventDefault();
e.stopImmediatePropagation();
e.stopPropagation();
},
startRecording(e) {
if ( e )
this.stop(e);
if ( this.active )
return;
this.active = true;
this.key = null;
},
record(e) {
const key = e.keyCode || e.which;
if ( BAD_KEYS.includes(key) )
return;
this.stop(e);
if ( IGNORE_KEYS.includes(key) )
return;
this.key = e;
},
cancelRecording() {
this.active = false;
},
finishRecording(e) {
const k = e.keyCode || e.which;
if ( BAD_KEYS.includes(k) )
return;
this.stop(e);
if ( IGNORE_KEYS.includes(k) )
return;
this.active = false;
const key = this.key;
this.key = null;
if ( ! key )
return;
let code = KEYS_MAP[key.code];
if ( ! code )
code = key.key;
const val = `${key.ctrlKey ? 'ctrl+' : ''}${key.altKey ? 'alt+' : ''}${key.shiftKey ? 'shift+' : ''}${code}`;
this.$emit('input', val);
},
clear() {
this.$emit('input', null);
}
}
}
</script>