X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=_source%2Fplugins%2Ffind%2Fdialogs%2Ffind.js;fp=_source%2Fplugins%2Ffind%2Fdialogs%2Ffind.js;h=0000000000000000000000000000000000000000;hb=4625dba05116026713fee9008dd93306be0d1553;hp=b6b2d450358f610b0b0581b23e6489b7284e4818;hpb=3fe9cac293e090ea459a3ee10d78cbe9e1dd0e03;p=ckeditor.git diff --git a/_source/plugins/find/dialogs/find.js b/_source/plugins/find/dialogs/find.js deleted file mode 100644 index b6b2d45..0000000 --- a/_source/plugins/find/dialogs/find.js +++ /dev/null @@ -1,922 +0,0 @@ -/* -Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. -For licensing, see LICENSE.html or http://ckeditor.com/license -*/ - -(function() -{ - var isReplace; - - function findEvaluator( node ) - { - return node.type == CKEDITOR.NODE_TEXT && node.getLength() > 0 && ( !isReplace || !node.isReadOnly() ); - } - - /** - * Elements which break characters been considered as sequence. - */ - function nonCharactersBoundary( node ) - { - return !( node.type == CKEDITOR.NODE_ELEMENT && node.isBlockBoundary( - CKEDITOR.tools.extend( {}, CKEDITOR.dtd.$empty, CKEDITOR.dtd.$nonEditable ) ) ); - } - - /** - * Get the cursor object which represent both current character and it's dom - * position thing. - */ - var cursorStep = function() - { - return { - textNode : this.textNode, - offset : this.offset, - character : this.textNode ? - this.textNode.getText().charAt( this.offset ) : null, - hitMatchBoundary : this._.matchBoundary - }; - }; - - var pages = [ 'find', 'replace' ], - fieldsMapping = [ - [ 'txtFindFind', 'txtFindReplace' ], - [ 'txtFindCaseChk', 'txtReplaceCaseChk' ], - [ 'txtFindWordChk', 'txtReplaceWordChk' ], - [ 'txtFindCyclic', 'txtReplaceCyclic' ] ]; - - /** - * Synchronize corresponding filed values between 'replace' and 'find' pages. - * @param {String} currentPageId The page id which receive values. - */ - function syncFieldsBetweenTabs( currentPageId ) - { - var sourceIndex, targetIndex, - sourceField, targetField; - - sourceIndex = currentPageId === 'find' ? 1 : 0; - targetIndex = 1 - sourceIndex; - var i, l = fieldsMapping.length; - for ( i = 0 ; i < l ; i++ ) - { - sourceField = this.getContentElement( pages[ sourceIndex ], - fieldsMapping[ i ][ sourceIndex ] ); - targetField = this.getContentElement( pages[ targetIndex ], - fieldsMapping[ i ][ targetIndex ] ); - - targetField.setValue( sourceField.getValue() ); - } - } - - var findDialog = function( editor, startupPage ) - { - // Style object for highlights: (#5018) - // 1. Defined as full match style to avoid compromising ordinary text color styles. - // 2. Must be apply onto inner-most text to avoid conflicting with ordinary text color styles visually. - var highlightStyle = new CKEDITOR.style( - CKEDITOR.tools.extend( { attributes : { 'data-cke-highlight': 1 }, fullMatch : 1, ignoreReadonly : 1, childRule : function(){ return 0; } }, - editor.config.find_highlight, true ) ); - - /** - * Iterator which walk through the specified range char by char. By - * default the walking will not stop at the character boundaries, until - * the end of the range is encountered. - * @param { CKEDITOR.dom.range } range - * @param {Boolean} matchWord Whether the walking will stop at character boundary. - */ - var characterWalker = function( range , matchWord ) - { - var self = this; - var walker = - new CKEDITOR.dom.walker( range ); - walker.guard = matchWord ? nonCharactersBoundary : function( node ) - { - !nonCharactersBoundary( node ) && ( self._.matchBoundary = true ); - }; - walker[ 'evaluator' ] = findEvaluator; - walker.breakOnFalse = 1; - - if ( range.startContainer.type == CKEDITOR.NODE_TEXT ) - { - this.textNode = range.startContainer; - this.offset = range.startOffset - 1; - } - - this._ = { - matchWord : matchWord, - walker : walker, - matchBoundary : false - }; - }; - - characterWalker.prototype = { - next : function() - { - return this.move(); - }, - - back : function() - { - return this.move( true ); - }, - - move : function( rtl ) - { - var currentTextNode = this.textNode; - // Already at the end of document, no more character available. - if ( currentTextNode === null ) - return cursorStep.call( this ); - - this._.matchBoundary = false; - - // There are more characters in the text node, step forward. - if ( currentTextNode - && rtl - && this.offset > 0 ) - { - this.offset--; - return cursorStep.call( this ); - } - else if ( currentTextNode - && this.offset < currentTextNode.getLength() - 1 ) - { - this.offset++; - return cursorStep.call( this ); - } - else - { - currentTextNode = null; - // At the end of the text node, walking foward for the next. - while ( !currentTextNode ) - { - currentTextNode = - this._.walker[ rtl ? 'previous' : 'next' ].call( this._.walker ); - - // Stop searching if we're need full word match OR - // already reach document end. - if ( this._.matchWord && !currentTextNode - || this._.walker._.end ) - break; - } - // Found a fresh text node. - this.textNode = currentTextNode; - if ( currentTextNode ) - this.offset = rtl ? currentTextNode.getLength() - 1 : 0; - else - this.offset = 0; - } - - return cursorStep.call( this ); - } - - }; - - /** - * A range of cursors which represent a trunk of characters which try to - * match, it has the same length as the pattern string. - */ - var characterRange = function( characterWalker, rangeLength ) - { - this._ = { - walker : characterWalker, - cursors : [], - rangeLength : rangeLength, - highlightRange : null, - isMatched : 0 - }; - }; - - characterRange.prototype = { - /** - * Translate this range to {@link CKEDITOR.dom.range} - */ - toDomRange : function() - { - var range = new CKEDITOR.dom.range( editor.document ); - var cursors = this._.cursors; - if ( cursors.length < 1 ) - { - var textNode = this._.walker.textNode; - if ( textNode ) - range.setStartAfter( textNode ); - else - return null; - } - else - { - var first = cursors[0], - last = cursors[ cursors.length - 1 ]; - - range.setStart( first.textNode, first.offset ); - range.setEnd( last.textNode, last.offset + 1 ); - } - - return range; - }, - /** - * Reflect the latest changes from dom range. - */ - updateFromDomRange : function( domRange ) - { - var cursor, - walker = new characterWalker( domRange ); - this._.cursors = []; - do - { - cursor = walker.next(); - if ( cursor.character ) - this._.cursors.push( cursor ); - } - while ( cursor.character ); - this._.rangeLength = this._.cursors.length; - }, - - setMatched : function() - { - this._.isMatched = true; - }, - - clearMatched : function() - { - this._.isMatched = false; - }, - - isMatched : function() - { - return this._.isMatched; - }, - - /** - * Hightlight the current matched chunk of text. - */ - highlight : function() - { - // Do not apply if nothing is found. - if ( this._.cursors.length < 1 ) - return; - - // Remove the previous highlight if there's one. - if ( this._.highlightRange ) - this.removeHighlight(); - - // Apply the highlight. - var range = this.toDomRange(), - bookmark = range.createBookmark(); - highlightStyle.applyToRange( range ); - range.moveToBookmark( bookmark ); - this._.highlightRange = range; - - // Scroll the editor to the highlighted area. - var element = range.startContainer; - if ( element.type != CKEDITOR.NODE_ELEMENT ) - element = element.getParent(); - element.scrollIntoView(); - - // Update the character cursors. - this.updateFromDomRange( range ); - }, - - /** - * Remove highlighted find result. - */ - removeHighlight : function() - { - if ( !this._.highlightRange ) - return; - - var bookmark = this._.highlightRange.createBookmark(); - highlightStyle.removeFromRange( this._.highlightRange ); - this._.highlightRange.moveToBookmark( bookmark ); - this.updateFromDomRange( this._.highlightRange ); - this._.highlightRange = null; - }, - - isReadOnly : function() - { - if ( !this._.highlightRange ) - return 0; - - return this._.highlightRange.startContainer.isReadOnly(); - }, - - moveBack : function() - { - var retval = this._.walker.back(), - cursors = this._.cursors; - - if ( retval.hitMatchBoundary ) - this._.cursors = cursors = []; - - cursors.unshift( retval ); - if ( cursors.length > this._.rangeLength ) - cursors.pop(); - - return retval; - }, - - moveNext : function() - { - var retval = this._.walker.next(), - cursors = this._.cursors; - - // Clear the cursors queue if we've crossed a match boundary. - if ( retval.hitMatchBoundary ) - this._.cursors = cursors = []; - - cursors.push( retval ); - if ( cursors.length > this._.rangeLength ) - cursors.shift(); - - return retval; - }, - - getEndCharacter : function() - { - var cursors = this._.cursors; - if ( cursors.length < 1 ) - return null; - - return cursors[ cursors.length - 1 ].character; - }, - - getNextCharacterRange : function( maxLength ) - { - var lastCursor, - nextRangeWalker, - cursors = this._.cursors; - - if ( ( lastCursor = cursors[ cursors.length - 1 ] ) && lastCursor.textNode ) - nextRangeWalker = new characterWalker( getRangeAfterCursor( lastCursor ) ); - // In case it's an empty range (no cursors), figure out next range from walker (#4951). - else - nextRangeWalker = this._.walker; - - return new characterRange( nextRangeWalker, maxLength ); - }, - - getCursors : function() - { - return this._.cursors; - } - }; - - - // The remaining document range after the character cursor. - function getRangeAfterCursor( cursor , inclusive ) - { - var range = new CKEDITOR.dom.range(); - range.setStart( cursor.textNode, - ( inclusive ? cursor.offset : cursor.offset + 1 ) ); - range.setEndAt( editor.document.getBody(), - CKEDITOR.POSITION_BEFORE_END ); - return range; - } - - // The document range before the character cursor. - function getRangeBeforeCursor( cursor ) - { - var range = new CKEDITOR.dom.range(); - range.setStartAt( editor.document.getBody(), - CKEDITOR.POSITION_AFTER_START ); - range.setEnd( cursor.textNode, cursor.offset ); - return range; - } - - var KMP_NOMATCH = 0, - KMP_ADVANCED = 1, - KMP_MATCHED = 2; - /** - * Examination the occurrence of a word which implement KMP algorithm. - */ - var kmpMatcher = function( pattern, ignoreCase ) - { - var overlap = [ -1 ]; - if ( ignoreCase ) - pattern = pattern.toLowerCase(); - for ( var i = 0 ; i < pattern.length ; i++ ) - { - overlap.push( overlap[i] + 1 ); - while ( overlap[ i + 1 ] > 0 - && pattern.charAt( i ) != pattern - .charAt( overlap[ i + 1 ] - 1 ) ) - overlap[ i + 1 ] = overlap[ overlap[ i + 1 ] - 1 ] + 1; - } - - this._ = { - overlap : overlap, - state : 0, - ignoreCase : !!ignoreCase, - pattern : pattern - }; - }; - - kmpMatcher.prototype = - { - feedCharacter : function( c ) - { - if ( this._.ignoreCase ) - c = c.toLowerCase(); - - while ( true ) - { - if ( c == this._.pattern.charAt( this._.state ) ) - { - this._.state++; - if ( this._.state == this._.pattern.length ) - { - this._.state = 0; - return KMP_MATCHED; - } - return KMP_ADVANCED; - } - else if ( !this._.state ) - return KMP_NOMATCH; - else - this._.state = this._.overlap[ this._.state ]; - } - - return null; - }, - - reset : function() - { - this._.state = 0; - } - }; - - var wordSeparatorRegex = - /[.,"'?!;: \u0085\u00a0\u1680\u280e\u2028\u2029\u202f\u205f\u3000]/; - - var isWordSeparator = function( c ) - { - if ( !c ) - return true; - var code = c.charCodeAt( 0 ); - return ( code >= 9 && code <= 0xd ) - || ( code >= 0x2000 && code <= 0x200a ) - || wordSeparatorRegex.test( c ); - }; - - var finder = { - searchRange : null, - matchRange : null, - find : function( pattern, matchCase, matchWord, matchCyclic, highlightMatched, cyclicRerun ) - { - if ( !this.matchRange ) - this.matchRange = - new characterRange( - new characterWalker( this.searchRange ), - pattern.length ); - else - { - this.matchRange.removeHighlight(); - this.matchRange = this.matchRange.getNextCharacterRange( pattern.length ); - } - - var matcher = new kmpMatcher( pattern, !matchCase ), - matchState = KMP_NOMATCH, - character = '%'; - - while ( character !== null ) - { - this.matchRange.moveNext(); - while ( ( character = this.matchRange.getEndCharacter() ) ) - { - matchState = matcher.feedCharacter( character ); - if ( matchState == KMP_MATCHED ) - break; - if ( this.matchRange.moveNext().hitMatchBoundary ) - matcher.reset(); - } - - if ( matchState == KMP_MATCHED ) - { - if ( matchWord ) - { - var cursors = this.matchRange.getCursors(), - tail = cursors[ cursors.length - 1 ], - head = cursors[ 0 ]; - - var rangeBefore = getRangeBeforeCursor( head ), - rangeAfter = getRangeAfterCursor( tail ); - - // The word boundary checks requires to trim the text nodes. (#9036) - rangeBefore.trim(); - rangeAfter.trim(); - - var headWalker = new characterWalker( rangeBefore, true ), - tailWalker = new characterWalker( rangeAfter, true ); - - if ( ! ( isWordSeparator( headWalker.back().character ) - && isWordSeparator( tailWalker.next().character ) ) ) - continue; - } - this.matchRange.setMatched(); - if ( highlightMatched !== false ) - this.matchRange.highlight(); - return true; - } - } - - this.matchRange.clearMatched(); - this.matchRange.removeHighlight(); - // Clear current session and restart with the default search - // range. - // Re-run the finding once for cyclic.(#3517) - if ( matchCyclic && !cyclicRerun ) - { - this.searchRange = getSearchRange( 1 ); - this.matchRange = null; - return arguments.callee.apply( this, - Array.prototype.slice.call( arguments ).concat( [ true ] ) ); - } - - return false; - }, - - /** - * Record how much replacement occurred toward one replacing. - */ - replaceCounter : 0, - - replace : function( dialog, pattern, newString, matchCase, matchWord, - matchCyclic , isReplaceAll ) - { - isReplace = 1; - - // Successiveness of current replace/find. - var result = 0; - - // 1. Perform the replace when there's already a match here. - // 2. Otherwise perform the find but don't replace it immediately. - if ( this.matchRange && this.matchRange.isMatched() - && !this.matchRange._.isReplaced && !this.matchRange.isReadOnly() ) - { - // Turn off highlight for a while when saving snapshots. - this.matchRange.removeHighlight(); - var domRange = this.matchRange.toDomRange(); - var text = editor.document.createText( newString ); - if ( !isReplaceAll ) - { - // Save undo snaps before and after the replacement. - var selection = editor.getSelection(); - selection.selectRanges( [ domRange ] ); - editor.fire( 'saveSnapshot' ); - } - domRange.deleteContents(); - domRange.insertNode( text ); - if ( !isReplaceAll ) - { - selection.selectRanges( [ domRange ] ); - editor.fire( 'saveSnapshot' ); - } - this.matchRange.updateFromDomRange( domRange ); - if ( !isReplaceAll ) - this.matchRange.highlight(); - this.matchRange._.isReplaced = true; - this.replaceCounter++; - result = 1; - } - else - result = this.find( pattern, matchCase, matchWord, matchCyclic, !isReplaceAll ); - - isReplace = 0; - - return result; - } - }; - - /** - * The range in which find/replace happened, receive from user - * selection prior. - */ - function getSearchRange( isDefault ) - { - var searchRange, - sel = editor.getSelection(), - body = editor.document.getBody(); - if ( sel && !isDefault ) - { - searchRange = sel.getRanges()[ 0 ].clone(); - searchRange.collapse( true ); - } - else - { - searchRange = new CKEDITOR.dom.range(); - searchRange.setStartAt( body, CKEDITOR.POSITION_AFTER_START ); - } - searchRange.setEndAt( body, CKEDITOR.POSITION_BEFORE_END ); - return searchRange; - } - - var lang = editor.lang.findAndReplace; - return { - title : lang.title, - resizable : CKEDITOR.DIALOG_RESIZE_NONE, - minWidth : 350, - minHeight : 170, - buttons : [ CKEDITOR.dialog.cancelButton ], // Cancel button only. - contents : [ - { - id : 'find', - label : lang.find, - title : lang.find, - accessKey : '', - elements : [ - { - type : 'hbox', - widths : [ '230px', '90px' ], - children : - [ - { - type : 'text', - id : 'txtFindFind', - label : lang.findWhat, - isChanged : false, - labelLayout : 'horizontal', - accessKey : 'F' - }, - { - type : 'button', - id : 'btnFind', - align : 'left', - style : 'width:100%', - label : lang.find, - onClick : function() - { - var dialog = this.getDialog(); - if ( !finder.find( dialog.getValueOf( 'find', 'txtFindFind' ), - dialog.getValueOf( 'find', 'txtFindCaseChk' ), - dialog.getValueOf( 'find', 'txtFindWordChk' ), - dialog.getValueOf( 'find', 'txtFindCyclic' ) ) ) - alert( lang - .notFoundMsg ); - } - } - ] - }, - { - type : 'fieldset', - label : CKEDITOR.tools.htmlEncode( lang.findOptions ), - style : 'margin-top:29px', - children : - [ - { - type : 'vbox', - padding : 0, - children : - [ - { - type : 'checkbox', - id : 'txtFindCaseChk', - isChanged : false, - label : lang.matchCase - }, - { - type : 'checkbox', - id : 'txtFindWordChk', - isChanged : false, - label : lang.matchWord - }, - { - type : 'checkbox', - id : 'txtFindCyclic', - isChanged : false, - 'default' : true, - label : lang.matchCyclic - } - ] - } - ] - } - ] - }, - { - id : 'replace', - label : lang.replace, - accessKey : 'M', - elements : [ - { - type : 'hbox', - widths : [ '230px', '90px' ], - children : - [ - { - type : 'text', - id : 'txtFindReplace', - label : lang.findWhat, - isChanged : false, - labelLayout : 'horizontal', - accessKey : 'F' - }, - { - type : 'button', - id : 'btnFindReplace', - align : 'left', - style : 'width:100%', - label : lang.replace, - onClick : function() - { - var dialog = this.getDialog(); - if ( !finder.replace( dialog, - dialog.getValueOf( 'replace', 'txtFindReplace' ), - dialog.getValueOf( 'replace', 'txtReplace' ), - dialog.getValueOf( 'replace', 'txtReplaceCaseChk' ), - dialog.getValueOf( 'replace', 'txtReplaceWordChk' ), - dialog.getValueOf( 'replace', 'txtReplaceCyclic' ) ) ) - alert( lang - .notFoundMsg ); - } - } - ] - }, - { - type : 'hbox', - widths : [ '230px', '90px' ], - children : - [ - { - type : 'text', - id : 'txtReplace', - label : lang.replaceWith, - isChanged : false, - labelLayout : 'horizontal', - accessKey : 'R' - }, - { - type : 'button', - id : 'btnReplaceAll', - align : 'left', - style : 'width:100%', - label : lang.replaceAll, - isChanged : false, - onClick : function() - { - var dialog = this.getDialog(); - var replaceNums; - - finder.replaceCounter = 0; - - // Scope to full document. - finder.searchRange = getSearchRange( 1 ); - if ( finder.matchRange ) - { - finder.matchRange.removeHighlight(); - finder.matchRange = null; - } - editor.fire( 'saveSnapshot' ); - while ( finder.replace( dialog, - dialog.getValueOf( 'replace', 'txtFindReplace' ), - dialog.getValueOf( 'replace', 'txtReplace' ), - dialog.getValueOf( 'replace', 'txtReplaceCaseChk' ), - dialog.getValueOf( 'replace', 'txtReplaceWordChk' ), - false, true ) ) - { /*jsl:pass*/ } - - if ( finder.replaceCounter ) - { - alert( lang.replaceSuccessMsg.replace( /%1/, finder.replaceCounter ) ); - editor.fire( 'saveSnapshot' ); - } - else - alert( lang.notFoundMsg ); - } - } - ] - }, - { - type : 'fieldset', - label : CKEDITOR.tools.htmlEncode( lang.findOptions ), - children : - [ - { - type : 'vbox', - padding : 0, - children : - [ - { - type : 'checkbox', - id : 'txtReplaceCaseChk', - isChanged : false, - label : lang.matchCase - }, - { - type : 'checkbox', - id : 'txtReplaceWordChk', - isChanged : false, - label : lang.matchWord - }, - { - type : 'checkbox', - id : 'txtReplaceCyclic', - isChanged : false, - 'default' : true, - label : lang.matchCyclic - } - ] - } - ] - } - ] - } - ], - onLoad : function() - { - var dialog = this; - - // Keep track of the current pattern field in use. - var patternField, wholeWordChkField; - - // Ignore initial page select on dialog show - var isUserSelect = 0; - this.on( 'hide', function() - { - isUserSelect = 0; - }); - this.on( 'show', function() - { - isUserSelect = 1; - }); - - this.selectPage = CKEDITOR.tools.override( this.selectPage, function( originalFunc ) - { - return function( pageId ) - { - originalFunc.call( dialog, pageId ); - - var currPage = dialog._.tabs[ pageId ]; - var patternFieldInput, patternFieldId, wholeWordChkFieldId; - patternFieldId = pageId === 'find' ? 'txtFindFind' : 'txtFindReplace'; - wholeWordChkFieldId = pageId === 'find' ? 'txtFindWordChk' : 'txtReplaceWordChk'; - - patternField = dialog.getContentElement( pageId, - patternFieldId ); - wholeWordChkField = dialog.getContentElement( pageId, - wholeWordChkFieldId ); - - // Prepare for check pattern text filed 'keyup' event - if ( !currPage.initialized ) - { - patternFieldInput = CKEDITOR.document - .getById( patternField._.inputId ); - currPage.initialized = true; - } - - // Synchronize fields on tab switch. - if ( isUserSelect ) - syncFieldsBetweenTabs.call( this, pageId ); - }; - } ); - - }, - onShow : function() - { - // Establish initial searching start position. - finder.searchRange = getSearchRange(); - - // Fill in the find field with selected text. - var selectedText = this.getParentEditor().getSelection().getSelectedText(), - patternFieldId = ( startupPage == 'find' ? 'txtFindFind' : 'txtFindReplace' ); - - var field = this.getContentElement( startupPage, patternFieldId ); - field.setValue( selectedText ); - field.select(); - - this.selectPage( startupPage ); - - this[ ( startupPage == 'find' && this._.editor.readOnly? 'hide' : 'show' ) + 'Page' ]( 'replace'); - }, - onHide : function() - { - var range; - if ( finder.matchRange && finder.matchRange.isMatched() ) - { - finder.matchRange.removeHighlight(); - editor.focus(); - - range = finder.matchRange.toDomRange(); - if ( range ) - editor.getSelection().selectRanges( [ range ] ); - } - - // Clear current session before dialog close - delete finder.matchRange; - }, - onFocus : function() - { - if ( startupPage == 'replace' ) - return this.getContentElement( 'replace', 'txtFindReplace' ); - else - return this.getContentElement( 'find', 'txtFindFind' ); - } - }; - }; - - CKEDITOR.dialog.add( 'find', function( editor ) - { - return findDialog( editor, 'find' ); - }); - - CKEDITOR.dialog.add( 'replace', function( editor ) - { - return findDialog( editor, 'replace' ); - }); -})();