Browse Source

Merge pull request #96 from theurere/upload-picture

Upload a picture for buddyPicture
pull/97/head
Simon Eisenmann 11 years ago
parent
commit
6a0800f80f
  1. 72
      src/styles/components/_buddypictureupload.scss
  2. 1
      src/styles/main.scss
  3. 2
      static/css/main.min.css
  4. 269
      static/js/directives/buddypictureupload.js
  5. 4
      static/js/directives/directives.js
  6. 4
      static/partials/buddypicturecapture.html
  7. 32
      static/partials/buddypictureupload.html
  8. 2
      static/partials/settings.html

72
src/styles/components/_buddypictureupload.scss

@ -0,0 +1,72 @@ @@ -0,0 +1,72 @@
/*
* Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG
*
* This file is part of Spreed WebRTC.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
.buddyPictureUpload {
position: relative;
.previewUpload {
}
.showUploadPicture {
border: 1px solid #EEEEEE;
height: 200px;
line-height: 200px;
margin-bottom: 10px;
overflow: hidden;
text-align: center;
width: 200px;
background-color: black;
}
.preview {
position: relative;
top: 0px;
left: 0px;
}
.imageUtilites {
line-height: 30px;
position: absolute;
visibility: hidden;
width: 200px;
z-index: 1;
.fa {
cursor: pointer;
color: $componentbg;
text-shadow: 0 0 5px black;
opacity: 0.8;
font-size: 40px;
width: 50px;
height: 50px;
}
}
.showUploadPicture:hover .imageUtilites {
visibility:visible;
}
.moveHorizontal {
top: -4px;
position: relative;
}
.moveVertical {
position: absolute;
left: 158px;
}
.resize {
position: relative;
top: 108px;
}
}

1
src/styles/main.scss

@ -39,6 +39,7 @@ @@ -39,6 +39,7 @@
@import "components/bar";
@import "components/buddylist";
@import "components/buddypicturecapture";
@import "components/buddypictureupload";
@import "components/settings";
@import "components/chat";
@import "components/usability";

2
static/css/main.min.css vendored

File diff suppressed because one or more lines are too long

269
static/js/directives/buddypictureupload.js

@ -0,0 +1,269 @@ @@ -0,0 +1,269 @@
/*
* Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG
*
* This file is part of Spreed WebRTC.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
define(['jquery', 'underscore', 'text!partials/buddypictureupload.html'], function($, _, template) {
// buddyPictureUpload
return ["$compile", function($compile) {
var controller = ['$scope', 'safeApply', '$timeout', '$q', 'translation', function($scope, safeApply, $timeout, $q, translation) {
var previewWidth = 205;
var previewHeight = 205;
$scope.maxUploadMb = 8;
var maxUploadBytes = $scope.maxUploadMb * 1024 * 1024;
$scope.showUploadPicture = false;
$scope.previewUpload = false;
$scope.imgData = null;
$scope.error = {
read: null,
image: null,
size: null
};
$scope.upload = {
status: 0
};
var completedUpload = function() {
$scope.upload.status = 99;
$timeout(function() {
$scope.upload.status = 100;
}, 500);
};
var setUploadImageDimension = function(data) {
$scope.prevImage.onload = function() {
// clear old dimensions
this.style.cssText = null;
// get new dimensions
var dim = getAutoFitDimensions(this, {width: previewWidth, height: previewHeight});
this.style.width = dim.width + 'px';
this.style.height = dim.height + 'px';
this.style.top = '0px';
this.style.left = '0px';
completedUpload();
safeApply($scope);
};
$scope.prevImage.src = data;
};
var getNumFromPx = function(px) {
return px.match(/[\-0-9]+/) ? Number(px.match(/[\-0-9]+/)[0]) : 0;
};
// Auto fit by smallest dimension
var getAutoFitDimensions = function(from, to) {
if (!from.width && !from.height && !to.width && !to.height) {
return null;
}
var width = null;
var height = null;
if (from.width < from.height) {
height = to.width * (from.height/from.width);
width = to.width;
} else {
height = to.height;
width = to.height * (from.width/from.height);
}
return {width: width, height: height};
};
// (image, canvas) -> object
var getScaledDimensions = function(from, to) {
if (!from.style.width && !from.style.height && !to.width && !to.height) {
return null;
}
var current = {
width: getNumFromPx(from.style.width),
height: getNumFromPx(from.style.height),
top: getNumFromPx(from.style.top),
left: getNumFromPx(from.style.left)
};
var scaleFactorX = previewWidth / to.width;
var scaleFactorY = previewHeight / to.height;
var width = current.width / scaleFactorX;
var height = current.height / scaleFactorY;
var x = current.left / scaleFactorX;
var y = current.top / scaleFactorY;
if (current.width < previewWidth) {
x = ((previewWidth - current.width) / scaleFactorX ) / 2;
}
if (current.height < previewHeight) {
y = ((previewHeight - current.height) / scaleFactorY ) / 2;
}
return {width: width, height: height, x: x, y: y};
};
var writeUploadToCanvas = function(canvas, img) {
var dim = getScaledDimensions(img, canvas);
var context = canvas.getContext("2d");
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(img, dim.x, dim.y, dim.width, dim.height);
//console.log('writeUploadToCanvas', dim);
};
$scope.usePicture = function() {
writeUploadToCanvas($scope.canvasPic, $scope.prevImage);
$scope.user.buddyPicture = $scope.canvasPic.toDataURL("image/jpeg");
$scope.reset();
safeApply($scope);
};
$scope.reset = function() {
$scope.showUploadPicture = false;
$scope.previewUpload = false;
};
$scope.handleUpload = function(event) {
var file = event.target.files[0];
if (!file) {
return;
}
//console.log('file', file);
var progress = function(event) {
//console.log('file progress', event);
var percentComplete = event.loaded/event.total * 100;
// show complete only when src is loaded in image element
if(percentComplete != 100) {
$scope.$apply(function(scope) {
$scope.upload.status = percentComplete;
});
}
};
var load = function(event) {
//console.log('file load', event);
$scope.$apply(function(scope) {
scope.imgData = event.target.result;
setUploadImageDimension(scope.imgData);
$scope.previewUpload = true;
});
};
var error = function(event) {
//console.log('file error', event);
if (event.target.error.name == 'NotReadableError') {
$scope.$apply(function(scope) {
scope.error.read = true;
});
}
if (event.target.error.name == 'NotImage') {
$scope.$apply(function(scope) {
scope.error.image = true;
});
}
if (event.target.error.name == 'Size') {
$scope.$apply(function(scope) {
scope.error.size = true;
});
}
};
if (!file.type.match(/image/)) {
error({target: {error: {name: 'NotImage'}}});
} else if (file.size > maxUploadBytes) {
error({target: {error: {name: 'Size'}}});
} else {
$scope.$apply(function(scope) {
$scope.upload.status = 5;
});
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onprogress = progress;
reader.onload = load;
reader.onerror = error;
}
};
}];
var link = function($scope, $element) {
$scope.prevImage = $(".showUploadPicture .preview").get(0);
$element.find("#uploadFile").on('change', $scope.handleUpload);
var intervalNum = {
num: null
};
var incrementPx = function(num) {
return ((Number(num.match(/[\-0-9]+/)) + 5) + 'px');
};
var decrementPx = function(num) {
return ((Number(num.match(/[\-0-9]+/)) - 5) + 'px');
};
var moveImageUp = function() {
$scope.prevImage.style.top = decrementPx($scope.prevImage.style.top);
};
var moveImageDown = function() {
$scope.prevImage.style.top = incrementPx($scope.prevImage.style.top);
};
var moveImageLeft = function() {
$scope.prevImage.style.left = decrementPx($scope.prevImage.style.left);
};
var moveImageRight = function() {
$scope.prevImage.style.left = incrementPx($scope.prevImage.style.left);
};
var makeImageLarger = function() {
$scope.prevImage.style.height = incrementPx($scope.prevImage.style.height);
$scope.prevImage.style.width = incrementPx($scope.prevImage.style.width);
};
var makeImageSmaller = function() {
$scope.prevImage.style.height = decrementPx($scope.prevImage.style.height);
$scope.prevImage.style.width = decrementPx($scope.prevImage.style.width);
};
var changeImage = function(evt) {
if (evt.data.intervalNum.num || !evt.data.action) {
clearInterval(evt.data.intervalNum.num);
evt.data.intervalNum.num = null;
} else {
evt.data.intervalNum.num = setInterval(function() {
evt.data.action();
}, 50);
}
};
$element.find("#arrow-up").on('mousedown', null, {intervalNum: intervalNum, action: moveImageUp}, changeImage);
$element.find("#arrow-down").on('mousedown', null, {intervalNum: intervalNum, action: moveImageDown}, changeImage);
$element.find("#arrow-up").on('mouseup', null, {intervalNum: intervalNum}, changeImage);
$element.find("#arrow-down").on('mouseup', null, {intervalNum: intervalNum}, changeImage);
$element.find("#arrow-left").on('mousedown', null, {intervalNum: intervalNum, action: moveImageLeft}, changeImage);
$element.find("#arrow-right").on('mousedown', null, {intervalNum: intervalNum, action: moveImageRight}, changeImage);
$element.find("#arrow-left").on('mouseup', null, {intervalNum: intervalNum}, changeImage);
$element.find("#arrow-right").on('mouseup', null, {intervalNum: intervalNum}, changeImage);
$element.find("#larger").on('mousedown', null, {intervalNum: intervalNum, action: makeImageLarger}, changeImage);
$element.find("#smaller").on('mousedown', null, {intervalNum: intervalNum, action: makeImageSmaller}, changeImage);
$element.find("#larger").on('mouseup', null, {intervalNum: intervalNum}, changeImage);
$element.find("#smaller").on('mouseup', null, {intervalNum: intervalNum}, changeImage);
};
return {
restrict: 'E',
replace: false,
template: template,
controller: controller,
link: link
};
}];
});

4
static/js/directives/directives.js

@ -26,6 +26,7 @@ define([ @@ -26,6 +26,7 @@ define([
'directives/statusmessage',
'directives/buddylist',
'directives/buddypicturecapture',
'directives/buddypictureupload',
'directives/settings',
'directives/chat',
'directives/audiovideo',
@ -41,7 +42,7 @@ define([ @@ -41,7 +42,7 @@ define([
'directives/pdfcanvas',
'directives/odfcanvas',
'directives/presentation',
'directives/youtubevideo',], function(_, onEnter, onEscape, statusMessage, buddyList, buddyPictureCapture, settings, chat, audioVideo, usability, audioLevel, fileInfo, screenshare, roomBar, socialShare, page, contactRequest, defaultDialog, pdfcanvas, odfcanvas, presentation, youtubevideo) {
'directives/youtubevideo',], function(_, onEnter, onEscape, statusMessage, buddyList, buddyPictureCapture, buddyPictureUpload, settings, chat, audioVideo, usability, audioLevel, fileInfo, screenshare, roomBar, socialShare, page, contactRequest, defaultDialog, pdfcanvas, odfcanvas, presentation, youtubevideo) {
var directives = {
onEnter: onEnter,
@ -49,6 +50,7 @@ define([ @@ -49,6 +50,7 @@ define([
statusMessage: statusMessage,
buddyList: buddyList,
buddyPictureCapture: buddyPictureCapture,
buddyPictureUpload: buddyPictureUpload,
settings: settings,
chat: chat,
audioVideo: audioVideo,

4
static/partials/buddypicturecapture.html

@ -18,7 +18,9 @@ @@ -18,7 +18,9 @@
<a class="btn btn-small btn-primary" ng-disabled="!previewPicture || waitingForPermission" ng-click="setAsProfilePicture()"> {{_('Set as Profile Picture')}}</a>
</div>
</div>
<a class="btn btn-small btn-primary" ng-show="!showTakePicture" ng-disabled="waitingForPermission" ng-click="initPicture()"> {{_('Take picture')}}</a>
<buddy-picture-upload></buddy-picture-upload>
<a class="btn btn-small btn-primary" ng-show="!showTakePicture && !showUploadPicture" ng-disabled="waitingForPermission" ng-click="initPicture()"> {{_('Take picture')}}</a>
<a class="btn btn-small btn-primary" ng-show="!showTakePicture && !showUploadPicture" ng-model="showUploadPicture" btn-checkbox>{{_('Upload picture')}}</a>
<span ng-show="waitingForPermission">
<i class="fa fa-circle-o-notch fa-spin"></i> {{_('Waiting for camera')}}
</span>

32
static/partials/buddypictureupload.html

@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
<div class="buddyPictureUpload collapse" collapse="!showUploadPicture">
<div class="showUploadPicture">
<div class="imageUtilites">
<div class="moveHorizontal">
<i id="arrow-left" class="fa fa-long-arrow-left"></i>
<i id="arrow-right" class="fa fa-long-arrow-right"></i>
</div>
<div class="moveVertical">
<i id="arrow-up" class="fa fa-long-arrow-up"></i>
<i id="arrow-down" class="fa fa-long-arrow-down"></i>
</div>
<div class="resize">
<i id="larger" class="fa fa-plus"></i>
<i id="smaller" class="fa fa-minus"></i>
</div>
</div>
<img class="preview" ng-class="{previewUpload: previewUpload}" />
</div>
<div class="alert alert-warning" ng-if="error.read">{{_('The file couldn\'t be read.')}}<button type="button" class="close" ng-click="error.read = null"><span>&times;</span></button></div>
<div class="alert alert-warning" ng-if="error.image">{{_('The file is not an image.')}}<button type="button" class="close" ng-click="error.image = null"><span>&times;</span></button></div>
<div class="alert alert-warning" ng-if="error.size">{{_('The file is too large. Max upload size is %d Mb', maxUploadMb)}}<button type="button" class="close" ng-click="error.size = null"><span>&times;</span></button></div>
<p ng-if="!imgData">{{_('Please choose a picture to upload, max %d Mb', maxUploadMb)}}</p>
<p ng-if="imgData">{{_('Upload a different picture')}}</p>
<div><input id="uploadFile" type="file"></div>
<div ng-if="upload.status != 100 && upload.status != 0">
<br>
<progressbar class="progress-striped active" value="upload.status"><i>{{upload.status | number:0}}%</i></progressbar>
</div>
<br>
<a class="btn btn-small btn-default" ng-click="reset()"> {{_('Cancel')}}</a>
<a class="btn btn-small btn-primary" ng-click="usePicture()"> {{_('Set as Profile Picture')}}</a>
</div>

2
static/partials/settings.html

@ -8,9 +8,7 @@ @@ -8,9 +8,7 @@
<div class="form-group">
<label class="col-xs-4 control-label">{{_('Your picture')}}</label>
<div class="col-xs-8">
<label>
<buddy-picture-capture></buddy-picture-capture>
</label>
</div>
</div>
<div class="form-group">

Loading…
Cancel
Save