Improved ARIA support
authorAlexander Ebert <ebert@woltlab.com>
Tue, 12 Mar 2019 11:32:53 +0000 (12:32 +0100)
committerAlexander Ebert <ebert@woltlab.com>
Tue, 12 Mar 2019 11:32:53 +0000 (12:32 +0100)
wcfsetup/install/files/js/3rdParty/redactor2/plugins/WoltLabButton.js
wcfsetup/install/files/js/3rdParty/redactor2/plugins/WoltLabObserve.js
wcfsetup/install/files/js/3rdParty/redactor2/plugins/WoltLabSource.js
wcfsetup/install/files/js/3rdParty/redactor2/plugins/source.js
wcfsetup/install/files/js/3rdParty/redactor2/redactor.js
wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Dropdown/Simple.js

index 7d9b4f9bece62686ce0eb8a2a0ad0c05d4f675ba..e57f590fb23bc5f7df4d9f25f4f8c2384e9c9b8f 100644 (file)
@@ -5,20 +5,6 @@ $.Redactor.prototype.WoltLabButton = function() {
        
        return {
                init: function() {
-                       // tooltips are handled on our own
-                       this.button.buildButtonTooltip = function () {};
-                       
-                       var mpClickCallback = this.button.clickCallback;
-                       this.button.clickCallback = (function(e, callback, btnName, args) {
-                               // prevent the browser from breaking the editor focus
-                               if (typeof e.preventDefault === 'function') {
-                                       e.preventDefault();
-                               }
-                               
-                               //noinspection JSUnresolvedFunction
-                               mpClickCallback.call(this, e, callback, btnName, args);
-                       }).bind(this);
-                       
                        // add custom buttons
                        var button, buttonName, i, length;
                        //noinspection JSUnresolvedVariable
@@ -30,6 +16,8 @@ $.Redactor.prototype.WoltLabButton = function() {
                                this.button.addCallback(button, this.WoltLabButton._handleCustomButton);
                        }
                        
+                       var toolbar = this.core.toolbar()[0];
+                       
                        // set button icons and labels
                        var buttonData, icon, iconIsImage;
                        for (i = 0, length = this.opts.buttons.length; i < length; i++) {
@@ -73,10 +61,7 @@ $.Redactor.prototype.WoltLabButton = function() {
                                }
                                
                                icon = buttonData.icon;
-                               iconIsImage = false;
-                               if (!icon.match(/^fa-/) && icon.match(/\.(gif|jpe?g|png|svg)$/)) {
-                                       iconIsImage = true;
-                               }
+                               iconIsImage = (!icon.match(/^fa-/) && icon.match(/\.(gif|jpe?g|png|svg)$/));
                                
                                // set icon
                                //noinspection CssUnknownTarget
@@ -87,7 +72,7 @@ $.Redactor.prototype.WoltLabButton = function() {
                                
                                // set title
                                //noinspection JSUnresolvedVariable
-                               elAttr(button[0], 'title', buttonData.title);
+                               button[0].title = buttonData.title;
                                button[0].classList.add('jsTooltip');
                                
                                // update dropdown label for list
@@ -98,9 +83,6 @@ $.Redactor.prototype.WoltLabButton = function() {
                                }
                        }
                        
-                       var toolbar = this.core.toolbar()[0];
-                       elBySelAll('.re-button-tooltip', toolbar.parentNode, elRemove);
-                       
                        // enforce button order as provided with `opts.buttons`
                        var listItem, toolbarButtons = {}, toolbarOrder = [];
                        while (toolbar.childElementCount) {
@@ -154,7 +136,7 @@ $.Redactor.prototype.WoltLabButton = function() {
                        }).bind(this));
                        
                        // prevent drag & drop of toolbar buttons
-                       this.$toolbar[0].addEventListener('dragstart', function (event) {
+                       toolbar.addEventListener('dragstart', function (event) {
                                event.preventDefault();
                        });
                        
index 00a2b1dbfdc244ba4365e5a598082deda29f5a5a..91d42f462e46b695b47919989ec8b8fe2197eb9f 100644 (file)
@@ -81,6 +81,10 @@ $.Redactor.prototype.WoltLabObserve = function() {
                                        this.button.enable('woltlabQuote');
                                }
                                
+                               if (isSource) {
+                                       this.button.setActive('html');
+                               }
+                               
                                // WoltLab modification: we know that there will be quite a few
                                // active button states, so we'll simply check all ancestors one
                                // by one instead of searching the DOM over and over again
index fefba54a90519d3d32eb5ae91ea521b74a9e3e81..9b07098964945629aa1e97d5d14ef96b25388c6f 100644 (file)
@@ -58,10 +58,6 @@ $.Redactor.prototype.WoltLabSource = function() {
                                });
                        }
                        
-                       // disable caret position in source mode
-                       this.source.setCaretOnShow = function () {};
-                       this.source.setCaretOnHide = function (html) { return html; };
-                       
                        var mpHide = this.source.hide;
                        this.source.hide = (function () {
                                // use jQuery to parse, its parser is much more graceful
index 8724a96520bdf0bd0ed561c838e17e85f7d568f3..09496cc8796644de5fee38d46ee5c34e4d69dfb6 100644 (file)
@@ -1,13 +1,10 @@
-(function($)
-{
-       $.Redactor.prototype.source = function()
-       {
+(function ($) {
+       $.Redactor.prototype.source = function () {
                return {
-                       init: function()
-                       {
+                       init: function () {
                                var button = this.button.addFirst('html', 'HTML');
                                this.button.addCallback(button, this.source.toggle);
-
+                               
                                var style = {
                                        'width': '100%',
                                        'margin': '0',
                                        'line-height': '22px',
                                        'font-family': 'Menlo, Monaco, Consolas, "Courier New", monospace'
                                };
-
+                               
                                this.source.$textarea = $('<textarea />');
                                this.source.$textarea.css(style).hide();
-
-                               if (this.opts.type === 'textarea')
-                               {
+                               
+                               if (this.opts.type === 'textarea') {
                                        this.core.box().append(this.source.$textarea);
                                }
-                               else
-                               {
+                               else {
                                        this.core.box().after(this.source.$textarea);
                                }
-
-                               this.core.element().on('destroy.callback.redactor', $.proxy(function()
-                               {
+                               
+                               this.core.element().on('destroy.callback.redactor', $.proxy(function () {
                                        this.source.$textarea.remove();
-
+                                       
                                }, this));
-
+                               
                        },
-                       toggle: function()
-                       {
+                       toggle: function () {
                                return (this.source.$textarea.hasClass('open')) ? this.source.hide() : this.source.show();
                        },
-                       setCaretOnShow: function()
-                       {
-                               this.source.offset = this.offset.get();
-                               var scroll = $(window).scrollTop();
-
-                               var     width = this.core.editor().innerWidth();
-                               var height = this.core.editor().innerHeight();
-
-                               // caret position sync
-                               this.source.start = 0;
-                               this.source.end = 0;
-                               var $editorDiv = $("<div/>").append($.parseHTML(this.core.editor().html(), document, true));
-                               var $selectionMarkers = $editorDiv.find("span.redactor-selection-marker");
-
-                               if ($selectionMarkers.length > 0)
-                               {
-                                       var editorHtml = $editorDiv.html().replace(/&amp;/g, '&');
-
-                                       if ($selectionMarkers.length === 1)
-                                       {
-                                               this.source.start = this.utils.strpos(editorHtml, $editorDiv.find("#selection-marker-1").prop("outerHTML"));
-                                               this.source.end = this.source.start;
-                                       }
-                                       else if ($selectionMarkers.length === 2)
-                                       {
-                                               this.source.start = this.utils.strpos(editorHtml, $editorDiv.find("#selection-marker-1").prop("outerHTML"));
-                                               this.source.end = this.utils.strpos(editorHtml, $editorDiv.find("#selection-marker-2").prop("outerHTML")) - $editorDiv.find("#selection-marker-1").prop("outerHTML").toString().length;
-                                       }
-                               }
-
-                       },
-                       setCaretOnHide: function(html)
-                       {
-                               this.source.start = this.source.$textarea.get(0).selectionStart;
-                               this.source.end = this.source.$textarea.get(0).selectionEnd;
-
-                               // if selection starts from end
-                               if (this.source.start > this.source.end && this.source.end > 0)
-                               {
-                                       var tempStart = this.source.end;
-                                       var tempEnd = this.source.start;
-
-                                       this.source.start = tempStart;
-                                       this.source.end = tempEnd;
-                               }
-
-                               this.source.start = this.source.enlargeOffset(html, this.source.start);
-                               this.source.end = this.source.enlargeOffset(html, this.source.end);
-
-                               html = html.substr(0, this.source.start) + this.marker.html(1) + html.substr(this.source.start);
-
-                               if (this.source.end > this.source.start)
-                               {
-                                       var markerLength = this.marker.html(1).toString().length;
-
-                                       html = html.substr(0, this.source.end + markerLength) + this.marker.html(2) + html.substr(this.source.end + markerLength);
-                               }
-
-                               return html;
-
-                       },
-                       hide: function()
-                       {
+                       setCaretOnShow: function () {},
+                       setCaretOnHide: function (html) { return html; },
+                       hide: function () {
                                this.source.$textarea.removeClass('open').hide();
                                this.source.$textarea.off('.redactor-source');
-
+                               
                                var code = this.source.$textarea.val();
-
+                               
                                code = this.paragraphize.load(code);
-                               code = this.source.setCaretOnHide(code);
-
+                               
                                this.code.start(code);
                                this.button.enableAll();
                                this.core.editor().show().focus();
                                this.selection.restore();
                                this.code.sync();
                        },
-                       show: function()
-                       {
+                       show: function () {
                                this.selection.save();
-                               this.source.setCaretOnShow();
-
+                               
                                var height = this.core.editor().innerHeight();
                                var code = this.code.get();
-                               code = code.replace(/\n\n\n/g, "\n");
-                               code = code.replace(/\n\n/g, "\n");
-
+                               code = code.replace(/\n\n\n/g, '\n');
+                               code = code.replace(/\n\n/g, '\n');
+                               
                                this.core.editor().hide();
                                this.button.disableAll('html');
                                this.source.$textarea.val(code).height(height).addClass('open').show();
-                               this.source.$textarea.on('keyup.redactor-source', $.proxy(function()
-                               {
-                                       if (this.opts.type === 'textarea')
-                                       {
+                               this.source.$textarea.on('keyup.redactor-source', $.proxy(function () {
+                                       if (this.opts.type === 'textarea') {
                                                this.core.textarea().val(this.source.$textarea.val());
                                        }
-
+                                       
                                }, this));
-
+                               
                                this.marker.remove();
-
+                               
                                $(window).scrollTop(scroll);
-
-                               if (this.source.$textarea[0].setSelectionRange)
-                               {
+                               
+                               if (this.source.$textarea[0].setSelectionRange) {
                                        this.source.$textarea[0].setSelectionRange(this.source.start, this.source.end);
                                }
-
+                               
                                this.source.$textarea[0].scrollTop = 0;
-
-                               setTimeout($.proxy(function()
-                               {
+                               
+                               setTimeout($.proxy(function () {
                                        this.source.$textarea.focus();
-
+                                       this.button.setActive('html');
                                }, this), 0);
                        },
-                       enlargeOffset: function(html, offset)
-                       {
-                               var htmlLength = html.length;
-                               var c = 0;
-
-                               if (html[offset] === '>')
-                               {
-                                       c++;
-                               }
-                               else
-                               {
-                                       for(var i = offset; i <= htmlLength; i++)
-                                       {
-                                               c++;
-
-                                               if (html[i] === '>')
-                                               {
-                                                       break;
-                                               }
-                                               else if (html[i] === '<' || i === htmlLength)
-                                               {
-                                                       c = 0;
-                                                       break;
-                                               }
-                                       }
-                               }
-
-                               return offset + c;
-                       }
+                       enlargeOffset: function () {}
                };
        };
 })(jQuery);
index aa06c0aaea45da11f850350c36d6b68b42848168..74923a50f1415edce1a82d03223635247c8acd6a 100644 (file)
                                                }).bind(this));
                                                
                                                elData(button, 'a11y-mouse-event', 'mousedown');
+                                               elData(button, 'aria-expanded', false);
                                                
                                                button.addEventListener('click', function (event) {
                                                        event.preventDefault();
                                clickCallback: function (e, callback, btnName, args) {
                                        var func;
                                        
+                                       if (e instanceof Event) {
+                                               e.preventDefault();
+                                       }
+                                       
                                        args = (typeof args === 'undefined') ? btnName : args;
                                        
                                        if ($.isFunction(callback)) {
                                                $btns = $btns.not('.re-' + key);
                                        }
                                        
-                                       $btns.removeClass('redactor-act');
+                                       $btns.removeClass('redactor-act').attr({
+                                               'aria-pressed': false,
+                                               tabindex: (key === 'html') ? 0 : -1
+                                       });
                                },
                                disable: function (key) {
-                                       this.button.get(key).addClass('redactor-button-disabled');
+                                       this.button.get(key).addClass('redactor-button-disabled').attr('aria-disabled', true);
                                },
                                enable: function (key) {
-                                       this.button.get(key).removeClass('redactor-button-disabled');
+                                       this.button.get(key).removeClass('redactor-button-disabled').attr('aria-disabled', false);
                                },
                                disableAll: function (key) {
                                        var $btns = this.button.toolbar().find('a.re-button');
                                                $btns = $btns.not('.re-' + key);
                                        }
                                        
-                                       $btns.addClass('redactor-button-disabled');
+                                       $btns.addClass('redactor-button-disabled').attr('aria-disabled', true);
                                },
                                enableAll: function () {
-                                       this.button.toolbar().find('a.re-button').removeClass('redactor-button-disabled');
+                                       this.button.toolbar().find('a.re-button').removeClass('redactor-button-disabled').attr('aria-disabled', false);
                                },
                                remove: function (key) {
                                        this.button.get(key).remove();
                                                        });
                                                        
                                                        this.button.setActive(this.dropdown.key);
-                                                       this.dropdown.button.addClass('dropact');
+                                                       this.dropdown.button.addClass('dropact').attr('aria-expanded', true);
                                                        
                                                        this.dropdown.enableCallback();
                                                }
                                                UiSimpleDropdown.close(id);
                                        });
                                        
-                                       this.dropdown.button.removeClass('redactor-act dropact');
+                                       this.dropdown.button.removeClass('redactor-act dropact').attr('aria-expanded', false);
                                        this.dropdown.button = false;
                                        this.dropdown.key = false;
                                        this.dropdown.active = false;
index 165b88ac45694d1ea90063bf28026a819c260b45..390c7bf0d449a58c213693d2c475fef9cfc73310 100644 (file)
@@ -597,10 +597,6 @@ define(
                                this._toggle(null, _activeTargetId);
                                if (button) button.focus();
                        }
-               },
-               
-               _getNextVisibleItem: function(activeItem, index) {
-                       var items = Array.prototype.slice.call(elBySelAll('li', activeItem.closest('.dropdownMenu')));
                }
        };
 });