Browse Source

Add skipFromStorage support to page and frames

improve-page-frames
Artur Arseniev 2 months ago
parent
commit
60868c1fe1
  1. 19
      packages/core/src/canvas/model/Frame.ts
  2. 4
      packages/core/src/canvas/model/Frames.ts
  3. 2
      packages/core/src/pages/index.ts
  4. 23
      packages/core/src/pages/model/Page.ts
  5. 125
      packages/core/test/specs/pages/index.ts

19
packages/core/src/canvas/model/Frame.ts

@ -3,6 +3,7 @@ import CanvasModule from '..';
import { ModuleModel } from '../../abstract'; import { ModuleModel } from '../../abstract';
import { BoxRect, PrevToNewIdMap } from '../../common'; import { BoxRect, PrevToNewIdMap } from '../../common';
import ComponentWrapper from '../../dom_components/model/ComponentWrapper'; import ComponentWrapper from '../../dom_components/model/ComponentWrapper';
import { ComponentDefinition } from '../../dom_components/model/types';
import Page from '../../pages/model/Page'; import Page from '../../pages/model/Page';
import { createId, isComponent, isObject } from '../../utils/mixins'; import { createId, isComponent, isObject } from '../../utils/mixins';
import FrameView from '../view/FrameView'; import FrameView from '../view/FrameView';
@ -13,6 +14,21 @@ import CanvasEvents from '../types';
const keyAutoW = '__aw'; const keyAutoW = '__aw';
const keyAutoH = '__ah'; const keyAutoH = '__ah';
export interface FrameProperties {
id?: string;
component?: string | ComponentDefinition | ComponentDefinition[] | ComponentWrapper;
width?: string | number | null;
height?: string | number | null;
x?: number;
y?: number;
attributes?: Record<string, unknown>;
head?: { tag: string; attributes: any }[];
styles?: string | CssRuleJSON[];
refFrame?: string | Frame | null;
skipFromStorage?: boolean;
[key: string]: unknown;
}
const getDimension = (frame: Frame, type: 'width' | 'height') => { const getDimension = (frame: Frame, type: 'width' | 'height') => {
const dim = frame.get(type); const dim = frame.get(type);
const viewDim = frame.view?.el[type === 'width' ? 'offsetWidth' : 'offsetHeight']; const viewDim = frame.view?.el[type === 'width' ? 'offsetWidth' : 'offsetHeight'];
@ -58,7 +74,7 @@ export default class Frame extends ModuleModel<CanvasModule> {
/** /**
* @hideconstructor * @hideconstructor
*/ */
constructor(module: CanvasModule, attr: any) { constructor(module: CanvasModule, attr: FrameProperties) {
super(module, attr); super(module, attr);
const { em } = this; const { em } = this;
const { styles, component } = this.attributes; const { styles, component } = this.attributes;
@ -254,6 +270,7 @@ export default class Frame extends ModuleModel<CanvasModule> {
const defaults = result(this, 'defaults'); const defaults = result(this, 'defaults');
if (opts.fromUndo) delete obj.component; if (opts.fromUndo) delete obj.component;
delete obj.skipFromStorage;
delete obj.styles; delete obj.styles;
delete obj.changesCount; delete obj.changesCount;
obj[keyAutoW] && delete obj.width; obj[keyAutoW] && delete obj.width;

4
packages/core/src/canvas/model/Frames.ts

@ -36,6 +36,10 @@ export default class Frames extends ModuleCollection<Frame> {
this.forEach((frame) => frame.initRefs()); this.forEach((frame) => frame.initRefs());
} }
toJSON(opts?: Parameters<Frame['toJSON']>[0]) {
return this.filter((frame) => !frame.get('skipFromStorage')).map((frame) => frame.toJSON(opts));
}
itemLoaded() { itemLoaded() {
this.loadedItems++; this.loadedItems++;

2
packages/core/src/pages/index.ts

@ -276,7 +276,7 @@ export default class PageManager extends ItemManagerModule<PageManagerConfig, Pa
} }
store() { store() {
return this.getProjectData(); return this.getProjectData(this.getAll().filter((page) => !page.get('skipFromStorage')));
} }
load(data: any) { load(data: any) {

23
packages/core/src/pages/model/Page.ts

@ -1,5 +1,6 @@
import { forEach, result } from 'underscore'; import { forEach, result } from 'underscore';
import { PageManagerConfig } from '../types'; import { PageManagerConfig } from '../types';
import type { FrameProperties } from '../../canvas/model/Frame';
import Frames from '../../canvas/model/Frames'; import Frames from '../../canvas/model/Frames';
import { Model } from '../../common'; import { Model } from '../../common';
import ComponentWrapper from '../../dom_components/model/ComponentWrapper'; import ComponentWrapper from '../../dom_components/model/ComponentWrapper';
@ -29,10 +30,20 @@ export interface PageProperties {
*/ */
styles?: string | CssRuleJSON[]; styles?: string | CssRuleJSON[];
/**
* Frames to load with the page.
*/
frames?: FrameProperties[];
/**
* Skip page from project storage.
*/
skipFromStorage?: boolean;
[key: string]: unknown; [key: string]: unknown;
} }
export interface PagePropertiesDefined extends Pick<PageProperties, 'id' | 'name'> { export interface PagePropertiesDefined extends Pick<PageProperties, 'id' | 'name' | 'skipFromStorage'> {
frames: Frames; frames: Frames;
[key: string]: unknown; [key: string]: unknown;
} }
@ -47,17 +58,17 @@ export default class Page extends Model<PagePropertiesDefined> {
} }
em: EditorModel; em: EditorModel;
constructor(props: any, opts: { em?: EditorModel; config?: PageManagerConfig } = {}) { constructor(props: PageProperties, opts: { em?: EditorModel; config?: PageManagerConfig } = {}) {
super(props, opts); super(props as any, opts);
const { em } = opts; const { em } = opts;
const defFrame: any = {}; const defFrame: FrameProperties = {};
this.em = em!; this.em = em!;
if (!props.frames) { if (!props.frames) {
defFrame.component = props.component; defFrame.component = props.component;
defFrame.styles = props.styles; defFrame.styles = props.styles;
['component', 'styles'].map((i) => this.unset(i)); ['component', 'styles'].map((i) => this.unset(i));
} }
const frms: any[] = props.frames || [defFrame]; const frms: FrameProperties[] = props.frames || [defFrame];
const frames = new Frames(em!.Canvas, frms); const frames = new Frames(em!.Canvas, frms);
frames.page = this; frames.page = this;
this.set('frames', frames); this.set('frames', frames);
@ -135,6 +146,8 @@ export default class Page extends Model<PagePropertiesDefined> {
const obj = Model.prototype.toJSON.call(this, opts); const obj = Model.prototype.toJSON.call(this, opts);
const defaults = result(this, 'defaults'); const defaults = result(this, 'defaults');
delete obj.skipFromStorage;
// Remove private keys // Remove private keys
forEach(obj, (value, key) => { forEach(obj, (value, key) => {
key.indexOf('_') === 0 && delete obj[key]; key.indexOf('_') === 0 && delete obj[key];

125
packages/core/test/specs/pages/index.ts

@ -281,6 +281,131 @@ describe('Managing pages', () => {
expect(rule2.getSelectorsString()).toBe(idSel2); expect(rule2.getSelectorsString()).toBe(idSel2);
expect(rule2.getStyle()).toEqual({ color: 'blue' }); expect(rule2.getStyle()).toEqual({ color: 'blue' });
}); });
test('Skip pages from project storage while keeping runtime models', () => {
const storedPage = pm.add({
id: 'stored-page',
component: '<div>Stored page</div>',
})!;
const skippedPage = pm.add({
id: 'skipped-page',
skipFromStorage: true,
frames: [
{
id: 'skipped-page-frame',
component: '<div>Skipped page frame</div>',
},
],
})!;
const storedPage2 = pm.add({
id: 'stored-page-2',
component: '<div>Stored page 2</div>',
})!;
expect(pm.getAll().map((page) => page.getId())).toEqual([
pm.getMain().getId(),
storedPage.getId(),
skippedPage.getId(),
storedPage2.getId(),
]);
expect(skippedPage.getFrames().length).toBe(1);
const storedPages = editor.getProjectData().pages;
expect(storedPages.map((page: any) => page.id)).toEqual([
pm.getMain().getId(),
storedPage.getId(),
storedPage2.getId(),
]);
expect(storedPages.find((page: any) => page.id === skippedPage.getId())).toBeUndefined();
expect(storedPages.every((page: any) => !('skipFromStorage' in page))).toBe(true);
});
test('Skip frames from project storage while keeping runtime models', () => {
const page = pm.add({
id: 'frames-page',
frames: [
{
id: 'frame-1',
component: '<div>Frame 1</div>',
},
{
id: 'frame-2',
component: '<div>Frame 2</div>',
skipFromStorage: true,
},
{
id: 'frame-3',
component: '<div>Frame 3</div>',
},
],
})!;
expect(page.getFrames().map((frame) => frame.id)).toEqual(['frame-1', 'frame-2', 'frame-3']);
const storedPage = editor.getProjectData().pages.find((item: any) => item.id === page.getId());
expect(storedPage.frames.map((frame: any) => frame.id)).toEqual(['frame-1', 'frame-3']);
expect(storedPage.frames.every((frame: any) => !('skipFromStorage' in frame))).toBe(true);
expect(storedPage.frames[0].component).toBeTruthy();
expect(storedPage.frames[1].component).toBeTruthy();
});
test('Load project data with skipped pages and frames but omit them on the next store', () => {
editor.loadProjectData({
assets: [],
pages: [
{
id: 'page-stored',
frames: [
{
id: 'frame-stored',
component: '<div>Stored frame</div>',
},
{
id: 'frame-skipped',
component: '<div>Skipped frame</div>',
skipFromStorage: true,
},
],
},
{
id: 'page-skipped',
skipFromStorage: true,
frames: [
{
id: 'frame-on-skipped-page',
component: '<div>Skipped page frame</div>',
},
],
},
],
styles: [],
} as any);
expect(pm.getAll().map((page) => page.getId())).toEqual(['page-stored', 'page-skipped']);
expect(pm.get('page-stored')?.getFrames().map((frame) => frame.id)).toEqual(['frame-stored', 'frame-skipped']);
expect(pm.get('page-skipped')?.getFrames().map((frame) => frame.id)).toEqual(['frame-on-skipped-page']);
const storedPages = editor.getProjectData().pages;
expect(storedPages.map((page: any) => page.id)).toEqual(['page-stored']);
expect(storedPages[0].frames.map((frame: any) => frame.id)).toEqual(['frame-stored']);
});
test('Do not leak skipFromStorage in direct page/frame serialization', () => {
const page = pm.add({
id: 'serialized-page',
skipFromStorage: false,
frames: [
{
id: 'serialized-frame',
component: '<div>Serialized frame</div>',
skipFromStorage: false,
},
],
})!;
expect(page.toJSON()).not.toHaveProperty('skipFromStorage');
expect(page.getMainFrame().toJSON()).not.toHaveProperty('skipFromStorage');
});
}); });
describe('Pages in canvas', () => { describe('Pages in canvas', () => {

Loading…
Cancel
Save