Toolbar using inline images for visual state

Description

Simple example of a toolbar widget using inline images to display the visual state of the buttons.

Keyboard Support

* Tab: move between toolbar items.
* Left and Right Arrows: move between button items.
* Space: toggle <code>aria-pressed</code> state of currently focused button until key is released.

Example Start

Example End

Roles

  • application
  • button
  • toolbar

Properties

  • aria-checked
  • aria-describedby
  • aria-labelledby
  • aria-pressed

HTML Source Code

CSS Source Code


ul.toolbar{
  float: left;
  display: inline;
  text-align: center;
  margin: 0 !important;
  padding: 0 1px !important;
  font-size: 100% !important;
  border: 1px solid black;
  background-color: #ccc;
}

ul.toolbar li{
  float: left;
  display: inline;
  text-align: center;
  margin: 0;
  padding: 3px;
  height: 36px;
  height: 34px;
}

ul div.italic{
   font-style: italic;
}

textarea.example {
  clear: both;
  margin: 0;
  padding: .25em;
  width: 60%;
  height: 200px;
  
}

.italic {
  font-style:italic;
}

.bold {
  font-weight:bold;
}

.hide {
position: absolute;
top: -20em;
left: -200em;
}

Javascript Source Code


var KEY_ENTER = 13;
var KEY_SPACE = 32;
var KEY_LEFT  = 37;
var KEY_UP    = 38;
var KEY_RIGHT = 39;
var KEY_DOWN  = 40;

$(document).ready(function() {

  $('ul.toolbar li').mousedown(function(event) {

    var ariaControls = '#' + $(this).attr('aria-controls');
    var button = $(this).attr('aria-labelledby');

    // remove "_label" from the button string
    button = button.substr(0, button.length - 6);

    // trigger the blur event to reset the button images to the unfocused state.
    // this is necessary because blur is not triggered for li elements when using the mouse
    $('ul.toolbar li').trigger('blur');

    $(this).siblings().attr('tabindex', "-1");
    $(this).attr('tabindex', "0");

    switch(button) {
      case 'bigger': {
        increaseFontSize(ariaControls);
        $(this).children('img').attr('src', "http://dev-static.oaa-accessibility.org/examples/images/button-biggerPressed-focus.png");
        break;
      }
      case 'smaller': {
        decreaseFontSize(ariaControls);
        $(this).children('img').attr('src', "http://dev-static.oaa-accessibility.org/examples/images/button-smallerPressed-focus.png");
        break;
      }
      case 'italic':
      case 'bold': {
        $(ariaControls).toggleClass(button);

        if ($(ariaControls).hasClass(button) == true) {
          $(this).children('img').attr('src', "http://dev-static.oaa-accessibility.org/examples/images/button-" + button + "Pressed-focus.png");
        }
        else
        {
          $(this).children('img').attr('src', "http://dev-static.oaa-accessibility.org/examples/images/button-" + button + "-focus.png");
        }
        break;
      }
      case 'left':
      case 'center':
      case 'right':
      case 'justify': {

        // Set the pressed-focus button state
        $(this).children('img').attr('src', "http://dev-static.oaa-accessibility.org/examples/images/button-" + button + "Pressed-focus.png");
        $(this).attr('aria-pressed', "true");

        setAlignment(button, ariaControls);

        // clear the other alignment buttons
        $(this).siblings().each(function(index) {
          var sib = $(this).attr('id');
          sib = sib.substr(0, sib.length - 1);
          $(this).children('img').attr('src', "http://dev-static.oaa-accessibility.org/examples/images/button-" + sib + ".png");
          $(this).attr('aria-pressed', "false");
        });

        break;
      }
    } // end switch

    if ($(this).hasClass('toggleButton') == true) {

      // This is a toggle button: toggle aria-pressed state
      togglePressed(this);
    }
    else if ($(this).hasClass('radioButton') == false) {

      // This is a momentary pushbutton: Set aria-pressed to true
      $(this).attr('aria-pressed', 'true');
    }

    // Give the current button focus
    $(this).focus();

    event.stopPropagation();
    return false;
  }); // end button click handler

  // bind a mouseup handler to the buttons to enable momentary pushbuttons
  // to return to unpressed state and toggle buttons to remain pressed
  //
  $('ul.toolbar li').mouseup(function(event) {

    if ($(this).hasClass('toggleButton') == false && $(this).hasClass('radioButton') == false) {

      // Set aria-pressed to false
      $(this).attr('aria-pressed', 'false');

      // change button image to reflect unpressed state
      switch ($(this).attr('aria-labelledby')) {
        case 'bigger_label': {
          $(this).children('img').attr('src', "http://dev-static.oaa-accessibility.org/examples/images/button-bigger-focus.png");
          break;
        }
        case 'smaller_label': {
          $(this).children('img').attr('src', "http://dev-static.oaa-accessibility.org/examples/images/button-smaller-focus.png");
          break;
        }
      } // end switch
    }

    event.stopPropagation();
    return false;
  }); // end mouseup handler

   // keypress handler
   //
   // The Opera browser performs some window commands from the keypress event,
   // not keydown like Firefox, Safari, and IE. This event handler consumes
   // keypresses for relevant keys so that Opera behaves when the user is
   // manipulating the buttons with the keyboard.
   //
  $('ul.toolbar li').keypress(function(event) {
    switch (event.keyCode) {
      case KEY_UP:
      case KEY_DOWN:
      case KEY_ENTER:
      case KEY_SPACE: {
        event.stopPropagation;
        return false;
        break;
      } // end case
    } //end switch

    return true;
  }); //end keypress event

  $('ul.toolbar li').keydown(function(event) {

    var ariaControls = '#' + $(this).attr('aria-controls');

    $(this).siblings().attr('tabindex', "-1");
    $(this).attr('tabindex', "0");


    switch (event.keyCode) {
      case KEY_UP:
      case KEY_LEFT: {
        selectedButton = $(this).prev();
        if (!$(selectedButton).length) {
          selectedButton = $(this).parent().children('li:last');
        }

        // Blur the other buttons in the toolbar
        $(selectedButton).siblings().trigger('blur');

        // Set focus to the selected button
        $(selectedButton).focus();

        event.stopPropagation();
        return false;

      } // end case
      case KEY_DOWN:
      case KEY_RIGHT: {
        selectedButton = $(this).next();
        if (!$(selectedButton).length) {
          selectedButton = $(this).parent().children('li:first');
        }

        // Blur the other buttons in the toolbar
        $(selectedButton).siblings().trigger('blur');

        // Set focus to the selected button
        $(selectedButton).focus();

        event.stopPropagation();
        return false;
        
      } // end case
      case KEY_ENTER:
      case KEY_SPACE: {
        var button = $(this).attr('aria-labelledby');

        // remove "_label" from the button string
        button = button.substr(0, button.length - 6);

          switch(button) {
          case 'bigger': {
            increaseFontSize(ariaControls);
            $(this).children('img').attr('src', "http://dev-static.oaa-accessibility.org/examples/images/button-biggerPressed-focus.png");
            break;
          }
          case 'smaller': {
            decreaseFontSize(ariaControls);
            $(this).children('img').attr('src', "http://dev-static.oaa-accessibility.org/examples/images/button-smallerPressed-focus.png");
            break;
          }
          case 'italic':
          case 'bold': {
            $(ariaControls).toggleClass(button);
    
            if ($(ariaControls).hasClass(button) == true) {
              $(this).children('img').attr('src', "http://dev-static.oaa-accessibility.org/examples/images/button-" + button + "Pressed-focus.png");
            }
            else
            {
              $(this).children('img').attr('src', "http://dev-static.oaa-accessibility.org/examples/images/button-" + button + "-focus.png");
            }
            break;
          }
          case 'left':
          case 'center':
          case 'right':
          case 'justify': {
    
            // Set the pressed-focus button state
            $(this).children('img').attr('src', "http://dev-static.oaa-accessibility.org/examples/images/button-" + button + "Pressed-focus.png");
            $(this).attr('aria-pressed', "true");
    
            setAlignment(button, ariaControls);
    
            // clear the other alignment buttons
            $(this).siblings().each(function(index) {
              var sib = $(this).attr('id');
              sib = sib.substr(0, sib.length - 1);
              $(this).children('img').attr('src', "http://dev-static.oaa-accessibility.org/examples/images/button-" + sib + ".png");
              $(this).attr('aria-pressed', "false");
            });
    
            break;
          }
        } // end switch  

        if ($(this).hasClass('toggleButton') == true) {

            // This is a toggle button: toggle aria-pressed state
            togglePressed(this);
        }
        else if ($(this).hasClass('radioButton') == false) {
            // This is a momentary pushbutton: Set aria-pressed to true
            $(this).attr('aria-pressed', 'true');
        }

        event.stopPropagation();
        return false;

      } // end case
      
    } // end switch

    return true;
  }); // end button click handler

  // bind a keyup handler to the buttons to enable momentary pushbuttons
  // to return to unpressed state and toggle buttons to remain pressed
  //
  $('ul.toolbar li').keyup(function(event) {
    
    var id = this;
    var selectedButton;

    switch (event.keyCode) {
      case KEY_ENTER:
      case KEY_SPACE: {
        if ($(this).hasClass('toggleButton') == false && $(this).hasClass('radioButton') == false) {
        
          // set aria-pressed to false
          $(id).attr('aria-pressed', 'false');

          // change button image to reflect unpressed state
          switch ($(this).attr('aria-labelledby')) {
            case 'bigger_label': {
              $(this).children('img').attr('src', "http://dev-static.oaa-accessibility.org/examples/images/button-bigger-focus.png");
              break;
            }
            case 'smaller_label': {
              $(this).children('img').attr('src', "http://dev-static.oaa-accessibility.org/examples/images/button-smaller-focus.png");
              break;
            }
          } // end switch
        }

        event.stopPropagation();
        return false;

      } // end case
    } // end switch

    return true;
  }); // end mouseup handler

  // bind a focus handler to set button image to show focus
  //
  $('ul.toolbar li').focus(function(event) {

    var pressed = "Pressed";
    var button = $(this).attr('aria-labelledby');

    // Remove "_label" from the button string
    button = button.substr(0, button.length - 6);

    // If aria-pressed is false, set pressed to be an empty string
    if ($(this).attr('aria-pressed') == 'false') {
      pressed = '';
    }

    $(this).children('img').attr('src', "http://dev-static.oaa-accessibility.org/examples/images/button-" + button + pressed + "-focus.png");
    
  }); // end focus handler

  // bind a blur handler to set button image to show focus
  //
  $('ul.toolbar li').blur(function(event) {

    var pressed = "Pressed";
    var button = $(this).attr('aria-labelledby');

    // Remove "_label" from the button string
    button = button.substr(0, button.length - 6);

    // If aria-pressed is false, set pressed to be an empty string
    if ($(this).attr('aria-pressed') == 'false') {
      pressed = '';
    }

    $(this).children('img').attr('src', "http://dev-static.oaa-accessibility.org/examples/images/button-" + button + pressed + ".png");

  }); // end blur handler

  /**
   * increaseFontSize() increases the font size for the controlled area
   *
   * @param (ariaControls) id of text area to modify
   *
   * @return N/A
   */
  function increaseFontSize(ariaControls) {
  
    var $text = $(ariaControls);
    var fontSize = parseFloat($text.css('fontSize'), 10);
  
    // increase the font size
    fontSize *= 1.4;
  
    if (fontSize > 120) {
      return;
    }
    // write the new value to the css
    // note: 'px' must be appended for valid css
    $text.css('fontSize', fontSize+'px');
  } // end increaseFontSize()
  
  /**
   * decreaseFontSize() decreases the font size for the controlled area
   *
   * @param (ariaControls) id of text area to modify
   *
   * @return N/A
   */
  function decreaseFontSize(ariaControls) {
  
    var $text = $(ariaControls);
    var fontSize = parseFloat($text.css('fontSize'), 10);
  
    // increase the font size
    fontSize /= 1.4;
  
    if (fontSize < 4) {
      return;
    }
  
    // write the new value to the css property
    // note: 'px' must be appended for valid css
    $text.css('fontSize', fontSize+'px');
  
  } // end decreaseFontSize
  
  /**
   * setAlignment() sets the aligment of text according to the values passed into the function
   *
   * @param (align) value of alignment to set
   * @param (id) button to be operated on
   *
   * @return N/A
   */
  function setAlignment(align, id) {
  
    // reverse the aria-pressed state
    $(id).css('text-align', align);
  }

  /**
   * togglePressed() toggles the aria-pressed atribute between true or false
   *
   * @param ( id object) button to be operated on
   *
   * @return N/A
   */
  function togglePressed(id) {
  
    // reverse the aria-pressed state
    if ($(id).attr('aria-pressed') == 'true') {
      $(id).attr('aria-pressed', 'false');
    }
    else {
      $(id).attr('aria-pressed', 'true');
    }
  }

}); // end ready