Compare commits

..

No commits in common. 'main' and 'csp-setting-fix' have entirely different histories.

@ -1,4 +1,3 @@
import { Storage } from "/storage/storage.js"
import { Layout } from "/components/layout.js" import { Layout } from "/components/layout.js"
import { Page } from "/components/page.js" import { Page } from "/components/page.js"
import { PageActions } from "/components/page-actions.js" import { PageActions } from "/components/page-actions.js"
@ -8,26 +7,14 @@ import { NavMenu } from "/components/nav-menu.js"
import { Dialog } from "/dialog/dialog.js" import { Dialog } from "/dialog/dialog.js"
import { ButtonGroup } from "/forms/button-group.js" import { ButtonGroup } from "/forms/button-group.js"
import { Dropdown } from "/menu/dropdown.js" import { Dropdown } from "/menu/dropdown.js"
import { NetworkSettings } from "/settings/network-settings.js"
import { PageSettings } from "/settings/page-settings.js" import { PageSettings } from "/settings/page-settings.js"
import { Connections } from "/settings/connections.js"
import { ConnectionEdit } from "/settings/connection-edit.js"
customElements.define('m-layout', Layout) customElements.define('m-layout', Layout)
customElements.define('m-page', Page) customElements.define('m-page', Page)
customElements.define('m-page-actions', PageActions) customElements.define('m-page-actions', PageActions)
customElements.define(
'm-settings-network-settings', NetworkSettings
)
customElements.define( customElements.define(
'm-settings-page-settings', PageSettings 'm-settings-page-settings', PageSettings
) )
customElements.define(
'm-settings-connections', Connections
)
customElements.define(
'm-settings-connection-edit', ConnectionEdit
)
customElements.define( customElements.define(
'm-file-group-page', FileGroupPage 'm-file-group-page', FileGroupPage
) )
@ -42,13 +29,6 @@ customElements.define(
) )
class Setup { class Setup {
constructor() {
this.layout = document.createElement(
'm-layout'
)
this.layout.storage = new Storage()
}
async runWithSw() { async runWithSw() {
navigator.serviceWorker.addEventListener( navigator.serviceWorker.addEventListener(
'controllerchange', 'controllerchange',
@ -63,10 +43,12 @@ class Setup {
} }
async runWithoutSw() { async runWithoutSw() {
this.layout.storage = new Storage() const layout = document.createElement(
this.layout.csp = undefined 'm-layout'
this.layout.header.menu.handleLinks = true )
document.body.appendChild(this.layout) layout.csp = undefined
layout.header.menu.handleLinks = true
document.body.appendChild(layout)
} }
async register() { async register() {
@ -76,9 +58,6 @@ class Setup {
'/sw.js', '/sw.js',
{scope: '/'} {scope: '/'}
) )
if (this.registration.waiting) {
this.registration.active.postMessage(['skipWaiting'])
}
} catch (err) { } catch (err) {
console.error( console.error(
'error registering service worker', err 'error registering service worker', err
@ -89,7 +68,7 @@ class Setup {
load() { load() {
if (this.registration.active) { if (this.registration.active) {
document.body.appendChild( document.body.appendChild(
this.layout document.createElement('m-layout')
) )
} }
} }

@ -29,10 +29,7 @@ addEventListener('message', event => {
frame !== undefined && event.source == frame.contentWindow frame !== undefined && event.source == frame.contentWindow
) )
if (isChild) { if (isChild) {
const transferArg = ( parent.postMessage(event.data, '*')
event.ports?.length ? [[...event.ports]] : []
)
parent.postMessage(event.data, '*', ...transferArg)
} else { } else {
let isNew = false let isNew = false
const d = event.data const d = event.data
@ -47,12 +44,7 @@ addEventListener('message', event => {
document.body.appendChild(frame) document.body.appendChild(frame)
} }
} else if (frame !== undefined) { } else if (frame !== undefined) {
const transferArg = ( frame.contentWindow.postMessage(event.data, '*')
event.ports?.length ? [[...event.ports]] : []
)
frame.contentWindow.postMessage(
event.data, '*', ...transferArg
)
} }
} }
}) })
@ -175,11 +167,7 @@ export class FileGroupPage extends HTMLElement {
async displayEdit() { async displayEdit() {
const doc = await this.editorBuild.build() const doc = await this.editorBuild.build()
const msg = [ const msg = ['srcdoc', doc]
'srcdoc',
doc,
{codeMirror: this.settings.codeMirror},
]
this.editFrame.contentWindow.postMessage( this.editFrame.contentWindow.postMessage(
msg, '*' msg, '*'
) )
@ -196,23 +184,13 @@ export class FileGroupPage extends HTMLElement {
} }
async handleViewMessage(event) { async handleViewMessage(event) {
if (Array.isArray(event.data)) {
if (['get', 'put'].includes(event.data[0])) {
await this.handleRequestMessage('view', event)
}
}
} }
async handleEditMessage(event) { async handleEditMessage(event) {
if (Array.isArray(event.data)) { if (Array.isArray(event.data)) {
if (event.data[0] === 'ready') { if (event.data[0] === 'ready') {
this.editFrame.contentWindow.postMessage( this.editFrame.contentWindow.postMessage(
[ ['doc', this.body], '*'
'doc',
this.body,
{codeMirror: !!(this.settings.codeMirror)}
],
'*'
) )
} else if (event.data[0] === 'html') { } else if (event.data[0] === 'html') {
const html = event.data[1] const html = event.data[1]
@ -220,88 +198,13 @@ export class FileGroupPage extends HTMLElement {
} else if (event.data[0] === 'save') { } else if (event.data[0] === 'save') {
const doc = event.data[1] const doc = event.data[1]
this.body = doc this.body = doc
} else if (['get', 'put'].includes(event.data[0])) {
await this.handleRequestMessage('edit', event)
} else if (event.data[0] === 'load') {
if (event.data[1] === '/editor-lib-codemirror/codemirror-bundle.js') {
const url = event.data[1]
const resp = await fetch(url)
const text = await resp.text()
const port = event.ports[0]
port.postMessage({
status: 200,
body: text,
})
port.close()
}
} }
} }
} }
async handleRequestMessage(frame, event) {
if (event.ports.length === 1) {
const port = event.ports[0]
const method = event.data[0]
const path = event.data[1]
const access = this.getAccess(path)
if (method === 'get') {
if (['read', 'readWrite'].includes(access)) {
port.postMessage({
status: 200,
body: this.getPage(path),
})
} else {
port.postMessage({
status: 401,
})
}
} else if (method === 'put') {
const body = event.data[2]
if (access === 'readWrite') {
this.setPage(path, body)
port.postMessage({
status: 200,
})
} else {
port.postMessage({
status: 401,
})
}
}
port.close()
} else {
throw new Error('request message without port')
}
}
getAccess(path) {
const settings = this.settings
const outbound = settings.connections?.outbound
if (outbound && outbound[path]) {
return outbound[path]
}
}
getPage(path) {
const body = this.storage.getItem(path)
try {
return JSON.parse(body)
} catch (err) {
return body
}
}
setPage(path, body) {
let value = body
if (typeof value !== 'string') {
value = JSON.stringify(value)
}
this.storage.setItem(path, value)
}
set body(value) { set body(value) {
try { try {
this.storage.setItem(this.path, value) localStorage.setItem(this.path, value)
} catch (err) { } catch (err) {
console.error(err) console.error(err)
} }
@ -309,7 +212,7 @@ export class FileGroupPage extends HTMLElement {
get body() { get body() {
try { try {
return this.storage.getItem(this.path) return localStorage.getItem(this.path)
} catch (err) { } catch (err) {
console.error(err) console.error(err)
return '' return ''
@ -318,7 +221,7 @@ export class FileGroupPage extends HTMLElement {
set settings(value) { set settings(value) {
try { try {
this.storage.setItem( localStorage.setItem(
'settings/page:' + this.path, 'settings/page:' + this.path,
JSON.stringify(value) JSON.stringify(value)
) )
@ -330,7 +233,7 @@ export class FileGroupPage extends HTMLElement {
get settings() { get settings() {
let data let data
try { try {
data = this.storage.getItem( data = localStorage.getItem(
'settings/page:' + this.path 'settings/page:' + this.path
) )
if (data === null || data === undefined) { if (data === null || data === undefined) {

@ -28,7 +28,6 @@ export class Header extends HTMLElement {
htmlCss: 'HTML/CSS', htmlCss: 'HTML/CSS',
singleFile: 'Single File', singleFile: 'Single File',
newPage: 'New Page', newPage: 'New Page',
go: 'Go',
} }
textEs = { textEs = {
@ -41,7 +40,6 @@ export class Header extends HTMLElement {
htmlCss: 'HTML/CSS', htmlCss: 'HTML/CSS',
singleFile: 'Archivo único', singleFile: 'Archivo único',
newPage: 'Nueva Página', newPage: 'Nueva Página',
go: 'Ir',
} }
constructor() { constructor() {
@ -52,12 +50,11 @@ export class Header extends HTMLElement {
this.appBar = document.createElement('div') this.appBar = document.createElement('div')
this.appBar.classList.add('app-bar') this.appBar.classList.add('app-bar')
this.shadowRoot.appendChild(this.appBar) this.shadowRoot.appendChild(this.appBar)
const navBtn = this.addButton( this.addButton(this.icons.menu, 'nav', () => {
this.icons.menu, this.menu.pages = this.getPages()
'nav', this.menuPanel.classList.add('open')
() => this.openNav(), this.overlay.classList.add('open')
) }).classList.add('left-end')
navBtn.classList.add('left-end')
this.addButton(this.icons.add, 'add', () => { this.addButton(this.icons.add, 'add', () => {
this.addPage() this.addPage()
}) })
@ -188,13 +185,6 @@ export class Header extends HTMLElement {
this.menu.addEventListener('close-menu', () => { this.menu.addEventListener('close-menu', () => {
this.close() this.close()
}) })
this.menu.addEventListener(
'click-location',
() => {
this.close()
this.navPage()
},
)
} }
addPageMenu() { addPageMenu() {
@ -204,14 +194,6 @@ export class Header extends HTMLElement {
this.shadowRoot.appendChild(this.pageMenu) this.shadowRoot.appendChild(this.pageMenu)
} }
openNav() {
this.menu.location = this.path
this.menu.pages = this.getPages()
this.menu.storageUse = this.getStorageUse()
this.menuPanel.classList.add('open')
this.overlay.classList.add('open')
}
close() { close() {
this.overlay.classList.add('closing') this.overlay.classList.add('closing')
this.overlay.classList.remove('open') this.overlay.classList.remove('open')
@ -222,21 +204,7 @@ export class Header extends HTMLElement {
} }
getPages() { getPages() {
return ( return Object.keys(localStorage).slice().sort()
this.storage.keys().slice()
.filter(s => s.startsWith('/'))
.sort()
)
}
getStorageUse() {
let bytes = 0
const entries = this.storage.entries()
for (const [k, v] of entries) {
bytes += k.length
bytes += v.length
}
return bytes / 5000000
} }
set editing(value) { set editing(value) {
@ -254,22 +222,6 @@ export class Header extends HTMLElement {
return this.editing ? this.icons.check : this.icons.edit return this.editing ? this.icons.check : this.icons.edit
} }
getTemplates() {
const text = this.storage.getItem(
'settings:templates'
)
if (text ?? undefined !== undefined) {
const data = JSON.parse(text)
return Object.entries(
data.templates
).map(([id, data]) => (
{...data, id}
))
} else {
return []
}
}
addPage() { addPage() {
const dialog = document.createElement('m-dialog') const dialog = document.createElement('m-dialog')
this.dialogWrap.replaceChildren(dialog) this.dialogWrap.replaceChildren(dialog)
@ -285,13 +237,6 @@ export class Header extends HTMLElement {
el.innerText = this.text[value] el.innerText = this.text[value]
return el return el
})) }))
const templates = this.getTemplates()
select.append(...templates.map(t => {
const el = document.createElement('option')
el.value = t.id
el.innerText = t.name
return el
}))
select.value = 'htmlCss' select.value = 'htmlCss'
input.addEventListener('input', e => { input.addEventListener('input', e => {
const ext = e.target.value.match(/\.\w+$/) const ext = e.target.value.match(/\.\w+$/)
@ -306,7 +251,7 @@ export class Header extends HTMLElement {
) )
bGroup.addPrimary(this.text.createPage, () => { bGroup.addPrimary(this.text.createPage, () => {
const newPath = this.encodePath(input.value) const newPath = this.encodePath(input.value)
const v = this.storage.getItem(newPath) const v = localStorage.getItem(newPath)
if (v !== null || newPath === this.path) { if (v !== null || newPath === this.path) {
if (!errorEl) { if (!errorEl) {
errorEl = document.createElement('p') errorEl = document.createElement('p')
@ -318,9 +263,10 @@ export class Header extends HTMLElement {
} }
return return
} }
let value const value = (
if (select.value === 'htmlCss') { select.value === 'singleFile' ?
value = JSON.stringify({ '' :
JSON.stringify({
type: 'm-file-group', type: 'm-file-group',
files: [ files: [
{ {
@ -333,13 +279,9 @@ export class Header extends HTMLElement {
}, },
], ],
}) })
} else { )
value = this.storage.getItem( localStorage.setItem(newPath, value)
select.value localStorage.setItem(
) ?? ''
}
this.storage.setItem(newPath, value)
this.storage.setItem(
'settings/page:' + newPath, '{}' 'settings/page:' + newPath, '{}'
) )
location.hash = newPath location.hash = newPath
@ -355,30 +297,6 @@ export class Header extends HTMLElement {
dialog.open() dialog.open()
} }
navPage() {
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)
const bGroup = document.createElement(
'm-forms-button-group'
)
bGroup.addPrimary(this.text.go, () => {
dialog.close()
location.hash = (
input.value.startsWith('/') ?
input.value : '/'
)
})
bGroup.addCancel(this.text.cancel, () => {
dialog.close()
})
dialog.footerEl.appendChild(bGroup)
dialog.open()
}
get language() { get language() {
return this._language return this._language
} }

@ -3,7 +3,7 @@ import { EditorBuild } from "/loader/editor-build.js"
export class Layout extends HTMLElement { export class Layout extends HTMLElement {
cspProfiles = { cspProfiles = {
local: "default-src 'self' 'unsafe-inline' 'unsafe-eval'", local: "default-src 'self' 'unsafe-inline' 'unsafe-eval'",
unpkg: "default-src unpkg.com 'self' 'unsafe-inline' 'unsafe-eval'", jsCdns: "default-src cdn.jsdelivr.com data.jsdelivr.com unpkg.com 'self' 'unsafe-inline' 'unsafe-eval'",
open: undefined, open: undefined,
} }
@ -68,10 +68,9 @@ export class Layout extends HTMLElement {
load() { load() {
const path = this.path const path = this.path
this.editing = false
const prevPage = this.page const prevPage = this.page
let isGroup = false let isGroup = false
const body = this.storage.getItem(path) || '' const body = localStorage.getItem(path) || ''
if (body.match(/^\s*{/)) { if (body.match(/^\s*{/)) {
try { try {
const bodyData = JSON.parse(body) const bodyData = JSON.parse(body)
@ -86,7 +85,6 @@ export class Layout extends HTMLElement {
this.page = document.createElement( this.page = document.createElement(
isGroup ? 'm-file-group-page' : 'm-page' isGroup ? 'm-file-group-page' : 'm-page'
) )
this.page.storage = this.storage
if (isGroup) { if (isGroup) {
this.page.cspOff = this.csp === undefined this.page.cspOff = this.csp === undefined
this.page.cspProfiles = this.cspProfiles this.page.cspProfiles = this.cspProfiles
@ -118,7 +116,7 @@ export class Layout extends HTMLElement {
} }
set editing(value) { set editing(value) {
this.storage.session.setItem( sessionStorage.setItem(
'editing', value ? 'true' : 'false' 'editing', value ? 'true' : 'false'
) )
this.header.editing = this.editing this.header.editing = this.editing
@ -130,7 +128,7 @@ export class Layout extends HTMLElement {
get editing() { get editing() {
try { try {
return ( return (
this.storage.session.getItem('editing') === 'true' sessionStorage.getItem('editing') === 'true'
) )
} catch (e) { } catch (e) {
return false return false
@ -143,14 +141,4 @@ export class Layout extends HTMLElement {
} }
return this._editorBuild return this._editorBuild
} }
set storage(value) {
this._storage = value
this.header.storage = value
this.pageActions.storage = value
}
get storage() {
return this._storage
}
} }

@ -1,17 +1,4 @@
export class NavMenu extends HTMLElement { export class NavMenu extends HTMLElement {
textByLang = {
en: {
pages: 'Pages',
localStorage: 'Local storage',
full: 'full',
},
es: {
pages: 'Páginas',
localStorage: 'Almacenamiento local',
full: 'lleno',
},
}
constructor() { constructor() {
super() super()
this.attachShadow({mode: 'open'}) this.attachShadow({mode: 'open'})
@ -27,21 +14,8 @@ export class NavMenu extends HTMLElement {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
color: #000; color: #000;
height: 100dvh;
max-height: 100dvh; max-height: 100dvh;
} }
.location-bar {
padding: 5px 25px;
display: flex;
flex-direction: row;
}
.location-box {
border: 2px solid #aaa;
border-radius: 3px;
flex-grow: 1;
padding: 5px;
font-size: 14px;
}
h1 { h1 {
width: 100%; width: 100%;
text-align: center; text-align: center;
@ -58,45 +32,15 @@ export class NavMenu extends HTMLElement {
display: block; display: block;
margin: 8px 10px; margin: 8px 10px;
} }
.footer {
padding: 3px 5px;
}
` `
this.shadowRoot.append(style) this.shadowRoot.append(style)
this.locationBar = document.createElement(
'div'
)
this.locationBar.classList.add(
'location-bar'
)
this.locationBox = document.createElement(
'div'
)
this.locationBox.classList.add(
'location-box'
)
this.locationBar.append(this.locationBox)
this.locationBox.addEventListener(
'click',
() => {
this.dispatchEvent(new CustomEvent(
'click-location', {bubbles: true}
))
}
)
this.shadowRoot.append(this.locationBar)
this.renderLocation()
this.header = document.createElement('h1') this.header = document.createElement('h1')
this.header.innerText = this.text.pages this.header.innerText = this.pagesText
this.shadowRoot.append(this.header) this.shadowRoot.append(this.header)
this.pageList = document.createElement('div') this.pageList = document.createElement('div')
this.pageList.classList.add('page-list') this.pageList.classList.add('page-list')
this.shadowRoot.append(this.pageList) this.shadowRoot.append(this.pageList)
this.renderPageList() this.renderPageList()
this.footer = document.createElement('div')
this.footer.classList.add('footer')
this.shadowRoot.append(this.footer)
this.renderFooter()
this.shadowRoot.addEventListener('click', e => { this.shadowRoot.addEventListener('click', e => {
if (e.target.classList.contains('page')) { if (e.target.classList.contains('page')) {
if (this.handleLinks) { if (this.handleLinks) {
@ -119,28 +63,14 @@ export class NavMenu extends HTMLElement {
set language(language) { set language(language) {
this._language = language this._language = language
this.text = this.textByLang[
this.langEs ? 'es' : 'en'
]
} }
get langEs() { get langEs() {
return /^es\b/.test(this.language) return /^es\b/.test(this.language)
} }
set location(location) { get pagesText() {
this._location = location return this.langEs ? 'Páginas' : 'Pages'
if (this.locationBox) {
this.renderLocation()
}
}
get location() {
return this._location
}
renderLocation() {
this.locationBox.innerText = this.location
} }
set pages(pages) { set pages(pages) {
@ -164,35 +94,4 @@ export class NavMenu extends HTMLElement {
}) })
this.pageList.replaceChildren(...els) this.pageList.replaceChildren(...els)
} }
set storageUse(n) {
this._storageUse = n
if (this.footer) {
this.renderFooter()
}
}
get storageUse() {
return this._storageUse
}
renderFooter() {
if (this.storageUse !== undefined) {
const fmt = new Intl.NumberFormat(
this.language,
{
style: 'percent',
minimumFractionDigits: 2,
maximumFractionDigits: 2,
},
)
this.footer.innerText = (
this.text.localStorage + ' ' +
fmt.format(
this.storageUse
).replaceAll(/\s+/g, '') + ' ' +
this.text.full
)
}
}
} }

@ -80,7 +80,7 @@ export class PageActions extends HTMLElement {
} }
download() { download() {
const text = this.storage.getItem(this.path) const text = localStorage.getItem(this.path)
const sp = this.path.split('/') const sp = this.path.split('/')
const filename = sp[sp.length - 1] const filename = sp[sp.length - 1]
const el = document.createElement('a') const el = document.createElement('a')
@ -111,7 +111,7 @@ export class PageActions extends HTMLElement {
) )
bGroup.addPrimary(this.text.rename, () => { bGroup.addPrimary(this.text.rename, () => {
const newPath = input.value const newPath = input.value
const v = this.storage.getItem(newPath) const v = localStorage.getItem(newPath)
if (v !== null || newPath === this.path) { if (v !== null || newPath === this.path) {
if (!errorEl) { if (!errorEl) {
errorEl = document.createElement('p') errorEl = document.createElement('p')
@ -122,36 +122,18 @@ export class PageActions extends HTMLElement {
} }
return return
} }
const sKeyOld = 'settings/page:' + this.path localStorage.setItem(
const sKeyNew = 'settings/page:' + newPath newPath,
const settingsJson = this.storage.getItem(sKeyOld) localStorage.getItem(this.path)
if (settingsJson ?? true === true) {
this.storage.setItem(sKeyNew, settingsJson)
this.storage.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( localStorage.setItem(
settingsData, dir, otherDir, this.path, newPath 'settings/page:' + newPath,
localStorage.getItem(this.path)
) )
} localStorage.removeItem(this.path)
} localStorage.removeItem(
} else { 'settings/page:' + newPath,
this.storage.removeItem(sKeyNew)
}
this.storage.setItem(
newPath,
this.storage.getItem(this.path)
) )
this.storage.removeItem(this.path)
dialog.close() dialog.close()
location.hash = newPath location.hash = newPath
}) })
@ -178,7 +160,7 @@ export class PageActions extends HTMLElement {
const btnText = this.text.duplicate const btnText = this.text.duplicate
bGroup.addPrimary(btnText, () => { bGroup.addPrimary(btnText, () => {
const newPath = input.value const newPath = input.value
const v = this.storage.getItem(newPath) const v = localStorage.getItem(newPath)
if (v !== null || newPath === this.path) { if (v !== null || newPath === this.path) {
if (!errorEl) { if (!errorEl) {
errorEl = document.createElement('p') errorEl = document.createElement('p')
@ -189,13 +171,13 @@ export class PageActions extends HTMLElement {
} }
return return
} }
this.storage.setItem( localStorage.setItem(
newPath, newPath,
this.storage.getItem(this.path) localStorage.getItem(this.path)
) )
this.storage.setItem( localStorage.setItem(
'settings/page:' + newPath, 'settings/page:' + newPath,
this.storage.getItem(this.path) ?? '{}' localStorage.getItem(this.path) ?? '{}'
) )
dialog.close() dialog.close()
location.hash = newPath location.hash = newPath
@ -222,8 +204,8 @@ export class PageActions extends HTMLElement {
'm-forms-button-group' 'm-forms-button-group'
) )
bGroup.addPrimary(this.text.delete_, () => { bGroup.addPrimary(this.text.delete_, () => {
this.storage.removeItem(this.path) localStorage.removeItem(this.path)
this.storage.removeItem( localStorage.removeItem(
'settings/page:' + this.path 'settings/page:' + this.path
) )
location.hash = '/' location.hash = '/'
@ -245,30 +227,13 @@ export class PageActions extends HTMLElement {
'm-settings-page-settings' 'm-settings-page-settings'
) )
settingsEl.cspProfiles = this.cspProfiles settingsEl.cspProfiles = this.cspProfiles
settingsEl.path = this.path
settingsEl.checkExists = path => (
this.storage.getItem(path) !== null
)
settingsEl.data = this.page.settings settingsEl.data = this.page.settings
const h = document.createElement('h2') dialog.bodyEl.appendChild(settingsEl)
h.innerText = this.text.settings
dialog.headerEl.append(h)
dialog.bodyEl.append(settingsEl)
const bGroup = document.createElement( const bGroup = document.createElement(
'm-forms-button-group' 'm-forms-button-group'
) )
bGroup.addPrimary(this.text.save, () => { bGroup.addPrimary(this.text.save, () => {
const settingsData = settingsEl.data this.page.settings = settingsEl.data
this.page.settings = settingsData
for (const dir of ['outbound', 'inbound']) {
const otherDir = (
dir === 'outbound' ? 'inbound' : 'outbound'
)
this.applyInverseSettings(
settingsData, dir, otherDir
)
}
this.applyTemplateSettings()
dialog.close() dialog.close()
this.dispatchEvent(new CustomEvent( this.dispatchEvent(new CustomEvent(
'settings-change', {bubbles: true, composed: true} 'settings-change', {bubbles: true, composed: true}
@ -281,87 +246,6 @@ export class PageActions extends HTMLElement {
dialog.open() 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 = this.storage.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
this.storage.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 = this.storage.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
this.storage.setItem(
key, JSON.stringify(data)
)
}
}
applyTemplateSettings() {
const templates = {}
for (const key of this.storage.keys()) {
try {
if (key.startsWith('settings/page:')) {
const data = JSON.parse(
this.storage.getItem(key)
)
if (data.template) {
const name = key.slice(
'settings/page:'.length
)
templates[name] = {name}
}
}
} catch (err) {
// do nothing
}
}
this.storage.setItem(
'settings:templates',
JSON.stringify({templates}),
)
}
get language() { get language() {
return this._language return this._language
} }

@ -141,7 +141,7 @@ export class Page extends HTMLElement {
set body(value) { set body(value) {
try { try {
this.storage.setItem(this.path, value) localStorage.setItem(this.path, value)
} catch (err) { } catch (err) {
console.error(err) console.error(err)
} }
@ -149,7 +149,7 @@ export class Page extends HTMLElement {
get body() { get body() {
try { try {
return this.storage.getItem(this.path) return localStorage.getItem(this.path)
} catch (err) { } catch (err) {
console.error(err) console.error(err)
return '' return ''

15
sw.js

@ -13,20 +13,13 @@ async function initCache() {
'/editor/file-group.js', '/editor/file-group.js',
'/editor/file-view.js', '/editor/file-view.js',
'/editor/text-edit.js', '/editor/text-edit.js',
'/editor/code-edit.js',
'/editor/header.js',
'/forms/button-group.js', '/forms/button-group.js',
'/index.html', '/index.html',
'/loader/builder.js', '/loader/builder.js',
'/loader/editor-build.js', '/loader/editor-build.js',
'/menu/dropdown.js', '/menu/dropdown.js',
'/settings/page-settings.js', '/settings/page-settings.js',
'/settings/network-settings.js', ]) //1
'/settings/connections.js',
'/settings/connection-edit.js',
'/editor-lib-codemirror/codemirror-bundle.js',
'/storage/storage.js', //2
])
} }
self.addEventListener("install", event => { self.addEventListener("install", event => {
@ -63,9 +56,3 @@ self.addEventListener('fetch', event => {
self.addEventListener('activate', event => { self.addEventListener('activate', event => {
event.waitUntil(clients.claim()) event.waitUntil(clients.claim())
}) })
self.addEventListener('message', e => {
if (Array.isArray(e.data) && e.data[0] === 'skipWaiting') {
self.skipWaiting()
}
})
Loading…
Cancel
Save