diff --git a/core/includes/common.inc b/core/includes/common.inc
index 540f42b..c10ef6f 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -2314,12 +2314,10 @@ function drupal_http_header_attributes(array $attributes = array()) {
*
* @see url()
*/
-function l($text, $path, array $options = array()) {
- static $use_theme = NULL;
+function l($content, $path, $options = array(), $attributes = array()) {
// Merge in defaults.
$options += array(
- 'attributes' => array(),
'query' => array(),
'html' => FALSE,
);
@@ -2334,47 +2332,23 @@ function l($text, $path, array $options = array()) {
$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) {
- $options['attributes']['class'][] = 'active';
+ $attributes['class'][] = 'active';
}
// Remove all HTML and PHP tags from a tooltip. For best performance, we act only
// if a quick strpos() pre-check gave a suspicion (because strip_tags() is expensive).
- if (isset($options['attributes']['title']) && strpos($options['attributes']['title'], '<') !== FALSE) {
- $options['attributes']['title'] = strip_tags($options['attributes']['title']);
- }
-
- // Determine if rendering of the link is to be done with a theme function
- // or the inline default. Inline is faster, but if the theme system has been
- // loaded and a module or theme implements a preprocess or process function
- // or overrides the theme_link() function, then invoke theme(). Preliminary
- // benchmarks indicate that invoking theme() can slow down the l() function
- // by 20% or more, and that some of the link-heavy Drupal pages spend more
- // than 10% of the total page request time in the l() function.
- if (!isset($use_theme) && function_exists('theme')) {
- // Allow edge cases to prevent theme initialization and force inline link
- // rendering.
- if (variable_get('theme_link', TRUE)) {
- drupal_theme_initialize();
- $registry = theme_get_registry(FALSE);
- // We don't want to duplicate functionality that's in theme(), so any
- // hint of a module or theme doing anything at all special with the 'link'
- // theme hook should simply result in theme() being called. This includes
- // the overriding of theme_link() with an alternate function or template,
- // the presence of preprocess or process functions, or the presence of
- // include files.
- $use_theme = !isset($registry['link']['function']) || ($registry['link']['function'] != 'theme_link');
- $use_theme = $use_theme || !empty($registry['link']['preprocess functions']) || !empty($registry['link']['process functions']) || !empty($registry['link']['includes']);
- }
- else {
- $use_theme = FALSE;
- }
- }
- if ($use_theme) {
- return theme('link', array('text' => $text, 'path' => $path, 'options' => $options));
+ if (isset($attributes['title']) && strpos($attributes['title'], '<') !== FALSE) {
+ $attributes['title'] = strip_tags($attributes['title']);
}
+
+ $attributes = new Attribute($attributes);
+
// The result of url() is a plain-text URL. Because we are using it here
// in an HTML argument context, we need to encode it properly.
- return '' . ($options['html'] ? $text : check_plain($text)) . '';
+ $href = check_plain(url($path, $options));
+ $content = $options['html'] ? $content : check_plain($content);
+
+ return '' . $content . '';
}
/**
@@ -5357,31 +5331,32 @@ function drupal_pre_render_conditional_comments($elements) {
*/
function drupal_pre_render_link($element) {
// By default, link options to pass to l() are normally set in #options.
- $element += array('#options' => array());
- // However, within the scope of renderable elements, #attributes is a valid
- // way to specify attributes, too. Take them into account, but do not override
- // attributes from #options.
- if (isset($element['#attributes'])) {
- $element['#options'] += array('attributes' => array());
- $element['#options']['attributes'] += $element['#attributes'];
+ $element += array(
+ '#content' => '',
+ '#path' => '',
+ '#options' => array(),
+ '#attributes' => array()
+ );
+
+ if (!isset($element['#content']) || !isset($element['#path'])) {
+ $oh_shit = TRUE;
}
// This #pre_render callback can be invoked from inside or outside of a Form
// API context, and depending on that, a HTML ID may be already set in
// different locations. #options should have precedence over Form API's #id.
- // #attributes have been taken over into #options above already.
- if (isset($element['#options']['attributes']['id'])) {
- $element['#id'] = $element['#options']['attributes']['id'];
+ if (isset($element['#attributes']['id'])) {
+ $element['#id'] = $element['#attributes']['id'];
}
elseif (isset($element['#id'])) {
- $element['#options']['attributes']['id'] = $element['#id'];
+ $element['#attributes']['id'] = $element['#id'];
}
// Conditionally invoke ajax_pre_render_element(), if #ajax is set.
if (isset($element['#ajax']) && !isset($element['#ajax_processed'])) {
// If no HTML ID was found above, automatically create one.
if (!isset($element['#id'])) {
- $element['#id'] = $element['#options']['attributes']['id'] = drupal_html_id('ajax-link');
+ $element['#id'] = $element['#attributes']['id'] = drupal_html_id('ajax-link');
}
// If #ajax['path] was not specified, use the href as Ajax request URL.
if (!isset($element['#ajax']['path'])) {
@@ -5391,7 +5366,7 @@ function drupal_pre_render_link($element) {
$element = ajax_pre_render_element($element);
}
- $element['#markup'] = l($element['#title'], $element['#href'], $element['#options']);
+ $element['#markup'] = l($element['#content'], $element['#path'], $element['#options'], $element['#attributes']);
return $element;
}
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index d2fe902..6f556ac 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -1620,25 +1620,33 @@ function theme_status_messages($variables) {
}
/**
+ * Preprocess variables for link templates.
+ */
+function template_preprocess_link(&$variables) {
+ $variables['attributes'] = new Attribute(isset($variables['attributes']) ? $variables['attributes'] : array());
+ $variables['content'] = $variables['options']['html'] ? $variables['content'] : check_plain($variables['content']);
+ $variables['href'] = check_plain(url($variables['path'], $variables['options']));
+ // Do not pass 'path' or 'options' to link functions or templates.
+ unset($variables['path']);
+ unset($variables['options']);
+}
+
+/**
* Returns HTML for a link.
*
- * All Drupal code that outputs a link should call the l() function. That
- * function performs some initial preprocessing, and then, if necessary, calls
- * theme('link') for rendering the anchor tag.
+ * All Drupal code that outputs a link should call the l() function.
*
- * To optimize performance for sites that don't need custom theming of links,
- * the l() function includes an inline copy of this function, and uses that copy
- * if none of the enabled modules or the active theme implement any preprocess
- * or process functions or override this theme implementation.
+ * theme('link') should only be used when HTML attributes for the tag
+ * such as 'class', 'id', etc. are not sufficient for themeing a given link.
*
* @param $variables
- * An associative array containing the keys 'text', 'path', and 'options'. See
- * the l() function for information about these variables.
+ * An associative array containing the keys 'content', 'href', and 'attributes'.
+ * See the l() function for information about $variables.
*
* @see l()
*/
function theme_link($variables) {
- return '' . ($variables['options']['html'] ? $variables['text'] : check_plain($variables['text'])) . '';
+ return '' . $variables['content'] . '';
}
/**
@@ -2967,7 +2975,7 @@ function drupal_common_theme() {
'variables' => array('display' => NULL),
),
'link' => array(
- 'variables' => array('text' => NULL, 'path' => NULL, 'options' => array()),
+ 'variables' => array('content' => NULL, 'path' => NULL, 'options' => array(), 'attributes' => array()),
),
'links' => array(
'variables' => array('links' => array(), 'attributes' => array('class' => array('links')), 'heading' => array()),
diff --git a/core/modules/overlay/overlay.module b/core/modules/overlay/overlay.module
index 8e6e65b..d0fa29c 100644
--- a/core/modules/overlay/overlay.module
+++ b/core/modules/overlay/overlay.module
@@ -444,9 +444,9 @@ function theme_overlay_disable_message($variables) {
// screen-reader users, this message appears in both the parent and child
// documents, but only the one in the child document is part of the tab order.
foreach (array('profile_link', 'dismiss_message_link') as $key) {
- $element[$key]['#options']['attributes']['class'][] = 'element-invisible';
+ $element[$key]['#attributes']['class'][] = 'element-invisible';
if (overlay_get_mode() == 'child') {
- $element[$key]['#options']['attributes']['class'][] = 'element-focusable';
+ $element[$key]['#attributes']['class'][] = 'element-focusable';
}
}
diff --git a/core/modules/shortcut/shortcut.module b/core/modules/shortcut/shortcut.module
index 9bbb12a..4753300 100644
--- a/core/modules/shortcut/shortcut.module
+++ b/core/modules/shortcut/shortcut.module
@@ -741,9 +741,10 @@ function shortcut_toolbar_pre_render($toolbar) {
if (shortcut_set_edit_access($shortcut_set)) {
$configure_link = array(
'#type' => 'link',
- '#title' => t('Edit shortcuts'),
- '#href' => 'admin/config/user-interface/shortcut/' . $shortcut_set->set_name,
- '#options' => array('attributes' => array('id' => 'edit-shortcuts')),
+ '#content' => t('Edit shortcuts'),
+ '#path' => 'admin/config/user-interface/shortcut/' . $shortcut_set->set_name,
+ '#options' => array(),
+ '#attributes' => array('id' => 'edit-shortcuts'),
);
}
diff --git a/core/modules/toolbar/toolbar.module b/core/modules/toolbar/toolbar.module
index a54743a..14aab92 100644
--- a/core/modules/toolbar/toolbar.module
+++ b/core/modules/toolbar/toolbar.module
@@ -77,30 +77,6 @@ function toolbar_toggle_page() {
}
/**
- * Formats an element used to toggle the toolbar drawer's visibility.
- *
- * @param $variables
- * An associative array containing:
- * - collapsed: A boolean value representing the toolbar drawer's visibility.
- * - attributes: An associative array of HTML attributes.
- *
- * @return
- * An HTML string representing the element for toggling.
- *
- * @ingroup themable
- */
-function theme_toolbar_toggle($variables) {
- if ($variables['collapsed']) {
- $toggle_text = t('Show shortcuts');
- }
- else {
- $toggle_text = t('Hide shortcuts');
- $variables['attributes']['class'][] = 'toggle-active';
- }
- return l($toggle_text, 'toolbar/toggle', array('query' => drupal_get_destination(), 'attributes' => array('title' => $toggle_text) + $variables['attributes']));
-}
-
-/**
* Determines the current state of the toolbar drawer's visibility.
*
* @return
@@ -250,10 +226,15 @@ function toolbar_view() {
);
// Add an anchor to be able to toggle the visibility of the drawer.
+ $toggle_text = _toolbar_is_collapsed() ? t('Show toolbar') : t('Hide toolbar');
+ $toggle_path = 'toolbar/toggle';
+ $toggle_options = array('query' => drupal_get_destination());
+ $toggle_attributes = array('class' => array('toggle'));
+ if (_toolbar_is_collapsed()) {
+ $toggle_attributes['class'][] = 'toggle-active';
+ }
$build['toolbar_toggle'] = array(
- '#theme' => 'toolbar_toggle',
- '#collapsed' => _toolbar_is_collapsed(),
- '#attributes' => array('class' => array('toggle')),
+ '#markup' => l($toggle_text, $toggle_path, $toggle_options, $toggle_attributes),
);
// Prepare the drawer links CSS classes.