Commit 70f62fd0 authored by willzyx's avatar willzyx

Issue #2839502 by willzyx: Add toolbar integration - make devel menu items more accessible

parent 8a6e8b06
toolbar_items:
- 'devel.admin_settings_link'
- 'devel.cache_clear'
- 'devel.container_info.service'
- 'devel.execute_php'
- 'devel.menu_rebuild'
- 'devel.reinstall'
- 'devel.route_info'
- 'devel.run_cron'
...@@ -28,6 +28,16 @@ devel.settings: ...@@ -28,6 +28,16 @@ devel.settings:
type: string type: string
label: 'Devel variable dumper' label: 'Devel variable dumper'
devel.toolbar.settings:
type: config_object
label: 'Devel Toolbar settings'
mapping:
toolbar_items:
type: sequence
label: 'Toolbar items'
sequence:
type: string
block.settings.devel_switch_user: block.settings.devel_switch_user:
type: block_settings type: block_settings
label: 'Switch user block' label: 'Switch user block'
......
/**
* @file
* Styling for devel toolbar module.
*/
.toolbar .toolbar-tray-vertical .edit-devel-toolbar {
text-align: right; /* LTR */
padding: 1em;
}
[dir="rtl"] .toolbar .toolbar-tray-vertical .edit-devel-toolbar {
text-align: left;
}
.toolbar .toolbar-tray-horizontal .edit-devel-toolbar {
float: right; /* LTR */
}
[dir="rtl"] .toolbar .toolbar-tray-horizontal .edit-devel-toolbar {
float: left;
}
.toolbar .toolbar-tray-horizontal .menu {
float: left; /* LTR */
}
[dir="rtl"] .toolbar .toolbar-tray-horizontal .menu {
float: right;
}
.toolbar .toolbar-bar .toolbar-icon-devel:before{
background-image: url(../icons/bebebe/cog.svg);
}
.toolbar-bar .toolbar-icon-devel:active:before,
.toolbar-bar .toolbar-icon-devel.is-active:before {
background-image: url(../icons/ffffff/cog.svg);
}
.toolbar-horizontal .toolbar-horizontal-item-hidden {
display: none;
}
...@@ -3,3 +3,9 @@ devel: ...@@ -3,3 +3,9 @@ devel:
css: css:
theme: theme:
css/devel.css: {} css/devel.css: {}
devel-toolbar:
version: VERSION
css:
component:
css/devel.toolbar.css: {}
...@@ -19,11 +19,13 @@ use Drupal\Core\Database\Query\AlterableInterface; ...@@ -19,11 +19,13 @@ use Drupal\Core\Database\Query\AlterableInterface;
use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Logger\RfcLogLevel; use Drupal\Core\Logger\RfcLogLevel;
use Drupal\Core\Menu\LocalTaskDefault;
use Drupal\Core\Render\Element; use Drupal\Core\Render\Element;
use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url; use Drupal\Core\Url;
use Drupal\Core\Utility\Error; use Drupal\Core\Utility\Error;
use Drupal\devel\EntityTypeInfo; use Drupal\devel\EntityTypeInfo;
use Drupal\devel\ToolbarHandler;
/** /**
* Implements hook_help(). * Implements hook_help().
...@@ -93,6 +95,30 @@ function devel_entity_operation(EntityInterface $entity) { ...@@ -93,6 +95,30 @@ function devel_entity_operation(EntityInterface $entity) {
->entityOperation($entity); ->entityOperation($entity);
} }
/**
* Implements hook_toolbar().
*/
function devel_toolbar() {
return \Drupal::service('class_resolver')
->getInstanceFromDefinition(ToolbarHandler::class)
->toolbar();
}
/**
* Implements hook_local_tasks_alter().
*/
function devel_local_tasks_alter(&$local_tasks) {
if (\Drupal::moduleHandler()->moduleExists('toolbar')) {
$local_tasks['devel.toolbar.settings_form'] = [
'title' => 'Toolbar Settings',
'base_route' => 'devel.admin_settings',
'route_name' => 'devel.toolbar.settings_form',
'class' => LocalTaskDefault::class,
'options' => [],
];
}
}
/** /**
* Sets message. * Sets message.
*/ */
......
...@@ -6,6 +6,15 @@ devel.admin_settings: ...@@ -6,6 +6,15 @@ devel.admin_settings:
requirements: requirements:
_permission: 'administer site configuration' _permission: 'administer site configuration'
devel.toolbar.settings_form:
path: 'admin/config/development/devel/toolbar'
defaults:
_form: '\Drupal\devel\Form\ToolbarSettingsForm'
_title: 'Devel Toolbar Settings'
requirements:
_permission: 'administer site configuration'
_module_dependencies: 'toolbar'
devel.reinstall: devel.reinstall:
path: '/devel/reinstall' path: '/devel/reinstall'
defaults: defaults:
......
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#bebebe" d="M15.176 9.041c.045-.327.076-.658.076-.998 0-.36-.035-.71-.086-1.056l-2.275-.293c-.115-.426-.283-.827-.498-1.201l1.396-1.808c-.416-.551-.906-1.039-1.459-1.452l-1.807 1.391c-.373-.215-.774-.383-1.2-.499l-.292-2.252c-.338-.048-.677-.081-1.029-.081s-.694.033-1.032.082l-.291 2.251c-.426.116-.826.284-1.2.499l-1.805-1.391c-.552.413-1.044.901-1.459 1.452l1.395 1.808c-.215.374-.383.774-.499 1.2l-2.276.294c-.05.346-.085.696-.085 1.056 0 .34.031.671.077.998l2.285.295c.115.426.284.826.499 1.2l-1.417 1.836c.411.55.896 1.038 1.443 1.452l1.842-1.42c.374.215.774.383 1.2.498l.298 2.311c.337.047.677.08 1.025.08s.688-.033 1.021-.08l.299-2.311c.426-.115.826-.283 1.201-.498l1.842 1.42c.547-.414 1.031-.902 1.443-1.452l-1.416-1.837c.215-.373.383-.773.498-1.199l2.286-.295zm-7.174 1.514c-1.406 0-2.543-1.137-2.543-2.541 0-1.402 1.137-2.541 2.543-2.541 1.402 0 2.541 1.138 2.541 2.541 0 1.404-1.139 2.541-2.541 2.541z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#ffffff" d="M15.176 9.041c.045-.327.076-.658.076-.998 0-.36-.035-.71-.086-1.056l-2.275-.293c-.115-.426-.283-.827-.498-1.201l1.396-1.808c-.416-.551-.906-1.039-1.459-1.452l-1.807 1.391c-.373-.215-.774-.383-1.2-.499l-.292-2.252c-.338-.048-.677-.081-1.029-.081s-.694.033-1.032.082l-.291 2.251c-.426.116-.826.284-1.2.499l-1.805-1.391c-.552.413-1.044.901-1.459 1.452l1.395 1.808c-.215.374-.383.774-.499 1.2l-2.276.294c-.05.346-.085.696-.085 1.056 0 .34.031.671.077.998l2.285.295c.115.426.284.826.499 1.2l-1.417 1.836c.411.55.896 1.038 1.443 1.452l1.842-1.42c.374.215.774.383 1.2.498l.298 2.311c.337.047.677.08 1.025.08s.688-.033 1.021-.08l.299-2.311c.426-.115.826-.283 1.201-.498l1.842 1.42c.547-.414 1.031-.902 1.443-1.452l-1.416-1.837c.215-.373.383-.773.498-1.199l2.286-.295zm-7.174 1.514c-1.406 0-2.543-1.137-2.543-2.541 0-1.402 1.137-2.541 2.543-2.541 1.402 0 2.541 1.138 2.541 2.541 0 1.404-1.139 2.541-2.541 2.541z"/></svg>
\ No newline at end of file
<?php
namespace Drupal\devel\Form;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Menu\MenuLinkTreeInterface;
use Drupal\Core\Menu\MenuTreeParameters;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Configures devel toolbar settings.
*/
class ToolbarSettingsForm extends ConfigFormBase {
/**
* The menu link tree service.
*
* @var \Drupal\Core\Menu\MenuLinkTree
*/
protected $menuLinkTree;
/**
* ToolbarSettingsForm constructor.
*
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory.
* @param \Drupal\Core\Menu\MenuLinkTreeInterface $menu_link_tree
* The menu link tree service.
*/
public function __construct(ConfigFactoryInterface $config_factory, MenuLinkTreeInterface $menu_link_tree) {
parent::__construct($config_factory);
$this->menuLinkTree = $menu_link_tree;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('config.factory'),
$container->get('menu.link_tree')
);
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'devel_toolbar_settings_form';
}
/**
* {@inheritdoc}
*/
protected function getEditableConfigNames() {
return [
'devel.toolbar.settings',
];
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$config = $this->config('devel.toolbar.settings');
$form['toolbar_items'] = [
'#type' => 'checkboxes',
'#title' => $this->t('Menu items always visible'),
'#options' => $this->getLinkLabels(),
'#default_value' => $config->get('toolbar_items') ?: [],
'#required' => TRUE,
'#description' => $this->t('Select the menu items always visible in devel toolbar tray. All the items not selected in this list will be visible only when the toolbar orientation is vertical.'),
];
return parent::buildForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$values = $form_state->getValues();
$toolbar_items = array_keys(array_filter($values['toolbar_items']));
$this->config('devel.toolbar.settings')
->set('toolbar_items', $toolbar_items)
->save();
parent::submitForm($form, $form_state);
}
/**
* Provides an array of available menu items.
*
* @return array
* Associative array of devel menu item labels keyed by plugin ID.
*/
protected function getLinkLabels() {
$options = [];
$parameters = new MenuTreeParameters();
$parameters->onlyEnabledLinks()->setTopLevelOnly();
$tree = $this->menuLinkTree->load('devel', $parameters);
foreach ($tree as $element) {
$link = $element->link;
$options[$link->getPluginId()] = $link->getTitle();
}
asort($options);
return $options;
}
}
<?php
namespace Drupal\devel;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Menu\MenuLinkTreeInterface;
use Drupal\Core\Menu\MenuTreeParameters;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Toolbar integration handler.
*/
class ToolbarHandler implements ContainerInjectionInterface {
use StringTranslationTrait;
/**
* The menu link tree service.
*
* @var \Drupal\Core\Menu\MenuLinkTreeInterface
*/
protected $menuLinkTree;
/**
* The devel toolbar config.
*
* @var \Drupal\Core\Config\ImmutableConfig
*/
protected $config;
/**
* The current user.
*
* @var \Drupal\Core\Session\AccountProxyInterface
*/
protected $account;
/**
* ToolbarHandler constructor.
*
* @param \Drupal\Core\Menu\MenuLinkTreeInterface $menu_link_tree
* The menu link tree service.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory.
* @param \Drupal\Core\Session\AccountProxyInterface $account
* The current user.
*/
public function __construct(MenuLinkTreeInterface $menu_link_tree, ConfigFactoryInterface $config_factory, AccountProxyInterface $account) {
$this->menuLinkTree = $menu_link_tree;
$this->config = $config_factory->get('devel.toolbar.settings');
$this->account = $account;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('menu.link_tree'),
$container->get('config.factory'),
$container->get('current_user')
);
}
/**
* Hook bridge.
*
* @return array
* The devel toolbar items render array.
*
* @see hook_toolbar()
*/
public function toolbar() {
$items['devel'] = [
'#cache' => [
'contexts' => ['user.permissions'],
],
];
if ($this->account->hasPermission('access devel information')) {
$items['devel'] += [
'#type' => 'toolbar_item',
'#weight' => 999,
'tab' => [
'#type' => 'link',
'#title' => $this->t('Devel'),
'#url' => Url::fromRoute('devel.admin_settings'),
'#attributes' => [
'title' => $this->t('Development menu'),
'class' => ['toolbar-icon', 'toolbar-icon-devel'],
],
],
'tray' => [
'#heading' => $this->t('Development menu'),
'devel_menu' => [
// Currently devel menu is uncacheable, so instead of poisoning the
// entire page cache we use a lazy builder.
// @see \Drupal\devel\Plugin\Menu\DestinationMenuLink
// @see \Drupal\devel\Plugin\Menu\RouteDetailMenuItem
'#lazy_builder' => [ToolbarHandler::class . ':lazyBuilder', []],
// Force the creation of the placeholder instead of rely on the
// automatical placeholdering or otherwise the page results
// uncacheable when max-age 0 is bubbled up.
'#create_placeholder' => TRUE,
],
'configuration' => [
'#type' => 'link',
'#title' => $this->t('Configure'),
'#url' => Url::fromRoute('devel.toolbar.settings_form'),
'#options' => [
'attributes' => ['class' => ['edit-devel-toolbar']],
],
],
],
'#attached' => [
'library' => 'devel/devel-toolbar',
],
];
}
return $items;
}
/**
* Lazy builder callback for the devel menu toolbar.
*
* @return array
* The renderable array rapresentation of the devel menu.
*/
public function lazyBuilder() {
$parameters = new MenuTreeParameters();
$parameters->onlyEnabledLinks()->setTopLevelOnly();
$tree = $this->menuLinkTree->load('devel', $parameters);
$manipulators = [
['callable' => 'menu.default_tree_manipulators:checkAccess'],
['callable' => 'menu.default_tree_manipulators:generateIndexAndSort'],
['callable' => ToolbarHandler::class . ':processTree'],
];
$tree = $this->menuLinkTree->transform($tree, $manipulators);
$build = $this->menuLinkTree->build($tree);
CacheableMetadata::createFromRenderArray($build)
->addCacheableDependency($this->config)
->applyTo($build);
return $build;
}
/**
* Adds toolbar-specific attributes to the menu link tree.
*
* @param \Drupal\Core\Menu\MenuLinkTreeElement[] $tree
* The menu link tree to manipulate.
*
* @return \Drupal\Core\Menu\MenuLinkTreeElement[]
* The manipulated menu link tree.
*/
public function processTree(array $tree) {
$visible_items = $this->config->get('toolbar_items') ?: [];
foreach ($tree as $element) {
$plugin_id = $element->link->getPluginId();
if (!in_array($plugin_id, $visible_items)) {
// Add a class that allow to hide the non prioritized menu items when
// the toolbar has horizontal orientation.
$element->options['attributes']['class'][] = 'toolbar-horizontal-item-hidden';
}
}
return $tree;
}
}
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment