MDL-41870 atto: keyboard navigation for toolbar (arrows)
authorDamyon Wiese <damyon@moodle.com>
Fri, 20 Sep 2013 06:16:47 +0000 (14:16 +0800)
committerDamyon Wiese <damyon@moodle.com>
Fri, 20 Sep 2013 06:59:20 +0000 (14:59 +0800)
lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js
lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-min.js
lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor.js
lib/editor/atto/yui/src/editor/js/editor.js
lib/editor/atto/yui/src/editor/meta/editor.json

index 2ebeb90..96ccd49 100644 (file)
Binary files a/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js and b/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js differ
index 9ce52aa..21a2ace 100644 (file)
Binary files a/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-min.js and b/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-min.js differ
index 2ebeb90..96ccd49 100644 (file)
Binary files a/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor.js and b/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor.js differ
index 8dc7d7a..30e1892 100644 (file)
@@ -157,19 +157,29 @@ M.editor_atto = M.editor_atto || {
      */
     add_toolbar_menu : function(elementid, plugin, icon, groupname, entries) {
         var toolbar = Y.one('#' + elementid + '_toolbar'),
-            group = Y.one('#' + elementid + '_toolbar .atto_group.' + groupname + '_group');
+            group = Y.one('#' + elementid + '_toolbar .atto_group.' + groupname + '_group'),
+            currentfocus,
+            button;
+
         if (!group) {
             group = Y.Node.create('<div class="atto_group ' + groupname + '_group"></div>');
             toolbar.append(group);
         }
-        var button = Y.Node.create('<button class="atto_' + plugin + '_button atto_hasmenu" ' +
+        button = Y.Node.create('<button class="atto_' + plugin + '_button atto_hasmenu" ' +
                                     'data-editor="' + Y.Escape.html(elementid) + '" ' +
+                                    'tabindex="-1" ' +
                                     'data-menu="' + plugin + '_' + elementid + '" >' +
                                     icon +
                                     '</button>');
 
         group.append(button);
 
+        currentfocus = toolbar.getAttribute('aria-activedescendant');
+        if (!currentfocus) {
+            button.setAttribute('tabindex', '0');
+            toolbar.setAttribute('aria-activedescendant', button.generateID());
+        }
+
         // Save the name of the plugin.
         M.editor_atto.widgets[plugin] = plugin;
 
@@ -226,20 +236,30 @@ M.editor_atto = M.editor_atto || {
      */
     add_toolbar_button : function(elementid, plugin, icon, groupname, handler) {
         var toolbar = Y.one('#' + elementid + '_toolbar'),
-            group = Y.one('#' + elementid + '_toolbar .atto_group.' + groupname + '_group');
+            group = Y.one('#' + elementid + '_toolbar .atto_group.' + groupname + '_group'),
+            button,
+            currentfocus;
+
         if (!group) {
             group = Y.Node.create('<div class="atto_group ' + groupname +'_group"></div>');
             toolbar.append(group);
         }
-        var button = Y.Node.create('<button class="atto_' + plugin + '_button" ' +
-                                   'data-editor="' + Y.Escape.html(elementid) + '" ' +
-                                   'data-plugin="' + Y.Escape.html(plugin) + '" ' +
-                                   'data-handler="' + Y.Escape.html(plugin) + '">' +
-                                    icon +
-                                    '</button>');
+        button = Y.Node.create('<button class="atto_' + plugin + '_button" ' +
+                               'data-editor="' + Y.Escape.html(elementid) + '" ' +
+                               'data-plugin="' + Y.Escape.html(plugin) + '" ' +
+                               'tabindex="-1" ' +
+                               'data-handler="' + Y.Escape.html(plugin) + '">' +
+                               icon +
+                               '</button>');
 
         group.append(button);
 
+        currentfocus = toolbar.getAttribute('aria-activedescendant');
+        if (!currentfocus) {
+            button.setAttribute('tabindex', '0');
+            toolbar.setAttribute('aria-activedescendant', button.generateID());
+        }
+
         // We only need to attach this once.
         if (!M.editor_atto.buttonhandlers[plugin]) {
             Y.one('body').delegate('click', M.editor_atto.buttonclicked_handler, '.atto_' + plugin + '_button');
@@ -292,7 +312,7 @@ M.editor_atto = M.editor_atto || {
                                             'spellcheck="true" ' +
                                             'class="editor_atto"/>');
         var cssfont = '';
-        var toolbar = Y.Node.create('<div class="editor_atto_toolbar" id="' + params.elementid + '_toolbar"/>');
+        var toolbar = Y.Node.create('<div class="editor_atto_toolbar" id="' + params.elementid + '_toolbar" role="toolbar"/>');
 
         // Bleh - why are we sent a url and not the css to apply directly?
         var css = Y.io(params.content_css, { sync: true });
@@ -321,10 +341,61 @@ M.editor_atto = M.editor_atto || {
             textarea.set('value', atto.getHTML());
         });
 
+        // Listen for Arrow left and Arrow right keys.
+        Y.one(Y.config.doc.body).delegate('key',
+                                          this.keyboard_navigation,
+                                          'down:37,39',
+                                          '#' + params.elementid + '_toolbar',
+                                          this,
+                                          params.elementid);
+
         // Save the file picker options for later.
         M.editor_atto.filepickeroptions[params.elementid] = params.filepickeroptions;
     },
 
+    /**
+     * Implement arrow key navigation for the buttons in the toolbar.
+     * @param Event e - the keyboard event.
+     * @param string elementid - the id of the textarea we created this editor from.
+     */
+    keyboard_navigation : function(e, elementid) {
+        var buttons,
+            current,
+            currentid,
+            currentindex;
+
+        e.preventDefault();
+
+        buttons = Y.all('#' + elementid + '_toolbar button');
+        currentid = Y.one('#' + elementid + '_toolbar').getAttribute('aria-activedescendant');
+        if (!currentid) {
+            return;
+        }
+        current = Y.one('#' + currentid);
+        current.setAttribute('tabindex', '-1');
+
+        currentindex = buttons.indexOf(current);
+
+        if (e.keyCode === 37) {
+            // Left
+            currentindex--;
+            if (currentindex < 0) {
+                currentindex = buttons.size()-1;
+            }
+        } else {
+            // Right
+            currentindex++;
+            if (currentindex >= buttons.size()) {
+                currentindex = 0;
+            }
+        }
+
+        current = buttons.item(currentindex);
+        current.setAttribute('tabindex', '0');
+        current.focus();
+        Y.one('#' + elementid + '_toolbar').setAttribute('aria-activedescendant', current.generateID());
+    },
+
     /**
      * Show the filepicker.
      * @param string elementid for this editor instance.
index 9e6959c..850911d 100644 (file)
@@ -5,6 +5,7 @@
         "io",
         "overlay",
         "escape",
+        "event-key",
         "moodle-core-notification"
       ]
   }