import {NgModule,Component,ElementRef,AfterViewInit,AfterContentInit,AfterViewChecked,DoCheck,Input,Output,ContentChildren,QueryList,TemplateRef,EventEmitter,ViewChild} from '@angular/core'; import {CommonModule} from '@angular/common'; import {ButtonModule} from '../button/button'; import {SharedModule,PrimeTemplate} from '../common/shared'; import {DomHandler} from '../dom/domhandler'; import {ObjectUtils} from '../utils/objectutils'; @Component({ selector: 'p-pickList', template: `
{{sourceHeader}}
{{targetHeader}}
`, providers: [DomHandler,ObjectUtils] }) export class PickList implements AfterViewChecked,AfterContentInit { @Input() source: any[]; @Input() target: any[]; @Input() sourceHeader: string; @Input() targetHeader: string; @Input() responsive: boolean; @Input() filterBy: string; @Input() showSourceFilter: boolean = true; @Input() showTargetFilter: boolean = true; @Input() metaKeySelection: boolean = true; @Input() dragdrop: boolean; @Input() dragdropScope: string; @Input() style: any; @Input() styleClass: string; @Input() sourceStyle: any; @Input() targetStyle: any; @Input() showSourceControls: boolean = true; @Input() showTargetControls: boolean = true; @Input() sourceFilterPlaceholder: string; @Input() targetFilterPlaceholder: string; @Input() disabled: boolean = false; @Output() onMoveToSource: EventEmitter = new EventEmitter(); @Output() onMoveAllToSource: EventEmitter = new EventEmitter(); @Output() onMoveAllToTarget: EventEmitter = new EventEmitter(); @Output() onMoveToTarget: EventEmitter = new EventEmitter(); @Output() onSourceReorder: EventEmitter = new EventEmitter(); @Output() onTargetReorder: EventEmitter = new EventEmitter(); @Output() onSourceSelect: EventEmitter = new EventEmitter(); @Output() onTargetSelect: EventEmitter = new EventEmitter(); @ViewChild('sourcelist') listViewSourceChild: ElementRef; @ViewChild('targetlist') listViewTargetChild: ElementRef; @ViewChild('sourceFilter') sourceFilterViewChild: ElementRef; @ViewChild('targetFilter') targetFilterViewChild: ElementRef; @ContentChildren(PrimeTemplate) templates: QueryList; public itemTemplate: TemplateRef; public visibleOptionsSource: any[]; public visibleOptionsTarget: any[]; selectedItemsSource: any[] = []; selectedItemsTarget: any[] = []; reorderedListElement: any; draggedItemIndexSource: number; draggedItemIndexTarget: number; dragOverItemIndexSource: number; dragOverItemIndexTarget: number; dragging: boolean; movedUp: boolean; movedDown: boolean; itemTouched: boolean; filterValueSource: string; filterValueTarget: string; fromListType: number; toListType: number; onListItemDroppoint: boolean; listHighlightTarget: boolean; listHighlightSource: boolean; constructor(public el: ElementRef, public domHandler: DomHandler, public objectUtils: ObjectUtils) {} ngAfterContentInit() { this.templates.forEach((item) => { switch(item.getType()) { case 'item': this.itemTemplate = item.template; break; default: this.itemTemplate = item.template; break; } }); } ngAfterViewChecked() { if(this.movedUp||this.movedDown) { let listItems = this.domHandler.find(this.reorderedListElement, 'li.ui-state-highlight'); let listItem; if(this.movedUp) listItem = listItems[0]; else listItem = listItems[listItems.length - 1]; this.domHandler.scrollInView(this.reorderedListElement, listItem); this.movedUp = false; this.movedDown = false; this.reorderedListElement = null; } } onItemClick(event, item: any, selectedItems: any[], callback: EventEmitter) { if(this.disabled) { return; } let index = this.findIndexInSelection(item,selectedItems); let selected = (index != -1); let metaSelection = this.itemTouched ? false : this.metaKeySelection; if(metaSelection) { let metaKey = (event.metaKey||event.ctrlKey); if(selected && metaKey) { selectedItems.splice(index, 1); } else { if(!metaKey) { selectedItems.length = 0; } selectedItems.push(item); } } else { if(selected) selectedItems.splice(index, 1); else selectedItems.push(item); } callback.emit({originalEvent: event, items: selectedItems}); this.itemTouched = false; } onSourceItemDblClick() { if(this.disabled) { return; } this.moveRight(); } onTargetItemDblClick() { if(this.disabled) { return; } this.moveLeft(); } onFilter(event: KeyboardEvent, data: any[], listType: number) { let query = ( event.target).value.trim().toLowerCase(); if(listType === -1) this.filterValueSource = query; else this.filterValueTarget = query; this.activateFilter(data, listType); } activateFilter(data: any[], listType: number) { let searchFields = this.filterBy.split(','); if(listType === -1) this.visibleOptionsSource = this.objectUtils.filter(data, searchFields, this.filterValueSource); else this.visibleOptionsTarget = this.objectUtils.filter(data, searchFields, this.filterValueTarget); } isItemVisible(item: any, listType: number): boolean { if(listType == -1) return this.isVisibleInList(this.visibleOptionsSource, item, this.filterValueSource); else return this.isVisibleInList(this.visibleOptionsTarget, item, this.filterValueTarget); } isVisibleInList(data: any[], item: any, filterValue: string): boolean { if(filterValue && filterValue.trim().length) { for(let i = 0; i < data.length; i++) { if(item == data[i]) { return true; } } } else { return true; } } onItemTouchEnd(event) { if(this.disabled) { return; } this.itemTouched = true; } private sortByIndexInList(items: any[], list: any) { return items.sort((item1, item2) => this.findIndexInList(item1, list) - this.findIndexInList(item2, list)); } moveUp(listElement, list, selectedItems, callback) { if(selectedItems && selectedItems.length) { selectedItems = this.sortByIndexInList(selectedItems, list); for(let i = 0; i < selectedItems.length; i++) { let selectedItem = selectedItems[i]; let selectedItemIndex: number = this.findIndexInList(selectedItem, list); if(selectedItemIndex != 0) { let movedItem = list[selectedItemIndex]; let temp = list[selectedItemIndex-1]; list[selectedItemIndex-1] = movedItem; list[selectedItemIndex] = temp; } else { break; } } this.movedUp = true; this.reorderedListElement = listElement; callback.emit({items: selectedItems}); } } moveTop(listElement, list, selectedItems, callback) { if(selectedItems && selectedItems.length) { selectedItems = this.sortByIndexInList(selectedItems, list); for(let i = 0; i < selectedItems.length; i++) { let selectedItem = selectedItems[i]; let selectedItemIndex: number = this.findIndexInList(selectedItem, list); if(selectedItemIndex != 0) { let movedItem = list.splice(selectedItemIndex,1)[0]; list.unshift(movedItem); } else { break; } } listElement.scrollTop = 0; callback.emit({items: selectedItems}); } } moveDown(listElement, list, selectedItems, callback) { if(selectedItems && selectedItems.length) { selectedItems = this.sortByIndexInList(selectedItems, list); for(let i = selectedItems.length - 1; i >= 0; i--) { let selectedItem = selectedItems[i]; let selectedItemIndex: number = this.findIndexInList(selectedItem, list); if(selectedItemIndex != (list.length - 1)) { let movedItem = list[selectedItemIndex]; let temp = list[selectedItemIndex+1]; list[selectedItemIndex+1] = movedItem; list[selectedItemIndex] = temp; } else { break; } } this.movedDown = true; this.reorderedListElement = listElement; callback.emit({items: selectedItems}); } } moveBottom(listElement, list, selectedItems, callback) { if(selectedItems && selectedItems.length) { selectedItems = this.sortByIndexInList(selectedItems, list); for(let i = selectedItems.length - 1; i >= 0; i--) { let selectedItem = selectedItems[i]; let selectedItemIndex: number = this.findIndexInList(selectedItem, list); if(selectedItemIndex != (list.length - 1)) { let movedItem = list.splice(selectedItemIndex,1)[0]; list.push(movedItem); } else { break; } } listElement.scrollTop = listElement.scrollHeight; callback.emit({items: selectedItems}); } } moveRight() { if(this.selectedItemsSource && this.selectedItemsSource.length) { for(let i = 0; i < this.selectedItemsSource.length; i++) { let selectedItem = this.selectedItemsSource[i]; if(this.findIndexInList(selectedItem, this.target) == -1) { this.target.push(this.source.splice(this.findIndexInList(selectedItem, this.source),1)[0]); } } this.onMoveToTarget.emit({ items: this.selectedItemsSource }); this.selectedItemsSource = []; } } moveAllRight() { if(this.source) { let movedItems = []; for(let i = 0; i < this.source.length; i++) { if(this.isItemVisible(this.source[i], -1)) { let removedItem = this.source.splice(i, 1)[0]; this.target.push(removedItem); movedItems.push(removedItem); i--; } } this.onMoveToTarget.emit({ items: movedItems }); this.onMoveAllToTarget.emit({ items: movedItems }); this.selectedItemsSource = []; } } moveLeft() { if(this.selectedItemsTarget && this.selectedItemsTarget.length) { for(let i = 0; i < this.selectedItemsTarget.length; i++) { let selectedItem = this.selectedItemsTarget[i]; if(this.findIndexInList(selectedItem, this.source) == -1) { this.source.push(this.target.splice(this.findIndexInList(selectedItem, this.target),1)[0]); } } this.onMoveToSource.emit({ items: this.selectedItemsTarget }); this.selectedItemsTarget = []; } } moveAllLeft() { if(this.target) { let movedItems = []; for(let i = 0; i < this.target.length; i++) { if(this.isItemVisible(this.target[i], 1)) { let removedItem = this.target.splice(i, 1)[0]; this.source.push(removedItem); movedItems.push(removedItem); i--; } } this.onMoveToSource.emit({ items: movedItems }); this.onMoveAllToSource.emit({ items: movedItems }); this.selectedItemsTarget = []; } } isSelected(item: any, selectedItems: any[]) { return this.findIndexInSelection(item, selectedItems) != -1; } findIndexInSelection(item: any, selectedItems: any[]): number { return this.findIndexInList(item, selectedItems); } findIndexInList(item: any, list: any): number { let index: number = -1; if(list) { for(let i = 0; i < list.length; i++) { if(list[i] == item) { index = i; break; } } } return index; } onDragStart(event: DragEvent, index: number, listType: number) { this.dragging = true; this.fromListType = listType; if(listType === -1) this.draggedItemIndexSource = index; else this.draggedItemIndexTarget = index; if(this.dragdropScope) { event.dataTransfer.setData("text", this.dragdropScope); } } onDragOver(event: DragEvent, index: number, listType: number) { if(listType == -1) { if(this.draggedItemIndexSource !== index && this.draggedItemIndexSource + 1 !== index || (this.fromListType === 1)) { this.dragOverItemIndexSource = index; event.preventDefault(); } } else { if(this.draggedItemIndexTarget !== index && this.draggedItemIndexTarget + 1 !== index || (this.fromListType === -1)) { this.dragOverItemIndexTarget = index; event.preventDefault(); } } this.onListItemDroppoint = true; } onDragLeave(event: DragEvent, listType: number) { this.dragOverItemIndexSource = null; this.dragOverItemIndexTarget = null; this.onListItemDroppoint = false; } onDrop(event: DragEvent, index: number, listType: number) { if(this.onListItemDroppoint) { if(listType === -1) { if(this.fromListType === 1) this.insert(this.draggedItemIndexTarget, this.target, index, this.source, this.onMoveToSource); else this.objectUtils.reorderArray(this.source, this.draggedItemIndexSource, (this.draggedItemIndexSource > index) ? index : (index === 0) ? 0 : index - 1); this.dragOverItemIndexSource = null; } else { if(this.fromListType === -1) this.insert(this.draggedItemIndexSource, this.source, index, this.target, this.onMoveToTarget); else this.objectUtils.reorderArray(this.target, this.draggedItemIndexTarget, (this.draggedItemIndexTarget > index) ? index : (index === 0) ? 0 : index - 1); this.dragOverItemIndexTarget = null; } this.listHighlightTarget = false; this.listHighlightSource = false; event.preventDefault(); } } onDragEnd(event: DragEvent) { this.dragging = false; } onListDrop(event: DragEvent, listType: number) { if(!this.onListItemDroppoint) { if(listType === -1) { if(this.fromListType === 1) this.insert(this.draggedItemIndexTarget, this.target, null, this.source, this.onMoveToSource); } else { if(this.fromListType === -1) this.insert(this.draggedItemIndexSource, this.source, null, this.target, this.onMoveToTarget); } this.listHighlightTarget = false; this.listHighlightSource = false; event.preventDefault(); } } insert(fromIndex, fromList, toIndex, toList, callback) { const elementtomove = fromList[fromIndex]; if(toIndex === null) toList.push(fromList.splice(fromIndex, 1)[0]); else toList.splice(toIndex, 0, fromList.splice(fromIndex, 1)[0]); callback.emit({ items: [elementtomove] }); } onListMouseMove(event: MouseEvent, listType: number) { if(this.dragging) { let moveListType = (listType == 0 ? this.listViewSourceChild : this.listViewTargetChild); let offsetY = moveListType.nativeElement.getBoundingClientRect().top + document.body.scrollTop; let bottomDiff = (offsetY + moveListType.nativeElement.clientHeight) - event.pageY; let topDiff = (event.pageY - offsetY); if(bottomDiff < 25 && bottomDiff > 0) moveListType.nativeElement.scrollTop += 15; else if(topDiff < 25 && topDiff > 0) moveListType.nativeElement.scrollTop -= 15; } if(listType === -1) { if(this.fromListType === 1) this.listHighlightSource = true; } else { if(this.fromListType === -1) this.listHighlightTarget = true; } event.preventDefault(); } onListDragLeave() { this.listHighlightTarget = false; this.listHighlightSource = false; } resetFilter() { this.visibleOptionsSource = null; this.filterValueSource = null; this.visibleOptionsTarget = null; this.filterValueTarget = null; ( this.sourceFilterViewChild.nativeElement).value = ''; ( this.targetFilterViewChild.nativeElement).value = ''; } } @NgModule({ imports: [CommonModule,ButtonModule,SharedModule], exports: [PickList,SharedModule], declarations: [PickList] }) export class PickListModule { }