Quellcode durchsuchen

Emoji picker: Accessibility improvements

Allow switching tabs using keyboard
Danilo Bargen vor 6 Jahren
Ursprung
Commit
7ee75111f3

+ 17 - 4
src/directives/compose_area.ts

@@ -458,11 +458,13 @@ export default [
                     emojiKeyboard.addClass('active');
                     emojiTrigger.addClass(TRIGGER_ACTIVE_CSS_CLASS);
 
-                    // Find all emoji
+                    // Find some selectors
                     const allEmoji: any = angular.element(emojiPicker.querySelectorAll('.content .em'));
+                    const allEmojiTabs: any = angular.element(emojiPicker.querySelectorAll('.tab label img'));
 
                     // Add event handlers
                     allEmoji.on('click', onEmojiChosen);
+                    allEmojiTabs.on('keydown', onEmojiTabSelected);
 
                     // set focus to fix chat scroll bug
                     $timeout(() => {
@@ -472,16 +474,19 @@ export default [
 
                 // Hide emoji picker element
                 function hideEmojiPicker() {
+                    const emojiPicker: HTMLElement = EmojiPickerContainer.get().htmlElement;
+
                     // Hide
                     emojiKeyboard.removeClass('active');
                     emojiTrigger.removeClass(TRIGGER_ACTIVE_CSS_CLASS);
 
-                    // Find all emoji
-                    const allEmoji: any = angular.element(
-                        EmojiPickerContainer.get().htmlElement.querySelectorAll('.content .em'));
+                    // Find some selectors
+                    const allEmoji: any = angular.element(emojiPicker.querySelectorAll('.content .em'));
+                    const allEmojiTabs: any = angular.element(emojiPicker.querySelectorAll('.tab label img'));
 
                     // Remove event handlers
                     allEmoji.off('click', onEmojiChosen);
+                    allEmojiTabs.off('keydown', onEmojiTabSelected);
                     EmojiPickerContainer.destroy();
                 }
 
@@ -502,6 +507,14 @@ export default [
                     insertEmoji(this.textContent);
                 }
 
+                // Emoji tab is selected
+                function onEmojiTabSelected(ev: KeyboardEvent): void {
+                    if (ev.key === ' ' || ev.key === 'Enter') {
+                        // Warning: Hacky
+                        this.parentElement.previousElementSibling.checked = true;
+                    }
+                }
+
                 function insertEmoji(emoji, posFrom?: number, posTo?: number): void {
                     const emojiElement = emojify(emoji);
                     insertHTMLElement(emoji, emojiElement, posFrom, posTo);

+ 8 - 8
src/partials/emoji-picker.html

@@ -2,7 +2,7 @@
     <div class="tab">
         <input type="radio" id="tab-0" name="tabs" checked>
         <label for="tab-0" title="Smileys &amp; People">
-            <img src="/emoji/people.svg" class="em-people" height="24" width="24"></span>
+            <img src="/emoji/people.svg" class="em-people" height="24" width="24" role="button" tabindex="0"></span>
         </label>
         <div class="content">
             <span class="em em-people-1f600" data-c="1f600" data-s=":grinning:" title="grinning face">&#x1f600;</span>
@@ -1140,7 +1140,7 @@
     <div class="tab">
         <input type="radio" id="tab-1" name="tabs">
         <label for="tab-1" title="Animals &amp; Nature">
-            <img src="/emoji/nature.svg" class="em-nature" height="24" width="24"></span>
+            <img src="/emoji/nature.svg" class="em-nature" height="24" width="24" role="button" tabindex="0"></span>
         </label>
         <div class="content">
             <span class="em em-nature-1f436" data-c="1f436" data-s=":dog:" title="dog face">&#x1f436;</span>
@@ -1325,7 +1325,7 @@
     <div class="tab">
         <input type="radio" id="tab-2" name="tabs">
         <label for="tab-2" title="Food &amp; Drink">
-            <img src="/emoji/food.svg" class="em-food" height="24" width="24"></span>
+            <img src="/emoji/food.svg" class="em-food" height="24" width="24" role="button" tabindex="0"></span>
         </label>
         <div class="content">
             <span class="em em-food-1f34f" data-c="1f34f" data-s=":green_apple:" title="green apple">&#x1f34f;</span>
@@ -1438,7 +1438,7 @@
     <div class="tab">
         <input type="radio" id="tab-3" name="tabs">
         <label for="tab-3" title="Activity">
-            <img src="/emoji/activity.svg" class="em-activity" height="24" width="24"></span>
+            <img src="/emoji/activity.svg" class="em-activity" height="24" width="24" role="button" tabindex="0"></span>
         </label>
         <div class="content">
             <span class="em em-activity-26bd" data-c="26bd" data-s=":soccer:" title="soccer ball">&#x26bd;</span>
@@ -1686,7 +1686,7 @@
     <div class="tab">
         <input type="radio" id="tab-4" name="tabs">
         <label for="tab-4" title="Travel &amp; Places">
-            <img src="/emoji/travel.svg" class="em-travel" height="24" width="24"></span>
+            <img src="/emoji/travel.svg" class="em-travel" height="24" width="24" role="button" tabindex="0"></span>
         </label>
         <div class="content">
             <span class="em em-travel-1f697" data-c="1f697" data-s=":red_car:" title="automobile">&#x1f697;</span>
@@ -1816,7 +1816,7 @@
     <div class="tab">
         <input type="radio" id="tab-5" name="tabs">
         <label for="tab-5" title="Objects">
-            <img src="/emoji/objects.svg" class="em-objects" height="24" width="24"></span>
+            <img src="/emoji/objects.svg" class="em-objects" height="24" width="24" role="button" tabindex="0"></span>
         </label>
         <div class="content">
             <span class="em em-objects-231a" data-c="231a" data-s=":watch:" title="watch">&#x231a;</span>
@@ -2031,7 +2031,7 @@
     <div class="tab">
         <input type="radio" id="tab-6" name="tabs">
         <label for="tab-6" title="Symbols">
-            <img src="/emoji/symbols.svg" class="em-symbols" height="24" width="24"></span>
+            <img src="/emoji/symbols.svg" class="em-symbols" height="24" width="24" role="button" tabindex="0"></span>
         </label>
         <div class="content">
             <span class="em em-symbols-2764" data-c="2764" data-s=":heart:" title="red heart">&#x2764;</span>
@@ -2314,7 +2314,7 @@
     <div class="tab">
         <input type="radio" id="tab-7" name="tabs">
         <label for="tab-7" title="Flags">
-            <img src="/emoji/flags.svg" class="em-flags" height="24" width="24"></span>
+            <img src="/emoji/flags.svg" class="em-flags" height="24" width="24" role="button" tabindex="0"></span>
         </label>
         <div class="content">
             <span class="em em-flags-1f3f3" data-c="1f3f3" data-s=":flag_white:" title="white flag">&#x1f3f3;</span>

+ 1 - 1
src/sass/components/_emoji_picker.scss

@@ -32,8 +32,8 @@
         position: relative;
         left: 1px;
         margin-left: -1px;
+        @include mouse-hand;
         img {
-            @include mouse-hand;
             position: relative;
             margin: 3px 4px 0;
         }

+ 1 - 1
tools/twemoji/generate-emoji-picker.py

@@ -38,7 +38,7 @@ for i, category in enumerate(category_order):
     print('    <div class="tab">')
     print('        <input type="radio" id="tab-%d" name="tabs"%s>' % (i, ' checked' if i == 0 else ''))
     print('        <label for="tab-%d" title="%s">' % (i, category['name']))
-    print('            <img src="/emoji/{0}.svg" class="em-{0}" height="24" width="24"></span>'.format(category['id']))
+    print('            <img src="/emoji/{0}.svg" class="em-{0}" height="24" width="24" role="button" tabindex="0"></span>'.format(category['id']))
     print('        </label>')
     print('        <div class="content">')
     for emoji in groups[category['id']]: