add a11y checker plugin to rce
closes CNVS-39091 test plan: - a Check Accessibility button should show on the right side of all editors - try adding a empty table - click the check a11y button - should have two errors - missing caption - missing headers - correct both errors - should show no errors detected and close Change-Id: I4028d98d082bdbdebc034facc529cccb67fc4dcf Reviewed-on: https://gerrit.instructure.com/128951 Reviewed-by: Clay Diffrient <cdiffrient@instructure.com> Tested-by: Jenkins QA-Review: Brent Burgoyne <bburgoyne@instructure.com> Product-Review: Brent Burgoyne <bburgoyne@instructure.com>
This commit is contained in:
parent
c3a4e90334
commit
6a77f6fc27
|
@ -45,6 +45,7 @@ function loadLegacyTinyMCE (callback) {
|
|||
legacyTinyMCELoaded = true
|
||||
require('tinymce.editor_box')
|
||||
require('compiled/tinymce')
|
||||
require('tinymce-a11y-checker')
|
||||
callback()
|
||||
}, 'legacyTinymceAsyncChunk')
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ function getSidebarSource(source_name) {
|
|||
return ret
|
||||
}
|
||||
|
||||
let RCELoader = {
|
||||
const RCELoader = {
|
||||
preload() {
|
||||
this.loadRCE(function(){})
|
||||
},
|
||||
|
@ -89,6 +89,7 @@ function getSidebarSource(source_name) {
|
|||
require.ensure([], (require) => {
|
||||
const first = !this.RCE
|
||||
this.RCE = require('canvas-rce/lib/async')
|
||||
require('tinymce-a11y-checker')
|
||||
if (first) {
|
||||
this.loadEventListeners()
|
||||
this.loadingFlag = false
|
||||
|
|
|
@ -26,3 +26,7 @@
|
|||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.mce-i-a11y:before {
|
||||
content: "\e900";
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
"timezone": "1.0.6",
|
||||
"tinycolor2": "1.4.1",
|
||||
"tinymce": "4.5.7",
|
||||
"tinymce-a11y-checker": "1.0.1",
|
||||
"tinymce-light-skin": "1.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -65,7 +65,7 @@ export default class EditorConfig {
|
|||
toolbar: this.toolbar(),
|
||||
theme: 'modern',
|
||||
skin: false,
|
||||
plugins: 'autolink,media,paste,table,textcolor,link,directionality,lists',
|
||||
plugins: 'autolink,media,paste,table,textcolor,link,directionality,lists,a11y_checker',
|
||||
external_plugins: {
|
||||
instructure_image: '/javascripts/tinymce_plugins/instructure_image/plugin.js',
|
||||
instructure_links: '/javascripts/tinymce_plugins/instructure_links/plugin.js',
|
||||
|
@ -143,7 +143,7 @@ export default class EditorConfig {
|
|||
*/
|
||||
formatBtnGroup = 'bold,italic,underline,forecolor,backcolor,removeformat,alignleft,aligncenter,alignright';
|
||||
positionBtnGroup = 'outdent,indent,superscript,subscript,bullist,numlist';
|
||||
fontBtnGroup = 'ltr,rtl,fontsizeselect,formatselect';
|
||||
fontBtnGroup = 'ltr,rtl,fontsizeselect,formatselect,check_a11y';
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -30,7 +30,7 @@ define [
|
|||
toolbar2 = "outdent,indent,superscript,subscript,bullist,numlist,table," +
|
||||
"media,instructure_links,unlink,instructure_image," +
|
||||
"instructure_equation"
|
||||
toolbar3 = "ltr,rtl,fontsizeselect,formatselect"
|
||||
toolbar3 = "ltr,rtl,fontsizeselect,formatselect,check_a11y"
|
||||
|
||||
QUnit.module "EditorConfig",
|
||||
setup: ->
|
||||
|
|
|
@ -23,6 +23,7 @@ define [
|
|||
'helpers/fakeENV'
|
||||
'helpers/editorUtils'
|
||||
'helpers/fixtures'
|
||||
'tinymce.editor_box'
|
||||
], (RichContentEditor, RceCommandShim, RCELoader, Sidebar, fakeENV, editorUtils, fixtures) ->
|
||||
|
||||
QUnit.module 'RichContentEditor - helper function:'
|
||||
|
@ -105,12 +106,15 @@ define [
|
|||
ENV.RICH_CONTENT_SERVICE_ENABLED = false
|
||||
sinon.stub(@$target, 'editorBox')
|
||||
@$target.editorBox.onCall(0).returns(@$target)
|
||||
RichContentEditor.loadNewEditor(@$target, {defaultContent: "content"})
|
||||
Promise.resolve().then =>
|
||||
ok @$target.editorBox.calledTwice
|
||||
ok @$target.editorBox.firstCall.calledWith()
|
||||
ok @$target.editorBox.secondCall.calledWith('set_code', "content")
|
||||
done()
|
||||
RichContentEditor.loadNewEditor(@$target, {defaultContent: "content"}, =>
|
||||
try
|
||||
ok @$target.editorBox.calledTwice, "called twice"
|
||||
ok @$target.editorBox.firstCall.calledWith(), "first called with nothing"
|
||||
ok @$target.editorBox.secondCall.calledWith('set_code', "content")
|
||||
done()
|
||||
catch err
|
||||
done(err)
|
||||
)
|
||||
|
||||
test 'skips instantiation when called with empty target', ->
|
||||
RichContentEditor.loadNewEditor($("#fixtures .invalidTarget"), {})
|
||||
|
@ -121,21 +125,27 @@ define [
|
|||
# false so we don't have to stub out freshNode or RCELoader.loadOnTarget
|
||||
ENV.RICH_CONTENT_SERVICE_ENABLED = false
|
||||
sinon.stub(RceCommandShim, 'focus')
|
||||
RichContentEditor.loadNewEditor(@$target, {focus: true})
|
||||
Promise.resolve().then =>
|
||||
ok RceCommandShim.focus.calledWith(@$target)
|
||||
RceCommandShim.focus.restore()
|
||||
done()
|
||||
RichContentEditor.loadNewEditor(@$target, {focus: true}, =>
|
||||
try
|
||||
ok RceCommandShim.focus.calledWith(@$target)
|
||||
RceCommandShim.focus.restore()
|
||||
done()
|
||||
catch err
|
||||
done(err)
|
||||
)
|
||||
|
||||
test 'with focus:true tries to show sidebar', (assert) ->
|
||||
done = assert.async()
|
||||
# false so we don't have to stub out RCELoader.loadOnTarget
|
||||
ENV.RICH_CONTENT_SERVICE_ENABLED = false
|
||||
RichContentEditor.initSidebar()
|
||||
RichContentEditor.loadNewEditor(@$target, {focus: true})
|
||||
Promise.resolve().then =>
|
||||
ok Sidebar.show.called
|
||||
done()
|
||||
RichContentEditor.loadNewEditor(@$target, {focus: true}, =>
|
||||
try
|
||||
ok Sidebar.show.called
|
||||
done()
|
||||
catch err
|
||||
done(err)
|
||||
)
|
||||
|
||||
test 'hides resize handle when called', ->
|
||||
$resize = fixtures.create('<div class="mce-resizehandle"></div>')
|
||||
|
|
|
@ -51,9 +51,7 @@ test('shows beginning info alert and adds styles to iframe', () => {
|
|||
/>
|
||||
)
|
||||
wrapper.instance().openModal(event)
|
||||
el = $('.ReactModalPortal')
|
||||
const alert = el.find('.before_external_content_info_alert')
|
||||
alert[0].focus()
|
||||
wrapper.instance().handleAlertFocus({ target: { className: "before" } })
|
||||
equal(wrapper.state().beforeExternalContentAlertClass, '')
|
||||
deepEqual(wrapper.state().iframeStyle, { border: '2px solid #008EE2', width: '300px' })
|
||||
})
|
||||
|
@ -65,9 +63,7 @@ test('shows ending info alert and adds styles to iframe', () => {
|
|||
/>
|
||||
)
|
||||
wrapper.instance().openModal(event)
|
||||
el = $('.ReactModalPortal')
|
||||
const alert = el.find('.after_external_content_info_alert')
|
||||
alert[0].focus()
|
||||
wrapper.instance().handleAlertFocus({ target: { className: "after" } })
|
||||
equal(wrapper.state().afterExternalContentAlertClass, '')
|
||||
deepEqual(wrapper.state().iframeStyle, { border: '2px solid #008EE2', width: '300px' })
|
||||
})
|
||||
|
@ -80,9 +76,7 @@ test('hides beginning info alert and adds styles to iframe', () => {
|
|||
)
|
||||
wrapper.instance().openModal(event)
|
||||
el = $('.ReactModalPortal')
|
||||
const alert = el.find('.before_external_content_info_alert')
|
||||
alert[0].focus()
|
||||
alert[0].blur()
|
||||
wrapper.instance().handleAlertBlur({ target: { className: "before" } })
|
||||
equal(wrapper.state().beforeExternalContentAlertClass, 'screenreader-only')
|
||||
deepEqual(wrapper.state().iframeStyle, { border: 'none', width: '100%' })
|
||||
})
|
||||
|
@ -94,10 +88,7 @@ test('hides ending info alert and adds styles to iframe', () => {
|
|||
/>
|
||||
)
|
||||
wrapper.instance().openModal(event)
|
||||
el = $('.ReactModalPortal')
|
||||
const alert = el.find('.after_external_content_info_alert')
|
||||
alert[0].focus()
|
||||
alert[0].blur()
|
||||
wrapper.instance().handleAlertBlur({ target: { className: "after" } })
|
||||
equal(wrapper.state().afterExternalContentAlertClass, 'screenreader-only')
|
||||
deepEqual(wrapper.state().iframeStyle, { border: 'none', width: '100%' })
|
||||
})
|
||||
|
|
44
yarn.lock
44
yarn.lock
|
@ -3679,6 +3679,10 @@ glob-stream@^3.1.5:
|
|||
through2 "^0.6.1"
|
||||
unique-stream "^1.0.0"
|
||||
|
||||
glob-to-regexp@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
|
||||
|
||||
glob-watcher@^0.0.6:
|
||||
version "0.0.6"
|
||||
resolved "https://registry.yarnpkg.com/glob-watcher/-/glob-watcher-0.0.6.tgz#b95b4a8df74b39c83298b0c05c978b4d9a3b710b"
|
||||
|
@ -5617,6 +5621,10 @@ marked@0.3.6:
|
|||
version "0.3.6"
|
||||
resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.6.tgz#b2c6c618fccece4ef86c4fc6cb8a7cbf5aeda8d7"
|
||||
|
||||
material-colors@^1.2.1:
|
||||
version "1.2.5"
|
||||
resolved "https://registry.yarnpkg.com/material-colors/-/material-colors-1.2.5.tgz#5292593e6754cb1bcc2b98030e4e0d6a3afc9ea1"
|
||||
|
||||
math-expression-evaluator@^1.2.14:
|
||||
version "1.2.17"
|
||||
resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz#de819fdbcd84dccd8fae59c6aeb79615b9d266ac"
|
||||
|
@ -7016,6 +7024,20 @@ react-apollo@^1.4.12:
|
|||
object-assign "^4.0.1"
|
||||
prop-types "^15.5.8"
|
||||
|
||||
react-aria-live@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/react-aria-live/-/react-aria-live-1.0.4.tgz#3f154670f156c5b64d9bd31f5dc620ca3760ab1c"
|
||||
|
||||
react-color@^2.13.4:
|
||||
version "2.13.8"
|
||||
resolved "https://registry.yarnpkg.com/react-color/-/react-color-2.13.8.tgz#bcc58f79a722b9bfc37c402e68cd18f26970aee4"
|
||||
dependencies:
|
||||
lodash "^4.0.1"
|
||||
material-colors "^1.2.1"
|
||||
prop-types "^15.5.10"
|
||||
reactcss "^1.2.0"
|
||||
tinycolor2 "^1.4.1"
|
||||
|
||||
react-crop@^4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/react-crop/-/react-crop-4.0.2.tgz#c507841f72642d0c936b289f65fa543ac09778fd"
|
||||
|
@ -7137,6 +7159,12 @@ react@0.14.9:
|
|||
envify "^3.0.0"
|
||||
fbjs "^0.6.1"
|
||||
|
||||
reactcss@^1.2.0:
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/reactcss/-/reactcss-1.2.3.tgz#c00013875e557b1cf0dfd9a368a1c3dab3b548dd"
|
||||
dependencies:
|
||||
lodash "^4.0.1"
|
||||
|
||||
read-file-stdin@^0.2.0:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/read-file-stdin/-/read-file-stdin-0.2.1.tgz#25eccff3a153b6809afacb23ee15387db9e0ee61"
|
||||
|
@ -8372,6 +8400,18 @@ tinycolor2@1.4.1, tinycolor2@^1.4.1:
|
|||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.1.tgz#f4fad333447bc0b07d4dc8e9209d8f39a8ac77e8"
|
||||
|
||||
tinymce-a11y-checker@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/tinymce-a11y-checker/-/tinymce-a11y-checker-1.0.1.tgz#855dc6a13e0f59b9428d35c66b258d271f0990e4"
|
||||
dependencies:
|
||||
instructure-icons "4.x"
|
||||
instructure-ui "3.x"
|
||||
react "^0.14.8 || ^15.0.0"
|
||||
react-aria-live "^1.0.4"
|
||||
react-color "^2.13.4"
|
||||
react-dom "^0.14.8 || ^15.0.0"
|
||||
wcag-element-contrast "^1.0.1"
|
||||
|
||||
tinymce-light-skin@1.3.1, tinymce-light-skin@~1.3.0:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/tinymce-light-skin/-/tinymce-light-skin-1.3.1.tgz#fcce7a8b5761716a381f756e1ac7f47c7a41ea88"
|
||||
|
@ -8728,6 +8768,10 @@ watchpack@^1.4.0:
|
|||
chokidar "^1.7.0"
|
||||
graceful-fs "^4.1.2"
|
||||
|
||||
wcag-element-contrast@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/wcag-element-contrast/-/wcag-element-contrast-1.0.1.tgz#5d0570d771d4b374a967915e7f69be2daf7485ff"
|
||||
|
||||
webpack-cleanup-plugin@^0.5.1:
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/webpack-cleanup-plugin/-/webpack-cleanup-plugin-0.5.1.tgz#df2d706bd75364c06e65b051186316d674eb96af"
|
||||
|
|
Loading…
Reference in New Issue