diff -u b/core/modules/tour/css/tour.css b/core/modules/tour/css/tour.css --- b/core/modules/tour/css/tour.css +++ b/core/modules/tour/css/tour.css @@ -11,0 +12,6 @@ + +.tour-progress { + position: absolute; + bottom: 10px; + right: 15px; +} diff -u b/core/modules/tour/js/jquery.joyride-2.0.3.js b/core/modules/tour/js/jquery.joyride-2.0.3.js --- b/core/modules/tour/js/jquery.joyride-2.0.3.js +++ b/core/modules/tour/js/jquery.joyride-2.0.3.js @@ -135,7 +135,7 @@ }, tip_template : function (opts) { - var $blank, content; + var $blank, content, $wrapper; opts.tip_class = opts.tip_class || ''; @@ -145,7 +145,14 @@ settings.template.link + methods.timer_instance(opts.index); - $blank.append($(settings.template.wrapper)); + $wrapper = $(settings.template.wrapper); + if (opts.li.attr('data-aria-labelledby')) { + $wrapper.attr('aria-labelledby', opts.li.attr('data-aria-labelledby')) + } + if (opts.li.attr('data-aria-describedby')) { + $wrapper.attr('aria-describedby', opts.li.attr('data-aria-describedby')) + } + $blank.append($wrapper); $blank.first().attr('data-index', opts.index); $('.joyride-content-wrapper', $blank).append(content); @@ -273,6 +280,7 @@ settings.$current_tip = settings.$next_tip; $('.joyride-next-tip', settings.$current_tip).focus(); + methods.tabbable(settings.$current_tip); // skip non-existent targets } else if (settings.$li && settings.$target.length < 1) { @@ -623,6 +631,33 @@ version : function () { return settings.version; + }, + + tabbable : function (el) { + $(el).on('keydown', function( event ) { + if (!event.isDefaultPrevented() && event.keyCode && + // Escape key. + event.keyCode === 27 ) { + event.preventDefault(); + methods.end(); + return; + } + + // Prevent tabbing out of tour items. + if ( event.keyCode !== 9 ) { + return; + } + var tabbables = $(el).find(":tabbable"), + first = tabbables.filter(":first"), + last = tabbables.filter(":last"); + if ( event.target === last[0] && !event.shiftKey ) { + first.focus( 1 ); + event.preventDefault(); + } else if ( event.target === first[0] && event.shiftKey ) { + last.focus( 1 ); + event.preventDefault(); + } + }); } }; diff -u b/core/modules/tour/js/tour.js b/core/modules/tour/js/tour.js --- b/core/modules/tour/js/tour.js +++ b/core/modules/tour/js/tour.js @@ -14,7 +14,8 @@ /** * Initializes the tour. */ - function setupTour(items, scope, context) { + function setupTour(items, scope) { + console.log('setting up'); if ($(items).length) { $(toolbar, scope).removeClass(toolbar_class); @@ -28,27 +29,28 @@ else { $(this).attr('data-text', Drupal.t('Next')); } + }); // Update the last item to have "Close" as the button. - $(items + " li").last().attr('data-text', Drupal.t('Close')); + $(items + " li").last().attr('data-text', Drupal.t('End tour')); } else { $(toolbar, scope).addClass(toolbar_class); } - $(toolbar, scope).on('click.tour-' + context, function() { - if ($(overlay).length) { + $(toolbar, scope).bind('click.tour', function() { + if ($(overlay).length || !window) { return false; } - if ($(toolbar + ".active", scope).length) { + if ($(toolbar + ".touring", scope).length) { $(items).attr('hidden', true).joyride('destroy'); - $(toolbar, scope).removeClass('active'); + closeTour(scope); } else { - $(toolbar, scope).addClass('active'); + $(toolbar, scope).addClass('touring'); $(items).attr('hidden', false).joyride({ 'postRideCallback': function() { - $(toolbar, scope).removeClass('active'); + $(toolbar, scope).removeClass('touring'); } }); } @@ -57,16 +59,55 @@ } /** + * Cleans up the tour. + */ + function closeTour(scope) { + var toolbar = "#toolbar-tab-tour"; + $(toolbar, scope).removeClass('touring'); + } + + /** + * Detaches up the tour. + */ + function detachTour(scope) { + var toolbar = "#toolbar-tab-tour"; + closeTour(scope); + $(toolbar, scope).unbind('click.tour'); + } + + /** * Initialize the appropriate tour. */ if ($(overlay_content).length) { - setupTour(overlay_content, window.parent.document, 'overlay'); - $.on('drupalOverlayClose', function() { - $(toolbar).off('click.tour-overlay'); - }) + // Remove tour events associated with overlay. + detachTour(window.parent.document); + // Attach it based on outer content. + setupTour(overlay_content, window.parent.document); } else { - setupTour(tour_items, window.document, 'parent'); + $(document).bind('drupalOverlayBeforeClose', function() { + // Remove tour events associated with overlay. + detachTour(window.document); + // Attach it based on outer content. + setupTour(tour_items, window.document); + console.log('closing'); + }); + $(document).bind('drupalOverlayBeforeLoad', function() { + // Remove tour events associated with overlay. + detachTour(window.document); + console.log('closing before move'); + }); + + // Don't run this in overlay. + // This only runs once in the parent. + if (window == window.parent) { + $('body').once('tour', function() { + setupTour(tour_items, window.document); + }); + } + else { + setupTour(tour_items, window.document); + } } } }; diff -u b/core/modules/tour/lib/Drupal/tour/Plugin/tour/tour/Tooltip.php b/core/modules/tour/lib/Drupal/tour/Plugin/tour/tour/Tooltip.php --- b/core/modules/tour/lib/Drupal/tour/Plugin/tour/tour/Tooltip.php +++ b/core/modules/tour/lib/Drupal/tour/Plugin/tour/tour/Tooltip.php @@ -47,6 +47,10 @@ if (!empty($this->entity->location)) { $attributes['data-options'] = 'tipLocation:' . $this->entity->location; } + // Add aria support. + $this->entity->ariaId = drupal_html_id($this->entity->id()); + $attributes['data-aria-describedby'] = 'tour-tooltip-' . $this->entity->ariaId . '-contents'; + $attributes['data-aria-labelledby'] = 'tour-tooltip-' . $this->entity->ariaId . '-label'; return $attributes; } diff -u b/core/modules/tour/tour.module b/core/modules/tour/tour.module --- b/core/modules/tour/tour.module +++ b/core/modules/tour/tour.module @@ -97,7 +97,6 @@ '#href' => '', '#options' => array( 'html' => FALSE, - 'fragment' => '#', 'attributes' => array( 'class' => array('icon', 'icon-help', 'tour-no-items-hidden'), 'id' => 'toolbar-tab-tour', @@ -135,8 +134,15 @@ $output = ""; return $output; @@ -147,8 +153,8 @@ */ function theme_tour_tooltip($vars) { $tooltip = $vars['tooltip']; - return '

' . check_plain($tooltip->label()) . '

-

' . filter_xss_admin($tooltip->body) . '

'; + return '

' . check_plain($tooltip->label()) . '

+

' . filter_xss_admin($tooltip->body) . '

'; } /**