import { Component, OnInit, Input, Directive, TemplateRef, ContentChild, Output, EventEmitter, ViewChild, ElementRef, Renderer2, ViewContainerRef } from '@angular/core'; import { IResizeEvent } from '@farris/ui-draggable'; @Directive({ selector: '[listNavHeader]' }) export class listNavHeaderTemplateDirective { constructor(public template: TemplateRef) { } } @Directive({ selector: '[listNavContent]' }) export class listNavContentTemplateDirective { constructor(public template: TemplateRef) { } } @Directive({ selector: '[listNavFooter]' }) export class listNavFooterTemplateDirective { constructor(public template: TemplateRef) { } } @Component({ selector: 'farris-list-nav', templateUrl: './list-nav.component.html', styleUrls: ['./list-nav.component.scss'] }) export class ListNavComponent implements OnInit { @ContentChild(listNavHeaderTemplateDirective, { read: TemplateRef }) HeaderTemplate: TemplateRef; @ContentChild(listNavContentTemplateDirective, { read: TemplateRef }) NavContentTemplate: TemplateRef; @ContentChild(listNavFooterTemplateDirective, { read: TemplateRef }) NavFooterTemplate: TemplateRef; /**收起折叠状态变化 */ @Output('navStateChange') navStateChange = new EventEmitter(); /** emitted when start resizing */ @Output() rzStart = new EventEmitter(); /** emitted when start resizing */ @Output() rzResizing = new EventEmitter(); /** emitted when stop resizing */ @Output() rzStop = new EventEmitter(); // 拖拽元素 @ViewChild('draggableWrapper') draggableWrapper: ElementRef; /**listnav 名称*/ @Input() title: string; /** * listnav宽度 * 不支持百分比,因为此处的宽度被用在内部是外部 */ @Input() listNavWidth: number = 218; // 初始收起状态 private initCollapse = false; // 初始时,是否隐藏Nav @Input() set hideNav(value) { if (value !== undefined && value !== null) { if (this.initCollapse !== value) { this.initCollapse = value; // this.toggleInitCollapseState(); } } } get hideNav() { return this.initCollapse; } // 显示入口 @Input() showEntry = true; //--未使用 @Input() hover: boolean = false; // 控件禁用 @Input() disabled: boolean = false; @Input() position: 'left' | 'right'|'top'|'bottom' = 'left'; // 拖拽到某个值时,自动收起的阈值。如果阈值设置小于0,则不处理自动收起 @Input() resizeCollapseThreshold = 20; // 启用拖拽功能 @Input() enableDraggable = false; // 设置拖拽的最小值 @Input() rzMinWidth:number=null; // 设置拖拽的方向 @Input() rzHandles: 'e' | 's' | 'n' | 'w' = 'e'; // 处理关联变动中,另外一处有iframe,iframe影响拖拽的性能 private _relatedIframeParent: string | ElementRef | any; // 记录真实的iframe父容器 private _relatedContainer = null; // 标记iframe父容器的样式属性position的值 private _relatedContainerPosition = ""; // 记录iframe在拖拽时的遮罩层 private _relatedIframeOverlay = null; // 标记iframe遮罩层是否已显示 private _iframeOverlayShownFlag = false; @Input() set relatedIframeParent(value: string | ElementRef | any) { this._relatedIframeParent=value; this.getRelatedIframeParent(value); } get relatedIframeParent() { return this._relatedContainer; } // collapse的动画样式名 private animateCls = "splitter-pane-collapse-animate"; // 标记是否需要更新变量 private updateParamsFlag = false; // 标记拖拽时上次的大小 private resizeDistance = -1; // 当前元素 private el:HTMLElement; /** * 原构造函数是没有参数的 * @param elementRef * @param renderer */ constructor(private elementRef: ElementRef, private renderer: Renderer2) { } ngOnInit() { if(this.elementRef){ this.compatibleEl(); } } ngAfterViewInit() { if(!this.el){ this.compatibleEl(); } } /** * 兼容旧表单写法 */ private compatibleEl() { this.el = this.elementRef.nativeElement; // 设置了iframe容器,但是没有创建遮罩 if (this._relatedIframeParent && !this._relatedIframeOverlay) { this.getRelatedIframeParent(this._relatedIframeParent); } } /** * 点击収折 * @param event */ toggle(event) { event&&event.stopPropagation(); if (this.disabled) { return; } // 初始没有加上这个样式,是避免初始设置收起的时候,看到有収折的动画 this.renderer&&this.renderer.addClass(this.el.querySelector('.f-list-nav-in'), this.animateCls); this.initCollapse=!this.initCollapse; this.navStateChange.emit({ 'showNav': !this.hideNav }); } //--未使用 hoverToggle(event) { this.hideNav = !this.hideNav; this.navStateChange.emit({ 'showNav': !this.hideNav }); } /** * 拖拽的变化中事件 * 如果超过阈值,不处理 * 暂未处理拖拽最大、最小值的问题 */ onRZResizing(pos) { if (pos && pos["size"]) { let changeProp = this.getStyleProp(); let resizeDirection = ""; if (this.resizeDistance >= 0) { // 开始记录后 // 此次值比上次记录大,说明在expand resizeDirection = pos["size"][changeProp] > this.resizeDistance ? "expand" : "collapse"; } this.resizeDistance = pos["size"][changeProp]; if (resizeDirection == "expand" && this.initCollapse) { this.initCollapse = false; } if ( pos["size"][changeProp] > this.resizeCollapseThreshold || !resizeDirection ) { // 拖拽速度快的时候,会漏掉计算的时机 return; } if (this.resizeCollapseThreshold > 0) { // 设置了自动収折阈值 if (!this.initCollapse && resizeDirection == "collapse") { // 处理拖拽収折过程中,自动收起;不处理展开过程中的,自动展开 if ( pos["actions"] && pos["actions"].hasOwnProperty("stopResize") ) { pos["actions"]["stopResize"](); } this.toggle(null); } } else { // 未设置自动収折阈值,需要单独处理 即将收起时状态、即将展开时状态 if (resizeDirection == "collapse") { if (pos["size"][changeProp] < 3 && !this.initCollapse) { this.initCollapse = true; } } } } this.rzResizing.emit(pos); } // 拖拽的开始的事件 onRZStart(pos) { // 禁用収折 if (this.draggableWrapper.nativeElement.className.indexOf(this.animateCls) > -1) { this.renderer.removeClass(this.draggableWrapper.nativeElement, this.animateCls); } // 如果有iframe遮罩并且没有显示 if (this._relatedIframeOverlay && !this._iframeOverlayShownFlag) { if ( ["relative", "absolute"].indexOf( this._relatedContainerPosition ) < 0 ) { this.renderer.setStyle( this._relatedContainer, "position", "relative" ); } this.renderer.setStyle( this._relatedIframeOverlay, "display", "block" ); this._iframeOverlayShownFlag = true; } if ( !this.updateParamsFlag && pos["actions"] && pos["actions"].hasOwnProperty("updateParams") ) { pos["actions"]["updateParams"]({ fixedEdge: true }); this.updateParamsFlag = true; } this.rzStart.emit(pos); } // 拖拽的停止事件 onRZStop(pos) { this.resizeDistance = -1; // 如果有iframe遮罩并且显示了 if (this._relatedIframeOverlay && this._iframeOverlayShownFlag) { if ( ["relative", "absolute"].indexOf( this._relatedContainerPosition ) < 0 ) { this.renderer.setStyle( this._relatedContainer, "position", this._relatedContainerPosition ); } this.renderer.setStyle( this._relatedIframeOverlay, "display", "none" ); this._iframeOverlayShownFlag = false; } this.rzStop.emit(pos); } /** * 布局排列不一样,影响到是设置宽度还是高度 */ private getStyleProp() { let hori = ["left", "right"].findIndex( item => item == this.position ); return hori > -1 ? "width" : "height"; } /** * 规范获取iframe所在的父容器 */ private getRelatedIframeParent(content) { if (!content || !this.elementRef) { this._relatedContainer = null; } if (content instanceof ElementRef) { this._relatedContainer = content.nativeElement; } else if (typeof content == "string") { this._relatedContainer = this.elementRef.nativeElement.parentElement.querySelector( content ); } else { this._relatedContainer = content; } if (this._relatedContainer) { this._relatedContainerPosition = this._relatedContainer["style"][ "position" ]; // 构造遮罩层 this._relatedIframeOverlay = this.renderer.createElement("div"); this._relatedIframeOverlay.className = "f-utils-absolute-all"; this.renderer.setStyle( this._relatedIframeOverlay, "display", "none" ); this.renderer.appendChild( this._relatedContainer, this._relatedIframeOverlay ); } } }