Browse Source

Small bug fixes and improvements (#6067)

* If storage is not defined exit before triggering storage start

* Fix duplicate assets when added with the same `src`

* Add layer delegate to Component

* Enable test on keyframes

* Up ParserCss test

* Fix format
pull/6068/head
Artur Arseniev 1 year ago
committed by GitHub
parent
commit
b3d4c47e68
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      README.md
  2. 8
      src/dom_components/model/types.ts
  3. 3
      src/domain_abstract/model/TypeableCollection.ts
  4. 16
      src/navigator/index.ts
  5. 9
      src/navigator/view/ItemsView.ts
  6. 4
      src/storage_manager/index.ts
  7. 21
      test/specs/css_composer/index.ts
  8. 3
      test/specs/parser/model/ParserCss.ts

2
README.md

@ -5,6 +5,8 @@
[![CDNJS](https://img.shields.io/cdnjs/v/grapesjs.svg)](https://cdnjs.com/libraries/grapesjs) [![CDNJS](https://img.shields.io/cdnjs/v/grapesjs.svg)](https://cdnjs.com/libraries/grapesjs)
[![npm](https://img.shields.io/npm/v/grapesjs.svg)](https://www.npmjs.com/package/grapesjs) [![npm](https://img.shields.io/npm/v/grapesjs.svg)](https://www.npmjs.com/package/grapesjs)
> If you looking to embed the [Studio](https://app.grapesjs.com/studio) editor in your application, we now offer the [Studio SDK](https://app.grapesjs.com/dashboard/sdk/licenses?ref=repo-readme), a ready-to-use visual builder that's easy to embed in external applications, with GrapesJS team support included.
<p align="center"><img src="http://grapesjs.com/assets/images/grapesjs-front-page-m.jpg" alt="GrapesJS" width="500" align="center"/></p> <p align="center"><img src="http://grapesjs.com/assets/images/grapesjs-front-page-m.jpg" alt="GrapesJS" width="500" align="center"/></p>
GrapesJS is a free and open source Web Builder Framework which helps building HTML templates, faster and easily, to be delivered in sites, newsletters or mobile apps. Mainly, GrapesJS was designed to be used inside a [CMS] to speed up the creation of dynamic templates. To better understand this concept check the image below GrapesJS is a free and open source Web Builder Framework which helps building HTML templates, faster and easily, to be delivered in sites, newsletters or mobile apps. Mainly, GrapesJS was designed to be used inside a [CMS] to speed up the creation of dynamic templates. To better understand this concept check the image below

8
src/dom_components/model/types.ts

@ -65,6 +65,14 @@ export interface ComponentDelegateProps {
* } * }
*/ */
select?: (cmp: Component) => Component | Nullable; select?: (cmp: Component) => Component | Nullable;
/**
* Delegate another component as a layer in the LayerManager.
* @example
* delegate: {
* layer: (cmp) => cmp.findType('other-type')[0],
* }
*/
layer?: (cmp: Component) => Component | Nullable;
} }
export interface ComponentProperties { export interface ComponentProperties {

3
src/domain_abstract/model/TypeableCollection.ts

@ -27,6 +27,9 @@ const TypeableCollection = {
const model = new Model(attrs, { ...options, em }); const model = new Model(attrs, { ...options, em });
model.typeView = View; model.typeView = View;
// As we're using a dynamic model function, backbone collection is unable to
// get `model.prototype.idAttribute`
this.model.prototype = Model.prototype;
return model; return model;
}; };
const init = this.init && this.init.bind(this); const init = this.init && this.init.bind(this);

16
src/navigator/index.ts

@ -127,9 +127,10 @@ export default class LayerManager extends Module<LayerManagerConfig> {
root = wrapper.find(component)[0] || wrapper; root = wrapper.find(component)[0] || wrapper;
} }
this.model.set('root', root); const result = this.__getLayerFromComponent(root);
this.model.set('root', result);
return root; return result;
} }
/** /**
@ -152,7 +153,10 @@ export default class LayerManager extends Module<LayerManagerConfig> {
* console.log(components); * console.log(components);
*/ */
getComponents(component: Component): Component[] { getComponents(component: Component): Component[] {
return component.components().filter((cmp: any) => this.__isLayerable(cmp)); return component
.components()
.map((cmp) => this.__getLayerFromComponent(cmp))
.filter((cmp: any) => this.__isLayerable(cmp));
} }
/** /**
@ -360,12 +364,16 @@ export default class LayerManager extends Module<LayerManagerConfig> {
this.__trgCustom(); this.__trgCustom();
} }
__getLayerFromComponent(cmp: Component) {
return cmp.delegate?.layer?.(cmp) || cmp;
}
__onComponent(component: Component) { __onComponent(component: Component) {
this.updateLayer(component); this.updateLayer(component);
} }
__isLayerable(cmp: Component): boolean { __isLayerable(cmp: Component): boolean {
const tag = cmp.get('tagName'); const tag = cmp.tagName;
const hideText = this.config.hideTextnode; const hideText = this.config.hideTextnode;
const isValid = !hideText || (!cmp.isInstanceOf('textnode') && tag !== 'br'); const isValid = !hideText || (!cmp.isInstanceOf('textnode') && tag !== 'br');

9
src/navigator/view/ItemsView.ts

@ -4,12 +4,14 @@ import Component from '../../dom_components/model/Component';
import EditorModel from '../../editor/model/Editor'; import EditorModel from '../../editor/model/Editor';
import ItemView from './ItemView'; import ItemView from './ItemView';
import Components from '../../dom_components/model/Components'; import Components from '../../dom_components/model/Components';
import LayerManager from '..';
export default class ItemsView extends View { export default class ItemsView extends View {
items: ItemView[]; items: ItemView[];
opt: any; opt: any;
config: any; config: any;
parentView: ItemView; parentView: ItemView;
module: LayerManager;
/** @ts-ignore */ /** @ts-ignore */
collection!: Components; collection!: Components;
@ -19,6 +21,7 @@ export default class ItemsView extends View {
this.opt = opt; this.opt = opt;
const config = opt.config || {}; const config = opt.config || {};
this.config = config; this.config = config;
this.module = opt.module;
this.parentView = opt.parentView; this.parentView = opt.parentView;
const pfx = config.stylePrefix || ''; const pfx = config.stylePrefix || '';
const ppfx = config.pStylePrefix || ''; const ppfx = config.pStylePrefix || '';
@ -128,10 +131,12 @@ export default class ItemsView extends View {
} }
render() { render() {
const { el, module } = this;
const frag = document.createDocumentFragment(); const frag = document.createDocumentFragment();
const el = this.el;
el.innerHTML = ''; el.innerHTML = '';
this.collection.each((model) => this.addToCollection(model, frag)); this.collection
.map((cmp) => module.__getLayerFromComponent(cmp))
.forEach((model) => this.addToCollection(model, frag));
el.appendChild(frag); el.appendChild(frag);
el.className = this.className!; el.className = this.className!;
return this; return this;

4
src/storage_manager/index.ts

@ -270,12 +270,12 @@ export default class StorageManager extends Module<
const { onStore, onLoad } = this.getConfig(); const { onStore, onLoad } = this.getConfig();
let result; let result;
this.onStart(ev, data);
if (!storage) { if (!storage) {
return data || {}; return data || {};
} }
this.onStart(ev, data);
try { try {
const editor = this.em?.getEditor(); const editor = this.em?.getEditor();
let response: any; let response: any;

21
test/specs/css_composer/index.ts

@ -418,8 +418,7 @@ describe('Css Composer', () => {
expect(getCSS(obj)).toEqual(cssRule.trim()); expect(getCSS(obj)).toEqual(cssRule.trim());
}); });
// TODO update jest to be able to test keyframes test('Add rules with @keyframes at rule', () => {
test.skip('Add rules with @keyframes at rule', () => {
const cssRule = ` const cssRule = `
@keyframes keyname { @keyframes keyname {
from { width: 0% } from { width: 0% }
@ -428,14 +427,24 @@ describe('Css Composer', () => {
} }
`; `;
const result = obj.addCollection(cssRule); const result = obj.addCollection(cssRule);
console.log({ result });
const [rule1, rule2, rule3] = result; const [rule1, rule2, rule3] = result;
console.log({ result: JSON.parse(JSON.stringify(rule1)) });
expect(result.length).toEqual(3); expect(result.length).toEqual(3);
expect(obj.getAll().length).toEqual(3); expect(obj.getAll().length).toEqual(3);
expect(rule1.get('mediaText')).toBe('keyname'); result.forEach((rule) => {
expect(rule1.get('atRuleType')).toBe('keyframes'); expect(rule.get('mediaText')).toBe('keyname');
// TODO to complete expect(rule.get('atRuleType')).toBe('keyframes');
});
expect(rule1.getSelectorsString()).toBe('from');
expect(rule1.getStyle()).toEqual({ width: '0%' });
expect(rule2.getSelectorsString()).toBe('40%, 50%');
expect(rule2.getStyle()).toEqual({ width: '50%' });
expect(rule3.getSelectorsString()).toBe('to');
expect(rule3.getStyle()).toEqual({ width: '100%' });
}); });
}); });
}); });

3
test/specs/parser/model/ParserCss.ts

@ -251,8 +251,7 @@ describe('ParserCss', () => {
expect(obj.parse(str)).toEqual([result]); expect(obj.parse(str)).toEqual([result]);
}); });
// Can't test keyframes https://github.com/NV/CSSOM/issues/95 test('Parse rule with a keyframes at-rule', () => {
test.skip('Parse rule with a keyframes at-rule', () => {
var str = `@keyframes { var str = `@keyframes {
from {opacity: 0;} from {opacity: 0;}
to {opacity: 1;} to {opacity: 1;}

Loading…
Cancel
Save