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
 * @module moodle-editor_atto-editor
18
 * @submodule commands
19
 */
20
 
21
/**
22
 * Selection functions for the Atto editor.
23
 *
24
 * See {{#crossLink "M.editor_atto.Editor"}}{{/crossLink}} for details.
25
 *
26
 * @namespace M.editor_atto
27
 * @class EditorCommand
28
 */
29
 
30
function EditorCommand() {}
31
 
32
EditorCommand.ATTRS = {
33
};
34
 
35
EditorCommand.prototype = {
36
    /**
37
     * Applies a callback method to editor if selection is uncollapsed or waits for input to select first.
38
     * @method applyFormat
39
     * @param e EventTarget Event to be passed to callback if selection is uncollapsed
40
     * @param method callback A callback method which changes editor when text is selected.
41
     * @param object context Context to be used for callback method
42
     * @param array args Array of arguments to pass to callback
43
     */
44
    applyFormat: function(e, callback, context, args) {
45
        function handleInsert(e, callback, context, args, anchorNode, anchorOffset) {
46
            // After something is inputed, select it and apply the formating function.
47
            Y.soon(Y.bind(function(e, callback, context, args, anchorNode, anchorOffset) {
48
                var selection = window.rangy.getSelection();
49
 
50
                // Set the start of the selection to where it was when the method was first called.
51
                var range = selection.getRangeAt(0);
52
                range.setStart(anchorNode, anchorOffset);
53
                selection.setSingleRange(range);
54
 
55
                // Now apply callback to the new text that is selected.
56
                callback.apply(context, [e, args]);
57
 
58
                // Collapse selection so cursor is at end of inserted material.
59
                selection.collapseToEnd();
60
 
61
                // Save save selection and editor contents.
62
                this.saveSelection();
63
                this.updateOriginal();
64
            }, this, e, callback, context, args, anchorNode, anchorOffset));
65
        }
66
 
67
        // Set default context for the method.
68
        context = context || this;
69
 
70
        // Check whether range is collapsed.
71
        var selection = window.rangy.getSelection();
72
 
73
        if (selection.isCollapsed) {
74
            // Selection is collapsed so listen for input into editor.
75
            var handle = this.editor.once('input', handleInsert, this, callback, context, args,
76
                    selection.anchorNode, selection.anchorOffset);
77
 
78
            // Cancel if selection changes before input.
79
            this.editor.onceAfter(['click', 'selectstart'], handle.detach, handle);
80
 
81
            return;
82
        }
83
 
84
        // The range is not collapsed; so apply callback method immediately.
85
        callback.apply(context, [e, args]);
86
 
87
        // Save save selection and editor contents.
88
        this.saveSelection();
89
        this.updateOriginal();
90
    },
91
 
92
    /**
93
     * Replaces all the tags in a node list with new type.
94
     * @method replaceTags
95
     * @param NodeList nodelist
96
     * @param String tag
97
     */
98
    replaceTags: function(nodelist, tag) {
99
        // We mark elements in the node list for iterations.
100
        nodelist.setAttribute('data-iterate', true);
101
        var node = this.editor.one('[data-iterate="true"]');
102
        while (node) {
103
            var clone = Y.Node.create('<' + tag + ' />')
104
                .setAttrs(node.getAttrs())
105
                .removeAttribute('data-iterate');
106
            // Copy class and style if not blank.
107
            if (node.getAttribute('style')) {
108
                clone.setAttribute('style', node.getAttribute('style'));
109
            }
110
            if (node.getAttribute('class')) {
111
                clone.setAttribute('class', node.getAttribute('class'));
112
            }
113
            // We use childNodes here because we are interested in both type 1 and 3 child nodes.
114
            var children = node.getDOMNode().childNodes;
115
            var child;
116
            child = children[0];
117
            while (typeof child !== "undefined") {
118
                clone.append(child);
119
                child = children[0];
120
            }
121
            node.replace(clone);
122
            node = this.editor.one('[data-iterate="true"]');
123
        }
124
    },
125
 
126
    /**
127
     * Change all tags with given type to a span with CSS class attribute.
128
     * @method changeToCSS
129
     * @param String tag Tag type to be changed to span
130
     * @param String markerClass CSS class that corresponds to desired tag
131
     */
132
    changeToCSS: function(tag, markerClass) {
133
        // Save the selection.
134
        var selection = window.rangy.saveSelection();
135
 
136
        // Remove display:none from rangy markers so browser doesn't delete them.
137
        this.editor.all('.rangySelectionBoundary').setStyle('display', null);
138
 
139
        // Replace tags with CSS classes.
140
        this.editor.all(tag).addClass(markerClass);
141
        this.replaceTags(this.editor.all('.' + markerClass), 'span');
142
 
143
        // Restore selection and toggle class.
144
        window.rangy.restoreSelection(selection);
145
    },
146
 
147
    /**
148
     * Change spans with CSS classes in editor into elements with given tag.
149
     * @method changeToCSS
150
     * @param String markerClass CSS class that corresponds to desired tag
151
     * @param String tag New tag type to be created
152
     */
153
    changeToTags: function(markerClass, tag) {
154
        // Save the selection.
155
        var selection = window.rangy.saveSelection();
156
 
157
        // Remove display:none from rangy markers so browser doesn't delete them.
158
        this.editor.all('.rangySelectionBoundary').setStyle('display', null);
159
 
160
        // Replace spans with given tag.
161
        this.replaceTags(this.editor.all('span[class="' + markerClass + '"]'), tag);
162
        this.editor.all(tag + '[class="' + markerClass + '"]').removeAttribute('class');
163
        this.editor.all('.' + markerClass).each(function(n) {
164
            n.wrap('<' + tag + '/>');
165
            n.removeClass(markerClass);
166
        });
167
 
168
        // Remove CSS classes.
169
        this.editor.all('[class="' + markerClass + '"]').removeAttribute('class');
170
        this.editor.all(tag).removeClass(markerClass);
171
 
172
        // Restore selection.
173
        window.rangy.restoreSelection(selection);
174
    }
175
};
176
 
177
Y.Base.mix(Y.M.editor_atto.Editor, [EditorCommand]);