2017-01-05 21:06:30 +00:00

295 lines
9.9 KiB
TypeScript

/*!
* @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 { Component, ViewChild, ElementRef, Input, Output, EventEmitter } from '@angular/core';
import 'rxjs/Rx';
import { AlfrescoTranslateService, LogService } from 'ng2-alfresco-core';
import { UploadService } from '../services/upload.service';
import { FileModel } from '../models/file.model';
declare let componentHandler: any;
const ERROR_FOLDER_ALREADY_EXIST = 409;
/**
* <alfresco-upload-button [showUdoNotificationBar]="boolean"
* [uploadFolders]="boolean"
* [multipleFiles]="boolean"
* [acceptedFilesType]="string"
* (onSuccess)="customMethod($event)">
* </alfresco-upload-button>
*
* This component, provide a set of buttons to upload files to alfresco.
*
* @InputParam {boolean} [true] showUdoNotificationBar - hide/show notification bar.
* @InputParam {boolean} [false] versioning - true to indicate that a major version should be created
* @InputParam {boolean} [false] uploadFolders - allow/disallow upload folders (only for chrome).
* @InputParam {boolean} [false] multipleFiles - allow/disallow multiple files.
* @InputParam {string} [*] acceptedFilesType - array of allowed file extensions.
* @InputParam {boolean} [false] versioning - true to indicate that a major version should be created
* @Output - onSuccess - The event is emitted when the file is uploaded
*
* @returns {UploadDragAreaComponent} .
*/
@Component({
selector: 'alfresco-upload-button',
moduleId: module.id,
templateUrl: './upload-button.component.html',
styleUrls: ['./upload-button.component.css']
})
export class UploadButtonComponent {
private static DEFAULT_ROOT_ID: string = '-root-';
@ViewChild('undoNotificationBar')
undoNotificationBar: any;
@Input()
showUdoNotificationBar: boolean = true;
@Input()
uploadFolders: boolean = false;
@Input()
multipleFiles: boolean = false;
@Input()
versioning: boolean = false;
@Input()
acceptedFilesType: string = '*';
@Input()
currentFolderPath: string = '/';
@Input()
rootFolderId: string = UploadButtonComponent.DEFAULT_ROOT_ID;
@Output()
onSuccess = new EventEmitter();
@Output()
onError = new EventEmitter();
@Output()
createFolder = new EventEmitter();
constructor(private el: ElementRef,
private uploadService: UploadService,
private translateService: AlfrescoTranslateService,
private logService: LogService) {
if (translateService) {
translateService.addTranslationFolder('ng2-alfresco-upload', 'node_modules/ng2-alfresco-upload/src');
}
}
ngOnChanges(changes) {
let formFields = this.createFormFields();
this.uploadService.setOptions(formFields, this.versioning);
}
/**
* Method called when files are dropped in the drag area.
*
* @param {File[]} files - files dropped in the drag area.
*/
onFilesAdded($event: any): void {
let files = $event.currentTarget.files;
this.uploadFiles(this.currentFolderPath, files);
// reset the value of the input file
$event.target.value = '';
}
/**
* Method called when a folder is dropped in the drag area.
*
* @param {File[]} files - files of a folder dropped in the drag area.
*/
onDirectoryAdded($event: any): void {
let files = $event.currentTarget.files;
let hashMapDir = this.convertIntoHashMap(files);
hashMapDir.forEach((filesDir, directoryPath) => {
let directoryName = this.getDirectoryName(directoryPath);
let absolutePath = this.currentFolderPath + this.getDirectoryPath(directoryPath);
this.uploadService.createFolder(absolutePath, directoryName)
.subscribe(
res => {
let relativeDir = this.currentFolderPath + '/' + directoryPath;
this.uploadFiles(relativeDir, filesDir);
},
error => {
let errorMessagePlaceholder = this.getErrorMessage(error.response);
if (errorMessagePlaceholder) {
this.onError.emit({value: errorMessagePlaceholder});
let errorMessage = this.formatString(errorMessagePlaceholder, [directoryName]);
if (errorMessage) {
this._showErrorNotificationBar(errorMessage);
}
}
this.logService.error(error);
}
);
});
// reset the value of the input file
$event.target.value = '';
}
/**
* Upload a list of file in the specified path
* @param path
* @param files
*/
private uploadFiles(path: string, files: any[]) {
if (files.length) {
let latestFilesAdded = this.uploadService.addToQueue(files);
this.uploadService.uploadFilesInTheQueue(this.rootFolderId, path, this.onSuccess);
if (this.showUdoNotificationBar) {
this._showUndoNotificationBar(latestFilesAdded);
}
}
}
/**
* It converts the array given as input into a map. The map is a key values pairs, where the key is the directory name and the value are
* all the files that the directory contains.
* @param files - array of files
* @returns {Map}
*/
private convertIntoHashMap(files: any[]) {
let directoryMap = new Map<string, Object[]>();
for (let file of files) {
let directory = this.getDirectoryPath(file.webkitRelativePath);
let filesSomeDir = directoryMap.get(directory) || [];
filesSomeDir.push(file);
directoryMap.set(directory, filesSomeDir);
}
return directoryMap;
}
/**
* Split the directory path given as input and cut the last directory name
* @param directory
* @returns {string}
*/
private getDirectoryPath(directory: string) {
let relativeDirPath = '';
let dirPath = directory.split('/');
if (dirPath.length > 1) {
dirPath.pop();
relativeDirPath = '/' + dirPath.join('/');
}
return relativeDirPath;
}
/**
* Split a directory path passed in input and return the first directory name
* @param directory
* @returns {string}
*/
private getDirectoryName(directory: string) {
let dirPath = directory.split('/');
if (dirPath.length > 1) {
return dirPath.pop();
} else {
return dirPath[0];
}
}
/**
* Show undo notification bar.
*
* @param {FileModel[]} latestFilesAdded - files in the upload queue enriched with status flag and xhr object.
*/
private _showUndoNotificationBar(latestFilesAdded: FileModel[]) {
if (componentHandler) {
componentHandler.upgradeAllRegistered();
}
let messageTranslate: any, actionTranslate: any;
messageTranslate = this.translateService.get('FILE_UPLOAD.MESSAGES.PROGRESS');
actionTranslate = this.translateService.get('FILE_UPLOAD.ACTION.UNDO');
if (this.undoNotificationBar.nativeElement.MaterialSnackbar) {
this.undoNotificationBar.nativeElement.MaterialSnackbar.showSnackbar({
message: messageTranslate.value,
timeout: 3000,
actionHandler: function () {
latestFilesAdded.forEach((uploadingFileModel: FileModel) => {
uploadingFileModel.emitAbort();
});
},
actionText: actionTranslate.value
});
}
}
/**
* Retrive the error message using the error status code
* @param response - object that contain the HTTP response
* @returns {string}
*/
private getErrorMessage(response: any): string {
if (response.body && response.body.error.statusCode === ERROR_FOLDER_ALREADY_EXIST) {
let errorMessage: any;
errorMessage = this.translateService.get('FILE_UPLOAD.MESSAGES.FOLDER_ALREADY_EXIST');
return errorMessage.value;
}
}
/**
* Show the error inside Notification bar
* @param Error message
* @private
*/
private _showErrorNotificationBar(errorMessage: string) {
if (componentHandler) {
componentHandler.upgradeAllRegistered();
}
if (this.undoNotificationBar.nativeElement.MaterialSnackbar) {
this.undoNotificationBar.nativeElement.MaterialSnackbar.showSnackbar({
message: errorMessage,
timeout: 3000
});
}
}
/**
* Replace a placeholder {0} in a message with the input keys
* @param message - the message that conains the placeholder
* @param keys - array of value
* @returns {string} - The message without placeholder
*/
private formatString(message: string, keys: any []) {
let i = keys.length;
while (i--) {
message = message.replace(new RegExp('\\{' + i + '\\}', 'gm'), keys[i]);
}
return message;
}
private createFormFields(): any {
return {
formFields: {
overwrite: true
}
};
}
}