web-components/ccp/js/inputwidgetcontroller.js

773 lines
29 KiB
JavaScript

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 += `<d4s-ccp-input-checklist readonly="${this.#data.schema.readOnly}" options="${opts}" default="${this.#data.schema.default}" maxOccurs="${this.#data.maxOccurs}" minOccurs="${this.#data.minOccurs}" name="${this.#data.id}" description="${btoa(this.#data.description)}" title="${this.#data.title}"></d4s-ccp-input-checklist>`
this.querySelector("d4s-ccp-input-checklist").default = this.#data.schema.default
} else if (this.isEnum()) {
const opts = this.#data.schema.enum.join(",")
this.innerHTML += `<d4s-ccp-input-enum readonly="${this.#data.schema.readOnly}" options="${opts}" default="${this.#data.schema.default}" maxOccurs="${this.#data.maxOccurs}" minOccurs="${this.#data.minOccurs}" name="${this.#data.id}" description="${btoa(this.#data.description)}" title="${this.#data.title}"></d4s-ccp-input-enum>`
this.querySelector("d4s-ccp-input-enum").default = this.#data.schema.default
} else if (this.isCode()) {
this.innerHTML += `<d4s-ccp-input-textarea readonly="${this.#data.schema.readOnly}" default="${this.#data.schema.default}" maxOccurs="${this.#data.maxOccurs}" minOccurs="${this.#data.minOccurs}" name="${this.#data.id}" description="${btoa(this.#data.description)}" title="${this.#data.title}"></d4s-ccp-input-textarea>`
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 += `<d4s-ccp-input-simple type="${t}" readonly="${this.#data.schema.readOnly}" default="${this.#data.schema.default}" maxOccurs="${this.#data.maxOccurs}" minOccurs="${this.#data.minOccurs}" name="${this.#data.id}" description="${btoa(this.#data.description)}" title="${this.#data.title}"></d4s-ccp-input-simple>`
this.querySelector("d4s-ccp-input-simple").default = this.#data.schema.default
} else if (this.isFile()) {
this.innerHTML += `<d4s-ccp-input-file readonly="${this.#data.schema.readOnly}" default="${this.#data.schema.default}" maxOccurs="${this.#data.maxOccurs}" minOccurs="${this.#data.minOccurs}" name="${this.#data.id}" description="${btoa(this.#data.description)}" title="${this.#data.title}"></d4s-ccp-input-file>`
this.querySelector("d4s-ccp-input-file").default = this.#data.schema.default
} else if (this.isRemoteFile()) {
this.innerHTML += `<d4s-ccp-input-remotefile readonly="${this.#data.schema.readOnly}" default="${this.#data.schema.default}" maxOccurs="${this.#data.maxOccurs}" minOccurs="${this.#data.minOccurs}" name="${this.#data.id}" description="${btoa(this.#data.description)}" title="${this.#data.title}"></d4s-ccp-input-remotefile>`
this.querySelector("d4s-ccp-input-remotefile").default = this.#data.schema.default
} else if (this.isSecret()) {
this.innerHTML += `<d4s-ccp-input-secret readonly="${this.#data.schema.readOnly}" default="${this.#data.schema.default}" maxOccurs="${this.#data.maxOccurs}" minOccurs="${this.#data.minOccurs }" name="${this.#data.id}" description="${btoa(this.#data.description)}" title="${this.#data.title}"></d4s-ccp-input-secret>`
this.querySelector("d4s-ccp-input-secret").default = this.#data.schema.default
} else if (this.isBoolean()) {
this.innerHTML += `<d4s-ccp-input-boolean readonly="${this.#data.schema.readOnly}" default="${this.#data.schema.default}" maxOccurs="${this.#data.maxOccurs}" minOccurs="${this.#data.minOccurs}" name="${this.#data.id}" description="${btoa(this.#data.description)}" title="${this.#data.title}"></d4s-ccp-input-boolean>`
this.querySelector("d4s-ccp-input-boolean").default = this.#data.schema.default
} else if (this.isNumber()) {
this.innerHTML += `<d4s-ccp-input-simple type="number" readonly="${this.#data.schema.readOnly}" default="${this.#data.schema.default}" maxOccurs="${this.#data.maxOccurs}" minOccurs="${this.#data.minOccurs}" name="${this.#data.id}" description="${btoa(this.#data.description)}" title="${this.#data.title}"></d4s-ccp-input-simple>`
this.querySelector("d4s-ccp-input-simple").default = this.#data.schema.default
} else {
this.innerHTML += `<d4s-ccp-input-simple readonly="${this.#data.schema.readOnly}" default="${this.#data.schema.default}" maxOccurs="${this.#data.maxOccurs}" minOccurs="${this.#data.minOccurs}" name="${this.#data.id}" description="${btoa(this.#data.description)}" title="${this.#data.title}"></d4s-ccp-input-simple>`
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() ? `<span name="plus" title="add one" class="badge text-success border-success btn">+</span>` : ``}
${this.isDecrementable() ? `<span name="minus" title="remove one" class="badge border border-danger text-danger btn">-</span>` : ``}
`
}
renderContent() {
this.rootdoc.querySelector("div[name=content]").innerHTML = this.content()
}
render() {
this.rootdoc.innerHTML = `
<div name="root" class="my-3 ccp-input-widget form-field row">
<label class="form-label">
<div class="d-flex justify-content-between">
<div>
${this.required ? `<span title="Required" class="p-1 text-danger">*</span>` : ``}
${this.title}
</div>
<div name="tools" class="d-flex" style="gap:2px">
<div name="plusminus">
</div>
</div>
</div>
<div>
<small class="text-muted">${atob(this.#description)}</small>
</div>
<div name="content">
</div>
</label>
</div>
`
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 `<input data-index="0" value="${this.value.length ? this.value[0] : ''}" class="my-2 form-control" placeholder="${this.title}" type="${this.type}" name="${this.name}" ${this.readonly ? 'readonly' : ''} ${this.required ? 'required' : ''}/>`
}
var out =
this.value.map((c, i) => {
return `
<input name="${this.name}" value="${c}" data-index="${i}" class="ccp-input my-2 form-control" placeholder="${this.title}" type="${this.type}" name="${this.name}" ${this.readonly ? 'readonly' : ''} ${this.required ? 'required' : ''}/>
`
}).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 => `<option value="${o}" ${this.value.length && o === this.value[0] ? 'selected' : ''}>${o}</option>`).join("\n") :
''
return `<select data-index="0" value="${this.value.length ? this.value[0] : ''}" class="my-2 form-control" placeholder="${this.title}" name="${this.name}" ${this.readonly ? 'disabled' : ''} ${this.required ? 'required' : ''}>${opts}</select>`
}
var out =
this.value.map((v, i) => {
const opts = this.options ?
this.options.map(o => `<option value="${o}" ${o === v ? 'selected' : ''}>${o}</option>`).join("\n") :
''
return `
<select data-index="${i}" value="${v}" class="my-2 form-control" placeholder="${this.title}" name="${this.name}" ${this.readonly ? 'disabled' : ''} ${this.required ? 'required' : ''}>${opts}</select>
`
}).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 => `
<div class="form-check form-switch form-check-inline">
<label>${o}</label>
<input data-index="${index}" class="form-check-input" type="checkbox" name="${this.name}" value="${o}" ${this.readonly ? 'readonly' : ''} ${selections.indexOf(o) > -1 ? 'checked' : ''}/></div>
`).join("\n") :
`
<div class="form-check form-switch form-check-inline">
<span class="muted text-danger">No options supplied</span>
</div>
`
}
content() {
if (this.value.length === 1) {
const opts = this.buildOpts(0, this.value.length ? this.value[0].split(",") : [])
return `
<div class="my-2">
${opts}
</div>
`
}
var out =
this.value.map((c, i) => {
const opts = this.buildOpts(i, c.split(","))
return `
<div class="my-2">
${opts}
</div>
`
}).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 `
<div class="my-2 form-check form-switch form-check-inline">
<input data-index="0" value="${this.value.length ? this.value[0] : false}" class="my-2 form-check-input" type="checkbox" name="${this.name}" ${this.readonly ? 'readonly' : ''} ${this.value[0] === "true" || this.value[0] === true ? 'checked' : ''} value="${this.value[0]}"/>
</div>
`
}
var out =
this.value.map((c, i) => {
return `
<div class="my-2 form-check form-switch form-check-inline">
<input data-index="${i}" value="${c}" class="my-2 form-check-input" type="checkbox" name="${this.name}" ${this.readonly ? 'readonly' : ''} ${c === "true" || c === true ? 'checked' : ''}/>
</div>
`
}).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 `<textarea data-index="0" class="my-2 form-control" placeholder="${this.title}" type="${this.type}" name="${this.name}" rows="5" ${this.readonly ? 'readonly' : ''} ${this.required ? 'required' : ''}>${this.value.length ? this.value[0] : ''}</textarea>`
}
var out =
this.value.map((c, i) => {
return `
<textarea name="${this.name}" data-index="${i}" class="ccp-input my-2 form-control" placeholder="${this.title}" type="${this.type}" name="${this.name}" rows="5" ${this.readonly ? 'readonly' : ''} ${this.required ? 'required' : ''}>${c}</textarea>
`
}).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 `
<input type="file" data-index="0" class="my-2 form-control" placeholder="${this.title}" name="${this.name}" ${this.readonly ? 'readonly' : ''} ${this.required && !v ? 'required' : ''} value="${v}"/>
<small name ="preview" class="form-text text-muted">${preview}</small>
`
}
var out =
this.value.map((c, i) => {
const preview = typeof(v) === "string" ? c.substring(0, 5) + "..." + c.substring(v.length - 5) : ""
return `
<input type="file" data-index="${i}" class="my-2 form-control" placeholder="${this.title}" name="${this.name}" ${this.readonly ? 'readonly' : ''} ${this.required ? 'required' : ''} value="${c}"/>
<small name ="preview" class="form-text text-muted">${preview}</small>
`
}).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 += `
<svg name="trigger" style="width:24;height:24;fill:#007bff; cursor:pointer" viewBox="0 -960 960 960">
<path d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h240l80 80h320q33 0 56.5 23.5T880-640H447l-80-80H160v480l96-320h684L837-217q-8 26-29.5 41.5T760-160H160Zm84-80h516l72-240H316l-72 240Zm0 0 72-240-72 240Zm-84-400v-80 80Z"/>
</svg>
<div name="ws" class="d-none position-absolute shadow border border-primary bg-light p-2" style="right:0;z-index:1000; line-height:1.5rem;overflow:hidden;padding:5px;">
<div class="mb-1" style="border-bottom: solid 1px gray;">
<div class="d-flex justify-content-between m-0">
<h5 class="text-secondary m-0">Access your workspace</h5>
<span class="btn text-danger p-0" style="font-weight:bold" name="closebtn">x</span>
</div>
<small class="text-muted m-0">Select an item or drag and drop it to a proper input</small>
</div>
<div style="min-width:350px; max-width:500px;overflow:auto;etxt-wrap:nowrap;text-overflow: ellipsis;min-height:5rem; max-height:10rem;">
<d4s-storage-tree
base-url="${addresses[iss]}"
file-download-enabled="true"
show-files="true"
allow-drag="true"/>
</div>
<div class="d-flex justify-content-end mt-1 pt-1" style="border-top: solid 1px gray;">
<span class="btn btn-primary" name="selectbtn">SELECT</span>
</div>
</div>
<div class="modal fade" style="background-color:rgba(0,0,0,0.3)" name="publicorprotected" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content shadow-lg border-primary">
<div class="modal-body">
Choose whether you want to use the public link or the protected link (requires authentication and authorization).
</div>
<div class="modal-footer">
<span name="public" class="btn btn-info">Public link</span>
<span name="protected" class="btn btn-primary">Protected link</span>
<span name="cancel" class="btn btn-danger">Cancel</span>
</div>
</div>
</div>
</div>
`
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 `
<input data-index="0" value="${this.value.length ? this.value[0] : ''}" class="my-2 form-control" placeholder="${this.title}" type="${this.type}" name="${this.name}" ${this.readonly ? 'readonly' : ''} ${this.required ? 'required' : ''}/>`
}
var out =
this.value.map((c, i) => {
return `
<input name="${this.name}" value="${c}" data-index="${i}" class="ccp-input my-2 form-control" placeholder="${this.title}" type="${this.type}" name="${this.name}" ${this.readonly ? 'readonly' : ''} ${this.required ? 'required' : ''}/>
`
}).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 `
<div style="position:relative">
<input data-index="0" value="${this.value.length ? this.value[0] : ''}" class="my-2 form-control" placeholder="${this.title}" type="password" name="${this.name}" ${this.readonly ? 'readonly' : ''} ${this.required ? 'required' : ''}/>
<span data-index="0" class="btn" style="position:absolute; right:0; bottom:0" name="password_toggle">&#128065;</span>
</div>
`
}
var out =
this.value.map((c, i) => {
return `
<div style="position:relative">
<input name="${this.name}" value="${c}" data-index="${i}" class="ccp-input my-2 form-control" placeholder="${this.title}" type="password" name="${this.name}" ${this.readonly ? 'readonly' : ''} ${this.required ? 'required' : ''}/>
<span data-index="${i}" class="btn" style="position:absolute; right:0; bottom:0" name="password_toggle">&#128065;</span>
</div>
`
}).join("\n")
return out
}
}
window.customElements.define('d4s-ccp-input-secret', CCPSecretInputWidgetController);