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