diff --git a/core/includes/common.inc b/core/includes/common.inc index be2f2a4..5f4694c 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -1321,35 +1321,17 @@ function l($text, $path, array $options = array()) { $variables['options']['attributes']['hreflang'] = $variables['options']['language']->id; } - // Because l() is called very often we statically cache values that require an - // extra function call. - static $drupal_static_fast; - if (!isset($drupal_static_fast['active'])) { - $drupal_static_fast['active'] = &drupal_static(__FUNCTION__); - } - $active = &$drupal_static_fast['active']; - if (!isset($active)) { - $active = array( - 'path' => current_path(), - 'front_page' => drupal_is_front_page(), - 'language' => language(Language::TYPE_URL)->id, - 'query' => Drupal::service('request')->query->all(), - ); + // Add a data-drupal-link-type attribute to let JavaScript know this link is + // used for navigation (as opposed to?) and so is potentially eligible for an + // active class. + if (!empty($variables['options']['query'])) { + $variables['options']['attributes']['data-drupal-link-query'] = json_encode($variables['options']['query']); } - // Determine whether this link is "active', meaning that it links to the - // current page. It is important that we stop checking "active" conditions if - // we know the link is not active. This helps ensure that l() remains fast. - // An active link's path is equal to the current path. - $variables['url_is_active'] = ($path == $active['path'] || ($path == '' && $active['front_page'])) - // The language of an active link is equal to the current language. - && (empty($variables['options']['language']) || $variables['options']['language']->id == $active['language']) - // The query parameters of an active link are equal to the current parameters. - && ($variables['options']['query'] == $active['query']); - - // Add the "active" class if appropriate. - if ($variables['url_is_active']) { - $variables['options']['attributes']['class'][] = 'active'; + // Add a data-drupal-link-system-path attribute to expose the system path for + // this link to JavaScript. + if (!isset($variables['options']['attributes']['data-drupal-link-system-path'])) { + $variables['options']['attributes']['data-drupal-link-system-path'] = Drupal::service('path.alias_manager.cached')->getSystemPath($path); } // Remove all HTML and PHP tags from a tooltip, calling expensive strip_tags() @@ -2234,13 +2216,20 @@ function drupal_add_js($data = NULL, $options = NULL) { // @todo Make this less hacky: http://drupal.org/node/1547376. $scriptPath = $GLOBALS['script_path']; $pathPrefix = ''; + $current_query = Drupal::service('request')->query->all(); url('', array('script' => &$scriptPath, 'prefix' => &$pathPrefix)); - $javascript['settings']['data'][] = array( + $path = array( 'basePath' => base_path(), 'scriptPath' => $scriptPath, 'pathPrefix' => $pathPrefix, 'currentPath' => current_path(), + 'isFront' => drupal_is_front_page(), + 'currentLanguage' => Drupal::languageManager()->getLanguage(Language::TYPE_URL)->id, ); + if (!empty($current_query)) { + $path['currentQuery'] = (object) $current_query; + } + $javascript['settings']['data'][] = array('path' => $path); } // All JavaScript settings are placed in the header of the page with // the library weight so that inline scripts appear afterwards. diff --git a/core/misc/active-link.js b/core/misc/active-link.js new file mode 100644 index 0000000..21b5e13 --- /dev/null +++ b/core/misc/active-link.js @@ -0,0 +1,54 @@ +(function (Drupal, drupalSettings) { + + "use strict"; + /** + * Append active class. + * + * The link is only active if its path corresponds to the current path, the + * language of the linked path is equal to the current language, and if the + * 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). + */ + Drupal.behaviors.l = { + attach: function queryL (context) { + // Start by finding all potentially active links. + var path = drupalSettings.path; + var queryString = JSON.stringify(path.currentQuery); + var querySelector = path.currentQuery ? "[data-drupal-link-query='" + queryString + "']" : ':not([data-drupal-link-query])'; + var originalSelectors = ['[data-drupal-link-system-path="' + path.currentPath + '"]']; + var selectors; + + // If this is the front page, we have to check for the path as well. + if (path.isFront) { + originalSelectors.push('[data-drupal-link-system-path=""]'); + } + + // Add language filtering. + selectors = [].concat( + // Links without any hreflang attributes (most of them). + originalSelectors.map(function (selector) { return selector + ':not([hreflang])';}), + // Links with hreflang equals to the current language. + originalSelectors.map(function (selector) { return selector + '[hreflang="' + path.currentLanguage + '"]';}) + ); + + // Add query string selector for pagers, exposed filters. + selectors = selectors.map(function (current) { return current + querySelector; }); + + // Query the DOM. + var activeLinks = context.querySelectorAll(selectors.join(',')); + for (var i = 0, il = activeLinks.length; i < il; i += 1) { + activeLinks[i].classList.add('active'); + } + }, + detach: function (context, settings, trigger) { + if (trigger === 'unload') { + var activeLinks = context.querySelectorAll('a.active'); + for (var i = 0, il = activeLinks.length; i < il; i += 1) { + activeLinks[i].classList.remove('active'); + } + } + } + }; + +})(Drupal, drupalSettings); diff --git a/core/misc/ajax.js b/core/misc/ajax.js index bdff14b..b7df052 100644 --- a/core/misc/ajax.js +++ b/core/misc/ajax.js @@ -625,7 +625,7 @@ Drupal.AjaxCommands.prototype = { if (new_content.parents('html').length > 0) { // Apply any settings from the returned JSON if available. settings = response.settings || ajax.settings || Drupal.settings; - Drupal.attachBehaviors(new_content, settings); + Drupal.attachBehaviors(new_content[0], settings); } }, diff --git a/core/misc/drupal.js b/core/misc/drupal.js index 9c86a0a..b14b185 100644 --- a/core/misc/drupal.js +++ b/core/misc/drupal.js @@ -270,7 +270,7 @@ Drupal.t = function (str, args, options) { * Returns the URL to a Drupal page. */ Drupal.url = function (path) { - return drupalSettings.basePath + drupalSettings.scriptPath + path; + return drupalSettings.path.basePath + drupalSettings.path.scriptPath + path; }; /** diff --git a/core/modules/system/system.module b/core/modules/system/system.module index 536e6d2..7d111cd 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -992,9 +992,11 @@ function system_library_info() { 'version' => VERSION, 'js' => array( 'core/misc/drupal.js' => array('group' => JS_LIBRARY, 'weight' => -18), + 'core/misc/active-link.js' => array(), ), 'dependencies' => array( array('system', 'domready'), + array('system', 'drupalSettings'), ), );