diff --git a/application/Espo/EntryPoints/Image.php b/application/Espo/EntryPoints/Image.php index eb356615ab..4a4e687b39 100644 --- a/application/Espo/EntryPoints/Image.php +++ b/application/Espo/EntryPoints/Image.php @@ -18,7 +18,7 @@ * * You should have received a copy of the GNU General Public License * along with EspoCRM. If not, see http://www.gnu.org/licenses/. - ************************************************************************/ + ************************************************************************/ namespace Espo\EntryPoints; @@ -37,9 +37,11 @@ class Image extends \Espo\Core\EntryPoints\Base 'image/gif', ); - protected $imageSizes = array( - 'x-small' => array(64, 64), - 'small' => array(128, 128), + protected $imageSizes = array( + 'xxx-small' => array(19, 19), + 'xx-small' => array(32, 32), + 'x-small' => array(64, 64), + 'small' => array(128, 128), 'medium' => array(256, 256), 'large' => array(512, 512), 'x-large' => array(864, 864), @@ -48,16 +50,16 @@ class Image extends \Espo\Core\EntryPoints\Base public function run() - { + { $id = $_GET['id']; if (empty($id)) { throw new BadRequest(); - } + } - $size = null; + $size = null; if (!empty($_GET['size'])) { $size = $_GET['size']; - } + } $this->show($id, $size); } @@ -68,10 +70,10 @@ class Image extends \Espo\Core\EntryPoints\Base if (!$attachment) { throw new NotFound(); - } + } if ($attachment->get('parentId') && $attachment->get('parentType')) { - $parent = $this->getEntityManager()->getEntity($attachment->get('parentType'), $attachment->get('parentId')); + $parent = $this->getEntityManager()->getEntity($attachment->get('parentType'), $attachment->get('parentId')); if ($parent && !$this->getAcl()->check($parent)) { throw new Forbidden(); } @@ -94,8 +96,8 @@ class Image extends \Espo\Core\EntryPoints\Base $thumbFilePath = "data/upload/thumbs/{$attachment->id}_{$size}"; if (!file_exists($thumbFilePath)) { - $targetImage = $this->getThumbImage($filePath, $fileType, $size); - ob_start(); + $targetImage = $this->getThumbImage($filePath, $fileType, $size); + ob_start(); switch ($fileType) { case 'image/jpeg': @@ -106,31 +108,31 @@ class Image extends \Espo\Core\EntryPoints\Base break; case 'image/gif': imagegif($targetImage); - break; + break; } $contents = ob_get_contents(); ob_end_clean(); - imagedestroy($targetImage); - $this->getContainer()->get('fileManager')->putContents($thumbFilePath, $contents); - } - $filePath = $thumbFilePath; + imagedestroy($targetImage); + $this->getContainer()->get('fileManager')->putContents($thumbFilePath, $contents); + } + $filePath = $thumbFilePath; } else { throw new Error(); - } + } } - if (!empty($size)) { + if (!empty($size)) { $fileName = $attachment->id . '_' . $size . '.jpg'; } else { $fileName = $attachment->get('name'); - } - header('Content-Disposition:inline;filename="'.$fileName.'"'); + } + header('Content-Disposition:inline;filename="'.$fileName.'"'); if (!empty($fileType)) { header('Content-Type: ' . $fileType); - } + } header('Pragma: public'); - $fileSize = filesize($filePath); + $fileSize = filesize($filePath); if ($fileSize) { header('Content-Length: ' . $fileSize); } @@ -148,11 +150,11 @@ class Image extends \Espo\Core\EntryPoints\Base if ($originalWidth <= $width && $originalHeight <= $height) { $targetWidth = $originalWidth; - $targetHeight = $originalHeight; + $targetHeight = $originalHeight; } else { if ($originalWidth > $originalHeight) { $targetWidth = $width; - $targetHeight = $originalHeight / ($originalWidth / $width); + $targetHeight = $originalHeight / ($originalWidth / $width); if ($targetHeight > $height) { $targetHeight = $height; $targetWidth = $originalWidth / ($originalHeight / $height); @@ -165,13 +167,13 @@ class Image extends \Espo\Core\EntryPoints\Base $targetHeight = $originalHeight / ($originalWidth / $width); } } - } + } - $targetImage = imagecreatetruecolor($targetWidth, $targetHeight); + $targetImage = imagecreatetruecolor($targetWidth, $targetHeight); switch ($fileType) { case 'image/jpeg': $sourceImage = imagecreatefromjpeg($filePath); - imagecopyresized($targetImage, $sourceImage, 0, 0, 0, 0, $targetWidth, $targetHeight, $originalWidth, $originalHeight); + imagecopyresampled ($targetImage, $sourceImage, 0, 0, 0, 0, $targetWidth, $targetHeight, $originalWidth, $originalHeight); break; case 'image/png': $sourceImage = imagecreatefrompng($filePath); @@ -183,8 +185,8 @@ class Image extends \Espo\Core\EntryPoints\Base break; case 'image/gif': $sourceImage = imagecreatefromgif($filePath); - imagecopyresized($targetImage, $sourceImage, 0, 0, 0, 0, $targetWidth, $targetHeight, $originalWidth, $originalHeight); - break; + imagecopyresampled($targetImage, $sourceImage, 0, 0, 0, 0, $targetWidth, $targetHeight, $originalWidth, $originalHeight); + break; } diff --git a/application/Espo/Resources/i18n/en_US/User.json b/application/Espo/Resources/i18n/en_US/User.json index b022be5003..c3c0140b9b 100644 --- a/application/Espo/Resources/i18n/en_US/User.json +++ b/application/Espo/Resources/i18n/en_US/User.json @@ -12,7 +12,8 @@ "password": "Password", "passwordConfirm": "Confirm Password", "newPassword": "New Password", - "newPasswordConfirm": "Confirm New Password" + "newPasswordConfirm": "Confirm New Password", + "avatar": "Avatar" }, "links": { "teams": "Teams", @@ -30,7 +31,8 @@ "Username": "Username", "Email Address": "Email Address", "Password": "Password", - "Login": "Login" + "Login": "Login", + "Setup Avatar": "Setup Avatar" }, "tooltips": { "defaultTeam": "All records created by this user will be related to this team by default.", diff --git a/application/Espo/Resources/metadata/app/jsLibs.json b/application/Espo/Resources/metadata/app/jsLibs.json index 0661c35675..a1ec890d53 100644 --- a/application/Espo/Resources/metadata/app/jsLibs.json +++ b/application/Espo/Resources/metadata/app/jsLibs.json @@ -2,13 +2,13 @@ "Flotr": { "path": "client/lib/flotr2.min.js", "exportsTo": "window", - "exportsAs": "Flotr" + "exportsAs": "Flotr" }, "Summernote": { "path": "client/lib/summernote.min.js", "exportsTo": "$", - "exportsAs": "summernote" - }, + "exportsAs": "summernote" + }, "Textcomplete": { "path": "client/lib/jquery.textcomplete.js", "exportsTo": "$", @@ -18,5 +18,10 @@ "path": "client/lib/select2.min.js", "exportsTo": "$", "exportsAs": "select2" + }, + "Cropper": { + "path": "client/lib/cropper.min.js", + "exportsTo": "$", + "exportsAs": "cropper" } } diff --git a/application/Espo/Resources/metadata/entityDefs/User.json b/application/Espo/Resources/metadata/entityDefs/User.json index 0726068503..b85d76e9d3 100644 --- a/application/Espo/Resources/metadata/entityDefs/User.json +++ b/application/Espo/Resources/metadata/entityDefs/User.json @@ -77,6 +77,11 @@ "roles": { "type": "linkMultiple", "tooltip": true + }, + "avatar": { + "type": "image", + "view": "User.Fields.Avatar", + "previewSize": "small" } }, "links": { diff --git a/frontend/client/css/cropper.css b/frontend/client/css/cropper.css new file mode 100644 index 0000000000..362733b2e8 --- /dev/null +++ b/frontend/client/css/cropper.css @@ -0,0 +1,276 @@ +/*! + * Cropper v0.7.4-beta + * https://github.com/fengyuanchen/cropper + * + * Copyright 2014 Fengyuan Chen + * Released under the MIT license + */ + +.cropper-container { + position: relative; + overflow: hidden; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + -webkit-tap-highlight-color: transparent; + -webkit-touch-callout: none; +} + +.cropper-container img { + width: 100%; + max-width: none !important; + height: 100%; + max-height: none !important; +} + +.cropper-modal, +.cropper-canvas { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; +} + +.cropper-canvas { + background-color: #fff; + filter: alpha(opacity=0); + opacity: 0; +} + +.cropper-modal { + background-color: #000; + filter: alpha(opacity=50); + opacity: .5; +} + +.cropper-dragger { + position: absolute; + top: 10%; + left: 10%; + width: 80%; + height: 80%; +} + +.cropper-viewer { + display: block; + width: 100%; + height: 100%; + overflow: hidden; + outline-width: 1px; + outline-style: solid; + outline-color: #69f; + outline-color: rgba(51, 102, 255, .75); +} + +.cropper-dashed { + position: absolute; + display: block; + filter: alpha(opacity=50); + border: 0 dashed #fff; + opacity: .5; +} + +.cropper-dashed.dashed-h { + top: 33.3%; + left: 0; + width: 100%; + height: 33.3%; + border-top-width: 1px; + border-bottom-width: 1px; +} + +.cropper-dashed.dashed-v { + top: 0; + left: 33.3%; + width: 33.3%; + height: 100%; + border-right-width: 1px; + border-left-width: 1px; +} + +.cropper-face, +.cropper-line, +.cropper-point { + position: absolute; + display: block; + width: 100%; + height: 100%; + filter: alpha(opacity=10); + opacity: .1; +} + +.cropper-face { + top: 0; + left: 0; + cursor: move; + background-color: #fff; +} + +.cropper-line { + background-color: #69f; +} + +.cropper-line.line-e { + top: 0; + right: -3px; + width: 5px; + cursor: e-resize; +} + +.cropper-line.line-n { + top: -3px; + left: 0; + height: 5px; + cursor: n-resize; +} + +.cropper-line.line-w { + top: 0; + left: -3px; + width: 5px; + cursor: w-resize; +} + +.cropper-line.line-s { + bottom: -3px; + left: 0; + height: 5px; + cursor: s-resize; +} + +.cropper-point { + width: 5px; + height: 5px; + background-color: #69f; + filter: alpha(opacity=75); + opacity: .75; +} + +.cropper-point.point-e { + top: 50%; + right: -3px; + margin-top: -3px; + cursor: e-resize; +} + +.cropper-point.point-n { + top: -3px; + left: 50%; + margin-left: -3px; + cursor: n-resize; +} + +.cropper-point.point-w { + top: 50%; + left: -3px; + margin-top: -3px; + cursor: w-resize; +} + +.cropper-point.point-s { + bottom: -3px; + left: 50%; + margin-left: -3px; + cursor: s-resize; +} + +.cropper-point.point-ne { + top: -3px; + right: -3px; + cursor: ne-resize; +} + +.cropper-point.point-nw { + top: -3px; + left: -3px; + cursor: nw-resize; +} + +.cropper-point.point-sw { + bottom: -3px; + left: -3px; + cursor: sw-resize; +} + +.cropper-point.point-se { + right: -3px; + bottom: -3px; + width: 20px; + height: 20px; + cursor: se-resize; + filter: alpha(opacity=100); + opacity: 1; +} + +.cropper-point.point-se:before { + position: absolute; + right: -50%; + bottom: -50%; + display: block; + width: 200%; + height: 200%; + content: " "; + background-color: #69f; + filter: alpha(opacity=0); + opacity: 0; +} + +@media (min-width: 768px) { + .cropper-point.point-se { + width: 15px; + height: 15px; + } +} + +@media (min-width: 992px) { + .cropper-point.point-se { + width: 10px; + height: 10px; + } +} + +@media (min-width: 1200px) { + .cropper-point.point-se { + width: 5px; + height: 5px; + filter: alpha(opacity=75); + opacity: .75; + } +} + +/* Helper classes for JavaScript */ + +.cropper-hidden { + display: none !important; +} + +.cropper-invisible { + position: fixed; + top: 0; + left: 0; + z-index: -1; + width: auto !important; + max-width: none !important; + height: auto !important; + max-height: none !important; + filter: alpha(opacity=0); + opacity: 0; +} + +.cropper-move { + cursor: move; +} + +.cropper-crop { + cursor: crosshair; +} + +.cropper-disabled .cropper-canvas, +.cropper-disabled .cropper-face, +.cropper-disabled .cropper-line, +.cropper-disabled .cropper-point { + cursor: not-allowed; +} diff --git a/frontend/client/lib/cropper.min.js b/frontend/client/lib/cropper.min.js new file mode 100644 index 0000000000..3af328e6ed --- /dev/null +++ b/frontend/client/lib/cropper.min.js @@ -0,0 +1,9 @@ +/*! + * Cropper v0.7.4-beta + * https://github.com/fengyuanchen/cropper + * + * Copyright 2014 Fengyuan Chen + * Released under the MIT license + */ + +!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a(jQuery)}(function(a){"use strict";var b=a(window),c=a(document),d=window.location,e=!0,f=!1,g=null,h=0/0,i=1/0,j="undefined",k="directive",l=".cropper",m=/^(e|n|w|s|ne|nw|sw|se|all|crop|move|zoom)$/,n=/^(x|y|width|height)$/,o=/^(naturalWidth|naturalHeight|width|height|aspectRatio|ratio|rotate)$/,p="cropper-modal",q="cropper-hidden",r="cropper-invisible",s="cropper-move",t="cropper-crop",u="cropper-disabled",v="mousedown touchstart",w="mousemove touchmove",x="mouseup mouseleave touchend touchleave touchcancel",y="wheel mousewheel DOMMouseScroll",z="resize"+l,A="dblclick",B="build"+l,C="built"+l,D="dragstart"+l,E="dragmove"+l,F="dragend"+l,G=function(a){return"number"==typeof a},H=function(b,c){this.element=b,this.$element=a(b),this.defaults=a.extend({},H.DEFAULTS,a.isPlainObject(c)?c:{}),this.$original=g,this.ready=f,this.built=f,this.cropped=f,this.rotated=f,this.disabled=f,this.replaced=f,this.init()},I=Math.round,J=Math.sqrt,K=Math.min,L=Math.max,M=Math.abs,N=Math.sin,O=Math.cos,P=parseFloat;H.prototype={constructor:H,support:{canvas:a.isFunction(a("")[0].getContext)},init:function(){var b=this.defaults;a.each(b,function(a,c){switch(a){case"aspectRatio":b[a]=M(P(c))||h;break;case"autoCropArea":b[a]=M(P(c))||.8;break;case"minWidth":case"minHeight":b[a]=M(P(c))||0;break;case"maxWidth":case"maxHeight":b[a]=M(P(c))||i}}),this.image={rotate:0},this.load()},load:function(){var b,c,d=this,g=this.$element,h=this.element,i=this.image;g.is("img")?c=g.prop("src"):g.is("canvas")&&this.support.canvas&&(c=h.toDataURL()),c&&(this.replaced&&(this.replaced=f,i.rotate=0),this.$clone=b=a("'),b.one("load",function(){i.naturalWidth=this.naturalWidth||b.width(),i.naturalHeight=this.naturalHeight||b.height(),i.aspectRatio=i.naturalWidth/i.naturalHeight,d.url=c,d.ready=e,d.build()}),b.addClass(r).prependTo("body"))},isCrossOriginURL:function(a){var b=a.match(/^(https?:)\/\/([^\:\/\?#]+):?(\d*)/i);return!b||b[1]===d.protocol&&b[2]===d.hostname&&b[3]===d.port?f:e},build:function(){var b,d,f=this.$element,g=this.defaults;this.ready&&(this.built&&this.unbuild(),f.one(B,g.build),b=a.Event(B),f.trigger(b),b.isDefaultPrevented()||(this.$cropper=d=a(H.TEMPLATE),f.addClass(q),this.$clone.removeClass(r).prependTo(d),this.rotated||(this.$original=this.$clone.clone(),this.$original.addClass(r).prependTo(this.$cropper),this.originalImage=a.extend({},this.image)),this.$container=f.parent(),this.$container.append(d),this.$canvas=d.find(".cropper-canvas"),this.$dragger=d.find(".cropper-dragger"),this.$viewer=d.find(".cropper-viewer"),g.autoCrop?this.cropped=e:this.$dragger.addClass(q),g.dragCrop&&this.setDragMode("crop"),g.modal&&this.$canvas.addClass(p),!g.dashed&&this.$dragger.find(".cropper-dashed").addClass(q),!g.movable&&this.$dragger.find(".cropper-face").data(k,"move"),!g.resizable&&this.$dragger.find(".cropper-line, .cropper-point").addClass(q),this.$scope=g.multiple?this.$cropper:c,this.addListeners(),this.initPreview(),this.built=e,this.update(),f.one(C,g.built),f.trigger(C)))},unbuild:function(){this.built&&(this.built=f,this.removeListeners(),this.$preview.empty(),this.$preview=g,this.$dragger=g,this.$canvas=g,this.$container=g,this.$cropper.remove(),this.$cropper=g)},update:function(a){this.initContainer(),this.initCropper(),this.initImage(),this.initDragger(),a?(this.setData(a,e),this.setDragMode("crop")):this.setData(this.defaults.data)},resize:function(){clearTimeout(this.resizing),this.resizing=setTimeout(a.proxy(this.update,this,this.getData()),200)},preview:function(){var b=this.image,c=this.dragger,d=b.width,e=b.height,f=c.left-b.left,g=c.top-b.top;this.$viewer.find("img").css({width:I(d),height:I(e),marginLeft:-I(f),marginTop:-I(g)}),this.$preview.each(function(){var b=a(this),h=b.width()/c.width;b.find("img").css({width:I(d*h),height:I(e*h),marginLeft:-I(f*h),marginTop:-I(g*h)})})},addListeners:function(){var c=this.defaults;this.$element.on(D,c.dragstart).on(E,c.dragmove).on(F,c.dragend),this.$cropper.on(v,this._dragstart=a.proxy(this.dragstart,this)).on(A,this._dblclick=a.proxy(this.dblclick,this)),c.zoomable&&this.$cropper.on(y,this._wheel=a.proxy(this.wheel,this)),this.$scope.on(w,this._dragmove=a.proxy(this.dragmove,this)).on(x,this._dragend=a.proxy(this.dragend,this)),b.on(z,this._resize=a.proxy(this.resize,this))},removeListeners:function(){var a=this.defaults;this.$element.off(D,a.dragstart).off(E,a.dragmove).off(F,a.dragend),this.$cropper.off(v,this._dragstart).off(A,this._dblclick),a.zoomable&&this.$cropper.off(y,this._wheel),this.$scope.off(w,this._dragmove).off(x,this._dragend),b.off(z,this._resize)},initPreview:function(){var b='';this.$preview=a(this.defaults.preview),this.$preview.html(b),this.$viewer.html(b)},initContainer:function(){var a=this.$container;this.container={width:L(a.width(),300),height:L(a.height(),150)}},initCropper:function(){var a,b=this.container,c=this.image;c.naturalWidth*b.height/c.naturalHeight-b.width>=0?(a={width:b.width,height:b.width/c.aspectRatio,left:0},a.top=(b.height-a.height)/2):(a={width:b.height*c.aspectRatio,height:b.height,top:0},a.left=(b.width-a.width)/2),this.$cropper.css({width:I(a.width),height:I(a.height),left:I(a.left),top:I(a.top)}),this.cropper=a},initImage:function(){var b=this.image,c=this.cropper,d={_width:c.width,_height:c.height,width:c.width,height:c.height,left:0,top:0,ratio:c.width/b.naturalWidth};this.defaultImage=a.extend({},b,d),b._width!==c.width||b._height!==c.height?a.extend(b,d):b=a.extend(d,b),this.image=b,this.renderImage()},renderImage:function(a){var b=this.image;"zoom"===a&&(b.left-=(b.width-b.oldWidth)/2,b.top-=(b.height-b.oldHeight)/2),b.left=K(L(b.left,b._width-b.width),0),b.top=K(L(b.top,b._height-b.height),0),this.$clone.css({width:I(b.width),height:I(b.height),marginLeft:I(b.left),marginTop:I(b.top)}),a&&(this.defaults.done(this.getData()),this.preview())},initDragger:function(){var b,c=this.defaults,d=this.cropper,e=c.aspectRatio||this.image.aspectRatio,f=this.image.ratio;b=d.height*e-d.width>=0?{height:d.width/e,width:d.width,left:0,top:(d.height-d.width/e)/2,maxWidth:d.width,maxHeight:d.width/e}:{height:d.height,width:d.height*e,left:(d.width-d.height*e)/2,top:0,maxWidth:d.height*e,maxHeight:d.height},b.minWidth=0,b.minHeight=0,c.aspectRatio?(isFinite(c.maxWidth)?(b.maxWidth=K(b.maxWidth,c.maxWidth*f),b.maxHeight=b.maxWidth/e):isFinite(c.maxHeight)&&(b.maxHeight=K(b.maxHeight,c.maxHeight*f),b.maxWidth=b.maxHeight*e),c.minWidth>0?(b.minWidth=L(0,c.minWidth*f),b.minHeight=b.minWidth/e):c.minHeight>0&&(b.minHeight=L(0,c.minHeight*f),b.minWidth=b.minHeight*e)):(b.maxWidth=K(b.maxWidth,c.maxWidth*f),b.maxHeight=K(b.maxHeight,c.maxHeight*f),b.minWidth=L(0,c.minWidth*f),b.minHeight=L(0,c.minHeight*f)),b.minWidth=K(b.maxWidth,b.minWidth),b.minHeight=K(b.maxHeight,b.minHeight),b.height*=c.autoCropArea,b.width*=c.autoCropArea,b.left=(d.width-b.width)/2,b.top=(d.height-b.height)/2,b.oldLeft=b.left,b.oldTop=b.top,this.defaultDragger=b,this.dragger=a.extend({},b)},renderDragger:function(){var a=this.dragger,b=this.cropper;a.width>a.maxWidth?(a.width=a.maxWidth,a.left=a.oldLeft):a.widtha.maxHeight?(a.height=a.maxHeight,a.top=a.oldTop):a.height').one("load",function(){i.width=this.width,i.height=this.height,d.clearRect(0,0,i.width,i.height),d.drawImage(this,0,0),g.load()})))},setData:function(b,c){var d=this.cropper,e=this.dragger,f=this.image,h=this.defaults.aspectRatio;this.built&&typeof b!==j&&((b===g||a.isEmptyObject(b))&&(e=a.extend({},this.defaultDragger)),a.isPlainObject(b)&&!a.isEmptyObject(b)&&(c||(this.defaults.data=b),b=this.transformData(b),G(b.x)&&b.x<=d.width-f.left&&(e.left=b.x+f.left),G(b.y)&&b.y<=d.height-f.top&&(e.top=b.y+f.top),h?G(b.width)&&b.width<=e.maxWidth&&b.width>=e.minWidth?(e.width=b.width,e.height=e.width/h):G(b.height)&&b.height<=e.maxHeight&&b.height>=e.minHeight&&(e.height=b.height,e.width=e.height*h):(G(b.width)&&b.width<=e.maxWidth&&b.width>=e.minWidth&&(e.width=b.width),G(b.height)&&b.height<=e.maxHeight&&b.height>=e.minHeight&&(e.height=b.height))),this.dragger=e,this.renderDragger())},getData:function(){var a=this.dragger,b=this.image,c={};return this.built&&(c={x:a.left-b.left,y:a.top-b.top,width:a.width,height:a.height},c=this.transformData(c,e)),c},transformData:function(b,c){var d=this.image.ratio,e={};return a.each(b,function(a,b){b=P(b),n.test(a)&&!isNaN(b)&&(e[a]=c?I(b/d):b*d)}),e},setAspectRatio:function(a){var b="auto"===a;a=P(a),(b||!isNaN(a)&&a>0)&&(this.defaults.aspectRatio=b?h:a,this.built&&(this.initDragger(),this.renderDragger()))},getImageData:function(){var b={};return this.ready&&a.each(this.image,function(a,c){o.test(a)&&(b[a]=c)}),b},getDataURL:function(b,c){var d,e=a("")[0],f=this.getData(),g="";return this.cropped&&this.support.canvas&&(e.width=f.width,e.height=f.height,d=e.getContext("2d"),"image/jpeg"===b&&(d.fillStyle="#fff",d.fillRect(0,0,f.width,f.height)),d.drawImage(this.$clone[0],f.x,f.y,f.width,f.height,0,0,f.width,f.height),g=e.toDataURL(b,c)),g},setDragMode:function(a){var b=this.$canvas,c=this.defaults,d=f,g=f;if(this.built&&!this.disabled){switch(a){case"crop":c.dragCrop&&(d=e,b.data(k,a));break;case"move":g=e,b.data(k,a);break;default:b.removeData(k)}b.toggleClass(t,d).toggleClass(s,g)}},enable:function(){this.built&&(this.disabled=f,this.$cropper.removeClass(u))},disable:function(){this.built&&(this.disabled=e,this.$cropper.addClass(u))},rotate:function(a){var b=this.image;a=P(a)||0,this.built&&0!==a&&!this.disabled&&this.defaults.rotatable&&this.support.canvas&&(this.rotated=e,a=b.rotate=(b.rotate+a)%360,this.replace(this.getRotatedDataURL(a),!0))},getRotatedDataURL:function(b){var c=a("")[0],d=c.getContext("2d"),e=b*Math.PI/180,f=M(b)%180,g=f>90?180-f:f,h=g*Math.PI/180,i=this.originalImage,j=i.naturalWidth,k=i.naturalHeight,l=M(j*O(h)+k*N(h)),m=M(j*N(h)+k*O(h));return c.width=l,c.height=m,d.save(),d.translate(l/2,m/2),d.rotate(e),d.drawImage(this.$original[0],-j/2,-k/2,j,k),d.restore(),c.toDataURL()},zoom:function(a){var b,c,d,e=this.image;a=P(a),this.built&&a&&!this.disabled&&this.defaults.zoomable&&(b=e.width*(1+a),c=e.height*(1+a),d=b/e._width,d>10||(1>d&&(b=e._width,c=e._height),this.setDragMode(1>=d?"crop":"move"),e.oldWidth=e.width,e.oldHeight=e.height,e.width=b,e.height=c,e.ratio=e.width/e.naturalWidth,this.renderImage("zoom")))},dblclick:function(){this.disabled||this.setDragMode(this.$canvas.hasClass(t)?"move":"crop")},wheel:function(a){var b,c=a.originalEvent,d=117.25,e=5,f=166.66665649414062,g=.1;this.disabled||(a.preventDefault(),c.deltaY?(b=c.deltaY,b=b%e===0?b/e:b%d===0?b/d:b/f):b=c.wheelDelta?-c.wheelDelta/120:c.detail?c.detail/3:0,this.zoom(b*g))},dragstart:function(b){var c,d,g,h=b.originalEvent.touches,i=b;if(!this.disabled){if(h){if(g=h.length,g>1){if(!this.defaults.zoomable||2!==g)return;i=h[1],this.startX2=i.pageX,this.startY2=i.pageY,c="zoom"}i=h[0]}if(c=c||a(i.target).data(k),m.test(c)){if(b.preventDefault(),d=a.Event(D),this.$element.trigger(d),d.isDefaultPrevented())return;this.directive=c,this.cropping=f,this.startX=i.pageX,this.startY=i.pageY,"crop"===c&&(this.cropping=e,this.$canvas.addClass(p))}}},dragmove:function(b){var c,d,e=b.originalEvent.touches,f=b;if(!this.disabled){if(e){if(d=e.length,d>1){if(!this.defaults.zoomable||2!==d)return;f=e[1],this.endX2=f.pageX,this.endY2=f.pageY}f=e[0]}if(this.directive){if(b.preventDefault(),c=a.Event(E),this.$element.trigger(c),c.isDefaultPrevented())return;this.endX=f.pageX,this.endY=f.pageY,this.dragging()}}},dragend:function(b){var c;if(!this.disabled&&this.directive){if(b.preventDefault(),c=a.Event(F),this.$element.trigger(c),c.isDefaultPrevented())return;this.cropping&&(this.cropping=f,this.$canvas.toggleClass(p,this.cropped&&this.defaults.modal)),this.directive=""}},dragging:function(){var a,b=this.directive,c=this.image,d=this.cropper,g=d.width,h=d.height,i=this.dragger,j=i.width,k=i.height,l=i.left,m=i.top,n=l+j,o=m+k,p=e,r=this.defaults,s=r.aspectRatio,t={x:this.endX-this.startX,y:this.endY-this.startY};switch(s&&(t.X=t.y*s,t.Y=t.x/s),b){case"all":l+=t.x,m+=t.y;break;case"e":if(t.x>=0&&(n>=g||s&&(0>=m||o>=h))){p=f;break}j+=t.x,s&&(k=j/s,m-=t.Y/2),0>j&&(b="w",j=0);break;case"n":if(t.y<=0&&(0>=m||s&&(0>=l||n>=g))){p=f;break}k-=t.y,m+=t.y,s&&(j=k*s,l+=t.X/2),0>k&&(b="s",k=0);break;case"w":if(t.x<=0&&(0>=l||s&&(0>=m||o>=h))){p=f;break}j-=t.x,l+=t.x,s&&(k=j/s,m+=t.Y/2),0>j&&(b="e",j=0);break;case"s":if(t.y>=0&&(o>=h||s&&(0>=l||n>=g))){p=f;break}k+=t.y,s&&(j=k*s,l-=t.X/2),0>k&&(b="n",k=0);break;case"ne":if(s){if(t.y<=0&&(0>=m||n>=g)){p=f;break}k-=t.y,m+=t.y,j=k*s}else t.x>=0?g>n?j+=t.x:t.y<=0&&0>=m&&(p=f):j+=t.x,t.y<=0?m>0&&(k-=t.y,m+=t.y):(k-=t.y,m+=t.y);0>k&&(b="sw",k=0,j=0);break;case"nw":if(s){if(t.y<=0&&(0>=m||0>=l)){p=f;break}k-=t.y,m+=t.y,j=k*s,l+=t.X}else t.x<=0?l>0?(j-=t.x,l+=t.x):t.y<=0&&0>=m&&(p=f):(j-=t.x,l+=t.x),t.y<=0?m>0&&(k-=t.y,m+=t.y):(k-=t.y,m+=t.y);0>k&&(b="se",k=0,j=0);break;case"sw":if(s){if(t.x<=0&&(0>=l||o>=h)){p=f;break}j-=t.x,l+=t.x,k=j/s}else t.x<=0?l>0?(j-=t.x,l+=t.x):t.y>=0&&o>=h&&(p=f):(j-=t.x,l+=t.x),t.y>=0?h>o&&(k+=t.y):k+=t.y;0>j&&(b="ne",k=0,j=0);break;case"se":if(s){if(t.x>=0&&(n>=g||o>=h)){p=f;break}j+=t.x,k=j/s}else t.x>=0?g>n?j+=t.x:t.y>=0&&o>=h&&(p=f):j+=t.x,t.y>=0?h>o&&(k+=t.y):k+=t.y;0>j&&(b="nw",k=0,j=0);break;case"move":c.left+=t.x,c.top+=t.y,this.renderImage("move"),p=f;break;case"zoom":r.zoomable&&(this.zoom(function(a,b,c,d,e,f){return(J(e*e+f*f)-J(c*c+d*d))/J(a*a+b*b)}(c.width,c.height,M(this.startX-this.startX2),M(this.startY-this.startY2),M(this.endX-this.endX2),M(this.endY-this.endY2))),this.endX2=this.startX2,this.endY2=this.startY2);break;case"crop":t.x&&t.y&&(a=this.$cropper.offset(),l=this.startX-a.left,m=this.startY-a.top,j=i.minWidth,k=i.minHeight,t.x>0?t.y>0?b="se":(b="ne",m-=k):t.y>0?(b="sw",l-=j):(b="nw",l-=j,m-=k),this.cropped||(this.cropped=e,this.$dragger.removeClass(q)))}p&&(i.width=j,i.height=k,i.left=l,i.top=m,this.directive=b,this.renderDragger()),this.startX=this.endX,this.startY=this.endY}},H.TEMPLATE=function(a,b){return b=b.split(","),a.replace(/\d+/g,function(a){return b[a]})}('<0 6="5-container"><0 6="5-canvas"><0 6="5-dragger"><1 6="5-viewer"><1 6="5-8 8-h"><1 6="5-8 8-v"><1 6="5-face" 3-2="all"><1 6="5-7 7-e" 3-2="e"><1 6="5-7 7-n" 3-2="n"><1 6="5-7 7-w" 3-2="w"><1 6="5-7 7-s" 3-2="s"><1 6="5-4 4-e" 3-2="e"><1 6="5-4 4-n" 3-2="n"><1 6="5-4 4-w" 3-2="w"><1 6="5-4 4-s" 3-2="s"><1 6="5-4 4-ne" 3-2="ne"><1 6="5-4 4-nw" 3-2="nw"><1 6="5-4 4-sw" 3-2="sw"><1 6="5-4 4-se" 3-2="se">',"div,span,directive,data,point,cropper,class,line,dashed"),H.DEFAULTS={aspectRatio:"auto",autoCropArea:.8,data:{},done:a.noop,preview:"",multiple:f,autoCrop:e,dragCrop:e,dashed:e,modal:e,movable:e,resizable:e,zoomable:e,rotatable:e,minWidth:0,minHeight:0,maxWidth:i,maxHeight:i,build:g,built:g,dragstart:g,dragmove:g,dragend:g},H.setDefaults=function(b){a.extend(H.DEFAULTS,b)},H.other=a.fn.cropper,a.fn.cropper=function(b){var c,d=[].slice.call(arguments,1);return this.each(function(){var e,f=a(this),g=f.data("cropper");g||f.data("cropper",g=new H(this,b)),"string"==typeof b&&a.isFunction(e=g[b])&&(c=e.apply(g,d))}),typeof c!==j?c:this},a.fn.cropper.Constructor=H,a.fn.cropper.setDefaults=H.setDefaults,a.fn.cropper.noConflict=function(){return a.fn.cropper=H.other,this}}); \ No newline at end of file diff --git a/frontend/client/res/templates/modals/image-crop.tpl b/frontend/client/res/templates/modals/image-crop.tpl new file mode 100644 index 0000000000..63dde9956e --- /dev/null +++ b/frontend/client/res/templates/modals/image-crop.tpl @@ -0,0 +1,12 @@ + +
+
+
+
+
+
+ + +
+
+
diff --git a/frontend/client/src/views/fields/file.js b/frontend/client/src/views/fields/file.js index 0000de690d..f94f2b0baa 100644 --- a/frontend/client/src/views/fields/file.js +++ b/frontend/client/src/views/fields/file.js @@ -17,7 +17,7 @@ * * You should have received a copy of the GNU General Public License * along with EspoCRM. If not, see http://www.gnu.org/licenses/. - ************************************************************************/ + ************************************************************************/ Espo.define('Views.Fields.File', 'Views.Fields.Link', function (Dep) { @@ -50,16 +50,16 @@ Espo.define('Views.Fields.File', 'Views.Fields.Link', function (Dep) { var $div = $(e.currentTarget).parent(); this.deleteAttachment(); $div.parent().remove(); - }, + }, 'change input.file': function (e) { var $file = $(e.currentTarget); - var files = e.currentTarget.files; + var files = e.currentTarget.files; if (files.length) { this.uploadFile(files[0]); $file.replaceWith($file.clone(true)); - } + } }, - 'click a[data-action="showImagePreview"]': function (e) { + 'click a[data-action="showImagePreview"]': function (e) { var id = $(e.currentTarget).data('id'); this.createView('preview', 'Modals.ImagePreview', { id: id, @@ -121,7 +121,7 @@ Espo.define('Views.Fields.File', 'Views.Fields.Link', function (Dep) { }, afterRender: function () { - if (this.mode == 'edit') { + if (this.mode == 'edit') { this.$attachment = this.$el.find('div.attachment'); var name = this.model.get(this.nameName); @@ -129,9 +129,9 @@ Espo.define('Views.Fields.File', 'Views.Fields.Link', function (Dep) { var id = this.model.get(this.idName); if (id) { this.addAttachmentBox(name, type, id); - } - } - }, + } + } + }, getDetailPreview: function (name, type, id) { var preview = name; @@ -141,7 +141,7 @@ Espo.define('Views.Fields.File', 'Views.Fields.Link', function (Dep) { case 'image/jpeg': case 'image/gif': preview = ''; - } + } return preview; }, @@ -179,17 +179,17 @@ Espo.define('Views.Fields.File', 'Views.Fields.Link', function (Dep) { } }, - deleteAttachment: function () { - var id = this.model.get(this.idName); - var o = {}; + deleteAttachment: function () { + var id = this.model.get(this.idName); + var o = {}; o[this.idName] = null; - o[this.nameName] = null; + o[this.nameName] = null; this.model.set(o); this.$attachment.empty(); if (id) { - if (this.model.isNew()) { + if (this.model.isNew()) { this.getModelFactory().create('Attachment', function (attachment) { attachment.id = id; attachment.destroy(); @@ -200,16 +200,16 @@ Espo.define('Views.Fields.File', 'Views.Fields.Link', function (Dep) { setAttachment: function (attachment) { var arr = _.clone(this.model.get(this.idsName)); - var o = {}; + var o = {}; o[this.idName] = attachment.id; o[this.nameName] = attachment.get('name'); this.model.set(o); }, - uploadFile: function (file) { + uploadFile: function (file) { var isCanceled = false; - this.getModelFactory().create('Attachment', function (attachment) { + this.getModelFactory().create('Attachment', function (attachment) { var $att = this.addAttachmentBox(file.name, file.type); this.$el.find('.attachment-button').addClass('hidden'); @@ -221,42 +221,53 @@ Espo.define('Views.Fields.File', 'Views.Fields.Link', function (Dep) { var fileReader = new FileReader(); fileReader.onload = function (e) { - $.ajax({ - type: 'POST', - url: 'Attachment/action/upload', - data: e.target.result, - contentType: 'multipart/encrypted', - timeout: 0, - }).done(function (data) { - attachment.id = data.attachmentId; - attachment.set('name', file.name); - attachment.set('type', file.type || 'text/plain'); - attachment.set('size', file.size); - attachment.set('role', 'Attachment'); - attachment.set('parentType', this.model.name); - attachment.set('parentId', this.model.id); - - attachment.once('sync', function () { - if (!isCanceled) { - $att.trigger('ready'); - this.setAttachment(attachment); - } - }, this); - attachment.save(); + this.handleFileUpload(file, e.target.result, function (result, fileParams) { + $.ajax({ + type: 'POST', + url: 'Attachment/action/upload', + data: result, + contentType: 'multipart/encrypted', + timeout: 0, + }).done(function (data) { + attachment.id = data.attachmentId; + attachment.set('name', fileParams.name); + attachment.set('type', fileParams.type || 'text/plain'); + attachment.set('size', fileParams.size); + attachment.set('role', 'Attachment'); + attachment.set('parentType', this.model.name); + attachment.set('parentId', this.model.id); + + attachment.once('sync', function () { + if (!isCanceled) { + $att.trigger('ready'); + this.setAttachment(attachment); + } + }, this); + attachment.save(); + }.bind(this)); }.bind(this)); }.bind(this); - fileReader.readAsDataURL(file); + fileReader.readAsDataURL(file); }, this); }, + + handleFileUpload: function (file, contents, callback) { + var params = { + name: file.name, + type: file.type, + size: file.size + }; + callback(contents, params); + }, addAttachmentBox: function (name, type, id) { this.$attachment.empty(); - var self = this; + var self = this; var removeLink = ''; - var preview = name; + var preview = name; if (this.showPreview && id) { preview = this.getEditPreview(name, type, id); } @@ -267,11 +278,11 @@ Espo.define('Views.Fields.File', 'Views.Fields.Link', function (Dep) { .append($('' + preview + '').css('width', '270px')) .append(removeLink); - var $container = $('
').append($att); - this.$attachment.append($container); + var $container = $('
').append($att); + this.$attachment.append($container); if (!id) { - var $loading = $('' + this.translate('Uploading...') + ''); + var $loading = $('' + this.translate('Uploading...') + ''); $container.append($loading); $att.on('ready', function () { $loading.html(self.translate('Ready')); diff --git a/frontend/client/src/views/fields/image.js b/frontend/client/src/views/fields/image.js index 5dcf3eef53..7116fc5c0e 100644 --- a/frontend/client/src/views/fields/image.js +++ b/frontend/client/src/views/fields/image.js @@ -17,7 +17,7 @@ * * You should have received a copy of the GNU General Public License * along with EspoCRM. If not, see http://www.gnu.org/licenses/. - ************************************************************************/ + ************************************************************************/ Espo.define('Views.Fields.Image', 'Views.Fields.File', function (Dep) { @@ -36,7 +36,7 @@ Espo.define('Views.Fields.Image', 'Views.Fields.File', function (Dep) { setup: function () { Dep.prototype.setup.call(this); - if ('previewSize' in this.params) { + if ('previewSize' in this.params && this.params.previewSize) { this.previewSize = this.params.previewSize; } }, diff --git a/frontend/client/src/views/modal.js b/frontend/client/src/views/modal.js index ed0db37387..93e1239473 100644 --- a/frontend/client/src/views/modal.js +++ b/frontend/client/src/views/modal.js @@ -17,15 +17,15 @@ * * You should have received a copy of the GNU General Public License * along with EspoCRM. If not, see http://www.gnu.org/licenses/. - ************************************************************************/ + ************************************************************************/ Espo.define('Views.Modal', 'View', function (Dep) { - return Dep.extend({ + return Dep.extend({ cssName: 'modal-dialog', - header: false, + header: false, dialog: null, @@ -38,7 +38,7 @@ Espo.define('Views.Modal', 'View', function (Dep) { onClick: function (dialog) { dialog.close(); } - } + } ], width: false, @@ -50,7 +50,7 @@ Espo.define('Views.Modal', 'View', function (Dep) { this.options = this.options || {}; this.options.el = this.containerSelector; - this.on('render', function () { + this.on('render', function () { $(containerSelector).remove(); $('
').css('display', 'none').attr('id', id).appendTo('body'); @@ -72,10 +72,10 @@ Espo.define('Views.Modal', 'View', function (Dep) { this.remove(); }.bind(this) }); - this.setElement(containerSelector + ' .body'); + this.setElement(containerSelector + ' .body'); }, this); - this.on('after:render', function () { + this.on('after:render', function () { $(containerSelector).show(); this.dialog.show(); }); @@ -90,7 +90,7 @@ Espo.define('Views.Modal', 'View', function (Dep) { close: function () { this.dialog.close(); - }, + }, }); }); diff --git a/frontend/client/src/views/modals/image-crop.js b/frontend/client/src/views/modals/image-crop.js new file mode 100644 index 0000000000..9fdb233a33 --- /dev/null +++ b/frontend/client/src/views/modals/image-crop.js @@ -0,0 +1,89 @@ +/************************************************************************ + * This file is part of EspoCRM. + * + * EspoCRM - Open Source CRM application. + * Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko + * Website: http://www.espocrm.com + * + * EspoCRM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EspoCRM 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EspoCRM. If not, see http://www.gnu.org/licenses/. + ************************************************************************/ + +Espo.define('Views.Modals.ImageCrop', ['Views.Modal', 'lib!Cropper'], function (Dep, Cropper) { + + return Dep.extend({ + + cssName: 'image-crop', + + template: 'modals.image-crop', + + events: { + 'click [data-action="zoomIn"]': function () { + this.$img.cropper('zoom', 0.1); + }, + 'click [data-action="zoomOut"]': function () { + this.$img.cropper('zoom', -0.1); + } + }, + + + data: function () { + return { + + }; + }, + + setup: function () { + this.header = this.translate('Setup Avatar', 'labels', 'User'); + + this.buttons = [ + { + name: 'crop', + label: 'Submit', + style: 'primary', + onClick: function (dialog) { + this.crop(); + }.bind(this) + }, + { + name: 'cancel', + label: 'Cancel', + onClick: function (dialog) { + this.close(); + }.bind(this) + } + ]; + }, + + afterRender: function () { + var $img = this.$img = $('').attr('src', this.options.contents).addClass('hidden'); + + this.$el.find('.image-container').append($img); + + $img.cropper({ + aspectRatio: 1, + movable: true, + resizable: true, + rotatable: false, + }); + }, + + crop: function () { + var dataUrl = this.$img.cropper('getDataURL', 'image/jpeg'); + this.trigger('crop', dataUrl); + this.close(); + } + + }); +}); + diff --git a/frontend/client/src/views/user/fields/avatar.js b/frontend/client/src/views/user/fields/avatar.js new file mode 100644 index 0000000000..ef017bc33a --- /dev/null +++ b/frontend/client/src/views/user/fields/avatar.js @@ -0,0 +1,56 @@ +/************************************************************************ + * This file is part of EspoCRM. + * + * EspoCRM - Open Source CRM application. + * Copyright (C) 2014 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko + * Website: http://www.espocrm.com + * + * EspoCRM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EspoCRM 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EspoCRM. If not, see http://www.gnu.org/licenses/. + ************************************************************************/ +Espo.define('Views.User.Fields.Avatar', 'Views.Fields.Image', function (Dep) { + + return Dep.extend({ + + handleFileUpload: function (file, contents, callback) { + + this.createView('crop', 'Modals.ImageCrop', { + contents: contents + }, function (view) { + view.render(); + + var croped = false; + + this.listenToOnce(view, 'crop', function (croppedContents, params) { + croped = true; + setTimeout(function () { + params = params || {}; + params.name = 'avatar.jpg'; + params.type = 'image/jpeg'; + + callback(croppedContents, params); + }.bind(this), 10); + }); + this.listenToOnce(view, 'remove', function () { + if (!croped) { + setTimeout(function () { + this.render(); + }.bind(this), 10); + } + }.bind(this)); + }.bind(this)); + }, + + }); + +}); diff --git a/frontend/client/src/views/user/record/detail-side.js b/frontend/client/src/views/user/record/detail-side.js index c8423a6a58..e39c4a7b5e 100644 --- a/frontend/client/src/views/user/record/detail-side.js +++ b/frontend/client/src/views/user/record/detail-side.js @@ -17,9 +17,9 @@ * * You should have received a copy of the GNU General Public License * along with EspoCRM. If not, see http://www.gnu.org/licenses/. - ************************************************************************/ + ************************************************************************/ -Espo.define('Views.User.Record.DetailSide', 'Views.Record.DetailSide', function (Dep) { +Espo.define('Views.User.Record.DetailSide', 'Views.Record.DetailSide', function (Dep) { return Dep.extend({ @@ -29,10 +29,10 @@ Espo.define('Views.User.Record.DetailSide', 'Views.Record.DetailSide', function label: false, view: 'Record.Panels.Side', options: { - fields: ['teams', 'roles'], + fields: ['avatar'], mode: 'detail', - } - } + } + } ], }); diff --git a/frontend/client/src/views/user/record/detail.js b/frontend/client/src/views/user/record/detail.js index 2fc38519f2..d2607d3537 100644 --- a/frontend/client/src/views/user/record/detail.js +++ b/frontend/client/src/views/user/record/detail.js @@ -17,17 +17,16 @@ * * You should have received a copy of the GNU General Public License * along with EspoCRM. If not, see http://www.gnu.org/licenses/. - ************************************************************************/ + ************************************************************************/ -Espo.define('Views.User.Record.Detail', 'Views.Record.Detail', function (Dep) { +Espo.define('Views.User.Record.Detail', 'Views.Record.Detail', function (Dep) { return Dep.extend({ - sideView: false, + sideView: 'User.Record.DetailSide', editModeEnabled: false, - setup: function () { Dep.prototype.setup.call(this); this.buttons = _.clone(this.buttons); @@ -58,12 +57,12 @@ Espo.define('Views.User.Record.Detail', 'Views.Record.Detail', function (Dep) { if (this.model.id == this.getUser().id) { this.listenTo(this.model, 'after:save', function () { - this.getUser().set(this.model.toJSON()); + this.getUser().set(this.model.toJSON()); }.bind(this)); } }, - actionChangePassword: function () { + actionChangePassword: function () { this.notify('Loading...'); this.createView('changePassword', 'Modals.ChangePassword', { @@ -73,7 +72,7 @@ Espo.define('Views.User.Record.Detail', 'Views.Record.Detail', function (Dep) { this.notify(false); this.listenToOnce(view, 'changed', function () { - setTimeout(function () { + setTimeout(function () { this.getBaseController().logout(); }.bind(this), 2000); }, this); @@ -94,20 +93,20 @@ Espo.define('Views.User.Record.Detail', 'Views.Record.Detail', function (Dep) { data: { id: this.model.id, } - }).done(function (aclData) { + }).done(function (aclData) { this.createView('access', 'User.Access', { aclData: aclData, model: this.model, }, function (view) { this.notify(false); - view.render(); + view.render(); }.bind(this)); }.bind(this)); }, - }); + }); }); diff --git a/frontend/client/src/views/user/record/edit-side.js b/frontend/client/src/views/user/record/edit-side.js index 9efb452135..bebd93cc99 100644 --- a/frontend/client/src/views/user/record/edit-side.js +++ b/frontend/client/src/views/user/record/edit-side.js @@ -17,9 +17,9 @@ * * You should have received a copy of the GNU General Public License * along with EspoCRM. If not, see http://www.gnu.org/licenses/. - ************************************************************************/ + ************************************************************************/ -Espo.define('Views.User.Record.EditSide', 'Views.Record.EditSide', function (Dep) { +Espo.define('Views.User.Record.EditSide', 'Views.Record.EditSide', function (Dep) { return Dep.extend({ @@ -29,13 +29,13 @@ Espo.define('Views.User.Record.EditSide', 'Views.Record.EditSide', function (Dep label: false, view: 'Record.Panels.Side', options: { - fields: ['teams', 'roles'], + fields: ['avatar'], mode: 'edit', - } - } + } + } ], - }); + }); }); diff --git a/frontend/client/src/views/user/record/edit.js b/frontend/client/src/views/user/record/edit.js index 6b8fc102ec..8b131f3292 100644 --- a/frontend/client/src/views/user/record/edit.js +++ b/frontend/client/src/views/user/record/edit.js @@ -17,20 +17,20 @@ * * You should have received a copy of the GNU General Public License * along with EspoCRM. If not, see http://www.gnu.org/licenses/. - ************************************************************************/ + ************************************************************************/ -Espo.define('Views.User.Record.Edit', 'Views.Record.Edit', function (Dep) { +Espo.define('Views.User.Record.Edit', 'Views.Record.Edit', function (Dep) { return Dep.extend({ - sideView: false, + sideView: 'User.Record.EditSide', setup: function () { Dep.prototype.setup.call(this); if (this.model.id == this.getUser().id) { this.listenTo(this.model, 'after:save', function () { - this.getUser().set(this.model.toJSON()); + this.getUser().set(this.model.toJSON()); }.bind(this)); } }, @@ -43,7 +43,7 @@ Espo.define('Views.User.Record.Edit', 'Views.Record.Edit', function (Dep) { var layout = _.clone(simpleLayout); - if (this.type == 'edit') { + if (this.type == 'edit') { layout.push({ label: 'Password', rows: [ @@ -53,7 +53,7 @@ Espo.define('Views.User.Record.Edit', 'Views.Record.Edit', function (Dep) { params: { required: self.isNew, readyToChange: true - } + } },{ name: 'generatePassword', view: 'User.Fields.GeneratePassword', @@ -65,7 +65,7 @@ Espo.define('Views.User.Record.Edit', 'Views.Record.Edit', function (Dep) { params: { required: self.isNew, readyToChange: true - } + } },{ name: 'passwordInfo', customLabel: '', @@ -101,7 +101,7 @@ Espo.define('Views.User.Record.Edit', 'Views.Record.Edit', function (Dep) { return data; } - }); + }); });