X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=_source%2Fplugins%2Fstyles%2Fplugin.js;h=9a4f13d0948698c0a57ccfce2c733bb6b75ce3fc;hb=refs%2Ftags%2Fv3.5.3;hp=eade43b36e2ce5532d35b403e8c77e9d495a615e;hpb=9afde8772159bd3436f1f5b7862960307710ae5a;p=ckeditor.git diff --git a/_source/plugins/styles/plugin.js b/_source/plugins/styles/plugin.js index eade43b..9a4f13d 100644 --- a/_source/plugins/styles/plugin.js +++ b/_source/plugins/styles/plugin.js @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. +Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ @@ -19,11 +19,11 @@ CKEDITOR.plugins.add( 'styles', }); /** - * Registers a function to be called whenever a style changes its state in the + * Registers a function to be called whenever the selection position changes in the * editing area. The current state is passed to the function. The possible * states are {@link CKEDITOR.TRISTATE_ON} and {@link CKEDITOR.TRISTATE_OFF}. * @param {CKEDITOR.style} style The style to be watched. - * @param {Function} callback The function to be called when the style state changes. + * @param {Function} callback The function to be called. * @example * // Create a style object for the <b> element. * var style = new CKEDITOR.style( { element : 'b' } ); @@ -61,17 +61,9 @@ CKEDITOR.editor.prototype.attachStyleStateChange = function( style, callback ) // callback. var currentState = callback.style.checkActive( ev.data.path ) ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF; - // If the state changed since the last check. - if ( callback.state !== currentState ) - { - // Call the callback function, passing the current - // state to it. - callback.fn.call( this, currentState ); - - // Save the current state, so it can be compared next - // time. - callback.state = currentState; - } + // Call the callback function, passing the current + // state to it. + callback.fn.call( this, currentState ); } }); } @@ -87,10 +79,14 @@ CKEDITOR.STYLE_OBJECT = 3; (function() { - var blockElements = { address:1,div:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,p:1,pre:1 }; - var objectElements = { a:1,embed:1,hr:1,img:1,li:1,object:1,ol:1,table:1,td:1,tr:1,th:1,ul:1,dl:1,dt:1,dd:1,form:1}; + var blockElements = { address:1,div:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,p:1,pre:1 }, + objectElements = { a:1,embed:1,hr:1,img:1,li:1,object:1,ol:1,table:1,td:1,tr:1,th:1,ul:1,dl:1,dt:1,dd:1,form:1}; - var semicolonFixRegex = /\s*(?:;\s*|$)/; + var semicolonFixRegex = /\s*(?:;\s*|$)/, + varRegex = /#\((.+?)\)/g; + + var notBookmark = CKEDITOR.dom.walker.bookmark( 0, 1 ), + nonWhitespaces = CKEDITOR.dom.walker.whitespaces( 1 ); CKEDITOR.style = function( styleDefinition, variablesValues ) { @@ -105,7 +101,7 @@ CKEDITOR.STYLE_OBJECT = 3; var element = this.element = ( styleDefinition.element || '*' ).toLowerCase(); this.type = - ( element == '#' || blockElements[ element ] ) ? + blockElements[ element ] ? CKEDITOR.STYLE_BLOCK : objectElements[ element ] ? CKEDITOR.STYLE_OBJECT @@ -147,6 +143,8 @@ CKEDITOR.STYLE_OBJECT = 3; return ( this.removeFromRange = this.type == CKEDITOR.STYLE_INLINE ? removeInlineStyle + : this.type == CKEDITOR.STYLE_BLOCK ? + removeBlockStyle : this.type == CKEDITOR.STYLE_OBJECT ? removeObjectStyle : null ).call( this, range ); @@ -365,7 +363,7 @@ CKEDITOR.STYLE_OBJECT = 3; // Gets the parent element which blocks the styling for an element. This // can be done through read-only elements (contenteditable=false) or - // elements with the "data-cke-nostyle" attribute. + // elements with the "data-nostyle" attribute. function getUnstylableParent( element ) { var unstylable, @@ -376,7 +374,7 @@ CKEDITOR.STYLE_OBJECT = 3; if ( element.getName() == 'body' ) break; - if ( element.getAttribute( 'data-cke-nostyle' ) ) + if ( element.getAttribute( 'data-nostyle' ) ) unstylable = element; else if ( !editable ) { @@ -426,7 +424,7 @@ CKEDITOR.STYLE_OBJECT = 3; var dtd = CKEDITOR.dtd[ elementName ] || ( isUnknownElement = true, CKEDITOR.dtd.span ); // Expand the range. - range.enlarge( CKEDITOR.ENLARGE_ELEMENT ); + range.enlarge( CKEDITOR.ENLARGE_ELEMENT, 1 ); range.trim(); // Get the first node to be processed and the last, which concludes the @@ -471,7 +469,7 @@ CKEDITOR.STYLE_OBJECT = 3; var nodeType = currentNode.type; var nodeName = nodeType == CKEDITOR.NODE_ELEMENT ? currentNode.getName() : null; var nodeIsReadonly = nodeName && ( currentNode.getAttribute( 'contentEditable' ) == 'false' ); - var nodeIsNoStyle = nodeName && currentNode.getAttribute( 'data-cke-nostyle' ); + var nodeIsNoStyle = nodeName && currentNode.getAttribute( 'data-nostyle' ); if ( nodeName && currentNode.data( 'cke-bookmark' ) ) { @@ -514,8 +512,8 @@ CKEDITOR.STYLE_OBJECT = 3; // This node is about to be included completelly, but, // if this is the last node in its parent, we must also // check if the parent itself can be added completelly - // to the range. - while ( !includedNode.$.nextSibling + // to the range, otherwise apply the style immediately. + while ( ( applyStyle = !includedNode.getNext( notBookmark ) ) && ( parentNode = includedNode.getParent(), dtd[ parentNode.getName() ] ) && ( parentNode.getPosition( firstNode ) | CKEDITOR.POSITION_FOLLOWING | CKEDITOR.POSITION_IDENTICAL | CKEDITOR.POSITION_IS_CONTAINED ) == ( CKEDITOR.POSITION_FOLLOWING + CKEDITOR.POSITION_IDENTICAL + CKEDITOR.POSITION_IS_CONTAINED ) && ( !def.childRule || def.childRule( parentNode ) ) ) @@ -525,11 +523,6 @@ CKEDITOR.STYLE_OBJECT = 3; styleRange.setEndAfter( includedNode ); - // If the included node still is the last node in its - // parent, it means that the parent can't be included - // in this style DTD, so apply the style immediately. - if ( !includedNode.$.nextSibling ) - applyStyle = true; } } else @@ -658,7 +651,7 @@ CKEDITOR.STYLE_OBJECT = 3; * Make sure our range has included all "collpased" parent inline nodes so * that our operation logic can be simpler. */ - range.enlarge( CKEDITOR.ENLARGE_ELEMENT ); + range.enlarge( CKEDITOR.ENLARGE_ELEMENT, 1 ); var bookmark = range.createBookmark(), startNode = bookmark.startNode; @@ -704,8 +697,10 @@ CKEDITOR.STYLE_OBJECT = 3; * them before removal. */ element.mergeSiblings(); - removeFromElement( this, element ); - + if ( element.getName() == this.element ) + removeFromElement( this, element ); + else + removeOverrides( element, getOverrides( this )[ element.getName() ] ); } } } @@ -814,26 +809,26 @@ CKEDITOR.STYLE_OBJECT = 3; } range.moveToBookmark( bookmark ); -} + } function applyObjectStyle( range ) { var root = range.getCommonAncestor( true, true ), - element = root.getAscendant( this.element, true ); + element = root.getAscendant( this.element, true ); element && setupElement( element, this ); } function removeObjectStyle( range ) { var root = range.getCommonAncestor( true, true ), - element = root.getAscendant( this.element, true ); + element = root.getAscendant( this.element, true ); if ( !element ) return; - var style = this; - var def = style._.definition; - var attributes = def.attributes; + var style = this, + def = style._.definition, + attributes = def.attributes; var styles = CKEDITOR.style.getStyleText( def ); // Remove all defined attributes. @@ -884,13 +879,55 @@ CKEDITOR.STYLE_OBJECT = 3; range.moveToBookmark( bookmark ); } + function removeBlockStyle( range ) + { + // Serializible bookmarks is needed here since + // elements may be merged. + var bookmark = range.createBookmark( 1 ); + + var iterator = range.createIterator(); + iterator.enforceRealBlocks = true; + iterator.enlargeBr = this._.enterMode != CKEDITOR.ENTER_BR; + + var block; + while ( ( block = iterator.getNextParagraph() ) ) + { + if ( this.checkElementRemovable( block ) ) + { + //
get special treatment. + if ( block.is( 'pre' ) ) + { + var newBlock = this._.enterMode == CKEDITOR.ENTER_BR ? + null : range.document.createElement( + this._.enterMode == CKEDITOR.ENTER_P ? 'p' : 'div' ); + + newBlock && block.copyAttributes( newBlock ); + replaceBlock( block, newBlock ); + } + else + removeFromElement( this, block, 1 ); + } + } + + range.moveToBookmark( bookmark ); + } + // Replace the original block with new one, with special treatment // forblocks to make sure content format is well preserved, and merging/splitting adjacent // when necessary.(#3188) function replaceBlock( block, newBlock ) { - var newBlockIsPre = newBlock.is( 'pre' ); - var blockIsPre = block.is( 'pre' ); + // Block is to be removed, create a temp element to + // save contents. + var removeBlock = !newBlock; + if ( removeBlock ) + { + newBlock = block.getDocument().createElement( 'div' ); + block.copyAttributes( newBlock ); + } + + var newBlockIsPre = newBlock && newBlock.is( 'pre' ); + var blockIsPre = block.is( 'pre' ); var isToPre = newBlockIsPre && !blockIsPre; var isFromPre = !newBlockIsPre && blockIsPre; @@ -899,7 +936,8 @@ CKEDITOR.STYLE_OBJECT = 3; newBlock = toPre( block, newBlock ); else if ( isFromPre ) // Split biginto pieces before start to convert. - newBlock = fromPres( splitIntoPres( block ), newBlock ); + newBlock = fromPres( removeBlock ? + [ block.getHtml() ] : splitIntoPres( block ), newBlock ); else block.moveChildren( newBlock ); @@ -910,9 +948,10 @@ CKEDITOR.STYLE_OBJECT = 3; // Merge previousblocks. mergePre( newBlock ); } + else if ( removeBlock ) + removeNoAttribsElement( newBlock ); } - var nonWhitespaces = CKEDITOR.dom.walker.whitespaces( true ); /** * Merge ablock with a previous sibling if available. */ @@ -981,12 +1020,16 @@ CKEDITOR.STYLE_OBJECT = 3; } ); return headBookmark + str.replace( regexp, replacement ) + tailBookmark; } + /** * Converting a list ofinto blocks with format well preserved. */ function fromPres( preHtmls, newBlock ) { - var docFrag = new CKEDITOR.dom.documentFragment( newBlock.getDocument() ); + var docFrag; + if ( preHtmls.length > 1 ) + docFrag = new CKEDITOR.dom.documentFragment( newBlock.getDocument() ); + for ( var i = 0 ; i < preHtmls.length ; i++ ) { var blockHtml = preHtmls[ i ]; @@ -1016,11 +1059,17 @@ CKEDITOR.STYLE_OBJECT = 3; return CKEDITOR.tools.repeat( ' ', match.length - 1 ) + ' ' ; } ) ; - var newBlockClone = newBlock.clone(); - newBlockClone.setHtml( blockHtml ); - docFrag.append( newBlockClone ); + if ( docFrag ) + { + var newBlockClone = newBlock.clone(); + newBlockClone.setHtml( blockHtml ); + docFrag.append( newBlockClone ); + } + else + newBlock.setHtml( blockHtml ); } - return docFrag; + + return docFrag || newBlock; } /** @@ -1028,6 +1077,9 @@ CKEDITOR.STYLE_OBJECT = 3; */ function toPre( block, newBlock ) { + var bogus = block.getBogus(); + bogus && bogus.remove(); + // First trim the block content. var preHtml = block.getHtml(); @@ -1050,6 +1102,7 @@ CKEDITOR.STYLE_OBJECT = 3; var temp = block.getDocument().createElement( 'div' ); temp.append( newBlock ); newBlock.$.outerHTML = '' + preHtml + ''; + newBlock.copyAttributes( temp.getFirst() ); newBlock = temp.getFirst().remove(); } else @@ -1089,7 +1142,12 @@ CKEDITOR.STYLE_OBJECT = 3; element.removeStyle( styleName ); } - removeEmpty && removeNoAttribsElement( element ); + if ( removeEmpty ) + { + !CKEDITOR.dtd.$block[ element.getName() ] || style._.enterMode == CKEDITOR.ENTER_BR && !element.hasAttributes() ? + removeNoAttribsElement( element ) : + element.renameNode( style._.enterMode == CKEDITOR.ENTER_P ? 'p' : 'div' ); + } } // Removes a style from inside an element. @@ -1098,9 +1156,8 @@ CKEDITOR.STYLE_OBJECT = 3; var def = style._.definition, attribs = def.attributes, styles = def.styles, - overrides = getOverrides( style ); - - var innerElements = element.getElementsByTag( style.element ); + overrides = getOverrides( style ), + innerElements = element.getElementsByTag( style.element ); for ( var i = innerElements.count(); --i >= 0 ; ) removeFromElement( style, innerElements.getItem( i ) ); @@ -1119,7 +1176,6 @@ CKEDITOR.STYLE_OBJECT = 3; } } } - } /** @@ -1166,32 +1222,46 @@ CKEDITOR.STYLE_OBJECT = 3; // leaving its children. if ( !element.hasAttributes() ) { - // Removing elements may open points where merging is possible, - // so let's cache the first and last nodes for later checking. - var firstChild = element.getFirst(); - var lastChild = element.getLast(); + if ( CKEDITOR.dtd.$block[ element.getName() ] ) + { + var previous = element.getPrevious( nonWhitespaces ), + next = element.getNext( nonWhitespaces ); - element.remove( true ); + if ( previous && ( previous.type == CKEDITOR.NODE_TEXT || !previous.isBlockBoundary( { br : 1 } ) ) ) + element.append( 'br', 1 ); + if ( next && ( next.type == CKEDITOR.NODE_TEXT || !next.isBlockBoundary( { br : 1 } ) ) ) + element.append( 'br' ); - if ( firstChild ) + element.remove( true ); + } + else { - // Check the cached nodes for merging. - firstChild.type == CKEDITOR.NODE_ELEMENT && firstChild.mergeSiblings(); + // Removing elements may open points where merging is possible, + // so let's cache the first and last nodes for later checking. + var firstChild = element.getFirst(); + var lastChild = element.getLast(); + + element.remove( true ); + + if ( firstChild ) + { + // Check the cached nodes for merging. + firstChild.type == CKEDITOR.NODE_ELEMENT && firstChild.mergeSiblings(); + + if ( lastChild && !firstChild.equals( lastChild ) + && lastChild.type == CKEDITOR.NODE_ELEMENT ) + lastChild.mergeSiblings(); + } - if ( lastChild && !firstChild.equals( lastChild ) - && lastChild.type == CKEDITOR.NODE_ELEMENT ) - lastChild.mergeSiblings(); } } } function getElement( style, targetDocument, element ) { - var el; - - var def = style._.definition; - - var elementName = style.element; + var el, + def = style._.definition, + elementName = style.element; // The "*" element name will always be a span for this function. if ( elementName == '*' ) @@ -1204,14 +1274,22 @@ CKEDITOR.STYLE_OBJECT = 3; if ( element ) element.copyAttributes( el ); - return setupElement( el, style ); + el = setupElement( el, style ); + + // Avoid ID duplication. + if ( targetDocument.getCustomData( 'doc_processing_style' ) && el.hasAttribute( 'id' ) ) + el.removeAttribute( 'id' ); + else + targetDocument.setCustomData( 'doc_processing_style', 1 ); + + return el; } function setupElement( el, style ) { - var def = style._.definition; - var attributes = def.attributes; - var styles = CKEDITOR.style.getStyleText( def ); + var def = style._.definition, + attributes = def.attributes, + styles = CKEDITOR.style.getStyleText( def ); // Assign all defined attributes. if ( attributes ) @@ -1229,7 +1307,6 @@ CKEDITOR.STYLE_OBJECT = 3; return el; } - var varRegex = /#\((.+?)\)/g; function replaceVariables( list, variablesValues ) { for ( var item in list ) @@ -1241,7 +1318,6 @@ CKEDITOR.STYLE_OBJECT = 3; } } - // Returns an object that can be used for style matching comparison. // Attributes names and values are all lowercased, and the styles get // merged with the style attribute. @@ -1421,8 +1497,6 @@ CKEDITOR.STYLE_OBJECT = 3; function applyStyle( document, remove ) { var selection = document.getSelection(), - // Bookmark the range so we can re-select it after processing. - bookmarks = selection.createBookmarks( 1 ), ranges = selection.getRanges(), func = remove ? this.removeFromRange : this.applyToRange, range; @@ -1431,13 +1505,9 @@ CKEDITOR.STYLE_OBJECT = 3; while ( ( range = iterator.getNextRange() ) ) func.call( this, range ); - if ( bookmarks.length == 1 && bookmarks[0].collapsed ) - { - selection.selectRanges( ranges ); - document.getById( bookmarks[ 0 ].startNode ).remove(); - } - else - selection.selectBookmarks( bookmarks ); + selection.selectRanges( ranges ); + + document.removeCustomData( 'doc_processing_style' ); } })(); @@ -1463,6 +1533,37 @@ CKEDITOR.styleCommand.prototype.exec = function( editor ) return !!doc; }; +/** + * Manages styles registration and loading. See also {@link CKEDITOR.config.stylesSet}. + * @namespace + * @augments CKEDITOR.resourceManager + * @constructor + * @since 3.2 + * @example + * // The set of styles for the Styles combo + * CKEDITOR.stylesSet.add( 'default', + * [ + * // Block Styles + * { name : 'Blue Title' , element : 'h3', styles : { 'color' : 'Blue' } }, + * { name : 'Red Title' , element : 'h3', styles : { 'color' : 'Red' } }, + * + * // Inline Styles + * { name : 'Marker: Yellow' , element : 'span', styles : { 'background-color' : 'Yellow' } }, + * { name : 'Marker: Green' , element : 'span', styles : { 'background-color' : 'Lime' } }, + * + * // Object Styles + * { + * name : 'Image on Left', + * element : 'img', + * attributes : + * { + * 'style' : 'padding: 5px; margin-right: 5px', + * 'border' : '2', + * 'align' : 'left' + * } + * } + * ]); + */ CKEDITOR.stylesSet = new CKEDITOR.resourceManager( '', 'stylesSet' ); // Backward compatibility (#5025).