improved consistency between config changes and default value #22

Merged
m.lettere merged 1 commits from master into prod 2024-09-25 09:55:43 +02:00
1 changed files with 143 additions and 80 deletions

View File

@ -1,37 +1,37 @@
class CCPInputWidgetEditorController extends HTMLElement{ class CCPInputWidgetEditorController extends HTMLElement {
#input = null #input = null
#index = null #index = null
#type = null #type = null
#messages = { #messages = {
"en" : { "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_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", "input_delete_help": "Delete this input",
"title" : "Title", "title": "Title",
"title_help" : "Title of the input. This is how the input will appear in forms.", "title_help": "Title of the input. This is how the input will appear in forms.",
"description" : "Description", "description": "Description",
"description_help" : "A description for this input", "description_help": "A description for this input",
"min_occurs" : "Min. count", "min_occurs": "Min. count",
"max_occurs" : "Max. count", "max_occurs": "Max. count",
"min_occurs_help" : "Minimum cardinality of this input", "min_occurs_help": "Minimum cardinality of this input",
"max_occurs_help" : "Maximum cardinality of this input", "max_occurs_help": "Maximum cardinality of this input",
"type" : "Type", "type": "Type",
"type_help" : "Set the type of the input. Either String or Enumeration", "type_help": "Set the type of the input. Either String or Enumeration",
"mime" : "Mime", "mime": "Mime",
"mime_help" : "Set MIME type of expected input", "mime_help": "Set MIME type of expected input",
"format" : "Format", "format": "Format",
"format_help" : "Set specific format to tune the widget that will be used in forms", "format_help": "Set specific format to tune the widget that will be used in forms",
"readonly" : "Read only", "readonly": "Read only",
"readonly_help" : "If enabled this input will not be editable in forms", "readonly_help": "If enabled this input will not be editable in forms",
"string" : "String", "string": "String",
"enum" : "Enumerated", "enum": "Enumerated",
"options" : "Options", "options": "Options",
"options_help" : "A comma separated list of options for this enumerated input", "options_help": "A comma separated list of options for this enumerated input",
"options_ext_help" : "Comma separated list of options", "options_ext_help": "Comma separated list of options",
"choice" : "Single choice", "choice": "Single choice",
"multichoice" : "Multiple choices", "multichoice": "Multiple choices",
"default" : "Default value", "default": "Default value",
"default_help" : "The default value applied for this input when nothing is set explicitly" "default_help": "The default value applied for this input when nothing is set explicitly"
} }
} }
@ -41,63 +41,63 @@ class CCPInputWidgetEditorController extends HTMLElement{
</svg> </svg>
` `
constructor(){ constructor() {
super(); super();
} }
connectedCallback(){ connectedCallback() {
} }
getLabel(key, localehint){ getLabel(key, localehint) {
const locale = localehint ? localehint : navigator.language const locale = localehint ? localehint : navigator.language
const actlocale = this.#messages[locale] ? locale : "en" const actlocale = this.#messages[locale] ? locale : "en"
const msg = this.#messages[actlocale][key] const msg = this.#messages[actlocale][key]
return msg == null || msg == undefined ? key : this.#messages[actlocale][key] return msg == null || msg == undefined ? key : this.#messages[actlocale][key]
} }
get index(){ get index() {
return this.#index return this.#index
} }
isSelectedFormat(fmt){ isSelectedFormat(fmt) {
return this.#input.schema.format === fmt return this.#input.schema.format === fmt
} }
renderDefaultByType(){ renderDefaultByType() {
return `<d4s-ccp-input name="default" input="${btoa(JSON.stringify(this.#input))}"></d4s-ccp-input>` return `<d4s-ccp-input name="default" input="${btoa(JSON.stringify(this.#input))}"></d4s-ccp-input>`
} }
renderDeleteButton(){ renderDeleteButton() {
return `<button data-index="${this.#index}" name="delete-input" title="${this.getLabel("input_delete_help")}" class="btn btn-danger ccp-toolbar-button"> 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} ${this.#delete_icon}
</button>` </button>`
} }
render(input, i, reopen){ render(input, i, reopen) {
this.#index = i this.#index = i
this.#input = input this.#input = input
this.#type = input.schema.enum ? "enum" : "string" this.#type = input.schema.enum ? "enum" : "string"
const minOccurs = input.minOccurs = Number(input.minOccurs) ? Number(input.minOccurs) : 0 const minOccurs = input.minOccurs = Number(input.minOccurs) ? Number(input.minOccurs) : 0
const maxOccurs = input.maxOccurs = Number(input.maxOccurs) ? Number(input.maxOccurs) : 0 const maxOccurs = input.maxOccurs = Number(input.maxOccurs) ? Number(input.maxOccurs) : 0
this.innerHTML = ` this.innerHTML = `
<details ${ reopen ? 'open' : ''}> <details ${reopen ? 'open' : ''}>
<summary class="mb-3"> <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 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() : ''} ${input.id !== 'ccpimage' ? this.renderDeleteButton() : ''}
</summary> </summary>
<div style="padding-left: 1rem;border-left: 1px solid gray;"> <div style="padding-left: 1rem;border-left: 1px solid gray;">
<div class="row mb-3"> <div class="row mb-3">
<div class="col"> <div class="col">
<div class="form-field" title="${this.getLabel("title_help")}"> <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' : ''}/> <input name="title" class="form-control" placeholder="${this.getLabel("title")}" value="${input.title}" required="required" ${input.id === 'ccpimage' ? 'readonly' : ''}/>
</div> </div>
</div> </div>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<div class="form-field" title="${this.getLabel("description_help")}"> <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> <textarea rows="1" name="description" class="form-control" placeholder="${this.getLabel("description")}" required="required" ${input.id === 'ccpimage' ? 'readonly' : ''}>${input.description}</textarea>
</div> </div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
@ -106,20 +106,20 @@ class CCPInputWidgetEditorController extends HTMLElement{
<label>${this.getLabel("type")}</label> <label>${this.getLabel("type")}</label>
<select name="type" class="form-control" placeholder="${this.getLabel("type")}" value="${this.#type}"> <select name="type" class="form-control" placeholder="${this.getLabel("type")}" value="${this.#type}">
<option value="string" ${this.#type === "string" ? "selected" : ""}>${this.getLabel("string")}</option> <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>` } ${input.id === 'ccpimage' ? '' : `<option value="enum" ${this.#type === "enum" ? "selected" : ""}>${this.getLabel("enum")}</option>`}
</select> </select>
</div> </div>
</div> </div>
<div class="col"> <div class="col">
<div class="form-field" title="${this.getLabel("min_occurs_help")}"> <div class="form-field" title="${this.getLabel("min_occurs_help")}">
<label>${this.getLabel("min_occurs")}</label> <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' : ''}/> <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> </div>
<div class="col"> <div class="col">
<div class="form-field" title="${this.getLabel("max_occurs_help")}"> <div class="form-field" title="${this.getLabel("max_occurs_help")}">
<label>${this.getLabel("max_occurs")}</label> <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' : ''}/> <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> </div>
<div class="col" title="${this.getLabel("readonly_help")}"> <div class="col" title="${this.getLabel("readonly_help")}">
@ -133,7 +133,7 @@ class CCPInputWidgetEditorController extends HTMLElement{
<div class="col-3"> <div class="col-3">
<div class="form-field" title="${this.getLabel("format_help")}"> <div class="form-field" title="${this.getLabel("format_help")}">
<label>${this.getLabel("format")}</label> <label>${this.getLabel("format")}</label>
<select value="${input.schema.format}" name="format" class="form-control" ${ input.id === 'ccpimage' ? 'readonly' : ''}> <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="none" ${this.isSelectedFormat('none') ? "selected" : ""}>None</option>
<option value="date" ${this.isSelectedFormat('date') ? "selected" : ""}>Date</option> <option value="date" ${this.isSelectedFormat('date') ? "selected" : ""}>Date</option>
<option value="time" ${this.isSelectedFormat('time') ? "selected" : ""}>Time</option> <option value="time" ${this.isSelectedFormat('time') ? "selected" : ""}>Time</option>
@ -152,7 +152,7 @@ class CCPInputWidgetEditorController extends HTMLElement{
<div class="col" title="${this.getLabel("mime_help")}"> <div class="col" title="${this.getLabel("mime_help")}">
<label>${this.getLabel("mime")}</label> <label>${this.getLabel("mime")}</label>
<div class="form-field"> <div class="form-field">
<input value="${input.schema.contentMediaType}" name="contentMediaType" class="form-control" placeholder="mime" ${ input.id === 'ccpimage' ? 'readonly' : ''}/> <input value="${input.schema.contentMediaType}" name="contentMediaType" class="form-control" placeholder="mime" ${input.id === 'ccpimage' ? 'readonly' : ''}/>
</div> </div>
</div> </div>
</div> </div>
@ -165,7 +165,7 @@ class CCPInputWidgetEditorController extends HTMLElement{
<label>${this.getLabel("format")}</label> <label>${this.getLabel("format")}</label>
<select value="${input.schema.format}" name="format" class="form-control"> <select value="${input.schema.format}" name="format" class="form-control">
<option value="select" ${this.isSelectedFormat('select') ? "selected" : ""}>${this.getLabel("choice")}</option> <option value="select" ${this.isSelectedFormat('select') ? "selected" : ""}>${this.getLabel("choice")}</option>
<option value="checklist" ${this.isSelectedFormat('checklist') ? "selected" : ""}>${this.getLabel("multi_choice")}e</option> <option value="checklist" ${this.isSelectedFormat('checklist') ? "selected" : ""}>${this.getLabel("multi_choice")}</option>
</select> </select>
</div> </div>
</div> </div>
@ -179,9 +179,9 @@ class CCPInputWidgetEditorController extends HTMLElement{
</div> </div>
</details> </details>
` `
this.addEventListener("click", ev=>{ this.addEventListener("click", ev => {
const ename = ev.target.getAttribute("name") const ename = ev.target.getAttribute("name")
if(ename === "password_toggle"){ if (ename === "password_toggle") {
const w = this.querySelector("div[name=input-default] input[name=default]") const w = this.querySelector("div[name=input-default] input[name=default]")
w.type = (w.type === "password" ? "" : "password") w.type = (w.type === "password" ? "" : "password")
ev.preventDefault() ev.preventDefault()
@ -189,17 +189,17 @@ class CCPInputWidgetEditorController extends HTMLElement{
}) })
const defaultinp = this.querySelector("div[name='input-default']") const defaultinp = this.querySelector("div[name='input-default']")
defaultinp.addEventListener("input", ev=>{ defaultinp.addEventListener("input", ev => {
const inp = this.querySelector("d4s-ccp-input") const inp = this.querySelector("d4s-ccp-input")
this.#input.schema.default = inp.value this.#input.schema.default = inp.value
}) })
defaultinp.addEventListener("change", ev=>{ defaultinp.addEventListener("change", ev => {
const inp = this.querySelector("d4s-ccp-input") const inp = this.querySelector("d4s-ccp-input")
this.#input.schema.default = inp.value this.#input.schema.default = inp.value
}) })
defaultinp.addEventListener("click", ev=>{ defaultinp.addEventListener("click", ev => {
const src = ev.target.getAttribute("name") const src = ev.target.getAttribute("name")
if (src === "plus" || src === "minus") { if (src === "plus" || src === "minus") {
const inp = this.querySelector("d4s-ccp-input") const inp = this.querySelector("d4s-ccp-input")
@ -207,54 +207,64 @@ class CCPInputWidgetEditorController extends HTMLElement{
} }
}) })
this.addEventListener("input", ev=>{ this.addEventListener("input", ev => {
const val = ev.target.value const val = ev.target.value
const ename = ev.target.getAttribute("name") const ename = ev.target.getAttribute("name")
const display = this.querySelector("div[name='default-container']") const display = this.querySelector("div[name='default-container']")
if(ename === "id"){ if (ename === "id") {
this.#input.id = val this.#input.id = val
} }
else if(ename === "title"){ else if (ename === "title") {
this.#input.title = val this.#input.title = val
display.innerHTML = this.renderDefaultByType() display.innerHTML = this.renderDefaultByType()
} }
else if(ename === "description"){ else if (ename === "description") {
this.#input.description = val this.#input.description = val
display.innerHTML = this.renderDefaultByType() display.innerHTML = this.renderDefaultByType()
} }
else if(ename === "minOccurs"){ else if (ename === "minOccurs") {
this.#input.minOccurs = Number(val) ? Number(val) : 0 this.#input.minOccurs = Number(val) ? Number(val) : 0
display.innerHTML = this.renderDefaultByType() display.innerHTML = this.renderDefaultByType()
} }
else if(ename === "maxOccurs"){ else if (ename === "maxOccurs") {
this.#input.maxOccurs = Number(val) ? Number(val) : 0 this.#input.maxOccurs = Number(val) ? Number(val) : 0
display.innerHTML = this.renderDefaultByType() display.innerHTML = this.renderDefaultByType()
} }
else if(ename === "format"){ else if (ename === "format") {
this.#input.schema.default = this.formatConversion(this.#input.schema.format, this.#input.schema.default, val)
this.#input.schema.format = val this.#input.schema.format = val
display.innerHTML = this.renderDefaultByType() display.innerHTML = this.renderDefaultByType()
} }
else if(ename === "contentMediaType"){ else if (ename === "contentMediaType") {
this.#input.schema.contentMediaType = val this.#input.schema.contentMediaType = val
display.innerHTML = this.renderDefaultByType() display.innerHTML = this.renderDefaultByType()
} }
else if(ename === "options"){ else if (ename === "options") {
this.#input.schema.enum = val.split(",") this.#input.schema.enum = val.split(",")
if (this.#input.schema.enum.indexOf(this.#input.schema.default) === -1) {
this.#input.schema.default = this.#input.schema.enum[0]
}
display.innerHTML = this.renderDefaultByType() display.innerHTML = this.renderDefaultByType()
} }
else if(ename === "readonly"){ else if (ename === "readonly") {
this.#input.schema.readOnly = ev.target.checked this.#input.schema.readOnly = ev.target.checked
display.innerHTML = this.renderDefaultByType() display.innerHTML = this.renderDefaultByType()
} }
else if(ename === "type"){ else if (ename === "type") {
this.#type = ev.target.value this.#type = ev.target.value
if(this.#type === "enum"){ if (this.#type === "enum") {
this.querySelector("div[name=string-input]").classList.add("d-none") this.querySelector("div[name=string-input]").classList.add("d-none")
this.querySelector("div[name=enum-input]").classList.remove("d-none") this.querySelector("div[name=enum-input]").classList.remove("d-none")
this.querySelector("div[name=enum-input] select[name=format]").value = "select"
this.#input.schema.format = "select"
this.#input.schema.enum = this.querySelector("input[name=options]").value.split(",") this.#input.schema.enum = this.querySelector("input[name=options]").value.split(",")
}else if(this.#type === "string"){ if (this.#input.schema.enum.indexOf(this.#input.schema.default) === -1) {
this.#input.schema.default = this.#input.schema.enum[0]
}
} else if (this.#type === "string") {
this.querySelector("div[name=enum-input]").classList.add("d-none") this.querySelector("div[name=enum-input]").classList.add("d-none")
this.querySelector("div[name=string-input]").classList.remove("d-none") this.querySelector("div[name=string-input]").classList.remove("d-none")
this.#input.schema.format = "none"
delete this.#input.schema['enum'] delete this.#input.schema['enum']
} }
display.innerHTML = this.renderDefaultByType() display.innerHTML = this.renderDefaultByType()
@ -262,5 +272,58 @@ class CCPInputWidgetEditorController extends HTMLElement{
}) })
} }
boolean2number(prev){
if(Array.isArray(prev)){
return prev.map(v=>(v === "true" || v === true ? "1" : "0"))
} else return prev === "true" || prev === true ? "1" : "0"
}
none2number(prev){
if(Array.isArray(prev)){
return prev.map(v=>(isNaN(Number(v)) ? "0" : v))
} else return isNaN(Number(prev)) ? "0" : prev
}
number2boolean(prev){
if(Array.isArray(prev)){
return prev.map(v=>(Number(v) !== 0 ? "true" : "false"))
} else return Number(prev) !== 0 ? "true" : "false"
}
none2boolean(prev){
if(Array.isArray(prev)){
return prev.map(v=>(["true", "false"].indexOf(v.toLowerCase()) !== -1 ? v.toLowerCase() : "false"))
} else return ["true", "false"].indexOf(prev.toLowerCase()) !== -1 ? prev.toLowerCase() : "false"
}
any2boolean(prev){
if(Array.isArray(prev)){
return prev.map(v=>String(!!v))
} else return String(!!v);
}
any2empty(prev){
if(Array.isArray(prev)){
return prev.map(v=>"")
} else return "";
}
formatConversion(prevformat, prevvalue, format){
if(format === "none"){
return prevvalue;
}
if(format === "number"){
if(prevformat === "boolean") return this.boolean2number(prevvalue);
if(!prevformat || prevformat === "none") return this.none2number(prevvalue);
return "0";
}
if(format === "boolean"){
if(prevformat === "number") return this.number2boolean(prevvalue)
if(!prevformat || prevformat === "none") return this.none2boolean(prevvalue)
return this.any2boolean(prevvalue)
}
return this.any2empty(prevvalue)
}
} }
window.customElements.define('d4s-ccp-input-editor', CCPInputWidgetEditorController); window.customElements.define('d4s-ccp-input-editor', CCPInputWidgetEditorController);