49日目 割烹芸人の開発9
これで最低限の機能が完了です……。つ、つかれた……
最低限の機能にもう一つ付けておきます。
HTMLタグをマスターしている人にとってもう少しカスタマイズしたいという人もいるのかなと思うのでその人たち向けにカスタムできる入力部も付けます。
通常はtextareaにコードを書いて、切替ボタンでHTMLの表示にする。そんなものを作ってみます。
class CustHTML{
static get enableLineBreaks(){
return true;
}
constructor({data, config, api}){
this.api=api;
this.config = config || {};
this.data = {
text: data.text || '',
view : false
};
this.settings = [
{
name:'view',
icon:'切替'
}
]
this.sanitizerConfig = {
div:{
style:true
},
span:{
style:true
},
p:{
style:true
},
h1:true,
h2:true,
h3:true,
b: true,
strong:true,
em:true,
hr:true,
q:true,
i: true,
small:true,
br:true,
sup:true,
sub:true,
code:true,
pre:true,
var:true,
blockquote:true,
img:{
src:true,
alt:true,
width:true,
height:true,
style:true
},
s:true,
u:true,
center:true,
font:true,
ol:{
listStyle:true
},
ul:{
listStyle:true
},
li:true,
a: {
href: true
},
table:{
style:true,
border:true
},
tr:true,
td:{
rowspan:true,
colspan:true
},
th:true
};
this._element = this.drawView();
}
drawView() {
const containr = document.createElement('div');
containr.classList.add('custom-html');
const textbox = document.createElement('textarea');
textbox.placeholder='ここにはなろうで使用できるHTMLタグが打ち込めます。ただ実際の見え方とは差異があると思います。許して。';
textbox.value = this.data.text;
containr.appendChild(textbox);
return containr;
}
renderSettings(){
const wrapper = document.createElement('div');
this.settings.forEach(tune =>{
let button = document.createElement('div');
button.classList.add(this.api.styles.settingsButton);
button.innerHTML = tune.icon;
wrapper.appendChild(button);
button.classList.toggle(this.api.styles.settingsButtonActive, this.data.view);
button.addEventListener('click', ()=>{
button.classList.toggle(this.api.styles.settingsButtonActive);
this.data.view = !this.data.view;
this._changeView();
});
});
return wrapper;
}
_changelinebrake(str){
return str.replace(/\r?\n/g, '
');
}
_changebr(str){
return str.replace(/
/g, '\n');
}
_sanitizeddata(textdata){
return this.api.sanitizer.clean(textdata || '', this.sanitizerConfig)
}
_changeView(){
if(this.data.view){
const textbox = this._element.querySelector('textarea');
this.data.text = this._sanitizeddata(textbox.value);
this._element.innerHTML = this._changelinebrake(this.data.text) ;
}else{
const textbox = document.createElement('textarea');
textbox.placeholder='ここにはなろうで使用できるHTMLタグが打ち込めます。ただ実際の見え方とは差異があると思います。許して。切替ボタンであれすることができます。';
textbox.value = this.data.text;
this._element.innerHTML ='';
this._element.appendChild(textbox);
}
}
/* static get sanitize(){
return {
b: true,
a: {
href: true
},
i: true // Allow HTML tags
};
}*/
validate(blockData) {
return blockData.text.trim() !== '';
}
save(toolsContent){
const textbox = this._element.querySelector('textarea');
if (textbox) {
return {
text: this.api.sanitizer.clean(textbox.value || '', this.sanitizerConfig)
};
}
return {
text: this.api.sanitizer.clean(toolsContent.innerHTML|| '', this.sanitizerConfig)
};
}
render(){
return this._element;
}
static get toolbox(){
return {
icon:'自由',
title:'HTMLタグが使えます。(なろうタグ限定)'
};
}
}
切替時にthis.sanitizerConfigで指定したタグのみを通過させることでXSSみたいにスクリプトタグを打ち込まれたり、想定していないタグの挿入を防ぎます。
保存時にもこのサニタイズで除去します。
切替ボタンで確認もできちゃいますね。
ということでカスタム完了です。