Browse Source

Merge branch 'GrapesJS:dev' into dev

pull/5719/head
Brian Ernesto 2 years ago
committed by GitHub
parent
commit
a424617dc6
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 77
      docs/api/assets.md
  2. 149
      src/asset_manager/index.ts
  3. 95
      src/asset_manager/types.ts
  4. 11
      src/asset_manager/view/FileUploader.ts
  5. 2
      src/block_manager/model/Block.ts
  6. 2
      src/canvas/model/Canvas.ts
  7. 3
      src/editor/index.ts
  8. 6
      src/pages/index.ts
  9. 11
      src/pages/types.ts
  10. 23
      test/specs/pages/index.ts
  11. 6
      yarn.lock

77
docs/api/assets.md

@ -19,18 +19,71 @@ const assetManager = editor.AssetManager;
```
## Available Events
* `asset:add` New asset added to the collection. The [Asset] is passed as an argument to the callback.
* `asset:open` - Asset Manager opened.
* `asset:close` - Asset Manager closed.
* `asset:add` - Asset added. The [Asset] is passed as an argument to the callback.
* `asset:remove` - Asset removed. The [Asset] is passed as an argument to the callback.
* `asset:update` - Asset updated. The updated [Asset] and the object containing changes are passed as arguments to the callback.
* `asset:upload:start` - Before the upload is started.
* `asset:upload:end` - After the upload is ended.
* `asset:upload:error` - On any error in upload, passes the error as an argument.
* `asset:upload:response` - On upload response, passes the result as an argument.
* `asset` - Catch-all event for all the events mentioned above. An object containing all the available data about the triggered event is passed as an argument to the callback.
* `asset:custom` - Event for handling custom Asset Manager UI.
```javascript
editor.on('asset:add', (asset) => { ... });
```
* `asset:remove` Asset removed from the collection. The [Asset] is passed as an argument to the callback.
```javascript
editor.on('asset:remove', (asset) => { ... });
```
* `asset:update` Asset updated. The [Asset] and the object containing changes are passed as arguments to the callback.
```javascript
editor.on('asset:update', (asset, updatedProps) => { ... });
```
* `asset:open` Asset Manager opened.
```javascript
editor.on('asset:open', () => { ... });
```
* `asset:close` Asset Manager closed.
```javascript
editor.on('asset:close', () => { ... });
```
* `asset:upload:start` Asset upload start.
```javascript
editor.on('asset:upload:start', () => { ... });
```
* `asset:upload:end` Asset upload end.
```javascript
editor.on('asset:upload:end', (result) => { ... });
```
* `asset:upload:error` Asset upload error.
```javascript
editor.on('asset:upload:error', (error) => { ... });
```
* `asset:upload:response` Asset upload response.
```javascript
editor.on('asset:upload:response', (res) => { ... });
```
* `asset:custom` Event to use in case of [custom Asset Manager UI](https://grapesjs.com/docs/modules/Assets.html#customization).
```javascript
editor.on('asset:custom', ({ container, assets, ... }) => { ... });
```
* `asset` Catch-all event for all the events mentioned above. An object containing all the available data about the triggered event is passed as an argument to the callback.
```javascript
editor.on('asset', ({ event, model, ... }) => { ... });
```
## Methods
@ -160,7 +213,7 @@ Remove asset
### Parameters
* `asset` **([String][13] | [Asset])** Asset or asset URL
* `opts` **Record<[string][13], any>?**
* `opts` **RemoveOptions?**
### Examples

149
src/asset_manager/index.ts

@ -14,18 +14,7 @@
* const assetManager = editor.AssetManager;
* ```
*
* ## Available Events
* * `asset:open` - Asset Manager opened.
* * `asset:close` - Asset Manager closed.
* * `asset:add` - Asset added. The [Asset] is passed as an argument to the callback.
* * `asset:remove` - Asset removed. The [Asset] is passed as an argument to the callback.
* * `asset:update` - Asset updated. The updated [Asset] and the object containing changes are passed as arguments to the callback.
* * `asset:upload:start` - Before the upload is started.
* * `asset:upload:end` - After the upload is ended.
* * `asset:upload:error` - On any error in upload, passes the error as an argument.
* * `asset:upload:response` - On upload response, passes the result as an argument.
* * `asset` - Catch-all event for all the events mentioned above. An object containing all the available data about the triggered event is passed as an argument to the callback.
* * `asset:custom` - Event for handling custom Asset Manager UI.
* {REPLACE_EVENTS}
*
* ## Methods
* * [open](#open)
@ -45,67 +34,20 @@
import { debounce, isFunction } from 'underscore';
import { ItemManagerModule } from '../abstract/Module';
import { AddOptions, RemoveOptions } from '../common';
import EditorModel from '../editor/model/Editor';
import { ProjectData } from '../storage_manager';
import defaults, { AssetManagerConfig } from './config/config';
import Asset from './model/Asset';
import Assets from './model/Assets';
import AssetsEvents, { AssetOpenOptions } from './types';
import AssetsView from './view/AssetsView';
import FileUploaderView from './view/FileUploader';
export type AssetEvent =
| 'asset'
| 'asset:open'
| 'asset:close'
| 'asset:add'
| 'asset:remove'
| 'asset:update'
| 'asset:custom'
| 'asset:upload:start'
| 'asset:upload:end'
| 'asset:upload:error'
| 'asset:upload:response';
export const evAll = 'asset';
export const evPfx = `${evAll}:`;
export const evSelect = `${evPfx}select`;
export const evUpdate = `${evPfx}update`;
export const evAdd = `${evPfx}add`;
export const evRemove = `${evPfx}remove`;
export const evRemoveBefore = `${evRemove}:before`;
export const evCustom = `${evPfx}custom`;
export const evOpen = `${evPfx}open`;
export const evClose = `${evPfx}close`;
export const evUpload = `${evPfx}upload`;
export const evUploadStart = `${evUpload}:start`;
export const evUploadEnd = `${evUpload}:end`;
export const evUploadError = `${evUpload}:error`;
export const evUploadRes = `${evUpload}:response`;
const assetCmd = 'open-assets';
const assetEvents = {
all: evAll,
select: evSelect,
update: evUpdate,
add: evAdd,
remove: evRemove,
removeBefore: evRemoveBefore,
custom: evCustom,
open: evOpen,
close: evClose,
uploadStart: evUploadStart,
uploadEnd: evUploadEnd,
uploadError: evUploadError,
uploadResponse: evUploadRes,
};
// TODO
type AssetProps = Record<string, any>;
type OpenOptions = {
select?: (asset: Asset, complete: boolean) => void;
types?: string[];
accept?: string;
target?: any;
};
const assetCmd = 'open-assets';
export default class AssetManager extends ItemManagerModule<AssetManagerConfig, Assets> {
storageKey = 'assets';
@ -115,7 +57,7 @@ export default class AssetManager extends ItemManagerModule<AssetManagerConfig,
am?: AssetsView;
fu?: FileUploaderView;
_bhv?: any;
events!: typeof assetEvents;
events = AssetsEvents;
/**
* Initialize module
@ -124,11 +66,10 @@ export default class AssetManager extends ItemManagerModule<AssetManagerConfig,
*/
constructor(em: EditorModel) {
// @ts-ignore
super(em, 'AssetManager', new Assets([], em), assetEvents, defaults);
super(em, 'AssetManager', new Assets([], em), AssetsEvents, defaults);
const { all, config } = this;
// @ts-ignore
this.assetsVis = new Assets([]);
// @ts-ignore
const ppfx = config.pStylePrefix;
if (ppfx) {
config.stylePrefix = `${ppfx}${config.stylePrefix}`;
@ -143,40 +84,6 @@ export default class AssetManager extends ItemManagerModule<AssetManagerConfig,
return this;
}
__propEv(ev: string, ...data: any[]) {
this.em.trigger(ev, ...data);
this.getAll().trigger(ev, ...data);
}
__trgCustom() {
const bhv = this.__getBehaviour();
const custom = this.getConfig().custom;
if (!bhv.container && !(custom as any).open) {
return;
}
this.em.trigger(this.events.custom, this.__customData());
}
__customData() {
const bhv = this.__getBehaviour();
return {
am: this as AssetManager,
open: this.isOpen(),
assets: this.getAll().models,
types: bhv.types || [],
container: bhv.container,
close: () => this.close(),
remove: (asset: string | Asset, opts?: Record<string, any>) => this.remove(asset, opts),
select: (asset: Asset, complete: boolean) => {
const res = this.add(asset);
isFunction(bhv.select) && bhv.select(res, complete);
},
// extra
options: bhv.options || {},
};
}
/**
* Open the asset manager.
* @param {Object} [options] Options for the asset manager.
@ -197,7 +104,7 @@ export default class AssetManager extends ItemManagerModule<AssetManagerConfig,
* // with your custom types (you should have assets with those types declared)
* assetManager.open({ types: ['doc'], ... });
*/
open(options: OpenOptions = {}) {
open(options: AssetOpenOptions = {}) {
const cmd = this.em.Commands;
cmd.run(assetCmd, {
types: ['image'],
@ -246,7 +153,7 @@ export default class AssetManager extends ItemManagerModule<AssetManagerConfig,
* });
* assetManager.add([{ src: 'img2.jpg' }, { src: 'img2.png' }]);
*/
add(asset: string | AssetProps | (string | AssetProps)[], opts: Record<string, any> = {}) {
add(asset: string | AssetProps | (string | AssetProps)[], opts: AddOptions = {}) {
// Put the model at the beginning
if (typeof opts.at == 'undefined') {
opts.at = 0;
@ -292,7 +199,7 @@ export default class AssetManager extends ItemManagerModule<AssetManagerConfig,
* const asset = assetManager.get('http://img.jpg');
* assetManager.remove(asset);
*/
remove(asset: string | Asset, opts?: Record<string, any>) {
remove(asset: string | Asset, opts?: RemoveOptions) {
return this.__remove(asset, opts);
}
@ -300,7 +207,7 @@ export default class AssetManager extends ItemManagerModule<AssetManagerConfig,
return this.getProjectData();
}
load(data: Record<string, any>) {
load(data: ProjectData) {
return this.loadProjectData(data);
}
@ -462,6 +369,40 @@ export default class AssetManager extends ItemManagerModule<AssetManagerConfig,
this.config.onDblClick = func;
}
__propEv(ev: string, ...data: any[]) {
this.em.trigger(ev, ...data);
this.getAll().trigger(ev, ...data);
}
__trgCustom() {
const bhv = this.__getBehaviour();
const custom = this.getConfig().custom;
if (!bhv.container && !(custom as any).open) {
return;
}
this.em.trigger(this.events.custom, this.__customData());
}
__customData() {
const bhv = this.__getBehaviour();
return {
am: this as AssetManager,
open: this.isOpen(),
assets: this.getAll().models,
types: bhv.types || [],
container: bhv.container,
close: () => this.close(),
remove: (asset: string | Asset, opts?: Record<string, any>) => this.remove(asset, opts),
select: (asset: Asset, complete: boolean) => {
const res = this.add(asset);
isFunction(bhv.select) && bhv.select(res, complete);
},
// extra
options: bhv.options || {},
};
}
__behaviour(opts = {}) {
return (this._bhv = {
...(this._bhv || {}),

95
src/asset_manager/types.ts

@ -0,0 +1,95 @@
import Asset from './model/Asset';
export type AssetEvent = `${AssetsEvents}`;
export interface AssetOpenOptions {
select?: (asset: Asset, complete: boolean) => void;
types?: string[];
accept?: string;
target?: any;
}
/**{START_EVENTS}*/
export enum AssetsEvents {
/**
* @event `asset:add` New asset added to the collection. The [Asset] is passed as an argument to the callback.
* @example
* editor.on('asset:add', (asset) => { ... });
*/
add = 'asset:add',
/**
* @event `asset:remove` Asset removed from the collection. The [Asset] is passed as an argument to the callback.
* @example
* editor.on('asset:remove', (asset) => { ... });
*/
remove = 'asset:remove',
removeBefore = 'asset:remove:before',
/**
* @event `asset:update` Asset updated. The [Asset] and the object containing changes are passed as arguments to the callback.
* @example
* editor.on('asset:update', (asset, updatedProps) => { ... });
*/
update = 'asset:update',
/**
* @event `asset:open` Asset Manager opened.
* @example
* editor.on('asset:open', () => { ... });
*/
open = 'asset:open',
/**
* @event `asset:close` Asset Manager closed.
* @example
* editor.on('asset:close', () => { ... });
*/
close = 'asset:close',
/**
* @event `asset:upload:start` Asset upload start.
* @example
* editor.on('asset:upload:start', () => { ... });
*/
uploadStart = 'asset:upload:start',
/**
* @event `asset:upload:end` Asset upload end.
* @example
* editor.on('asset:upload:end', (result) => { ... });
*/
uploadEnd = 'asset:upload:end',
/**
* @event `asset:upload:error` Asset upload error.
* @example
* editor.on('asset:upload:error', (error) => { ... });
*/
uploadError = 'asset:upload:error',
/**
* @event `asset:upload:response` Asset upload response.
* @example
* editor.on('asset:upload:response', (res) => { ... });
*/
uploadResponse = 'asset:upload:response',
/**
* @event `asset:custom` Event to use in case of [custom Asset Manager UI](https://grapesjs.com/docs/modules/Assets.html#customization).
* @example
* editor.on('asset:custom', ({ container, assets, ... }) => { ... });
*/
custom = 'asset:custom',
/**
* @event `asset` Catch-all event for all the events mentioned above. An object containing all the available data about the triggered event is passed as an argument to the callback.
* @example
* editor.on('asset', ({ event, model, ... }) => { ... });
*/
all = 'asset',
}
/**{END_EVENTS}*/
// need this to avoid the TS documentation generator to break
export default AssetsEvents;

11
src/asset_manager/view/FileUploader.ts

@ -1,3 +1,4 @@
import AssetManager from '..';
import { View } from '../../common';
import EditorModel from '../../editor/model/Editor';
import fetch from '../../utils/fetch';
@ -18,7 +19,7 @@ export default class FileUploaderView extends View {
pfx: string;
ppfx: string;
em: EditorModel;
module: any;
module: AssetManager;
target: any;
uploadId: string;
disabled: boolean;
@ -80,7 +81,7 @@ export default class FileUploaderView extends View {
*/
onUploadStart() {
const { module } = this;
module && module.__propEv('asset:upload:start');
module?.__propEv(module.events.uploadStart);
}
/**
@ -90,7 +91,7 @@ export default class FileUploaderView extends View {
*/
onUploadEnd(res: any) {
const { $el, module } = this;
module && module.__propEv('asset:upload:end', res);
module?.__propEv(module.events.uploadEnd, res);
const input = $el.find('input');
input && input.val('');
}
@ -104,7 +105,7 @@ export default class FileUploaderView extends View {
const { module } = this;
console.error(err);
this.onUploadEnd(err);
module && module.__propEv('asset:upload:error', err);
module?.__propEv(module.events.uploadError, err);
}
/**
@ -121,7 +122,7 @@ export default class FileUploaderView extends View {
json = text;
}
module && module.__propEv('asset:upload:response', json);
module?.__propEv(module.events.uploadResponse, json);
if (config.autoAdd && target) {
target.add(json.data, { at: 0 });

2
src/block_manager/model/Block.ts

@ -14,7 +14,7 @@ export interface BlockProperties {
/**
* The content of the block. Might be an HTML string or a [Component Defintion](/modules/Components.html#component-definition)
*/
content: string | ComponentDefinition;
content: string | ComponentDefinition | (string | ComponentDefinition)[];
/**
* HTML string for the media/icon of the block, eg. `<svg ...`, `<img ...`, etc.
* @default ''

2
src/canvas/model/Canvas.ts

@ -42,7 +42,7 @@ export default class Canvas extends ModuleModel<CanvasModule> {
init() {
const { em } = this;
const mainPage = em.Pages.getMain();
const mainPage = em.Pages._initPage();
this.set('frames', mainPage.getFrames());
this.updateDevice({ frame: mainPage.getMainFrame() });
}

3
src/editor/index.ts

@ -55,7 +55,8 @@
* @module docsjs.Editor
*/
import { IBaseModule } from '../abstract/Module';
import AssetManager, { AssetEvent } from '../asset_manager';
import AssetManager from '../asset_manager';
import { AssetEvent } from '../asset_manager/types';
import BlockManager, { BlockEvent } from '../block_manager';
import CanvasModule, { CanvasEvent } from '../canvas';
import CodeManagerModule from '../code_manager';

6
src/pages/index.ts

@ -93,7 +93,7 @@ export default class PageManager extends ItemManagerModule<PageManagerConfig, Pa
const opt = { silent: true };
const configPages = config.pages?.map(page => new Page(page, { em, config })) || [];
pages.add(configPages, opt);
const mainPage = !pages.length ? this.add({ type: typeMain }, opt) : this.getMain();
const mainPage = !pages.length ? this.add({ type: typeMain }, opt) : this._initPage();
mainPage && this.select(mainPage, opt);
}
@ -242,6 +242,10 @@ export default class PageManager extends ItemManagerModule<PageManagerConfig, Pa
return result;
}
_initPage() {
return this.get(this.config.selected!) || this.getMain();
}
_createId() {
const pages = this.getAll();
const len = pages.length + 16;

11
src/pages/types.ts

@ -1,7 +1,16 @@
import { ModuleConfig } from '../abstract/Module';
import { PageProperties } from './model/Page';
export interface PageManagerConfig extends ModuleConfig {
pages?: any[];
/**
* Default pages.
*/
pages?: PageProperties[];
/**
* ID of the page to select on editor load.
*/
selected?: string;
}
export interface SelectableOption {

23
test/specs/pages/index.ts

@ -1,6 +1,7 @@
import { ComponentDefinition } from '../../../src/dom_components/model/types';
import Editor from '../../../src/editor';
import EditorModel from '../../../src/editor/model/Editor';
import { PageProperties } from '../../../src/pages/model/Page';
describe('Pages', () => {
let editor: Editor;
@ -70,7 +71,7 @@ describe('Pages', () => {
let idComp2 = 'comp2';
let comp1: ComponentDefinition;
let comp2: ComponentDefinition;
let initPages;
let initPages: PageProperties[];
let allbyId: ReturnType<Editor['Components']['allById']>;
const createCompDef = (id: string): ComponentDefinition => ({
@ -116,8 +117,8 @@ describe('Pages', () => {
},
});
em = editor.getModel();
domc = em.get('DomComponents');
pm = em.get('PageManager');
domc = em.Components;
pm = em.Pages;
pm.onLoad();
allbyId = domc.allById();
initCmpLen = Object.keys(allbyId).length;
@ -145,7 +146,21 @@ describe('Pages', () => {
// Number of wrappers (eg. 3) where each one containes 1 component and 1 textnode (3 * 3)
expect(initCmpLen).toBe(initPages.length * 3);
// Each page contains 1 rule per component
expect(em.get('CssComposer').getAll().length).toBe(initPages.length);
expect(em.Css.getAll().length).toBe(initPages.length);
});
test('Change initial selected page', () => {
const selected = 'page-3';
editor = new Editor({
pageManager: {
pages: initPages,
selected,
},
});
pm = editor.getModel().Pages;
pm.onLoad();
pm.getSelected();
expect(pm.getSelected()?.id).toBe(selected);
});
});
});

6
yarn.lock

@ -6258,9 +6258,9 @@ fn-name@~2.0.1:
integrity sha512-oIDB1rXf3BUnn00bh2jVM0byuqr94rBh6g7ZfdKcbmp1we2GQtPzKdloyvBXHs+q3fvxB8EqX5ecFba3RwCSjA==
follow-redirects@^1.0.0:
version "1.15.4"
resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz#cdc7d308bf6493126b17ea2191ea0ccf3e535adf"
integrity sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==
version "1.15.6"
resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b"
integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==
for-each@^0.3.3:
version "0.3.3"

Loading…
Cancel
Save