annotate core/modules/settings_tray/settings_tray.module @ 4:a9cd425dd02b

Update, including to Drupal core 8.6.10
author Chris Cannam
date Thu, 28 Feb 2019 13:11:55 +0000
parents c75dbcec494b
children 12f9dff5fda9
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 /**
Chris@0 4 * @file
Chris@0 5 * Allows configuring blocks and other configuration from the site front-end.
Chris@0 6 */
Chris@0 7
Chris@0 8 use Drupal\Core\Asset\AttachedAssetsInterface;
Chris@0 9 use Drupal\Core\Routing\RouteMatchInterface;
Chris@0 10 use Drupal\block\entity\Block;
Chris@0 11 use Drupal\block\BlockInterface;
Chris@0 12 use Drupal\settings_tray\Block\BlockEntitySettingTrayForm;
Chris@0 13
Chris@0 14 /**
Chris@0 15 * Implements hook_help().
Chris@0 16 */
Chris@0 17 function settings_tray_help($route_name, RouteMatchInterface $route_match) {
Chris@0 18 switch ($route_name) {
Chris@0 19 case 'help.page.settings_tray':
Chris@0 20 $output = '<h3>' . t('About') . '</h3>';
Chris@0 21 $output .= '<p>' . t('The Settings Tray module allows users with the <a href=":administer_block_permission">Administer blocks</a> and <a href=":contextual_permission">Use contextual links</a> permissions to edit blocks without visiting a separate page. For more information, see the <a href=":handbook_url">online documentation for the Settings Tray module</a>.', [':handbook_url' => 'https://www.drupal.org/documentation/modules/settings_tray', ':administer_block_permission' => \Drupal::url('user.admin_permissions', [], ['fragment' => 'module-block']), ':contextual_permission' => \Drupal::url('user.admin_permissions', [], ['fragment' => 'module-contextual'])]) . '</p>';
Chris@0 22 $output .= '<h3>' . t('Uses') . '</h3>';
Chris@0 23 $output .= '<dl>';
Chris@0 24 $output .= '<dt>' . t('Editing blocks in place') . '</dt>';
Chris@0 25 $output .= '<dd>';
Chris@0 26 $output .= '<p>' . t('To edit blocks in place, either click the <strong>Edit</strong> button in the toolbar and then click on the block, or choose "Quick edit" from the block\'s contextual link. (See the <a href=":contextual">Contextual Links module help</a> for more information about how to use contextual links.)', [':contextual' => \Drupal::url('help.page', ['name' => 'contextual'])]) . '</p>';
Chris@0 27 $output .= '<p>' . t('The Settings Tray for the block will open in a sidebar, with a compact form for configuring what the block shows.') . '</p>';
Chris@0 28 $output .= '<p>' . t('Save the form and the changes will be immediately visible on the page.') . '</p>';
Chris@0 29 $output .= '</dd>';
Chris@0 30 $output .= '</dl>';
Chris@0 31 return ['#markup' => $output];
Chris@0 32 }
Chris@0 33 }
Chris@0 34
Chris@0 35 /**
Chris@0 36 * Implements hook_contextual_links_view_alter().
Chris@0 37 *
Chris@0 38 * Change Configure Blocks into off_canvas links.
Chris@0 39 */
Chris@0 40 function settings_tray_contextual_links_view_alter(&$element, $items) {
Chris@0 41 if (isset($element['#links']['settings-trayblock-configure'])) {
Chris@0 42 // Place settings_tray link first.
Chris@0 43 $settings_tray_link = $element['#links']['settings-trayblock-configure'];
Chris@0 44 unset($element['#links']['settings-trayblock-configure']);
Chris@0 45 $element['#links'] = ['settings-trayblock-configure' => $settings_tray_link] + $element['#links'];
Chris@0 46
Chris@0 47 // If this is content block change title to avoid duplicate "Quick Edit".
Chris@0 48 if (isset($element['#links']['block-contentblock-edit'])) {
Chris@0 49 $element['#links']['settings-trayblock-configure']['title'] = t('Quick edit settings');
Chris@0 50 }
Chris@0 51
Chris@0 52 $element['#attached']['library'][] = 'core/drupal.dialog.off_canvas';
Chris@0 53 }
Chris@0 54 }
Chris@0 55
Chris@0 56 /**
Chris@0 57 * Checks if a block has overrides.
Chris@0 58 *
Chris@0 59 * @param \Drupal\block\BlockInterface $block
Chris@0 60 * The block to check for overrides.
Chris@0 61 *
Chris@0 62 * @return bool
Chris@0 63 * TRUE if the block has overrides otherwise FALSE.
Chris@0 64 *
Chris@0 65 * @internal
Chris@0 66 */
Chris@0 67 function _settings_tray_has_block_overrides(BlockInterface $block) {
Chris@0 68 // @todo Replace the following with $block->hasOverrides() in https://www.drupal.org/project/drupal/issues/2910353
Chris@0 69 // and remove this function.
Chris@0 70 return \Drupal::config($block->getEntityType()->getConfigPrefix() . '.' . $block->id())->hasOverrides();
Chris@0 71 }
Chris@0 72
Chris@0 73 /**
Chris@0 74 * Implements hook_block_view_alter().
Chris@0 75 */
Chris@0 76 function settings_tray_block_view_alter(array &$build) {
Chris@0 77 if (isset($build['#contextual_links']['block'])) {
Chris@0 78 // Ensure that contextual links vary by whether the block has config overrides
Chris@0 79 // or not.
Chris@0 80 // @see _contextual_links_to_id()
Chris@0 81 $build['#contextual_links']['block']['metadata']['has_overrides'] = _settings_tray_has_block_overrides($build['#block']) ? 1 : 0;
Chris@0 82 }
Chris@0 83
Chris@0 84 // Force a new 'data-contextual-id' attribute on blocks when this module is
Chris@0 85 // enabled so as not to reuse stale data cached client-side.
Chris@0 86 // @todo Remove when https://www.drupal.org/node/2773591 is fixed.
Chris@0 87 $build['#contextual_links']['settings_tray'] = [
Chris@0 88 'route_parameters' => [],
Chris@0 89 ];
Chris@0 90 }
Chris@0 91
Chris@0 92 /**
Chris@0 93 * Implements hook_entity_type_build().
Chris@0 94 */
Chris@0 95 function settings_tray_entity_type_build(array &$entity_types) {
Chris@0 96 /* @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */
Chris@0 97 $entity_types['block']
Chris@0 98 ->setFormClass('settings_tray', BlockEntitySettingTrayForm::class)
Chris@0 99 ->setLinkTemplate('settings_tray-form', '/admin/structure/block/manage/{block}/settings-tray');
Chris@0 100 }
Chris@0 101
Chris@0 102 /**
Chris@0 103 * Implements hook_preprocess_HOOK() for block templates.
Chris@0 104 */
Chris@0 105 function settings_tray_preprocess_block(&$variables) {
Chris@0 106 // Only blocks that have a settings_tray form and have no configuration
Chris@0 107 // overrides will have a "Quick Edit" link. We could wait for the contextual
Chris@0 108 // links to be initialized on the client side, and then add the class and
Chris@0 109 // data- attribute below there (via JavaScript). But that would mean that it
Chris@0 110 // would be impossible to show Settings Tray's clickable regions immediately
Chris@0 111 // when the page loads. When latency is high, this will cause flicker.
Chris@0 112 // @see \Drupal\settings_tray\Access\BlockPluginHasSettingsTrayFormAccessCheck
Chris@0 113 /** @var \Drupal\settings_tray\Access\BlockPluginHasSettingsTrayFormAccessCheck $access_checker */
Chris@0 114 $access_checker = \Drupal::service('access_check.settings_tray.block.settings_tray_form');
Chris@0 115 /** @var \Drupal\Core\Block\BlockManagerInterface $block_plugin_manager */
Chris@0 116 $block_plugin_manager = \Drupal::service('plugin.manager.block');
Chris@0 117 /** @var \Drupal\Core\Block\BlockPluginInterface $block_plugin */
Chris@0 118 $block_plugin = $block_plugin_manager->createInstance($variables['plugin_id']);
Chris@0 119 if (isset($variables['elements']['#contextual_links']['block']['route_parameters']['block'])) {
Chris@0 120 $block = Block::load($variables['elements']['#contextual_links']['block']['route_parameters']['block']);
Chris@0 121 if ($access_checker->accessBlockPlugin($block_plugin)->isAllowed() && !_settings_tray_has_block_overrides($block)) {
Chris@0 122 // Add class and attributes to all blocks to allow Javascript to target.
Chris@0 123 $variables['attributes']['class'][] = 'settings-tray-editable';
Chris@0 124 $variables['attributes']['data-drupal-settingstray'] = 'editable';
Chris@0 125 }
Chris@0 126 }
Chris@0 127 }
Chris@0 128
Chris@0 129 /**
Chris@0 130 * Implements hook_toolbar_alter().
Chris@0 131 *
Chris@0 132 * Alters the 'contextual' toolbar tab if it exists (meaning the user is allowed
Chris@0 133 * to use contextual links) and if they can administer blocks.
Chris@0 134 *
Chris@0 135 * @todo Remove the "administer blocks" requirement in
Chris@0 136 * https://www.drupal.org/node/2822965.
Chris@0 137 *
Chris@0 138 * @see contextual_toolbar()
Chris@0 139 */
Chris@0 140 function settings_tray_toolbar_alter(&$items) {
Chris@0 141 $items['contextual']['#cache']['contexts'][] = 'user.permissions';
Chris@0 142 if (isset($items['contextual']['tab']) && \Drupal::currentUser()->hasPermission('administer blocks')) {
Chris@0 143 $items['contextual']['#weight'] = -1000;
Chris@0 144 $items['contextual']['#attached']['library'][] = 'settings_tray/drupal.settings_tray';
Chris@0 145 $items['contextual']['tab']['#attributes']['data-drupal-settingstray'] = 'toggle';
Chris@0 146
Chris@0 147 // Set a class on items to mark whether they should be active in edit mode.
Chris@0 148 // @todo Create a dynamic method for modules to set their own items.
Chris@0 149 // https://www.drupal.org/node/2784589.
Chris@0 150 $edit_mode_items = ['contextual', 'block_place'];
Chris@0 151 foreach ($items as $key => $item) {
Chris@0 152 if (!in_array($key, $edit_mode_items) && (!isset($items[$key]['#wrapper_attributes']['class']) || !in_array('hidden', $items[$key]['#wrapper_attributes']['class']))) {
Chris@0 153 $items[$key]['#wrapper_attributes']['class'][] = 'edit-mode-inactive';
Chris@0 154 }
Chris@0 155 }
Chris@0 156 }
Chris@0 157 }
Chris@0 158
Chris@0 159 /**
Chris@0 160 * Implements hook_block_alter().
Chris@0 161 *
Chris@0 162 * Ensures every block plugin definition has an 'settings_tray' form specified.
Chris@0 163 *
Chris@0 164 * @see \Drupal\settings_tray\Access\BlockPluginHasSettingsTrayFormAccessCheck
Chris@0 165 */
Chris@0 166 function settings_tray_block_alter(&$definitions) {
Chris@0 167 foreach ($definitions as &$definition) {
Chris@0 168 // If a block plugin does not define its own 'settings_tray' form, use the
Chris@0 169 // plugin class itself.
Chris@0 170 if (!isset($definition['forms']['settings_tray'])) {
Chris@0 171 $definition['forms']['settings_tray'] = $definition['class'];
Chris@0 172 }
Chris@0 173 }
Chris@0 174 }
Chris@0 175
Chris@0 176 /**
Chris@0 177 * Implements hook_css_alter().
Chris@0 178 */
Chris@0 179 function settings_tray_css_alter(&$css, AttachedAssetsInterface $assets) {
Chris@0 180 // @todo Remove once conditional ordering is introduced in
Chris@0 181 // https://www.drupal.org/node/1945262.
Chris@0 182 $path = drupal_get_path('module', 'settings_tray') . '/css/settings_tray.theme.css';
Chris@0 183 if (isset($css[$path])) {
Chris@0 184 // Use 200 to come after CSS_AGGREGATE_THEME.
Chris@0 185 $css[$path]['group'] = 200;
Chris@0 186 }
Chris@0 187 }