Ticket #2150: 2150_4.patch

File 2150_4.patch, 22.5 kB (added by martinkou, 5 months ago)
  • _whatsnew.html

     
    3939        <ul> 
    4040                <li>[<a target="_blank" href="http://dev.fckeditor.net/ticket/2142">#2142</a>] HTML samples will 
    4141                now use sampleposteddata.php in action parameter inside a form.</li> 
     42                <li>[<a target="_blank" href="http://dev.fckeditor.net/ticket/2150">#2150</a>] The searching 
     43                        speed of the Find/Replace dialog has been vastly improved.</li> 
    4244        </ul> 
    4345        <p> 
    4446                Fixed Bugs:</p> 
     
    6870                        class=&quot;Apple-style-span&quot;&gt; created after inserting special characters.</li> 
    6971                <li>[<a target="_blank" href="http://dev.fckeditor.net/ticket/2170">#2170</a>] Fixed Ctrl-Insert hotkey 
    7072                        for copying.</li> 
     73                <li>[<a target="_blank" href="http://dev.fckeditor.net/ticket/2159">#2159</a>] Selection are now 
     74                        correctly restored when undoing changes made by the Replace dialog.</li> 
     75                <li>[<a target="_blank" href="http://dev.fckeditor.net/ticket/2160">#2160</a>] "Match whole word" in the 
     76                        Find and Replace dialog will now find words next to punctuation marks as well.</li> 
    7177        </ul> 
    7278        <h3> 
    7379                Version 2.6</h3> 
  • editor/dialog/fck_replace.html

     
    3434var dialogArguments = dialog.Args() ; 
    3535 
    3636var FCKLang = oEditor.FCKLang ; 
     37var FCKDomTools = oEditor.FCKDomTools ; 
     38var FCKDomRange = oEditor.FCKDomRange ; 
     39var FCKListsLib = oEditor.FCKListsLib ; 
     40var FCKTools = oEditor.FCKTools ; 
     41var EditorDocument = oEditor.FCK.EditorDocument ; 
     42var HighlightStyle = oEditor.FCKStyles.GetStyle( '_FCK_SelectionHighlight' )  ; 
    3743 
    3844dialog.AddTab( 'Find', FCKLang.DlgFindTitle ) ; 
    3945dialog.AddTab( 'Replace', FCKLang.DlgReplaceTitle ) ; 
     
    5157                dialog.SetAutoSize( true ) ; 
    5258} 
    5359 
    54 // Place a range at the start of document. 
    55 // This will be the starting point of our search. 
    56 var GlobalRange = new oEditor.FCKDomRange( oEditor.FCK.EditorWindow ) ; 
    57  
    58 function ResetGlobalRange() 
     60GetNextNonEmptyTextNode = function( node, stopNode ) 
    5961{ 
    60         GlobalRange.SetStart( oEditor.FCK.EditorDocument.body, 1 ) ; 
    61         GlobalRange.SetEnd( oEditor.FCK.EditorDocument.body, 1 ) ; 
    62         GlobalRange.Collapse( true ) ; 
     62        var node ; 
     63        while ( ( node = FCKDomTools.GetNextSourceNode( node, false, 3, stopNode ) ) && node && node.length < 1 ) ; 
     64        return node ; 
    6365} 
    64 ResetGlobalRange() ; 
    6566 
    66 var HighlightRange = null ; 
    67 function Highlight() 
     67CharacterCursor = function( arg ) 
    6868{ 
    69         if ( HighlightRange ) 
    70                 ClearHighlight() ; 
    71         var cloneRange = GlobalRange.Clone() ; 
    72         oEditor.FCKStyles.GetStyle( '_FCK_SelectionHighlight' ).ApplyToRange( cloneRange, false, true ) ; 
    73         HighlightRange = cloneRange ; 
    74         GlobalRange = HighlightRange.Clone() ; 
    75 } 
    76  
    77 function ClearHighlight() 
    78 { 
    79         if ( HighlightRange ) 
     69        if ( arg.nodeType && arg.nodeType == 9 ) 
    8070        { 
    81                 oEditor.FCKStyles.GetStyle( '_FCK_SelectionHighlight' ).RemoveFromRange( HighlightRange, false, true ) ; 
    82                 HighlightRange = null ; 
     71                this._textNode = GetNextNonEmptyTextNode( arg.body, arg.documentElement ) ; 
     72                this._offset = 0 ; 
     73                this._doc = arg ; 
    8374        } 
     75        else 
     76        { 
     77                this._textNode = arguments[0] ; 
     78                this._offset = arguments[1] ; 
     79                this._doc = FCKTools.GetElementDocument( arguments[0] ) ; 
     80        } 
    8481} 
    85  
    86 function OnLoad() 
     82CharacterCursor.prototype = 
    8783{ 
    88         // First of all, translate the dialog box texts. 
    89         oEditor.FCKLanguageManager.TranslatePage( document ) ; 
     84        GetCharacter : function() 
     85        { 
     86                return ( this._textNode && this._textNode.nodeValue.charAt( this._offset ) ) || null ; 
     87        }, 
    9088 
    91         // Show the appropriate tab at startup. 
    92         if ( dialogArguments.CustomValue == 'Find' ) 
     89        // Non-normalized. 
     90        GetTextNode : function() 
    9391        { 
    94                 dialog.SetSelectedTab( 'Find' ) ; 
    95                 dialog.SetAutoSize( true ) ; 
    96         } 
    97         else 
    98                 dialog.SetSelectedTab( 'Replace' ) ; 
     92                return this._textNode ; 
     93        }, 
    9994 
    100         SelectField( 'txtFind' + dialogArguments.CustomValue ) ; 
    101 } 
     95        // Non-normalized. 
     96        GetIndex : function() 
     97        { 
     98                return this._offset ; 
     99        }, 
    102100 
    103 function btnStat() 
    104 { 
    105         GetE('btnReplace').disabled = 
    106                 GetE('btnReplaceAll').disabled = 
    107                         GetE('btnFind').disabled = 
    108                                 ( GetE(idMap["FindText"]).value.length == 0 ) ; 
    109 } 
     101        // Return value means whehther we've crossed a line break or a paragraph boundary. 
     102        MoveNext : function() 
     103        { 
     104                if ( this._offset < this._textNode.length - 1 ) 
     105                { 
     106                        this._offset++ ; 
     107                        return false ; 
     108                } 
    110109 
    111 function btnStatDelayed() 
    112 { 
    113         setTimeout( btnStat, 1 ) ; 
    114 } 
     110                var crossed = false ; 
     111                var curNode = this._textNode ; 
     112                while ( ( curNode = FCKDomTools.GetNextSourceNode( curNode ) ) 
     113                                && curNode && ( curNode.nodeType != 3 || curNode.length < 1 ) ) 
     114                { 
     115                        var tag = curNode.nodeName.toLowerCase() ; 
     116                        if ( FCKListsLib.BlockElements[tag] || tag == 'br' ) 
     117                                crossed = true ; 
     118                } 
    115119 
    116 function GetSearchString() 
    117 { 
    118         return GetE(idMap['FindText']).value ; 
    119 } 
     120                this._textNode = curNode ; 
     121                this._offset = 0 ; 
     122                return crossed ; 
     123        }, 
    120124 
    121 function GetReplaceString() 
    122 { 
    123         return GetE("txtReplace").value ; 
    124 } 
     125        // Return value means whehther we've crossed a line break or a paragraph boundary. 
     126        MoveBack : function() 
     127        { 
     128                if ( this._offset > 0 && this._textNode.length > 0 ) 
     129                { 
     130                        this._offset = Math.min( this._offset - 1, this._textNode.length - 1 ) ; 
     131                        return false ; 
     132                } 
    125133 
    126 function GetCheckCase() 
    127 { 
    128         return !! ( GetE(idMap['CheckCase']).checked ) ; 
    129 } 
     134                var crossed = false ; 
     135                var curNode = this._textNode ; 
     136                while ( ( curNode = FCKDomTools.GetPreviousSourceNode( curNode ) ) 
     137                                && curNode && ( curNode.nodeType != 3 || curNode.length < 1 ) ) 
     138                { 
     139                        var tag = curNode.nodeName.toLowerCase() ; 
     140                        if ( FCKListsLib.BlockElements[tag] || tag == 'br' ) 
     141                                crossed = true ; 
     142                } 
    130143 
    131 function GetMatchWord() 
     144                this._textNode = curNode ; 
     145                this._offset = curNode.length - 1 ; 
     146                return crossed ; 
     147        }, 
     148 
     149        Clone : function() 
     150        { 
     151                return new CharacterCursor( this._textNode, this._offset ) ; 
     152        } 
     153} ; 
     154 
     155CharacterRange = function( initCursor, maxLength ) 
    132156{ 
    133         return !! ( GetE(idMap['CheckWord']).checked ) ; 
     157        this._cursors = initCursor.push ? initCursor : [initCursor] ; 
     158        this._maxLength = maxLength ; 
     159        this._highlightRange = null ; 
    134160} 
    135  
    136 // Get the data pointed to by a bookmark. 
    137 function GetData( bookmark ) 
     161CharacterRange.prototype = 
    138162{ 
    139         var cursor = oEditor.FCK.EditorDocument.documentElement ; 
    140         for ( var i = 0 ; i < bookmark.length ; i++ ) 
     163        ToDomRange : function() 
    141164        { 
    142                 var target = bookmark[i] ; 
    143                 var currentIndex = -1 ; 
    144                 if ( cursor.nodeType != 3 ) 
     165                var firstCursor = this._cursors[0] ; 
     166                var lastCursor = this._cursors[ this._cursors.length - 1 ] ; 
     167                var domRange = new FCKDomRange( FCKTools.GetElementWindow( firstCursor.GetTextNode() ) ) ; 
     168                var w3cRange = domRange._Range = domRange.CreateRange() ; 
     169                w3cRange.setStart( firstCursor.GetTextNode(), firstCursor.GetIndex() ) ; 
     170                w3cRange.setEnd( lastCursor.GetTextNode(), lastCursor.GetIndex() + 1 ) ; 
     171                domRange._UpdateElementInfo() ; 
     172                return domRange ; 
     173        }, 
     174 
     175        Highlight : function() 
     176        { 
     177                if ( this._cursors.length < 1 ) 
     178                        return ; 
     179 
     180                var domRange = this.ToDomRange() ; 
     181                HighlightStyle.ApplyToRange( domRange, false, true ) ; 
     182                this._highlightRange = domRange ; 
     183 
     184                var charRange = CharacterRange.CreateFromDomRange( domRange ) ; 
     185                var focusNode = domRange.StartNode ; 
     186                if ( focusNode.nodeType != 1 ) 
     187                        focusNode = focusNode.parentNode ; 
     188                focusNode.scrollIntoView( false ) ; 
     189                this._cursors = charRange._cursors ; 
     190        }, 
     191 
     192        RemoveHighlight : function() 
     193        { 
     194                if ( this._highlightRange ) 
    145195                { 
    146                         for (var j = 0 ; j < cursor.childNodes.length ; j++ ) 
    147                         { 
    148                                 var candidate = cursor.childNodes[j] ; 
    149                                 if ( candidate.nodeType == 3 && 
    150                                                 candidate.previousSibling && 
    151                                                 candidate.previousSibling.nodeType == 3 ) 
    152                                         continue ; 
    153                                 currentIndex++ ; 
    154                                 if ( currentIndex == target ) 
    155                                 { 
    156                                         cursor = candidate ; 
    157                                         break ; 
    158                                 } 
    159                         } 
    160                         if ( currentIndex < target ) 
    161                                 return null ; 
     196                        HighlightStyle.RemoveFromRange( this._highlightRange, false, true ) ; 
     197                        var charRange = CharacterRange.CreateFromDomRange( this._highlightRange ) ; 
     198                        this._cursors = charRange._cursors ; 
     199                        this._highlightRange = null ; 
    162200                } 
    163                 else 
    164                 { 
    165                         if ( i != bookmark.length - 1 ) 
    166                                 return null ; 
    167                         while ( target >= cursor.length && cursor.nextSibling && cursor.nextSibling.nodeType == 3 ) 
    168                         { 
    169                                 target -= cursor.length ; 
    170                                 cursor = cursor.nextSibling ; 
    171                         } 
    172                         cursor = cursor.nodeValue.charAt( target ) ; 
    173                         if ( cursor == "" ) 
    174                                 cursor = null ; 
    175                 } 
     201        }, 
     202 
     203        GetHighlightDomRange : function() 
     204        { 
     205                return this._highlightRange; 
     206        }, 
     207 
     208        MoveNext : function() 
     209        { 
     210                var next = this._cursors[ this._cursors.length - 1 ].Clone() ; 
     211                var retval = next.MoveNext() ; 
     212                if ( retval ) 
     213                        this._cursors = [] ; 
     214                this._cursors.push( next ) ; 
     215                if ( this._cursors.length > this._maxLength ) 
     216                        this._cursors.shift() ; 
     217                return retval ; 
     218        }, 
     219 
     220        MoveBack : function() 
     221        { 
     222                var prev = this._cursors[0].Clone() ; 
     223                var retval = prev.MoveBack() ; 
     224                if ( retval ) 
     225                        this._cursors = [] ; 
     226                this._cursors.unshift( prev ) ; 
     227                if ( this._cursors.length > this._maxLength ) 
     228                        this._cursors.pop() ; 
     229                return retval ; 
     230        }, 
     231 
     232        GetEndCharacter : function() 
     233        { 
     234                if ( this._cursors.length < 1 ) 
     235                        return null ; 
     236                var retval = this._cursors[ this._cursors.length - 1 ].GetCharacter() ; 
     237                return retval ; 
     238        }, 
     239 
     240        GetNextRange : function( len ) 
     241        {                
     242                if ( this._cursors.length == 0 ) 
     243                        return null ; 
     244                var cur = this._cursors[ this._cursors.length - 1 ].Clone() ; 
     245                cur.MoveNext() ; 
     246                return new CharacterRange( cur, len ) ; 
     247        }, 
     248 
     249        GetCursors : function() 
     250        { 
     251                return this._cursors ; 
    176252        } 
    177         return cursor ; 
    178 } 
     253} ; 
    179254 
    180 // With this function, we can treat the bookmark as an iterator for DFS. 
    181 function NextPosition( bookmark ) 
     255CharacterRange.CreateFromDomRange = function( domRange ) 
    182256{ 
    183         // See if there's anything further down the tree. 
    184         var next = bookmark.concat( [0] ) ; 
    185         if ( GetData( next ) != null ) 
    186                 return next ; 
     257        var w3cRange = domRange._Range ; 
     258        var startContainer = w3cRange.startContainer ; 
     259        var endContainer = w3cRange.endContainer ; 
     260        var startTextNode, startIndex, endTextNode, endIndex ; 
    187261 
    188         // Nothing down there? See if there's anything next to me. 
    189         var next = bookmark.slice( 0, bookmark.length - 1 ).concat( [ bookmark[ bookmark.length - 1 ] + 1 ] ) ; 
    190         if ( GetData( next ) != null ) 
    191                 return next ; 
     262        if ( startContainer.nodeType == 3 ) 
     263        { 
     264                startTextNode = startContainer ; 
     265                startIndex = w3cRange.startOffset ; 
     266        } 
     267        else if ( domRange.StartNode.nodeType == 3 ) 
     268        { 
     269                startTextNode = domRange.StartNode ; 
     270                startIndex = 0 ; 
     271        } 
     272        else 
     273        { 
     274                startTextNode = GetNextNonEmptyTextNode( domRange.StartNode, domRange.StartNode.parentNode ) ; 
     275                if ( !startTextNode ) 
     276                        return null ; 
     277                startIndex = 0 ; 
     278        } 
    192279 
    193         // Nothing even next to me? See if there's anything next to my ancestors. 
    194         for ( var i = bookmark.length - 1 ; i > 0 ; i-- ) 
     280        if ( endContainer.nodeType == 3 && w3cRange.endOffset > 0 ) 
    195281        { 
    196                 var next = bookmark.slice( 0, i - 1 ).concat( [ bookmark[ i - 1 ] + 1 ] ) ; 
    197                 if ( GetData( next ) != null ) 
    198                         return next ; 
     282                endTextNode = endContainer ; 
     283                endIndex = w3cRange.endOffset - 1 ; 
    199284        } 
     285        else 
     286        { 
     287                endTextNode = domRange.EndNode ; 
     288                while ( endTextNode.nodeType != 3 ) 
     289                        endTextNode = endTextNode.lastChild ; 
     290                endIndex = endTextNode.length - 1 ; 
     291        } 
    200292 
    201         // There's absolutely nothing left to walk, return null. 
    202         return null ; 
    203 } 
    204  
    205 // Is this character a unicode whitespace? 
    206 // Reference: http://unicode.org/Public/UNIDATA/PropList.txt 
    207 function CheckIsWhitespace( c ) 
    208 { 
    209         var code = c.charCodeAt( 0 ); 
    210         if ( code >= 9 && code <= 0xd ) 
    211                 return true; 
    212         if ( code >= 0x2000 && code <= 0x200a ) 
    213                 return true; 
    214         switch ( code ) 
     293        var cursors = [] ; 
     294        var current = new CharacterCursor( startTextNode, startIndex ) ; 
     295        cursors.push( current ) ; 
     296        if ( !( current.GetTextNode() == endTextNode && current.GetIndex() == endIndex ) ) 
    215297        { 
    216                 case 0x20: 
    217                 case 0x85: 
    218                 case 0xa0: 
    219                 case 0x1680: 
    220                 case 0x180e: 
    221                 case 0x2028: 
    222                 case 0x2029: 
    223                 case 0x202f: 
    224                 case 0x205f: 
    225                 case 0x3000: 
    226                         return true; 
    227                 default: 
    228                         return false; 
     298                do 
     299                { 
     300                        current = current.Clone() ; 
     301                        current.MoveNext() ; 
     302                        cursors.push( current ) ; 
     303                } 
     304                while ( !( current.GetTextNode() == endTextNode && current.GetIndex() == endIndex ) ) ; 
    229305        } 
     306 
     307        return new CharacterRange( cursors, cursors.length ) ; 
    230308} 
    231309 
    232310// Knuth-Morris-Pratt Algorithm for stream input 
    233311KMP_NOMATCH = 0 ; 
    234312KMP_ADVANCED = 1 ; 
    235313KMP_MATCHED = 2 ; 
    236 function KmpMatch( pattern, ignoreCase ) 
     314KmpMatch = function( pattern, ignoreCase ) 
    237315{ 
    238316        var overlap = [ -1 ] ; 
    239317        for ( var i = 0 ; i < pattern.length ; i++ ) 
     
    251329                this.Pattern = pattern ; 
    252330} 
    253331KmpMatch.prototype = { 
    254         "FeedCharacter" : function( c ) 
     332        FeedCharacter : function( c ) 
    255333        { 
    256334                if ( this._IgnoreCase ) 
    257335                        c = c.toLowerCase(); 
     
    277355 
    278356                return null ; 
    279357        }, 
    280         "Reset" : function() 
     358 
     359        Reset : function() 
    281360        { 
    282361                this._State = 0 ; 
    283362        } 
    284363}; 
    285364 
    286 function _Find() 
     365// Place a range at the start of document. 
     366function OnLoad() 
    287367{ 
    288         // Start from the end of the current selection. 
    289         var matcher = new KmpMatch( GetSearchString(), ! GetCheckCase() ) ; 
    290         var cursor = GlobalRange.CreateBookmark2().End ; 
    291         var matchState = KMP_NOMATCH ; 
    292         var matchBookmark = null ; 
    293         var matchBookmarkStart = [] ; 
     368        // First of all, translate the dialog box texts. 
     369        oEditor.FCKLanguageManager.TranslatePage( document ) ; 
    294370 
    295         // Match finding. 
    296         while ( true ) 
     371        // Show the appropriate tab at startup. 
     372        if ( dialogArguments.CustomValue == 'Find' ) 
    297373        { 
    298                 // Perform KMP stream matching. 
    299                 //      - Reset KMP matcher if we encountered a block element. 
    300                 var data = GetData( cursor ) ; 
    301                 if ( data ) 
    302                 { 
    303                         if ( data.tagName ) 
    304                         { 
    305                                 if ( oEditor.FCKListsLib.BlockElements[ data.tagName.toLowerCase() ] ) 
    306                                 { 
    307                                         matcher.Reset(); 
    308                                         matchBookmarkStart = [] ; 
    309                                 } 
    310                         } 
    311                         else if ( data.charAt != undefined ) 
    312                         { 
    313                                 matchState = matcher.FeedCharacter(data) ; 
     374                dialog.SetSelectedTab( 'Find' ) ; 
     375                dialog.SetAutoSize( true ) ; 
     376        } 
     377        else 
     378                dialog.SetSelectedTab( 'Replace' ) ; 
    314379 
    315                                 // No possible match of any useful substring in the pattern for the currently scanned character. 
    316                                 // So delete any positional information. 
    317                                 if ( matchState == KMP_NOMATCH ) 
    318                                         matchBookmarkStart = [] ; 
    319                                 // We've matched something, but it's not a complete match, so let's just mark down the position for backtracking later. 
    320                                 else if ( matchState == KMP_ADVANCED ) 
    321                                 { 
    322                                         matchBookmarkStart.push( cursor.concat( [] ) ) ; 
    323                                         if ( matchBookmarkStart.length > matcher._State ) 
    324                                                 matchBookmarkStart.shift() ; 
    325                                 } 
    326                                 // Found a complete match! Mark down the ending position as well. 
    327                                 else if ( matchState == KMP_MATCHED ) 
    328                                 { 
    329                                         // It is possible to get a KMP_MATCHED without KMP_ADVANCED when the match pattern is only 1 character. 
    330                                         // So need to check and mark down the starting position as well. 
    331                                         if ( matchBookmarkStart.length == 0 ) 
    332                                                 matchBookmarkStart = [cursor.concat( [] )] ; 
     380        SelectField( 'txtFind' + dialogArguments.CustomValue ) ; 
     381} 
    333382 
    334                                         matchBookmark = { 'Start' : matchBookmarkStart.shift(), 'End' : cursor.concat( [] ) } ; 
    335                                         matchBookmark.End[ matchBookmark.End.length - 1 ]++; 
     383function btnStat() 
     384{ 
     385        GetE('btnReplace').disabled = 
     386                GetE('btnReplaceAll').disabled = 
     387                        GetE('btnFind').disabled = 
     388                                ( GetE(idMap["FindText"]).value.length == 0 ) ; 
     389} 
    336390 
    337                                         // Wait, do we have to match a whole word? 
    338                                         // If yes, carry out additional checks on what we've got. 
    339                                         if ( GetMatchWord() ) 
    340                                         { 
    341                                                 var startOk = false ; 
    342                                                 var endOk = false ; 
    343                                                 var start = matchBookmark.Start ; 
    344                                                 var end = matchBookmark.End ; 
    345                                                 if ( start[ start.length - 1 ] == 0 ) 
    346                                                         startOk = true ; 
    347                                                 else 
    348                                                 { 
    349                                                         var cursorBeforeStart = start.slice( 0, start.length - 1 ) ; 
    350                                                         cursorBeforeStart.push( start[ start.length - 1 ] - 1 ) ; 
    351                                                         var dataBeforeStart = GetData( cursorBeforeStart ) ; 
    352                                                         if ( dataBeforeStart == null || dataBeforeStart.charAt == undefined ) 
    353                                                                 startOk = true ; 
    354                                                         else if ( CheckIsWhitespace( dataBeforeStart ) ) 
    355                                                                 startOk = true ; 
    356                                                 } 
     391function btnStatDelayed() 
     392{ 
     393        setTimeout( btnStat, 1 ) ; 
     394} 
    357395 
    358                                                 // this is already one character beyond the last char, no need to move 
    359                                                 var cursorAfterEnd = end ; 
    360                                                 var dataAfterEnd = GetData( cursorAfterEnd ); 
    361                                                 if ( dataAfterEnd == null || dataAfterEnd.charAt == undefined ) 
    362                                                         endOk = true ; 
    363                                                 else if ( CheckIsWhitespace( dataAfterEnd ) ) 
    364                                                         endOk = true ; 
     396function GetSearchString() 
     397{ 
     398        return GetE(idMap['FindText']).value ; 
     399} 
    365400 
    366                                                 if ( startOk && endOk ) 
    367                                                         break ; 
    368                                                 else 
    369                                                         matcher.Reset() ; 
    370                                         } 
    371                                         else 
    372                                                 break ; 
    373                                 } 
    374                         } 
    375                 } 
     401function GetReplaceString() 
     402{ 
     403        return GetE("txtReplace").value ; 
     404} 
    376405 
    377                 // Perform DFS across the document, until we've reached the end. 
    378                 cursor = NextPosition( cursor ) ; 
    379                 if ( cursor == null ) 
    380                         break; 
     406function GetCheckCase() 
     407{ 
     408        return !! ( GetE(idMap['CheckCase']).checked ) ; 
     409} 
     410 
     411function GetMatchWord() 
     412{ 
     413        return !! ( GetE(idMap['CheckWord']).checked ) ; 
     414} 
     415 
     416/* Is this character a unicode whitespace or a punctuation mark? 
     417 * References: 
     418 * http://unicode.org/Public/UNIDATA/PropList.txt (whitespaces) 
     419 * http://php.chinaunix.net/manual/tw/ref.regex.php (punctuation marks) 
     420 */ 
     421function CheckIsWordSeparator( c ) 
     422{ 
     423        var code = c.charCodeAt( 0 ); 
     424        if ( code >= 9 && code <= 0xd ) 
     425                return true; 
     426        if ( code >= 0x2000 && code <= 0x200a ) 
     427                return true; 
     428        switch ( code ) 
     429        { 
     430                case 0x20: 
     431                case 0x85: 
     432                case 0xa0: 
     433                case 0x1680: 
     434                case 0x180e: 
     435                case 0x2028: 
     436                case 0x2029: 
     437                case 0x202f: 
     438                case 0x205f: 
     439                case 0x3000: 
     440  &