UNPKG

@syncfusion/ej2-filemanager

Version:
1,192 lines (1,130 loc) 69.1 kB
import { ListBase, ListBaseOptions, ItemCreatedArgs } from '@syncfusion/ej2-lists'; import { createElement, select, selectAll, EventHandler, KeyboardEvents, closest, DragEventArgs, Draggable, Fetch } from '@syncfusion/ej2-base'; import { isNullOrUndefined as isNOU, addClass, removeClass, Touch, TapEventArgs, isVisible } from '@syncfusion/ej2-base'; import { TouchEventArgs, MouseEventArgs, KeyboardEventArgs, getValue, setValue, remove } from '@syncfusion/ej2-base'; import { IFileManager, FileOpenEventArgs, FileLoadEventArgs } from '../base/interface'; import { FileSelectEventArgs, NotifyArgs, FileSelectionEventArgs } from '../base/interface'; import { DataManager, Query, DataUtil } from '@syncfusion/ej2-data'; import { hideSpinner, showSpinner } from '@syncfusion/ej2-popups'; import * as events from '../base/constant'; import { ReadArgs, MouseArgs, BeforeImageLoadEventArgs } from '../../index'; import * as CLS from '../base/classes'; import { createCheckBox } from '@syncfusion/ej2-buttons'; import { read, GetDetails, Delete, triggerFetchFailure, triggerFetchSuccess } from '../common/operations'; import { doRename, getAccessClass, getPathObject, getFullPath, getDirectoryPath, rename, doDownload, getItemName } from '../common/index'; import { removeBlur, cutFiles, copyFiles, addBlur, openSearchFolder, removeActive, pasteHandler } from '../common/index'; import { createVirtualDragElement, dragStopHandler, dragStartHandler, draggingHandler, getModule } from '../common/index'; import { updateRenamingData, doDeleteFiles, doDownloadFiles } from '../common/index'; import { openAction, fileType, refresh, getImageUrl, getSortedData, createDeniedDialog, updateLayout, getLocaleText } from '../common/utility'; import { createEmptyElement, hasReadAccess, hasEditAccess } from '../common/utility'; import { createDialog, createImageDialog } from '../pop-up/dialog'; /** * LargeIconsView module */ export class LargeIconsView { /* Internal variables */ private parent: IFileManager; public element: HTMLElement; public listObj: ListBaseOptions; private keyboardModule: KeyboardEvents; private keyboardDownModule: KeyboardEvents; private keyConfigs: { [key: string]: string }; private isInteraction: boolean = true; public itemList: HTMLElement[]; // specifies the current view items in large icon public items: Object[]; public allItems: Object[]; private clickObj: Touch; private perRow: number; private startItem: Element; private multiSelect: boolean; public listElements: HTMLElement; public uploadOperation: boolean = false; private count: number = 0; private isRendered: boolean = true; private tapCount: number = 0; private isSelectAllCalled: boolean = false; private tapEvent: TapEventArgs; private isPasteOperation: boolean = false; private dragObj: Draggable; private isInteracted: boolean = true; private imageEventArgsMap: Map<string, BeforeImageLoadEventArgs> = new Map<string, BeforeImageLoadEventArgs>(); private imageUrlCache: Map<string, string> = new Map<string, string>(); /** * Constructor for the LargeIcons module. * * @param {IFileManager} parent - specifies the parent element. * @hidden */ constructor(parent?: IFileManager) { this.parent = parent; this.element = <HTMLElement>select('#' + this.parent.element.id + CLS.LARGEICON_ID, this.parent.element); addClass([this.element], CLS.LARGE_ICONS); this.addEventListener(); this.keyConfigs = { end: 'end', home: 'home', tab: 'tab', moveDown: 'downarrow', moveLeft: 'leftarrow', moveRight: 'rightarrow', moveUp: 'uparrow', ctrlEnd: 'ctrl+end', ctrlHome: 'ctrl+home', ctrlDown: 'ctrl+downarrow', ctrlLeft: 'ctrl+leftarrow', ctrlRight: 'ctrl+rightarrow', ctrlUp: 'ctrl+uparrow', shiftEnd: 'shift+end', shiftHome: 'shift+home', shiftDown: 'shift+downarrow', shiftLeft: 'shift+leftarrow', shiftRight: 'shift+rightarrow', shiftUp: 'shift+uparrow', csEnd: 'ctrl+shift+end', csHome: 'ctrl+shift+home', csDown: 'ctrl+shift+downarrow', csLeft: 'ctrl+shift+leftarrow', csRight: 'ctrl+shift+rightarrow', csUp: 'ctrl+shift+uparrow', space: 'space', ctrlSpace: 'ctrl+space', shiftSpace: 'shift+space', csSpace: 'ctrl+shift+space', ctrlA: 'ctrl+a', enter: 'enter', altEnter: 'alt+enter', esc: 'escape', del: 'delete', ctrlX: this.parent.isMac ? 'cmd+x' : 'ctrl+x', ctrlC: this.parent.isMac ? 'cmd+c' : 'ctrl+c', ctrlV: this.parent.isMac ? 'cmd+v' : 'ctrl+v', f2: 'f2', shiftdel: 'shift+delete', back: 'backspace', ctrlD: 'ctrl+d' }; } private render(args: ReadArgs): void { this.parent.visitedItem = null; this.startItem = null; showSpinner(this.parent.element); if (this.parent.view === 'LargeIcons') { this.resetMultiSelect(); this.element.setAttribute('tabindex', '0'); if (this.listObj) { this.unWireEvents(); this.removeEventListener(); } this.parent.notify(events.hideLayout, {}); const iconsView: Element = select('#' + this.parent.element.id + CLS.LARGEICON_ID, this.parent.element); const ul: HTMLUListElement = select('ul', iconsView) as HTMLUListElement; if (ul) { remove(ul); } this.listObj = { ariaAttributes: { itemRole: 'option', listRole: 'listbox', itemText: '', groupItemRole: 'group', wrapperRole: '' }, showIcon: true, fields: { text: 'name', iconCss: '_fm_icon', imageUrl: '_fm_imageUrl', imageAttributes: '_fm_imageAttr', htmlAttributes: '_fm_htmlAttr' }, sortOrder: this.parent.sortOrder, itemCreated: this.onItemCreated.bind(this), enableHtmlSanitizer: this.parent.enableHtmlSanitizer }; this.items = []; this.items = this.renderList(args); if (this.parent.sortComparer && this.parent.sortBy !== 'None'){ this.items = this.allItems = DataUtil.sort(this.items, this.parent.sortBy, this.comparer.bind(this) as Function); } else { this.items = this.allItems = getSortedData(this.parent, this.items); } iconsView.classList.remove(CLS.DISPLAY_NONE); if (this.parent.enableVirtualization && this.allItems.length > 0 && !isNOU(this.parent.virtualizationModule)) { this.parent.virtualizationModule.setUIVirtualization(); } this.listElements = ListBase.createListFromJson(createElement, <{ [key: string]: Object; }[]>this.items, this.listObj); this.itemList = Array.prototype.slice.call(selectAll('.' + CLS.LIST_ITEM, this.listElements)); this.element.appendChild(this.listElements); if (this.imageEventArgsMap.size > 0) { this.loadImages(); } this.listElements.setAttribute('aria-label', 'listbox'); this.preventImgDrag(); this.createDragObj(); if (this.itemList.length === 0) { const emptyList: Element = this.element.querySelector('.' + CLS.LIST_PARENT); this.element.removeChild(emptyList); createEmptyElement(this.parent, this.element, args); } else if (this.itemList.length !== 0 && this.element.querySelector('.' + CLS.EMPTY)) { this.element.removeChild(this.element.querySelector('.' + CLS.EMPTY)); } if (this.isPasteOperation === true) { this.selectItems(this.parent.pasteNodes); this.isPasteOperation = false; } /* istanbul ignore next */ if (this.uploadOperation === true) { this.selectItems(this.parent.uploadItem); this.parent.setProperties({ selectedItems: [] }, true); this.count++; if (this.count === this.parent.uploadItem.length) { this.uploadOperation = false; this.parent.uploadItem = []; } } const activeEle: NodeListOf<Element> = this.element.querySelectorAll('.' + CLS.ACTIVE); if (activeEle.length !== 0) { this.parent.activeModule = 'largeiconsview'; } for (let i: number = 0; i < activeEle.length; i++) { activeEle[i as number].setAttribute('aria-selected', 'true'); } this.element.style.maxHeight = '100%'; this.getItemCount(); this.addEventListener(); this.wireEvents(); if (this.parent.enableVirtualization && this.allItems.length > 0 && !isNOU(this.parent.virtualizationModule)) { this.parent.virtualizationModule.setUlElementHeight(); this.parent.virtualizationModule.wireScrollEvent(false); } this.isRendered = true; hideSpinner(this.parent.element); if (this.parent.selectedItems.length) { this.checkItem(); } } } private loadImages(): void { const imageEle: NodeListOf<Element> = this.parent.element.querySelectorAll('.e-list-img'); imageEle.forEach((imgElement: HTMLElement) => { const imageKey: string = imgElement.getAttribute('data-image-key'); if (!imageKey) {return; } if (this.imageUrlCache.has(imageKey)) { imgElement.setAttribute('src', this.imageUrlCache.get(imageKey)); imgElement.classList.remove('image-blur'); return; } const imageDetails: BeforeImageLoadEventArgs = this.imageEventArgsMap.get(imageKey); if (!imageDetails) {return; } const fetch: Fetch = new Fetch({ url: getValue('url', imageDetails.ajaxSettings), type: getValue('type', imageDetails.ajaxSettings), contentType: getValue('contentType', imageDetails.ajaxSettings), responseType: getValue('responseType', imageDetails.ajaxSettings), beforeSend: getValue('beforeSend', imageDetails.ajaxSettings), onSuccess: (blob: Blob) => { const blobUrl: string = URL.createObjectURL(blob); this.imageUrlCache.set(imageKey, blobUrl); imgElement.setAttribute('src', blobUrl); imgElement.classList.remove('image-blur'); triggerFetchSuccess(this.parent, imageDetails.ajaxSettings); }, onFailure: (response: Response) => { const result: ReadArgs = { files: null, error: { code: response.status ? response.status.toString() : '404', message: getLocaleText(this.parent, 'Network-Error') + ' ' + getValue('url', imageDetails.ajaxSettings), fileExists: null } }; triggerFetchFailure(this.parent, imageDetails.ajaxSettings, result); } }); fetch.send(getValue('data', imageDetails.ajaxSettings)); }); } private comparer (x: number | string, y: number | string): number | string { if (this.parent.sortOrder === 'Descending') { const z: number | string = x; x = y; y = z; } return (this.parent.sortComparer as Function)(x, y); } private preventImgDrag(): void { let i: number = 0; while (i < this.itemList.length) { if (this.itemList[i as number].querySelector('img')) { /* istanbul ignore next */ this.itemList[i as number].ondragstart = () => { return false; }; } i++; } } private createDragObj(): void { if (this.listObj) { if (this.parent.allowDragAndDrop) { if (this.dragObj) { this.dragObj.destroy(); } this.dragObj = new Draggable(this.listElements, { enableTailMode: true, distance: 5, enableAutoScroll: false, dragTarget: '.' + CLS.LARGE_ICON, helper: this.dragHelper.bind(this), cursorAt: this.parent.dragCursorPosition, dragArea: this.parent.element, dragStop: dragStopHandler.bind(this, this.parent), drag: draggingHandler.bind(this, this.parent), clone: true, dragStart: (args: DragEventArgs) => { dragStartHandler(this.parent, args, this.dragObj); } }); } else if (this.dragObj && !this.parent.allowDragAndDrop) { this.dragObj.destroy(); } } } public dragHelper(args: { element: HTMLElement, sender: MouseEvent & TouchEvent }): HTMLElement { const dragTarget: Element = <Element>args.sender.target; const dragLi: Element = closest(dragTarget, '.e-list-item'); if (!dragLi) { return null; } if (dragLi && !dragLi.classList.contains('e-active')) { this.setFocus(dragLi); } const activeEle: NodeListOf<Element> = this.element.querySelectorAll('.' + CLS.ACTIVE); this.parent.activeElements = []; this.parent.dragData = []; for (let i: number = 0; i < activeEle.length; i++) { this.parent.dragData.push(<{ [key: string]: Object; }>this.getItemObject(activeEle[parseInt(i.toString(), 10)])); this.parent.activeElements.push(activeEle[i as number]); } getModule(this.parent, dragLi); this.parent.dragPath = this.parent.path; createVirtualDragElement(this.parent); return this.parent.virtualDragElement; } private onDropInit(args: DragEventArgs): void { if (this.parent.targetModule === this.getModuleName()) { const dropLi: Element = closest(args.target, '.e-list-item'); const cwdData: Object = getValue(this.parent.pathId[this.parent.pathId.length - 1], this.parent.feParent); if (dropLi) { const info: { [key: string]: Object; } = <{ [key: string]: Object; }>this.getItemObject(dropLi); this.parent.dropPath = info.isFile ? this.parent.path : getFullPath(this.parent, info, this.parent.path); this.parent.dropData = info.isFile ? cwdData : info; } else { this.parent.dropPath = this.parent.path; this.parent.dropData = cwdData; } } } /** * For internal use only - Get the module name. * * @returns {string} - returns the module name. * @private */ private getModuleName(): string { return 'largeiconsview'; } private onItemCreated(args: ItemCreatedArgs): void { args.item.removeAttribute('aria-level'); if (!this.parent.showFileExtension && getValue('isFile', args.curData)) { const textEle: Element = args.item.querySelector('.' + CLS.LIST_TEXT); const txt: string = getValue('name', args.curData); const type: string = getValue('type', args.curData); if (txt.indexOf(type) !== -1) { textEle.innerHTML = txt.substr(0, txt.length - type.length); } } this.renderCheckbox(args); const eventArgs: FileLoadEventArgs = { element: args.item, fileDetails: args.curData, module: 'LargeIconsView' }; this.parent.trigger('fileLoad', eventArgs); } private renderCheckbox(args: ItemCreatedArgs): void { if (!this.parent.showItemCheckBoxes) { return; } const checkElement: Element = createCheckBox(createElement, false, { checked: false, cssClass: 'e-small' }); checkElement.setAttribute('role', 'checkbox'); checkElement.setAttribute('aria-checked', 'false'); checkElement.setAttribute('aria-label', 'checkbox'); args.item.firstElementChild.insertBefore(checkElement, args.item.firstElementChild.childNodes[0]); } private onLayoutChange(args: ReadArgs): void { if (this.parent.view === 'LargeIcons') { this.destroy(); if (this.parent.enableVirtualization) { this.parent.setProperties({ selectedItems: [] }, true); } this.render(args); /* istanbul ignore next */ if (getValue('name', args) === 'layout-change' && this.parent.fileAction === 'move' && this.parent.isCut && this.parent.selectedNodes && this.parent.selectedNodes.length !== 0) { const indexes: number[] = this.getIndexes(this.parent.selectedNodes); let length: number = 0; while (length < indexes.length) { addBlur(this.itemList[indexes[length as number]]); length++; } } const activeEle: NodeListOf<Element> = this.element.querySelectorAll('.' + CLS.ACTIVE); if (activeEle.length !== 0) { this.element.focus(); } this.checkItem(); this.parent.isLayoutChange = false; } else { this.element.setAttribute('tabindex', '-1'); } } private checkItem(): void { const checkEle: NodeListOf<Element> = this.element.querySelectorAll('.' + CLS.ACTIVE); if (checkEle) { let checkLength: number = 0; while (checkLength < checkEle.length) { this.checkState(checkEle[checkLength as number], true); checkLength++; } } } private renderList(args?: ReadArgs): Object[] { let i: number = 0; const items: Object[] = JSON.parse(JSON.stringify(args.files)); while (i < items.length) { const icon: string = fileType(items[i as number]); const name: string = getValue('name', items[i as number]); const selected: string = getItemName(this.parent, items[i as number]); let className: string = ((this.parent.selectedItems && this.parent.selectedItems.indexOf(selected) !== -1)) ? CLS.LARGE_ICON + ' e-active' : CLS.LARGE_ICON; if (!hasEditAccess(items[i as number])) { className += ' ' + getAccessClass(items[i as number]); } if (icon === CLS.ICON_IMAGE && this.parent.showThumbnail && hasReadAccess(items[i as number])) { const imageData: BeforeImageLoadEventArgs = getImageUrl(this.parent, items[i as number]); if (imageData.useImageAsUrl) { setValue('_fm_imageUrl', imageData.imageUrl, items[i as number]); setValue('_fm_imageAttr', { alt: name }, items[i as number]); } else { const uniqueKey: string = `img_${name}_${i}`; this.imageEventArgsMap.set(uniqueKey, imageData); setValue('_fm_imageUrl', '', items[i as number]); setValue('_fm_imageAttr', {alt: name, class: 'e-list-img image-blur', 'data-image-key': uniqueKey }, items[i as number]); } } else { setValue('_fm_icon', icon, items[i as number]); } setValue('_fm_htmlAttr', { class: className, title: name }, items[i as number]); i++; } return items; } private onFinalizeEnd(args: ReadArgs): void { this.render(args); } private onCreateEnd(args: ReadArgs): void { if (this.parent.view !== 'LargeIcons') { return; } this.onLayoutChange(args); this.clearSelect(); this.selectItems([getValue(this.parent.hasId ? 'id' : 'name', this.parent.createdItem)]); this.parent.createdItem = null; this.parent.largeiconsviewModule.element.focus(); this.parent.activeModule = 'largeiconsview'; } private onSelectedData(): void { if (this.parent.activeModule === 'largeiconsview') { this.updateSelectedData(); } } private onDeleteInit(): void { if (this.parent.activeModule === 'largeiconsview') { Delete(this.parent, this.parent.selectedItems, this.parent.path, 'delete'); } } /* istanbul ignore next */ private onDeleteEnd(args: ReadArgs): void { if (this.parent.view !== 'LargeIcons') { return; } this.onLayoutChange(args); this.parent.setProperties({ selectedItems: [] }, true); this.clearSelect(); } private onRefreshEnd(args: ReadArgs): void { if (this.parent.view !== 'LargeIcons') { return; } this.onLayoutChange(args); } private onRenameInit(): void { if (this.parent.activeModule === 'largeiconsview' && this.parent.selectedItems.length === 1) { this.updateRenameData(); } } private onPathChanged(args: ReadArgs): void { this.parent.isCut = false; /* istanbul ignore next */ if (this.parent.breadcrumbbarModule.searchObj.element.value === '') { this.parent.searchedItems = []; } if (this.parent.view === 'LargeIcons') { removeBlur(this.parent); this.parent.setProperties({ selectedItems: [] }, true); this.onLayoutChange(args); if (this.parent.renamedItem && this.parent.activeModule === 'largeiconsview') { this.clearSelect(); this.addSelection(this.parent.renamedItem); } } } private onOpenInit(args: NotifyArgs): void { if (this.parent.activeModule === 'largeiconsview') { this.doOpenAction(args.target); } } private onHideLayout(): void { if (this.parent.view !== 'LargeIcons' && this.element) { this.element.classList.add(CLS.DISPLAY_NONE); } } private onSelectAllInit(): void { if (this.parent.view === 'LargeIcons') { this.startItem = this.getFirstItem(); const lastItem: Element = this.getLastItem(); const eveArgs: KeyboardEventArgs = { ctrlKey: true, shiftKey: true } as KeyboardEventArgs; this.doSelection(lastItem, eveArgs); this.isInteraction = true; this.isInteracted = true; } } private onClearAllInit(): void { if (this.parent.view === 'LargeIcons') { this.clearSelection(); this.isInteraction = true; this.isInteracted = true; } } private onBeforeRequest(): void { this.isRendered = false; } private onAfterRequest(): void { this.isRendered = true; } /* istanbul ignore next */ private onSearch(args: ReadArgs): void { if (this.parent.view === 'LargeIcons') { this.parent.setProperties({ selectedItems: [] }, true); this.parent.notify(events.selectionChanged, {}); this.parent.searchedItems = args.files; this.onLayoutChange(args); } } private onLayoutRefresh(): void { if (this.parent.view !== 'LargeIcons') { return; } } private onUpdateSelectionData(): void { if (this.parent.view !== 'LargeIcons') { return; } this.updateSelectedData(); } private onPathColumn(): void { if (this.parent.view === 'LargeIcons' && !isNOU(this.listObj) && this.parent.breadcrumbbarModule.searchObj.element.value === '' && !this.parent.isFiltered && this.parent.sortBy === 'filterPath') { this.parent.sortBy = 'name'; this.parent.notify(events.sortByChange, {}); } } private removeEventListener(): void { if (this.parent.isDestroyed) { return; } this.parent.off(events.pathColumn, this.onPathColumn); this.parent.off(events.finalizeEnd, this.onFinalizeEnd); this.parent.off(events.createEnd, this.onCreateEnd); this.parent.off(events.selectedData, this.onSelectedData); this.parent.off(events.deleteInit, this.onDeleteInit); this.parent.off(events.deleteEnd, this.onDeleteEnd); this.parent.off(events.refreshEnd, this.onRefreshEnd); this.parent.off(events.pathChanged, this.onPathChanged); this.parent.off(events.layoutChange, this.onLayoutChange); this.parent.off(events.search, this.onSearch); this.parent.off(events.openInit, this.onOpenInit); this.parent.off(events.openEnd, this.onPathChanged); this.parent.off(events.modelChanged, this.onPropertyChanged); this.parent.off(events.methodCall, this.onMethodCall); this.parent.off(events.actionFailure, this.onActionFailure); this.parent.off(events.renameInit, this.onRenameInit); this.parent.off(events.renameEnd, this.onPathChanged); this.parent.off(events.hideLayout, this.onHideLayout); this.parent.off(events.selectAllInit, this.onSelectAllInit); this.parent.off(events.clearAllInit, this.onClearAllInit); this.parent.off(events.menuItemData, this.onMenuItemData); this.parent.off(events.beforeRequest, this.onBeforeRequest); this.parent.off(events.afterRequest, this.onAfterRequest); this.parent.off(events.splitterResize, this.splitterResizeHandler); this.parent.off(events.resizeEnd, this.resizeHandler); this.parent.off(events.pasteInit, this.onpasteInit); this.parent.off(events.pasteEnd, this.onpasteEnd); this.parent.off(events.cutCopyInit, this.oncutCopyInit); this.parent.off(events.dropInit, this.onDropInit); this.parent.off(events.detailsInit, this.onDetailsInit); this.parent.off(events.layoutRefresh, this.onLayoutRefresh); this.parent.off(events.dropPath, this.onDropPath); this.parent.off(events.updateSelectionData, this.onUpdateSelectionData); this.parent.off(events.filterEnd, this.onPathChanged); } private addEventListener(): void { this.parent.on(events.pathColumn, this.onPathColumn, this); this.parent.on(events.finalizeEnd, this.onFinalizeEnd, this); this.parent.on(events.createEnd, this.onCreateEnd, this); this.parent.on(events.refreshEnd, this.onRefreshEnd, this); this.parent.on(events.selectedData, this.onSelectedData, this); this.parent.on(events.pathChanged, this.onPathChanged, this); this.parent.on(events.deleteInit, this.onDeleteInit, this); this.parent.on(events.pasteInit, this.onpasteInit, this); this.parent.on(events.deleteEnd, this.onDeleteEnd, this); this.parent.on(events.layoutChange, this.onLayoutChange, this); this.parent.on(events.search, this.onSearch, this); this.parent.on(events.openInit, this.onOpenInit, this); this.parent.on(events.renameInit, this.onRenameInit, this); this.parent.on(events.renameEnd, this.onPathChanged, this); this.parent.on(events.openEnd, this.onPathChanged, this); this.parent.on(events.modelChanged, this.onPropertyChanged, this); this.parent.on(events.methodCall, this.onMethodCall, this); this.parent.on(events.actionFailure, this.onActionFailure, this); this.parent.on(events.hideLayout, this.onHideLayout, this); this.parent.on(events.selectAllInit, this.onSelectAllInit, this); this.parent.on(events.clearAllInit, this.onClearAllInit, this); this.parent.on(events.menuItemData, this.onMenuItemData, this); this.parent.on(events.beforeRequest, this.onBeforeRequest, this); this.parent.on(events.afterRequest, this.onAfterRequest, this); this.parent.on(events.dropInit, this.onDropInit, this); this.parent.on(events.detailsInit, this.onDetailsInit, this); this.parent.on(events.splitterResize, this.splitterResizeHandler, this); this.parent.on(events.resizeEnd, this.resizeHandler, this); this.parent.on(events.pasteEnd, this.onpasteEnd, this); this.parent.on(events.cutCopyInit, this.oncutCopyInit, this); this.parent.on(events.layoutRefresh, this.onLayoutRefresh, this); this.parent.on(events.dropPath, this.onDropPath, this); this.parent.on(events.updateSelectionData, this.onUpdateSelectionData, this); this.parent.on(events.filterEnd, this.onPathChanged, this); } private onActionFailure(): void { this.isInteraction = true; this.isInteracted = true; } private onMenuItemData(args: { [key: string]: Object; }): void { if (this.parent.activeModule === this.getModuleName()) { const ele: Element = closest(<Element>args.target, 'li'); this.parent.itemData = [this.getItemObject(ele)]; } } private onDetailsInit(): void { if (this.parent.activeModule === this.getModuleName()) { if (this.parent.selectedItems.length !== 0) { this.updateSelectedData(); } else { this.parent.itemData = [getValue(this.parent.pathId[this.parent.pathId.length - 1], this.parent.feParent)]; } } } private onpasteInit(): void { if (this.parent.activeModule === this.getModuleName()) { this.parent.itemData = (this.parent.folderPath === '') ? [getPathObject(this.parent)] : [this.getItemObject(select('.e-active', this.element))]; } } private oncutCopyInit(): void { if (this.parent.activeModule === this.getModuleName()) { const activeEle: NodeListOf<Element> = this.element.querySelectorAll('.' + CLS.ACTIVE); this.parent.activeRecords = []; this.parent.activeElements = []; for (let i: number = 0; i < activeEle.length; i++) { this.parent.activeElements.push(activeEle[i as number]); this.parent.activeRecords.push(this.getItemObject(activeEle[i as number])); } } } private onpasteEnd(args: ReadArgs): void { if (this.parent.view === 'LargeIcons') { this.isPasteOperation = true; if (this.parent.path === this.parent.destinationPath || this.parent.path === getDirectoryPath(this.parent, args) || this.parent.hasId) { this.onPathChanged(args); } } } private onDropPath(args: ReadArgs): void { if (this.parent.view === 'LargeIcons') { this.isPasteOperation = true; this.onPathChanged(args); } } private onPropertyChanged(e: NotifyArgs): void { let currentSelected: string[]; if (e.module !== this.getModuleName() && e.module !== 'common') { return; } for (const prop of Object.keys(e.newProp)) { switch (prop) { case 'allowDragAndDrop': this.createDragObj(); break; case 'selectedItems': this.isInteraction = false; this.isInteracted = false; currentSelected = isNOU(this.parent.selectedItems) ? [] : this.parent.selectedItems.slice(0); currentSelected = this.parent.allowMultiSelection ? currentSelected : currentSelected.slice(currentSelected.length - 1); this.parent.setProperties({ selectedItems: [] }, true); this.onClearAllInit(); if (currentSelected.length) { this.selectItems(currentSelected); } this.parent.setProperties({ selectedItems: this.parent.selectedItems }, true); this.isInteraction = true; this.isInteracted = true; break; case 'showThumbnail': refresh(this.parent); break; case 'showFileExtension': read(this.parent, events.pathChanged, this.parent.path); break; case 'showHiddenItems': read(this.parent, events.pathChanged, this.parent.path); break; case 'allowMultiSelection': case 'showItemCheckBoxes': if (this.parent.view !== 'LargeIcons') { break; } refresh(this.parent); break; case 'view': updateLayout(this.parent, 'LargeIcons'); break; } } } public destroy(): void { if (this.parent.isDestroyed) { return; } this.removeEventListener(); if (this.listObj) { this.unWireEvents(); } this.startItem = null; this.listElements = null; } private wireEvents(): void { this.wireClickEvent(true); this.keyboardModule = new KeyboardEvents( this.element, { keyAction: this.keyActionHandler.bind(this), keyConfigs: this.keyConfigs, eventName: 'keyup' } ); this.keyboardDownModule = new KeyboardEvents( this.element, { keyAction: this.keydownActionHandler.bind(this), keyConfigs: this.keyConfigs, eventName: 'keydown' } ); EventHandler.add(this.element, 'mouseover', this.onMouseOver, this); } private unWireEvents(): void { this.wireClickEvent(false); EventHandler.remove(this.element, 'mouseover', this.onMouseOver); this.keyboardModule.destroy(); this.keyboardDownModule.destroy(); } /* istanbul ignore next */ private onMouseOver(e: MouseArgs): void { const targetEle: Element = closest(e.target, '.e-list-item'); removeBlur(this.parent, 'hover'); if (targetEle !== null) { targetEle.classList.add(CLS.HOVER); } } private wireClickEvent(toBind: boolean): void { if (toBind) { this.clickObj = new Touch(this.element, { tap: (eve: TapEventArgs) => { if (this.parent.isDevice) { this.tapCount = eve.tapCount; this.tapEvent = eve; setTimeout( () => { if (this.tapCount > 0) { this.doTapAction(this.tapEvent); } this.tapCount = 0; }, 350); } else { if (eve.tapCount === 2 && eve.originalEvent.which !== 3) { this.dblClickHandler(eve); } else { this.clickHandler(eve); } } }, tapHold: (e: TapEventArgs) => { if (this.parent.isDevice) { this.multiSelect = this.parent.allowMultiSelection ? true : false; if (this.parent.allowMultiSelection) { addClass([this.parent.element], CLS.MULTI_SELECT); } this.clickHandler(e); } } }); } else { if (this.clickObj) { this.clickObj.destroy(); } } } private doTapAction(eve: TapEventArgs): void { const target: Element = <Element>eve.originalEvent.target; const item: Element = closest(target, '.' + CLS.LIST_ITEM); if (this.multiSelect || target.classList.contains(CLS.LIST_PARENT) || isNOU(item)) { this.clickHandler(eve); } else { this.parent.isFile = false; this.updateType(item); if (!this.parent.isFile) { this.dblClickHandler(eve); } else if (eve.tapCount === 2) { this.clickHandler(eve); this.dblClickHandler(eve); } else { this.clickHandler(eve); } } } private clickHandler(e: TapEventArgs): void { const target: Element = <Element>e.originalEvent.target; removeBlur(this.parent, 'hover'); this.doSelection(target, e.originalEvent); this.parent.activeModule = 'largeiconsview'; } /** * * @param {Element} target - specifies the target element. * @param {TouchEventArgs | MouseEventArgs | KeyboardEventArgs} e - specifies event arguements. * @returns {void} * @hidden */ public doSelection(target: Element, e: TouchEventArgs | MouseEventArgs | KeyboardEventArgs): void { const ctrlKey: boolean = this.parent.isMac ? e.metaKey : e.ctrlKey; const isMacRightClick: boolean = this.parent.isMac && e.ctrlKey && e.shiftKey; const item: Element = closest(target, '.' + CLS.LIST_ITEM); const cList: DOMTokenList = target.classList; this.parent.isFile = false; let action: string = 'select'; if ((e.which === 3 || isMacRightClick) && !isNOU(item) && item.classList.contains(CLS.ACTIVE)) { this.addActive(item); this.updateType(item); return; } else if (!isNOU(item)) { if (this.parent.allowMultiSelection && item.classList.contains(CLS.ACTIVE) && (ctrlKey || target.classList.contains(CLS.CHECK))) { action = 'unselect'; } if (ctrlKey && e.shiftKey && !isMacRightClick) { this.isSelectAllCalled = true; } const fileSelectionArgs: FileSelectionEventArgs = this.triggerSelection(action, item); if (fileSelectionArgs.cancel !== true) { if ((!this.parent.allowMultiSelection || (!this.multiSelect && (e && !ctrlKey))) && !cList.contains(CLS.FRAME)) { this.updateType(item); this.clearSelect(); } if (this.parent.allowMultiSelection && e.shiftKey && !isMacRightClick) { if (!(e && ctrlKey)) { this.clearSelect(); } if (!this.startItem) { this.startItem = item; } const startIndex: number = this.itemList.indexOf(<HTMLElement>this.startItem); const endIndex: number = this.itemList.indexOf(<HTMLElement>item); if (startIndex > endIndex) { for (let i: number = startIndex; i >= endIndex; i--) { this.addActive(this.itemList[i as number]); } } else { for (let i: number = startIndex; i <= endIndex; i++) { this.addActive(this.itemList[i as number]); } } this.addFocus(this.itemList[endIndex as number]); } else { this.startItem = item; if (this.parent.allowMultiSelection && item.classList.contains(CLS.ACTIVE)) { this.removeActive(item); } else { this.addActive(item); } this.addFocus(item); } if (this.parent.selectedItems.length === 0) { this.resetMultiSelect(); } this.parent.notify(events.selectionChanged, {}); this.triggerSelect(action, item); } } else { if (this.parent.selectedItems.length === this.itemList.length) { this.isSelectAllCalled = true; } this.clearSelection(); } if (!isNOU(item)) { this.isSelectAllCalled = false; this.updateType(item); } } private dblClickHandler(e: TapEventArgs): void { this.parent.activeModule = 'largeiconsview'; const target: Element = <Element>e.originalEvent.target; this.doOpenAction(target); } private clearSelection(): void { this.clearSelect(); this.resetMultiSelect(); this.parent.notify(events.selectionChanged, {}); } private resetMultiSelect(): void { this.multiSelect = false; removeClass([this.parent.element], CLS.MULTI_SELECT); } private doOpenAction(target: Element): void { if (isNOU(target)) { return; } const item: Element = closest(target, '.' + CLS.LIST_ITEM); this.parent.isFile = false; if (!isNOU(item)) { this.updateType(item); const details: Object = this.getItemObject(item); if (!hasReadAccess(details)) { createDeniedDialog(this.parent, details, events.permissionRead); return; } const eventArgs: FileOpenEventArgs = { cancel: false, fileDetails: details, module: 'LargeIconsView' }; this.parent.trigger('fileOpen', eventArgs, (fileOpenArgs: FileOpenEventArgs) => { if (!fileOpenArgs.cancel) { const text: string = getValue('name', details); if (!this.parent.isFile) { const val: string = this.parent.breadcrumbbarModule.searchObj.element.value; if (val === '' && !this.parent.isFiltered) { const id: string = getValue('id', details); this.parent.oldPath = this.parent.path; const newPath: string = this.parent.path + (isNOU(id) ? text : id) + '/'; this.parent.setProperties({ path: newPath }, true); this.parent.pathNames.push(text); this.parent.pathId.push(getValue('_fm_id', details)); this.parent.itemData = [details]; openAction(this.parent); } else { openSearchFolder(this.parent, details); } this.parent.isFiltered = false; this.parent.setProperties({ selectedItems: [] }, true); } else { const icon: string = fileType(details); if (icon === CLS.ICON_IMAGE) { const imageData: BeforeImageLoadEventArgs = getImageUrl(this.parent, details); createImageDialog(this.parent, text, imageData); } } } }); } } private updateType(item: Element): void { const folder: Element = select('.' + CLS.FOLDER, item); this.parent.isFile = isNOU(folder) ? true : false; } /* istanbul ignore next */ private keydownActionHandler(e: KeyboardEventArgs): void { if (!this.isRendered) { return; } switch (e.action) { case 'end': case 'home': case 'moveDown': case 'moveLeft': case 'moveRight': case 'moveUp': case 'ctrlEnd': case 'shiftEnd': case 'csEnd': case 'ctrlHome': case 'shiftHome': case 'csHome': case 'ctrlDown': case 'shiftDown': case 'csDown': case 'ctrlLeft': case 'shiftLeft': case 'csLeft': case 'ctrlRight': case 'shiftRight': case 'csRight': case 'space': case 'ctrlSpace': case 'shiftSpace': case 'csSpace': case 'ctrlA': case 'enter': case 'altEnter': case 'esc': case 'del': case 'shiftdel': case 'ctrlC': case 'ctrlV': case 'ctrlX': case 'f2': case 'ctrlD': e.preventDefault(); break; default: break; } } /* istanbul ignore next */ private keyActionHandler(e: KeyboardEventArgs): void { if (!this.isRendered) { return; } const fItem: Element = this.getFocusedItem(); const firstItem: Element = this.getFirstItem(); const lastItem: Element = this.getLastItem(); switch (e.action) { case 'end': if (this.parent.enableVirtualization) { this.clearSelect(); this.element.firstElementChild.scrollTo(0, this.element.firstElementChild.scrollHeight); setTimeout(() => { this.navigateItem(this.itemList[this.itemList.length - 1]); }, 10); } else { this.navigateItem(lastItem); } break; case 'home': if (this.parent.enableVirtualization) { this.clearSelect(); this.element.firstElementChild.scrollTop = 0; setTimeout(() => { this.navigateItem(this.itemList[0]); }, 10); } else { this.navigateItem(firstItem); } break; case 'tab': if (!isNOU(fItem)) { this.addFocus(fItem); } else if (!isNOU(firstItem)) { this.addFocus(firstItem); } break; case 'moveDown': this.navigateDown(fItem, true); break; case 'moveLeft': this.navigateRight(fItem, false); break; case 'moveRight': this.navigateRight(fItem, true); break; case 'moveUp': this.navigateDown(fItem, false); break; case 'ctrlEnd': case 'shiftEnd': case 'csEnd': this.csEndKey(lastItem, e); break; case 'ctrlHome': case 'shiftHome': case 'csHome': this.csHomeKey(firstItem, e); break; case 'ctrlDown': case 'shiftDown': case 'csDown': this.csDownKey(fItem, e); break; case 'ctrlLeft': case 'shiftLeft': case 'csLeft': this.csLeftKey(fItem, e); break; case 'ctrlRight': case 'shiftRight': case 'csRight': this.csRightKey(fItem, e); break; case 'ctrlUp': case 'shiftUp': case 'csUp': this.csUpKey(fItem, e); break; case 'space': this.spaceKey(fItem); break; case 'ctrlSpace': case 'shiftSpace': case 'csSpace': if (!isNOU(fItem)) { this.doSelection(fItem, e); } break; case 'ctrlA': this.ctrlAKey(firstItem, lastItem); break; case 'enter': this.doOpenAction(this.parent.visitedItem ? this.parent.visitedItem : this.getVisitedItem()); break; case 'altEnter': this.parent.notify(events.detailsInit, {}); GetDetails(this.parent, this.parent.selectedItems, this.parent.path, 'details'); break; case 'esc': removeActive(this.parent); break; case 'del': case 'shiftdel': this.performDelete(); break; case 'ctrlC': copyFiles(this.parent); break; case 'ctrlV': this.parent.folderPath = ''; pasteHandler(this.parent); break; case 'ctrlX': cutFiles(this.parent); break; case 'f2': this.performRename(); break; case 'ctrlD': this.doDownload(); break; case 'back': this.parent.traverseBackward(); break; } } private doDownload(): void { this.updateSelectedData(); doDownload(this.parent); } private performDelete(): void { if (this.parent.selectedItems && this.parent.selectedItems.length > 0) { this.updateSelectedData(); const data: Object[] = this.parent.itemData; for (let i: number = 0; i < data.length; i++) { if (!hasEditAccess(data[i as number])) { createDeniedDialog(this.parent, data[i as number], events.permissionEdit); return; } } createDialog(this.parent, 'Delete'); } } private performRename(): void { if (this.parent.selectedItems.length === 1) { this.updateRenameData(); doRename(this.parent); } } private updateRenameData(): void { const item: Element = select('.' + CLS.LIST_ITEM + '.' + CLS.ACTIVE, this.element); const data: Object = this.getItemObject