2009-12-06 01:00:27 +00:00
< ? php
/**
* @ file
* Adds contextual links to perform actions related to elements on a page .
*/
2019-04-16 05:38:27 +00:00
use Drupal\Core\Url ;
2014-04-18 15:32:47 +00:00
use Drupal\Component\Serialization\Json ;
2014-03-05 20:22:39 +00:00
use Drupal\Component\Utility\UrlHelper ;
2015-05-18 13:55:26 +00:00
use Drupal\Core\Language\LanguageInterface ;
2014-06-30 03:33:08 +00:00
use Drupal\Core\Routing\RouteMatchInterface ;
2013-11-23 03:40:33 +00:00
2013-02-12 21:46:04 +00:00
/**
* Implements hook_toolbar () .
*/
function contextual_toolbar () {
2015-06-01 16:49:02 +00:00
$items = [];
$items [ 'contextual' ] = [
'#cache' => [
'contexts' => [
'user.permissions' ,
],
],
];
2013-08-31 06:59:28 +00:00
2013-09-16 03:58:06 +00:00
if ( ! \Drupal :: currentUser () -> hasPermission ( 'access contextual links' )) {
2015-06-01 16:49:02 +00:00
return $items ;
2013-02-12 21:46:04 +00:00
}
2017-03-04 01:20:24 +00:00
$items [ 'contextual' ] += [
2014-01-08 08:40:53 +00:00
'#type' => 'toolbar_item' ,
2017-03-04 01:20:24 +00:00
'tab' => [
2013-02-12 21:46:04 +00:00
'#type' => 'html_tag' ,
'#tag' => 'button' ,
'#value' => t ( 'Edit' ),
2017-03-04 01:20:24 +00:00
'#attributes' => [
'class' => [ 'toolbar-icon' , 'toolbar-icon-edit' ],
2013-02-12 21:46:04 +00:00
'aria-pressed' => 'false' ,
2017-03-07 01:13:44 +00:00
'type' => 'button' ,
2017-03-04 01:20:24 +00:00
],
],
'#wrapper_attributes' => [
'class' => [ 'hidden' , 'contextual-toolbar-tab' ],
],
'#attached' => [
'library' => [
2014-03-09 19:59:45 +00:00
'contextual/drupal.contextual-toolbar' ,
2017-03-04 01:20:24 +00:00
],
],
];
2013-02-12 21:46:04 +00:00
2015-06-01 16:49:02 +00:00
return $items ;
2013-02-12 21:46:04 +00:00
}
2013-05-20 08:35:41 +00:00
/**
2014-10-16 12:36:06 +00:00
* Implements hook_page_attachments () .
2013-05-20 08:35:41 +00:00
*
* Adds the drupal . contextual - links library to the page for any user who has the
* 'access contextual links' permission .
*
* @ see contextual_preprocess ()
*/
2014-10-16 12:36:06 +00:00
function contextual_page_attachments ( array & $page ) {
2013-09-16 03:58:06 +00:00
if ( ! \Drupal :: currentUser () -> hasPermission ( 'access contextual links' )) {
2013-05-20 08:35:41 +00:00
return ;
}
2014-03-09 19:59:45 +00:00
$page [ '#attached' ][ 'library' ][] = 'contextual/drupal.contextual-links' ;
2013-05-20 08:35:41 +00:00
}
2009-12-11 16:57:24 +00:00
/**
* Implements hook_help () .
*/
2014-06-30 03:33:08 +00:00
function contextual_help ( $route_name , RouteMatchInterface $route_match ) {
2014-05-07 02:04:53 +00:00
switch ( $route_name ) {
case 'help.page.contextual' :
2009-12-11 16:57:24 +00:00
$output = '' ;
$output .= '<h3>' . t ( 'About' ) . '</h3>' ;
2017-03-04 01:20:24 +00:00
$output .= '<p>' . t ( 'The Contextual links module gives users with the <em>Use contextual links</em> permission quick access to tasks associated with certain areas of pages on your site. For example, a menu displayed as a block has links to edit the menu and configure the block. For more information, see the <a href=":contextual">online documentation for the Contextual Links module</a>.' , [ ':contextual' => 'https://www.drupal.org/documentation/modules/contextual' ]) . '</p>' ;
2009-12-11 16:57:24 +00:00
$output .= '<h3>' . t ( 'Uses' ) . '</h3>' ;
$output .= '<dl>' ;
$output .= '<dt>' . t ( 'Displaying contextual links' ) . '</dt>' ;
2014-08-14 03:50:32 +00:00
$output .= '<dd>' ;
$output .= t ( 'Contextual links for an area on a page are displayed using a contextual links button. There are two ways to make the contextual links button visible:' );
$output .= '<ol>' ;
2015-09-17 23:15:05 +00:00
$sample_picture = [
'#theme' => 'image' ,
'#uri' => 'core/misc/icons/bebebe/pencil.svg' ,
2018-05-11 09:40:33 +00:00
'#alt' => t ( 'contextual links button' ),
2015-09-17 23:15:05 +00:00
];
$sample_picture = \Drupal :: service ( 'renderer' ) -> render ( $sample_picture );
2017-03-04 01:20:24 +00:00
$output .= '<li>' . t ( 'Hovering over the area of interest will temporarily make the contextual links button visible (which looks like a pencil in most themes, and is normally displayed in the upper right corner of the area). The icon typically looks like this: @picture' , [ '@picture' => $sample_picture ]) . '</li>' ;
2019-04-16 05:38:27 +00:00
$output .= '<li>' . t ( 'If you have the <a href=":toolbar">Toolbar module</a> enabled, clicking the contextual links button in the toolbar (which looks like a pencil) will make all contextual links buttons on the page visible. Clicking this button again will toggle them to invisible.' , [ ':toolbar' => ( \Drupal :: moduleHandler () -> moduleExists ( 'toolbar' )) ? Url :: fromRoute ( 'help.page' , [ 'name' => 'toolbar' ]) -> toString () : '#' ]) . '</li>' ;
2014-08-14 03:50:32 +00:00
$output .= '</ol>' ;
$output .= t ( 'Once the contextual links button for the area of interest is visible, click the button to display the links.' );
$output .= '</dd>' ;
2009-12-11 16:57:24 +00:00
$output .= '</dl>' ;
return $output ;
}
}
2009-12-06 01:00:27 +00:00
/**
2011-11-24 21:29:07 +00:00
* Implements hook_preprocess () .
2009-12-06 01:00:27 +00:00
*
2022-05-02 13:20:14 +00:00
* @ see \Drupal\contextual\Element\ContextualLinksPlaceholder
2014-10-16 12:36:06 +00:00
* @ see contextual_page_attachments ()
2013-05-20 08:35:41 +00:00
* @ see \Drupal\contextual\ContextualController :: render ()
2009-12-06 01:00:27 +00:00
*/
2013-06-12 15:57:44 +00:00
function contextual_preprocess ( & $variables , $hook , $info ) {
2009-12-06 01:00:27 +00:00
// Determine the primary theme function argument.
2013-06-12 15:57:44 +00:00
if ( ! empty ( $info [ 'variables' ])) {
$keys = array_keys ( $info [ 'variables' ]);
2009-12-06 01:00:27 +00:00
$key = $keys [ 0 ];
}
2013-06-12 15:57:44 +00:00
elseif ( ! empty ( $info [ 'render element' ])) {
$key = $info [ 'render element' ];
2009-12-06 01:00:27 +00:00
}
2010-06-13 05:36:58 +00:00
if ( ! empty ( $key ) && isset ( $variables [ $key ])) {
2009-12-06 01:00:27 +00:00
$element = $variables [ $key ];
}
if ( isset ( $element ) && is_array ( $element ) && ! empty ( $element [ '#contextual_links' ])) {
2022-05-16 13:35:23 +00:00
$variables [ '#cache' ][ 'contexts' ][] = 'user.permissions' ;
if ( \Drupal :: currentUser () -> hasPermission ( 'access contextual links' )) {
// Mark this element as potentially having contextual links attached to it.
$variables [ 'attributes' ][ 'class' ][] = 'contextual-region' ;
2013-05-20 08:35:41 +00:00
2022-05-16 13:35:23 +00:00
// Renders a contextual links placeholder unconditionally, thus not breaking
// the render cache. Although the empty placeholder is rendered for all
// users, contextual_page_attachments() only adds the asset library for
// users with the 'access contextual links' permission, thus preventing
// unnecessary HTTP requests for users without that permission.
$variables [ 'title_suffix' ][ 'contextual_links' ] = [
'#type' => 'contextual_links_placeholder' ,
'#id' => _contextual_links_to_id ( $element [ '#contextual_links' ]),
];
}
2009-12-06 01:00:27 +00:00
}
}
2013-05-20 08:35:41 +00:00
/**
* Implements hook_contextual_links_view_alter () .
*
* @ see \Drupal\contextual\Plugin\views\field\ContextualLinks :: render ()
*/
function contextual_contextual_links_view_alter ( & $element , $items ) {
if ( isset ( $element [ '#contextual_links' ][ 'contextual' ])) {
2013-11-06 19:45:16 +00:00
$encoded_links = $element [ '#contextual_links' ][ 'contextual' ][ 'metadata' ][ 'contextual-views-field-links' ];
Issue #2093173 by longwave, Cyberschorsch, forbesgraham, sandipmkhairnar, damiankloip, rbayliss, grom358, harijari, InternetDevels, dawehner: Remove all calls to drupal_json_decode(), use \Drupal\Component\Utility\Json::decode().
2014-03-20 16:06:41 +00:00
$element [ '#links' ] = Json :: decode ( rawurldecode ( $encoded_links ));
2013-05-20 08:35:41 +00:00
}
}
/**
* Serializes #contextual_links property value array to a string.
*
* Examples :
2015-05-18 13:55:26 +00:00
* - node : node = 1 : langcode = en
* - views_ui_edit : view = frontpage : location = page & view_name = frontpage & view_display_id = page_1 & langcode = en
2022-08-22 08:06:38 +00:00
* - menu : menu = tools : langcode = en | block : block = olivero . tools : langcode = en
2013-05-20 08:35:41 +00:00
*
* So , expressed in a pattern :
2013-11-06 19:45:16 +00:00
* < group >:< route parameters >:< metadata >
2013-05-20 08:35:41 +00:00
*
2013-11-06 19:45:16 +00:00
* The route parameters and options are encoded as query strings .
2013-05-20 08:35:41 +00:00
*
* @ param array $contextual_links
* The $element [ '#contextual_links' ] value for some render element .
*
* @ return string
* A serialized representation of a #contextual_links property value array for
* use in a data - attribute .
*/
function _contextual_links_to_id ( $contextual_links ) {
2017-03-04 01:20:24 +00:00
$ids = [];
2015-05-18 13:55:26 +00:00
$langcode = \Drupal :: languageManager () -> getCurrentLanguage ( LanguageInterface :: TYPE_URL ) -> getId ();
2013-11-06 19:45:16 +00:00
foreach ( $contextual_links as $group => $args ) {
2014-03-05 20:22:39 +00:00
$route_parameters = UrlHelper :: buildQuery ( $args [ 'route_parameters' ]);
2015-05-18 13:55:26 +00:00
$args += [ 'metadata' => []];
// Add the current URL language to metadata so a different ID will be
// computed when URLs vary by language. This allows to store different
// language-aware contextual links on the client side.
$args [ 'metadata' ] += [ 'langcode' => $langcode ];
$metadata = UrlHelper :: buildQuery ( $args [ 'metadata' ]);
2013-11-06 19:45:16 +00:00
$ids [] = " { $group } : { $route_parameters } : { $metadata } " ;
2013-05-20 08:35:41 +00:00
}
2013-11-06 19:45:16 +00:00
return implode ( '|' , $ids );
2013-05-20 08:35:41 +00:00
}
/**
* Unserializes the result of _contextual_links_to_id () .
*
SA-CORE-2018-006 by alexpott, attilatilman, bkosborne, catch, bonus, Wim Leers, Sam152, Berdir, Damien Tournoud, Dave Reid, Kova101, David_Rothstein, dawehner, dsnopek, samuel.mortenson, stefan.r, tedbow, xjm, timmillwood, pwolanin, njbooher, dyates, effulgentsia, klausi, mlhess, larowlan
2018-10-17 22:46:04 +00:00
* Note that $id is user input . Before calling this method the ID should be
* checked against the token stored in the 'data-contextual-token' attribute
* which is passed via the 'tokens' request parameter to
* \Drupal\contextual\ContextualController :: render () .
2013-05-20 08:35:41 +00:00
*
* @ param string $id
* A serialized representation of a #contextual_links property value array.
*
* @ return array
* The value for a #contextual_links property.
SA-CORE-2018-006 by alexpott, attilatilman, bkosborne, catch, bonus, Wim Leers, Sam152, Berdir, Damien Tournoud, Dave Reid, Kova101, David_Rothstein, dawehner, dsnopek, samuel.mortenson, stefan.r, tedbow, xjm, timmillwood, pwolanin, njbooher, dyates, effulgentsia, klausi, mlhess, larowlan
2018-10-17 22:46:04 +00:00
*
* @ see _contextual_links_to_id ()
* @ see \Drupal\contextual\ContextualController :: render ()
2013-05-20 08:35:41 +00:00
*/
function _contextual_id_to_links ( $id ) {
2017-03-04 01:20:24 +00:00
$contextual_links = [];
2013-05-20 08:35:41 +00:00
$contexts = explode ( '|' , $id );
foreach ( $contexts as $context ) {
2021-11-15 02:35:55 +00:00
[ $group , $route_parameters_raw , $metadata_raw ] = explode ( ':' , $context );
2013-11-06 19:45:16 +00:00
parse_str ( $route_parameters_raw , $route_parameters );
2017-03-04 01:20:24 +00:00
$metadata = [];
2013-06-29 23:09:39 +00:00
parse_str ( $metadata_raw , $metadata );
2017-03-04 01:20:24 +00:00
$contextual_links [ $group ] = [
2013-11-06 19:45:16 +00:00
'route_parameters' => $route_parameters ,
'metadata' => $metadata ,
2017-03-04 01:20:24 +00:00
];
2013-05-20 08:35:41 +00:00
}
return $contextual_links ;
}