Skip to content

Commit b2789a6

Browse files
authored
Refactor LayerManager (GrapesJS#4338)
* Move Layers to TS * Update root update in LayerManager. Closes GrapesJS#4083 * Update Layer view * Update ItemsView * Move layer opened container * Clean ItemView * Update import ItemsView * Update layer manager module * Add getComponents to Layers * Add visibility methods to Layers * Add locked check in Layers * Add locked property to Component * Add rename in LayerManager * Up layer listeners * Update layer selection * Update children counter in ItemView * Update visibility methods in ItemView * Add open methods to layers * Update selection * Update hover in layers * Fix layer * Update TS model in LayerManager * Layer config TS * Move ItemView to TS * Move ItemsView to TS * Update TS LayerManager * Update Module and Layers init * Update layer tests * Up item view
1 parent 5f2b3a0 commit b2789a6

File tree

10 files changed

+543
-374
lines changed

10 files changed

+543
-374
lines changed

src/abstract/Module.ts

+27-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { isElement, isUndefined } from 'underscore';
22
import { Collection, View } from '../common';
33
import EditorModel from '../editor/model/Editor';
4-
import { createId, isDef } from '../utils/mixins';
4+
import { createId, isDef, deepMerge } from '../utils/mixins';
55

66
export interface IModule<TConfig extends any = any>
77
extends IBaseModule<TConfig> {
@@ -20,8 +20,9 @@ export interface IBaseModule<TConfig extends any> {
2020
}
2121

2222
export interface ModuleConfig {
23-
name: string;
23+
name?: string;
2424
stylePrefix?: string;
25+
appendTo?: string;
2526
}
2627

2728
export interface IStorableModule extends IModule {
@@ -39,8 +40,10 @@ export default abstract class Module<T extends ModuleConfig = ModuleConfig>
3940
private _name: string;
4041
cls: any[] = [];
4142
events: any;
43+
model?: any;
44+
view?: any;
4245

43-
constructor(em: EditorModel, moduleName: string) {
46+
constructor(em: EditorModel, moduleName: string, defaults?: T) {
4447
this._em = em;
4548
this._name = moduleName;
4649
const name = this.name.charAt(0).toLowerCase() + this.name.slice(1);
@@ -53,7 +56,9 @@ export default abstract class Module<T extends ModuleConfig = ModuleConfig>
5356
if (!isUndefined(cfgParent) && !cfgParent) {
5457
cfg._disable = 1;
5558
}
56-
this._config = cfg;
59+
60+
cfg.em = em;
61+
this._config = deepMerge(defaults || {}, cfg) as T;
5762
}
5863

5964
public get em() {
@@ -65,8 +70,9 @@ export default abstract class Module<T extends ModuleConfig = ModuleConfig>
6570
//abstract name: string;
6671
isPrivate: boolean = false;
6772
onLoad?(): void;
68-
init(cfg: any) {}
73+
init(cfg: T) {}
6974
abstract destroy(): void;
75+
abstract render(): HTMLElement;
7076
postLoad(key: any): void {}
7177

7278
get name(): string {
@@ -83,6 +89,20 @@ export default abstract class Module<T extends ModuleConfig = ModuleConfig>
8389
}
8490

8591
postRender?(view: any): void;
92+
93+
/**
94+
* Move the main DOM element of the module.
95+
* To execute only post editor render (in postRender)
96+
*/
97+
__appendTo() {
98+
const elTo = this.getConfig().appendTo;
99+
100+
if (elTo) {
101+
const el = isElement(elTo) ? elTo : document.querySelector(elTo);
102+
if (!el) return this.__logWarn('"appendTo" element not found');
103+
el.appendChild(this.render());
104+
}
105+
}
86106
}
87107

88108
export abstract class ItemManagerModule<
@@ -105,6 +125,7 @@ export abstract class ItemManagerModule<
105125
abstract storageKey: string;
106126
abstract destroy(): void;
107127
postLoad(key: any): void {}
128+
// @ts-ignore
108129
render() {}
109130

110131
getProjectData(data?: any) {
@@ -215,6 +236,7 @@ export abstract class ItemManagerModule<
215236
if (elTo) {
216237
const el = isElement(elTo) ? elTo : document.querySelector(elTo);
217238
if (!el) return this.__logWarn('"appendTo" element not found');
239+
// @ts-ignore
218240
el.appendChild(this.render());
219241
}
220242
}

src/dom_components/model/Component.js

+3
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ export const keyUpdateInside = `${keyUpdate}-inside`;
7373
* @property {Boolean} [layerable=true] Set to `false` if you need to hide the component inside Layers. Default: `true`
7474
* @property {Boolean} [selectable=true] Allow component to be selected when clicked. Default: `true`
7575
* @property {Boolean} [hoverable=true] Shows a highlight outline when hovering on the element if `true`. Default: `true`
76+
* @property {Boolean} [locked=false] Disable the selection of the component and its children in the canvas. Default: `false`
7677
* @property {Boolean} [void=false] This property is used by the HTML exporter as void elements don't have closing tags, eg. `<br/>`, `<hr/>`, etc. Default: `false`
7778
* @property {Object} [style={}] Component default style, eg. `{ width: '100px', height: '100px', 'background-color': 'red' }`
7879
* @property {String} [styles=''] Component related styles, eg. `.my-component-class { color: red }`
@@ -202,6 +203,7 @@ export default class Component extends StyleableModel {
202203

203204
__onChange(m, opts) {
204205
const changed = this.changedAttributes();
206+
keys(changed).forEach(prop => this.emitUpdate(prop));
205207
['status', 'open', 'toolbar', 'traits'].forEach(name => delete changed[name]);
206208
// Propagate component prop changes
207209
if (!isEmptyObj(changed)) {
@@ -1963,6 +1965,7 @@ Component.prototype.defaults = {
19631965
layerable: true,
19641966
selectable: true,
19651967
hoverable: true,
1968+
locked: false,
19661969
void: false,
19671970
state: '', // Indicates if the component is in some CSS state like ':hover', ':active', etc.
19681971
status: '', // State, eg. 'selected'

src/dom_components/view/ComponentView.js

+16-15
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export default class ComponentView extends Backbone.View {
3232
this.listenTo(model, 'change:style', this.updateStyle);
3333
this.listenTo(model, 'change:attributes', this.renderAttributes);
3434
this.listenTo(model, 'change:highlightable', this.updateHighlight);
35-
this.listenTo(model, 'change:status', this.updateStatus);
35+
this.listenTo(model, 'change:status change:locked', this.updateStatus);
3636
this.listenTo(model, 'change:script rerender', this.reset);
3737
this.listenTo(model, 'change:content', this.updateContent);
3838
this.listenTo(model, 'change', this.handleChange);
@@ -177,41 +177,42 @@ export default class ComponentView extends Backbone.View {
177177
* @private
178178
* */
179179
updateStatus(opts = {}) {
180-
const { em } = this;
180+
const { em, el, ppfx, model } = this;
181181
const { extHl } = em ? em.get('Canvas').getConfig() : {};
182-
const el = this.el;
183-
const status = this.model.get('status');
184-
const ppfx = this.ppfx;
182+
const status = model.get('status');
185183
const selectedCls = `${ppfx}selected`;
186184
const selectedParentCls = `${selectedCls}-parent`;
187185
const freezedCls = `${ppfx}freezed`;
188186
const hoveredCls = `${ppfx}hovered`;
189-
const toRemove = [selectedCls, selectedParentCls, freezedCls, hoveredCls];
187+
const noPointerCls = `${ppfx}no-pointer`;
188+
const toRemove = [selectedCls, selectedParentCls, freezedCls, hoveredCls, noPointerCls];
190189
const selCls = extHl && !opts.noExtHl ? '' : selectedCls;
191190
this.$el.removeClass(toRemove.join(' '));
192-
var actualCls = el.getAttribute('class') || '';
193-
var cls = '';
191+
const actualCls = el.getAttribute('class') || '';
192+
const cls = [actualCls];
194193

195194
switch (status) {
196195
case 'selected':
197-
cls = `${actualCls} ${selCls}`;
196+
cls.push(selCls);
198197
break;
199198
case 'selected-parent':
200-
cls = `${actualCls} ${selectedParentCls}`;
199+
cls.push(selectedParentCls);
201200
break;
202201
case 'freezed':
203-
cls = `${actualCls} ${freezedCls}`;
202+
cls.push(freezedCls);
204203
break;
205204
case 'freezed-selected':
206-
cls = `${actualCls} ${freezedCls} ${selCls}`;
205+
cls.push(freezedCls, selCls);
207206
break;
208207
case 'hovered':
209-
cls = !opts.avoidHover ? `${actualCls} ${hoveredCls}` : '';
208+
!opts.avoidHover && cls.push(hoveredCls);
210209
break;
211210
}
212211

213-
cls = cls.trim();
214-
cls && el.setAttribute('class', cls);
212+
model.get('locked') && cls.push(noPointerCls);
213+
214+
const clsStr = cls.filter(Boolean).join(' ');
215+
clsStr && el.setAttribute('class', clsStr);
215216
}
216217

217218
/**

src/modal_dialog/config/config.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ export default {
44
title: '',
55

66
content: '',
7-
8-
// Close modal on interact with backdrop
7+
8+
// Close modal on interact with backdrop
99
backdrop: true,
1010

1111
// Avoid rendering the default modal.

src/navigator/config/config.js renamed to src/navigator/config/config.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,23 @@ export default {
66
appendTo: '',
77

88
// Enable/Disable globally the possibility to sort layers
9-
sortable: 1,
9+
sortable: true,
1010

1111
// Enable/Disable globally the possibility to hide layers
12-
hidable: 1,
12+
hidable: true,
1313

1414
// Hide textnodes
15-
hideTextnode: 1,
15+
hideTextnode: true,
1616

1717
// Indicate a query string of the element to be selected as the root of layers.
1818
// By default the root is the wrapper
1919
root: '',
2020

2121
// Indicates if the wrapper is visible in layers
22-
showWrapper: 1,
22+
showWrapper: true,
2323

2424
// Show hovered components in canvas
25-
showHover: 1,
25+
showHover: true,
2626

2727
// Scroll to selected component in Canvas when it's selected in Layers
2828
// true, false or `scrollIntoView`-like options,
@@ -34,7 +34,7 @@ export default {
3434
scrollLayers: { behavior: 'auto', block: 'nearest' },
3535

3636
// Highlight when a layer component is hovered
37-
highlightHover: 1,
37+
highlightHover: true,
3838

3939
/**
4040
* WARNING: Experimental option

src/navigator/index.js

-108
This file was deleted.

0 commit comments

Comments
 (0)