weekly release 4.5dev
[moodle.git] / lib / editor / atto / plugins / indent / yui / build / moodle-atto_indent-button / moodle-atto_indent-button-debug.js
blob72008e298996d9f1dd1d9cf5799fe777c88873bc
1 YUI.add('moodle-atto_indent-button', function (Y, NAME) {
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.
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/>.
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  */
24 /**
25  * @module     moodle-atto_indent-button
26  */
28 /**
29  * Atto text editor indent plugin.
30  *
31  * @namespace M.atto_indent
32  * @class button
33  * @extends M.editor_atto.EditorPlugin
34  */
36 Y.namespace('M.atto_indent').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], {
37     initializer: function() {
39         this.addButton({
40             icon: 'e/decrease_indent',
41             title: 'outdent',
42             buttonName: 'outdent',
43             callback: this.outdent
44         });
46         this.addButton({
47             icon: 'e/increase_indent',
48             title: 'indent',
49             buttonName: 'indent',
50             callback: this.indent
51         });
52     },
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();
65         // Remove display:none from rangy markers so browser doesn't delete them.
66         this.editor.all('.rangySelectionBoundary').setStyle('display', null);
68         // Mark all existing block quotes in case the user has actually added some.
69         blockquotes.addClass('pre-existing');
71         // Run the indent command.
72         document.execCommand('indent', false, null);
74         // Fix indent list item.
75         this.fixupListItemsAfterIndent();
77         // Get all blockquotes, both existing and new.
78         blockquotes = this.editor.all('blockquote');
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         }
92         // Remove the selection markers - a clean up really.
93         window.rangy.removeMarkers(selection);
95         // Mark the text as having been updated.
96         this.markUpdated();
97     },
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();
110         // Mark existing blockquotes so that we don't convert them later.
111         blockquotes.addClass('pre-existing');
113         // Replace all div indents with blockquote indents so that we can rely on the browser functionality.
114         this.replaceEditorIndents(this.editor);
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();
121         // Outdent.
122         document.execCommand('outdent', false, null);
124         // Get all blockquotes so that we can work out what happened.
125         blockquotes = this.editor.all('blockquote');
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         }
138         // Clean up any left over selection markers.
139         window.rangy.removeMarkers(selection);
141         // Mark the text as having been updated.
142         this.markUpdated();
143     },
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     },
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;
212         listelement = listelement.closest('ol, ul');
213         if (!(listelement && rootelement.contains(listelement))) {
214             return;
215         }
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     }
227 }, '@VERSION@', {"requires": ["moodle-editor_atto-plugin"]});