mirror of https://github.com/artf/grapesjs.git
committed by
GitHub
49 changed files with 1861 additions and 851 deletions
@ -1,61 +1,123 @@ |
|||
import Component from '../../../dom_components/model/Component'; |
|||
import { ComponentDefinition, ComponentOptions } from '../../../dom_components/model/types'; |
|||
import { |
|||
ComponentDefinition as ComponentProperties, |
|||
ComponentDefinitionDefined, |
|||
ComponentOptions, |
|||
ToHTMLOptions, |
|||
ComponentAddType, |
|||
} from '../../../dom_components/model/types'; |
|||
import { toLowerCase } from '../../../utils/mixins'; |
|||
import { DataCondition, DataConditionProps, DataConditionType } from './DataCondition'; |
|||
import { DataCondition, DataConditionOutputChangedEvent, DataConditionProps, DataConditionType } from './DataCondition'; |
|||
import { ConditionProps } from './DataConditionEvaluator'; |
|||
import { StringOperation } from './operators/StringOperator'; |
|||
import { ObjectAny } from '../../../common'; |
|||
import { DataConditionIfTrueType, DataConditionIfFalseType } from './constants'; |
|||
|
|||
export type DataConditionDisplayType = typeof DataConditionIfTrueType | typeof DataConditionIfFalseType; |
|||
|
|||
export interface ComponentDataConditionProps extends ComponentProperties { |
|||
type: typeof DataConditionType; |
|||
dataResolver: DataConditionProps; |
|||
} |
|||
|
|||
export default class ComponentDataCondition extends Component { |
|||
dataResolver: DataCondition; |
|||
|
|||
constructor(props: DataConditionProps, opt: ComponentOptions) { |
|||
const dataConditionInstance = new DataCondition(props, { em: opt.em }); |
|||
|
|||
super( |
|||
{ |
|||
...props, |
|||
type: DataConditionType, |
|||
components: dataConditionInstance.getDataValue(), |
|||
droppable: false, |
|||
get defaults(): ComponentDefinitionDefined { |
|||
return { |
|||
// @ts-ignore
|
|||
...super.defaults, |
|||
droppable: false, |
|||
type: DataConditionType, |
|||
dataResolver: { |
|||
condition: { |
|||
left: '', |
|||
operator: StringOperation.equalsIgnoreCase, |
|||
right: '', |
|||
}, |
|||
}, |
|||
opt, |
|||
); |
|||
this.dataResolver = dataConditionInstance; |
|||
this.dataResolver.onValueChange = this.handleConditionChange.bind(this); |
|||
components: [ |
|||
{ |
|||
type: DataConditionIfTrueType, |
|||
}, |
|||
{ |
|||
type: DataConditionIfFalseType, |
|||
}, |
|||
], |
|||
}; |
|||
} |
|||
|
|||
getCondition() { |
|||
return this.dataResolver.getCondition(); |
|||
constructor(props: ComponentDataConditionProps, opt: ComponentOptions) { |
|||
// @ts-ignore
|
|||
super(props, opt); |
|||
|
|||
const { condition } = props.dataResolver; |
|||
this.dataResolver = new DataCondition({ condition }, { em: opt.em }); |
|||
|
|||
this.listenToPropsChange(); |
|||
} |
|||
|
|||
getIfTrue() { |
|||
return this.dataResolver.getIfTrue(); |
|||
isTrue() { |
|||
return this.dataResolver.isTrue(); |
|||
} |
|||
|
|||
getIfFalse() { |
|||
return this.dataResolver.getIfFalse(); |
|||
getCondition() { |
|||
return this.dataResolver.getCondition(); |
|||
} |
|||
|
|||
private handleConditionChange() { |
|||
this.components(this.dataResolver.getDataValue()); |
|||
getIfTrueContent(): Component | undefined { |
|||
return this.components().at(0); |
|||
} |
|||
|
|||
static isComponent(el: HTMLElement) { |
|||
return toLowerCase(el.tagName) === DataConditionType; |
|||
getIfFalseContent(): Component | undefined { |
|||
return this.components().at(1); |
|||
} |
|||
|
|||
getOutputContent(): Component | undefined { |
|||
return this.isTrue() ? this.getIfTrueContent() : this.getIfFalseContent(); |
|||
} |
|||
|
|||
setCondition(newCondition: ConditionProps) { |
|||
this.dataResolver.setCondition(newCondition); |
|||
} |
|||
|
|||
setIfTrue(newIfTrue: any) { |
|||
this.dataResolver.setIfTrue(newIfTrue); |
|||
setIfTrueComponents(content: ComponentAddType) { |
|||
this.setComponentsAtIndex(0, content); |
|||
} |
|||
|
|||
setIfFalseComponents(content: ComponentAddType) { |
|||
this.setComponentsAtIndex(1, content); |
|||
} |
|||
|
|||
getInnerHTML(opts?: ToHTMLOptions): string { |
|||
return this.getOutputContent()?.getInnerHTML(opts) ?? ''; |
|||
} |
|||
|
|||
private setComponentsAtIndex(index: number, newContent: ComponentAddType) { |
|||
const component = this.components().at(index); |
|||
component?.components(newContent); |
|||
} |
|||
|
|||
private listenToPropsChange() { |
|||
this.on('change:dataResolver', () => { |
|||
this.dataResolver.set(this.get('dataResolver')); |
|||
}); |
|||
} |
|||
|
|||
setIfFalse(newIfFalse: any) { |
|||
this.dataResolver.setIfFalse(newIfFalse); |
|||
toJSON(opts?: ObjectAny): ComponentProperties { |
|||
const json = super.toJSON(opts); |
|||
const dataResolver = this.dataResolver.toJSON(); |
|||
delete dataResolver.type; |
|||
delete dataResolver.ifTrue; |
|||
delete dataResolver.ifFalse; |
|||
|
|||
return { |
|||
...json, |
|||
dataResolver, |
|||
}; |
|||
} |
|||
|
|||
toJSON(): ComponentDefinition { |
|||
return this.dataResolver.toJSON(); |
|||
static isComponent(el: HTMLElement) { |
|||
return toLowerCase(el.tagName) === DataConditionType; |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,19 @@ |
|||
import Component from '../../../dom_components/model/Component'; |
|||
import { ComponentDefinitionDefined, ToHTMLOptions } from '../../../dom_components/model/types'; |
|||
import { toLowerCase } from '../../../utils/mixins'; |
|||
import { isDataConditionDisplayType } from '../../utils'; |
|||
|
|||
export default class ConditionalOutputBase extends Component { |
|||
get defaults(): ComponentDefinitionDefined { |
|||
return { |
|||
// @ts-ignore
|
|||
...super.defaults, |
|||
removable: false, |
|||
draggable: false, |
|||
}; |
|||
} |
|||
|
|||
static isComponent(el: HTMLElement) { |
|||
return isDataConditionDisplayType(toLowerCase(el.tagName)); |
|||
} |
|||
} |
|||
@ -0,0 +1,2 @@ |
|||
export const DataConditionIfTrueType = 'data-condition-true-content'; |
|||
export const DataConditionIfFalseType = 'data-condition-false-content'; |
|||
@ -1,67 +0,0 @@ |
|||
import EditorModel from '../../editor/model/Editor'; |
|||
import { DataResolver, DataResolverProps } from '../types'; |
|||
import { DataCollectionStateMap } from './data_collection/types'; |
|||
import DataCollectionVariable from './data_collection/DataCollectionVariable'; |
|||
import { DataCollectionVariableType } from './data_collection/constants'; |
|||
import { DataConditionType, DataCondition } from './conditional_variables/DataCondition'; |
|||
import DataVariable, { DataVariableProps, DataVariableType } from './DataVariable'; |
|||
|
|||
export function isDataResolverProps(value: any): value is DataResolverProps { |
|||
return ( |
|||
typeof value === 'object' && [DataVariableType, DataConditionType, DataCollectionVariableType].includes(value?.type) |
|||
); |
|||
} |
|||
|
|||
export function isDataResolver(value: any): value is DataResolver { |
|||
return value instanceof DataVariable || value instanceof DataCondition; |
|||
} |
|||
|
|||
export function isDataVariable(variable: any): variable is DataVariableProps { |
|||
return variable?.type === DataVariableType; |
|||
} |
|||
|
|||
export function isDataCondition(variable: any) { |
|||
return variable?.type === DataConditionType; |
|||
} |
|||
|
|||
export function evaluateVariable(variable: any, em: EditorModel) { |
|||
return isDataVariable(variable) ? new DataVariable(variable, { em }).getDataValue() : variable; |
|||
} |
|||
|
|||
export function getDataResolverInstance( |
|||
resolverProps: DataResolverProps, |
|||
options: { em: EditorModel; collectionsStateMap?: DataCollectionStateMap }, |
|||
): DataResolver { |
|||
const { type } = resolverProps; |
|||
let resolver: DataResolver; |
|||
|
|||
switch (type) { |
|||
case DataVariableType: |
|||
resolver = new DataVariable(resolverProps, options); |
|||
break; |
|||
case DataConditionType: { |
|||
resolver = new DataCondition(resolverProps, options); |
|||
break; |
|||
} |
|||
case DataCollectionVariableType: { |
|||
resolver = new DataCollectionVariable(resolverProps, options); |
|||
break; |
|||
} |
|||
default: |
|||
throw new Error(`Unsupported dynamic type: ${type}`); |
|||
} |
|||
|
|||
return resolver; |
|||
} |
|||
|
|||
export function getDataResolverInstanceValue( |
|||
resolverProps: DataResolverProps, |
|||
options: { |
|||
em: EditorModel; |
|||
collectionsStateMap?: DataCollectionStateMap; |
|||
}, |
|||
) { |
|||
const resolver = getDataResolverInstance(resolverProps, options); |
|||
|
|||
return resolver.getDataValue(); |
|||
} |
|||
@ -0,0 +1,91 @@ |
|||
import EditorModel from '../editor/model/Editor'; |
|||
import { DataResolver, DataResolverProps } from './types'; |
|||
import { DataConditionDisplayType } from './model/conditional_variables/ComponentDataCondition'; |
|||
import { DataCollectionStateMap } from './model/data_collection/types'; |
|||
import DataCollectionVariable from './model/data_collection/DataCollectionVariable'; |
|||
import { DataCollectionVariableType } from './model/data_collection/constants'; |
|||
import { DataConditionType, DataCondition } from './model/conditional_variables/DataCondition'; |
|||
import DataVariable, { DataVariableProps, DataVariableType } from './model/DataVariable'; |
|||
import Component from '../dom_components/model/Component'; |
|||
import { ComponentDefinition, ComponentOptions } from '../dom_components/model/types'; |
|||
import { serialize } from '../utils/mixins'; |
|||
import { DataConditionIfFalseType, DataConditionIfTrueType } from './model/conditional_variables/constants'; |
|||
|
|||
export function isDataResolverProps(value: any): value is DataResolverProps { |
|||
return ( |
|||
typeof value === 'object' && [DataVariableType, DataConditionType, DataCollectionVariableType].includes(value?.type) |
|||
); |
|||
} |
|||
|
|||
export function isDataResolver(value: any): value is DataResolver { |
|||
return value instanceof DataVariable || value instanceof DataCondition; |
|||
} |
|||
|
|||
export function isDataVariable(variable: any): variable is DataVariableProps { |
|||
return variable?.type === DataVariableType; |
|||
} |
|||
|
|||
export function isDataCondition(variable: any) { |
|||
return variable?.type === DataConditionType; |
|||
} |
|||
|
|||
export function resolveDynamicValue(variable: any, em: EditorModel) { |
|||
return isDataResolverProps(variable) ? getDataResolverInstanceValue(variable, { em }) : variable; |
|||
} |
|||
|
|||
export function getDataResolverInstance( |
|||
resolverProps: DataResolverProps, |
|||
options: { em: EditorModel; collectionsStateMap?: DataCollectionStateMap }, |
|||
) { |
|||
const { type } = resolverProps; |
|||
let resolver: DataResolver; |
|||
|
|||
switch (type) { |
|||
case DataVariableType: |
|||
resolver = new DataVariable(resolverProps, options); |
|||
break; |
|||
case DataConditionType: { |
|||
resolver = new DataCondition(resolverProps, options); |
|||
break; |
|||
} |
|||
case DataCollectionVariableType: { |
|||
resolver = new DataCollectionVariable(resolverProps, options); |
|||
break; |
|||
} |
|||
default: |
|||
options.em?.logError(`Unsupported dynamic type: ${type}`); |
|||
return; |
|||
} |
|||
|
|||
return resolver; |
|||
} |
|||
|
|||
export function getDataResolverInstanceValue( |
|||
resolverProps: DataResolverProps, |
|||
options: { |
|||
em: EditorModel; |
|||
collectionsStateMap?: DataCollectionStateMap; |
|||
}, |
|||
) { |
|||
const resolver = getDataResolverInstance(resolverProps, options); |
|||
|
|||
return resolver?.getDataValue(); |
|||
} |
|||
|
|||
export const ensureComponentInstance = ( |
|||
cmp: Component | ComponentDefinition | undefined, |
|||
opt: ComponentOptions, |
|||
): Component => { |
|||
if (cmp instanceof Component) return cmp; |
|||
|
|||
const componentType = (cmp?.type as string) ?? 'default'; |
|||
const defaultModel = opt.em.Components.getType('default'); |
|||
const type = opt.em.Components.getType(componentType) ?? defaultModel; |
|||
const Model = type.model; |
|||
|
|||
return new Model(serialize(cmp ?? {}), opt); |
|||
}; |
|||
|
|||
export const isDataConditionDisplayType = (type: string | undefined): type is DataConditionDisplayType => { |
|||
return !!type && [DataConditionIfTrueType, DataConditionIfFalseType].includes(type); |
|||
}; |
|||
@ -1,4 +1,46 @@ |
|||
import ComponentView from '../../dom_components/view/ComponentView'; |
|||
import ComponentDataCondition from '../model/conditional_variables/ComponentDataCondition'; |
|||
import DataResolverListener from '../model/DataResolverListener'; |
|||
|
|||
export default class ComponentDataConditionView extends ComponentView<ComponentDataCondition> {} |
|||
export default class ComponentDataConditionView extends ComponentView<ComponentDataCondition> { |
|||
dataResolverListener!: DataResolverListener; |
|||
|
|||
initialize(opt = {}) { |
|||
super.initialize(opt); |
|||
|
|||
this.postRender = this.postRender.bind(this); |
|||
this.listenTo(this.model.components(), 'reset', this.postRender); |
|||
this.dataResolverListener = new DataResolverListener({ |
|||
em: this.em, |
|||
resolver: this.model.dataResolver, |
|||
onUpdate: this.postRender, |
|||
}); |
|||
} |
|||
|
|||
renderDataResolver() { |
|||
const componentTrue = this.model.getIfTrueContent(); |
|||
const componentFalse = this.model.getIfFalseContent(); |
|||
|
|||
const elTrue = componentTrue?.getEl(); |
|||
const elFalse = componentFalse?.getEl(); |
|||
|
|||
const isTrue = this.model.isTrue(); |
|||
if (elTrue) { |
|||
elTrue.style.display = isTrue ? '' : 'none'; |
|||
} |
|||
if (elFalse) { |
|||
elFalse.style.display = isTrue ? 'none' : ''; |
|||
} |
|||
} |
|||
|
|||
postRender() { |
|||
this.renderDataResolver(); |
|||
super.postRender(); |
|||
} |
|||
|
|||
remove() { |
|||
this.stopListening(this.model.components(), 'reset', this.postRender); |
|||
this.dataResolverListener.destroy(); |
|||
return super.remove(); |
|||
} |
|||
} |
|||
|
|||
File diff suppressed because it is too large
Loading…
Reference in new issue