Browse Source

Merge branch 'amirrahmani76-dev' into dev

pull/5642/head
Artur Arseniev 2 years ago
parent
commit
f873aeb3f3
  1. 2
      dist/css/grapes.min.css
  2. 8
      src/abstract/ModuleCategories.ts
  3. 12
      src/abstract/ModuleCategory.ts
  4. 41
      src/abstract/ModuleCategoryView.ts
  5. 4
      src/block_manager/index.ts
  6. 4
      src/block_manager/model/Block.ts
  7. 6
      src/block_manager/view/BlocksView.ts
  8. 2
      src/domain_abstract/view/DomainViews.ts
  9. 9
      src/index.ts
  10. 29
      src/styles/scss/_gjs_traits.scss
  11. 42
      src/trait_manager/index.ts
  12. 13
      src/trait_manager/model/Trait.ts
  13. 6
      src/trait_manager/view/TraitView.ts
  14. 138
      src/trait_manager/view/TraitsView.ts

2
dist/css/grapes.min.css

File diff suppressed because one or more lines are too long

8
src/block_manager/model/Categories.ts → src/abstract/ModuleCategories.ts

@ -1,11 +1,11 @@
import { isArray, isString } from 'underscore';
import { AddOptions, Collection } from '../../common';
import { normalizeKey } from '../../utils/mixins';
import Category, { BlockCategoryProperties } from './Category';
import { AddOptions, Collection } from '../common';
import { normalizeKey } from '../utils/mixins';
import Category, { CategoryProperties } from './ModuleCategory';
export default class Categories extends Collection<Category> {
/** @ts-ignore */
add(model: (BlockCategoryProperties | Category)[] | BlockCategoryProperties | Category, opts?: AddOptions) {
add(model: (CategoryProperties | Category)[] | CategoryProperties | Category, opts?: AddOptions) {
const models = isArray(model) ? model : [model];
models.forEach(md => md && (md.id = normalizeKey(`${md.id}`)));
return super.add(model, opts);

12
src/block_manager/model/Category.ts → src/abstract/ModuleCategory.ts

@ -1,7 +1,7 @@
import { Model } from '../../common';
import CategoryView from '../view/CategoryView';
import { Model } from '../common';
import CategoryView from './ModuleCategoryView';
export interface BlockCategoryProperties {
export interface CategoryProperties {
/**
* Category id.
*/
@ -26,7 +26,7 @@ export interface BlockCategoryProperties {
attributes?: Record<string, any>;
}
export default class Category extends Model<BlockCategoryProperties> {
export default class Category extends Model<CategoryProperties> {
view?: CategoryView;
defaults() {
@ -37,4 +37,8 @@ export default class Category extends Model<BlockCategoryProperties> {
attributes: {},
};
}
getId() {
return this.get('id')!;
}
}

41
src/block_manager/view/CategoryView.ts → src/abstract/ModuleCategoryView.ts

@ -1,11 +1,12 @@
import { View } from '../../common';
import EditorModel from '../../editor/model/Editor';
import html from '../../utils/html';
import Category from '../model/Category';
import { View } from '../common';
import EditorModel from '../editor/model/Editor';
import html from '../utils/html';
import Category from './ModuleCategory';
export interface CategoryViewConfig {
em: EditorModel;
pStylePrefix?: string;
stylePrefix?: string;
}
export default class CategoryView extends View<Category> {
@ -17,7 +18,8 @@ export default class CategoryView extends View<Category> {
iconClass: string;
activeClass: string;
iconEl?: HTMLElement;
blocksEl?: HTMLElement;
typeEl?: HTMLElement;
catName: string;
events() {
return {
@ -25,13 +27,13 @@ export default class CategoryView extends View<Category> {
};
}
template({ pfx, label }: { pfx: string; label: string }) {
template({ pfx, label, catName }: { pfx: string; label: string; catName: string }) {
return html`
<div class="${pfx}title" data-title>
<i class="${pfx}caret-icon"></i>
${label}
</div>
<div class="${pfx}blocks-c"></div>
<div class="${pfx}${catName}s-c"></div>
`;
}
@ -40,17 +42,18 @@ export default class CategoryView extends View<Category> {
return this.model.get('attributes') || {};
}
constructor(o: any, config: CategoryViewConfig) {
constructor(o: any, config: CategoryViewConfig, catName: string) {
super(o);
this.config = config;
const pfx = config.pStylePrefix || '';
this.em = config.em;
this.catName = catName;
this.pfx = pfx;
this.caretR = 'fa fa-caret-right';
this.caretD = 'fa fa-caret-down';
this.iconClass = `${pfx}caret-icon`;
this.activeClass = `${pfx}open`;
this.className = `${pfx}block-category`;
this.className = `${pfx}${catName}-category`;
this.listenTo(this.model, 'change:open', this.updateVisibility);
this.model.view = this;
}
@ -63,13 +66,13 @@ export default class CategoryView extends View<Category> {
open() {
this.$el.addClass(this.activeClass);
this.getIconEl()!.className = `${this.iconClass} ${this.caretD}`;
this.getBlocksEl()!.style.display = '';
this.getTypeEl()!.style.display = '';
}
close() {
this.$el.removeClass(this.activeClass);
this.getIconEl()!.className = `${this.iconClass} ${this.caretR}`;
this.getBlocksEl()!.style.display = 'none';
this.getTypeEl()!.style.display = 'none';
}
toggle() {
@ -85,22 +88,22 @@ export default class CategoryView extends View<Category> {
return this.iconEl;
}
getBlocksEl() {
if (!this.blocksEl) {
this.blocksEl = this.el.querySelector(`.${this.pfx}blocks-c`)!;
getTypeEl() {
if (!this.typeEl) {
this.typeEl = this.el.querySelector(`.${this.pfx}${this.catName}s-c`)!;
}
return this.blocksEl;
return this.typeEl;
}
append(el: HTMLElement) {
this.getBlocksEl().appendChild(el);
this.getTypeEl().appendChild(el);
}
render() {
const { em, el, $el, model, pfx } = this;
const label = em.t(`blockManager.categories.${model.id}`) || model.get('label');
el.innerHTML = this.template({ pfx, label });
const { em, el, $el, model, pfx, catName } = this;
const label = em.t(`${catName}Manager.categories.${model.id}`) || model.get('label');
el.innerHTML = this.template({ pfx, label, catName });
$el.addClass(this.className!);
$el.css({ order: model.get('order')! });
this.updateVisibility();

4
src/block_manager/index.ts

@ -34,8 +34,8 @@ import EditorModel from '../editor/model/Editor';
import defaults, { BlockManagerConfig } from './config/config';
import Block, { BlockProperties } from './model/Block';
import Blocks from './model/Blocks';
import Categories from './model/Categories';
import Category from './model/Category';
import Categories from '../abstract/ModuleCategories';
import Category from '../abstract/ModuleCategory';
import { BlocksEvents } from './types';
import BlocksView from './view/BlocksView';

4
src/block_manager/model/Block.ts

@ -1,7 +1,7 @@
import { Model } from '../../common';
import { isFunction } from 'underscore';
import Editor from '../../editor';
import { BlockCategoryProperties } from './Category';
import { CategoryProperties } from '../../abstract/ModuleCategory';
import { ComponentDefinition } from '../../dom_components/model/types';
/** @private */
@ -23,7 +23,7 @@ export interface BlockProperties {
* Block category, eg. `Basic blocks`
* @default ''
*/
category?: string | BlockCategoryProperties;
category?: string | CategoryProperties;
/**
* If true, triggers the `active` event on the dropped component.
* @default false

6
src/block_manager/view/BlocksView.ts

@ -4,9 +4,9 @@ import { View } from '../../common';
import Component from '../../dom_components/model/Component';
import EditorModel from '../../editor/model/Editor';
import Block from '../model/Block';
import Categories from '../model/Categories';
import Categories from '../../abstract/ModuleCategories';
import BlockView from './BlockView';
import CategoryView from './CategoryView';
import CategoryView from '../../abstract/ModuleCategoryView';
export interface BlocksViewConfig {
em: EditorModel;
@ -152,7 +152,7 @@ export default class BlocksView extends View {
model.set('category', catModel, { silent: true });
if (!catView && categories) {
catView = new CategoryView({ model: catModel }, config).render();
catView = new CategoryView({ model: catModel }, config, 'block').render();
renderedCategories.set(catId, catView);
categories.appendChild(catView.el);
}

2
src/domain_abstract/view/DomainViews.ts

@ -8,7 +8,7 @@ export default class DomainViews extends View {
itemView?: any;
// Defines the View per type
itemsView = '';
itemsView = '' as any;
itemType = 'type';

9
src/index.ts

@ -92,13 +92,18 @@ export const grapesjs = {
},
};
/**
* @deprecated Changed to CategoryProperties
*/
export type { CategoryProperties as BlockCategoryProperties } from './abstract/ModuleCategory';
// Exports for TS
export type { default as Asset } from './asset_manager/model/Asset';
export type { default as Assets } from './asset_manager/model/Assets';
export type { default as Block } from './block_manager/model/Block';
export type { default as Blocks } from './block_manager/model/Blocks';
export type { default as Categories } from './block_manager/model/Categories';
export type { default as Category } from './block_manager/model/Category';
export type { default as Categories } from './abstract/ModuleCategories';
export type { default as Category } from './abstract/ModuleCategory';
export type { default as Canvas } from './canvas/model/Canvas';
export type { default as CanvasSpot } from './canvas/model/CanvasSpot';
export type { default as CanvasSpots } from './canvas/model/CanvasSpots';

29
src/styles/scss/_gjs_traits.scss

@ -21,6 +21,32 @@
flex-grow: 1;
}
}
&traits-c {
display: flex;
flex-direction: column;
}
&trait-categories {
display: flex;
flex-direction: column;
}
&trait-category {
width: 100%;
&.#{$app-prefix}open {
@extend .#{$app-prefix}category-open;
}
.#{$app-prefix}title {
@extend .#{$app-prefix}category-title;
}
.#{$app-prefix}caret-icon {
margin-right: 5px;
}
}
}
.#{$trt-prefix}header {
@ -35,6 +61,7 @@
font-weight: lighter;
align-items: center;
text-align: left;
gap: 5px;
&s {
font-size: var(--gjs-font-size);
@ -45,4 +72,4 @@
text-overflow: ellipsis;
overflow: hidden;
}
}
}

42
src/trait_manager/index.ts

@ -12,6 +12,8 @@ import TraitButtonView from './view/TraitButtonView';
import EditorModel from '../editor/model/Editor';
import Component from '../dom_components/model/Component';
import Trait from './model/Trait';
import Category from '../abstract/ModuleCategory';
import Categories from '../abstract/ModuleCategories';
export const evAll = 'trait';
export const evPfx = `${evAll}:`;
@ -38,12 +40,21 @@ interface ITraitView {
export type CustomTrait<T> = ITraitView & T & ThisType<T & TraitView>;
export default class TraitManager extends Module<TraitManagerConfig & { pStylePrefix?: string }> {
export interface TraitManagerConfigModule extends TraitManagerConfig {
pStylePrefix?: string;
em: EditorModel;
}
export default class TraitManager extends Module<TraitManagerConfigModule> {
view?: TraitsView;
types: { [id: string]: { new (o: any): TraitView } };
model: Model;
__ctn?: any;
categories: Categories;
TraitsView = TraitsView;
Category = Category;
Categories = Categories;
events = {
all: evAll,
@ -62,10 +73,13 @@ export default class TraitManager extends Module<TraitManagerConfig & { pStylePr
* @private
*/
constructor(em: EditorModel) {
super(em, 'TraitManager', defaults);
super(em, 'TraitManager', defaults as any);
const model = new Model();
this.model = model;
this.types = typesDef;
const ppfx = this.config.pStylePrefix;
ppfx && (this.config.stylePrefix = `${ppfx}${this.config.stylePrefix}`);
this.categories = new Categories();
const upAll = debounce(() => this.__upSel(), 0);
model.listenTo(em, 'component:toggled', upAll);
@ -147,16 +161,24 @@ export default class TraitManager extends Module<TraitManagerConfig & { pStylePr
return this.types;
}
/**
* Get all available categories.
* @return {Array<Category>}
*/
getCategories() {
return [...this.categories.models];
}
render() {
let { view, em } = this;
const config = this.getConfig();
const el = view && view.el;
let { view } = this;
const { categories, em } = this;
view = new TraitsView(
{
el,
el: view?.el,
collection: [],
editor: em,
config,
config: this.getConfig(),
categories,
},
this.getTypes()
);
@ -165,7 +187,13 @@ export default class TraitManager extends Module<TraitManagerConfig & { pStylePr
}
destroy() {
const colls = [this.categories];
colls.forEach(c => {
c.stopListening();
c.reset();
});
this.model.stopListening();
this.model.clear();
this.view?.remove();
}
}

13
src/trait_manager/model/Trait.ts

@ -5,6 +5,7 @@ import Editor from '../../editor';
import EditorModel from '../../editor/model/Editor';
import TraitView from '../view/TraitView';
import { isDef } from '../../utils/mixins';
import { CategoryProperties } from '../../abstract/ModuleCategory';
/** @private */
export interface TraitProperties {
@ -18,13 +19,19 @@ export interface TraitProperties {
* The name of the trait used as a key for the attribute/property.
* By default, the name is used as attribute name or property in case `changeProp` in enabled.
*/
name: string;
name?: string;
/**
* Trait id, eg. `my-trait-id`.
* If not specified, the `name` will be used as id.
*/
id?: string;
id?: string | number;
/**
* Trait category.
* @default ''
*/
category?: string | CategoryProperties;
/**
* The trait label to show for the rendered trait.
@ -80,6 +87,7 @@ type TraitOption = {
* @property {String} type Trait type, defines how the trait should rendered. Possible values: `text` (default), `number`, `select`, `checkbox`, `color`, `button`
* @property {String} label The trait label to show for the rendered trait.
* @property {String} name The name of the trait used as a key for the attribute/property. By default, the name is used as attribute name or property in case `changeProp` in enabled.
* @property {String} [category=''] Trait category.
* @property {Boolean} changeProp If `true` the trait value is applied on component
*
*/
@ -99,6 +107,7 @@ export default class Trait extends Model<TraitProperties> {
value: '',
default: '',
placeholder: '',
category: '',
changeProp: false,
options: [],
};

6
src/trait_manager/view/TraitView.ts

@ -48,11 +48,11 @@ export default class TraitView extends View<Trait> {
const { type } = model.attributes;
this.config = config;
this.em = config.em;
this.pfx = config.stylePrefix || '';
this.ppfx = config.pStylePrefix || '';
this.pfx = this.ppfx + config.stylePrefix || '';
this.target = target;
const { ppfx } = this;
this.clsField = `${ppfx}field ${ppfx}field-${type}`;
this.className = this.pfx + 'trait';
this.clsField = `${this.ppfx}field ${this.ppfx}field-${type}`;
const evToListen: [string, any][] = [
['change:value', this.onValueChange],
['remove', this.removeView],

138
src/trait_manager/view/TraitsView.ts

@ -1,24 +1,53 @@
import DomainViews from '../../domain_abstract/view/DomainViews';
import EditorModel from '../../editor/model/Editor';
import TraitView from './TraitView';
import CategoryView from '../../abstract/ModuleCategoryView';
import Categories from '../../abstract/ModuleCategories';
import Trait from '../model/Trait';
import { isObject, isString } from 'underscore';
import TraitManager, { TraitManagerConfigModule } from '..';
interface TraitsViewProps {
el?: HTMLElement;
collection: any[];
editor: EditorModel;
config: TraitManagerConfigModule;
categories: Categories;
}
const ATTR_CATEGORIES = 'data-categories';
const ATTR_NO_CATEGORIES = 'data-no-categories';
export default class TraitsView extends DomainViews {
reuseView = true;
em: EditorModel;
pfx: string;
ppfx: string;
categories: Categories;
renderedCategories = new Map<string, CategoryView>();
config: TraitManagerConfigModule;
traitContClass: string;
catsClass: string;
catsEl?: HTMLElement;
traitsEl?: HTMLElement;
rendered?: boolean;
itemsView: TraitManager['types'];
constructor(o: any = {}, itemsView: any) {
super(o);
constructor(props: TraitsViewProps, itemsView: TraitManager['types']) {
super(props);
this.itemsView = itemsView;
const config = o.config || {};
const em = o.editor;
const config = props.config || {};
this.config = config;
const em = props.editor;
this.em = em;
this.ppfx = config.pStylePrefix || '';
this.pfx = this.ppfx + config.stylePrefix || '';
const ppfx = config.pStylePrefix || '';
this.ppfx = ppfx;
this.pfx = ppfx + config.stylePrefix || '';
this.className = `${this.pfx}traits`;
this.categories = props.categories || '';
this.traitContClass = `${ppfx}traits-c`;
this.catsClass = `${ppfx}trait-categories`;
this.listenTo(em, 'component:toggled', this.updatedCollection);
this.updatedCollection();
}
@ -28,14 +57,101 @@ export default class TraitsView extends DomainViews {
* @private
*/
updatedCollection() {
const { ppfx, className, em } = this;
const { ppfx, em } = this;
const comp = em.getSelected();
this.el.className = `${className} ${ppfx}one-bg ${ppfx}two-color`;
this.el.className = `${this.traitContClass}s ${ppfx}one-bg ${ppfx}two-color`;
// @ts-ignore
this.collection = comp ? comp.traits : [];
this.collection = comp ? comp.get('traits') : [];
this.render();
}
/**
* Render new model inside the view
* @param {Model} model
* @param {Object} fragment Fragment collection
* @private
* */
add(model: Trait, fragment?: DocumentFragment) {
const { config, renderedCategories } = this;
let itemView = this.itemView;
const typeField = model.get(this.itemType as any);
if (this.itemsView && this.itemsView[typeField]) {
itemView = this.itemsView[typeField];
}
const view = new itemView({
config,
model,
attributes: model.get('attributes'),
});
const rendered = view.render().el;
let category = model.get('category');
// TODO: this part could be consolidated better with BlocksView.ts
// Check for categories
if (category && this.categories && !(config as any).ignoreCategories) {
if (isString(category)) {
category = { id: category, label: category };
} else if (isObject(category) && !category.id) {
category.id = category.label;
}
const catModel = this.categories.add(category);
const catId = catModel.getId();
const categories = this.getCategoriesEl();
let catView = renderedCategories.get(catId);
model.set('category', catModel as any, { silent: true });
if (!catView && categories) {
catView = new CategoryView({ model: catModel }, config, 'trait').render();
renderedCategories.set(catId, catView);
categories.appendChild(catView.el);
}
catView && catView.append(rendered);
return;
}
fragment ? fragment.appendChild(rendered) : this.append(rendered);
}
getCategoriesEl() {
if (!this.catsEl) {
this.catsEl = this.el.querySelector(`[${ATTR_CATEGORIES}]`)!;
}
return this.catsEl;
}
getTraitsEl() {
if (!this.traitsEl) {
this.traitsEl = this.el.querySelector(`[${ATTR_NO_CATEGORIES}]`)!;
}
return this.traitsEl;
}
append(el: HTMLElement | DocumentFragment) {
const traits = this.getTraitsEl();
traits?.appendChild(el);
}
render() {
const { ppfx, catsClass, traitContClass } = this;
const frag = document.createDocumentFragment();
delete this.catsEl;
delete this.traitsEl;
this.renderedCategories = new Map();
this.el.innerHTML = `
<div class="${catsClass}" ${ATTR_CATEGORIES}></div>
<div class="${traitContClass}" ${ATTR_NO_CATEGORIES}></div>
`;
this.collection.forEach(model => this.add(model, frag));
this.append(frag);
const cls = `${traitContClass}s ${ppfx}one-bg ${ppfx}two-color`;
this.$el.addClass(cls);
this.rendered = true;
return this;
}
}
// @ts-ignore
TraitsView.prototype.itemView = TraitView;

Loading…
Cancel
Save