summaryrefslogtreecommitdiff
path: root/src/web
diff options
context:
space:
mode:
authorこぴなたみぽ <syuilotan@yahoo.co.jp>2018-02-20 20:29:52 +0900
committerこぴなたみぽ <syuilotan@yahoo.co.jp>2018-02-20 20:29:52 +0900
commitf8bb47a60b7ed895a83bae3daf389e72b65e3239 (patch)
tree5f5eb6f12448bf0b6e232b0f40b2810b05c50442 /src/web
parentwip (diff)
downloadmisskey-f8bb47a60b7ed895a83bae3daf389e72b65e3239.tar.gz
misskey-f8bb47a60b7ed895a83bae3daf389e72b65e3239.tar.bz2
misskey-f8bb47a60b7ed895a83bae3daf389e72b65e3239.zip
wip
Diffstat (limited to 'src/web')
-rw-r--r--src/web/app/desktop/-tags/autocomplete-suggestion.tag197
-rw-r--r--src/web/app/desktop/views/components/autocomplete.vue190
2 files changed, 190 insertions, 197 deletions
diff --git a/src/web/app/desktop/-tags/autocomplete-suggestion.tag b/src/web/app/desktop/-tags/autocomplete-suggestion.tag
deleted file mode 100644
index d3c3b6b35a..0000000000
--- a/src/web/app/desktop/-tags/autocomplete-suggestion.tag
+++ /dev/null
@@ -1,197 +0,0 @@
-<mk-autocomplete-suggestion>
- <ol class="users" ref="users" v-if="users.length > 0">
- <li each={ users } @click="parent.onClick" onkeydown={ parent.onKeydown } tabindex="-1">
- <img class="avatar" src={ avatar_url + '?thumbnail&size=32' } alt=""/>
- <span class="name">{ name }</span>
- <span class="username">@{ username }</span>
- </li>
- </ol>
- <style lang="stylus" scoped>
- :scope
- display block
- position absolute
- z-index 65535
- margin-top calc(1em + 8px)
- overflow hidden
- background #fff
- border solid 1px rgba(0, 0, 0, 0.1)
- border-radius 4px
-
- > .users
- display block
- margin 0
- padding 4px 0
- max-height 190px
- max-width 500px
- overflow auto
- list-style none
-
- > li
- display block
- padding 4px 12px
- white-space nowrap
- overflow hidden
- font-size 0.9em
- color rgba(0, 0, 0, 0.8)
- cursor default
-
- &, *
- user-select none
-
- &:hover
- &[data-selected='true']
- color #fff
- background $theme-color
-
- .name
- color #fff
-
- .username
- color #fff
-
- &:active
- color #fff
- background darken($theme-color, 10%)
-
- .name
- color #fff
-
- .username
- color #fff
-
- .avatar
- vertical-align middle
- min-width 28px
- min-height 28px
- max-width 28px
- max-height 28px
- margin 0 8px 0 0
- border-radius 100%
-
- .name
- margin 0 8px 0 0
- /*font-weight bold*/
- font-weight normal
- color rgba(0, 0, 0, 0.8)
-
- .username
- font-weight normal
- color rgba(0, 0, 0, 0.3)
-
- </style>
- <script lang="typescript">
- import contains from '../../common/scripts/contains';
-
- this.mixin('api');
-
- this.q = this.opts.q;
- this.textarea = this.opts.textarea;
- this.fetching = true;
- this.users = [];
- this.select = -1;
-
- this.on('mount', () => {
- this.textarea.addEventListener('keydown', this.onKeydown);
-
- document.querySelectorAll('body *').forEach(el => {
- el.addEventListener('mousedown', this.mousedown);
- });
-
- this.$root.$data.os.api('users/search_by_username', {
- query: this.q,
- limit: 30
- }).then(users => {
- this.update({
- fetching: false,
- users: users
- });
- });
- });
-
- this.on('unmount', () => {
- this.textarea.removeEventListener('keydown', this.onKeydown);
-
- document.querySelectorAll('body *').forEach(el => {
- el.removeEventListener('mousedown', this.mousedown);
- });
- });
-
- this.mousedown = e => {
- if (!contains(this.root, e.target) && (this.root != e.target)) this.close();
- };
-
- this.onClick = e => {
- this.complete(e.item);
- };
-
- this.onKeydown = e => {
- const cancel = () => {
- e.preventDefault();
- e.stopPropagation();
- };
-
- switch (e.which) {
- case 10: // [ENTER]
- case 13: // [ENTER]
- if (this.select !== -1) {
- cancel();
- this.complete(this.users[this.select]);
- } else {
- this.close();
- }
- break;
-
- case 27: // [ESC]
- cancel();
- this.close();
- break;
-
- case 38: // [↑]
- if (this.select !== -1) {
- cancel();
- this.selectPrev();
- } else {
- this.close();
- }
- break;
-
- case 9: // [TAB]
- case 40: // [↓]
- cancel();
- this.selectNext();
- break;
-
- default:
- this.close();
- }
- };
-
- this.selectNext = () => {
- if (++this.select >= this.users.length) this.select = 0;
- this.applySelect();
- };
-
- this.selectPrev = () => {
- if (--this.select < 0) this.select = this.users.length - 1;
- this.applySelect();
- };
-
- this.applySelect = () => {
- Array.from(this.$refs.users.children).forEach(el => {
- el.removeAttribute('data-selected');
- });
-
- this.$refs.users.children[this.select].setAttribute('data-selected', 'true');
- this.$refs.users.children[this.select].focus();
- };
-
- this.complete = user => {
- this.opts.complete(user);
- };
-
- this.close = () => {
- this.opts.close();
- };
-
- </script>
-</mk-autocomplete-suggestion>
diff --git a/src/web/app/desktop/views/components/autocomplete.vue b/src/web/app/desktop/views/components/autocomplete.vue
new file mode 100644
index 0000000000..a99d405e82
--- /dev/null
+++ b/src/web/app/desktop/views/components/autocomplete.vue
@@ -0,0 +1,190 @@
+<template>
+<div class="mk-autocomplete">
+ <ol class="users" ref="users" v-if="users.length > 0">
+ <li v-for="user in users" @click="complete(user)" @keydown="onKeydown" tabindex="-1">
+ <img class="avatar" :src="`${user.avatar_url}?thumbnail&size=32`" alt=""/>
+ <span class="name">{{ user.name }}</span>
+ <span class="username">@{{ user.username }}</span>
+ </li>
+ </ol>
+</div>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+import contains from '../../../common/scripts/contains';
+
+export default Vue.extend({
+ props: ['q', 'textarea', 'complete', 'close'],
+ data() {
+ return {
+ fetching: true,
+ users: [],
+ select: -1
+ }
+ },
+ mounted() {
+ this.textarea.addEventListener('keydown', this.onKeydown);
+
+ Array.from(document.querySelectorAll('body *')).forEach(el => {
+ el.addEventListener('mousedown', this.onMousedown);
+ });
+
+ (this as any).api('users/search_by_username', {
+ query: this.q,
+ limit: 30
+ }).then(users => {
+ this.users = users;
+ this.fetching = false;
+ });
+ },
+ beforeDestroy() {
+ this.textarea.removeEventListener('keydown', this.onKeydown);
+
+ Array.from(document.querySelectorAll('body *')).forEach(el => {
+ el.removeEventListener('mousedown', this.onMousedown);
+ });
+ },
+ methods: {
+ onMousedown(e) {
+ if (!contains(this.$el, e.target) && (this.$el != e.target)) this.close();
+ },
+
+ onKeydown(e) {
+ const cancel = () => {
+ e.preventDefault();
+ e.stopPropagation();
+ };
+
+ switch (e.which) {
+ case 10: // [ENTER]
+ case 13: // [ENTER]
+ if (this.select !== -1) {
+ cancel();
+ this.complete(this.users[this.select]);
+ } else {
+ this.close();
+ }
+ break;
+
+ case 27: // [ESC]
+ cancel();
+ this.close();
+ break;
+
+ case 38: // [↑]
+ if (this.select !== -1) {
+ cancel();
+ this.selectPrev();
+ } else {
+ this.close();
+ }
+ break;
+
+ case 9: // [TAB]
+ case 40: // [↓]
+ cancel();
+ this.selectNext();
+ break;
+
+ default:
+ this.close();
+ }
+ },
+
+ selectNext() {
+ if (++this.select >= this.users.length) this.select = 0;
+ this.applySelect();
+ },
+
+ selectPrev() {
+ if (--this.select < 0) this.select = this.users.length - 1;
+ this.applySelect();
+ },
+
+ applySelect() {
+ const els = (this.$refs.users as Element).children;
+
+ Array.from(els).forEach(el => {
+ el.removeAttribute('data-selected');
+ });
+
+ els[this.select].setAttribute('data-selected', 'true');
+ (els[this.select] as any).focus();
+ }
+ }
+});
+</script>
+
+<style lang="stylus" scoped>
+.mk-autocomplete
+ position absolute
+ z-index 65535
+ margin-top calc(1em + 8px)
+ overflow hidden
+ background #fff
+ border solid 1px rgba(0, 0, 0, 0.1)
+ border-radius 4px
+
+ > .users
+ display block
+ margin 0
+ padding 4px 0
+ max-height 190px
+ max-width 500px
+ overflow auto
+ list-style none
+
+ > li
+ display block
+ padding 4px 12px
+ white-space nowrap
+ overflow hidden
+ font-size 0.9em
+ color rgba(0, 0, 0, 0.8)
+ cursor default
+
+ &, *
+ user-select none
+
+ &:hover
+ &[data-selected='true']
+ color #fff
+ background $theme-color
+
+ .name
+ color #fff
+
+ .username
+ color #fff
+
+ &:active
+ color #fff
+ background darken($theme-color, 10%)
+
+ .name
+ color #fff
+
+ .username
+ color #fff
+
+ .avatar
+ vertical-align middle
+ min-width 28px
+ min-height 28px
+ max-width 28px
+ max-height 28px
+ margin 0 8px 0 0
+ border-radius 100%
+
+ .name
+ margin 0 8px 0 0
+ /*font-weight bold*/
+ font-weight normal
+ color rgba(0, 0, 0, 0.8)
+
+ .username
+ font-weight normal
+ color rgba(0, 0, 0, 0.3)
+
+</style>