Skip to content
This repository was archived by the owner on Aug 30, 2021. It is now read-only.

feat(users): Profile picture cropping, mobile uploading and progress bar #1443

Merged
merged 2 commits into from
Aug 26, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@
"angular": "~1.5.0",
"angular-animate": "~1.5.0",
"angular-bootstrap": "~1.2.1",
"angular-file-upload": "~2.2.0",
"angular-messages": "~1.5.0",
"angular-mocks": "~1.5.0",
"angular-resource": "~1.5.0",
"angular-ui-router": "~0.2.18",
"bootstrap": "~3.3.6",
"ng-file-upload": "^12.1.0",
"ng-img-crop": "ngImgCrop#^0.3.2",
"owasp-password-strength-test": "~1.3.0"
},
"overrides": {
Expand Down
4 changes: 3 additions & 1 deletion config/assets/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ module.exports = {
// bower:css
'public/lib/bootstrap/dist/css/bootstrap.css',
'public/lib/bootstrap/dist/css/bootstrap-theme.css',
'public/lib/ng-img-crop/compile/unminified/ng-img-crop.css'
// endbower
],
js: [
// bower:js
'public/lib/angular/angular.js',
'public/lib/angular-animate/angular-animate.js',
'public/lib/angular-bootstrap/ui-bootstrap-tpls.js',
'public/lib/angular-file-upload/dist/angular-file-upload.min.js',
'public/lib/ng-file-upload/ng-file-upload.js',
'public/lib/ng-img-crop/compile/unminified/ng-img-crop.js',
'public/lib/angular-messages/angular-messages.js',
'public/lib/angular-mocks/angular-mocks.js',
'public/lib/angular-resource/angular-resource.js',
Expand Down
2 changes: 1 addition & 1 deletion modules/core/client/app/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

var service = {
applicationModuleName: applicationModuleName,
applicationModuleVendorDependencies: ['ngResource', 'ngAnimate', 'ngMessages', 'ui.router', 'ui.bootstrap', 'angularFileUpload'],
applicationModuleVendorDependencies: ['ngResource', 'ngAnimate', 'ngMessages', 'ui.router', 'ui.bootstrap', 'ngFileUpload', 'ngImgCrop'],
registerModule: registerModule
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,82 +5,52 @@
.module('users')
.controller('ChangeProfilePictureController', ChangeProfilePictureController);

ChangeProfilePictureController.$inject = ['$scope', '$timeout', '$window', 'Authentication', 'FileUploader'];
ChangeProfilePictureController.$inject = ['$timeout', 'Authentication', 'Upload'];

function ChangeProfilePictureController($scope, $timeout, $window, Authentication, FileUploader) {
function ChangeProfilePictureController($timeout, Authentication, Upload) {
var vm = this;

vm.user = Authentication.user;
vm.imageURL = vm.user.profileImageURL;
vm.uploadProfilePicture = uploadProfilePicture;
vm.fileSelected = false;

vm.cancelUpload = cancelUpload;
// Create file uploader instance
vm.uploader = new FileUploader({
url: 'api/users/picture',
alias: 'newProfilePicture',
onAfterAddingFile: onAfterAddingFile,
onSuccessItem: onSuccessItem,
onErrorItem: onErrorItem
});

// Set file uploader image filter
vm.uploader.filters.push({
name: 'imageFilter',
fn: function (item, options) {
var type = '|' + item.type.slice(item.type.lastIndexOf('/') + 1) + '|';
return '|jpg|png|jpeg|bmp|gif|'.indexOf(type) !== -1;
}
});
vm.upload = function (dataUrl, name) {
vm.success = vm.error = null;

// Called after the user selected a new picture file
function onAfterAddingFile(fileItem) {
if ($window.FileReader) {
var fileReader = new FileReader();
fileReader.readAsDataURL(fileItem._file);

fileReader.onload = function (fileReaderEvent) {
$timeout(function () {
vm.imageURL = fileReaderEvent.target.result;
}, 0);
};
}
}
Upload.upload({
url: 'api/users/picture',
data: {
newProfilePicture: Upload.dataUrltoBlob(dataUrl, name)
}
}).then(function (response) {
$timeout(function () {
onSuccessItem(response.data);
});
}, function (response) {
if (response.status > 0) onErrorItem(response.data);
}, function (evt) {
vm.progress = parseInt(100.0 * evt.loaded / evt.total, 10);
});
};

// Called after the user has successfully uploaded a new picture
function onSuccessItem(fileItem, response, status, headers) {
function onSuccessItem(response) {
// Show success message
vm.success = true;

// Populate user object
vm.user = Authentication.user = response;

// Clear upload buttons
cancelUpload();
// Reset form
vm.fileSelected = false;
vm.progress = 0;
}

// Called after the user has failed to uploaded a new picture
function onErrorItem(fileItem, response, status, headers) {
// Clear upload buttons
cancelUpload();
function onErrorItem(response) {
vm.fileSelected = false;

// Show error message
vm.error = response.message;
}

// Change user profile picture
function uploadProfilePicture() {
// Clear messages
vm.success = vm.error = null;

// Start upload
vm.uploader.uploadAll();
}

// Cancel the upload process
function cancelUpload() {
vm.uploader.clearQueue();
vm.imageURL = vm.user.profileImageURL;
}
}
}());
5 changes: 5 additions & 0 deletions modules/users/client/css/users.css
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,8 @@
min-height: 150px;
max-height: 150px;
}
.cropArea {
background: #E4E4E4;
width: 300px;
height: 300px;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,26 @@
<div class="col-xs-offset-1 col-xs-10 col-md-offset-3 col-md-4">
<form class="signin form-horizontal">
<fieldset>
<div ng-show="vm.fileSelected" class="text-center form-group">
<p>Crop your picture then press upload below:</p>
<div ngf-drop ng-model="picFile" ngf-pattern="image/*" class="cropArea">
<img-crop image="picFile | ngfDataUrl" result-image="croppedDataUrl" ng-init="croppedDataUrl=''"></img-crop>
</div>
</div>
<div class="form-group text-center">
<img ng-src="{{vm.imageURL}}" alt="{{vm.user.displayName}}" class="img-thumbnail user-profile-picture">
<img ng-src="{{vm.fileSelected ? croppedDataUrl : vm.user.profileImageURL}}" alt="{{vm.user.displayName}}" class="img-thumbnail user-profile-picture" ngf-drop>
</div>
<div ng-show="!vm.fileSelected" class="text-center form-group">
<button class="btn btn-default btn-file" ngf-select="vm.fileSelected = true; vm.success = null" ng-model="picFile" accept="image/*">Select Picture</button>
</div>
<div class="text-center form-group" ng-hide="vm.uploader.queue.length">
<span class="btn btn-default btn-file">
Select Image <input type="file" nv-file-select uploader="vm.uploader">
</span>
<div ng-show="vm.fileSelected" class="text-center form-group">
<button class="btn btn-primary" ng-click="vm.upload(croppedDataUrl, picFile.name)">Upload</button>
<button class="btn btn-default" ng-click="vm.fileSelected = false">Cancel</button>
</div>
<div class="text-center form-group" ng-show="vm.uploader.queue.length">
<button class="btn btn-primary" ng-click="vm.uploadProfilePicture();">Upload</button>
<button class="btn btn-default" ng-click="vm.cancelUpload();">Cancel</button>
<div ng-show="vm.fileSelected" class="progress text-center">
<div class="progress-bar" role="progressbar" aria-valuenow="{{vm.progress}}" aria-valuemin="0" aria-valuemax="100" style="width:{{vm.progress}}%" ng-bind="vm.progress + '%'">
<span class="sr-only">{{vm.progress}}% Complete</span>
</div>
</div>
<div ng-show="vm.success" class="text-center text-success">
<strong>Profile Picture Changed Successfully</strong>
Expand Down