diff --git a/demo-shell-ng2/app/components/files/files.component.html b/demo-shell-ng2/app/components/files/files.component.html index d39543fd10..7d15d01ed5 100644 --- a/demo-shell-ng2/app/components/files/files.component.html +++ b/demo-shell-ng2/app/components/files/files.component.html @@ -18,6 +18,7 @@ [currentFolderId]="currentFolderId" [contextMenuActions]="true" [contentActions]="true" + [allowDropFiles]="true" (error)="onNavigationError($event)" (success)="resetError()" (preview)="showFile($event)"> diff --git a/ng2-components/ng2-alfresco-core/README.md b/ng2-components/ng2-alfresco-core/README.md index f55df51def..9866d8648a 100644 --- a/ng2-components/ng2-alfresco-core/README.md +++ b/ng2-components/ng2-alfresco-core/README.md @@ -43,26 +43,134 @@ necessary configuration, see this [page](https://github.com/Alfresco/alfresco-ng npm install --save ng2-alfresco-core ``` -## Main components and services +## Library content -### Components +- Components + - Context Menu directive + - Material Design directives + - [mdl] + - [alfresco-mdl-button] + - [alfresco-mdl-menu] + - [alfresco-mdl-tabs] +- Directives + - UploadDirective +- Services + - **LogService**, log service implementation + - **NotificationService**, Notification service implementation + - **AlfrescoApiService**, provides access to Alfresco JS API instance + - **AlfrescoAuthenticationService**, main authentication APIs + - **AlfrescoTranslationService**, various i18n-related APIs + - **ContextMenuService**, global context menu APIs -- Context Menu directive -- Material Design directives - - [mdl] - - [alfresco-mdl-button] - - [alfresco-mdl-menu] - - [alfresco-mdl-tabs] -### Services +## UploadDirective -- **LogService**, log service implementation -- **NotificationService**, Notification service implementation -- **AlfrescoApiService**, provides access to Alfresco JS API instance -- **AlfrescoAuthenticationService**, main authentication APIs -- **AlfrescoTranslationService**, various i18n-related APIs -- **ContextMenuService**, global context menu APIs +Allows your components or common HTML elements reacting on File drag and drop in order to upload content. +Used by attaching to an element or component. +### Basic usage + +The directive itself does not do any file management process, +but collects information on dropped files and raises corresponding events instead. + +```html +
+ Drop files here... +
+``` + +It is possible controlling when upload behaviour is enabled/disabled by binding directive to a `boolean` value or expression: + +```html +
...
+
...
+
...
+``` + +### Events + +Once a single or multiple files are dropped on the decorated element the `upload-files` [CustomEvent](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent) is raised. +The DOM event is configured to have `bubbling` enabled, so any component up the component tree can handle, process or prevent it: + +```html +
+
+
+``` + +```ts +onUploadFiles(e: CustomEvent) { + console.log(e.detail.files); + + // your code +} +``` + +Please note that event will be raised only if valid [Files](https://developer.mozilla.org/en-US/docs/Web/API/File) were dropped onto the decorated element. + +The `upload-files` event is cancellable, so you can stop propagation of the drop event to uppper levels in case it has been already handled by your code: + +```ts +onUploadFiles(e: CustomEvent) { + e.stopPropagation(); + e.preventDefault(); + + // your code +} +``` + +It is also possible attaching arbitrary data to each event in order to access it from within external event handlers. +A typical scenario is data tables where you may want to handle also the data row and/or underlying data to be accessible upon files drop. + +You may be using `adf-upload-data` to bind custom values or objects for every event raised: + +```html +
+
+
+
+``` + +As part of the `details` property of the [CustomEvent](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent) you can get access to the following: + +```ts +detail: { + sender: UploadDirective, // directive that raised given event + data: any, // arbitrary data associated (bound) + files: File[] // dropped files +} +``` + +### Styling + +The decorated element gets `adf-upload__dragging` CSS class name in the class list every time files are dragged over it. +This allows changing look and feel of your components in case additional visual indication is required, +for example you may want drawing a dashed border around the table row on drag: + +```html + + + ... + +
+``` + +```css +.adf-upload__dragging > td:first-child { + border-left: 1px dashed rgb(68,138,255); +} + +.adf-upload__dragging > td { + border-top: 1px dashed rgb(68,138,255); + border-bottom: 1px dashed rgb(68,138,255); +} + +.adf-upload__dragging > td:last-child { + border-right: 1px dashed rgb(68,138,255); +} +``` ## Alfresco Api Service @@ -78,7 +186,7 @@ export class MyComponent implements OnInit { ngOnInit() { let nodeId = 'some-node-id'; let params = {}; - this.getAlfrescoApi().nodes + this.apiService.getInstance().nodes .getNodeChildren(nodeId, params) .then(result => console.log(result)); } @@ -92,8 +200,8 @@ In case of any TypeScript type check errors you can still call any supported Alfresco JS api by casting the instance to `any` type like the following:_ ```ts -let apiService: any = this.authService.getAlfrescoApi(); -apiService.nodes.addNode('-root-', body, {}); +let api: any = this.apiService.getInstance(); +api.nodes.addNode('-root-', body, {}); ``` ## Notification Service diff --git a/ng2-components/ng2-alfresco-core/index.ts b/ng2-components/ng2-alfresco-core/index.ts index ea3b9eab5a..a6aa07a0ba 100644 --- a/ng2-components/ng2-alfresco-core/index.ts +++ b/ng2-components/ng2-alfresco-core/index.ts @@ -39,6 +39,7 @@ import { NotificationService } from './src/services/index'; +import { UploadDirective } from './src/directives/upload.directive'; import { DataColumnComponent } from './src/components/data-column/data-column.component'; import { DataColumnListComponent } from './src/components/data-column/data-column-list.component'; import { MATERIAL_DESIGN_DIRECTIVES } from './src/components/material/index'; @@ -48,6 +49,7 @@ export * from './src/services/index'; export * from './src/components/index'; export * from './src/components/data-column/data-column.component'; export * from './src/components/data-column/data-column-list.component'; +export * from './src/directives/upload.directive'; export * from './src/utils/index'; export * from './src/events/base.event'; export * from './src/events/base-ui.event'; @@ -90,6 +92,7 @@ export function createTranslateLoader(http: Http, logService: LogService) { declarations: [ ...MATERIAL_DESIGN_DIRECTIVES, ...CONTEXT_MENU_DIRECTIVES, + UploadDirective, DataColumnComponent, DataColumnListComponent ], @@ -105,6 +108,7 @@ export function createTranslateLoader(http: Http, logService: LogService) { TranslateModule, ...MATERIAL_DESIGN_DIRECTIVES, ...CONTEXT_MENU_DIRECTIVES, + UploadDirective, DataColumnComponent, DataColumnListComponent ] diff --git a/ng2-components/ng2-alfresco-core/src/directives/upload.directive.spec.ts b/ng2-components/ng2-alfresco-core/src/directives/upload.directive.spec.ts new file mode 100644 index 0000000000..166c9afd52 --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/directives/upload.directive.spec.ts @@ -0,0 +1,136 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ElementRef } from '@angular/core'; +import { UploadDirective } from './upload.directive'; + +describe('UploadDirective', () => { + + let directive: UploadDirective; + let nativeElement: any; + + beforeEach(() => { + nativeElement = { + dispatchEvent: () => {} + }; + directive = new UploadDirective(new ElementRef(nativeElement)); + }); + + it('should be enabled by default', () => { + expect(directive.enabled).toBeTruthy(); + }); + + it('should have debug mode switched off by default', () => { + expect(directive.debug).toBeFalsy(); + }); + + it('should update drag status on dragenter', () => { + expect(directive.isDragging).toBeFalsy(); + directive.enabled = true; + directive.onDragEnter(); + expect(directive.isDragging).toBeTruthy(); + }); + + it('should not update drag status on dragenter when disabled', () => { + expect(directive.isDragging).toBeFalsy(); + directive.enabled = false; + directive.onDragEnter(); + expect(directive.isDragging).toBeFalsy(); + }); + + it('should update drag status on dragover', () => { + expect(directive.isDragging).toBeFalsy(); + directive.enabled = true; + directive.onDragOver(null); + expect(directive.isDragging).toBeTruthy(); + }); + + it('should prevent default event on dragover', () => { + let event = new Event('dom-event'); + spyOn(event, 'preventDefault').and.stub(); + directive.enabled = true; + directive.onDragOver(event); + expect(event.preventDefault).toHaveBeenCalled(); + expect(directive.isDragging).toBeTruthy(); + }); + + it('should not update drag status on dragover when disabled', () => { + expect(directive.isDragging).toBeFalsy(); + directive.enabled = false; + directive.onDragOver(null); + }); + + it('should update drag status on dragleave', () => { + directive.enabled = true; + directive.isDragging = true; + directive.onDragLeave(); + expect(directive.isDragging).toBeFalsy(); + }); + + it('should not update drag status on dragleave when disabled', () => { + directive.enabled = false; + directive.isDragging = true; + directive.onDragLeave(); + expect(directive.isDragging).toBeTruthy(); + }); + + it('should prevent default event on drop', () => { + directive.enabled = true; + let event = jasmine.createSpyObj('event', ['preventDefault', 'stopPropagation']); + directive.onDrop(event); + expect(event.preventDefault).toHaveBeenCalled(); + }); + + it('should stop default event propagation on drop', () => { + directive.enabled = true; + let event = jasmine.createSpyObj('event', ['preventDefault', 'stopPropagation']); + directive.onDrop(event); + expect(event.stopPropagation).toHaveBeenCalled(); + }); + + it('should not prevent default event on drop when disabled', () => { + directive.enabled = false; + let event = jasmine.createSpyObj('event', ['preventDefault', 'stopPropagation']); + directive.onDrop(event); + expect(event.preventDefault).not.toHaveBeenCalled(); + }); + + it('should raise upload-files event on files drop', () => { + directive.enabled = true; + let files = [ {}]; + let event = jasmine.createSpyObj('event', ['preventDefault', 'stopPropagation']); + spyOn(directive, 'getFilesDropped').and.returnValue(files); + spyOn(nativeElement, 'dispatchEvent').and.stub(); + directive.onDrop(event); + expect(nativeElement.dispatchEvent).toHaveBeenCalled(); + }); + + it('should provide dropped files in upload-files event', () => { + directive.enabled = true; + let files = [ {}]; + let event = jasmine.createSpyObj('event', ['preventDefault', 'stopPropagation']); + spyOn(directive, 'getFilesDropped').and.returnValue(files); + + spyOn(nativeElement, 'dispatchEvent').and.callFake(e => { + expect(e.detail.files.length).toBe(1); + expect(e.detail.files[0]).toBe(files[0]); + }); + directive.onDrop(event); + expect(nativeElement.dispatchEvent).toHaveBeenCalled(); + }); + +}); diff --git a/ng2-components/ng2-alfresco-core/src/directives/upload.directive.ts b/ng2-components/ng2-alfresco-core/src/directives/upload.directive.ts new file mode 100644 index 0000000000..b3fb37d393 --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/directives/upload.directive.ts @@ -0,0 +1,113 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Directive, Input, HostBinding, HostListener, ElementRef } from '@angular/core'; + +@Directive({ + selector: '[adf-upload]' +}) +export class UploadDirective { + + @Input('adf-upload') + enabled: boolean = true; + + @Input('adf-upload-data') + data: any; + + @Input() + debug: boolean = false; + + @HostBinding('class.adf-upload__dragging') + isDragging: boolean; + + constructor(private el: ElementRef) { + } + + @HostListener('dragenter') + onDragEnter() { + if (this.enabled) { + this.isDragging = true; + } + } + + @HostListener('dragover', ['$event']) + onDragOver(event: Event) { + if (this.enabled) { + if (event) { + event.preventDefault(); + } + this.isDragging = true; + } + } + + @HostListener('dragleave') + onDragLeave() { + if (this.enabled) { + this.isDragging = false; + } + } + + @HostListener('drop', ['$event']) + onDrop(event: DragEvent) { + if (this.enabled) { + event.preventDefault(); + event.stopPropagation(); + + this.isDragging = false; + + let files = this.getFilesDropped(event.dataTransfer); + if (files.length > 0) { + let e = new CustomEvent('upload-files', { + detail: { + sender: this, + data: this.data, + files: files + }, + bubbles: true + }); + + this.el.nativeElement.dispatchEvent(e); + } + } + } + + /** + * Extract files from the DataTransfer object used to hold the data that is being dragged during a drag and drop operation. + * @param dataTransfer DataTransfer object + */ + protected getFilesDropped(dataTransfer: DataTransfer): File[] { + let result: File[] = []; + + if (dataTransfer) { + let items: DataTransferItemList = dataTransfer.items; + + if (items && items.length > 0) { + for (let i = 0; i < items.length; i++) { + let item: DataTransferItem = items[i]; + if (item.type) { + let file = item.getAsFile(); + if (file) { + result.push(file); + } + } + } + } + } + + return result; + } +} diff --git a/ng2-components/ng2-alfresco-datatable/README.md b/ng2-components/ng2-alfresco-datatable/README.md index 615a6e84bb..621d864df4 100644 --- a/ng2-components/ng2-alfresco-datatable/README.md +++ b/ng2-components/ng2-alfresco-datatable/README.md @@ -184,6 +184,7 @@ You can also use HTML-based schema declaration like shown below: | `actionsPosition` | string (left\|right) | right | Position of the actions dropdown menu. | | `fallbackThumbnail` | string | | Fallback image for row ehre thubnail is missing| | `contextMenu` | boolean | false | Toggles custom context menu for the component | +| `allowDropFiles` | boolean | false | Toggle file drop support for rows (see **ng2-alfresco-core/UploadDirective** for more details) | ### DataColumn Properties diff --git a/ng2-components/ng2-alfresco-datatable/src/components/datatable/datatable.component.css b/ng2-components/ng2-alfresco-datatable/src/components/datatable/datatable.component.css index 16b994b908..eeb366bd82 100644 --- a/ng2-components/ng2-alfresco-datatable/src/components/datatable/datatable.component.css +++ b/ng2-components/ng2-alfresco-datatable/src/components/datatable/datatable.component.css @@ -122,3 +122,16 @@ .alfresco-datatable__row--selected { color: rgb(68,138,255); } + +.adf-upload__dragging > td { + border-top: 1px dashed rgb(68,138,255); + border-bottom: 1px dashed rgb(68,138,255); +} + +.adf-upload__dragging > td:first-child { + border-left: 1px dashed rgb(68,138,255); +} + +.adf-upload__dragging > td:last-child { + border-right: 1px dashed rgb(68,138,255); +} diff --git a/ng2-components/ng2-alfresco-datatable/src/components/datatable/datatable.component.html b/ng2-components/ng2-alfresco-datatable/src/components/datatable/datatable.component.html index 14fdc4b502..62ee352727 100644 --- a/ng2-components/ng2-alfresco-datatable/src/components/datatable/datatable.component.html +++ b/ng2-components/ng2-alfresco-datatable/src/components/datatable/datatable.component.html @@ -37,7 +37,8 @@ + [class.alfresco-datatable__row--selected]="selectedRow === row" + [adf-upload]="allowDropFiles" [adf-upload-data]="row"> diff --git a/ng2-components/ng2-alfresco-datatable/src/components/datatable/datatable.component.ts b/ng2-components/ng2-alfresco-datatable/src/components/datatable/datatable.component.ts index 6144b5ff15..44bc6a2c11 100644 --- a/ng2-components/ng2-alfresco-datatable/src/components/datatable/datatable.component.ts +++ b/ng2-components/ng2-alfresco-datatable/src/components/datatable/datatable.component.ts @@ -51,6 +51,9 @@ export class DataTableComponent implements AfterContentInit { @Input() contextMenu: boolean = false; + @Input() + allowDropFiles: boolean = false; + @Output() rowClick: EventEmitter = new EventEmitter(); diff --git a/ng2-components/ng2-alfresco-documentlist/README.md b/ng2-components/ng2-alfresco-documentlist/README.md index 927ed6b00b..657708c7e1 100644 --- a/ng2-components/ng2-alfresco-documentlist/README.md +++ b/ng2-components/ng2-alfresco-documentlist/README.md @@ -184,9 +184,10 @@ The properties currentFolderId, folderNode and node are the entry initialization | `contentActionsPosition` | string (left\|right) | right | Position of the content actions dropdown menu. | | `contextMenuActions` | boolean | false | Toggles context menus for each row | | `enablePagination` | boolean | true | Shows pagination | -| `creationMenuActions` | boolean | true | Toggles the creation menu actions| -| `rowFilter` | `RowFilter` | | Custom row filter, [see more](#custom-row-filter). -| `imageResolver` | `ImageResolver` | | Custom image resolver, [see more](#custom-image-resolver). +| `creationMenuActions` | boolean | true | Toggles the creation menu actions | +| `rowFilter` | `RowFilter` | | Custom row filter, [see more](#custom-row-filter). | +| `imageResolver` | `ImageResolver` | | Custom image resolver, [see more](#custom-image-resolver). | +| `allowDropFiles` | boolean | false | Toggle file drop support for rows (see **ng2-alfresco-core/UploadDirective** for more details) | ### Events diff --git a/ng2-components/ng2-alfresco-documentlist/src/components/document-list.component.html b/ng2-components/ng2-alfresco-documentlist/src/components/document-list.component.html index 5b6d96bb64..27df657479 100644 --- a/ng2-components/ng2-alfresco-documentlist/src/components/document-list.component.html +++ b/ng2-components/ng2-alfresco-documentlist/src/components/document-list.component.html @@ -10,6 +10,7 @@ [actionsPosition]="contentActionsPosition" [multiselect]="multiselect" [fallbackThumbnail]="fallbackThumbnail" + [allowDropFiles]="allowDropFiles" [contextMenu]="contextMenuActions" (showRowContextMenu)="onShowRowContextMenu($event)" (showRowActionsMenu)="onShowRowActionsMenu($event)" diff --git a/ng2-components/ng2-alfresco-documentlist/src/components/document-list.component.ts b/ng2-components/ng2-alfresco-documentlist/src/components/document-list.component.ts index 1bee1e1083..3b2667984c 100644 --- a/ng2-components/ng2-alfresco-documentlist/src/components/document-list.component.ts +++ b/ng2-components/ng2-alfresco-documentlist/src/components/document-list.component.ts @@ -82,6 +82,9 @@ export class DocumentListComponent implements OnInit, OnChanges, AfterContentIni @Input() emptyFolderImageUrl: string = this.baseComponentPath + 'assets/images/empty_doc_lib.svg'; + @Input() + allowDropFiles: boolean = false; + skipCount: number = 0; pagination: Pagination; diff --git a/ng2-components/ng2-alfresco-upload/src/components/upload-button.component.ts b/ng2-components/ng2-alfresco-upload/src/components/upload-button.component.ts index 4ae3b1d1b3..2de9d609eb 100644 --- a/ng2-components/ng2-alfresco-upload/src/components/upload-button.component.ts +++ b/ng2-components/ng2-alfresco-upload/src/components/upload-button.component.ts @@ -128,7 +128,7 @@ export class UploadButtonComponent { let directoryName = this.getDirectoryName(directoryPath); let absolutePath = this.currentFolderPath + this.getDirectoryPath(directoryPath); - this.uploadService.createFolder(absolutePath, directoryName) + this.uploadService.createFolder(absolutePath, directoryName, this.rootFolderId) .subscribe( res => { let relativeDir = this.currentFolderPath + '/' + directoryPath; diff --git a/ng2-components/ng2-alfresco-upload/src/components/upload-drag-area.component.css b/ng2-components/ng2-alfresco-upload/src/components/upload-drag-area.component.css index a728c81263..7dc4760dca 100644 --- a/ng2-components/ng2-alfresco-upload/src/components/upload-drag-area.component.css +++ b/ng2-components/ng2-alfresco-upload/src/components/upload-drag-area.component.css @@ -4,8 +4,7 @@ text-align: center; } -.input-focus { +.file-draggable__input-focus { color: #2196F3; - margin-left: 3px; - border: 3px dashed #2196F3; + border: 1px dashed #2196F3; } diff --git a/ng2-components/ng2-alfresco-upload/src/components/upload-drag-area.component.html b/ng2-components/ng2-alfresco-upload/src/components/upload-drag-area.component.html index 8140a1fec3..fda0fca497 100644 --- a/ng2-components/ng2-alfresco-upload/src/components/upload-drag-area.component.html +++ b/ng2-components/ng2-alfresco-upload/src/components/upload-drag-area.component.html @@ -2,6 +2,7 @@ (onFilesDropped)="onFilesDropped($event)" (onFilesEntityDropped)="onFilesEntityDropped($event)" (onFolderEntityDropped)="onFolderEntityDropped($event)" + (upload-files)="onUploadFiles($event)" dropzone="" webkitdropzone="*" #droparea> diff --git a/ng2-components/ng2-alfresco-upload/src/components/upload-drag-area.component.ts b/ng2-components/ng2-alfresco-upload/src/components/upload-drag-area.component.ts index 9c552f8f85..e5c9dd2242 100644 --- a/ng2-components/ng2-alfresco-upload/src/components/upload-drag-area.component.ts +++ b/ng2-components/ng2-alfresco-upload/src/components/upload-drag-area.component.ts @@ -72,16 +72,35 @@ export class UploadDragAreaComponent { this.uploadService.setOptions(formFields, this.versioning); } + /** + * Handles 'upload-files' events raised by child components. + * @param e DOM event + */ + onUploadFiles(e: CustomEvent) { + e.stopPropagation(); + e.preventDefault(); + + let files = e.detail.files; + if (files && files.length > 0) { + if (e.detail.data.obj.entry.isFolder) { + let id = e.detail.data.obj.entry.id; + this.onFilesDropped(files, id, '/'); + } else { + this.onFilesDropped(files); + } + } + } + /** * Method called when files are dropped in the drag area. * * @param {File[]} files - files dropped in the drag area. */ - onFilesDropped(files: File[]): void { + onFilesDropped(files: File[], rootId?: string, directory?: string): void { if (files.length) { if (this.checkValidity(files)) { this.uploadService.addToQueue(files); - this.uploadService.uploadFilesInTheQueue(this.rootFolderId, this.currentFolderPath, this.onSuccess); + this.uploadService.uploadFilesInTheQueue(rootId || this.rootFolderId, directory || this.currentFolderPath, this.onSuccess); let latestFilesAdded = this.uploadService.getQueue(); if (this.showNotificationBar) { this.showUndoNotificationBar(latestFilesAdded); @@ -132,7 +151,7 @@ export class UploadDragAreaComponent { let relativePath = folder.fullPath.replace(folder.name, ''); relativePath = this.currentFolderPath + relativePath; - this.uploadService.createFolder(relativePath, folder.name) + this.uploadService.createFolder(relativePath, folder.name, this.rootFolderId) .subscribe( message => { this.onSuccess.emit({ diff --git a/ng2-components/ng2-alfresco-upload/src/directives/file-draggable.directive.spec.ts b/ng2-components/ng2-alfresco-upload/src/directives/file-draggable.directive.spec.ts index 79f9b9b224..807467bbde 100644 --- a/ng2-components/ng2-alfresco-upload/src/directives/file-draggable.directive.spec.ts +++ b/ng2-components/ng2-alfresco-upload/src/directives/file-draggable.directive.spec.ts @@ -19,7 +19,7 @@ import { FileDraggableDirective } from '../directives/file-draggable.directive'; describe('FileDraggableDirective', () => { - let component; + let component: FileDraggableDirective; beforeEach( () => { component = new FileDraggableDirective(); @@ -51,7 +51,7 @@ describe('FileDraggableDirective', () => { done(); }); - component._onDropFiles(fakeEvent); + component.onDropFiles(fakeEvent); }); it('should emit onFilesDropped event when a file is dragged not with Chrome' , (done) => { @@ -70,7 +70,7 @@ describe('FileDraggableDirective', () => { done(); }); - component._onDropFiles(fakeEvent); + component.onDropFiles(fakeEvent); }); it('should emit onFilesDropped event when a file is dragged with Chrome', (done) => { @@ -90,7 +90,7 @@ describe('FileDraggableDirective', () => { done(); }); - component._onDropFiles(fakeEvent); + component.onDropFiles(fakeEvent); }); it('should take the focus when the drag enter is called', () => { @@ -98,7 +98,7 @@ describe('FileDraggableDirective', () => { spyOn(mockEvent, 'preventDefault'); expect(component.getInputFocus()).toBe(false); - component._onDragEnter(mockEvent); + component.onDragEnter(mockEvent); expect(component.getInputFocus()).toBe(true); }); }); diff --git a/ng2-components/ng2-alfresco-upload/src/directives/file-draggable.directive.ts b/ng2-components/ng2-alfresco-upload/src/directives/file-draggable.directive.ts index 6718ab97a6..e6a3f89d77 100644 --- a/ng2-components/ng2-alfresco-upload/src/directives/file-draggable.directive.ts +++ b/ng2-components/ng2-alfresco-upload/src/directives/file-draggable.directive.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { Directive, EventEmitter, Output } from '@angular/core'; +import { Directive, HostListener, HostBinding, EventEmitter, Output } from '@angular/core'; /** * [file-draggable] @@ -29,17 +29,12 @@ import { Directive, EventEmitter, Output } from '@angular/core'; * @returns {FileDraggableDirective} . */ @Directive({ - selector: '[file-draggable]', - host: { - '(drop)': '_onDropFiles($event)', - '(dragenter)': '_onDragEnter($event)', - '(dragleave)': '_onDragLeave($event)', - '(dragover)': '_onDragOver($event)', - '[class.input-focus]': '_inputFocusClass' - } + selector: '[file-draggable]' }) export class FileDraggableDirective { + files: File []; + @Output() onFilesDropped: EventEmitter = new EventEmitter(); @@ -49,41 +44,39 @@ export class FileDraggableDirective { @Output() onFolderEntityDropped: EventEmitter = new EventEmitter(); - files: File []; - - private _inputFocusClass: boolean = false; - - constructor() { - } + @HostBinding('class.file-draggable__input-focus') + inputFocusClass: boolean = false; /** * Method called when files is dropped in the drag and drop area. - * - * @param {$event} $event - DOM $event. + * @param event DOM event. */ - _onDropFiles($event: any): void { - this._preventDefault($event); + @HostListener('drop', ['$event']) + onDropFiles(event: any): void { + if (!event.defaultPrevented) { + this.preventDefault(event); - let items = $event.dataTransfer.items; - if (items) { - for (let i = 0; i < items.length; i++) { - if (typeof items[i].webkitGetAsEntry !== 'undefined') { - let item = items[i].webkitGetAsEntry(); - if (item) { - this._traverseFileTree(item); + let items = event.dataTransfer.items; + if (items) { + for (let i = 0; i < items.length; i++) { + if (typeof items[i].webkitGetAsEntry !== 'undefined') { + let item = items[i].webkitGetAsEntry(); + if (item) { + this.traverseFileTree(item); + } + } else { + let files = event.dataTransfer.files; + this.onFilesDropped.emit(files); } - } else { - let files = $event.dataTransfer.files; - this.onFilesDropped.emit(files); } + } else { + // safari or FF + let files = event.dataTransfer.files; + this.onFilesDropped.emit(files); } - } else { - // safari or FF - let files = $event.dataTransfer.files; - this.onFilesDropped.emit(files); - } - this._inputFocusClass = false; + this.inputFocusClass = false; + } } /** @@ -91,7 +84,7 @@ export class FileDraggableDirective { * * @param {Object} item - can contains files or folders. */ - private _traverseFileTree(item: any): void { + private traverseFileTree(item: any): void { if (item.isFile) { let self = this; self.onFilesEntityDropped.emit(item); @@ -105,44 +98,50 @@ export class FileDraggableDirective { /** * Change the style of the drag area when a file drag in. * - * @param {$event} $event - DOM $event. + * @param {event} event - DOM event. */ - _onDragEnter($event: Event): void { - this._preventDefault($event); - - this._inputFocusClass = true; + @HostListener('dragenter', ['$event']) + onDragEnter(event: Event): void { + if (!event.defaultPrevented) { + this.preventDefault(event); + this.inputFocusClass = true; + } } /** * Change the style of the drag area when a file drag out. * - * @param {$event} $event - DOM $event. + * @param {event} event - DOM event. */ - _onDragLeave($event: Event): void { - this._preventDefault($event); - - this._inputFocusClass = false; + @HostListener('dragleave', ['$event']) + onDragLeave(event: Event): void { + if (!event.defaultPrevented) { + this.preventDefault(event); + this.inputFocusClass = false; + } } /** * Change the style of the drag area when a file is over the drag area. * - * @param $event - * @private + * @param event */ - _onDragOver($event: Event): void { - this._preventDefault($event); - this._inputFocusClass = true; + @HostListener('dragover', ['$event']) + onDragOver(event: Event): void { + if (!event.defaultPrevented) { + this.preventDefault(event); + this.inputFocusClass = true; + } } /** * Prevent default and stop propagation of the DOM event. * - * @param {$event} $event - DOM $event. + * @param {event} $event - DOM event. */ - _preventDefault($event: Event): void { - $event.stopPropagation(); - $event.preventDefault(); + preventDefault(event: Event): void { + event.stopPropagation(); + event.preventDefault(); } /** @@ -150,6 +149,6 @@ export class FileDraggableDirective { * @returns {boolean} */ getInputFocus () { - return this._inputFocusClass; + return this.inputFocusClass; } } diff --git a/ng2-components/ng2-alfresco-upload/src/services/upload.service.ts b/ng2-components/ng2-alfresco-upload/src/services/upload.service.ts index 788cf7f4a7..5f0628b1f8 100644 --- a/ng2-components/ng2-alfresco-upload/src/services/upload.service.ts +++ b/ng2-components/ng2-alfresco-upload/src/services/upload.service.ts @@ -162,17 +162,14 @@ export class UploadService { * Create a folder * @param name - the folder name */ - createFolder(relativePath: string, name: string) { - return Observable.fromPromise(this.callApiCreateFolder(relativePath, name)) - .map(res => { - return res; - }) + createFolder(relativePath: string, name: string, parentId?: string) { + return Observable.fromPromise(this.callApiCreateFolder(relativePath, name, parentId)) .do(data => this.logService.info('Node data', data)) // eyeball results in the console .catch(err => this.handleError(err)); } - callApiCreateFolder(relativePath: string, name: string): Promise { - return this.apiService.getInstance().nodes.createFolder(name, relativePath); + callApiCreateFolder(relativePath: string, name: string, parentId?: string): Promise { + return this.apiService.getInstance().nodes.createFolder(name, relativePath, parentId); } /**