From cc100bd0c1047d2a9fc54fcc22848af133c995bc Mon Sep 17 00:00:00 2001 From: Alex Hoyau Date: Fri, 11 Oct 2024 11:51:52 +0300 Subject: [PATCH] more events for plugins --- src/ts/client/events.ts | 11 +- src/ts/client/grapesjs/PublicationManager.ts | 35 ++++-- src/ts/client/grapesjs/PublicationUi.ts | 120 ++++++++++--------- src/ts/client/grapesjs/index.ts | 2 +- src/ts/client/grapesjs/storage.ts | 2 +- 5 files changed, 97 insertions(+), 73 deletions(-) diff --git a/src/ts/client/events.ts b/src/ts/client/events.ts index 88f8c43b8..104c131fd 100644 --- a/src/ts/client/events.ts +++ b/src/ts/client/events.ts @@ -23,12 +23,15 @@ export enum ClientEvent { GRAPESJS_END = 'silex:grapesjs:end', /* GrapesJS is ready to be used, `editor` is passed as an argument */ // Sent on GrapesJs editor object (returned by silex.getEditor()) - PUBLISH_START = 'silex:publish:start', /* Publication starts, you can read+write {projectData, siteSettings} */ - PUBLISH_PAGE = 'silex:publish:page', /* Publication of a page, read+write { siteSettings, pageSettings, page } */ - PUBLISH_DATA = 'silex:publish:data', /* Just before we send the published data to the server, read+write all publication data, check PublicationData type in types.ts */ + PUBLICATION_UI_OPEN = 'silex:publication-ui:open', /* The publication UI is opened, you can access it with { publicationUi } */ + PUBLICATION_UI_CLOSE = 'silex:publication-ui:close', /* The publication UI is closed, you can access it with { publicationUi } */ + PUBLISH_BEFORE = 'silex:publish:before', /* Publication is about to start, you can read+write {projectData, siteSettings} */ + PUBLISH_START = 'silex:publish:start', /* Publication starts, you can read+write project data/settings, use publication manager/ui, prevent publication {projectData, siteSettings, publicationManager, prenventDefault} */ + PUBLISH_PAGE = 'silex:publish:page', /* Publication of a page, read+write settings and page data, use publication manager and prevent publication { siteSettings, pageSettings, page, publicationManager, preventDefault } */ + PUBLISH_DATA = 'silex:publish:data', /* Just before we send the published data to the server, read+write all publication data, check PublicationData type in types.ts { data, publicationManager } */ PUBLISH_END = 'silex:publish:end', /* Publication is over, the argument is the publication result with {success: boolean, message: string} */ PUBLISH_ERROR = 'silex:publish:error', /* Publication failed, the argument is the publication result with {success: boolean, message: string} */ - PUBLISH_LOGIN_START = 'silex:publish:login:start', + PUBLISH_LOGIN_START = 'silex:publish:login:start', /* The user is about to login before publication, you can read+write connector data and use publication manager and prevent publication {connector, publicationManager, preventDefault} */ PUBLISH_LOGIN_END = 'silex:publish:login:end', ASSET_WRITE_END = 'silex:asset:write:end', WRITE_END = 'silex:write:end', diff --git a/src/ts/client/grapesjs/PublicationManager.ts b/src/ts/client/grapesjs/PublicationManager.ts index 2ea399018..ccc3ab086 100644 --- a/src/ts/client/grapesjs/PublicationManager.ts +++ b/src/ts/client/grapesjs/PublicationManager.ts @@ -152,6 +152,13 @@ export class PublicationManager { } async goLogin(connector: ConnectorData) { + let preventDefault = false + this.editor.trigger(ClientEvent.PUBLISH_LOGIN_START, { connector, publicationManager: this, preventDefault: () => preventDefault = true }) + if(preventDefault) { + this.status = PublicationStatus.STATUS_NONE + this.dialog && this.dialog.displayPending(this.job, this.status) + return + } // Check if the user is already logged in if(connector.isLoggedIn) { this.settings = { @@ -216,12 +223,12 @@ export class PublicationManager { } } - async getPublicationData(projectData, siteSettings): Promise { + async getPublicationData(projectData, siteSettings, preventDefault: () => void): Promise { // Data to publish // See assetUrl.ts which is a default transformer, always present this.setPublicationTransformers() // Build the files structure - const files: ClientSideFile[] = (await this.getHtmlFiles(siteSettings)) + const files: ClientSideFile[] = (await this.getHtmlFiles(siteSettings, preventDefault)) .flatMap(file => ([{ path: file.htmlPath, // Already "transformed" in getHtmlFiles content: file.html, @@ -267,7 +274,7 @@ export class PublicationManager { this.resetPublicationTransformers() // Let plugins transform the data transformFiles(this.editor, data) - this.editor.trigger(ClientEvent.PUBLISH_DATA, data) + this.editor.trigger(ClientEvent.PUBLISH_DATA, { data, preventDefault, publicationManager: this }) // Return the data return data } @@ -285,15 +292,27 @@ export class PublicationManager { // Get the data to publish, clone the objects because plugins can change it const projectData = { ...this.editor.getProjectData() as WebsiteData } const siteSettings = { ...this.editor.getModel().get('settings') as WebsiteSettings } - this.editor.trigger(ClientEvent.PUBLISH_START, {projectData, siteSettings}) + let preventDefaultStart = false + this.editor.trigger(ClientEvent.PUBLISH_START, {projectData, siteSettings, preventDefault: () => preventDefaultStart = true, publicationManager: this }) + if(preventDefaultStart) { + this.status = PublicationStatus.STATUS_NONE + this.dialog && this.dialog.displayPending(this.job, this.status) + return + } + // Get the data to publish + let preventDefaultData = false + const data = await this.getPublicationData(projectData, siteSettings, () => preventDefaultData = true) + if(preventDefaultData) { + this.status = PublicationStatus.STATUS_NONE + this.dialog && this.dialog.displayPending(this.job, this.status) + return + } // User and where to publish const storageUser = this.editor.getModel().get('user') as ConnectorUser if(!storageUser) throw new Error('User not logged in to a storage connector') if(!this.settings.connector?.connectorId) throw new Error('User not logged in to a hosting connector') const websiteId = this.options.websiteId const storageId = storageUser.storage.connectorId - // Get the data to publish - const data = await this.getPublicationData(projectData, siteSettings) // Use the publication API const [url, job] = await publish({ websiteId, @@ -326,7 +345,7 @@ export class PublicationManager { } } - async getHtmlFiles(siteSettings: WebsiteSettings): Promise { + async getHtmlFiles(siteSettings: WebsiteSettings, preventDefault): Promise { return Promise.all(this.editor.Pages.getAll().map(async page => { // Clone the settings because plugins can change them siteSettings = { ...siteSettings } @@ -352,7 +371,7 @@ export class PublicationManager { const htmlPath = transformPath(this.editor, htmlInitialPath, ClientSideFileType.HTML) // Let plugins transform the data - this.editor.trigger(ClientEvent.PUBLISH_PAGE, { page, siteSettings, pageSettings }) + this.editor.trigger(ClientEvent.PUBLISH_PAGE, { page, siteSettings, pageSettings, preventDefault, publicationManager: this }) // Useful data for HTML result const title = getSetting('title') diff --git a/src/ts/client/grapesjs/PublicationUi.ts b/src/ts/client/grapesjs/PublicationUi.ts index a3c7e859d..29a7308af 100644 --- a/src/ts/client/grapesjs/PublicationUi.ts +++ b/src/ts/client/grapesjs/PublicationUi.ts @@ -23,6 +23,7 @@ import { ConnectorData, ConnectorType, PublicationJobData, PublicationSettings } import { connectorList } from '../api' import { defaultKms } from './keymaps' import { titleCase } from '../utils' +import { ClientEvent } from '../events' /** * @fileoverview define the publication dialog @@ -120,12 +121,9 @@ export class PublicationUi { // ** // Functions to open and close the dialog - getDialogElements(): { el: HTMLElement, primary: HTMLElement, secondary: HTMLElement } { - const el = document.querySelector('#publish-dialog') as HTMLElement - const primary = el?.querySelector('#publish-button--primary') as HTMLElement - const secondary = el?.querySelector('#publish-button--secondary') as HTMLElement - if(!el || !primary || !secondary) throw new Error('Publication dialog elements not found') - return { el, primary, secondary } + userContent: TemplateResult | null = null + setUserContent(content: TemplateResult) { + this.userContent = content } createDialogElements(): HTMLElement { // Create the dialog element @@ -182,59 +180,61 @@ export class PublicationUi { `}
- ${this.isPending(status) ? html` -

Publication in progress...

- ` : ''} - ${this.isReady(status) ? html` -

Click on the button below to publish your website.

- ${this.settings.options && Object.entries(this.settings.options).length && html`

Publication options:

    ${ Object.entries(this.settings.options).map(([key, value]) => html`
  • ${key}: ${value}
  • `) }

`} - ` : ''} - ${this.isSuccess(status) ? html` -

Publication success ${unsafeHTML(svgSuccess)}

- ${this.settings.options?.websiteUrl ? html`

Click here to view the published website

` : ''} - ` : ''} - ${this.isError(status) || this.isLoggedOut(status) ? html` -

Publication error ${unsafeHTML(svgError)}

-
- Details - ${unsafeHTML(this.errorMessage)} -
- ` : ''} - ${job?.message ? html` -
- Details - ${unsafeHTML(job.message)} -
- ` : ''} - ${this.isPending(status) ? html` - - ` : ''} - ${job?.logs?.length && job.logs[0].length ? html` -
- Logs -
${unsafeHTML(cleanupLogEntry(job.logs))}
-
- ` : ''} - ${job?.errors?.length && job.errors[0].length ? html` -
- Errors -
${unsafeHTML(cleanupLogEntry(job.errors))}
-          
-
- ` : ''} - ${this.isPending(status) || this.isLoggedOut(status) ? '' : html` - + ${this.userContent || html` + ${this.isPending(status) ? html` +

Publication in progress...

+ ` : ''} + ${this.isReady(status) ? html` +

Click on the button below to publish your website.

+ ${this.settings.options && Object.entries(this.settings.options).length && html`

Publication options:

    ${ Object.entries(this.settings.options).map(([key, value]) => html`
  • ${key}: ${value}
  • `) }

`} + ` : ''} + ${this.isSuccess(status) ? html` +

Publication success ${unsafeHTML(svgSuccess)}

+ ${this.settings.options?.websiteUrl ? html`

Click here to view the published website

` : ''} + ` : ''} + ${this.isError(status) || this.isLoggedOut(status) ? html` +

Publication error ${unsafeHTML(svgError)}

+
+ Details + ${unsafeHTML(this.errorMessage)} +
+ ` : ''} + ${job?.message ? html` +
+ Details + ${unsafeHTML(job.message)} +
+ ` : ''} + ${this.isPending(status) ? html` + + ` : ''} + ${job?.logs?.length && job.logs[0].length ? html` +
+ Logs +
${unsafeHTML(cleanupLogEntry(job.logs))}
+
+ ` : ''} + ${job?.errors?.length && job.errors[0].length ? html` +
+ Errors +
${unsafeHTML(cleanupLogEntry(job.errors))}
+            
+
+ ` : ''} + ${this.isPending(status) || this.isLoggedOut(status) ? '' : html` + + `} `}