Created
August 26, 2019 17:19
-
-
Save imana97/8d672ed0d31fc3842f1f8604103a1d81 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
/** | |
* @ngdoc directive | |
* @name ngXwell.directive:fileManager | |
* @description | |
* # fileManager | |
*/ | |
angular.module('ngXwell') | |
.directive('fileManager', function () { | |
return { | |
templateUrl: 'views/core/file-manager.html', | |
restrict: 'E', | |
scope: { | |
parseObject: '=' | |
}, | |
controller: function ( | |
$scope, $element, $attrs, aResolve, dialogs, | |
NgTableParams, buildService, notify, userService, $window, tools, $q, $http) { | |
const XWfiles = Parse.Object.extend('files'); | |
let mainWorker; // create worker variable | |
// if worker exist, use web worker. | |
if (typeof(Worker) !== 'undefined') { | |
mainWorker = undefined; // set it to undefined, make it fresh | |
mainWorker = new Worker('files/worker-file-manager.js'); // assign worker variable. | |
} else { | |
$scope.noWorker = true; | |
} | |
// defile read only | |
$attrs.readOnly === 'true' ? $scope.readOnly = true : $scope.readOnly = false; | |
$scope.historyManager = { | |
parent: undefined, | |
history: [], | |
path: ['files'] | |
}; | |
const setParent = (folder) => { | |
$scope.historyManager.parent = folder; | |
$scope.historyManager.path.push(folder.get('name')); | |
$scope.historyManager.history.push(folder); | |
}; | |
// listen for parse object to become available. | |
const stopWatch = $scope.$watch('parseObject', function (obj) { | |
if (obj.id) { | |
stopWatch(); | |
_loadComponent(obj); | |
} | |
}); | |
const fieldName = $attrs.fieldName || 'files'; | |
/** | |
* | |
* @param parentParseObject | |
* @param file | |
* @param fileKey | |
* @param parentDir | |
* @return {*} | |
* @private | |
*/ | |
const _uploadFiles = (parentParseObject, file, fileKey, parentDir) => { | |
const deferred = $q.defer(); | |
if (file.size > 3e+7) { | |
deferred.reject(new Error(file.name + ' is too big. Max file size is 30MB')); | |
} else { | |
// first we create a reader. | |
const reader = new FileReader(); | |
// Once read is completed. | |
reader.onload = (e) => { | |
// create an encrypted key | |
const key = tools.generatePassword(8); | |
let worker = {}; // create worker variable | |
// create worker. | |
Worker['_' + fileKey] = new Worker('files/worker-file-manager.js'); // assign worker variable. | |
// send data and key to encrypt the file. | |
Worker['_' + fileKey].postMessage({ | |
action: 'encryptBase64', | |
payload: { | |
base64: e.target.result, | |
key: key | |
}, | |
}); | |
// get result from worker | |
Worker['_' + fileKey].onmessage = function (event) { | |
if (event.data.type === 'encryptBase64') { | |
// terminate worker. | |
Worker['_' + fileKey].terminate(); | |
delete Worker['_' + fileKey]; | |
const encryptedBase64 = event.data.result; | |
// create a base64 with the key and with the encrypted file. | |
const newFile = new Parse.File('modulefile', {base64: encryptedBase64}); | |
new XWfiles() | |
.set('name', file.name || '') | |
.set('size', file.size || -1) | |
.set('lastModified', file.lastModifiedDate || new Date()) | |
.set('file', newFile) | |
.set('mimeType', file.type) | |
.set('dir', false) | |
.set('isRoot', typeof(parentDir) === 'undefined') | |
.set('key', key) | |
.set('encrypted', true) | |
.setACL(parentParseObject.getACL()) | |
.save() | |
.then((savedFile) => { | |
parentParseObject.relation(fieldName).add(savedFile); | |
parentParseObject.save() | |
.then(() => { | |
if (parentDir) { | |
parentDir.addUnique('children', savedFile).save() | |
.then(() => deferred.resolve(savedFile)) | |
.catch(deferred.reject); | |
} else { | |
deferred.resolve(savedFile); | |
} | |
}) | |
.catch(deferred.reject); | |
}) | |
.catch(deferred.reject); | |
} | |
}; | |
}; | |
// read the file as base64 | |
reader.readAsDataURL(file); | |
} | |
return deferred.promise; | |
}; | |
/** | |
* Create folder. | |
* @param parentParseObject | |
* @param dirName | |
* @param parentDir | |
* @return {*} | |
* @private | |
*/ | |
const _createFolder = (parentParseObject, dirName, parentDir) => aResolve(async () => { | |
const newFolder = await new XWfiles() | |
.set('name', dirName) | |
.set('dir', true) | |
.set('children', []) | |
.set('isRoot', typeof(parentDir) === 'undefined') | |
.setACL(parentParseObject.getACL()) | |
.save(); | |
parentParseObject.relation(fieldName).add(newFolder); | |
await parentParseObject.save(); | |
if (parentDir) { | |
await parentDir.addUnique('children', newFolder).save(); | |
} | |
return newFolder; | |
}); | |
/** | |
* | |
* @param obj | |
* @param isRoot | |
* @private | |
*/ | |
const _loadFiles = (obj, isRoot = true) => { | |
// fetch files | |
if (isRoot) { | |
$scope.changePromise = aResolve(() => obj | |
.relation(fieldName) | |
.query() | |
.limit(1000) | |
.equalTo('isRoot', true) | |
.find()) | |
.then(files => $scope.files = files) | |
.catch((error) => dialogs.error('Error', error.message)); | |
} else { | |
$scope.changePromise = aResolve(() => obj.fetchWithInclude('children')) | |
.then(folder => $scope.files = folder.get('children')) | |
.catch((error) => dialogs.error('Error', error.message)); | |
} | |
}; | |
/** | |
* load all other components with parse object is available | |
* @param obj | |
* @private | |
*/ | |
const _loadComponent = (obj) => { | |
// for the root folder. | |
_loadFiles(obj); | |
// to delete a file | |
$scope.deleteFile = function (file) { | |
dialogs.confirm('Confirm Delete', 'Are you sure you want to permanently delete ' + file.get('name') + '?') | |
.result | |
.then(() => { | |
aResolve(async () => { | |
if (file.get('dir')) { | |
// if file is a folder, make sure it is empty | |
await file.fetchWithInclude('children'); | |
if (file.get('children').length > 0) { | |
throw new Error('Folder is not empty!'); | |
} | |
} | |
if ($scope.historyManager.parent) { | |
// remove file from parent | |
await $scope.historyManager.parent.remove('children', file).save(); | |
} | |
return file.destroy(); | |
}) | |
.then(() => $scope.files.splice($scope.files.indexOf(file), 1)) | |
.catch(error => dialogs.error('Error', error.message)); | |
}).catch(angular.noop); | |
}; | |
// download file | |
$scope.downloadFile = function (file) { | |
$scope.progress = true; | |
$http.get(file.get('file').url()) | |
.then(function successCallback(response) { | |
mainWorker.postMessage({ | |
action: 'encryptedBase64ToBlob', | |
payload: { | |
encryptedBase64: response.data, | |
key: file.get('key'), | |
contentType: file.get('mimeType') | |
}, | |
}); | |
mainWorker.onmessage = function (event) { | |
if (event.data.type === 'encryptedBase64ToBlob') { | |
$scope.$apply(() => $scope.progress = false); | |
const url = URL.createObjectURL(event.data.result); | |
const pom = $window.document.createElement('a'); | |
pom.setAttribute('href', url); | |
pom.setAttribute('download', file.get('name')); | |
if ($window.document.createEvent) { | |
const event = $window.document.createEvent('MouseEvents'); | |
event.initEvent('click', true, true); | |
pom.dispatchEvent(event); | |
} | |
else { | |
pom.click(); | |
} | |
} | |
}; | |
}, function errorCallback(response) { | |
dialogs.error('File does not exist', response.error); | |
}); | |
}; | |
// create new folder | |
$scope.newFolder = () => { | |
tools.prompt('New Folder','Folder name:','Create Folder','Cancel') | |
.then((prompt)=>{ | |
_createFolder(obj, prompt, $scope.historyManager.parent) | |
.then((newDir) => $scope.files.unshift(newDir)) | |
.catch(error => dialogs.error('Failed Creating Folder', error.message)); | |
}) | |
.catch(angular.noop); | |
}; | |
$scope.rename = (file) => { | |
tools.prompt('Rename File','Insert new file name:','Rename','Cancel') | |
.then(newName=>{ | |
aResolve(() => file.set('name', newName).save()) | |
.catch(error => dialogs.error('Can not rename', error.message)); | |
}) | |
.catch(angular.noop); | |
}; | |
// open folder | |
$scope.openFolder = (folder) => { | |
_loadFiles(folder, false); | |
setParent(folder); | |
}; | |
$scope.goBack = () => { | |
console.log($scope.historyManager); | |
if ($scope.historyManager.history.length > 1) { | |
$scope.historyManager.history.pop(); | |
$scope.historyManager.parent = $scope.historyManager.history[$scope.historyManager.history.length - 1]; | |
_loadFiles($scope.historyManager.parent, false); | |
$scope.historyManager.path.pop(); | |
} else if ($scope.historyManager.parent) { | |
$scope.historyManager = { | |
parent: undefined, | |
history: [], | |
path: ['files'] | |
}; | |
_loadFiles(obj); | |
} | |
}; | |
$scope.setHover = (txt) => { | |
$scope.hoverFile = txt; | |
}; | |
// get files | |
const fileInput = $element.find('input'); | |
fileInput.on('change', function () { | |
$scope.$apply(() => $scope.progress = true); | |
if (fileInput[0].files.length > 0) { | |
angular.forEach(fileInput[0].files, (file, key) => { | |
// some files choosen | |
$scope.changePromise = _uploadFiles(obj, file, key, $scope.historyManager.parent) | |
.then(newFile => { | |
$scope.files.unshift(newFile); | |
$scope.progress = false; | |
}) | |
.catch(error => dialogs.error('Error Uploading File', error.message)); | |
}); | |
} | |
}); | |
} | |
} | |
}; | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment