summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwebchick2015-10-22 17:53:38 -0700
committerwebchick2015-10-22 17:53:38 -0700
commit5c5ceccc6ff111c2baeba9160d9052a3690240bc (patch)
tree68c2db06ed841de077274e99929db73be7cf4c6e
parenta9247a53f2bf9257863511c9003039d044bc431a (diff)
Issue #1938900 by joelpittet, lokapujya, Cottser, lauriii, swentel, neochief, tstoeckler, andypost, duellj: Convert theme_field_ui_table into a template (DIE THEME FUNCTIONS DIE)
-rw-r--r--core/modules/field_ui/field_ui.module92
-rw-r--r--core/modules/field_ui/src/Element/FieldUiTable.php226
-rw-r--r--core/modules/field_ui/src/Form/EntityDisplayFormBase.php98
-rw-r--r--core/modules/field_ui/templates/field-ui-table.html.twig47
4 files changed, 291 insertions, 172 deletions
diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module
index 269aa67..56375fc 100644
--- a/core/modules/field_ui/field_ui.module
+++ b/core/modules/field_ui/field_ui.module
@@ -53,8 +53,17 @@ function field_ui_help($route_name, RouteMatchInterface $route_match) {
function field_ui_theme() {
return array(
'field_ui_table' => array(
- 'render element' => 'elements',
- 'function' => 'theme_field_ui_table',
+ 'variables' => array(
+ 'header' => NULL,
+ 'rows' => NULL,
+ 'footer' => NULL,
+ 'attributes' => array(),
+ 'caption' => NULL,
+ 'colgroups' => array(),
+ 'sticky' => FALSE,
+ 'responsive' => TRUE,
+ 'empty' => '',
+ ),
),
);
}
@@ -209,84 +218,17 @@ function field_ui_entity_form_mode_delete(EntityFormModeInterface $form_mode) {
}
/**
- * Returns HTML for Field UI overview tables.
+ * Prepares variables for field UI overview table templates.
*
- * @param $variables
+ * Default template: field-ui-table.html.twig.
+ *
+ * @param array $variables
* An associative array containing:
* - elements: An associative array containing a Form API structure to be
* rendered as a table.
- *
- * @ingroup themeable
*/
-function theme_field_ui_table($variables) {
- $elements = $variables['elements'];
- $table = array('#type' => 'table');
-
- // Add table headers and attributes.
- foreach (array('#header', '#attributes') as $key) {
- if (isset($elements[$key])) {
- $table[$key] = $elements[$key];
- }
- }
-
- // Determine the colspan to use for region rows, by checking the number of
- // columns in the headers.
- $columns_count = 0;
- foreach ($table['#header'] as $header) {
- $columns_count += (is_array($header) && isset($header['colspan']) ? $header['colspan'] : 1);
- }
-
- // Render rows, region by region.
- foreach ($elements['#regions'] as $region_name => $region) {
- $region_name_class = Html::getClass($region_name);
-
- // Add region rows.
- if (isset($region['title']) && empty($region['invisible'])) {
- $table['#rows'][] = array(
- 'class' => array('region-title', 'region-' . $region_name_class . '-title'),
- 'no_striping' => TRUE,
- 'data' => array(
- array('data' => $region['title'], 'colspan' => $columns_count),
- ),
- );
- }
- if (isset($region['message'])) {
- $class = (empty($region['rows_order']) ? 'region-empty' : 'region-populated');
- $table['#rows'][] = array(
- 'class' => array('region-message', 'region-' . $region_name_class . '-message', $class),
- 'no_striping' => TRUE,
- 'data' => array(
- array('data' => $region['message'], 'colspan' => $columns_count),
- ),
- );
- }
-
- // Add form rows, in the order determined at pre-render time.
- foreach ($region['rows_order'] as $name) {
- $element = $elements[$name];
-
- $row = array('data' => array());
- if (isset($element['#attributes'])) {
- $row += $element['#attributes'];
- }
-
- // Render children as table cells.
- foreach (Element::children($element) as $cell_key) {
- $child = &$element[$cell_key];
- // Do not render a cell for children of #type 'value'.
- if (!(isset($child['#type']) && $child['#type'] == 'value')) {
- $cell = array('data' => drupal_render($child));
- if (isset($child['#cell_attributes'])) {
- $cell += $child['#cell_attributes'];
- }
- $row['data'][] = $cell;
- }
- }
- $table['#rows'][] = $row;
- }
- }
-
- return drupal_render($table);
+function template_preprocess_field_ui_table(&$variables) {
+ template_preprocess_table($variables);
}
/**
diff --git a/core/modules/field_ui/src/Element/FieldUiTable.php b/core/modules/field_ui/src/Element/FieldUiTable.php
index 361a17e..8c80baa 100644
--- a/core/modules/field_ui/src/Element/FieldUiTable.php
+++ b/core/modules/field_ui/src/Element/FieldUiTable.php
@@ -7,23 +7,237 @@
namespace Drupal\field_ui\Element;
-use Drupal\Core\Render\Element\RenderElement;
+use Drupal\Component\Utility\Html;
+use Drupal\Core\Render\Element;
+use Drupal\Core\Render\Element\Table;
/**
* Provides a field_ui table element.
*
* @RenderElement("field_ui_table")
*/
-class FieldUiTable extends RenderElement {
+class FieldUiTable extends Table {
/**
* {@inheritdoc}
*/
public function getInfo() {
- return array(
- '#theme' => 'field_ui_table',
- '#regions' => array('' => array()),
- );
+ $info = parent::getInfo();
+ $info['#regions'] = ['' => []];
+ $info['#theme'] = 'field_ui_table';
+ // Prepend FieldUiTable's prerender callbacks.
+ array_unshift($info['#pre_render'], [$this, 'tablePreRender'], [$this, 'preRenderRegionRows']);
+ return $info;
+ }
+
+ /**
+ * Performs pre-render tasks on field_ui_table elements.
+ *
+ * @param array $elements
+ * A structured array containing two sub-levels of elements. Properties
+ * used:
+ * - #tabledrag: The value is a list of $options arrays that are passed to
+ * drupal_attach_tabledrag(). The HTML ID of the table is added to each
+ * $options array.
+ *
+ * @return array
+ * The $element with prepared variables ready for field-ui-table.html.twig.
+ *
+ * @see drupal_render()
+ * @see \Drupal\Core\Render\Element\Table::preRenderTable()
+ */
+ public static function tablePreRender($elements) {
+ $js_settings = array();
+
+ // For each region, build the tree structure from the weight and parenting
+ // data contained in the flat form structure, to determine row order and
+ // indentation.
+ $regions = $elements['#regions'];
+ $tree = ['' => ['name' => '', 'children' => []]];
+ $trees = array_fill_keys(array_keys($regions), $tree);
+
+ $parents = [];
+ $children = Element::children($elements);
+ $list = array_combine($children, $children);
+
+ // Iterate on rows until we can build a known tree path for all of them.
+ while ($list) {
+ foreach ($list as $name) {
+ $row = &$elements[$name];
+ $parent = $row['parent_wrapper']['parent']['#value'];
+ // Proceed if parent is known.
+ if (empty($parent) || isset($parents[$parent])) {
+ // Grab parent, and remove the row from the next iteration.
+ $parents[$name] = $parent ? array_merge($parents[$parent], [$parent]) : [];
+ unset($list[$name]);
+
+ // Determine the region for the row.
+ $region_name = call_user_func($row['#region_callback'], $row);
+
+ // Add the element in the tree.
+ $target = &$trees[$region_name][''];
+ foreach ($parents[$name] as $key) {
+ $target = &$target['children'][$key];
+ }
+ $target['children'][$name] = ['name' => $name, 'weight' => $row['weight']['#value']];
+
+ // Add tabledrag indentation to the first row cell.
+ if ($depth = count($parents[$name])) {
+ $children = Element::children($row);
+ $cell = current($children);
+ $row[$cell]['#prefix'] = [
+ '#theme' => 'indentation',
+ '#size' => $depth,
+ '#suffix' => isset($row[$cell]['#prefix']) ? $row[$cell]['#prefix'] : '',
+ ];
+ }
+
+ // Add row id and associate JS settings.
+ $id = Html::getClass($name);
+ $row['#attributes']['id'] = $id;
+ if (isset($row['#js_settings'])) {
+ $row['#js_settings'] += [
+ 'rowHandler' => $row['#row_type'],
+ 'name' => $name,
+ 'region' => $region_name,
+ ];
+ $js_settings[$id] = $row['#js_settings'];
+ }
+ }
+ }
+ }
+
+ // Determine rendering order from the tree structure.
+ foreach ($regions as $region_name => $region) {
+ $elements['#regions'][$region_name]['rows_order'] = array_reduce($trees[$region_name], [static::class, 'reduceOrder']);
+ }
+
+ $elements['#attached']['drupalSettings']['fieldUIRowsData'] = $js_settings;
+
+ // If the custom #tabledrag is set and there is a HTML ID, add the table's
+ // HTML ID to the options and attach the behavior.
+ // @see \Drupal\Core\Render\Element\Table::preRenderTable()
+ if (!empty($elements['#tabledrag']) && isset($elements['#attributes']['id'])) {
+ foreach ($elements['#tabledrag'] as $options) {
+ $options['table_id'] = $elements['#attributes']['id'];
+ drupal_attach_tabledrag($elements, $options);
+ }
+ }
+
+ return $elements;
+ }
+
+ /**
+ * Performs pre-render to move #regions to rows.
+ *
+ * @param array $elements
+ * A structured array containing two sub-levels of elements. Properties
+ * used:
+ * - #tabledrag: The value is a list of $options arrays that are passed to
+ * drupal_attach_tabledrag(). The HTML ID of the table is added to each
+ * $options array.
+ *
+ * @return array
+ * The $element with prepared variables ready for field-ui-table.html.twig.
+ */
+ public static function preRenderRegionRows($elements) {
+ // Determine the colspan to use for region rows, by checking the number of
+ // columns in the headers.
+ $columns_count = 0;
+ foreach ($elements['#header'] as $header) {
+ $columns_count += (is_array($header) && isset($header['colspan']) ? $header['colspan'] : 1);
+ }
+
+ $rows = [];
+ foreach (Element::children($elements) as $key) {
+ $rows[$key] = $elements[$key];
+ unset($elements[$key]);
+ }
+
+ // Render rows, region by region.
+ foreach ($elements['#regions'] as $region_name => $region) {
+ $region_name_class = Html::getClass($region_name);
+
+ // Add region rows.
+ if (isset($region['title']) && empty($region['invisible'])) {
+ $elements['#rows'][] = [
+ 'class' => [
+ 'region-title',
+ 'region-' . $region_name_class . '-title'
+ ],
+ 'no_striping' => TRUE,
+ 'data' => [
+ ['data' => $region['title'], 'colspan' => $columns_count],
+ ],
+ ];
+ }
+ if (isset($region['message'])) {
+ $class = (empty($region['rows_order']) ? 'region-empty' : 'region-populated');
+ $elements['#rows'][] = [
+ 'class' => [
+ 'region-message',
+ 'region-' . $region_name_class . '-message', $class,
+ ],
+ 'no_striping' => TRUE,
+ 'data' => [
+ ['data' => $region['message'], 'colspan' => $columns_count],
+ ],
+ ];
+ }
+
+ // Add form rows, in the order determined at pre-render time.
+ foreach ($region['rows_order'] as $name) {
+ $element = $rows[$name];
+
+ $row = ['data' => []];
+ if (isset($element['#attributes'])) {
+ $row += $element['#attributes'];
+ }
+
+ // Render children as table cells.
+ foreach (Element::children($element) as $cell_key) {
+ $child = $element[$cell_key];
+ // Do not render a cell for children of #type 'value'.
+ if (!(isset($child['#type']) && $child['#type'] == 'value')) {
+ $cell = ['data' => $child];
+ if (isset($child['#cell_attributes'])) {
+ $cell += $child['#cell_attributes'];
+ }
+ $row['data'][] = $cell;
+ }
+ }
+ $elements['#rows'][] = $row;
+ }
+ }
+
+ return $elements;
+ }
+
+ /**
+ * Determines the rendering order of an array representing a tree.
+ *
+ * Callback for array_reduce() within ::tablePreRender().
+ *
+ * @param mixed $array
+ * Holds the return value of the previous iteration; in the case of the
+ * first iteration it instead holds the value of the initial array.
+ * @param mixed $a
+ * Holds the value of the current iteration.
+ *
+ * @return array
+ * Array where rendering order has been determined.
+ */
+ public static function reduceOrder($array, $a) {
+ $array = !$array ? [] : $array;
+ if ($a['name']) {
+ $array[] = $a['name'];
+ }
+ if (!empty($a['children'])) {
+ uasort($a['children'], ['Drupal\Component\Utility\SortArray', 'sortByWeightElement']);
+ $array = array_merge($array, array_reduce($a['children'], [static::class, 'reduceOrder']));
+ }
+
+ return $array;
}
}
diff --git a/core/modules/field_ui/src/Form/EntityDisplayFormBase.php b/core/modules/field_ui/src/Form/EntityDisplayFormBase.php
index 6681f61..e0b622a 100644
--- a/core/modules/field_ui/src/Form/EntityDisplayFormBase.php
+++ b/core/modules/field_ui/src/Form/EntityDisplayFormBase.php
@@ -19,6 +19,7 @@ use Drupal\Core\Field\PluginSettingsInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\field_ui\Element\FieldUiTable;
use Drupal\field_ui\FieldUI;
/**
@@ -159,17 +160,12 @@ abstract class EntityDisplayFormBase extends EntityForm {
$table = array(
'#type' => 'field_ui_table',
- '#pre_render' => array(array($this, 'tablePreRender')),
- '#tree' => TRUE,
'#header' => $this->getTableHeader(),
'#regions' => $this->getRegions(),
'#attributes' => array(
'class' => array('field-ui-overview'),
'id' => 'field-display-overview',
),
- // Add Ajax wrapper.
- '#prefix' => '<div id="field-display-overview-wrapper">',
- '#suffix' => '</div>',
'#tabledrag' => array(
array(
'action' => 'order',
@@ -691,85 +687,11 @@ abstract class EntityDisplayFormBase extends EntityForm {
*
* @see drupal_render()
* @see \Drupal\Core\Render\Element\Table::preRenderTable()
+ *
+ * @deprecated in Drupal 8.0.0, will be removed before Drupal 9.0.0.
*/
public function tablePreRender($elements) {
- $js_settings = array();
-
- // For each region, build the tree structure from the weight and parenting
- // data contained in the flat form structure, to determine row order and
- // indentation.
- $regions = $elements['#regions'];
- $tree = array('' => array('name' => '', 'children' => array()));
- $trees = array_fill_keys(array_keys($regions), $tree);
-
- $parents = array();
- $children = Element::children($elements);
- $list = array_combine($children, $children);
-
- // Iterate on rows until we can build a known tree path for all of them.
- while ($list) {
- foreach ($list as $name) {
- $row = &$elements[$name];
- $parent = $row['parent_wrapper']['parent']['#value'];
- // Proceed if parent is known.
- if (empty($parent) || isset($parents[$parent])) {
- // Grab parent, and remove the row from the next iteration.
- $parents[$name] = $parent ? array_merge($parents[$parent], array($parent)) : array();
- unset($list[$name]);
-
- // Determine the region for the row.
- $region_name = call_user_func($row['#region_callback'], $row);
-
- // Add the element in the tree.
- $target = &$trees[$region_name][''];
- foreach ($parents[$name] as $key) {
- $target = &$target['children'][$key];
- }
- $target['children'][$name] = array('name' => $name, 'weight' => $row['weight']['#value']);
-
- // Add tabledrag indentation to the first row cell.
- if ($depth = count($parents[$name])) {
- $children = Element::children($row);
- $cell = current($children);
- $indentation = array(
- '#theme' => 'indentation',
- '#size' => $depth,
- );
- $row[$cell]['#prefix'] = drupal_render($indentation) . (isset($row[$cell]['#prefix']) ? $row[$cell]['#prefix'] : '');
- }
-
- // Add row id and associate JS settings.
- $id = Html::getClass($name);
- $row['#attributes']['id'] = $id;
- if (isset($row['#js_settings'])) {
- $row['#js_settings'] += array(
- 'rowHandler' => $row['#row_type'],
- 'name' => $name,
- 'region' => $region_name,
- );
- $js_settings[$id] = $row['#js_settings'];
- }
- }
- }
- }
- // Determine rendering order from the tree structure.
- foreach ($regions as $region_name => $region) {
- $elements['#regions'][$region_name]['rows_order'] = array_reduce($trees[$region_name], array($this, 'reduceOrder'));
- }
-
- $elements['#attached']['drupalSettings']['fieldUIRowsData'] = $js_settings;
-
- // If the custom #tabledrag is set and there is a HTML ID, add the table's
- // HTML ID to the options and attach the behavior.
- // @see \Drupal\Core\Render\Element\Table::preRenderTable()
- if (!empty($elements['#tabledrag']) && isset($elements['#attributes']['id'])) {
- foreach ($elements['#tabledrag'] as $options) {
- $options['table_id'] = $elements['#attributes']['id'];
- drupal_attach_tabledrag($elements, $options);
- }
- }
-
- return $elements;
+ return FieldUiTable::tablePreRender($elements);
}
/**
@@ -777,17 +699,11 @@ abstract class EntityDisplayFormBase extends EntityForm {
*
* Callback for array_reduce() within
* \Drupal\field_ui\Form\EntityDisplayFormBase::tablePreRender().
+ *
+ * @deprecated in Drupal 8.0.0, will be removed before Drupal 9.0.0.
*/
public function reduceOrder($array, $a) {
- $array = !isset($array) ? array() : $array;
- if ($a['name']) {
- $array[] = $a['name'];
- }
- if (!empty($a['children'])) {
- uasort($a['children'], array('Drupal\Component\Utility\SortArray', 'sortByWeightElement'));
- $array = array_merge($array, array_reduce($a['children'], array($this, 'reduceOrder')));
- }
- return $array;
+ return FieldUiTable::reduceOrder($array, $a);
}
/**
diff --git a/core/modules/field_ui/templates/field-ui-table.html.twig b/core/modules/field_ui/templates/field-ui-table.html.twig
new file mode 100644
index 0000000..f7ff026
--- /dev/null
+++ b/core/modules/field_ui/templates/field-ui-table.html.twig
@@ -0,0 +1,47 @@
+{#
+/**
+ * @file
+ * Default theme implementation to display a Field UI table.
+ *
+ * Available variables:
+ * - attributes: HTML attributes to apply to the <table> tag.
+ * - caption: A localized string for the <caption> tag.
+ * - colgroups: Column groups. Each group contains the following properties:
+ * - attributes: HTML attributes to apply to the <col> tag.
+ * Note: Drupal currently supports only one table header row, see
+ * https://www.drupal.org/node/893530 and
+ * http://api.drupal.org/api/drupal/includes!theme.inc/function/theme_table/7#comment-5109.
+ * - header: Table header cells. Each cell contains the following properties:
+ * - tag: The HTML tag name to use; either TH or TD.
+ * - attributes: HTML attributes to apply to the tag.
+ * - content: A localized string for the title of the column.
+ * - field: Field name (required for column sorting).
+ * - sort: Default sort order for this column ("asc" or "desc").
+ * - sticky: A flag indicating whether to use a "sticky" table header.
+ * - rows: Table rows. Each row contains the following properties:
+ * - attributes: HTML attributes to apply to the <tr> tag.
+ * - data: Table cells.
+ * - no_striping: A flag indicating that the row should receive no
+ * 'even / odd' styling. Defaults to FALSE.
+ * - cells: Table cells of the row. Each cell contains the following keys:
+ * - tag: The HTML tag name to use; either TH or TD.
+ * - attributes: Any HTML attributes, such as "colspan", to apply to the
+ * table cell.
+ * - content: The string to display in the table cell.
+ * - active_table_sort: A boolean indicating whether the cell is the active
+ table sort.
+ * - footer: Table footer rows, in the same format as the rows variable.
+ * - empty: The message to display in an extra row if table does not have
+ * any rows.
+ * - no_striping: A boolean indicating that the row should receive no striping.
+ * - header_columns: The number of columns in the header.
+ *
+ * @see template_preprocess_field_ui_table()
+ *
+ * @ingroup themeable
+ */
+#}
+{# Add Ajax wrapper. #}
+<div id="field-display-overview-wrapper">
+ {% include 'table.html.twig' %}
+</div>