diff --git a/core/includes/common.inc b/core/includes/common.inc index 8f60fe4..502052d 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -3527,7 +3527,7 @@ function drupal_pre_render_link($element) { * Pre-render callback: Collects child links into a single array. * * This function can be added as a pre_render callback for a renderable array, - * usually one which will be themed by theme_links(). It iterates through all + * usually one which will be themed by links.html.twig. It iterates through all * unrendered children of the element, collects any #links properties it finds, * merges them into the parent element's #links array, and prevents those * children from being rendered separately. @@ -3548,21 +3548,21 @@ function drupal_pre_render_link($element) { * '#theme' => 'links__node__comment', * '#links' => array( * // An array of links associated with node comments, suitable for - * // passing in to theme_links(). + * // passing in to links.html.twig. * ), * ), * 'statistics' => array( * '#theme' => 'links__node__statistics', * '#links' => array( * // An array of links associated with node statistics, suitable for - * // passing in to theme_links(). + * // passing in to links.html.twig. * ), * ), * 'translation' => array( * '#theme' => 'links__node__translation', * '#links' => array( * // An array of links associated with node translation, suitable for - * // passing in to theme_links(). + * // passing in to links.html.twig. * ), * ), * ); diff --git a/core/includes/form.inc b/core/includes/form.inc index 5867a36..0885aeb 100644 --- a/core/includes/form.inc +++ b/core/includes/form.inc @@ -1422,7 +1422,7 @@ function form_pre_render_actions_dropbutton(array $element) { } // Add this button to the corresponding dropbutton. // @todo Change #type 'dropbutton' to be based on theme_item_list() - // instead of theme_links() to avoid this preemptive rendering. + // instead of links.html.twig to avoid this preemptive rendering. $button = drupal_render($element[$key]); $dropbuttons[$dropbutton]['#links'][$key] = array( 'title' => $button, diff --git a/core/includes/menu.inc b/core/includes/menu.inc index a8a30b6..618f16e 100644 --- a/core/includes/menu.inc +++ b/core/includes/menu.inc @@ -1936,7 +1936,7 @@ function menu_navigation_links($menu_name, $level = 0) { if ($item['link']['href'] == $router_item['tab_root_href'] && $item['link']['href'] != current_path()) { $l['attributes']['class'][] = 'active'; } - // Keyed with the unique mlid to generate classes in theme_links(). + // Keyed with the unique mlid to generate classes in links.html.twig. $links['menu-' . $item['link']['mlid'] . $class] = $l; } } @@ -2186,6 +2186,114 @@ function _menu_get_legacy_tasks($router_item, &$data, &$root_path) { } /** + * Retrieves contextual links for a path based on registered local tasks. + * + * This leverages the menu system to retrieve the first layer of registered + * local tasks for a given system path. All local tasks of the tab type + * MENU_CONTEXT_INLINE are taken into account. + * + * For example, when considering the following registered local tasks: + * - node/%node/view (default local task) with no 'context' defined + * - node/%node/edit with context: MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE + * - node/%node/revisions with context: MENU_CONTEXT_PAGE + * - node/%node/report-as-spam with context: MENU_CONTEXT_INLINE + * + * If the path "node/123" is passed to this function, then it will return the + * links for 'edit' and 'report-as-spam'. + * + * @param $module + * The name of the implementing module. This is used to prefix the key for + * each contextual link, which is transformed into a CSS class during + * rendering by links.html.twig. For example, if $module is 'block' and the + * retrieved local task path argument is 'edit', then the resulting CSS class + * will be 'block-edit'. + * @param $parent_path + * The static menu router path of the object to retrieve local tasks for, for + * example 'node' or 'admin/structure/block/manage'. + * @param $args + * A list of dynamic path arguments to append to $parent_path to form the + * fully-qualified menu router path; for example, array(123) for a certain + * node or array('system', 'tools') for a certain block. + * + * @return + * A list of menu router items that are local tasks for the passed-in path. + * + * @see contextual_links_preprocess() + * @see hook_menu() + */ +function menu_contextual_links($module, $parent_path, $args) { + static $path_empty = array(); + + $links = array(); + // Performance: In case a previous invocation for the same parent path did not + // return any links, we immediately return here. + if (isset($path_empty[$parent_path]) && strpos($parent_path, '%') !== FALSE) { + return $links; + } + // Construct the item-specific parent path. + $path = $parent_path . '/' . implode('/', $args); + + // Get the router item for the given parent link path. + $router_item = menu_get_item($path); + if (!$router_item || !$router_item['access']) { + $path_empty[$parent_path] = TRUE; + return $links; + } + $data = &drupal_static(__FUNCTION__, array()); + $root_path = $router_item['path']; + + // Performance: For a single, normalized path (such as 'node/%') we only query + // available tasks once per request. + if (!isset($data[$root_path])) { + // Get all contextual links that are direct children of the router item and + // not of the tab type 'view'. + $data[$root_path] = db_select('menu_router', 'm') + ->fields('m') + ->condition('tab_parent', $router_item['tab_root']) + ->condition('context', MENU_CONTEXT_NONE, '<>') + ->condition('context', MENU_CONTEXT_PAGE, '<>') + ->orderBy('weight') + ->orderBy('title') + ->execute() + ->fetchAllAssoc('path', PDO::FETCH_ASSOC); + } + $parent_length = drupal_strlen($root_path) + 1; + $map = $router_item['original_map']; + foreach ($data[$root_path] as $item) { + // Extract the actual "task" string from the path argument. + $key = drupal_substr($item['path'], $parent_length); + + // Denormalize and translate the contextual link. + _menu_translate($item, $map, TRUE); + if (!$item['access']) { + continue; + } + + // If this item is a default local task, rewrite the href to link to its + // parent item. + if ($item['type'] == MENU_DEFAULT_LOCAL_TASK) { + $item['href'] = $item['tab_parent_href']; + } + + // All contextual links are keyed by the actual "task" path argument, + // prefixed with the name of the implementing module. + $links[$module . '-' . $key] = $item; + } + + // Allow modules to alter contextual links. + drupal_alter('menu_contextual_links', $links, $router_item, $root_path); + + // Performance: If the current user does not have access to any links for this + // router path and no other module added further links, we assign FALSE here + // to skip the entire process the next time the same router path is requested. + if (empty($links)) { + $path_empty[$parent_path] = TRUE; + } + + return $links; +} + +/** * Returns the rendered local tasks at the top level. */ function menu_primary_local_tasks() { diff --git a/core/includes/theme.inc b/core/includes/theme.inc index 6ce5c63..7f08c02 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -1609,9 +1609,11 @@ function template_preprocess_status_messages(&$variables) { } /** - * Returns HTML for a set of links. + * Prepares variables for links templates. * - * @param $variables + * Default template: links.html.twig. + * + * @param array $variables * An associative array containing: * - links: An associative array of links to be themed. The key for each link * is used as its CSS class. Each link should be itself an array, with the @@ -1645,11 +1647,14 @@ function template_preprocess_status_messages(&$variables) { * http://juicystudio.com/article/screen-readers-display-none.php and * http://www.w3.org/TR/WCAG-TECHS/H42.html for more information. */ +<<<<<<< HEAD function theme_links($variables) { +======= +function template_preprocess_links(&$variables) { + $language_url = language(Language::TYPE_URL); +>>>>>>> Applying patch to issue 1939064 on comment #79 $links = $variables['links']; - $attributes = $variables['attributes']; - $heading = $variables['heading']; - $output = ''; + $heading = &$variables['heading']; if (!empty($links)) { // Prepend the heading to the list, if any. @@ -1667,14 +1672,11 @@ function theme_links($variables) { if (isset($heading['class'])) { $heading['attributes']['class'] = $heading['class']; } - - $output .= '<' . $heading['level'] . new Attribute($heading['attributes']) . '>'; - $output .= String::checkPlain($heading['text']); - $output .= '' . $heading['level'] . '>'; + // Convert the attributes array into an attributes object. + $heading['attributes'] = new Attribute($heading['attributes']); + $heading['text'] = String::checkPlain($heading['text']); } - $output .= '