// This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . /* * @package atto_accessibilityhelper * @copyright 2014 Damyon Wiese * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ /** * @module moodle-atto_accessibilityhelper-button */ /** * Atto text editor accessibilityhelper plugin. * * This plugin adds some functions to do things that screen readers do not do well. * Specifically, listing the active styles for the selected text, * listing the images in the page, listing the links in the page. * * * @namespace M.atto_accessibilityhelper * @class Button * @extends M.editor_atto.EditorPlugin */ var COMPONENT = 'atto_accessibilityhelper', TEMPLATE = '' + // The list of styles. '

' + '{{get_string "liststyles" component}}
' + '' + '

' + '' + '

' + '{{get_string "listlinks" component}}
' + '' + '

' + '' + '

' + '{{get_string "listimages" component}}
' + '' + '

' + '', CSS = { STYLESLABEL: COMPONENT + '_styleslabel', LINKSLABEL: COMPONENT + '_linkslabel', IMAGESLABEL: COMPONENT + '_imageslabel' }; Y.namespace('M.atto_accessibilityhelper').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], { initializer: function() { this.addButton({ icon: 'e/screenreader_helper', callback: this._displayDialogue }); }, /** * Display the Accessibility Helper tool. * * @method _displayDialogue * @private */ _displayDialogue: function() { var dialogue = this.getDialogue({ headerContent: M.util.get_string('pluginname', COMPONENT), width: '800px', focusAfterHide: true }); // Set the dialogue content, and then show the dialogue. dialogue.set('bodyContent', this._getDialogueContent()) .show(); }, /** * Return the dialogue content for the tool, attaching any required * events. * * @method _getDialogueContent * @private * @return {Node} The content to place in the dialogue. */ _getDialogueContent: function() { var template = Y.Handlebars.compile(TEMPLATE), content = Y.Node.create(template({ CSS: CSS, component: COMPONENT })); // Add the data. content.one('.listStyles') .empty() .appendChild(this._listStyles()); content.one('.listLinks') .empty() .appendChild(this._listLinks()); content.one('.listImages') .empty() .appendChild(this._listImages()); return content; }, /** * List the styles present for the selection. * * @method _listStyles * @return {String} The list of styles in use. * @private */ _listStyles: function() { // Clear the status node. var list = [], host = this.get('host'), current = host.getSelectionParentNode(), tagname; if (current) { current = Y.one(current); } while (current && (current !== this.editor)) { tagname = current.get('tagName'); if (typeof tagname !== 'undefined') { list.push(Y.Escape.html(tagname)); } current = current.ancestor(); } if (list.length === 0) { list.push(M.util.get_string('nostyles', COMPONENT)); } list.reverse(); // Append the list of current styles. return list.join(', '); }, /** * List the links for the current editor * * @method _listLinks * @return {string} * @private */ _listLinks: function() { var list = Y.Node.create('
    '), listitem, selectlink; this.editor.all('a').each(function(link) { selectlink = Y.Node.create('' + Y.Escape.html(link.get('text')) + ''); selectlink.setData('sourcelink', link); selectlink.on('click', this._linkSelected, this); listitem = Y.Node.create('
  1. '); listitem.appendChild(selectlink); list.appendChild(listitem); }, this); if (!list.hasChildNodes()) { list.append('
  2. ' + M.util.get_string('nolinks', COMPONENT) + '
  3. '); } // Append the list of current styles. return list; }, /** * List the images used in the editor. * * @method _listImages * @return {Node} A Node containing all of the images present in the editor. * @private */ _listImages: function() { var list = Y.Node.create('
      '), listitem, selectimage; this.editor.all('img').each(function(image) { // Get the alt or title or img url of the image. var imgalt = image.getAttribute('alt'); if (imgalt === '') { imgalt = image.getAttribute('title'); if (imgalt === '') { imgalt = image.getAttribute('src'); } } selectimage = Y.Node.create('' + Y.Escape.html(imgalt) + ''); selectimage.setData('sourceimage', image); selectimage.on('click', this._imageSelected, this); listitem = Y.Node.create('
    1. '); listitem.append(selectimage); list.append(listitem); }, this); if (!list.hasChildNodes()) { list.append('
    2. ' + M.util.get_string('noimages', COMPONENT) + '
    3. '); } // Append the list of current styles. return list; }, /** * Event handler for selecting an image. * * @method _imageSelected * @param {EventFacade} e * @private */ _imageSelected: function(e) { e.preventDefault(); this.getDialogue({ focusAfterNode: null }).hide(); var host = this.get('host'), target = e.target.getData('sourceimage'); this.editor.focus(); host.setSelection(host.getSelectionFromNode(target)); }, /** * Event handler for selecting a link. * * @method _linkSelected * @param {EventFacade} e * @private */ _linkSelected: function(e) { e.preventDefault(); this.getDialogue({ focusAfterNode: null }).hide(); var host = this.get('host'), target = e.target.getData('sourcelink'); this.editor.focus(); host.setSelection(host.getSelectionFromNode(target)); } });