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

Commit

Permalink
feat(profile): Profile picture cropping, mobile uploading and progres…
Browse files Browse the repository at this point in the history
…s bar (#1443)

* Add ng-file-upload and picture cropping

* Update bower.json

Remove bower dependency for angular-file-upload
  • Loading branch information
hyperreality authored and lirantal committed Aug 26, 2016
1 parent 25bd40c commit 246c5d9
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 67 deletions.
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

3 comments on commit 246c5d9

@mleanos
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hyperreality The client-side mime-type filter was removed with this commit. Can we add it back?

I know there is a bit of a disconnect with ng-file-upload and the user's first selection of the file, which goes directly into the cropping. This creates more complexity than what existed before. However, there should be a way to enforce an explicit check on the mime-type here.

Would you like to look into this?

@hyperreality
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mleanos Indeed. I thought I had it covered with the directives ngf-pattern="image/*" and accept="image/*" but I just attempted to upload a PDF and succeeded. I'll look into it right away.

@hyperreality
Copy link
Contributor Author

@hyperreality hyperreality commented on 246c5d9 Aug 29, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.