source: sandbox/3.0/phpgwapi/js/ckeditor/_source/plugins/indent/plugin.js @ 2862

Revision 2862, 11.5 KB checked in by rodsouza, 14 years ago (diff)

Ticket #663 - Atualizando e centralizando o CKEditor (v. 3.2.1)

Line 
1/*
2Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.html or http://ckeditor.com/license
4*/
5
6/**
7 * @file Increse and decrease indent commands.
8 */
9
10(function()
11{
12        var listNodeNames = { ol : 1, ul : 1 };
13
14        function setState( editor, state )
15        {
16                editor.getCommand( this.name ).setState( state );
17        }
18
19        function onSelectionChange( evt )
20        {
21                var elements = evt.data.path.elements,
22                        listNode, listItem,
23                        editor = evt.editor;
24
25                for ( var i = 0 ; i < elements.length ; i++ )
26                {
27                        if ( elements[i].getName() == 'li' )
28                        {
29                                listItem = elements[i];
30                                continue;
31                        }
32                        if ( listNodeNames[ elements[i].getName() ] )
33                        {
34                                listNode = elements[i];
35                                break;
36                        }
37                }
38
39                if ( listNode )
40                {
41                        if ( this.name == 'outdent' )
42                                return setState.call( this, editor, CKEDITOR.TRISTATE_OFF );
43                        else
44                        {
45                                while ( listItem && ( listItem = listItem.getPrevious( CKEDITOR.dom.walker.whitespaces( true ) ) ) )
46                                {
47                                        if ( listItem.getName && listItem.getName() == 'li' )
48                                                return setState.call( this, editor, CKEDITOR.TRISTATE_OFF );
49                                }
50                                return setState.call( this, editor, CKEDITOR.TRISTATE_DISABLED );
51                        }
52                }
53
54                if ( !this.useIndentClasses && this.name == 'indent' )
55                        return setState.call( this, editor, CKEDITOR.TRISTATE_OFF );
56
57                var path = evt.data.path,
58                        firstBlock = path.block || path.blockLimit;
59                if ( !firstBlock )
60                        return setState.call( this, editor, CKEDITOR.TRISTATE_DISABLED );
61
62                if ( this.useIndentClasses )
63                {
64                        var indentClass = firstBlock.$.className.match( this.classNameRegex ),
65                                indentStep = 0;
66                        if ( indentClass )
67                        {
68                                indentClass = indentClass[1];
69                                indentStep = this.indentClassMap[ indentClass ];
70                        }
71                        if ( ( this.name == 'outdent' && !indentStep ) ||
72                                        ( this.name == 'indent' && indentStep == editor.config.indentClasses.length ) )
73                                return setState.call( this, editor, CKEDITOR.TRISTATE_DISABLED );
74                        return setState.call( this, editor, CKEDITOR.TRISTATE_OFF );
75                }
76                else
77                {
78                        var indent = parseInt( firstBlock.getStyle( this.indentCssProperty ), 10 );
79                        if ( isNaN( indent ) )
80                                indent = 0;
81                        if ( indent <= 0 )
82                                return setState.call( this, editor, CKEDITOR.TRISTATE_DISABLED );
83                        return setState.call( this, editor, CKEDITOR.TRISTATE_OFF );
84                }
85        }
86
87        function indentList( editor, range, listNode )
88        {
89                // Our starting and ending points of the range might be inside some blocks under a list item...
90                // So before playing with the iterator, we need to expand the block to include the list items.
91                var startContainer = range.startContainer,
92                        endContainer = range.endContainer;
93                while ( startContainer && !startContainer.getParent().equals( listNode ) )
94                        startContainer = startContainer.getParent();
95                while ( endContainer && !endContainer.getParent().equals( listNode ) )
96                        endContainer = endContainer.getParent();
97
98                if ( !startContainer || !endContainer )
99                        return;
100
101                // Now we can iterate over the individual items on the same tree depth.
102                var block = startContainer,
103                        itemsToMove = [],
104                        stopFlag = false;
105                while ( !stopFlag )
106                {
107                        if ( block.equals( endContainer ) )
108                                stopFlag = true;
109                        itemsToMove.push( block );
110                        block = block.getNext();
111                }
112                if ( itemsToMove.length < 1 )
113                        return;
114
115                // Do indent or outdent operations on the array model of the list, not the
116                // list's DOM tree itself. The array model demands that it knows as much as
117                // possible about the surrounding lists, we need to feed it the further
118                // ancestor node that is still a list.
119                var listParents = listNode.getParents( true );
120                for ( var i = 0 ; i < listParents.length ; i++ )
121                {
122                        if ( listParents[i].getName && listNodeNames[ listParents[i].getName() ] )
123                        {
124                                listNode = listParents[i];
125                                break;
126                        }
127                }
128                var indentOffset = this.name == 'indent' ? 1 : -1,
129                        startItem = itemsToMove[0],
130                        lastItem = itemsToMove[ itemsToMove.length - 1 ],
131                        database = {};
132
133                // Convert the list DOM tree into a one dimensional array.
134                var listArray = CKEDITOR.plugins.list.listToArray( listNode, database );
135
136                // Apply indenting or outdenting on the array.
137                var baseIndent = listArray[ lastItem.getCustomData( 'listarray_index' ) ].indent;
138                for ( i = startItem.getCustomData( 'listarray_index' ); i <= lastItem.getCustomData( 'listarray_index' ); i++ )
139                {
140                        listArray[ i ].indent += indentOffset;
141                        // Make sure the newly created sublist get a brand-new element of the same type. (#5372)
142                        var listRoot = listArray[ i ].parent;
143                        listArray[ i ].parent = new CKEDITOR.dom.element( listRoot.getName(), listRoot.getDocument() );
144                }
145
146                for ( i = lastItem.getCustomData( 'listarray_index' ) + 1 ;
147                                i < listArray.length && listArray[i].indent > baseIndent ; i++ )
148                        listArray[i].indent += indentOffset;
149
150                // Convert the array back to a DOM forest (yes we might have a few subtrees now).
151                // And replace the old list with the new forest.
152                var newList = CKEDITOR.plugins.list.arrayToList( listArray, database, null, editor.config.enterMode, 0 );
153
154                // Avoid nested <li> after outdent even they're visually same,
155                // recording them for later refactoring.(#3982)
156                if ( this.name == 'outdent' )
157                {
158                        var parentLiElement;
159                        if ( ( parentLiElement = listNode.getParent() ) && parentLiElement.is( 'li' ) )
160                        {
161                                var children = newList.listNode.getChildren(),
162                                        pendingLis = [],
163                                        count = children.count(),
164                                        child;
165
166                                for ( i = count - 1 ; i >= 0 ; i-- )
167                                {
168                                        if ( ( child = children.getItem( i ) ) && child.is && child.is( 'li' )  )
169                                                pendingLis.push( child );
170                                }
171                        }
172                }
173
174                if ( newList )
175                        newList.listNode.replace( listNode );
176
177                // Move the nested <li> to be appeared after the parent.
178                if ( pendingLis && pendingLis.length )
179                {
180                        for (  i = 0; i < pendingLis.length ; i++ )
181                        {
182                                var li = pendingLis[ i ],
183                                        followingList = li;
184
185                                // Nest preceding <ul>/<ol> inside current <li> if any.
186                                while ( ( followingList = followingList.getNext() ) &&
187                                           followingList.is &&
188                                           followingList.getName() in listNodeNames )
189                                {
190                                        li.append( followingList );
191                                }
192
193                                li.insertAfter( parentLiElement );
194                        }
195                }
196
197                // Clean up the markers.
198                CKEDITOR.dom.element.clearAllMarkers( database );
199        }
200
201        function indentBlock( editor, range )
202        {
203                var iterator = range.createIterator(),
204                        enterMode = editor.config.enterMode;
205                iterator.enforceRealBlocks = true;
206                iterator.enlargeBr = enterMode != CKEDITOR.ENTER_BR;
207                var block;
208                while ( ( block = iterator.getNextParagraph() ) )
209                {
210
211                        if ( this.useIndentClasses )
212                        {
213                                // Transform current class name to indent step index.
214                                var indentClass = block.$.className.match( this.classNameRegex ),
215                                        indentStep = 0;
216                                if ( indentClass )
217                                {
218                                        indentClass = indentClass[1];
219                                        indentStep = this.indentClassMap[ indentClass ];
220                                }
221
222                                // Operate on indent step index, transform indent step index back to class
223                                // name.
224                                if ( this.name == 'outdent' )
225                                        indentStep--;
226                                else
227                                        indentStep++;
228                                indentStep = Math.min( indentStep, editor.config.indentClasses.length );
229                                indentStep = Math.max( indentStep, 0 );
230                                var className = CKEDITOR.tools.ltrim( block.$.className.replace( this.classNameRegex, '' ) );
231                                if ( indentStep < 1 )
232                                        block.$.className = className;
233                                else
234                                        block.$.className = CKEDITOR.tools.ltrim( className + ' ' + editor.config.indentClasses[ indentStep - 1 ] );
235                        }
236                        else
237                        {
238                                var currentOffset = parseInt( block.getStyle( this.indentCssProperty ), 10 );
239                                if ( isNaN( currentOffset ) )
240                                        currentOffset = 0;
241                                currentOffset += ( this.name == 'indent' ? 1 : -1 ) * editor.config.indentOffset;
242                                currentOffset = Math.max( currentOffset, 0 );
243                                currentOffset = Math.ceil( currentOffset / editor.config.indentOffset ) * editor.config.indentOffset;
244                                block.setStyle( this.indentCssProperty, currentOffset ? currentOffset + editor.config.indentUnit : '' );
245                                if ( block.getAttribute( 'style' ) === '' )
246                                        block.removeAttribute( 'style' );
247                        }
248                }
249        }
250
251        function indentCommand( editor, name )
252        {
253                this.name = name;
254                this.useIndentClasses = editor.config.indentClasses && editor.config.indentClasses.length > 0;
255                if ( this.useIndentClasses )
256                {
257                        this.classNameRegex = new RegExp( '(?:^|\\s+)(' + editor.config.indentClasses.join( '|' ) + ')(?=$|\\s)' );
258                        this.indentClassMap = {};
259                        for ( var i = 0 ; i < editor.config.indentClasses.length ; i++ )
260                                this.indentClassMap[ editor.config.indentClasses[i] ] = i + 1;
261                }
262                else
263                        this.indentCssProperty = editor.config.contentsLangDirection == 'ltr' ? 'margin-left' : 'margin-right';
264                this.startDisabled = name == 'outdent';
265        }
266
267        indentCommand.prototype = {
268                exec : function( editor )
269                {
270                        var selection = editor.getSelection(),
271                                range = selection && selection.getRanges()[0];
272
273                        if ( !selection || !range )
274                                return;
275
276                        var bookmarks = selection.createBookmarks( true ),
277                                nearestListBlock = range.getCommonAncestor();
278
279                        while ( nearestListBlock && !( nearestListBlock.type == CKEDITOR.NODE_ELEMENT &&
280                                listNodeNames[ nearestListBlock.getName() ] ) )
281                                nearestListBlock = nearestListBlock.getParent();
282
283                        if ( nearestListBlock )
284                                indentList.call( this, editor, range, nearestListBlock );
285                        else
286                                indentBlock.call( this, editor, range );
287
288                        editor.focus();
289                        editor.forceNextSelectionCheck();
290                        selection.selectBookmarks( bookmarks );
291                }
292        };
293
294        CKEDITOR.plugins.add( 'indent',
295        {
296                init : function( editor )
297                {
298                        // Register commands.
299                        var indent = new indentCommand( editor, 'indent' ),
300                                outdent = new indentCommand( editor, 'outdent' );
301                        editor.addCommand( 'indent', indent );
302                        editor.addCommand( 'outdent', outdent );
303
304                        // Register the toolbar buttons.
305                        editor.ui.addButton( 'Indent',
306                                {
307                                        label : editor.lang.indent,
308                                        command : 'indent'
309                                });
310                        editor.ui.addButton( 'Outdent',
311                                {
312                                        label : editor.lang.outdent,
313                                        command : 'outdent'
314                                });
315
316                        // Register the state changing handlers.
317                        editor.on( 'selectionChange', CKEDITOR.tools.bind( onSelectionChange, indent ) );
318                        editor.on( 'selectionChange', CKEDITOR.tools.bind( onSelectionChange, outdent ) );
319                },
320
321                requires : [ 'domiterator', 'list' ]
322        } );
323})();
324
325CKEDITOR.tools.extend( CKEDITOR.config,
326        {
327                indentOffset : 40,
328                indentUnit : 'px',
329                indentClasses : null
330        });
331
332/**
333 * Size of each indentation step
334 * @type Number
335 * @example
336 * config.indentOffset = 40;
337 */
338
339 /**
340 * Unit for the indentation style
341 * @type String
342 * @example
343 * config.indentUnit = 'px';
344 */
345
346 /**
347 * List of classes to use for indenting the contents.
348 * @type Array
349 * @example
350 * // Don't use classes for indenting. (this is the default value)
351 * config.indentClasses = null;
352 * @example
353 * // Use the classes 'Indent1', 'Indent2', 'Indent3'
354 * config.indentClasses = ['Indent1', 'Indent2', 'Indent3'];
355 */
356
357/**
358 * Size of each indentation step
359 * @type Number
360 * @default 40
361 * @example
362 * config.indentOffset = 4;
363 */
364
365 /**
366 * Unit for the indentation style
367 * @type String
368 * @default 'px'
369 * @example
370 * config.indentUnit = 'em';
371 */
372
373 /**
374 * List of classes to use for indenting the contents. If it's null, no classes will be used
375 * and instead the {@link #indentUnit} and {@link #indentOffset} properties will be used.
376 * @type Array
377 * default null
378 * @example
379 * // Use the classes 'Indent1', 'Indent2', 'Indent3'
380 * config.indentClasses = ['Indent1', 'Indent2', 'Indent3'];
381 */
Note: See TracBrowser for help on using the repository browser.