mirror of
https://github.com/Oreolek/ifhub.club.git
synced 2024-06-26 03:30:48 +03:00
Доработка загрузки фото и аватарки
This commit is contained in:
parent
265db4e2e4
commit
ea26c7f230
|
@ -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"));
|
||||
}
|
||||
|
|
|
@ -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'));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает полный веб путь до фото
|
||||
*
|
||||
|
|
|
@ -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' => 'Обрезка изображения'
|
||||
),
|
||||
/**
|
||||
|
|
|
@ -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() );
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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}
|
|
@ -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}
|
Loading…
Reference in a new issue