diff --git a/docs-site/src/pages/pattern-lab/_patterns/04-pages/60-editor/10-editor-1.twig b/docs-site/src/pages/pattern-lab/_patterns/04-pages/60-editor/10-editor-1.twig index ac7224daf4..2859b48c4e 100644 --- a/docs-site/src/pages/pattern-lab/_patterns/04-pages/60-editor/10-editor-1.twig +++ b/docs-site/src/pages/pattern-lab/_patterns/04-pages/60-editor/10-editor-1.twig @@ -1,6 +1,12 @@
+
@@ -96,6 +102,12 @@
+
diff --git a/packages/editor/src/editor.js b/packages/editor/src/editor.js index f1c0064e64..2e4cc52aaf 100644 --- a/packages/editor/src/editor.js +++ b/packages/editor/src/editor.js @@ -18,13 +18,15 @@ function addGrapesCssToPage() { } /** - * @param {HTMLElement} space - * @param {HTMLElement} uiWrapper + * @param {Object} opt + * @param {HTMLElement} opt.space + * @param {HTMLElement} opt.uiWrapper + * @param {BoltEditorConfig} opt.config * @return {grapesjs.Editor} */ -export function enableEditor(space, uiWrapper) { +export function enableEditor({ space, uiWrapper, config }) { addGrapesCssToPage(); - /** @type {{[key: string]: HTMLElement}} */ + /** @type {{ [key: string]: HTMLElement }} */ const editorSlots = { buttons: uiWrapper.querySelector('.pega-editor-ui__slot--buttons'), layers: uiWrapper.querySelector('.pega-editor-ui__slot--layers'), @@ -33,40 +35,12 @@ export function enableEditor(space, uiWrapper) { }; const stylePrefix = 'pega-editor-'; - /** - * CSS files to add to editor iframe - * @type {string[]} - */ - const styles = []; - - /** - * JS files to add to editor iframe - * @type {string[]} - */ - const scripts = []; - - for (let i = 0; i < document.styleSheets.length; i++) { - const styleSheet = document.styleSheets[i]; - if (styleSheet.ownerNode instanceof window.HTMLLinkElement) { - // eslint-disable-next-line - const ownerNode = /** @type {HTMLLinkElement} */ (styleSheet.ownerNode); - - const isLink = ownerNode.tagName === 'LINK'; - if (isLink) { - styles.push(ownerNode.href); - } - } - } - - for (let i = 0; i < document.scripts.length; i++) { - const script = document.scripts[i]; - scripts.push(script.src); - } /** @type {grapesjs.EditorConfig} */ const editorConfig = { container: space, fromElement: true, + autorender: false, // height: '100vh', // width: 'auto', plugins: [setupBolt, setupComponents, setupPanels, setupBlocks], @@ -196,13 +170,23 @@ export function enableEditor(space, uiWrapper) { canvas: { // assigning this overrides the default of `cv-` which prevents the layout styles from hitting it stylePrefix: `${stylePrefix}canvas-`, - styles, - scripts, + styles: config.styles, }, }; const editor = grapesjs.init(editorConfig); + editor.render(); + const canvasDoc = editor.Canvas.getDocument(); + const canvasWindow = editor.Canvas.getWindow(); + + config.scripts.forEach(script => { + const scriptEl = canvasDoc.createElement('script'); + scriptEl.src = script; + canvasDoc.body.appendChild(scriptEl); + }); + // console.log({ canvasDoc, canvasWindow }); + // const { BlockManager, Panels, DomComponents } = editor; window['editor'] = editor; // eslint-disable-line dot-notation diff --git a/packages/editor/src/index.js b/packages/editor/src/index.js index 82d1bfe04c..3963770e3f 100644 --- a/packages/editor/src/index.js +++ b/packages/editor/src/index.js @@ -1,5 +1,7 @@ import { query } from './utils'; +const defaultConfig = {}; + /** * @param {HTMLElement} [appendTo] - HTMLElement to append to * @returns {{ el: HTMLElement, destroy: function(): void }} cleanup function to remove HTML @@ -31,6 +33,7 @@ function init() { }, trigger: '.js-pega-editor__trigger', space: '.js-pega-editor__space', + config: '.js-pega-editor__config', }; const EDITOR_STATES = { @@ -71,6 +74,37 @@ function init() { return; } + const [configEl] = query(selectors.config, pegaEditor); + + if (!configEl) { + console.error( + `Pega editor found no "config" selector "${selectors.config}"`, + { pegaEditor }, + ); + return; + } + + let userConfig; + try { + userConfig = JSON.parse(configEl.innerHTML); + } catch (err) { + console.error('Error parsing user config from this tag', configEl); + return; + } + + /** @type {BoltEditorConfig} */ + const config = Object.assign({}, defaultConfig, userConfig); + + if (!config.styles || config.styles.length === 0) { + console.error('Bolt Editor Config requires "styles" an array of paths to CSS files. Current config is: ', config); + return; + } + + if (!config.scripts || config.scripts.length === 0) { + console.error('Bolt Editor Config requires "scripts" an array of paths to JS files. Current config is: ', config); + return; + } + /** @type {import('grapesjs').Editor} */ let editor; @@ -104,7 +138,7 @@ function init() { uiWrapper = createEditorUiHtml(); // eslint-disable-next-line no-unused-vars - editor = enableEditor(space, uiWrapper.el); + editor = enableEditor({ space, uiWrapper: uiWrapper.el, config }); trigger.innerText = 'Save & Close'; editorState = EDITOR_STATES.OPEN; break; diff --git a/packages/editor/src/index.scss b/packages/editor/src/index.scss index 8769177218..555b0032e0 100644 --- a/packages/editor/src/index.scss +++ b/packages/editor/src/index.scss @@ -4,6 +4,7 @@ right: 0; bottom: 0; left: 0; + z-index: 1000; width: 100vw; height: 30vh; diff --git a/packages/editor/types/grapesjs/index.d.ts b/packages/editor/types/grapesjs/index.d.ts index 6f27660545..dc15c60ab0 100644 --- a/packages/editor/types/grapesjs/index.d.ts +++ b/packages/editor/types/grapesjs/index.d.ts @@ -1,5 +1,10 @@ declare module '*.yml'; +interface BoltEditorConfig { + styles?: string[]; + scripts?: string[]; +} + interface Window { HTMLLinkElement: typeof HTMLLinkElement; } @@ -26,6 +31,8 @@ declare module 'grapesjs' { components?: string; style?: string; fromElement?: boolean; + /** renders editor on init */ + autorender?: boolean; /** Show an alert before unload the page with unsaved changes */ noticeOnUnload?: boolean; showOffsets?: boolean; @@ -86,13 +93,30 @@ declare module 'grapesjs' { BlockManager: BlockManager; Panels: Panels; Modal: Modal; + Canvas: Canvas; getHtml(): string; + getJs(): string; destroy(): void; /** Total unsaved changes */ getDirtyCount(): number; getContainer(): HTMLElement; getComponents(): Array; on(event: GrapesEvent, callback: Function): Editor; + once(event: GrapesEvent, callback: Function): Editor; + /** Returns editor element */ + render(): HTMLElement; + /** Returns editor element */ + getEl(): HTMLElement; + + /** + * Update editor dimensions and refresh data useful for positioning of tools + * + * This method could be useful when you update, for example, some position + * of the editor element (eg. canvas, panels, etc.) with CSS, where without + * refresh you'll get misleading position of tools (eg. rich text editor, + * component highlighter, etc.) + */ + refresh(): void; } interface Panels { @@ -167,6 +191,7 @@ declare module 'grapesjs' { }; }, ): void; + getType(type: string): any; } @@ -181,7 +206,7 @@ declare module 'grapesjs' { attributes?: object; // https://grapesjs.com/docs/modules/Blocks.html#custom-render render?: ({ - model: { }, + model: {}, className: string, el: HTMLElement, }) => string | void; @@ -195,7 +220,7 @@ declare module 'grapesjs' { id?: string; autosave?: boolean; autoload?: boolean; - type?: "local" | "remote" | "null"; + type?: 'local' | 'remote' | 'null'; stepsBeforeSave?: number; storeComponents?: boolean; storeStyles?: boolean; @@ -337,6 +362,19 @@ declare module 'grapesjs' { getContent(): string; } + interface Canvas { + getConfig(): CanvasConfig | object; + getElement(): HTMLElement; + getFrameEl(): HTMLIFrameElement; + getWindow(): Window; + getDocument(): HTMLDocument; + getBody(): HTMLBodyElement; + getWrapperEl(): HTMLElement; + setCustomBadgeLabel(f: Function): void; + hasFocus(): boolean; + // scrollTo(el: HTMLElement | object, opts?: boolean | GrapesScrollIntoViewOptions): void; + } + interface TraitManagerConfig { stylePrefix?: string; appendTo?: HTMLElement;