Unverified Commit d77f9a68 authored by Alex Pott's avatar Alex Pott
Browse files

Issue #2979044 by BR0kEN, alexpott: Unable to change menu items weight when...

Issue #2979044 by BR0kEN, alexpott: Unable to change menu items weight when the "system.site.weight_select_max" exceeded and "#pre_render" for "number" element is modified

(cherry picked from commit d90d0ebb)
parent b2af74b6
Loading
Loading
Loading
Loading
+6 −10
Original line number Diff line number Diff line
@@ -45,16 +45,16 @@ public function getInfo() {
  }

  /**
   * Expands a weight element into a select element.
   * Expands a weight element into a select/number element.
   */
  public static function processWeight(&$element, FormStateInterface $form_state, &$complete_form) {
    // If the number of options is small enough, use a select field. Otherwise,
    // use a number field.
    $type = $element['#delta'] <= \Drupal::config('system.site')->get('weight_select_max') ? 'select' : 'number';
    $element = array_merge($element, \Drupal::service('element_info')->getInfo($type));
    $element['#is_weight'] = TRUE;

    $element_info_manager = \Drupal::service('element_info');
    // If the number of options is small enough, use a select field.
    $max_elements = \Drupal::config('system.site')->get('weight_select_max');
    if ($element['#delta'] <= $max_elements) {
      $element['#type'] = 'select';
    if ($type === 'select') {
      $weights = [];
      for ($n = (-1 * $element['#delta']); $n <= $element['#delta']; $n++) {
        $weights[$n] = $n;
@@ -65,14 +65,10 @@ public static function processWeight(&$element, FormStateInterface $form_state,
        ksort($weights);
      }
      $element['#options'] = $weights;
      $element += $element_info_manager->getInfo('select');
    }
    // Otherwise, use a text field.
    else {
      $element['#type'] = 'number';
      // Use a field big enough to fit most weights.
      $element['#size'] = 10;
      $element += $element_info_manager->getInfo('number');
    }

    return $element;
+5 −0
Original line number Diff line number Diff line
name: 'Element info test'
type: module
package: Testing
version: VERSION
core: 8.x
+24 −0
Original line number Diff line number Diff line
<?php

/**
 * @file
 * Element info test.
 */

/**
 * Implements hook_element_info_alter().
 */
function element_info_test_element_info_alter(array &$info) {
  $info['number'] += ['#pre_render' => []];
  /* @see \Drupal\KernelTests\Core\Render\Element\WeightTest::testProcessWeightSelectMax() */
  $info['number']['#pre_render'][] = 'element_info_test_element_pre_render';
}

/**
 * {@inheritdoc}
 *
 * @see \Drupal\KernelTests\Core\Render\Element\WeightTest::testProcessWeightSelectMax()
 */
function element_info_test_element_pre_render(array $element) {
  return $element;
}
+75 −1
Original line number Diff line number Diff line
@@ -3,6 +3,8 @@
namespace Drupal\KernelTests\Core\Render\Element;

use Drupal\Core\Form\FormState;
use Drupal\Core\Render\Element\Number;
use Drupal\Core\Render\Element\Select;
use Drupal\Core\Render\Element\Weight;
use Drupal\KernelTests\KernelTestBase;

@@ -15,7 +17,7 @@ class WeightTest extends KernelTestBase {
  /**
   * {@inheritdoc}
   */
  protected static $modules = ['system'];
  protected static $modules = ['system', 'element_info_test'];

  /**
   * {@inheritdoc}
@@ -49,4 +51,76 @@ public function testProcessWeight() {
    );
  }

  /**
   * Test transformation from "select" to "number" for MAX_DELTA + 1.
   *
   * @throws \Exception
   *
   * @covers ::processWeight
   */
  public function testProcessWeightSelectMax() {
    $form_state = new FormState();
    $definition = [
      '#type' => 'weight',
      '#delta' => $this->container
        ->get('config.factory')
        ->get('system.site')
        ->get('weight_select_max'),
      // Expected by the "doBuildForm()" method of "form_builder" service.
      '#parents' => [],
    ];

    $assert = function ($type, array $element, array $expected) use ($form_state) {
      // Pretend we have a form to trigger the "#process" callbacks.
      $element = $this->container
        ->get('form_builder')
        ->doBuildForm(__FUNCTION__, $element, $form_state);

      $expected['#type'] = $type;

      foreach ($expected as $property => $value) {
        static::assertSame($value, $element[$property]);
      }

      return $element;
    };

    // When the "#delta" is less or equal to maximum the "weight" must be
    // rendered as a "select".
    $select = $definition;
    $assert('select', $select, [
      '#process' => [
        [Select::class, 'processSelect'],
        [Select::class, 'processAjaxForm'],
      ],
      '#pre_render' => [
        [Select::class, 'preRenderSelect'],
      ],
    ]);

    $number = $definition;
    // Increase "#delta" in order to start rendering "number" elements
    // instead of "select".
    $number['#delta']++;
    // The "number" element definition has the "#pre_render" declaration by
    // default. The "hook_element_info_alter()" allows to modify the definition
    // of an element. We must be sure the standard "#pre_render" callbacks
    // are presented (unless explicitly removed) even in a case when the array
    // is modified by the alter hook.
    $assert('number', $number, [
      '#process' => [
        [Number::class, 'processAjaxForm'],
      ],
      '#element_validate' => [
        [Number::class, 'validateNumber'],
      ],
      '#pre_render' => [
        [Number::class, 'preRenderNumber'],
        // The custom callback is appended.
        /* @see element_info_test_element_info_alter() */
        'element_info_test_element_pre_render',
      ],
    ]);
  }

}