Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
YUI.add('moodle-atto_indent-button', function (Y, NAME) {
2
 
3
// This file is part of Moodle - http://moodle.org/
4
//
5
// Moodle is free software: you can redistribute it and/or modify
6
// it under the terms of the GNU General Public License as published by
7
// the Free Software Foundation, either version 3 of the License, or
8
// (at your option) any later version.
9
//
10
// Moodle is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
// GNU General Public License for more details.
14
//
15
// You should have received a copy of the GNU General Public License
16
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17
 
18
/*
19
 * @package    atto_indent
20
 * @copyright  2013 Damyon Wiese  <damyon@moodle.com>
21
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22
 */
23
 
24
/**
25
 * @module     moodle-atto_indent-button
26
 */
27
 
28
/**
29
 * Atto text editor indent plugin.
30
 *
31
 * @namespace M.atto_indent
32
 * @class button
33
 * @extends M.editor_atto.EditorPlugin
34
 */
35
 
36
Y.namespace('M.atto_indent').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], {
37
    initializer: function() {
38
 
39
        this.addButton({
40
            icon: 'e/decrease_indent',
41
            title: 'outdent',
42
            buttonName: 'outdent',
43
            callback: this.outdent
44
        });
45
 
46
        this.addButton({
47
            icon: 'e/increase_indent',
48
            title: 'indent',
49
            buttonName: 'indent',
50
            callback: this.indent
51
        });
52
    },
53
 
54
    /**
55
     * Indents the currently selected content.
56
     *
57
     * @method indent
58
     */
59
    indent: function() {
60
        // Save the current selection - we want to restore this.
61
        var selection = window.rangy.saveSelection(),
62
            blockquotes = this.editor.all('blockquote'),
63
            count = blockquotes.size();
64
 
65
        // Remove display:none from rangy markers so browser doesn't delete them.
66
        this.editor.all('.rangySelectionBoundary').setStyle('display', null);
67
 
68
        // Mark all existing block quotes in case the user has actually added some.
69
        blockquotes.addClass('pre-existing');
70
 
71
        // Run the indent command.
72
        document.execCommand('indent', false, null);
73
 
74
        // Fix indent list item.
75
        this.fixupListItemsAfterIndent();
76
 
77
        // Get all blockquotes, both existing and new.
78
        blockquotes = this.editor.all('blockquote');
79
 
80
        if (blockquotes.size() !== count) {
81
            // There are new block quotes, the indent exec has wrapped some content in block quotes in order
82
            // to indent the selected content.
83
            // We don't want blockquotes, we're going to convert them to divs.
84
            this.replaceBlockquote(this.editor);
85
            // Finally restore the seelction. The content has changed - sometimes this works - but not always :(
86
            window.rangy.restoreSelection(selection);
87
        } else if (blockquotes.size() > 0) {
88
            // There were no new blockquotes, this happens if the user is indenting/outdenting a list.
89
            blockquotes.removeClass('pre-existing');
90
        }
91
 
92
        // Remove the selection markers - a clean up really.
93
        window.rangy.removeMarkers(selection);
94
 
95
        // Mark the text as having been updated.
96
        this.markUpdated();
97
    },
98
 
99
    /**
100
     * Outdents the currently selected content.
101
     *
102
     * @method outdent
103
     */
104
    outdent: function() {
105
        // Save the selection we will want to restore it.
106
        var selection = window.rangy.saveSelection(),
107
            blockquotes = this.editor.all('blockquote'),
108
            count = blockquotes.size();
109
 
110
        // Mark existing blockquotes so that we don't convert them later.
111
        blockquotes.addClass('pre-existing');
112
 
113
        // Replace all div indents with blockquote indents so that we can rely on the browser functionality.
114
        this.replaceEditorIndents(this.editor);
115
 
116
        // Restore the users selection - otherwise the next outdent operation won't work!
117
        window.rangy.restoreSelection(selection);
118
        // And save it once more.
119
        selection = window.rangy.saveSelection();
120
 
121
        // Outdent.
122
        document.execCommand('outdent', false, null);
123
 
124
        // Get all blockquotes so that we can work out what happened.
125
        blockquotes = this.editor.all('blockquote');
126
 
127
        if (blockquotes.size() !== count) {
128
            // The number of blockquotes hasn't changed.
129
            // This occurs when the user has outdented a list item.
130
            this.replaceBlockquote(this.editor);
131
            window.rangy.restoreSelection(selection);
132
        } else if (blockquotes.size() > 0) {
133
            // The number of blockquotes is the same and is more than 0 we just need to clean up the class
134
            // we added to mark pre-existing blockquotes.
135
            blockquotes.removeClass('pre-existing');
136
        }
137
 
138
        // Clean up any left over selection markers.
139
        window.rangy.removeMarkers(selection);
140
 
141
        // Mark the text as having been updated.
142
        this.markUpdated();
143
    },
144
 
145
    /**
146
     * Replaces all blockquotes within an editor with div indents.
147
     * @method replaceBlockquote
148
     * @param Editor editor
149
     */
150
    replaceBlockquote: function(editor) {
151
        editor.all('blockquote').setAttribute('data-iterate', true);
152
        var blockquote = editor.one('blockquote'),
153
            margindir = (Y.one('body.dir-ltr')) ? 'marginLeft' : 'marginRight';
154
        while (blockquote) {
155
            blockquote.removeAttribute('data-iterate');
156
            if (blockquote.hasClass('pre-existing')) {
157
                blockquote.removeClass('pre-existing');
158
            } else {
159
                var clone = Y.Node.create('<div></div>')
160
                        .setAttrs(blockquote.getAttrs())
161
                        .setStyle(margindir, '30px')
162
                        .addClass('editor-indent');
163
                // We use childNodes here because we are interested in both type 1 and 3 child nodes.
164
                var children = blockquote.getDOMNode().childNodes;
165
                var child;
166
                child = children[0];
167
                while (typeof child !== "undefined") {
168
                    clone.append(child);
169
                    child = children[0];
170
                }
171
                blockquote.replace(clone);
172
            }
173
            blockquote = editor.one('blockquote[data-iterate]');
174
        }
175
    },
176
 
177
    /**
178
     * Replaces all div indents with blockquotes.
179
     * @method replaceEditorIndents
180
     * @param Editor editor
181
     */
182
    replaceEditorIndents: function(editor) {
183
        // We use the editor-indent class because it is preserved between saves.
184
        var indent = editor.one('.editor-indent');
185
        while (indent) {
186
            var clone = Y.Node.create('<blockquote></blockquote>')
187
                    .setAttrs(indent
188
                    .getAttrs())
189
                    .removeClass('editor-indent');
190
            // We use childNodes here because we are interested in both type 1 and 3 child nodes.
191
            var children = indent.getDOMNode().childNodes;
192
            var child;
193
            child = children[0];
194
            while (typeof child !== "undefined") {
195
                clone.append(child);
196
                child = children[0];
197
            }
198
            indent.replace(clone);
199
            indent = editor.one('.editor-indent');
200
        }
201
    },
202
    /**
203
     * Fixup for list item after indent.
204
     *
205
     * @method fixupListItemsAfterIndent
206
     */
207
    fixupListItemsAfterIndent: function() {
208
        var selection = window.rangy.getSelection(),
209
            rootelement = this.editor.getDOMNode(),
210
            listelement = selection.anchorNode.parentElement;
211
 
212
        listelement = listelement.closest('ol, ul');
213
        if (!(listelement && rootelement.contains(listelement))) {
214
            return;
215
        }
216
 
217
        // We will move the child list into previous list item of the parent.
218
        var previous = listelement.previousElementSibling;
219
        if (previous && previous.tagName === 'LI') {
220
            previous.appendChild(listelement);
221
            selection.collapseToEnd();
222
        }
223
    }
224
});
225
 
226
 
227
}, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]});