From 341618a9d5febfe2c36bf764b0a573b6c1131d89 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 25 Feb 2018 17:38:16 +0900 Subject: [PATCH] v3880 --- package.json | 2 +- .../common/views/components/autocomplete.vue | 52 ++++++++++------ .../common/views/directives/autocomplete.ts | 62 ++++++++++++------- 3 files changed, 73 insertions(+), 43 deletions(-) diff --git a/package.json b/package.json index 5f35c5e013..aa2ce56341 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "misskey", "author": "syuilo ", - "version": "0.0.3878", + "version": "0.0.3880", "license": "MIT", "description": "A miniblog-based SNS", "bugs": "https://github.com/syuilo/misskey/issues", diff --git a/src/web/app/common/views/components/autocomplete.vue b/src/web/app/common/views/components/autocomplete.vue index f31a624746..401eb043d0 100644 --- a/src/web/app/common/views/components/autocomplete.vue +++ b/src/web/app/common/views/components/autocomplete.vue @@ -87,22 +87,9 @@ export default Vue.extend({ el.addEventListener('mousedown', this.onMousedown); }); - if (this.type == 'user') { - (this as any).api('users/search_by_username', { - query: this.q, - limit: 30 - }).then(users => { - this.users = users; - this.fetching = false; - }); - } else if (this.type == 'emoji') { - const matched = []; - emjdb.some(x => { - if (x.name.indexOf(this.q) > -1 && !matched.some(y => y.emoji == x.emoji)) matched.push(x); - return matched.length == 30; - }); - this.emojis = matched; - } + this.exec(); + + this.$watch('q', this.exec); }, beforeDestroy() { this.textarea.removeEventListener('keydown', this.onKeydown); @@ -112,6 +99,35 @@ export default Vue.extend({ }); }, methods: { + exec() { + if (this.type == 'user') { + const cache = sessionStorage.getItem(this.q); + if (cache) { + const users = JSON.parse(cache); + this.users = users; + this.fetching = false; + } else { + (this as any).api('users/search_by_username', { + query: this.q, + limit: 30 + }).then(users => { + this.users = users; + this.fetching = false; + + // キャッシュ + sessionStorage.setItem(this.q, JSON.stringify(users)); + }); + } + } else if (this.type == 'emoji') { + const matched = []; + emjdb.some(x => { + if (x.name.indexOf(this.q) > -1 && !matched.some(y => y.emoji == x.emoji)) matched.push(x); + return matched.length == 30; + }); + this.emojis = matched; + } + }, + onMousedown(e) { if (!contains(this.$el, e.target) && (this.$el != e.target)) this.close(); }, @@ -152,9 +168,6 @@ export default Vue.extend({ cancel(); this.selectNext(); break; - - default: - this.close(); } }, @@ -189,6 +202,7 @@ export default Vue.extend({ background #fff border solid 1px rgba(0, 0, 0, 0.1) border-radius 4px + transition top 0.1s ease, left 0.1s ease > ol display block diff --git a/src/web/app/common/views/directives/autocomplete.ts b/src/web/app/common/views/directives/autocomplete.ts index e221cce71e..3440c4212a 100644 --- a/src/web/app/common/views/directives/autocomplete.ts +++ b/src/web/app/common/views/directives/autocomplete.ts @@ -6,7 +6,6 @@ export default { const self = el._autoCompleteDirective_ = {} as any; self.x = new Autocomplete(el, vn.context, binding.value); self.x.attach(); - console.log(vn.context); }, unbind(el, binding, vn) { @@ -23,6 +22,7 @@ class Autocomplete { private textarea: any; private vm: any; private model: any; + private currentType: string; private get text(): string { return this.vm[this.model]; @@ -67,24 +67,32 @@ class Autocomplete { * テキスト入力時 */ private onInput() { - this.close(); - const caret = this.textarea.selectionStart; const text = this.text.substr(0, caret); const mentionIndex = text.lastIndexOf('@'); const emojiIndex = text.lastIndexOf(':'); + let opened = false; + if (mentionIndex != -1 && mentionIndex > emojiIndex) { const username = text.substr(mentionIndex + 1); - if (!username.match(/^[a-zA-Z0-9-]+$/)) return; - this.open('user', username); + if (username != '' && username.match(/^[a-zA-Z0-9-]+$/)) { + this.open('user', username); + opened = true; + } } if (emojiIndex != -1 && emojiIndex > mentionIndex) { const emoji = text.substr(emojiIndex + 1); - if (!emoji.match(/^[\+\-a-z0-9_]+$/)) return; - this.open('emoji', emoji); + if (emoji != '' && emoji.match(/^[\+\-a-z0-9_]+$/)) { + this.open('emoji', emoji); + opened = true; + } + } + + if (!opened) { + this.close(); } } @@ -92,8 +100,10 @@ class Autocomplete { * サジェストを提示します。 */ private open(type, q) { - // 既に開いているサジェストは閉じる - this.close(); + if (type != this.currentType) { + this.close(); + } + this.currentType = type; //#region サジェストを表示すべき位置を計算 const caretPosition = getCaretCoordinates(this.textarea, this.textarea.selectionStart); @@ -104,21 +114,27 @@ class Autocomplete { const y = rect.top + caretPosition.top - this.textarea.scrollTop; //#endregion - // サジェスト要素作成 - this.suggestion = new MkAutocomplete({ - propsData: { - textarea: this.textarea, - complete: this.complete, - close: this.close, - type: type, - q: q, - x, - y - } - }).$mount(); + if (this.suggestion) { + this.suggestion.x = x; + this.suggestion.y = y; + this.suggestion.q = q; + } else { + // サジェスト要素作成 + this.suggestion = new MkAutocomplete({ + propsData: { + textarea: this.textarea, + complete: this.complete, + close: this.close, + type: type, + q: q, + x, + y + } + }).$mount(); - // 要素追加 - document.body.appendChild(this.suggestion.$el); + // 要素追加 + document.body.appendChild(this.suggestion.$el); + } } /**