diff --git a/ccp/js/executionformcontroller.js b/ccp/js/executionformcontroller.js
index 6e53f7c..246decb 100644
--- a/ccp/js/executionformcontroller.js
+++ b/ccp/js/executionformcontroller.js
@@ -61,7 +61,7 @@ class CCPExecutionForm extends HTMLElement{
-
diff --git a/ccp/js/inputwidgetcontroller.js b/ccp/js/inputwidgetcontroller.js
index 12c98e3..33a82d9 100644
--- a/ccp/js/inputwidgetcontroller.js
+++ b/ccp/js/inputwidgetcontroller.js
@@ -1,181 +1,319 @@
class CCPInputWidgetController extends HTMLElement {
-
- #input = null;
- #renderer = null;
+
+ #data = null;
constructor(){
- super()
- this.#input = JSON.parse(this.getAttribute("input"))
- this.#renderer = Renderer.instance(this.#input)
+ super()
}
connectedCallback(){
- console.log("Widget connected")
- this.innerHTML = this.render()
- this.#renderer.connectedCallback(this)
+ this.#data = JSON.parse(this.getAttribute("input"))
+
+ if(this.isEnum()){
+ const opts = this.#data.schema.enum.join(",")
+ this.innerHTML += `
`
+
+ }else if(this.isCode()){
+ this.innerHTML += `
`
+
+ }else if(this.isDateTime()){
+ const t = this.#data.schema.format.toLowerCase() === "datetime" ?
+ "datetime-local" : this.#data.schema.format.toLowerCase()
+ this.innerHTML += `
`
+
+ }else if(this.isFile()){
+ this.innerHTML += `
`
+
+ }else if(this.isSecret()){
+ this.innerHTML += `
`
+
+ }else{
+ this.innerHTML += `
`
+ }
}
- render(){
- return this.#renderer.render()
- }
-
- get name(){
- return this.#renderer.name
+ set value(value){
+ this.firstElementChild.value = value
}
get value(){
- return this.#renderer.getValue(this)
+ return this.firstElementChild.value.length === 1 ?
+ this.firstElementChild.value[0] :
+ this.firstElementChild.value
}
- set value(v){
- return this.#renderer.setValue(this, v)
+ get name(){
+ return this.firstElementChild.name
+ }
+
+ isEnum(input){
+ return (this.#data.schema.type === "string") && ("enum" in this.#data.schema)
+ }
+
+ isSecret(){
+ return (this.#data.schema.type === "string") &&
+ ("format" in this.#data.schema) &&
+ (this.#data.schema.format != null) &&
+ (this.#data.schema.format.toLowerCase() === "secret")
+ }
+
+ isCode(){
+ return (this.#data.schema.type === "string") &&
+ ("format" in this.#data.schema) &&
+ (this.#data.schema.format != null) &&
+ (this.#data.schema.format.toLowerCase() === "code")
+ }
+
+ isFile(){
+ return (this.#data.schema.type === "string") &&
+ ("format" in this.#data.schema) &&
+ (this.#data.schema.format != null) &&
+ (this.#data.schema.format.toLowerCase() === "file")
+ }
+
+ isDateTime(){
+ return (this.#data.schema.type === "string") &&
+ ("format" in this.#data.schema) &&
+ (this.#data.schema.format != null) &&
+ (["date", "time", "datetime"].indexOf(this.#data.schema.format.toLowerCase()) !== -1)
}
}
window.customElements.define('d4s-ccp-input', CCPInputWidgetController);
-class Renderer{
+class CCPBaseInputWidgetController extends HTMLElement{
+ #rootdoc = null;
+ #minOccurs = 1;
+ #maxOccurs = 1;
+ #description = ""
+ #title = ""
+ #name = ""
+ #default = null
+ #options = null
+ #value = null
+ #readonly = false
- #input = null;
+ //useful to avoid having a custom element for every basic input type
+ #type = null
- constructor(input){
- this.#input = input
- }
+ #count = 1
- connectedCallback(controller){
+ constructor(){
+ super()
+ this.#rootdoc = this//this.attachShadow({ mode: "open" });
+ this.#name = this.getAttribute("name")
+ this.#title = this.getAttribute("title")
+ this.#description = this.getAttribute("description")
+ this.#default = this.getAttribute("default")
+ this.#minOccurs = Number(this.getAttribute("minoccurs") ? this.getAttribute("minoccurs") : 1)
+ this.#maxOccurs = Number(this.getAttribute("maxoccurs") ? this.getAttribute("maxoccurs") : 1)
+ this.#readonly = this.getAttribute("readonly") === "true"
+ // coalesce all basic input types
+ this.#type = this.getAttribute("type")
+
+ // Handle enum case
+ this.#options = (this.getAttribute("options") ? this.getAttribute("options").split(",") : null)
+
+ this.value = Array(Math.max(this.#minOccurs,1)).fill(this.#default)
}
- get schema(){
- return this.#input.schema
+ set value(v){
+ const actual = Array.isArray(v) ? v : [v]
+ if(actual.length < this.#minOccurs || actual.length > this.#maxOccurs){
+ throw `Value with length ${v.length} does not respect bounds [${this.minOccurs},${this.maxOccurs}]`
+ }
+ this.#value = actual
+ this.render()
}
- get name(){
- return this.#input.id
- }
-
- get title(){
- return this.#input.title
+ get value(){
+ return this.#value
}
- get description(){
- return this.#input.description
+ get rootdoc(){
+ return this.#rootdoc
}
get required(){
- return this.#input.minOccurs > 0
- }
-
- get readOnly(){
- return this.#input.schema.readOnly
+ return this.#minOccurs > 0
}
- static instance(input){
- if(this.isEnum(input)){
- return new EnumInputRenderer(input)
- }
- if(this.isCode(input)){
- return new CodeInputRenderer(input)
- }
- if(this.isDateTime(input)){
- return new DateTimeInputRenderer(input)
- }
- if(this.isSecret(input)){
- return new SecretInputRenderer(input)
- }
- if(this.isFile(input)){
- return new FileInputRenderer(input)
- }
- return new SimpleInputRenderer(input)
+ get readonly(){
+ return this.#readonly
}
- static isEnum(input){
- return (input.schema.type === "string") && ("enum" in input.schema)
- }
-
- static isSecret(input){
- return (input.schema.type === "string") &&
- ("format" in input.schema) &&
- (input.schema.format != null) &&
- (input.schema.format.toLowerCase() === "secret")
+ isIncrementable(){
+ return this.#value.length < this.#maxOccurs
}
- static isCode(input){
- return (input.schema.type === "string") &&
- ("format" in input.schema) &&
- (input.schema.format != null) &&
- (input.schema.format.toLowerCase() === "code")
- }
-
- static isFile(input){
- return (input.schema.type === "string") &&
- ("format" in input.schema) &&
- (input.schema.format != null) &&
- (input.schema.format.toLowerCase() === "file")
+ isDecrementable(){
+ return this.#value.length > this.#minOccurs && this.#value.length > 1
}
- static isDateTime(input){
- return (input.schema.type === "string") &&
- ("format" in input.schema) &&
- (input.schema.format != null) &&
- (["date", "time", "datetime"].indexOf(input.schema.format.toLowerCase()) !== -1)
- }
-}
-
-class SimpleInputRenderer extends Renderer{
-
- #html = null;
-
- constructor(input){
- super(input)
+ get count(){
+ return this.#count
}
- getValue(parent){
- return parent.querySelector("input").value
+ get name(){
+ return this.#name
}
- setValue(parent, v){
- parent.querySelector("input").value = v
+ get title(){
+ return this.#title
+ }
+
+ get description(){
+ return this.#description
+ }
+
+ get default(){
+ return this.#default
+ }
+
+ get options(){
+ return this.#options
+ }
+
+ set default(v){
+ this.#default = v
+ }
+
+ get type(){
+ return this.#type
}
render(){
- let required = this.required ? 'required="required"' : ""
- let readonly = this.readOnly ? 'readonly="readOnly"' : ""
- this.#html = `
-
+ `
+ this.#rootdoc.querySelector("div[name=root]").addEventListener("click", ev=>{
+ const src = ev.target.getAttribute("name")
+ if(src === "plus"){
+ this.#value.push(this.#default)
+ this.render()
+ }else if(src === "minus"){
+ this.#value.pop()
+ this.render()
+ }
+ })
}
}
-class FileInputRenderer extends Renderer{
-
- #html = null;
- #content = null;
-
- constructor(input){
- super(input)
+class CCPSimpleInputWidgetController extends CCPBaseInputWidgetController{
+
+ constructor(){
+ super()
}
- connectedCallback(controller){
- controller.querySelector(`input[name=${this.name}]`).addEventListener("change", ev=>{
+ connectedCallback(){
+ this.rootdoc.addEventListener("input", ev=>{
+ if(ev.target.getAttribute("name") === this.name){
+ const index = Number(ev.target.getAttribute("data-index"))
+ this.value[index] = ev.target.value
+ }
+ })
+ }
+
+ content(){
+ if(this.value.length <= 1){
+ return `
`
+ }
+ var out =
+ this.value.map((c,i)=>{
+ return `
+
+ `
+ }).join("\n")
+ return out
+ }
+}
+window.customElements.define('d4s-ccp-input-simple', CCPSimpleInputWidgetController);
+
+class CCPEnumInputWidgetController extends CCPBaseInputWidgetController{
+
+ constructor(){
+ super()
+ }
+
+ connectedCallback(){
+ this.rootdoc.addEventListener("change", ev=>{
+ if(ev.target.getAttribute("name") === this.name){
+ const index = Number(ev.target.getAttribute("data-index"))
+ this.value[index] = ev.target.value
+ }
+ })
+ }
+
+ content(){
+ const opts = this.options.map(o=>`
`).join("\n")
+ if(this.value.length <= 1){
+ return `
`
+ }
+ var out =
+ this.value.map((c,i)=>{
+ return `
+
+ `
+ }).join("\n")
+ return out
+ }
+}
+window.customElements.define('d4s-ccp-input-enum', CCPEnumInputWidgetController);
+
+class CCPTextAreaWidgetController extends CCPBaseInputWidgetController{
+
+ constructor(){
+ super()
+ }
+
+ connectedCallback(){
+ this.rootdoc.addEventListener("input", ev=>{
+ if(ev.target.getAttribute("name") === this.name){
+ const index = Number(ev.target.getAttribute("data-index"))
+ this.value[index] = ev.target.value
+ }
+ })
+ }
+
+ content(){
+ if(this.value.length <= 1){
+ return `
`
+ }
+ var out =
+ this.value.map((c,i)=>{
+ return `
+
+ `
+ }).join("\n")
+ return out
+ }
+}
+window.customElements.define('d4s-ccp-input-textarea', CCPTextAreaWidgetController);
+
+class CCPFileInputWidgetController extends CCPBaseInputWidgetController{
+
+ constructor(){
+ super()
+ }
+
+ connectedCallback(){
+ this.rootdoc.addEventListener("change", ev=>{
const tgt = ev.target
- const ename = tgt.getAttribute("name")
- if(ename === this.name){
+ if(tgt.getAttribute("name") === this.name){
+ const index = Number(tgt.getAttribute("data-index"))
const file = ev.target.files[0]
- /*if(file.type !== this.schema.contentMediaType){
- alert("Unsupported media type. Must be " + this.schema.contentMediaType)
- ev.stopPropagation()
- ev.preventDefault()
- tgt.value = null
- return false
- }*/
if(file.size > 100*1024){
alert("This input allows only small files (100K). Use references instead ")
ev.stopPropagation()
@@ -189,197 +327,73 @@ class FileInputRenderer extends Renderer{
if ((encoded.length % 4) > 0) {
encoded += '='.repeat(4 - (encoded.length % 4));
}
- this.#content = encoded
+ this.value[index] = encoded
+ this.querySelector("small[name=preview]").textContent = encoded.substr(0,5) + "..." + encoded.substr(encoded.length-5)
})
reader.readAsDataURL(file)
}
})
}
- getValue(parent){
- return this.#content
- }
-
- setValue(parent, v){
- parent.querySelector("input").value = v
- }
-
- render(){
- let required = this.required ? 'required="required"' : ""
- let readonly = this.readOnly ? 'readonly="readOnly"' : ""
- this.#html = `
-
-
-
-
- `
- return this.#html
+ content(){
+ if(this.value.length <= 1){
+ const v = this.value.length ? this.value[0] : ''
+ return `
+
+
${v.substr(0,5) + "..." + v.substr(v.length-5)}
+ `
+ }
+ var out =
+ this.value.map((c,i)=>{
+ return `
+
+
${c.substr(0,5) + "..." + c.substr(s.length-5)}
+ `
+ }).join("\n")
+ return out
}
}
+window.customElements.define('d4s-ccp-input-file', CCPFileInputWidgetController);
-class SecretInputRenderer extends Renderer{
-
- #html = null;
-
- constructor(input){
- super(input)
+class CCPSecretInputWidgetController extends CCPBaseInputWidgetController{
+
+ constructor(){
+ super()
}
- getValue(parent){
- return parent.querySelector("input").value
- }
-
- setValue(parent, v){
- parent.querySelector("input").value = v
- }
-
- connectedCallback(controller){
- controller.addEventListener("click", ev=>{
- const ename = ev.target.getAttribute("name")
- if(ename === "password_toggle"){
- const w = controller.querySelector("div.ccp-input-widget input")
- w.type = (w.type === "password" ? "" : "password")
- ev.preventDefault()
+ connectedCallback(){
+ this.rootdoc.addEventListener("input", ev=>{
+ if(ev.target.getAttribute("name") === this.name){
+ const index = Number(ev.target.getAttribute("data-index"))
+ this.value[index] = ev.target.value
+ }
+ })
+
+ this.rootdoc.addEventListener("click", ev=>{
+ if(ev.target.getAttribute("name") === "password_toggle"){
+ const index = Number(ev.target.getAttribute("data-index"))
+ const field = this.rootdoc.querySelector(`input[data-index='${index}']`)
+ if(field.type === "text") field.type="password";
+ else field.type = "text";
}
})
}
-
- render(){
- let required = this.required ? 'required="required"' : ""
- let readonly = this.readOnly ? 'readonly="readOnly"' : ""
- this.#html = `
-
-
-
- 👁
-
- `
- return this.#html
- }
-}
-
-class DateTimeInputRenderer extends Renderer{
-
- #html = null;
-
- constructor(input){
- super(input)
- }
-
- getValue(parent){
- return parent.querySelector("input").value
- }
-
- setValue(parent, v){
- parent.querySelector("input").value = v
- }
-
- render(){
- let required = this.required ? 'required="required"' : ""
- let readonly = this.schema.readOnly ? 'readonly="readOnly"' : ""
- let t = this.schema.format.toLowerCase() === "datetime" ? "datetime-local" : this.schema.format.toLowerCase()
- this.#html = `
-
-
-
-
- `
- return this.#html
- }
-}
-
-class EnumInputRenderer extends Renderer{
-
- #html = null;
-
- constructor(input){
- super(input)
- }
-
- getValue(parent){
- return parent.querySelector("select").value
- }
-
- setValue(parent, v){
- parent.querySelector("select").value = v
- }
-
- render(){
- let options = this.schema.enum.map(e => {
- return e === this.schema.default ?
- `
` :
- `
`
- })
- let required = this.required ? 'required="required"' : ""
- let readonly = this.schema.readOnly ? 'readonly="readOnly"' : ""
- this.#html = `
-
-
-
-
- `
- return this.#html
- }
-}
-
-class CodeInputRenderer extends Renderer{
-
- #html = null;
- #codemirror = null;
-
- constructor(input){
- super(input)
- }
-
- getValue(parent){
- return parent.querySelector("textarea").value
- }
-
- setValue(parent, v){
- parent.querySelector("textarea").value = v
- }
-
- connectedCallback(controller){
- /*const ta = controller.querySelector("textarea")
- const opts = {
- lineNumbers: true,
- indentUnit: 4,
- matchBrackets: true,
- mode: this.schema.contentMediaType,
- readOnly : this.schema.readOnly ? true : false
- }
- this.#codemirror = CodeMirror.fromTextArea(ta, opts)
- this.#codemirror.setValue(this.schema.default)
- this.#codemirror.refresh()*/
- }
-
- render(){
- let required = this.required ? 'required="required"' : ""
- let readonly = this.schema.readOnly ? 'readonly="readOnly"' : ""
- this.#html = `
-
-
-
-
- `
- return this.#html
+ content(){
+ if(this.value.length <= 1){
+ return `
+
+
👁
+ `
+ }
+ var out =
+ this.value.map((c,i)=>{
+ return `
+
+
👁
+ `
+ }).join("\n")
+ return out
}
}
+window.customElements.define('d4s-ccp-input-secret', CCPSecretInputWidgetController);
\ No newline at end of file
diff --git a/ccp/js/inputwidgeteditorcontroller.js b/ccp/js/inputwidgeteditorcontroller.js
index 0408631..9da3f80 100644
--- a/ccp/js/inputwidgeteditorcontroller.js
+++ b/ccp/js/inputwidgeteditorcontroller.js
@@ -92,14 +92,14 @@ class CCPInputWidgetEditorController extends HTMLElement{