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:
Mzhelskiy Maxim 2013-12-25 19:19:33 +07:00
parent 593e2871fb
commit 51b1e75786
14 changed files with 1461 additions and 94 deletions

View file

@ -51,7 +51,7 @@ class ActionAjax extends Action {
$this->AddEventPreg('/^vote$/i','/^blog$/','EventVoteBlog');
$this->AddEventPreg('/^vote$/i','/^user$/','EventVoteUser');
$this->AddEventPreg('/^vote$/i','/^question$/','EventVoteQuestion');
$this->AddEventPreg('/^vote/i','/^get/','/^info/','EventVoteGetInfo');
$this->AddEventPreg('/^vote$/i','/^get$/','/^info$/','EventVoteGetInfo');
$this->AddEventPreg('/^favourite$/i','/^save-tags/','EventFavouriteSaveTags');
$this->AddEventPreg('/^favourite$/i','/^topic$/','EventFavouriteTopic');
@ -67,7 +67,7 @@ class ActionAjax extends Action {
$this->AddEventPreg('/^blogs$/i','/^get-by-category$/','EventBlogsGetByCategory');
$this->AddEventPreg('/^preview$/i','/^text$/','EventPreviewText');
$this->AddEventPreg('/^preview$/i','/^topic/','EventPreviewTopic');
$this->AddEventPreg('/^preview$/i','/^topic$/','EventPreviewTopic');
$this->AddEventPreg('/^upload$/i','/^image$/','EventUploadImage');
@ -76,10 +76,17 @@ class ActionAjax extends Action {
$this->AddEventPreg('/^comment$/i','/^delete$/','EventCommentDelete');
$this->AddEventPreg('/^geo/i','/^get/','/^regions$/','EventGeoGetRegions');
$this->AddEventPreg('/^geo/i','/^get/','/^cities/','EventGeoGetCities');
$this->AddEventPreg('/^geo$/i','/^get/','/^regions$/','EventGeoGetRegions');
$this->AddEventPreg('/^geo$/i','/^get/','/^cities$/','EventGeoGetCities');
$this->AddEventPreg('/^infobox/i','/^info/','/^blog/','EventInfoboxInfoBlog');
$this->AddEventPreg('/^infobox$/i','/^info$/','/^blog$/','EventInfoboxInfoBlog');
$this->AddEventPreg('/^media$/i','/^upload$/','/^$/','EventMediaUpload');
$this->AddEventPreg('/^media$/i','/^generate-target-tmp$/','/^$/','EventMediaGenerateTargetTmp');
$this->AddEventPreg('/^media$/i','/^submit-insert$/','/^$/','EventMediaSubmitInsert');
$this->AddEventPreg('/^media$/i','/^submit-create-photoset$/','/^$/','EventMediaSubmitCreatePhotoset');
$this->AddEventPreg('/^media$/i','/^load-gallery$/','/^$/','EventMediaLoadGallery');
$this->AddEventPreg('/^media$/i','/^remove-file$/','/^$/','EventMediaRemoveFile');
}
@ -88,6 +95,179 @@ class ActionAjax extends Action {
**********************************************************************************
*/
protected function EventMediaRemoveFile() {
/**
* Пользователь авторизован?
*/
if (!$this->oUserCurrent) {
$this->Message_AddErrorSingle($this->Lang_Get('need_authorization'),$this->Lang_Get('error'));
return;
}
$sId=getRequestStr('id');
if ($oMedia=$this->Media_GetMediaByIdAndUserId($sId,$this->oUserCurrent->getId())) {
$this->Media_DeleteFile($oMedia);
} else {
$this->Message_AddErrorSingle($this->Lang_Get('system_error'));
}
}
protected function EventMediaLoadGallery() {
/**
* Пользователь авторизован?
*/
if (!$this->oUserCurrent) {
$this->Message_AddErrorSingle($this->Lang_Get('need_authorization'),$this->Lang_Get('error'));
return;
}
$sType=getRequestStr('target_type');
$sId=getRequestStr('target_id');
$sTmp=getRequestStr('target_tmp');
$aMediaItems=array();
if ($sId) {
$aMediaItems=$this->Media_GetMediaByTarget($sType,$sId,$this->oUserCurrent->getId());
} elseif($sTmp) {
$aMediaItems=$this->Media_GetMediaByTargetTmp($sTmp,$this->oUserCurrent->getId());
}
$oViewer=$this->Viewer_GetLocalViewer();
$sTemplate='';
foreach($aMediaItems as $oMediaItem) {
$oViewer->Assign('oMediaItem',$oMediaItem);
$sTemplate.=$oViewer->Fetch('modals/modal.upload_image.gallery.item.tpl');
}
$this->Viewer_AssignAjax('sTemplate',$sTemplate);
}
protected function EventMediaSubmitInsert() {
$aIds=array(0);
foreach((array)getRequest('ids') as $iId) {
$aIds[]=(int)$iId;
}
$iUserId=$this->oUserCurrent ? $this->oUserCurrent->getId() : null;
$aMediaItems=$this->Media_GetMediaItemsByFilter(array(
'#where'=>array('id in (?a) AND ( user_id is null OR user_id = ?d )'=>array($aIds,$iUserId))
)
);
if (!$aMediaItems) {
$this->Message_AddError('Необходимо выбрать элементы');
return false;
}
$aParams=array(
'align'=>getRequestStr('align'),
'size'=>getRequestStr('size')
);
$sTextResult='';
foreach($aMediaItems as $oMedia) {
$sTextResult.=$this->Media_BuildCodeForEditor($oMedia,$aParams)."\r\n";
}
$this->Viewer_AssignAjax('sTextResult',$sTextResult);
}
protected function EventMediaSubmitCreatePhotoset() {
$aIds=array(0);
foreach((array)getRequest('ids') as $iId) {
$aIds[]=(int)$iId;
}
$iUserId=$this->oUserCurrent ? $this->oUserCurrent->getId() : null;
$aMediaItems=$this->Media_GetMediaItemsByFilter(array(
'#where'=>array('id in (?a) AND ( user_id is null OR user_id = ?d )'=>array($aIds,$iUserId))
)
);
if (!$aMediaItems) {
$this->Message_AddError('Необходимо выбрать элементы');
return false;
}
$aParams=array(
'size'=>'100crop',
);
$sTextResult='<div class="fotorama" data-nav="thumbs">'."\r\n";
foreach($aMediaItems as $oMedia) {
$sTextResult.="\t".$this->Media_BuildCodeForEditor($oMedia,$aParams)."\r\n";
}
$sTextResult.="</div>\r\n";
$this->Viewer_AssignAjax('sTextResult',$sTextResult);
}
protected function EventMediaGenerateTargetTmp() {
$sType=getRequestStr('type');
if ($this->Media_IsAllowTargetType($sType)) {
$sTmp=func_generator();
setcookie('media_target_tmp_'.$sType,$sTmp, time()+24*3600,Config::Get('sys.cookie.path'),Config::Get('sys.cookie.host'));
$this->Viewer_AssignAjax('sTmpKey',$sTmp);
}
}
protected function EventMediaUpload() {
if (getRequest('is_iframe')) {
$this->Viewer_SetResponseAjax('jsonIframe', false);
} else {
$this->Viewer_SetResponseAjax('json');
}
/**
* Пользователь авторизован?
*/
if (!$this->oUserCurrent) {
$this->Message_AddErrorSingle($this->Lang_Get('need_authorization'),$this->Lang_Get('error'));
return;
}
/**
* Файл был загружен?
*/
if (!isset($_FILES['filedata']['tmp_name'])) {
$this->Message_AddError($this->Lang_Get('system_error'), $this->Lang_Get('error'));
return false;
}
/**
* Проверяем корректность target'а
*/
$sTargetType=getRequestStr('target_type');
$sTargetId=getRequestStr('target_id');
$sTargetTmp=empty($_COOKIE['media_target_tmp_'.$sTargetType]) ? getRequestStr('target_tmp') : $_COOKIE['media_target_tmp_'.$sTargetType];
if ($sTargetId) {
$sTargetTmp=null;
if (!$this->Media_CheckTarget($sTargetType,$sTargetId)) {
$this->Message_AddError($this->Lang_Get('system_error'), $this->Lang_Get('error'));
return false;
}
} else {
$sTargetId=null;
if (!$sTargetTmp or !$this->Media_IsAllowTargetType($sTargetType)) {
$this->Message_AddError($this->Lang_Get('system_error'), $this->Lang_Get('error'));
return false;
}
}
/**
* TODO: необходима проверка на максимальное общее количество файлов, на максимальный размер файла
* Эти настройки можно хранить в конфиге: module.media.type.topic.max_file_count=30 и т.п.
*/
/**
* Выполняем загрузку файла
*/
if ($mResult=$this->Media_Upload($_FILES['filedata'],$sTargetType,$sTargetId,$sTargetTmp) and is_object($mResult)) {
$oViewer=$this->Viewer_GetLocalViewer();
$oViewer->Assign('oMediaItem',$mResult);
$sTemplateFile=$oViewer->Fetch('modals/modal.upload_image.gallery.item.tpl');
$this->Viewer_AssignAjax('sTemplateFile',$sTemplateFile);
} else {
$this->Message_AddError(is_string($mResult) ? $mResult : $this->Lang_Get('system_error'), $this->Lang_Get('error'));
}
}
/**
* Вывод информации о блоге
*/

View file

@ -348,6 +348,18 @@ class ActionTopic extends Action {
* Обновляем количество топиков в блоге
*/
$this->Blog_RecalculateCountTopicByBlogId($oTopic->getBlogId());
/**
* Фиксируем ID у media файлов топика
*/
if (isset($_COOKIE['media_target_tmp_topic']) and is_string($_COOKIE['media_target_tmp_topic'])) {
$aTargetItems=$this->Media_GetTargetItemsByTargetTmpAndTargetType($_COOKIE['media_target_tmp_topic'],'topic');
foreach($aTargetItems as $oTarget) {
$oTarget->setTargetTmp(null);
$oTarget->setTargetId($oTopic->getId());
$oTarget->Update();
}
}
setcookie('media_target_tmp_topic',null);
/**
* Добавляем автора топика в подписчики на новые комментарии к этому топику
*/

View file

@ -0,0 +1,397 @@
<?php
/**
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Модуль управления медиа-данными (изображения, видео и т.п.)
*/
class ModuleMedia extends ModuleORM {
/**
* Список типов медиа
* Свои кастомные типы необходимо нумеровать с 1000
*/
const TYPE_IMAGE=1;
const TYPE_VIDEO=2;
/**
* Объект текущего пользователя
*
* @var ModuleUser_EntityUser|null
*/
protected $oUserCurrent;
protected $oMapper=null;
protected $aTargetTypes=array(
'topic'=>array(),
);
/**
* Список доступных типов медиа
*
* @var array
*/
protected $aMediaTypes=array(
self::TYPE_IMAGE,self::TYPE_VIDEO
);
/**
* Инициализация
*
*/
public function Init() {
parent::Init();
$this->oMapper=Engine::GetMapper(__CLASS__);
$this->oUserCurrent=$this->User_GetUserCurrent();
}
/**
* Возвращает список типов объектов
*
* @return array
*/
public function GetTargetTypes() {
return $this->aTargetTypes;
}
/**
* Добавляет в разрешенные новый тип
*
* @param string $sTargetType Тип
* @param array $aParams Параметры
* @return bool
*/
public function AddTargetType($sTargetType,$aParams=array()) {
if (!array_key_exists($sTargetType,$this->aTargetTypes)) {
$this->aTargetTypes[$sTargetType]=$aParams;
return true;
}
return false;
}
/**
* Проверяет разрешен ли данный тип
*
* @param string $sTargetType Тип
* @return bool
*/
public function IsAllowTargetType($sTargetType) {
return in_array($sTargetType,array_keys($this->aTargetTypes));
}
/**
* Возвращает парметры нужного типа
*
* @param string $sTargetType
*
* @return mixed
*/
public function GetTargetTypeParams($sTargetType) {
if ($this->IsAllowTargetType($sTargetType)) {
return $this->aTargetTypes[$sTargetType];
}
}
/**
* Проверяет разрешен ли тип медиа
*
* @param string $sType
*
* @return bool
*/
public function IsAllowMediaType($sType) {
return in_array($sType,$this->aMediaTypes);
}
/**
* Проверка объекта target - владелец медиа
*
* @param string $sTargetType Тип
* @param int $iTargetId ID владельца
* @return bool
*/
public function CheckTarget($sTargetType,$iTargetId) {
if (!$this->IsAllowTargetType($sTargetType)) {
return false;
}
$sMethod = 'CheckTarget'.func_camelize($sTargetType);
if (method_exists($this,$sMethod)) {
return $this->$sMethod($iTargetId);
}
return false;
}
public function Upload($aFile,$sTargetType,$sTargetId,$sTargetTmp=null) {
if (is_string($aFile)) {
return $this->UploadUrl($aFile,$sTargetType,$sTargetId,$sTargetTmp);
} else {
return $this->UploadLocal($aFile,$sTargetType,$sTargetId,$sTargetTmp);
}
}
public function UploadLocal($aFile,$sTargetType,$sTargetId,$sTargetTmp=null) {
if(!is_array($aFile) || !isset($aFile['tmp_name']) || !isset($aFile['name'])) {
return false;
}
$aPathInfo=pathinfo($aFile['name']);
$sExtension=isset($aPathInfo['extension']) ? $aPathInfo['extension'] : 'unknown';
$sFileName = $aPathInfo['filename'].'.'.$sExtension;
/**
* Копируем загруженный файл
*/
$sDirTmp=Config::Get('path.tmp.server').'/media/';
if (!is_dir($sDirTmp)) {
@mkdir($sDirTmp,0777,true);
}
$sFileTmp=$sDirTmp.$sFileName;
if (!move_uploaded_file($aFile['tmp_name'],$sFileTmp)) {
return 'Не удалось загрузить файл';
}
/**
* TODO: проверить на размер файла в байтах
*/
return $this->ProcessingFile($sFileTmp,$sTargetType,$sTargetId,$sTargetTmp);
}
public function UploadUrl($sFileUrl,$sTargetType,$sTargetId,$sTargetTmp=null) {
/**
* TODO: сделать загрузку по урлу
*/
return false;
}
public function ProcessingFile($sFileTmp,$sTargetType,$sTargetId,$sTargetTmp=null) {
/**
* Определяем тип файла по расширенияю и запускаем обработку
*/
$aPathInfo=pathinfo($sFileTmp);
$sExtension=strtolower($aPathInfo['extension']);
if (in_array($sExtension,array('jpg','jpeg','gif','png'))) {
return $this->ProcessingFileImage($sFileTmp,$sTargetType,$sTargetId,$sTargetTmp);
}
return 'Неверный тип файла';
}
public function ProcessingFileImage($sFileTmp,$sTargetType,$sTargetId,$sTargetTmp=null) {
$aPathInfo=pathinfo($sFileTmp);
$aParams=$this->Image_BuildParams('media.'.$sTargetType);
$oImage =$this->Image_CreateImageObject($sFileTmp);
/**
* Если объект изображения не создан, возвращаем ошибку
*/
if($sError=$oImage->get_last_error()) {
@unlink($sFileTmp);
return $sError;
}
/**
* Превышает максимальные размеры из конфига
*/
if (($oImage->get_image_params('width')>Config::Get('module.media.image_max_width')) or ($oImage->get_image_params('height')>Config::Get('module.media.image_max_height'))) {
@unlink($sFileTmp);
return 'Превышен максимальный размер изображения';
}
$iWidth=$oImage->get_image_params('width');
$iHeight=$oImage->get_image_params('height');
$sPath=$this->GetSaveDir($sTargetType,$sTargetId);
if (!is_dir(Config::Get('path.root.server').$sPath)) {
@mkdir(Config::Get('path.root.server').$sPath,0777,true);
}
/**
* Копируем файл в нужный каталог
*/
$sFileName=func_generator(20);
$sFilePath=Config::Get('path.root.server').$sPath.$sFileName.'.'.$oImage->get_image_params('format');
rename($sFileTmp,$sFilePath);
$aSizes=Config::Get("module.media.type.{$sTargetType}.image_sizes");
if (!$aSizes) {
$aSizes=Config::Get("module.media.image_sizes");
}
foreach ($aSizes as $aSize) {
/**
* Для каждого указанного в конфиге размера генерируем картинку
*/
$sNewFileName = $sFileName.'_'.$aSize['w'];
$oImage = $this->Image_CreateImageObject($sFilePath);
if ($aSize['crop']) {
$this->Image_CropProportion($oImage, $aSize['w'], $aSize['h'], true);
$sNewFileName .= 'crop';
}
$this->Image_Resize($sFilePath,$sPath,$sNewFileName,Config::Get('module.media.image_max_width'),Config::Get('module.media.image_max_height'),$aSize['w'],$aSize['h'],true,$aParams,$oImage);
}
/**
* Сохраняем медиа
*/
$oMedia=Engine::GetEntity('ModuleMedia_EntityMedia');
$oMedia->setUserId($this->oUserCurrent ? $this->oUserCurrent->getId() : null);
$oMedia->setType(self::TYPE_IMAGE);
$oMedia->setFilePath($this->Image_GetWebPath($sFilePath));
$oMedia->setFileName($aPathInfo['filename']);
$oMedia->setFileSize(filesize($sFilePath));
$oMedia->setWidth($iWidth);
$oMedia->setHeight($iHeight);
$oMedia->setDataOne('image_sizes',$aSizes);
if ($oMedia->Add()) {
/**
* Создаем связь с владельцем
*/
$oTarget=Engine::GetEntity('ModuleMedia_EntityTarget');
$oTarget->setMediaId($oMedia->getId());
$oTarget->setTargetType($sTargetType);
$oTarget->setTargetId($sTargetId ? $sTargetId : null);
$oTarget->setTargetTmp($sTargetTmp ? $sTargetTmp : null);
if ($oTarget->Add()) {
return $oMedia;
}
}
return false;
}
/**
* Возвращает каталог для сохранения контента медиа
*
* @param string $sTargetType
* @param string|null $sTargetId Желательно для одного типа при формировании каталога для загрузки выбрать что-то одно - использовать $sTargetId или нет
*
* @return string
*/
public function GetSaveDir($sTargetType,$sTargetId=null) {
return Config::Get('path.uploads.base')."/media/{$sTargetType}/".date('Y/m/d/H/');
}
/**
* Проверка владельца с типом "topic"
* Название метода формируется автоматически
*
* @param int $iTargetId ID владельца
* @return bool
*/
public function CheckTargetTopic($iTargetId) {
if ($oTopic=$this->Topic_GetTopicById($iTargetId)) {
/**
* Проверяем права на редактирование топика
*/
if ($this->ACL_IsAllowEditTopic($oTopic,$this->oUserCurrent)) {
return true;
}
}
return false;
}
public function BuildCodeForEditor($oMedia,$aParams) {
$sCode='';
if ($oMedia->getType()==self::TYPE_IMAGE) {
$aSizes=(array)$oMedia->getDataOne('image_sizes');
$sSizeParam=isset($aParams['size']) ? (string)$aParams['size'] : '';
$sSize='original';
$bNeedHref=false;
/**
* Проверяем корректность размера
*/
foreach($aSizes as $aSizeAllow) {
$sSizeKey=$aSizeAllow['w'].($aSizeAllow['crop'] ? 'crop' : '');
if ($sSizeKey==$sSizeParam) {
$sSize=$sSizeKey;
/**
* Необходимость лайтбокса
*/
if ($aSizeAllow['w']<$oMedia->getWidth()) {
$bNeedHref=true;
}
}
}
$sPath=$oMedia->getFileWebPath($sSize=='original' ? null : $sSize);
$sCode='<img src="'.$sPath.'" ';
if ($oMedia->getDataOne('title')) {
$sCode.=' title="'.htmlspecialchars($oMedia->getDataOne('title')).'" ';
$sCode.=' alt="'.htmlspecialchars($oMedia->getDataOne('title')).'" ';
}
if (isset($aParams['align']) and in_array($aParams['align'],array('left','right','center'))) {
if ($aParams['align'] == 'center') {
$sCode.=' class="image-center"';
} else {
$sCode.=' align="'.htmlspecialchars($aParams['align']).'" ';
}
}
$sCode.=' />';
if ($bNeedHref) {
$sCode='<a href="'.$oMedia->getFileWebPath().'">'.$sCode.'</a>';
}
}
return $sCode;
}
public function BuildHTML($sPath,$aParams) {
$sText='<img src="'.$sPath.'" ';
if (isset($aParams['title']) and $aParams['title']!='') {
$sText.=' title="'.htmlspecialchars($aParams['title']).'" ';
/**
* Если не определен ALT заполняем его тайтлом
*/
if(!isset($aParams['alt'])) $aParams['alt']=$aParams['title'];
}
if (isset($aParams['align']) and in_array($aParams['align'],array('left','right','center'))) {
if ($aParams['align'] == 'center') {
$sText.=' class="image-center"';
} else {
$sText.=' align="'.htmlspecialchars($aParams['align']).'" ';
}
}
$sAlt = isset($aParams['alt'])
? ' alt="'.htmlspecialchars($aParams['alt']).'"'
: ' alt=""';
$sText.=$sAlt.' />';
return $sText;
}
public function GetMediaByTarget($sTargetType,$iTargetId,$iUserId=null) {
return $this->oMapper->GetMediaByTarget($sTargetType,$iTargetId,$iUserId);
}
public function GetMediaByTargetTmp($sTargetTmp,$iUserId=null) {
return $this->oMapper->GetMediaByTargetTmp($sTargetTmp,$iUserId);
}
public function DeleteFile($oMedia) {
/**
* Сначала удаляем все файлы
*/
if ($oMedia->getType()==self::TYPE_IMAGE) {
$aSizes=$oMedia->getDataOne('image_sizes');
foreach($aSizes as $aSize) {
$sSize = $aSize['w'];
if ($aSize['crop']) {
$sSize.='crop';
}
$this->Image_RemoveFile($this->Image_GetServerPath($oMedia->getFileWebPath($sSize)));
}
}
/**
* Удаляем все связи
*/
$aTargets=$oMedia->getTargets();
foreach($aTargets as $oTarget) {
$oTarget->Delete();
}
return $oMedia->Delete();
}
}

View file

@ -0,0 +1,77 @@
<?php
/**
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
class ModuleMedia_EntityMedia extends EntityORM {
protected $aValidateRules=array(
);
protected $aRelations=array(
'targets' => array(self::RELATION_TYPE_HAS_MANY,'ModuleMedia_EntityTarget','media_id'),
);
protected function beforeSave() {
if ($this->_isNew()) {
$this->setDateAdd(date("Y-m-d H:i:s"));
}
return true;
}
public function getFileWebPath($sWidth = null) {
if ($this->getFilePath()) {
if ($sWidth) {
$aPathInfo=pathinfo($this->getFilePath());
return $aPathInfo['dirname'].'/'.$aPathInfo['filename'].'_'.$sWidth.'.'.$aPathInfo['extension'];
} else {
return $this->getFilePath();
}
} else {
return null;
}
}
public function getData() {
$aData=@unserialize($this->_getDataOne('data'));
if (!$aData) {
$aData=array();
}
return $aData;
}
public function setData($aRules) {
$this->_aData['data']=@serialize($aRules);
}
public function getDataOne($sKey) {
$aData=$this->getData();
if (isset($aData[$sKey])) {
return $aData[$sKey];
}
return null;
}
public function setDataOne($sKey,$mValue) {
$aData=$this->getData();
$aData[$sKey]=$mValue;
$this->setData($aData);
}
}

View file

@ -0,0 +1,38 @@
<?php
/**
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
class ModuleMedia_EntityTarget extends EntityORM {
protected $aValidateRules=array(
);
protected $aRelations=array(
);
protected function beforeSave() {
if ($this->_isNew()) {
$this->setDateAdd(date("Y-m-d H:i:s"));
}
return true;
}
}

View file

@ -0,0 +1,71 @@
<?php
/**
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Маппер для работы с БД
*
* @package modules.media
* @since 1.0
*/
class ModuleMedia_MapperMedia extends Mapper {
public function GetMediaByTarget($sTargetType,$iTargetId,$iUserId=null) {
$sql = "SELECT
m.*
FROM ".Config::Get('db.table.media_target')." AS t
JOIN ".Config::Get('db.table.media')." as m on ( m.id=t.media_id { and m.user_id = ?d } )
WHERE
t.target_id = ?d
AND
t.target_type = ?
ORDER BY
m.id desc
limit 0,500";
$aResult = array();
if ($aRows = $this->oDb->select($sql,$iUserId ? $iUserId : DBSIMPLE_SKIP,$iTargetId, $sTargetType)) {
foreach ($aRows as $aRow) {
$aResult[]=Engine::GetEntity('ModuleMedia_EntityMedia',$aRow);
}
}
return $aResult;
}
public function GetMediaByTargetTmp($sTargetTmp,$iUserId=null) {
$sql = "SELECT
m.*
FROM ".Config::Get('db.table.media_target')." AS t
JOIN ".Config::Get('db.table.media')." as m on ( m.id=t.media_id { and m.user_id = ?d } )
WHERE
t.target_tmp = ?
ORDER BY
m.id desc
limit 0,500";
$aResult = array();
if ($aRows = $this->oDb->select($sql,$iUserId ? $iUserId : DBSIMPLE_SKIP,$sTargetTmp)) {
foreach ($aRows as $aRow) {
$aResult[]=Engine::GetEntity('ModuleMedia_EntityMedia',$aRow);
}
}
return $aResult;
}
}

View file

@ -228,6 +228,34 @@ $config['module']['topic']['photoset']['size'] = array( // спис
)
);
/**
* Модуль Media
*/
$config['module']['media']['image_max_width'] = 5000; // Максимальный размер изображения по ширине
$config['module']['media']['image_max_height'] = 5000; // Максимальный размер изображения по высоте
$config['module']['media']['image_sizes'] = array( // список размеров, которые необходимо делать при загрузке изображения
array(
'w' => 1000,
'h' => null,
'crop' => false,
),
array(
'w' => 500,
'h' => null,
'crop' => false,
),
array(
'w' => 100,
'h' => 100,
'crop' => true,
),
array(
'w' => 50,
'h' => 50,
'crop' => true,
)
);
// Какие модули должны быть загружены на старте
$config['module']['autoLoad'] = array('Hook','Cache','Security','Session','Lang','Message','User');
/**
@ -288,6 +316,8 @@ $config['db']['table']['property_select'] = '___db.table.prefix___property_se
$config['db']['table']['property_value'] = '___db.table.prefix___property_value';
$config['db']['table']['property_value_tag'] = '___db.table.prefix___property_value_tag';
$config['db']['table']['property_value_select'] = '___db.table.prefix___property_value_select';
$config['db']['table']['media'] = '___db.table.prefix___media';
$config['db']['table']['media_target'] = '___db.table.prefix___media_target';
$config['db']['tables']['engine'] = 'InnoDB'; // InnoDB или MyISAM
@ -441,6 +471,7 @@ $config['head']['default']['js'] = array(
"___path.framework.frontend.web___/js/vendor/jquery.placeholder.min.js",
"___path.framework.frontend.web___/js/vendor/jquery.charcount.js",
"___path.framework.frontend.web___/js/vendor/jquery.imagesloaded.js",
"___path.framework.frontend.web___/js/vendor/jquery.fileupload.js",
"___path.framework.frontend.web___/js/vendor/notifier/jquery.notifier.js",
"___path.framework.frontend.web___/js/vendor/prettify/prettify.js",
"___path.framework.frontend.web___/js/vendor/prettyphoto/js/jquery.prettyphoto.js",
@ -493,6 +524,7 @@ $config['head']['default']['js'] = array(
"___path.application.web___/frontend/common/js/admin.js",
"___path.application.web___/frontend/common/js/userfield.js",
"___path.application.web___/frontend/common/js/captcha.js",
"___path.application.web___/frontend/common/js/media.js",
"___path.application.web___/frontend/common/js/init.js",
"http://yandex.st/share/share.js" => array('merge'=>false),

View file

@ -0,0 +1,321 @@
/**
* Фотосет
*
* @module ls/media
*
* @license GNU General Public License, version 2
* @copyright 2013 OOO "ЛС-СОФТ" {@link http://livestreetcms.com}
* @author Denis Shakhov <denis.shakhov@gmail.com>
*/
var ls = ls || {};
ls.media =( function ($) {
var _defaultsFileupload = {
url: aRouter['ajax']+"media/upload/",
sequentialUploads: false,
singleFileUploads: true,
limitConcurrentUploads: 3
};
var _defaults = {
target_type: '',
target_id: '',
target_tmp: '',
fileupload: _defaultsFileupload
};
this.mode='insert';
this.setMode = function(mode) {
this.mode=mode;
this.showSettingsMode();
};
this.showSettingsMode = function($item) {
$('.js-media-settings-mode').hide();
/**
* Показываем только если есть выделенные элементы
*/
if (this.getSelected().length) {
$('#media-settings-mode-'+this.mode).show();
$item=$item || this.getCurrent();
/**
* Выставляем настройки по вставке медиа
*/
var $select=$('select[name=size]').html('');
var sizes=$item.data('mediaImageSizes');
$.each(sizes,function(k,v){
/**
* Расчитываем пропорциональную высоту изображения
*/
var height=v.h;
if (!v.h) {
height=parseInt(v.w*$item.data('mediaHeight')/$item.data('mediaWidth'));
}
$select.append('<option value="'+ v.w +(v.crop ? 'crop' : '')+'">'+v.w+' × '+height+'</option>');
});
}
};
this.hideSettingsMode = function() {
$('.js-media-settings-mode').hide();
};
this.initUpload = function(options) {
this.options = $.extend(true, {}, _defaults, options);
this.options.target_tmp=this.options.target_tmp ? this.options.target_tmp : $.cookie('media_target_tmp_'+this.options.target_type);
if (!this.options.target_id && !this.options.target_tmp) {
ls.media.generateTargetTmp(this.options.target_type);
}
var params=this.options.fileupload;
params.formData=$.extend({}, params.formData || {}, {
security_ls_key: LIVESTREET_SECURITY_KEY,
target_type: this.options.target_type,
target_id: this.options.target_id,
target_tmp: this.options.target_tmp
});
$.each(params.formData,function(k,v){
if (v==null) {
params.formData[k]='';
}
});
$('.js-media-upload-file').fileupload(params);
$('.js-media-upload-file').bind('fileuploadadd',function(e,data) {
ls.media.addPreload(data);
});
$('.js-media-upload-file').bind('fileuploaddone',function(e,data) {
if (data.result.bStateError) {
ls.media.addFileError(data.context,data.result);
} else {
ls.media.addFile(data.context,data.result);
}
});
$('.js-media-upload-file').bind('fileuploadprogress',function(e,data) {
data.context.html(parseInt(data.loaded / data.total * 100, 10)+'%');
});
this.loadGallery();
this.bindFileEvents();
};
/**
* Инициализация
*/
this.init = function() {
};
this.removeCurrentFile = function() {
var $item=this.getCurrent();
if ($item.length) {
return this.removeFile($item.data('mediaId'));
}
return false;
};
this.removeFile = function(id) {
$this=this;
ls.ajax.load(aRouter['ajax']+"media/remove-file/", { id: id }, function(result) {
$('.js-media-upload-gallery-item[data-media-id='+id+']').fadeOut(500,function(){
$(this).remove();
if ($itemNext=$this.searchNextSelected()) {
$this.setCurrent($itemNext,true);
} else {
$this.hideDetail();
}
});
});
};
this.loadGallery = function() {
$('.js-media-upload-gallery-list').addClass('loader');
ls.ajax.load(aRouter['ajax']+"media/load-gallery/", { target_type: this.options.target_type, target_id: this.options.target_id, target_tmp: this.options.target_tmp }, function(result) {
$('.js-media-upload-gallery-list').removeClass('loader');
$('.js-media-upload-gallery-list').html(result.sTemplate);
});
};
this.generateTargetTmp = function(type) {
ls.ajax.load(aRouter['ajax']+"media/generate-target-tmp/", { type: type }, function(result) {
if (result.sTmpKey) {
this.options.target_tmp=result.sTmpKey;
}
}.bind(this));
};
this.addPreload = function(data) {
data.context=$('<li class="modal-upload-image-gallery-list-item">' +
'loader...' +
'</li>');
$('.js-media-upload-gallery-list').prepend(data.context);
};
this.bindFileEvents = function() {
$('.js-media-upload-gallery-list').on('click','.js-media-upload-gallery-item',function(e){
var $item=$(e.currentTarget);
var allowMany=(this.mode=='create-photoset' || e.ctrlKey || e.metaKey);
if ($item.hasClass('active')) {
/**
* Снимаем выделение с текущего
*/
$item.removeClass('active').removeClass('is-selected');
/**
* Делаем активным другой выделенный элемент
*/
if ($itemNext=this.searchNextSelected($item)) {
this.setCurrent($itemNext,true);
} else {
this.hideDetail();
}
} else {
/**
* Делаем текущим и показываем детальную информацию
*/
this.setCurrent($item,allowMany);
}
}.bind(this));
};
this.addFile = function(context,response) {
/**
* Завершение загрузки файла
*/
var $item=$(response.sTemplateFile);
context.replaceWith($item);
this.setSelected($item,true);
};
this.addFileError = function(context,response) {
/**
* Помечаем файл как ошибочный (глюк при загрузке)
*/
ls.msg.error(response.sMsgTitle,response.sMsg);
context.html('ERROR');
};
this.searchNextSelected = function($itemOld) {
var $item=$('.js-media-upload-gallery-item.is-selected:first');
if ($item.length==0) {
return false;
}
return $item;
};
this.setCurrent = function($item,allowMany) {
$('.js-media-upload-gallery-item.active').removeClass('active');
$item.addClass('active');
this.setSelected($item,allowMany);
/**
* Показываем детальную информацию
*/
this.showDetail($item);
};
this.getCurrent = function() {
return $('.js-media-upload-gallery-item.active');
};
this.setSelected = function($item,allowMany) {
if (!allowMany) {
this.getSelected().removeClass('is-selected');
}
$item.addClass('is-selected');
/**
* Если нет еще нет активного элемента, то делаем активным текущий
*/
if (this.getCurrent().length==0) {
this.setCurrent($item,allowMany);
}
};
this.getSelected = function() {
return $('.js-media-upload-gallery-item.is-selected');
};
this.showDetail = function($item) {
$('.js-media-detail-preview').attr('src',$item.data('mediaPreview'));
$('.js-media-detail-name').html($item.data('mediaFileName'));
$('.js-media-detail-date').html($item.data('mediaDateAdd'));
$('.js-media-detail-dimensions').html($item.data('mediaWidth')+' × '+$item.data('mediaHeight'));
$('.js-media-detail-file-size').html(parseInt($item.data('mediaFileSize')/1024)+'kB');
$('.js-media-detail-area').show();
this.showSettingsMode($item);
};
this.hideDetail = function() {
$('.js-media-detail-area').hide();
this.hideSettingsMode();
};
this.submitInsert = function() {
var $aItems=this.getSelected();
if (!$aItems.length) {
return false;
}
/**
* Формируем список ID элементов
*/
var aIds=[];
$aItems.each(function(k,v){
var $item=$(v);
aIds.push($item.data('mediaId'));
});
var params={
ids: aIds,
align: $('#media-settings-mode-insert').find('select[name=align]').val(),
size: $('#media-settings-mode-insert').find('select[name=size]').val()
}
ls.ajax.load(aRouter['ajax']+"media/submit-insert/", params, function(result) {
if (result.bStateError) {
ls.msg.error(result.sMsgTitle,result.sMsg);
} else {
$.markItUp({
replaceWith: result.sTextResult
});
$('#modal-image-upload').modal('hide');
}
});
};
this.submitCreatePhotoset = function() {
var $aItems=this.getSelected();
if (!$aItems.length) {
return false;
}
/**
* Формируем список ID элементов
*/
var aIds=[];
$aItems.each(function(k,v){
var $item=$(v);
aIds.push($item.data('mediaId'));
});
var params={
ids: aIds
}
ls.ajax.load(aRouter['ajax']+"media/submit-create-photoset/", params, function(result) {
if (result.bStateError) {
ls.msg.error(result.sMsgTitle,result.sMsg);
} else {
$.markItUp({
replaceWith: result.sTextResult
});
$('#modal-image-upload').modal('hide');
}
});
};
return this;
}).call(ls.media || {},jQuery);

View file

@ -26,4 +26,74 @@
.write-list li.write-item-type-link .write-item-image { background-position: -200px 0; }
.write-list li.write-item-type-photoset .write-item-image { background-position: -300px 0; }
.write-list li.write-item-type-blog .write-item-image { background-position: -400px 0; }
.write-list li.write-item-type-draft .write-item-image { background-position: -500px 0; }
.write-list li.write-item-type-draft .write-item-image { background-position: -500px 0; }
/**
* Add media
*
* @template modals/modal.upload_image.tpl
*/
.modal-upload-image { max-width: 1200px; border: none; }
.modal-upload-image .grid-row { background: #222; }
/* Nav */
.modal-upload-image-nav { float: left; width: 150px; padding-top: 15px; }
.modal-upload-image-nav li a { display: block; padding: 10px 15px; color: #eee; }
.modal-upload-image-nav li a:hover { background: #2a2a2a; }
.modal-upload-image-nav li.active a { background: #333; }
/* Content */
.modal-upload-image-content { min-height: 300px; margin-left: 150px; background: #fff; border-left: 1px solid #eee; }
/* Upload area */
.form-input-file.form-input-file-media {
display: block;
border: 3px dashed #eee;
color: #555;
cursor: pointer;
padding: 20px;
margin-bottom: 20px;
text-align: center;
}
/* Manager */
.modal-upload-image-gallery { overflow: hidden; }
.modal-upload-image-gallery-list { overflow: auto; width: 68%; margin-right: 2%; max-height: 354px; float: left; }
.modal-upload-image-gallery-list-item {
position: relative;
cursor: pointer;
border: 3px solid transparent;
padding: 1px;
float: left;
margin: 0 10px 10px 0;
}
.modal-upload-image-gallery-list-item img { vertical-align: top; width: 100px; height: 100px; }
.modal-upload-image-gallery-list-item:hover { border-color: #eee; }
/* Selected */
.modal-upload-image-gallery-list-item.is-selected { border-color: #D5CE3D; }
/* Active */
.modal-upload-image-gallery-list-item.is-selected.active { border-color: #7979FC; }
.modal-upload-image-gallery-list-item.is-selected.active .modal-upload-image-gallery-list-item-checkbox {background: #7979FC; }
/* Checkbox */
.modal-upload-image-gallery-list-item input { display: none; }
.modal-upload-image-gallery-list-item.is-selected .modal-upload-image-gallery-list-item-checkbox { position: absolute; right: 0; bottom: 0; width: 20px; height: 20px; background: #D5CE3D; cursor: pointer; }
.modal-upload-image-gallery-list-item.is-selected input:checked + .modal-upload-image-gallery-list-item-checkbox { background: #000; }
/* Info */
.modal-upload-image-gallery-info { width: 30%; float: left; padding: 20px; background: #fafafa; }
.modal-upload-image-gallery-info ul li { margin-bottom: 5px; }
.modal-upload-image-gallery-list,
.modal-upload-image-gallery-info {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
/* Note */
.modal-upload-image-note { margin-bottom: 20px; }

View file

@ -24,7 +24,11 @@
{block name='add_topic_options'}{/block}
{* Подключение редактора *}
{include file='forms/editor.init.tpl'}
{$sMediaTargetId=''}
{if $oTopicEdit}
{$sMediaTargetId=$oTopicEdit->getId()}
{/if}
{include file='forms/editor.init.tpl' sMediaTargetType='topic' sMediaTargetId=$sMediaTargetId}
{hook run="add_topic_`$sTopicType`_begin"}

View file

@ -0,0 +1,24 @@
{**
* Добавление медиа-файла / Список изображений / Блок с изображением
*
* @styles css/modals.css
*
* TODO: Передавать сюда объект изображения вместо отдельных переменных
*}
<li class="js-media-upload-gallery-item modal-upload-image-gallery-list-item {if $bIsSelected}is-selected{/if} {if $bIsActive}active{/if}"
data-media-id="{$oMediaItem->getId()}"
data-media-type="{$oMediaItem->getType()}"
data-media-date-add="{$oMediaItem->getDateAdd()}"
data-media-data-title="{$oMediaItem->getDataOne('title')|escape:'html'}"
data-media-file-name="{$oMediaItem->getFileName()|escape:'html'}"
data-media-file-size="{$oMediaItem->getFileSize()}"
data-media-width="{$oMediaItem->getWidth()}"
data-media-height="{$oMediaItem->getHeight()}"
data-media-preview="{$oMediaItem->getFileWebPath('100crop')}"
data-media-image-sizes={json var=$oMediaItem->getDataOne('image_sizes')}
>
<img src="{$oMediaItem->getFileWebPath('100crop')}" alt="Image">
<input id="checkbox_02" type="checkbox">
<label for="checkbox_02" class="modal-upload-image-gallery-list-item-checkbox" title="Убрать выделение"></label>
</li>

View file

@ -0,0 +1,68 @@
{**
* Добавление медиа-файла / Список изображений
*
* @styles css/modals.css
*}
<div id="upload-gallery-image">
<label for="upload-file" class="form-input-file form-input-file-media js-media-upload-area">
<span>Перетащите сюда файлы или кликните по этому тексту</span>
<input type="file" name="filedata" class="js-media-upload-file" id="upload-file" multiple>
</label>
<div class="modal-upload-image-gallery">
<ul class="modal-upload-image-gallery-list js-media-upload-gallery-list">
</ul>
<div class="modal-upload-image-gallery-info">
<div class="js-media-detail-area" style="display: none;">
<img src="" alt="" class="js-media-detail-preview">
<ul class="mb-20">
<li><strong class="js-media-detail-name"></strong></li>
<li class="js-media-detail-date"></li>
<li><span class="js-media-detail-dimensions"></span>, <span class="js-media-detail-file-size"></span></li>
<li><a href="#" onclick="if (confirm('Удалить текущий файл?')) { ls.media.removeCurrentFile(); }; return false;">Удалить файл</a></li>
</ul>
{* Title *}
{include file='forms/form.field.text.tpl'
sFieldName = 'title'
sFieldLabel = $aLang.uploadimg_title}
</div>
<div class="js-media-settings-mode" id="media-settings-mode-insert" style="display: none;">
Опции вставки
{* Align *}
<p>
<label>{$aLang.uploadimg_align}:</label>
<select name="align" class="width-full">
<option value="">{$aLang.uploadimg_align_no}</option>
<option value="left">{$aLang.uploadimg_align_left}</option>
<option value="right">{$aLang.uploadimg_align_right}</option>
<option value="center" selected="selected">{$aLang.uploadimg_align_center}</option>
</select>
</p>
<p>
{$aImageSizes=Config::Get('module.media.image_sizes')}
<label>Размер:</label>
<select name="size" class="width-full">
{foreach $aImageSizes as $aSize}
<option value="{$aSize.w}{if $aSize.crop}crop{/if}">{$aSize.w} × {if $aSize.h}{$aSize.h}{else}*{/if}</option>
{/foreach}
<option value="original">Оригинал</option>
</select>
</p>
</div>
<div class="js-media-settings-mode" id="media-settings-mode-create-photoset" style="display: none;">
Опции фотосета
</div>
</div>
</div>
</div>

View file

@ -1,87 +1,107 @@
{**
* Загрузка изображения
*
* @styles css/modals.css
*}
{extends file='modals/modal_base.tpl'}
{block name='modal_id'}modal-image-upload{/block}
{block name='modal_class'}modal-image-upload js-modal-default{/block}
{block name='modal_title'}{$aLang.uploadimg}{/block}
{block name='modal_header_after'}
<ul class="nav nav-pills nav-pills-tabs" data-type="tabs">
<li data-type="tab" data-tab-target="tab-upload-pc" class="active"><a href="#">{$aLang.uploadimg_from_pc}</a></li>
<li data-type="tab" data-tab-target="tab-upload-link"><a href="#">{$aLang.uploadimg_from_link}</a></li>
</ul>
{/block}
{block name='modal_content_after'}
<div data-type="tab-panes">
{**
* Загрузка
*}
<form method="POST" action="" enctype="multipart/form-data" id="tab-upload-pc" onsubmit="return false;" data-type="tab-pane" class="tab-pane" style="display: block">
<div class="modal-content">
<p><label for="img_file">{$aLang.uploadimg_file}:</label>
<input type="file" name="img_file" id="img_file" value="" class="width-full" /></p>
{hook run="uploadimg_source"}
<p>
<label for="form-image-align">{$aLang.uploadimg_align}:</label>
<select name="align" id="form-image-align" class="width-full">
<option value="">{$aLang.uploadimg_align_no}</option>
<option value="left">{$aLang.uploadimg_align_left}</option>
<option value="right">{$aLang.uploadimg_align_right}</option>
<option value="center">{$aLang.uploadimg_align_center}</option>
</select>
</p>
<p><label for="form-image-title">{$aLang.uploadimg_title}:</label>
<input type="text" name="title" id="form-image-title" value="" class="width-full" /></p>
{hook run="uploadimg_additional"}
</div>
<div class="modal-footer">
<button type="submit" class="button button-primary js-upload-image-button" data-form-id="tab-upload-pc">{$aLang.uploadimg_submit}</button>
<button type="button" class="button" data-type="modal-close">{$aLang.uploadimg_cancel}</button>
</div>
</form>
{**
* Ссылка
*}
<form method="POST" action="" enctype="multipart/form-data" id="tab-upload-link" onsubmit="return false;" data-type="tab-pane" class="tab-pane">
<div class="modal-content">
<p><label for="img_file">{$aLang.uploadimg_url}:</label>
<input type="text" name="img_url" id="img_url" value="http://" class="width-full" /></p>
<p>
<label for="form-image-url-align">{$aLang.uploadimg_align}:</label>
<select name="align" id="form-image-url-align" class="width-full">
<option value="">{$aLang.uploadimg_align_no}</option>
<option value="left">{$aLang.uploadimg_align_left}</option>
<option value="right">{$aLang.uploadimg_align_right}</option>
<option value="center">{$aLang.uploadimg_align_center}</option>
</select>
</p>
<p><label for="form-image-url-title">{$aLang.uploadimg_title}:</label>
<input type="text" name="title" id="form-image-url-title" value="" class="width-full" /></p>
{hook run="uploadimg_link_additional"}
</div>
<div class="modal-footer">
<button type="submit" class="button button-primary js-insert-image-button">{$aLang.uploadimg_link_submit_paste}</button>
<button type="submit" class="button button-primary js-upload-image-button" data-form-id="tab-upload-link">{$aLang.uploadimg_link_submit_load}</button>
<button type="button" class="button" data-type="modal-close">{$aLang.uploadimg_cancel}</button>
</div>
</form>
</div>
{/block}
{**
* Загрузка медиа-файлов
*
* @styles css/modals.css
*}
{extends file='modals/modal_base.tpl'}
{block name='modal_id'}modal-image-upload{/block}
{block name='modal_class'}modal-upload-image js-modal-default{/block}
{block name='modal_title'}Добавить медиа-файл{/block}
{block name='modal_attributes'}data-modal-center="false"{/block}
{block name='modal_content_after'}
<script type="text/javascript">
jQuery(function($){
$('.js-tab-show-gallery').on('tabbeforeactivate',function(event,tab){
$('#upload-gallery-image').appendTo($('#'+tab.options.target).find('.modal-content'));
ls.media.setMode($(event.target).data('mediaMode'));
});
ls.media.setMode('insert');
ls.media.initUpload({
target_type: {json var=$sMediaTargetType},
target_id: {json var=$sMediaTargetId},
target_tmp: {json var=$sMediaTargetTmp},
fileupload: {
dropZone: $('.js-media-upload-area')
}
});
});
</script>
<div class="grid-row">
{* Side navigation *}
<ul class="modal-upload-image-nav" data-type="tabs">
<li data-type="tab" data-tab-target="tab-media-insert" data-media-mode="insert" class="active js-tab-show-gallery"><a href="#">Вставить</a></li>
<li data-type="tab" data-tab-target="tab-media-create-photoset" data-media-mode="create-photoset" class="js-tab-show-gallery"><a href="#">Создать фотосет</a></li>
<!--<li data-type="tab" data-tab-target="tab-media-link"><a href="#">{$aLang.uploadimg_from_link}</a></li>-->
</ul>
{* Side navigation content *}
<div data-type="tab-panes" class="modal-upload-image-content">
{**
* Загрузка
*}
<div id="tab-media-insert" data-type="tab-pane" class="tab-pane modal-upload-image-pane" style="display: block">
<div class="modal-content">
{include file='modals/modal.upload_image.gallery.tpl'}
</div>
<div class="modal-footer">
<button type="submit" class="button button-primary" onclick="ls.media.submitInsert();">Вставить</button>
<button type="button" class="button" data-type="modal-close">{$aLang.uploadimg_cancel}</button>
</div>
</div>
{**
* Ссылка
*}
<form method="POST" action="" enctype="multipart/form-data" id="tab-media-link" onsubmit="return false;" data-type="tab-pane" class="tab-pane modal-upload-image-pane">
<div class="modal-content">
<p><label for="img_url">{$aLang.uploadimg_url}:</label>
<input type="text" name="img_url" id="img_url" value="http://" class="width-full" /></p>
<p>
<label for="form-image-url-align">{$aLang.uploadimg_align}:</label>
<select name="align" id="form-image-url-align" class="width-full">
<option value="">{$aLang.uploadimg_align_no}</option>
<option value="left">{$aLang.uploadimg_align_left}</option>
<option value="right">{$aLang.uploadimg_align_right}</option>
<option value="center">{$aLang.uploadimg_align_center}</option>
</select>
</p>
<p><label for="form-image-url-title">{$aLang.uploadimg_title}:</label>
<input type="text" name="title" id="form-image-url-title" value="" class="width-full" /></p>
</div>
<div class="modal-footer">
<button type="submit" class="button button-primary js-insert-image-button">Вставить</button>
<button type="submit" class="button button-primary js-upload-image-button" data-form-id="tab-upload-link">{$aLang.uploadimg_link_submit_load}</button>
<button type="button" class="button" data-type="modal-close">{$aLang.uploadimg_cancel}</button>
</div>
</form>
{**
* Фотосет
*}
<div id="tab-media-create-photoset" data-type="tab-pane" class="tab-pane modal-upload-image-pane">
<div class="modal-content">
</div>
<div class="modal-footer">
<button type="submit" class="button button-primary" onclick="ls.media.submitCreatePhotoset();">Создать фотосет</button>
<button type="button" class="button" data-type="modal-close">{$aLang.uploadimg_cancel}</button>
</div>
</div>
</div>
</div>
{/block}
{block name='modal_footer'}{/block}

View file

@ -139,4 +139,57 @@ CREATE TABLE IF NOT EXISTS `prefix_property_value_select` (
KEY `target_id` (`target_id`),
KEY `property_id` (`property_id`),
KEY `select_id` (`select_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `prefix_media` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT NULL,
`type` int(11) NOT NULL,
`file_path` varchar(500) NOT NULL,
`file_name` varchar(500) NOT NULL,
`file_size` int(11) NOT NULL,
`width` int(11) NOT NULL,
`height` int(11) NOT NULL,
`date_add` datetime NOT NULL,
`data` text NOT NULL,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `type` (`type`),
KEY `file_size` (`file_size`),
KEY `width` (`width`),
KEY `height` (`height`),
KEY `date_add` (`date_add`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Структура таблицы `prefix_media_target`
--
CREATE TABLE IF NOT EXISTS `prefix_media_target` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`media_id` int(11) NOT NULL,
`target_id` int(11) DEFAULT NULL,
`target_type` varchar(50) NOT NULL,
`target_tmp` varchar(50) DEFAULT NULL,
`date_add` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `media_id` (`media_id`),
KEY `target_id` (`target_id`),
KEY `target_type` (`target_type`),
KEY `target_tmp` (`target_tmp`),
KEY `date_add` (`date_add`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Ограничения внешнего ключа сохраненных таблиц
--
--
-- Ограничения внешнего ключа таблицы `prefix_media_target`
--
ALTER TABLE `prefix_media_target`
ADD CONSTRAINT `prefix_media_target_ibfk_1` FOREIGN KEY (`media_id`) REFERENCES `prefix_media` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;