From f0a49e662de237c4096d6384a07e3ccc2b43999c Mon Sep 17 00:00:00 2001 From: Dries Buytaert Date: Sat, 26 Jun 2010 02:06:53 +0000 Subject: - Patch #616240 by yched, marcingy: make field UI screens extensible from contrib. --- .../field_ui/field_ui-field-overview-form.tpl.php | 94 ------ modules/field_ui/field_ui-rtl.css | 3 +- modules/field_ui/field_ui.admin.inc | 373 ++++++++++++++------- modules/field_ui/field_ui.css | 5 +- modules/field_ui/field_ui.module | 45 ++- modules/field_ui/field_ui.test | 6 +- 6 files changed, 284 insertions(+), 242 deletions(-) delete mode 100644 modules/field_ui/field_ui-field-overview-form.tpl.php (limited to 'modules/field_ui') diff --git a/modules/field_ui/field_ui-field-overview-form.tpl.php b/modules/field_ui/field_ui-field-overview-form.tpl.php deleted file mode 100644 index 781119d36..000000000 --- a/modules/field_ui/field_ui-field-overview-form.tpl.php +++ /dev/null @@ -1,94 +0,0 @@ - - - - - - - - - - - - - - - - row_type): - case 'field': ?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- label; ?> - weight . $row->hidden_name; ?>field_name; ?>type; ?>widget_type; ?>edit; ?>delete; ?> - label; ?> - weight . $row->hidden_name; ?>name; ?>description; ?>edit; ?>delete; ?> -
-
- label; ?> -
-
 
weight . $row->hidden_name; ?>
 
field_name; ?>
 
type; ?>
 
widget_type; ?>
-
-
- label; ?> -
-
 
weight . $row->hidden_name; ?>
 
field_name; ?>
 
widget_type; ?>
- - diff --git a/modules/field_ui/field_ui-rtl.css b/modules/field_ui/field_ui-rtl.css index 6823e1e0b..49aadb528 100644 --- a/modules/field_ui/field_ui-rtl.css +++ b/modules/field_ui/field_ui-rtl.css @@ -1,8 +1,7 @@ /* $Id$ */ /* 'Manage fields' overview */ -#field-overview .label-add-new-field, -#field-overview .label-add-existing-field { +#field-overview tr.add-new .label-input { float: right; } diff --git a/modules/field_ui/field_ui.admin.inc b/modules/field_ui/field_ui.admin.inc index 064770b9b..94fe876c5 100644 --- a/modules/field_ui/field_ui.admin.inc +++ b/modules/field_ui/field_ui.admin.inc @@ -62,6 +62,105 @@ function field_ui_inactive_message($entity_type, $bundle) { } } +/** + * Helper function: determines the rendering order of a tree array. + * + * This is intended as a callback for array_reduce(). + */ +function _field_ui_reduce_order($array, $a) { + $array = is_null($array) ? array() : $array; + if ($a['name']) { + $array[] = $a['name']; + } + if (!empty($a['children'])) { + uasort($a['children'], 'drupal_sort_weight'); + $array = array_merge($array, array_reduce($a['children'], '_field_ui_reduce_order')); + } + return $array; +} + +/** + * Theme preprocess function for theme_field_ui_table(). + * + * @see theme_field_ui_table() + */ +function template_preprocess_field_ui_table(&$variables) { + $elements = &$variables['elements']; + + // Build the tree structure from the weight and parenting data contained in + // the flat form structure, to determine row order and indentation. + $tree = array('' => array('name' => '', 'children' => array())); + $parents = array(); + $list = drupal_map_assoc(element_children($elements)); + // 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])) { + // Remove from the next iteration. + $parents[$name] = $parent ? array_merge($parents[$parent], array($parent)) : array(); + unset($list[$name]); + + // Add the element in the tree. + $target = &$tree['']; + 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])) { + $cell = current(element_children($row)); + $row[$cell]['#prefix'] = theme('indentation', array('size' => $depth)) . (isset($row[$cell]['#prefix']) ? $row[$cell]['#prefix'] : ''); + } + } + } + } + + // Determine rendering order for the tree. + $variables['row_order'] = array_reduce($tree, '_field_ui_reduce_order'); +} + +/** + * Returns HTML for Field UI overview tables. + * + * @param $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(); + + foreach (array('header', 'attributes') as $key) { + if (isset($elements["#$key"])) { + $table[$key] = $elements["#$key"]; + } + } + + foreach ($variables['row_order'] as $key) { + $element = $elements[$key]; + $row = array('data' => array()); + $row += $element['#attributes']; + + foreach (element_children($element) as $cell_key) { + $cell = array('data' => drupal_render($element[$cell_key])); + if (isset($element[$cell_key]['#cell_attributes'])) { + $cell += $element[$cell_key]['#cell_attributes']; + } + $row['data'][] = $cell; + } + $table['rows'][] = $row; + } + + return theme('table', $table); +} + /** * Menu callback; listing of fields for a bundle. * @@ -89,23 +188,60 @@ function field_ui_field_overview_form($form, &$form_state, $entity_type, $bundle $weights = array(); $form += array( - '#tree' => TRUE, '#entity_type' => $entity_type, '#bundle' => $bundle, '#fields' => array_keys($instances), '#extra' => array_keys($extra_fields), - '#field_rows' => array(), ); + $table = array( + '#type' => 'table', + '#tree' => TRUE, + '#header' => array( + t('Label'), + t('Weight'), + t('Parent'), + t('Name'), + t('Field'), + t('Widget'), + array('data' => t('Operations'), 'colspan' => 2), + ), + '#attributes' => array('id' => 'field-overview'), + ); + + $parent_options = array('' => t('')); + // Fields. foreach ($instances as $name => $instance) { $field = field_info_field($instance['field_name']); $admin_field_path = $admin_path . '/fields/' . $instance['field_name']; $weight = $instance['widget']['weight']; - $form[$name] = array( + $weights[] = $weight; + $table[$name] = array( + '#parents' => array($name), + '#attributes' => array('class' => array('draggable tabledrag-leaf')), 'label' => array( '#markup' => check_plain($instance['label']), ), + 'weight' => array( + '#type' => 'textfield', + '#default_value' => $weight, + '#size' => 3, + '#attributes' => array('class' => array('field-weight')), + ), + 'parent_wrapper' => array( + 'parent' => array( + '#type' => 'select', + '#options' => $parent_options, + '#attributes' => array('class' => array('field-parent')), + '#parents' => array($name, 'parent'), + ), + 'hidden_name' => array( + '#type' => 'hidden', + '#default_value' => $name, + '#attributes' => array('class' => array('field-name')), + ), + ), 'field_name' => array( '#markup' => $instance['field_name'], ), @@ -133,64 +269,60 @@ function field_ui_field_overview_form($form, &$form_state, $entity_type, $bundle '#href' => $admin_field_path . '/delete', '#options' => array('attributes' => array('title' => t('Delete instance.'))), ), - 'weight' => array( - '#type' => 'textfield', - '#default_value' => $weight, - '#size' => 3, - '#title_display' => 'invisible', - '#title' => t('Weight for @row', array('@row' => $instance['label'])), - ), - 'hidden_name' => array( - '#type' => 'hidden', - '#default_value' => $instance['field_name'], - ), - '#row_type' => 'field', ); if (!empty($instance['locked'])) { - $form[$name]['edit'] = array('#value' => t('Locked')); - $form[$name]['delete'] = array(); - $form[$name]['#disabled_row'] = TRUE; + $table[$name]['edit'] = array('#value' => t('Locked')); + $table[$name]['delete'] = array(); + $table[$name]['#attributes']['class'][] = 'menu-disabled'; } - $form['#field_rows'][] = $name; - $weights[] = $weight; } // Non-field elements. foreach ($extra_fields as $name => $extra_field) { $weight = $extra_field['weight']; - $form[$name] = array( + $weights[] = $weight; + $table[$name] = array( + '#parents' => array($name), + '#attributes' => array('class' => array('draggable', 'tabledrag-leaf', 'menu-disabled')), 'label' => array( '#markup' => check_plain($extra_field['label']), ), - 'name' => array( - '#markup' => $name, - ), - 'description' => array( - '#markup' => isset($extra_field['description']) ? $extra_field['description'] : '', - ), 'weight' => array( '#type' => 'textfield', '#default_value' => $weight, '#size' => 3, + '#attributes' => array('class' => array('field-weight')), '#title_display' => 'invisible', '#title' => t('Weight for @row', array('@row' => $extra_field['label'])), ), + 'parent_wrapper' => array( + 'parent' => array( + '#type' => 'select', + '#options' => $parent_options, + '#attributes' => array('class' => array('field-parent')), + '#parents' => array($name, 'parent'), + ), + 'hidden_name' => array( + '#type' => 'hidden', + '#default_value' => $name, + '#attributes' => array('class' => array('field-name')), + ), + ), + 'field_name' => array( + '#markup' => $name, + ), + 'type' => array( + '#markup' => isset($extra_field['description']) ? $extra_field['description'] : '', + '#cell_attributes' => array('colspan' => 2), + ), 'edit' => array( '#markup' => isset($extra_field['edit']) ? $extra_field['edit'] : '', ), 'delete' => array( '#markup' => isset($extra_field['delete']) ? $extra_field['delete'] : '', ), - 'hidden_name' => array( - '#type' => 'hidden', - '#default_value' => $name, - ), - '#disabled_row' => TRUE, - '#row_type' => 'extra', ); - $form['#field_rows'][] = $name; - $weights[] = $weight; } // Additional row: add new field. @@ -201,11 +333,38 @@ function field_ui_field_overview_form($form, &$form_state, $entity_type, $bundle array_unshift($field_type_options, t('- Select a field type -')); array_unshift($widget_type_options, t('- Select a widget -')); $name = '_add_new_field'; - $form[$name] = array( + $table[$name] = array( + '#parents' => array($name), + '#attributes' => array('class' => array('draggable', 'tabledrag-leaf', 'add-new')), 'label' => array( '#type' => 'textfield', '#size' => 15, '#description' => t('Label'), + '#prefix' => '
' . t('Add new field') .'
', + '#suffix' => '
', + ), + 'weight' => array( + '#type' => 'textfield', + '#default_value' => $weight, + '#size' => 3, + '#title_display' => 'invisible', + '#title' => t('Weight for new field'), + '#attributes' => array('class' => array('field-weight')), + '#prefix' => '
 
', + ), + 'parent_wrapper' => array( + 'parent' => array( + '#type' => 'select', + '#options' => $parent_options, + '#attributes' => array('class' => array('field-parent')), + '#prefix' => '
 
', + '#parents' => array($name, 'parent'), + ), + 'hidden_name' => array( + '#type' => 'hidden', + '#default_value' => $name, + '#attributes' => array('class' => array('field-name')), + ), ), 'field_name' => array( '#type' => 'textfield', @@ -215,32 +374,24 @@ function field_ui_field_overview_form($form, &$form_state, $entity_type, $bundle '#attributes' => array('dir'=>'ltr'), '#size' => 15, '#description' => t('Field name (a-z, 0-9, _)'), + '#prefix' => '
 
', ), 'type' => array( '#type' => 'select', '#options' => $field_type_options, '#description' => t('Type of data to store.'), + '#attributes' => array('class' => array('field-type-select')), + '#prefix' => '
 
', ), 'widget_type' => array( '#type' => 'select', '#options' => $widget_type_options, '#description' => t('Form element to edit the data.'), + '#attributes' => array('class' => array('widget-type-select')), + '#cell_attributes' => array('colspan' => 3), + '#prefix' => '
 
', ), - 'weight' => array( - '#type' => 'textfield', - '#default_value' => $weight, - '#size' => 3, - '#title_display' => 'invisible', - '#title' => t('Weight for new field'), - ), - 'hidden_name' => array( - '#type' => 'hidden', - '#default_value' => $name, - ), - '#add_new' => TRUE, - '#row_type' => 'add_new_field', ); - $form['#field_rows'][] = $name; } // Additional row: add existing field. @@ -249,108 +400,85 @@ function field_ui_field_overview_form($form, &$form_state, $entity_type, $bundle $weight++; array_unshift($existing_field_options, t('- Select an existing field -')); $name = '_add_existing_field'; - $form[$name] = array( + $table[$name] = array( + '#parents' => array($name), + '#attributes' => array('class' => array('draggable', 'tabledrag-leaf', 'menu-disabled')), 'label' => array( '#type' => 'textfield', '#size' => 15, '#description' => t('Label'), + '#attributes' => array('class' => array('label-textfield')), + '#prefix' => '
' . t('Add existing field') .'
', + '#suffix' => '
', + ), + 'weight' => array( + '#type' => 'textfield', + '#default_value' => $weight, + '#size' => 3, + '#title_display' => 'invisible', + '#title' => t('Weight for added field'), + '#attributes' => array('class' => array('field-weight')), + '#prefix' => '
 
', + ), + 'parent_wrapper' => array( + 'parent' => array( + '#type' => 'select', + '#options' => $parent_options, + '#attributes' => array('class' => array('field-parent')), + '#prefix' => '
 
', + '#parents' => array($name, 'parent'), + ), + 'hidden_name' => array( + '#type' => 'hidden', + '#default_value' => $name, + '#attributes' => array('class' => array('field-name')), + ), ), 'field_name' => array( '#type' => 'select', '#options' => $existing_field_options, '#description' => t('Field to share'), + '#attributes' => array('class' => array('field-select')), + '#cell_attributes' => array('colspan' => 2), + '#prefix' => '
 
', ), 'widget_type' => array( '#type' => 'select', '#options' => $widget_type_options, '#description' => t('Form element to edit the data.'), + '#attributes' => array('class' => array('widget-type-select')), + '#cell_attributes' => array('colspan' => 3), + '#prefix' => '
 
', ), - 'weight' => array( - '#type' => 'textfield', - '#default_value' => $weight, - '#size' => 3, - '#title_display' => 'invisible', - '#title' => t('Weight for added field'), - ), - 'hidden_name' => array( - '#type' => 'hidden', - '#default_value' => $name, - ), - '#add_new' => TRUE, - '#row_type' => 'add_existing_field', ); - $form['#field_rows'][] = $name; } + $form['table'] = $table; + $form['actions'] = array('#type' => 'actions'); $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save')); - return $form; -} - -/** - * Theme preprocess function for field_ui-field-overview-form.tpl.php. - */ -function template_preprocess_field_ui_field_overview_form(&$vars) { - $form = &$vars['form']; - drupal_add_css(drupal_get_path('module', 'field_ui') . '/field_ui.css'); - drupal_add_tabledrag('field-overview', 'order', 'sibling', 'field-weight'); - drupal_add_js(drupal_get_path('module', 'field_ui') . '/field_ui.js'); + $form['#attached']['css'][] = drupal_get_path('module', 'field_ui') . '/field_ui.css'; + $form['#attached']['js'][] = drupal_get_path('module', 'field_ui') . '/field_ui.js'; // Add settings for the update selects behavior. $js_fields = array(); - foreach (field_ui_existing_field_options($form['#entity_type'], $form['#bundle']) as $field_name => $fields) { + foreach ($existing_field_options as $field_name => $fields) { $field = field_info_field($field_name); $instance = field_info_instance($form['#entity_type'], $field_name, $form['#bundle']); $js_fields[$field_name] = array('label' => $instance['label'], 'type' => $field['type'], 'widget' => $instance['widget']['type']); } - drupal_add_js(array('fieldWidgetTypes' => field_ui_widget_type_options(), 'fields' => $js_fields), 'setting'); - $order = _field_ui_overview_order($form, $form['#field_rows']); - $rows = array(); + $form['#attached']['js'][] = array( + 'type' => 'setting', + 'data' => array('fields' => $js_fields, 'fieldWidgetTypes' => field_ui_widget_type_options(), + ), + ); - // Identify the 'new item' keys in the form. - $keys = array_keys($form); - $add_rows = array(); - foreach ($keys as $key) { - if (substr($key, 0, 4) == '_add') { - $add_rows[] = $key; - } - } - while ($order) { - $key = reset($order); - $element = &$form[$key]; - $row = new stdClass(); - - // Add target classes for the tabledrag behavior. - $element['weight']['#attributes']['class'][] = 'field-weight'; - $element['hidden_name']['#attributes']['class'][] = 'field-name'; - // Add target classes for the update selects behavior. - switch ($element['#row_type']) { - case 'add_new_field': - $element['type']['#attributes']['class'][] = 'field-type-select'; - $element['widget_type']['#attributes']['class'][] = 'widget-type-select'; - break; - - case 'add_existing_field': - $element['field_name']['#attributes']['class'][] = 'field-select'; - $element['widget_type']['#attributes']['class'][] = 'widget-type-select'; - $element['label']['#attributes']['class'][] = 'label-textfield'; - break; - } - foreach (element_children($element) as $child) { - $row->{$child} = drupal_render($element[$child]); - } - $row->label_class = 'label-' . strtr($element['#row_type'], '_', '-'); - $row->row_type = $element['#row_type']; - $row->class = 'draggable'; - $row->class .= isset($element['#add_new']) ? ' add-new' : ''; - $row->class .= isset($element['#disabled_row']) ? ' menu-disabled' : ''; + // Add tabledrag behavior. + $form['#attached']['drupal_add_tabledrag'][] = array('field-overview', 'order', 'sibling', 'field-weight'); + $form['#attached']['drupal_add_tabledrag'][] = array('field-overview', 'match', 'parent', 'field-parent', 'field-parent', 'field-name'); - $rows[] = $row; - array_shift($order); - } - $vars['rows'] = $rows; - $vars['submit'] = drupal_render_children($form); + return $form; } /** @@ -1420,6 +1548,7 @@ function field_ui_next_destination($entity_type, $bundle) { /** * Helper function to order fields when theming overview forms. + * @todo Remove when 'Manage display' screen is done. */ function _field_ui_overview_order(&$form, $field_rows) { // Put weight and parenting values into a $dummy render structure and let diff --git a/modules/field_ui/field_ui.css b/modules/field_ui/field_ui.css index 43d9b78f6..6d03c8b61 100644 --- a/modules/field_ui/field_ui.css +++ b/modules/field_ui/field_ui.css @@ -1,8 +1,7 @@ /* $Id$ */ /* 'Manage fields' overview */ -#field-overview .label-add-new-field, -#field-overview .label-add-existing-field { +#field-overview tr.add-new .label-input { float: left; /* LTR */ } #field-overview tr.add-new .tabledrag-changed { @@ -11,7 +10,7 @@ #field-overview tr.add-new .description { margin-bottom: 0; } -#field-overview .new { +#field-overview tr.add-new .add-new-placeholder { font-weight: bold; padding-bottom: .5em; } diff --git a/modules/field_ui/field_ui.module b/modules/field_ui/field_ui.module index 470abe6d7..59aabb46c 100644 --- a/modules/field_ui/field_ui.module +++ b/modules/field_ui/field_ui.module @@ -48,24 +48,6 @@ function field_ui_help($path, $arg) { } } -/** - * Implements hook_theme(). - */ -function field_ui_theme() { - return array( - 'field_ui_field_overview_form' => array( - 'render element' => 'form', - 'file' => 'field_ui.admin.inc', - 'template' => 'field_ui-field-overview-form', - ), - 'field_ui_display_overview_table' => array( - 'render element' => 'elements', - 'file' => 'field_ui.admin.inc', - 'template' => 'field_ui-display-overview-table', - ), - ); -} - /** * Implements hook_menu(). */ @@ -288,6 +270,33 @@ function _field_ui_view_mode_menu_access($entity_type, $bundle, $view_mode, $acc } } +/** + * Implements hook_theme(). + */ +function field_ui_theme() { + return array( + 'field_ui_display_overview_table' => array( + 'render element' => 'elements', + 'file' => 'field_ui.admin.inc', + 'template' => 'field_ui-display-overview-table', + ), + 'field_ui_table' => array( + 'render element' => 'elements', + ), + ); +} + +/** + * Implements hook_element_info(). + */ +function field_ui_element_info() { + return array( + 'table' => array( + '#theme' => 'field_ui_table', + ), + ); +} + /** * Implements hook_field_attach_create_bundle(). */ diff --git a/modules/field_ui/field_ui.test b/modules/field_ui/field_ui.test index a45e0bcca..4a82c7a2e 100644 --- a/modules/field_ui/field_ui.test +++ b/modules/field_ui/field_ui.test @@ -289,7 +289,7 @@ class FieldUITestCase extends DrupalWebTestCase { // Check that the newly added instance appears on the 'Manage Fields' // screen. $this->drupalGet($bundle_path); - $this->assertFieldByXPath('//table[@id="field-overview"]//span[@class="label-field"]', $instance['label'], t('Field was created and appears in the overview page.')); + $this->assertFieldByXPath('//table[@id="field-overview"]//td[1]', $instance['label'], t('Field was created and appears in the overview page.')); // Check that the instance does not appear in the 'add existing field' row // on other bundles. @@ -338,7 +338,7 @@ class FieldUITestCase extends DrupalWebTestCase { $this->assertRaw(t('Saved %label configuration.', array('%label' => $label)), t('Redirected to "Manage fields" page.')); // Check that the field appears in the overview form. - $this->assertFieldByXPath('//table[@id="field-overview"]//span[@class="label-field"]', $label, t('Field was created and appears in the overview page.')); + $this->assertFieldByXPath('//table[@id="field-overview"]//td[1]', $label, t('Field was created and appears in the overview page.')); } /** @@ -369,7 +369,7 @@ class FieldUITestCase extends DrupalWebTestCase { $this->assertRaw(t('Saved %label configuration.', array('%label' => $label)), t('Redirected to "Manage fields" page.')); // Check that the field appears in the overview form. - $this->assertFieldByXPath('//table[@id="field-overview"]//span[@class="label-field"]', $label, t('Field was created and appears in the overview page.')); + $this->assertFieldByXPath('//table[@id="field-overview"]//td[1]', $label, t('Field was created and appears in the overview page.')); } /** -- cgit v1.2.3