Skip to content

Commit

Permalink
Wire New Trait impl in the editor
Browse files Browse the repository at this point in the history
  • Loading branch information
xQwexx committed Dec 16, 2023
1 parent 83bcf5f commit e66f59f
Show file tree
Hide file tree
Showing 15 changed files with 240 additions and 169 deletions.
1 change: 0 additions & 1 deletion dist/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5147,7 +5147,6 @@ export declare class Component extends StyleableModel<ComponentProperties> {
* @private
*/
initToolbar(): void;
__loadTraits(tr?: Traits | TraitProperties[], opts?: {}): this;
/**
* Get traits.
* @returns {Array<Trait>}
Expand Down
89 changes: 48 additions & 41 deletions src/common/traits/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { isString } from 'underscore';
import { Model } from '..';
import EditorModel from '../../editor/model/Editor';
import Trait, { TraitProperties } from './model/Trait';
import TraitButtonView, { TraitButtonViewOpts } from './view/TraitButtonView';
import TraitCheckboxView from './view/TraitCheckboxView';
import TraitColorView from './view/TraitColorView';
import TraitNumberView, {
import {
TraitNumberView,
TraitNumberUnitView,
TraitNumberUnitViewOpts,
TraitNumberViewOpts,
Expand All @@ -12,57 +15,53 @@ import TraitSelectView, { TraitSelectViewOpts } from './view/TraitSelectView';
import TraitTextView from './view/TraitTextView';
import TraitView, { TraitViewOpts } from './view/TraitView';

type InputProperties =
| { type?: string; opts: { em: EditorModel; name?: string } }
| {
type: 'text';
opts: TraitViewOpts;
}
| {
type: 'number';
opts: TraitNumberViewOpts | TraitNumberUnitViewOpts;
}
| {
type: 'select';
opts: TraitSelectViewOpts;
}
| {
type: 'checkbox';
opts: TraitViewOpts;
}
| {
type: 'color';
opts: TraitViewOpts;
}
| {
type: 'button';
opts: TraitButtonViewOpts<Model>;
};

export type InputViewProperties =
| ({ type?: '' } & TraitViewOpts)
| ({ type: 'text' } & TraitViewOpts)
| ({ type: 'number' } & (TraitNumberViewOpts | TraitNumberUnitViewOpts))
| ({ type: 'select' } & TraitSelectViewOpts)
| ({ type: 'checkbox' } & TraitViewOpts)
| ({ type: 'color' } & TraitViewOpts)
| ({ type: 'button' } & TraitButtonViewOpts<Model>);
export type InputProperties = TraitProperties & { name: string };
export default abstract class InputFactory {
static build(model: Model, trait: string | (InputProperties & InputViewProperties) | Trait): Trait {
if (!(trait instanceof Trait)) {
return isString(trait) ? new Trait(trait, model) : new Trait(trait.name, model, trait);
} else {
return trait;
}
}
/**
* Build props object by their name
*/
static build<M extends Model>(name: string, model: M, prop: InputProperties): TraitView<M, any> {
let type = 'text';
let opts: any = { name, ...prop.opts };
if (prop.type !== undefined) {
type = prop.type;
opts = prop.opts;
static buildView<M extends Model, T extends any>(
target: Trait<T>,
em: EditorModel,
opts?: InputViewProperties
): TraitView<M, T | any> {
let type: string | undefined;
let prop: any = { name: target.name, ...opts };
if (opts !== undefined) {
type = opts.type;
prop = opts;
}

switch (name) {
let view: TraitView<M, T | any>;
switch (target.name) {
case 'target':
const options = opts.em.Traits.config.optionsTarget;
return new TraitSelectView(name, model, { ...prop.opts, name, default: false, options });
const options = em.Traits.config.optionsTarget;
view = new TraitSelectView(em, { name: target.name, ...prop, default: false, options });
break;
default:
const ViewClass = this.getView(type, opts);
const ViewClass = this.getView(type, prop);
//@ts-ignore
return new ViewClass(name, model, opts);
view = new ViewClass(em, opts);
break;
}
return view.setTarget(target);
}

private static getView<M extends Model>(type: string, opts: any) {
private static getView(type?: string, opts?: any) {
switch (type) {
case 'text':
return TraitTextView;
Expand All @@ -81,3 +80,11 @@ export default abstract class InputFactory {
}
}
}

export type { default as TraitButtonView } from './view/TraitButtonView';
export type { default as TraitCheckboxView } from './view/TraitCheckboxView';
export type { default as TraitColorView } from './view/TraitColorView';
export type { TraitNumberView, TraitNumberUnitView } from './view/TraitNumberView';
export type { default as TraitSelectView } from './view/TraitSelectView';
export type { default as TraitTextView } from './view/TraitTextView';
export type { default as TraitView } from './view/TraitView';
42 changes: 34 additions & 8 deletions src/common/traits/model/Trait.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,53 @@ export interface OnUpdateView<TraitValueType> {
onUpdateEvent(value: TraitValueType): void;
}

export default class Trait<TraitValueType> {
private name: string;
private defaultValue: TraitValueType;
private model: Model;
export interface TraitProperties {
default?: any;
value?: any;
changeProp?: boolean;
}

export default class Trait<TraitValueType = any> {
readonly name: string;
opts: TraitProperties;
readonly model: Model;
private view?: OnUpdateView<TraitValueType>;

constructor(name: string, model: Model, defaultValue: TraitValueType) {
constructor(name: string, model: Model, opts?: TraitProperties) {
this.name = name;
model.on('change:' + name, this.setValueFromModel, this);
this.model = model;
this.defaultValue = defaultValue;
this.opts = { ...opts, default: opts?.value ?? opts?.default ?? '' };
}

public registerForUpdateEvent(view: OnUpdateView<TraitValueType>) {
this.view = view;
}

public get value(): TraitValueType {
return this.model.get(this.name) ?? this.defaultValue;
const { changeProp, model, name } = this;
const value = changeProp
? model.get(name)
: // @ts-ignore TODO update post component update
model.getAttributes()[name];

return value ?? this.opts.default;
}
public get changeProp(): boolean {
return this.opts.changeProp ?? false;
}

private updatingValue = false;
public set value(value: TraitValueType) {
const { name, model, changeProp } = this;
this.updatingValue = true;
this.model.set(this.name, value);

if (changeProp) {
model.set(name, value);
} else {
//@ts-ignore
model.addAttributes({ [name]: value });
}
this.updatingValue = false;
}

Expand All @@ -37,4 +59,8 @@ export default class Trait<TraitValueType> {
this.view?.onUpdateEvent(this.value);
}
}

updateOpts(opts: any) {
this.opts = { ...this.opts, ...opts };
}
}
5 changes: 3 additions & 2 deletions src/common/traits/view/TraitButtonView.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { isString } from 'underscore';
import { Model, $ } from '../..';
import Editor from '../../../editor';
import EditorModel from '../../../editor/model/Editor';
import TraitView, { TraitViewOpts } from './TraitView';

export interface TraitButtonViewOpts<TModel> extends TraitViewOpts {
Expand All @@ -20,8 +21,8 @@ export default class TraitButtonView<TModel extends Model> extends TraitView<TMo
};
}

constructor(popertyName: string, model: TModel, opts: TraitButtonViewOpts<TModel>) {
super(popertyName, model, opts);
constructor(em: EditorModel, opts: TraitButtonViewOpts<TModel>) {
super(em, opts);
this.command = opts.command;
this.text = opts.text;
this.full = opts.full;
Expand Down
15 changes: 8 additions & 7 deletions src/common/traits/view/TraitNumberView.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { bindAll, indexOf, isUndefined } from 'underscore';
import { Model, $ } from '../..';
import EditorModel from '../../../editor/model/Editor';
import { off, on } from '../../../utils/dom';
import TraitView, { TraitViewOpts } from './TraitView';

Expand Down Expand Up @@ -31,8 +32,8 @@ abstract class TraitNumberViewAbstract<TModel extends Model, TraitValueType> ext
};
}

constructor(popertyName: string, model: TModel, opts: TraitNumberViewOpts) {
super(popertyName, model, opts);
constructor(em: EditorModel, opts: TraitNumberViewOpts) {
super(em, opts);
bindAll(this, 'moveIncrement', 'upIncrement');
this.step = opts.step ?? 1;
this.min = opts.min;
Expand Down Expand Up @@ -245,11 +246,11 @@ abstract class TraitNumberViewAbstract<TModel extends Model, TraitValueType> ext
}
}

export default class TraitNumberView<TModel extends Model> extends TraitNumberViewAbstract<TModel, number> {
export class TraitNumberView<TModel extends Model> extends TraitNumberViewAbstract<TModel, number> {
unitEl?: any;

constructor(popertyName: string, model: TModel, opts: TraitNumberViewOpts) {
super(popertyName, model, opts);
constructor(em: EditorModel, opts: TraitNumberViewOpts) {
super(em, opts);
}

get inputValue(): number {
Expand All @@ -269,8 +270,8 @@ export class TraitNumberUnitView<TModel extends Model> extends TraitNumberViewAb
unitEl?: HTMLSelectElement;
units: string[];

constructor(popertyName: string, model: TModel, opts: TraitNumberUnitViewOpts) {
super(popertyName, model, opts);
constructor(em: EditorModel, opts: TraitNumberUnitViewOpts) {
super(em, opts);
this.units = opts.units;
}

Expand Down
5 changes: 3 additions & 2 deletions src/common/traits/view/TraitSelectView.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { isString, isUndefined } from 'underscore';
import { Model, $ } from '../..';
import EditorModel from '../../../editor/model/Editor';
import TraitView, { TraitViewOpts } from './TraitView';

type SelectOption =
Expand All @@ -18,8 +19,8 @@ export default class TraitSelectView<TModel extends Model> extends TraitView<TMo
protected type = 'select';
options: SelectOption[];

constructor(popertyName: string, model: TModel, opts: TraitSelectViewOpts) {
super(popertyName, model, opts);
constructor(em: EditorModel, opts: TraitSelectViewOpts) {
super(em, opts);
this.options = opts.options;
}

Expand Down
42 changes: 27 additions & 15 deletions src/common/traits/view/TraitView.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
import { EventsHash } from 'backbone';
import { isUndefined } from 'underscore';
import { isString, isUndefined } from 'underscore';
import { InputViewProperties } from '..';
import { Model } from '../..';
import { $, View } from '../../../common';
import EditorModel from '../../../editor/model/Editor';
import { capitalize } from '../../../utils/mixins';
import Trait, { OnUpdateView } from '../model/Trait';
import Trait, { OnUpdateView, TraitProperties } from '../model/Trait';

export interface TraitViewOpts {
em: EditorModel;
default?: any;
name?: string;
label?: string;
paceholder?: string;
noLabel?: boolean;
}

export default abstract class TraitView<TModel extends Model, TraitValueType>
export default abstract class TraitView<TModel extends Model = Model, TraitValueType = any>
extends View<TModel>
implements OnUpdateView<TraitValueType>
{
Expand All @@ -32,9 +34,9 @@ export default abstract class TraitView<TModel extends Model, TraitValueType>
input?: HTMLInputElement;
$input?: JQuery<HTMLInputElement>;
eventCapture!: string[];
noLabel?: boolean;
noLabel: boolean;
em: EditorModel;
target: Trait<TraitValueType>;
target!: Trait<TraitValueType>;

events(): EventsHash {
return {
Expand All @@ -55,18 +57,29 @@ export default abstract class TraitView<TModel extends Model, TraitValueType>
return `<div class="${clsField}" data-input></div>`;
}

constructor(popertyName: string, model: TModel, opts: TraitViewOpts) {
super({ model });
this.em = opts.em;
constructor(em: EditorModel, opts?: TraitViewOpts) {
super({});
this.em = em;
const config = this.em.Traits.config;
this.ppfx = config.pStylePrefix || '';
this.pfx = this.ppfx + config.stylePrefix || '';
this.name = opts.name;
this.target = new Trait(popertyName, model, opts.default ?? '');
this.target.registerForUpdateEvent(this);
this.name = opts?.name;
this.noLabel = opts?.noLabel ?? false;
}

setTarget(popertyName: string, model: TModel, opts?: TraitProperties): this;
setTarget(target: Trait<TraitValueType>): this;
setTarget(target: unknown, model?: TModel, opts?: TraitProperties) {
if (isString(target) && model !== undefined) {
target = new Trait(target, model, opts);
}
this.target = target as Trait<TraitValueType>;
this.model = this.target.model as any;
this.name ?? (this.name = this.target.name);
this.listenTo(model, 'change:label', this.render);
this.listenTo(model, 'change:placeholder', this.rerender);
this.target.registerForUpdateEvent(this);
return this;
}

abstract get inputValue(): TraitValueType;
Expand Down Expand Up @@ -146,8 +159,7 @@ export default abstract class TraitView<TModel extends Model, TraitValueType>
}

hasLabel() {
const { label } = this.model.attributes;
return !this.noLabel && label !== false;
return !this.noLabel;
}

rerender() {
Expand All @@ -157,7 +169,7 @@ export default abstract class TraitView<TModel extends Model, TraitValueType>

render() {
const { $el, pfx, ppfx, name, type } = this;
const hasLabel = this.hasLabel && this.hasLabel();
const hasLabel = this.hasLabel();
const cls = `${pfx}trait`;
delete this.$input;
let tmpl = `<div class="${cls} ${cls}--${type}">
Expand Down
Loading

0 comments on commit e66f59f

Please sign in to comment.