Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
// This file is part of Moodle - http://moodle.org/
2
//
3
// Moodle is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, either version 3 of the License, or
6
// (at your option) any later version.
7
//
8
// Moodle is distributed in the hope that it will be useful,
9
// but WITHOUT ANY WARRANTY; without even the implied warranty of
10
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
// GNU General Public License for more details.
12
//
13
// You should have received a copy of the GNU General Public License
14
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
15
 
16
/*
17
 * @package    atto_accessibilityhelper
18
 * @copyright  2014 Damyon Wiese  <damyon@moodle.com>
19
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
20
 */
21
 
22
/**
23
 * @module moodle-atto_accessibilityhelper-button
24
 */
25
 
26
/**
27
 * Atto text editor accessibilityhelper plugin.
28
 *
29
 * This plugin adds some functions to do things that screen readers do not do well.
30
 * Specifically, listing the active styles for the selected text,
31
 * listing the images in the page, listing the links in the page.
32
 *
33
 *
34
 * @namespace M.atto_accessibilityhelper
35
 * @class Button
36
 * @extends M.editor_atto.EditorPlugin
37
 */
38
 
39
var COMPONENT = 'atto_accessibilityhelper',
40
    TEMPLATE = '' +
41
        // The list of styles.
42
        '<div><p id="{{elementid}}_{{CSS.STYLESLABEL}}">' +
43
            '{{get_string "liststyles" component}}<br/>' +
44
            '<span aria-labelledby="{{elementid}}_{{CSS.STYLESLABEL}}" />' +
45
        '</p></div>' +
46
        '<span class="listStyles"></span>' +
47
 
48
        '<p id="{{elementid}}_{{CSS.LINKSLABEL}}">' +
49
            '{{get_string "listlinks" component}}<br/>' +
50
            '<span aria-labelledby="{{elementid}}_{{CSS.LINKSLABEL}}"/>' +
51
        '</p>' +
52
        '<span class="listLinks"></span>' +
53
 
54
        '<p id="{{elementid}}_{{CSS.IMAGESLABEL}}">' +
55
            '{{get_string "listimages" component}}<br/>' +
56
            '<span aria-labelledby="{{elementid}}_{{CSS.IMAGESLABEL}}"/>' +
57
        '</p>' +
58
        '<span class="listImages"></span>',
59
 
60
    CSS = {
61
        STYLESLABEL: COMPONENT + '_styleslabel',
62
        LINKSLABEL: COMPONENT + '_linkslabel',
63
        IMAGESLABEL: COMPONENT + '_imageslabel'
64
    };
65
 
66
Y.namespace('M.atto_accessibilityhelper').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], {
67
 
68
    initializer: function() {
69
        this.addButton({
70
            icon: 'e/screenreader_helper',
71
            callback: this._displayDialogue
72
        });
73
    },
74
 
75
    /**
76
     * Display the Accessibility Helper tool.
77
     *
78
     * @method _displayDialogue
79
     * @private
80
     */
81
    _displayDialogue: function() {
82
        var dialogue = this.getDialogue({
83
            headerContent: M.util.get_string('pluginname', COMPONENT),
84
            width: '800px',
85
            focusAfterHide: true
86
        });
87
 
88
        // Set the dialogue content, and then show the dialogue.
89
        dialogue.set('bodyContent', this._getDialogueContent())
90
                .show();
91
    },
92
 
93
    /**
94
     * Return the dialogue content for the tool, attaching any required
95
     * events.
96
     *
97
     * @method _getDialogueContent
98
     * @private
99
     * @return {Node} The content to place in the dialogue.
100
     */
101
    _getDialogueContent: function() {
102
        var template = Y.Handlebars.compile(TEMPLATE),
103
            content = Y.Node.create(template({
104
                CSS: CSS,
105
                component: COMPONENT
106
            }));
107
 
108
        // Add the data.
109
        content.one('.listStyles')
110
                .empty()
111
                .appendChild(this._listStyles());
112
        content.one('.listLinks')
113
                .empty()
114
                .appendChild(this._listLinks());
115
        content.one('.listImages')
116
                .empty()
117
                .appendChild(this._listImages());
118
 
119
        return content;
120
    },
121
 
122
    /**
123
     * List the styles present for the selection.
124
     *
125
     * @method _listStyles
126
     * @return {String} The list of styles in use.
127
     * @private
128
     */
129
    _listStyles: function() {
130
        // Clear the status node.
131
        var list = [],
132
            host = this.get('host'),
133
            current = host.getSelectionParentNode(),
134
            tagname;
135
 
136
        if (current) {
137
            current = Y.one(current);
138
        }
139
 
140
        while (current && (current !== this.editor)) {
141
            tagname = current.get('tagName');
142
            if (typeof tagname !== 'undefined') {
143
                list.push(Y.Escape.html(tagname));
144
            }
145
            current = current.ancestor();
146
        }
147
        if (list.length === 0) {
148
            list.push(M.util.get_string('nostyles', COMPONENT));
149
        }
150
 
151
        list.reverse();
152
 
153
        // Append the list of current styles.
154
        return list.join(', ');
155
    },
156
 
157
    /**
158
     * List the links for the current editor
159
     *
160
     * @method _listLinks
161
     * @return {string}
162
     * @private
163
     */
164
    _listLinks: function() {
165
        var list = Y.Node.create('<ol />'),
166
            listitem,
167
            selectlink;
168
 
169
        this.editor.all('a').each(function(link) {
170
            selectlink = Y.Node.create('<a href="#" title="' +
171
                    M.util.get_string('selectlink', COMPONENT) + '">' +
172
                    Y.Escape.html(link.get('text')) +
173
                    '</a>');
174
 
175
            selectlink.setData('sourcelink', link);
176
            selectlink.on('click', this._linkSelected, this);
177
 
178
            listitem = Y.Node.create('<li></li>');
179
            listitem.appendChild(selectlink);
180
 
181
            list.appendChild(listitem);
182
        }, this);
183
 
184
        if (!list.hasChildNodes()) {
185
            list.append('<li>' + M.util.get_string('nolinks', COMPONENT) + '</li>');
186
        }
187
 
188
        // Append the list of current styles.
189
        return list;
190
    },
191
 
192
    /**
193
     * List the images used in the editor.
194
     *
195
     * @method _listImages
196
     * @return {Node} A Node containing all of the images present in the editor.
197
     * @private
198
     */
199
    _listImages: function() {
200
        var list = Y.Node.create('<ol/>'),
201
            listitem,
202
            selectimage;
203
 
204
        this.editor.all('img').each(function(image) {
205
            // Get the alt or title or img url of the image.
206
            var imgalt = image.getAttribute('alt');
207
            if (imgalt === '') {
208
                imgalt = image.getAttribute('title');
209
                if (imgalt === '') {
210
                    imgalt = image.getAttribute('src');
211
                }
212
            }
213
 
214
            selectimage = Y.Node.create('<a href="#" title="' +
215
                    M.util.get_string('selectimage', COMPONENT) + '">' +
216
                    Y.Escape.html(imgalt) +
217
                    '</a>');
218
 
219
            selectimage.setData('sourceimage', image);
220
            selectimage.on('click', this._imageSelected, this);
221
 
222
            listitem = Y.Node.create('<li></li>');
223
            listitem.append(selectimage);
224
            list.append(listitem);
225
        }, this);
226
        if (!list.hasChildNodes()) {
227
            list.append('<li>' + M.util.get_string('noimages', COMPONENT) + '</li>');
228
        }
229
 
230
        // Append the list of current styles.
231
        return list;
232
    },
233
 
234
    /**
235
     * Event handler for selecting an image.
236
     *
237
     * @method _imageSelected
238
     * @param {EventFacade} e
239
     * @private
240
     */
241
    _imageSelected: function(e) {
242
        e.preventDefault();
243
 
244
        this.getDialogue({
245
            focusAfterNode: null
246
        }).hide();
247
 
248
        var host = this.get('host'),
249
            target = e.target.getData('sourceimage');
250
 
251
        this.editor.focus();
252
        host.setSelection(host.getSelectionFromNode(target));
253
    },
254
 
255
    /**
256
     * Event handler for selecting a link.
257
     *
258
     * @method _linkSelected
259
     * @param {EventFacade} e
260
     * @private
261
     */
262
    _linkSelected: function(e) {
263
        e.preventDefault();
264
 
265
        this.getDialogue({
266
            focusAfterNode: null
267
        }).hide();
268
 
269
        var host = this.get('host'),
270
            target = e.target.getData('sourcelink');
271
 
272
        this.editor.focus();
273
        host.setSelection(host.getSelectionFromNode(target));
274
    }
275
});