Skip to content

Instantly share code, notes, and snippets.

@imana97
Created August 26, 2019 17:19
Show Gist options
  • Save imana97/8d672ed0d31fc3842f1f8604103a1d81 to your computer and use it in GitHub Desktop.
Save imana97/8d672ed0d31fc3842f1f8604103a1d81 to your computer and use it in GitHub Desktop.
'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