diff --git a/package.json b/package.json index 274962c368..2ced82cd19 100644 --- a/package.json +++ b/package.json @@ -78,6 +78,7 @@ "@types/websocket": "0.0.37", "accesses": "2.5.0", "animejs": "2.2.0", + "autosize": "4.0.0", "autwh": "0.0.1", "bcryptjs": "2.4.3", "body-parser": "1.18.2", diff --git a/src/web/app/common/views/components/autocomplete.vue b/src/web/app/common/views/components/autocomplete.vue index 1980804927..b068ecc4fa 100644 --- a/src/web/app/common/views/components/autocomplete.vue +++ b/src/web/app/common/views/components/autocomplete.vue @@ -22,7 +22,7 @@ import * as pictograph from 'pictograph'; import contains from '../../../common/scripts/contains'; export default Vue.extend({ - props: ['type', 'q', 'textarea', 'complete', 'close'], + props: ['type', 'q', 'textarea', 'complete', 'close', 'x', 'y'], data() { return { fetching: true, @@ -37,6 +37,27 @@ export default Vue.extend({ return (this.$refs.suggests as Element).children; } }, + updated() { + //#region 位置調整 + const margin = 32; + + if (this.x + this.$el.offsetWidth > window.innerWidth - margin) { + this.$el.style.left = (this.x - this.$el.offsetWidth) + 'px'; + this.$el.style.marginLeft = '-16px'; + } else { + this.$el.style.left = this.x + 'px'; + this.$el.style.marginLeft = '0'; + } + + if (this.y + this.$el.offsetHeight > window.innerHeight - margin) { + this.$el.style.top = (this.y - this.$el.offsetHeight) + 'px'; + this.$el.style.marginTop = '0'; + } else { + this.$el.style.top = this.y + 'px'; + this.$el.style.marginTop = 'calc(1em + 8px)'; + } + //#endregion + }, mounted() { this.textarea.addEventListener('keydown', this.onKeydown); @@ -136,7 +157,7 @@ export default Vue.extend({ diff --git a/src/web/app/common/views/directives/autocomplete.ts b/src/web/app/common/views/directives/autocomplete.ts index bd9c9cb611..4d6ba41df1 100644 --- a/src/web/app/common/views/directives/autocomplete.ts +++ b/src/web/app/common/views/directives/autocomplete.ts @@ -82,6 +82,15 @@ class Autocomplete { // 既に開いているサジェストは閉じる this.close(); + //#region サジェストを表示すべき位置を計算 + const caretPosition = getCaretCoordinates(this.textarea, this.textarea.selectionStart); + + const rect = this.textarea.getBoundingClientRect(); + + const x = rect.left + caretPosition.left - this.textarea.scrollLeft; + const y = rect.top + caretPosition.top - this.textarea.scrollTop; + //#endregion + // サジェスト要素作成 this.suggestion = new MkAutocomplete({ propsData: { @@ -89,22 +98,12 @@ class Autocomplete { complete: this.complete, close: this.close, type: type, - q: q + q: q, + x, + y } }).$mount(); - //#region サジェストを表示すべき位置を計算 - const caretPosition = getCaretCoordinates(this.textarea, this.textarea.selectionStart); - - const rect = this.textarea.getBoundingClientRect(); - - const x = rect.left + window.pageXOffset + caretPosition.left - this.textarea.scrollLeft; - const y = rect.top + window.pageYOffset + caretPosition.top - this.textarea.scrollTop; - //#endregion - - this.suggestion.$el.style.left = x + 'px'; - this.suggestion.$el.style.top = y + 'px'; - // 要素追加 document.body.appendChild(this.suggestion.$el); }