diff --git a/lib/editor/atto/plugins/accessibilitychecker/styles.css b/lib/editor/atto/plugins/accessibilitychecker/styles.css new file mode 100644 index 00000000000..a8330154580 --- /dev/null +++ b/lib/editor/atto/plugins/accessibilitychecker/styles.css @@ -0,0 +1,4 @@ +.accessibilitywarnings img { + max-width: 32px; + max-height: 32px; +} diff --git a/lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button-debug.js b/lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button-debug.js index 7db1ffad061..f8eb598c803 100644 --- a/lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button-debug.js +++ b/lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button-debug.js @@ -36,6 +36,15 @@ M.atto_accessibilitychecker = M.atto_accessibilitychecker || { */ dialogue : null, + /** + * Array of nodes that have an accessibility problem + * + * @property displayedwarnings + * @type Array + * @default null + */ + displayedwarnings: [], + /** * Display the ui dialogue. * @@ -61,11 +70,26 @@ M.atto_accessibilitychecker = M.atto_accessibilitychecker || { dialogue.render(); } else { dialogue = M.atto_accessibilitychecker.dialogue; + // Clear the array of previously displayed warnings. + M.atto_accessibilitychecker.displayedwarnings = []; } dialogue.set('bodyContent', M.atto_accessibilitychecker.get_report(elementid)); dialogue.centerDialogue(); + // Add ability to select problem areas in the editor. + Y.all('.accessibilitywarnings li').on('click', function(e) { + e.preventDefault(); + + var index = e.target.getAttribute("data-index"); + var node = M.atto_accessibilitychecker.displayedwarnings[index]; + + M.atto_accessibilitychecker.dialogue.hide(); + if (node) { + M.editor_atto.set_selection(M.editor_atto.get_selection_from_node(node)); + } + }); + dialogue.show(); M.atto_accessibilitychecker.dialogue = dialogue; }, @@ -88,16 +112,28 @@ M.atto_accessibilitychecker = M.atto_accessibilitychecker || { * @param Y.Node list - node to append the html to. * @param String description - description of this failure. * @param Y.Node[] nodes - list of failing nodes. + * @param boolean imagewarnings - true if the warnings are related to images, false if text. */ - add_warnings : function(list, description, nodes) { - var warning, fails, i; + add_warnings : function(list, description, nodes, imagewarnings) { + var warning, fails, i, key, src, textfield; if (nodes.length > 0) { warning = Y.Node.create('

' + description + '

'); - fails = Y.Node.create('
    '); + fails = Y.Node.create('
      '); i = 0; for (i = 0; i < nodes.length; i++) { - fails.append(Y.Node.create('
    1. ' + Y.Escape.html(nodes[i].get('outerHTML')) + '
    2. ')); + if (imagewarnings) { + key = 'image_'+i; + src = nodes[i].getAttribute('src'); + + fails.append(Y.Node.create('
    3. '+src+'
    4. ')); + } else { + key = 'text_'+i; + + textfield = ('innerText' in nodes[i])? 'innerText' : 'textContent'; + fails.append(Y.Node.create('
    5. ' + nodes[i].get(textfield) + '
    6. ')); + } + M.atto_accessibilitychecker.displayedwarnings[key] = nodes[i]; } warning.append(fails); @@ -151,8 +187,7 @@ M.atto_accessibilitychecker = M.atto_accessibilitychecker || { var editable = M.editor_atto.get_editable_node(elementid); - // Missing alternatives. - var missingalt = [], dodgycontrast = []; + var problemnodes = []; // Images with no alt text or dodgy alt text. var alt; @@ -160,14 +195,15 @@ M.atto_accessibilitychecker = M.atto_accessibilitychecker || { alt = img.getAttribute('alt'); if (typeof alt === 'undefined' || alt === '') { if (img.getAttribute('role') !== 'presentation') { - missingalt.push(img); + problemnodes.push(img); } } }, this); - this.add_warnings(list, M.util.get_string('imagesmissingalt', 'atto_accessibilitychecker'), missingalt); + this.add_warnings(list, M.util.get_string('imagesmissingalt', 'atto_accessibilitychecker'), problemnodes, true); // Contrast ratios. + problemnodes = []; var foreground, background, lum1, lum2, ratio; editable.all('*').each(function (node) { // Check for non-empty text. @@ -193,26 +229,26 @@ M.atto_accessibilitychecker = M.atto_accessibilitychecker || { // We only want the highest node with dodgy contrast reported. var i = 0, found = false; - for (i = 0; i < dodgycontrast.length; i++) { - if (node.ancestors('*').indexOf(dodgycontrast[i]) !== -1) { + for (i = 0; i < problemnodes.length; i++) { + if (node.ancestors('*').indexOf(problemnodes[i]) !== -1) { // Do not add node - it already has a parent in the list. found = true; break; - } else if (dodgycontrast[i].ancestors('*').indexOf(node) !== -1) { + } else if (problemnodes[i].ancestors('*').indexOf(node) !== -1) { // Replace the existing node with this one because it is higher up the DOM. - dodgycontrast[i] = node; + problemnodes[i] = node; found = true; break; } } if (!found) { - dodgycontrast.push(node); + problemnodes.push(node); } } } }, this); - this.add_warnings(list, M.util.get_string('needsmorecontrast', 'atto_accessibilitychecker'), dodgycontrast); + this.add_warnings(list, M.util.get_string('needsmorecontrast', 'atto_accessibilitychecker'), problemnodes, false); if (!list.hasChildNodes()) { list.append('

      ' + M.util.get_string('nowarnings', 'atto_accessibilitychecker') + '

      '); diff --git a/lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button-min.js b/lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button-min.js index c83edce7c39..8b64be89ebf 100644 --- a/lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button-min.js +++ b/lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button-min.js @@ -1 +1 @@ -YUI.add("moodle-atto_accessibilitychecker-button",function(e,t){M.atto_accessibilitychecker=M.atto_accessibilitychecker||{dialogue:null,display_ui:function(e,t){e.preventDefault(),M.editor_atto.is_active(t)||M.editor_atto.focus(t);var n;M.atto_accessibilitychecker.dialogue?n=M.atto_accessibilitychecker.dialogue:(n=new M.core.dialogue({visible:!1,modal:!0,close:!0,draggable:!0,width:"800px"}),n.set("headerContent",M.util.get_string("pluginname","atto_accessibilitychecker")),n.render()),n.set("bodyContent",M.atto_accessibilitychecker.get_report(t)),n.centerDialogue(),n.show(),M.atto_accessibilitychecker.dialogue=n},init:function(e){var t=M.util.image_url("e/visual_blocks","core");M.editor_atto.add_toolbar_button(e.elementid,"accessibilitychecker",t,e.group,this.display_ui)},add_warnings:function(t,n,r){var i,s,o;if(r.length>0){i=e.Node.create("

      "+n+"

      "),s=e.Node.create("
        "),o=0;for(o=0;o"+e.Escape.html(r[o].get("outerHTML"))+""));i.append(s),t.append(i)}},get_luminance_from_css_color:function(t){var n;t==="transparent"&&(t="#ffffff"),n=e.Color.toArray(e.Color.toRGB(t));var r=function(e){return e=parseInt(e,10)/255,e<=.03928?e/=12.92:e=Math.pow((e+.055)/1.055,2.4),e},i=r(n[0]),s=r(n[1]),o=r(n[2]);return.2126*i+.7152*s+.0722*o},list_warnings:function(t){var n=e.Node.create("
        "),r=M.editor_atto.get_editable_node(t),i=[],s=[],o;r.all("img").each(function(e){o=e.getAttribute("alt"),(typeof o=="undefined"||o==="")&&e.getAttribute("role")!=="presentation"&&i.push(e)},this),this.add_warnings(n,M.util.get_string("imagesmissingalt","atto_accessibilitychecker"),i);var u,a,f,l,c;return r.all("*").each(function(t){if(e.Lang.trim(t.get("text"))!==""){u=t.getComputedStyle("color"),a=t.getComputedStyle("backgroundColor"),f=this.get_luminance_from_css_color(u),l=this.get_luminance_from_css_color(a),f>l?c=(f+.05)/(l+.05):c=(l+.05)/(f+.05);if(c<=4.5){var n=0,r=!1;for(n=0;n"+M.util.get_string("nowarnings","atto_accessibilitychecker")+"

        "),n},get_report:function(t){var n='
        ',r=e.Node.create(n);return r.append(this.list_warnings(t)),r}}},"@VERSION@",{requires:["node","escape","color-base"]}); +YUI.add("moodle-atto_accessibilitychecker-button",function(e,t){M.atto_accessibilitychecker=M.atto_accessibilitychecker||{dialogue:null,displayedwarnings:[],display_ui:function(t,n){t.preventDefault(),M.editor_atto.is_active(n)||M.editor_atto.focus(n);var r;M.atto_accessibilitychecker.dialogue?(r=M.atto_accessibilitychecker.dialogue,M.atto_accessibilitychecker.displayedwarnings=[]):(r=new M.core.dialogue({visible:!1,modal:!0,close:!0,draggable:!0,width:"800px"}),r.set("headerContent",M.util.get_string("pluginname","atto_accessibilitychecker")),r.render()),r.set("bodyContent",M.atto_accessibilitychecker.get_report(n)),r.centerDialogue(),e.all(".accessibilitywarnings li").on("click",function(e){e.preventDefault();var t=e.target.getAttribute("data-index"),n=M.atto_accessibilitychecker.displayedwarnings[t];M.atto_accessibilitychecker.dialogue.hide(),n&&M.editor_atto.set_selection(M.editor_atto.get_selection_from_node(n))}),r.show(),M.atto_accessibilitychecker.dialogue=r},init:function(e){var t=M.util.image_url("e/visual_blocks","core");M.editor_atto.add_toolbar_button(e.elementid,"accessibilitychecker",t,e.group,this.display_ui)},add_warnings:function(t,n,r,i){var s,o,u,a,f,l;if(r.length>0){s=e.Node.create("

        "+n+"

        "),o=e.Node.create('
          '),u=0;for(u=0;u '+f+""))):(a="text_"+u,l="innerText"in r[u]?"innerText":"textContent",o.append(e.Node.create('
        1. '+r[u].get(l)+"
        2. "))),M.atto_accessibilitychecker.displayedwarnings[a]=r[u];s.append(o),t.append(s)}},get_luminance_from_css_color:function(t){var n;t==="transparent"&&(t="#ffffff"),n=e.Color.toArray(e.Color.toRGB(t));var r=function(e){return e=parseInt(e,10)/255,e<=.03928?e/=12.92:e=Math.pow((e+.055)/1.055,2.4),e},i=r(n[0]),s=r(n[1]),o=r(n[2]);return.2126*i+.7152*s+.0722*o},list_warnings:function(t){var n=e.Node.create("
          "),r=M.editor_atto.get_editable_node(t),i=[],s;r.all("img").each(function(e){s=e.getAttribute("alt"),(typeof s=="undefined"||s==="")&&e.getAttribute("role")!=="presentation"&&i.push(e)},this),this.add_warnings(n,M.util.get_string("imagesmissingalt","atto_accessibilitychecker"),i,!0),i=[];var o,u,a,f,l;return r.all("*").each(function(t){if(e.Lang.trim(t.get("text"))!==""){o=t.getComputedStyle("color"),u=t.getComputedStyle("backgroundColor"),a=this.get_luminance_from_css_color(o),f=this.get_luminance_from_css_color(u),a>f?l=(a+.05)/(f+.05):l=(f+.05)/(a+.05);if(l<=4.5){var n=0,r=!1;for(n=0;n"+M.util.get_string("nowarnings","atto_accessibilitychecker")+"

          "),n},get_report:function(t){var n='
          ',r=e.Node.create(n);return r.append(this.list_warnings(t)),r}}},"@VERSION@",{requires:["node","escape","color-base"]}); diff --git a/lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button.js b/lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button.js index 0ae360a1e5a..860f5b48351 100644 --- a/lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button.js +++ b/lib/editor/atto/plugins/accessibilitychecker/yui/build/moodle-atto_accessibilitychecker-button/moodle-atto_accessibilitychecker-button.js @@ -36,6 +36,15 @@ M.atto_accessibilitychecker = M.atto_accessibilitychecker || { */ dialogue : null, + /** + * Array of nodes that have an accessibility problem + * + * @property displayedwarnings + * @type Array + * @default null + */ + displayedwarnings: [], + /** * Display the ui dialogue. * @@ -61,11 +70,26 @@ M.atto_accessibilitychecker = M.atto_accessibilitychecker || { dialogue.render(); } else { dialogue = M.atto_accessibilitychecker.dialogue; + // Clear the array of previously displayed warnings. + M.atto_accessibilitychecker.displayedwarnings = []; } dialogue.set('bodyContent', M.atto_accessibilitychecker.get_report(elementid)); dialogue.centerDialogue(); + // Add ability to select problem areas in the editor. + Y.all('.accessibilitywarnings li').on('click', function(e) { + e.preventDefault(); + + var index = e.target.getAttribute("data-index"); + var node = M.atto_accessibilitychecker.displayedwarnings[index]; + + M.atto_accessibilitychecker.dialogue.hide(); + if (node) { + M.editor_atto.set_selection(M.editor_atto.get_selection_from_node(node)); + } + }); + dialogue.show(); M.atto_accessibilitychecker.dialogue = dialogue; }, @@ -88,16 +112,28 @@ M.atto_accessibilitychecker = M.atto_accessibilitychecker || { * @param Y.Node list - node to append the html to. * @param String description - description of this failure. * @param Y.Node[] nodes - list of failing nodes. + * @param boolean imagewarnings - true if the warnings are related to images, false if text. */ - add_warnings : function(list, description, nodes) { - var warning, fails, i; + add_warnings : function(list, description, nodes, imagewarnings) { + var warning, fails, i, key, src, textfield; if (nodes.length > 0) { warning = Y.Node.create('

          ' + description + '

          '); - fails = Y.Node.create('
            '); + fails = Y.Node.create('
              '); i = 0; for (i = 0; i < nodes.length; i++) { - fails.append(Y.Node.create('
            1. ' + Y.Escape.html(nodes[i].get('outerHTML')) + '
            2. ')); + if (imagewarnings) { + key = 'image_'+i; + src = nodes[i].getAttribute('src'); + + fails.append(Y.Node.create('
            3. '+src+'
            4. ')); + } else { + key = 'text_'+i; + + textfield = ('innerText' in nodes[i])? 'innerText' : 'textContent'; + fails.append(Y.Node.create('
            5. ' + nodes[i].get(textfield) + '
            6. ')); + } + M.atto_accessibilitychecker.displayedwarnings[key] = nodes[i]; } warning.append(fails); @@ -151,8 +187,7 @@ M.atto_accessibilitychecker = M.atto_accessibilitychecker || { var editable = M.editor_atto.get_editable_node(elementid); - // Missing alternatives. - var missingalt = [], dodgycontrast = []; + var problemnodes = []; // Images with no alt text or dodgy alt text. var alt; @@ -160,14 +195,15 @@ M.atto_accessibilitychecker = M.atto_accessibilitychecker || { alt = img.getAttribute('alt'); if (typeof alt === 'undefined' || alt === '') { if (img.getAttribute('role') !== 'presentation') { - missingalt.push(img); + problemnodes.push(img); } } }, this); - this.add_warnings(list, M.util.get_string('imagesmissingalt', 'atto_accessibilitychecker'), missingalt); + this.add_warnings(list, M.util.get_string('imagesmissingalt', 'atto_accessibilitychecker'), problemnodes, true); // Contrast ratios. + problemnodes = []; var foreground, background, lum1, lum2, ratio; editable.all('*').each(function (node) { // Check for non-empty text. @@ -188,26 +224,26 @@ M.atto_accessibilitychecker = M.atto_accessibilitychecker || { // We only want the highest node with dodgy contrast reported. var i = 0, found = false; - for (i = 0; i < dodgycontrast.length; i++) { - if (node.ancestors('*').indexOf(dodgycontrast[i]) !== -1) { + for (i = 0; i < problemnodes.length; i++) { + if (node.ancestors('*').indexOf(problemnodes[i]) !== -1) { // Do not add node - it already has a parent in the list. found = true; break; - } else if (dodgycontrast[i].ancestors('*').indexOf(node) !== -1) { + } else if (problemnodes[i].ancestors('*').indexOf(node) !== -1) { // Replace the existing node with this one because it is higher up the DOM. - dodgycontrast[i] = node; + problemnodes[i] = node; found = true; break; } } if (!found) { - dodgycontrast.push(node); + problemnodes.push(node); } } } }, this); - this.add_warnings(list, M.util.get_string('needsmorecontrast', 'atto_accessibilitychecker'), dodgycontrast); + this.add_warnings(list, M.util.get_string('needsmorecontrast', 'atto_accessibilitychecker'), problemnodes, false); if (!list.hasChildNodes()) { list.append('

              ' + M.util.get_string('nowarnings', 'atto_accessibilitychecker') + '

              '); diff --git a/lib/editor/atto/plugins/accessibilitychecker/yui/src/button/js/button.js b/lib/editor/atto/plugins/accessibilitychecker/yui/src/button/js/button.js index 2d3951cf654..b1f87aa5b91 100644 --- a/lib/editor/atto/plugins/accessibilitychecker/yui/src/button/js/button.js +++ b/lib/editor/atto/plugins/accessibilitychecker/yui/src/button/js/button.js @@ -34,6 +34,15 @@ M.atto_accessibilitychecker = M.atto_accessibilitychecker || { */ dialogue : null, + /** + * Array of nodes that have an accessibility problem + * + * @property displayedwarnings + * @type Array + * @default null + */ + displayedwarnings: [], + /** * Display the ui dialogue. * @@ -59,11 +68,26 @@ M.atto_accessibilitychecker = M.atto_accessibilitychecker || { dialogue.render(); } else { dialogue = M.atto_accessibilitychecker.dialogue; + // Clear the array of previously displayed warnings. + M.atto_accessibilitychecker.displayedwarnings = []; } dialogue.set('bodyContent', M.atto_accessibilitychecker.get_report(elementid)); dialogue.centerDialogue(); + // Add ability to select problem areas in the editor. + Y.all('.accessibilitywarnings li').on('click', function(e) { + e.preventDefault(); + + var index = e.target.getAttribute("data-index"); + var node = M.atto_accessibilitychecker.displayedwarnings[index]; + + M.atto_accessibilitychecker.dialogue.hide(); + if (node) { + M.editor_atto.set_selection(M.editor_atto.get_selection_from_node(node)); + } + }); + dialogue.show(); M.atto_accessibilitychecker.dialogue = dialogue; }, @@ -86,16 +110,28 @@ M.atto_accessibilitychecker = M.atto_accessibilitychecker || { * @param Y.Node list - node to append the html to. * @param String description - description of this failure. * @param Y.Node[] nodes - list of failing nodes. + * @param boolean imagewarnings - true if the warnings are related to images, false if text. */ - add_warnings : function(list, description, nodes) { - var warning, fails, i; + add_warnings : function(list, description, nodes, imagewarnings) { + var warning, fails, i, key, src, textfield; if (nodes.length > 0) { warning = Y.Node.create('

              ' + description + '

              '); - fails = Y.Node.create('
                '); + fails = Y.Node.create('
                  '); i = 0; for (i = 0; i < nodes.length; i++) { - fails.append(Y.Node.create('
                1. ' + Y.Escape.html(nodes[i].get('outerHTML')) + '
                2. ')); + if (imagewarnings) { + key = 'image_'+i; + src = nodes[i].getAttribute('src'); + + fails.append(Y.Node.create('
                3. '+src+'
                4. ')); + } else { + key = 'text_'+i; + + textfield = ('innerText' in nodes[i])? 'innerText' : 'textContent'; + fails.append(Y.Node.create('
                5. ' + nodes[i].get(textfield) + '
                6. ')); + } + M.atto_accessibilitychecker.displayedwarnings[key] = nodes[i]; } warning.append(fails); @@ -149,8 +185,7 @@ M.atto_accessibilitychecker = M.atto_accessibilitychecker || { var editable = M.editor_atto.get_editable_node(elementid); - // Missing alternatives. - var missingalt = [], dodgycontrast = []; + var problemnodes = []; // Images with no alt text or dodgy alt text. var alt; @@ -158,14 +193,15 @@ M.atto_accessibilitychecker = M.atto_accessibilitychecker || { alt = img.getAttribute('alt'); if (typeof alt === 'undefined' || alt === '') { if (img.getAttribute('role') !== 'presentation') { - missingalt.push(img); + problemnodes.push(img); } } }, this); - this.add_warnings(list, M.util.get_string('imagesmissingalt', 'atto_accessibilitychecker'), missingalt); + this.add_warnings(list, M.util.get_string('imagesmissingalt', 'atto_accessibilitychecker'), problemnodes, true); // Contrast ratios. + problemnodes = []; var foreground, background, lum1, lum2, ratio; editable.all('*').each(function (node) { // Check for non-empty text. @@ -191,26 +227,26 @@ M.atto_accessibilitychecker = M.atto_accessibilitychecker || { // We only want the highest node with dodgy contrast reported. var i = 0, found = false; - for (i = 0; i < dodgycontrast.length; i++) { - if (node.ancestors('*').indexOf(dodgycontrast[i]) !== -1) { + for (i = 0; i < problemnodes.length; i++) { + if (node.ancestors('*').indexOf(problemnodes[i]) !== -1) { // Do not add node - it already has a parent in the list. found = true; break; - } else if (dodgycontrast[i].ancestors('*').indexOf(node) !== -1) { + } else if (problemnodes[i].ancestors('*').indexOf(node) !== -1) { // Replace the existing node with this one because it is higher up the DOM. - dodgycontrast[i] = node; + problemnodes[i] = node; found = true; break; } } if (!found) { - dodgycontrast.push(node); + problemnodes.push(node); } } } }, this); - this.add_warnings(list, M.util.get_string('needsmorecontrast', 'atto_accessibilitychecker'), dodgycontrast); + this.add_warnings(list, M.util.get_string('needsmorecontrast', 'atto_accessibilitychecker'), problemnodes, false); if (!list.hasChildNodes()) { list.append('

                  ' + M.util.get_string('nowarnings', 'atto_accessibilitychecker') + '

                  ');