Chris@0: /** Chris@0: * @file Chris@0: * A Backbone View that provides the aural view of the edit mode toggle. Chris@0: */ Chris@0: Chris@17: (function($, Drupal, Backbone, _) { Chris@17: Drupal.contextualToolbar.AuralView = Backbone.View.extend( Chris@17: /** @lends Drupal.contextualToolbar.AuralView# */ { Chris@17: /** Chris@17: * Tracks whether the tabbing constraint announcement has been read once. Chris@17: * Chris@17: * @type {bool} Chris@17: */ Chris@17: announcedOnce: false, Chris@0: Chris@17: /** Chris@17: * Renders the aural view of the edit mode toggle (screen reader support). Chris@17: * Chris@17: * @constructs Chris@17: * Chris@17: * @augments Backbone.View Chris@17: * Chris@17: * @param {object} options Chris@17: * Options for the view. Chris@17: */ Chris@17: initialize(options) { Chris@17: this.options = options; Chris@0: Chris@17: this.listenTo(this.model, 'change', this.render); Chris@17: this.listenTo(this.model, 'change:isViewing', this.manageTabbing); Chris@0: Chris@17: $(document).on('keyup', _.bind(this.onKeypress, this)); Chris@17: this.manageTabbing(); Chris@17: }, Chris@0: Chris@17: /** Chris@17: * @inheritdoc Chris@17: * Chris@17: * @return {Drupal.contextualToolbar.AuralView} Chris@17: * The current contextual toolbar aural view. Chris@17: */ Chris@17: render() { Chris@17: // Render the state. Chris@17: this.$el Chris@17: .find('button') Chris@17: .attr('aria-pressed', !this.model.get('isViewing')); Chris@17: Chris@17: return this; Chris@17: }, Chris@17: Chris@17: /** Chris@17: * Limits tabbing to the contextual links and edit mode toolbar tab. Chris@17: */ Chris@17: manageTabbing() { Chris@17: let tabbingContext = this.model.get('tabbingContext'); Chris@17: // Always release an existing tabbing context. Chris@17: if (tabbingContext) { Chris@17: // Only announce release when the context was active. Chris@17: if (tabbingContext.active) { Chris@17: Drupal.announce(this.options.strings.tabbingReleased); Chris@17: } Chris@17: tabbingContext.release(); Chris@17: } Chris@17: // Create a new tabbing context when edit mode is enabled. Chris@17: if (!this.model.get('isViewing')) { Chris@17: tabbingContext = Drupal.tabbingManager.constrain( Chris@17: $('.contextual-toolbar-tab, .contextual'), Chris@17: ); Chris@17: this.model.set('tabbingContext', tabbingContext); Chris@17: this.announceTabbingConstraint(); Chris@17: this.announcedOnce = true; Chris@17: } Chris@17: }, Chris@17: Chris@17: /** Chris@17: * Announces the current tabbing constraint. Chris@17: */ Chris@17: announceTabbingConstraint() { Chris@17: const strings = this.options.strings; Chris@17: Drupal.announce( Chris@17: Drupal.formatString(strings.tabbingConstrained, { Chris@17: '@contextualsCount': Drupal.formatPlural( Chris@17: Drupal.contextual.collection.length, Chris@17: '@count contextual link', Chris@17: '@count contextual links', Chris@17: ), Chris@17: }), Chris@17: ); Chris@17: Drupal.announce(strings.pressEsc); Chris@17: }, Chris@17: Chris@17: /** Chris@17: * Responds to esc and tab key press events. Chris@17: * Chris@17: * @param {jQuery.Event} event Chris@17: * The keypress event. Chris@17: */ Chris@17: onKeypress(event) { Chris@17: // The first tab key press is tracked so that an announcement about Chris@17: // tabbing constraints can be raised if edit mode is enabled when the page Chris@17: // is loaded. Chris@17: if ( Chris@17: !this.announcedOnce && Chris@17: event.keyCode === 9 && Chris@17: !this.model.get('isViewing') Chris@17: ) { Chris@17: this.announceTabbingConstraint(); Chris@17: // Set announce to true so that this conditional block won't run again. Chris@17: this.announcedOnce = true; Chris@17: } Chris@17: // Respond to the ESC key. Exit out of edit mode. Chris@17: if (event.keyCode === 27) { Chris@17: this.model.set('isViewing', true); Chris@17: } Chris@17: }, Chris@0: }, Chris@17: ); Chris@17: })(jQuery, Drupal, Backbone, _);