add csp setting

csp-setting
Benjamin Atkin 3 years ago
parent 0622d10db4
commit 9e90b8a3b8

@ -7,10 +7,14 @@ import { NavMenu } from "/components/nav-menu.js"
import { Dialog } from "/dialog/dialog.js"
import { ButtonGroup } from "/forms/button-group.js"
import { Dropdown } from "/menu/dropdown.js"
import { PageSettings } from "/settings/page-settings.js"
customElements.define('m-layout', Layout)
customElements.define('m-page', Page)
customElements.define('m-page-actions', PageActions)
customElements.define(
'm-settings-page-settings', PageSettings
)
customElements.define(
'm-file-group-page', FileGroupPage
)

@ -56,9 +56,9 @@ export class FileGroupPage extends HTMLElement {
constructor() {
super()
this.attachShadow({mode: 'open'})
this.csp = "default-src 'self' 'unsafe-inline' 'unsafe-eval'"
this.viewLoaded = false
this.onceOnLoaded = undefined
this.isGroup = true
}
connectedCallback() {
@ -80,10 +80,10 @@ export class FileGroupPage extends HTMLElement {
width: 100%;
}
:host(.editing) iframe.view {
display: none;
visibility: hidden;
}
:host(.viewing) iframe.edit {
display: none;
visibility: hidden;
}
`
this.shadowRoot.append(style)
@ -100,12 +100,13 @@ export class FileGroupPage extends HTMLElement {
initEditFrame() {
const frame = document.createElement('iframe')
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"
const url = new URL(
'/-/frame', location.href
)
url.searchParams.set('csp', this.csp)
url.searchParams.set('csp', csp)
url.searchParams.set('html', frameHtml)
frame.src = url.href
} else {
@ -125,12 +126,13 @@ export class FileGroupPage extends HTMLElement {
initViewFrame() {
const frame = document.createElement('iframe')
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"
const url = new URL(
'/-/frame', location.href
)
url.searchParams.set('csp', this.csp)
url.searchParams.set('csp', csp)
url.searchParams.set('html', frameHtml)
frame.src = url.href
} 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) {
this._editing = value
if (this.shadowRoot.host) {

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

@ -1,6 +1,12 @@
import { EditorBuild } from "/loader/editor-build.js"
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() {
super()
this.attachShadow({mode: 'open'})
@ -11,6 +17,7 @@ export class Layout extends HTMLElement {
this.pageActions = document.createElement(
'm-page-actions'
)
this.pageActions.cspProfiles = this.cspProfiles
this.header.pageActions = this.pageActions
this.shadowRoot.append(
this.header,
@ -54,6 +61,9 @@ export class Layout extends HTMLElement {
this.addEventListener('hash-change', () => {
this.load()
})
this.addEventListener('settings-change', () => {
this.load()
})
}
load() {
@ -75,7 +85,12 @@ export class Layout extends HTMLElement {
this.page = document.createElement(
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) {
this.page.editorBuild = this.editorBuild
}
@ -87,6 +102,7 @@ export class Layout extends HTMLElement {
this.shadowRoot.appendChild(this.page)
this.header.path = path
this.pageActions.path = path
this.pageActions.page = this.page
}
get path() {

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

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

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

Loading…
Cancel
Save