1
0
Fork 0
mirror of https://github.com/Oreolek/ifhub.club.git synced 2024-06-26 03:30:48 +03:00

Доработка загрузки фото и аватарки

This commit is contained in:
Denis Shakhov 2014-11-14 20:35:53 +07:00
parent 265db4e2e4
commit ea26c7f230
11 changed files with 180 additions and 61 deletions

View file

@ -170,10 +170,14 @@ class ActionAjax extends Action
{
$oViewer = $this->Viewer_GetLocalViewer();
$oViewer->Assign('usePreview', getRequest('use_preview'), true);
$oViewer->Assign('usePreview', (bool) getRequest('use_preview'), true);
$oViewer->Assign('image', getRequestStr('image_src'), true);
$oViewer->Assign('width', getRequest('width'), true);
$oViewer->Assign('height', getRequest('height'), true);
$oViewer->Assign('originalWidth', (int) getRequest('original_width'), true);
$oViewer->Assign('originalHeight', (int) getRequest('original_height'), true);
$oViewer->Assign('width', (int) getRequest('width'), true);
$oViewer->Assign('height', (int) getRequest('height'), true);
$oViewer->Assign('title', getRequestStr('title'), true);
$oViewer->Assign('desc', getRequestStr('desc'), true);
$this->Viewer_AssignAjax('sText', $oViewer->Fetch("components/crop/crop.tpl"));
}

View file

@ -85,6 +85,8 @@ class ActionSettings extends Action
$this->AddEventPreg('/^ajax-crop-cancel-photo$/i', '/^$/i', 'EventAjaxCropCancelPhoto');
$this->AddEventPreg('/^ajax-remove-photo$/i', '/^$/i', 'EventAjaxRemovePhoto');
$this->AddEventPreg('/^ajax-change-avatar$/i', '/^$/i', 'EventAjaxChangeAvatar');
$this->AddEventPreg('/^ajax-modal-crop-photo$/i', '/^$/i', 'EventAjaxModalCropPhoto');
$this->AddEventPreg('/^ajax-modal-crop-avatar$/i', '/^$/i', 'EventAjaxModalCropAvatar');
}
@ -134,13 +136,16 @@ class ActionSettings extends Action
$sDir = Config::Get('path.uploads.images') . "/tmp/userphoto/{$oUser->getId()}";
if ($sFileOriginal = $oImage->resize(1000, null)->saveSmart($sDir, 'original')) {
if ($sFilePreview = $oImage->resize(350, null)->saveSmart($sDir, 'preview')) {
list($iWidth, $iHeight) = @getimagesize($this->Fs_GetPathServer($sFileOriginal));
list($iOriginalWidth, $iOriginalHeight) = @getimagesize($this->Fs_GetPathServer($sFileOriginal));
list($iWidth, $iHeight) = @getimagesize($this->Fs_GetPathServer($sFilePreview));
/**
* Сохраняем в сессии временный файл с изображением
*/
$this->Session_Set('sPhotoFileTmp', $sFileOriginal);
$this->Session_Set('sPhotoFilePreviewTmp', $sFilePreview);
$this->Viewer_AssignAjax('path', $this->Fs_GetPathWeb($sFilePreview));
$this->Viewer_AssignAjax('original_width', $iOriginalWidth);
$this->Viewer_AssignAjax('original_height', $iOriginalHeight);
$this->Viewer_AssignAjax('width', $iWidth);
$this->Viewer_AssignAjax('height', $iHeight);
$this->Fs_RemoveFileLocal($sFileTmp);
@ -187,13 +192,49 @@ class ActionSettings extends Action
*/
$this->User_CreateProfileAvatar($oUser->getProfileFoto(), $oUser);
$this->Viewer_AssignAjax('sChooseText', $this->Lang_Get('user.blocks.photo.change_photo'));
$this->Viewer_AssignAjax('sFile', $oUser->getProfileFotoPath());
$this->Viewer_AssignAjax('upload_text', $this->Lang_Get('user.photo.actions.change_photo'));
$this->Viewer_AssignAjax('photo', $oUser->getProfileFotoPath());
} else {
$this->Message_AddError(is_string($res) ? $res : $this->Lang_Get('error'));
}
}
/**
* Показывает модальное окно с кропом фото
*/
protected function EventAjaxModalCropPhoto()
{
$this->Viewer_SetResponseAjax('json');
$oViewer = $this->Viewer_GetLocalViewer();
$oViewer->Assign('image', getRequestStr('image_src'), true);
$oViewer->Assign('originalWidth', (int) getRequest('original_width'), true);
$oViewer->Assign('originalHeight', (int) getRequest('original_height'), true);
$oViewer->Assign('width', (int) getRequest('width'), true);
$oViewer->Assign('height', (int) getRequest('height'), true);
$this->Viewer_AssignAjax('sText', $oViewer->Fetch("components/user/modals/modal.crop-photo.tpl"));
}
/**
* Показывает модальное окно с кропом аватарки
*/
protected function EventAjaxModalCropAvatar()
{
$this->Viewer_SetResponseAjax('json');
$oViewer = $this->Viewer_GetLocalViewer();
$oViewer->Assign('image', getRequestStr('image_src'), true);
$oViewer->Assign('originalWidth', (int) getRequest('original_width'), true);
$oViewer->Assign('originalHeight', (int) getRequest('original_height'), true);
$oViewer->Assign('width', (int) getRequest('width'), true);
$oViewer->Assign('height', (int) getRequest('height'), true);
$this->Viewer_AssignAjax('sText', $oViewer->Fetch("components/user/modals/modal.crop-avatar.tpl"));
}
/**
* Удаляет временные файлы кропа фото
*/
@ -237,8 +278,10 @@ class ActionSettings extends Action
$this->User_DeleteProfilePhoto($oUser);
$this->User_DeleteProfileAvatar($oUser);
$this->User_Update($oUser);
$this->Viewer_AssignAjax('sChooseText', $this->Lang_Get('user.blocks.photo.upload_photo'));
$this->Viewer_AssignAjax('sFile', $oUser->getProfileFotoPath());
$this->Viewer_AssignAjax('upload_text', $this->Lang_Get('user.photo.actions.upload_photo'));
$this->Viewer_AssignAjax('photo', $oUser->getProfileFotoPath());
$this->Viewer_AssignAjax('avatars', $oUser->GetProfileAvatarsPath());
}
/**
@ -259,13 +302,7 @@ class ActionSettings extends Action
getRequestStr('canvas_width')))
) {
// Формируем массив с путями до аватаров
$aAvatars = array();
foreach (Config::Get('module.blog.avatar_size') as $sSize) {
$aAvatars[ $sSize ] = $oUser->getProfileAvatarPath( $sSize );
}
$this->Viewer_AssignAjax('sFile', $aAvatars);
$this->Viewer_AssignAjax('avatars', $oUser->GetProfileAvatarsPath());
} else {
$this->Message_AddError(is_string($res) ? $res : $this->Lang_Get('error'));
}

View file

@ -457,6 +457,23 @@ class ModuleUser_EntityUser extends Entity
}
}
/**
* Формирует массив с путями до аватаров
*
* @param object $oUser Пользователь
* @return array Массив с путями до аватаров
*/
public function GetProfileAvatarsPath()
{
$aAvatars = array();
foreach (Config::Get('module.user.avatar_size') as $sSize) {
$aAvatars[ $sSize ] = $this->getProfileAvatarPath( $sSize );
}
return $aAvatars;
}
/**
* Возвращает полный веб путь до фото
*

View file

@ -1394,6 +1394,23 @@ return array(
)
),
),
'photo' => array(
'crop_avatar' => array(
'title' => 'Выбор аватары',
'desc' => 'Выберите квадратную область для аватарки.',
),
'crop_photo' => array(
'title' => 'Ваша фотография',
'desc' => 'Необходимо выбрать область для фотографии, которая будет отбражаться в вашем профиле.',
'submit' => 'Сохранить и продолжить',
),
'actions' => array(
'change_photo' => 'Изменить фотографию',
'upload_photo' => 'Загрузить фотографию',
'change_avatar' => 'Изменить аватар',
'remove' => '___common.remove___'
)
),
// Блоки
'blocks' => array(
'cities' => array(
@ -1401,13 +1418,7 @@ return array(
),
'countries' => array(
'title' => 'Страны'
),
'photo' => array(
'change_photo' => 'Изменить фотографию',
'upload_photo' => 'Загрузить фотографию',
'change_avatar' => 'Изменить аватар',
'remove' => '___common.remove___',
),
)
),
// Сообщения
'notices' => array(
@ -1755,7 +1766,7 @@ return array(
/**
* Обрезка изображения
*/
'modal_image_crop' => array(
'crop' => array(
'title' => 'Обрезка изображения'
),
/**

View file

@ -287,13 +287,13 @@ jQuery(document).ready(function($){
urls: {
upload: aRouter.settings + 'ajax-upload-photo',
remove: aRouter.settings + 'ajax-remove-photo',
crop_photo: aRouter.ajax + 'modal/image-crop/',
crop_avatar: aRouter.ajax + 'modal/image-crop/',
crop_photo: aRouter.settings + 'ajax-modal-crop-photo',
crop_avatar: aRouter.settings + 'ajax-modal-crop-avatar',
save_photo: aRouter.settings + 'ajax-crop-photo',
save_avatar: aRouter.settings + 'ajax-change-avatar',
cancel_photo: aRouter.settings + 'ajax-crop-cancel-photo',
},
cropavatar: function ( event, _this, avatars ) {
changeavatar: function ( event, _this, avatars ) {
$( '.js-user-profile-avatar' ).attr( 'src', avatars[ '64crop' ] + '?' + Math.random() );
}
});

View file

@ -1,30 +1,43 @@
{**
* Ресайз загруженного изображения
* Обрезка загруженного изображения
*
* @param string $title
* @param string $desc
* @param string $image
* @param array $width
* @param array $height
* @param integer $width
* @param integer $height
* @param integer $originalWidth
* @param integer $originalHeight
*
* TODO: Возможность задавать размеры превью
*}
{extends 'components/modal/modal.tpl'}
{block 'modal_id'}modal-image-crop{/block}
{block 'modal_class'}modal--crop js-modal-default{/block}
{block 'modal_title'}{lang 'modal_image_crop.title'}{/block}
{block 'modal_options' append}
{$title = $smarty.local.title|escape|default:{lang 'crop.title'}}
{$desc = $smarty.local.desc|escape}
{$usePreview = $smarty.local.usePreview}
{/block}
{block 'modal_class'}modal--crop{/block}
{block 'modal_title'}{$title}{/block}
{block 'modal_content'}
{if $desc}
<p class="crop-desc">{$desc}</p>
{/if}
{$image = "{$smarty.local.image|escape}?v{rand( 0, 10e10 )}"}
<div class="crop js-crop" data-crop-width="{$smarty.local.width}" data-crop-height="{$smarty.local.height}">
<div class="crop js-crop" data-crop-width="{$smarty.local.originalWidth}" data-crop-height="{$smarty.local.originalHeight}">
{* Изображение *}
<div class="crop-image-holder js-crop-image-holder">
<img src="{$image}" style="width: 370px;" class="crop-image js-crop-image">
<img src="{$image}" width="{$smarty.local.width}" height="{$smarty.local.height}" class="crop-image js-crop-image">
</div>
{* Превью *}
{if $smarty.local.usePreview}
{if $usePreview}
<div class="crop-previews js-crop-previews">
{foreach [ 100, 64, 48 ] as $size}
<div style="width: {$size}px; height: {$size}px;" class="crop-preview js-crop-preview">

View file

@ -22,5 +22,11 @@
* Модальное окно
*/
.modal--crop {
max-width: 600px;
max-width: 550px;
}
.modal--crop .modal-footer {
text-align: center;
}
.modal--crop .crop-desc {
margin-bottom: 20px;
}

View file

@ -40,19 +40,19 @@
<label class="form-input-file">
<span class="js-user-photo-actions-upload-label">
{if $oUserProfile->getProfileFoto()}
{lang 'user.blocks.photo.change_photo'}
{lang 'user.photo.actions.change_photo'}
{else}
{lang 'user.blocks.photo.upload_photo'}
{lang 'user.photo.actions.upload_photo'}
{/if}
</span>
<input type="file" name="photo" class="js-user-photo-actions-upload-input">
</label>
</li>
<li class="js-user-photo-actions-crop-avatar" style="{if !$oUserProfile->getProfileFoto()}display:none;{/if}">
{lang 'user.blocks.photo.change_avatar'}
{lang 'user.photo.actions.change_avatar'}
</li>
<li class="js-user-photo-actions-remove" style="{if !$oUserProfile->getProfileFoto()}display:none;{/if}">
{lang 'user.blocks.photo.remove'}
{lang 'user.photo.actions.remove'}
</li>
</ul>
{/if}

View file

@ -46,8 +46,8 @@
// Параметры передаваемые в аякс запросах
params: {}
// Успешный кроп аватара
// cropavatar: function() {}
// Изменение аватара
// changeavatar: function() {}
},
/**
@ -76,17 +76,7 @@
_this.upload( $( this ) );
});
this.elements.actions.crop_avatar.on( 'click' + this.eventNamespace, function() {
var photo = $('.js-user-photo-image');
_this.cropAvatar({
path: photo.attr( 'src' ),
// TODO: IE8 naturalWidth naturalHeight
width: photo[0].naturalWidth,
height: photo[0].naturalHeight
});
});
this.elements.actions.crop_avatar.on( 'click' + this.eventNamespace, this.cropAvatar.bind( this ) );
this.elements.actions.remove.on( 'click' + this.eventNamespace, this.remove.bind( this ) );
},
@ -99,10 +89,12 @@
ls.msg.error( null, response.sMsg );
} else {
this.element.addClass( this.option( 'classes.nophoto' ) );
this.elements.image.attr( 'src', response.sFile );
this.elements.actions.upload_label.text( response.sChooseText );
this.elements.image.attr( 'src', response.photo );
this.elements.actions.upload_label.text( response.upload_text );
this.elements.actions.remove.hide();
this.elements.actions.crop_avatar.hide();
this._trigger( 'changeavatar', null, [ this, response.avatars ] );
}
}.bind( this ));
},
@ -140,10 +132,13 @@
save_url : this.option( 'urls.save_photo' ),
save_callback : function( response, modal, image ) {
this.element.removeClass( this.option( 'classes.nophoto' ) );
this.elements.image.attr( 'src', response.sFile );
this.elements.actions.upload_label.text( response.sChooseText );
this.elements.image.attr( 'src', response.photo );
this.elements.actions.upload_label.text( response.upload_text );
this.elements.actions.remove.show();
this.elements.actions.crop_avatar.show();
// TODO: Временный хак (модальное не показывается сразу после закрытия предыдущего окна)
setTimeout( this.cropAvatar.bind( this ), 300);
},
modal_close_callback : function( event, modal ) {
ls.ajax.load( this.option( 'urls.cancel_photo' ), this.option( 'params' ) );
@ -153,17 +148,25 @@
/**
* Показывает модальное кропа аватара
*
* TODO: Возвращать в ответе пути до аватаров всех размеров
*/
cropAvatar: function( image ) {
cropAvatar: function() {
var photo = $('.js-user-photo-image');
var image = {
path: photo.attr( 'src' ),
// TODO: IE8 naturalWidth naturalHeight
original_width: photo[0].naturalWidth,
original_height: photo[0].naturalHeight,
width: photo[0].naturalWidth,
height: photo[0].naturalHeight
};
this.showModal( image, true, {
crop_params : {
minSize: [ 100, 100 ],
aspectRatio: 1
},
save_callback : function( response, modal, image ) {
this._trigger( 'cropavatar', null, [ this, response.sFile ] );
this._trigger( 'changeavatar', null, [ this, response.avatars ] );
},
save_params : this.option( 'params' ),
crop_url : this.option( 'urls.crop_avatar' ),
@ -180,6 +183,8 @@
var _this = this;
ls.modal.load( params.crop_url, {
original_width: image.original_width,
original_height: image.original_height,
width: image.width,
height: image.height,
image_src: image.path,

View file

@ -0,0 +1,11 @@
{**
* Кроп фотографии
*}
{extends 'components/crop/crop.tpl'}
{block 'modal_options' append}
{$title = {lang 'user.photo.crop_avatar.title'}}
{$desc = {lang 'user.photo.crop_avatar.desc'}}
{$usePreview = true}
{/block}

View file

@ -0,0 +1,15 @@
{**
* Кроп фотографии
*}
{extends 'components/crop/crop.tpl'}
{block 'modal_options' append}
{$title = {lang 'user.photo.crop_photo.title'}}
{$desc = {lang 'user.photo.crop_photo.desc'}}
{$usePreview = false}
{/block}
{block 'modal_footer_begin'}
{include 'components/button/button.tpl' text={lang 'user.photo.crop_photo.submit'} classes='js-crop-submit' mods='primary'}
{/block}