diff --git a/core/composer.json b/core/composer.json index 53ab8fa..862b5a3 100644 --- a/core/composer.json +++ b/core/composer.json @@ -94,6 +94,7 @@ "drupal/editor": "self.version", "drupal/entity_reference": "self.version", "drupal/field": "self.version", + "drupal/field_layout": "self.version", "drupal/field_ui": "self.version", "drupal/file": "self.version", "drupal/filter": "self.version", diff --git a/core/modules/field_layout/config/schema/field_layout.schema.yml b/core/modules/field_layout/config/schema/field_layout.schema.yml new file mode 100644 index 0000000..29840c8 --- /dev/null +++ b/core/modules/field_layout/config/schema/field_layout.schema.yml @@ -0,0 +1,10 @@ +core.entity_view_display.*.*.*.third_party.field_layout: + type: sequence + label: 'Per-view mode field layout settings' + sequence: + type: mapping + label: 'Fields' + mapping: + region: + type: string + label: 'Region' diff --git a/core/modules/field_layout/field_layout.info.yml b/core/modules/field_layout/field_layout.info.yml new file mode 100644 index 0000000..a1951da --- /dev/null +++ b/core/modules/field_layout/field_layout.info.yml @@ -0,0 +1,8 @@ +name: 'Field Layout' +type: module +description: '@todo.' +package: Core (Experimental) +version: VERSION +core: 8.x +dependencies: + - field_ui diff --git a/core/modules/field_layout/field_layout.libraries.yml b/core/modules/field_layout/field_layout.libraries.yml new file mode 100644 index 0000000..8e3d53e --- /dev/null +++ b/core/modules/field_layout/field_layout.libraries.yml @@ -0,0 +1,10 @@ +drupal.field_layout: + version: VERSION + js: + js/field_layout.js: {} + dependencies: + - core/jquery + - core/jquery.once + - core/drupal + - core/drupal.form + - core/drupalSettings diff --git a/core/modules/field_layout/field_layout.module b/core/modules/field_layout/field_layout.module new file mode 100644 index 0000000..f0ef20b --- /dev/null +++ b/core/modules/field_layout/field_layout.module @@ -0,0 +1,89 @@ +' . t('About') . ''; + $output .= '

' . t('@todo.') . '

'; + return $output; + } +} + +/** + * Implements hook_entity_type_alter(). + */ +function field_layout_entity_type_alter(array &$entity_types) { + /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */ + $entity_types['entity_view_display']->setFormClass('edit', FieldLayoutEntityViewDisplayEditForm::class); +} + +/** + * @todo. + * + * @return array + */ +function _field_layout_get_layout() { + $layouts = [ + '1col_stacked' => [ + 'label' => t('One column stacked'), + 'regions' => [ + 'top' => [ + 'label' => t('Top'), + ], + 'bottom' => [ + 'label' => t('Bottom'), + ], + ], + ], + '2col' => [ + 'label' => t('Two column'), + 'regions' => [ + 'left' => [ + 'label' => t('Left'), + ], + 'right' => [ + 'label' => t('Right'), + ], + ], + ], + ]; + return $layouts['1col_stacked']; +} + +/** + * Implements hook_entity_view_alter(). + */ +function field_layout_entity_view_alter(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display) { + if (!$field_layout = $display->getThirdPartySettings('field_layout')) { + return; + } + + // Add the regions to the $build in the correct order. + $regions = array_keys(_field_layout_get_layout()['regions']); + foreach ($regions as $region) { + // @todo Reconsider using region as a wrapper. + $build[$region]['#theme_wrappers'][] = 'region'; + $build[$region]['#region'] = $region; + } + + foreach ($display->getComponents() as $name => $component) { + if (isset($build[$name]) && isset($field_layout[$name]['region'])) { + $region = $field_layout[$name]['region']; + $build[$region][$name] = $build[$name]; + unset($build[$name]); + } + } +} diff --git a/core/modules/field_layout/js/field_layout.js b/core/modules/field_layout/js/field_layout.js new file mode 100644 index 0000000..810c9b8 --- /dev/null +++ b/core/modules/field_layout/js/field_layout.js @@ -0,0 +1,63 @@ +(function ($, Drupal) { + + "use strict"; + + /** + * Row handlers for the 'Manage display' screen. + */ + Drupal.fieldUIDisplayOverview = Drupal.fieldUIDisplayOverview || {}; + + Drupal.fieldUIDisplayOverview.field_layout = function (row, data) { + this.row = row; + this.name = data.name; + this.region = data.region; + this.tableDrag = data.tableDrag; + + // Attach change listener to the 'plugin type' select. + this.$regionSelect = $(row).find('select.field-layout-region'); + this.$regionSelect.on('change', Drupal.fieldUIOverview.onChange); + + return this; + }; + + Drupal.fieldUIDisplayOverview.field_layout.prototype = { + + /** + * Returns the region corresponding to the current form values of the row. + * + * @return {string} + * Either 'hidden' or 'content'. + */ + getRegion: function () { + return this.$regionSelect.val(); + }, + + /** + * Reacts to a row being changed regions. + * + * This function is called when the row is moved to a different region, as + * a + * result of either : + * - a drag-and-drop action (the row's form elements then probably need to + * be updated accordingly) + * - user input in one of the form elements watched by the + * {@link Drupal.fieldUIOverview.onChange} change listener. + * + * @param {string} region + * The name of the new region for the row. + * + * @return {object} + * A hash object indicating which rows should be Ajax-updated as a result + * of the change, in the format expected by + * {@link Drupal.fieldUIOverview.AJAXRefreshRows}. + */ + regionChange: function (region) { + // Replace dashes with underscores. + region = region.replace(/-/g, '_'); + + // Set the region of the select list. + this.$regionSelect.val(region); + } + }; + +})(jQuery, Drupal); diff --git a/core/modules/field_layout/src/Form/FieldLayoutEntityViewDisplayEditForm.php b/core/modules/field_layout/src/Form/FieldLayoutEntityViewDisplayEditForm.php new file mode 100644 index 0000000..c593dc5 --- /dev/null +++ b/core/modules/field_layout/src/Form/FieldLayoutEntityViewDisplayEditForm.php @@ -0,0 +1,127 @@ +getValue('fields') as $field_name => $values) { + $entity->setThirdPartySetting('field_layout', $field_name, ['region' => $values['region']]); + } + } + } + + /** + * {@inheritdoc} + */ + public function getRowRegion($row) { + switch ($row['#row_type']) { + case 'field': + case 'extra_field': + return $row['region']['#value'] ?: 'hidden'; + } + } + + /** + * {@inheritdoc} + */ + public function getRegions() { + $regions = []; + + $layout = _field_layout_get_layout(); + foreach ($layout['regions'] as $name => $region) { + $regions[$name] = [ + 'title' => $region['label'], + 'message' => $this->t('No field is displayed.') + ]; + } + + $regions['hidden'] = [ + 'title' => $this->t('Disabled', [], ['context' => 'Plural']), + 'message' => $this->t('No field is hidden.') + ]; + + return $regions; + } + + /** + * {@inheritdoc} + */ + protected function buildFieldRow(FieldDefinitionInterface $field_definition, array $form, FormStateInterface $form_state) { + $row = parent::buildFieldRow($field_definition, $form, $form_state); + $row['#js_settings']['rowHandler'] = 'field_layout'; + return $this->addRegionSelect($row, $field_definition->getName(), $field_definition->getLabel()); + } + + /** + * {@inheritdoc} + */ + protected function buildExtraFieldRow($field_id, $extra_field) { + $row = parent::buildExtraFieldRow($field_id, $extra_field); + $row['#js_settings']['rowHandler'] = 'field_layout'; + return $this->addRegionSelect($row, $field_id, $extra_field['label']); + } + + /** + * @todo. + */ + protected function addRegionSelect($row, $field_id, $label) { + $field_layout = $this->entity->getThirdPartySetting('field_layout', $field_id, []); + $field_layout += ['region' => 'hidden']; + $new_row = [ + 'region' => [ + '#type' => 'select', + '#title' => $this->t('Region for @title', ['@title' => $label]), + '#title_display' => 'invisible', + '#options' => $this->getRegionOptions(), + '#empty_value' => 'hidden', + '#default_value' => $field_layout['region'], + '#attributes' => ['class' => ['field-layout-region']], + ], + ]; + + $position = array_search('parent_wrapper', array_keys($row)) + 1; + return array_merge(array_slice($row, 0, $position), $new_row, array_slice($row, $position)); + } + + /** + * {@inheritdoc} + */ + protected function getTableHeader() { + $header = parent::getTableHeader(); + array_splice($header, 3, 0, [$this->t('Region')]); + return $header; + } + +}