Добавляем TV тип ввода GalleryItemList для компонента Gallery
- 19.04.2013
- MODx, Gallery, Дополнение, Работа с изображениями, Трюки, Сниппеты
Компонент Gallery стал стандартом де-факто для большинства разработчиков сайтов на MODx Revolution в вопросе управления фото галереями. В целом Gallery весьма хорошо справляется с этой задачей, но и его есть куда улучшать.
Сегодня показываем еще одно улучшение, а именно создадим новый тип ввода для TV параметров, позволяющий выбрать отдельное изображение из конкретной галереи.
Картинка для затравки:

В этом примере (рассматриваем сайт дверей) потребовалось для каждой конкретной модели двери указать, какая фурнитура (ручки, броненакладки) применяется. Указывать отдельную фотографию в этом случае не очень удобно, вариант, когда фотография выбирается из списка - предпочтительней, т.к. ассортимент фурнитуры ограничен и меняется довольно редко.
Основные принципы:
- Создаем в компоненте Gallery 2 галереи: Ручки, Броненакладки. Заполняем их необходимыми нам изображениями.
- Создаем 2 TV поля, привязываем их у нужному нам шаблону.
- Нам необходим новый тип ввода, позволяющий выбрать из конкретной галереи, конкретное изображение. В базе данных мы будем хранить идентификатор этого изображения (id).
Добавляем GalleryItemList TV
Все действия производим в каталоге
/core/components/gallery/elements/tv/
1. Создаем файл galleryitemlist.input.tpl:
<input id="tv{$tv->id}" type="text" />
{literal}
<script type="text/javascript">
// <![CDATA[
Ext.onReady(function() {
var galStore{/literal}{$tv->id}{literal} = new Ext.data.ArrayStore({
fields: ['id','name', 'cover'],
data : {/literal}{$list}{literal}
});
var galTpl{/literal}{$tv->id}{literal} = new Ext.XTemplate(
'<tpl for="."><div class="search-item" style="padding: 4px">'
,'<tpl if="cover"><div style="float: right;"><img src="{cover}" alt="" /></div></tpl>'
,'{name}'
,'<br /><span style="font-size: small; font-style: italic">{description}</span>'
,'<div style="clear: both;"></div></div></tpl>'
);
var fld = MODx.load({{/literal}
xtype: 'combo'
,store: galStore{$tv->id}
,displayField: 'name'
,valueField: 'id'
,name: 'tv{$tv->id}'
,hiddenName: 'tv{$tv->id}'
,mode: 'local'
,triggerAction: 'all'
,applyTo: 'tv{$tv->id}'
,value: '{$tv->value}'
,tpl: galTpl{$tv->id}
,itemSelector: 'div.search-item'
,width: {if $params.width}{$params.width}{else}400{/if}
,allowBlank: {if $params.allowBlank == 1 || $params.allowBlank == 'true'}true{else}false{/if}
{if $params.listWidth},listWidth: {$params.listWidth}{/if}
{if $params.typeAhead}
,typeAhead: true
,typeAheadDelay: {if $params.typeAheadDelay && $params.typeAheadDelay != ''}{$params.typeAheadDelay}{else}250{/if}
{else}
,editable: false
,typeAhead: false
{/if}
{if $params.listEmptyText}
,listEmptyText: '{$params.listEmptyText}'
{/if}
,forceSelection: {if $params.forceSelection && $params.forceSelection != 'false'}true{else}false{/if}
,msgTarget: 'under'
,listeners: { 'select': { fn:MODx.fireResourceFormChange, scope:this}}
{literal}});
var pr = Ext.getCmp('modx-panel-resource');
if (pr) {
pr.getForm().add(fld);
}
MODx.makeDroppable(fld);
});
// ]]>
</script>
{/literal}
2. Создаем файл galleryitemlist.inputproperties.tpl:
<div id="tv-input-properties-form{$tv}"></div>
{literal}
<script type="text/javascript">
// <![CDATA[
var params = {
{/literal}{foreach from=$params key=k item=v name='p'}
'{$k}': '{$v|escape:"javascript"}'{if NOT $smarty.foreach.p.last},{/if}
{/foreach}{literal}
};
var oc = {'change':{fn:function(){Ext.getCmp('modx-panel-tv').markDirty();},scope:this}};
MODx.load({
xtype: 'panel'
,layout: 'form'
,autoHeight: true
,labelWidth: 150
,border: false
,items: [{
xtype: 'textfield'
,fieldLabel: 'Альбом'
,description: '{/literal}{$gl.parent_desc}{literal}'
,name: 'inopt_album'
,id: 'inopt_album{/literal}{$tv}{literal}'
,value: params['album'] || ''
,width: 300
,listeners: oc
},{
xtype: 'combo-boolean'
,fieldLabel: _('required')
,description: _('required_desc')
,name: 'inopt_allowBlank'
,hiddenName: 'inopt_allowBlank'
,id: 'inopt_allowBlank{/literal}{$tv}{literal}'
,value: params['allowBlank'] == 0 || params['allowBlank'] == 'false' ? false : true
,width: 300
,listeners: oc
},{
xtype: 'combo'
,store: [['rank','{/literal}{$gl.rank}{literal}'],['name','{/literal}{$gl.name}{literal}']]
,fieldLabel: '{/literal}{$gl.sort}{literal}'
,description: '{/literal}{$gl.sort_desc}{literal}'
,name: 'inopt_sort'
,hiddenName: 'inopt_sort'
,forceSelection: true
,typeAhead: false
,editable: false
,triggerAction: 'all'
,id: 'inopt_sort{/literal}{$tv}{literal}'
,value: params['sort'] || 'rank'
,width: 300
,listeners: oc
},{
xtype: 'combo'
,store: [['ASC','{/literal}{$gl.ascending}{literal}'],['DESC','{/literal}{$gl.descending}{literal}']]
,fieldLabel: '{/literal}{$gl.sortdir}{literal}'
,description: '{/literal}{$gl.sortdir_desc}{literal}'
,name: 'inopt_dir'
,hiddenName: 'inopt_dir'
,forceSelection: true
,typeAhead: false
,editable: false
,triggerAction: 'all'
,id: 'inopt_dir{/literal}{$tv}{literal}'
,value: params['dir'] || 'DESC'
,width: 300
,listeners: oc
},{
xtype: 'textfield'
,fieldLabel: '{/literal}{$gl.limit}{literal}'
,description: '{/literal}{$gl.limit_desc}{literal}'
,name: 'inopt_limit'
,hiddenName: 'inopt_limit'
,id: 'inopt_limit{/literal}{$tv}{literal}'
,value: params['limit'] || 0
,width: 300
,listeners: oc
},{
xtype: 'textfield'
,fieldLabel: '{/literal}{$gl.start}{literal}'
,description: '{/literal}{$gl.start_desc}{literal}'
,name: 'inopt_start'
,hiddenName: 'inopt_start'
,id: 'inopt_start{/literal}{$tv}{literal}'
,value: params['start'] || 0
,width: 300
,listeners: oc
}]
,renderTo: 'tv-input-properties-form{/literal}{$tv}{literal}'
});
// ]]>
</script>
{/literal}
3. Создаем файл input/galleryitemlist.php:
<?php
$modx->lexicon->load('tv_widget','gallery:default');
$modx->smarty->assign('base_url',$this->xpdo->getOption('base_url'));
$corePath = $modx->getOption('gallery.core_path',null,$modx->getOption('core_path').'components/gallery/');
$modx->addPackage('gallery',$corePath.'model/');
if (empty($params)) $params = array();
/* setup default properties */
$sort = $modx->getOption('sort',$params,'rank');
$dir = $modx->getOption('dir',$params,'ASC');
$limit = intval($modx->getOption('limit',$params,0));
$start = intval($modx->getOption('start',$params,0));
$album = intval($modx->getOption('album',$params,''));
/* get albums */
$c = $modx->newQuery('galAlbumItem');
$c->setClassAlias('AlbumItem');
$c->innerJoin('galItem','Item', '');
$c->select($modx->getSelectColumns('galAlbumItem','AlbumItem', '', array('album', 'rank')));
$c->select($modx->getSelectColumns('galItem','Item', '', array('id','name', 'filename', 'active')));
if ($album != '') {
$c->where(array(
'AlbumItem.album' => $album,
));
}
$c->where(array(
'Item.active' => 1,
));
$c->sortby($sort,$dir);
if ($limit > 0) {
$c->limit($limit,$start);
}
#$c->prepare();
#echo $c->toSql();
#die;
#$items = $modx->getCollection('galAlbumItem',$c);
$items = array();
$list = array();
if ($c->prepare() && $c->stmt->execute()) {
$items = $c->stmt->fetchAll(PDO::FETCH_ASSOC);
}
$list[] = array('', '(Нет)', '');
for($i = 0; $i < count($items); $i++){
$row = array();
$row[] = $items[$i]['id'];
$row[] = $items[$i]['name'];
$row[] = '/assets/gallery/.thumb/'.$items[$i]['filename'];
$list[] = $row;
}
$modx->smarty->assign('list',$modx->toJSON($list));
return $modx->smarty->fetch($corePath.'elements/tv/galleryitemlist.input.tpl');
4. Создаем файл inputoptions/galleryitemlist.php
<?php
$modx->lexicon->load('tv_widget','gallery:tvprops');
$modx->smarty->assign('base_url',$modx->getOption('base_url'));
$corePath = $modx->getOption('gallery.core_path',null,$modx->getOption('core_path').'components/gallery/');
$modx->addPackage('gallery',$corePath.'model/');
/* get TV input properties specific language strings */
$lang = $modx->lexicon->fetch('galtv.',true);
$modx->smarty->assign('gl',$lang);
return $modx->smarty->fetch($corePath.'elements/tv/galleryitemlist.inputproperties.tpl');
Обратите внимание, что 2 последних файла создаются в каталогах.
Внимание! В этой статье используется прием генерации превью изображения при загрузке, описанный в этой статье. Без нее у вас не будут показываться изображения! В этом случае вам надо изменить строку #53 в файле input/galleryitemlist.php, указав другой путь к картинке, так, как это делается в Gallery по умолчанию, через connector.php. Для примера смотрите файл /core/components/gallery/model/gallery/galitem.class.php
Результат
Если вы все сделали правильно, то теперь при создании нового TV поля в админке, в поле Тип ввода (вкладка Параметры ввода) появился новый доступный тип galleryitemlist:

Обратите внимание, на выделенное желтым. Это дополнительные параметры/настройки для нашего TV поля. В нем обязательно необходимо указать Id Альбома в компоненте Gallery, из которого мы будем брать фотографии.
Теперь сохраняем TV, и при редактировании ресурса можно увидеть картину, аналогичную первому изображению в этой статье!
Как вывести изображение из TV на сайте?
Мы используем небольшие сниппеты для этой цели. Полный код я приводить не буду, лишь небольшой, но в тоже время понятный напросок:
// получаем фото, myTV - значение, хранящееся в TV поле ресурса
$galItem = $modx->getObject('galItem', $myTV);
// если такое изображение существует
if($galItem != null){
// нам доступны все поля в нем
$id = $res->get('id');
$name = $galItem->get('name');
$image = $galItem->get('absoluteImage');
// ... остальные поля можно посмотреть в таблице modx_gallery_items
}
Если есть вопросы и замечания - оставляйте в комментариях.
