X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;ds=sidebyside;f=_source%2Fplugins%2Fpastefromword%2Ffilter%2Fdefault.js;h=dce3649ab778a1a2c2d38014908a1c04dc4d050b;hb=4e90e78dc97789709ee7404359a5517540c27553;hp=745bda36cd1d3190cf186022f09072c1e4426a58;hpb=941b0a9ba4e673e292510d80a5a86806994b8ea6;p=ckeditor.git diff --git a/_source/plugins/pastefromword/filter/default.js b/_source/plugins/pastefromword/filter/default.js index 745bda3..dce3649 100644 --- a/_source/plugins/pastefromword/filter/default.js +++ b/_source/plugins/pastefromword/filter/default.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 */ @@ -25,7 +25,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license for ( var i = 0; i < children.length; i++ ) { child = children[ i ]; - if( !child.name ) + if ( !child.name ) continue; if ( child.name == tagName ) @@ -60,15 +60,13 @@ For licensing, see LICENSE.html or http://ckeditor.com/license child = child.firstChild( evaluator ); if ( child ) return child; - else - continue; } } return null; }; - // Adding a (set) of styles to the element's attributes. + // Adding a (set) of styles to the element's 'style' attributes. elementPrototype.addStyle = function( name, value, isPrepend ) { var styleText, addingStyleText = ''; @@ -80,9 +78,9 @@ For licensing, see LICENSE.html or http://ckeditor.com/license // style literal. if ( typeof name == 'object' ) { - for( var style in name ) + for ( var style in name ) { - if( name.hasOwnProperty( style ) ) + if ( name.hasOwnProperty( style ) ) addingStyleText += style + ':' + name[ style ] + ';'; } } @@ -93,7 +91,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license isPrepend = value; } - if( !this.attributes ) + if ( !this.attributes ) this.attributes = {}; styleText = this.attributes.style || ''; @@ -120,65 +118,107 @@ For licensing, see LICENSE.html or http://ckeditor.com/license return result; }; - var cssLengthRelativeUnit = /^(\d[.\d]*)+(em|ex|px|gd|rem|vw|vh|vm|ch|mm|cm|in|pt|pc|deg|rad|ms|s|hz|khz){1}?/i; - var emptyMarginRegex = /^(?:\b0[^\s]*\s*){1,4}$/; + // 1. move consistent list item styles up to list root. + // 2. clear out unnecessary list item numbering. + function postProcessList( list ) + { + var children = list.children, + child, + attrs, + count = list.children.length, + match, + mergeStyle, + styleTypeRegexp = /list-style-type:(.*?)(?:;|$)/, + stylesFilter = CKEDITOR.plugins.pastefromword.filters.stylesFilter; + + attrs = list.attributes; + if ( styleTypeRegexp.exec( attrs.style ) ) + return; + + for ( var i = 0; i < count; i++ ) + { + child = children[ i ]; + + if ( child.attributes.value && Number( child.attributes.value ) == i + 1 ) + delete child.attributes.value; + + match = styleTypeRegexp.exec( child.attributes.style ); + + if ( match ) + { + if ( match[ 1 ] == mergeStyle || !mergeStyle ) + mergeStyle = match[ 1 ]; + else + { + mergeStyle = null; + break; + } + } + } + + if ( mergeStyle ) + { + for ( i = 0; i < count; i++ ) + { + attrs = children[ i ].attributes; + attrs.style && ( attrs.style = stylesFilter( [ [ 'list-style-type'] ] )( attrs.style ) || '' ); + } + + list.addStyle( 'list-style-type', mergeStyle ); + } + } + + var cssLengthRelativeUnit = /^([.\d]*)+(em|ex|px|gd|rem|vw|vh|vm|ch|mm|cm|in|pt|pc|deg|rad|ms|s|hz|khz){1}?/i; + var emptyMarginRegex = /^(?:\b0[^\s]*\s*){1,4}$/; // e.g. 0px 0pt 0px + var romanLiternalPattern = '^m{0,4}(cm|cd|d?c{0,3})(xc|xl|l?x{0,3})(ix|iv|v?i{0,3})$', + lowerRomanLiteralRegex = new RegExp( romanLiternalPattern ), + upperRomanLiteralRegex = new RegExp( romanLiternalPattern.toUpperCase() ); + + var orderedPatterns = { 'decimal' : /\d+/, 'lower-roman': lowerRomanLiteralRegex, 'upper-roman': upperRomanLiteralRegex, 'lower-alpha' : /^[a-z]+$/, 'upper-alpha': /^[A-Z]+$/ }, + unorderedPatterns = { 'disc' : /[l\u00B7\u2002]/, 'circle' : /[\u006F\u00D8]/,'square' : /[\u006E\u25C6]/}, + listMarkerPatterns = { 'ol' : orderedPatterns, 'ul' : unorderedPatterns }, + romans = [ [1000, 'M'], [900, 'CM'], [500, 'D'], [400, 'CD'], [100, 'C'], [90, 'XC'], [50, 'L'], [40, 'XL'], [10, 'X'], [9, 'IX'], [5, 'V'], [4, 'IV'], [1, 'I'] ], + alpahbets = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + // Convert roman numbering back to decimal. + function fromRoman( str ) + { + str = str.toUpperCase(); + var l = romans.length, retVal = 0; + for ( var i = 0; i < l; ++i ) + { + for ( var j = romans[i], k = j[1].length; str.substr( 0, k ) == j[1]; str = str.substr( k ) ) + retVal += j[ 0 ]; + } + return retVal; + } + + // Convert alphabet numbering back to decimal. + function fromAlphabet( str ) + { + str = str.toUpperCase(); + var l = alpahbets.length, retVal = 1; + for ( var x = 1; str.length > 0; x *= l ) + { + retVal += alpahbets.indexOf( str.charAt( str.length - 1 ) ) * x; + str = str.substr( 0, str.length - 1 ); + } + return retVal; + } var listBaseIndent = 0, - previousListItemMargin; + previousListItemMargin = null, + previousListId; - CKEDITOR.plugins.pastefromword = + var plugin = ( CKEDITOR.plugins.pastefromword = { utils : { // Create a which indicate an list item type. - createListBulletMarker : function ( bulletStyle, bulletText ) + createListBulletMarker : function ( bullet, bulletText ) { - var marker = new CKEDITOR.htmlParser.element( 'cke:listbullet' ), - listType; - - // TODO: Support more list style type from MS-Word. - if ( !bulletStyle ) - { - bulletStyle = 'decimal'; - listType = 'ol'; - } - else if ( bulletStyle[ 2 ] ) - { - if ( !isNaN( bulletStyle[ 1 ] ) ) - bulletStyle = 'decimal'; - // No way to distinguish between Roman numerals and Alphas, - // detect them as a whole. - else if ( /^[a-z]+$/.test( bulletStyle[ 1 ] ) ) - bulletStyle = 'lower-alpha'; - else if ( /^[A-Z]+$/.test( bulletStyle[ 1 ] ) ) - bulletStyle = 'upper-alpha'; - // Simply use decimal for the rest forms of unrepresentable - // numerals, e.g. Chinese... - else - bulletStyle = 'decimal'; - - listType = 'ol'; - } - else - { - if ( /[l\u00B7\u2002]/.test( bulletStyle[ 1 ] ) ) //l·• - bulletStyle = 'disc'; - else if ( /[\u006F\u00D8]/.test( bulletStyle[ 1 ] ) ) //oØ - bulletStyle = 'circle'; - else if ( /[\u006E\u25C6]/.test( bulletStyle[ 1 ] ) ) //n◆ - bulletStyle = 'square'; - else - bulletStyle = 'disc'; - - listType = 'ul'; - } - - // Represent list type as CSS style. - marker.attributes = - { - 'cke:listtype' : listType, - 'style' : 'list-style-type:' + bulletStyle + ';' - }; + var marker = new CKEDITOR.htmlParser.element( 'cke:listbullet' ); + marker.attributes = { 'cke:listsymbol' : bullet[ 0 ] }; marker.add( new CKEDITOR.htmlParser.text( bulletText ) ); return marker; }, @@ -186,7 +226,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license isListBulletIndicator : function( element ) { var styleText = element.attributes && element.attributes.style; - if( /mso-list\s*:\s*Ignore/i.test( styleText ) ) + if ( /mso-list\s*:\s*Ignore/i.test( styleText ) ) return true; }, @@ -200,48 +240,69 @@ For licensing, see LICENSE.html or http://ckeditor.com/license resolveList : function( element ) { // indicate a list item. - var children = element.children, - attrs = element.attributes, + var attrs = element.attributes, listMarker; if ( ( listMarker = element.removeAnyChildWithName( 'cke:listbullet' ) ) - && listMarker.length - && ( listMarker = listMarker[ 0 ] ) ) + && listMarker.length + && ( listMarker = listMarker[ 0 ] ) ) { element.name = 'cke:li'; if ( attrs.style ) { - attrs.style = CKEDITOR.plugins.pastefromword.filters.stylesFilter( + attrs.style = plugin.filters.stylesFilter( [ // Text-indent is not representing list item level any more. [ 'text-indent' ], [ 'line-height' ], - // Resolve indent level from 'margin-left' value. + // First attempt is to resolve indent level from on a constant margin increment. [ ( /^margin(:?-left)?$/ ), null, function( margin ) { - // Be able to deal with component/short-hand form style. + // Deal with component/short-hand form. var values = margin.split( ' ' ); - margin = values[ 3 ] || values[ 1 ] || values [ 0 ]; + margin = plugin.utils.convertToPx( values[ 3 ] || values[ 1 ] || values [ 0 ] ); margin = parseInt( margin, 10 ); - // Figure out the indent unit by looking at the first increament. - if ( !listBaseIndent && previousListItemMargin && margin > previousListItemMargin ) + // Figure out the indent unit by checking the first time of incrementation. + if ( !listBaseIndent && previousListItemMargin !== null && margin > previousListItemMargin ) listBaseIndent = margin - previousListItemMargin; - attrs[ 'cke:margin' ] = previousListItemMargin = margin; + previousListItemMargin = margin; + + attrs[ 'cke:indent' ] = listBaseIndent && ( Math.ceil( margin / listBaseIndent ) + 1 ) || 1; + } ], + // The best situation: "mso-list:l0 level1 lfo2" tells the belonged list root, list item indentation, etc. + [ ( /^mso-list$/ ), null, function( val ) + { + val = val.split( ' ' ); + var listId = Number( val[ 0 ].match( /\d+/ ) ), + indent = Number( val[ 1 ].match( /\d+/ ) ); + + listId !== previousListId && ( attrs[ 'cke:reset' ] = 1 ); + previousListId = listId; + attrs[ 'cke:indent' ] = indent; } ] - ] )( attrs.style, element ) || '' ; + ] )( attrs.style, element ) || ''; } - // Inherit list-type-style from bullet. - var listBulletAttrs = listMarker.attributes, - listBulletStyle = listBulletAttrs.style; + // First level list item might be presented without a margin. - element.addStyle( listBulletStyle ); - CKEDITOR.tools.extend( attrs, listBulletAttrs ); + + // In case all above doesn't apply. + if ( !attrs[ 'cke:indent' ] ) + { + previousListItemMargin = 0; + attrs[ 'cke:indent' ] = 1; + } + + // Inherit attributes from bullet. + CKEDITOR.tools.extend( attrs, listMarker.attributes ); return true; } + // Current list disconnected. + else + previousListId = previousListItemMargin = listBaseIndent = null; return false; }, @@ -257,7 +318,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license return function( cssLength ) { - if( cssLengthRelativeUnit.test( cssLength ) ) + if ( cssLengthRelativeUnit.test( cssLength ) ) { calculator.setStyle( 'width', cssLength ); return calculator.$.clientWidth + 'px'; @@ -307,7 +368,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license // Resolve how many level nested. while ( parent ) { - parent.attributes && parent.attributes[ 'cke:list'] && indentLevel++; + parent.attributes && parent.attributes[ 'cke:list' ] && indentLevel++; parent = parent.parent; } @@ -328,14 +389,14 @@ For licensing, see LICENSE.html or http://ckeditor.com/license child = children[ i ]; var attributes = child.attributes; - if( child.name in CKEDITOR.dtd.$listItem ) + if ( child.name in CKEDITOR.dtd.$listItem ) { var listItemChildren = child.children, count = listItemChildren.length, last = listItemChildren[ count - 1 ]; // Move out nested list. - if( last.name in CKEDITOR.dtd.$list ) + if ( last.name in CKEDITOR.dtd.$list ) { children.splice( i + 1, 0, last ); last.parent = element; @@ -346,10 +407,29 @@ For licensing, see LICENSE.html or http://ckeditor.com/license } child.name = 'cke:li'; + + // Inherit numbering from list root on the first list item. + attrs.start && !i && ( attributes.value = attrs.start ); + + plugin.filters.stylesFilter( + [ + [ 'tab-stops', null, function( val ) + { + var margin = val.split( ' ' )[ 1 ].match( cssLengthRelativeUnit ); + margin && ( previousListItemMargin = parseInt( plugin.utils.convertToPx( margin[ 0 ] ), 10 ) ); + } ], + [ 'mso-list', null, function( val ) + { + val = val.split( ' ' ); + var listId = Number( val[ 0 ].match( /\d+/ ) ); + listId !== previousListId && ( attributes[ 'cke:reset' ] = 1 ); + previousListId = listId; + } ] + ] )( attributes.style ); + attributes[ 'cke:indent' ] = indentLevel; - previousListItemMargin = 0; attributes[ 'cke:listtype' ] = element.name; - listStyleType && child.addStyle( 'list-style-type', listStyleType, true ); + attributes[ 'cke:list-style-type' ] = listStyleType; } } @@ -369,11 +449,19 @@ For licensing, see LICENSE.html or http://ckeditor.com/license var children = element.children, child, listItem, // The current processing cke:li element. listItemAttrs, - listType, // Determine the root type of the list. listItemIndent, // Indent level of current list item. + lastIndent, lastListItem, // The previous one just been added to the list. - list, parentList, // Current staging list and it's parent list if any. - indent; + list, // Current staging list and it's parent list if any. + openedLists = [], + previousListStyleType, + previousListType; + + // Properties of the list item are to be resolved from the list bullet. + var bullet, + listType, + listStyleType, + itemNumeric; for ( var i = 0; i < children.length; i++ ) { @@ -384,44 +472,129 @@ For licensing, see LICENSE.html or http://ckeditor.com/license child.name = 'li'; listItem = child; listItemAttrs = listItem.attributes; - listType = listItem.attributes[ 'cke:listtype' ]; + bullet = listItemAttrs[ 'cke:listsymbol' ]; + bullet = bullet && bullet.match( /^(?:[(]?)([^\s]+?)([.)]?)$/ ); + listType = listStyleType = itemNumeric = null; + + if ( listItemAttrs[ 'cke:ignored' ] ) + { + children.splice( i--, 1 ); + continue; + } + + + // This's from a new list root. + listItemAttrs[ 'cke:reset' ] && ( list = lastIndent = lastListItem = null ); // List item indent level might come from a real list indentation or // been resolved from a pseudo list item's margin value, even get // no indentation at all. - listItemIndent = parseInt( listItemAttrs[ 'cke:indent' ], 10 ) - || listBaseIndent && ( Math.ceil( listItemAttrs[ 'cke:margin' ] / listBaseIndent ) ) - || 1; - - // Ignore the 'list-style-type' attribute if it's matched with - // the list root element's default style type. - listItemAttrs.style && ( listItemAttrs.style = - CKEDITOR.plugins.pastefromword.filters.stylesFilter( - [ - [ 'list-style-type', listType == 'ol' ? 'decimal' : 'disc' ] - ] )( listItemAttrs.style ) - || '' ); + listItemIndent = Number( listItemAttrs[ 'cke:indent' ] ); + + // We're moving out of the current list, cleaning up. + if ( listItemIndent != lastIndent ) + previousListType = previousListStyleType = null; + + // List type and item style are already resolved. + if ( !bullet ) + { + listType = listItemAttrs[ 'cke:listtype' ] || 'ol'; + listStyleType = listItemAttrs[ 'cke:list-style-type' ]; + } + else + { + // Probably share the same list style type with previous list item, + // give it priority to avoid ambiguous between C(Alpha) and C.(Roman). + if ( previousListType && listMarkerPatterns[ previousListType ] [ previousListStyleType ].test( bullet[ 1 ] ) ) + { + listType = previousListType; + listStyleType = previousListStyleType; + } + else + { + for ( var type in listMarkerPatterns ) + { + for ( var style in listMarkerPatterns[ type ] ) + { + if ( listMarkerPatterns[ type ][ style ].test( bullet[ 1 ] ) ) + { + // Small numbering has higher priority, when dealing with ambiguous + // between C(Alpha) and C.(Roman). + if ( type == 'ol' && ( /alpha|roman/ ).test( style ) ) + { + var num = /roman/.test( style ) ? fromRoman( bullet[ 1 ] ) : fromAlphabet( bullet[ 1 ] ); + if ( !itemNumeric || num < itemNumeric ) + { + itemNumeric = num; + listType = type; + listStyleType = style; + } + } + else + { + listType = type; + listStyleType = style; + break; + } + } + } + } + } + + // Simply use decimal/disc for the rest forms of unrepresentable + // numerals, e.g. Chinese..., but as long as there a second part + // included, it has a bigger chance of being a order list ;) + !listType && ( listType = bullet[ 2 ] ? 'ol' : 'ul' ); + } + + previousListType = listType; + previousListStyleType = listStyleType || ( listType == 'ol' ? 'decimal' : 'disc' ); + if ( listStyleType && listStyleType != ( listType == 'ol' ? 'decimal' : 'disc' ) ) + listItem.addStyle( 'list-style-type', listStyleType ); + // Figure out start numbering. + if ( listType == 'ol' && bullet ) + { + switch ( listStyleType ) + { + case 'decimal' : + itemNumeric = Number( bullet[ 1 ] ); + break; + case 'lower-roman': + case 'upper-roman': + itemNumeric = fromRoman( bullet[ 1 ] ); + break; + case 'lower-alpha': + case 'upper-alpha': + itemNumeric = fromAlphabet( bullet[ 1 ] ); + break; + } + + // Always create the numbering, swipe out unnecessary ones later. + listItem.attributes.value = itemNumeric; + } + + // Start the list construction. if ( !list ) { - list = new CKEDITOR.htmlParser.element( listType ); + openedLists.push( list = new CKEDITOR.htmlParser.element( listType ) ); list.add( listItem ); children[ i ] = list; } else { - if ( listItemIndent > indent ) + if ( listItemIndent > lastIndent ) { - list = new CKEDITOR.htmlParser.element( listType ); + openedLists.push( list = new CKEDITOR.htmlParser.element( listType ) ); list.add( listItem ); lastListItem.add( list ); } - else if ( listItemIndent < indent ) + else if ( listItemIndent < lastIndent ) { // There might be a negative gap between two list levels. (#4944) - var diff = indent - listItemIndent, - parent = list.parent; - while( diff-- && parent ) + var diff = lastIndent - listItemIndent, + parent; + while ( diff-- && ( parent = list.parent ) ) list = parent.parent; list.add( listItem ); @@ -433,13 +606,16 @@ For licensing, see LICENSE.html or http://ckeditor.com/license } lastListItem = listItem; - indent = listItemIndent; + lastIndent = listItemIndent; } - else - list = null; + else if ( list ) + list = lastIndent = lastListItem = null; } - listBaseIndent = 0; + for ( i = 0; i < openedLists.length; i++ ) + postProcessList( openedLists[ i ] ); + + list = lastIndent = lastListItem = previousListId = previousListItemMargin = listBaseIndent = null; }, /** @@ -465,7 +641,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license // html-encoded quote might be introduced by 'font-family' // from MS-Word which confused the following regexp. e.g. //'font-family: "Lucida, Console"' - styleText + ( styleText || '' ) .replace( /"/g, '"' ) .replace( /\s*([^ :;]+)\s*:\s*([^;]+)\s*(?=;|$)/g, function( match, name, value ) @@ -477,9 +653,9 @@ For licensing, see LICENSE.html or http://ckeditor.com/license valuePattern, newValue, newName; - for( var i = 0 ; i < styles.length; i++ ) + for ( var i = 0 ; i < styles.length; i++ ) { - if( styles[ i ] ) + if ( styles[ i ] ) { namePattern = styles[ i ][ 0 ]; valuePattern = styles[ i ][ 1 ]; @@ -492,15 +668,15 @@ For licensing, see LICENSE.html or http://ckeditor.com/license name = newName || name; whitelist && ( newValue = newValue || value ); - if( typeof newValue == 'function' ) + if ( typeof newValue == 'function' ) newValue = newValue( value, element, name ); // Return an couple indicate both name and value // changed. - if( newValue && newValue.push ) + if ( newValue && newValue.push ) name = newValue[ 0 ], newValue = newValue[ 1 ]; - if( typeof newValue == 'string' ) + if ( typeof newValue == 'string' ) rules.push( [ name, newValue ] ); return; } @@ -567,7 +743,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license */ bogusAttrFilter : function( value, element ) { - if( element.name.indexOf( 'cke:' ) == -1 ) + if ( element.name.indexOf( 'cke:' ) == -1 ) return false; }, @@ -589,7 +765,6 @@ For licensing, see LICENSE.html or http://ckeditor.com/license stylesFilter = filters.stylesFilter, elementMigrateFilter = filters.elementMigrateFilter, styleMigrateFilter = CKEDITOR.tools.bind( this.filters.styleMigrateFilter, this.filters ), - bogusAttrFilter = filters.bogusAttrFilter, createListBulletMarker = this.utils.createListBulletMarker, flattenList = filters.flattenList, assembleList = filters.assembleList, @@ -645,7 +820,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license { element.filterChildren(); // Is the heading actually a list item? - if( resolveListItem( element ) ) + if ( resolveListItem( element ) ) return; // Adapt heading styles to editor's convention. @@ -720,12 +895,12 @@ For licensing, see LICENSE.html or http://ckeditor.com/license className = className.substring( 1, className.length ); // Reject MS-Word Normal styles. - if( className.match( /MsoNormal/ ) ) + if ( className.match( /MsoNormal/ ) ) return; - if( !rules[ tagName ] ) + if ( !rules[ tagName ] ) rules[ tagName ] = {}; - if( className ) + if ( className ) rules[ tagName ][ className ] = styleBlock; else rules[ tagName ] = styleBlock; @@ -738,10 +913,10 @@ For licensing, see LICENSE.html or http://ckeditor.com/license var name = rules[ '*' ] ? '*' : element.name, className = element.attributes && element.attributes[ 'class' ], style; - if( name in rules ) + if ( name in rules ) { style = rules[ name ]; - if( typeof style == 'object' ) + if ( typeof style == 'object' ) style = style[ className ]; // Maintain style rules priorities. style && element.addStyle( style, true ); @@ -754,11 +929,21 @@ For licensing, see LICENSE.html or http://ckeditor.com/license 'p' : function( element ) { - element.filterChildren(); + // This's a fall-back approach to recognize list item in FF3.6, + // as it's not perfect as not all list style (e.g. "heading list") is shipped + // with this pattern. (#6662) + if ( /MsoListParagraph/.exec( element.attributes[ 'class' ] ) ) + { + var bulletText = element.firstChild( function( node ) + { + return node.type == CKEDITOR.NODE_TEXT && !containsNothingButSpaces( node.parent ); + }); + var bullet = bulletText && bulletText.parent, + bulletAttrs = bullet && bullet.attributes; + bulletAttrs && !bulletAttrs.style && ( bulletAttrs.style = 'mso-list: Ignore;' ); + } - var attrs = element.attributes, - parent = element.parent, - children = element.children; + element.filterChildren(); // Is the paragraph actually a list item? if ( resolveListItem( element ) ) @@ -782,7 +967,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license // table cells inherit as text-align styles, which is wrong. // Instead we use a clear-float div after the table to properly achieve the same layout. var singleChild = element.onlyChild(); - if( singleChild && singleChild.name == 'table' ) + if ( singleChild && singleChild.name == 'table' ) { var attrs = element.attributes; singleChild.attributes = CKEDITOR.tools.extend( singleChild.attributes, attrs ); @@ -810,8 +995,8 @@ For licensing, see LICENSE.html or http://ckeditor.com/license 'font' : function( element ) { - // IE/Safari: drop the font tag if it comes from list bullet text. - if ( !CKEDITOR.env.gecko && isListBulletIndicator( element.parent ) ) + // Drop the font tag if it comes from list bullet text. + if ( isListBulletIndicator( element.parent ) ) { delete element.name; return; @@ -829,7 +1014,6 @@ For licensing, see LICENSE.html or http://ckeditor.com/license element.attributes ); styleText && parent.addStyle( styleText ); delete element.name; - return; } // Convert the merged into a span with all attributes preserved. else @@ -863,8 +1047,8 @@ For licensing, see LICENSE.html or http://ckeditor.com/license 'span' : function( element ) { - // IE/Safari: remove the span if it comes from list bullet text. - if ( !CKEDITOR.env.gecko && isListBulletIndicator( element.parent ) ) + // Remove the span if it comes from list bullet text. + if ( isListBulletIndicator( element.parent ) ) return false; element.filterChildren(); @@ -874,9 +1058,9 @@ For licensing, see LICENSE.html or http://ckeditor.com/license return null; } - // For IE/Safari: List item bullet type is supposed to be indicated by + // List item bullet type is supposed to be indicated by // the text of a span with style 'mso-list : Ignore' or an image. - if ( !CKEDITOR.env.gecko && isListBulletIndicator( element ) ) + if ( isListBulletIndicator( element ) ) { var listSymbolNode = element.firstChild( function( node ) { @@ -884,8 +1068,18 @@ For licensing, see LICENSE.html or http://ckeditor.com/license }); var listSymbol = listSymbolNode && ( listSymbolNode.value || 'l.' ), - listType = listSymbol.match( /^([^\s]+?)([.)]?)$/ ); - return createListBulletMarker( listType, listSymbol ); + listType = listSymbol && listSymbol.match( /^(?:[(]?)([^\s]+?)([.)]?)$/ ); + + if ( listType ) + { + var marker = createListBulletMarker( listType, listSymbol ); + // Some non-existed list items might be carried by an inconsequential list, indicate by "mso-hide:all/display:none", + // those are to be removed later, now mark it with "cke:ignored". + var ancestor = element.getAncestor( 'span' ); + if ( ancestor && (/ mso-hide:\s*all|display:\s*none /).test( ancestor.attributes.style ) ) + marker.attributes[ 'cke:ignored' ] = 1; + return marker; + } } // Update the src attribute of image element with href. @@ -924,14 +1118,14 @@ For licensing, see LICENSE.html or http://ckeditor.com/license 'a' : function( element ) { var attrs = element.attributes; - if( attrs && !attrs.href && attrs.name ) + if ( attrs && !attrs.href && attrs.name ) delete element.name; }, 'cke:listbullet' : function( element ) { if ( element.getAncestor( /h\d/ ) && !config.pasteFromWordNumberedHeadingToList ) delete element.name; - } + } }, attributeNames : @@ -953,6 +1147,9 @@ For licensing, see LICENSE.html or http://ckeditor.com/license // Provide a white-list of styles that we preserve, those should // be the ones that could later be altered with editor tools. [ + // Leave list-style-type + [ ( /^list-style-type$/ ), null ], + // Preserve margin-left/right which used as default indent style in the editor. [ ( /^margin$|^margin-(?!bottom|top)/ ), null, function( value, element, name ) { @@ -983,14 +1180,14 @@ For licensing, see LICENSE.html or http://ckeditor.com/license [ ( /^border.*|margin.*|vertical-align|float$/ ), null, function( value, element ) { - if( element.name == 'img' ) + if ( element.name == 'img' ) return value; } ], [ (/^width|height$/ ), null, function( value, element ) { - if( element.name in { table : 1, td : 1, th : 1, img : 1 } ) + if ( element.name in { table : 1, td : 1, th : 1, img : 1 } ) return value; } ] ] : @@ -1000,9 +1197,9 @@ For licensing, see LICENSE.html or http://ckeditor.com/license // Fixing color values. [ ( /-color$/ ), null, function( value ) { - if( value == 'transparent' ) + if ( value == 'transparent' ) return false; - if( CKEDITOR.env.gecko ) + if ( CKEDITOR.env.gecko ) return value.replace( /-moz-use-text-color/g, 'transparent' ); } ], // Remove empty margin values, e.g. 0.00001pt 0em 0pt @@ -1017,13 +1214,13 @@ For licensing, see LICENSE.html or http://ckeditor.com/license // Prefer width styles over 'width' attributes. 'width' : function( value, element ) { - if( element.name in dtd.$tableContent ) + if ( element.name in dtd.$tableContent ) return false; }, // Prefer border styles over table 'border' attributes. 'border' : function( value, element ) { - if( element.name in dtd.$tableContent ) + if ( element.name in dtd.$tableContent ) return false; }, @@ -1059,12 +1256,12 @@ For licensing, see LICENSE.html or http://ckeditor.com/license { // Bullet symbol could be either text or an image. var listSymbol = listInfo[ 1 ] || ( imageInfo && 'l.' ), - listType = listSymbol && listSymbol.match( />([^\s]+?)([.)]?)(?:[(]?)([^\s]+?)([.)]?) element in conditional comments for Firefox. - if( CKEDITOR.env.gecko && imageInfo ) + if ( CKEDITOR.env.gecko && imageInfo ) { var img = CKEDITOR.htmlParser.fragment.fromHtml( imageInfo[ 0 ] ).children[ 0 ], previousComment = node.previous, @@ -1082,7 +1279,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license : falsyFilter }; } - }; + }); // The paste processor here is just a reduced copy of html data processor. var pasteProcessor = function() @@ -1107,7 +1304,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license // Firefox will be confused by those downlevel-revealed IE conditional // comments, fixing them first( convert it to upperlevel-revealed one ). // e.g. ... - if( CKEDITOR.env.gecko ) + if ( CKEDITOR.env.gecko ) data = data.replace( /(([\S\s]*?))/gi, '$1$2$3' ); var dataProcessor = new pasteProcessor(), @@ -1144,11 +1341,12 @@ For licensing, see LICENSE.html or http://ckeditor.com/license })(); /** - * Whether the ignore all font-related format styles, including: - * - font size; - * - font family; - * - font fore/background color; + * Whether to ignore all font related formatting styles, including: + * * @name CKEDITOR.config.pasteFromWordRemoveFontStyles + * @since 3.1 * @type Boolean * @default true * @example @@ -1156,8 +1354,9 @@ For licensing, see LICENSE.html or http://ckeditor.com/license */ /** - * Whether transform MS-Word Outline Numbered Heading into html list. + * Whether to transform MS Word outline numbered headings into lists. * @name CKEDITOR.config.pasteFromWordNumberedHeadingToList + * @since 3.1 * @type Boolean * @default false * @example @@ -1165,10 +1364,11 @@ For licensing, see LICENSE.html or http://ckeditor.com/license */ /** - * Whether remove element styles that can't be managed with editor, note that this - * this doesn't handle the font-specific styles, which depends on - * how {@link CKEDITOR.config.pasteFromWordRemoveFontStyles} is configured. + * Whether to remove element styles that can't be managed with the editor. Note + * that this doesn't handle the font specific styles, which depends on the + * {@link CKEDITOR.config.pasteFromWordRemoveFontStyles} setting instead. * @name CKEDITOR.config.pasteFromWordRemoveStyles + * @since 3.1 * @type Boolean * @default true * @example