import * as _ from 'lodash' ; import { Component , OnInit , AfterViewInit , Input , ViewChild , ElementRef , ComponentFactoryResolver , OnDestroy } from '@angular/core' ; import { ViewContainRefHostDirective } from 'src/app/editor/directive/view-contain-ref-host.directive' ; import { SettingObject } from 'src/app/editor/model/setting-object.module' ; import { SettingPage } from 'src/app/editor/model/setting-page.model' ; import { CompConfigService } from 'src/app/editor/provider/comp-config.service' ; import { CompDynamicCreateService } from 'src/app/editor/provider/comp-dynamic-create.service' ; import { Router } from '@angular/router' ; import { EmitSubService } from 'src/app/core/emitSub/emit-sub.service' ; import { EventManager } from '@angular/platform-browser' ; import { SettingObjComponent } from 'src/app/editor/model/setting-object.interface' ; import { AuxiliaryComponent } from 'src/app/editor/comps/comp-lib/tool/auxiliary/auxiliary.component' ; import { AreaComponent } from 'src/app/editor/comps/comp-lib/tool/area/area.component' ; import { AppService } from 'src/app/providers/app.service' ; import { UserAgentService } from 'src/app/core/tool/user-agent.service' ; import { ContentPageSize } from '../model/setting-content-page-size.model' ; import * as $ from 'jquery' ; import { ActivatedRoute } from '@angular/router' ; import { BaseHttpService } from '../../core/provider/baseHttp/base-http.service' ; import { HttpClient } from '@angular/common/http' ; import { Observable , Subscription } from 'rxjs' ; import { CompStorageLocalService } from '../provider/comp-storage-local.service' ; import { TempoToastrService } from 'src/app/core/provider/toaster/toastr.service' ; import removeGhosting from 'remove-drag-ghosting' ; import { IndexDBService } from 'src/app/core/provider/indexDB/indexDB.service' ; @ Component ( { selector : 'app-development' , templateUrl : './development.html' , styleUrls : [ './development.scss' ] } ) export class DevelopmentPageComponent extends BaseHttpService implements OnInit , AfterViewInit , OnDestroy { @ Input ( ) componets : Component [ ] ; @ ViewChild ( ViewContainRefHostDirective , { static : true } ) viewContRef : ViewContainRefHostDirective ; PAGE_URL = 'page' ; pagesUrl = "pages" ; development_setting_bg : string = 'bg-grid' ; componentModules : any [ ] ; basicComponents : any [ ] ; auxiComp : any = { } ; areaComp : any = { } ; cmpRef : any [ ] ; projectId : number ; pageId : number ; currentPage : any ; currentViewContRef : any ; currnetPageComps : any [ ] ; components : any [ ] ; currentIndex = - 1 ; activeCompSettingObject : SettingObject ; multipleChoiceArray : any [ ] = [ ] ; copyComp : any ; copyNum : number ; dragCompStartX : any ; dragCompStartY : any ; PAGE_SIZE : number ; mouseState = { down : false , move : false , up : false } ; compBodyDom : any ; pageList : SettingPage [ ] ; selectPageInfo : SettingPage ; contentPageSize : ContentPageSize ; pageGridSetting = { showLeft : true , showRight : true } ; sub : Subscription ; constructor ( public localStorageService , public emitSerice , private http , private elementRef , private componentFactoryResolver , private service , private infoService , private dynamicService , private activeRoute , private router , private userAgentService , private eventManager , private toaster , public indexDBService ) { super ( http , '' ) ; } ngOnInit ( ) { this . initData ( ) ; } ngOnDestroy ( ) { this . sub . unsubscribe ( ) ; } ngAfterViewInit ( ) { this . compBodyDom = this . elementRef . nativeElement . querySelector ( '#componentsBody' ) ; this . compBodyDom . addEventListener ( 'click' , this . clickListernerHandle . bind ( this ) ) ; this . compBodyDom . addEventListener ( 'mousedown' , this . selectArea . bind ( this ) ) ; this . compBodyDom . addEventListener ( 'mousemove' , this . selectArea . bind ( this ) ) ; this . compBodyDom . addEventListener ( 'mouseup' , this . selectArea . bind ( this ) ) ; this . getPageSize ( ) ; } getPageSize ( ) { let contetDom = this . elementRef . nativeElement . querySelector ( '#componentsBody' ) ; this . contentPageSize [ 'left' ] = contetDom . offsetLeft ; this . contentPageSize [ 'top' ] = contetDom . offsetTop ; } initData ( ) { this . currentViewContRef = this . viewContRef . viewContainerRef ; this . currnetPageComps = null ; this . auxiComp = this . infoService . getAuxiComp ( ) ; this . areaComp = this . infoService . getAreaComp ( ) ; this . contentPageSize = { top : 0 , left : 0 , rigth : 0 , bottom : 0 } ; this . getRouteParams ( ) ; this . eventListener ( ) ; this . eventEmitterSub ( ) ; } getRouteParams ( ) { this . activeRoute . queryParams . subscribe ( res => { this . projectId = res [ 'projectId' ] ; this . pageId = res [ 'project' ] ; } ) ; } eventEmitterSub ( ) { let parentCompList = _ . cloneDeep ( this . currnetPageComps ) ; this . sub = this . emitSerice . getEmitEvent ( ) . subscribe ( res => { if ( res && res [ 'type' ] === 'child-comp' ) { let data = res [ 'data' ] ; let currentList = _ . concat ( parentCompList , data ) ; this . initViewContRef ( ) ; this . getCompList ( currentList ) ; } } ) ; } eventListener ( ) { this . eventManager . addGlobalEventListener ( 'window' , 'keydown' , ( $event ) => { if ( ! this . activeCompSettingObject ) { return ; } let del_window = this . userAgentService . isWindows && $event && $event . code === 'Delete' ; let del_mac = this . userAgentService . isMac && $event && $event . code === 'Backspace' && $event . keyCode === 8 ; let activeEleBool = document . activeElement && document . activeElement [ 'selectionStart' ] !== undefined ; let _doc = document . activeElement as unknown as NodeListOf < HTMLElement > ; let _delCompItem = $event && $event [ 'target' ] && $event [ 'target' ] [ 'class' ] && $event [ 'target' ] [ 'classList' ] . indexOf ( 'comp-item' ) > - 1 ; if ( ( del_window || del_mac && ( activeEleBool === false || activeEleBool && ! _doc [ 'value' ] && _delCompItem ) || ( del_mac && $event . ctrlKey && this . activeCompSettingObject ) ) || ( ( del_window || del_mac ) && $event . ctrlKey ) ) { this . delCompEvet ( $event ) ; } else if ( $event . ctrlKey && this . currentIndex >= 0 ) { if ( $event . code === 'KeyC' || $event . code === 'KeyV' ) { this . copyCompEvet ( $event ) ; } } else if ( [ 'ArrowLeft' , 'ArrowRight' , 'ArrowDown' , 'ArrowUp' ] . indexOf ( $event . code ) > - 1 && this . activeCompSettingObject ) { this . arrowEvent ( $event . code , $event ) ; } } ) ; } dragCompEnd ( event ) { let compType = event && event [ 'compType' ] || 'text' ; this . addComponent ( compType , event ) ; } addComponent ( compType ? , event ? , addComp ? ) { let compDefinInfo = this . dynamicService . createComponent ( compType , this . infoService . getCompDefaultConfig ( compType ) ) ; let addCompJson = addComp || compDefinInfo && compDefinInfo [ 'data' ] ; this . initCompsState ( ) ; if ( compType && event ) { this . initCopyState ( ) ; this . getAuxiliaryComponent ( null , 'addComponent' ) ; if ( addCompJson && addCompJson [ 'style' ] ) { let _top = event [ 'y' ] - this . contentPageSize . top || addCompJson [ 'style' ] [ 'top' ] ; let _left = event [ 'x' ] - this . contentPageSize . left || addCompJson [ 'style' ] [ 'left' ] ; addCompJson [ 'style' ] [ 'top' ] = _top >= 0 ? _top : 0 ; addCompJson [ 'style' ] [ 'left' ] = _left >= 0 ? _left : 0 ; addCompJson [ 'contentPageSize' ] = this . contentPageSize ; addCompJson [ 'active' ] = true ; } } this . currnetPageComps . push ( addCompJson ) ; this . currentIndex = this . currnetPageComps . length - 1 ; let currentComp = this . dynamicService . getComp ( addCompJson ) ; this . activeCompSettingObject = addCompJson ; this . components . push ( currentComp ) ; this . renderComponent ( this . currentIndex ) ; } initCompsState ( ) { this . currentIndex = - 1 ; this . activeCompSettingObject = null ; _ . map ( this . currnetPageComps , ( item , k ) => { item [ 'active' ] = false ; } ) ; } chengeComponent ( event ) { let settingObj = event ; let compInstance = this . components [ this . currentIndex ] ; return ( < SettingObjComponent > compInstance ) . settingObj = settingObj ; } clickListernerHandle ( e ) { if ( ! this . currnetPageComps ) return ; this . initCompsState ( ) ; this . getPageSize ( ) ; let currentComp = this . currnetPageComps [ this . currentIndex ] ; if ( currentComp && currentComp [ 'type' ] === 'text' ) { currentComp [ 'editeabled' ] = false ; } this . getAuxiliaryComponent ( null , 'parentListerner' ) ; } initViewContRef ( ) { if ( ! this . components ) return ; this . currentViewContRef . clear ( ) ; } deleteComponent ( event ) { let _delComp = this . currentIndex ; this . getAuxiliaryComponent ( null , 'deleteComponent' ) ; if ( _delComp > - 1 ) { this . initViewContRef ( ) ; this . currnetPageComps . splice ( _delComp , 1 ) ; this . getCompList ( this . currnetPageComps ) ; } this . initCompsState ( ) ; } getCompList ( jsonList ) { this . components = this . dynamicService . getCompList ( jsonList ) ; this . updateComponent ( this . components ) ; } updateComponent ( compList ) { compList . forEach ( ( comp , k ) => { this . renderComponent ( k ) ; } ) ; } renderComponent ( currentIndex ) { let currentComponent = this . components [ currentIndex ] ; let compFactory = this . componentFactoryResolver . resolveComponentFactory ( currentComponent . compType ) ; let compRef = this . currentViewContRef . createComponent ( compFactory ) ; let compInstance = compRef . instance ; let changeX = 0 ; let changeY = 0 ; ( < SettingObjComponent > compInstance ) . settingObj = currentComponent . settingObj ; ( compInstance ) . onChildComponentChange . subscribe ( ( e ) => { removeGhosting ( e ) ; if ( e && e . stopPropagation ) { e . stopPropagation ( ) ; let eventType = e && e . type ; let style = currentComponent . settingObj && currentComponent . settingObj [ 'style' ] ; if ( e [ 'ignoreDragBool' ] ) { } else if ( eventType === 'dragstart' ) { this . dragCompStartX = e . clientX ; this . dragCompStartY = e . clientY ; changeX = this . dragCompStartX - style [ 'left' ] ; changeY = this . dragCompStartY - style [ 'top' ] ; } else if ( eventType === 'drag' ) { if ( e . clientY === 0 && e . clientY === 0 ) return ; style [ 'left' ] = ( e . clientX - changeX ) >= 0 ? ( e . clientX - changeX ) : 0 ; style [ 'top' ] = ( e . clientY - changeY ) >= 0 ? ( e . clientY - changeY ) : 0 ; } if ( eventType === 'dragend' ) { style [ 'left' ] = style [ 'left' ] >= 0 ? style [ 'left' ] : 0 ; style [ 'top' ] = style [ 'top' ] >= 0 ? style [ 'top' ] : 0 ; } this . selectComp ( currentComponent . settingObj , eventType ) ; this . initCopyState ( ) ; } } ) ; } selectComp ( settingObj , eventType ) { this . activeCompSettingObject = settingObj ; this . getActiveComponent ( settingObj ) ; if ( eventType === 'click' ) { this . getAuxiliaryComponent ( settingObj [ 'style' ] , 'selectComponent' ) ; } } getActiveComponent ( settingObj ) { this . initCompsState ( ) ; _ . map ( this . currnetPageComps , ( comp , k ) => { if ( comp === settingObj ) { this . currentIndex = k ; comp [ 'active' ] = true ; this . activeCompSettingObject = settingObj ; } } ) ; } getCurrentPage ( page ) { this . initViewContRef ( ) ; this . currentPage = page ; let localComp = this . localStorageService . getPreViceComponent ( ) ; let useLocal = localComp && JSON . parse ( localComp ) . length > 0 ; let comps = useLocal ? JSON . parse ( localComp ) : page [ 'componentList' ] && JSON . parse ( page [ 'componentList' ] ) || [ ] ; this . router . navigate ( [ '/develop' ] , { queryParams : { project : page [ 'projectId' ] , page : page [ 'id' ] } } ) ; this . currnetPageComps = comps ; this . initPageCompState ( ) ; this . getCompList ( comps ) ; this . activeCompSettingObject = null ; this . getAuxiliaryComponent ( null , 'deleteComponent' ) ; } activeComp ( comp ) { this . initPageCompState ( ) ; this . clickListernerHandle ( null ) ; comp [ 'active' ] = true ; this . activeCompSettingObject = comp ; _ . map ( this . currnetPageComps , ( item , k ) => { if ( item [ 'active' ] ) { this . currentIndex = k ; } } ) ; this . getAuxiliaryComponent ( this . activeCompSettingObject [ 'style' ] , 'selectComponent' ) ; } initPageCompState ( ) { _ . map ( this . currnetPageComps , item => { if ( [ 'area' , 'auxi' ] . indexOf ( item [ 'type' ] ) === - 1 ) { item [ 'active' ] = false ; } } ) ; } getAuxiliaryComponent ( selectStyle ? , eventType ? ) { /**
         * 1.parentListerner 监听父类容器
         * 2.selectComponent 选择动态组件
         * 3.addComponent 添加组件
         * 4.deleteComponent 删除组件
         */ this . auxiCompInit ( ) ; if ( eventType === 'selectComponent' && this . activeCompSettingObject && this . activeCompSettingObject [ 'type' ] !== 'line' ) { this . auxiComp = this . infoService . getAuxiComp ( ) ; this . auxiComp [ 'style' ] = selectStyle ; this . auxiComp [ 'contentPageSize' ] = this . contentPageSize ; this . currnetPageComps . push ( this . auxiComp ) ; let compFactory = this . componentFactoryResolver . resolveComponentFactory ( AuxiliaryComponent ) ; let compRef = this . currentViewContRef . createComponent ( compFactory ) ; let compInstance = compRef . instance ; ( < SettingObjComponent > compInstance ) . settingObj = this . auxiComp ; } } auxiCompInit ( ) { let auxiIndex = _ . findIndex ( this . currnetPageComps , function ( item ) { return item [ 'type' ] == 'auxi' ; } ) ; if ( auxiIndex > - 1 ) { this . components . splice ( auxiIndex , 1 ) ; this . currnetPageComps . splice ( auxiIndex , 1 ) ; this . currentViewContRef . remove ( auxiIndex ) ; } } preView ( ) { this . auxiCompInit ( ) ; let comps = this . initPageComponentsStatus ( ) ; this . localStorageService . setPreViewPageInfo ( JSON . stringify ( this . currentPage ) ) ; this . localStorageService . setPreViewComponent ( JSON . stringify ( comps ) ) ; this . router . navigate ( [ '/workspace/develop/preview' ] , { queryParams : { project : this . projectId , page : this . pageId } } ) ; } addPage ( event ) { Observable . forkJoin ( this . create ( { } , this . PAGE_URL ) ) . subscribe ( res => { } ) ; } savePage ( ) { let page = this . initPageStatus ( ) ; let comps = this . initPageComponentsStatus ( ) ; let compString = JSON . stringify ( comps ) ; page [ 'componentList' ] = compString ; Observable . forkJoin ( [ this . indexDBService . updateData ( this . pagesUrl , page ) ] ) . subscribe ( res => { this . emitSerice . setEmitEvent ( 'update-projects' ) ; this . toaster . showToaster ( { state : this . toaster . STATE . SUCCESS , info : '页面更新成功' } ) ; } , error => { this . toaster . showToaster ( { state : this . toaster . STATE . ERROR , info : '页面更新失败' } ) ; } ) ; } initPageStatus ( ) { let _page = _ . cloneDeep ( this . currentPage ) ; delete _page [ 'actived' ] ; return _page ; } initPageComponentsStatus ( ) { let _comps = _ . cloneDeep ( this . currnetPageComps ) ; let _auxiIndex = _ . findIndex ( _comps , function ( item ) { return item [ 'type' ] == 'auxi' ; } ) ; if ( _auxiIndex > - 1 ) { _comps . splice ( _auxiIndex , 1 ) ; } _ . map ( _comps , item => { delete item [ 'active' ] ; } ) ; return _comps ; } delCompEvet ( event ) { this . deleteComponent ( event ) ; } copyCompEvet ( event ) { if ( event [ 'key' ] === 'c' ) { this . initCopyState ( ) ; let currComp = this . currnetPageComps [ this . currentIndex ] ; this . copyComp = _ . cloneDeep ( currComp ) ; this . copyComp [ 'active' ] = false ; this . getAuxiliaryComponent ( null , 'addComponent' ) ; } else if ( event [ 'key' ] === 'v' && this . copyComp ) { ++ this . copyNum ; let _copyComp = _ . cloneDeep ( this . copyComp ) ; let _top = _copyComp && _copyComp [ 'style' ] && _copyComp [ 'style' ] [ 'top' ] ; let _height = _copyComp && _copyComp [ 'style' ] && _copyComp [ 'style' ] [ 'height' ] ; _copyComp [ 'style' ] [ 'top' ] = _top + _height * this . copyNum ; this . addComponent ( null , null , _copyComp ) ; } } arrowEvent ( direction , event ) { let styleObj = this . activeCompSettingObject && this . activeCompSettingObject [ 'style' ] ; switch ( direction ) { case 'ArrowLeft' : styleObj [ 'left' ] = styleObj [ 'left' ] > 0 ? styleObj [ 'left' ] - 1 : 0 ; this . stopWindowScroll ( event ) ; break ; case 'ArrowRight' : styleObj [ 'left' ] = styleObj [ 'left' ] + 1 ; this . stopWindowScroll ( event ) ; break ; case 'ArrowDown' : if ( ! $ ( 'input:focus' ) [ 'length' ] ) { styleObj [ 'top' ] = styleObj [ 'top' ] >= 0 ? styleObj [ 'top' ] + 1 : 0 ; this . stopWindowScroll ( event ) ; } else if ( $ ( 'input:focus' ) && $ ( 'input:focus' ) [ 'length' ] > 0 && $ ( 'input:focus' ) [ 0 ] [ 'id' ] === 'setTopVal' ) { styleObj [ 'top' ] = styleObj [ 'top' ] >= 0 ? styleObj [ 'top' ] - 1 : 0 ; } break ; case 'ArrowUp' : if ( ! $ ( 'input:focus' ) [ 'length' ] ) { styleObj [ 'top' ] = styleObj [ 'top' ] >= 1 ? styleObj [ 'top' ] - 1 : 0 ; this . stopWindowScroll ( event ) ; } else if ( $ ( 'input:focus' ) && $ ( 'input:focus' ) [ 'length' ] > 0 && $ ( 'input:focus' ) [ 0 ] [ 'id' ] === 'setTopVal' ) { styleObj [ 'top' ] = styleObj [ 'top' ] >= 1 ? styleObj [ 'top' ] + 1 : 0 ; } break ; } } stopWindowScroll ( event ) { event . preventDefault ( ) ; } initCopyState ( ) { this . copyComp = null ; this . copyNum = null ; } selectArea ( event ) { let state = event && event [ 'type' ] ; let _left = this . areaComp [ 'style' ] [ 'left' ] ; let _top = this . areaComp [ 'style' ] [ 'top' ] ; switch ( state ) { case 'mousedown' : this . mouseState [ 'down' ] = true ; this . mouseState [ 'up' ] = false ; this . mouseState [ 'move' ] = false ; if ( this . areaComp && this . areaComp [ 'style' ] ) { this . areaComp [ 'style' ] [ 'left' ] = event . x - this . contentPageSize . left ; this . areaComp [ 'style' ] [ 'top' ] = event . y - this . contentPageSize . top ; } break ; case 'mousemove' : if ( this . mouseState [ 'down' ] && ! this . mouseState [ 'move' ] && event . ctrlKey ) { this . mouseState [ 'move' ] = true ; this . mouseState [ 'up' ] = false ; this . areaCompInit ( 'add' ) ; } else if ( this . mouseState [ 'down' ] ) { let _w = event . x - _left - this . contentPageSize . left ; let _h = event . y - _top - this . contentPageSize . top ; if ( _w > 1 ) { this . areaComp [ 'style' ] [ 'right' ] = null ; this . areaComp [ 'style' ] [ 'width' ] = _w ; } else { this . areaComp [ 'style' ] [ 'right' ] = this . areaComp [ 'style' ] [ 'right' ] || _left ; this . areaComp [ 'style' ] [ 'left' ] = event . x - this . contentPageSize . left ; this . areaComp [ 'style' ] [ 'width' ] = this . areaComp [ 'style' ] [ 'right' ] - _left ; } if ( _h > 1 ) { this . areaComp [ 'style' ] [ 'bottom' ] = null ; this . areaComp [ 'style' ] [ 'height' ] = _h ; } else { this . areaComp [ 'style' ] [ 'bottom' ] = this . areaComp [ 'style' ] [ 'bottom' ] || _top ; this . areaComp [ 'style' ] [ 'top' ] = event . y - this . contentPageSize . top ; this . areaComp [ 'style' ] [ 'height' ] = this . areaComp [ 'style' ] [ 'bottom' ] - _top ; } } break ; case 'mouseup' : this . mouseState [ 'down' ] = false ; this . mouseState [ 'up' ] = true ; this . mouseState [ 'move' ] = false ; this . areaCompInit ( ) ; break ; } } areaCompInit ( state ? ) { let areaIndex = _ . findIndex ( this . currnetPageComps , function ( item ) { return item [ 'type' ] == 'area' ; } ) ; if ( areaIndex === - 1 && state === 'add' ) { this . areaComp = this . infoService . getAreaComp ( ) ; this . currnetPageComps . push ( this . areaComp ) ; let compFactory = this . componentFactoryResolver . resolveComponentFactory ( AreaComponent ) ; let compRef = this . currentViewContRef . createComponent ( compFactory ) ; let compInstance = compRef . instance ; ( < SettingObjComponent > compInstance ) . settingObj = this . areaComp ; } else if ( areaIndex > - 1 ) { this . delAreaComp ( ) ; } } delAreaComp ( ) { let areaIndex = _ . findIndex ( this . currnetPageComps , function ( item ) { return item [ 'type' ] == 'area' ; } ) ; if ( areaIndex > - 1 ) { this . currnetPageComps . splice ( areaIndex , 1 ) ; this . currentViewContRef . remove ( areaIndex ) ; this . initViewContRef ( ) ; this . getCompList ( this . currnetPageComps ) ; } } changeBg ( event ) { this . development_setting_bg = event === 'open' ? 'bg-grid' : 'bg-blank' || this . development_setting_bg ; } }