source: trunk/filemanager/tp/ckeditor/_source/plugins/selection/plugin.js @ 2000

Revision 2000, 28.8 KB checked in by amuller, 14 years ago (diff)

Ticket #597 - Implementação do módulo gerenciador de arquivos

Line 
1/*
2Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.html or http://ckeditor.com/license
4*/
5
6(function()
7{
8        // #### checkSelectionChange : START
9
10        // The selection change check basically saves the element parent tree of
11        // the current node and check it on successive requests. If there is any
12        // change on the tree, then the selectionChange event gets fired.
13        function checkSelectionChange()
14        {
15                try
16                {
17                        // In IE, the "selectionchange" event may still get thrown when
18                        // releasing the WYSIWYG mode, so we need to check it first.
19                        var sel = this.getSelection();
20                        if ( !sel )
21                                return;
22
23                        var firstElement = sel.getStartElement();
24                        var currentPath = new CKEDITOR.dom.elementPath( firstElement );
25
26                        if ( !currentPath.compare( this._.selectionPreviousPath ) )
27                        {
28                                this._.selectionPreviousPath = currentPath;
29                                this.fire( 'selectionChange', { selection : sel, path : currentPath, element : firstElement } );
30                        }
31                }
32                catch (e)
33                {}
34        }
35
36        var checkSelectionChangeTimer,
37                checkSelectionChangeTimeoutPending;
38
39        function checkSelectionChangeTimeout()
40        {
41                // Firing the "OnSelectionChange" event on every key press started to
42                // be too slow. This function guarantees that there will be at least
43                // 200ms delay between selection checks.
44
45                checkSelectionChangeTimeoutPending = true;
46
47                if ( checkSelectionChangeTimer )
48                        return;
49
50                checkSelectionChangeTimeoutExec.call( this );
51
52                checkSelectionChangeTimer = CKEDITOR.tools.setTimeout( checkSelectionChangeTimeoutExec, 200, this );
53        }
54
55        function checkSelectionChangeTimeoutExec()
56        {
57                checkSelectionChangeTimer = null;
58
59                if ( checkSelectionChangeTimeoutPending )
60                {
61                        // Call this with a timeout so the browser properly moves the
62                        // selection after the mouseup. It happened that the selection was
63                        // being moved after the mouseup when clicking inside selected text
64                        // with Firefox.
65                        CKEDITOR.tools.setTimeout( checkSelectionChange, 0, this );
66
67                        checkSelectionChangeTimeoutPending = false;
68                }
69        }
70
71        // #### checkSelectionChange : END
72
73        var selectAllCmd =
74        {
75                exec : function( editor )
76                {
77                        switch ( editor.mode )
78                        {
79                                case 'wysiwyg' :
80                                        editor.document.$.execCommand( 'SelectAll', false, null );
81                                        break;
82                                case 'source' :
83                                        // TODO
84                        }
85                },
86                canUndo : false
87        };
88
89        CKEDITOR.plugins.add( 'selection',
90        {
91                init : function( editor )
92                {
93                        editor.on( 'contentDom', function()
94                                {
95                                        var doc = editor.document;
96
97                                        if ( CKEDITOR.env.ie )
98                                        {
99                                                // Other browsers don't loose the selection if the
100                                                // editor document loose the focus. In IE, we don't
101                                                // have support for it, so we reproduce it here, other
102                                                // than firing the selection change event.
103
104                                                var savedRange,
105                                                        saveEnabled;
106
107                                                // "onfocusin" is fired before "onfocus". It makes it
108                                                // possible to restore the selection before click
109                                                // events get executed.
110                                                doc.on( 'focusin', function()
111                                                        {
112                                                                // If we have saved a range, restore it at this
113                                                                // point.
114                                                                if ( savedRange )
115                                                                {
116                                                                        // Well not break because of this.
117                                                                        try
118                                                                        {
119                                                                                savedRange.select();
120                                                                        }
121                                                                        catch (e)
122                                                                        {}
123
124                                                                        savedRange = null;
125                                                                }
126                                                        });
127
128                                                editor.window.on( 'focus', function()
129                                                        {
130                                                                // Enable selections to be saved.
131                                                                saveEnabled = true;
132
133                                                                saveSelection();
134                                                        });
135
136                                                // Check document selection before 'blur' fired, this
137                                                // will prevent us from breaking text selection somewhere
138                                                // else on the host page.(#3909)
139                                                editor.document.on( 'beforedeactivate', function()
140                                                        {
141                                                                // Disable selections from being saved.
142                                                                saveEnabled = false;
143
144                                                                // IE may leave the selection still inside the
145                                                                // document. Let's force it to be removed.
146                                                                // TODO: The following has effect for
147                                                                // collapsed selections.
148                                                                editor.document.$.execCommand( 'Unselect' );
149                                                        });
150
151                                                // IE fires the "selectionchange" event when clicking
152                                                // inside a selection. We don't want to capture that.
153                                                doc.on( 'mousedown', disableSave );
154                                                doc.on( 'mouseup',
155                                                        function()
156                                                        {
157                                                                saveEnabled = true;
158                                                                setTimeout( function()
159                                                                        {
160                                                                                saveSelection( true );
161                                                                        },
162                                                                        0 );
163                                                        });
164
165                                                doc.on( 'keydown', disableSave );
166                                                doc.on( 'keyup',
167                                                        function()
168                                                        {
169                                                                saveEnabled = true;
170                                                                saveSelection();
171                                                        });
172
173
174                                                // IE is the only to provide the "selectionchange"
175                                                // event.
176                                                doc.on( 'selectionchange', saveSelection );
177
178                                                function disableSave()
179                                                {
180                                                        saveEnabled = false;
181                                                }
182
183                                                function saveSelection( testIt )
184                                                {
185                                                        if ( saveEnabled )
186                                                        {
187                                                                var doc = editor.document,
188                                                                        sel = doc && doc.$.selection;
189
190                                                                // There is a very specific case, when clicking
191                                                                // inside a text selection. In that case, the
192                                                                // selection collapses at the clicking point,
193                                                                // but the selection object remains in an
194                                                                // unknown state, making createRange return a
195                                                                // range at the very start of the document. In
196                                                                // such situation we have to test the range, to
197                                                                // be sure it's valid.
198                                                                if ( testIt && sel && sel.type == 'None' )
199                                                                {
200                                                                        // The "InsertImage" command can be used to
201                                                                        // test whether the selection is good or not.
202                                                                        // If not, it's enough to give some time to
203                                                                        // IE to put things in order for us.
204                                                                        if ( !doc.$.queryCommandEnabled( 'InsertImage' ) )
205                                                                        {
206                                                                                CKEDITOR.tools.setTimeout( saveSelection, 50, this, true );
207                                                                                return;
208                                                                        }
209                                                                }
210
211                                                                savedRange = sel && sel.createRange();
212
213                                                                checkSelectionChangeTimeout.call( editor );
214                                                        }
215                                                }
216                                        }
217                                        else
218                                        {
219                                                // In other browsers, we make the selection change
220                                                // check based on other events, like clicks or keys
221                                                // press.
222
223                                                doc.on( 'mouseup', checkSelectionChangeTimeout, editor );
224                                                doc.on( 'keyup', checkSelectionChangeTimeout, editor );
225                                        }
226                                });
227
228                        editor.addCommand( 'selectAll', selectAllCmd );
229                        editor.ui.addButton( 'SelectAll',
230                                {
231                                        label : editor.lang.selectAll,
232                                        command : 'selectAll'
233                                });
234
235                        editor.selectionChange = checkSelectionChangeTimeout;
236                }
237        });
238
239        /**
240         * Gets the current selection from the editing area when in WYSIWYG mode.
241         * @returns {CKEDITOR.dom.selection} A selection object or null if not on
242         *              WYSIWYG mode or no selection is available.
243         * @example
244         * var selection = CKEDITOR.instances.editor1.<b>getSelection()</b>;
245         * alert( selection.getType() );
246         */
247        CKEDITOR.editor.prototype.getSelection = function()
248        {
249                return this.document && this.document.getSelection();
250        };
251
252        CKEDITOR.editor.prototype.forceNextSelectionCheck = function()
253        {
254                delete this._.selectionPreviousPath;
255        };
256
257        /**
258         * Gets the current selection from the document.
259         * @returns {CKEDITOR.dom.selection} A selection object.
260         * @example
261         * var selection = CKEDITOR.instances.editor1.document.<b>getSelection()</b>;
262         * alert( selection.getType() );
263         */
264        CKEDITOR.dom.document.prototype.getSelection = function()
265        {
266                var sel = new CKEDITOR.dom.selection( this );
267                return ( !sel || sel.isInvalid ) ? null : sel;
268        };
269
270        /**
271         * No selection.
272         * @constant
273         * @example
274         * if ( editor.getSelection().getType() == CKEDITOR.SELECTION_NONE )
275         *     alert( 'Nothing is selected' );
276         */
277        CKEDITOR.SELECTION_NONE         = 1;
278
279        /**
280         * Text or collapsed selection.
281         * @constant
282         * @example
283         * if ( editor.getSelection().getType() == CKEDITOR.SELECTION_TEXT )
284         *     alert( 'Text is selected' );
285         */
286        CKEDITOR.SELECTION_TEXT         = 2;
287
288        /**
289         * Element selection.
290         * @constant
291         * @example
292         * if ( editor.getSelection().getType() == CKEDITOR.SELECTION_ELEMENT )
293         *     alert( 'An element is selected' );
294         */
295        CKEDITOR.SELECTION_ELEMENT      = 3;
296
297        /**
298         * Manipulates the selection in a DOM document.
299         * @constructor
300         * @example
301         */
302        CKEDITOR.dom.selection = function( document )
303        {
304                var lockedSelection = document.getCustomData( 'cke_locked_selection' );
305
306                if ( lockedSelection )
307                        return lockedSelection;
308
309                this.document = document;
310                this.isLocked = false;
311                this._ =
312                {
313                        cache : {}
314                };
315
316                /**
317                 * IE BUG: The selection's document may be a different document than the
318                 * editor document. Return null if that's the case.
319                 */
320                if ( CKEDITOR.env.ie )
321                {
322                        var range = this.getNative().createRange();
323                        if ( !range
324                                || ( range.item && range.item(0).ownerDocument != this.document.$ )
325                                || ( range.parentElement && range.parentElement().ownerDocument != this.document.$ ) )
326                        {
327                                this.isInvalid = true;
328                        }
329                }
330
331                return this;
332        };
333
334        var styleObjectElements =
335        {
336                img:1,hr:1,li:1,table:1,tr:1,td:1,embed:1,object:1,ol:1,ul:1,
337                a:1, input:1, form:1, select:1, textarea:1, button:1, fieldset:1, th:1, thead:1, tfoot:1
338        };
339
340        CKEDITOR.dom.selection.prototype =
341        {
342                /**
343                 * Gets the native selection object from the browser.
344                 * @function
345                 * @returns {Object} The native selection object.
346                 * @example
347                 * var selection = editor.getSelection().<b>getNative()</b>;
348                 */
349                getNative :
350                        CKEDITOR.env.ie ?
351                                function()
352                                {
353                                        return this._.cache.nativeSel || ( this._.cache.nativeSel = this.document.$.selection );
354                                }
355                        :
356                                function()
357                                {
358                                        return this._.cache.nativeSel || ( this._.cache.nativeSel = this.document.getWindow().$.getSelection() );
359                                },
360
361                /**
362                 * Gets the type of the current selection. The following values are
363                 * available:
364                 * <ul>
365                 *              <li>{@link CKEDITOR.SELECTION_NONE} (1): No selection.</li>
366                 *              <li>{@link CKEDITOR.SELECTION_TEXT} (2): Text is selected or
367                 *                      collapsed selection.</li>
368                 *              <li>{@link CKEDITOR.SELECTION_ELEMENT} (3): A element
369                 *                      selection.</li>
370                 * </ul>
371                 * @function
372                 * @returns {Number} One of the following constant values:
373                 *              {@link CKEDITOR.SELECTION_NONE}, {@link CKEDITOR.SELECTION_TEXT} or
374                 *              {@link CKEDITOR.SELECTION_ELEMENT}.
375                 * @example
376                 * if ( editor.getSelection().<b>getType()</b> == CKEDITOR.SELECTION_TEXT )
377                 *     alert( 'Text is selected' );
378                 */
379                getType :
380                        CKEDITOR.env.ie ?
381                                function()
382                                {
383                                        var cache = this._.cache;
384                                        if ( cache.type )
385                                                return cache.type;
386
387                                        var type = CKEDITOR.SELECTION_NONE;
388
389                                        try
390                                        {
391                                                var sel = this.getNative(),
392                                                        ieType = sel.type;
393
394                                                if ( ieType == 'Text' )
395                                                        type = CKEDITOR.SELECTION_TEXT;
396
397                                                if ( ieType == 'Control' )
398                                                        type = CKEDITOR.SELECTION_ELEMENT;
399
400                                                // It is possible that we can still get a text range
401                                                // object even when type == 'None' is returned by IE.
402                                                // So we'd better check the object returned by
403                                                // createRange() rather than by looking at the type.
404                                                if ( sel.createRange().parentElement )
405                                                        type = CKEDITOR.SELECTION_TEXT;
406                                        }
407                                        catch(e) {}
408
409                                        return ( cache.type = type );
410                                }
411                        :
412                                function()
413                                {
414                                        var cache = this._.cache;
415                                        if ( cache.type )
416                                                return cache.type;
417
418                                        var type = CKEDITOR.SELECTION_TEXT;
419
420                                        var sel = this.getNative();
421
422                                        if ( !sel )
423                                                type = CKEDITOR.SELECTION_NONE;
424                                        else if ( sel.rangeCount == 1 )
425                                        {
426                                                // Check if the actual selection is a control (IMG,
427                                                // TABLE, HR, etc...).
428
429                                                var range = sel.getRangeAt(0),
430                                                        startContainer = range.startContainer;
431
432                                                if ( startContainer == range.endContainer
433                                                        && startContainer.nodeType == 1
434                                                        && ( range.endOffset - range.startOffset ) == 1
435                                                        && styleObjectElements[ startContainer.childNodes[ range.startOffset ].nodeName.toLowerCase() ] )
436                                                {
437                                                        type = CKEDITOR.SELECTION_ELEMENT;
438                                                }
439                                        }
440
441                                        return ( cache.type = type );
442                                },
443
444                getRanges :
445                        CKEDITOR.env.ie ?
446                                ( function()
447                                {
448                                        // Finds the container and offset for a specific boundary
449                                        // of an IE range.
450                                        var getBoundaryInformation = function( range, start )
451                                        {
452                                                // Creates a collapsed range at the requested boundary.
453                                                range = range.duplicate();
454                                                range.collapse( start );
455
456                                                // Gets the element that encloses the range entirely.
457                                                var parent = range.parentElement();
458                                                var siblings = parent.childNodes;
459
460                                                var testRange;
461
462                                                for ( var i = 0 ; i < siblings.length ; i++ )
463                                                {
464                                                        var child = siblings[ i ];
465                                                        if ( child.nodeType == 1 )
466                                                        {
467                                                                testRange = range.duplicate();
468
469                                                                testRange.moveToElementText( child );
470                                                                testRange.collapse();
471
472                                                                var comparison = testRange.compareEndPoints( 'StartToStart', range );
473
474                                                                if ( comparison > 0 )
475                                                                        break;
476                                                                else if ( comparison === 0 )
477                                                                        return {
478                                                                                container : parent,
479                                                                                offset : i
480                                                                        };
481
482                                                                testRange = null;
483                                                        }
484                                                }
485
486                                                if ( !testRange )
487                                                {
488                                                        testRange = range.duplicate();
489                                                        testRange.moveToElementText( parent );
490                                                        testRange.collapse( false );
491                                                }
492
493                                                testRange.setEndPoint( 'StartToStart', range );
494                                                // IE report line break as CRLF with range.text but
495                                                // only LF with textnode.nodeValue, normalize them to avoid
496                                                // breaking character counting logic below. (#3949)
497                                                var distance = testRange.text.replace( /(\r\n|\r)/g, '\n' ).length;
498
499                                                while ( distance > 0 )
500                                                        distance -= siblings[ --i ].nodeValue.length;
501
502                                                if ( distance === 0 )
503                                                {
504                                                        return {
505                                                                container : parent,
506                                                                offset : i
507                                                        };
508                                                }
509                                                else
510                                                {
511                                                        return {
512                                                                container : siblings[ i ],
513                                                                offset : -distance
514                                                        };
515                                                }
516                                        };
517
518                                        return function()
519                                        {
520                                                var cache = this._.cache;
521                                                if ( cache.ranges )
522                                                        return cache.ranges;
523
524                                                // IE doesn't have range support (in the W3C way), so we
525                                                // need to do some magic to transform selections into
526                                                // CKEDITOR.dom.range instances.
527
528                                                var sel = this.getNative(),
529                                                        nativeRange = sel && sel.createRange(),
530                                                        type = this.getType(),
531                                                        range;
532
533                                                if ( !sel )
534                                                        return [];
535
536                                                if ( type == CKEDITOR.SELECTION_TEXT )
537                                                {
538                                                        range = new CKEDITOR.dom.range( this.document );
539
540                                                        var boundaryInfo = getBoundaryInformation( nativeRange, true );
541                                                        range.setStart( new CKEDITOR.dom.node( boundaryInfo.container ), boundaryInfo.offset );
542
543                                                        boundaryInfo = getBoundaryInformation( nativeRange );
544                                                        range.setEnd( new CKEDITOR.dom.node( boundaryInfo.container ), boundaryInfo.offset );
545
546                                                        return ( cache.ranges = [ range ] );
547                                                }
548                                                else if ( type == CKEDITOR.SELECTION_ELEMENT )
549                                                {
550                                                        var retval = this._.cache.ranges = [];
551
552                                                        for ( var i = 0 ; i < nativeRange.length ; i++ )
553                                                        {
554                                                                var element = nativeRange.item( i ),
555                                                                        parentElement = element.parentNode,
556                                                                        j = 0;
557
558                                                                range = new CKEDITOR.dom.range( this.document );
559
560                                                                for (; j < parentElement.childNodes.length && parentElement.childNodes[j] != element ; j++ )
561                                                                { /*jsl:pass*/ }
562
563                                                                range.setStart( new CKEDITOR.dom.node( parentElement ), j );
564                                                                range.setEnd( new CKEDITOR.dom.node( parentElement ), j + 1 );
565                                                                retval.push( range );
566                                                        }
567
568                                                        return retval;
569                                                }
570
571                                                return ( cache.ranges = [] );
572                                        };
573                                })()
574                        :
575                                function()
576                                {
577                                        var cache = this._.cache;
578                                        if ( cache.ranges )
579                                                return cache.ranges;
580
581                                        // On browsers implementing the W3C range, we simply
582                                        // tranform the native ranges in CKEDITOR.dom.range
583                                        // instances.
584
585                                        var ranges = [];
586                                        var sel = this.getNative();
587
588                                        if ( !sel )
589                                                return [];
590
591                                        for ( var i = 0 ; i < sel.rangeCount ; i++ )
592                                        {
593                                                var nativeRange = sel.getRangeAt( i );
594                                                var range = new CKEDITOR.dom.range( this.document );
595
596                                                range.setStart( new CKEDITOR.dom.node( nativeRange.startContainer ), nativeRange.startOffset );
597                                                range.setEnd( new CKEDITOR.dom.node( nativeRange.endContainer ), nativeRange.endOffset );
598                                                ranges.push( range );
599                                        }
600
601                                        return ( cache.ranges = ranges );
602                                },
603
604                /**
605                 * Gets the DOM element in which the selection starts.
606                 * @returns {CKEDITOR.dom.element} The element at the beginning of the
607                 *              selection.
608                 * @example
609                 * var element = editor.getSelection().<b>getStartElement()</b>;
610                 * alert( element.getName() );
611                 */
612                getStartElement : function()
613                {
614                        var cache = this._.cache;
615                        if ( cache.startElement !== undefined )
616                                return cache.startElement;
617
618                        var node,
619                                sel = this.getNative();
620
621                        switch ( this.getType() )
622                        {
623                                case CKEDITOR.SELECTION_ELEMENT :
624                                        return this.getSelectedElement();
625
626                                case CKEDITOR.SELECTION_TEXT :
627
628                                        var range = this.getRanges()[0];
629
630                                        if ( range )
631                                        {
632                                                if ( !range.collapsed )
633                                                {
634                                                        range.optimize();
635
636                                                        // Decrease the range content to exclude particial
637                                                        // selected node on the start which doesn't have
638                                                        // visual impact. ( #3231 )
639                                                        while( true )
640                                                        {
641                                                                var startContainer = range.startContainer,
642                                                                        startOffset = range.startOffset;
643                                                                if ( startOffset == ( startContainer.getChildCount ?
644                                                                        startContainer.getChildCount() : startContainer.getLength() ) )
645                                                                        range.setStartAfter( startContainer );
646                                                                else break;
647                                                        }
648
649                                                        node = range.startContainer;
650
651                                                        if ( node.type != CKEDITOR.NODE_ELEMENT )
652                                                                return node.getParent();
653
654                                                        node = node.getChild( range.startOffset );
655
656                                                        if ( !node || node.type != CKEDITOR.NODE_ELEMENT )
657                                                                return range.startContainer;
658
659                                                        var child = node.getFirst();
660                                                        while (  child && child.type == CKEDITOR.NODE_ELEMENT )
661                                                        {
662                                                                node = child;
663                                                                child = child.getFirst();
664                                                        }
665
666                                                        return node;
667                                                }
668                                        }
669
670                                        if ( CKEDITOR.env.ie )
671                                        {
672                                                range = sel.createRange();
673                                                range.collapse( true );
674
675                                                node = range.parentElement();
676                                        }
677                                        else
678                                        {
679                                                node = sel.anchorNode;
680
681                                                if ( node && node.nodeType != 1 )
682                                                        node = node.parentNode;
683                                        }
684                        }
685
686                        return cache.startElement = ( node ? new CKEDITOR.dom.element( node ) : null );
687                },
688
689                /**
690                 * Gets the current selected element.
691                 * @returns {CKEDITOR.dom.element} The selected element. Null if no
692                 *              selection is available or the selection type is not
693                 *              {@link CKEDITOR.SELECTION_ELEMENT}.
694                 * @example
695                 * var element = editor.getSelection().<b>getSelectedElement()</b>;
696                 * alert( element.getName() );
697                 */
698                getSelectedElement : function()
699                {
700                        var cache = this._.cache;
701                        if ( cache.selectedElement !== undefined )
702                                return cache.selectedElement;
703
704                        var node;
705
706                        if ( this.getType() == CKEDITOR.SELECTION_ELEMENT )
707                        {
708                                var sel = this.getNative();
709
710                                if ( CKEDITOR.env.ie )
711                                {
712                                        try
713                                        {
714                                                node = sel.createRange().item(0);
715                                        }
716                                        catch(e) {}
717                                }
718                                else
719                                {
720                                        var range = sel.getRangeAt( 0 );
721                                        node = range.startContainer.childNodes[ range.startOffset ];
722                                }
723                        }
724
725                        return cache.selectedElement = ( node ? new CKEDITOR.dom.element( node ) : null );
726                },
727
728                lock : function()
729                {
730                        // Call all cacheable function.
731                        this.getRanges();
732                        this.getStartElement();
733                        this.getSelectedElement();
734
735                        // The native selection is not available when locked.
736                        this._.cache.nativeSel = {};
737
738                        this.isLocked = true;
739
740                        // Save this selection inside the DOM document.
741                        this.document.setCustomData( 'cke_locked_selection', this );
742                },
743
744                unlock : function( restore )
745                {
746                        var doc = this.document,
747                                lockedSelection = doc.getCustomData( 'cke_locked_selection' );
748
749                        if ( lockedSelection )
750                        {
751                                doc.setCustomData( 'cke_locked_selection', null );
752
753                                if ( restore )
754                                {
755                                        var selectedElement = lockedSelection.getSelectedElement(),
756                                                ranges = !selectedElement && lockedSelection.getRanges();
757
758                                        this.isLocked = false;
759                                        this.reset();
760
761                                        doc.getBody().focus();
762
763                                        if ( selectedElement )
764                                                this.selectElement( selectedElement );
765                                        else
766                                                this.selectRanges( ranges );
767                                }
768                        }
769
770                        if  ( !lockedSelection || !restore )
771                        {
772                                this.isLocked = false;
773                                this.reset();
774                        }
775                },
776
777                reset : function()
778                {
779                        this._.cache = {};
780                },
781
782                selectElement : function( element )
783                {
784                        if ( this.isLocked )
785                        {
786                                var range = new CKEDITOR.dom.range( this.document );
787                                range.setStartBefore( element );
788                                range.setEndAfter( element );
789
790                                this._.cache.selectedElement = element;
791                                this._.cache.startElement = element;
792                                this._.cache.ranges = [ range ];
793                                this._.cache.type = CKEDITOR.SELECTION_ELEMENT;
794
795                                return;
796                        }
797
798                        if ( CKEDITOR.env.ie )
799                        {
800                                this.getNative().empty();
801
802                                try
803                                {
804                                        // Try to select the node as a control.
805                                        range = this.document.$.body.createControlRange();
806                                        range.addElement( element.$ );
807                                        range.select();
808                                }
809                                catch(e)
810                                {
811                                        // If failed, select it as a text range.
812                                        range = this.document.$.body.createTextRange();
813                                        range.moveToElementText( element.$ );
814                                        range.select();
815                                }
816
817                                this.reset();
818                        }
819                        else
820                        {
821                                // Create the range for the element.
822                                range = this.document.$.createRange();
823                                range.selectNode( element.$ );
824
825                                // Select the range.
826                                var sel = this.getNative();
827                                sel.removeAllRanges();
828                                sel.addRange( range );
829
830                                this.reset();
831                        }
832                },
833
834                selectRanges : function( ranges )
835                {
836                        if ( this.isLocked )
837                        {
838                                this._.cache.selectedElement = null;
839                                this._.cache.startElement = ranges[ 0 ].getTouchedStartNode();
840                                this._.cache.ranges = ranges;
841                                this._.cache.type = CKEDITOR.SELECTION_TEXT;
842
843                                return;
844                        }
845
846                        if ( CKEDITOR.env.ie )
847                        {
848                                // IE doesn't accept multiple ranges selection, so we just
849                                // select the first one.
850                                if ( ranges[ 0 ] )
851                                        ranges[ 0 ].select();
852
853                                this.reset();
854                        }
855                        else
856                        {
857                                var sel = this.getNative();
858                                sel.removeAllRanges();
859
860                                for ( var i = 0 ; i < ranges.length ; i++ )
861                                {
862                                        var range = ranges[ i ];
863                                        var nativeRange = this.document.$.createRange();
864                                        var startContainer = range.startContainer;
865
866                                        // In FF2, if we have a collapsed range, inside an empty
867                                        // element, we must add something to it otherwise the caret
868                                        // will not be visible.
869                                        if ( range.collapsed &&
870                                                ( CKEDITOR.env.gecko && CKEDITOR.env.version < 10900 ) &&
871                                                startContainer.type == CKEDITOR.NODE_ELEMENT &&
872                                                !startContainer.getChildCount() )
873                                        {
874                                                startContainer.appendText( '' );
875                                        }
876
877                                        nativeRange.setStart( startContainer.$, range.startOffset );
878                                        nativeRange.setEnd( range.endContainer.$, range.endOffset );
879
880                                        // Select the range.
881                                        sel.addRange( nativeRange );
882                                }
883
884                                this.reset();
885                        }
886                },
887
888                createBookmarks : function( serializable )
889                {
890                        var retval = [],
891                                ranges = this.getRanges(),
892                                length = ranges.length,
893                                bookmark;
894                        for ( var i = 0; i < length ; i++ )
895                        {
896                            retval.push( bookmark = ranges[ i ].createBookmark( serializable, true ) );
897
898                                serializable = bookmark.serializable;
899
900                                var bookmarkStart = serializable ? this.document.getById( bookmark.startNode ) : bookmark.startNode,
901                                        bookmarkEnd = serializable ? this.document.getById( bookmark.endNode ) : bookmark.endNode;
902
903                            // Updating the offset values for rest of ranges which have been mangled(#3256).
904                            for ( var j = i + 1 ; j < length ; j++ )
905                            {
906                                var dirtyRange = ranges[ j ],
907                                       rangeStart = dirtyRange.startContainer,
908                                       rangeEnd = dirtyRange.endContainer;
909
910                               rangeStart.equals( bookmarkStart.getParent() ) && dirtyRange.startOffset++;
911                               rangeStart.equals( bookmarkEnd.getParent() ) && dirtyRange.startOffset++;
912                               rangeEnd.equals( bookmarkStart.getParent() ) && dirtyRange.endOffset++;
913                               rangeEnd.equals( bookmarkEnd.getParent() ) && dirtyRange.endOffset++;
914                            }
915                        }
916
917                        return retval;
918                },
919
920                createBookmarks2 : function( normalized )
921                {
922                        var bookmarks = [],
923                                ranges = this.getRanges();
924
925                        for ( var i = 0 ; i < ranges.length ; i++ )
926                                bookmarks.push( ranges[i].createBookmark2( normalized ) );
927
928                        return bookmarks;
929                },
930
931                selectBookmarks : function( bookmarks )
932                {
933                        var ranges = [];
934                        for ( var i = 0 ; i < bookmarks.length ; i++ )
935                        {
936                                var range = new CKEDITOR.dom.range( this.document );
937                                range.moveToBookmark( bookmarks[i] );
938                                ranges.push( range );
939                        }
940                        this.selectRanges( ranges );
941                        return this;
942                }
943        };
944})();
945
946CKEDITOR.dom.range.prototype.select =
947        CKEDITOR.env.ie ?
948                // V2
949                function( forceExpand )
950                {
951                        var collapsed = this.collapsed;
952                        var isStartMarkerAlone;
953                        var dummySpan;
954
955                        var bookmark = this.createBookmark();
956
957                        // Create marker tags for the start and end boundaries.
958                        var startNode = bookmark.startNode;
959
960                        var endNode;
961                        if ( !collapsed )
962                                endNode = bookmark.endNode;
963
964                        // Create the main range which will be used for the selection.
965                        var ieRange = this.document.$.body.createTextRange();
966
967                        // Position the range at the start boundary.
968                        ieRange.moveToElementText( startNode.$ );
969                        ieRange.moveStart( 'character', 1 );
970
971                        if ( endNode )
972                        {
973                                // Create a tool range for the end.
974                                var ieRangeEnd = this.document.$.body.createTextRange();
975
976                                // Position the tool range at the end.
977                                ieRangeEnd.moveToElementText( endNode.$ );
978
979                                // Move the end boundary of the main range to match the tool range.
980                                ieRange.setEndPoint( 'EndToEnd', ieRangeEnd );
981                                ieRange.moveEnd( 'character', -1 );
982                        }
983                        else
984                        {
985                                // The isStartMarkerAlone logic comes from V2. It guarantees that the lines
986                                // will expand and that the cursor will be blinking on the right place.
987                                // Actually, we are using this flag just to avoid using this hack in all
988                                // situations, but just on those needed.
989                                isStartMarkerAlone = forceExpand || !startNode.hasPrevious() || ( startNode.getPrevious().is && startNode.getPrevious().is( 'br' ) );
990
991                                // Append a temporary <span>&#65279;</span> before the selection.
992                                // This is needed to avoid IE destroying selections inside empty
993                                // inline elements, like <b></b> (#253).
994                                // It is also needed when placing the selection right after an inline
995                                // element to avoid the selection moving inside of it.
996                                dummySpan = this.document.createElement( 'span' );
997                                dummySpan.setHtml( '&#65279;' );        // Zero Width No-Break Space (U+FEFF). See #1359.
998                                dummySpan.insertBefore( startNode );
999
1000                                if ( isStartMarkerAlone )
1001                                {
1002                                        // To expand empty blocks or line spaces after <br>, we need
1003                                        // instead to have any char, which will be later deleted using the
1004                                        // selection.
1005                                        // \ufeff = Zero Width No-Break Space (U+FEFF). (#1359)
1006                                        this.document.createText( '\ufeff' ).insertBefore( startNode );
1007                                }
1008                        }
1009
1010                        // Remove the markers (reset the position, because of the changes in the DOM tree).
1011                        this.setStartBefore( startNode );
1012                        startNode.remove();
1013
1014                        if ( collapsed )
1015                        {
1016                                if ( isStartMarkerAlone )
1017                                {
1018                                        // Move the selection start to include the temporary \ufeff.
1019                                        ieRange.moveStart( 'character', -1 );
1020
1021                                        ieRange.select();
1022
1023                                        // Remove our temporary stuff.
1024                                        this.document.$.selection.clear();
1025                                }
1026                                else
1027                                        ieRange.select();
1028
1029                                dummySpan.remove();
1030                        }
1031                        else
1032                        {
1033                                this.setEndBefore( endNode );
1034                                endNode.remove();
1035                                ieRange.select();
1036                        }
1037                }
1038        :
1039                function()
1040                {
1041                        var startContainer = this.startContainer;
1042
1043                        // If we have a collapsed range, inside an empty element, we must add
1044                        // something to it, otherwise the caret will not be visible.
1045                        if ( this.collapsed && startContainer.type == CKEDITOR.NODE_ELEMENT && !startContainer.getChildCount() )
1046                                startContainer.append( new CKEDITOR.dom.text( '' ) );
1047
1048                        var nativeRange = this.document.$.createRange();
1049                        nativeRange.setStart( startContainer.$, this.startOffset );
1050
1051                        try
1052                        {
1053                                nativeRange.setEnd( this.endContainer.$, this.endOffset );
1054                        }
1055                        catch ( e )
1056                        {
1057                                // There is a bug in Firefox implementation (it would be too easy
1058                                // otherwise). The new start can't be after the end (W3C says it can).
1059                                // So, let's create a new range and collapse it to the desired point.
1060                                if ( e.toString().indexOf( 'NS_ERROR_ILLEGAL_VALUE' ) >= 0 )
1061                                {
1062                                        this.collapse( true );
1063                                        nativeRange.setEnd( this.endContainer.$, this.endOffset );
1064                                }
1065                                else
1066                                        throw( e );
1067                        }
1068
1069                        var selection = this.document.getSelection().getNative();
1070                        selection.removeAllRanges();
1071                        selection.addRange( nativeRange );
1072                };
Note: See TracBrowser for help on using the repository browser.