現在のカスタムプラグインページは3つ(有料会員の場合は5つ)のテキストエリアが常に表示されています。
プレビュー機能を追加する上で、プレビュー画面も複数用意することも可能ですが、1つのカスタムプラグインを編集してるときは基本的に1つのプレビューしか見なくても問題ないはずなので、画面上にはテキストエリアが1つだけ見えるようにします。
条件分岐を行いながらPHPでレンダリングしているので、Vue.jsで置き換えることは難しかったためCSSとJavaScirptでタブメニューを実装します。
```js
export default class TabMenu {
private _tabs: HTMLElement;
private _contents: NodeListOf;
constructor(tab_selectors: string, content_selectors: string) {
this._tabs = document.querySelector(tab_selectors) as HTMLElement;
this._contents = document.querySelectorAll(content_selectors)
this._tabs.addEventListener('click', this._onClick);
}
get activeTab() {
const tab = Array.from(this._tabs.children).find(el => {
return /active/.test(el.className);
});
return tab;
}
get activeContent() {
return this._contents.forEach(contents => {
const content = Array.from(contents.children).find(el => {
return /active/.test(el.className);
});
return content;
})
}
private _onClick = (ev: Event): void => {
const target = ev.target as HTMLElement;
if (this._tabs.tagName === target.tagName) {
return;
}
ev.preventDefault();
this._removeClassNameActive(this._tabs.children);
this._contents.forEach(contents => {
this._removeClassNameActive(contents.children);
});
target.className += ' active';
const index = this._findIndexOfActiveTab(this._tabs.children);
this._contents.forEach(contents => {
contents.children[index].className += ' active';
});
}
private _findIndexOfActiveTab = (collection: HTMLCollection): number => {
const index = Array.from(collection).findIndex(el => {
return /active/.test(el.className);
});
return index;
}
private _removeClassNameActive = (collection: HTMLCollection): void => {
Array.from(collection).forEach(el => {
el.className = el.className.replace(/\sactive/g, '');
});
}
}
new TabMenu('#tab_items', '.tab_contents');
```
```css
#tab_items {
list-style-type: none;
margin: 0px;
}
#tab_items > .tab {
white-space: nowrap;
padding: 4px;
}
.tab:hover {
cursor: pointer;
}
#tab_items > .tab.active {
padding: 3px;
background-color: rgba(0, 0,0, 0.1);
border-left: 1px solid rgb(204, 204, 204);
border-top: 1px solid rgb(204, 204, 204);
border-bottom: 1px solid rgb(204, 204, 204);
}
.tab_content {
padding-right: 40px;
display: none;
}
.tab_content.active {
display: block;
}
```
クラスにする必要もなさそうな気がしますが、今後他のページでもタブメニューを使うことになった時、クラスの利用者が内部を意識しないで利用できるようにしています。
当初タブとコンテンツは1対1の関係で書いていましたが、カスタムプラグインページのレイアウトの関係で1対nの関係でも動くように修正しました。