Alex

Alex

С нами с 02 января 2017; Место в рейтинге пользователей: #262
Alex
20 октября 2017, 22:37
0
Александр. У меня тоже переодически выскакивает эта же ошибка на open server, на самом деле, лично для меня, она особого дискомфорта не создает. На рабочих проектах подобной ошибки никогда не наблюдал.
Alex
07 октября 2017, 16:15
0
Возможно. Я с битриксом никогда не сталкивался, поэтому сказать ничего не могу. Свой личный магазин я сделал на MODX, но обязательно буду съезжать, скорее всего на Ларку.
Alex
06 октября 2017, 21:19
0
Да, на самом деле так и есть. Практически одинаковый результат можно получить что за 10к, что за 2к. Таковы суровые реалии. Действительно, 95% заказчиков, а то и все 99% вообще не интересует, что там внутри и как это сделано, главное чтобы работало и, снова таки, они в чем-то правы. Если у них не сложный и не большой магазин, то разницы они практически не почувствуют, а вот финансовая разница ощутима. А те заки, которым важно как это работает и у них большие сложные сайты не делают магазины на MODX и сомневаюсь что пользуются услугами фрилансеров. Так что дешевле не всегда хуже. Некоторые местные гуру-модекс-программисты такую лажу продают в модсторе, что просто жесть.
Alex
03 октября 2017, 13:18
0
На счет двух вызовов не знаю, не сталкивался. Вам подойдет для разделения на десктоп и мобильный дополнение mobileDetect.
Еще, если мне не изменяет память, дополнение msMinicartDynamic не пересчитывает динамически полную сумму корзины, поэтому я для пересчета итоговой суммы оставил логику стандартной корзины. Вот код как у меня выглядит миникорзина.
<div id="msCart" class="modal-wrap">
    <div class="full-cart-msg not_empty">
        {$_modx->runSnippet('!msMiniCartDynamic', [
            'tplOuter' => 'minicartModalOuter.tpl',
            'tpl' => 'minicartModalRow.tpl',
            'img' => 'small'
        ])}
    </div>
    <div class="minicart-full-info">
        {'ms2_minicart_goods' | lexicon} <strong class="ms2_total_count">{$total_count}</strong> {'ms2_frontend_count_unit' | lexicon},
        {'ms2_minicart_cost' | lexicon} <strong class="ms2_total_cost">{$total_cost}</strong> грн.
    </div>
    <div class="clr"></div>
</div>
Скорее всего вы что-то не правильно сделали. Попробуйте сделать точно по документации. Прямо один в один.
Alex
02 октября 2017, 23:42
+1
Всунуть куда-то в код шаблона вот это
<script src="/assets/components/msminicartdynamic/js/web/msminicartdynamic.js"></script>
И миникорзина должна обновляться как положено.
UPD. Читайте внимательно описание компонента, там этот момент указан. Видимо по каким-то причинам автоматическая подгрузка скрипта не была реализована.
Alex
29 сентября 2017, 18:05
0
Еще актуально? Могу написать код.
Alex
29 сентября 2017, 17:55
+3
«один из основателей MODX Василий Наумкин». Вася один из основателей MODX? Я что-то пропустил???
Alex
30 августа 2017, 05:31
0
Такое бывает если название картинки на кириллице например.
Alex
29 августа 2017, 23:35
0
Здравствуйте. Есть небольшой баг в результате подсчета просмотренных товаров. Например, заходим с чистой сессией, смотрим один товар, потом другой, возвращаемся в предыдущий товар и вот тут «просмотренных товаров (2)», хотя выводится один, так как текущий товар исключается из результатов сниппета looked.
Alex
26 августа 2017, 20:27
0
Спасибо за ответ уже сам разобрался как и что, и… уже не актуально (наверно надо статус топика сменить). Тем более начал изучать Laravel, с MODX уже «наигрался».
Alex
25 августа 2017, 01:47
0
Расширить стандартный класс modDocument, написать свой пхп класс, коннекторы, процессор, который будет передавать нужные данные, процессоры для сохранения/обновления, оформить интерфейс в админке на extJs и тд тп. Всего-то. Тут вам 100% никто инструкцию не напишет как это сделать, потому что для того чтобы добавить «всего одно поле» в админку модекса, нужно написать немало кода. Можно еще через плагин затулить, это решение чуть проще, но не всегда подходит.
Alex
02 августа 2017, 16:26
-1
При таком количестве товаров остро встает вопрос по управлению всем этим делом в админке. Также в дальнейшем проекту может понадобиться какой-то дополнительный функционал и также встанет вопрос о его внедрении. Считаю что над этими вопросами уже стоит задуматься и прикинуть подходит ли MODX.
Alex
31 июля 2017, 10:00
0
Разобрался самостоятельно, все что хотел сделал. Всем спасибо за ответы.
Alex
30 июля 2017, 07:44
0
Спасибо большое за подсказку. Что то я это место упустил из виду. Надо попробовать. Не подскажете какая функция в extJs подхватывает $data? Это не оно Scrapx.utils.renderActions = function…?
Alex
30 июля 2017, 00:59
+1
Спасибо, разберусь. Нахрена код копирую? Ну вы же не экстрасенс чтобы знать что я там понаписал. Или лучше на пальцах объяснять? Ну вам виднее.
Alex
30 июля 2017, 00:50
0
Спасибо за совет. Я уже «вкурил» что есть основная таблица defaul.grid.js а от нее наследуется order.grid.js. Сложно так вот сразу понять схему работы всего этого дела. Также понял как работает вот это из отдельного файла:

miniShop2.utils.renderActions = function (value, props, row) {
    var res = [];
    var cls, icon, title, action, item = '';
    for (var i in row.data.actions) {
        if (!row.data.actions.hasOwnProperty(i)) {
            continue;
        }
        var a = row.data.actions[i];
        if (!a['button']) {
            continue;
        }

        icon = a['icon'] ? a['icon'] : '';
        if (typeof(a['cls']) == 'object') {
            if (typeof(a['cls']['button']) != 'undefined') {
                icon += ' ' + a['cls']['button'];
            }
        }
        else {
            cls = a['cls'] ? a['cls'] : '';
        }
        action = a['action'] ? a['action'] : '';
        title = a['title'] ? a['title'] : '';

        item = String.format(
            '<li class="{0}"><button class="btn btn-default {1}" action="{2}" title="{3}"></button></li>',
            cls, icon, action, title
        );

        res.push(item);
    }

    return String.format(
        '<ul class="minishop2-row-actions">{0}</ul>',
        res.join('')
    );
};
То есть надо написать так (ну это я так понял, может и не так):

Ext.namespace('Scrapx.utils'); // вот это я так понимаю указывает что мы расширяем пространство имен

// и тут уже можно писать рендерер
Scrapx.utils.renderActions = function (value, props, row) {
    var res = [];
    var cls, icon, title, action, item = '';
    for (var i in row.data.actions) {
        if (!row.data.actions.hasOwnProperty(i)) {
            continue;
        }
        var a = row.data.actions[i];
        if (!a['button']) {
            continue;
        }

        icon = a['icon'] ? a['icon'] : '';
        if (typeof(a['cls']) == 'object') {
            if (typeof(a['cls']['button']) != 'undefined') {
                icon += ' ' + a['cls']['button'];
            }
        }
        else {
            cls = a['cls'] ? a['cls'] : '';
        }
        action = a['action'] ? a['action'] : '';
        title = a['title'] ? a['title'] : '';

        item = String.format(
            '<li class="{0}"><button class="btn btn-default {1}" action="{2}" title="{3}"></button></li>',
            cls, icon, action, title
        );

        res.push(item);
    }

    return String.format(
        '<ul class="minishop2-row-actions">{0}</ul>',
        res.join('')
    );
};
Добавляем в файле core/components/scrapx/controllers/default/scrapxpresets.class.php:

$this->addJavascript($this->scrapx->config['jsUrl'].'mgr/widgets/utils.js');
Теперь я вызываю у себя в файле assets/components/scrapx/js/mgr/widgets/scrapxpresets.grid.js рендерер вот так:

{
	header:_('scrapx.header_actions')
	,dataIndex: 'actions'
	,sortable: true
	,renderer: Scrapx.utils.renderActions
				
}
И он работает.

В вашем файле core/componenets/minishop2/processors/mgr/orders/getlist.php есть такая функция, которая как мне показалось отвечает за вызов собственно кнопок действий:

public function prepareArray(array $data)
    {
        if (empty($data['customer'])) {
            $data['customer'] = $data['customer_username'];
        }

        $data['status'] = '<span style="color:#' . $data['color'] . ';">' . $data['status'] . '</span>';
        unset($data['color']);

        if (isset($data['cost'])) {
            $data['cost'] = $this->ms2->formatPrice($data['cost']);
        }
        if (isset($data['cart_cost'])) {
            $data['cart_cost'] = $this->ms2->formatPrice($data['cart_cost']);
        }
        if (isset($data['delivery_cost'])) {
            $data['delivery_cost'] = $this->ms2->formatPrice($data['delivery_cost']);
        }
        if (isset($data['weight'])) {
            $data['weight'] = $this->ms2->formatWeight($data['weight']);
        }

        $data['actions'] = array(
            array(
                'cls' => '',
                'icon' => 'icon icon-edit',
                'title' => $this->modx->lexicon('ms2_menu_update'),
                'action' => 'updateOrder',
                'button' => true,
                'menu' => true,
            ),
            array(
                'cls' => array(
                    'menu' => 'red',
                    'button' => 'red',
                ),
                'icon' => 'icon icon-trash-o',
                'title' => $this->modx->lexicon('ms2_menu_remove'),
                'multiple' => $this->modx->lexicon('ms2_menu_remove_multiple'),
                'action' => 'removeOrder',
                'button' => true,
                'menu' => true,
            ),
            /*
            array(
                'cls' => '',
                'icon' => 'icon icon-cog actions-menu',
                'menu' => false,
                'button' => true,
                'action' => 'showMenu',
                'type' => 'menu',
            ),
            */
        );

        return $data;
    }
Я у себя в файле core/components/scrapx/processors/mgr/scrapxpresets/getlist.class.php добавил вот так:

<?php
class ScrapxPresetsGetListProcessor extends modObjectGetListProcessor {
    public $languageTopics = array('scrapx:scrapxpresets');
    public $classKey = 'ScrapxPresets';
    public $defaultSortField = 'id';
    public $defaultSortDirection = 'ASC';
    public $checkListPermission = true;
    public function prepareQueryBeforeCount(xPDOQuery $c) {
        $query = $this->getProperty('query');
        if (!empty($query)) {
            $c->where(array('name:LIKE' => '%'.$query.'%'));
        }
        return $c;
    }

    /**
     * @param array $data
     *
     * @return array
     */
    public function prepareArray(array $data){
        $data['actions'] = array(
            array(
                'cls' => '',
                'icon' => 'icon icon-edit',
                'title' => $this->modx->lexicon('scrapx.scrapping'),
                'action' => 'scrapping',
                'button' => true,
                'menu' => true,
            ),
        );

        return $data;
    }
}
return 'ScrapxPresetsGetListProcessor';
Но никакие кнопки в таблице пока не появились. Пока не разобрался что делать дальше.
В месте где должны быть кнопки в таблице у меня выводится обертка

<ul class="minishop2-row-actions"></ul>
Но пунктов никаких нет. Вот теперь думаю как передать правильно туда данные… вообще не пойму пока что делать дальше. Изучаю ваши исходники минишопа и экспериментирую методом тыка…
Alex
29 июля 2017, 18:39
0
У меня что-то рендер не хочет работать если его поместить в отдельный файл как в минишопе, сделал так.
Scrapx.grid.ScrapxPresets = function(config) {
    config = config || {};
    Ext.applyIf(config,{
        id: 'scrapx-grid-scrapxpresets'
        ,url: Scrapx.config.connectorUrl
        ,baseParams: { action: 'mgr/scrapxpresets/getList' }
        ,fields: ['id','home_url','scrap_url','resource_class','category_id','actions']
        ,paging: true
        ,remoteSort: true
        ,anchor: '97%'
        ,autoExpandColumn: 'name'
        ,save_action: 'mgr/scrapxpresets/updateFromGrid'
        ,autosave: true
        ,columns: [{
				header:_('scrapx.header_id')
				,dataIndex: 'id'
				,sortable: true
				,hidden: true
			},{
				header:_('scrapx.header_home_url')
				,dataIndex: 'home_url'
				,sortable: true
				,editor: {
					xtype: 'textfield'
				}
			},{
				header:_('scrapx.header_scrap_url')
				,dataIndex: 'scrap_url'
				,sortable: true
				,editor: {
					xtype: 'textfield'
				}
			},{
				header:_('scrapx.header_resource_class')
				,dataIndex: 'resource_class'
				,sortable: true
				,editor: {
					xtype: 'modx-combo-class-derivatives'
				}
                ,fieldLabel: _('resource_type')
                ,description: '<b>[[*class_key]]</b><br />'
                ,name: 'class_key'
                ,hiddenName: 'class_key'
                ,id: 'modx-resource-class-key'
                ,anchor: '100%'
			},{
				header:_('scrapx.header_category_id')
				,dataIndex: 'category_id'
				,sortable: true
				,editor: {
					xtype: 'numberfield'
				}
			},{
				//header:_('scrapx.header_actions')
				
                dataIndex: 'actions',
                id: 'actions',
                width: 195,
                sortable: false,
                fixed: true,
                width: 150,
                renderer: this.renderActions

			}],tbar:[{
             text: '<i class="icon icon-clipboard"></i>  ' + _('scrapx.btn_create')


            ,handler: { xtype: 'scrapx-window-scrapxpresets-create' ,blankValues: true }
            },'->',{
            xtype: 'textfield'
            ,name: 'search'
            ,id: 'scrapx-search-filter'
            ,emptyText: _('scrapx.search')+'...'
            ,listeners: {
                'change': {fn:this.search,scope:this}
                ,'render': {fn: function(cmp) {
                    new Ext.KeyMap(cmp.getEl(), {
                        key: Ext.EventObject.ENTER
                        ,fn: function() {
                            this.fireEvent('change',this);
                            this.blur();
                            return true;
                        }
                        ,scope: cmp
                    });
                },scope:this}
            }
        },{
            xtype: 'button'
            ,id: 'scrapx-filter-clear'
            ,text: _('scrapx.filter_clear')
            ,listeners: {
                'click': {fn: this.clearFilter, scope: this}
            }
        }]


        ,getMenu: function() {
            return [{
                text: _('scrapx.menu.edit')
                ,handler: this.editScrapxPresets
            },'-',{
                text: _('scrapx.menu.remove')
                ,handler: this.removeScrapxPresets
            }];
        },editScrapxPresets: function(btn,e) {
            if (!this.editScrapxPresetsWindow) {
                this.editScrapxPresetsWindow = MODx.load({
                    xtype: 'scrapx-window-scrapxpresets-edit'
                    ,record: this.menu.record
                    ,listeners: {
                        'success': {fn:this.refresh,scope:this}
                    }
                });
            }
            this.editScrapxPresetsWindow.setValues(this.menu.record);
            this.editScrapxPresetsWindow.show(e.target);
        },removeScrapxPresets: function() {
            MODx.msg.confirm({
                title: _('scrapx.title.win_remove')
                ,text: _('scrapx.confirm.remove')
                ,url: this.config.url
                ,params: {
                    action: 'mgr/scrapxpresets/remove'
                    ,id: this.menu.record.id
                }
                ,listeners: {
                    'success': {fn:this.refresh,scope:this}
                }
            });
        }

    });
    Scrapx.grid.ScrapxPresets.superclass.constructor.call(this,config)
};
Ext.extend(Scrapx.grid.ScrapxPresets,MODx.grid.Grid,{
    search: function(tf,nv,ov) {
        var s = this.getStore();
        s.baseParams.query = tf.getValue();
        this.getBottomToolbar().changePage(1);
        this.refresh();
    }
    ,clearFilter: function() {
        var s = this.getStore();
        s.baseParams.search = '';
        Ext.getCmp('scrapx-search-filter').reset();
        this.getBottomToolbar().changePage(1);
        this.refresh();
    },
    renderActions:  function (value, props, row) {
    var res = [];
    var cls, icon, title, action, item;
    if (typeof(value) == 'object') {
        for (var i in value) {
            if (!value.hasOwnProperty(i)) {
                continue;
            }
            var a = value[i];
            if (!a['button']) {
                continue;
            }

            icon = a['icon'] ? a['icon'] : '';
            if (typeof(a['cls']) == 'object') {
                if (typeof(a['cls']['button']) != 'undefined') {
                    icon += ' ' + a['cls']['button'];
                }
            } else {
                cls = a['cls'] ? a['cls'] : '';
            }
            action = a['action'] ? a['action'] : '';
            title = a['title'] ? a['title'] : '';

            item = String.format(
                '<li class="{0}"><button class="btn btn-default {1}" action="{2}" title="{3}"></button></li>',
                cls, icon, action, title
            );

            res.push(item);
        }
    }

    return String.format(
        '<ul class="xp-row-actions">{0}</ul>',
        res.join('')
    );
}
});
Ext.reg('scrapx-grid-scrapxpresets',Scrapx.grid.ScrapxPresets);

Scrapx.window.EditScrapxPresets = function(config) {
    config = config || {};
    var self = this;
    Ext.applyIf(config,{
        title: _('scrapx.title.win_edit')
        ,url: Scrapx.config.connectorUrl
        ,autoHeight: true
        ,modal: true
        ,baseParams: {
            action: 'mgr/scrapxpresets/update'
        }
        ,fields: [{
				xtype: 'hidden'
				,name: 'id'
			},{
				xtype: 'textarea'
				,fieldLabel: _('scrapx.label_home_url')
				,description: '<b>[[*home_url]]</b><br />'+_('scrapx.label_home_url_help')
				,name: 'home_url'
				,allowBlank:false
				,anchor: '100%'
			},{
				xtype: 'textarea'
				,fieldLabel: _('scrapx.label_scrap_url')
				,description: '<b>[[*scrap_url]]</b><br />'+_('scrapx.label_scrap_url_help')
				,name: 'scrap_url'
				,allowBlank:false
				,anchor: '100%'
			},{
				xtype: 'textfield'
				,fieldLabel: _('scrapx.label_resource_class')
				,description: '<b>[[*resource_class]]</b><br />'+_('scrapx.label_resource_class_help')
				,name: 'resource_class'
				,allowBlank:false
				,anchor: '100%'
			},{
				xtype: 'numberfield'
				,fieldLabel: _('scrapx.label_category_id')
				,description: '<b>[[*category_id]]</b><br />'+_('scrapx.label_category_id_help')
				,name: 'category_id'
				,allowBlank:false
				,anchor: '100%'
			}]
    });
    Scrapx.window.EditScrapxPresets.superclass.constructor.call(this,config);
};
Ext.extend(Scrapx.window.EditScrapxPresets,MODx.Window,{});
Ext.reg('scrapx-window-scrapxpresets-edit',Scrapx.window.EditScrapxPresets);


Scrapx.window.CreateScrapxPresets = function(config) {
    config = config || {};
    var self = this;
    Ext.applyIf(config,{
        title: _('scrapx.title.win_create')
        ,url: Scrapx.config.connectorUrl
        ,autoHeight:true
        ,modal: true
        ,baseParams: {
            action: 'mgr/scrapxpresets/create'
        }
        ,fields: [{
				xtype: 'hidden'
				,name: 'id'
			},{
				xtype: 'textarea'
				,fieldLabel: _('scrapx.label_home_url')
				,description: '<b>[[*home_url]]</b><br />'+_('scrapx.label_home_url_help')
				,name: 'home_url'
				,allowBlank:false
				,anchor: '100%'
			},{
				xtype: 'textarea'
				,fieldLabel: _('scrapx.label_scrap_url')
				,description: '<b>[[*scrap_url]]</b><br />'+_('scrapx.label_scrap_url_help')
				,name: 'scrap_url'
				,allowBlank:false
				,anchor: '100%'
			},{
				xtype: 'textfield'
				,fieldLabel: _('scrapx.label_resource_class')
				,description: '<b>[[*resource_class]]</b><br />'+_('scrapx.label_resource_class_help')
				,name: 'resource_class'
				,allowBlank:false
				,anchor: '100%'
			},{
				xtype: 'numberfield'
				,fieldLabel: _('scrapx.label_category_id')
				,description: '<b>[[*category_id]]</b><br />'+_('scrapx.label_category_id_help')
				,name: 'category_id'
				,allowBlank:false
				,anchor: '100%'
			}]
    });
    Scrapx.window.CreateScrapxPresets.superclass.constructor.call(this,config);
};
Ext.extend(Scrapx.window.CreateScrapxPresets,MODx.Window);
Ext.reg('scrapx-window-scrapxpresets-create',Scrapx.window.CreateScrapxPresets);
Обертка для кнопок появляется в разметке, а вот кнопок нет. Значит их надо откуда-то передать. Смотрим getList процессор минишопа, там есть вот такая функция:

/**
     * @param array $data
     *
     * @return array
     */
    public function prepareArray(array $data)
    {
        if (empty($data['customer'])) {
            $data['customer'] = $data['customer_username'];
        }

        $data['status'] = '<span style="color:#' . $data['color'] . ';">' . $data['status'] . '</span>';
        unset($data['color']);

        if (isset($data['cost'])) {
            $data['cost'] = $this->ms2->formatPrice($data['cost']);
        }
        if (isset($data['cart_cost'])) {
            $data['cart_cost'] = $this->ms2->formatPrice($data['cart_cost']);
        }
        if (isset($data['delivery_cost'])) {
            $data['delivery_cost'] = $this->ms2->formatPrice($data['delivery_cost']);
        }
        if (isset($data['weight'])) {
            $data['weight'] = $this->ms2->formatWeight($data['weight']);
        }

        $data['actions'] = array(
            array(
                'cls' => '',
                'icon' => 'icon icon-edit',
                'title' => $this->modx->lexicon('ms2_menu_update'),
                'action' => 'updateOrder',
                'button' => true,
                'menu' => true,
            ),
            array(
                'cls' => array(
                    'menu' => 'red',
                    'button' => 'red',
                ),
                'icon' => 'icon icon-trash-o',
                'title' => $this->modx->lexicon('ms2_menu_remove'),
                'multiple' => $this->modx->lexicon('ms2_menu_remove_multiple'),
                'action' => 'removeOrder',
                'button' => true,
                'menu' => true,
            ),
            /*
            array(
                'cls' => '',
                'icon' => 'icon icon-cog actions-menu',
                'menu' => false,
                'button' => true,
                'action' => 'showMenu',
                'type' => 'menu',
            ),
            */
        );

        return $data;
    }
Вот это нас не интересует:

if (empty($data['customer'])) {
            $data['customer'] = $data['customer_username'];
        }

        $data['status'] = '<span style="color:#' . $data['color'] . ';">' . $data['status'] . '</span>';
        unset($data['color']);

        if (isset($data['cost'])) {
            $data['cost'] = $this->ms2->formatPrice($data['cost']);
        }
        if (isset($data['cart_cost'])) {
            $data['cart_cost'] = $this->ms2->formatPrice($data['cart_cost']);
        }
        if (isset($data['delivery_cost'])) {
            $data['delivery_cost'] = $this->ms2->formatPrice($data['delivery_cost']);
        }
        if (isset($data['weight'])) {
            $data['weight'] = $this->ms2->formatWeight($data['weight']);
        }
Значит оставляем примерно так:
/**
     * @param array $data
     *
     * @return array
     */
    public function prepareArray(array $data){
        $data['actions'] = array(
            array(
                'cls' => '',
                'icon' => 'icon icon-edit',
                'title' => $this->modx->lexicon('scrapx.action_parse'),
                'action' => 'getScraping',
                'button' => true,
                'menu' => true,
            ),
        );

        return $data;
    }
Но вот это $data['actions'] тоже надо откуда то взять в процессоре… Блин как все запутано. Может я вообще нет так делаю?:)
Alex
29 июля 2017, 16:45
0
Изучая исходники минишопа я понял что рендер для кнопок находится в js/mgr/misc/ms2.utils.js
Вот он:
miniShop2.utils.renderActions = function (value, props, row) {
    var res = [];
    var cls, icon, title, action, item = '';
    for (var i in row.data.actions) {
        if (!row.data.actions.hasOwnProperty(i)) {
            continue;
        }
        var a = row.data.actions[i];
        if (!a['button']) {
            continue;
        }

        icon = a['icon'] ? a['icon'] : '';
        if (typeof(a['cls']) == 'object') {
            if (typeof(a['cls']['button']) != 'undefined') {
                icon += ' ' + a['cls']['button'];
            }
        }
        else {
            cls = a['cls'] ? a['cls'] : '';
        }
        action = a['action'] ? a['action'] : '';
        title = a['title'] ? a['title'] : '';

        item = String.format(
            '<li class="{0}"><button class="btn btn-default {1}" action="{2}" title="{3}"></button></li>',
            cls, icon, action, title
        );

        res.push(item);
    }

    return String.format(
        '<ul class="minishop2-row-actions">{0}</ul>',
        res.join('')
    );
};
Но что с ним дальше делать непонятно…
Alex
29 июля 2017, 16:30
0
Смотрел, не могу разобраться. Я в extJS совсем зеленый.
Alex
28 июля 2017, 02:50
0
А что в чанке tpl.msProducts.row2?