Mercurial > hg > isophonics-drupal-site
comparison core/modules/field_ui/src/Element/FieldUiTable.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | c2387f117808 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
1 <?php | |
2 | |
3 namespace Drupal\field_ui\Element; | |
4 | |
5 use Drupal\Component\Utility\Html; | |
6 use Drupal\Core\Render\Element; | |
7 use Drupal\Core\Render\Element\Table; | |
8 | |
9 /** | |
10 * Provides a field_ui table element. | |
11 * | |
12 * @RenderElement("field_ui_table") | |
13 */ | |
14 class FieldUiTable extends Table { | |
15 | |
16 /** | |
17 * {@inheritdoc} | |
18 */ | |
19 public function getInfo() { | |
20 $info = parent::getInfo(); | |
21 $info['#regions'] = ['' => []]; | |
22 $info['#theme'] = 'field_ui_table'; | |
23 // Prepend FieldUiTable's prerender callbacks. | |
24 array_unshift($info['#pre_render'], [$this, 'tablePreRender'], [$this, 'preRenderRegionRows']); | |
25 return $info; | |
26 } | |
27 | |
28 /** | |
29 * Performs pre-render tasks on field_ui_table elements. | |
30 * | |
31 * @param array $elements | |
32 * A structured array containing two sub-levels of elements. Properties | |
33 * used: | |
34 * - #tabledrag: The value is a list of $options arrays that are passed to | |
35 * drupal_attach_tabledrag(). The HTML ID of the table is added to each | |
36 * $options array. | |
37 * | |
38 * @return array | |
39 * The $element with prepared variables ready for field-ui-table.html.twig. | |
40 * | |
41 * @see drupal_render() | |
42 * @see \Drupal\Core\Render\Element\Table::preRenderTable() | |
43 */ | |
44 public static function tablePreRender($elements) { | |
45 $js_settings = []; | |
46 | |
47 // For each region, build the tree structure from the weight and parenting | |
48 // data contained in the flat form structure, to determine row order and | |
49 // indentation. | |
50 $regions = $elements['#regions']; | |
51 $tree = ['' => ['name' => '', 'children' => []]]; | |
52 $trees = array_fill_keys(array_keys($regions), $tree); | |
53 | |
54 $parents = []; | |
55 $children = Element::children($elements); | |
56 $list = array_combine($children, $children); | |
57 | |
58 // Iterate on rows until we can build a known tree path for all of them. | |
59 while ($list) { | |
60 foreach ($list as $name) { | |
61 $row = &$elements[$name]; | |
62 $parent = $row['parent_wrapper']['parent']['#value']; | |
63 // Proceed if parent is known. | |
64 if (empty($parent) || isset($parents[$parent])) { | |
65 // Grab parent, and remove the row from the next iteration. | |
66 $parents[$name] = $parent ? array_merge($parents[$parent], [$parent]) : []; | |
67 unset($list[$name]); | |
68 | |
69 // Determine the region for the row. | |
70 $region_name = call_user_func_array($row['#region_callback'], [&$row]); | |
71 | |
72 // Add the element in the tree. | |
73 $target = &$trees[$region_name]['']; | |
74 foreach ($parents[$name] as $key) { | |
75 $target = &$target['children'][$key]; | |
76 } | |
77 $target['children'][$name] = ['name' => $name, 'weight' => $row['weight']['#value']]; | |
78 | |
79 // Add tabledrag indentation to the first row cell. | |
80 if ($depth = count($parents[$name])) { | |
81 $children = Element::children($row); | |
82 $cell = current($children); | |
83 $indentation = [ | |
84 '#theme' => 'indentation', | |
85 '#size' => $depth, | |
86 '#suffix' => isset($row[$cell]['#prefix']) ? $row[$cell]['#prefix'] : '', | |
87 ]; | |
88 $row[$cell]['#prefix'] = \Drupal::service('renderer')->render($indentation); | |
89 } | |
90 | |
91 // Add row id and associate JS settings. | |
92 $id = Html::getClass($name); | |
93 $row['#attributes']['id'] = $id; | |
94 if (isset($row['#js_settings'])) { | |
95 $row['#js_settings'] += [ | |
96 'rowHandler' => $row['#row_type'], | |
97 'name' => $name, | |
98 'region' => $region_name, | |
99 ]; | |
100 $js_settings[$id] = $row['#js_settings']; | |
101 } | |
102 } | |
103 } | |
104 } | |
105 | |
106 // Determine rendering order from the tree structure. | |
107 foreach ($regions as $region_name => $region) { | |
108 $elements['#regions'][$region_name]['rows_order'] = array_reduce($trees[$region_name], [static::class, 'reduceOrder']); | |
109 } | |
110 | |
111 $elements['#attached']['drupalSettings']['fieldUIRowsData'] = $js_settings; | |
112 | |
113 // If the custom #tabledrag is set and there is a HTML ID, add the table's | |
114 // HTML ID to the options and attach the behavior. | |
115 // @see \Drupal\Core\Render\Element\Table::preRenderTable() | |
116 if (!empty($elements['#tabledrag']) && isset($elements['#attributes']['id'])) { | |
117 foreach ($elements['#tabledrag'] as $options) { | |
118 $options['table_id'] = $elements['#attributes']['id']; | |
119 drupal_attach_tabledrag($elements, $options); | |
120 } | |
121 } | |
122 | |
123 return $elements; | |
124 } | |
125 | |
126 /** | |
127 * Performs pre-render to move #regions to rows. | |
128 * | |
129 * @param array $elements | |
130 * A structured array containing two sub-levels of elements. Properties | |
131 * used: | |
132 * - #tabledrag: The value is a list of $options arrays that are passed to | |
133 * drupal_attach_tabledrag(). The HTML ID of the table is added to each | |
134 * $options array. | |
135 * | |
136 * @return array | |
137 * The $element with prepared variables ready for field-ui-table.html.twig. | |
138 */ | |
139 public static function preRenderRegionRows($elements) { | |
140 // Determine the colspan to use for region rows, by checking the number of | |
141 // columns in the headers. | |
142 $columns_count = 0; | |
143 foreach ($elements['#header'] as $header) { | |
144 $columns_count += (is_array($header) && isset($header['colspan']) ? $header['colspan'] : 1); | |
145 } | |
146 | |
147 $rows = []; | |
148 foreach (Element::children($elements) as $key) { | |
149 $rows[$key] = $elements[$key]; | |
150 unset($elements[$key]); | |
151 } | |
152 | |
153 // Render rows, region by region. | |
154 foreach ($elements['#regions'] as $region_name => $region) { | |
155 $region_name_class = Html::getClass($region_name); | |
156 | |
157 // Add region rows. | |
158 if (isset($region['title']) && empty($region['invisible'])) { | |
159 $elements['#rows'][] = [ | |
160 'class' => [ | |
161 'region-title', | |
162 'region-' . $region_name_class . '-title' | |
163 ], | |
164 'no_striping' => TRUE, | |
165 'data' => [ | |
166 ['data' => $region['title'], 'colspan' => $columns_count], | |
167 ], | |
168 ]; | |
169 } | |
170 if (isset($region['message'])) { | |
171 $class = (empty($region['rows_order']) ? 'region-empty' : 'region-populated'); | |
172 $elements['#rows'][] = [ | |
173 'class' => [ | |
174 'region-message', | |
175 'region-' . $region_name_class . '-message', $class, | |
176 ], | |
177 'no_striping' => TRUE, | |
178 'data' => [ | |
179 ['data' => $region['message'], 'colspan' => $columns_count], | |
180 ], | |
181 ]; | |
182 } | |
183 | |
184 // Add form rows, in the order determined at pre-render time. | |
185 foreach ($region['rows_order'] as $name) { | |
186 $element = $rows[$name]; | |
187 | |
188 $row = ['data' => []]; | |
189 if (isset($element['#attributes'])) { | |
190 $row += $element['#attributes']; | |
191 } | |
192 | |
193 // Render children as table cells. | |
194 foreach (Element::children($element) as $cell_key) { | |
195 $child = $element[$cell_key]; | |
196 // Do not render a cell for children of #type 'value'. | |
197 if (!(isset($child['#type']) && $child['#type'] == 'value')) { | |
198 $cell = ['data' => $child]; | |
199 if (isset($child['#cell_attributes'])) { | |
200 $cell += $child['#cell_attributes']; | |
201 } | |
202 $row['data'][] = $cell; | |
203 } | |
204 } | |
205 $elements['#rows'][] = $row; | |
206 } | |
207 } | |
208 | |
209 return $elements; | |
210 } | |
211 | |
212 /** | |
213 * Determines the rendering order of an array representing a tree. | |
214 * | |
215 * Callback for array_reduce() within ::tablePreRender(). | |
216 * | |
217 * @param mixed $array | |
218 * Holds the return value of the previous iteration; in the case of the | |
219 * first iteration it instead holds the value of the initial array. | |
220 * @param mixed $a | |
221 * Holds the value of the current iteration. | |
222 * | |
223 * @return array | |
224 * Array where rendering order has been determined. | |
225 */ | |
226 public static function reduceOrder($array, $a) { | |
227 $array = !$array ? [] : $array; | |
228 if ($a['name']) { | |
229 $array[] = $a['name']; | |
230 } | |
231 if (!empty($a['children'])) { | |
232 uasort($a['children'], ['Drupal\Component\Utility\SortArray', 'sortByWeightElement']); | |
233 $array = array_merge($array, array_reduce($a['children'], [static::class, 'reduceOrder'])); | |
234 } | |
235 | |
236 return $array; | |
237 } | |
238 | |
239 } |