From 7c8ff7233449dfb3ae985e2a19b6c10af2d667ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotrek=20Reinmar=20Koszuli=C5=84ski?= Date: Mon, 7 Jul 2014 09:51:02 +0200 Subject: [PATCH 1/5] Introduced editor#ariaEditorHelpLabel event in order to communicate editable and a11yhelp plugin. --- core/editable.js | 40 +++++++++++++++---- plugins/a11yhelp/plugin.js | 4 ++ plugins/wysiwygarea/plugin.js | 19 +++++---- tests/core/editable/aria.js | 63 ++++++++++++++++++++++++++++++ tests/plugins/wysiwygarea/aria.js | 64 +++++++++++++++++++++++++++++++ tests/tickets/9638/1.js | 50 ++++++++++++++++++++++++ 6 files changed, 224 insertions(+), 16 deletions(-) create mode 100644 tests/core/editable/aria.js create mode 100644 tests/plugins/wysiwygarea/aria.js create mode 100644 tests/tickets/9638/1.js diff --git a/core/editable.js b/core/editable.js index 8ed79673ffe..f90cd7c1771 100644 --- a/core/editable.js +++ b/core/editable.js @@ -1164,14 +1164,17 @@ if ( ariaLabel ) editable.changeAttr( 'title', ariaLabel ); - // Put the voice label in different spaces, depending on element mode, so - // the DOM element get auto detached on mode reload or editor destroy. - var ct = this.ui.space( this.elementMode == CKEDITOR.ELEMENT_MODE_INLINE ? 'top' : 'contents' ); - if ( ct ) { - var ariaDescId = CKEDITOR.tools.getNextId(), - desc = CKEDITOR.dom.element.createFromHtml( '' + this.lang.common.editorHelp + '' ); - ct.append( desc ); - editable.changeAttr( 'aria-describedby', ariaDescId ); + var helpLabel = editor.fire( 'ariaEditorHelpLabel', {} ).label; + if ( helpLabel ) { + // Put the voice label in different spaces, depending on element mode, so + // the DOM element get auto detached on mode reload or editor destroy. + var ct = this.ui.space( this.elementMode == CKEDITOR.ELEMENT_MODE_INLINE ? 'top' : 'contents' ); + if ( ct ) { + var ariaDescId = CKEDITOR.tools.getNextId(), + desc = CKEDITOR.dom.element.createFromHtml( '' + helpLabel + '' ); + ct.append( desc ); + editable.changeAttr( 'aria-describedby', ariaDescId ); + } } } } ); @@ -2137,6 +2140,27 @@ * @member CKEDITOR.config */ +/** + * Event fired by the editor in order to get accessibility help label. + * The event is responded by a component which provides accessibility + * help (i.e. `a11yhelp` plugin) hence editor is notified whether help is available. + * + * Providing info: + * + * editor.on( 'ariaEditorHelpLabel', function( evt ) { + * evt.data.label = editor.lang.common.editorHelp; + * } ); + * + * Getting label: + * + * var helpLabel = editor.fire( 'ariaEditorHelpLabel', {} ).label; + * + * @since 4.4.3 + * @event ariaEditorHelpLabel + * @param {String} label The label to be used. + * @member CKEDITOR.editor + */ + /** * @event focus * @todo diff --git a/plugins/a11yhelp/plugin.js b/plugins/a11yhelp/plugin.js index 98b1d6a1418..105a7e8a7e0 100644 --- a/plugins/a11yhelp/plugin.js +++ b/plugins/a11yhelp/plugin.js @@ -40,6 +40,10 @@ editor.setKeystroke( CKEDITOR.ALT + 48 /*0*/, 'a11yHelp' ); CKEDITOR.dialog.add( commandName, this.path + 'dialogs/a11yhelp.js' ); + + editor.on( 'ariaEditorHelpLabel', function( evt ) { + evt.data.label = editor.lang.common.editorHelp; + } ); } } ); } )(); diff --git a/plugins/wysiwygarea/plugin.js b/plugins/wysiwygarea/plugin.js index 1e369f387b5..dff4869d67a 100644 --- a/plugins/wysiwygarea/plugin.js +++ b/plugins/wysiwygarea/plugin.js @@ -46,28 +46,31 @@ iframe.on( 'load', onLoad ); var frameLabel = editor.title, - frameDesc = editor.lang.common.editorHelp; + helpLabel = editor.fire( 'ariaEditorHelpLabel', {} ).label; if ( frameLabel ) { - if ( CKEDITOR.env.ie ) - frameLabel += ', ' + frameDesc; + if ( CKEDITOR.env.ie && helpLabel ) + frameLabel += ', ' + helpLabel; iframe.setAttribute( 'title', frameLabel ); } - var labelId = CKEDITOR.tools.getNextId(), - desc = CKEDITOR.dom.element.createFromHtml( '' + frameDesc + '' ); + if ( helpLabel ) { + var labelId = CKEDITOR.tools.getNextId(), + desc = CKEDITOR.dom.element.createFromHtml( '' + helpLabel + '' ); - contentSpace.append( desc, 1 ); + contentSpace.append( desc, 1 ); + iframe.setAttribute( 'aria-describedby', labelId ); + } // Remove the ARIA description. editor.on( 'beforeModeUnload', function( evt ) { evt.removeListener(); - desc.remove(); + if ( desc ) + desc.remove(); } ); iframe.setAttributes( { - 'aria-describedby': labelId, tabIndex: editor.tabIndex, allowTransparency: 'true' } ); diff --git a/tests/core/editable/aria.js b/tests/core/editable/aria.js new file mode 100644 index 00000000000..41d0ec39cc6 --- /dev/null +++ b/tests/core/editable/aria.js @@ -0,0 +1,63 @@ +/* bender-tags: editor,unit */ + +( function() { + 'use strict'; + + bender.test( { + 'test editor#ariaEditorHelpLabel event - responded': function() { + var fired = 0; + + bender.editorBot.create( { + name: 'editor1', + creator: 'inline', + config: { + extraPlugins: 'toolbar', + removePlugins: 'a11yhelp', + on: { + pluginsLoaded: function() { + this.on( 'ariaEditorHelpLabel', function( evt ) { + evt.data.label = 'foo'; + fired += 1; + } ); + } + } + } + }, function( bot ) { + var editor = bot.editor, + describedBy = editor.editable().getAttribute( 'aria-describedby' ); + + assert.areSame( 1, fired, 'event was fired once' ); + assert.isNotNull( describedBy, 'editable has aria-describedby attribute' ); + var label = editor.ui.space( 'top' ).findOne( '#' + describedBy ); + assert.isNotNull( label, 'label element exists within top space' ); + assert.areSame( 'foo', label.getHtml(), 'label\'s content' ); + } ); + }, + + 'test editor#ariaEditorHelpLabel event - not responded': function() { + var fired = 0; + + bender.editorBot.create( { + name: 'editor2', + creator: 'inline', + config: { + extraPlugins: 'toolbar', + removePlugins: 'a11yhelp', + on: { + pluginsLoaded: function() { + this.on( 'ariaEditorHelpLabel', function( evt ) { + fired += 1; + } ); + } + } + } + }, function( bot ) { + var editor = bot.editor, + describedBy = editor.editable().getAttribute( 'aria-describedby' ); + + assert.areSame( 1, fired, 'event was fired once' ); + assert.isNull( describedBy, 'editable does not have has aria-describedby attribute' ); + } ); + } + } ); +} )(); \ No newline at end of file diff --git a/tests/plugins/wysiwygarea/aria.js b/tests/plugins/wysiwygarea/aria.js new file mode 100644 index 00000000000..0771b096f73 --- /dev/null +++ b/tests/plugins/wysiwygarea/aria.js @@ -0,0 +1,64 @@ +/* bender-tags: editor,unit */ + +( function() { + 'use strict'; + + bender.test( { + 'test editor#ariaEditorHelpLabel event - responded': function() { + var fired = 0; + + bender.editorBot.create( { + name: 'editor1', + config: { + extraPlugins: 'toolbar', + removePlugins: 'a11yhelp', + on: { + pluginsLoaded: function() { + this.on( 'ariaEditorHelpLabel', function( evt ) { + evt.data.label = 'foo'; + fired += 1; + } ); + } + } + } + }, function( bot ) { + var editor = bot.editor, + iframe = editor.window.getFrame(), + describedBy = iframe.getAttribute( 'aria-describedby' ); + + assert.areSame( 1, fired, 'event was fired once' ); + assert.isNotNull( describedBy, 'iframe has aria-describedby attribute' ); + var label = editor.ui.space( 'contents' ).findOne( '#' + describedBy ); + assert.isNotNull( label, 'label element exists within top space' ); + assert.areSame( 'foo', label.getHtml(), 'label\'s content' ); + if ( CKEDITOR.env.ie ) + assert.areSame( editor.title + ', foo', iframe.getAttribute( 'title' ), 'on IE title contains label' ); + } ); + }, + + 'test editor#ariaEditorHelpLabel event - not responded': function() { + var fired = 0; + + bender.editorBot.create( { + name: 'editor2', + config: { + extraPlugins: 'toolbar', + removePlugins: 'a11yhelp', + on: { + pluginsLoaded: function() { + this.on( 'ariaEditorHelpLabel', function( evt ) { + fired += 1; + } ); + } + } + } + }, function( bot ) { + var editor = bot.editor, + describedBy = editor.window.getFrame().getAttribute( 'aria-describedby' ); + + assert.areSame( 1, fired, 'event was fired once' ); + assert.isNull( describedBy, 'iframe does not have aria-describedby attribute' ); + } ); + } + } ); +} )(); \ No newline at end of file diff --git a/tests/tickets/9638/1.js b/tests/tickets/9638/1.js new file mode 100644 index 00000000000..b21e3835fae --- /dev/null +++ b/tests/tickets/9638/1.js @@ -0,0 +1,50 @@ +/* bender-tags: editor,unit,a11yhelp */ + +( function() { + 'use strict'; + + bender.test( { + 'async:init': function() { + var that = this; + + bender.tools.setUpEditors( { + withA11y: { + name: 'editor1', + creator: 'inline', + config: { + extraPlugins: 'a11yhelp,toolbar' + } + }, + withoutA11y: { + name: 'editor2', + creator: 'inline', + config: { + removePlugins: 'a11yhelp', + extraPlugins: 'toolbar' + } + } + }, function( editors, bots ) { + that.editorBots = bots; + that.editors = editors; + that.callback(); + } ); + }, + + 'test editor with a11y plugin has aria-describedby': function() { + var editor = this.editors.withA11y, + describedBy = editor.editable().getAttribute( 'aria-describedby' ); + + assert.isNotNull( describedBy, 'editable has aria-describedby attribute' ); + var label = CKEDITOR.document.getById( describedBy ); + assert.isNotNull( label, 'label element exists' ); + assert.areSame( editor.lang.common.editorHelp, label.getHtml(), 'label\'s content' ); + }, + + 'test editor without a11y plugin has aria-describedby': function() { + var editor = this.editors.withoutA11y, + describedBy = editor.editable().getAttribute( 'aria-describedby' ); + + assert.isNull( describedBy, 'editable does not have aria-describedby attribute' ); + } + } ); +} )(); \ No newline at end of file From f8a4554acce1b2319d734b5702d38b71019166cb Mon Sep 17 00:00:00 2001 From: Marek Lewandowski Date: Mon, 7 Jul 2014 15:19:39 +0200 Subject: [PATCH 2/5] Renamed some tests and reused bender-ckeditor-plugins meta information to include toolbar plugin. --- tests/core/editable/aria.js | 7 +++---- tests/plugins/wysiwygarea/aria.js | 7 +++---- tests/tickets/9638/1.js | 6 +++--- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/tests/core/editable/aria.js b/tests/core/editable/aria.js index 41d0ec39cc6..d32413c5c6c 100644 --- a/tests/core/editable/aria.js +++ b/tests/core/editable/aria.js @@ -1,17 +1,17 @@ /* bender-tags: editor,unit */ +/* bender-ckeditor-plugins: toolbar */ ( function() { 'use strict'; bender.test( { - 'test editor#ariaEditorHelpLabel event - responded': function() { + 'test editor#ariaEditorHelpLabel event - handled': function() { var fired = 0; bender.editorBot.create( { name: 'editor1', creator: 'inline', config: { - extraPlugins: 'toolbar', removePlugins: 'a11yhelp', on: { pluginsLoaded: function() { @@ -34,14 +34,13 @@ } ); }, - 'test editor#ariaEditorHelpLabel event - not responded': function() { + 'test editor#ariaEditorHelpLabel event - unhandled': function() { var fired = 0; bender.editorBot.create( { name: 'editor2', creator: 'inline', config: { - extraPlugins: 'toolbar', removePlugins: 'a11yhelp', on: { pluginsLoaded: function() { diff --git a/tests/plugins/wysiwygarea/aria.js b/tests/plugins/wysiwygarea/aria.js index 0771b096f73..9b905d8869f 100644 --- a/tests/plugins/wysiwygarea/aria.js +++ b/tests/plugins/wysiwygarea/aria.js @@ -1,16 +1,16 @@ /* bender-tags: editor,unit */ +/* bender-ckeditor-plugins: toolbar */ ( function() { 'use strict'; bender.test( { - 'test editor#ariaEditorHelpLabel event - responded': function() { + 'test editor#ariaEditorHelpLabel event - handled': function() { var fired = 0; bender.editorBot.create( { name: 'editor1', config: { - extraPlugins: 'toolbar', removePlugins: 'a11yhelp', on: { pluginsLoaded: function() { @@ -36,13 +36,12 @@ } ); }, - 'test editor#ariaEditorHelpLabel event - not responded': function() { + 'test editor#ariaEditorHelpLabel event - not handled': function() { var fired = 0; bender.editorBot.create( { name: 'editor2', config: { - extraPlugins: 'toolbar', removePlugins: 'a11yhelp', on: { pluginsLoaded: function() { diff --git a/tests/tickets/9638/1.js b/tests/tickets/9638/1.js index b21e3835fae..513ee2af44e 100644 --- a/tests/tickets/9638/1.js +++ b/tests/tickets/9638/1.js @@ -1,4 +1,5 @@ /* bender-tags: editor,unit,a11yhelp */ +/* bender-ckeditor-plugins: toolbar */ ( function() { 'use strict'; @@ -12,15 +13,14 @@ name: 'editor1', creator: 'inline', config: { - extraPlugins: 'a11yhelp,toolbar' + extraPlugins: 'a11yhelp' } }, withoutA11y: { name: 'editor2', creator: 'inline', config: { - removePlugins: 'a11yhelp', - extraPlugins: 'toolbar' + removePlugins: 'a11yhelp' } } }, function( editors, bots ) { From 4fd232587b1d758243a913152d1e008c9f75d53a Mon Sep 17 00:00:00 2001 From: Marek Lewandowski Date: Mon, 7 Jul 2014 15:21:57 +0200 Subject: [PATCH 3/5] Created dir for a11yhelp plugin tests. --- tests/{tickets/9638 => plugins/a11yhelp}/1.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/{tickets/9638 => plugins/a11yhelp}/1.js (100%) diff --git a/tests/tickets/9638/1.js b/tests/plugins/a11yhelp/1.js similarity index 100% rename from tests/tickets/9638/1.js rename to tests/plugins/a11yhelp/1.js From b1d130314a95860e8441b2fc00589d2425b55bf9 Mon Sep 17 00:00:00 2001 From: Marek Lewandowski Date: Mon, 7 Jul 2014 15:27:20 +0200 Subject: [PATCH 4/5] Testsuite file rename. --- tests/plugins/a11yhelp/{1.js => editorhelp.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/plugins/a11yhelp/{1.js => editorhelp.js} (100%) diff --git a/tests/plugins/a11yhelp/1.js b/tests/plugins/a11yhelp/editorhelp.js similarity index 100% rename from tests/plugins/a11yhelp/1.js rename to tests/plugins/a11yhelp/editorhelp.js From c8bf3cdf39830f8558f967b7f117f43f9bfdfc84 Mon Sep 17 00:00:00 2001 From: Marek Lewandowski Date: Mon, 7 Jul 2014 15:36:19 +0200 Subject: [PATCH 5/5] Changelog entry. --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index ed2ae75ac8d..7977511a9f1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,6 +11,7 @@ Fixed Issues: * [#12140](http://dev.ckeditor.com/ticket/12140): Fixed: Double-clicking linked widgets opens two dialogs. * [#12132](http://dev.ckeditor.com/ticket/12132): Fixed: Image is inserted with `width` and `height` styles even when they are not allowed. * [#9317](http://dev.ckeditor.com/ticket/9317): [IE] Fixed: [`config.disableObjectResizing`](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-disableObjectResizing) does not work on IE. **Note**: We were not able to fix this issue on IE11+ because necessary events stopped working. See a [last resort workaround](http://dev.ckeditor.com/ticket/9317#comment:16) and make sure to [support our complaint](https://connect.microsoft.com/IE/feedback/details/742593/please-respect-execcommand-enableobjectresizing-in-contenteditable-elements). +* [#9638](http://dev.ckeditor.com/ticket/9638): Added [`config.ariaEditorHelpLabel`](http://docs.ckeditor.com/#!/api/CKEDITOR.editor-event-ariaEditorHelpLabel) event, allowing to set/disable a11yhelp availability. ## CKEditor 4.4.2