import { Element } from './element' ; import * as _ from 'lodash' ; import * as Mobx from 'mobx' ; import { PatternSlot } from '../pattern' ; import { Project } from '../project' ; import * as Types from '@meetalva/types' ; import * as uuid from 'uuid' ; export interface ElementContentContext { project : Project ; } export interface ElementContentInit { elementIds : string [ ] ; forcedOpen : boolean ; highlighted : boolean ; id : string ; open : boolean ; parentElementId ? : string ; slotId : string ; } export class ElementContent { public readonly model = Types . ModelName . ElementContent ; @ Mobx . observable private elementIds : string [ ] = [ ] ; @ Mobx . observable private forcedOpen : boolean ; @ Mobx . observable private highlighted : boolean ; @ Mobx . observable private id : string ; @ Mobx . observable private open : boolean ; @ Mobx . observable private parentElementId ? : string ; private project : Project ; @ Mobx . observable private slotId : string ; @ Mobx . computed private get elements ( ) : Element [ ] { return [ ... new Set ( this . elementIds ) ] . map ( id => this . project . getElementById ( id ) ) . filter ( ( element ) : element is Element => typeof element !== 'undefined' ) ; } @ Mobx . computed private get descendants ( ) : Element [ ] { return this . getElements ( ) . reduce < Element [ ] > ( ( acc , element ) => [ ... acc , element , ... element . getDescendants ( ) ] , [ ] ) ; } public constructor ( init , context ) { this . forcedOpen = init . forcedOpen ; this . id = init . id ; this . open = init . open ; this . elementIds = init . elementIds ; this . highlighted = init . highlighted ; this . slotId = init . slotId ; this . project = context . project ; if ( init . parentElementId ) { this . parentElementId = init . parentElementId ; } } public static from ( serialized , context ) { return new ElementContent ( { elementIds : serialized . elementIds , forcedOpen : serialized . forcedOpen , highlighted : serialized . highlighted , id : serialized . id , open : serialized . open , parentElementId : serialized . parentElementId , slotId : serialized . slotId } , context ) ; } public static fromSlot ( slot , context ) { return new ElementContent ( { elementIds : [ ] , forcedOpen : false , highlighted : false , id : uuid . v4 ( ) , open : true , slotId : slot . getId ( ) } , context ) ; } public accepts ( child ) { const parentElementId = this . getParentElementId ( ) ; if ( ! parentElementId ) { return false ; } return ! child . isAncestorOfById ( parentElementId ) && this . acceptsChildren ( ) ; } public acceptsChildren ( ) { return true ; } public equals ( b ) { return _ . isEqual ( b . toJSON ( ) , this . toJSON ( ) ) ; } @ Mobx . action public clone ( opts ) { const withState = Boolean ( opts && opts . withState ) ; const target = opts && opts . target ? opts . target : this . project ; const previousPattern = this . getParentElement ( ) ! . getPattern ( ) ! ; const previousLibrary = previousPattern . getPatternLibrary ( ) ; const nextLibrary = target . getPatternLibraryByContextId ( previousLibrary . contextId ) ! ; const nextPattern = nextLibrary . getPatternByContextId ( previousPattern . getContextId ( ) ) ; const previousSlot = this . getSlot ( ) ! ; const nextSlot = nextPattern ! . getSlotByContextId ( previousSlot . getContextId ( ) ) ! ; const clonedElements = this . elementIds . map ( elementId => this . project . getElementById ( elementId ) ) . filter ( ( e ) : e is Element => typeof e !== 'undefined' ) . map ( e => e . clone ( { withState , target } ) ) ; const clone = new ElementContent ( { elementIds : clonedElements . map ( e => e . getId ( ) ) , forcedOpen : withState ? this . forcedOpen : false , highlighted : withState ? this . highlighted : false , id : uuid . v4 ( ) , open : withState ? this . open : false , slotId : nextSlot . getId ( ) } , { project : target } ) ; clonedElements . forEach ( clonedElement => { target . addElement ( clonedElement ) ; } ) ; return clone ; } public getDescendants ( ) { return this . descendants ; } public getElementIndexById ( id ) { return this . elementIds . indexOf ( id ) ; } public getElements ( ) { return this . elements ; } public getForcedOpen ( ) { return this . forcedOpen ; } public getHighlighted ( ) { return this . highlighted ; } public getId ( ) { return this . id ; } public getOpen ( ) { return this . open ; } public getParentElement ( ) { if ( ! this . parentElementId ) { return ; } return this . project . getElementById ( this . parentElementId ) ; } public getParentElementId ( ) { return this . parentElementId ; } public getSlot ( ) { return this . project . getPatternSlotById ( this . slotId ) ; } public getSlotId ( ) { return this . slotId ; } public getSlotContextId ( ) { const slot = this . getSlot ( ) ; if ( ! slot ) { return ; } return slot . getContextId ( ) ; } public getSlotType ( ) { const slot = this . getSlot ( ) ; return slot ? slot . getType ( ) : undefined ; } @ Mobx . action public insert ( options ) { const id = options . element . getId ( ) ; if ( this . elementIds . find ( eid => eid === id ) ) { return ; } if ( typeof options . at !== 'undefined' ) { this . elementIds . splice ( options . at , 0 , id ) ; } else { this . elementIds . push ( id ) ; } } @ Mobx . action public remove ( options ) { const index = this . elementIds . indexOf ( options . element . getId ( ) ) ; if ( index === - 1 ) { return ; } this . elementIds . splice ( index , 1 ) ; } @ Mobx . action public setForcedOpen ( forcedOpen ) { this . forcedOpen = forcedOpen ; } @ Mobx . action public setHighlighted ( highlighted ) { this . highlighted = highlighted ; } @ Mobx . action public setOpen ( open ) { this . open = open ; } @ Mobx . action public setParentElement ( element ) { this . parentElementId = element . getId ( ) ; } public setProject ( project ) { this . project = project ; } @ Mobx . action public toggleOpen ( ) { this . setOpen ( ! this . getOpen ( ) && ! this . getForcedOpen ( ) ) ; this . setForcedOpen ( false ) ; } public toJSON ( ) { return { model : this . model , elementIds : Array . from ( this . elementIds ) , forcedOpen : this . forcedOpen , highlighted : this . highlighted , id : this . id , open : this . open , parentElementId : this . parentElementId , slotId : this . slotId } ; } @ Mobx . action public update ( b ) { this . elementIds = b . elementIds ; this . forcedOpen = b . forcedOpen ; this . highlighted = b . highlighted ; this . open = b . open ; this . parentElementId = b . parentElementId ; this . slotId = b . slotId ; } }