Drupal: перетаскиваемый стол родитель-ребенок - PullRequest
4 голосов
/ 22 октября 2011

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

Category 1
|
|--Item 1
|--Item 2
Category 2
|
|--Item 3
|--Item 4
|--Item 5

Я хотел бы иметь возможность сортировать элементы 1 и 2 друг с другом, а также элементы 3, 4 и 5 друг с другом, но не перемещать их между категориями.1 и Категория 2. Мне также нужно иметь возможность сортировать категории 1 и 2 друг с другом, забирая детей с собой.Я прошел через множество комбинаций настроек $action, $group, $subgroup, смешанных с настройками $class для категорий и элементов, которые я потерял.Ничто из того, что я пробовал до сих пор, не дало желаемого результата.Вот соответствующие биты моего кода в том виде, в котором он есть на данный момент:

В моей форме:

$form['#tree'] = true;
foreach($categories as $cat) {
    if(!isset($form['categories'][$cat->cid])){
        $form['categories'][$cat->cid] = array(
            'weight' => array(
                '#type'         => 'weight',
                '#delta'        => 25,
                '#attributes'   => array('class' => array('item-weight', 'item-weight-' . $cat->cid)),
            ),
            'cid' => array(
                '#type'         => 'hidden',
                '#value'        => $cat->cid,
                '#attributes'   => array('class' => array('cid')),
            ),
        );
        foreach($cats[$cat->cid] as $item) {
            $form['categories'][$cat->cid]['items'][$item->id] = array(
                'weight' => array(
                    '#type'         => 'weight',
                    '#delta'        => 25,
                    '#default_value'=> $item->weight,
                    '#attributes'   => array('class' => array('item-weight', 'item-weight-' . $cat->cid)),
                ),
                'cid' => array(
                    '#type'         => 'hidden',
                    '#value'        => $cat->cid,
                    '#attributes'   => array('class' => array('cid')),
                ),
            );
        }
    }
}

В моей теме:

$children = element_children($form['categories']);
$rows = array();
if(count($children) > 0) {
    foreach($children as $cid) {
        $row = array(
            drupal_render($form['categories'][$cid]['weight']) .
                drupal_render($form['categories'][$cid]['cid']),
        );

        $rows[] = array(
            'data' => $row,
            'class' => array('draggable', 'tabledrag-root'),
        );
        foreach(element_children($form['categories'][$cid]['items']) as $id) {
            $row = array(
                theme('indentation', array('size' => 1)) . drupal_render($form['categories'][$cid]['items'][$id]['name']),
                drupal_render($form['categories'][$cid]['items'][$id]['weight']) .
                    drupal_render($form['categories'][$cid]['items'][$id]['cid']),
            );

            $rows[] = array(
                'data' => $row,
                'class' => array('draggable', 'tabledrag-leaf'),
            );
        }
        drupal_add_tabledrag('cat-table', 'order', 'sibling', 'item-weight', 'item-weight-' . $cid);
    }
}


drupal_add_tabledrag('cat-table', 'match', 'parent', 'cid', 'cid', 'cid', true, 1);
$output = theme('table', array('header' => $headers, 'rows' => $rows, 'attributes' => array('id' => 'cat-table')));
$output .= drupal_render_children($form);
return $output;

Я прочитал болеедокументация для drupal_add_tabledrag(), просмотр кода, пример кода, поиск по drupal.org и Google, но ничего не найдено.

Мое единственное решение до сих пор - копировать и изменятьфайл tabledrag.js, чтобы просто исключить эти возможности, но, при этом, останавливая проблему с отступами для элементов (то есть не позволяя им относиться к тем же категориям), хранить их в одной категории было неинтересно.

Полагаю, самый важный вопрос: возможно ли использование стандартного Drupal?

Ответы [ 3 ]

0 голосов
/ 24 декабря 2013

Только что закончил добавлять эту функциональность в мой модуль

https://github.com/player259/ajax_table

Нет помощи, демоверсия устарела, но я время от времени работаю над ней

Поддержка разделов была достигнута путем переопределения функций tabledrag.js

Используйте этот фрагмент для вставки таблицы

$form['map'] = array(
  '#type' => 'ajax_table',
  '#header' => array(t('Element'), t('Settings'), t('Weight')),
  'rows' => array(),
  '#draggable' => array(
    // drupal_add_tabledrag will be called in theme layer
    // NULL first arg to apply to this table
    array(NULL, 'match', 'parent', 'perfect-form-parent', 'perfect-form-parent', 'perfect-form-index'),
    array(NULL, 'depth', 'group', 'perfect-form-depth', NULL, NULL, FALSE),
    array(NULL, 'order', 'sibling', 'perfect-form-weight'),
  ),
  '#draggable_groups' => array(),
);

foreach ($map as $i => $element) {

  // ... some logic

  $form['map']['rows'][$i] = array(
    'data' => array(
      'element' => array(),
      'settings' => array(),
      'tabledrag' => array(
        'index' => array(
          '#type' => 'hidden',
          '#value' => $element['data']['tabledrag']['index'],  
          '#attributes' => array('class' => array('perfect-form-index')),
        ),
        'parent' => array(
          '#type' => 'hidden',
          '#default_value' => $element['data']['tabledrag']['parent'],
          '#attributes' => array('class' => array('perfect-form-parent')),
        ),
        'depth' => array(
          '#type' => 'hidden',
          '#default_value' => $element['data']['tabledrag']['depth'],
          '#attributes' => array('class' => array('perfect-form-depth')),
        ),          
        'weight' => array(
          '#type' => 'weight',
          '#delta' => $max_weight,
          '#default_value' => $weight,
          '#attributes' => array('class' => array('perfect-form-weight')),
        ),
      ),
    ),
    '#attributes' => array('class' => array($row_class_current, $row_class_child)),
  );

  // This means that row with $row_class_child class could have as parent
  // only row with $row_class_parent class
  // NULL means root - there are no parents

  $form['map']['#draggable_groups'][$row_class_child] =
    $depth ? $row_class_parent : NULL;
}
0 голосов
/ 25 января 2016

У меня была похожая проблема на работе, поэтому выкладываю здесь свое решение, так как ни одно из найденных мною не работает правильно во всех ситуациях.Это сделано на 100% в javascript, на стороне php вам просто нужно установить tabledrag в соответствии с parent на pid и отсортировать по весу братьев и сестер.

Текущий код работает на примере модуля (tabledrag parent / child), чтобы адаптировать его к вашим потребностям, измените .example-item-pid вашим классом для поля ввода PID.Вам просто нужно добавить его в пример кода, чтобы он работал и посмотреть, соответствует ли он вашим потребностям.

Первая функция делает недействительной любую попытку отбросить элементы, у которых нет того же родителя (PID), что и уцелевой элемент.

Вторая функция обходит функцию dragRow, чтобы поместить элемент в правильное место (= последние дочерние элементы целевой строки) и на правильную глубину (= та же глубина, что и целевая строка).

/**
 * Invalidate swap check if the row target is not of the same parent
 * So we can only sort elements under the same parent and not move them to another parent
 *
 * @override Drupal.tableDrag.row.isValidSwap
 */
// Keep the original implementation - we still need it.
Drupal.tableDrag.prototype.row.prototype._isValidSwap = Drupal.tableDrag.prototype.row.prototype.isValidSwap;
Drupal.tableDrag.prototype.row.prototype.isValidSwap = function(row) {
  if (this.indentEnabled) {
    if (row && $('.example-item-pid', this.element).val() !== $('.example-item-pid', row).val()) {
      return false;
    }
  }

  // Return the original result.
  return this._isValidSwap(row);
}

/**
 * Position the dragged element under the last children of the element target for swapping when moving down our dragged element.
 * Removed the indentation, since we can not change parent.
 * @override Drupal.tableDrag.row.dragRow
 */
Drupal.tableDrag.prototype.dragRow = function (event, self) {
  if (self.dragObject) {
    self.currentMouseCoords = self.mouseCoords(event);

    var y = self.currentMouseCoords.y - self.dragObject.initMouseOffset.y;
    var x = self.currentMouseCoords.x - self.dragObject.initMouseOffset.x;

    // Check for row swapping and vertical scrolling.
    if (y != self.oldY) {
      self.rowObject.direction = y > self.oldY ? 'down' : 'up';
      self.oldY = y; // Update the old value.

      // Check if the window should be scrolled (and how fast).
      var scrollAmount = self.checkScroll(self.currentMouseCoords.y);
      // Stop any current scrolling.
      clearInterval(self.scrollInterval);
      // Continue scrolling if the mouse has moved in the scroll direction.
      if (scrollAmount > 0 && self.rowObject.direction == 'down' || scrollAmount < 0 && self.rowObject.direction == 'up') {
        self.setScroll(scrollAmount);
      }

      // If we have a valid target, perform the swap and restripe the table.
      var currentRow = self.findDropTargetRow(x, y);
      if (currentRow) {
        if (self.rowObject.direction == 'down') {

          /**
           * When going down we want to position the element after the last children and not right under the currentRow
           */
          // create a new row prototype with currentRow
          var rowObject = new self.row(currentRow, 'mouse', self.indentEnabled, self.maxDepth, false);
          // extract all children
          var childrenRows = rowObject.findChildren();
          // if we have children
          if (childrenRows.length > 0) {
            // we change the row to swap with the last children
            currentRow = childrenRows[childrenRows.length - 1];
          } 

          self.rowObject.swap('after', currentRow, self);
        }
        else {
          self.rowObject.swap('before', currentRow, self);
        }
        self.restripeTable();
      }
    }
    /**
     * We have disabled the indentation changes since it is not possible to change parent.
     */

    return false;
  }
};
0 голосов
/ 01 июня 2012

Я знаю, что вы уже проделали большую работу по кодированию, так что на этом этапе вы, возможно, не захотите отказываться от этого, но DraggableViews отлично подходит для этого. Вы можете настроить нормальное представление и добавить этот фильтр draggableviews, он добавляет вес и, необязательно, родительскую ссылку. Само представление использует ту же систему drag-n-drop, что и остальные бэкэнд-таблицы Drupal.

В качестве альтернативы вы можете использовать ссылку на термин и привязывать термины таксономии к узлам и просто использовать этот метод drag-n-drop.

Если я что-то упустил в ваших потребностях, мои извинения, просто подумал, что я бы предложил это более простое решение, поскольку оно определенно хорошо мне помогло в прошлом. Желаем удачи в любом случае.

...