/*\r
-Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.\r
+Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved.\r
For licensing, see LICENSE.html or http://ckeditor.com/license\r
*/\r
\r
child = child.firstChild( evaluator );\r
if ( child )\r
return child;\r
- else\r
- continue;\r
}\r
}\r
\r
return null;\r
};\r
\r
- // Adding a (set) of styles to the element's attributes.\r
+ // Adding a (set) of styles to the element's 'style' attributes.\r
elementPrototype.addStyle = function( name, value, isPrepend )\r
{\r
var styleText, addingStyleText = '';\r
return result;\r
};\r
\r
- 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;\r
- var emptyMarginRegex = /^(?:\b0[^\s]*\s*){1,4}$/;\r
+ // 1. move consistent list item styles up to list root.\r
+ // 2. clear out unnecessary list item numbering.\r
+ function postProcessList( list )\r
+ {\r
+ var children = list.children,\r
+ child,\r
+ attrs,\r
+ count = list.children.length,\r
+ match,\r
+ mergeStyle,\r
+ styleTypeRegexp = /list-style-type:(.*?)(?:;|$)/,\r
+ stylesFilter = CKEDITOR.plugins.pastefromword.filters.stylesFilter;\r
+\r
+ attrs = list.attributes;\r
+ if ( styleTypeRegexp.exec( attrs.style ) )\r
+ return;\r
+\r
+ for ( var i = 0; i < count; i++ )\r
+ {\r
+ child = children[ i ];\r
+\r
+ if ( child.attributes.value && Number( child.attributes.value ) == i + 1 )\r
+ delete child.attributes.value;\r
+\r
+ match = styleTypeRegexp.exec( child.attributes.style );\r
+\r
+ if ( match )\r
+ {\r
+ if ( match[ 1 ] == mergeStyle || !mergeStyle )\r
+ mergeStyle = match[ 1 ];\r
+ else\r
+ {\r
+ mergeStyle = null;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ if ( mergeStyle )\r
+ {\r
+ for ( i = 0; i < count; i++ )\r
+ {\r
+ attrs = children[ i ].attributes;\r
+ attrs.style && ( attrs.style = stylesFilter( [ [ 'list-style-type'] ] )( attrs.style ) || '' );\r
+ }\r
+\r
+ list.addStyle( 'list-style-type', mergeStyle );\r
+ }\r
+ }\r
+\r
+ 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;\r
+ var emptyMarginRegex = /^(?:\b0[^\s]*\s*){1,4}$/; // e.g. 0px 0pt 0px\r
+ var romanLiternalPattern = '^m{0,4}(cm|cd|d?c{0,3})(xc|xl|l?x{0,3})(ix|iv|v?i{0,3})$',\r
+ lowerRomanLiteralRegex = new RegExp( romanLiternalPattern ),\r
+ upperRomanLiteralRegex = new RegExp( romanLiternalPattern.toUpperCase() );\r
+\r
+ var orderedPatterns = { 'decimal' : /\d+/, 'lower-roman': lowerRomanLiteralRegex, 'upper-roman': upperRomanLiteralRegex, 'lower-alpha' : /^[a-z]+$/, 'upper-alpha': /^[A-Z]+$/ },\r
+ unorderedPatterns = { 'disc' : /[l\u00B7\u2002]/, 'circle' : /[\u006F\u00D8]/,'square' : /[\u006E\u25C6]/},\r
+ listMarkerPatterns = { 'ol' : orderedPatterns, 'ul' : unorderedPatterns },\r
+ 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'] ],\r
+ alpahbets = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";\r
+\r
+ // Convert roman numbering back to decimal.\r
+ function fromRoman( str )\r
+ {\r
+ str = str.toUpperCase();\r
+ var l = romans.length, retVal = 0;\r
+ for ( var i = 0; i < l; ++i )\r
+ {\r
+ for ( var j = romans[i], k = j[1].length; str.substr( 0, k ) == j[1]; str = str.substr( k ) )\r
+ retVal += j[ 0 ];\r
+ }\r
+ return retVal;\r
+ }\r
+\r
+ // Convert alphabet numbering back to decimal.\r
+ function fromAlphabet( str )\r
+ {\r
+ str = str.toUpperCase();\r
+ var l = alpahbets.length, retVal = 1;\r
+ for ( var x = 1; str.length > 0; x *= l )\r
+ {\r
+ retVal += alpahbets.indexOf( str.charAt( str.length - 1 ) ) * x;\r
+ str = str.substr( 0, str.length - 1 );\r
+ }\r
+ return retVal;\r
+ }\r
\r
var listBaseIndent = 0,\r
- previousListItemMargin;\r
+ previousListItemMargin = null,\r
+ previousListId;\r
\r
- CKEDITOR.plugins.pastefromword =\r
+ var plugin = ( CKEDITOR.plugins.pastefromword =\r
{\r
utils :\r
{\r
// Create a <cke:listbullet> which indicate an list item type.\r
- createListBulletMarker : function ( bulletStyle, bulletText )\r
+ createListBulletMarker : function ( bullet, bulletText )\r
{\r
- var marker = new CKEDITOR.htmlParser.element( 'cke:listbullet' ),\r
- listType;\r
-\r
- // TODO: Support more list style type from MS-Word.\r
- if ( !bulletStyle )\r
- {\r
- bulletStyle = 'decimal';\r
- listType = 'ol';\r
- }\r
- else if ( bulletStyle[ 2 ] )\r
- {\r
- if ( !isNaN( bulletStyle[ 1 ] ) )\r
- bulletStyle = 'decimal';\r
- // No way to distinguish between Roman numerals and Alphas,\r
- // detect them as a whole.\r
- else if ( /^[a-z]+$/.test( bulletStyle[ 1 ] ) )\r
- bulletStyle = 'lower-alpha';\r
- else if ( /^[A-Z]+$/.test( bulletStyle[ 1 ] ) )\r
- bulletStyle = 'upper-alpha';\r
- // Simply use decimal for the rest forms of unrepresentable\r
- // numerals, e.g. Chinese...\r
- else\r
- bulletStyle = 'decimal';\r
-\r
- listType = 'ol';\r
- }\r
- else\r
- {\r
- if ( /[l\u00B7\u2002]/.test( bulletStyle[ 1 ] ) ) //l·•\r
- bulletStyle = 'disc';\r
- else if ( /[\u006F\u00D8]/.test( bulletStyle[ 1 ] ) ) //oØ\r
- bulletStyle = 'circle';\r
- else if ( /[\u006E\u25C6]/.test( bulletStyle[ 1 ] ) ) //n◆\r
- bulletStyle = 'square';\r
- else\r
- bulletStyle = 'disc';\r
-\r
- listType = 'ul';\r
- }\r
-\r
- // Represent list type as CSS style.\r
- marker.attributes =\r
- {\r
- 'cke:listtype' : listType,\r
- 'style' : 'list-style-type:' + bulletStyle + ';'\r
- };\r
+ var marker = new CKEDITOR.htmlParser.element( 'cke:listbullet' );\r
+ marker.attributes = { 'cke:listsymbol' : bullet[ 0 ] };\r
marker.add( new CKEDITOR.htmlParser.text( bulletText ) );\r
return marker;\r
},\r
resolveList : function( element )\r
{\r
// <cke:listbullet> indicate a list item.\r
- var children = element.children,\r
- attrs = element.attributes,\r
+ var attrs = element.attributes,\r
listMarker;\r
\r
if ( ( listMarker = element.removeAnyChildWithName( 'cke:listbullet' ) )\r
- && listMarker.length\r
- && ( listMarker = listMarker[ 0 ] ) )\r
+ && listMarker.length\r
+ && ( listMarker = listMarker[ 0 ] ) )\r
{\r
element.name = 'cke:li';\r
\r
if ( attrs.style )\r
{\r
- attrs.style = CKEDITOR.plugins.pastefromword.filters.stylesFilter(\r
+ attrs.style = plugin.filters.stylesFilter(\r
[\r
// Text-indent is not representing list item level any more.\r
[ 'text-indent' ],\r
[ 'line-height' ],\r
- // Resolve indent level from 'margin-left' value.\r
+ // First attempt is to resolve indent level from on a constant margin increment.\r
[ ( /^margin(:?-left)?$/ ), null, function( margin )\r
{\r
- // Be able to deal with component/short-hand form style.\r
+ // Deal with component/short-hand form.\r
var values = margin.split( ' ' );\r
- margin = values[ 3 ] || values[ 1 ] || values [ 0 ];\r
- margin = parseInt( margin, 10 );\r
+ margin = CKEDITOR.tools.convertToPx( values[ 3 ] || values[ 1 ] || values [ 0 ] );\r
\r
- // Figure out the indent unit by looking at the first increament.\r
- if ( !listBaseIndent && previousListItemMargin && margin > previousListItemMargin )\r
+ // Figure out the indent unit by checking the first time of incrementation.\r
+ if ( !listBaseIndent && previousListItemMargin !== null && margin > previousListItemMargin )\r
listBaseIndent = margin - previousListItemMargin;\r
\r
- attrs[ 'cke:margin' ] = previousListItemMargin = margin;\r
+ previousListItemMargin = margin;\r
+\r
+ attrs[ 'cke:indent' ] = listBaseIndent && ( Math.ceil( margin / listBaseIndent ) + 1 ) || 1;\r
+ } ],\r
+ // The best situation: "mso-list:l0 level1 lfo2" tells the belonged list root, list item indentation, etc.\r
+ [ ( /^mso-list$/ ), null, function( val )\r
+ {\r
+ val = val.split( ' ' );\r
+ var listId = Number( val[ 0 ].match( /\d+/ ) ),\r
+ indent = Number( val[ 1 ].match( /\d+/ ) );\r
+\r
+ if ( indent == 1 )\r
+ {\r
+ listId !== previousListId && ( attrs[ 'cke:reset' ] = 1 );\r
+ previousListId = listId;\r
+ }\r
+ attrs[ 'cke:indent' ] = indent;\r
} ]\r
- ] )( attrs.style, element ) || '' ;\r
+ ] )( attrs.style, element ) || '';\r
}\r
\r
- // Inherit list-type-style from bullet.\r
- var listBulletAttrs = listMarker.attributes,\r
- listBulletStyle = listBulletAttrs.style;\r
+ // First level list item might be presented without a margin.\r
+\r
\r
- element.addStyle( listBulletStyle );\r
- CKEDITOR.tools.extend( attrs, listBulletAttrs );\r
+ // In case all above doesn't apply.\r
+ if ( !attrs[ 'cke:indent' ] )\r
+ {\r
+ previousListItemMargin = 0;\r
+ attrs[ 'cke:indent' ] = 1;\r
+ }\r
+\r
+ // Inherit attributes from bullet.\r
+ CKEDITOR.tools.extend( attrs, listMarker.attributes );\r
return true;\r
}\r
+ // Current list disconnected.\r
+ else\r
+ previousListId = previousListItemMargin = listBaseIndent = null;\r
\r
return false;\r
},\r
\r
- // Convert various length units to 'px' in ignorance of DPI.\r
- convertToPx : ( function ()\r
- {\r
- var calculator = CKEDITOR.dom.element.createFromHtml(\r
- '<div style="position:absolute;left:-9999px;' +\r
- 'top:-9999px;margin:0px;padding:0px;border:0px;"' +\r
- '></div>', CKEDITOR.document );\r
- CKEDITOR.document.getBody().append( calculator );\r
-\r
- return function( cssLength )\r
- {\r
- if ( cssLengthRelativeUnit.test( cssLength ) )\r
- {\r
- calculator.setStyle( 'width', cssLength );\r
- return calculator.$.clientWidth + 'px';\r
- }\r
-\r
- return cssLength;\r
- };\r
- } )(),\r
-\r
// Providing a shorthand style then retrieve one or more style component values.\r
getStyleComponents : ( function()\r
{\r
// E.g. <ul><li>level1<ol><li>level2</li></ol></li> =>\r
// <cke:li cke:listtype="ul" cke:indent="1">level1</cke:li>\r
// <cke:li cke:listtype="ol" cke:indent="2">level2</cke:li>\r
- flattenList : function( element )\r
+ flattenList : function( element, level )\r
{\r
- var attrs = element.attributes,\r
- parent = element.parent;\r
-\r
- var listStyleType,\r
- indentLevel = 1;\r
+ level = typeof level == 'number' ? level : 1;\r
\r
- // Resolve how many level nested.\r
- while ( parent )\r
- {\r
- parent.attributes && parent.attributes[ 'cke:list'] && indentLevel++;\r
- parent = parent.parent;\r
- }\r
+ var attrs = element.attributes,\r
+ listStyleType;\r
\r
// All list items are of the same type.\r
switch ( attrs.type )\r
case 'a' :\r
listStyleType = 'lower-alpha';\r
break;\r
+ case '1' :\r
+ listStyleType = 'decimal';\r
+ break;\r
// TODO: Support more list style type from MS-Word.\r
}\r
\r
for ( var i = 0; i < children.length; i++ )\r
{\r
child = children[ i ];\r
- var attributes = child.attributes;\r
\r
if ( child.name in CKEDITOR.dtd.$listItem )\r
{\r
- var listItemChildren = child.children,\r
+ var attributes = child.attributes,\r
+ listItemChildren = child.children,\r
count = listItemChildren.length,\r
last = listItemChildren[ count - 1 ];\r
\r
// Move out nested list.\r
if ( last.name in CKEDITOR.dtd.$list )\r
{\r
- children.splice( i + 1, 0, last );\r
- last.parent = element;\r
+ element.add( last, i + 1 );\r
\r
// Remove the parent list item if it's just a holder.\r
if ( !--listItemChildren.length )\r
- children.splice( i, 1 );\r
+ children.splice( i--, 1 );\r
}\r
\r
child.name = 'cke:li';\r
- attributes[ 'cke:indent' ] = indentLevel;\r
- previousListItemMargin = 0;\r
+\r
+ // Inherit numbering from list root on the first list item.\r
+ attrs.start && !i && ( attributes.value = attrs.start );\r
+\r
+ plugin.filters.stylesFilter(\r
+ [\r
+ [ 'tab-stops', null, function( val )\r
+ {\r
+ var margin = val.split( ' ' )[ 1 ].match( cssLengthRelativeUnit );\r
+ margin && ( previousListItemMargin = CKEDITOR.tools.convertToPx( margin[ 0 ] ) );\r
+ } ],\r
+ ( level == 1 ? [ 'mso-list', null, function( val )\r
+ {\r
+ val = val.split( ' ' );\r
+ var listId = Number( val[ 0 ].match( /\d+/ ) );\r
+ listId !== previousListId && ( attributes[ 'cke:reset' ] = 1 );\r
+ previousListId = listId;\r
+ } ] : null )\r
+ ] )( attributes.style );\r
+\r
+ attributes[ 'cke:indent' ] = level;\r
attributes[ 'cke:listtype' ] = element.name;\r
- listStyleType && child.addStyle( 'list-style-type', listStyleType, true );\r
+ attributes[ 'cke:list-style-type' ] = listStyleType;\r
+ }\r
+ // Flatten sub list.\r
+ else if ( child.name in CKEDITOR.dtd.$list )\r
+ {\r
+ // Absorb sub list children.\r
+ arguments.callee.apply( this, [ child, level + 1 ] );\r
+ children = children.slice( 0, i ).concat( child.children ).concat( children.slice( i + 1 ) );\r
+ element.children = [];\r
+ for ( var j = 0, num = children.length; j < num ; j++ )\r
+ element.add( children[ j ] );\r
}\r
}\r
\r
var children = element.children, child,\r
listItem, // The current processing cke:li element.\r
listItemAttrs,\r
- listType, // Determine the root type of the list.\r
listItemIndent, // Indent level of current list item.\r
+ lastIndent,\r
lastListItem, // The previous one just been added to the list.\r
- list, parentList, // Current staging list and it's parent list if any.\r
- indent;\r
+ list, // Current staging list and it's parent list if any.\r
+ openedLists = [],\r
+ previousListStyleType,\r
+ previousListType;\r
+\r
+ // Properties of the list item are to be resolved from the list bullet.\r
+ var bullet,\r
+ listType,\r
+ listStyleType,\r
+ itemNumeric;\r
\r
for ( var i = 0; i < children.length; i++ )\r
{\r
child.name = 'li';\r
listItem = child;\r
listItemAttrs = listItem.attributes;\r
- listType = listItem.attributes[ 'cke:listtype' ];\r
+ bullet = listItemAttrs[ 'cke:listsymbol' ];\r
+ bullet = bullet && bullet.match( /^(?:[(]?)([^\s]+?)([.)]?)$/ );\r
+ listType = listStyleType = itemNumeric = null;\r
+\r
+ if ( listItemAttrs[ 'cke:ignored' ] )\r
+ {\r
+ children.splice( i--, 1 );\r
+ continue;\r
+ }\r
+\r
+\r
+ // This's from a new list root.\r
+ listItemAttrs[ 'cke:reset' ] && ( list = lastIndent = lastListItem = null );\r
\r
// List item indent level might come from a real list indentation or\r
// been resolved from a pseudo list item's margin value, even get\r
// no indentation at all.\r
- listItemIndent = parseInt( listItemAttrs[ 'cke:indent' ], 10 )\r
- || listBaseIndent && ( Math.ceil( listItemAttrs[ 'cke:margin' ] / listBaseIndent ) )\r
- || 1;\r
-\r
- // Ignore the 'list-style-type' attribute if it's matched with\r
- // the list root element's default style type.\r
- listItemAttrs.style && ( listItemAttrs.style =\r
- CKEDITOR.plugins.pastefromword.filters.stylesFilter(\r
- [\r
- [ 'list-style-type', listType == 'ol' ? 'decimal' : 'disc' ]\r
- ] )( listItemAttrs.style )\r
- || '' );\r
+ listItemIndent = Number( listItemAttrs[ 'cke:indent' ] );\r
\r
+ // We're moving out of the current list, cleaning up.\r
+ if ( listItemIndent != lastIndent )\r
+ previousListType = previousListStyleType = null;\r
+\r
+ // List type and item style are already resolved.\r
+ if ( !bullet )\r
+ {\r
+ listType = listItemAttrs[ 'cke:listtype' ] || 'ol';\r
+ listStyleType = listItemAttrs[ 'cke:list-style-type' ];\r
+ }\r
+ else\r
+ {\r
+ // Probably share the same list style type with previous list item,\r
+ // give it priority to avoid ambiguous between C(Alpha) and C.(Roman).\r
+ if ( previousListType && listMarkerPatterns[ previousListType ] [ previousListStyleType ].test( bullet[ 1 ] ) )\r
+ {\r
+ listType = previousListType;\r
+ listStyleType = previousListStyleType;\r
+ }\r
+ else\r
+ {\r
+ for ( var type in listMarkerPatterns )\r
+ {\r
+ for ( var style in listMarkerPatterns[ type ] )\r
+ {\r
+ if ( listMarkerPatterns[ type ][ style ].test( bullet[ 1 ] ) )\r
+ {\r
+ // Small numbering has higher priority, when dealing with ambiguous\r
+ // between C(Alpha) and C.(Roman).\r
+ if ( type == 'ol' && ( /alpha|roman/ ).test( style ) )\r
+ {\r
+ var num = /roman/.test( style ) ? fromRoman( bullet[ 1 ] ) : fromAlphabet( bullet[ 1 ] );\r
+ if ( !itemNumeric || num < itemNumeric )\r
+ {\r
+ itemNumeric = num;\r
+ listType = type;\r
+ listStyleType = style;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ listType = type;\r
+ listStyleType = style;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ // Simply use decimal/disc for the rest forms of unrepresentable\r
+ // numerals, e.g. Chinese..., but as long as there a second part\r
+ // included, it has a bigger chance of being a order list ;)\r
+ !listType && ( listType = bullet[ 2 ] ? 'ol' : 'ul' );\r
+ }\r
+\r
+ previousListType = listType;\r
+ previousListStyleType = listStyleType || ( listType == 'ol' ? 'decimal' : 'disc' );\r
+ if ( listStyleType && listStyleType != ( listType == 'ol' ? 'decimal' : 'disc' ) )\r
+ listItem.addStyle( 'list-style-type', listStyleType );\r
+\r
+ // Figure out start numbering.\r
+ if ( listType == 'ol' && bullet )\r
+ {\r
+ switch ( listStyleType )\r
+ {\r
+ case 'decimal' :\r
+ itemNumeric = Number( bullet[ 1 ] );\r
+ break;\r
+ case 'lower-roman':\r
+ case 'upper-roman':\r
+ itemNumeric = fromRoman( bullet[ 1 ] );\r
+ break;\r
+ case 'lower-alpha':\r
+ case 'upper-alpha':\r
+ itemNumeric = fromAlphabet( bullet[ 1 ] );\r
+ break;\r
+ }\r
+\r
+ // Always create the numbering, swipe out unnecessary ones later.\r
+ listItem.attributes.value = itemNumeric;\r
+ }\r
+\r
+ // Start the list construction.\r
if ( !list )\r
{\r
- list = new CKEDITOR.htmlParser.element( listType );\r
+ openedLists.push( list = new CKEDITOR.htmlParser.element( listType ) );\r
list.add( listItem );\r
children[ i ] = list;\r
}\r
else\r
{\r
- if ( listItemIndent > indent )\r
+ if ( listItemIndent > lastIndent )\r
{\r
- list = new CKEDITOR.htmlParser.element( listType );\r
+ openedLists.push( list = new CKEDITOR.htmlParser.element( listType ) );\r
list.add( listItem );\r
lastListItem.add( list );\r
}\r
- else if ( listItemIndent < indent )\r
+ else if ( listItemIndent < lastIndent )\r
{\r
// There might be a negative gap between two list levels. (#4944)\r
- var diff = indent - listItemIndent,\r
- parent;\r
+ var diff = lastIndent - listItemIndent,\r
+ parent;\r
while ( diff-- && ( parent = list.parent ) )\r
list = parent.parent;\r
\r
}\r
\r
lastListItem = listItem;\r
- indent = listItemIndent;\r
+ lastIndent = listItemIndent;\r
}\r
- else\r
- list = null;\r
+ else if ( list )\r
+ list = lastIndent = lastListItem = null;\r
}\r
\r
- listBaseIndent = 0;\r
+ for ( i = 0; i < openedLists.length; i++ )\r
+ postProcessList( openedLists[ i ] );\r
+\r
+ list = lastIndent = lastListItem = previousListId = previousListItemMargin = listBaseIndent = null;\r
},\r
\r
/**\r
// html-encoded quote might be introduced by 'font-family'\r
// from MS-Word which confused the following regexp. e.g.\r
//'font-family: "Lucida, Console"'\r
- styleText\r
+ ( styleText || '' )\r
.replace( /"/g, '"' )\r
.replace( /\s*([^ :;]+)\s*:\s*([^;]+)\s*(?=;|$)/g,\r
function( match, name, value )\r
stylesFilter = filters.stylesFilter,\r
elementMigrateFilter = filters.elementMigrateFilter,\r
styleMigrateFilter = CKEDITOR.tools.bind( this.filters.styleMigrateFilter, this.filters ),\r
- bogusAttrFilter = filters.bogusAttrFilter,\r
createListBulletMarker = this.utils.createListBulletMarker,\r
flattenList = filters.flattenList,\r
assembleList = filters.assembleList,\r
isListBulletIndicator = this.utils.isListBulletIndicator,\r
containsNothingButSpaces = this.utils.isContainingOnlySpaces,\r
resolveListItem = this.utils.resolveList,\r
- convertToPx = this.utils.convertToPx,\r
+ convertToPx = function( value )\r
+ {\r
+ value = CKEDITOR.tools.convertToPx( value );\r
+ return isNaN( value ) ? value : value + 'px';\r
+ },\r
getStyleComponents = this.utils.getStyleComponents,\r
listDtdParents = this.utils.listDtdParents,\r
removeFontStyles = config.pasteFromWordRemoveFontStyles !== false,\r
\r
'p' : function( element )\r
{\r
- element.filterChildren();\r
+ // This's a fall-back approach to recognize list item in FF3.6,\r
+ // as it's not perfect as not all list style (e.g. "heading list") is shipped\r
+ // with this pattern. (#6662)\r
+ if ( /MsoListParagraph/.exec( element.attributes[ 'class' ] ) )\r
+ {\r
+ var bulletText = element.firstChild( function( node )\r
+ {\r
+ return node.type == CKEDITOR.NODE_TEXT && !containsNothingButSpaces( node.parent );\r
+ });\r
+ var bullet = bulletText && bulletText.parent,\r
+ bulletAttrs = bullet && bullet.attributes;\r
+ bulletAttrs && !bulletAttrs.style && ( bulletAttrs.style = 'mso-list: Ignore;' );\r
+ }\r
\r
- var attrs = element.attributes,\r
- parent = element.parent,\r
- children = element.children;\r
+ element.filterChildren();\r
\r
// Is the paragraph actually a list item?\r
if ( resolveListItem( element ) )\r
\r
'font' : function( element )\r
{\r
- // IE/Safari: drop the font tag if it comes from list bullet text.\r
- if ( !CKEDITOR.env.gecko && isListBulletIndicator( element.parent ) )\r
+ // Drop the font tag if it comes from list bullet text.\r
+ if ( isListBulletIndicator( element.parent ) )\r
{\r
delete element.name;\r
return;\r
element.attributes );\r
styleText && parent.addStyle( styleText );\r
delete element.name;\r
- return;\r
}\r
// Convert the merged into a span with all attributes preserved.\r
else\r
\r
'span' : function( element )\r
{\r
- // IE/Safari: remove the span if it comes from list bullet text.\r
- if ( !CKEDITOR.env.gecko && isListBulletIndicator( element.parent ) )\r
+ // Remove the span if it comes from list bullet text.\r
+ if ( isListBulletIndicator( element.parent ) )\r
return false;\r
\r
element.filterChildren();\r
return null;\r
}\r
\r
- // For IE/Safari: List item bullet type is supposed to be indicated by\r
+ // List item bullet type is supposed to be indicated by\r
// the text of a span with style 'mso-list : Ignore' or an image.\r
- if ( !CKEDITOR.env.gecko && isListBulletIndicator( element ) )\r
+ if ( isListBulletIndicator( element ) )\r
{\r
var listSymbolNode = element.firstChild( function( node )\r
{\r
});\r
\r
var listSymbol = listSymbolNode && ( listSymbolNode.value || 'l.' ),\r
- listType = listSymbol.match( /^([^\s]+?)([.)]?)$/ );\r
- return createListBulletMarker( listType, listSymbol );\r
+ listType = listSymbol && listSymbol.match( /^(?:[(]?)([^\s]+?)([.)]?)$/ );\r
+\r
+ if ( listType )\r
+ {\r
+ var marker = createListBulletMarker( listType, listSymbol );\r
+ // Some non-existed list items might be carried by an inconsequential list, indicate by "mso-hide:all/display:none",\r
+ // those are to be removed later, now mark it with "cke:ignored".\r
+ var ancestor = element.getAncestor( 'span' );\r
+ if ( ancestor && (/ mso-hide:\s*all|display:\s*none /).test( ancestor.attributes.style ) )\r
+ marker.attributes[ 'cke:ignored' ] = 1;\r
+ return marker;\r
+ }\r
}\r
\r
// Update the src attribute of image element with href.\r
var attrs = element.attributes;\r
if ( attrs && !attrs.href && attrs.name )\r
delete element.name;\r
+ else if ( CKEDITOR.env.webkit && attrs.href && attrs.href.match( /file:\/\/\/[\S]+#/i ) )\r
+ attrs.href = attrs.href.replace( /file:\/\/\/[^#]+/i,'' );\r
},\r
'cke:listbullet' : function( element )\r
{\r
if ( element.getAncestor( /h\d/ ) && !config.pasteFromWordNumberedHeadingToList )\r
delete element.name;\r
- }\r
+ }\r
},\r
\r
attributeNames :\r
// Provide a white-list of styles that we preserve, those should\r
// be the ones that could later be altered with editor tools.\r
[\r
+ // Leave list-style-type\r
+ [ ( /^list-style-type$/ ), null ],\r
+\r
// Preserve margin-left/right which used as default indent style in the editor.\r
[ ( /^margin$|^margin-(?!bottom|top)/ ), null, function( value, element, name )\r
{\r
{\r
// Bullet symbol could be either text or an image.\r
var listSymbol = listInfo[ 1 ] || ( imageInfo && 'l.' ),\r
- listType = listSymbol && listSymbol.match( />([^\s]+?)([.)]?)</ );\r
+ listType = listSymbol && listSymbol.match( />(?:[(]?)([^\s]+?)([.)]?)</ );\r
return createListBulletMarker( listType, listSymbol );\r
}\r
\r
: falsyFilter\r
};\r
}\r
- };\r
+ });\r
\r
// The paste processor here is just a reduced copy of html data processor.\r
var pasteProcessor = function()\r