diff --git a/core/lib/Drupal/Core/Entity/ContentEntityForm.php b/core/lib/Drupal/Core/Entity/ContentEntityForm.php index 14e910d..3cd9e51 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityForm.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityForm.php @@ -100,17 +100,6 @@ protected function getBundleEntity() { * {@inheritdoc} */ public function form(array $form, FormStateInterface $form_state) { - - if ($this->showRevisionUi()) { - // Advanced tab must be the first, because other fields rely on that. - if (!isset($form['advanced'])) { - $form['advanced'] = [ - '#type' => 'vertical_tabs', - '#weight' => 99, - ]; - } - } - $form = parent::form($form, $form_state); // Content entity forms do not use the parent's #after_build callback @@ -387,13 +376,12 @@ protected function addRevisionableFormFields(array &$form) { // Add a log field if the "Create new revision" option is checked, or if the // current user has the ability to check that option. + // @todo Convert to a field group. $form['revision_information'] = [ '#type' => 'details', '#title' => $this->t('Revision information'), // Open by default when "Create new revision" is checked. '#open' => $new_revision_default, - '#group' => 'advanced', - '#weight' => 20, '#access' => $new_revision_default || $this->entity->get($entity_type->getKey('revision'))->access('update'), '#optional' => TRUE, '#attributes' => [ diff --git a/core/lib/Drupal/Core/Entity/EntityDisplayBase.php b/core/lib/Drupal/Core/Entity/EntityDisplayBase.php index b6c73e5..d9370f0 100644 --- a/core/lib/Drupal/Core/Entity/EntityDisplayBase.php +++ b/core/lib/Drupal/Core/Entity/EntityDisplayBase.php @@ -163,18 +163,16 @@ protected function init() { if (!isset($this->content[$name]) && !isset($this->hidden[$name])) { // Extra fields are visible by default unless they explicitly say so. if (!isset($definition['visible']) || $definition['visible'] == TRUE) { - $this->content[$name] = array( - 'weight' => $definition['weight'] - ); + $definition += ['region' => $default_region]; + $this->content[$name] = [ + 'weight' => $definition['weight'], + 'region' => $definition['region'], + ]; } else { $this->hidden[$name] = TRUE; } } - // Ensure extra fields have a 'region'. - if (isset($this->content[$name])) { - $this->content[$name] += ['region' => $default_region]; - } } // Fill in defaults for fields. diff --git a/core/lib/Drupal/Core/Render/Element/Actions.php b/core/lib/Drupal/Core/Render/Element/Actions.php index 1f94466..ca9ff6d 100644 --- a/core/lib/Drupal/Core/Render/Element/Actions.php +++ b/core/lib/Drupal/Core/Render/Element/Actions.php @@ -35,8 +35,12 @@ public function getInfo() { // @todo Move this to #pre_render. array($class, 'preRenderActionsDropbutton'), array($class, 'processActions'), + array($class, 'processGroup'), array($class, 'processContainer'), ), + '#pre_render' => array( + array($class, 'preRenderGroup'), + ), '#weight' => 100, '#theme_wrappers' => array('container'), ); diff --git a/core/modules/book/book.module b/core/modules/book/book.module index ecccb74..efdd44a 100644 --- a/core/modules/book/book.module +++ b/core/modules/book/book.module @@ -127,6 +127,25 @@ function book_node_links_alter(array &$links, NodeInterface $node, array &$conte } /** + * Implements hook_entity_extra_field_info(). + */ +function book_entity_extra_field_info() { + $extra = []; + $description = t('Book module element'); + foreach (array_keys(\Drupal::service('entity_type.bundle.info')->getBundleInfo('node')) as $bundle) { + // @todo Convert to a field group. + $extra['node'][$bundle]['form']['book'] = [ + 'label' => t('Book outline'), + 'description' => $description, + 'weight' => 10, + 'region' => 'advanced', + ]; + } + + return $extra; +} + +/** * Implements hook_form_BASE_FORM_ID_alter() for \Drupal\node\NodeForm. * * Adds the book form element to the node form. diff --git a/core/modules/book/src/BookManager.php b/core/modules/book/src/BookManager.php index 60754be..1205806 100644 --- a/core/modules/book/src/BookManager.php +++ b/core/modules/book/src/BookManager.php @@ -159,12 +159,11 @@ public function addFormElements(array $form, FormStateInterface $form_state, Nod if ($form_state->hasValue('book')) { $node->book = $form_state->getValue('book'); } + // @todo Convert to a field group. $form['book'] = array( '#type' => 'details', '#title' => $this->t('Book outline'), - '#weight' => 10, '#open' => !$collapsed, - '#group' => 'advanced', '#attributes' => array( 'class' => array('book-outline-form'), ), diff --git a/core/modules/comment/src/Plugin/Field/FieldWidget/CommentWidget.php b/core/modules/comment/src/Plugin/Field/FieldWidget/CommentWidget.php index 818226d..67aa977 100644 --- a/core/modules/comment/src/Plugin/Field/FieldWidget/CommentWidget.php +++ b/core/modules/comment/src/Plugin/Field/FieldWidget/CommentWidget.php @@ -58,7 +58,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen // If the advanced settings tabs-set is available (normally rendered in the // second column on wide-resolutions), place the field as a details element // in this tab-set. - if (isset($form['advanced'])) { + if ($entity->getEntityType()->showRevisionUi()) { // Get default value from the field. $field_default_values = $this->fieldDefinition->getDefaultValue($entity); @@ -70,7 +70,6 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen // Open the details when the selected value is different to the stored // default values for the field. '#open' => ($items->status != $field_default_values[0]['status']), - '#group' => 'advanced', '#attributes' => array( 'class' => array('comment-' . Html::getClass($entity->getEntityTypeId()) . '-settings-form'), ), diff --git a/core/modules/content_translation/content_translation.module b/core/modules/content_translation/content_translation.module index 70413d9..a3d7725 100644 --- a/core/modules/content_translation/content_translation.module +++ b/core/modules/content_translation/content_translation.module @@ -355,9 +355,11 @@ function content_translation_entity_extra_field_info() { foreach (\Drupal::entityManager()->getDefinitions() as $entity_type => $info) { foreach ($bundle_info_service->getBundleInfo($entity_type) as $bundle => $bundle_info) { if (\Drupal::service('content_translation.manager')->isEnabled($entity_type, $bundle)) { - $extra[$entity_type][$bundle]['form']['translation'] = array( + // @todo Convert to a field group. + $extra[$entity_type][$bundle]['form']['content_translation'] = array( 'label' => t('Translation'), 'description' => t('Translation settings'), + 'region' => 'advanced', 'weight' => 10, ); } diff --git a/core/modules/content_translation/src/ContentTranslationHandler.php b/core/modules/content_translation/src/ContentTranslationHandler.php index c155069..4c6778c 100644 --- a/core/modules/content_translation/src/ContentTranslationHandler.php +++ b/core/modules/content_translation/src/ContentTranslationHandler.php @@ -377,6 +377,7 @@ public function entityFormAlter(array &$form, FormStateInterface $form_state, En // We need to display the translation tab only when there is at least one // translation available or a new one is about to be created. if ($new_translation || $has_translations) { + // @todo Convert to a field group. $form['content_translation'] = array( '#type' => 'details', '#title' => t('Translation'), @@ -386,10 +387,8 @@ public function entityFormAlter(array &$form, FormStateInterface $form_state, En '#multilingual' => TRUE, ); - if (isset($form['advanced'])) { + if ($entity->getEntityType()->showRevisionUi()) { $form['content_translation'] += array( - '#group' => 'advanced', - '#weight' => 100, '#attributes' => array( 'class' => array('entity-translation-options'), ), diff --git a/core/modules/field_layout/field_layout.install b/core/modules/field_layout/field_layout.install index 5956bf1..c0f3bbc 100644 --- a/core/modules/field_layout/field_layout.install +++ b/core/modules/field_layout/field_layout.install @@ -14,6 +14,8 @@ * Implements hook_install(). */ function field_layout_install() { + module_set_weight('field_layout', 20); + // Ensure each entity display has a layout. $entity_save = function (EntityDisplayWithLayoutInterface $entity) { $entity->ensureLayout()->save(); diff --git a/core/modules/field_layout/src/Form/FieldLayoutEntityDisplayFormTrait.php b/core/modules/field_layout/src/Form/FieldLayoutEntityDisplayFormTrait.php index 043e5c7..304831b 100644 --- a/core/modules/field_layout/src/Form/FieldLayoutEntityDisplayFormTrait.php +++ b/core/modules/field_layout/src/Form/FieldLayoutEntityDisplayFormTrait.php @@ -31,10 +31,12 @@ public function getRegions() { $layout_definition = $this->layoutPluginManager->getDefinition($this->getEntity()->getLayoutId()); foreach ($layout_definition->getRegions() as $name => $region) { - $regions[$name] = [ - 'title' => $region['label'], - 'message' => $this->t('No field is displayed.'), - ]; + if (empty($region['hidden'])) { + $regions[$name] = [ + 'title' => $region['label'], + 'message' => $this->t('No field is displayed.'), + ]; + } } $regions['hidden'] = [ diff --git a/core/modules/menu_ui/menu_ui.module b/core/modules/menu_ui/menu_ui.module index 92254c2..cc2ec7e 100644 --- a/core/modules/menu_ui/menu_ui.module +++ b/core/modules/menu_ui/menu_ui.module @@ -257,6 +257,24 @@ function menu_ui_get_menu_link_defaults(NodeInterface $node) { } /** + * Implements hook_entity_extra_field_info(). + */ +function menu_ui_entity_extra_field_info() { + $extra = []; + $description = t('Menu UI module element'); + foreach (array_keys(\Drupal::service('entity_type.bundle.info')->getBundleInfo('node')) as $bundle) { + $extra['node'][$bundle]['form']['menu'] = [ + 'label' => t('Menu settings'), + 'description' => $description, + 'weight' => -2, + 'region' => 'advanced', + ]; + } + + return $extra; +} + +/** * Implements hook_form_BASE_FORM_ID_alter() for \Drupal\node\NodeForm. * * Adds menu item fields to the node form. @@ -295,12 +313,10 @@ function menu_ui_form_node_form_alter(&$form, FormStateInterface $form_state) { '#title' => t('Menu settings'), '#access' => \Drupal::currentUser()->hasPermission('administer menu'), '#open' => (bool) $defaults['id'], - '#group' => 'advanced', '#attached' => array( 'library' => array('menu_ui/drupal.menu_ui'), ), '#tree' => TRUE, - '#weight' => -2, '#attributes' => array('class' => array('menu-link-form')), ); $form['menu']['enabled'] = array( diff --git a/core/modules/node/node.info.yml b/core/modules/node/node.info.yml index 9b53d58..a4f091d 100644 --- a/core/modules/node/node.info.yml +++ b/core/modules/node/node.info.yml @@ -6,4 +6,5 @@ version: VERSION core: 8.x configure: entity.node_type.collection dependencies: + - field_layout - text diff --git a/core/modules/node/node.layouts.yml b/core/modules/node/node.layouts.yml new file mode 100644 index 0000000..66710be --- /dev/null +++ b/core/modules/node/node.layouts.yml @@ -0,0 +1,14 @@ +node_form: + label: 'Node form' + template: templates/layout--node-edit-form + library: node/form + category: 'Columns: 2' + default_region: content + regions: + content: + label: Content + advanced: + label: Advanced + footer: + label: Footer + hidden: true diff --git a/core/modules/node/node.module b/core/modules/node/node.module index d3a83e0..f2a40f7 100644 --- a/core/modules/node/node.module +++ b/core/modules/node/node.module @@ -337,6 +337,7 @@ function node_add_body_field(NodeTypeInterface $type, $label = 'Body') { ->setComponent('body', array( 'type' => 'text_textarea_with_summary', )) + ->setLayoutId('node_form') ->save(); // Assign display settings for the 'default' and 'teaser' view modes. @@ -376,6 +377,22 @@ function node_entity_extra_field_info() { 'weight' => 100, 'visible' => TRUE, ); + // @todo Convert to a field group. + $extra['node'][$bundle->id()]['form']['author'] = [ + 'label' => t('Authoring information'), + 'description' => $description, + 'weight' => 90, + 'region' => 'advanced', + 'visible' => TRUE, + ]; + // @todo Convert to a field group. + $extra['node'][$bundle->id()]['form']['options'] = [ + 'label' => t('Promotion options'), + 'description' => $description, + 'weight' => 95, + 'region' => 'advanced', + 'visible' => TRUE, + ]; } return $extra; diff --git a/core/modules/node/src/NodeForm.php b/core/modules/node/src/NodeForm.php index bb58377..3f4cc1a 100644 --- a/core/modules/node/src/NodeForm.php +++ b/core/modules/node/src/NodeForm.php @@ -97,20 +97,17 @@ public function form(array $form, FormStateInterface $form_state) { $form = parent::form($form, $form_state); - $form['advanced']['#attributes']['class'][] = 'entity-meta'; - // Node author information for administrators. + // @todo Convert to a field group. $form['author'] = array( '#type' => 'details', '#title' => t('Authoring information'), - '#group' => 'advanced', '#attributes' => array( 'class' => array('node-form-author'), ), '#attached' => array( 'library' => array('node/drupal.node'), ), - '#weight' => 90, '#optional' => TRUE, ); @@ -123,17 +120,16 @@ public function form(array $form, FormStateInterface $form_state) { } // Node options for administrators. + // @todo Convert to a field group. $form['options'] = array( '#type' => 'details', '#title' => t('Promotion options'), - '#group' => 'advanced', '#attributes' => array( 'class' => array('node-form-options'), ), '#attached' => array( 'library' => array('node/drupal.node'), ), - '#weight' => 95, '#optional' => TRUE, ); @@ -145,8 +141,6 @@ public function form(array $form, FormStateInterface $form_state) { $form['sticky']['#group'] = 'options'; } - $form['#attached']['library'][] = 'node/form'; - $form['#entity_builders']['update_status'] = '::updateStatus'; return $form; @@ -178,6 +172,7 @@ function updateStatus($entity_type_id, NodeInterface $node, array $form, FormSta */ protected function actions(array $form, FormStateInterface $form_state) { $element = parent::actions($form, $form_state); + $element['#group'] = 'footer'; $node = $this->entity; $preview_mode = $node->type->entity->getPreviewMode(); diff --git a/core/modules/node/templates/layout--node-edit-form.html.twig b/core/modules/node/templates/layout--node-edit-form.html.twig new file mode 100644 index 0000000..3e2097d --- /dev/null +++ b/core/modules/node/templates/layout--node-edit-form.html.twig @@ -0,0 +1,31 @@ +{# +/** + * @file + * Default theme implementation to display a two-column layout. + * + * Available variables: + * - content: The content for this layout. + * - attributes: HTML attributes for the layout
. + * + * @ingroup themeable + */ +#} +{% +set classes = [ +'layout-node-form', +'clearfix', +] +%} +{% if content %} + +
+ {{ content.content }} +
+
+ {{ content.advanced }} +
+ +
+{% endif %} diff --git a/core/modules/path/path.module b/core/modules/path/path.module index 182c6a9..f0fc788 100644 --- a/core/modules/path/path.module +++ b/core/modules/path/path.module @@ -37,15 +37,34 @@ function path_help($route_name, RouteMatchInterface $route_match) { } /** + * Implements hook_entity_extra_field_info(). + */ +function path_entity_extra_field_info() { + $extra = []; + $description = t('Path module element'); + foreach (array_keys(\Drupal::service('entity_type.bundle.info')->getBundleInfo('node')) as $bundle) { + // @todo Convert to a field group. + $extra['node'][$bundle]['form']['path_settings'] = [ + 'label' => t('Path settings'), + 'description' => $description, + 'weight' => 30, + 'region' => 'advanced', + ]; + } + + return $extra; +} + +/** * Implements hook_form_BASE_FORM_ID_alter() for \Drupal\node\NodeForm. */ function path_form_node_form_alter(&$form, FormStateInterface $form_state) { $node = $form_state->getFormObject()->getEntity(); + // @todo Convert to a field group. $form['path_settings'] = array( '#type' => 'details', '#title' => t('URL path settings'), '#open' => !empty($form['path']['widget'][0]['alias']['#value']), - '#group' => 'advanced', '#access' => !empty($form['path']['#access']) && $node->hasField('path') && $node->get('path')->access('edit'), '#attributes' => array( 'class' => array('path-form'), @@ -53,7 +72,6 @@ function path_form_node_form_alter(&$form, FormStateInterface $form_state) { '#attached' => array( 'library' => array('path/drupal.path'), ), - '#weight' => 30, ); $form['path']['#group'] = 'path_settings'; } diff --git a/core/modules/system/system.module b/core/modules/system/system.module index a637443..2b51fe1 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -1436,6 +1436,29 @@ function system_entity_type_build(array &$entity_types) { } /** + * Implements hook_entity_extra_field_info(). + */ +function system_entity_extra_field_info() { + $extra = []; + $description = t('System module element'); + foreach (\Drupal::entityTypeManager()->getDefinitions() as $entity_type_id => $entity_type) { + if ($entity_type->showRevisionUi()) { + foreach (array_keys(\Drupal::service('entity_type.bundle.info')->getBundleInfo($entity_type_id)) as $bundle) { + // @todo Convert to a field group. + $extra[$entity_type_id][$bundle]['form']['revision_information'] = [ + 'label' => t('Revision information'), + 'description' => $description, + 'weight' => 20, + 'region' => 'advanced', + ]; + } + } + } + + return $extra; +} + +/** * Implements hook_block_view_BASE_BLOCK_ID_alter(). */ function system_block_view_system_main_block_alter(array &$build, BlockPluginInterface $block) { diff --git a/core/profiles/standard/config/install/core.entity_form_display.node.article.default.yml b/core/profiles/standard/config/install/core.entity_form_display.node.article.default.yml index c94e36e..76ac1ad 100644 --- a/core/profiles/standard/config/install/core.entity_form_display.node.article.default.yml +++ b/core/profiles/standard/config/install/core.entity_form_display.node.article.default.yml @@ -10,14 +10,25 @@ dependencies: - node.type.article module: - comment + - field_layout - image + - node - path - text +third_party_settings: + field_layout: + id: node_form + settings: { } id: node.article.default targetEntityType: node bundle: article mode: default content: + author: + weight: 90 + region: advanced + settings: { } + third_party_settings: { } body: type: text_textarea_with_summary weight: 1 @@ -29,14 +40,14 @@ content: third_party_settings: { } comment: type: comment_default - weight: 20 - region: content + weight: 10 + region: advanced settings: { } third_party_settings: { } created: type: datetime_timestamp - weight: 10 - region: content + weight: 92 + region: advanced settings: { } third_party_settings: { } field_image: @@ -51,27 +62,56 @@ content: type: entity_reference_autocomplete_tags weight: 3 region: content + settings: + match_operator: CONTAINS + size: 60 + placeholder: '' + third_party_settings: { } + langcode: + type: language_select + weight: 2 + region: content + settings: { } + third_party_settings: { } + menu: + weight: 5 + region: advanced + settings: { } + third_party_settings: { } + options: + weight: 95 + region: advanced settings: { } third_party_settings: { } path: type: path + weight: 31 + region: advanced + settings: { } + third_party_settings: { } + path_settings: weight: 30 - region: content + region: advanced settings: { } third_party_settings: { } promote: type: boolean_checkbox settings: display_label: true - weight: 15 - region: content + weight: 96 + region: advanced + third_party_settings: { } + revision_information: + weight: 20 + region: advanced + settings: { } third_party_settings: { } sticky: type: boolean_checkbox settings: display_label: true - weight: 16 - region: content + weight: 97 + region: advanced third_party_settings: { } title: type: string_textfield @@ -83,8 +123,8 @@ content: third_party_settings: { } uid: type: entity_reference_autocomplete - weight: 5 - region: content + weight: 91 + region: advanced settings: match_operator: CONTAINS size: 60 diff --git a/core/profiles/standard/config/install/core.entity_form_display.node.page.default.yml b/core/profiles/standard/config/install/core.entity_form_display.node.page.default.yml index 0b7ffd1..0307208 100644 --- a/core/profiles/standard/config/install/core.entity_form_display.node.page.default.yml +++ b/core/profiles/standard/config/install/core.entity_form_display.node.page.default.yml @@ -5,8 +5,14 @@ dependencies: - field.field.node.page.body - node.type.page module: + - field_layout + - node - path - text +third_party_settings: + field_layout: + id: node_form + settings: { } id: node.page.default targetEntityType: node bundle: page @@ -24,13 +30,13 @@ content: created: type: datetime_timestamp weight: 10 - region: content + region: advanced settings: { } third_party_settings: { } path: type: path weight: 30 - region: content + region: advanced settings: { } third_party_settings: { } promote: @@ -38,14 +44,14 @@ content: settings: display_label: true weight: 15 - region: content + region: advanced third_party_settings: { } sticky: type: boolean_checkbox settings: display_label: true weight: 16 - region: content + region: advanced third_party_settings: { } title: type: string_textfield @@ -58,7 +64,7 @@ content: uid: type: entity_reference_autocomplete weight: 5 - region: content + region: advanced settings: match_operator: CONTAINS size: 60 diff --git a/core/profiles/standard/standard.info.yml b/core/profiles/standard/standard.info.yml index 82af32e..5788903 100644 --- a/core/profiles/standard/standard.info.yml +++ b/core/profiles/standard/standard.info.yml @@ -19,6 +19,7 @@ dependencies: - block_content - quickedit - editor + - field_layout - help - image - menu_ui diff --git a/core/themes/seven/seven.theme b/core/themes/seven/seven.theme index 64ee724..08ba8b7 100644 --- a/core/themes/seven/seven.theme +++ b/core/themes/seven/seven.theme @@ -153,14 +153,13 @@ function seven_form_node_form_alter(&$form, FormStateInterface $form_state) { /** @var \Drupal\node\NodeInterface $node */ $node = $form_state->getFormObject()->getEntity(); - $form['#theme'] = array('node_edit_form'); $form['#attached']['library'][] = 'seven/node-form'; - $form['advanced']['#type'] = 'container'; $is_new = !$node->isNew() ? format_date($node->getChangedTime(), 'short') : t('Not saved yet'); $form['meta'] = array( '#attributes' => array('class' => array('entity-meta__header')), '#type' => 'container', + // @todo Convert to a layout. '#group' => 'advanced', '#weight' => -100, 'published' => array(