Skip to content

Commit

Permalink
ACL - Editor w/ performance improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
auniverseaway committed Jan 13, 2025
1 parent c1f374b commit 6e4cbb1
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 104 deletions.
48 changes: 33 additions & 15 deletions blocks/edit/da-content/da-content.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
import { LitElement, html } from 'da-lit';
import { LitElement, html, nothing } from 'da-lit';

import getSheet from '../../shared/sheet.js';
import '../da-editor/da-editor.js';
import '../da-preview/da-preview.js';
import '../da-versions/da-versions.js';

const sheet = await getSheet('/blocks/edit/da-content/da-content.css');

export default class DaContent extends LitElement {
static properties = {
details: { attribute: false },
_sourceUrl: { state: true },
permissions: { attribute: false },
_editorLoaded: { state: true },
_versionUrl: { state: true },
};

connectedCallback() {
super.connectedCallback();
this.shadowRoot.adoptedStyleSheets = [sheet];
this._sourceUrl = this.details.sourceUrl;
}

update(props) {
super.update(props);
}

showPreview() {
Expand All @@ -31,6 +33,14 @@ export default class DaContent extends LitElement {
this.daVersions.classList.add('show-versions');
}

async handleEditorLoaded() {
if (this._editorLoaded) return;
const preview = import('../da-preview/da-preview.js');
const versions = import('../da-versions/da-versions.js');
await Promise.all([preview, versions]);
this._editorLoaded = true;
}

handleReset() {
this._versionUrl = null;
}
Expand All @@ -52,18 +62,26 @@ export default class DaContent extends LitElement {
render() {
return html`
<div class="editor-wrapper">
<da-editor path="${this._sourceUrl}" version="${this._versionUrl}" @versionreset=${this.handleReset}></da-editor>
<div class="da-editor-tabs">
<div class="da-editor-tabs-full">
<button class="da-editor-tab show-preview" title="Preview" @click=${this.showPreview}>Preview</button>
</div>
<div class="da-editor-tabs-quiet">
<button class="da-editor-tab quiet show-versions" title="Versions" @click=${this.showVersions}>Versions</button>
<da-editor
path="${this.details.sourceUrl}"
version="${this._versionUrl}"
.permissions=${this.permissions}
@proseloaded=${this.handleEditorLoaded}
@versionreset=${this.handleReset}>
</da-editor>
${this._editorLoaded ? html`
<div class="da-editor-tabs">
<div class="da-editor-tabs-full">
<button class="da-editor-tab show-preview" title="Preview" @click=${this.showPreview}>Preview</button>
</div>
<div class="da-editor-tabs-quiet">
<button class="da-editor-tab quiet show-versions" title="Versions" @click=${this.showVersions}>Versions</button>
</div>
</div>
</div>
` : nothing}
</div>
<da-preview path=${this.details.previewUrl}></da-preview>
<da-versions path=${this.details.fullpath} @preview=${this.handlePreview} @close=${this.handleCloseVersions}></da-versions>
${this._editorLoaded ? html`<da-preview path=${this.details.previewUrl}></da-preview>` : nothing}
${this._editorLoaded ? html`<da-versions path=${this.details.fullpath} @preview=${this.handlePreview} @close=${this.handleCloseVersions}></da-versions>` : nothing}
`;
}
}
Expand Down
44 changes: 12 additions & 32 deletions blocks/edit/da-editor/da-editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export default class DaEditor extends LitElement {
static properties = {
path: { type: String },
version: { type: String },
permissions: { state: true },
_imsLoaded: { state: false },
_versionDom: { state: true },
};
Expand All @@ -35,6 +36,7 @@ export default class DaEditor extends LitElement {
}

async fetchVersion() {
this._versionDom = null;
const resp = await daFetch(this.version);
if (!resp.ok) return;
const text = await resp.text();
Expand Down Expand Up @@ -80,47 +82,25 @@ export default class DaEditor extends LitElement {
}

render() {
if (this.version && !this._versionDom) this.fetchVersion();
if (!this._imsLoaded) return null;
return html`
<div class="da-prose-mirror"></div>
${this._versionDom ? this.renderVersion() : nothing}
`;
}

async getPermissions() {
const resp = await daFetch(this.path, { method: 'HEAD' });

const daActions = resp.headers.get('X-da-actions');
if (!daActions) return [];
const actions = daActions.split('=');
if (actions) {
return actions[1].split(',');
}
return [];
}

async updated(props) {
if (!this._imsLoaded) return;
if (!(props.has('version') || props.has('_versionDom'))) {
this.disconnectWebsocket();
const prose = this.shadowRoot.querySelector('.da-prose-mirror');
prose.innerHTML = '';

const permissions = await this.getPermissions();
this.wsProvider = initProse({ editor: prose, path: this.path, permissions });
if (props.has('version') && this.version) {
this.fetchVersion();
}

const titleEl = this.ownerDocument.querySelector('da-title')?.shadowRoot?.querySelector('.da-title-inner');
const verBtn = this.parentElement.querySelector('button.show-versions');
// Do not setup prosemirror until we know the permissions
if (props.has('permissions')) {
if (this.path && this.permissions) {
this.disconnectWebsocket();
const editor = this.shadowRoot.querySelector('.da-prose-mirror');
editor.innerHTML = '';

titleEl.classList.remove('da-title-readonly');
prose.classList.remove('da-prose-mirror-readonly');
prose.querySelector('.ProseMirror')?.setAttribute('contenteditable', permissions.includes('write'));
verBtn.removeAttribute('disabled');
if (!permissions.includes('write')) {
titleEl.classList.add('da-title-readonly');
prose.classList.add('da-prose-mirror-readonly');
verBtn.setAttribute('disabled', '');
this.wsProvider = initProse({ editor, path: this.path, permissions: this.permissions });
}
}
}
Expand Down
29 changes: 12 additions & 17 deletions blocks/edit/da-preview/da-preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,6 @@ export default class DaPreview extends LitElement {
body: { state: true },
};

constructor() {
super();
this.channel = new MessageChannel();
this.port1 = this.channel.port1;
this.parent = document.querySelector('da-content');
}

connectedCallback() {
super.connectedCallback();
this.shadowRoot.adoptedStyleSheets = [sheet];
Expand All @@ -41,7 +34,7 @@ export default class DaPreview extends LitElement {
}

hidePreview() {
this.parent.classList.remove('show-preview');
this._daContent.classList.remove('show-preview');
this.classList.remove('show-preview');
}

Expand All @@ -59,16 +52,20 @@ export default class DaPreview extends LitElement {
}

iframeLoaded({ target }) {
this.setWidth('mobile');
const channel = new MessageChannel();
this.port1 = channel.port1;
this.port2 = channel.port2;

this.port1.onmessage = (e) => { this.setHeight(e.data); };

// Delay so the initial loading of the document can complete.
setTimeout(() => {
target.contentWindow.postMessage({ init: true }, '*', [this.channel.port2]);
this.port1.onmessage = (e) => { this.setHeight(e.data); };
target.contentWindow.postMessage({ init: true }, '*', [this.port2]);
}, 1500);
}

get _daContent() {
return document.querySelector('da-content');
}

render() {
return html`
<div class="da-preview-menubar">
Expand All @@ -88,11 +85,9 @@ export default class DaPreview extends LitElement {
}

updated(props) {
super.updated(props);
this.iframe ??= this.shadowRoot.querySelector('iframe');
props.forEach((oldValue, propName) => {
if (propName === 'body') this.setBody();
});
if (props.has('body')) this.setBody();
super.updated(props);
}
}

Expand Down
14 changes: 11 additions & 3 deletions blocks/edit/da-title/da-title.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
}

h1 {
position: relative;
margin-top: 0;
}

Expand Down Expand Up @@ -39,9 +40,16 @@ h1 {
align-items: end;
}

.da-title-readonly h1::after {
content: ' 🔒';
font-size: 0.8em;
.da-title-inner.is-read-only h1::before {
display: block;
content: '';
position: absolute;
width: 18px;
height: 18px;
top: 50%;
left: -36px;
background: url(/blocks/edit/img/Smock_LockClosed_18_N.svg) center center / 18px no-repeat;
transform: translateY(-50%);
}

.da-title-name-label {
Expand Down
8 changes: 7 additions & 1 deletion blocks/edit/da-title/da-title.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const CLOUD_ICONS = {
export default class DaTitle extends LitElement {
static properties = {
details: { attribute: false },
permissions: { attribute: false },
collabStatus: { attribute: false },
collabUsers: { attribute: false },
_actionsVis: {},
Expand Down Expand Up @@ -92,6 +93,11 @@ export default class DaTitle extends LitElement {
this._actionsVis = !this._actionsVis;
}

get _readOnly() {
if (!this.permissions) return false;
return !this.permissions.some((permission) => permission === 'write');
}

renderSave() {
return html`
<button
Expand Down Expand Up @@ -149,7 +155,7 @@ export default class DaTitle extends LitElement {

render() {
return html`
<div class="da-title-inner">
<div class="da-title-inner ${this._readOnly ? 'is-read-only' : ''}">
<div class="da-title-name">
<a
href="/#${this.details.parent}"
Expand Down
47 changes: 33 additions & 14 deletions blocks/edit/edit.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,51 @@
import getPathDetails from '../shared/pathDetails.js';
import './da-title/da-title.js';

async function setUI(el) {
el.innerHTML = '';
async function setUI(el, utils) {
const details = getPathDetails();
if (!details) {
el.classList.add('no-url');
el.innerHTML = '<h1>Please edit a page.</h1>';
return;
}

document.title = `Edit ${details.name} - DA`;

// Title Pane
const daTitle = document.createElement('da-title');
daTitle.details = details;
el.append(daTitle);
// Title area
let daTitle = document.querySelector('da-title');
if (!daTitle) {
daTitle = document.createElement('da-title');
daTitle.details = details;
el.append(daTitle);
} else {
daTitle.details = details;
}

// Content area
let daContent = document.querySelector('da-content');
if (!daContent) {
daContent = document.createElement('da-content');
daContent.details = details;
el.append(daContent);
} else {
daContent.details = details;
}

// Content Pane
await import('./da-content/da-content.js');
const daContent = document.createElement('da-content');
daContent.details = details;
el.append(daContent);
const { daFetch } = await utils;
const { permissions } = await daFetch(details.sourceUrl, { method: 'HEAD' });
daTitle.permissions = permissions;
daContent.permissions = permissions;
}

export default async function init(el) {
setUI(el);
const utils = import('../shared/utils.js');
const title = import('./da-title/da-title.js');
const content = import('./da-content/da-content.js');

await Promise.all([utils, title, content]);

setUI(el, utils);

window.addEventListener('hashchange', () => {
setUI(el);
setUI(el, utils);
});
}
11 changes: 11 additions & 0 deletions blocks/edit/img/Smock_LockClosed_18_N.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 6e4cbb1

Please sign in to comment.