rendering.mjs (7694B)
1 function generateTemplate(className, variable, selector) { 2 if (className[variable] === undefined) { 3 className[variable] = document.querySelector(selector).content; 4 } 5 } 6 7 class ParameterTemplate extends HTMLElement { 8 default = null; 9 10 inputElement = null; 11 12 static baseTemplate; 13 constructor(options = {}, className, selector, defaultValue=null, ...args) { 14 super(); 15 generateTemplate(ParameterTemplate, "baseTemplate", "#parameter"); 16 generateTemplate(className, "template", selector); 17 let baseClone = ParameterTemplate.baseTemplate.cloneNode(true); 18 19 let clone = className["template"].cloneNode(true); 20 21 this.initialize(clone, ...args); 22 23 this.inputElement = clone.querySelector("*[data-oninput]"); 24 if (this.inputElement !== null) { 25 this.inputElement.addEventListener("input", this.input.bind(this)); 26 } 27 28 clone.slot = "parameter"; 29 baseClone.appendChild(clone); 30 31 const shadowRoot = this.attachShadow({ mode: "open" }); 32 shadowRoot.appendChild(baseClone); 33 34 if ("defaultValue" in options) { 35 this.default = options.defaultValue; 36 this.setValue(options.defaultValue); 37 } else if (this.default === null) { 38 this.default = defaultValue; 39 } 40 } 41 42 setValue(v) { 43 if (this.inputElement !== null) { 44 this.inputElement.value = v; 45 } 46 } 47 48 getEventValue(event) { 49 return event.target.value; 50 } 51 52 input(event) { 53 this.dispatchEvent(new CustomEvent("parameter-input", { 54 detail: this.getEventValue(event) 55 })); 56 } 57 58 initialize(clone) { 59 60 } 61 } 62 63 customElements.define("terminus-param", ParameterTemplate); 64 65 class BooleanTemplate extends ParameterTemplate { 66 static template; 67 constructor(options) { 68 super(options, BooleanTemplate, "template#boolean", false); 69 } 70 71 getEventValue(event) { 72 return event.target.checked; 73 } 74 75 setValue(v) { 76 this.inputElement.checked = v; 77 } 78 } 79 80 customElements.define("terminus-param-boolean", BooleanTemplate); 81 82 class NumberTemplate extends ParameterTemplate { 83 static template; 84 constructor(options) { 85 super(options, NumberTemplate, "template#number", 0); 86 } 87 88 getEventValue(event) { 89 return parseFloat(event.target.value); 90 } 91 } 92 93 customElements.define("terminus-param-number", NumberTemplate); 94 95 class StringTemplate extends ParameterTemplate { 96 static template; 97 constructor(options) { 98 super(options, StringTemplate, "template#string", ""); 99 } 100 } 101 102 customElements.define("terminus-param-string", StringTemplate); 103 104 class StringArrayTemplate extends ParameterTemplate { 105 static template; 106 constructor(options) { 107 super(options, StringArrayTemplate, "template#string-array", []); 108 } 109 110 getEventValue(event) { 111 return event.target.value.split(","); 112 } 113 } 114 115 customElements.define("terminus-param-string-array", StringArrayTemplate); 116 117 class EnumOption extends HTMLElement { 118 static template; 119 constructor(optionText) { 120 super(); 121 generateTemplate(EnumOption, "template", "template#enum-option"); 122 let clone = EnumOption.template.cloneNode(true); 123 124 clone.querySelector("slot[name='option-text']").parentElement.innerText = optionText; 125 126 this.append(...clone.children); 127 } 128 } 129 130 customElements.define("terminus-enum-option", EnumOption); 131 132 class EnumTemplate extends ParameterTemplate { 133 static template; 134 135 #enumType; 136 constructor(options, enumType) { 137 super(options, EnumTemplate, "template#enum", null, enumType); 138 this.#enumType = enumType; 139 } 140 141 initialize(clone, enumType) { 142 let options = clone.querySelector("*[data-options]"); 143 144 for (let entry of enumType.getAllEntries()) { 145 146 if (this.default === null) { 147 this.default = entry[0]; 148 } 149 options.append(...(new EnumOption(entry[0])).children); 150 } 151 } 152 153 getEventValue(event) { 154 return this.#enumType[event.target.value]; 155 } 156 } 157 158 customElements.define("terminus-param-enum", EnumTemplate); 159 160 class TerminusParams extends HTMLElement { 161 #params = []; 162 163 constructor(library, evaluateExternal, params){ 164 super(); 165 166 for (var i = 0; i < params.length; i++) { 167 let param = params[i]; 168 let paramName = document.createElement("span"); 169 paramName.slot = "param-name"; 170 paramName.innerText = param.name; 171 172 var newChild; 173 174 switch (param.typeUse) { 175 case "string": 176 newChild = new StringTemplate(param); 177 this.#params[i] = ""; 178 break; 179 case "boolean": 180 newChild = new BooleanTemplate(param); 181 this.#params[i] = false; 182 break; 183 case "number": 184 newChild = new NumberTemplate(param); 185 this.#params[i] = 0; 186 break; 187 case "Array<string>": 188 newChild = new StringArrayTemplate(param); 189 this.#params[i] = []; 190 break; 191 case "enumerator": 192 newChild = new EnumTemplate(param, library[param.type]); 193 this.#params[i] = newChild.default 194 break; 195 case "external": 196 let updateParamEvent = (value) => { 197 this.#params[i] = value; 198 }; 199 evaluateExternal(param, updateParamEvent); 200 break; 201 default: 202 console.error("Unrecognized parameter: ", param); 203 break; 204 } 205 206 newChild.addEventListener("parameter-input", this.input.bind(this, i)); 207 this.#params[i] = newChild.default; 208 209 newChild.appendChild(paramName); 210 this.appendChild(newChild); 211 } 212 } 213 214 input(paramIdx, event) { 215 this.#params[paramIdx] = event.detail; 216 } 217 218 get paramArray() { 219 return this.#params; 220 } 221 } 222 223 customElements.define("terminus-params", TerminusParams); 224 225 export class TerminusRender extends HTMLElement { 226 static template; 227 228 #func = null; 229 #parameters; 230 #output; 231 constructor(library, evaluateExternal, terminus) { 232 super(); 233 generateTemplate(TerminusRender, "template", "template#terminus"); 234 let clone = TerminusRender.template.cloneNode(true); 235 236 this.id = terminus.funcName; 237 238 this.#func = terminus.func; 239 240 let button = clone.querySelector("*[data-submit]"); 241 button.addEventListener("click", this.submit.bind(this)); 242 243 let funcText = document.createElement("span"); 244 funcText.slot = "func-name"; 245 funcText.innerText = terminus.funcName; 246 this.appendChild(funcText); 247 248 this.#parameters = new TerminusParams(library, evaluateExternal, terminus.parameters); 249 this.#parameters.slot = "parameters"; 250 this.appendChild(this.#parameters); 251 252 this.#output = document.createElement("span"); 253 this.#output.slot = "output"; 254 255 this.appendChild(this.#output); 256 257 const shadowRoot = this.attachShadow({ mode: "open" }); 258 shadowRoot.appendChild(clone); 259 } 260 261 submit() { 262 try { 263 this.#output.innerText = this.#func(...this.#parameters.paramArray); 264 } catch(e) { 265 this.#output.innerText = e; 266 throw e; 267 } 268 } 269 } 270 271 customElements.define("terminus-render", TerminusRender);