async function GetImageMetadata(imageId) { const response = await fetch(`/api/v1/images/${imageId}/metadata`) const metadata = await response.json() return metadata } async function GetImageTags(imageId) { const responseTags = await fetch(`/api/v1/images/tags`) const tags = await responseTags.json() const names = Object.keys(tags.names).sort((a, b) => tags.names[b] - tags.names[a]) const values = Object.keys(tags.values).sort((a, b) => tags.values[b] - tags.values[a]) console.log(values) return { names: names, values: values, } } async function RenderImagePage(mountPoint, values) { const metadata = await GetImageMetadata(values.imageId) const tagNamesValues = await GetImageTags(values.imageId) console.log(metadata) mountPoint.innerHTML = `
${values.imageId}:
Add tag
` const tagList = mountPoint.querySelector('.image_page__tag-list') const addTagButton = mountPoint.querySelector('.image_page__tag-list__button') const saveMetadata = async () => { const children = tagList.children; const tags = [] for (const i in children) { if (i >= children.length - 1) { break } const tag = children[i].innerText.trim().split(":") if (tag.length == 1) { tags.push({ "name": tag[0].trim(), "value": "", }) } else { tags.push({ "name": tag[0].trim(), "value": tag[1].trim(), }) } } metadata.tags = tags const response = await fetch(`/api/v1/images/${metadata.name}/metadata`, { headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, method: "PUT", body: JSON.stringify(metadata) }) const result = await response.text(); console.log('result', result) } const addNewDiv = (text, focused) => { const div = document.createElement("div") div.classList.add('image_page__tag-list__tag') const textDiv = document.createElement("div") textDiv.classList.add("image_page__tag-list__text") textDiv.innerText = text div.appendChild(textDiv) let editable = false; let dropdownDiv const autocomplete = () => { } const makeNotEditable = async () => { if (!editable) return editable = false console.log("not editable") textDiv.innerText = textDiv.innerText.trim() textDiv.contentEditable = "false" textDiv.removeEventListener("keypress", whenEditable) textDiv.removeEventListener("keydown", whenEditableDown) textDiv.removeEventListener("blur", makeNotEditable) div.removeChild(dropdownDiv) dropdownDiv = null if (textDiv.innerText.trim() === "") { div.parentElement.removeChild(div) } await saveMetadata() } const whenEditableDown = (event) => { if (event.key === "Tab") { event.preventDefault(); } } const whenEditable = async (event) => { if (event.key === "Enter") { event.preventDefault(); await makeNotEditable() } else if (event.key === "Tab") { event.preventDefault(); let tag = MakeDropdownText(tagNamesValues, textDiv.innerText.trim())[0] if (tag) { if (!tag.includes(":")) tag += ":" textDiv.innerText = tag.trim(); setTimeout(() => { var range = document.createRange() var sel = window.getSelection() range.setStart(textDiv.childNodes[0], tag.length) range.collapse(true) sel.removeAllRanges() sel.addRange(range) }) setTimeout(() => { dropdownDiv.innerHTML = MakeDropdownText(tagNamesValues, textDiv.innerText.trim()).join("
") }) } } else { setTimeout(() => { dropdownDiv.innerHTML = MakeDropdownText(tagNamesValues, textDiv.innerText.trim()).join("
") }) } } const makeEditable = () => { if (editable) return editable = true console.log("editable") dropdownDiv = document.createElement("div") dropdownDiv.classList.add('image_page__tag-list__dropdown') div.appendChild(dropdownDiv) textDiv.contentEditable = "true" textDiv.addEventListener("keyup", whenEditable) textDiv.addEventListener("keydown", whenEditableDown) textDiv.addEventListener("blur", makeNotEditable) textDiv.focus() setTimeout(() => { dropdownDiv.innerHTML = MakeDropdownText(tagNamesValues, textDiv.innerText.trim()).join("
") }) } div.addEventListener('dblclick', makeEditable) tagList.insertBefore(div, addTagButton) if (focused) { makeEditable() div.focus() } return div } addTagButton.addEventListener('click', async () => { addNewDiv(``, true) }) for (const tag of metadata.tags || []) { if (tag.value != "") addNewDiv(`${tag.name}:${tag.value}`, false) else addNewDiv(`${tag.name}`, false) } const img = mountPoint.querySelector('.image_page__image') img.onload = (e) => { console.log('image on load', e) } img.onerror = (e) => { console.log('image onerror', e, e.type) } } function MakeDropdownText(tags, prefix) { const hasColon = prefix.includes(":") const array = hasColon ? tags.values : tags.names const idx = prefix.indexOf(":"); const pr = hasColon ? prefix.slice(idx + 1) : prefix console.log('hasColon', hasColon) console.log('pr', pr) let suggestions = array.filter((it) => it.startsWith(pr)).slice(0, 20) console.log("suggestions", suggestions) if (hasColon) { const addPref = prefix.slice(0, idx + 1) return suggestions.map((it) => addPref + it) } else { return suggestions } }