diff --git a/core/modules/field_ui/field_ui.admin.inc b/core/modules/field_ui/field_ui.admin.inc index bd605e54224..1c29e13fae2 100644 --- a/core/modules/field_ui/field_ui.admin.inc +++ b/core/modules/field_ui/field_ui.admin.inc @@ -6,6 +6,8 @@ */ use Drupal\field\FieldInstance; +use Drupal\field_ui\FieldOverview; +use Drupal\field_ui\DisplayOverview; /** * Page callback: Lists all defined fields for quick reference. @@ -100,18 +102,18 @@ function _field_ui_reduce_order($array, $a) { * Returns the region to which a row in the 'Manage fields' screen belongs. * * This function is used as a #region_callback in - * field_ui_field_overview_form(). It is called during + * Drupal\field_ui\DisplayOverview::form(). It is called during * field_ui_table_pre_render(). */ function field_ui_field_overview_row_region($row) { switch ($row['#row_type']) { case 'field': case 'extra_field': - return 'main'; + return 'content'; case 'add_new_field': // If no input in 'label', assume the row has not been dragged out of the // 'add new' section. - return (!empty($row['label']['#value']) ? 'main' : 'add_new'); + return (!empty($row['label']['#value']) ? 'content' : 'hidden'); } } @@ -119,14 +121,14 @@ function field_ui_field_overview_row_region($row) { * Returns the region to which a row in the 'Manage display' screen belongs. * * This function is used as a #region_callback in - * field_ui_field_overview_form(), and is called during + * Drupal\field_ui\FieldOverview::form(), and is called during * field_ui_table_pre_render(). */ function field_ui_display_overview_row_region($row) { switch ($row['#row_type']) { case 'field': case 'extra_field': - return ($row['format']['type']['#value'] == 'hidden' ? 'hidden' : 'visible'); + return ($row['format']['type']['#value'] == 'hidden' ? 'hidden' : 'content'); } } @@ -241,7 +243,7 @@ function theme_field_ui_table($variables) { $region_name_class = drupal_html_class($region_name); // Add region rows. - if (isset($region['title'])) { + if (isset($region['title']) && empty($region['invisible'])) { $table['rows'][] = array( 'class' => array('region-title', 'region-' . $region_name_class . '-title'), 'no_striping' => TRUE, @@ -290,437 +292,34 @@ function theme_field_ui_table($variables) { } /** - * Form constructor for the 'Manage fields' form of a bundle. + * Returns the built and processed 'Manage fields' form of a bundle. * * The resulting form allows fields and pseudo-fields to be re-ordered. * + * @param string $entity_type + * The entity type for the fieldable entity. + * @param string $bundle + * The bundle for the fieldable entity. + * + * @return + * The processed form for the given entity type and bundle. + * * @see field_ui_menu() * @see field_ui_field_overview_form_validate() * @see field_ui_field_overview_form_submit() * @ingroup forms */ -function field_ui_field_overview_form($form, &$form_state, $entity_type, $bundle) { +function field_ui_field_overview($entity_type, $bundle) { $bundle = field_extract_bundle($entity_type, $bundle); - field_ui_inactive_message($entity_type, $bundle); - $admin_path = _field_ui_bundle_admin_path($entity_type, $bundle); - // When displaying the form, make sure the list of fields is up-to-date. - if (empty($form_state['post'])) { - field_info_cache_clear(); - } + $field_overview = new FieldOverview($entity_type, $bundle); - // Gather bundle information. - $instances = field_info_instances($entity_type, $bundle); - $field_types = field_info_field_types(); + $form_state = array(); + $form_state['build_info']['callback'] = array($field_overview, 'form'); + $form_state['build_info']['args'] = array($entity_type, $bundle); - $extra_fields = field_info_extra_fields($entity_type, $bundle, 'form'); - - $form += array( - '#entity_type' => $entity_type, - '#bundle' => $bundle, - '#fields' => array_keys($instances), - '#extra' => array_keys($extra_fields), - ); - - $table = array( - '#type' => 'field_ui_table', - '#tree' => TRUE, - '#header' => array( - t('Label'), - t('Weight'), - t('Parent'), - t('Machine name'), - t('Field type'), - t('Widget'), - t('Operations'), - ), - '#parent_options' => array(), - '#regions' => array( - 'main' => array('message' => t('No fields are present yet.')), - 'add_new' => array('title' => ' '), - ), - '#attributes' => array( - 'class' => array('field-ui-overview'), - 'id' => 'field-overview', - ), - ); - - // Fields. - foreach ($instances as $name => $instance) { - $field = field_info_field($instance['field_name']); - $admin_field_path = $admin_path . '/fields/' . $instance['field_name']; - $widget_definition = $instance->getWidget()->getDefinition(); - - $table[$name] = array( - '#attributes' => array('class' => array('draggable', 'tabledrag-leaf')), - '#row_type' => 'field', - '#region_callback' => 'field_ui_field_overview_row_region', - 'label' => array( - '#markup' => check_plain($instance['label']), - ), - 'weight' => array( - '#type' => 'textfield', - '#title' => t('Weight for @title', array('@title' => $instance['label'])), - '#title_display' => 'invisible', - '#default_value' => $instance['widget']['weight'], - '#size' => 3, - '#attributes' => array('class' => array('field-weight')), - ), - 'parent_wrapper' => array( - 'parent' => array( - '#type' => 'select', - '#title' => t('Parent for @title', array('@title' => $instance['label'])), - '#title_display' => 'invisible', - '#options' => $table['#parent_options'], - '#empty_value' => '', - '#attributes' => array('class' => array('field-parent')), - '#parents' => array('fields', $name, 'parent'), - ), - 'hidden_name' => array( - '#type' => 'hidden', - '#default_value' => $name, - '#attributes' => array('class' => array('field-name')), - ), - ), - 'field_name' => array( - '#markup' => $instance['field_name'], - ), - 'type' => array( - '#type' => 'link', - '#title' => t($field_types[$field['type']]['label']), - '#href' => $admin_field_path . '/field-settings', - '#options' => array('attributes' => array('title' => t('Edit field settings.'))), - ), - 'widget_type' => array( - '#type' => 'link', - '#title' => $widget_definition['label'], - '#href' => $admin_field_path . '/widget-type', - '#options' => array('attributes' => array('title' => t('Change widget type.'))), - ), - ); - $links = array(); - $links['edit'] = array( - 'title' => t('edit'), - 'href' => $admin_field_path, - 'attributes' => array('title' => t('Edit instance settings.')), - ); - $links['delete'] = array( - 'title' => t('delete'), - 'href' => "$admin_field_path/delete", - 'attributes' => array('title' => t('Delete instance.')), - ); - $table[$name]['operations']['data'] = array( - '#type' => 'operations', - '#links' => $links, - ); - - if (!empty($instance['locked'])) { - $table[$name]['operations'] = array('#value' => t('Locked')); - $table[$name]['#attributes']['class'][] = 'menu-disabled'; - } - } - - // Non-field elements. - foreach ($extra_fields as $name => $extra_field) { - $table[$name] = array( - '#attributes' => array('class' => array('draggable', 'tabledrag-leaf')), - '#row_type' => 'extra_field', - '#region_callback' => 'field_ui_field_overview_row_region', - 'label' => array( - '#markup' => check_plain($extra_field['label']), - ), - 'weight' => array( - '#type' => 'textfield', - '#default_value' => $extra_field['weight'], - '#size' => 3, - '#attributes' => array('class' => array('field-weight')), - '#title_display' => 'invisible', - '#title' => t('Weight for @title', array('@title' => $extra_field['label'])), - ), - 'parent_wrapper' => array( - 'parent' => array( - '#type' => 'select', - '#title' => t('Parent for @title', array('@title' => $extra_field['label'])), - '#title_display' => 'invisible', - '#options' => $table['#parent_options'], - '#empty_value' => '', - '#attributes' => array('class' => array('field-parent')), - '#parents' => array('fields', $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), - ), - 'operations' => array( - '#markup' => '', - ), - ); - } - - // Additional row: add new field. - $max_weight = field_info_max_weight($entity_type, $bundle, 'form'); - $field_type_options = field_ui_field_type_options(); - $widget_type_options = field_ui_widget_type_options(NULL, TRUE); - if ($field_type_options && $widget_type_options) { - $name = '_add_new_field'; - $table[$name] = array( - '#attributes' => array('class' => array('draggable', 'tabledrag-leaf', 'add-new')), - '#row_type' => 'add_new_field', - '#region_callback' => 'field_ui_field_overview_row_region', - 'label' => array( - '#type' => 'textfield', - '#title' => t('New field label'), - '#title_display' => 'invisible', - '#size' => 15, - '#description' => t('Label'), - '#prefix' => '
' . t('Add new field') .'
', - '#suffix' => '
', - ), - 'weight' => array( - '#type' => 'textfield', - '#default_value' => $max_weight + 1, - '#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', - '#title' => t('Parent for new field'), - '#title_display' => 'invisible', - '#options' => $table['#parent_options'], - '#empty_value' => '', - '#attributes' => array('class' => array('field-parent')), - '#prefix' => '
 
', - '#parents' => array('fields', $name, 'parent'), - ), - 'hidden_name' => array( - '#type' => 'hidden', - '#default_value' => $name, - '#attributes' => array('class' => array('field-name')), - ), - ), - 'field_name' => array( - '#type' => 'machine_name', - '#title' => t('New field name'), - '#title_display' => 'invisible', - // This field should stay LTR even for RTL languages. - '#field_prefix' => 'field_', - '#field_suffix' => '‎', - '#size' => 15, - '#description' => t('A unique machine-readable name containing letters, numbers, and underscores.'), - // 32 characters minus the 'field_' prefix. - '#maxlength' => 26, - '#prefix' => '
 
', - '#machine_name' => array( - 'source' => array('fields', $name, 'label'), - 'exists' => '_field_ui_field_name_exists', - 'standalone' => TRUE, - 'label' => '', - ), - '#required' => FALSE, - ), - 'type' => array( - '#type' => 'select', - '#title' => t('Type of new field'), - '#title_display' => 'invisible', - '#options' => $field_type_options, - '#empty_option' => t('- Select a field type -'), - '#description' => t('Type of data to store.'), - '#attributes' => array('class' => array('field-type-select')), - '#prefix' => '
 
', - ), - 'widget_type' => array( - '#type' => 'select', - '#title' => t('Widget for new field'), - '#title_display' => 'invisible', - '#options' => $widget_type_options, - '#empty_option' => t('- Select a widget -'), - '#description' => t('Form element to edit the data.'), - '#attributes' => array('class' => array('widget-type-select')), - '#cell_attributes' => array('colspan' => 3), - '#prefix' => '
 
', - ), - // Place the 'translatable' property as an explicit value so that contrib - // modules can form_alter() the value for newly created fields. - 'translatable' => array( - '#type' => 'value', - '#value' => FALSE, - ), - ); - } - - // Additional row: re-use existing field. - $existing_fields = field_ui_existing_field_options($entity_type, $bundle); - if ($existing_fields && $widget_type_options) { - // Build list of options. - $existing_field_options = array(); - foreach ($existing_fields as $field_name => $info) { - $text = t('@type: @field (@label)', array( - '@type' => $info['type_label'], - '@label' => $info['label'], - '@field' => $info['field'], - )); - $existing_field_options[$field_name] = truncate_utf8($text, 80, FALSE, TRUE); - } - asort($existing_field_options); - $name = '_add_existing_field'; - $table[$name] = array( - '#attributes' => array('class' => array('draggable', 'tabledrag-leaf', 'add-new')), - '#row_type' => 'add_new_field', - '#region_callback' => 'field_ui_field_overview_row_region', - 'label' => array( - '#type' => 'textfield', - '#title' => t('Existing field label'), - '#title_display' => 'invisible', - '#size' => 15, - '#description' => t('Label'), - '#attributes' => array('class' => array('label-textfield')), - '#prefix' => '
' . t('Re-use existing field') .'
', - '#suffix' => '
', - ), - 'weight' => array( - '#type' => 'textfield', - '#default_value' => $max_weight + 2, - '#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', - '#title' => t('Parent for existing field'), - '#title_display' => 'invisible', - '#options' => $table['#parent_options'], - '#empty_value' => '', - '#attributes' => array('class' => array('field-parent')), - '#prefix' => '
 
', - '#parents' => array('fields', $name, 'parent'), - ), - 'hidden_name' => array( - '#type' => 'hidden', - '#default_value' => $name, - '#attributes' => array('class' => array('field-name')), - ), - ), - 'field_name' => array( - '#type' => 'select', - '#title' => t('Existing field to share'), - '#title_display' => 'invisible', - '#options' => $existing_field_options, - '#empty_option' => t('- Select an existing field -'), - '#description' => t('Field to share'), - '#attributes' => array('class' => array('field-select')), - '#cell_attributes' => array('colspan' => 2), - '#prefix' => '
 
', - ), - 'widget_type' => array( - '#type' => 'select', - '#title' => t('Widget for existing field'), - '#title_display' => 'invisible', - '#options' => $widget_type_options, - '#empty_option' => t('- Select a widget -'), - '#description' => t('Form element to edit the data.'), - '#attributes' => array('class' => array('widget-type-select')), - '#cell_attributes' => array('colspan' => 3), - '#prefix' => '
 
', - ), - ); - } - $form['fields'] = $table; - - $form['actions'] = array('#type' => 'actions'); - $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save')); - - $form['#attached']['library'][] = array('field_ui', 'drupal.field_ui'); - - // Add settings for the update selects behavior. - $js_fields = array(); - foreach ($existing_fields as $field_name => $info) { - $js_fields[$field_name] = array('label' => $info['label'], 'type' => $info['type'], 'widget' => $info['widget_type']); - } - - $form['#attached']['js'][] = array( - 'type' => 'setting', - 'data' => array('fields' => $js_fields, 'fieldWidgetTypes' => field_ui_widget_type_options()), - ); - - // 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'); - - return $form; -} - -/** - * Form validation handler for field_ui_field_overview_form(). - * - * @see field_ui_field_overview_form_submit() - */ -function field_ui_field_overview_form_validate($form, &$form_state) { - _field_ui_field_overview_form_validate_add_new($form, $form_state); - _field_ui_field_overview_form_validate_add_existing($form, $form_state); -} - -/** - * Validates the 'add new field' row of field_ui_field_overview_form(). - * - * @see field_ui_field_overview_form_validate() - */ -function _field_ui_field_overview_form_validate_add_new($form, &$form_state) { - $field = $form_state['values']['fields']['_add_new_field']; - - // Validate if any information was provided in the 'add new field' row. - if (array_filter(array($field['label'], $field['field_name'], $field['type'], $field['widget_type']))) { - // Missing label. - if (!$field['label']) { - form_set_error('fields][_add_new_field][label', t('Add new field: you need to provide a label.')); - } - - // Missing field name. - if (!$field['field_name']) { - form_set_error('fields][_add_new_field][field_name', t('Add new field: you need to provide a field name.')); - } - // Field name validation. - else { - $field_name = $field['field_name']; - - // Add the 'field_' prefix. - $field_name = 'field_' . $field_name; - form_set_value($form['fields']['_add_new_field']['field_name'], $field_name, $form_state); - } - - // Missing field type. - if (!$field['type']) { - form_set_error('fields][_add_new_field][type', t('Add new field: you need to select a field type.')); - } - - // Missing widget type. - if (!$field['widget_type']) { - form_set_error('fields][_add_new_field][widget_type', t('Add new field: you need to select a widget.')); - } - // Wrong widget type. - elseif ($field['type']) { - $widget_types = field_ui_widget_type_options($field['type']); - if (!isset($widget_types[$field['widget_type']])) { - form_set_error('fields][_add_new_field][widget_type', t('Add new field: invalid widget.')); - } - } - } + return drupal_build_form('field_ui_field_overview_form', $form_state); } /** @@ -742,688 +341,36 @@ function _field_ui_field_name_exists($value) { } /** - * Validates the 're-use existing field' row of field_ui_field_overview_form(). + * Returns the built and processed 'Manage display' form of a bundle. * - * @see field_ui_field_overview_form_validate() - */ -function _field_ui_field_overview_form_validate_add_existing($form, &$form_state) { - // The form element might be absent if no existing fields can be added to - // this bundle. - if (isset($form_state['values']['fields']['_add_existing_field'])) { - $field = $form_state['values']['fields']['_add_existing_field']; - - // Validate if any information was provided in the 're-use existing field' row. - if (array_filter(array($field['label'], $field['field_name'], $field['widget_type']))) { - // Missing label. - if (!$field['label']) { - form_set_error('fields][_add_existing_field][label', t('Re-use existing field: you need to provide a label.')); - } - - // Missing existing field name. - if (!$field['field_name']) { - form_set_error('fields][_add_existing_field][field_name', t('Re-use existing field: you need to select a field.')); - } - - // Missing widget type. - if (!$field['widget_type']) { - form_set_error('fields][_add_existing_field][widget_type', t('Re-use existing field: you need to select a widget.')); - } - // Wrong widget type. - elseif ($field['field_name'] && ($existing_field = field_info_field($field['field_name']))) { - $widget_types = field_ui_widget_type_options($existing_field['type']); - if (!isset($widget_types[$field['widget_type']])) { - form_set_error('fields][_add_existing_field][widget_type', t('Re-use existing field: invalid widget.')); - } - } - } - } -} - -/** - * Form submission handler for field_ui_field_overview_form(). + * The resulting form allows fields and pseudo-fields to be re-ordered. * - * @see field_ui_field_overview_form_validate() - */ -function field_ui_field_overview_form_submit($form, &$form_state) { - $form_values = $form_state['values']['fields']; - $entity_type = $form['#entity_type']; - $bundle = $form['#bundle']; - $admin_path = _field_ui_bundle_admin_path($entity_type, $bundle); - - $bundle_settings = field_bundle_settings($entity_type, $bundle); - - // Update field weights. - foreach ($form_values as $key => $values) { - if (in_array($key, $form['#fields'])) { - $instance = field_read_instance($entity_type, $key, $bundle); - $instance['widget']['weight'] = $values['weight']; - field_update_instance($instance); - } - elseif (in_array($key, $form['#extra'])) { - $bundle_settings['extra_fields']['form'][$key]['weight'] = $values['weight']; - } - } - - field_bundle_settings($entity_type, $bundle, $bundle_settings); - - $destinations = array(); - - // Create new field. - $field = array(); - if (!empty($form_values['_add_new_field']['field_name'])) { - $values = $form_values['_add_new_field']; - - $field = array( - 'field_name' => $values['field_name'], - 'type' => $values['type'], - 'translatable' => $values['translatable'], - ); - $instance = array( - 'field_name' => $field['field_name'], - 'entity_type' => $entity_type, - 'bundle' => $bundle, - 'label' => $values['label'], - 'widget' => array( - 'type' => $values['widget_type'], - 'weight' => $values['weight'], - ), - ); - - // Create the field and instance. - try { - field_create_field($field); - field_create_instance($instance); - - $destinations[] = $admin_path . '/fields/' . $field['field_name'] . '/field-settings'; - $destinations[] = $admin_path . '/fields/' . $field['field_name']; - - // Store new field information for any additional submit handlers. - $form_state['fields_added']['_add_new_field'] = $field['field_name']; - } - catch (Exception $e) { - drupal_set_message(t('There was a problem creating field %label: !message', array('%label' => $instance['label'], '!message' => $e->getMessage())), 'error'); - } - } - - // Re-use existing field. - if (!empty($form_values['_add_existing_field']['field_name'])) { - $values = $form_values['_add_existing_field']; - $field = field_info_field($values['field_name']); - if (!empty($field['locked'])) { - drupal_set_message(t('The field %label cannot be added because it is locked.', array('%label' => $values['label'])), 'error'); - } - else { - $instance = array( - 'field_name' => $field['field_name'], - 'entity_type' => $entity_type, - 'bundle' => $bundle, - 'label' => $values['label'], - 'widget' => array( - 'type' => $values['widget_type'], - 'weight' => $values['weight'], - ), - ); - - try { - field_create_instance($instance); - $destinations[] = $admin_path . '/fields/' . $instance['field_name'] . '/edit'; - // Store new field information for any additional submit handlers. - $form_state['fields_added']['_add_existing_field'] = $instance['field_name']; - } - catch (Exception $e) { - drupal_set_message(t('There was a problem creating field instance %label: @message.', array('%label' => $instance['label'], '@message' => $e->getMessage())), 'error'); - } - } - } - - if ($destinations) { - $destination = drupal_get_destination(); - $destinations[] = $destination['destination']; - unset($_GET['destination']); - $form_state['redirect'] = field_ui_get_destinations($destinations); - } - else { - drupal_set_message(t('Your settings have been saved.')); - } -} - -/** - * Form constructor for the field display settings for a given view mode. + * @param string $entity_type + * The entity type for the fieldable entity. + * @param string $bundle + * The bundle for the fieldable entity. + * @param string $view_mode + * The view mode for the fieldable entity. + * + * @return + * The processed form for the given entity type and bundle. * * @see field_ui_menu() * @see field_ui_display_overview_multistep_submit() - * @see field_ui_display_overview_form_submit() + * @see Drupal\field_ui\DisplayOverview::submit() * @ingroup forms */ -function field_ui_display_overview_form($form, &$form_state, $entity_type, $bundle, $view_mode) { +function field_ui_display_overview($entity_type, $bundle, $view_mode) { $bundle = field_extract_bundle($entity_type, $bundle); - field_ui_inactive_message($entity_type, $bundle); - $admin_path = _field_ui_bundle_admin_path($entity_type, $bundle); - // Gather type information. - $instances = field_info_instances($entity_type, $bundle); - $field_types = field_info_field_types(); - $extra_fields = field_info_extra_fields($entity_type, $bundle, 'display'); + $display_overview = new DisplayOverview($entity_type, $bundle, $view_mode); - $form_state += array( - 'formatter_settings_edit' => NULL, - ); + $form_state = array(); + $form_state['build_info']['callback'] = array($display_overview, 'form'); + $form_state['build_info']['args'] = array($entity_type, $bundle, $view_mode); - $form += array( - '#entity_type' => $entity_type, - '#bundle' => $bundle, - '#view_mode' => $view_mode, - '#fields' => array_keys($instances), - '#extra' => array_keys($extra_fields), - ); - - if (empty($instances) && empty($extra_fields)) { - drupal_set_message(t('There are no fields yet added. You can add new fields on the Manage fields page.', array('@link' => url($admin_path . '/fields'))), 'warning'); - return $form; - } - - $table = array( - '#type' => 'field_ui_table', - '#tree' => TRUE, - '#header' => array( - t('Field'), - t('Weight'), - t('Parent'), - t('Label'), - array('data' => t('Format'), 'colspan' => 3), - ), - '#regions' => array( - 'visible' => array('message' => t('No field is displayed.')), - 'hidden' => array('title' => t('Hidden'), 'message' => t('No field is hidden.')), - ), - '#parent_options' => array(), - '#attributes' => array( - 'class' => array('field-ui-overview'), - 'id' => 'field-display-overview', - ), - // Add Ajax wrapper. - '#prefix' => '
', - '#suffix' => '
', - ); - - $field_label_options = array( - 'above' => t('Above'), - 'inline' => t('Inline'), - 'hidden' => t(''), - ); - $extra_visibility_options = array( - 'visible' => t('Visible'), - 'hidden' => t('Hidden'), - ); - - // Field rows. - foreach ($instances as $name => $instance) { - $field = field_info_field($instance['field_name']); - - // Provide default settings if needed. - if (isset($instance['display'][$view_mode])) { - $display = $instance['display'][$view_mode]; - } - else { - $display = array( - 'type' => 'hidden', - 'label' => 'above', - 'settings' => array(), - 'weight' => 0, - ); - } - - $table[$name] = array( - '#attributes' => array('class' => array('draggable', 'tabledrag-leaf')), - '#row_type' => 'field', - '#region_callback' => 'field_ui_display_overview_row_region', - '#js_settings' => array( - 'rowHandler' => 'field', - 'defaultFormatter' => $field_types[$field['type']]['default_formatter'], - ), - 'human_name' => array( - '#markup' => check_plain($instance['label']), - ), - 'weight' => array( - '#type' => 'textfield', - '#title' => t('Weight for @title', array('@title' => $instance['label'])), - '#title_display' => 'invisible', - '#default_value' => $display['weight'], - '#size' => 3, - '#attributes' => array('class' => array('field-weight')), - ), - 'parent_wrapper' => array( - 'parent' => array( - '#type' => 'select', - '#title' => t('Label display for @title', array('@title' => $instance['label'])), - '#title_display' => 'invisible', - '#options' => $table['#parent_options'], - '#empty_value' => '', - '#attributes' => array('class' => array('field-parent')), - '#parents' => array('fields', $name, 'parent'), - ), - 'hidden_name' => array( - '#type' => 'hidden', - '#default_value' => $name, - '#attributes' => array('class' => array('field-name')), - ), - ), - 'label' => array( - '#type' => 'select', - '#title' => t('Label display for @title', array('@title' => $instance['label'])), - '#title_display' => 'invisible', - '#options' => $field_label_options, - '#default_value' => $display['label'], - ), - ); - - $formatter_options = field_ui_formatter_options($field['type']); - $formatter_options['hidden'] = t(''); - $table[$name]['format'] = array( - 'type' => array( - '#type' => 'select', - '#title' => t('Formatter for @title', array('@title' => $instance['label'])), - '#title_display' => 'invisible', - '#options' => $formatter_options, - '#default_value' => $display['type'], - '#parents' => array('fields', $name, 'type'), - '#attributes' => array('class' => array('field-formatter-type')), - ), - 'settings_edit_form' => array(), - ); - - // Formatter settings. - - // Check the currently selected formatter, and merge persisted values for - // formatter settings. - if (isset($form_state['values']['fields'][$name]['type'])) { - $display['type'] = $form_state['values']['fields'][$name]['type']; - } - if (isset($form_state['formatter_settings'][$name])) { - $display['settings'] = $form_state['formatter_settings'][$name]; - } - $formatter = $instance->getFormatter($display); - - // Base button element for the various formatter settings actions. - $base_button = array( - '#submit' => array('field_ui_display_overview_multistep_submit'), - '#ajax' => array( - 'callback' => 'field_ui_display_overview_multistep_js', - 'wrapper' => 'field-display-overview-wrapper', - 'effect' => 'fade', - ), - '#field_name' => $name, - ); - - if ($form_state['formatter_settings_edit'] == $name) { - // We are currently editing this field's formatter settings. Display the - // settings form and submit buttons. - $table[$name]['format']['settings_edit_form'] = array(); - - if ($formatter) { - $formatter_type_info = $formatter->getDefinition(); - - // Generate the settings form and allow other modules to alter it. - $settings_form = $formatter->settingsForm($form, $form_state); - $context = array( - 'formatter' => $formatter, - 'field' => $field, - 'instance' => $instance, - 'view_mode' => $view_mode, - 'form' => $form, - ); - drupal_alter('field_formatter_settings_form', $settings_form, $form_state, $context); - - if ($settings_form) { - $table[$name]['format']['#cell_attributes'] = array('colspan' => 3); - $table[$name]['format']['settings_edit_form'] = array( - '#type' => 'container', - '#attributes' => array('class' => array('field-formatter-settings-edit-form')), - '#parents' => array('fields', $name, 'settings_edit_form'), - 'label' => array( - '#markup' => t('Format settings:') . ' ' . $formatter_type_info['label'] . '', - ), - 'settings' => $settings_form, - 'actions' => array( - '#type' => 'actions', - 'save_settings' => $base_button + array( - '#type' => 'submit', - '#name' => $name . '_formatter_settings_update', - '#value' => t('Update'), - '#op' => 'update', - ), - 'cancel_settings' => $base_button + array( - '#type' => 'submit', - '#name' => $name . '_formatter_settings_cancel', - '#value' => t('Cancel'), - '#op' => 'cancel', - // Do not check errors for the 'Cancel' button, but make sure we - // get the value of the 'formatter type' select. - '#limit_validation_errors' => array(array('fields', $name, 'type')), - ), - ), - ); - $table[$name]['#attributes']['class'][] = 'field-formatter-settings-editing'; - } - } - } - else { - $table[$name]['settings_summary'] = array(); - $table[$name]['settings_edit'] = array(); - - if ($formatter) { - // Display a summary of the current formatter settings, and (if the - // summary is not empty) a button to edit them. - $summary = $formatter->settingsSummary(); - - // Allow other modules to alter the summary. - $context = array( - 'formatter' => $formatter, - 'field' => $field, - 'instance' => $instance, - 'view_mode' => $view_mode, - ); - drupal_alter('field_formatter_settings_summary', $summary, $context); - - if ($summary) { - $table[$name]['settings_summary'] = array( - '#markup' => '
' . $summary . '
', - '#cell_attributes' => array('class' => array('field-formatter-summary-cell')), - ); - $table[$name]['settings_edit'] = $base_button + array( - '#type' => 'image_button', - '#name' => $name . '_formatter_settings_edit', - '#src' => 'core/misc/configure-dark.png', - '#attributes' => array('class' => array('field-formatter-settings-edit'), 'alt' => t('Edit')), - '#op' => 'edit', - // Do not check errors for the 'Edit' button, but make sure we get - // the value of the 'formatter type' select. - '#limit_validation_errors' => array(array('fields', $name, 'type')), - '#prefix' => '
', - '#suffix' => '
', - ); - } - } - } - } - - // Non-field elements. - foreach ($extra_fields as $name => $extra_field) { - $display = $extra_field['display'][$view_mode]; - $table[$name] = array( - '#attributes' => array('class' => array('draggable', 'tabledrag-leaf')), - '#row_type' => 'extra_field', - '#region_callback' => 'field_ui_display_overview_row_region', - '#js_settings' => array('rowHandler' => 'field'), - 'human_name' => array( - '#markup' => check_plain($extra_field['label']), - ), - 'weight' => array( - '#type' => 'textfield', - '#title' => t('Weight for @title', array('@title' => $extra_field['label'])), - '#title_display' => 'invisible', - '#default_value' => $display['weight'], - '#size' => 3, - '#attributes' => array('class' => array('field-weight')), - ), - 'parent_wrapper' => array( - 'parent' => array( - '#type' => 'select', - '#title' => t('Parents for @title', array('@title' => $extra_field['label'])), - '#title_display' => 'invisible', - '#options' => $table['#parent_options'], - '#empty_value' => '', - '#attributes' => array('class' => array('field-parent')), - '#parents' => array('fields', $name, 'parent'), - ), - 'hidden_name' => array( - '#type' => 'hidden', - '#default_value' => $name, - '#attributes' => array('class' => array('field-name')), - ), - ), - 'empty_cell' => array( - '#markup' => ' ', - ), - 'format' => array( - 'type' => array( - '#type' => 'select', - '#title' => t('Visibility for @title', array('@title' => $extra_field['label'])), - '#title_display' => 'invisible', - '#options' => $extra_visibility_options, - '#default_value' => $display['visible'] ? 'visible' : 'hidden', - '#parents' => array('fields', $name, 'type'), - '#attributes' => array('class' => array('field-formatter-type')), - ), - ), - 'settings_summary' => array(), - 'settings_edit' => array(), - ); - } - - $form['fields'] = $table; - - // Custom display settings. - if ($view_mode == 'default') { - $entity_info = entity_get_info($entity_type); - $view_modes = $entity_info['view modes']; - // Only show the settings if there is more than one view mode. - if (count($view_modes) > 1) { - $form['modes'] = array( - '#type' => 'fieldset', - '#title' => t('Custom display settings'), - '#collapsible' => TRUE, - '#collapsed' => TRUE, - ); - // Collect options and default values for the 'Custom display settings' - // checkboxes. - $options = array(); - $default = array(); - $view_mode_settings = field_view_mode_settings($entity_type, $bundle); - foreach ($view_modes as $view_mode_name => $view_mode_info) { - $options[$view_mode_name] = $view_mode_info['label']; - if (!empty($view_mode_settings[$view_mode_name]['custom_settings'])) { - $default[] = $view_mode_name; - } - } - $form['modes']['view_modes_custom'] = array( - '#type' => 'checkboxes', - '#title' => t('Use custom display settings for the following view modes'), - '#options' => $options, - '#default_value' => $default, - ); - } - } - - // In overviews involving nested rows from contributed modules (i.e - // field_group), the 'format type' selects can trigger a series of changes in - // child rows. The #ajax behavior is therefore not attached directly to the - // selects, but triggered by the client-side script through a hidden #ajax - // 'Refresh' button. A hidden 'refresh_rows' input tracks the name of - // affected rows. - $form['refresh_rows'] = array('#type' => 'hidden'); - $form['refresh'] = array( - '#type' => 'submit', - '#value' => t('Refresh'), - '#op' => 'refresh_table', - '#submit' => array('field_ui_display_overview_multistep_submit'), - '#ajax' => array( - 'callback' => 'field_ui_display_overview_multistep_js', - 'wrapper' => 'field-display-overview-wrapper', - 'effect' => 'fade', - // The button stays hidden, so we hide the Ajax spinner too. Ad-hoc - // spinners will be added manually by the client-side script. - 'progress' => 'none', - ), - ); - - $form['actions'] = array('#type' => 'actions'); - $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save')); - - $form['#attached']['library'][] = array('field_ui', 'drupal.field_ui'); - - // Add tabledrag behavior. - $form['#attached']['drupal_add_tabledrag'][] = array('field-display-overview', 'order', 'sibling', 'field-weight'); - $form['#attached']['drupal_add_tabledrag'][] = array('field-display-overview', 'match', 'parent', 'field-parent', 'field-parent', 'field-name'); - - return $form; -} - -/** - * Form submission handler for buttons in field_ui_display_overview_form(). - */ -function field_ui_display_overview_multistep_submit($form, &$form_state) { - $trigger = $form_state['triggering_element']; - $op = $trigger['#op']; - - switch ($op) { - case 'edit': - // Store the field whose settings are currently being edited. - $field_name = $trigger['#field_name']; - $form_state['formatter_settings_edit'] = $field_name; - break; - - case 'update': - // Store the saved settings, and set the field back to 'non edit' mode. - $field_name = $trigger['#field_name']; - $values = $form_state['values']['fields'][$field_name]['settings_edit_form']['settings']; - $form_state['formatter_settings'][$field_name] = $values; - unset($form_state['formatter_settings_edit']); - break; - - case 'cancel': - // Set the field back to 'non edit' mode. - unset($form_state['formatter_settings_edit']); - break; - - case 'refresh_table': - // If the currently edited field is one of the rows to be refreshed, set - // it back to 'non edit' mode. - $updated_rows = explode(' ', $form_state['values']['refresh_rows']); - if (isset($form_state['formatter_settings_edit']) && in_array($form_state['formatter_settings_edit'], $updated_rows)) { - unset($form_state['formatter_settings_edit']); - } - break; - } - - $form_state['rebuild'] = TRUE; -} - -/** - * Ajax handler: Handles multistep buttons in field_ui_display_overview_form(). - */ -function field_ui_display_overview_multistep_js($form, &$form_state) { - $trigger = $form_state['triggering_element']; - $op = $trigger['#op']; - - // Pick the elements that need to receive the ajax-new-content effect. - switch ($op) { - case 'edit': - $updated_rows = array($trigger['#field_name']); - $updated_columns = array('format'); - break; - - case 'update': - case 'cancel': - $updated_rows = array($trigger['#field_name']); - $updated_columns = array('format', 'settings_summary', 'settings_edit'); - break; - - case 'refresh_table': - $updated_rows = array_values(explode(' ', $form_state['values']['refresh_rows'])); - $updated_columns = array('settings_summary', 'settings_edit'); - break; - } - - foreach ($updated_rows as $name) { - foreach ($updated_columns as $key) { - $element = &$form['fields'][$name][$key]; - $element['#prefix'] = '
' . (isset($element['#prefix']) ? $element['#prefix'] : ''); - $element['#suffix'] = (isset($element['#suffix']) ? $element['#suffix'] : '') . '
'; - } - } - - // Return the whole table. - return $form['fields']; -} - -/** - * Form submission handler for field_ui_display_overview_form(). - */ -function field_ui_display_overview_form_submit($form, &$form_state) { - $form_values = $form_state['values']; - $entity_type = $form['#entity_type']; - $bundle = $form['#bundle']; - $view_mode = $form['#view_mode']; - - // Save data for 'regular' fields. - foreach ($form['#fields'] as $field_name) { - // Retrieve the stored instance settings to merge with the incoming values. - $instance = field_read_instance($entity_type, $field_name, $bundle); - $values = $form_values['fields'][$field_name]; - // Get formatter settings. They lie either directly in submitted form - // values (if the whole form was submitted while some formatter - // settings were being edited), or have been persisted in - // $form_state. - $settings = array(); - if (isset($values['settings_edit_form']['settings'])) { - $settings = $values['settings_edit_form']['settings']; - } - elseif (isset($form_state['formatter_settings'][$field_name])) { - $settings = $form_state['formatter_settings'][$field_name]; - } - elseif (isset($instance['display'][$view_mode]['settings'])) { - $settings = $instance['display'][$view_mode]['settings']; - } - - // Only save settings actually used by the selected formatter. - $default_settings = field_info_formatter_settings($values['type']); - $settings = array_intersect_key($settings, $default_settings); - - $instance['display'][$view_mode] = array( - 'label' => $values['label'], - 'type' => $values['type'], - 'weight' => $values['weight'], - 'settings' => $settings, - ); - field_update_instance($instance); - } - - // Get current bundle settings. - $bundle_settings = field_bundle_settings($entity_type, $bundle); - - // Save data for 'extra' fields. - foreach ($form['#extra'] as $name) { - $bundle_settings['extra_fields']['display'][$name][$view_mode] = array( - 'weight' => $form_values['fields'][$name]['weight'], - 'visible' => $form_values['fields'][$name]['type'] == 'visible', - ); - } - - // Save view modes data. - if ($view_mode == 'default' && !empty($form_values['view_modes_custom'])) { - $entity_info = entity_get_info($entity_type); - foreach ($form_values['view_modes_custom'] as $view_mode_name => $value) { - // Display a message for each view mode newly configured to use custom - // settings. - $view_mode_settings = field_view_mode_settings($entity_type, $bundle); - if (!empty($value) && empty($view_mode_settings[$view_mode_name]['custom_settings'])) { - $view_mode_label = $entity_info['view modes'][$view_mode_name]['label']; - $path = _field_ui_bundle_admin_path($entity_type, $bundle) . "/display/$view_mode_name"; - drupal_set_message(t('The %view_mode mode now uses custom display settings. You might want to configure them.', array('%view_mode' => $view_mode_label, '@url' => url($path)))); - // Initialize the newly customized view mode with the display settings - // from the default view mode. - _field_ui_add_default_view_mode_settings($entity_type, $bundle, $view_mode_name, $bundle_settings); - } - $bundle_settings['view_modes'][$view_mode_name]['custom_settings'] = !empty($value); - } - } - - // Save updated bundle settings. - field_bundle_settings($entity_type, $bundle, $bundle_settings); - - drupal_set_message(t('Your settings have been saved.')); + return drupal_build_form('field_ui_display_overview_form', $form_state); } /** @@ -1446,7 +393,7 @@ function field_ui_display_overview_form_submit($form, &$form_state) { * An associative array of bundle settings, as expected by * field_bundle_settings(). * - * @see field_ui_display_overview_form_submit(). + * @see Drupal\field_ui\DisplayOverview::submit(). * @see field_bundle_settings() */ function _field_ui_add_default_view_mode_settings($entity_type, $bundle, $view_mode, &$settings) { diff --git a/core/modules/field_ui/field_ui.js b/core/modules/field_ui/field_ui.js index 25366acfc8c..d55f30b29ef 100644 --- a/core/modules/field_ui/field_ui.js +++ b/core/modules/field_ui/field_ui.js @@ -300,7 +300,7 @@ Drupal.fieldUIDisplayOverview.field.prototype = { * Returns the region corresponding to the current form values of the row. */ getRegion: function () { - return (this.$formatSelect.val() === 'hidden') ? 'hidden' : 'visible'; + return (this.$formatSelect.val() === 'hidden') ? 'hidden' : 'content'; }, /** @@ -326,7 +326,9 @@ Drupal.fieldUIDisplayOverview.field.prototype = { // to the new region. var currentValue = this.$formatSelect.val(); var value; - if (region === 'visible') { + // @TODO Check if this couldn't just be like + // if (region !== 'hidden') { + if (region === 'content') { if (currentValue === 'hidden') { // Restore the formatter back to the default formatter. Pseudo-fields do // not have default formatters, we just return to 'visible' for those. diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module index e984b870925..b3dc6f03d4c 100644 --- a/core/modules/field_ui/field_ui.module +++ b/core/modules/field_ui/field_ui.module @@ -103,8 +103,8 @@ function field_ui_menu() { $items["$path/fields"] = array( 'title' => 'Manage fields', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('field_ui_field_overview_form', $entity_type, $bundle_arg), + 'page callback' => 'field_ui_field_overview', + 'page arguments' => array($entity_type, $bundle_arg), 'type' => MENU_LOCAL_TASK, 'weight' => 1, 'file' => 'field_ui.admin.inc', @@ -154,8 +154,8 @@ function field_ui_menu() { // 'Manage display' tab. $items["$path/display"] = array( 'title' => 'Manage display', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('field_ui_display_overview_form', $entity_type, $bundle_arg, 'default'), + 'page callback' => 'field_ui_display_overview', + 'page arguments' => array($entity_type, $bundle_arg, 'default'), 'type' => MENU_LOCAL_TASK, 'weight' => 2, 'file' => 'field_ui.admin.inc', @@ -173,7 +173,8 @@ function field_ui_menu() { foreach ($view_modes as $view_mode => $view_mode_info) { $items["$path/display/$view_mode"] = array( 'title' => $view_mode_info['label'], - 'page arguments' => array('field_ui_display_overview_form', $entity_type, $bundle_arg, $view_mode), + 'page callback' => 'field_ui_display_overview', + 'page arguments' => array($entity_type, $bundle_arg, $view_mode), // The access callback needs to check both the current 'custom // display' setting for the view mode, and the overall access // rules for the bundle admin pages. diff --git a/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverview.php b/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverview.php new file mode 100644 index 00000000000..086f6ee8881 --- /dev/null +++ b/core/modules/field_ui/lib/Drupal/field_ui/DisplayOverview.php @@ -0,0 +1,557 @@ + array( + 'title' => t('Content'), + 'invisible' => TRUE, + 'message' => t('No field is displayed.') + ), + 'hidden' => array( + 'title' => t('Disabled'), + 'message' => t('No field is hidden.') + ), + ); + } + + /** + * Overrides Drupal\field_ui\OverviewBase::form(). + * + * @param array $form + * An associative array containing the structure of the form. + * @param array $form_state + * A reference to a keyed array containing the current state of the form. + * + * @return array + * The array containing the complete form. + */ + public function form(array $form, array &$form_state) { + $form = parent::form($form, $form_state); + + // Gather type information. + $instances = field_info_instances($this->entity_type, $this->bundle); + $field_types = field_info_field_types(); + $extra_fields = field_info_extra_fields($this->entity_type, $this->bundle, 'display'); + + $form_state += array( + 'formatter_settings_edit' => NULL, + ); + + $form += array( + '#entity_type' => $this->entity_type, + '#bundle' => $this->bundle, + '#view_mode' => $this->view_mode, + '#fields' => array_keys($instances), + '#extra' => array_keys($extra_fields), + ); + + if (empty($instances) && empty($extra_fields)) { + drupal_set_message(t('There are no fields yet added. You can add new fields on the Manage fields page.', array('@link' => url($admin_path . '/fields'))), 'warning'); + return $form; + } + + $table = array( + '#type' => 'field_ui_table', + '#tree' => TRUE, + '#header' => array( + t('Field'), + t('Weight'), + t('Parent'), + t('Label'), + array('data' => t('Format'), 'colspan' => 3), + ), + '#regions' => $this->getRegions(), + '#parent_options' => drupal_map_assoc(array_keys($this->getRegions())), + '#attributes' => array( + 'class' => array('field-ui-overview'), + 'id' => 'field-display-overview', + ), + // Add Ajax wrapper. + '#prefix' => '
', + '#suffix' => '
', + ); + + $field_label_options = array( + 'above' => t('Above'), + 'inline' => t('Inline'), + 'hidden' => t(''), + ); + $extra_visibility_options = array( + 'content' => t('Visible'), + 'hidden' => t('Hidden'), + ); + + // Field rows. + foreach ($instances as $name => $instance) { + $field = field_info_field($instance['field_name']); + $display = $instance['display'][$this->view_mode]; + $table[$name] = array( + '#attributes' => array('class' => array('draggable', 'tabledrag-leaf')), + '#row_type' => 'field', + '#region_callback' => 'field_ui_display_overview_row_region', + '#js_settings' => array( + 'rowHandler' => 'field', + 'defaultFormatter' => $field_types[$field['type']]['default_formatter'], + ), + 'human_name' => array( + '#markup' => check_plain($instance['label']), + ), + 'weight' => array( + '#type' => 'textfield', + '#title' => t('Weight for @title', array('@title' => $instance['label'])), + '#title_display' => 'invisible', + '#default_value' => $display['weight'], + '#size' => 3, + '#attributes' => array('class' => array('field-weight')), + ), + 'parent_wrapper' => array( + 'parent' => array( + '#type' => 'select', + '#title' => t('Label display for @title', array('@title' => $instance['label'])), + '#title_display' => 'invisible', + '#options' => $table['#parent_options'], + '#empty_value' => '', + '#attributes' => array('class' => array('field-parent')), + '#parents' => array('fields', $name, 'parent'), + ), + 'hidden_name' => array( + '#type' => 'hidden', + '#default_value' => $name, + '#attributes' => array('class' => array('field-name')), + ), + ), + 'label' => array( + '#type' => 'select', + '#title' => t('Label display for @title', array('@title' => $instance['label'])), + '#title_display' => 'invisible', + '#options' => $field_label_options, + '#default_value' => $display['label'], + ), + ); + + $formatter_options = field_ui_formatter_options($field['type']); + $formatter_options['hidden'] = t(''); + $table[$name]['format'] = array( + 'type' => array( + '#type' => 'select', + '#title' => t('Formatter for @title', array('@title' => $instance['label'])), + '#title_display' => 'invisible', + '#options' => $formatter_options, + '#default_value' => $display['type'], + '#parents' => array('fields', $name, 'type'), + '#attributes' => array('class' => array('field-formatter-type')), + ), + 'settings_edit_form' => array(), + ); + + // Check the currently selected formatter, and merge persisted values for + // formatter settings. + if (isset($form_state['values']['fields'][$name]['type'])) { + $display['type'] = $form_state['values']['fields'][$name]['type']; + } + if (isset($form_state['formatter_settings'][$name])) { + $display['settings'] = $form_state['formatter_settings'][$name]; + } + $formatter = $instance->getFormatter($display); + + // Base button element for the various formatter settings actions. + $base_button = array( + '#submit' => array(array($this, 'multistepSubmit')), + '#ajax' => array( + 'callback' => array($this, 'multistepAjax'), + 'wrapper' => 'field-display-overview-wrapper', + 'effect' => 'fade', + ), + '#field_name' => $name, + ); + + if ($form_state['formatter_settings_edit'] == $name) { + // We are currently editing this field's formatter settings. Display the + // settings form and submit buttons. + $table[$name]['format']['settings_edit_form'] = array(); + + if ($formatter) { + $formatter_type_info = $formatter->getDefinition(); + + // Generate the settings form and allow other modules to alter it. + $settings_form = $formatter->settingsForm($form, $form_state); + $context = array( + 'formatter' => $formatter, + 'field' => $field, + 'instance' => $instance, + 'view_mode' => $this->view_mode, + 'form' => $form, + ); + drupal_alter('field_formatter_settings_form', $settings_form, $form_state, $context); + + if ($settings_form) { + $table[$name]['format']['#cell_attributes'] = array('colspan' => 3); + $table[$name]['format']['settings_edit_form'] = array( + '#type' => 'container', + '#attributes' => array('class' => array('field-formatter-settings-edit-form')), + '#parents' => array('fields', $name, 'settings_edit_form'), + 'label' => array( + '#markup' => t('Format settings:') . ' ' . $formatter_type_info['label'] . '', + ), + 'settings' => $settings_form, + 'actions' => array( + '#type' => 'actions', + 'save_settings' => $base_button + array( + '#type' => 'submit', + '#name' => $name . '_formatter_settings_update', + '#value' => t('Update'), + '#op' => 'update', + ), + 'cancel_settings' => $base_button + array( + '#type' => 'submit', + '#name' => $name . '_formatter_settings_cancel', + '#value' => t('Cancel'), + '#op' => 'cancel', + // Do not check errors for the 'Cancel' button, but make sure we + // get the value of the 'formatter type' select. + '#limit_validation_errors' => array(array('fields', $name, 'type')), + ), + ), + ); + $table[$name]['#attributes']['class'][] = 'field-formatter-settings-editing'; + } + } + } + else { + $table[$name]['settings_summary'] = array(); + $table[$name]['settings_edit'] = array(); + + if ($formatter) { + // Display a summary of the current formatter settings, and (if the + // summary is not empty) a button to edit them. + $summary = $formatter->settingsSummary(); + + // Allow other modules to alter the summary. + $context = array( + 'formatter' => $formatter, + 'field' => $field, + 'instance' => $instance, + 'view_mode' => $this->view_mode, + ); + drupal_alter('field_formatter_settings_summary', $summary, $context); + + if ($summary) { + $table[$name]['settings_summary'] = array( + '#markup' => '
' . $summary . '
', + '#cell_attributes' => array('class' => array('field-formatter-summary-cell')), + ); + $table[$name]['settings_edit'] = $base_button + array( + '#type' => 'image_button', + '#name' => $name . '_formatter_settings_edit', + '#src' => 'core/misc/configure-dark.png', + '#attributes' => array('class' => array('field-formatter-settings-edit'), 'alt' => t('Edit')), + '#op' => 'edit', + // Do not check errors for the 'Edit' button, but make sure we get + // the value of the 'formatter type' select. + '#limit_validation_errors' => array(array('fields', $name, 'type')), + '#prefix' => '
', + '#suffix' => '
', + ); + } + } + } + } + + // Non-field elements. + foreach ($extra_fields as $name => $extra_field) { + $display = $extra_field['display'][$this->view_mode]; + $table[$name] = array( + '#attributes' => array('class' => array('draggable', 'tabledrag-leaf')), + '#row_type' => 'extra_field', + '#region_callback' => 'field_ui_display_overview_row_region', + '#js_settings' => array('rowHandler' => 'field'), + 'human_name' => array( + '#markup' => check_plain($extra_field['label']), + ), + 'weight' => array( + '#type' => 'textfield', + '#title' => t('Weight for @title', array('@title' => $extra_field['label'])), + '#title_display' => 'invisible', + '#default_value' => $display['weight'], + '#size' => 3, + '#attributes' => array('class' => array('field-weight')), + ), + 'parent_wrapper' => array( + 'parent' => array( + '#type' => 'select', + '#title' => t('Parents for @title', array('@title' => $extra_field['label'])), + '#title_display' => 'invisible', + '#options' => $table['#parent_options'], + '#empty_value' => '', + '#attributes' => array('class' => array('field-parent')), + '#parents' => array('fields', $name, 'parent'), + ), + 'hidden_name' => array( + '#type' => 'hidden', + '#default_value' => $name, + '#attributes' => array('class' => array('field-name')), + ), + ), + 'empty_cell' => array( + '#markup' => ' ', + ), + 'format' => array( + 'type' => array( + '#type' => 'select', + '#title' => t('Visibility for @title', array('@title' => $extra_field['label'])), + '#title_display' => 'invisible', + '#options' => $extra_visibility_options, + '#default_value' => $display['visible'] ? 'content' : 'hidden', + '#parents' => array('fields', $name, 'type'), + '#attributes' => array('class' => array('field-formatter-type')), + ), + ), + 'settings_summary' => array(), + 'settings_edit' => array(), + ); + } + + $form['fields'] = $table; + + // Custom display settings. + if ($this->view_mode == 'default') { + $entity_info = entity_get_info($this->entity_type); + $view_modes = $entity_info['view modes']; + // Only show the settings if there is more than one view mode. + if (count($view_modes) > 1) { + $form['modes'] = array( + '#type' => 'fieldset', + '#title' => t('Custom display settings'), + '#collapsible' => TRUE, + '#collapsed' => TRUE, + ); + // Collect options and default values for the 'Custom display settings' + // checkboxes. + $options = array(); + $default = array(); + $view_mode_settings = field_view_mode_settings($this->entity_type, $this->bundle); + foreach ($view_modes as $view_mode_name => $view_mode_info) { + $options[$view_mode_name] = $view_mode_info['label']; + if (!empty($view_mode_settings[$view_mode_name]['custom_settings'])) { + $default[] = $view_mode_name; + } + } + $form['modes']['view_modes_custom'] = array( + '#type' => 'checkboxes', + '#title' => t('Use custom display settings for the following view modes'), + '#options' => $options, + '#default_value' => $default, + ); + } + } + + // In overviews involving nested rows from contributed modules (i.e + // field_group), the 'format type' selects can trigger a series of changes + // in child rows. The #ajax behavior is therefore not attached directly to + // the selects, but triggered by the client-side script through a hidden + // #ajax 'Refresh' button. A hidden 'refresh_rows' input tracks the name of + // affected rows. + $form['refresh_rows'] = array('#type' => 'hidden'); + $form['refresh'] = array( + '#type' => 'submit', + '#value' => t('Refresh'), + '#op' => 'refresh_table', + '#submit' => array(array($this, 'multistepSubmit')), + '#ajax' => array( + 'callback' => array($this, 'multistepAjax'), + 'wrapper' => 'field-display-overview-wrapper', + 'effect' => 'fade', + // The button stays hidden, so we hide the Ajax spinner too. Ad-hoc + // spinners will be added manually by the client-side script. + 'progress' => 'none', + ), + ); + + $form['actions'] = array('#type' => 'actions'); + $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save')); + + $form['#attached']['library'][] = array('field_ui', 'drupal.field_ui'); + + // Add tabledrag behavior. + $form['#attached']['drupal_add_tabledrag'][] = array('field-display-overview', 'order', 'sibling', 'field-weight'); + $form['#attached']['drupal_add_tabledrag'][] = array('field-display-overview', 'match', 'parent', 'field-parent', 'field-parent', 'field-name'); + + return $form; + } + + /** + * Overrides Drupal\field_ui\OverviewBase::submit(). + * + * @param array $form + * An associative array containing the structure of the form. + * @param array $form_state + * A reference to a keyed array containing the current state of the form. + */ + public function submit(array $form, array &$form_state) { + $form_values = $form_state['values']; + + // Save data for 'regular' fields. + foreach ($form['#fields'] as $field_name) { + // Retrieve the stored instance settings to merge with the incoming + // values. + $instance = field_read_instance($this->entity_type, $field_name, $this->bundle); + $values = $form_values['fields'][$field_name]; + // Get formatter settings. They lie either directly in submitted form + // values (if the whole form was submitted while some formatter + // settings were being edited), or have been persisted in + // $form_state. + $settings = array(); + if (isset($values['settings_edit_form']['settings'])) { + $settings = $values['settings_edit_form']['settings']; + } + elseif (isset($form_state['formatter_settings'][$field_name])) { + $settings = $form_state['formatter_settings'][$field_name]; + } + elseif (isset($instance['display'][$this->view_mode]['settings'])) { + $settings = $instance['display'][$this->view_mode]['settings']; + } + + // Only save settings actually used by the selected formatter. + $default_settings = field_info_formatter_settings($values['type']); + $settings = array_intersect_key($settings, $default_settings); + + $instance['display'][$this->view_mode] = array( + 'label' => $values['label'], + 'type' => $values['type'], + 'weight' => $values['weight'], + 'settings' => $settings, + ); + field_update_instance($instance); + } + + // Get current bundle settings. + $bundle_settings = field_bundle_settings($this->entity_type, $this->bundle); + + // Save data for 'extra' fields. + foreach ($form['#extra'] as $name) { + $bundle_settings['extra_fields']['display'][$name][$this->view_mode] = array( + 'weight' => $form_values['fields'][$name]['weight'], + 'visible' => $form_values['fields'][$name]['type'] == 'content', + ); + } + + // Save view modes data. + if ($this->view_mode == 'default' && !empty($form_values['view_modes_custom'])) { + $entity_info = entity_get_info($this->entity_type); + foreach ($form_values['view_modes_custom'] as $view_mode_name => $value) { + // Display a message for each view mode newly configured to use custom + // settings. + $view_mode_settings = field_view_mode_settings($this->entity_type, $this->bundle); + if (!empty($value) && empty($view_mode_settings[$view_mode_name]['custom_settings'])) { + $view_mode_label = $entity_info['view modes'][$view_mode_name]['label']; + $path = _field_ui_bundle_admin_path($this->entity_type, $this->bundle) . "/display/$view_mode_name"; + drupal_set_message(t('The %view_mode mode now uses custom display settings. You might want to configure them.', array('%view_mode' => $view_mode_label, '@url' => url($path)))); + // Initialize the newly customized view mode with the display settings + // from the default view mode. + _field_ui_add_default_view_mode_settings($this->entity_type, $this->bundle, $view_mode_name, $bundle_settings); + } + $bundle_settings['view_modes'][$view_mode_name]['custom_settings'] = !empty($value); + } + } + + // Save updated bundle settings. + field_bundle_settings($this->entity_type, $this->bundle, $bundle_settings); + + drupal_set_message(t('Your settings have been saved.')); + } + + /** + * Form submission handler for multistep buttons. + */ + public function multistepSubmit($form, &$form_state) { + $trigger = $form_state['triggering_element']; + $op = $trigger['#op']; + + switch ($op) { + case 'edit': + // Store the field whose settings are currently being edited. + $field_name = $trigger['#field_name']; + $form_state['formatter_settings_edit'] = $field_name; + break; + + case 'update': + // Store the saved settings, and set the field back to 'non edit' mode. + $field_name = $trigger['#field_name']; + $values = $form_state['values']['fields'][$field_name]['settings_edit_form']['settings']; + $form_state['formatter_settings'][$field_name] = $values; + unset($form_state['formatter_settings_edit']); + break; + + case 'cancel': + // Set the field back to 'non edit' mode. + unset($form_state['formatter_settings_edit']); + break; + + case 'refresh_table': + // If the currently edited field is one of the rows to be refreshed, set + // it back to 'non edit' mode. + $updated_rows = explode(' ', $form_state['values']['refresh_rows']); + if (isset($form_state['formatter_settings_edit']) && in_array($form_state['formatter_settings_edit'], $updated_rows)) { + unset($form_state['formatter_settings_edit']); + } + break; + } + + $form_state['rebuild'] = TRUE; + } + + /** + * Ajax handler for multistep buttons. + */ + public function multistepAjax($form, &$form_state) { + $trigger = $form_state['triggering_element']; + $op = $trigger['#op']; + + // Pick the elements that need to receive the ajax-new-content effect. + switch ($op) { + case 'edit': + $updated_rows = array($trigger['#field_name']); + $updated_columns = array('format'); + break; + + case 'update': + case 'cancel': + $updated_rows = array($trigger['#field_name']); + $updated_columns = array('format', 'settings_summary', 'settings_edit'); + break; + + case 'refresh_table': + $updated_rows = array_values(explode(' ', $form_state['values']['refresh_rows'])); + $updated_columns = array('settings_summary', 'settings_edit'); + break; + } + + foreach ($updated_rows as $name) { + foreach ($updated_columns as $key) { + $element = &$form['fields'][$name][$key]; + $element['#prefix'] = '
' . (isset($element['#prefix']) ? $element['#prefix'] : ''); + $element['#suffix'] = (isset($element['#suffix']) ? $element['#suffix'] : '') . '
'; + } + } + + // Return the whole table. + return $form['fields']; + } +} diff --git a/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php b/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php new file mode 100644 index 00000000000..5629ac9682b --- /dev/null +++ b/core/modules/field_ui/lib/Drupal/field_ui/FieldOverview.php @@ -0,0 +1,641 @@ +entity_type = $entity_type; + $this->bundle = $bundle; + $this->view_mode = 'form'; + $this->adminPath = _field_ui_bundle_admin_path($this->entity_type, $this->bundle); + } + + /** + * Implements Drupal\field_ui\OverviewBase::getRegions(). + */ + public function getRegions() { + return array( + 'content' => array( + 'title' => t('Content'), + 'invisible' => TRUE, + 'message' => t('No fields are present yet.'), + ), + 'hidden' => array( + 'title' => t('Hidden'), + 'invisible' => TRUE, + 'message' => t('No fields.'), + ), + ); + } + + /** + * Overrides Drupal\field_ui\OverviewBase::form(). + * + * @param array $form + * An associative array containing the structure of the form. + * @param array $form_state + * A reference to a keyed array containing the current state of the form. + * + * @return array + * The array containing the complete form. + */ + public function form(array $form, array &$form_state) { + $form = parent::form($form, $form_state); + + // When displaying the form, make sure the list of fields is up-to-date. + if (empty($form_state['post'])) { + field_info_cache_clear(); + } + + // Gather bundle information. + $instances = field_info_instances($this->entity_type, $this->bundle); + $field_types = field_info_field_types(); + $widget_types = field_info_widget_types(); + $extra_fields = field_info_extra_fields($this->entity_type, $this->bundle, 'form'); + + $form += array( + '#entity_type' => $this->entity_type, + '#bundle' => $this->bundle, + '#fields' => array_keys($instances), + '#extra' => array_keys($extra_fields), + ); + + $table = array( + '#type' => 'field_ui_table', + '#tree' => TRUE, + '#header' => array( + t('Label'), + t('Weight'), + t('Parent'), + t('Machine name'), + t('Field type'), + t('Widget'), + t('Operations'), + ), + '#parent_options' => array(), + '#regions' => $this->getRegions(), + '#attributes' => array( + 'class' => array('field-ui-overview'), + 'id' => 'field-overview', + ), + ); + + // Fields. + foreach ($instances as $name => $instance) { + $field = field_info_field($instance['field_name']); + $admin_field_path = $this->adminPath . '/fields/' . $instance['field_name']; + $table[$name] = array( + '#attributes' => array('class' => array('draggable', 'tabledrag-leaf')), + '#row_type' => 'field', + '#region_callback' => 'field_ui_field_overview_row_region', + 'label' => array( + '#markup' => check_plain($instance['label']), + ), + 'weight' => array( + '#type' => 'textfield', + '#title' => t('Weight for @title', array('@title' => $instance['label'])), + '#title_display' => 'invisible', + '#default_value' => $instance['widget']['weight'], + '#size' => 3, + '#attributes' => array('class' => array('field-weight')), + ), + 'parent_wrapper' => array( + 'parent' => array( + '#type' => 'select', + '#title' => t('Parent for @title', array('@title' => $instance['label'])), + '#title_display' => 'invisible', + '#options' => $table['#parent_options'], + '#empty_value' => '', + '#attributes' => array('class' => array('field-parent')), + '#parents' => array('fields', $name, 'parent'), + ), + 'hidden_name' => array( + '#type' => 'hidden', + '#default_value' => $name, + '#attributes' => array('class' => array('field-name')), + ), + ), + 'field_name' => array( + '#markup' => $instance['field_name'], + ), + 'type' => array( + '#type' => 'link', + '#title' => t($field_types[$field['type']]['label']), + '#href' => $admin_field_path . '/field-settings', + '#options' => array('attributes' => array('title' => t('Edit field settings.'))), + ), + 'widget_type' => array( + '#type' => 'link', + '#title' => t($widget_types[$instance['widget']['type']]['label']), + '#href' => $admin_field_path . '/widget-type', + '#options' => array('attributes' => array('title' => t('Change widget type.'))), + ), + ); + + $links = array(); + $links['edit'] = array( + 'title' => t('edit'), + 'href' => $admin_field_path, + 'attributes' => array('title' => t('Edit instance settings.')), + ); + $links['delete'] = array( + 'title' => t('delete'), + 'href' => "$admin_field_path/delete", + 'attributes' => array('title' => t('Delete instance.')), + ); + $table[$name]['operations']['data'] = array( + '#type' => 'operations', + '#links' => $links, + ); + + if (!empty($instance['locked'])) { + $table[$name]['operations'] = array('#value' => t('Locked')); + $table[$name]['#attributes']['class'][] = 'menu-disabled'; + } + } + + // Non-field elements. + foreach ($extra_fields as $name => $extra_field) { + $table[$name] = array( + '#attributes' => array('class' => array('draggable', 'tabledrag-leaf')), + '#row_type' => 'extra_field', + '#region_callback' => 'field_ui_field_overview_row_region', + 'label' => array( + '#markup' => check_plain($extra_field['label']), + ), + 'weight' => array( + '#type' => 'textfield', + '#default_value' => $extra_field['weight'], + '#size' => 3, + '#attributes' => array('class' => array('field-weight')), + '#title_display' => 'invisible', + '#title' => t('Weight for @title', array('@title' => $extra_field['label'])), + ), + 'parent_wrapper' => array( + 'parent' => array( + '#type' => 'select', + '#title' => t('Parent for @title', array('@title' => $extra_field['label'])), + '#title_display' => 'invisible', + '#options' => $table['#parent_options'], + '#empty_value' => '', + '#attributes' => array('class' => array('field-parent')), + '#parents' => array('fields', $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), + ), + 'operations' => array( + '#markup' => '', + ), + ); + } + + // Additional row: add new field. + $max_weight = field_info_max_weight($this->entity_type, $this->bundle, 'form'); + $field_type_options = field_ui_field_type_options(); + $widget_type_options = field_ui_widget_type_options(NULL, TRUE); + if ($field_type_options && $widget_type_options) { + $name = '_add_new_field'; + $table[$name] = array( + '#attributes' => array('class' => array('draggable', 'tabledrag-leaf', 'add-new')), + '#row_type' => 'add_new_field', + '#region_callback' => 'field_ui_field_overview_row_region', + 'label' => array( + '#type' => 'textfield', + '#title' => t('New field label'), + '#title_display' => 'invisible', + '#size' => 15, + '#description' => t('Label'), + '#prefix' => '
' . t('Add new field') .'
', + '#suffix' => '
', + ), + 'weight' => array( + '#type' => 'textfield', + '#default_value' => $max_weight + 1, + '#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', + '#title' => t('Parent for new field'), + '#title_display' => 'invisible', + '#options' => $table['#parent_options'], + '#empty_value' => '', + '#attributes' => array('class' => array('field-parent')), + '#prefix' => '
 
', + '#parents' => array('fields', $name, 'parent'), + ), + 'hidden_name' => array( + '#type' => 'hidden', + '#default_value' => $name, + '#attributes' => array('class' => array('field-name')), + ), + ), + 'field_name' => array( + '#type' => 'machine_name', + '#title' => t('New field name'), + '#title_display' => 'invisible', + // This field should stay LTR even for RTL languages. + '#field_prefix' => 'field_', + '#field_suffix' => '‎', + '#size' => 15, + '#description' => t('A unique machine-readable name containing letters, numbers, and underscores.'), + // 32 characters minus the 'field_' prefix. + '#maxlength' => 26, + '#prefix' => '
 
', + '#machine_name' => array( + 'source' => array('fields', $name, 'label'), + 'exists' => '_field_ui_field_name_exists', + 'standalone' => TRUE, + 'label' => '', + ), + '#required' => FALSE, + ), + 'type' => array( + '#type' => 'select', + '#title' => t('Type of new field'), + '#title_display' => 'invisible', + '#options' => $field_type_options, + '#empty_option' => t('- Select a field type -'), + '#description' => t('Type of data to store.'), + '#attributes' => array('class' => array('field-type-select')), + '#prefix' => '
 
', + ), + 'widget_type' => array( + '#type' => 'select', + '#title' => t('Widget for new field'), + '#title_display' => 'invisible', + '#options' => $widget_type_options, + '#empty_option' => t('- Select a widget -'), + '#description' => t('Form element to edit the data.'), + '#attributes' => array('class' => array('widget-type-select')), + '#cell_attributes' => array('colspan' => 3), + '#prefix' => '
 
', + ), + // Place the 'translatable' property as an explicit value so that + // contrib modules can form_alter() the value for newly created fields. + 'translatable' => array( + '#type' => 'value', + '#value' => FALSE, + ), + ); + } + + // Additional row: re-use existing field. + $existing_fields = field_ui_existing_field_options($this->entity_type, $this->bundle); + if ($existing_fields && $widget_type_options) { + // Build list of options. + $existing_field_options = array(); + foreach ($existing_fields as $field_name => $info) { + $text = t('@type: @field (@label)', array( + '@type' => $info['type_label'], + '@label' => $info['label'], + '@field' => $info['field'], + )); + $existing_field_options[$field_name] = truncate_utf8($text, 80, FALSE, TRUE); + } + asort($existing_field_options); + $name = '_add_existing_field'; + $table[$name] = array( + '#attributes' => array('class' => array('draggable', 'tabledrag-leaf', 'add-new')), + '#row_type' => 'add_new_field', + '#region_callback' => 'field_ui_field_overview_row_region', + 'label' => array( + '#type' => 'textfield', + '#title' => t('Existing field label'), + '#title_display' => 'invisible', + '#size' => 15, + '#description' => t('Label'), + '#attributes' => array('class' => array('label-textfield')), + '#prefix' => '
' . t('Re-use existing field') .'
', + '#suffix' => '
', + ), + 'weight' => array( + '#type' => 'textfield', + '#default_value' => $max_weight + 2, + '#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', + '#title' => t('Parent for existing field'), + '#title_display' => 'invisible', + '#options' => $table['#parent_options'], + '#empty_value' => '', + '#attributes' => array('class' => array('field-parent')), + '#prefix' => '
 
', + '#parents' => array('fields', $name, 'parent'), + ), + 'hidden_name' => array( + '#type' => 'hidden', + '#default_value' => $name, + '#attributes' => array('class' => array('field-name')), + ), + ), + 'field_name' => array( + '#type' => 'select', + '#title' => t('Existing field to share'), + '#title_display' => 'invisible', + '#options' => $existing_field_options, + '#empty_option' => t('- Select an existing field -'), + '#description' => t('Field to share'), + '#attributes' => array('class' => array('field-select')), + '#cell_attributes' => array('colspan' => 2), + '#prefix' => '
 
', + ), + 'widget_type' => array( + '#type' => 'select', + '#title' => t('Widget for existing field'), + '#title_display' => 'invisible', + '#options' => $widget_type_options, + '#empty_option' => t('- Select a widget -'), + '#description' => t('Form element to edit the data.'), + '#attributes' => array('class' => array('widget-type-select')), + '#cell_attributes' => array('colspan' => 3), + '#prefix' => '
 
', + ), + ); + } + $form['fields'] = $table; + + // Add AJAX wrapper. + $form['fields']['#prefix'] = '
'; + $form['fields']['#suffix'] = '
'; + + // This key is used to store the current updated field. + $form_state += array( + 'formatter_settings_edit' => NULL, + ); + + $form['actions'] = array('#type' => 'actions'); + $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save')); + + $form['#attached']['library'][] = array('field_ui', 'drupal.field_ui'); + + // Add settings for the update selects behavior. + $js_fields = array(); + foreach ($existing_fields as $field_name => $info) { + $js_fields[$field_name] = array('label' => $info['label'], 'type' => $info['type'], 'widget' => $info['widget_type']); + } + + $form['#attached']['js'][] = array( + 'type' => 'setting', + 'data' => array('fields' => $js_fields, 'fieldWidgetTypes' => field_ui_widget_type_options()), + ); + + // 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'); + + return $form; + } + + /** + * Overrides Drupal\field_ui\OverviewBase::validate(). + * + * @param array $form + * An associative array containing the structure of the form. + * @param array $form_state + * A reference to a keyed array containing the current state of the form. + */ + public function validate(array $form, array &$form_state) { + $this->validateAddNew($form, $form_state); + $this->validateAddExisting($form, $form_state); + } + + /** + * Validates the 'add new field' row. + * + * @param array $form + * An associative array containing the structure of the form. + * @param array $form_state + * A reference to a keyed array containing the current state of the form. + * + * @see Drupal\field_ui\FieldOverview::validate() + */ + protected function validateAddNew(array $form, array &$form_state) { + $field = $form_state['values']['fields']['_add_new_field']; + + // Validate if any information was provided in the 'add new field' row. + if (array_filter(array($field['label'], $field['field_name'], $field['type'], $field['widget_type']))) { + // Missing label. + if (!$field['label']) { + form_set_error('fields][_add_new_field][label', t('Add new field: you need to provide a label.')); + } + + // Missing field name. + if (!$field['field_name']) { + form_set_error('fields][_add_new_field][field_name', t('Add new field: you need to provide a field name.')); + } + // Field name validation. + else { + $field_name = $field['field_name']; + + // Add the 'field_' prefix. + $field_name = 'field_' . $field_name; + form_set_value($form['fields']['_add_new_field']['field_name'], $field_name, $form_state); + } + + // Missing field type. + if (!$field['type']) { + form_set_error('fields][_add_new_field][type', t('Add new field: you need to select a field type.')); + } + + // Missing widget type. + if (!$field['widget_type']) { + form_set_error('fields][_add_new_field][widget_type', t('Add new field: you need to select a widget.')); + } + // Wrong widget type. + elseif ($field['type']) { + $widget_types = field_ui_widget_type_options($field['type']); + if (!isset($widget_types[$field['widget_type']])) { + form_set_error('fields][_add_new_field][widget_type', t('Add new field: invalid widget.')); + } + } + } + } + + /** + * Validates the 're-use existing field' row. + * + * @param array $form + * An associative array containing the structure of the form. + * @param array $form_state + * A reference to a keyed array containing the current state of the form. + * + * @see Drupal\field_ui\FieldOverview::validate() + */ + protected function validateAddExisting(array $form, array &$form_state) { + // The form element might be absent if no existing fields can be added to + // this bundle. + if (isset($form_state['values']['fields']['_add_existing_field'])) { + $field = $form_state['values']['fields']['_add_existing_field']; + + // Validate if any information was provided in the + // 're-use existing field' row. + if (array_filter(array($field['label'], $field['field_name'], $field['widget_type']))) { + // Missing label. + if (!$field['label']) { + form_set_error('fields][_add_existing_field][label', t('Re-use existing field: you need to provide a label.')); + } + + // Missing existing field name. + if (!$field['field_name']) { + form_set_error('fields][_add_existing_field][field_name', t('Re-use existing field: you need to select a field.')); + } + + // Missing widget type. + if (!$field['widget_type']) { + form_set_error('fields][_add_existing_field][widget_type', t('Re-use existing field: you need to select a widget.')); + } + // Wrong widget type. + elseif ($field['field_name'] && ($existing_field = field_info_field($field['field_name']))) { + $widget_types = field_ui_widget_type_options($existing_field['type']); + if (!isset($widget_types[$field['widget_type']])) { + form_set_error('fields][_add_existing_field][widget_type', t('Re-use existing field: invalid widget.')); + } + } + } + } + } + + /** + * Overrides Drupal\field_ui\OverviewBase::submit(). + * + * @param array $form + * An associative array containing the structure of the form. + * @param array $form_state + * A reference to a keyed array containing the current state of the form. + */ + public function submit(array $form, array &$form_state) { + $form_values = $form_state['values']['fields']; + + $bundle_settings = field_bundle_settings($this->entity_type, $this->bundle); + + // Update field weights. + foreach ($form_values as $key => $values) { + if (in_array($key, $form['#fields'])) { + $instance = field_read_instance($this->entity_type, $key, $this->bundle); + $instance['widget']['weight'] = $values['weight']; + field_update_instance($instance); + } + elseif (in_array($key, $form['#extra'])) { + $bundle_settings['extra_fields']['form'][$key]['weight'] = $values['weight']; + } + } + + field_bundle_settings($this->entity_type, $this->bundle, $bundle_settings); + + $destinations = array(); + + // Create new field. + $field = array(); + if (!empty($form_values['_add_new_field']['field_name'])) { + $values = $form_values['_add_new_field']; + + $field = array( + 'field_name' => $values['field_name'], + 'type' => $values['type'], + 'translatable' => $values['translatable'], + ); + $instance = array( + 'field_name' => $field['field_name'], + 'entity_type' => $this->entity_type, + 'bundle' => $this->bundle, + 'label' => $values['label'], + 'widget' => array( + 'type' => $values['widget_type'], + 'weight' => $values['weight'], + ), + ); + + // Create the field and instance. + try { + field_create_field($field); + field_create_instance($instance); + + $destinations[] = $this->adminPath. '/fields/' . $field['field_name'] . '/field-settings'; + $destinations[] = $this->adminPath . '/fields/' . $field['field_name']; + + // Store new field information for any additional submit handlers. + $form_state['fields_added']['_add_new_field'] = $field['field_name']; + } + catch (Exception $e) { + drupal_set_message(t('There was a problem creating field %label: !message', array('%label' => $instance['label'], '!message' => $e->getMessage())), 'error'); + } + } + + // Re-use existing field. + if (!empty($form_values['_add_existing_field']['field_name'])) { + $values = $form_values['_add_existing_field']; + $field = field_info_field($values['field_name']); + if (!empty($field['locked'])) { + drupal_set_message(t('The field %label cannot be added because it is locked.', array('%label' => $values['label'])), 'error'); + } + else { + $instance = array( + 'field_name' => $field['field_name'], + 'entity_type' => $this->entity_type, + 'bundle' => $this->bundle, + 'label' => $values['label'], + 'widget' => array( + 'type' => $values['widget_type'], + 'weight' => $values['weight'], + ), + ); + + try { + field_create_instance($instance); + $destinations[] = $this->adminPath . '/fields/' . $instance['field_name'] . '/edit'; + // Store new field information for any additional submit handlers. + $form_state['fields_added']['_add_existing_field'] = $instance['field_name']; + } + catch (Exception $e) { + drupal_set_message(t('There was a problem creating field instance %label: @message.', array('%label' => $instance['label'], '@message' => $e->getMessage())), 'error'); + } + } + } + + if ($destinations) { + $destination = drupal_get_destination(); + $destinations[] = $destination['destination']; + unset($_GET['destination']); + $form_state['redirect'] = field_ui_get_destinations($destinations); + } + else { + drupal_set_message(t('Your settings have been saved.')); + } + } +} diff --git a/core/modules/field_ui/lib/Drupal/field_ui/OverviewBase.php b/core/modules/field_ui/lib/Drupal/field_ui/OverviewBase.php new file mode 100644 index 00000000000..c49b3ee7bf3 --- /dev/null +++ b/core/modules/field_ui/lib/Drupal/field_ui/OverviewBase.php @@ -0,0 +1,133 @@ +entity_type = $entity_type; + $this->bundle = $bundle; + $this->view_mode = (isset($view_mode) ? $view_mode : 'default'); + $this->adminPath = _field_ui_bundle_admin_path($this->entity_type, $this->bundle); + } + + /** + * Creates a field UI overview form. + * + * @param array $form + * An associative array containing the structure of the form. + * @param array $form_state + * A reference to a keyed array containing the current state of the form. + * + * @return array + * The array containing the complete form. + */ + public function form(array $form, array &$form_state) { + // Add the validate and submit behavior. + $form['#validate'] = array(array($this, 'validate')); + $form['#submit'] = array(array($this, 'submit')); + return $form; + } + + /** + * Validate handler for the field UI overview form. + * + * @param array $form + * The root element or form. + * @param array $form_state + * The state of the form. + */ + public function validate(array $form, array &$form_state) { + } + + /** + * Submit handler for the field UI overview form. + * + * @param array $form + * An associative array containing the structure of the form. + * @param array $form_state + * A reference to a keyed array containing the current state of the form. + */ + public function submit(array $form, array &$form_state) { + } + + /** + * Get the regions needed to create the overview form. + * + * @return array + * Example usage: + * @code + * return array( + * 'content' => array( + * // label for the region. + * 'title' => t('Content'), + * // Indicates if the region is visible in the UI. + * 'invisible' => TRUE, + * // A mesage to indicate that there is nothing to be displayed in + * // the region. + * 'message' => t('No field is displayed.'), + * ), + * ); + * @endcode + */ + abstract public function getRegions(); + + /** + * Returns an associative array of all regions. + */ + public function getRegionOptions() { + $options = array(); + foreach ($this->getRegions() as $region => $data) { + $options[$region] = $data['title']; + } + return $options; + } + +} diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeTypeInitialLanguageTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeTypeInitialLanguageTest.php index e191ecacf2b..e079a3e6b42 100644 --- a/core/modules/node/lib/Drupal/node/Tests/NodeTypeInitialLanguageTest.php +++ b/core/modules/node/lib/Drupal/node/Tests/NodeTypeInitialLanguageTest.php @@ -118,11 +118,11 @@ class NodeTypeInitialLanguageTest extends NodeTestBase { // Changes Language field visibility to true and check if it is saved. $edit = array( - 'fields[language][type]' => 'visible', + 'fields[language][type]' => 'content', ); $this->drupalPost('admin/structure/types/manage/article/display', $edit, t('Save')); $this->drupalGet('admin/structure/types/manage/article/display'); - $this->assertOptionSelected('edit-fields-language-type', 'visible', 'Language field has been set to visible.'); + $this->assertOptionSelected('edit-fields-language-type', 'content', 'Language field has been set to visible.'); // Loads node page and check if Language field is shown. $this->drupalGet('node/' . $node->nid);