Skip to content

Commit

Permalink
Add trait list
Browse files Browse the repository at this point in the history
  • Loading branch information
xQwexx committed Dec 18, 2023
1 parent e66f59f commit ccbaaf0
Show file tree
Hide file tree
Showing 14 changed files with 218 additions and 47 deletions.
30 changes: 21 additions & 9 deletions src/common/traits/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import { isString } from 'underscore';
import { Model } from '..';
import EditorModel from '../../editor/model/Editor';
import Trait, { TraitProperties } from './model/Trait';
import TraitList from './model/TraitList';
import TraitButtonView, { TraitButtonViewOpts } from './view/TraitButtonView';
import TraitCheckboxView from './view/TraitCheckboxView';
import TraitColorView from './view/TraitColorView';
import TraitListView from './view/TraitListView';
import {
TraitNumberView,
TraitNumberUnitView,
Expand All @@ -22,35 +24,43 @@ export type InputViewProperties =
| ({ type: 'select' } & TraitSelectViewOpts)
| ({ type: 'checkbox' } & TraitViewOpts)
| ({ type: 'color' } & TraitViewOpts)
| ({ type: 'button' } & TraitButtonViewOpts<Model>);
| ({ type: 'button' } & TraitButtonViewOpts<Model>)
| ({ type: 'list' } & 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);
if (isString(trait)) {
return new Trait(trait, model);
} else {
switch (trait.type) {
case 'list':
return new TraitList(trait.name, model, trait);
default:
return new Trait(trait.name, model, trait);
}
}
} else {
return trait;
}
}
/**
* Build props object by their name
*/
static buildView<M extends Model, T extends any>(
target: Trait<T>,
em: EditorModel,
opts?: InputViewProperties
): TraitView<M, T | any> {
static buildView<T extends Trait<Model, any>>(target: T, em: EditorModel, opts?: InputViewProperties): TraitView<T> {
let type: string | undefined;
let prop: any = { name: target.name, ...opts };
if (opts !== undefined) {
type = opts.type;
prop = opts;
}
let view: TraitView<M, T | any>;
let view: TraitView<T>;
switch (target.name) {
case 'target':
const options = em.Traits.config.optionsTarget;
view = new TraitSelectView(em, { name: target.name, ...prop, default: false, options });
view = new TraitSelectView(em, { name: target.name, ...prop, default: false, options }) as any;
break;
default:
const ViewClass = this.getView(type, prop);
Expand All @@ -75,6 +85,8 @@ export default abstract class InputFactory {
return TraitColorView;
case 'button':
return TraitButtonView;
case 'list':
return TraitListView;
default:
return TraitTextView;
}
Expand Down
19 changes: 9 additions & 10 deletions src/common/traits/model/Trait.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ export interface TraitProperties {
changeProp?: boolean;
}

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

constructor(name: string, model: Model, opts?: TraitProperties) {
constructor(name: string, model: TModel, opts?: TraitProperties) {
this.name = name;
model.on('change:' + name, this.setValueFromModel, this);
this.model = model;
Expand All @@ -31,30 +31,29 @@ export default class Trait<TraitValueType = any> {
const { changeProp, model, name } = this;
const value = changeProp
? model.get(name)
: // @ts-ignore TODO update post component update
model.getAttributes()[name];
: // TODO update post component update
model.get('attributes')[name];

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

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

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

private setValueFromModel() {
protected setValueFromModel() {
if (!this.updatingValue) {
this.view?.onUpdateEvent(this.value);
}
Expand Down
29 changes: 29 additions & 0 deletions src/common/traits/model/TraitItem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Model } from '../..';
import Trait, { TraitProperties } from './Trait';

export interface TraitItemProperties extends TraitProperties {
prefix: string;
}

export default class TraitItem<TModel extends Model = Model, TraitValueType = any> extends Trait<
TModel,
TraitValueType
> {
readonly prefix: string;
constructor(name: string, model: TModel, opts: any) {
super(name, model, opts);
this.prefix = opts.prefix;
}

public get value(): TraitValueType {
const { prefix, model, name } = this;
const value = model.get(prefix)[name];
return value ?? this.opts.default;
}
public set value(value: TraitValueType) {
const { name, model, prefix } = this;
this.updatingValue = true;
model.set(prefix, { ...model.get(prefix), [name]: value });
this.updatingValue = false;
}
}
66 changes: 66 additions & 0 deletions src/common/traits/model/TraitList.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { InputProperties, InputViewProperties } from '..';
import { Model } from '../..';
import Trait, { TraitProperties } from './Trait';
import TraitItem from './TraitItem';

export interface TraitListProperties extends TraitProperties {
default?: any;
value?: any;
}

export default class TraitList<TModel extends Model = Model> extends Trait<TModel, Trait[]> {
// traits: (InputViewProperties) []
collection?: Trait[];
constructor(name: string, model: TModel, opts?: TraitListProperties) {
super(name, model, { ...opts, type: 'list', changeProp: true } as any);
// this.model.on("all", (e) => console.log(e))
// this.traits = opts?.traits ?? [{type: "list"}]
model.get(name) ?? model.set(name, {});
}

protected setValueFromModel() {
this.collection = undefined;
if (!this.updatingValue) {
this.view?.onUpdateEvent(this.value);
}
}

public get value(): Trait[] {
const { model, name } = this;
if (!this.collection) {
const map = model.get(name);
this.collection = Object.keys(map).map(
key => new TraitItem(key, model, { type: 'text', name: key, prefix: name, value: map[key] })
);
}
return this.collection!;
}

public set value(values: Trait[]) {
const { name, model } = this;
this.updatingValue = true;

model.set(
name,
values.reduce((map: any, tr) => {
map[tr.name] = tr.value;
return map;
}, {})
);
this.updatingValue = false;
}

public add(key: string) {
const { model, name } = this;
if (!this.collection?.find(tr => tr.name == key)) {
this.value.push(new TraitItem(key, model, { type: 'text', name: key, prefix: name }));
}
}

public remove(key: string) {
const index = this.collection?.findIndex(tr => tr.name == key) ?? -1;
if (index > -1) {
this.value.splice(index, 1);
}
}
}
3 changes: 2 additions & 1 deletion src/common/traits/view/TraitButtonView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { isString } from 'underscore';
import { Model, $ } from '../..';
import Editor from '../../../editor';
import EditorModel from '../../../editor/model/Editor';
import Trait from '../model/Trait';
import TraitView, { TraitViewOpts } from './TraitView';

export interface TraitButtonViewOpts<TModel> extends TraitViewOpts {
Expand All @@ -10,7 +11,7 @@ export interface TraitButtonViewOpts<TModel> extends TraitViewOpts {
full?: boolean;
}

export default class TraitButtonView<TModel extends Model> extends TraitView<TModel, any> {
export default class TraitButtonView<TModel extends Model> extends TraitView<Trait<TModel, any>> {
type = 'button';
command: string | ((e: Editor, m: TModel) => void);
text?: string;
Expand Down
3 changes: 2 additions & 1 deletion src/common/traits/view/TraitCheckboxView.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Model } from 'backbone';
import Trait from '../model/Trait';
import TraitView from './TraitView';

export default class TraitCheckboxView<TModel extends Model> extends TraitView<TModel, boolean> {
export default class TraitCheckboxView<TModel extends Model> extends TraitView<Trait<TModel, boolean>> {
type = 'checkbox';
appendInput = false;

Expand Down
3 changes: 2 additions & 1 deletion src/common/traits/view/TraitColorView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import TraitView from './TraitView';
import { Model, $ } from '../..';
import { isUndefined } from 'underscore';
import ColorPicker from '../../../utils/ColorPicker';
import Trait from '../model/Trait';

$ && ColorPicker($);

Expand All @@ -11,7 +12,7 @@ const getColor = (color: any) => {
return name || cl.replace(/ /g, '');
};

export default class TraitColorView<TModel extends Model> extends TraitView<TModel, any> {
export default class TraitColorView<TModel extends Model> extends TraitView<Trait<TModel, any>> {
type = 'text';
colorPicker?: any;
templateInput() {
Expand Down
58 changes: 58 additions & 0 deletions src/common/traits/view/TraitListView.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { isString } from 'underscore';
import TraitView from './TraitView';
import { Model } from '../..';
import EditorModel from '../../../editor/model/Editor';
import TraitList, { TraitListProperties } from '../model/TraitList';
import { TraitViewOpts } from './TraitView';
import InputFactory from '..';

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

export default class TraitListView<TModel extends Model = Model> extends TraitView<TraitList<TModel>> {
protected type = 'list';

get inputValue(): any {
return this.target.value;
}
set inputValue(value: any) {}
constructor(em: EditorModel, opts?: TraitListViewOpts) {
super(em, opts);
}

setTarget(popertyName: string, model: TModel, opts?: TraitListProperties): this;
setTarget(target: TraitList<TModel>): this;
setTarget(target: unknown, model?: TModel, opts?: TraitListProperties) {
if (isString(target) && model !== undefined) {
target = new TraitList(target, model, opts);
}
this.target = target as TraitList<TModel>;
this.model = this.target.model as any;
this.name ?? (this.name = this.target.name);
this.target.registerForUpdateEvent(this);
return this;
}

render() {
const { em } = this;
var frag = document.createDocumentFragment();
this.$el.empty();

if (this.target.value.length) {
this.target.value.forEach(view => {
const rendered = InputFactory.buildView(view, em, view.opts).render().el;
console.log(rendered);
frag.appendChild(rendered);
});
}
console.log(frag);

this.$el.append(frag);
return this;
}
}
5 changes: 4 additions & 1 deletion src/common/traits/view/TraitNumberView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { bindAll, indexOf, isUndefined } from 'underscore';
import { Model, $ } from '../..';
import EditorModel from '../../../editor/model/Editor';
import { off, on } from '../../../utils/dom';
import Trait from '../model/Trait';
import TraitView, { TraitViewOpts } from './TraitView';

export interface TraitNumberViewOpts extends TraitViewOpts {
Expand All @@ -11,7 +12,9 @@ export interface TraitNumberViewOpts extends TraitViewOpts {
fixedValues?: string[];
}

abstract class TraitNumberViewAbstract<TModel extends Model, TraitValueType> extends TraitView<TModel, TraitValueType> {
abstract class TraitNumberViewAbstract<TModel extends Model, TraitValueType> extends TraitView<
Trait<TModel, TraitValueType>
> {
protected type = 'number';
moved?: boolean;
prValue?: number;
Expand Down
3 changes: 2 additions & 1 deletion src/common/traits/view/TraitSelectView.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { isString, isUndefined } from 'underscore';
import { Model, $ } from '../..';
import EditorModel from '../../../editor/model/Editor';
import Trait from '../model/Trait';
import TraitView, { TraitViewOpts } from './TraitView';

type SelectOption =
Expand All @@ -15,7 +16,7 @@ export interface TraitSelectViewOpts extends TraitViewOpts {
options: SelectOption[];
}

export default class TraitSelectView<TModel extends Model> extends TraitView<TModel, string> {
export default class TraitSelectView<TModel extends Model> extends TraitView<Trait<TModel, string>> {
protected type = 'select';
options: SelectOption[];

Expand Down
3 changes: 2 additions & 1 deletion src/common/traits/view/TraitTextView.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Model } from '../..';
import Trait from '../model/Trait';
import TraitView from './TraitView';

export default class TraitTextView<TModel extends Model> extends TraitView<TModel, string> {
export default class TraitTextView<TModel extends Model> extends TraitView<Trait<TModel, string>> {
protected type: string = 'text';

getInputElem() {
Expand Down
Loading

0 comments on commit ccbaaf0

Please sign in to comment.