generated at
suggestWindow
入力補完用windowを作成・操作するクラス

script.js
export class suggestWindow{ constructor() { this.box = document.createElement('div'); this.box.setAttribute('id', 'external-suggestion'); this.box.classList.add('form-group'); this.box.style.position = 'absolute'; this.container = document.createElement('div'); this.container.classList.add('dropdown'); this.box.appendChild(this.container); this.items = document.createElement('ul'); this.items.classList.add('dropdown-menu'); this.items.style.whiteSpace='nowrap'; // 文字列を折り返さない this.container.appendChild(this.items); this.editor = document.getElementById('editor'); this.editor.appendChild(this.box); } // 入力補完window を開く open() { // 入力候補がなければ開かない if (this.getItems().length == 0) return; this.container.classList.add('open'); } // 入力補完window を閉じる close(cursor = null) { //console.log('close the window.'); this.container.classList.remove('open'); this.items.textContent=''; if(!cursor) cursor = document.getElementById('text-input'); cursor.focus(); } // 入力補完window の開閉判定 isOpen() { return this.container.classList.contains('open'); } // 入力候補に表示するアイテムを更新する updateItems(items) { const newList = document.createElement('ul'); newList.classList.add('dropdown-menu'); newList.style.whiteSpace='nowrap';
入力補完windowが長すぎる場合は、以下のコードをここに追記する
newList.style.maxHeight='calc(50vh - 100px)';
script.js
for(const item of items) { let listItem = document.createElement('li'); listItem.classList.add('dropdown-item'); listItem.appendChild(item); newList.appendChild(listItem) } this.items.replaceWith(newList); this.items = newList; // これを書かないと置き換えが完了しない } getItems() { return this.items.children; } // 入力補完windowの位置を更新する reDraw(cursor) { this.box.style.top = `${parseInt(cursor.style.top) + parseInt(cursor.style.height) + 3}px`; this.box.style.left = `${parseInt(cursor.style.left)}px`; } // 現在focusがあたっている入力候補を返す getFocusedItem() { return this.items.querySelector(':focus'); } hasFocus(){ return this.getFocusedItem() != null; } // 補完候補の先頭にfocusを当てる selectFirstItem() { this.items.firstElementChild.firstElementChild.focus(); //console.log('the first item is focused.'); } // 最初の補完候補にfocusがあたっているかどうか hasFirstItemFocus() { //console.log(`selectedItem: ${this.getFocusedItem()}`); return this.getFocusedItem() == this.items.firstElementChild.firstElementChild; } // 次の補完候補に移動する selectNextItem(cursor) { // focusが当たっている要素を取得 const selectedItem = this.items.querySelector(':focus'); if(!selectedItem) { this.selectFirstItem(); return; } if(selectedItem == this.items.lastElementChild) { this.selectFirstItem(); return; } //selectedItem.nextElementSibling.firstElementChild.focus(); } // 前の補完候補に移動する selectPreviousItem(cursor) { // focusが当たっている要素を取得 const selectedItem = this.items.querySelector(':focus'); if(!selectedItem) { this.close(); return; } //selectedItem.previousElementSibling.firstElementChild.focus(); } // 現在の選択候補の文字列を取得する getCurrentItemString() { const selectedItem = this.items.querySelector(':focus'); if(!selectedItem) { return undefined; } return selectedItem.textContent; } }

UserScript