Обработка элемента по клику в CMP ExtJS

Здравствуйте. Есть своя табличка CMP. Данные сохраняются, обновляются с этим проблем нет. Проблема в другом. Есть строка в таблице, в строке 5 колонок, id скрыто по умолчанию (его не считаем), название (текст), урл (текст), класс ресурса (варчар), шаблон (инт) и в конце этого дела есть кнопка. Так вот, кнопку я явно сделал не правильно, мне бы такую как в минишопе в таблице заказов, где редактировать, удалить и тд. Я как бы впиперил кнопку туда, но теперь ума не приложу как заставить ее работать.
Теперь основная суть вопроса: как по клику на кнопку передать id записи таблицы в процессор в виде переменной. То есть клик, айди попал в процессоре в переменную, и дальше я уже использую эту переменную для формирования нужного запроса и тд.
Alex
29 июля 2017, 03:35
modx.pro
2 614
0

Комментарии: 12

Володя
29 июля 2017, 08:53
+1
    Alex
    29 июля 2017, 16:30
    0
    Смотрел, не могу разобраться. Я в extJS совсем зеленый.
      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('')
          );
      };
      Но что с ним дальше делать непонятно…
        Володя
        29 июля 2017, 17:55
        0
        либо продолжать дальше вникать и понять что там нехватает, либо приложить код и возможно кто то подскажет что у вас не так…
          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'] тоже надо откуда то взять в процессоре… Блин как все запутано. Может я вообще нет так делаю?:)
      Василий Наумкин
      30 июля 2017, 00:18
      +1
      Вот здесь происходит распознавание клика по таблице.

      Туда прилетают любые клики, а дальше идёт проверка, по какому именно месту кликнули. Если это кнопка или ссылка — то идёт работа. Если нет, то событие пропускается дальше.

      Это — основная таблица элементов miniShop2, от неё наследуются все остальные, поэтому ты и не нашёл этот обработчик.
        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>
        Но пунктов никаких нет. Вот теперь думаю как передать правильно туда данные… вообще не пойму пока что делать дальше. Изучаю ваши исходники минишопа и экспериментирую методом тыка…
          Василий Наумкин
          30 июля 2017, 00:54
          0
          Да нахрена ж ты копируешь эти километровые куски кода?

          Даже читать не буду, разбирайся дальше сам.
            Alex
            30 июля 2017, 00:59
            +1
            Спасибо, разберусь. Нахрена код копирую? Ну вы же не экстрасенс чтобы знать что я там понаписал. Или лучше на пальцах объяснять? Ну вам виднее.
            Павел Гвоздь
            30 июля 2017, 07:36
            +1
            Обратите внимание на метод prepareArray, который вы используете в процессоре GetList. Он нигде не прописан у вас. У Василия же вот тут.
              Alex
              30 июля 2017, 07:44
              0
              Спасибо большое за подсказку. Что то я это место упустил из виду. Надо попробовать. Не подскажете какая функция в extJs подхватывает $data? Это не оно Scrapx.utils.renderActions = function…?
          Alex
          31 июля 2017, 10:00
          0
          Разобрался самостоятельно, все что хотел сделал. Всем спасибо за ответы.
            Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
            12