core/lib/Drupal/Core/Entity/Field/Field.php | 14 ++- .../Drupal/Core/Entity/Field/FieldDefinition.php | 107 ++++++++++++++++++++ core/modules/edit/js/editors/directEditor.js | 8 +- .../edit/Access/EditEntityFieldAccessCheck.php | 13 ++- .../edit/lib/Drupal/edit/EditController.php | 17 +++- .../edit/lib/Drupal/edit/Form/EditFieldForm.php | 30 +++++- .../edit/lib/Drupal/edit/MetadataGenerator.php | 8 +- core/modules/field/field.module | 10 ++ .../field/Plugin/Type/FieldType/ConfigField.php | 20 +++- .../field/Plugin/Type/Formatter/FormatterBase.php | 2 +- .../Type/Formatter/FormatterPluginManager.php | 37 ++++++- .../Drupal/field/Plugin/Type/Widget/WidgetBase.php | 2 +- .../Plugin/Type/Widget/WidgetPluginManager.php | 45 ++++++++ .../node/lib/Drupal/node/NodeFormController.php | 19 ++-- .../node/lib/Drupal/node/NodeStorageController.php | 4 +- .../node/Plugin/field/widget/TitleWidget.php | 79 +++++++++++++++ .../node/Tests/Condition/NodeConditionTest.php | 2 +- .../node/lib/Drupal/node/Tests/NodeTitleTest.php | 2 +- core/modules/node/node.module | 2 +- core/modules/rdf/rdf.module | 2 +- .../lib/Drupal/simpletest/WebTestBase.php | 2 +- .../system/Tests/Plugin/ContextPluginTest.php | 2 +- 22 files changed, 389 insertions(+), 38 deletions(-) diff --git a/core/lib/Drupal/Core/Entity/Field/Field.php b/core/lib/Drupal/Core/Entity/Field/Field.php index 0ff36d7..04aba68 100644 --- a/core/lib/Drupal/Core/Entity/Field/Field.php +++ b/core/lib/Drupal/Core/Entity/Field/Field.php @@ -7,6 +7,7 @@ namespace Drupal\Core\Entity\Field; +use Drupal\Core\Entity\Field\FieldDefinition; use Drupal\Core\Entity\Field\FieldInterface; use Drupal\Core\Session\AccountInterface; use Drupal\Core\TypedData\TypedDataInterface; @@ -37,6 +38,13 @@ class Field extends ItemList implements FieldInterface { protected $list = array(); /** + * The field definition. + * + * @var \Drupal\Core\Entity\Field\FieldDefinitionInterface + */ + protected $fieldDefinition; + + /** * Overrides TypedData::__construct(). */ public function __construct(array $definition, $name = NULL, TypedDataInterface $parent = NULL) { @@ -52,8 +60,10 @@ public function __construct(array $definition, $name = NULL, TypedDataInterface * {@inheritdoc} */ public function getFieldDefinition() { - // @todo https://drupal.org/node/1988612 - return NULL; + if (!isset($this->fieldDefinition)) { + $this->fieldDefinition = new FieldDefinition($this); + } + return $this->fieldDefinition; } /** diff --git a/core/lib/Drupal/Core/Entity/Field/FieldDefinition.php b/core/lib/Drupal/Core/Entity/Field/FieldDefinition.php new file mode 100644 index 0000000..d11dca4 --- /dev/null +++ b/core/lib/Drupal/Core/Entity/Field/FieldDefinition.php @@ -0,0 +1,107 @@ +field = $field; + $this->definition = $field->getDefinition() + \Drupal::typedData()->getDefinition($field->getType()); + } + + /** + * {@inheritdoc} + */ + public function getFieldName() { + return $this->field->getName(); + } + + /** + * {@inheritdoc} + */ + public function getFieldType() { + return $this->definition['id']; + } + + /** + * {@inheritdoc} + */ + public function getFieldSettings() { + return $this->definition['settings']; + } + + /** + * {@inheritdoc} + */ + public function getFieldSetting($setting_name) { + return $this->definition['settings'][$setting_name]; + } + + /** + * {@inheritdoc} + */ + public function getFieldPropertyNames() { + return array_keys($this->field->getPropertyDefinitions()); + } + + /** + * {@inheritdoc} + */ + public function isFieldTranslatable() { + return !empty($this->definition['translatable']); + } + + /** + * {@inheritdoc} + */ + public function getFieldLabel() { + return $this->definition['label']; + } + + /** + * {@inheritdoc} + */ + public function getFieldDescription() { + return $this->definition['description']; + } + + /** + * {@inheritdoc} + */ + public function getFieldCardinality() { + return isset($this->definition['cardinality']) ? $this->definition['cardinality'] : 1; + } + + /** + * {@inheritdoc} + */ + public function isFieldRequired() { + return !empty($this->definition['required']); + } + +} diff --git a/core/modules/edit/js/editors/directEditor.js b/core/modules/edit/js/editors/directEditor.js index 5fed240..59bb6d8 100644 --- a/core/modules/edit/js/editors/directEditor.js +++ b/core/modules/edit/js/editors/directEditor.js @@ -21,7 +21,13 @@ Drupal.edit.editors.direct = Drupal.edit.EditorView.extend({ var fieldModel = this.fieldModel; // Store the original value of this field. Necessary for reverting changes. - var $textElement = this.$textElement = this.$el.find('.field-item:first'); + var $textElement; + if (this.$el.is(':has(.field-item)')) { + $textElement = this.$textElement = this.$el.find('.field-item:first'); + } + else { + $textElement = this.$textElement = this.$el; + } editorModel.set('originalValue', $.trim(this.$textElement.text())); // Sets the state to 'changed' whenever the value changes diff --git a/core/modules/edit/lib/Drupal/edit/Access/EditEntityFieldAccessCheck.php b/core/modules/edit/lib/Drupal/edit/Access/EditEntityFieldAccessCheck.php index 9559be7..8e204dd 100644 --- a/core/modules/edit/lib/Drupal/edit/Access/EditEntityFieldAccessCheck.php +++ b/core/modules/edit/lib/Drupal/edit/Access/EditEntityFieldAccessCheck.php @@ -42,7 +42,13 @@ public function access(Route $route, Request $request) { * {@inheritdoc} */ public function accessEditEntityField(EntityInterface $entity, $field_name) { - return $entity->access('update') && ($field = field_info_field($field_name)) && field_access('edit', $field, $entity->entityType(), $entity); + $property_definitions = $entity->getPropertyDefinitions(); + if (isset($property_definitions[$field_name]['configurable']) && $property_definitions[$field_name]['configurable'] === TRUE) { + return $entity->access('update') && ($field = field_info_field($field_name)) && field_access('edit', $field, $entity->entityType(), $entity); + } + else { + return $entity->access('update'); + } } /** @@ -65,13 +71,16 @@ protected function validateAndUpcastRequestAttributes(Request $request) { // Validate the field name and language. $field_name = $request->attributes->get('field_name'); - if (!$field_name || !field_info_instance($entity->entityType(), $field_name, $entity->bundle())) { + if (!$field_name) { throw new NotFoundHttpException(); } $langcode = $request->attributes->get('langcode'); if (!$langcode || (field_valid_language($langcode) !== $langcode)) { throw new NotFoundHttpException(); } + if (!($field_definition = $entity->getTranslation($langcode)->get($field_name)->getFieldDefinition())) { + throw new NotFoundHttpException(); + } } } diff --git a/core/modules/edit/lib/Drupal/edit/EditController.php b/core/modules/edit/lib/Drupal/edit/EditController.php index 2979e89..a3ccb9f 100644 --- a/core/modules/edit/lib/Drupal/edit/EditController.php +++ b/core/modules/edit/lib/Drupal/edit/EditController.php @@ -25,6 +25,7 @@ use Drupal\edit\Ajax\EntitySavedCommand; use Drupal\edit\Ajax\MetadataCommand; use Drupal\user\TempStoreFactory; +use Drupal\field\FieldInstanceInterface; /** * Returns responses for Edit module routes. @@ -132,12 +133,15 @@ public function metadata(Request $request) { } // Validate the field name and language. - if (!$field_name || !($instance = $this->fieldInfo->getInstance($entity->entityType(), $entity->bundle(), $field_name))) { + if (!$field_name) { throw new NotFoundHttpException(); } if (!$langcode || (field_valid_language($langcode) !== $langcode)) { throw new NotFoundHttpException(); } + if (!($field_definition = $entity->getTranslation($langcode)->get($field_name)->getFieldDefinition())) { + throw new NotFoundHttpException(); + } // If the entity information for this field is requested, include it. $entity_id = $entity->entityType() . '/' . $entity_id; @@ -145,7 +149,7 @@ public function metadata(Request $request) { $metadata[$entity_id] = $this->metadataGenerator->generateEntity($entity, $langcode); } - $metadata[$field] = $this->metadataGenerator->generateField($entity, $instance, $langcode, $view_mode); + $metadata[$field] = $this->metadataGenerator->generateField($entity, $field_definition, $langcode, $view_mode); } return new JsonResponse($metadata); @@ -216,7 +220,14 @@ public function fieldForm(EntityInterface $entity, $field_name, $langcode, $view $entity = $this->tempStoreFactory->get('edit')->get($entity->uuid()); // @todo Remove when http://drupal.org/node/1346214 is complete. $entity = $entity->getBCEntity(); - $output = field_view_field($entity, $field_name, $view_mode_id, $langcode); + + $field = $entity->getNGEntity()->get($field_name); + if ($field->getFieldDefinition() instanceof FieldInstanceInterface) { + $output = field_view_field($entity, $field_name, $view_mode_id, $langcode); + } + else { + $output = \Drupal::service('plugin.manager.field.formatter')->viewBaseField($field); + } $response->addCommand(new FieldFormSavedCommand(drupal_render($output))); } diff --git a/core/modules/edit/lib/Drupal/edit/Form/EditFieldForm.php b/core/modules/edit/lib/Drupal/edit/Form/EditFieldForm.php index e14e0d2..05312d8 100644 --- a/core/modules/edit/lib/Drupal/edit/Form/EditFieldForm.php +++ b/core/modules/edit/lib/Drupal/edit/Form/EditFieldForm.php @@ -10,6 +10,7 @@ use Drupal; use Drupal\Core\Entity\EntityInterface; use Drupal\user\TempStoreFactory; +use Drupal\field\FieldInstanceInterface; /** * Builds and process a form for editing a single entity field. @@ -33,7 +34,13 @@ public function build(array $form, array &$form_state, EntityInterface $entity, $this->tempStoreFactory = $temp_store_factory; // Add the field form. - field_attach_form($form_state['entity'], $form, $form_state, $form_state['langcode'], array('field_name' => $form_state['field_name'])); + $field = $entity->getNGEntity()->get($field_name); + if ($field->getFieldDefinition() instanceof FieldInstanceInterface) { + field_attach_form($form_state['entity'], $form, $form_state, $form_state['langcode'], array('field_name' => $form_state['field_name'])); + } + else { + $form[$field_name] = \Drupal::service('plugin.manager.field.widget')->baseFieldForm($field, $form, $form_state, $form_state['langcode']); + } // Add a submit button. Give it a class for easy JavaScript targeting. $form['actions'] = array('#type' => 'actions'); @@ -90,7 +97,14 @@ protected function init(array &$form_state, EntityInterface $entity, $field_name */ public function validate(array $form, array &$form_state) { $entity = $this->buildEntity($form, $form_state); - field_attach_form_validate($entity, $form, $form_state, array('field_name' => $form_state['field_name'])); + $field_name = $form_state['field_name']; + $field = $entity->getNGEntity()->get($field_name); + if ($field->getFieldDefinition() instanceof FieldInstanceInterface) { + field_attach_form_validate($entity, $form, $form_state, array('field_name' => $field_name)); + } + else { + // @todo + } } /** @@ -112,13 +126,19 @@ public function submit(array $form, array &$form_state) { protected function buildEntity(array $form, array &$form_state) { $entity = clone $form_state['entity']; - field_attach_extract_form_values($entity, $form, $form_state, array('field_name' => $form_state['field_name'])); + $field_name = $form_state['field_name']; + $field = $entity->getNGEntity()->get($field_name); + if ($field->getFieldDefinition() instanceof FieldInstanceInterface) { + field_attach_extract_form_values($entity, $form, $form_state, array('field_name' => $field_name)); + } + else { + \Drupal::service('plugin.manager.field.widget')->baseFieldExtractFormValues($field, $form, $form_state, $form_state['langcode']); + } // @todo Refine automated log messages and abstract them to all entity // types: http://drupal.org/node/1678002. if ($entity->entityType() == 'node' && $entity->isNewRevision() && !isset($entity->log)) { - $instance = field_info_instance($entity->entityType(), $form_state['field_name'], $entity->bundle()); - $entity->log = t('Updated the %field-name field through in-place editing.', array('%field-name' => $instance['label'])); + $entity->log = t('Updated the %field-name field through in-place editing.', array('%field-name' => $field->getFieldDefinition()->getFieldLabel())); } return $entity; diff --git a/core/modules/edit/lib/Drupal/edit/MetadataGenerator.php b/core/modules/edit/lib/Drupal/edit/MetadataGenerator.php index 74d13f9..279019e 100644 --- a/core/modules/edit/lib/Drupal/edit/MetadataGenerator.php +++ b/core/modules/edit/lib/Drupal/edit/MetadataGenerator.php @@ -77,7 +77,13 @@ public function generateField(EntityInterface $entity, FieldDefinitionInterface } // Early-return if no editor is available. - $formatter_id = entity_get_render_display($entity, $view_mode)->getRenderer($field_name)->getPluginId(); + if ($field_definition instanceof FieldInstanceInterface) { + $formatter_id = entity_get_render_display($entity, $view_mode)->getRenderer($field_name)->getPluginId(); + } + else { + $field_type_info = field_info_field_types($field_definition->getFieldType()); + $formatter_id = $field_type_info['default_formatter']; + } $items = $entity->getTranslation($langcode)->get($field_name)->getValue(); $editor_id = $this->editorSelector->getEditor($formatter_id, $field_definition, $items); if (!isset($editor_id)) { diff --git a/core/modules/field/field.module b/core/modules/field/field.module index 2457e4a..8d249ff 100644 --- a/core/modules/field/field.module +++ b/core/modules/field/field.module @@ -177,6 +177,9 @@ function field_theme() { 'field' => array( 'render element' => 'element', ), + 'field__title' => array( + 'base hook' => 'field', + ), 'field_multiple_value_form' => array( 'render element' => 'element', ), @@ -1085,6 +1088,13 @@ function theme_field($variables) { } /** + * @todo Document. + */ +function theme_field__title($variables) { + return '' . drupal_render($variables['items']) . ''; +} + +/** * Assembles a partial entity structure with initial IDs. * * @param stdClass $ids diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigField.php b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigField.php index 29ce028..042d63c 100644 --- a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigField.php +++ b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigField.php @@ -24,6 +24,13 @@ class ConfigField extends Field implements ConfigFieldInterface { protected $instance; /** + * @todo Document. + * + * @var array + */ + protected $instances; + + /** * {@inheritdoc} */ public function __construct(array $definition, $name = NULL, TypedDataInterface $parent = NULL) { @@ -37,9 +44,14 @@ public function __construct(array $definition, $name = NULL, TypedDataInterface * {@inheritdoc} */ public function getInstance() { - if (!isset($this->instance) && $parent = $this->getParent()) { - $instances = FieldAPI::fieldInfo()->getBundleInstances($parent->entityType(), $parent->bundle()); - $this->instance = $instances[$this->getName()]; + if (!isset($this->instance)) { + if (!isset($this->instances) && $parent = $this->getParent()) { + $this->instances = FieldAPI::fieldInfo()->getBundleInstances($parent->entityType(), $parent->bundle()); + } + $field_name = $this->getName(); + if (isset($this->instances[$field_name])) { + $this->instance = $this->instances[$field_name]; + } } return $this->instance; } @@ -48,7 +60,7 @@ public function getInstance() { * {@inheritdoc} */ public function getFieldDefinition() { - return $this->getInstance(); + return $this->getInstance() ?: parent::getFieldDefinition(); } /** diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterBase.php b/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterBase.php index aa93124..f2d9a61 100644 --- a/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterBase.php +++ b/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterBase.php @@ -135,7 +135,7 @@ protected function checkFieldAccess($op, $entity) { return field_access($op, $field, $entity->entityType(), $entity); } else { - return FALSE; + return TRUE; } } diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterPluginManager.php b/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterPluginManager.php index 3b5c813..165251f 100644 --- a/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterPluginManager.php +++ b/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterPluginManager.php @@ -17,7 +17,7 @@ use Drupal\Core\Plugin\Discovery\CacheDecorator; use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery; use Drupal\Core\Plugin\Discovery\AlterDecorator; -use Drupal\field\Plugin\Core\Entity\FieldInstance; +use Drupal\Core\Entity\Field\FieldInterface; /** * Plugin type manager for field formatters. @@ -112,7 +112,7 @@ public function getInstance(array $options) { // Fill in default configuration if needed. if (!isset($options['prepare']) || $options['prepare'] == TRUE) { - $configuration = $this->prepareConfiguration($field_type, $configuration); + $configuration = $this->prepareConfiguration($field_definition, $configuration); } $plugin_id = $configuration['type']; @@ -145,7 +145,7 @@ public function getInstance(array $options) { * @return array * The display properties with defaults added. */ - public function prepareConfiguration($field_type, array $configuration) { + public function prepareConfiguration($field_definition, array $configuration) { // Fill in defaults for missing properties. $configuration += array( 'label' => 'above', @@ -207,4 +207,35 @@ public function getDefaultSettings($type) { return isset($info['settings']) ? $info['settings'] : array(); } + /** + * @todo Document. + */ + public function viewBaseField(FieldInterface $field) { + $options = array( + 'field_definition' => $field->getFieldDefinition(), + 'view_mode' => 'default', + 'configuration' => array( + 'label' => 'hidden', + ), + ); + + if (($field_data_definition = $field->getDefinition()) && isset($field_data_definition['default_formatter'])) { + $options['configuration']['type'] = $field_data_definition['default_formatter']; + } + $formatter = $this->getInstance($options); + + $entity = $field->getParent()->getBCEntity(); + $entity_id = $entity->id(); + $langcode = $entity->language()->id; + $items = $field->getValue(); + + $items_multi = array($entity_id => $items); + $formatter->prepareView(array($entity_id => $entity), $langcode, $items_multi); + $items = $items_multi[$entity_id]; + + $result = $formatter->view($entity, $langcode, $items); + $field_name = $field->getName(); + return isset($result[$field_name]) ? $result[$field_name] : array(); + } + } diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetBase.php b/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetBase.php index 7c7a343..5fc83ff 100644 --- a/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetBase.php +++ b/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetBase.php @@ -444,7 +444,7 @@ protected function checkFieldAccess($op, $entity) { return field_access($op, $field, $entity->entityType(), $entity); } else { - return FALSE; + return TRUE; } } diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetPluginManager.php b/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetPluginManager.php index 12bb296..152e4fa 100644 --- a/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetPluginManager.php +++ b/core/modules/field/lib/Drupal/field/Plugin/Type/Widget/WidgetPluginManager.php @@ -18,6 +18,7 @@ use Drupal\Core\Plugin\Discovery\CacheDecorator; use Drupal\Core\Plugin\Discovery\AlterDecorator; use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery; +use Drupal\Core\Entity\Field\FieldInterface; /** * Plugin type manager for field widgets. @@ -206,4 +207,48 @@ public function getDefaultSettings($type) { return isset($info['settings']) ? $info['settings'] : array(); } + /** + * @todo Document. + */ + public function baseFieldForm(FieldInterface $field, array &$form, array &$form_state, $langcode) { + $options = array( + 'field_definition' => $field->getFieldDefinition(), + 'form_mode' => 'default', + 'configuration' => array(), + ); + if (($field_data_definition = $field->getDefinition()) && isset($field_data_definition['default_widget'])) { + $options['configuration']['type'] = $field_data_definition['default_widget']; + } + $widget = $this->getInstance($options); + + $entity = $field->getParent()->getBCEntity(); + $items = $field->getValue(); + + $form += array('#parents' => array()); + $result = $widget->form($entity, $langcode, $items, $form, $form_state); + $field_name = $field->getName(); + return isset($result[$field_name]) ? $result[$field_name] : array(); + } + + /** + * @todo Document. + */ + public function baseFieldExtractFormValues(FieldInterface $field, array &$form, array &$form_state, $langcode) { + $options = array( + 'field_definition' => $field->getFieldDefinition(), + 'form_mode' => 'default', + 'configuration' => array(), + ); + if (($field_data_definition = $field->getDefinition()) && isset($field_data_definition['default_widget'])) { + $options['configuration']['type'] = $field_data_definition['default_widget']; + } + $widget = $this->getInstance($options); + + $entity = $field->getParent()->getBCEntity(); + $items = $field->getValue(); + + $widget->extractFormValues($entity, $langcode, $items, $form, $form_state); + $field->setValue($items); + } + } diff --git a/core/modules/node/lib/Drupal/node/NodeFormController.php b/core/modules/node/lib/Drupal/node/NodeFormController.php index c9649ef..426e760 100644 --- a/core/modules/node/lib/Drupal/node/NodeFormController.php +++ b/core/modules/node/lib/Drupal/node/NodeFormController.php @@ -101,14 +101,8 @@ public function form(array $form, array &$form_state) { $node_type = node_type_load($node->type); if ($node_type->has_title) { - $form['title'] = array( - '#type' => 'textfield', - '#title' => check_plain($node_type->title_label), - '#required' => TRUE, - '#default_value' => $node->title, - '#maxlength' => 255, - '#weight' => -5, - ); + $form['title'] = \Drupal::service('plugin.manager.field.widget')->baseFieldForm($node->getNGEntity()->title, $form, $form_state, $this->getFormLangcode($form_state)); + $form['title']['#weight'] = -5; } $language_configuration = module_invoke('language', 'get_default_configuration', 'node', $node->type); @@ -322,6 +316,15 @@ protected function actions(array $form, array &$form_state) { } /** + * {@inheritdoc} + */ + public function buildEntity(array $form, array &$form_state) { + $node = parent::buildEntity($form, $form_state); + \Drupal::service('plugin.manager.field.widget')->baseFieldExtractFormValues($node->getNGEntity()->title, $form, $form_state, $this->getFormLangcode($form_state)); + return $node; + } + + /** * Overrides Drupal\Core\Entity\EntityFormController::validate(). */ public function validate(array $form, array &$form_state) { diff --git a/core/modules/node/lib/Drupal/node/NodeStorageController.php b/core/modules/node/lib/Drupal/node/NodeStorageController.php index 1a874fe..ea2f0d8 100644 --- a/core/modules/node/lib/Drupal/node/NodeStorageController.php +++ b/core/modules/node/lib/Drupal/node/NodeStorageController.php @@ -154,7 +154,7 @@ public function baseFieldDefinitions() { $properties['title'] = array( 'label' => t('Title'), 'description' => t('The title of this node, always treated as non-markup plain text.'), - 'type' => 'string_field', + 'type' => 'field_item:text', 'required' => TRUE, 'settings' => array( 'default_value' => '', @@ -162,6 +162,8 @@ public function baseFieldDefinitions() { 'property_constraints' => array( 'value' => array('Length' => array('max' => 255)), ), + 'default_widget' => 'node_title', + 'default_formatter' => 'text_default', ); $properties['uid'] = array( 'label' => t('User ID'), diff --git a/core/modules/node/lib/Drupal/node/Plugin/field/widget/TitleWidget.php b/core/modules/node/lib/Drupal/node/Plugin/field/widget/TitleWidget.php new file mode 100644 index 0000000..b5710f2 --- /dev/null +++ b/core/modules/node/lib/Drupal/node/Plugin/field/widget/TitleWidget.php @@ -0,0 +1,79 @@ +fieldDefinition->getFieldName(); + + // @todo Make EntityManager::getFieldDefinitions() allow for per-bundle + // definitions of base fields, so that here, we could just call + // $this->fieldDefinition->getFieldLabel() instead. + if ($entity->entityType() == 'node' && $field_name == 'title') { + $node_type = node_type_load($entity->bundle()); + $label = $node_type->title_label; + } + else { + $label = $this->fieldDefinition->getFieldLabel(); + } + + $addition[$field_name] = array( + '#type' => 'textfield', + '#title' => check_plain($label), + '#required' => $this->fieldDefinition->isFieldRequired(), + '#default_value' => isset($items[0]['value']) ? $items[0]['value'] : '', + '#maxlength' => $this->fieldDefinition->getFieldSetting('max_length'), + ); + return $addition; + } + + /** + * {@inheritdoc} + */ + public function extractFormValues(EntityInterface $entity, $langcode, array &$items, array $form, array &$form_state) { + $field_name = $this->fieldDefinition->getFieldName(); + + // Extract the values from $form_state['values']. + $path = array_merge($form['#parents'], array($field_name)); + $key_exists = NULL; + $value = NestedArray::getValue($form_state['values'], $path, $key_exists); + + if ($key_exists) { + $items = array(array('value' => $value)); + } + } + + /** + * {@inheritdoc} + */ + public function formElement(array $items, $delta, array $element, $langcode, array &$form, array &$form_state) { + return array(); + } +} diff --git a/core/modules/node/lib/Drupal/node/Tests/Condition/NodeConditionTest.php b/core/modules/node/lib/Drupal/node/Tests/Condition/NodeConditionTest.php index 31d515f..6ee7d48 100644 --- a/core/modules/node/lib/Drupal/node/Tests/Condition/NodeConditionTest.php +++ b/core/modules/node/lib/Drupal/node/Tests/Condition/NodeConditionTest.php @@ -14,7 +14,7 @@ */ class NodeConditionTest extends DrupalUnitTestBase { - public static $modules = array('system', 'node', 'field'); + public static $modules = array('system', 'node', 'field', 'text'); public static function getInfo() { return array( diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeTitleTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeTitleTest.php index c23332e..ed3ae9c 100644 --- a/core/modules/node/lib/Drupal/node/Tests/NodeTitleTest.php +++ b/core/modules/node/lib/Drupal/node/Tests/NodeTitleTest.php @@ -59,7 +59,7 @@ function testNodeTitle() { $this->assertEqual(current($this->xpath($xpath)), $node->label(), 'Node breadcrumb is equal to node title.', 'Node'); // Test node title in comment preview. - $this->assertEqual(current($this->xpath('//article[@id=:id]/h2/a', array(':id' => 'node-' . $node->id()))), $node->label(), 'Node preview title is equal to node title.', 'Node'); + $this->assertEqual(current($this->xpath('//article[@id=:id]/h2/a/span', array(':id' => 'node-' . $node->id()))), $node->label(), 'Node preview title is equal to node title.', 'Node'); // Test node title is clickable on teaser list (/node). $this->drupalGet('node'); diff --git a/core/modules/node/node.module b/core/modules/node/node.module index dab8696..38fc0e5 100644 --- a/core/modules/node/node.module +++ b/core/modules/node/node.module @@ -700,7 +700,7 @@ function template_preprocess_node(&$variables) { $uri = $node->uri(); $variables['node_url'] = url($uri['path'], $uri['options']); - $variables['label'] = check_plain($node->label()); + $variables['label'] = Drupal::service('plugin.manager.field.formatter')->viewBaseField($node->getNGEntity()->title); $variables['page'] = $variables['view_mode'] == 'full' && node_is_page($node); // Helpful $content variable for templates. diff --git a/core/modules/rdf/rdf.module b/core/modules/rdf/rdf.module index 06b25a0..379ee88 100644 --- a/core/modules/rdf/rdf.module +++ b/core/modules/rdf/rdf.module @@ -260,7 +260,7 @@ function rdf_preprocess_node(&$variables) { $title_mapping = $mapping->getPreparedFieldMapping('title'); if ($title_mapping) { $title_attributes['property'] = empty($title_mapping['properties']) ? NULL : $title_mapping['properties']; - $title_attributes['content'] = $variables['label']; + $title_attributes['content'] = $variables['node']->label(); $variables['title_suffix']['rdf_meta_title'] = array( '#theme' => 'rdf_metadata', '#metadata' => array($title_attributes), diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php index ab24fc8..118f935 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php @@ -2099,7 +2099,7 @@ protected function assertNoLinkByHref($href, $message = '', $group = 'Other') { */ protected function clickLink($label, $index = 0) { $url_before = $this->getUrl(); - $urls = $this->xpath('//a[normalize-space(text())=:label]', array(':label' => $label)); + $urls = $this->xpath('//a[normalize-space()=:label]', array(':label' => $label)); if (isset($urls[$index])) { $url_target = $this->getAbsoluteUrl($urls[$index]['href']); diff --git a/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php b/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php index b04e2d8..cb8ec55 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php @@ -17,7 +17,7 @@ */ class ContextPluginTest extends DrupalUnitTestBase { - public static $modules = array('system', 'user', 'node'); + public static $modules = array('system', 'user', 'node', 'text'); public static function getInfo() { return array(