diff --git a/core/includes/common.inc b/core/includes/common.inc index cbac8af..3ebc4df 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -1942,11 +1942,7 @@ function url($path = NULL, array $options = array()) { * Boolean TRUE or FALSE, where TRUE indicates an external path. */ function url_is_external($path) { - $colonpos = strpos($path, ':'); - // Avoid calling drupal_strip_dangerous_protocols() if there is any - // slash (/), hash (#) or question_mark (?) before the colon (:) - // occurrence - if any - as this would clearly mean it is not a URL. - return $colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && drupal_strip_dangerous_protocols($path) == $path; + return drupal_container()->get('router.generator')->urlIsExternal($path); } /** @@ -2035,10 +2031,7 @@ function l($text, $path, array $options = array()) { // query parameters of the link equal those of the current request, since the // same request with different query parameters may yield a different page // (e.g., pagers). - $is_active = ($path == current_path() || ($path == '' && drupal_is_front_page())); - $is_active = $is_active && (empty($options['language']) || $options['language']->langcode == language(LANGUAGE_TYPE_URL)->langcode); - $is_active = $is_active && (drupal_container()->get('request')->query->all() == $options['query']); - if ($is_active) { + if (drupal_container()->get('router.generator')->urlIsActive($path, $options)) { $options['attributes']['class'][] = 'active'; } diff --git a/core/includes/theme.inc b/core/includes/theme.inc index 0edb028..10f248a 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -1691,7 +1691,11 @@ function theme_status_messages($variables) { * @see l() */ function theme_link($variables) { - return '' . ($variables['options']['html'] ? $variables['text'] : check_plain($variables['text'])) . ''; + $attributes = new Attribute($variables['options']['attributes']); + if (drupal_container()->get('router.generator')->urlIsActive($path, $options)) { + $attributes['class'][] = 'active'; + } + return '' . ($variables['options']['html'] ? $variables['text'] : check_plain($variables['text'])) . ''; } /** diff --git a/core/lib/Drupal/Core/Routing/UrlGenerator.php b/core/lib/Drupal/Core/Routing/UrlGenerator.php index 518c02d..aa545d9 100644 --- a/core/lib/Drupal/Core/Routing/UrlGenerator.php +++ b/core/lib/Drupal/Core/Routing/UrlGenerator.php @@ -92,9 +92,9 @@ public function generateFromPath($path = NULL, $options = array()) { if (!isset($options['external'])) { // Return an external link if $path contains an allowed absolute URL. Only // call the slow drupal_strip_dangerous_protocols() if $path contains a ':' - // before any / ? or #. Note: we could use url_is_external($path) here, but - // that would require another function call, and performance inside url() is - // critical. + // before any / ? or #. Note: we could use $this->urlIsExternal($path) here, + // but that would require another function call, and performance inside + // url() is critical. $colonpos = strpos($path, ':'); $options['external'] = ($colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && $this->stripDisallowedProtocols($path) == $path); } @@ -165,6 +165,41 @@ public function generateFromPath($path = NULL, $options = array()) { } /** + * Returns TRUE if the given path, language and query match those of the current request. + */ + public function urlIsActive($path = NULL, $options = array()) { + // A path is only active if it corresponds to the current path, the + // language of the path is equal to the current language, and if the + // query parameters of the url equal those of the current request, since the + // same request with different query parameters may yield a different page + // (e.g., pagers). + // @todo Figure out how to deal with urlIsActive() calls when there is no request. + if ($this->request) { + $path_query = $this->request->query->all(); + $path_match = ($path == $this->request->getPathInfo() || ($path == '' && drupal_is_front_page())); + $lang_match = (empty($options['language']) || $options['language']->langcode == language(LANGUAGE_TYPE_URL)->langcode); + $query_match = (empty($options['query']) && empty($path_query)) || ($options['query'] == $path_query); + + return $path_match && $lang_match && $query_match; + } + else { + return FALSE; + } + } + + /** + * Returns TRUE if path points to an external URL. + */ + public function urlIsExternal($path) { + // Link is external if $path contains an allowed absolute URL. Only + // call the slow drupal_strip_dangerous_protocols() if $path contains a ':' + // before any / ? or #. + $colonpos = strpos($path, ':'); + + return ($colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && $this->stripDisallowedProtocols($path) == $path); + } + + /** * Implements \Drupal\Core\Routing\PathBasedGeneratorInterface::stripDisallowedProtocols(). */ public function stripDisallowedProtocols($uri) {