Добавляем 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 }
Если есть вопросы и замечания - оставляйте в комментариях.