suggestWindow
2020-09-21 09:08:43
windowの幅を調節した
2020-09-17 06:24:10
<li>
にidを付与した
Web Componentsを使って書き換えたいな
script.jsexport class suggestWindow {
constructor({id, maxHeight = 'calc(50vh - 100px)'} = {}) {
this.box = document.createElement('div');
this.box.setAttribute('id', id);
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.items.style.maxHeight = maxHeight;
this.items.style.maxWidth = 'calc(-100px + 50vw)';
this.items.style.overflow = 'auto';
this.container.appendChild(this.items);
this.editor = document.getElementById('editor');
this.editor.appendChild(this.box);
// 入力候補リストの最初の要素のidに使う番号
this.SEED = new Date().getTime().toString(16);
}
// 入力補完window を開く
open() {
// 入力候補がなければ開かない
if (this.length == 0) return;
this.container.classList.add('open');
}
// 入力補完window を閉じる
close() {
//console.log('close the window.');
if(!this.isOpen()) return;
this.container.classList.remove('open');
this.items.textContent ='';
document.getElementById('text-input').focus();
}
// 入力補完window の開閉判定
isOpen() {
return this.container.classList.contains('open');
}
// 入力候補の数
get length() {
return this.items.children.length;
}
_makeId(index) {
return `item-${this.SEED}-${index}`;
}
// 入力候補を追加する
appendItems(newItems) {
newItems.forEach((newItem, index) => {
this.items.appendChild(this._makeNewItem({
elements: newItem.elements,
onComfirm: newItem.onComfirm,
index: index
}))
});
}
// 入力候補を上書きする
resetItems(items) {
// アイテムを消す
this.items.textContent ='';
this.appendItems(items);
}
_makeNewItem({elements, onComfirm, index}) {
const listItem = document.createElement('li');
listItem.classList.add('dropdown-item');
const a = document.createElement('a');
a.setAttribute('id', this._makeId(index));
a.dataset.index = index;
a.setAttribute('tabindex', '-1');
elements.forEach(element => a.appendChild(element));
a.onclick = onComfirm;
listItem.appendChild(a);
return listItem;
}
// indexから要素を取得する
getItem(index) {
const id = this._makeId(index);
const item = document.getElementById(id);
if(!item) {
//console.log(`item the id of which is ${id} isn't found.`);
return undefined;
}
return item;
}
// 先頭要素
get firstItem() {
//console.log('getting the first item...');
return this.getItem(0);
}
// 末尾要素
get lastItem() {
return this.getItem(this.length - 1);
}
// 入力補完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があたっている入力候補を返す
get focusedItem() {
return this.items.querySelector(':focus');
}
hasFocus(){
return this.focusedItem != null;
}
// 補完候補の先頭にfocusを当てる
selectFirstItem() {
this.firstItem.focus();
}
// 補完候補の末尾にfocusを当てる
selectLastItem() {
this.lastItem.focus();
}
// 最初の補完候補にfocusがあたっているかどうか
hasFirstItemFocus() {
//console.log(`selectedItem: ${document.activeElement}`);
return document.activeElement == this.firstItem;
}
// 最後の補完候補にfocusがあたっているかどうか
hasLastItemFocus() {
//console.log(`selectedItem: ${document.activeElement}`);
return document.activeElement == this.lastItem;
}
// 次の補完候補に移動する
selectNextItem({wrap = false} = {}) {
//console.log('Start selecting the next item...');
// focusが当たっている要素を取得
const selectedItem = this.focusedItem;
if(!selectedItem) {
//console.log('No item is focused. Instead selecting the first item...');
this.selectFirstItem();
return;
}
if(selectedItem == this.lastItem){
// 一番下まで行ったら先頭に戻す
if(wrap) this.selectFirstItem();
return;
}
//console.log(`index: ${this.indexOfFocusedItem}`);
this.getItem(this.indexOfFocusedItem + 1).focus();
}
// 前の補完候補に移動する
selectPreviousItem({wrap = false} = {}) {
//console.log('Start selecting the previous item...');
// focusが当たっている要素を取得
const selectedItem = this.focusedItem;
if(!selectedItem) {
//console.log('No item is focused. Instead selecting the last item...');
this.selectLastItem();
return;
}
if(selectedItem == this.firstItem){
// 一番上まで行ったら末尾に移動する
if(wrap) this.selectLastItem();
return;
}
this.getItem(this.indexOfFocusedItem - 1).focus();
}
// focusが当たっている要素の通し番号を取得する
get indexOfFocusedItem() {
const selectedItem = this.focusedItem;
if(!selectedItem) return undefined;
return parseInt(selectedItem.dataset.index);
}
}