Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
bec48319ec | |||
71a93b2b43 | |||
6ed3f9e414 | |||
dc8f592c1f | |||
f66c31c771 | |||
55e2ae1408 | |||
19c72627fc |
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"author": "syuilo <i@syuilo.com>",
|
"author": "syuilo <i@syuilo.com>",
|
||||||
"version": "8.48.0",
|
"version": "8.50.0",
|
||||||
"clientVersion": "1.0.9876",
|
"clientVersion": "1.0.9883",
|
||||||
"codename": "nighthike",
|
"codename": "nighthike",
|
||||||
"main": "./built/index.js",
|
"main": "./built/index.js",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
@ -1,27 +1,42 @@
|
|||||||
import keyCode from './keycode';
|
import keyCode from './keycode';
|
||||||
|
import { concat } from '../../../prelude/array';
|
||||||
|
|
||||||
const getKeyMap = keymap => Object.keys(keymap).map(input => {
|
type pattern = {
|
||||||
const result = {} as any;
|
which: string[];
|
||||||
|
ctrl?: boolean;
|
||||||
|
shift?: boolean;
|
||||||
|
alt?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
const { keyup, keydown } = keymap[input];
|
type action = {
|
||||||
|
patterns: pattern[];
|
||||||
|
|
||||||
input.split('+').forEach(keyName => {
|
callback: Function;
|
||||||
switch (keyName.toLowerCase()) {
|
};
|
||||||
case 'ctrl':
|
|
||||||
case 'alt':
|
const getKeyMap = keymap => Object.entries(keymap).map(([patterns, callback]): action => {
|
||||||
case 'shift':
|
const result = {
|
||||||
case 'meta':
|
patterns: [],
|
||||||
result[keyName] = true;
|
callback: callback
|
||||||
break;
|
} as action;
|
||||||
default:
|
|
||||||
result.keyCode = keyCode(keyName);
|
result.patterns = patterns.split('|').map(part => {
|
||||||
|
const pattern = {
|
||||||
|
which: []
|
||||||
|
} as pattern;
|
||||||
|
|
||||||
|
part.trim().split('+').forEach(key => {
|
||||||
|
key = key.trim().toLowerCase();
|
||||||
|
switch (key) {
|
||||||
|
case 'ctrl': pattern.ctrl = true; break;
|
||||||
|
case 'alt': pattern.alt = true; break;
|
||||||
|
case 'shift': pattern.shift = true; break;
|
||||||
|
default: pattern.which = keyCode(key).map(k => k.toLowerCase());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
result.callback = {
|
return pattern;
|
||||||
keydown: keydown || keymap[input],
|
});
|
||||||
keyup
|
|
||||||
};
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
@ -34,28 +49,40 @@ export default {
|
|||||||
bind(el, binding) {
|
bind(el, binding) {
|
||||||
el._hotkey_global = binding.modifiers.global === true;
|
el._hotkey_global = binding.modifiers.global === true;
|
||||||
|
|
||||||
el._keymap = getKeyMap(binding.value);
|
const actions = getKeyMap(binding.value);
|
||||||
|
|
||||||
el.dataset.reservedKeyCodes = el._keymap.map(key => `'${key.keyCode}'`).join(' ');
|
// flatten
|
||||||
|
const reservedKeys = concat(concat(actions.map(a => a.patterns.map(p => p.which))));
|
||||||
|
|
||||||
|
el.dataset.reservedKeys = reservedKeys.map(key => `'${key}'`).join(' ');
|
||||||
|
|
||||||
el._keyHandler = e => {
|
el._keyHandler = e => {
|
||||||
const reservedKeyCodes = document.activeElement ? ((document.activeElement as any).dataset || {}).reservedKeyCodes || '' : '';
|
const key = e.code.toLowerCase();
|
||||||
|
|
||||||
|
const targetReservedKeys = document.activeElement ? ((document.activeElement as any).dataset || {}).reservedKeys || '' : '';
|
||||||
if (document.activeElement && ignoreElemens.some(el => document.activeElement.matches(el))) return;
|
if (document.activeElement && ignoreElemens.some(el => document.activeElement.matches(el))) return;
|
||||||
|
|
||||||
for (const hotkey of el._keymap) {
|
for (const action of actions) {
|
||||||
if (el._hotkey_global && reservedKeyCodes.includes(`'${e.keyCode}'`)) break;
|
if (el._hotkey_global && targetReservedKeys.includes(`'${key}'`)) break;
|
||||||
|
|
||||||
const callback = hotkey.keyCode === e.keyCode &&
|
const matched = action.patterns.some(pattern => {
|
||||||
!!hotkey.ctrl === e.ctrlKey &&
|
let matched = pattern.which.includes(key);
|
||||||
!!hotkey.alt === e.altKey &&
|
if (pattern.ctrl && !e.ctrlKey) matched = false;
|
||||||
!!hotkey.shift === e.shiftKey &&
|
if (pattern.shift && !e.shiftKey) matched = false;
|
||||||
!!hotkey.meta === e.metaKey &&
|
if (pattern.alt && !e.altKey) matched = false;
|
||||||
hotkey.callback[e.type];
|
|
||||||
|
|
||||||
if (callback) {
|
if (matched) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
callback(e);
|
action.callback(e);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (matched) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,117 +1,20 @@
|
|||||||
export default searchInput => {
|
export default (input: string): string[] => {
|
||||||
// Keyboard Events
|
if (Object.keys(aliases).some(a => a.toLowerCase() == input.toLowerCase())) {
|
||||||
if (searchInput && typeof searchInput === 'object') {
|
const codes = aliases[input];
|
||||||
const hasKeyCode = searchInput.which || searchInput.keyCode || searchInput.charCode;
|
return Array.isArray(codes) ? codes : [codes];
|
||||||
if (hasKeyCode) {
|
} else {
|
||||||
searchInput = hasKeyCode;
|
return [input];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Numbers
|
|
||||||
// if (typeof searchInput === 'number') {
|
|
||||||
// return names[searchInput]
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Everything else (cast to string)
|
|
||||||
const search = String(searchInput);
|
|
||||||
|
|
||||||
// check codes
|
|
||||||
const foundNamedKeyCodes = codes[search.toLowerCase()];
|
|
||||||
if (foundNamedKeyCodes) {
|
|
||||||
return foundNamedKeyCodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check aliases
|
|
||||||
const foundNamedKeyAliases = aliases[search.toLowerCase()];
|
|
||||||
if (foundNamedKeyAliases) {
|
|
||||||
return foundNamedKeyAliases;
|
|
||||||
}
|
|
||||||
|
|
||||||
// weird character?
|
|
||||||
if (search.length === 1) {
|
|
||||||
return search.charCodeAt(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return undefined;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Get by name
|
|
||||||
*
|
|
||||||
* exports.code['enter'] // => 13
|
|
||||||
*/
|
|
||||||
|
|
||||||
export const codes = {
|
|
||||||
'backspace': 8,
|
|
||||||
'tab': 9,
|
|
||||||
'enter': 13,
|
|
||||||
'shift': 16,
|
|
||||||
'ctrl': 17,
|
|
||||||
'alt': 18,
|
|
||||||
'pause/break': 19,
|
|
||||||
'caps lock': 20,
|
|
||||||
'esc': 27,
|
|
||||||
'space': 32,
|
|
||||||
'page up': 33,
|
|
||||||
'page down': 34,
|
|
||||||
'end': 35,
|
|
||||||
'home': 36,
|
|
||||||
'left': 37,
|
|
||||||
'up': 38,
|
|
||||||
'right': 39,
|
|
||||||
'down': 40,
|
|
||||||
// 'add': 43,
|
|
||||||
'insert': 45,
|
|
||||||
'delete': 46,
|
|
||||||
'command': 91,
|
|
||||||
'left command': 91,
|
|
||||||
'right command': 93,
|
|
||||||
'numpad *': 106,
|
|
||||||
// 'numpad +': 107,
|
|
||||||
'numpad +': 43,
|
|
||||||
'numpad add': 43, // as a trick
|
|
||||||
'numpad -': 109,
|
|
||||||
'numpad .': 110,
|
|
||||||
'numpad /': 111,
|
|
||||||
'num lock': 144,
|
|
||||||
'scroll lock': 145,
|
|
||||||
'my computer': 182,
|
|
||||||
'my calculator': 183,
|
|
||||||
';': 186,
|
|
||||||
'=': 187,
|
|
||||||
',': 188,
|
|
||||||
'-': 189,
|
|
||||||
'.': 190,
|
|
||||||
'/': 191,
|
|
||||||
'`': 192,
|
|
||||||
'[': 219,
|
|
||||||
'\\': 220,
|
|
||||||
']': 221,
|
|
||||||
"'": 222
|
|
||||||
};
|
|
||||||
|
|
||||||
// Helper aliases
|
|
||||||
|
|
||||||
export const aliases = {
|
export const aliases = {
|
||||||
'windows': 91,
|
'esc': 'Escape',
|
||||||
'⇧': 16,
|
'enter': ['Enter', 'NumpadEnter'],
|
||||||
'⌥': 18,
|
'up': 'ArrowUp',
|
||||||
'⌃': 17,
|
'down': 'ArrowDown',
|
||||||
'⌘': 91,
|
'left': 'ArrowLeft',
|
||||||
'ctl': 17,
|
'right': 'ArrowRight',
|
||||||
'control': 17,
|
'plus': ['NumpadAdd', 'Semicolon'],
|
||||||
'option': 18,
|
|
||||||
'pause': 19,
|
|
||||||
'break': 19,
|
|
||||||
'caps': 20,
|
|
||||||
'return': 13,
|
|
||||||
'escape': 27,
|
|
||||||
'spc': 32,
|
|
||||||
'pgup': 33,
|
|
||||||
'pgdn': 34,
|
|
||||||
'ins': 45,
|
|
||||||
'del': 46,
|
|
||||||
'cmd': 91
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -120,20 +23,11 @@ export const aliases = {
|
|||||||
|
|
||||||
// lower case chars
|
// lower case chars
|
||||||
for (let i = 97; i < 123; i++) {
|
for (let i = 97; i < 123; i++) {
|
||||||
codes[String.fromCharCode(i)] = i - 32;
|
const char = String.fromCharCode(i);
|
||||||
|
aliases[char] = `Key${char.toUpperCase()}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// numbers
|
// numbers
|
||||||
for (let i = 48; i < 58; i++) {
|
|
||||||
codes[i - 48] = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
// function keys
|
|
||||||
for (let i = 1; i < 13; i++) {
|
|
||||||
codes['f' + i] = i + 111;
|
|
||||||
}
|
|
||||||
|
|
||||||
// numpad keys
|
|
||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
codes['numpad ' + i] = i + 96;
|
aliases[i] = [`Numpad${i}`, `Digit${i}`];
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<div class="backdrop" ref="backdrop" @click="close"></div>
|
<div class="backdrop" ref="backdrop" @click="close"></div>
|
||||||
<div class="popover" :class="{ compact, big }" ref="popover">
|
<div class="popover" :class="{ compact, big }" ref="popover">
|
||||||
<p v-if="!compact">{{ title }}</p>
|
<p v-if="!compact">{{ title }}</p>
|
||||||
<div>
|
<div ref="buttons" :class="{ showFocus }">
|
||||||
<button @click="react('like')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="1" title="%i18n:common.reactions.like%"><mk-reaction-icon reaction='like'/></button>
|
<button @click="react('like')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="1" title="%i18n:common.reactions.like%"><mk-reaction-icon reaction='like'/></button>
|
||||||
<button @click="react('love')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="2" title="%i18n:common.reactions.love%"><mk-reaction-icon reaction='love'/></button>
|
<button @click="react('love')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="2" title="%i18n:common.reactions.love%"><mk-reaction-icon reaction='love'/></button>
|
||||||
<button @click="react('laugh')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="3" title="%i18n:common.reactions.laugh%"><mk-reaction-icon reaction='laugh'/></button>
|
<button @click="react('laugh')" @mouseover="onMouseover" @mouseout="onMouseout" tabindex="3" title="%i18n:common.reactions.laugh%"><mk-reaction-icon reaction='laugh'/></button>
|
||||||
@ -50,18 +50,37 @@ export default Vue.extend({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: false,
|
required: false,
|
||||||
default: false
|
default: false
|
||||||
|
},
|
||||||
|
|
||||||
|
showFocus: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
|
||||||
|
animation: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
title: placeholder
|
title: placeholder,
|
||||||
|
focus: null
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
keymap(): any {
|
keymap(): any {
|
||||||
return {
|
return {
|
||||||
|
'esc': this.close,
|
||||||
|
'enter|space|plus': this.choose,
|
||||||
|
'up': this.focusUp,
|
||||||
|
'right': this.focusRight,
|
||||||
|
'down': this.focusDown,
|
||||||
|
'left': this.focusLeft,
|
||||||
'1': () => this.react('like'),
|
'1': () => this.react('like'),
|
||||||
'2': () => this.react('love'),
|
'2': () => this.react('love'),
|
||||||
'3': () => this.react('laugh'),
|
'3': () => this.react('laugh'),
|
||||||
@ -76,8 +95,20 @@ export default Vue.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
focus(i) {
|
||||||
|
this.$refs.buttons.childNodes[i].focus();
|
||||||
|
|
||||||
|
if (this.showFocus) {
|
||||||
|
this.title = this.$refs.buttons.childNodes[i].title;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
|
this.focus = 0;
|
||||||
|
|
||||||
const popover = this.$refs.popover as any;
|
const popover = this.$refs.popover as any;
|
||||||
|
|
||||||
const rect = this.source.getBoundingClientRect();
|
const rect = this.source.getBoundingClientRect();
|
||||||
@ -99,7 +130,7 @@ export default Vue.extend({
|
|||||||
anime({
|
anime({
|
||||||
targets: this.$refs.backdrop,
|
targets: this.$refs.backdrop,
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
duration: 100,
|
duration: this.animation ? 100 : 0,
|
||||||
easing: 'linear'
|
easing: 'linear'
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -107,7 +138,7 @@ export default Vue.extend({
|
|||||||
targets: this.$refs.popover,
|
targets: this.$refs.popover,
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
scale: [0.5, 1],
|
scale: [0.5, 1],
|
||||||
duration: 500
|
duration: this.animation ? 500 : 0
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -137,7 +168,7 @@ export default Vue.extend({
|
|||||||
anime({
|
anime({
|
||||||
targets: this.$refs.backdrop,
|
targets: this.$refs.backdrop,
|
||||||
opacity: 0,
|
opacity: 0,
|
||||||
duration: 200,
|
duration: this.animation ? 200 : 0,
|
||||||
easing: 'linear'
|
easing: 'linear'
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -146,13 +177,33 @@ export default Vue.extend({
|
|||||||
targets: this.$refs.popover,
|
targets: this.$refs.popover,
|
||||||
opacity: 0,
|
opacity: 0,
|
||||||
scale: 0.5,
|
scale: 0.5,
|
||||||
duration: 200,
|
duration: this.animation ? 200 : 0,
|
||||||
easing: 'easeInBack',
|
easing: 'easeInBack',
|
||||||
complete: () => {
|
complete: () => {
|
||||||
this.$emit('closed');
|
this.$emit('closed');
|
||||||
this.destroyDom();
|
this.destroyDom();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
focusUp() {
|
||||||
|
this.focus = this.focus == 0 ? 9 : this.focus < 5 ? (this.focus + 4) : (this.focus - 5);
|
||||||
|
},
|
||||||
|
|
||||||
|
focusDown() {
|
||||||
|
this.focus = this.focus == 9 ? 0 : this.focus >= 5 ? (this.focus - 4) : (this.focus + 5);
|
||||||
|
},
|
||||||
|
|
||||||
|
focusRight() {
|
||||||
|
this.focus = this.focus == 9 ? 0 : (this.focus + 1);
|
||||||
|
},
|
||||||
|
|
||||||
|
focusLeft() {
|
||||||
|
this.focus = this.focus == 0 ? 9 : (this.focus - 1);
|
||||||
|
},
|
||||||
|
|
||||||
|
choose() {
|
||||||
|
this.$refs.buttons.childNodes[this.focus].click();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -238,6 +289,21 @@ root(isDark)
|
|||||||
width 240px
|
width 240px
|
||||||
text-align center
|
text-align center
|
||||||
|
|
||||||
|
&.showFocus
|
||||||
|
> button:focus
|
||||||
|
z-index 1
|
||||||
|
|
||||||
|
&:after
|
||||||
|
content ""
|
||||||
|
pointer-events none
|
||||||
|
position absolute
|
||||||
|
top 0
|
||||||
|
right 0
|
||||||
|
bottom 0
|
||||||
|
left 0
|
||||||
|
border 2px solid rgba($theme-color, 0.3)
|
||||||
|
border-radius 4px
|
||||||
|
|
||||||
> button
|
> button
|
||||||
padding 0
|
padding 0
|
||||||
width 40px
|
width 40px
|
||||||
|
@ -48,7 +48,7 @@
|
|||||||
<button class="renoteButton" @click="renote" title="%i18n:@renote%">
|
<button class="renoteButton" @click="renote" title="%i18n:@renote%">
|
||||||
%fa:retweet%<p class="count" v-if="p.renoteCount > 0">{{ p.renoteCount }}</p>
|
%fa:retweet%<p class="count" v-if="p.renoteCount > 0">{{ p.renoteCount }}</p>
|
||||||
</button>
|
</button>
|
||||||
<button class="reactionButton" :class="{ reacted: p.myReaction != null }" @click="react" ref="reactButton" title="%i18n:@add-reaction%">
|
<button class="reactionButton" :class="{ reacted: p.myReaction != null }" @click="react()" ref="reactButton" title="%i18n:@add-reaction%">
|
||||||
%fa:plus%<p class="count" v-if="p.reactions_count > 0">{{ p.reactions_count }}</p>
|
%fa:plus%<p class="count" v-if="p.reactions_count > 0">{{ p.reactions_count }}</p>
|
||||||
</button>
|
</button>
|
||||||
<button @click="menu" ref="menuButton">
|
<button @click="menu" ref="menuButton">
|
||||||
@ -113,13 +113,11 @@ export default Vue.extend({
|
|||||||
computed: {
|
computed: {
|
||||||
keymap(): any {
|
keymap(): any {
|
||||||
return {
|
return {
|
||||||
'r': this.reply,
|
'r|left': this.reply,
|
||||||
'a': this.react,
|
'a|plus': () => this.react(true),
|
||||||
'n': this.renote,
|
'n|right': this.renote,
|
||||||
'up': this.focusBefore,
|
'up|shift+tab': this.focusBefore,
|
||||||
'shift+tab': this.focusBefore,
|
'down|tab': this.focusAfter,
|
||||||
'down': this.focusAfter,
|
|
||||||
'tab': this.focusAfter,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -244,10 +242,13 @@ export default Vue.extend({
|
|||||||
}).$once('closed', this.focus);
|
}).$once('closed', this.focus);
|
||||||
},
|
},
|
||||||
|
|
||||||
react() {
|
react(viaKeyboard = false) {
|
||||||
|
this.blur();
|
||||||
(this as any).os.new(MkReactionPicker, {
|
(this as any).os.new(MkReactionPicker, {
|
||||||
source: this.$refs.reactButton,
|
source: this.$refs.reactButton,
|
||||||
note: this.p
|
note: this.p,
|
||||||
|
showFocus: viaKeyboard,
|
||||||
|
animation: !viaKeyboard
|
||||||
}).$once('closed', this.focus);
|
}).$once('closed', this.focus);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -262,6 +263,10 @@ export default Vue.extend({
|
|||||||
this.$el.focus();
|
this.$el.focus();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
blur() {
|
||||||
|
this.$el.blur();
|
||||||
|
},
|
||||||
|
|
||||||
focusBefore() {
|
focusBefore() {
|
||||||
focus(this.$el, e => e.previousElementSibling);
|
focus(this.$el, e => e.previousElementSibling);
|
||||||
},
|
},
|
||||||
|
Reference in New Issue
Block a user