1/* DokuWiki MoaiEditor Button.js file 2 Author : MoaiTools <info@moaitools.org> 3 License : GPL 3 (http://www.gnu.org/licenses/gpl.html) */ 4 5/* Class to create the buttons you see at the top. 6 It can handle buttons with multiple states/modes. 7*/ 8/* 9 DEF 10 11 outer: 12 name: for #id and local storage variable names 13 type: submit 14 icon: 15 onClick: 16 tooltip: 17 tooltip_width: 18 default_mode: 19 classes: 20 cls_remove: 21 states[mode] 22 icon: 23 onClick: 24 tooltip: 25 next_mode: 26 classes_add: 27 classes_remove: 28*/ 29MoaiEditor.Button = class { 30 31 constructor(def) { 32 33 // Parameters 34 this.id = 'moaied__btn_'+def.name; 35 this.name = def.name; 36 this.outer = def.outer; 37 this.type = def?.type ?? ''; 38 this.icon = def?.icon; 39 this.text = def?.text; 40 this.onClick = def.onClick; 41 this.classes = def?.classes; 42 this.states = def?.states; 43 this.tooltip = def?.tooltip; 44 this.tooltip_width = def?.tooltip_width; 45 this.tooltips = def?.tooltips; 46 this.cls_remove = def?.cls_remove; 47 this.default_mode = def?.default_mode; 48 49 // Objects 50 if (this.states !== undefined) { 51 const mode_names = Object.keys(this.states); 52 this.storage = new MoaiEditor.LocalStorage('btn_'+def.name, this.default_mode, mode_names); 53 } 54 // Init 55 this.__init(); 56 } 57 58 __init() { 59 const id = 'id="'+this.id+'"'; 60 const icon = '<i></i>'; 61 const text = '<span class="moaied-button-text"></span>'; 62 const type = 'type="'+this.type+'"'; 63 const classes = 'class="moaied-button moaied-tooltip '+(this.classes ?? '')+'"'; 64 const tooltip = '<span class="moaied-tooltip-text" '+this.__getTooltipWidthStyle()+'></span>'; 65 const onclick = 'onclick="moaiEditor.buttons.'+this.name+'.__onClick(event)"'; 66 const html = '<button form="" '+id+' '+type+' '+classes+' '+onclick+'>'+text+icon+tooltip+'</button>'; 67 this.handle = moaiEditor.createHTML(html); 68 //document.body.appendChild(this.handle); 69 this.update(); 70 } 71 72 __getTooltipWidthStyle() { 73 if (!this.tooltip_width) 74 return ''; 75 const width = "width:"+this.tooltip_width+"px !important;"; 76 const mleft = "margin-left: -"+Math.round(this.tooltip_width/2)+"px !important;"; 77 return 'style="'+width+mleft+'"'; 78 } 79 80 __onClick(event) { 81 82 // Toggle state and call state function 83 if (this.mode !== null && this.states) { 84 85 // Change the mode if applicable 86 const next_mode = this.states[this.mode]?.next_mode; 87 if (next_mode) 88 this.mode = next_mode; 89 90 // Get the current state 91 const state = this.states[this.mode]; 92 93 // Call a state function if defined 94 if (state.onClick) 95 state.onClick(event); 96 } 97 // Call a common function if defined 98 if (this.onClick) 99 this.onClick(event); 100 101 // Update the button appearance 102 this.update(); 103 } 104 105 update() { 106 // Return if the browser local storage failed 107 if (this.state === null) 108 return; 109 // Get the handle and the state 110 var state = {}; 111 if (this.states) 112 state = this.states[this.mode]; 113 // Icon 114 var icon = ''; 115 if (state?.icon ?? this.icon) { 116 var icon = state?.icon ?? this.icon; 117 if (!icon.startsWith('<img')) 118 icon = moaiEditor.icons?.[state?.icon ?? this.icon]; 119 } 120 this.handle.querySelector(':scope > i').innerHTML = icon; 121 // Text 122 var text = ''; 123 if (state?.text ?? this.text) 124 text = state?.text ?? this.text; 125 this.handle.querySelector(':scope > span.moaied-button-text').innerHTML = text; 126 // State tooltip 127 var tooltip = this.handle.querySelector(':scope > span.moaied-tooltip-text'); 128 if (state?.tooltip ?? this?.tooltip) 129 tooltip.style.display = 'block'; 130 // Button tooltip 131 else 132 tooltip.style.display = 'none'; 133 tooltip.innerHTML = state?.tooltip ?? this?.tooltip; 134 // Composite tooltip (tooltip is composed of messages added by several external processes) 135 if (this.tooltips) { 136 let html = ''; 137 for (let key in this.tooltips) 138 html += this.tooltips[key]; 139 tooltip.innerHTML = html; 140 } 141 // Classes 142 var classList = new MoaiEditor.ElementClassList(this.handle); 143 classList.removeByString(this?.cls_remove); 144 classList.removeByString(state?.cls_remove); 145 classList.addByString(this?.classes); 146 classList.addByString(state?.cls_add); 147 // Mirror mode into data-attribute for convinience 148 this.handle.dataset.moaiedMode = this.mode; 149 } 150 151 set mode(mode) { 152 if (this.storage !== undefined) { 153 this.storage.value = mode; 154 this.update(); 155 } 156 } 157 158 get mode() { 159 if (this.storage !== undefined) { 160 return this.storage.value; 161 } else 162 return null; 163 } 164}; // End Class 165 166// ▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆▆ 167 168MoaiEditor.ElementClassList = class { 169 170 constructor(node) { 171 this.node = node; 172 } 173 174 addByString(string) { 175 for (let name of this.splitString(string)) 176 this.node.classList.add(name) 177 } 178 179 removeByString(string) { 180 for (let name of this.splitString(string)) 181 this.node.classList.remove(name) 182 } 183 184 splitString(string) { 185 if (!string) 186 return []; 187 var array = []; 188 for (let name of string.split(" ")) { 189 name = name.trim(); 190 if (name.length > 0) 191 array.push(name); 192 } 193 return array; 194 } 195}; // End Class 196 197