Update Composer, update everything

This commit is contained in:
Oliver Davies 2018-11-23 12:29:20 +00:00
parent ea3e94409f
commit dda5c284b6
19527 changed files with 1135420 additions and 351004 deletions

View file

@ -0,0 +1,73 @@
/**
* @file
* Menu UI admin behaviors.
*/
(function($, Drupal) {
/**
*
* @type {Drupal~behavior}
*/
Drupal.behaviors.menuUiChangeParentItems = {
attach(context, settings) {
const $menu = $('#edit-menu').once('menu-parent');
if ($menu.length) {
// Update the list of available parent menu items to match the initial
// available menus.
Drupal.menuUiUpdateParentList();
// Update list of available parent menu items.
$menu.on('change', 'input', Drupal.menuUiUpdateParentList);
}
},
};
/**
* Function to set the options of the menu parent item dropdown.
*/
Drupal.menuUiUpdateParentList = function() {
const $menu = $('#edit-menu');
const values = [];
$menu.find('input:checked').each(function() {
// Get the names of all checked menus.
values.push(Drupal.checkPlain($.trim($(this).val())));
});
$.ajax({
url: `${window.location.protocol}//${window.location.host}${Drupal.url(
'admin/structure/menu/parents',
)}`,
type: 'POST',
data: { 'menus[]': values },
dataType: 'json',
success(options) {
const $select = $('#edit-menu-parent');
// Save key of last selected element.
const selected = $select.val();
// Remove all existing options from dropdown.
$select.children().remove();
// Add new options to dropdown. Keep a count of options for testing later.
let totalOptions = 0;
Object.keys(options || {}).forEach(machineName => {
$select.append(
$(
`<option ${
machineName === selected ? ' selected="selected"' : ''
}></option>`,
)
.val(machineName)
.text(options[machineName]),
);
totalOptions++;
});
// Hide the parent options if there are no options for it.
$select
.closest('div')
.toggle(totalOptions > 0)
.attr('hidden', totalOptions === 0);
},
});
};
})(jQuery, Drupal);

View file

@ -1,68 +1,50 @@
/**
* @file
* Menu UI admin behaviors.
*/
* DO NOT EDIT THIS FILE.
* See the following change record for more information,
* https://www.drupal.org/node/2815083
* @preserve
**/
(function ($, Drupal) {
'use strict';
/**
*
* @type {Drupal~behavior}
*/
Drupal.behaviors.menuUiChangeParentItems = {
attach: function (context, settings) {
attach: function attach(context, settings) {
var $menu = $('#edit-menu').once('menu-parent');
if ($menu.length) {
// Update the list of available parent menu items to match the initial
// available menus.
Drupal.menuUiUpdateParentList();
// Update list of available parent menu items.
$menu.on('change', 'input', Drupal.menuUiUpdateParentList);
}
}
};
/**
* Function to set the options of the menu parent item dropdown.
*/
Drupal.menuUiUpdateParentList = function () {
var $menu = $('#edit-menu');
var values = [];
$menu.find('input:checked').each(function () {
// Get the names of all checked menus.
values.push(Drupal.checkPlain($.trim($(this).val())));
});
$.ajax({
url: location.protocol + '//' + location.host + Drupal.url('admin/structure/menu/parents'),
url: window.location.protocol + '//' + window.location.host + Drupal.url('admin/structure/menu/parents'),
type: 'POST',
data: {'menus[]': values},
data: { 'menus[]': values },
dataType: 'json',
success: function (options) {
success: function success(options) {
var $select = $('#edit-menu-parent');
// Save key of last selected element.
var selected = $select.val();
// Remove all existing options from dropdown.
$select.children().remove();
// Add new options to dropdown. Keep a count of options for testing later.
var totalOptions = 0;
for (var machineName in options) {
if (options.hasOwnProperty(machineName)) {
$select.append(
$('<option ' + (machineName === selected ? ' selected="selected"' : '') + '></option>').val(machineName).text(options[machineName])
);
totalOptions++;
}
}
// Hide the parent options if there are no options for it.
var selected = $select.val();
$select.children().remove();
var totalOptions = 0;
Object.keys(options || {}).forEach(function (machineName) {
$select.append($('<option ' + (machineName === selected ? ' selected="selected"' : '') + '></option>').val(machineName).text(options[machineName]));
totalOptions++;
});
$select.closest('div').toggle(totalOptions > 0).attr('hidden', totalOptions === 0);
}
});
};
})(jQuery, Drupal);
})(jQuery, Drupal);

View file

@ -0,0 +1,96 @@
/**
* @file
* Menu UI behaviors.
*/
(function($, Drupal) {
/**
* Set a summary on the menu link form.
*
* @type {Drupal~behavior}
*
* @prop {Drupal~behaviorAttach} attach
* Find the form and call `drupalSetSummary` on it.
*/
Drupal.behaviors.menuUiDetailsSummaries = {
attach(context) {
$(context)
.find('.menu-link-form')
.drupalSetSummary(context => {
const $context = $(context);
if (
$context.find('.js-form-item-menu-enabled input').is(':checked')
) {
return Drupal.checkPlain(
$context.find('.js-form-item-menu-title input').val(),
);
}
return Drupal.t('Not in menu');
});
},
};
/**
* Automatically fill in a menu link title, if possible.
*
* @type {Drupal~behavior}
*
* @prop {Drupal~behaviorAttach} attach
* Attaches change and keyup behavior for automatically filling out menu
* link titles.
*/
Drupal.behaviors.menuUiLinkAutomaticTitle = {
attach(context) {
const $context = $(context);
$context.find('.menu-link-form').each(function() {
const $this = $(this);
// Try to find menu settings widget elements as well as a 'title' field
// in the form, but play nicely with user permissions and form
// alterations.
const $checkbox = $this.find('.js-form-item-menu-enabled input');
const $linkTitle = $context.find('.js-form-item-menu-title input');
const $title = $this
.closest('form')
.find('.js-form-item-title-0-value input');
// Bail out if we do not have all required fields.
if (!($checkbox.length && $linkTitle.length && $title.length)) {
return;
}
// If there is a link title already, mark it as overridden. The user
// expects that toggling the checkbox twice will take over the node's
// title.
if ($checkbox.is(':checked') && $linkTitle.val().length) {
$linkTitle.data('menuLinkAutomaticTitleOverridden', true);
}
// Whenever the value is changed manually, disable this behavior.
$linkTitle.on('keyup', () => {
$linkTitle.data('menuLinkAutomaticTitleOverridden', true);
});
// Global trigger on checkbox (do not fill-in a value when disabled).
$checkbox.on('change', () => {
if ($checkbox.is(':checked')) {
if (!$linkTitle.data('menuLinkAutomaticTitleOverridden')) {
$linkTitle.val($title.val());
}
} else {
$linkTitle.val('');
$linkTitle.removeData('menuLinkAutomaticTitleOverridden');
}
$checkbox.closest('.vertical-tabs-pane').trigger('summaryUpdated');
$checkbox.trigger('formUpdated');
});
// Take over any title change.
$title.on('keyup', () => {
if (
!$linkTitle.data('menuLinkAutomaticTitleOverridden') &&
$checkbox.is(':checked')
) {
$linkTitle.val($title.val());
$linkTitle.val($title.val()).trigger('formUpdated');
}
});
});
},
};
})(jQuery, Drupal);

View file

@ -6,4 +6,4 @@ version: VERSION
core: 8.x
configure: entity.menu.collection
dependencies:
- menu_link_content
- drupal:menu_link_content

View file

@ -1,91 +1,66 @@
/**
* @file
* Menu UI behaviors.
*/
* DO NOT EDIT THIS FILE.
* See the following change record for more information,
* https://www.drupal.org/node/2815083
* @preserve
**/
(function ($, Drupal) {
'use strict';
/**
* Set a summary on the menu link form.
*
* @type {Drupal~behavior}
*
* @prop {Drupal~behaviorAttach} attach
* Find the form and call `drupalSetSummary` on it.
*/
Drupal.behaviors.menuUiDetailsSummaries = {
attach: function (context) {
attach: function attach(context) {
$(context).find('.menu-link-form').drupalSetSummary(function (context) {
var $context = $(context);
if ($context.find('.js-form-item-menu-enabled input').is(':checked')) {
return Drupal.checkPlain($context.find('.js-form-item-menu-title input').val());
}
else {
return Drupal.t('Not in menu');
}
return Drupal.t('Not in menu');
});
}
};
/**
* Automatically fill in a menu link title, if possible.
*
* @type {Drupal~behavior}
*
* @prop {Drupal~behaviorAttach} attach
* Attaches change and keyup behavior for automatically filling out menu
* link titles.
*/
Drupal.behaviors.menuUiLinkAutomaticTitle = {
attach: function (context) {
attach: function attach(context) {
var $context = $(context);
$context.find('.menu-link-form').each(function () {
var $this = $(this);
// Try to find menu settings widget elements as well as a 'title' field
// in the form, but play nicely with user permissions and form
// alterations.
var $checkbox = $this.find('.js-form-item-menu-enabled input');
var $link_title = $context.find('.js-form-item-menu-title input');
var $linkTitle = $context.find('.js-form-item-menu-title input');
var $title = $this.closest('form').find('.js-form-item-title-0-value input');
// Bail out if we do not have all required fields.
if (!($checkbox.length && $link_title.length && $title.length)) {
if (!($checkbox.length && $linkTitle.length && $title.length)) {
return;
}
// If there is a link title already, mark it as overridden. The user
// expects that toggling the checkbox twice will take over the node's
// title.
if ($checkbox.is(':checked') && $link_title.val().length) {
$link_title.data('menuLinkAutomaticTitleOverridden', true);
if ($checkbox.is(':checked') && $linkTitle.val().length) {
$linkTitle.data('menuLinkAutomaticTitleOverridden', true);
}
// Whenever the value is changed manually, disable this behavior.
$link_title.on('keyup', function () {
$link_title.data('menuLinkAutomaticTitleOverridden', true);
$linkTitle.on('keyup', function () {
$linkTitle.data('menuLinkAutomaticTitleOverridden', true);
});
// Global trigger on checkbox (do not fill-in a value when disabled).
$checkbox.on('change', function () {
if ($checkbox.is(':checked')) {
if (!$link_title.data('menuLinkAutomaticTitleOverridden')) {
$link_title.val($title.val());
if (!$linkTitle.data('menuLinkAutomaticTitleOverridden')) {
$linkTitle.val($title.val());
}
}
else {
$link_title.val('');
$link_title.removeData('menuLinkAutomaticTitleOverridden');
} else {
$linkTitle.val('');
$linkTitle.removeData('menuLinkAutomaticTitleOverridden');
}
$checkbox.closest('.vertical-tabs-pane').trigger('summaryUpdated');
$checkbox.trigger('formUpdated');
});
// Take over any title change.
$title.on('keyup', function () {
if (!$link_title.data('menuLinkAutomaticTitleOverridden') && $checkbox.is(':checked')) {
$link_title.val($title.val());
$link_title.val($title.val()).trigger('formUpdated');
if (!$linkTitle.data('menuLinkAutomaticTitleOverridden') && $checkbox.is(':checked')) {
$linkTitle.val($title.val());
$linkTitle.val($title.val()).trigger('formUpdated');
}
});
});
}
};
})(jQuery, Drupal);
})(jQuery, Drupal);

View file

@ -10,7 +10,6 @@
use Drupal\Core\Breadcrumb\Breadcrumb;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Block\BlockPluginInterface;
use Drupal\Core\Link;
use Drupal\Core\Menu\MenuLinkInterface;
@ -27,6 +26,8 @@ use Drupal\node\NodeInterface;
* @deprecated in Drupal 8.3.x and will be removed before Drupal 9.0.0. Use
* \Drupal\Core\Config\Entity\ConfigEntityStorage::MAX_ID_LENGTH because the
* menu name is a configuration entity ID.
*
* @see https://www.drupal.org/node/2831620
*/
const MENU_MAX_MENU_NAME_LENGTH_UI = 27;
@ -71,49 +72,9 @@ function menu_ui_entity_type_build(array &$entity_types) {
->setLinkTemplate('edit-form', '/admin/structure/menu/manage/{menu}')
->setLinkTemplate('add-link-form', '/admin/structure/menu/manage/{menu}/add')
->setLinkTemplate('collection', '/admin/structure/menu');
}
/**
* Implements hook_ENTITY_TYPE_insert( for menu entities.
*/
function menu_ui_menu_insert(Menu $menu) {
menu_cache_clear_all();
// Invalidate the block cache to update menu-based derivatives.
if (\Drupal::moduleHandler()->moduleExists('block')) {
\Drupal::service('plugin.manager.block')->clearCachedDefinitions();
}
}
/**
* Implements hook_ENTITY_TYPE_update() for menu entities.
*/
function menu_ui_menu_update(Menu $menu) {
menu_cache_clear_all();
// Invalidate the block cache to update menu-based derivatives.
if (\Drupal::moduleHandler()->moduleExists('block')) {
\Drupal::service('plugin.manager.block')->clearCachedDefinitions();
}
}
/**
* Implements hook_ENTITY_TYPE_predelete() for menu entities.
*/
function menu_ui_menu_predelete(Menu $menu) {
// Delete all links from the menu.
/** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
$menu_link_manager->deleteLinksInMenu($menu->id());
}
/**
* Implements hook_ENTITY_TYPE_delete() for menu entities.
*/
function menu_ui_menu_delete(Menu $menu) {
menu_cache_clear_all();
// Invalidate the block cache to update menu-based derivatives.
if (\Drupal::moduleHandler()->moduleExists('block')) {
\Drupal::service('plugin.manager.block')->clearCachedDefinitions();
if (isset($entity_types['node'])) {
$entity_types['node']->addConstraint('MenuSettings', []);
}
}
@ -166,24 +127,6 @@ function _menu_ui_node_save(NodeInterface $node, array $values) {
$entity->save();
}
/**
* Implements hook_ENTITY_TYPE_predelete() for node entities.
*/
function menu_ui_node_predelete(EntityInterface $node) {
// Delete all MenuLinkContent links that point to this node.
/** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
$result = $menu_link_manager->loadLinksByRoute('entity.node.canonical', ['node' => $node->id()]);
if (!empty($result)) {
foreach ($result as $id => $instance) {
if ($instance->isDeletable() && strpos($id, 'menu_link_content:') === 0) {
$instance->deleteLink();
}
}
}
}
/**
* Returns the definition for a menu link for the given node.
*
@ -233,6 +176,7 @@ function menu_ui_get_menu_link_defaults(NodeInterface $node) {
'title' => $menu_link->getTitle(),
'title_max_length' => $menu_link->getFieldDefinitions()['title']->getSetting('max_length'),
'description' => $menu_link->getDescription(),
'description_max_length' => $menu_link->getFieldDefinitions()['description']->getSetting('max_length'),
'menu_name' => $menu_link->getMenuName(),
'parent' => $menu_link->getParentId(),
'weight' => $menu_link->getWeight(),
@ -245,12 +189,14 @@ function menu_ui_get_menu_link_defaults(NodeInterface $node) {
// definition.
$field_definitions = \Drupal::entityManager()->getBaseFieldDefinitions('menu_link_content');
$max_length = $field_definitions['title']->getSetting('max_length');
$description_max_length = $field_definitions['description']->getSetting('max_length');
$defaults = [
'entity_id' => 0,
'id' => '',
'title' => '',
'title_max_length' => $max_length,
'description' => '',
'description_max_length' => $description_max_length,
'menu_name' => $menu_name,
'parent' => '',
'weight' => 0,
@ -275,11 +221,15 @@ function menu_ui_form_node_form_alter(&$form, FormStateInterface $form_state) {
$node_type = $node->type->entity;
/** @var \Drupal\Core\Menu\MenuParentFormSelectorInterface $menu_parent_selector */
$menu_parent_selector = \Drupal::service('menu.parent_form_selector');
$menu_names = menu_ui_get_menus();
$type_menus = $node_type->getThirdPartySetting('menu_ui', 'available_menus', ['main']);
$type_menus_ids = $node_type->getThirdPartySetting('menu_ui', 'available_menus', ['main']);
if (empty($type_menus_ids)) {
return;
}
/** @var \Drupal\system\MenuInterface[] $type_menus */
$type_menus = Menu::loadMultiple($type_menus_ids);
$available_menus = [];
foreach ($type_menus as $menu) {
$available_menus[$menu] = $menu_names[$menu];
$available_menus[$menu->id()] = $menu->label();
}
if ($defaults['id']) {
$default = $defaults['menu_name'] . ':' . $defaults['parent'];
@ -334,11 +284,11 @@ function menu_ui_form_node_form_alter(&$form, FormStateInterface $form_state) {
];
$form['menu']['link']['description'] = [
'#type' => 'textarea',
'#type' => 'textfield',
'#title' => t('Description'),
'#default_value' => $defaults['description'],
'#rows' => 1,
'#description' => t('Shown when hovering over the menu link.'),
'#maxlength' => $defaults['description_max_length'],
];
$form['menu']['link']['menu_parent'] = $parent_element;
@ -357,6 +307,15 @@ function menu_ui_form_node_form_alter(&$form, FormStateInterface $form_state) {
$form['actions'][$action]['#submit'][] = 'menu_ui_form_node_form_submit';
}
}
$form['#entity_builders'][] = 'menu_ui_node_builder';
}
/**
* Entity form builder to add the menu information to the node.
*/
function menu_ui_node_builder($entity_type, NodeInterface $entity, &$form, FormStateInterface $form_state) {
$entity->menu = $form_state->getValue('menu');
}
/**
@ -500,7 +459,6 @@ function menu_ui_preprocess_block(&$variables) {
}
}
/**
* Implements hook_system_breadcrumb_alter().
*/

View file

@ -4,10 +4,12 @@ label: Menu UI configuration
migration_tags:
- Drupal 6
- Drupal 7
- Configuration
source:
plugin: variable
variables:
- menu_override_parent_selector
source_module: menu
process:
override_parent_selector: menu_override_parent_selector
destination:

View file

@ -10,6 +10,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Defines a confirmation form for deletion of a custom menu.
*
* @internal
*/
class MenuDeleteForm extends EntityDeleteForm {

View file

@ -13,6 +13,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
*
* The menu link plugin defines which class defines the corresponding form.
*
* @internal
*
* @see \Drupal\Core\Menu\MenuLinkInterface::getFormClass()
*/
class MenuLinkEditForm extends FormBase {
@ -89,7 +91,7 @@ class MenuLinkEditForm extends FormBase {
public function submitForm(array &$form, FormStateInterface $form_state) {
$link = $form['#plugin_form']->submitConfigurationForm($form, $form_state);
drupal_set_message($this->t('The menu link has been saved.'));
$this->messenger()->addStatus($this->t('The menu link has been saved.'));
$form_state->setRedirect(
'entity.menu.edit_form',
['menu' => $link->getMenuName()]

View file

@ -12,6 +12,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Defines a confirmation form for resetting a single modified menu link.
*
* @internal
*/
class MenuLinkResetForm extends ConfirmFormBase {
@ -100,7 +102,7 @@ class MenuLinkResetForm extends ConfirmFormBase {
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$this->link = $this->menuLinkManager->resetLink($this->link->getPluginId());
drupal_set_message($this->t('The menu link was reset to its default settings.'));
$this->messenger()->addStatus($this->t('The menu link was reset to its default settings.'));
$form_state->setRedirectUrl($this->getCancelUrl());
}

View file

@ -19,6 +19,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Base form for menu edit forms.
*
* @internal
*/
class MenuForm extends EntityForm {
@ -164,11 +166,11 @@ class MenuForm extends EntityForm {
$status = $menu->save();
$edit_link = $this->entity->link($this->t('Edit'));
if ($status == SAVED_UPDATED) {
drupal_set_message($this->t('Menu %label has been updated.', ['%label' => $menu->label()]));
$this->messenger()->addStatus($this->t('Menu %label has been updated.', ['%label' => $menu->label()]));
$this->logger('menu')->notice('Menu %label has been updated.', ['%label' => $menu->label(), 'link' => $edit_link]);
}
else {
drupal_set_message($this->t('Menu %label has been added.', ['%label' => $menu->label()]));
$this->messenger()->addStatus($this->t('Menu %label has been added.', ['%label' => $menu->label()]));
$this->logger('menu')->notice('Menu %label has been added.', ['%label' => $menu->label(), 'link' => $edit_link]);
}
@ -221,7 +223,7 @@ class MenuForm extends EntityForm {
$this->getRequest()->attributes->set('_menu_admin', FALSE);
// Determine the delta; the number of weights to be made available.
$count = function(array $tree) {
$count = function (array $tree) {
$sum = function ($carry, MenuLinkTreeElement $item) {
return $carry + $item->count();
};

View file

@ -0,0 +1,19 @@
<?php
namespace Drupal\menu_ui\Plugin\Validation\Constraint;
use Symfony\Component\Validator\Constraint;
/**
* Validation constraint for changing the menu settings in pending revisions.
*
* @Constraint(
* id = "MenuSettings",
* label = @Translation("Menu settings.", context = "Validation"),
* )
*/
class MenuSettingsConstraint extends Constraint {
public $message = 'You can only change the menu settings for the <em>published</em> version of this content.';
}

View file

@ -0,0 +1,64 @@
<?php
namespace Drupal\menu_ui\Plugin\Validation\Constraint;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
/**
* Constraint validator for changing the menu settings in pending revisions.
*/
class MenuSettingsConstraintValidator extends ConstraintValidator {
/**
* {@inheritdoc}
*/
public function validate($entity, Constraint $constraint) {
if (isset($entity) && !$entity->isNew() && !$entity->isDefaultRevision()) {
$defaults = menu_ui_get_menu_link_defaults($entity);
$values = $entity->menu;
$violation_path = NULL;
if (trim($values['title']) && !empty($values['menu_parent'])) {
list($menu_name, $parent) = explode(':', $values['menu_parent'], 2);
$values['menu_name'] = $menu_name;
$values['parent'] = $parent;
}
// Handle the case when a menu link is added to a pending revision.
if (!$defaults['entity_id'] && $values['enabled']) {
$violation_path = 'menu';
}
// Handle the case when the menu link is deleted in a pending revision.
elseif (empty($values['enabled']) && $defaults['entity_id']) {
$violation_path = 'menu';
}
// Handle all the other menu link changes in a pending revision.
elseif ($defaults['entity_id']) {
if (($values['title'] != $defaults['title'])) {
$violation_path = 'menu.title';
}
elseif (($values['description'] != $defaults['description'])) {
$violation_path = 'menu.description';
}
elseif ($defaults['entity_id'] && ($values['menu_name'] != $defaults['menu_name'])) {
$violation_path = 'menu.menu_parent';
}
elseif (isset($values['parent']) && ($values['parent'] != $defaults['parent'])) {
$violation_path = 'menu.menu_parent';
}
elseif (($values['weight'] != $defaults['weight'])) {
$violation_path = 'menu.weight';
}
}
if ($violation_path) {
$this->context->buildViolation($constraint->message)
->atPath($violation_path)
->setInvalidValue($entity)
->addViolation();
}
}
}
}

View file

@ -2,10 +2,17 @@
namespace Drupal\menu_ui\Tests;
@trigger_error(__NAMESPACE__ . '\MenuWebTestBase is deprecated in Drupal 8.5.x and will be removed before Drupal 9.0.0. Use the \Drupal\Tests\BrowserTestBase base class and the \Drupal\Tests\menu_ui\Traits\MenuUiTrait trait instead. See https://www.drupal.org/node/2917910.', E_USER_DEPRECATED);
use Drupal\simpletest\WebTestBase;
/**
* Base class for menu web tests.
*
* @deprecated in Drupal 8.5.x, will be removed before Drupal 9.0.x. Use
* \Drupal\Tests\menu_ui\Traits\MenuUiTrait methods, instead.
*
* @see https://www.drupal.org/node/2917910
*/
abstract class MenuWebTestBase extends WebTestBase {

View file

@ -4,7 +4,7 @@ namespace Drupal\Tests\menu_ui\Functional;
use Drupal\Core\Url;
use Drupal\menu_link_content\Entity\MenuLinkContent;
use Drupal\system\Tests\Cache\PageCacheTagsTestBase;
use Drupal\Tests\system\Functional\Cache\PageCacheTagsTestBase;
use Drupal\system\Entity\Menu;
/**
@ -82,9 +82,9 @@ class MenuCacheTagsTest extends PageCacheTagsTestBase {
'parent' => '',
'title' => 'Alpaca',
'menu_name' => 'llama',
'link' => [[
'uri' => 'internal:/',
]],
'link' => [
['uri' => 'internal:/'],
],
'bundle' => 'menu_name',
]);
$menu_link_2->save();

View file

@ -0,0 +1,166 @@
<?php
namespace Drupal\Tests\menu_ui\Functional;
use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\content_moderation\Traits\ContentModerationTestTrait;
/**
* Tests Menu UI and Content Moderation integration.
*
* @group menu_ui
*/
class MenuUiContentModerationTest extends BrowserTestBase {
use ContentModerationTestTrait;
/**
* Modules to install.
*
* @var array
*/
public static $modules = ['block', 'content_moderation', 'node', 'menu_ui', 'test_page_test'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->drupalPlaceBlock('system_menu_block:main');
// Create a 'page' content type.
$this->drupalCreateContentType([
'type' => 'page',
'name' => 'Basic page',
'display_submitted' => FALSE,
]);
$workflow = $this->createEditorialWorkflow();
$workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'page');
$workflow->save();
}
/**
* Tests that node drafts can not modify the menu settings.
*/
public function testMenuUiWithPendingRevisions() {
$editor = $this->drupalCreateUser([
'administer nodes',
'administer menu',
'create page content',
'edit any page content',
'use editorial transition create_new_draft',
'use editorial transition publish',
'view latest version',
'view any unpublished content',
]);
$this->drupalLogin($editor);
// Create a node.
$node = $this->drupalCreateNode();
// Publish the node with no changes.
$this->drupalPostForm('node/' . $node->id() . '/edit', [], t('Save'));
$this->assertSession()->responseContains(t('Page %label has been updated.', ['%label' => $node->toLink($node->label())->toString()]));
// Create a pending revision with no changes.
$edit = ['moderation_state[0][state]' => 'draft'];
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
$this->assertSession()->responseContains(t('Page %label has been updated.', ['%label' => $node->toLink($node->label())->toString()]));
// Add a menu link and save a new default (published) revision.
$edit = [
'menu[enabled]' => 1,
'menu[title]' => 'Test menu link',
'moderation_state[0][state]' => 'published',
];
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
$this->assertSession()->linkExists('Test menu link');
// Try to change the menu link title and save a new non-default (draft)
// revision.
$edit = [
'menu[title]' => 'Test menu link draft',
'moderation_state[0][state]' => 'draft',
];
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
// Check that the menu settings were not applied.
$this->assertSession()->pageTextContains('You can only change the menu settings for the published version of this content.');
$this->assertSession()->linkExists('Test menu link');
$this->assertSession()->linkNotExists('Test menu link draft');
// Try to change the menu link description and save a new non-default
// (draft) revision.
$edit = [
'menu[description]' => 'Test menu link description',
'moderation_state[0][state]' => 'draft',
];
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
// Check that the menu settings were not applied.
$this->assertSession()->pageTextContains('You can only change the menu settings for the published version of this content.');
// Try to change the menu link weight and save a new non-default (draft)
// revision.
$edit = [
'menu[weight]' => 1,
'moderation_state[0][state]' => 'draft',
];
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
// Check that the menu settings were not applied.
$this->assertSession()->pageTextContains('You can only change the menu settings for the published version of this content.');
// Try to change the menu link parent and save a new non-default (draft)
// revision.
$edit = [
'menu[menu_parent]' => 'main:test_page_test.front_page',
'moderation_state[0][state]' => 'draft',
];
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
// Check that the menu settings were not applied.
$this->assertSession()->pageTextContains('You can only change the menu settings for the published version of this content.');
// Try to delete the menu link and save a new non-default (draft) revision.
$edit = [
'menu[enabled]' => 0,
'moderation_state[0][state]' => 'draft',
];
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
// Check that the menu settings were not applied.
$this->assertSession()->pageTextContains('You can only change the menu settings for the published version of this content.');
$this->assertSession()->linkExists('Test menu link');
// Try to save a new non-default (draft) revision without any changes and
// check that the error message is not shown.
$edit = ['moderation_state[0][state]' => 'draft'];
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
// Check that the menu settings were not applied.
$this->assertSession()->pageTextNotContains('You can only change the menu settings for the published version of this content.');
$this->assertSession()->linkExists('Test menu link');
// Create a node.
$node = $this->drupalCreateNode();
// Publish the node with no changes.
$edit = ['moderation_state[0][state]' => 'published'];
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
$this->assertSession()->responseContains(t('Page %label has been updated.', ['%label' => $node->toLink($node->label())->toString()]));
// Add a menu link and save and create a new non-default (draft) revision.
$edit = [
'menu[enabled]' => 1,
'menu[title]' => 'Test menu link',
'moderation_state[0][state]' => 'draft',
];
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
$this->assertSession()->pageTextContains('You can only change the menu settings for the published version of this content.');
}
}

View file

@ -1,10 +1,11 @@
<?php
namespace Drupal\menu_ui\Tests;
namespace Drupal\Tests\menu_ui\Functional;
use Drupal\Component\Utility\Unicode;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\language\Entity\ContentLanguageSettings;
use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\menu_ui\Traits\MenuUiTrait;
/**
* Tests for menu_ui language settings.
@ -14,14 +15,20 @@ use Drupal\language\Entity\ContentLanguageSettings;
*
* @group menu_ui
*/
class MenuLanguageTest extends MenuWebTestBase {
class MenuUiLanguageTest extends BrowserTestBase {
use MenuUiTrait;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['language'];
protected static $modules = [
'language',
'menu_link_content',
'menu_ui',
];
protected function setUp() {
parent::setUp();
@ -43,7 +50,7 @@ class MenuLanguageTest extends MenuWebTestBase {
public function testMenuLanguage() {
// Create a test menu to test the various language-related settings.
// Machine name has to be lowercase.
$menu_name = Unicode::strtolower($this->randomMachineName(16));
$menu_name = mb_strtolower($this->randomMachineName(16));
$label = $this->randomString();
$edit = [
'id' => $menu_name,
@ -73,11 +80,11 @@ class MenuLanguageTest extends MenuWebTestBase {
// Check the link was added with the correct menu link default language.
$menu_links = entity_load_multiple_by_properties('menu_link_content', ['title' => $link_title]);
$menu_link = reset($menu_links);
$this->assertMenuLink($menu_link->getPluginId(), [
$this->assertMenuLink([
'menu_name' => $menu_name,
'route_name' => '<front>',
'langcode' => 'bb',
]);
], $menu_link->getPluginId());
// Edit menu link default, changing it to cc.
ContentLanguageSettings::loadByEntityTypeBundle('menu_link_content', 'menu_link_content')
@ -95,22 +102,22 @@ class MenuLanguageTest extends MenuWebTestBase {
// Check the link was added with the correct new menu link default language.
$menu_links = entity_load_multiple_by_properties('menu_link_content', ['title' => $link_title]);
$menu_link = reset($menu_links);
$this->assertMenuLink($menu_link->getPluginId(), [
$this->assertMenuLink([
'menu_name' => $menu_name,
'route_name' => '<front>',
'langcode' => 'cc',
]);
], $menu_link->getPluginId());
// Now change the language of the new link to 'bb'.
$edit = [
'langcode[0][value]' => 'bb',
];
$this->drupalPostForm('admin/structure/menu/item/' . $menu_link->id() . '/edit', $edit, t('Save'));
$this->assertMenuLink($menu_link->getPluginId(), [
$this->assertMenuLink([
'menu_name' => $menu_name,
'route_name' => '<front>',
'langcode' => 'bb',
]);
], $menu_link->getPluginId());
// Saving menu link items ends up on the edit menu page. To check the menu
// link has the correct language default on edit, go to the menu link edit

View file

@ -1,18 +1,18 @@
<?php
namespace Drupal\menu_ui\Tests;
namespace Drupal\Tests\menu_ui\Functional;
use Drupal\simpletest\WebTestBase;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\menu_link_content\Entity\MenuLinkContent;
use Drupal\node\Entity\Node;
use Drupal\Tests\BrowserTestBase;
/**
* Add, edit, and delete a node with menu link.
*
* @group menu_ui
*/
class MenuNodeTest extends WebTestBase {
class MenuUiNodeTest extends BrowserTestBase {
/**
* An editor user.
@ -60,12 +60,17 @@ class MenuNodeTest extends WebTestBase {
// item" options in menu_ui_form_node_type_form_alter(). The "log out" link
// adds the "user.roles:authenticated" cache context.
$this->drupalGet('admin/structure/types/manage/page');
$this->assertCacheContext('user.roles:authenticated');
$this->assertSession()->responseHeaderContains('X-Drupal-Cache-Contexts', 'user.roles:authenticated');
// Verify that the menu link title has the correct maxlength.
$max_length = \Drupal::entityManager()->getBaseFieldDefinitions('menu_link_content')['title']->getSetting('max_length');
$title_max_length = \Drupal::entityManager()->getBaseFieldDefinitions('menu_link_content')['title']->getSetting('max_length');
$this->drupalGet('node/add/page');
$this->assertPattern('/<input .* id="edit-menu-title" .* maxlength="' . $max_length . '" .* \/>/', 'Menu link title field has correct maxlength in node add form.');
$this->assertPattern('/<input .* id="edit-menu-title" .* maxlength="' . $title_max_length . '" .* \/>/', 'Menu link title field has correct maxlength in node add form.');
// Verify that the menu link description has the correct maxlength.
$description_max_length = \Drupal::entityManager()->getBaseFieldDefinitions('menu_link_content')['description']->getSetting('max_length');
$this->drupalGet('node/add/page');
$this->assertPattern('/<input .* id="edit-menu-description" .* maxlength="' . $description_max_length . '" .* \/>/', 'Menu link description field has correct maxlength in node add form.');
// Disable the default main menu, so that no menus are enabled.
$edit = [
@ -134,8 +139,7 @@ class MenuNodeTest extends WebTestBase {
$this->drupalGet('test-page');
$this->assertNoLink($node_title);
// Use not only the save button, but also the two special buttons:
// 'Save and publish' as well as 'Save and keep published'.
// Make sure the menu links only appear when the node is published.
// These buttons just appear for 'administer nodes' users.
$admin_user = $this->drupalCreateUser([
'access administration pages',
@ -146,21 +150,20 @@ class MenuNodeTest extends WebTestBase {
'edit any page content',
]);
$this->drupalLogin($admin_user);
foreach (['Save and unpublish' => FALSE, 'Save and keep unpublished' => FALSE, 'Save and publish' => TRUE, 'Save and keep published' => TRUE] as $submit => $visible) {
$edit = [
'menu[enabled]' => 1,
'menu[title]' => $node_title,
];
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, $submit);
// Assert that the link exists.
$this->drupalGet('test-page');
if ($visible) {
$this->assertLink($node_title, 0, 'Found a menu link after submitted with ' . $submit);
}
else {
$this->assertNoLink($node_title, 'Found no menu link after submitted with ' . $submit);
}
}
// Assert that the link does not exist if unpublished.
$edit = [
'menu[enabled]' => 1,
'menu[title]' => $node_title,
'status[value]' => FALSE,
];
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, 'Save');
$this->drupalGet('test-page');
$this->assertNoLink($node_title, 'Found no menu link with the node unpublished');
// Assert that the link exists if published.
$edit['status[value]'] = TRUE;
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, 'Save');
$this->drupalGet('test-page');
$this->assertLink($node_title, 0, 'Found a menu link with the node published');
// Log back in as normal user.
$this->drupalLogin($this->editor);
@ -177,7 +180,8 @@ class MenuNodeTest extends WebTestBase {
$this->drupalGet('node/' . $node->id() . '/edit');
$this->assertFieldById('edit-menu-weight', 17, 'Menu weight correct in edit form');
$this->assertPattern('/<input .* id="edit-menu-title" .* maxlength="' . $max_length . '" .* \/>/', 'Menu link title field has correct maxlength in node edit form.');
$this->assertPattern('/<input .* id="edit-menu-title" .* maxlength="' . $title_max_length . '" .* \/>/', 'Menu link title field has correct maxlength in node edit form.');
$this->assertPattern('/<input .* id="edit-menu-description" .* maxlength="' . $description_max_length . '" .* \/>/', 'Menu link description field has correct maxlength in node add form.');
// Disable the menu link, then edit the node--the link should stay disabled.
$link_id = menu_ui_get_menu_link_defaults($node)['entity_id'];

View file

@ -1,16 +1,17 @@
<?php
namespace Drupal\menu_ui\Tests;
namespace Drupal\Tests\menu_ui\Functional;
use Drupal\block\Entity\Block;
use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
use Drupal\Core\Menu\MenuLinkInterface;
use Drupal\Core\Url;
use Drupal\menu_link_content\Entity\MenuLinkContent;
use Drupal\system\Entity\Menu;
use Drupal\node\Entity\Node;
use Drupal\node\NodeInterface;
use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\menu_ui\Traits\MenuUiTrait;
/**
* Add a custom menu, add menu links to the custom menu and Tools menu, check
@ -18,14 +19,25 @@ use Drupal\node\NodeInterface;
*
* @group menu_ui
*/
class MenuTest extends MenuWebTestBase {
class MenuUiTest extends BrowserTestBase {
use MenuUiTrait;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['node', 'block', 'contextual', 'help', 'path', 'test_page_test'];
protected static $modules = [
'block',
'contextual',
'help',
'menu_link_content',
'menu_ui',
'node',
'path',
'test_page_test',
];
/**
* A user with administration rights.
@ -195,7 +207,7 @@ class MenuTest extends MenuWebTestBase {
$this->assertRaw(t('@name cannot be longer than %max characters but is currently %length characters long.', [
'@name' => t('Menu name'),
'%max' => MENU_MAX_MENU_NAME_LENGTH_UI,
'%length' => Unicode::strlen($menu_name),
'%length' => mb_strlen($menu_name),
]));
// Change the menu_name so it no longer exceeds the maximum length.
@ -207,7 +219,7 @@ class MenuTest extends MenuWebTestBase {
$this->assertNoRaw(t('@name cannot be longer than %max characters but is currently %length characters long.', [
'@name' => t('Menu name'),
'%max' => MENU_MAX_MENU_NAME_LENGTH_UI,
'%length' => Unicode::strlen($menu_name),
'%length' => mb_strlen($menu_name),
]));
// Verify that the confirmation message is displayed.
$this->assertRaw(t('Menu %label has been added.', ['%label' => $label]));
@ -216,7 +228,7 @@ class MenuTest extends MenuWebTestBase {
// Confirm that the custom menu block is available.
$this->drupalGet('admin/structure/block/list/' . $this->config('system.theme')->get('default'));
$this->clickLinkPartialName('Place block');
$this->clickLink('Place block');
$this->assertText($label);
// Enable the block.
@ -310,25 +322,25 @@ class MenuTest extends MenuWebTestBase {
// -- item2
// --- item3
$this->assertMenuLink($item1->getPluginId(), [
$this->assertMenuLink([
'children' => [$item2->getPluginId(), $item3->getPluginId()],
'parents' => [$item1->getPluginId()],
// We assert the language code here to make sure that the language
// selection element degrades gracefully without the Language module.
'langcode' => 'en',
]);
$this->assertMenuLink($item2->getPluginId(), [
], $item1->getPluginId());
$this->assertMenuLink([
'children' => [$item3->getPluginId()],
'parents' => [$item2->getPluginId(), $item1->getPluginId()],
// See above.
'langcode' => 'en',
]);
$this->assertMenuLink($item3->getPluginId(), [
], $item2->getPluginId());
$this->assertMenuLink([
'children' => [],
'parents' => [$item3->getPluginId(), $item2->getPluginId(), $item1->getPluginId()],
// See above.
'langcode' => 'en',
]);
], $item3->getPluginId());
// Verify menu links.
$this->verifyMenuLink($item1, $node1);
@ -350,18 +362,18 @@ class MenuTest extends MenuWebTestBase {
// -- item5
// -- item6
$this->assertMenuLink($item4->getPluginId(), [
$this->assertMenuLink([
'children' => [$item5->getPluginId(), $item6->getPluginId()],
'parents' => [$item4->getPluginId()],
// See above.
'langcode' => 'en',
]);
$this->assertMenuLink($item5->getPluginId(), [
], $item4->getPluginId());
$this->assertMenuLink([
'children' => [],
'parents' => [$item5->getPluginId(), $item4->getPluginId()],
'langcode' => 'en',
]);
$this->assertMenuLink($item6->getPluginId(), [
], $item5->getPluginId());
$this->assertMenuLink([
'children' => [],
'parents' => [$item6->getPluginId(), $item4->getPluginId()],
'route_name' => 'entity.node.canonical',
@ -369,7 +381,7 @@ class MenuTest extends MenuWebTestBase {
'url' => '',
// See above.
'langcode' => 'en',
]);
], $item6->getPluginId());
// Modify menu links.
$this->modifyMenuLink($item1);
@ -390,37 +402,37 @@ class MenuTest extends MenuWebTestBase {
// ---- item3
// -- item6
$this->assertMenuLink($item1->getPluginId(), [
$this->assertMenuLink([
'children' => [],
'parents' => [$item1->getPluginId()],
// See above.
'langcode' => 'en',
]);
$this->assertMenuLink($item4->getPluginId(), [
], $item1->getPluginId());
$this->assertMenuLink([
'children' => [$item5->getPluginId(), $item6->getPluginId(), $item2->getPluginId(), $item3->getPluginId()],
'parents' => [$item4->getPluginId()],
// See above.
'langcode' => 'en',
]);
], $item4->getPluginId());
$this->assertMenuLink($item5->getPluginId(), [
$this->assertMenuLink([
'children' => [$item2->getPluginId(), $item3->getPluginId()],
'parents' => [$item5->getPluginId(), $item4->getPluginId()],
// See above.
'langcode' => 'en',
]);
$this->assertMenuLink($item2->getPluginId(), [
], $item5->getPluginId());
$this->assertMenuLink([
'children' => [$item3->getPluginId()],
'parents' => [$item2->getPluginId(), $item5->getPluginId(), $item4->getPluginId()],
// See above.
'langcode' => 'en',
]);
$this->assertMenuLink($item3->getPluginId(), [
], $item2->getPluginId());
$this->assertMenuLink([
'children' => [],
'parents' => [$item3->getPluginId(), $item2->getPluginId(), $item5->getPluginId(), $item4->getPluginId()],
// See above.
'langcode' => 'en',
]);
], $item3->getPluginId());
// Add 102 menu links with increasing weights, then make sure the last-added
// item's weight doesn't get changed because of the old hardcoded delta=50.
@ -428,7 +440,7 @@ class MenuTest extends MenuWebTestBase {
for ($i = -50; $i <= 51; $i++) {
$items[$i] = $this->addMenuLink('', '/node/' . $node1->id(), $menu_name, TRUE, strval($i));
}
$this->assertMenuLink($items[51]->getPluginId(), ['weight' => '51']);
$this->assertMenuLink(['weight' => '51'], $items[51]->getPluginId());
// Disable a link and then re-enable the link via the overview form.
$this->disableMenuLink($item1);
@ -446,15 +458,15 @@ class MenuTest extends MenuWebTestBase {
$item5->save();
// Verify in the database.
$this->assertMenuLink($item1->getPluginId(), ['enabled' => 1]);
$this->assertMenuLink(['enabled' => 1], $item1->getPluginId());
// Add an external link.
$item7 = $this->addMenuLink('', 'https://www.drupal.org', $menu_name);
$this->assertMenuLink($item7->getPluginId(), ['url' => 'https://www.drupal.org']);
$this->assertMenuLink(['url' => 'https://www.drupal.org'], $item7->getPluginId());
// Add <front> menu item.
$item8 = $this->addMenuLink('', '/', $menu_name);
$this->assertMenuLink($item8->getPluginId(), ['route_name' => '<front>']);
$this->assertMenuLink(['route_name' => '<front>'], $item8->getPluginId());
$this->drupalGet('');
$this->assertResponse(200);
// Make sure we get routed correctly.
@ -531,7 +543,7 @@ class MenuTest extends MenuWebTestBase {
// Make sure menu shows up with new name in block addition.
$default_theme = $this->config('system.theme')->get('default');
$this->drupalget('admin/structure/block/list/' . $default_theme);
$this->clickLinkPartialName('Place block');
$this->clickLink('Place block');
$this->assertText($edit['label']);
}
@ -557,30 +569,7 @@ class MenuTest extends MenuWebTestBase {
$this->assertNoText($item->getTitle(), "Menu link pointing to unpublished node is only visible to users with 'bypass node access' permission");
// The cache contexts associated with the (in)accessible menu links are
// bubbled. See DefaultMenuLinkTreeManipulators::menuLinkCheckAccess().
$this->assertCacheContext('user.permissions');
}
/**
* Tests the contextual links on a menu block.
*/
public function testBlockContextualLinks() {
$this->drupalLogin($this->drupalCreateUser(['administer menu', 'access contextual links', 'administer blocks']));
$custom_menu = $this->addCustomMenu();
$this->addMenuLink('', '/', $custom_menu->id());
$block = $this->drupalPlaceBlock('system_menu_block:' . $custom_menu->id(), ['label' => 'Custom menu', 'provider' => 'system']);
$this->drupalGet('test-page');
$id = 'block:block=' . $block->id() . ':langcode=en|menu:menu=' . $custom_menu->id() . ':langcode=en';
// @see \Drupal\contextual\Tests\ContextualDynamicContextTest:assertContextualLinkPlaceHolder()
$this->assertRaw('<div data-contextual-id="' . $id . '"></div>', format_string('Contextual link placeholder with id @id exists.', ['@id' => $id]));
// Get server-rendered contextual links.
// @see \Drupal\contextual\Tests\ContextualDynamicContextTest:renderContextualLinks()
$post = ['ids[0]' => $id];
$response = $this->drupalPost('contextual/render', 'application/json', $post, ['query' => ['destination' => 'test-page']]);
$this->assertResponse(200);
$json = Json::decode($response);
$this->assertIdentical($json[$id], '<ul class="contextual-links"><li class="block-configure"><a href="' . base_path() . 'admin/structure/block/manage/' . $block->id() . '">Configure block</a></li><li class="entitymenuedit-form"><a href="' . base_path() . 'admin/structure/menu/manage/' . $custom_menu->id() . '">Edit menu</a></li></ul>');
$this->assertSession()->responseHeaderContains('X-Drupal-Cache-Contexts', 'user.permissions');
}
/**
@ -627,7 +616,7 @@ class MenuTest extends MenuWebTestBase {
$menu_link = reset($menu_links);
$this->assertTrue($menu_link, 'Menu link was found in database.');
$this->assertMenuLink($menu_link->getPluginId(), ['menu_name' => $menu_name, 'children' => [], 'parent' => $parent]);
$this->assertMenuLink(['menu_name' => $menu_name, 'children' => [], 'parent' => $parent], $menu_link->getPluginId());
return $menu_link;
}
@ -673,7 +662,7 @@ class MenuTest extends MenuWebTestBase {
$this->drupalPostForm("admin/structure/menu/manage/{$this->menu->id()}/add", $edit, t('Save'));
$menu_links = entity_load_multiple_by_properties('menu_link_content', ['title' => $title]);
$last_link = reset($menu_links);
$created_links[] = 'tools:' . $last_link->getPluginId();
$created_links[] = 'tools:' . $last_link->getPluginId();
}
// The last link cannot be a parent in the new menu link form.
@ -841,7 +830,7 @@ class MenuTest extends MenuWebTestBase {
// Unlike most other modules, there is no confirmation message displayed.
// Verify in the database.
$this->assertMenuLink($item->getPluginId(), ['enabled' => 0]);
$this->assertMenuLink(['enabled' => 0], $item->getPluginId());
}
/**
@ -856,25 +845,23 @@ class MenuTest extends MenuWebTestBase {
$this->drupalPostForm("admin/structure/menu/item/$mlid/edit", $edit, t('Save'));
// Verify in the database.
$this->assertMenuLink($item->getPluginId(), ['enabled' => 1]);
$this->assertMenuLink(['enabled' => 1], $item->getPluginId());
}
/**
* Tests if administrative users other than user 1 can access the menu parents
* AJAX callback.
* Tests if admin users, other than UID1, can access parents AJAX callback.
*/
public function testMenuParentsJsAccess() {
$admin = $this->drupalCreateUser(['administer menu']);
$this->drupalLogin($admin);
$this->drupalLogin($this->drupalCreateUser(['administer menu']));
// Just check access to the callback overall, the POST data is irrelevant.
$this->drupalGetAjax('admin/structure/menu/parents');
$this->assertResponse(200);
$this->drupalGet('admin/structure/menu/parents', ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax']], ['X-Requested-With: XMLHttpRequest']);
$this->assertSession()->statusCodeEquals(200);
// Do standard user tests.
// Log in the user.
$this->drupalLogin($this->authenticatedUser);
$this->drupalGetAjax('admin/structure/menu/parents');
$this->assertResponse(403);
// Log in as authenticated user.
$this->drupalLogin($this->drupalCreateUser());
// Check that a simple user is not able to access the menu.
$this->drupalGet('admin/structure/menu/parents', ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax']], ['X-Requested-With: XMLHttpRequest']);
$this->assertSession()->statusCodeEquals(403);
}
/**

View file

@ -0,0 +1,157 @@
<?php
namespace Drupal\Tests\menu_ui\FunctionalJavascript;
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
use Drupal\system\Entity\Menu;
use Drupal\Tests\contextual\FunctionalJavascript\ContextualLinkClickTrait;
use Drupal\Tests\menu_ui\Traits\MenuUiTrait;
/**
* Tests custom menu and menu links operations using the UI.
*
* @group menu_ui
*/
class MenuUiJavascriptTest extends WebDriverTestBase {
use ContextualLinkClickTrait;
use MenuUiTrait;
/**
* {@inheritdoc}
*/
protected static $modules = [
'block',
'contextual',
'menu_link_content',
'menu_ui',
'test_page_test',
];
/**
* Tests the contextual links on a menu block.
*/
public function testBlockContextualLinks() {
$this->drupalLogin($this->drupalCreateUser([
'administer menu',
'access contextual links',
'administer blocks',
]));
$menu = $this->addCustomMenu();
$block = $this->drupalPlaceBlock('system_menu_block:' . $menu->id(), [
'label' => 'Custom menu',
'provider' => 'system',
]);
$this->addMenuLink('', '/', $menu->id());
$this->drupalGet('test-page');
// Click on 'Configure block' contextual link.
$this->clickContextualLink("#block-{$block->id()}", 'Configure block');
// Check that we're on block configuration form.
$this->assertNotEmpty($this->getSession()->getPage()->findLink('Remove block'));
$this->drupalGet('test-page');
// Click on 'Edit menu' contextual link.
$this->clickContextualLink("#block-{$block->id()}", 'Edit menu');
// Check that we're on block configuration form.
$this->assertSession()->pageTextContains("Machine name: {$menu->id()}");
}
/**
* Creates a custom menu.
*
* @return \Drupal\system\Entity\Menu
* The custom menu that has been created.
*/
protected function addCustomMenu() {
// Try adding a menu using a menu_name that is too long.
$label = $this->randomMachineName(16);
$menu_id = strtolower($this->randomMachineName(MENU_MAX_MENU_NAME_LENGTH_UI + 1));
$this->drupalGet('admin/structure/menu/add');
$page = $this->getSession()->getPage();
// Type the label to activate the machine name field and the edit button.
$page->fillField('Title', $label);
// Wait for the machine name widget to be activated.
$this->assertSession()->waitForElementVisible('css', 'button[type=button].link:contains(Edit)');
// Activate the machine name text field.
$page->pressButton('Edit');
// Try to fill a text longer than the allowed limit.
$page->fillField('Menu name', $menu_id);
$page->pressButton('Save');
// Check that the menu was saved with the ID truncated to the max length.
$menu = Menu::load(substr($menu_id, 0, MENU_MAX_MENU_NAME_LENGTH_UI));
$this->assertEquals($label, $menu->label());
// Check that the menu was added.
$this->drupalGet('admin/structure/menu');
$this->assertSession()->pageTextContains($label);
// Confirm that the custom menu block is available.
$this->drupalGet('admin/structure/block/list/' . $this->config('system.theme')->get('default'));
$this->clickLink('Place block');
// Wait for the modal dialog to be loaded.
$this->assertSession()->waitForElement('css', "div[aria-describedby=drupal-modal]");
// Check that the block is available to be placed.
$this->assertSession()->pageTextContains($label);
return $menu;
}
/**
* Adds a menu link using the UI.
*
* @param string $parent
* Optional parent menu link id.
* @param string $path
* The path to enter on the form. Defaults to the front page.
* @param string $menu_id
* Menu ID. Defaults to 'tools'.
* @param bool $expanded
* Whether or not this menu link is expanded. Setting this to TRUE should
* test whether it works when we do the authenticatedUser tests. Defaults
* to FALSE.
* @param string $weight
* Menu weight. Defaults to 0.
*
* @return \Drupal\menu_link_content\Entity\MenuLinkContent
* A menu link entity.
*/
protected function addMenuLink($parent = '', $path = '/', $menu_id = 'tools', $expanded = FALSE, $weight = '0') {
// View add menu link page.
$this->drupalGet("admin/structure/menu/manage/$menu_id/add");
$title = '!link_' . $this->randomMachineName(16);
$edit = [
'link[0][uri]' => $path,
'title[0][value]' => $title,
'description[0][value]' => '',
'enabled[value]' => 1,
'expanded[value]' => $expanded,
'menu_parent' => $menu_id . ':' . $parent,
'weight[0][value]' => $weight,
];
// Add menu link.
$this->drupalPostForm(NULL, $edit, 'Save');
$this->assertSession()->pageTextContains('The menu link has been saved.');
$storage = $this->container->get('entity_type.manager')->getStorage('menu_link_content');
$menu_links = $storage->loadByProperties(['title' => $title]);
$menu_link = reset($menu_links);
// Check that the stored menu link meeting the expectations.
$this->assertNotNull($menu_link);
$this->assertMenuLink([
'menu_name' => $menu_id,
'children' => [],
'parent' => $parent,
], $menu_link->getPluginId());
return $menu_link;
}
}

View file

@ -0,0 +1,69 @@
<?php
namespace Drupal\Tests\menu_ui\Traits;
/**
* Provides common methods for Menu UI module tests.
*/
trait MenuUiTrait {
/**
* Asserts that a menu fetched from the database matches an expected one.
*
* @param array $expected_item
* Array containing properties to check.
* @param int $menu_plugin_id
* Menu item id.
*/
protected function assertMenuLink(array $expected_item, $menu_plugin_id) {
// Retrieve the menu link.
/** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
$menu_link_manager->resetDefinitions();
// Reset the static load cache.
\Drupal::entityTypeManager()->getStorage('menu_link_content')->resetCache();
$definition = $menu_link_manager->getDefinition($menu_plugin_id);
$entity = NULL;
// Pull the path from the menu link content.
if (strpos($menu_plugin_id, 'menu_link_content') === 0) {
list(, $uuid) = explode(':', $menu_plugin_id, 2);
/** @var \Drupal\menu_link_content\Entity\MenuLinkContent $entity */
$entity = \Drupal::service('entity.repository')
->loadEntityByUuid('menu_link_content', $uuid);
}
if (isset($expected_item['children'])) {
$child_ids = array_values($menu_link_manager->getChildIds($menu_plugin_id));
sort($expected_item['children']);
if ($child_ids) {
sort($child_ids);
}
$this->assertSame($expected_item['children'], $child_ids);
unset($expected_item['children']);
}
if (isset($expected_item['parents'])) {
$parent_ids = array_values($menu_link_manager->getParentIds($menu_plugin_id));
$this->assertSame($expected_item['parents'], $parent_ids);
unset($expected_item['parents']);
}
if (isset($expected_item['langcode']) && $entity) {
$this->assertEquals($expected_item['langcode'], $entity->langcode->value);
unset($expected_item['langcode']);
}
if (isset($expected_item['enabled']) && $entity) {
$this->assertEquals($expected_item['enabled'], $entity->enabled->value);
unset($expected_item['enabled']);
}
foreach ($expected_item as $key => $value) {
$this->assertNotNull($definition[$key]);
$this->assertSame($value, $definition[$key]);
}
}
}