2 changed files with 194 additions and 1 deletions
@ -0,0 +1,178 @@ |
|||||
|
const frameHtml = `<!doctype html> |
||||
|
<html> |
||||
|
<head> |
||||
|
<title>Frame</title> |
||||
|
<style> |
||||
|
html, body, iframe { |
||||
|
margin: 0; |
||||
|
padding: 0; |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
} |
||||
|
iframe { |
||||
|
border: none; |
||||
|
display: block; |
||||
|
} |
||||
|
html { |
||||
|
box-sizing: border-box; |
||||
|
} |
||||
|
*, *:before, *:after { |
||||
|
box-sizing: inherit; |
||||
|
} |
||||
|
</style> |
||||
|
</head> |
||||
|
<body> |
||||
|
${'<'}script type="module"> |
||||
|
let frame = undefined |
||||
|
addEventListener('message', event => { |
||||
|
let isNew = false |
||||
|
const d = event.data |
||||
|
if (Array.isArray(d) && d[0] === 'srcdoc') { |
||||
|
isNew = frame === undefined |
||||
|
if (isNew) { |
||||
|
frame = document.createElement('iframe') |
||||
|
frame.sandbox = "allow-scripts allow-top-navigation" |
||||
|
} |
||||
|
frame.srcdoc = d[1] |
||||
|
} else if (frame !== undefined) { |
||||
|
frame.postMessage(event.data) |
||||
|
} |
||||
|
if (isNew) { |
||||
|
document.body.appendChild(frame) |
||||
|
} |
||||
|
}) |
||||
|
${'</'}script> |
||||
|
</body> |
||||
|
</html>` |
||||
|
|
||||
|
export class FileGroupPage extends HTMLElement { |
||||
|
constructor() { |
||||
|
super() |
||||
|
this.attachShadow({mode: 'open'}) |
||||
|
this.csp = "default-src 'self' 'unsafe-inline' 'unsafe-eval'" |
||||
|
} |
||||
|
|
||||
|
connectedCallback() { |
||||
|
const style = document.createElement('style') |
||||
|
style.textContent = ` |
||||
|
:host { |
||||
|
display: grid; |
||||
|
grid-template-columns: 1fr; |
||||
|
grid-template-rows: 1fr; |
||||
|
grid-template-areas: "main"; |
||||
|
flex-direction: column; |
||||
|
align-items: stretch; |
||||
|
} |
||||
|
iframe { |
||||
|
border: none; |
||||
|
margin: 0; |
||||
|
padding: 0; |
||||
|
grid-area: main; |
||||
|
width: 100%; |
||||
|
} |
||||
|
:host(.editing) iframe.view { |
||||
|
display: none; |
||||
|
} |
||||
|
:host(.viewing) iframe.edit { |
||||
|
display: none; |
||||
|
} |
||||
|
` |
||||
|
this.shadowRoot.append(style) |
||||
|
this.initEditFrame() |
||||
|
this.initViewFrame() |
||||
|
this.editing = this.editing |
||||
|
} |
||||
|
|
||||
|
initEditFrame() { |
||||
|
const frame = document.createElement('iframe') |
||||
|
if (this.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('html', frameHtml) |
||||
|
frame.src = url.href |
||||
|
} else { |
||||
|
frame.sandbox = "allow-scripts allow-top-navigation" |
||||
|
frame.srcdoc = frameHtml |
||||
|
} |
||||
|
frame.addEventListener('load', () => { |
||||
|
this.displayEdit() |
||||
|
}) |
||||
|
this.editFrame = frame |
||||
|
this.shadowRoot.append(frame) |
||||
|
} |
||||
|
|
||||
|
initViewFrame() { |
||||
|
const frame = document.createElement('iframe') |
||||
|
if (this.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('html', frameHtml) |
||||
|
frame.src = url.href |
||||
|
} else { |
||||
|
frame.sandbox = "allow-scripts allow-top-navigation" |
||||
|
frame.srcdoc = frameHtml |
||||
|
} |
||||
|
frame.addEventListener('load', () => { |
||||
|
this.displayView() |
||||
|
}) |
||||
|
this.viewFrame = frame |
||||
|
this.shadowRoot.append(frame) |
||||
|
} |
||||
|
|
||||
|
displayView() { |
||||
|
let doc = 'view here' |
||||
|
const msg = ['srcdoc', doc] |
||||
|
this.viewFrame.contentWindow.postMessage( |
||||
|
msg, '*' |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
displayEdit() { |
||||
|
let doc = 'edit here' |
||||
|
const msg = ['srcdoc', doc] |
||||
|
this.viewFrame.contentWindow.postMessage( |
||||
|
msg, '*' |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
set body(value) { |
||||
|
try { |
||||
|
localStorage.setItem(this.path, value) |
||||
|
} catch (err) { |
||||
|
console.error(err) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
get body() { |
||||
|
try { |
||||
|
return localStorage.getItem(this.path) |
||||
|
} catch (err) { |
||||
|
console.error(err) |
||||
|
return '' |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
set editing(value) { |
||||
|
this._editing = value |
||||
|
if (this.shadowRoot.host) { |
||||
|
const classes = this.shadowRoot.host.classList |
||||
|
if (this.editing) { |
||||
|
classes.add('editing') |
||||
|
classes.remove('viewing') |
||||
|
} else { |
||||
|
classes.add('viewing') |
||||
|
classes.remove('editing') |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
get editing() { |
||||
|
return this._editing |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue