JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
vanilla ckeditor-3.4b
[ckeditor.git] / _source / plugins / find / dialogs / find.js
index b4196fa..bc9f8a4 100644 (file)
@@ -1,23 +1,24 @@
 /*\r
-Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.\r
+Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.\r
 For licensing, see LICENSE.html or http://ckeditor.com/license\r
 */\r
 \r
 (function()\r
 {\r
-       function guardDomWalkerNonEmptyTextNode( node )\r
+       var isReplace;\r
+\r
+       function findEvaluator( node )\r
        {\r
-               return ( node.type == CKEDITOR.NODE_TEXT && node.getLength() > 0 );\r
+               return node.type == CKEDITOR.NODE_TEXT && node.getLength() > 0 && ( !isReplace || !node.isReadOnly() );\r
        }\r
 \r
        /**\r
         * Elements which break characters been considered as sequence.\r
        */\r
-       function checkCharactersBoundary ( node )\r
+       function nonCharactersBoundary( node )\r
        {\r
-               var dtd = CKEDITOR.dtd;\r
-               return node.isBlockBoundary(\r
-                       CKEDITOR.tools.extend( {}, dtd.$empty, dtd.$nonEditable ) );\r
+               return !( node.type == CKEDITOR.NODE_ELEMENT && node.isBlockBoundary(\r
+                       CKEDITOR.tools.extend( {}, CKEDITOR.dtd.$empty, CKEDITOR.dtd.$nonEditable ) ) );\r
        }\r
 \r
        /**\r
@@ -67,8 +68,11 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
 \r
        var findDialog = function( editor, startupPage )\r
        {\r
-               // Style object for highlights.\r
-               var highlightStyle = new CKEDITOR.style( editor.config.find_highlight );\r
+               // Style object for highlights: (#5018)\r
+               // 1. Defined as full match style to avoid compromising ordinary text color styles.\r
+               // 2. Must be apply onto inner-most text to avoid conflicting with ordinary text color styles visually.\r
+               var highlightStyle = new CKEDITOR.style( CKEDITOR.tools.extend( { fullMatch : true, childRule : function(){ return false; } },\r
+                       editor.config.find_highlight ) );\r
 \r
                /**\r
                 * Iterator which walk through the specified range char by char. By\r
@@ -81,8 +85,8 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                {\r
                        var walker =\r
                                new CKEDITOR.dom.walker( range );\r
-                       walker[ matchWord ? 'guard' : 'evaluator' ] =\r
-                               guardDomWalkerNonEmptyTextNode;\r
+                       walker.guard = matchWord ? nonCharactersBoundary : null;\r
+                       walker[ 'evaluator' ] = findEvaluator;\r
                        walker.breakOnFalse = true;\r
 \r
                        this._ = {\r
@@ -107,20 +111,20 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                        {\r
                                var currentTextNode = this.textNode;\r
                                // Already at the end of document, no more character available.\r
-                               if(  currentTextNode === null )\r
+                               if (  currentTextNode === null )\r
                                        return cursorStep.call( this );\r
 \r
                                this._.matchBoundary = false;\r
 \r
                                // There are more characters in the text node, step forward.\r
-                               if( currentTextNode\r
+                               if ( currentTextNode\r
                                    && rtl\r
                                        && this.offset > 0 )\r
                                {\r
                                        this.offset--;\r
                                        return cursorStep.call( this );\r
                                }\r
-                               else if( currentTextNode\r
+                               else if ( currentTextNode\r
                                        && this.offset < currentTextNode.getLength() - 1 )\r
                                {\r
                                        this.offset++;\r
@@ -142,8 +146,8 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                                        break;\r
 \r
                                                // Marking as match character boundaries.\r
-                                               if( !currentTextNode\r
-                                                  && checkCharactersBoundary( this._.walker.current ) )\r
+                                               if ( !currentTextNode\r
+                                                  && !nonCharactersBoundary( this._.walker.current ) )\r
                                                        this._.matchBoundary = true;\r
 \r
                                        }\r
@@ -181,16 +185,25 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                         */\r
                        toDomRange : function()\r
                        {\r
+                               var range = new CKEDITOR.dom.range( editor.document );\r
                                var cursors = this._.cursors;\r
                                if ( cursors.length < 1 )\r
-                                       return null;\r
+                               {\r
+                                       var textNode = this._.walker.textNode;\r
+                                       if ( textNode )\r
+                                                       range.setStartAfter( textNode );\r
+                                       else\r
+                                               return null;\r
+                               }\r
+                               else\r
+                               {\r
+                                       var first = cursors[0],\r
+                                                       last = cursors[ cursors.length - 1 ];\r
 \r
-                               var first = cursors[0],\r
-                                       last = cursors[ cursors.length - 1 ],\r
-                                       range = new CKEDITOR.dom.range( editor.document );\r
+                                       range.setStart( first.textNode, first.offset );\r
+                                       range.setEnd( last.textNode, last.offset + 1 );\r
+                               }\r
 \r
-                               range.setStart( first.textNode, first.offset );\r
-                               range.setEnd( last.textNode, last.offset + 1 );\r
                                return range;\r
                        },\r
                        /**\r
@@ -240,8 +253,10 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                        this.removeHighlight();\r
 \r
                                // Apply the highlight.\r
-                               var range = this.toDomRange();\r
+                               var range = this.toDomRange(),\r
+                                       bookmark = range.createBookmark();\r
                                highlightStyle.applyToRange( range );\r
+                               range.moveToBookmark( bookmark );\r
                                this._.highlightRange = range;\r
 \r
                                // Scroll the editor to the highlighted area.\r
@@ -262,11 +277,21 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                if ( !this._.highlightRange )\r
                                        return;\r
 \r
+                               var bookmark = this._.highlightRange.createBookmark();\r
                                highlightStyle.removeFromRange( this._.highlightRange );\r
+                               this._.highlightRange.moveToBookmark( bookmark );\r
                                this.updateFromDomRange( this._.highlightRange );\r
                                this._.highlightRange = null;\r
                        },\r
 \r
+                       isReadOnly : function()\r
+                       {\r
+                               if ( !this._.highlightRange )\r
+                                       return 0;\r
+\r
+                               return this._.highlightRange.startContainer.isReadOnly();\r
+                       },\r
+\r
                        moveBack : function()\r
                        {\r
                                var retval = this._.walker.back(),\r
@@ -310,13 +335,16 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                        getNextCharacterRange : function( maxLength )\r
                        {\r
                                var lastCursor,\r
+                                               nextRangeWalker,\r
                                                cursors = this._.cursors;\r
-                               if ( !( lastCursor = cursors[ cursors.length - 1 ] ) )\r
-                                       return null;\r
-                               return new characterRange(\r
-                                                                               new characterWalker(\r
-                                                                                       getRangeAfterCursor( lastCursor ) ),\r
-                                                                               maxLength );\r
+\r
+                               if ( ( lastCursor = cursors[ cursors.length - 1 ] ) && lastCursor.textNode )\r
+                                       nextRangeWalker = new characterWalker( getRangeAfterCursor( lastCursor ) );\r
+                               // In case it's an empty range (no cursors), figure out next range from walker (#4951).\r
+                               else\r
+                                       nextRangeWalker = this._.walker;\r
+\r
+                               return new characterRange( nextRangeWalker, maxLength );\r
                        },\r
 \r
                        getCursors : function()\r
@@ -427,7 +455,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                        matchRange : null,\r
                        find : function( pattern, matchCase, matchWord, matchCyclic, highlightMatched, cyclicRerun )\r
                        {\r
-                               if( !this.matchRange )\r
+                               if ( !this.matchRange )\r
                                        this.matchRange =\r
                                                new characterRange(\r
                                                        new characterWalker( this.searchRange ),\r
@@ -500,13 +528,15 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                        replace : function( dialog, pattern, newString, matchCase, matchWord,\r
                                matchCyclic , isReplaceAll )\r
                        {\r
+                               isReplace = 1;\r
+\r
                                // Successiveness of current replace/find.\r
                                var result = false;\r
 \r
                                // 1. Perform the replace when there's already a match here.\r
                                // 2. Otherwise perform the find but don't replace it immediately.\r
                                if ( this.matchRange && this.matchRange.isMatched()\r
-                                               && !this.matchRange._.isReplaced )\r
+                                               && !this.matchRange._.isReplaced && !this.matchRange.isReadOnly() )\r
                                {\r
                                        // Turn off highlight for a while when saving snapshots.\r
                                        this.matchRange.removeHighlight();\r
@@ -536,6 +566,8 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                else\r
                                        result = this.find( pattern, matchCase, matchWord, matchCyclic, !isReplaceAll );\r
 \r
+                               isReplace = 0;\r
+\r
                                return result;\r
                        }\r
                };\r
@@ -708,7 +740,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                                                                        finder.matchRange = null;\r
                                                                                }\r
                                                                                editor.fire( 'saveSnapshot' );\r
-                                                                               while( finder.replace( dialog,\r
+                                                                               while ( finder.replace( dialog,\r
                                                                                        dialog.getValueOf( 'replace', 'txtFindReplace' ),\r
                                                                                        dialog.getValueOf( 'replace', 'txtReplace' ),\r
                                                                                        dialog.getValueOf( 'replace', 'txtReplaceCaseChk' ),\r
@@ -801,7 +833,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                                                currPage.initialized = true;\r
                                                        }\r
 \r
-                                                       if( isUserSelect )\r
+                                                       if ( isUserSelect )\r
                                                                // synchronize fields on tab switch.\r
                                                                syncFieldsBetweenTabs.call( this, pageId );\r
                                                };\r
@@ -813,23 +845,30 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                // Establish initial searching start position.\r
                                finder.searchRange = getSearchRange();\r
 \r
-                               if ( startupPage == 'replace' )\r
-                                       this.getContentElement( 'replace', 'txtFindReplace' ).focus();\r
-                               else\r
-                                       this.getContentElement( 'find', 'txtFindFind' ).focus();\r
+                               this.selectPage( startupPage );\r
                        },\r
                        onHide : function()\r
                        {\r
+                               var range;\r
                                if ( finder.matchRange && finder.matchRange.isMatched() )\r
                                {\r
                                        finder.matchRange.removeHighlight();\r
                                        editor.focus();\r
-                                       editor.getSelection().selectRanges(\r
-                                               [ finder.matchRange.toDomRange() ] );\r
+\r
+                                       range = finder.matchRange.toDomRange();\r
+                                       if ( range )\r
+                                               editor.getSelection().selectRanges( [ range ] );\r
                                }\r
 \r
                                // Clear current session before dialog close\r
                                delete finder.matchRange;\r
+                       },\r
+                       onFocus : function()\r
+                       {\r
+                               if ( startupPage == 'replace' )\r
+                                       return this.getContentElement( 'replace', 'txtFindReplace' );\r
+                               else\r
+                                       return this.getContentElement( 'find', 'txtFindFind' );\r
                        }\r
                };\r
        };\r