class CCPInputWidgetController extends HTMLElement { #data = null; constructor() { super() } connectedCallback() { this.#data = JSON.parse(atob(this.getAttribute("input"))) if (this.isChecklist()) { const opts = this.#data.schema.enum.join(",") this.innerHTML += `` this.querySelector("d4s-ccp-input-checklist").default = this.#data.schema.default } else if (this.isEnum()) { const opts = this.#data.schema.enum.join(",") this.innerHTML += `` this.querySelector("d4s-ccp-input-enum").default = this.#data.schema.default } else if (this.isCode()) { this.innerHTML += `` this.querySelector("d4s-ccp-input-textarea").default = this.#data.schema.default } else if (this.isDateTime()) { const t = this.#data.schema.format.toLowerCase() === "datetime" ? "datetime-local" : this.#data.schema.format.toLowerCase() this.innerHTML += `` this.querySelector("d4s-ccp-input-simple").default = this.#data.schema.default } else if (this.isFile()) { this.innerHTML += `` this.querySelector("d4s-ccp-input-file").default = this.#data.schema.default } else if (this.isRemoteFile()) { this.innerHTML += `` this.querySelector("d4s-ccp-input-remotefile").default = this.#data.schema.default } else if (this.isSecret()) { this.innerHTML += `` this.querySelector("d4s-ccp-input-secret").default = this.#data.schema.default } else if (this.isBoolean()) { this.innerHTML += `` this.querySelector("d4s-ccp-input-boolean").default = this.#data.schema.default } else if (this.isNumber()) { this.innerHTML += `` this.querySelector("d4s-ccp-input-simple").default = this.#data.schema.default } else { this.innerHTML += `` this.querySelector("d4s-ccp-input-simple").default = this.#data.schema.default } } set value(value) { this.firstElementChild.value = value } get value() { return this.firstElementChild.value.length === 1 ? this.firstElementChild.value[0] : this.firstElementChild.value } get name() { return this.firstElementChild.name } isChecklist() { return this.isEnum() && (this.#data.schema.format === "checklist") } isNumber() { return (this.#data.schema.type === "string") && ("format" in this.#data.schema) && (this.#data.schema.format != null) && (this.#data.schema.format.toLowerCase() === "number") } isBoolean() { return (this.#data.schema.type === "string") && ("format" in this.#data.schema) && (this.#data.schema.format != null) && (this.#data.schema.format.toLowerCase() === "boolean") } isEnum() { 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") } isRemoteFile() { return (this.#data.schema.type === "string") && ("format" in this.#data.schema) && (this.#data.schema.format != null) && (this.#data.schema.format.toLowerCase() === "remotefile") } 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 CCPBaseInputWidgetController extends HTMLElement { #rootdoc = null; #minOccurs = 1; #maxOccurs = 1; #description = "" #title = "" #name = "" #default = null #options = null #value = null #readonly = false //useful to avoid having a custom element for every basic input type #type = null #count = 1 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.#maxOccurs = Math.max(this.#minOccurs, this.#maxOccurs) 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) } set default(def){ this.#default = def const defarr = Array.isArray(def) ? def : [def] const min = Math.max(this.#minOccurs, 1) var v = [] for(let j=0; j < this.#maxOccurs; j++){ if(j < defarr.length){ v.push(defarr[j]) }else if(j < min){ v.push(defarr[defarr.length - 1]) } } this.value = v } setValue(v) { this.#value = v this.render() } 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 value() { return this.#value } get rootdoc() { return this.#rootdoc } get required() { return this.#minOccurs > 0 } get readonly() { return this.#readonly } isIncrementable() { return this.#value.length < this.#maxOccurs } isDecrementable() { return this.#value.length > this.#minOccurs && this.#value.length > 1 } get count() { return this.#count } get name() { return this.#name } get title() { return this.#title } get description() { return this.#description } get default() { return this.#default } get options() { return this.#options } get type() { return this.#type } renderPlusMinus() { this.rootdoc.querySelector("div[name=plusminus]").innerHTML = ` ${this.isIncrementable() ? `+` : ``} ${this.isDecrementable() ? `-` : ``} ` } renderContent() { this.rootdoc.querySelector("div[name=content]").innerHTML = this.content() } render() { this.rootdoc.innerHTML = `
` this.renderPlusMinus() this.renderContent() this.#rootdoc.querySelector("div[name=root]").addEventListener("click", ev => { const src = ev.target.getAttribute("name") if (src === "plus") { this.#value.push(this.#value[this.#value.length - 1]) this.renderPlusMinus() this.renderContent() ev.preventDefault() } else if (src === "minus") { this.#value.pop() this.renderPlusMinus() this.renderContent() ev.preventDefault() } }) } } class CCPSimpleInputWidgetController 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-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() { if (this.value.length <= 1) { const opts = this.options ? this.options.map(o => ``).join("\n") : '' return `` } var out = this.value.map((v, i) => { const opts = this.options ? this.options.map(o => ``).join("\n") : '' return ` ` }).join("\n") return out } } window.customElements.define('d4s-ccp-input-enum', CCPEnumInputWidgetController); class CCPChecklistInputWidgetController 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")) const elems = Array.prototype.slice.call(ev.currentTarget.querySelectorAll(`input[name='${this.name}'][data-index='${index}']`)) this.value[index] = elems.filter(e => e.checked).map(e => e.value).join(",") } }) } buildOpts(index, selections) { return this.options ? this.options.map(o => `
-1 ? 'checked' : ''}/>
`).join("\n") : `
No options supplied
` } content() { if (this.value.length === 1) { const opts = this.buildOpts(0, this.value.length ? this.value[0].split(",") : []) return `
${opts}
` } var out = this.value.map((c, i) => { const opts = this.buildOpts(i, c.split(",")) return `
${opts}
` }).join("\n") return out } } window.customElements.define('d4s-ccp-input-checklist', CCPChecklistInputWidgetController); class CCPBooleanInputWidgetController 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.checked } }) } 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-boolean', CCPBooleanInputWidgetController); 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 if (tgt.getAttribute("name") === this.name) { const index = Number(tgt.getAttribute("data-index")) const file = ev.target.files[0] if (file.size > 100 * 1024) { alert("This input allows only small files (100K). Use references instead ") ev.stopPropagation() ev.preventDefault() tgt.value = null return false } const reader = new FileReader() reader.addEventListener('load', ev => { let encoded = ev.target.result.toString().replace(/^data:(.*,)?/, ''); if ((encoded.length % 4) > 0) { encoded += '='.repeat(4 - (encoded.length % 4)); } this.value[index] = encoded this.querySelector("small[name=preview]").textContent = encoded.length > 15 ? encoded.substring(0, 5) + "..." + encoded.substring(encoded.length - 5) : encoded const newev = new Event("input", { bubbles : true}) this.dispatchEvent(newev) }) reader.readAsDataURL(file) } }) } content() { if (this.value.length <= 1) { const v = this.value.length ? this.value[0] : '' const preview = typeof(v) === "string" ? v.substring(0, 5) + "..." + v.substring(v.length - 5) : "" return ` ${preview} ` } var out = this.value.map((c, i) => { const preview = typeof(v) === "string" ? c.substring(0, 5) + "..." + c.substring(v.length - 5) : "" return ` ${preview} ` }).join("\n") return out } } window.customElements.define('d4s-ccp-input-file', CCPFileInputWidgetController); class CCPRemoteFileInputWidgetController extends CCPBaseInputWidgetController { #publicorprotected_dialog = null; #target = null #publiclink = null; #protectedlink = null; #index = null; constructor() { super() } async setPublicLink(l){ const b = document.querySelector("d4s-boot-2") const link = await b.secureFetch(l) if(link.ok){ const result = await link.json() this.#target.value = this.value[this.#index] = result this.#publicorprotected_dialog.style.display = "none" this.#publicorprotected_dialog.classList.remove("show") this.#publiclink = this.#protectedlink = this.#target = this.#index = null const newev = new Event("input", { bubbles : true}) this.dispatchEvent(newev) }else{ alert("Unable to get public link for item") this.#target.value = this.value[this.#index] = "" } } addToolContent() { const iss = document.querySelector("d4s-boot-2").loginToken.iss; const addresses = { "https://accounts.dev.d4science.org/auth/realms/d4science": "https://workspace-repository.dev.d4science.org/storagehub/workspace", "https://accounts.pre.d4science.org/auth/realms/d4science": "https://pre.d4science.org/workspace", "https://accounts.d4science.org/auth/realms/d4science": "https://api.d4science.org/workspace" }; this.rootdoc.querySelector("div[name=tools]").innerHTML += `
Access your workspace
x
Select an item or drag and drop it to a proper input
SELECT
` this.#publicorprotected_dialog = this.rootdoc.querySelector("div.modal[name=publicorprotected]") this.#publicorprotected_dialog.addEventListener("click", ev => { ev.stopPropagation() ev.preventDefault() const name = ev.target.getAttribute("name") if(this.#index != null && this.#target != null){ if(name === "public") { this.setPublicLink(this.#publiclink); } else if(name === "protected"){ this.#target.value = this.value[this.#index] = this.#protectedlink; this.#publicorprotected_dialog.style.display = "none" this.#publicorprotected_dialog.classList.remove("show") this.#publiclink = this.#protectedlink = this.#target = this.#index = null const newev = new Event("input", { bubbles : true}) this.dispatchEvent(newev) }else{ this.#publicorprotected_dialog.style.display = "none" this.#publicorprotected_dialog.classList.remove("show") this.#publiclink = this.#protectedlink = this.#target = this.#index = null } } }) const ws = this.rootdoc.querySelector("div[name=ws]") const st = ws.querySelector("d4s-storage-tree") this.addEventListener("click", ev=>{ ev.stopPropagation() ev.preventDefault() if (ev.target.getAttribute("name") == "selectbtn") { this.#publicorprotected_dialog.style.display = "block" this.#publicorprotected_dialog.classList.add("show") this.#target = this.querySelector("input") this.#index = 0 this.#publiclink = st.d4sWorkspace.getPublicLink(st.currentId) this.#protectedlink = st.d4sWorkspace.getDownloadLink(st.currentId) } }) this.rootdoc.querySelector("svg[name=trigger]").addEventListener("click", ev => { ws.classList.toggle("d-none") ev.preventDefault() ev.stopPropagation() }) this.rootdoc.querySelector("span[name=closebtn]").addEventListener("click", ev => { ws.classList.add("d-none") ev.preventDefault() ev.stopPropagation() }) this.addEventListener("dragover", ev => { ev.preventDefault() }) this.addEventListener("drop", ev => { ev.stopPropagation() if (ev.target.getAttribute("name") == this.name && ev.target.getAttribute("data-index") != null) { this.#publicorprotected_dialog.style.display = "block" this.#publicorprotected_dialog.classList.add("show") this.#target = ev.target this.#index = Number(ev.target.getAttribute("data-index")) this.#publiclink = ev.dataTransfer.getData("text/plain+publiclink") this.#protectedlink = ev.dataTransfer.getData("text/plain+downloadlink") } }) this.addEventListener("input", ev => { ev.stopPropagation() if (ev.target.getAttribute("name") == this.name && ev.target.getAttribute("data-index") != null) { this.value[Number(ev.target.getAttribute("data-index"))] = ev.target.value } }) document.addEventListener("keydown", ev => { if (ev.code == 'Escape') ws.classList.add("d-none"); }) } content() { if(!this.readonly && !this.querySelector("div[name=ws]")) this.addToolContent(); if (this.value.length <= 1) { return ` ` } var out = this.value.map((c, i) => { return ` ` }).join("\n") return out } } window.customElements.define('d4s-ccp-input-remotefile', CCPRemoteFileInputWidgetController); class CCPSecretInputWidgetController 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 } }) 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"; } }) } 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);