1
0
Fork 0
mirror of https://github.com/Oreolek/ifhub.club.git synced 2024-05-19 09:18:18 +03:00

Создание аватара на основе фото профиля

This commit is contained in:
Mzhelskiy Maxim 2014-02-20 17:06:49 +07:00
parent 2e5c8677a0
commit defbeb80c0
11 changed files with 155 additions and 226 deletions

View file

@ -98,6 +98,7 @@ class ActionAjax extends Action {
$this->AddEventPreg('/^poll$/i','/^vote$/','/^$/','EventPollVote');
$this->AddEvent('modal-friend-list', 'EventModalFriendList');
$this->AddEventPreg('/^modal$/i','/^image-crop$/','/^$/','EventModalImageCrop');
}
@ -110,9 +111,6 @@ class ActionAjax extends Action {
* Показывает модальное окно с друзьями
*/
protected function EventModalFriendList() {
// Устанавливаем формат Ajax ответа
$this->Viewer_SetResponseAjax('json');
if ( ! $this->oUserCurrent ) {
return parent::EventNotFound();
}
@ -136,6 +134,17 @@ class ActionAjax extends Action {
$this->Viewer_AssignAjax('sText', $oViewer->Fetch("modals/modal.user_list.tpl"));
}
/**
* Показывает модальное окно с функцией кропа изображения
*/
protected function EventModalImageCrop() {
$oViewer = $this->Viewer_GetLocalViewer();
$oViewer->Assign('sImageSrc',getRequestStr('image_src'));
$this->Viewer_AssignAjax('sText', $oViewer->Fetch("modals/modal.image_crop.tpl"));
}
protected function EventPollVote() {
if (!$this->oUserCurrent) {

View file

@ -67,10 +67,6 @@ class ActionSettings extends Action {
* Регистрация евентов
*/
protected function RegisterEvent() {
$this->AddEventPreg('/^profile$/i','/^upload-avatar/i','/^$/i','EventUploadAvatar');
$this->AddEventPreg('/^profile$/i','/^resize-avatar/i','/^$/i','EventResizeAvatar');
$this->AddEventPreg('/^profile$/i','/^remove-avatar/i','/^$/i','EventRemoveAvatar');
$this->AddEventPreg('/^profile$/i','/^cancel-avatar/i','/^$/i','EventCancelAvatar');
$this->AddEvent('profile','EventProfile');
$this->AddEvent('invite','EventInvite');
$this->AddEvent('tuning','EventTuning');
@ -78,6 +74,7 @@ class ActionSettings extends Action {
$this->AddEventPreg('/^ajax-upload-photo$/i','/^$/i','EventAjaxUploadPhoto');
$this->AddEventPreg('/^ajax-remove-photo$/i','/^$/i','EventAjaxRemovePhoto');
$this->AddEventPreg('/^ajax-change-avatar$/i','/^$/i','EventAjaxChangeAvatar');
}
@ -86,6 +83,9 @@ class ActionSettings extends Action {
**********************************************************************************
*/
/**
* Загрузка фотографии в профиль пользователя
*/
protected function EventAjaxUploadPhoto() {
/**
* Устанавливаем формат Ajax ответа
@ -106,11 +106,17 @@ class ActionSettings extends Action {
$this->Message_AddError(is_bool($sResult) ? '' : $sResult,$this->Lang_Get('error'));
return false;
}
/**
* Создаем аватар на основе фото
*/
$this->User_CreateProfileAvatar($oUser->getProfileFoto(),$oUser);
$this->Viewer_AssignAjax('sChooseText',$this->Lang_Get('settings_profile_photo_change'));
$this->Viewer_AssignAjax('sFile',$oUser->getProfileFotoPath());
}
/**
* Удаление фотографии профиля
*/
protected function EventAjaxRemovePhoto() {
$this->Viewer_SetResponseAjax('json');
@ -121,126 +127,29 @@ class ActionSettings extends Action {
return $this->EventErrorDebug();
}
$this->User_DeleteFoto($oUser);
$this->User_DeleteProfilePhoto($oUser);
$this->User_DeleteProfileAvatar($oUser);
$this->User_Update($oUser);
$this->Viewer_AssignAjax('sChooseText',$this->Lang_Get('settings_profile_photo_upload'));
$this->Viewer_AssignAjax('sFile',$oUser->getProfileFotoPath());
}
/**
* Загрузка временной картинки для аватара
* Обновление аватара на основе фото профиля
*/
protected function EventUploadAvatar() {
/**
* Устанавливаем формат Ajax ответа
*/
$this->Viewer_SetResponseAjax('jsonIframe',false);
protected function EventAjaxChangeAvatar() {
$this->Viewer_SetResponseAjax('json');
if(!isset($_FILES['avatar']['tmp_name'])) {
if (!$oUser=$this->User_GetUserById(getRequestStr('user_id'))) {
return $this->EventErrorDebug();
}
/**
* Копируем загруженный файл
*/
$sFileTmp=Config::Get('sys.cache.dir').func_generator();
if (!move_uploaded_file($_FILES['avatar']['tmp_name'],$sFileTmp)) {
if (!$oUser->isAllowEdit()) {
return $this->EventErrorDebug();
}
/**
* Ресайзим и сохраняем уменьшенную копию
*/
$sDir=Config::Get('path.uploads.images')."/tmp/avatars/{$this->oUserCurrent->getId()}";
if ($sFileAvatar=$this->Image_Resize($sFileTmp,$sDir,'original',Config::Get('view.img_max_width'),Config::Get('view.img_max_height'),200,null,true)) {
/**
* Зписываем в сессию
*/
$this->Session_Set('sAvatarFileTmp',$sFileAvatar);
$this->Viewer_AssignAjax('sTmpFile',$this->Image_GetWebPath($sFileAvatar));
} else {
$this->Message_AddError($this->Image_GetLastError(),$this->Lang_Get('error'));
}
unlink($sFileTmp);
}
/**
* Вырезает из временной аватарки область нужного размера, ту что задал пользователь
*/
protected function EventResizeAvatar() {
/**
* Устанавливаем формат Ajax ответа
*/
$this->Viewer_SetResponseAjax('json');
/**
* Получаем файл из сессии
*/
$sFileAvatar=$this->Session_Get('sAvatarFileTmp');
if (!file_exists($sFileAvatar)) {
return $this->EventErrorDebug();
}
/**
* Получаем размер области из параметров
*/
$aSize=array();
$aSizeTmp=getRequest('size');
if (isset($aSizeTmp['x']) and is_numeric($aSizeTmp['x'])
and isset($aSizeTmp['y']) and is_numeric($aSizeTmp['y'])
and isset($aSizeTmp['x2']) and is_numeric($aSizeTmp['x2'])
and isset($aSizeTmp['y2']) and is_numeric($aSizeTmp['y2'])) {
$aSize=array('x1'=>$aSizeTmp['x'],'y1'=>$aSizeTmp['y'],'x2'=>$aSizeTmp['x2'],'y2'=>$aSizeTmp['y2']);
}
/**
* Вырезаем аватарку
*/
if ($sFileWeb=$this->User_UploadAvatar($sFileAvatar,$this->oUserCurrent,$aSize)) {
/**
* Удаляем старые аватарки
*/
if ($sFileWeb!=$this->oUserCurrent->getProfileAvatar()) {
$this->User_DeleteAvatar($this->oUserCurrent);
}
$this->oUserCurrent->setProfileAvatar($sFileWeb);
$this->User_Update($this->oUserCurrent);
$this->Session_Drop('sAvatarFileTmp');
$this->Viewer_AssignAjax('sFile',$this->oUserCurrent->getProfileAvatarPath(100));
$this->Viewer_AssignAjax('sTitleUpload',$this->Lang_Get('settings_profile_avatar_change'));
} else {
$this->Message_AddError($this->Lang_Get('settings_profile_avatar_error'),$this->Lang_Get('error'));
if (true!==($res=$this->User_CreateProfileAvatar($oUser->getProfileFoto(),$oUser,getRequest('size'),getRequestStr('canvas_width')))) {
$this->Message_AddError(is_string($res) ? $res : $this->Lang_Get('error'));
}
}
/**
* Удаляет аватар
*/
protected function EventRemoveAvatar() {
/**
* Устанавливаем формат Ajax ответа
*/
$this->Viewer_SetResponseAjax('json');
/**
* Удаляем
*/
$this->User_DeleteAvatar($this->oUserCurrent);
$this->oUserCurrent->setProfileAvatar(null);
$this->User_Update($this->oUserCurrent);
/**
* Возвращает дефолтную аватарку
*/
$this->Viewer_AssignAjax('sFile',$this->oUserCurrent->getProfileAvatarPath(100));
$this->Viewer_AssignAjax('sTitleUpload',$this->Lang_Get('settings_profile_avatar_upload'));
}
/**
* Отмена ресайза аватарки, необходимо удалить временный файл
*/
protected function EventCancelAvatar() {
/**
* Устанавливаем формат Ajax ответа
*/
$this->Viewer_SetResponseAjax('json');
/**
* Достаем из сессии файл и удаляем
*/
$sFileAvatar=$this->Session_Get('sAvatarFileTmp');
$this->Image_RemoveFile($sFileAvatar);
$this->Session_Drop('sAvatarFileTmp');
}
/**
* Дополнительные настройки сайта
*/

View file

@ -871,7 +871,7 @@ class ModuleBlog extends Module {
/**
* Имя файла для сохранения
*/
$sFileName='avatar_blog_'.$oBlog->getId();
$sFileName='avatar-blog-'.$oBlog->getId();
/**
* Сохраняем оригинальную копию
*/

View file

@ -1054,119 +1054,69 @@ class ModuleUser extends Module {
return $this->oMapper->GetReminderByCode($sCode);
}
/**
* Загрузка аватара пользователя
* Создает аватар пользователя на основе области из изображения
*
* @param string $sFileTmp Серверный путь до временного аватара
* @param ModuleUser_EntityUser $oUser Объект пользователя
* @param array $aSize Размер области из которой нужно вырезать картинку - array('x1'=>0,'y1'=>0,'x2'=>100,'y2'=>100)
* @return string|bool
* @param $sFileFrom
* @param $oUser
* @param $aSize
* @param null $iCanvasWidth
*
* @return bool
*/
public function UploadAvatar($sFileTmp,$oUser,$aSize=array()) {
if (!file_exists($sFileTmp)) {
return false;
}
$sPath = $this->Image_GetIdDir($oUser->getId());
$aParams=$this->Image_BuildParams('avatar');
public function CreateProfileAvatar($sFileFrom,$oUser,$aSize=null,$iCanvasWidth=null) {
$aParams=$this->Image_BuildParams('profile_avatar');
/**
* Срезаем квадрат
* Если объект изображения не создан, возвращаем ошибку
*/
$oImage = $this->Image_CreateImageObject($sFileTmp);
/**
* Если объект изображения не создан,
* возвращаем ошибку
*/
if($sError=$oImage->get_last_error()) {
// Вывод сообщения об ошибки, произошедшей при создании объекта изображения
// $this->Message_AddError($sError,$this->Lang_Get('error'));
@unlink($sFileTmp);
return false;
if(!$oImage=$this->Image_OpenFrom($sFileFrom,$aParams)) {
return $this->Image_GetLastError();
}
/**
* Если нет области, то берем центральный квадрат
*/
if (!$aSize) {
$oImage = $this->Image_CropSquare($oImage);
$oImage->set_jpg_quality($aParams['jpg_quality']);
$oImage->output(null,$sFileTmp);
$oImage->cropSquare();
} else {
$iWSource=$oImage->get_image_params('width');
$iHSource=$oImage->get_image_params('height');
/**
* Достаем переменные x1 и т.п. из $aSize
* Вырезаем область из исходного файла
*/
extract($aSize,EXTR_PREFIX_SAME,'ops');
if ($x1>$x2) {
// меняем значения переменных
$x1 = $x1 + $x2;
$x2 = $x1 - $x2;
$x1 = $x1 - $x2;
}
if ($y1>$y2) {
$y1 = $y1 + $y2;
$y2 = $y1 - $y2;
$y1 = $y1 - $y2;
}
if ($x1<0) {
$x1=0;
}
if ($y1<0) {
$y1=0;
}
if ($x2>$iWSource) {
$x2=$iWSource;
}
if ($y2>$iHSource) {
$y2=$iHSource;
}
$iW=$x2-$x1;
// Допускаем минимальный клип в 32px (исключая маленькие изображения)
if ($iW<32 && $x1+32<=$iWSource) {
$iW=32;
}
$iH=$iW;
if ($iH+$y1>$iHSource) {
$iH=$iHSource-$y1;
}
$oImage->crop($iW,$iH,$x1,$y1);
$oImage->output(null,$sFileTmp);
$oImage->cropFromSelected($aSize,$iCanvasWidth);
}
if ($sFileAvatar=$this->Image_Resize($sFileTmp,$sPath,'avatar_100x100',Config::Get('view.img_max_width'),Config::Get('view.img_max_height'),100,100,false,$aParams)) {
$aSize=Config::Get('module.user.avatar_size');
foreach ($aSize as $iSize) {
if ($iSize==0) {
$this->Image_Resize($sFileTmp,$sPath,'avatar',Config::Get('view.img_max_width'),Config::Get('view.img_max_height'),null,null,false,$aParams);
} else {
$this->Image_Resize($sFileTmp,$sPath,"avatar_{$iSize}x{$iSize}",Config::Get('view.img_max_width'),Config::Get('view.img_max_height'),$iSize,$iSize,false,$aParams);
}
}
@unlink($sFileTmp);
/**
* Если все нормально, возвращаем расширение загруженного аватара
*/
return $this->Image_GetWebPath($sFileAvatar);
if ($sError=$this->Image_GetLastError()) {
return $sError;
}
@unlink($sFileTmp);
/**
* В случае ошибки, возвращаем false
* Сохраняем во временный файл для дальнейшего ресайза
*/
return false;
}
/**
* Удаляет аватар пользователя
*
* @param ModuleUser_EntityUser $oUser Объект пользователя
*/
public function DeleteAvatar($oUser) {
/**
* Если аватар есть, удаляем его и его рейсайзы
*/
if($oUser->getProfileAvatar()) {
$aSize=array_merge(Config::Get('module.user.avatar_size'),array(100));
foreach ($aSize as $iSize) {
$this->Image_RemoveFile($this->Image_GetServerPath($oUser->getProfileAvatarPath($iSize)));
}
if (false===($sFileTmp=$oImage->saveTmp())) {
return $this->Image_GetLastError();
}
$sPath=$this->Image_GetIdDir($oUser->getId(),'users');
/**
* Удаляем старый аватар
*/
$this->DeleteProfileAvatar($oUser);
/**
* Имя файла для сохранения
*/
$sFileName='avatar-user-'.$oUser->getId();
/**
* Сохраняем оригинальный аватар
*/
if (false===($sFileResult=$oImage->saveSmart($sPath,$sFileName))) {
return $this->Image_GetLastError();
}
/**
* Генерируем варианты с необходимыми размерами
*/
$this->Media_GenerateImageBySizes($sFileTmp,$sPath,$sFileName,Config::Get('module.user.avatar_size'),$aParams);
/**
* Теперь можно удалить временный файл
*/
$this->Fs_RemoveFileLocal($sFileTmp);
$oUser->setProfileAvatar($sFileResult);
$this->User_Update($oUser);
return true;
}
/**
* Загрузка фото в профиль пользователя
@ -1216,7 +1166,7 @@ class ModuleUser extends Module {
/**
* Если было старое фото, то удаляем
*/
$this->DeleteFoto($oUser);
$this->DeleteProfilePhoto($oUser);
$oUser->setProfileFoto($sFileResult);
$this->User_Update($oUser);
return true;
@ -1226,12 +1176,23 @@ class ModuleUser extends Module {
*
* @param ModuleUser_EntityUser $oUser
*/
public function DeleteFoto($oUser) {
public function DeleteProfilePhoto($oUser) {
if ($oUser->getProfileFoto()) {
$this->Image_RemoveFile($oUser->getProfileFoto());
$oUser->setProfileFoto(null);
}
}
/**
* Удаляет аватар пользователя
*
* @param ModuleUser_EntityUser $oUser
*/
public function DeleteProfileAvatar($oUser) {
if ($oUser->getProfileAvatar()) {
$this->Media_RemoveImageBySizes($oUser->getProfileAvatar(),Config::Get('module.user.avatar_size'));
$oUser->setProfileAvatar(null);
}
}
/**
* Проверяет логин на корректность
*

View file

@ -368,7 +368,10 @@ class ModuleUser_EntityUser extends Entity {
*/
public function getProfileAvatarPath($iSize=100) {
if ($sPath=$this->getProfileAvatar()) {
return str_replace('_100x100',(($iSize==0)?"":"_{$iSize}x{$iSize}"),$sPath."?".date('His',strtotime($this->getProfileDate())));
if (is_numeric($iSize)) {
$iSize.='crop';
}
return $this->Media_GetImageWebPath($sPath,$iSize);
} else {
return Config::Get('path.skin.assets.web').'/images/avatars/avatar_'.($this->getProfileSex()=='woman' ? 'female' : 'male').'_'.$iSize.'x'.$iSize.'.png';
}

View file

@ -124,7 +124,7 @@ $config['module']['user']['friend_on_profile'] = 15; // Ограни
$config['module']['user']['friend_notice']['delete'] = false; // Отправить talk-сообщение в случае удаления пользователя из друзей
$config['module']['user']['friend_notice']['accept'] = false; // Отправить talk-сообщение в случае одобрения заявки на добавление в друзья
$config['module']['user']['friend_notice']['reject'] = false; // Отправить talk-сообщение в случае отклонения заявки на добавление в друзья
$config['module']['user']['avatar_size'] = array(100,64,48,24,0); // Список размеров аватаров у пользователя. 0 - исходный размер
$config['module']['user']['avatar_size'] = array(100,64,48,24); // Список размеров аватаров у пользователя
$config['module']['user']['login']['min_size'] = 3; // Минимальное количество символов в логине
$config['module']['user']['login']['max_size'] = 30; // Максимальное количество символов в логине
$config['module']['user']['login']['charset'] = '0-9a-z_\-'; // Допустимые в имени пользователя символы

View file

@ -115,6 +115,11 @@ ls.user = (function ($) {
self.removeProfilePhoto($(this).data('userId'));
return false;
});
// Изменения аватара
$('.js-ajax-user-avatar-change').on('click', function () {
self.changeProfileAvatar($(this).data('userId'));
return false;
});
};
/**
@ -265,6 +270,7 @@ ls.user = (function ($) {
$('.js-ajax-user-photo-image').attr('src',data.sFile);
$('.js-ajax-user-photo-upload-choose').html(data.sChooseText);
$('.js-ajax-user-photo-upload-remove').show();
$('.js-ajax-user-avatar-change').show();
}
form.remove();
}.bind(this));
@ -280,6 +286,50 @@ ls.user = (function ($) {
$('.js-ajax-user-photo-image').attr('src',result.sFile);
$('.js-ajax-user-photo-upload-choose').html(result.sChooseText);
$('.js-ajax-user-photo-upload-remove').hide();
$('.js-ajax-user-avatar-change').hide();
}
});
return false;
};
this.changeProfileAvatar = function(idUser) {
var self = this;
ls.modal.load(aRouter.ajax+'modal/image-crop/', {image_src: $('.js-ajax-user-photo-image').attr('src') }, {
aftershow: function() {
this.jcropImage && this.jcropImage.destroy();
$('.js-image-crop').css({
'width': 'auto',
'height': 'auto'
});
$('.js-image-crop').Jcrop({ minSize: [32, 32], aspectRatio: 1 }, function () {
self.jcropImage = this;
var w=$('.js-image-crop').innerWidth();
var h=$('.js-image-crop').innerHeight();
w=w/2-75;
h=h/2-75;
w=w>0 ? Math.round(w) : 0;
h=h>0 ? Math.round(h) : 0;
this.setSelect([w, h, w+150, h+150]);
});
$('.js-ajax-image-crop-submit').on('click',function() {
var params={
user_id: idUser,
size: self.jcropImage.tellSelect(),
canvas_width: $('.js-image-crop').innerWidth()
}
ls.ajax.load(aRouter.settings+'ajax-change-avatar/', params, function(result) {
if (result.bStateError) {
ls.msg.error(null,result.sMsg);
} else {
$('#modal-image-crop').modal('hide');
}
});
});
}
});
return false;

View file

@ -42,6 +42,7 @@
<input type="file" name="photo" id="photo" class="js-ajax-user-photo-upload" data-user-id="{$oUserProfile->getId()}">
</label>
&nbsp;&nbsp;&nbsp;
<a href="#" data-user-id="{$oUserProfile->getId()}" class="js-ajax-user-avatar-change link-dotted" style="{if !$oUserProfile->getProfileFoto()}display:none;{/if}">{$aLang.settings_profile_avatar_change}</a>
<a href="#" data-user-id="{$oUserProfile->getId()}" class="js-ajax-user-photo-upload-remove link-dotted" style="{if !$oUserProfile->getProfileFoto()}display:none;{/if}">{$aLang.settings_profile_foto_delete}</a>
</p>
{/if}

View file

@ -8,5 +8,4 @@
{block name='layout_content_begin' append}
{include file='navs/nav.settings.tpl'}
{include file='modals/modal.image_crop.tpl'}
{/block}

View file

@ -11,12 +11,9 @@
{block name='modal_title'}{$aLang.uploadimg}{/block}
{block name='modal_content'}
<img src="" alt="" class="js-image-crop">
<img src="{$sImageSrc|escape:'html'}" alt="" class="js-image-crop">
{/block}
{block name='modal_footer_begin'}
<button type="submit" class="button button-primary js-ajax-image-upload-crop-submit">{$aLang.settings_profile_avatar_resize_apply}</button>
<button type="submit" class="button js-ajax-image-upload-crop-cancel">{$aLang.settings_profile_avatar_resize_cancel}</button>
{/block}
{block name='modal_footer_cancel'}{/block}
<button type="submit" class="button button-primary js-ajax-image-crop-submit">{$aLang.common.save}</button>
{/block}

@ -1 +1 @@
Subproject commit 72e2e230186f03ed83fce20fd13e08e4291497f3
Subproject commit eddd2af40c77a6a407817ce190ce2ceaedd97658