Skip to content

Commit

Permalink
more events for plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
lexoyo committed Oct 11, 2024
1 parent 336f98d commit cc100bd
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 73 deletions.
11 changes: 7 additions & 4 deletions src/ts/client/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
35 changes: 27 additions & 8 deletions src/ts/client/grapesjs/PublicationManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -216,12 +223,12 @@ export class PublicationManager {
}
}

async getPublicationData(projectData, siteSettings): Promise<PublicationData> {
async getPublicationData(projectData, siteSettings, preventDefault: () => void): Promise<PublicationData> {
// 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,
Expand Down Expand Up @@ -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
}
Expand All @@ -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,
Expand Down Expand Up @@ -326,7 +345,7 @@ export class PublicationManager {
}
}

async getHtmlFiles(siteSettings: WebsiteSettings): Promise<WebsiteFile[]> {
async getHtmlFiles(siteSettings: WebsiteSettings, preventDefault): Promise<WebsiteFile[]> {
return Promise.all(this.editor.Pages.getAll().map(async page => {
// Clone the settings because plugins can change them
siteSettings = { ...siteSettings }
Expand All @@ -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')
Expand Down
120 changes: 61 additions & 59 deletions src/ts/client/grapesjs/PublicationUi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -182,59 +180,61 @@ export class PublicationUi {
</button>`}
</header>
<main>
${this.isPending(status) ? html`
<p>Publication in progress...</p>
` : ''}
${this.isReady(status) ? html`
<p>Click on the button below to publish your website.</p>
${this.settings.options && Object.entries(this.settings.options).length && html`<p>Publication options: <ul>${ Object.entries(this.settings.options).map(([key, value]) => html`<li>${key}: ${value}</li>`) }</ul></p>`}
` : ''}
${this.isSuccess(status) ? html`
<h3 class="status">Publication success ${unsafeHTML(svgSuccess)}</h3>
${this.settings.options?.websiteUrl ? html`<p><a href="${this.settings.options.websiteUrl}" target="_blank">Click here to view the published website</a></p>` : ''}
` : ''}
${this.isError(status) || this.isLoggedOut(status) ? html`
<h3 class="status">Publication error ${unsafeHTML(svgError)}</h3>
<details open>
<summary>Details</summary>
${unsafeHTML(this.errorMessage)}
</details>
` : ''}
${job?.message ? html`
<details open>
<summary>Details</summary>
${unsafeHTML(job.message)}
</details>
` : ''}
${this.isPending(status) ? html`
<progress
value=""
style="width: 100%;"
></progress>
` : ''}
${job?.logs?.length && job.logs[0].length ? html`
<details>
<summary>Logs</summary>
<div class="logs">${unsafeHTML(cleanupLogEntry(job.logs))}</div>
</details>
` : ''}
${job?.errors?.length && job.errors[0].length ? html`
<details>
<summary>Errors</summary>
<pre style="
max-width: 100%;
font-size: x-small;
"
>${unsafeHTML(cleanupLogEntry(job.errors))}
</pre>
</details>
` : ''}
${this.isPending(status) || this.isLoggedOut(status) ? '' : html`
<button
class="silex-button silex-button--primary"
id="publish-button--primary"
@click=${() => this.editor.Commands.run(cmdPublicationStart)}
>Publish</button>
${this.userContent || html`
${this.isPending(status) ? html`
<p>Publication in progress...</p>
` : ''}
${this.isReady(status) ? html`
<p>Click on the button below to publish your website.</p>
${this.settings.options && Object.entries(this.settings.options).length && html`<p>Publication options: <ul>${ Object.entries(this.settings.options).map(([key, value]) => html`<li>${key}: ${value}</li>`) }</ul></p>`}
` : ''}
${this.isSuccess(status) ? html`
<h3 class="status">Publication success ${unsafeHTML(svgSuccess)}</h3>
${this.settings.options?.websiteUrl ? html`<p><a href="${this.settings.options.websiteUrl}" target="_blank">Click here to view the published website</a></p>` : ''}
` : ''}
${this.isError(status) || this.isLoggedOut(status) ? html`
<h3 class="status">Publication error ${unsafeHTML(svgError)}</h3>
<details open>
<summary>Details</summary>
${unsafeHTML(this.errorMessage)}
</details>
` : ''}
${job?.message ? html`
<details open>
<summary>Details</summary>
${unsafeHTML(job.message)}
</details>
` : ''}
${this.isPending(status) ? html`
<progress
value=""
style="width: 100%;"
></progress>
` : ''}
${job?.logs?.length && job.logs[0].length ? html`
<details>
<summary>Logs</summary>
<div class="logs">${unsafeHTML(cleanupLogEntry(job.logs))}</div>
</details>
` : ''}
${job?.errors?.length && job.errors[0].length ? html`
<details>
<summary>Errors</summary>
<pre style="
max-width: 100%;
font-size: x-small;
"
>${unsafeHTML(cleanupLogEntry(job.errors))}
</pre>
</details>
` : ''}
${this.isPending(status) || this.isLoggedOut(status) ? '' : html`
<button
class="silex-button silex-button--primary"
id="publish-button--primary"
@click=${() => this.editor.Commands.run(cmdPublicationStart)}
>Publish</button>
`}
`}
</main>
<footer>
Expand Down Expand Up @@ -331,6 +331,7 @@ export class PublicationUi {
this.sender.set('active', 0)
} // Deactivate the button to make it ready to be clicked again
this.sender = null
this.editor.trigger(ClientEvent.PUBLICATION_UI_CLOSE, { publicationUi: this })
}
async toggleDialog() {
if (this.isOpen) this.closeDialog()
Expand Down Expand Up @@ -360,5 +361,6 @@ export class PublicationUi {
// Publication
//this.editor.Commands.run(cmdPublicationStart)
this.renderDialog(null, PublicationStatus.STATUS_NONE)
this.editor.trigger(ClientEvent.PUBLICATION_UI_OPEN, { publicationUi: this })
}
}
2 changes: 1 addition & 1 deletion src/ts/client/grapesjs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ export async function initEditor(config: EditorConfig) {
() => {
const notificationButton = editor.Panels.getPanel(PROJECT_BAR_PANEL_ID).view?.el.querySelector('.notifications-btn')
;(editor as NotificationEditor)
.NotificationManager.length ? notificationButton?.classList.add('project-bar__dirty') : notificationButton?.classList.remove('project-bar__dirty')
.NotificationManager['length'] ? notificationButton?.classList.add('project-bar__dirty') : notificationButton?.classList.remove('project-bar__dirty')
}
)

Expand Down
2 changes: 1 addition & 1 deletion src/ts/client/grapesjs/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

import { ConnectorId, WebsiteId, WebsiteData, ConnectorUser, ConnectorType, ApiError, Asset, Page, Component, Style } from '../../types'
import { ConnectorId, WebsiteId, WebsiteData, ConnectorUser, ConnectorType, ApiError } from '../../types'
import { websiteLoad, websiteSave } from '../api'
import { cmdLogin, eventLoggedIn, eventLoggedOut, getCurrentUser, updateUser } from './LoginDialog'
import { addTempDataToPages, addTempDataToAssetUrl, addTempDataToStyles, removeTempDataFromAssetUrl, removeTempDataFromPages, removeTempDataFromStyles } from '../assetUrl'
Expand Down

0 comments on commit cc100bd

Please sign in to comment.