diff options
author | Dries Buytaert <dries@buytaert.net> | 2010-11-06 00:18:24 +0000 |
---|---|---|
committer | Dries Buytaert <dries@buytaert.net> | 2010-11-06 00:18:24 +0000 |
commit | 755bf9cd70be27fafb1c2fd28920559e2d5f055c (patch) | |
tree | ad22554ff2da32a3b4b2fe551000c16e9237762d /modules/overlay | |
parent | 7ab426ecae5e383ee1c662756e89320207f91cbd (diff) | |
download | brdo-755bf9cd70be27fafb1c2fd28920559e2d5f055c.tar.gz brdo-755bf9cd70be27fafb1c2fd28920559e2d5f055c.tar.bz2 |
- Patch #896364 by frega, effulgentsia, Jacine, sun, David_Rothstein, Jeff Burnz, james.elliott, casey, mgifford: screen reader users and some keyboard only users need a clear, quick way to disable the overlay.
Diffstat (limited to 'modules/overlay')
-rw-r--r-- | modules/overlay/overlay-child.css | 25 | ||||
-rw-r--r-- | modules/overlay/overlay-child.js | 13 | ||||
-rw-r--r-- | modules/overlay/overlay-parent.css | 14 | ||||
-rw-r--r-- | modules/overlay/overlay-parent.js | 10 | ||||
-rw-r--r-- | modules/overlay/overlay.module | 147 | ||||
-rw-r--r-- | modules/overlay/overlay.tpl.php | 1 |
6 files changed, 204 insertions, 6 deletions
diff --git a/modules/overlay/overlay-child.css b/modules/overlay/overlay-child.css index 0a2d4a099..c50e911f1 100644 --- a/modules/overlay/overlay-child.css +++ b/modules/overlay/overlay-child.css @@ -6,6 +6,8 @@ html.js { } html.js body { background: transparent !important; + margin-left: 0; + margin-right: 0; padding: 20px 0; } @@ -138,3 +140,26 @@ html.js body { * html #overlay-close:hover { position: absolute; } + +/** + * Disable message. + */ +#overlay-disable-message { + background-color: #fff; + margin: -20px auto 20px; + width: 80%; + -moz-border-radius: 0 0 8px 8px; + -webkit-border-bottom-left-radius: 8px; + -webkit-border-bottom-right-radius: 8px; + border-radius: 0 0 8px 8px; +} +.overlay-disable-message-focused { + padding: 0.5em; +} +.overlay-disable-message-focused a { + display: block; + float: left; +} +.overlay-disable-message-focused #overlay-dismiss-message { + float: right; +} diff --git a/modules/overlay/overlay-child.js b/modules/overlay/overlay-child.js index d0e4b8df8..4c2666cd9 100644 --- a/modules/overlay/overlay-child.js +++ b/modules/overlay/overlay-child.js @@ -57,6 +57,19 @@ Drupal.behaviors.overlayChild = { // Attach child related behaviors to the iframe document. Drupal.overlayChild.attachBehaviors(context, settings); + + // There are two links within the message that informs people about the + // overlay and how to disable it. Make sure both links are visible when + // either one has focus and add a class to the wrapper for styling purposes. + $('#overlay-disable-message', context) + .focusin(function () { + $(this).addClass('overlay-disable-message-focused'); + $('a.element-focusable', this).removeClass('element-invisible'); + }) + .focusout(function () { + $(this).removeClass('overlay-disable-message-focused'); + $('a.element-focusable', this).addClass('element-invisible'); + }); } }; diff --git a/modules/overlay/overlay-parent.css b/modules/overlay/overlay-parent.css index 50e8e364e..196ca177e 100644 --- a/modules/overlay/overlay-parent.css +++ b/modules/overlay/overlay-parent.css @@ -35,3 +35,17 @@ html.overlay-open .displace-top, html.overlay-open .displace-bottom { z-index: 600; } + +/** + * Within the overlay parent, the message about disabling the overlay is for + * screen-reader users only. It is always kept invisible with the + * element-invisible class, and removed from the tab order. Overlay-child.css + * contains styling for the same message appearing within the overlay, and + * intended for sighted users. + */ +#overlay-disable-message { + display: none; +} +html.overlay-open #overlay-disable-message { + display: block; +} diff --git a/modules/overlay/overlay-parent.js b/modules/overlay/overlay-parent.js index a4eb5aaa2..d176234cf 100644 --- a/modules/overlay/overlay-parent.js +++ b/modules/overlay/overlay-parent.js @@ -825,9 +825,15 @@ Drupal.overlay.getDisplacement = function (region) { * the entire page. */ Drupal.overlay.makeDocumentUntabbable = function (context) { - // Manipulating tabindexes is unacceptably slow in IE6 and IE7, so in those - // browsers, the underlying page will still be reachable via the tab key. + // Manipulating tabindexes for the entire document is unacceptably slow in IE6 + // and IE7, so in those browsers, the underlying page will still be reachable + // via the tab key. However, we still make the links within the Disable + // message unreachable, because the same message also exists within the + // child document. The duplicate copy in the underlying document is only for + // assisting screen-reader users navigating the document with reading commands + // that follow markup order rather than tab order. if (jQuery.browser.msie && parseInt(jQuery.browser.version, 10) < 8) { + $('#overlay-disable-message a', context).attr('tabindex', -1); return; } diff --git a/modules/overlay/overlay.module b/modules/overlay/overlay.module index 5172809b7..aa78f2123 100644 --- a/modules/overlay/overlay.module +++ b/modules/overlay/overlay.module @@ -30,10 +30,29 @@ function overlay_menu() { 'access arguments' => array('access overlay'), 'type' => MENU_CALLBACK, ); + $items['overlay/dismiss-message'] = array( + 'title' => '', + 'page callback' => 'overlay_user_dismiss_message', + 'access arguments' => array('access overlay'), + 'type' => MENU_CALLBACK, + ); return $items; } /** + * Implements hook_admin_paths(). + */ +function overlay_admin_paths() { + $paths = array( + // This is marked as an administrative path so that if it is visited from + // within the overlay, the user will stay within the overlay while the + // callback is being processed. + 'overlay/dismiss-message' => TRUE, + ); + return $paths; +} + +/** * Implements hook_permission(). */ function overlay_permission() { @@ -54,6 +73,9 @@ function overlay_theme() { 'render element' => 'page', 'template' => 'overlay', ), + 'overlay_disable_message' => array( + 'render element' => 'element', + ), ); } @@ -254,10 +276,127 @@ function overlay_page_alter(&$page) { } } - if (overlay_get_mode() == 'child') { + $mode = overlay_get_mode(); + if ($mode == 'child') { // Add the overlay wrapper before the html wrapper. array_unshift($page['#theme_wrappers'], 'overlay'); } + elseif ($mode == 'parent' && ($message = overlay_disable_message())) { + $page['page_top']['disable_overlay'] = $message; + } +} + +/** + * Menu callback; dismisses the overlay accessibility message for this user. + */ +function overlay_user_dismiss_message() { + global $user; + // It's unlikely, but possible that "access overlay" permission is granted to + // the anonymous role. In this case, we do not display the message to disable + // the overlay, so there is nothing to dismiss. Also, protect against + // cross-site request forgeries by validating a token. + if (empty($user->uid) || !isset($_GET['token']) || !drupal_valid_token($_GET['token'], 'overlay')) { + return MENU_ACCESS_DENIED; + } + else { + user_save(user_load($user->uid), array('data' => array('overlay_message_dismissed' => 1))); + drupal_set_message(t('The message has been dismissed. You can change your overlay settings at any time by visiting your profile page.')); + // Destination is normally given. Go to the user profile as a fallback. + drupal_goto('user/' . $user->uid . '/edit'); + } +} + +/** + * Returns a renderable array representing a message for disabling the overlay. + * + * If the current user can access the overlay and has not previously indicated + * that this message should be dismissed, this function returns a message + * containing a link to disable the overlay. Nothing is returned for anonymous + * users, because the links control per-user settings. Therefore, because some + * screen readers are unable to properly read overlay contents, site builders + * are discouraged from granting the "access overlay" permission to the + * anonymous role. See http://drupal.org/node/890284. + */ +function overlay_disable_message() { + global $user; + + if (!empty($user->uid) && empty($user->data['overlay_message_dismissed']) && (!isset($user->data['overlay']) || $user->data['overlay']) && user_access('access overlay')) { + $build = array( + '#theme' => 'overlay_disable_message', + '#weight' => -99, + // Link to the user's profile page, where the overlay can be disabled. + 'profile_link' => array( + '#type' => 'link', + '#title' => t('If you have problems accessing administrative pages on this site, disable the overlay on your profile page.'), + '#href' => 'user/' . $user->uid . '/edit', + '#options' => array( + 'query' => drupal_get_destination(), + 'fragment' => 'edit-overlay-control', + 'attributes' => array( + 'id' => 'overlay-profile-link', + // Prevent the target page from being opened in the overlay. + 'class' => array('overlay-exclude'), + ), + ), + ), + // Link to a menu callback that allows this message to be permanently + // dismissed for the current user. + 'dismiss_message_link' => array( + '#type' => 'link', + '#title' => t('Dismiss this message.'), + '#href' => 'overlay/dismiss-message', + '#options' => array( + 'query' => drupal_get_destination() + array( + // Add a token to protect against cross-site request forgeries. + 'token' => drupal_get_token('overlay'), + ), + 'attributes' => array( + 'id' => 'overlay-dismiss-message', + // If this message is being displayed outside the overlay, prevent + // this link from opening the overlay. + 'class' => (overlay_get_mode() == 'parent') ? array('overlay-exclude') : array(), + ), + ), + ) + ); + } + else { + $build = array(); + } + + return $build; +} + +/** + * Returns the HTML for the message about how to disable the overlay. + * + * @see overlay_disable_message() + */ +function theme_overlay_disable_message($variables) { + $element = $variables['element']; + + // Add CSS classes to hide the links from most sighted users, while keeping + // them accessible to screen-reader users and keyboard-only users. To assist + // 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'; + if (overlay_get_mode() == 'child') { + $element[$key]['#options']['attributes']['class'][] = 'element-focusable'; + } + } + + // Render the links. + $output = drupal_render($element['profile_link']) . ' ' . drupal_render($element['dismiss_message_link']); + + // Add a heading for screen-reader users. The heading doesn't need to be seen + // by sighted users. + $output = '<h3 class="element-invisible">' . t('Options for the administrative overlay') . '</h3>' . $output; + + // Wrap in a container for styling. + $output = '<div id="overlay-disable-message" class="clearfix">' . $output . '</div>'; + + return $output; } /** @@ -324,9 +463,9 @@ function overlay_preprocess_maintenance_page(&$variables) { * @see overlay.tpl.php */ function template_preprocess_overlay(&$variables) { - $variables['tabs'] = menu_primary_local_tasks(); - $variables['title'] = drupal_get_title(); - + $variables['tabs'] = menu_primary_local_tasks(); + $variables['title'] = drupal_get_title(); + $variables['disable_overlay'] = overlay_disable_message(); $variables['content_attributes_array']['class'][] = 'clearfix'; } diff --git a/modules/overlay/overlay.tpl.php b/modules/overlay/overlay.tpl.php index d6d9e1c59..5dfcade9b 100644 --- a/modules/overlay/overlay.tpl.php +++ b/modules/overlay/overlay.tpl.php @@ -21,6 +21,7 @@ */ ?> +<?php print render($disable_overlay); ?> <div id="overlay" <?php print $attributes; ?>> <div id="overlay-titlebar" class="clearfix"> <div id="overlay-title-wrapper" class="clearfix"> |