Implemented d4s storage tree and folder web components
This commit is contained in:
parent
ac1f18cf2d
commit
9a1a3b6c91
|
@ -0,0 +1,360 @@
|
|||
/**
|
||||
* Base class of <d4s-storage-tree> and <d4s-storage-folder>
|
||||
*/
|
||||
class D4SStorageHtmlElement extends HTMLElement {
|
||||
|
||||
#d4s = null
|
||||
#d4smissmsg = 'Required d4s-boot-2 component not found'
|
||||
|
||||
//#baseurl = 'https://api.dev.d4science.org'
|
||||
#baseurl = 'https://storagehub.pre.d4science.net/storagehub/workspace'
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
}
|
||||
|
||||
appendStylesheets(root) {
|
||||
const linkElem1 = document.createElement('link')
|
||||
linkElem1.setAttribute('rel', 'stylesheet')
|
||||
linkElem1.setAttribute('href', 'https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css')
|
||||
const linkElem2 = document.createElement('link')
|
||||
linkElem2.setAttribute('rel', 'stylesheet')
|
||||
linkElem2.setAttribute('href', 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css')
|
||||
root.appendChild(linkElem1)
|
||||
root.appendChild(linkElem2)
|
||||
}
|
||||
|
||||
get d4s() {
|
||||
if (this.#d4s == null) {
|
||||
this.#d4s = document.querySelector('d4s-boot-2')
|
||||
if (!this.#d4s) {
|
||||
console.error(this.#d4smissmsg)
|
||||
}
|
||||
}
|
||||
return this.#d4s
|
||||
}
|
||||
|
||||
buildListUrl(id) {
|
||||
return this.#baseurl + '/items/' + id + '/children'
|
||||
}
|
||||
|
||||
get baseUrl() {
|
||||
return this.#baseurl
|
||||
}
|
||||
|
||||
set baseUrl(url) {
|
||||
this.#baseurl = url
|
||||
this.setAttribute("baseurl", url)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Builds storagehub VREFolder tree
|
||||
* <d4s-storage-tree
|
||||
* /@filelist-id: identifier of d4s-storage-folder component
|
||||
* /@baseurl: the base endpoint url [defaults to: https://storagehub.pre.d4science.net/storagehub/workspace]
|
||||
*/
|
||||
window.customElements.define('d4s-storage-tree', class extends D4SStorageHtmlElement {
|
||||
|
||||
#storageFilelistId = null
|
||||
|
||||
#loadedClass = 'loaded'
|
||||
#selectedClass = 'selected'
|
||||
#selectedbgcolor = 'lightgray'
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
}
|
||||
|
||||
/*
|
||||
Notes:
|
||||
API docs: https://gcube.wiki.gcube-system.org/gcube/StorageHub_REST_API
|
||||
Preprod: https://accounts.pre.d4science.org
|
||||
Sample context: %2Fpred4s%2Fpreprod%2FpreVRE
|
||||
User workspace: https://storagehub.pre.d4science.net/storagehub/workspace
|
||||
vrefolder: https://storagehub.pre.d4science.net/storagehub/workspace/vrefolder
|
||||
-> and if "id": "e0cd15d2-0071-43ca-bc42-aef8d80660fe",
|
||||
the tree dir of vrefolder: https://storagehub.pre.d4science.net/storagehub/workspace/items/e0cd15d2-0071-43ca-bc42-aef8d80660fe/children
|
||||
download of a file (domenica.jpg): https://storagehub.pre.d4science.net/storagehub/workspace/items/a5086811-59d1-4230-99fa-98431e820cf1/download
|
||||
*/
|
||||
connectedCallback() {
|
||||
const shadowRoot = this.attachShadow({mode: 'open'})
|
||||
this.appendStylesheets(shadowRoot)
|
||||
|
||||
var div = document.createElement('div')
|
||||
const style = `
|
||||
<style>
|
||||
.selected > *:first-child {
|
||||
background-color: ${this.#selectedbgcolor};
|
||||
}
|
||||
ul, li {
|
||||
list-style-type: none;
|
||||
}
|
||||
li {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
`
|
||||
div.innerHTML = style
|
||||
|
||||
this.d4s.service(
|
||||
this.baseUrl + '/vrefolder',
|
||||
'GET', null,
|
||||
(resp) => {
|
||||
this.parseResponse(div, resp)
|
||||
shadowRoot.appendChild(div)
|
||||
},
|
||||
(err) => { alert(err) }
|
||||
)
|
||||
}
|
||||
|
||||
parseResponse(parentElement, response) {
|
||||
parentElement.classList.add(this.#loadedClass)
|
||||
var ul = document.createElement('ul')
|
||||
ul.classList.add('nested')
|
||||
var jresp = JSON.parse(response)
|
||||
if (jresp.item) {
|
||||
const itemname = jresp.item.displayName
|
||||
const itemid = jresp.item.id
|
||||
const path = this.buildListUrl(itemid)
|
||||
ul.appendChild(this.createListItem(itemname, itemid))
|
||||
parentElement.appendChild(ul)
|
||||
|
||||
} else if (jresp.itemlist) {
|
||||
jresp
|
||||
.itemlist
|
||||
.filter(item => item['@class'].includes('FolderItem'))
|
||||
.forEach(item => {
|
||||
const itemname = item.name
|
||||
const itemid = item.id
|
||||
const path = this.buildListUrl(itemid)
|
||||
ul.appendChild(this.createListItem(itemname, itemid))
|
||||
})
|
||||
parentElement.appendChild(ul)
|
||||
} else {
|
||||
console.error(jresp)
|
||||
}
|
||||
}
|
||||
|
||||
createListItem(label, id) {
|
||||
var li = document.createElement('li')
|
||||
li.setAttribute('data-id', id)
|
||||
var child = document.createElement('span')
|
||||
child.innerHTML = label
|
||||
li.appendChild(child)
|
||||
|
||||
li.addEventListener('click', (ev) => {
|
||||
ev.stopPropagation()
|
||||
this.select(ev.currentTarget.getAttribute('data-id'))
|
||||
})
|
||||
return li
|
||||
}
|
||||
|
||||
select(id) {
|
||||
var li = this.shadowRoot.querySelector(`*[data-id='${id}']`)
|
||||
this.displayPath(li)
|
||||
|
||||
// if it was already selected then do nothing
|
||||
if (li.classList.contains(this.#selectedClass)) {
|
||||
this.toggleULDisplay(li)
|
||||
return
|
||||
}
|
||||
// switch selected and lists folder contents
|
||||
if (!li.classList.contains(this.#selectedClass)) {
|
||||
const selected = this.shadowRoot.querySelector('.' + this.#selectedClass)
|
||||
if (selected) {
|
||||
selected.classList.remove(this.#selectedClass)
|
||||
}
|
||||
li.classList.add(this.#selectedClass)
|
||||
if (this.#storageFilelistId) {
|
||||
var folder = document.getElementById(this.#storageFilelistId)
|
||||
folder.join(this)
|
||||
folder.list(id)
|
||||
}
|
||||
}
|
||||
if (li.classList.contains(this.#loadedClass)) {
|
||||
return
|
||||
}
|
||||
this.d4s.service(
|
||||
this.buildListUrl(id),
|
||||
'GET', null,
|
||||
(resp) => this.parseResponse(li, resp),
|
||||
(err) => { alert(err) }
|
||||
)
|
||||
}
|
||||
|
||||
displayPath(li) {
|
||||
var curr = li
|
||||
while (curr.parentElement != null) {
|
||||
if (curr.parentElement.tagName == 'UL') {
|
||||
curr.parentElement.style.display = 'block'
|
||||
}
|
||||
curr = curr.parentElement
|
||||
}
|
||||
}
|
||||
|
||||
toggleULDisplay(li) {
|
||||
const ul = li.querySelector('ul')
|
||||
if (ul) {
|
||||
ul.style.display = (ul.style.display === 'none') ? 'block' : 'none'
|
||||
}
|
||||
}
|
||||
|
||||
static get observedAttributes() {
|
||||
return ["base-url", "filelist-id"];
|
||||
}
|
||||
|
||||
attributeChangedCallback(name, oldValue, newValue) {
|
||||
if (oldValue !== newValue) {
|
||||
switch (name) {
|
||||
case "filelist-id":
|
||||
this.#storageFilelistId = newValue
|
||||
break
|
||||
case "base-url":
|
||||
this.baseUrl = newValue
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get filelistId() {
|
||||
return this.#storageFilelistId
|
||||
}
|
||||
|
||||
set filelistId(id) {
|
||||
this.#storageFilelistId = id
|
||||
this.setAttribute("filelist-id", id)
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* Lists elements in selected folder
|
||||
*
|
||||
* <d4s-storage-folder
|
||||
* /@id: specify the id to join this component with storage tree component
|
||||
* /@baseurl: the base endpoint url [defaults to: https://storagehub.pre.d4science.net/storagehub/workspace]
|
||||
*/
|
||||
window.customElements.define('d4s-storage-folder', class extends D4SStorageHtmlElement {
|
||||
|
||||
#d4sstorageTree = null
|
||||
#selectedbgcolor = 'lightgray'
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
const shadowRoot = this.attachShadow({mode: 'open'})
|
||||
this.appendStylesheets(shadowRoot)
|
||||
|
||||
const style = document.createElement('style')
|
||||
style.innerHTML = `
|
||||
span {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
`
|
||||
shadowRoot.appendChild(style)
|
||||
this.createContainer()
|
||||
}
|
||||
|
||||
createContainer() {
|
||||
var div = document.createElement('div')
|
||||
div.classList.add('d4s-folder')
|
||||
var child = this.shadowRoot.querySelector('.d4s-folder')
|
||||
if (child) {
|
||||
this.shadowRoot.removeChild(child)
|
||||
}
|
||||
this.shadowRoot.appendChild(div)
|
||||
return div
|
||||
}
|
||||
|
||||
join(tree) {
|
||||
if (this.#d4sstorageTree == null) {
|
||||
this.#d4sstorageTree = tree
|
||||
}
|
||||
}
|
||||
|
||||
list(folderId) {
|
||||
this.d4s.service(
|
||||
this.buildListUrl(folderId),
|
||||
'GET', null,
|
||||
(resp) => this.parseResponse(resp),
|
||||
(err) => { alert(err) }
|
||||
)
|
||||
}
|
||||
|
||||
parseResponse(response) {
|
||||
const root = this.createContainer()
|
||||
var jresp = JSON.parse(response)
|
||||
if (jresp.itemlist) {
|
||||
jresp.itemlist.forEach(item => root.appendChild(this.createFileRow(item)))
|
||||
|
||||
} else {
|
||||
console.error(jresp)
|
||||
}
|
||||
}
|
||||
|
||||
createFileRow(item) {
|
||||
var div = document.createElement('div')
|
||||
div.classList.add('row')
|
||||
var filename = document.createElement('div')
|
||||
filename.classList.add('col')
|
||||
var name = `<span>${item.name}</span>`
|
||||
filename.innerHTML = this.iconTag(item) + name
|
||||
const isFolder = item['@class'].includes('FolderItem')
|
||||
filename.addEventListener('click', (ev) => {
|
||||
ev.stopPropagation()
|
||||
if (isFolder) {
|
||||
const span = ev.currentTarget.querySelector(':nth-child(2)')
|
||||
if (span) {
|
||||
span.style = 'background-color: ' + this.#selectedbgcolor
|
||||
}
|
||||
if (this.#d4sstorageTree != null) {
|
||||
this.#d4sstorageTree.select(item.id)
|
||||
}
|
||||
} else {
|
||||
console.info("Download of " + item.id)
|
||||
this.d4s.download(this.buildDownloadUrl(item.id), item.name)
|
||||
}
|
||||
})
|
||||
|
||||
div.appendChild(filename)
|
||||
return div
|
||||
}
|
||||
|
||||
iconTag(item) {
|
||||
var i = `<i class="fa-regular fa-file fa-fw"></i>`
|
||||
if (item['@class'].includes('FolderItem')) {
|
||||
i = `<i class="fa-regular fa-folder fa-fw"></i>`
|
||||
} else if (item['@class'].includes('ImageFile')) {
|
||||
i = `<i class="fa-regular fa-image fa-fw"></i>`
|
||||
} else if (item['@class'].includes('PDFFileItem')) {
|
||||
i = `<i class="fa-regular fa-file-pdf fa-fw"></i>`
|
||||
}
|
||||
return '<span class="px-2">' + i + '</span>'
|
||||
}
|
||||
|
||||
buildDownloadUrl(id) {
|
||||
return this.baseUrl+ '/items/' + id + '/download'
|
||||
}
|
||||
|
||||
static get observedAttributes() {
|
||||
return ["base-url"];
|
||||
}
|
||||
|
||||
attributeChangedCallback(name, oldValue, newValue) {
|
||||
if (oldValue !== newValue) {
|
||||
switch (name) {
|
||||
case "base-url":
|
||||
this.baseUrl = newValue
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})
|
Loading…
Reference in New Issue