93日目 割烹芸人の実装9
最後にLINE割烹を作っていきます。
さて、最後にLINE風割烹を作っていきます。
とりあえずまずはLINE風のブロックを作れるように割烹エディターに追加していきます。
class ChatStyle
を作って、 constructor、render、renderSettings、save、sanitize、toolboxなどを設定していきましてっと。
class ChatStyle{
static get enableLineBreaks(){
return true;
}
constructor({data, config, api}){
this.api=api;
this.config = config || {};
this.data = {
text: data.text || '',
fontSize : data.fontSize !== undefined ? data.fontSize : '1',
color: data.color !== undefined ? data.color : '#333333',
backcolor: data.backcolor !== undefined ? data.backcolor : '#B1ED8B',
position:data.position !== undefined ? data.position : 'rightside',
imgurl:data.imgurl !== undefined ? data.imgurl : ''
};
this._element = this.drawView();
this._changePosition(this.data.position);
const headerbox = this._element.querySelector('.chat-text');
const chatallow = this._element.querySelector('.chat-allow');
headerbox.innerHTML = this.data.text;
headerbox.style.color=this.data.color;
headerbox.style.background=this.data.backcolor;
chatallow .style.borderLeftColor=this.data.backcolor;
chatallow .style.borderRightColor=this.data.backcolor;
headerbox.style.fontSize=this.data.fontSize+ 'em';
this.settings = [
{
name:'leftside',
icon:'左向'
},
{
name:'rightside',
icon:'右向'
},
{
name: 'color',
icon:'装飾',
},
{
name:'copy',
icon:'複製'
}
]
}
onKeyDOWN(e){
if( e.key === 'Enter' && !e.shiftKey ){
e.stopPropagation();
e.preventDefault();
let selection = window.getSelection(),
range = selection.getRangeAt(0),
newline = document.createTextNode('\u200B'),//零幅スペース
br = document.createElement('br');
range.deleteContents();
range.insertNode(newline);
range.insertNode(br);
range.setStartAfter(br);
range.setEndAfter(br);
range.collapse(false);
selection.removeAllRanges();
selection.addRange(range);
}
}
drawView() {
const containr = document.createElement('div');
const textblock = document.createElement('div');
const imgblock = document.createElement('div');
const allowblock = document.createElement('div');
const setblock = document.createElement('form');
textblock.classList.add('chat-text');
allowblock.classList.add('chat-allow');
imgblock.classList.add('chat-img');
containr.classList.add('custom-chat');
textblock.contentEditable = true;
textblock.addEventListener('keydown', this.onKeyDOWN);
containr.appendChild(imgblock);
containr.appendChild(allowblock);
containr.appendChild(textblock);
containr.appendChild(setblock);
return containr;
}
render(){
return this._element;
}
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);
if(tune.name === 'leftside' || tune.name === 'rightside'){
button.classList.toggle(this.api.styles.settingsButtonActive, tune.name === this.data.position);
}else if(tune.name === 'copy'){
}else{
if(this._setform){
button.classList.toggle(this.api.styles.settingsButtonActive);
}
}
button.addEventListener('click', ()=>{
if(tune.name === 'leftside' || tune.name === 'rightside'){
wrapper.querySelectorAll(`.${this.api.styles.settingsButton}`).forEach(el => {
if((el.innerHTML === '左向' || el.innerHTML === '右向') ){
el.classList.remove(this.api.styles.settingsButtonActive);
}
});
button.classList.add(this.api.styles.settingsButtonActive);
this._changePosition(tune.name);
}else if(tune.name === 'color'){
button.classList.toggle(this.api.styles.settingsButtonActive);
if(button.classList.contains(this.api.styles.settingsButtonActive)){
this._showColorPicker();
this._setform=true;
}else{
this._hideColorPicker();
this._setform=false;
}
}else if(tune.name==='copy'){
this._copyblock();
}
});
});
return wrapper;
}
save(toolsContent){
const textbox = this._element.querySelector('.chat-text');
return {
text:textbox.innerHTML,
position:this.data.position,
fontSize:this.data.fontSize,
color:this.data.color,
backcolor:this.data.backcolor,
imgurl:this.data.imgurl
}
}
_changePosition(tune){
this.data.position=tune;
this._element.classList.remove('rightside');
this._element.classList.remove('leftside');
this._element.classList.add(tune);
}
_showColorPicker(){
const setbox = this._element.querySelector('form');
const fontsize = document.createElement('input');
const textcolor = document.createElement('input');
const backcolor = document.createElement('input');
fontsize.type = 'number';
fontsize.step = '0.1';
fontsize.min= "0.1" ;
fontsize.max= "10";
fontsize.value = this.data.fontSize;
textcolor.type = 'color';
textcolor.value = this.data.color;
backcolor.type = 'color';
backcolor.value = this.data.backcolor;
setbox.insertAdjacentHTML('beforeend', '文字色:');
setbox.appendChild(textcolor);
setbox.insertAdjacentHTML('beforeend', '
背景色:');
setbox.appendChild(backcolor);
setbox.insertAdjacentHTML('beforeend', '
文字サイズ(em):');
setbox.appendChild(fontsize);
fontsize.onchange = () => {
const headerbox = this._element.querySelector('.chat-text');
this.data.fontSize=fontsize.value;
headerbox.style.fontSize=this.data.fontSize + 'em';
};
textcolor.onchange = () => {
const headerbox = this._element.querySelector('.chat-text');
this.data.color = textcolor.value;
headerbox.style.color=this.data.color;
};
backcolor.onchange = () => {
const headerbox = this._element.querySelector('.chat-text');
const chatallow = this._element.querySelector('.chat-allow');
this.data.backcolor = backcolor.value;
headerbox.style.background=this.data.backcolor;
chatallow .style.borderLeftColor=this.data.backcolor;
chatallow .style.borderRightColor=this.data.backcolor;
};
}
_hideColorPicker(){
const setbox = this._element.querySelector('form');
setbox.innerHTML='';
}
_copyblock(){
const headerbox = this._element.querySelector('.chat-text');
this.api.blocks.insert('chat',{text:headerbox.innerHTML,
width:this.data.width,
fontSize:this.data.fontSize,
position:this.data.position,
color:this.data.color,
bordercolor:this.data.bordercolor,
backcolor:this.data.backcolor,
url:this.data.url},{},this.api.blocks.getBlocksCount());
}
static get sanitize() {
return {
text: {
br: true,
span:{
style:true
},
}
};
}
validate(blockData) {
return blockData.text.trim() !== '';
}
static get toolbox(){
return {
icon:'吹出',
title:'吹出を挿入'
};
}
}
これでLINE風の吹き出しが出せるようになりました。
画像も入れられるようにしたかったですが、ちょっと時間が足りなさそうなので今後の課題ということで。
さて、次にデフォルトの背景を変えられるようにもしています。これはLINE風割烹限定にしておきます。
背景色を選べるようにして、変わった時に背景を変えるようにしておきます。
デフォルトはLINE風にしておきます。
さて、これでLINE割烹も完了ですね。
予定していたものはこれで大体できました。あとは取説を作っていったん完成させます。




