Source: controller.js

/**
 * Родительский "класс" для карточек, таблиц и фильтров
 */
var IrisController = Backbone.View.extend({

  render: function () {},

  events: {},

  /**
   * Запрос к серверу для построения пользовательского грида
   *
   * @param {Object} params Параметры для передачи на сервер.
   * Допустимые свойства:
   * * section - Код раздела, в котором расположен файл с серверной логикой
   * * class - Название класса с серверной логикой
   * * method - Название серверного обработчика
   * * [parameters] - Параметры для передачи на сервер. Эти параметры передаются
   * в серверный обработчик
   * * [properties] - Свойства грида
   * * onSelect - JS-обработчик выбора записи в гриде, который принимает 
   * id выбранной в гриде записи.
   *
   * Метод, указанный в свойстве method, должен возвращать ассоциативный массив
   * с элементами:
   * * Card - HTML карточки с пользовательским гридом
   * * GridId - Идентификатор грида
   * * Или Error - С текустом ошибки в случае ошибки.
   *
   * Для примера серверного обработчика см. config/sections/Task/c_task.php
   *
   * @example <caption>Выбор следующей цели из карточки дела</caption>
   * selectNextTarget: function() {
   *   var self = this;
   *   this.customGrid({
   *     section: 'Task',
   *     'class': 'c_Task',
   *     method: 'renderSelectRecordDialog',
   *     parameters: {
   *       taskid: this.parameter('id'),
   *       projectid: this.fieldValue('ProjectID'),
   *       targetid: this.fieldValue('TaskTargetID'),
   *       nexttargetid: this.fieldValue('NextTaskTargetID')
   *     },
   *     onSelect: function(record_id) {
   *       self.fieldValue('NextTaskTargetID', record_id);
   *     }
   *   });
   * },
   */
  customGrid: function(params) {
    var prop = params.properties;
    if (prop == null || prop == undefined) {
      prop = {};
    }
    if (prop.title == undefined) {
      prop.title = T.t('Выберите запись');
    }
    if (prop.width == undefined) {
      prop.width = 700;
    }
    if (prop.height == undefined) {
      prop.height = 350;
    }

    // Подготовка окна (чтобы оно уже было на экране)
    var data = {
      template_name: g_layout_params.STYLE_NAME,
      title: prop.title
    };

    var window_id = "wnd" + (Math.random() + "").slice(3);
    var win = new Window({
      id: window_id, 
      wiredDrag: g_layout_params.gridwnd_wiredDrag, 
      className: "iris_win", 
      title: _.template(jQuery('#card-title').html(), {data: data}),
      width: prop.width, 
      height: prop.height
    });

    win.getContent().innerHTML = _.template(
        jQuery('#card-loading').html(), {data: data});
    win.toFront();
    win.setZIndex(Windows.maxZIndex + 1);
    win.setDestroyOnClose();
    win.showCenter(0);

    // Запрос содердимого окна с сервера, там строится таблица
    Transport.request({
      section: params.section, //'Task', 
      'class': params['class'], //'c_Task', 
      method: params['method'], //'renderSelectRecordDialog', 
      parameters: params.parameters,
      onSuccess: function (transport) {
        var res = JSON.parse(transport.responseText).data;
        if (res.Error) {
          win.getContent().innerHTML = res.Error;
          return;
        }
        win.getContent().innerHTML = res.Card;
        // Растягивает таблицу на всю форму
        resizeGridWindow(win);
        // Передвинуть прокрутку на текущую запись
        SelectGridRow(res.GridId);

        jWindow = jQuery(win.getContent());

        var selectRecord = function() {
          var grid = jWindow.find('#' + res.GridId);
          var row_num = grid.attr('selectedrow');
          var record_id = grid.find('tr:eq(' + row_num + ')').attr('rec_id');
          if (params.onSelect != undefined) {
            params.onSelect(record_id);
          }
          win.close();
        };

        // Навешиваем обработчик на Ок - чтобы значение вернулось в карточку
        jWindow.find('.button_ok').on('click', selectRecord);
        jWindow.find('#' + res.GridId + ' tr').on('dblclick', selectRecord);
      }
    });
  }

});