first commit

This commit is contained in:
2024-07-15 12:33:27 +02:00
commit ce50ae282b
22084 changed files with 2623791 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
name: Admin Toolbar Search
description: Provides search of Admin Toolbar items.
package: Administration
type: module
core_version_requirement: ^9.2 || ^10
configure: admin_toolbar_search.settings
dependencies:
- admin_toolbar:admin_toolbar_tools
# Information added by Drupal.org packaging script on 2023-09-29
version: '3.4.2'
project: 'admin_toolbar'
datestamp: 1696006156

View File

@@ -0,0 +1,11 @@
search:
css:
theme:
css/admin.toolbar_search.css: {}
js:
js/admin_toolbar_search.js: {}
dependencies:
- core/jquery
- core/drupal
- core/once
- core/drupal.autocomplete

View File

@@ -0,0 +1,5 @@
admin_toolbar_search.settings:
title: 'Admin Toolbar Search'
description: 'Configure the Admin Toolbar Search module.'
route_name: admin_toolbar_search.settings
parent: system.admin_config_ui

View File

@@ -0,0 +1,142 @@
<?php
/**
* @file
* Functionality for search of Admin Toolbar.
*/
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url;
/**
* Implements hook_help().
*/
function admin_toolbar_search_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
// Main module help.
case 'help.page.admin_toolbar_search':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('The Admin Toolbar Search module add a search option to the toolbar for site administrative tasks.') . '</p>';
return $output;
}
}
/**
* Implements hook_toolbar_alter().
*/
function admin_toolbar_search_toolbar_alter(&$items) {
if (!\Drupal::currentUser()->hasPermission('use admin toolbar search')) {
return;
}
$admin_toolbar_tools_enabled = \Drupal::service('module_handler')
->moduleExists('admin_toolbar_tools');
$config = \Drupal::config('admin_toolbar_search.settings');
$display_menu_item = $config->get('display_menu_item');
if (!$display_menu_item) {
$items['administration_mobile_search'] = [
'#type' => 'toolbar_item',
'#weight' => 100,
'tab' => [
'#type' => 'link',
'#title' => new TranslatableMarkup('Search'),
'#url' => Url::fromRoute('system.admin'),
'#attributes' => [
'class' => [
'toolbar-icon',
],
],
],
'#wrapper_attributes' => [
'id' => 'admin-toolbar-mobile-search-tab',
],
];
$items['administration_search'] = [
"#type" => "toolbar_item",
'#weight' => 101,
'tab' => [
'search' => [
'#title' => t('Search'),
'#title_display' => 'invisible',
'#type' => 'search',
'#size' => 30,
'#attributes' => [
'placeholder' => new TranslatableMarkup('Admin Toolbar quick search'),
],
'#id' => 'admin-toolbar-search-input',
],
],
'#attached' => [
'library' => [
'admin_toolbar_search/search',
],
'drupalSettings' => [
'adminToolbarSearch' => [
'loadExtraLinks' => $admin_toolbar_tools_enabled,
],
],
],
'#wrapper_attributes' => [
'id' => 'admin-toolbar-search-tab',
],
'#cache' => [
'contexts' => [
'user.permissions',
],
'tags' => [
'config:admin_toolbar_search.settings',
],
],
];
}
else {
$items['administration_search'] = [
"#type" => "toolbar_item",
'tab' => [
'#type' => 'link',
'#title' => new TranslatableMarkup('Search'),
'#url' => URL::fromRoute('system.admin'),
'#attributes' => [
'class' => [
'toolbar-icon',
],
],
],
'tray' => [
'search' => [
'#title' => t('Search'),
'#type' => 'search',
'#size' => 60,
'#id' => 'admin-toolbar-search-input',
],
],
'#attached' => [
'library' => [
'admin_toolbar_search/search',
],
'drupalSettings' => [
'adminToolbarSearch' => [
'loadExtraLinks' => $admin_toolbar_tools_enabled,
],
],
],
'#wrapper_attributes' => [
"id" => "admin-toolbar-search-tab",
],
'#cache' => [
'contexts' => [
'user.permissions',
],
'tags' => [
'config:admin_toolbar_search.settings',
],
],
];
}
}

View File

@@ -0,0 +1,2 @@
use admin toolbar search:
title: 'Use Admin Toolbar search'

View File

@@ -0,0 +1,14 @@
admin_toolbar.search:
path: '/admin/admin-toolbar-search'
defaults:
_controller: '\Drupal\admin_toolbar_search\Controller\AdminToolbarSearchController::search'
requirements:
_permission: 'use admin toolbar search'
admin_toolbar_search.settings:
path: '/admin/config/user-interface/admin-toolbar-search-settings'
defaults:
_title: 'Admin toolbar search settings'
_form: 'Drupal\admin_toolbar_search\Form\AdminToolbarSearchSettingsForm'
requirements:
_permission: 'administer site configuration'

View File

@@ -0,0 +1,10 @@
services:
admin_toolbar_search.search_links:
class: Drupal\admin_toolbar_search\SearchLinks
arguments:
- '@entity_type.manager'
- '@module_handler'
- '@router.route_provider'
- '@cache_contexts_manager'
- '@cache.toolbar'
- '@config.factory'

View File

@@ -0,0 +1,110 @@
#admin-toolbar-mobile-search-tab ~ #admin-toolbar-search-tab {
display: none;
}
#admin-toolbar-mobile-search-tab ~ #admin-toolbar-search-tab.visible {
display: block;
width: 100%;
}
#admin-toolbar-mobile-search-tab ~ #admin-toolbar-search-tab .js-form-item.form-item {
margin: 0.75rem 0;
padding-left: 1rem;
padding-right: 1rem;
}
#admin-toolbar-mobile-search-tab .toolbar-item::before {
background-image: url('../../misc/icons/bebebe/loupe.svg');
}
#admin-toolbar-mobile-search-tab ~ #admin-toolbar-search-tab #admin-toolbar-search-input {
width: 100%;
}
@media only screen and (min-width: 769px) {
#admin-toolbar-mobile-search-tab {
display: none;
}
#admin-toolbar-mobile-search-tab ~ #admin-toolbar-search-tab {
display: block;
}
#admin-toolbar-mobile-search-tab ~ #admin-toolbar-search-tab.visible {
width: auto;
}
#admin-toolbar-mobile-search-tab ~ #admin-toolbar-search-tab .js-form-item.form-item {
margin-top: 0.3rem;
margin-bottom: 0;
}
}
#admin-toolbar-search-input {
min-height: 30px;
height: 100%;
padding: 0 0.4rem;
line-height: 1.75rem;
margin: 0;
color: #3b3b3b;
background: #fcfcfa;
border: 1px solid #ccc;
border-radius: unset;
font-size: 1em;
}
.ui-autocomplete .ui-menu-item span.admin-toolbar-search-url {
display: none;
}
.admin-toolbar-search-autocomplete-list {
max-height: 300px;
overflow-y: scroll;
}
.admin-toolbar-search-autocomplete-list .ui-menu-item .ui-state-active {
margin: 0;
}
.admin-toolbar-search-autocomplete-list .ui-menu-item .ui-menu-item-wrapper {
border: 1px solid transparent;
padding: 3px 1em 3px 0.4em;
}
.admin-toolbar-search-autocomplete-list .ui-menu-item a {
text-decoration: none;
}
.admin-toolbar-search-autocomplete-list .ui-menu-item .ui-state-active:hover a,
.admin-toolbar-search-autocomplete-list .ui-menu-item .ui-state-active a {
color: white;
}
#toolbar-item-administration-search-tray label {
display: inline-block;
color: #000000;
margin-right: .5em;
font-weight: bold;
}
#toolbar-item-administration-search-tray div.form-item {
margin: 0.75em;
}
#toolbar-item-administration-search-tray input {
display: inline-block;
padding: 0.3em 0.4em 0.3em 0.5em;
font-size: 1em;
}
#admin-toolbar-search-tab .toolbar-item:before {
background-image: url('../../misc/icons/bebebe/loupe.svg');
}
#admin-toolbar-search-tab .toolbar-item:active:before,
#admin-toolbar-search-tab .toolbar-item.is-active:before {
background-image: url('../../misc/icons/ffffff/loupe.svg');
}
#toolbar-item-administration-search-tray div.form-item.js-form-type-textfield {
margin: 0.75em 0;
}

View File

@@ -0,0 +1,151 @@
/**
* @file
* Behaviors for the search widget in the admin toolbar.
*/
(function ($, Drupal) {
'use strict';
Drupal.behaviors.adminToolbarSearch = {
// If extra links have been fetched.
extraFetched: false,
attach: function (context) {
if (context != document) {
return;
}
var $self = this;
const elements = once('admin-toolbar-search', '#toolbar-bar', context);
$(elements).each(function () {
$self.links = [];
var $searchTab = $(this).find('#admin-toolbar-search-tab')
var $searchInput = $searchTab.find('#admin-toolbar-search-input');
if ($searchInput.length === 0) {
return;
}
$searchInput.autocomplete({
minLength: 2,
position: { collision : 'fit' },
source: function (request, response) {
var data = $self.handleAutocomplete(request.term);
if (!$self.extraFetched && drupalSettings.adminToolbarSearch.loadExtraLinks) {
$.getJSON( Drupal.url('admin/admin-toolbar-search'), function ( data ) {
$(data).each(function () {
var item = this;
item.label = this.labelRaw + ' ' + this.value;
$self.links.push(item);
});
$self.extraFetched = true;
var results = $self.handleAutocomplete(request.term);
response(results);
});
}
else {
response(data);
}
},
open: function () {
var zIndex = $('#toolbar-item-administration-tray')
.css('z-index') + 1;
$(this).autocomplete('widget').css('z-index', zIndex);
return false;
},
select: function (event, ui) {
if (ui.item.value) {
location.href = ui.item.value;
return false;
}
}
}).data('ui-autocomplete')._renderItem = (function (ul, item) {
ul.addClass('admin-toolbar-search-autocomplete-list');
return $('<li>')
.append('<div ><a href="' + item.value + '" onclick="window.open(this.href); return false;" >' + item.labelRaw + ' <span class="admin-toolbar-search-url">' + item.value + '</span></a></div>')
.appendTo(ul);
});
// Populate the links for search results when the input is pressed.
$searchInput.focus(function () {
Drupal.behaviors.adminToolbarSearch.populateLinks($self);
});
// Show/hide search input field when mobile tab item is pressed.
$('#admin-toolbar-mobile-search-tab .toolbar-item', context).click(function (e) {
e.preventDefault();
$(this).toggleClass('is-active');
$searchTab.toggleClass('visible');
$searchInput.focus();
});
});
},
getItemLabel: function (item) {
var breadcrumbs = [];
$(item).parents().each(function () {
if ($(this).hasClass('menu-item')) {
var $link = $(this).find('a:first');
if ($link.length && !$link.hasClass('admin-toolbar-search-ignore')) {
breadcrumbs.unshift($link.text());
}
}
});
return breadcrumbs.join(' > ');
},
handleAutocomplete: function (term) {
var $self = this;
var keywords = term.split(" "); // Split search terms into list.
var suggestions = [];
$self.links.forEach(function (element) {
var label = element.label.toLowerCase();
// Add exact matches.
if (label.indexOf(term.toLowerCase()) >= 0) {
suggestions.push(element);
}
else {
// Add suggestions where it matches all search terms.
var matchCount = 0;
keywords.forEach(function (keyword) {
if (label.indexOf(keyword.toLowerCase()) >= 0) {
matchCount++;
}
});
if (matchCount == keywords.length) {
suggestions.push(element);
}
}
});
return suggestions;
},
/**
* Populates the links in admin toolbar search.
*/
populateLinks: function ($self) {
// Populate only when links array is empty (only the first time).
if ($self.links.length === 0) {
var getUrl = window.location;
var baseUrl = getUrl.protocol + "//" + getUrl.host + "/";
$('.toolbar-tray a[data-drupal-link-system-path]').each(function () {
if (this.href !== baseUrl) {
var label = $self.getItemLabel(this);
$self.links.push({
'value': this.href,
'label': label + ' ' + this.href,
'labelRaw': Drupal.checkPlain(label)
});
}
});
}
},
};
})(jQuery, Drupal);

View File

@@ -0,0 +1,50 @@
<?php
namespace Drupal\admin_toolbar_search\Controller;
use Drupal\admin_toolbar_search\SearchLinks;
use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
/**
* Class AdminToolbarSearchController to the search functionality.
*
* @package Drupal\admin_toolbar_tools\Controller
*/
class AdminToolbarSearchController extends ControllerBase {
/**
* The search links service.
*
* @var \Drupal\admin_toolbar_search\SearchLinks
*/
protected $links;
/**
* Constructs an AdminToolbarSearchController object.
*
* @param \Drupal\admin_toolbar_search\SearchLinks $links
* The search links service.
*/
public function __construct(SearchLinks $links) {
$this->links = $links;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('admin_toolbar_search.search_links')
);
}
/**
* Return additional search links.
*/
public function search() {
return new JsonResponse($this->links->getLinks());
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace Drupal\admin_toolbar_search\Form;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
/**
* Configure Admin Toolbar Search settings for this site.
*/
class AdminToolbarSearchSettingsForm extends ConfigFormBase {
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'admin_toolbar_search_admin_toolbar_search_settings';
}
/**
* {@inheritdoc}
*/
protected function getEditableConfigNames() {
return ['admin_toolbar_search.settings'];
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['display_menu_item'] = [
'#type' => 'checkbox',
'#title' => $this->t('Display the search input as a menu item.'),
'#description' => $this->t("If set, instead of displaying a text input field, it displays a menu item in the toolbar so the user has to click on it to toggle the search input."),
'#default_value' => $this->config('admin_toolbar_search.settings')->get('display_menu_item'),
];
return parent::buildForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$this->config('admin_toolbar_search.settings')
->set('display_menu_item', $form_state->getValue('display_menu_item'))
->save();
parent::submitForm($form, $form_state);
}
}

View File

@@ -0,0 +1,317 @@
<?php
namespace Drupal\admin_toolbar_search;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Cache\Context\CacheContextsManager;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Routing\RouteProviderInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Url;
use Drupal\system\Entity\Menu;
/**
* Extra search links.
*/
class SearchLinks {
use StringTranslationTrait;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The module handler.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* The route provider.
*
* @var \Drupal\Core\Routing\RouteProviderInterface
*/
protected $routeProvider;
/**
* The cache context manager service.
*
* @var \Drupal\Core\Cache\Context\CacheContextsManager
*/
protected $cacheContextManager;
/**
* The toolbar cache bin.
*
* @var \Drupal\Core\Cache\CacheBackendInterface
*/
protected $toolbarCache;
/**
* The admin toolbar tools configuration.
*
* @var \Drupal\Core\Config\Config
*/
protected $config;
/**
* Constructs a SearchLinks object.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
* @param \Drupal\Core\Routing\RouteProviderInterface $route_provider
* The route provider.
* @param \Drupal\Core\Cache\Context\CacheContextsManager $cache_context_manager
* The cache contexts manager.
* @param \Drupal\Core\Cache\CacheBackendInterface $toolbar_cache
* Cache backend instance to use.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* Config factory mservice.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager, ModuleHandlerInterface $module_handler, RouteProviderInterface $route_provider, CacheContextsManager $cache_context_manager, CacheBackendInterface $toolbar_cache, ConfigFactoryInterface $config_factory) {
$this->entityTypeManager = $entity_type_manager;
$this->moduleHandler = $module_handler;
$this->routeProvider = $route_provider;
$this->cacheContextManager = $cache_context_manager;
$this->toolbarCache = $toolbar_cache;
$this->config = $config_factory->get('admin_toolbar_tools.settings');
}
/**
* Gets extra links for admin toolbar search feature.
*
* @return array
* An array of link data for the JSON used for search.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
public function getLinks() {
$max_bundle_number = $this->config->get('max_bundle_number');
$additional_keys = $this->cacheContextManager->convertTokensToKeys([
'languages:' . LanguageInterface::TYPE_INTERFACE,
'user.permissions',
])->getKeys();
$cid_parts = array_merge(['admin_toolbar_search:links'], $additional_keys);
$cid = implode(':', $cid_parts);
if ($cache = $this->toolbarCache->get($cid)) {
return $cache->data;
}
$links = [];
$cache_tags = [];
$content_entities = $this->getBundleableEntitiesList();
// Adds common links to entities.
foreach ($content_entities as $entities) {
$content_entity_bundle = $entities['content_entity_bundle'];
$content_entity = $entities['content_entity'];
// Load the remaining items that were not loaded by the toolbar.
$content_entity_bundle_storage = $this->entityTypeManager->getStorage($content_entity_bundle);
$bundles_ids = $content_entity_bundle_storage->getQuery()->sort('weight')->range($max_bundle_number)->execute();
if (!empty($bundles_ids)) {
$bundles = $this->entityTypeManager
->getStorage($content_entity_bundle)
->loadMultiple($bundles_ids);
foreach ($bundles as $machine_name => $bundle) {
$cache_tags = Cache::mergeTags($cache_tags, $bundle->getEntityType()->getListCacheTags());
$tparams = [
'@entity_type' => $bundle->getEntityType()->getLabel(),
'@bundle' => $bundle->label(),
];
$label_base = $this->t('@entity_type > @bundle', $tparams);
$params = [$content_entity_bundle => $machine_name];
if ($this->routeExists('entity.' . $content_entity_bundle . '.overview_form')) {
// Some bundles have an overview/list form that make a better root
// link.
$url = Url::fromRoute('entity.' . $content_entity_bundle . '.overview_form', $params);
if ($url->access()) {
$url_string = $url->toString();
$links[] = [
'labelRaw' => $label_base,
'value' => $url_string,
];
}
}
if ($this->routeExists('entity.' . $content_entity_bundle . '.edit_form')) {
$url = Url::fromRoute('entity.' . $content_entity_bundle . '.edit_form', $params);
if ($url->access()) {
$url_string = $url->toString();
$links[] = [
'labelRaw' => $label_base . ' > ' . $this->t('Edit'),
'value' => $url_string,
];
}
}
if ($this->moduleHandler->moduleExists('field_ui')) {
if ($this->routeExists('entity.' . $content_entity . '.field_ui_fields')) {
$url = Url::fromRoute('entity.' . $content_entity . '.field_ui_fields', $params);
if ($url->access()) {
$url_string = $url->toString();
$links[] = [
'labelRaw' => $label_base . ' > ' . $this->t('Manage fields'),
'value' => $url_string,
];
}
}
if ($this->routeExists('entity.entity_form_display.' . $content_entity . '.default')) {
$url = Url::fromRoute('entity.entity_form_display.' . $content_entity . '.default', $params);
if ($url->access()) {
$url_string = $url->toString();
$links[] = [
'labelRaw' => $label_base . ' > ' . $this->t('Manage form display'),
'value' => $url_string,
];
}
}
if ($this->routeExists('entity.entity_view_display.' . $content_entity . '.default')) {
$url = Url::fromRoute('entity.entity_view_display.' . $content_entity . '.default', $params);
if ($url->access()) {
$url_string = $url->toString();
$links[] = [
'labelRaw' => $label_base . ' > ' . $this->t('Manage display'),
'value' => $url_string,
];
}
}
if ($this->moduleHandler->moduleExists('devel') && $this->routeExists('entity.' . $content_entity_bundle . '.devel_load')) {
$url = Url::fromRoute($route_name = 'entity.' . $content_entity_bundle . '.devel_load', $params);
if ($url->access()) {
$url_string = $url->toString();
$links[] = [
'labelRaw' => $label_base . ' > ' . $this->t('Devel'),
'value' => $url_string,
];
}
}
if ($this->routeExists('entity.' . $content_entity_bundle . '.delete_form')) {
$url = Url::fromRoute('entity.' . $content_entity_bundle . '.delete_form', $params);
if ($url->access()) {
$url_string = $url->toString();
$links[] = [
'labelRaw' => $label_base . ' > ' . $this->t('Delete'),
'value' => $url_string,
];
}
}
}
}
}
}
// Add menu links.
if ($this->moduleHandler->moduleExists('menu_ui')) {
$menus = $this->entityTypeManager->getStorage('menu')->loadMultiple();
uasort($menus, [Menu::class, 'sort']);
$menus = array_slice($menus, $max_bundle_number);
$cache_tags = Cache::mergeTags($cache_tags, ['config:menu_list']);
foreach ($menus as $menu_id => $menu) {
$route_name = 'entity.menu.edit_form';
$params = ['menu' => $menu_id];
$url = Url::fromRoute($route_name, $params);
if ($url->access()) {
$url_string = $url->toString();
$links[] = [
'labelRaw' => $this->t('Menus > @menu_label', ['@menu_label' => $menu->label()]),
'value' => $url_string,
];
}
$route_name = 'entity.menu.add_link_form';
$params = ['menu' => $menu_id];
$url = Url::fromRoute($route_name, $params);
if ($url->access()) {
$url_string = $url->toString();
$links[] = [
'labelRaw' => $this->t('Menus > @menu_label > Add link', ['@menu_label' => $menu->label()]),
'value' => $url_string,
];
}
$menus = ['admin', 'devel', 'footer', 'main', 'tools', 'account'];
if (!in_array($menu_id, $menus)) {
$route_name = 'entity.menu.delete_form';
$params = ['menu' => $menu_id];
$url = Url::fromRoute($route_name, $params);
if ($url->access()) {
$url_string = $url->toString();
$links[] = [
'labelRaw' => $this->t('Menus > @menu_label > Delete', ['@menu_label' => $menu->label()]),
'value' => $url_string,
];
}
}
if ($this->moduleHandler->moduleExists('devel') && $this->routeExists('entity.menu.devel_load')) {
$route_name = 'entity.menu.devel_load';
$params = ['menu' => $menu_id];
$url = Url::fromRoute($route_name, $params);
if ($url->access()) {
$url_string = $url->toString();
$links[] = [
'labelRaw' => $this->t('Menus > @menu_label > Devel', ['@menu_label' => $menu->label()]),
'value' => $url_string,
];
}
}
}
}
$this->toolbarCache->set($cid, $links, Cache::PERMANENT, $cache_tags);
return $links;
}
/**
* Gets a list of content entities.
*
* @return array
* An array of metadata about content entities.
*/
protected function getBundleableEntitiesList() {
$entity_types = $this->entityTypeManager->getDefinitions();
$content_entities = [];
foreach ($entity_types as $key => $entity_type) {
if ($entity_type->getBundleEntityType() && ($entity_type->get('field_ui_base_route') != '')) {
$content_entities[$key] = [
'content_entity' => $key,
'content_entity_bundle' => $entity_type->getBundleEntityType(),
];
}
}
return $content_entities;
}
/**
* Determine if a route exists by name.
*
* @param string $route_name
* The name of the route to check.
*
* @return bool
* Whether a route with that route name exists.
*/
public function routeExists($route_name) {
return (count($this->routeProvider->getRoutesByNames([$route_name])) === 1);
}
}

View File

@@ -0,0 +1,85 @@
<?php
namespace Drupal\Tests\admin_toolbar_search\Functional;
use Drupal\Core\Url;
use Drupal\Tests\BrowserTestBase;
/**
* Test the functionality of admin toolbar search.
*
* @group admin_toolbar
* @group admin_toolbar_search
*/
class AdminToolbarSearchSettingTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* {@inheritdoc}
*/
protected static $modules = [
'admin_toolbar_search',
'node',
'media',
'field_ui',
'menu_ui',
'block',
];
/**
* A user with the 'Use Admin Toolbar search' permission.
*
* @var \Drupal\user\UserInterface
*/
protected $userWithAccess;
/**
* A test user without the 'Use Admin Toolbar search' permission..
*
* @var \Drupal\user\UserInterface
*/
protected $noAccessUser;
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$permissions = [
'access toolbar',
'administer menu',
'access administration pages',
'administer site configuration',
'administer content types',
];
$this->noAccessUser = $this->drupalCreateUser($permissions);
$permissions[] = 'use admin toolbar search';
$this->userWithAccess = $this->drupalCreateUser($permissions);
}
/**
* Tests search functionality without admin_toolbar_tools enabled.
*/
public function testToolbarSearch() {
$this->drupalLogin($this->userWithAccess);
$this->drupalGet(Url::fromRoute('system.admin'));
$this->assertSession()->responseNotContains('id="toolbar-item-administration-search');
$this->config('admin_toolbar_search.settings')->set('display_menu_item', 1);
$this->config('admin_toolbar_search.settings')->save();
$this->drupalGet(Url::fromRoute('system.admin'));
$this->assertSession()->responseContains('id="toolbar-item-administration-search');
$this->config('admin_toolbar_search.settings')->set('display_menu_item', 0);
$this->config('admin_toolbar_search.settings')->save();
$this->drupalGet(Url::fromRoute('system.admin'));
$this->assertSession()->responseNotContains('id="toolbar-item-administration-search');
}
}

View File

@@ -0,0 +1,51 @@
<?php
namespace Drupal\Tests\admin_toolbar_search\FunctionalJavascript;
/**
* Test the functionality of admin toolbar search.
*
* @group admin_toolbar
* @group admin_toolbar_search
*/
class AdminToolbarSearchTest extends AdminToolbarSearchTestBase {
/**
* Tests search functionality without admin_toolbar_tools enabled.
*/
public function testToolbarSearch() {
$search_tab = '#admin-toolbar-search-tab';
$search_toolbar_item = '#toolbar-item-administration-search';
$search_tray = '#toolbar-item-administration-search-tray';
$this->drupalLogin($this->userWithAccess);
$assert_session = $this->assertSession();
$assert_session->responseContains('admin.toolbar_search.css');
$assert_session->responseContains('admin_toolbar_search.js');
$assert_session->waitForElementVisible('css', $search_tab);
$assert_session->waitForElementVisible('css', $search_toolbar_item);
$assert_session->waitForElementVisible('css', $search_tray);
$this->assertSuggestionContains('perfor', 'admin/config/development/performance');
$this->assertSuggestionContains('develop', 'admin/config/development/maintenance');
$this->assertSuggestionContains('types', 'admin/structure/types');
}
/**
* Tests a user without the search permission can't use search.
*/
public function testNoAccess() {
$search_tab = '#admin-toolbar-search-tab';
$search_toolbar_item = '#toolbar-item-administration-search';
$search_tray = '#toolbar-item-administration-search-tray';
$this->drupalLogin($this->noAccessUser);
$assert_session = $this->assertSession();
$assert_session->responseNotContains('admin.toolbar_search.css');
$assert_session->responseNotContains('admin_toolbar_search.js');
$assert_session->elementNotExists('css', $search_tab);
$assert_session->elementNotExists('css', $search_toolbar_item);
$assert_session->elementNotExists('css', $search_tray);
}
}

View File

@@ -0,0 +1,192 @@
<?php
namespace Drupal\Tests\admin_toolbar_search\FunctionalJavascript;
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
use Drupal\system\Entity\Menu;
/**
* Base class for testing the functionality of admin toolbar search.
*
* @group admin_toolbar
* @group admin_toolbar_search
*/
abstract class AdminToolbarSearchTestBase extends WebDriverTestBase {
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* {@inheritdoc}
*/
protected static $modules = [
'admin_toolbar_search',
'node',
'media',
'field_ui',
'menu_ui',
'block',
];
/**
* A user with the 'Use Admin Toolbar search' permission.
*
* @var \Drupal\user\UserInterface
*/
protected $userWithAccess;
/**
* A test user without the 'Use Admin Toolbar search' permission..
*
* @var \Drupal\user\UserInterface
*/
protected $noAccessUser;
/**
* {@inheritdoc}
*/
public function setUp(): void {
parent::setUp();
$baby_names = [
'ada' => 'Ada',
'amara' => 'Amara',
'amelia' => 'Amelia',
'arabella' => 'Arabella',
'asher' => 'Asher',
'astrid' => 'Astrid',
'atticus' => 'Atticus',
'aurora' => 'Aurora',
'ava' => 'Ava',
'cora' => 'Cora',
'eleanor' => 'Eleanor',
'eloise' => 'Eloise',
'felix' => 'Felix',
'freya' => 'Freya',
'genevieve' => 'Genevieve',
'isla' => 'Isla',
'jasper' => 'Jasper',
'luna' => 'Luna',
'maeve' => 'Maeve',
'milo' => 'Milo',
'nora' => 'Nora',
'olivia' => 'Olivia',
'ophelia' => 'Ophelia',
'posie' => 'Posie',
'rose' => 'Rose',
'silas' => 'Silas',
'soren' => 'Soren',
];
foreach ($baby_names as $id => $label) {
$menu = Menu::create([
'id' => $id,
'label' => $label,
]);
$menu->save();
}
$this->drupalPlaceBlock('local_tasks_block');
$permissions = [
'access toolbar',
'administer menu',
'access administration pages',
'administer site configuration',
'administer content types',
];
$this->noAccessUser = $this->drupalCreateUser($permissions);
$permissions[] = 'use admin toolbar search';
$this->userWithAccess = $this->drupalCreateUser($permissions);
}
/**
* Assert that the search suggestions contain a given string with given input.
*
* @param string $search
* The string to search for.
* @param string $contains
* Some HTML that is expected to be within the suggestions element.
*/
protected function assertSuggestionContains($search, $contains) {
$this->resetSearch();
$page = $this->getSession()->getPage();
$page->fillField('admin-toolbar-search-input', $search);
$this->getSession()->getDriver()->keyDown('//input[@id="admin-toolbar-search-input"]', ' ');
$page->waitFor(3, function () use ($page) {
return ($page->find('css', 'ul.ui-autocomplete')->isVisible() === TRUE);
});
$suggestions_markup = $page->find('css', 'ul.ui-autocomplete')->getHtml();
$this->assertStringContainsString($contains, $suggestions_markup);
}
/**
* Assert that the search suggestions does not contain a given string.
*
* Assert that the search suggestions does not contain a given string with a
* given input.
*
* @param string $search
* The string to search for.
* @param string $contains
* Some HTML that is not expected to be within the suggestions element.
*/
protected function assertSuggestionNotContains($search, $contains) {
$this->resetSearch();
$page = $this->getSession()->getPage();
$page->fillField('admin-toolbar-search-input', $search);
$this->getSession()->getDriver()->keyDown('//input[@id="admin-toolbar-search-input"]', ' ');
$page->waitFor(3, function () use ($page) {
return ($page->find('css', 'ul.ui-autocomplete')->isVisible() === TRUE);
});
if ($page->find('css', 'ul.ui-autocomplete')->isVisible() === FALSE) {
return;
}
else {
$suggestions_markup = $page->find('css', 'ul.ui-autocomplete')->getHtml();
$this->assertStringNotContainsString($contains, $suggestions_markup);
}
}
/**
* Search for an empty string to clear out the autocomplete suggestions.
*/
protected function resetSearch() {
$page = $this->getSession()->getPage();
// Empty out the suggestions.
$page->fillField('admin-toolbar-search-input', '');
$this->getSession()->getDriver()->keyDown('//input[@id="admin-toolbar-search-input"]', ' ');
$page->waitFor(3, function () use ($page) {
return ($page->find('css', 'ul.ui-autocomplete')->isVisible() === FALSE);
});
}
/**
* Checks that there is a link with the specified url in the admin toolbar.
*
* @param string $url
* The url to assert exists in the admin menu.
*
* @throws \Behat\Mink\Exception\ElementNotFoundException
*/
protected function assertMenuHasHref($url) {
$this->assertSession()
->elementExists('xpath', '//div[@id="toolbar-item-administration-tray"]//a[contains(@href, "' . $url . '")]');
}
/**
* Checks that there is no link with the specified url in the admin toolbar.
*
* @param string $url
* The url to assert exists in the admin menu.
*
* @throws \Behat\Mink\Exception\ExpectationException
*/
protected function assertMenuDoesNotHaveHref($url) {
$this->assertSession()
->elementNotExists('xpath', '//div[@id="toolbar-item-administration-tray"]//a[contains(@href, "' . $url . '")]');
}
}

View File

@@ -0,0 +1,216 @@
<?php
namespace Drupal\Tests\admin_toolbar_search\FunctionalJavascript;
use Drupal\media\Entity\MediaType;
use Drupal\Tests\media\Traits\MediaTypeCreationTrait;
/**
* Test the functionality of admin toolbar search.
*
* @group admin_toolbar
* @group admin_toolbar_search
*/
class AdminToolbarToolsSearchTest extends AdminToolbarSearchTestBase {
use MediaTypeCreationTrait;
/**
* {@inheritdoc}
*/
protected static $modules = [
'admin_toolbar_tools',
'admin_toolbar_search',
'node',
'media',
'field_ui',
'menu_ui',
'block',
];
/**
* The admin user for tests.
*
* @var \Drupal\user\UserInterface
*/
protected $adminUser;
/**
* {@inheritdoc}
*/
public function setUp(): void {
parent::setUp();
$this->drupalCreateContentType([
'type' => 'article',
'name' => 'Article',
]);
$dog_names = [
'archie' => 'Archie',
'bailey' => 'Bailey',
'bella' => 'Bella',
'buddy' => 'Buddy',
'charlie' => 'Charlie',
'coco' => 'Coco',
'daisy' => 'Daisy',
'frankie' => 'Frankie',
'jack' => 'Jack',
'lola' => 'Lola',
'lucy' => 'Lucy',
'max' => 'Max',
'milo' => 'Milo',
'molly' => 'Molly',
'ollie' => 'Ollie',
'oscar' => 'Oscar',
'rosie' => 'Rosie',
'ruby' => 'Ruby',
'teddy' => 'Teddy',
'toby' => 'Toby',
'tonga' => 'Tonga',
'tracey' => 'Tracey',
'tuna' => 'Tuna',
'uno' => 'Uno',
'venus' => 'Venus',
'vicky' => 'Vicky',
'wimpy' => 'Wimpy',
'yellow' => 'Yellow',
'zac' => 'zac',
'zora' => 'zora',
];
foreach ($dog_names as $machine_name => $label) {
$this->createMediaType('image', [
'id' => $machine_name,
'label' => $label,
]);
}
$this->adminUser = $this->drupalCreateUser([
'access toolbar',
'administer menu',
'access administration pages',
'administer site configuration',
'administer content types',
'administer node fields',
'access media overview',
'administer media',
'administer media fields',
'administer media form display',
'administer media display',
'administer media types',
'use admin toolbar search',
]);
}
/**
* Tests search functionality with admin_toolbar_tools enabled.
*/
public function testToolbarSearch() {
$search_tab = '#admin-toolbar-search-tab';
$search_toolbar_item = '#toolbar-item-administration-search';
$search_tray = '#toolbar-item-administration-search-tray';
$this->drupalLogin($this->adminUser);
$assert_session = $this->assertSession();
$assert_session->responseContains('admin.toolbar_search.css');
$assert_session->responseContains('admin_toolbar_search.js');
$assert_session->waitForElementVisible('css', $search_tab);
$assert_session->waitForElementVisible('css', $search_toolbar_item);
$assert_session->waitForElementVisible('css', $search_tray);
$this->assertSuggestionContains('basic', 'admin/config/system/site-information');
// Rebuild menu items.
drupal_flush_all_caches();
// Test that the route admin_toolbar.search returns expected json.
$this->drupalGet('/admin/admin-toolbar-search');
$search_menus = [
'maeve',
'milo',
'nora',
'olivia',
'ophelia',
'posie',
'rose',
'silas',
'soren',
];
$toolbar_menus = [
'ada',
'amara',
'amelia',
'arabella',
'asher',
'astrid',
'atticus',
'aurora',
'ava',
];
foreach ($search_menus as $menu_id) {
$assert_session->responseContains('\/admin\/structure\/menu\/manage\/' . $menu_id);
}
foreach ($toolbar_menus as $menu_id) {
$assert_session->responseNotContains('\/admin\/structure\/menu\/manage\/' . $menu_id);
}
$this->drupalGet('/admin');
foreach ($search_menus as $menu_id) {
$this->assertMenuDoesNotHaveHref('/admin/structure/menu/manage/' . $menu_id);
}
foreach ($toolbar_menus as $menu_id) {
$this->assertMenuHasHref('/admin/structure/menu/manage/' . $menu_id);
}
$this->drupalGet('admin/structure/types/manage/article/fields');
$assert_session->waitForElementVisible('css', $search_tray);
$this->assertSuggestionContains('article manage fields', '/admin/structure/types/manage/article/fields');
$suggestions = $assert_session
->waitForElementVisible('css', 'ul.ui-autocomplete');
// Assert there is only one suggestion with a link to
// /admin/structure/types/manage/article/fields.
$count = count($suggestions->findAll('xpath', '//span[contains(text(), "/admin/structure/types/manage/article/fields")]'));
$this->assertEquals(1, $count);
// Test that bundle within admin toolbar appears in search.
$this->assertSuggestionContains('lola', 'admin/structure/media/manage/lola/fields');
// Assert that a link after the limit doesn't appear in admin toolbar.
$zora_url = '/admin/structure/media/manage/zora/fields';
$assert_session->elementNotContains('css', '#toolbar-administration', $zora_url);
// Assert that a link excluded from admin toolbar appears in search.
$this->assertSuggestionContains('zora', $zora_url);
// Test that adding a new bundle updates the extra links loaded from
// admin_toolbar.search route.
$this->createMediaType('image', [
'id' => 'zuzu',
'label' => 'Zuzu',
]);
$this->drupalGet('admin');
$assert_session->waitForElementVisible('css', $search_tray);
$this->assertSuggestionContains('zuzu', '/admin/structure/media/manage/zuzu/fields');
// Test that deleting a bundle updates the extra links loaded from
// admin_toolbar.search route.
$zora = MediaType::load('zora');
$zora->delete();
$this->getSession()->reload();
$assert_session->waitForElementVisible('css', $search_tray);
$this->assertSuggestionNotContains('zora', $zora);
}
}