web-components/ccp/js/inputwidgeteditorcontroller.js

267 lines
13 KiB
JavaScript

class CCPInputWidgetEditorController extends HTMLElement{
#input = null
#index = null
#type = null
#messages = {
"en" : {
"input_id_help" : "The Id of the input. This has to be unique accross all the inputs the method. This is used as variable expansion in scripts.",
"input_delete_help" : "Delete this input",
"title" : "Title",
"title_help" : "Title of the input. This is how the input will appear in forms.",
"description" : "Description",
"description_help" : "A description for this input",
"min_occurs" : "Min. count",
"max_occurs" : "Max. count",
"min_occurs_help" : "Minimum cardinality of this input",
"max_occurs_help" : "Maximum cardinality of this input",
"type" : "Type",
"type_help" : "Set the type of the input. Either String or Enumeration",
"mime" : "Mime",
"mime_help" : "Set MIME type of expected input",
"format" : "Format",
"format_help" : "Set specific format to tune the widget that will be used in forms",
"readonly" : "Read only",
"readonly_help" : "If enabled this input will not be editable in forms",
"string" : "String",
"enum" : "Enumerated",
"options" : "Options",
"options_help" : "A comma separated list of options for this enumerated input",
"options_ext_help" : "Comma separated list of options",
"choice" : "Single choice",
"multichoice" : "Multiple choices",
"default" : "Default value",
"default_help" : "The default value applied for this input when nothing is set explicitly"
}
}
#delete_icon = `
<svg style="width:24px;height:24px;pointer-events: none;" viewBox="0 0 24 24">
<path d="M19,4H15.5L14.5,3H9.5L8.5,4H5V6H19M6,19A2,2 0 0,0 8,21H16A2,2 0 0,0 18,19V7H6V19Z" />
</svg>
`
constructor(){
super();
}
connectedCallback(){
}
getLabel(key, localehint){
const locale = localehint ? localehint : navigator.language
const actlocale = this.#messages[locale] ? locale : "en"
const msg = this.#messages[actlocale][key]
return msg == null || msg == undefined ? key : this.#messages[actlocale][key]
}
get index(){
return this.#index
}
isSelectedFormat(fmt){
return this.#input.schema.format === fmt
}
renderDefaultByType(){
return `<d4s-ccp-input name="default" input="${btoa(JSON.stringify(this.#input))}"></d4s-ccp-input>`
}
renderDeleteButton(){
return `<button data-index="${this.#index}" name="delete-input" title="${this.getLabel("input_delete_help")}" class="btn btn-danger ccp-toolbar-button">
${this.#delete_icon}
</button>`
}
render(input, i, reopen){
this.#index = i
this.#input = input
this.#type = input.schema.enum ? "enum" : "string"
const minOccurs = input.minOccurs = Number(input.minOccurs) ? Number(input.minOccurs) : 0
const maxOccurs = input.maxOccurs = Number(input.maxOccurs) ? Number(input.maxOccurs) : 0
this.innerHTML = `
<details ${ reopen ? 'open' : ''}>
<summary class="mb-3">
<input class="form-control" style="width:auto;display:inline" required="required" name="id" value="${input.id}" title="${this.getLabel("input_id_help")}" ${ input.id === 'ccpimage' ? 'readonly' : ''}/>
${ input.id !== 'ccpimage' ? this.renderDeleteButton() : ''}
</summary>
<div style="padding-left: 1rem;border-left: 1px solid gray;">
<div class="row mb-3">
<div class="col">
<div class="form-field" title="${this.getLabel("title_help")}">
<input name="title" class="form-control" placeholder="${this.getLabel("title")}" value="${input.title}" required="required" ${ input.id === 'ccpimage' ? 'readonly' : ''}/>
</div>
</div>
</div>
<div class="mb-3">
<div class="form-field" title="${this.getLabel("description_help")}">
<textarea rows="1" name="description" class="form-control" placeholder="${this.getLabel("description")}" required="required" ${ input.id === 'ccpimage' ? 'readonly' : ''}>${input.description}</textarea>
</div>
</div>
<div class="row mb-3">
<div class="col-3">
<div class="form-field" title="${this.getLabel("type_help")}">
<label>${this.getLabel("type")}</label>
<select name="type" class="form-control" placeholder="${this.getLabel("type")}" value="${this.#type}">
<option value="string" ${this.#type === "string" ? "selected" : ""}>${this.getLabel("string")}</option>
${ input.id === 'ccpimage' ? '' : `<option value="enum" ${this.#type === "enum" ? "selected" : ""}>${this.getLabel("enum")}</option>` }
</select>
</div>
</div>
<div class="col">
<div class="form-field" title="${this.getLabel("min_occurs_help")}">
<label>${this.getLabel("min_occurs")}</label>
<input value="${minOccurs}" type="number" min="0" step="1" name="minOccurs" value="${minOccurs}" required="required" class="form-control" placeholder="${this.getLabel("min_occurs")}" ${ input.id === 'ccpimage' ? 'readonly' : ''}/>
</div>
</div>
<div class="col">
<div class="form-field" title="${this.getLabel("max_occurs_help")}">
<label>${this.getLabel("max_occurs")}</label>
<input value="${maxOccurs}" type="number" min="0" step="1" name="maxOccurs" value="${maxOccurs}" required="required" class="form-control" placeholder="${this.getLabel("max_occurs")}" ${ input.id === 'ccpimage' ? 'readonly' : ''}/>
</div>
</div>
<div class="col" title="${this.getLabel("readonly_help")}">
<label>${this.getLabel("readonly")}</label>
<div class="form-field">
<input type="checkbox" ${input.schema.readOnly ? 'checked' : ''} name="readonly" class="form-check-input">
</div>
</div>
</div>
<div name="string-input" class="${this.#type === 'enum' ? 'd-none' : ''} row mb-3">
<div class="col-3">
<div class="form-field" title="${this.getLabel("format_help")}">
<label>${this.getLabel("format")}</label>
<select value="${input.schema.format}" name="format" class="form-control" ${ input.id === 'ccpimage' ? 'readonly' : ''}>
<option value="none" ${this.isSelectedFormat('none') ? "selected" : ""}>None</option>
<option value="date" ${this.isSelectedFormat('date') ? "selected" : ""}>Date</option>
<option value="time" ${this.isSelectedFormat('time') ? "selected" : ""}>Time</option>
<option value="dateTime" ${this.isSelectedFormat('dateTime') ? "selected" : ""}>Date time</option>
<option value="number" ${this.isSelectedFormat('number') ? "selected" : ""}>Number</option>
<option value="boolean" ${this.isSelectedFormat('boolean') ? "selected" : ""}>True/False</option>
<option value="code" ${this.isSelectedFormat('code') ? "selected" : ""}>Code</option>
<option value="file" ${this.isSelectedFormat('file') ? "selected" : ""}>File</option>
<option value="remotefile" ${this.isSelectedFormat('remotefile') ? "selected" : ""}>Workspace file</option>
<option value="geo" ${this.isSelectedFormat('geo') ? "selected" : ""}>Geography</option>
<option value="secret" ${this.isSelectedFormat('secret') ? "selected" : ""}>Secret</option>
<option value="url" ${this.isSelectedFormat('url') ? "selected" : ""}>Url</option>
</select>
</div>
</div>
<div class="col" title="${this.getLabel("mime_help")}">
<label>${this.getLabel("mime")}</label>
<div class="form-field">
<input value="${input.schema.contentMediaType}" name="contentMediaType" class="form-control" placeholder="mime" ${ input.id === 'ccpimage' ? 'readonly' : ''}/>
</div>
</div>
</div>
<div name="enum-input" class="${this.#type !== 'enum' ? 'd-none' : ''} mb-3">
<div class="form-field" title="${this.getLabel("options_help")}">
<input name="options" class="form-control" type="text" placeholder="${this.getLabel("options")}" value="${input.schema.enum ? input.schema.enum.join(',') : ''}"/>
<small class="form-text text-muted">${this.getLabel("options_ext_help")}</small>
</div>
<div class="form-field" title="${this.getLabel("format_help")}">
<label>${this.getLabel("format")}</label>
<select value="${input.schema.format}" name="format" class="form-control">
<option value="select" ${this.isSelectedFormat('select') ? "selected" : ""}>${this.getLabel("choice")}</option>
<option value="checklist" ${this.isSelectedFormat('checklist') ? "selected" : ""}>${this.getLabel("multi_choice")}e</option>
</select>
</div>
</div>
<div name="input-default" class="mb-3">
<label>${this.getLabel("default")}</label>
<div class="form-field border border-info px-2 py-1" style="background-color:#0dcaf022" title="${this.getLabel("default_help")}">
<div name="default-container">${this.renderDefaultByType()}</div>
<span style="user-select:none;position:relative;top:-1.6rem;float:right;cursor:pointer" name="password_toggle" class="${this.isSelectedFormat('secret') ? 'inline' : 'd-none'}">&#128065;</span>
</div>
</div>
</div>
</details>
`
this.addEventListener("click", ev=>{
const ename = ev.target.getAttribute("name")
if(ename === "password_toggle"){
const w = this.querySelector("div[name=input-default] input[name=default]")
w.type = (w.type === "password" ? "" : "password")
ev.preventDefault()
}
})
const defaultinp = this.querySelector("div[name='input-default']")
defaultinp.addEventListener("input", ev=>{
const inp = this.querySelector("d4s-ccp-input")
this.#input.schema.default = inp.value
})
defaultinp.addEventListener("change", ev=>{
const inp = this.querySelector("d4s-ccp-input")
this.#input.schema.default = inp.value
})
defaultinp.addEventListener("click", ev=>{
const src = ev.target.getAttribute("name")
if (src === "plus" || src === "minus") {
const inp = this.querySelector("d4s-ccp-input")
this.#input.schema.default = inp.value
}
})
this.addEventListener("input", ev=>{
const val = ev.target.value
const ename = ev.target.getAttribute("name")
const display = this.querySelector("div[name='default-container']")
if(ename === "id"){
this.#input.id = val
}
else if(ename === "title"){
this.#input.title = val
display.innerHTML = this.renderDefaultByType()
}
else if(ename === "description"){
this.#input.description = val
display.innerHTML = this.renderDefaultByType()
}
else if(ename === "minOccurs"){
this.#input.minOccurs = Number(val) ? Number(val) : 0
display.innerHTML = this.renderDefaultByType()
}
else if(ename === "maxOccurs"){
this.#input.maxOccurs = Number(val) ? Number(val) : 0
display.innerHTML = this.renderDefaultByType()
}
else if(ename === "format"){
this.#input.schema.format = val
display.innerHTML = this.renderDefaultByType()
}
else if(ename === "contentMediaType"){
this.#input.schema.contentMediaType = val
display.innerHTML = this.renderDefaultByType()
}
else if(ename === "options"){
this.#input.schema.enum = val.split(",")
display.innerHTML = this.renderDefaultByType()
}
else if(ename === "readonly"){
this.#input.schema.readOnly = ev.target.checked
display.innerHTML = this.renderDefaultByType()
}
else if(ename === "type"){
this.#type = ev.target.value
if(this.#type === "enum"){
this.querySelector("div[name=string-input]").classList.add("d-none")
this.querySelector("div[name=enum-input]").classList.remove("d-none")
this.#input.schema.enum = this.querySelector("input[name=options]").value.split(",")
}else if(this.#type === "string"){
this.querySelector("div[name=enum-input]").classList.add("d-none")
this.querySelector("div[name=string-input]").classList.remove("d-none")
delete this.#input.schema['enum']
}
display.innerHTML = this.renderDefaultByType()
}
})
}
}
window.customElements.define('d4s-ccp-input-editor', CCPInputWidgetEditorController);