Merge pull request 'add csp setting' (#57) from csp-setting into main

Reviewed-on: https://codeberg.org/macchiato/pages/pulls/57
csp-setting-fix
bat 3 years ago
commit 1a9f5e9ce4

@ -7,10 +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 { PageSettings } from "/settings/page-settings.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-page-settings', PageSettings
)
customElements.define( customElements.define(
'm-file-group-page', FileGroupPage 'm-file-group-page', FileGroupPage
) )

@ -56,9 +56,9 @@ export class FileGroupPage extends HTMLElement {
constructor() { constructor() {
super() super()
this.attachShadow({mode: 'open'}) this.attachShadow({mode: 'open'})
this.csp = "default-src 'self' 'unsafe-inline' 'unsafe-eval'"
this.viewLoaded = false this.viewLoaded = false
this.onceOnLoaded = undefined this.onceOnLoaded = undefined
this.isGroup = true
} }
connectedCallback() { connectedCallback() {
@ -80,10 +80,10 @@ export class FileGroupPage extends HTMLElement {
width: 100%; width: 100%;
} }
:host(.editing) iframe.view { :host(.editing) iframe.view {
display: none; visibility: hidden;
} }
:host(.viewing) iframe.edit { :host(.viewing) iframe.edit {
display: none; visibility: hidden;
} }
` `
this.shadowRoot.append(style) this.shadowRoot.append(style)
@ -100,12 +100,13 @@ export class FileGroupPage extends HTMLElement {
initEditFrame() { initEditFrame() {
const frame = document.createElement('iframe') const frame = document.createElement('iframe')
frame.classList.add('edit') frame.classList.add('edit')
if (this.csp !== undefined) { const csp = this.csp
if (csp !== undefined) {
frame.sandbox = "allow-same-origin allow-scripts allow-top-navigation" frame.sandbox = "allow-same-origin allow-scripts allow-top-navigation"
const url = new URL( const url = new URL(
'/-/frame', location.href '/-/frame', location.href
) )
url.searchParams.set('csp', this.csp) url.searchParams.set('csp', csp)
url.searchParams.set('html', frameHtml) url.searchParams.set('html', frameHtml)
frame.src = url.href frame.src = url.href
} else { } else {
@ -125,12 +126,13 @@ export class FileGroupPage extends HTMLElement {
initViewFrame() { initViewFrame() {
const frame = document.createElement('iframe') const frame = document.createElement('iframe')
frame.classList.add('view') frame.classList.add('view')
if (this.csp !== undefined) { const csp = this.csp
if (csp !== undefined) {
frame.sandbox = "allow-same-origin allow-scripts allow-top-navigation" frame.sandbox = "allow-same-origin allow-scripts allow-top-navigation"
const url = new URL( const url = new URL(
'/-/frame', location.href '/-/frame', location.href
) )
url.searchParams.set('csp', this.csp) url.searchParams.set('csp', csp)
url.searchParams.set('html', frameHtml) url.searchParams.set('html', frameHtml)
frame.src = url.href frame.src = url.href
} else { } else {
@ -217,6 +219,47 @@ export class FileGroupPage extends HTMLElement {
} }
} }
set settings(value) {
try {
localStorage.setItem(
'settings/page:' + this.path,
JSON.stringify(value)
)
} catch (err) {
console.error(err)
}
}
get settings() {
let data
try {
data = localStorage.getItem(
'settings/page:' + this.path
)
if (data === null || data === undefined) {
return {}
}
} catch (err) {
console.error(err)
return {}
}
try {
return JSON.parse(data)
} catch (err) {
return {}
}
}
get csp() {
if (this.cspOff) {
return undefined
} else {
return this.cspProfiles[
this.settings.networkAccess
] ?? this.cspProfiles.local
}
}
set editing(value) { set editing(value) {
this._editing = value this._editing = value
if (this.shadowRoot.host) { if (this.shadowRoot.host) {

@ -68,6 +68,11 @@ export class Header extends HTMLElement {
this.icons.dot, this.icons.dot,
'page', 'page',
() => { () => {
const actions = this.pageActions.menuActions
this.pageMenu.clear()
for (const {text, click} of actions) {
this.pageMenu.add(text, click)
}
this.pageMenu.open(this.pageButton) this.pageMenu.open(this.pageButton)
} }
) )
@ -186,10 +191,6 @@ export class Header extends HTMLElement {
this.pageMenu = document.createElement( this.pageMenu = document.createElement(
'm-menu-dropdown' 'm-menu-dropdown'
) )
const actions = this.pageActions.menuActions
for (const {text, click} of actions) {
this.pageMenu.add(text, click)
}
this.shadowRoot.appendChild(this.pageMenu) this.shadowRoot.appendChild(this.pageMenu)
} }
@ -280,6 +281,9 @@ export class Header extends HTMLElement {
}) })
) )
localStorage.setItem(newPath, value) localStorage.setItem(newPath, value)
localStorage.setItem(
'settings/page:' + newPath, '{}'
)
location.hash = newPath location.hash = newPath
dialog.close() dialog.close()
this.dispatchEvent(new CustomEvent( this.dispatchEvent(new CustomEvent(

@ -1,6 +1,12 @@
import { EditorBuild } from "/loader/editor-build.js" import { EditorBuild } from "/loader/editor-build.js"
export class Layout extends HTMLElement { export class Layout extends HTMLElement {
cspProfiles = {
local: "default-src 'self' 'unsafe-inline' 'unsafe-eval'",
jsCdns: "default-src cdn.jsdelivr.com data.jsdelivr.com unpkg.com 'self' 'unsafe-inline' 'unsafe-eval'",
open: undefined,
}
constructor() { constructor() {
super() super()
this.attachShadow({mode: 'open'}) this.attachShadow({mode: 'open'})
@ -11,6 +17,7 @@ export class Layout extends HTMLElement {
this.pageActions = document.createElement( this.pageActions = document.createElement(
'm-page-actions' 'm-page-actions'
) )
this.pageActions.cspProfiles = this.cspProfiles
this.header.pageActions = this.pageActions this.header.pageActions = this.pageActions
this.shadowRoot.append( this.shadowRoot.append(
this.header, this.header,
@ -54,6 +61,9 @@ export class Layout extends HTMLElement {
this.addEventListener('hash-change', () => { this.addEventListener('hash-change', () => {
this.load() this.load()
}) })
this.addEventListener('settings-change', () => {
this.load()
})
} }
load() { load() {
@ -75,7 +85,12 @@ 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.csp = this.csp if (isGroup) {
this.page.cspOff = this.csp === undefined
this.page.cspProfiles = this.cspProfiles
} else {
this.page.csp = this.csp
}
if (isGroup) { if (isGroup) {
this.page.editorBuild = this.editorBuild this.page.editorBuild = this.editorBuild
} }
@ -87,6 +102,7 @@ export class Layout extends HTMLElement {
this.shadowRoot.appendChild(this.page) this.shadowRoot.appendChild(this.page)
this.header.path = path this.header.path = path
this.pageActions.path = path this.pageActions.path = path
this.pageActions.page = this.page
} }
get path() { get path() {

@ -10,6 +10,8 @@ export class PageActions extends HTMLElement {
), ),
cancel: 'Cancel', cancel: 'Cancel',
alreadyExists: 'There is already a page with that name.', alreadyExists: 'There is already a page with that name.',
save: 'Guardar',
close: 'Close',
} }
textEs = { textEs = {
@ -23,6 +25,8 @@ export class PageActions extends HTMLElement {
), ),
cancel: 'Cancelar', cancel: 'Cancelar',
alreadyExists: 'Ya existe una página con ese nombre.', alreadyExists: 'Ya existe una página con ese nombre.',
save: 'Guardar',
close: 'Cerrar',
} }
constructor() { constructor() {
@ -31,7 +35,20 @@ export class PageActions extends HTMLElement {
this.language = navigator.language this.language = navigator.language
this.dialogWrap = document.createElement('div') this.dialogWrap = document.createElement('div')
this.shadowRoot.append(this.dialogWrap) this.shadowRoot.append(this.dialogWrap)
this.menuActions = [ }
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, text: this.text.download,
click: this.download.bind(this), click: this.download.bind(this),
@ -48,20 +65,18 @@ export class PageActions extends HTMLElement {
text: this.text.delete_, text: this.text.delete_,
click: this.delete_.bind(this), click: this.delete_.bind(this),
}, },
//{
// text: this.text.settings,
// click: this.settings.bind(this),
//},
] ]
} if (this.page.isGroup) {
connectedCallback() { return [
const style = document.createElement('style') ...baseActions,
style.textContent = ` {
m-dialog::part(footer) { text: this.text.settings,
padding-top: 15px; click: this.settings.bind(this),
} },
` ]
this.shadowRoot.appendChild(style) } else {
return baseActions
}
} }
download() { download() {
@ -111,7 +126,14 @@ export class PageActions extends HTMLElement {
newPath, newPath,
localStorage.getItem(this.path) localStorage.getItem(this.path)
) )
localStorage.setItem(
'settings/page:' + newPath,
localStorage.getItem(this.path)
)
localStorage.removeItem(this.path) localStorage.removeItem(this.path)
localStorage.removeItem(
'settings/page:' + newPath,
)
dialog.close() dialog.close()
location.hash = newPath location.hash = newPath
}) })
@ -153,6 +175,10 @@ export class PageActions extends HTMLElement {
newPath, newPath,
localStorage.getItem(this.path) localStorage.getItem(this.path)
) )
localStorage.setItem(
'settings/page:' + newPath,
localStorage.getItem(this.path) ?? '{}'
)
dialog.close() dialog.close()
location.hash = newPath location.hash = newPath
}) })
@ -179,6 +205,9 @@ export class PageActions extends HTMLElement {
) )
bGroup.addPrimary(this.text.delete_, () => { bGroup.addPrimary(this.text.delete_, () => {
localStorage.removeItem(this.path) localStorage.removeItem(this.path)
localStorage.removeItem(
'settings/page:' + this.path
)
location.hash = '/' location.hash = '/'
dialog.close() dialog.close()
}) })
@ -194,34 +223,21 @@ export class PageActions extends HTMLElement {
'm-dialog' 'm-dialog'
) )
this.dialogWrap.replaceChildren(dialog) this.dialogWrap.replaceChildren(dialog)
const input = document.createElement('input') const settingsEl = document.createElement(
input.value = this.path 'm-settings-page-settings'
input.style.minWidth = '300px' )
dialog.bodyEl.appendChild(input) settingsEl.cspProfiles = this.cspProfiles
let errorEl settingsEl.data = this.page.settings
dialog.bodyEl.appendChild(settingsEl)
const bGroup = document.createElement( const bGroup = document.createElement(
'm-forms-button-group' 'm-forms-button-group'
) )
bGroup.addPrimary(this.text.rename, () => { bGroup.addPrimary(this.text.save, () => {
const newPath = input.value this.page.settings = settingsEl.data
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.removeItem(this.path)
dialog.close() dialog.close()
location.hash = newPath this.dispatchEvent(new CustomEvent(
'settings-change', {bubbles: true, composed: true}
))
}) })
bGroup.addCancel(this.text.cancel, () => { bGroup.addCancel(this.text.cancel, () => {
dialog.close() dialog.close()

@ -58,6 +58,7 @@ export class Page extends HTMLElement {
div.classList.add('twrap') div.classList.add('twrap')
div.appendChild(this.textArea) div.appendChild(this.textArea)
this.shadowRoot.appendChild(div) this.shadowRoot.appendChild(div)
this.isGroup = false
} }
connectedCallback() { connectedCallback() {
@ -73,7 +74,7 @@ export class Page extends HTMLElement {
align-items: stretch; align-items: stretch;
} }
div.twrap { div.twrap {
padding: 10px 10px; padding: 10px;
display: flex; display: flex;
align-items: stretch; align-items: stretch;
flex-direction: column; flex-direction: column;
@ -84,9 +85,6 @@ export class Page extends HTMLElement {
font-size: 0.90em; font-size: 0.90em;
height: 100%; height: 100%;
} }
textarea:focus {
height: 45vh;
}
iframe { iframe {
border: none; border: none;
margin: 0; margin: 0;

@ -18,7 +18,8 @@ async function initCache() {
'/loader/builder.js', '/loader/builder.js',
'/loader/editor-build.js', '/loader/editor-build.js',
'/menu/dropdown.js', '/menu/dropdown.js',
]) //2 '/settings/page-settings.js',
])
} }
self.addEventListener("install", event => { self.addEventListener("install", event => {

Loading…
Cancel
Save