You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
pages/components/page-actions.js

348 lines
9.0 KiB
JavaScript

export class PageActions extends HTMLElement {
textEn = {
download: 'Download',
rename: 'Move/Rename',
duplicate: 'Duplicate',
delete_: 'Delete',
settings: 'Settings',
confirmDelete: f => (
`Are you sure you want to delete ${f}?`
),
cancel: 'Cancel',
alreadyExists: 'There is already a page with that name.',
save: 'Guardar',
close: 'Close',
}
textEs = {
download: 'Descargar',
rename: 'Mover/Renombrar',
duplicate: 'Duplicar',
delete_: 'Borrar',
settings: 'Configuración',
confirmDelete: f => (
`¿Desea borrar ${f}?`
),
cancel: 'Cancelar',
alreadyExists: 'Ya existe una página con ese nombre.',
save: 'Guardar',
close: 'Cerrar',
}
constructor() {
super()
this.attachShadow({mode: 'open'})
this.language = navigator.language
this.dialogWrap = document.createElement('div')
this.shadowRoot.append(this.dialogWrap)
}
connectedCallback() {
const style = document.createElement('style')
style.textContent = `
m-dialog::part(footer) {
padding-top: 15px;
}
`
this.shadowRoot.appendChild(style)
}
get menuActions() {
const baseActions = [
{
text: this.text.download,
click: this.download.bind(this),
},
{
text: this.text.rename,
click: this.rename.bind(this),
},
{
text: this.text.duplicate,
click: this.duplicate.bind(this),
},
{
text: this.text.delete_,
click: this.delete_.bind(this),
},
]
if (this.page.isGroup) {
return [
...baseActions,
{
text: this.text.settings,
click: this.settings.bind(this),
},
]
} else {
return baseActions
}
}
download() {
const text = localStorage.getItem(this.path)
const sp = this.path.split('/')
const filename = sp[sp.length - 1]
const el = document.createElement('a')
el.setAttribute(
'href',
'data:text/plain;charset=utf-8,' +
encodeURIComponent(text)
)
el.setAttribute('download', filename)
el.style.display = 'none'
this.shadowRoot.appendChild(el)
el.click()
this.shadowRoot.removeChild(el)
}
rename() {
const dialog = document.createElement(
'm-dialog'
)
this.dialogWrap.replaceChildren(dialog)
const input = document.createElement('input')
input.value = this.path
input.style.minWidth = '300px'
dialog.bodyEl.appendChild(input)
let errorEl
const bGroup = document.createElement(
'm-forms-button-group'
)
bGroup.addPrimary(this.text.rename, () => {
const newPath = input.value
const v = localStorage.getItem(newPath)
if (v !== null || newPath === this.path) {
if (!errorEl) {
errorEl = document.createElement('p')
errorEl.style.color = 'red'
const errText = this.text.alreadyExists
errorEl.innerText = errText
dialog.bodyEl.appendChild(errorEl)
}
return
}
const sKeyOld = 'settings/page:' + this.path
const sKeyNew = 'settings/page:' + newPath
const settingsJson = localStorage.getItem(sKeyOld)
if (settingsJson ?? true === true) {
localStorage.setItem(sKeyNew, settingsJson)
localStorage.removeItem(sKeyOld)
let settingsData
try {
settingsData = JSON.parse(settingsJson)
} catch (err) {
settingsData = {}
}
if (settingsData?.connections) {
for (const dir of ['outbound', 'inbound']) {
const otherDir = (
dir === 'outbound' ? 'inbound' : 'outbound'
)
this.applyInverseRename(
settingsData, dir, otherDir, this.path, newPath
)
}
}
} else {
localStorage.removeItem(sKeyNew)
}
localStorage.setItem(
newPath,
localStorage.getItem(this.path)
)
localStorage.removeItem(this.path)
dialog.close()
location.hash = newPath
})
bGroup.addCancel(this.text.cancel, () => {
dialog.close()
})
dialog.footerEl.appendChild(bGroup)
dialog.open()
}
duplicate() {
const dialog = document.createElement(
'm-dialog'
)
this.dialogWrap.replaceChildren(dialog)
const input = document.createElement('input')
input.value = this.path
input.style.minWidth = '300px'
dialog.bodyEl.appendChild(input)
let errorEl
const bGroup = document.createElement(
'm-forms-button-group'
)
const btnText = this.text.duplicate
bGroup.addPrimary(btnText, () => {
const newPath = input.value
const v = localStorage.getItem(newPath)
if (v !== null || newPath === this.path) {
if (!errorEl) {
errorEl = document.createElement('p')
errorEl.style.color = 'red'
const errText = this.text.alreadyExists
errorEl.innerText = errText
dialog.bodyEl.appendChild(errorEl)
}
return
}
localStorage.setItem(
newPath,
localStorage.getItem(this.path)
)
localStorage.setItem(
'settings/page:' + newPath,
localStorage.getItem(this.path) ?? '{}'
)
dialog.close()
location.hash = newPath
})
bGroup.addCancel(this.text.cancel, () => {
dialog.close()
})
dialog.footerEl.appendChild(bGroup)
dialog.open()
}
delete_() {
const dialog = document.createElement(
'm-dialog'
)
this.dialogWrap.replaceChildren(dialog)
const p = document.createElement('p')
p.innerText = this.text.confirmDelete(
JSON.stringify(this.path)
)
dialog.bodyEl.appendChild(p)
const bGroup = document.createElement(
'm-forms-button-group'
)
bGroup.addPrimary(this.text.delete_, () => {
localStorage.removeItem(this.path)
localStorage.removeItem(
'settings/page:' + this.path
)
location.hash = '/'
dialog.close()
})
bGroup.addCancel(this.text.cancel, () => {
dialog.close()
})
dialog.footerEl.appendChild(bGroup)
dialog.open()
}
settings() {
const dialog = document.createElement(
'm-dialog'
)
this.dialogWrap.replaceChildren(dialog)
const settingsEl = document.createElement(
'm-settings-page-settings'
)
settingsEl.cspProfiles = this.cspProfiles
settingsEl.path = this.path
settingsEl.data = this.page.settings
const h = document.createElement('h2')
h.innerText = this.text.settings
dialog.headerEl.append(h)
dialog.bodyEl.append(settingsEl)
const bGroup = document.createElement(
'm-forms-button-group'
)
bGroup.addPrimary(this.text.save, () => {
const settingsData = settingsEl.data
this.page.settings = settingsData
for (const dir of ['outbound', 'inbound']) {
const otherDir = (
dir === 'outbound' ? 'inbound' : 'outbound'
)
this.applyInverseSettings(
settingsData, dir, otherDir
)
}
dialog.close()
this.dispatchEvent(new CustomEvent(
'settings-change', {bubbles: true, composed: true}
))
})
bGroup.addCancel(this.text.cancel, () => {
dialog.close()
})
dialog.footerEl.appendChild(bGroup)
dialog.open()
}
applyInverseSettings(settingsData, dir, otherDir) {
const selfEntries = Object.entries(
settingsData.connections[dir]
)
for (const [path, access] of selfEntries) {
const key = 'settings/page:' + path
let val = localStorage.getItem(key)
try {
if (val !== null) {
val = JSON.parse(val)
}
} catch (err) {
// ignore
}
const data = val ?? {}
data.connections = data.connections ?? {}
data.connections[otherDir] = (
data.connections[otherDir] ?? {}
)
data.connections[otherDir][this.path] = access
localStorage.setItem(
key, JSON.stringify(data)
)
}
}
applyInverseRename(
settingsData, dir, otherDir, oldPath, newPath
) {
const selfEntries = Object.entries(
settingsData.connections[dir] ?? {}
)
for (const [path, access] of selfEntries) {
const key = 'settings/page:' + path
let val = localStorage.getItem(key)
try {
if (val !== null) {
val = JSON.parse(val)
}
} catch (err) {
// ignore
}
const data = val ?? {}
data.connections = data.connections ?? {}
data.connections[otherDir] = (
data.connections[otherDir] ?? {}
)
const accessValue = data.connections[otherDir][oldPath]
data.connections[otherDir][newPath] = accessValue
data.connections[otherDir][oldPath] = undefined
localStorage.setItem(
key, JSON.stringify(data)
)
}
}
get language() {
return this._language
}
set language(language) {
this._language = language
this.text = this.langEs ? this.textEs : this.textEn
}
get langEs() {
return /^es\b/.test(this.language)
}
}