[REVO] Добавляем к ресурсу неограниченное количество изображений

Появилась необходимость прикреплять на своём сайте заранее не известное кол-во фотографий, изначально пользовался ТВ, создал 4 ТВ и вполне хватало, пока не появилась необходимость прикрепить больше 4 фотографий, написал сырой пока еще скриптец для этих целей



Вот собственно сам скрипт

assets/modx.images.js
Ext.onReady(function () {
    var mainPanel = Ext.getCmp('modx-panel-resource'),
        data = mainPanel.config.record,
        panelRight = Ext.getCmp('modx-resource-main-right'),
        tabpanel = Ext.getCmp('modx-resource-tabs'),
        image_field = {
            xtype: 'ms-combo-browser',
            openTo: '',
            value: '',
            name: 'images[]',
            fieldLabel: '',
            anchor: '50%',
        },
        title = 'Изображение',
        index = 1;

    Ext.getCmp('modx-resource-access-permissions').destroy();
    Ext.getCmp('modx-page-settings').destroy();

    tabpanel.add({
        title: 'Фотки',
        closable: false,
        items: [{
            xtype: 'panel',
            id: 'modx-resource-images',
            border: false,
            layout: 'form',
            padding: 10,
            labelAlign: 'top',
            tbar: {
                style: {
                    'margin': '5px 0 0 0',
                    'border-bottom': '1px solid #DDD',
                    'background-color': '#FAFAFA',
                    'border-top': '1px solid #DDD',
                    'padding': '5px 10px',
                },
                items: [{
                    text: 'Добавить фото',
                    handler: function () {
                        image_field.fieldLabel = title + ' ' + index;
                        panel.add(image_field);
                        panel.doLayout();
                        index += 1;
                    }
                }]
            }
        }]
    })

    var panel = Ext.getCmp('modx-resource-images');
    if (typeof data.properties.images === 'object') {
        var images = data.properties.images;
        for (img in images) {
            image_field.value = images[img];
            image_field.openTo = images[img];
            image_field.fieldLabel = title + ' ' + index;
            panel.add(image_field);
            index += 1;
        };
        panel.doLayout();
        image_field.value = '';
        image_field.openTo = '';
    };

    panelRight.doLayout();

});


Вот сам плагин который сохраняет всё это дело в поле Properties ресурса, вешается на два события OnDocFormPrerender и OnBeforeDocFormSave
<?php
switch($modx->event->name) {
case 'OnDocFormPrerender':
    $template = is_object($resource) ? $resource->get('template') : 5;
    
    $modx->regClientStartupScript(MODX_ASSETS_URL.'modx.extras.js');
    if ($template === 5) {
        $modx->regClientStartupScript(MODX_ASSETS_URL.'modx.images.js');
    }
    break;
case 'OnBeforeDocFormSave':
    $resource =& $modx->event->params['resource'];

    function prepareArray(array $array) {
        foreach ($array as $k => &$v) {
            $v = trim($v);
            if (empty($v)) {
                unset($array[$k]);
            } else {
                $array[$k] = $v;
            }
        }
        $array = array_values(array_unique($array));
        $i = 0;
        $images = array();
        foreach ($array as $img) {
            $images['img_'.$i] = $img;
            $i += 1;
        }
        return $images;
    }

    if (isset($_POST['images'])) {
        $images = prepareArray($_POST['images']);
        $resource->setProperties($images,'images',false);
    }

    break;
}


assets/modx.extras.js
// Модифицированный modx-combo-browser для MODx
MODx.combo.Browser = function(config) {
    config = config || {};
    if (config.length !== 0 && typeof config.openTo !== "undefined") {
        if (!/^\//.test(config.openTo)) {
            config.openTo = '/' + config.openTo;
        }
        if (!/$\//.test(config.openTo)) {
            var tmp = config.openTo.split('/');
            delete tmp[tmp.length - 1];
            tmp = tmp.join('/');
            config.openTo = tmp.substr(1);
        }
    }

    Ext.applyIf(config,{
        width: 300,
        triggerAction: 'all'
    });
    MODx.combo.Browser.superclass.constructor.call(this,config);
    this.config = config;
};
Ext.extend(MODx.combo.Browser,Ext.form.TriggerField,{
    browser: null,
    onTriggerClick : function(btn){
        if (this.disabled){
            return false;
        }

        if (this.browser === null) {
            this.browser = MODx.load({
                xtype: 'modx-browser',
                id: Ext.id(),
                multiple: true,
                source: this.config.source || MODx.config.default_media_source,
                // hideFiles: this.config.hideFiles || false,
                rootVisible: this.config.rootVisible || false,
                allowedFileTypes: this.config.allowedFileTypes || '',
                wctx: this.config.wctx || 'web',
                openTo: this.config.openTo || '',
                rootId: this.config.rootId || '/',
                hideSourceCombo: this.config.hideSourceCombo || false,
                hideFiles: this.config.hideFiles || true,
                listeners: {
                    'select': {fn: function(data) {
                        this.setValue(data.fullRelativeUrl);
                        this.fireEvent('select',data);
                        MODx.fireResourceFormChange();
                    },scope:this}
                }
            });
        }
        this.browser.win.buttons[0].on('disable',function(e) {
            this.enable();
        });
        this.browser.win.tree.on('click', function(n,e) {
                path = this.getPath(n);
                this.setValue(path);
            },this
        );
        this.browser.win.tree.on('dblclick', function(n,e) {
                path = this.getPath(n);
                this.setValue(path);
                this.browser.hide();
            },this
        );
        this.browser.show(btn);
        return true;
    },
    onDestroy: function(){
        MODx.combo.Browser.superclass.onDestroy.call(this);
    },
    getPath: function(n) {
        if (n.id == '/') {return '';}
        data = n.attributes;
        path = data.path + '/';

        return path;
    }
});
Ext.reg('ms-combo-browser',MODx.combo.Browser);


Хранятся картинки в таком формате
{
    "images": {
        "img_1": "888.jpg",
        "img_2": "111.jpg",
        "img_3": "xxx.png"
    }
}


Пример сниппета [[getImages]]
<?php
$images = $modx->resource->getProperties('images');
$site_url = $modx->getOption('site_url');

$output = '';
if (count($images) > 0) {
    foreach ($images as $img) {
        $output .= '<img src="'.$site_url.$img.'" />';
    }
}
return $output;


Как получить одну картинку по её индексу, очень просто
Пример сниппета [[getImage]]
<?php
// Получаем изображение с ID img_1, если изображения нет, ставим дефолтную картинку 'assets/blank.png'
$image = $modx->resource->getProperty('img_1','images','assets/blank.png');
$site_url = $modx->getOption('site_url');

$output = '<img src="'.$site_url.$image.'" />';

return $output;


Выглядит пока вот так, дальше планирую сделать превьюшки, сортировку, удаление, описание и удобную загрузку

18 комментариев

avatar
Какие преимущества перед MIGX?
  • Shin
  • 0
avatar
MIGX тянет картинки к примеру c TV. т.е. это джоин, а здесь всё в ресурсе.
MIGX тяжелее в освоении, здесь просто (правда сухо ещё ).
А если в общем — MIGX круче понятно, у него куча возможностей и.т.д…
avatar
Нет, конечно, ну да, джойн. Без него быстрее. Но вот это решение, прошу меня простить, но ни фига не проще, а куда мудрёнее MIGX. Для небольших «галерей», скажем, до десятка фоток/файлов легко используется «обычный» MIGX. Немного покурить документацию, разобраться с конфигами и создание migx-tv будет простой рутиной.
Если же мне нужно много картинок, файлов или однотипных элементов, скажем, информация по дилерам-шмилерам — migx-db также поможет. Причем самое сложное в этом — это собрать у себя в голове и перенести в код структуру таблицы. Остальное — достаточно скучное и маловысокотворческое занятие.

И главное — при использовании MIGX нуль изменений в core-коде. Следовательно, после очередного обновления MODX мне не нужно будет рыться в коде, снова и снова чего-то там подправляя.
avatar
Виталий, а где вы видите здесь изменения «core-коде»?
Во первых это пример не до конца реализованный (нету превью картинок, названий для картинок и.т.д), но сама идея очень хорошая.
Но вот это решение, прошу меня простить, но ни фига не проще
По вашему просто нажать и загрузить картинку, куда не проще чем:
Немного покурить документацию, разобраться с конфигами и создание migx-tv будет простой рутиной.
?
Ну, тогда не знаю я… Одному проще просто нажать на кнопку, а другому наверное проще городить конструкции.
Я не говорю что MIGX — это плохо. он очень гипкий инструмент для разных задач, этот-же пример демонстрирует просто галлерею и ничего более.
avatar
А, ок, прогнал про код. Увидел концовку и сделал скоропалительный вывод. Так что прошу прощения.
Опять же — понимаю, что не до конца реализованный. Ну и сколь широко и глубоко он может быть реализован? Давайте все, кому не лень, в этот properties пихать. Один решатель запихнет, другой — потом будет придумывать, как котлеты с мухами не мешать.
Не нравится мне решение — не изящное и не простое.
Кроме того, что это решение, что MIGX предполагает одинаковый алгоритм — сначала делаем нечто, а только потом пользователь где-то что-то нажимает и картинки прикрепляет. И пользователю, что в первом случае, что во втором — знаний нужно одинаковое количество.
Но я, конечно же, не объективен — MIGX у меня всегда и везде, что называется, на кончиках пальцев. Так что это сугубо персональное и необъективное мнение. :)
avatar
Знаете, с другим бы спорил и может что-то доказывал :), но так как я знаю. что вы ФАНАТ MIGX — отступаю.
Думаю каждый будет решать, что ему и куда пихать. от этого, как вы выше написали, конечный результат будет одинаковый.
avatar
Очень было бы удобно к этому решению мультивыбор картинок
а то если картинок прикрепляют больше 4-5 то удобней было бы сразу выбрать все
avatar
Тоже правильно, нужно менеджер подшаманить
avatar
если к этому добавить еще и название картинки то это решает вопрос галлереи на процентов 90%
тоесть все простенькие галереи делаются на раз )

давно хочу прикрутить для EVO к multiPhoto но красиво пока так и не получилось (
avatar
Названия тоже нужно сделать
avatar
Странно, н оу меня категорически не заводится 0_о
avatar
чёт всё сырое/недопиленное сильно.
Пример сниппета [[getImages]]
Как сделать что бы по id страницы цеплялось? Мне вот надоть в чанке вызывать в getResources к примеру

В плагине шаблон жёстко прописан.

поправь, пожалуйста, я то разбирусь, а кто менее опытные врядли.
avatar
Я просто оставлю это здесь
Вызов сниппета
[[!getResImage?
&id=`[[+id]]`
&tpl=`Имя чанка для строки вывода`
&pathPhdr=`имя плейсхолдера куда сохраняем путь к картинке`
]]

Чуть-чуть допиленный сниппет вывода кортинок ресурса

<?
$res = $modx->getObject('modResource', $id);

$images = $res->getProperties('images');

$site_url = $modx->getOption('site_url');

$output = '';
if (count($images) > 0) {
    foreach ($images as $img) {

		$output .=$modx->getChunk($tpl,array($pathPhdr => $site_url.$img));
    }
}
return $output;

Комментарий отредактирован 2013-04-12 06:04:16 пользователем SurRealistik
avatar
Здравствуйте!
Это супер штука, но как сделать такой TV?
Просто я создал новый плагин, залил 2 js файла, создал сниппет getimage.
Но как это всё собрать в TV?
Правда, мне очень нужно это решение)
Это просто мега супер штука для доп.фото)
avatar
Можно и к TV прикрутить, как поправлюсь постараюсь написать
avatar
если к этому добавить еще и название картинки
и еще превью загружаемых картинок
avatar
Названия я уже сделал, только не выкладывал в сообщество
avatar
может поделитесь? а то решение очень уж приятное.
А городить MIGx ради пары дополнительных фото считаю излишеством
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.