JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
vanilla ckeditor-3.5.3
[ckeditor.git] / _source / plugins / pastefromword / filter / default.js
index 6b2a632..dce3649 100644 (file)
@@ -118,70 +118,107 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                return result;\r
        };\r
 \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
-                                       else if ( lowerRomanLiteralRegex.test( bulletStyle[ 1 ] ) )\r
-                                               bulletStyle = 'lower-roman';\r
-                                       else if ( upperRomanLiteralRegex.test( bulletStyle[ 1 ] ) )\r
-                                               bulletStyle = 'upper-roman';\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 ] ) )\r
-                                               bulletStyle = 'disc';\r
-                                       else if ( /[\u006F\u00D8]/.test( bulletStyle[ 1 ] ) )\r
-                                               bulletStyle = 'circle';\r
-                                       else if ( /[\u006E\u25C6]/.test( bulletStyle[ 1 ] ) )\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
@@ -207,43 +244,65 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                        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 = CKEDITOR.plugins.pastefromword.utils.convertToPx( values[ 3 ] || values[ 1 ] || values [ 0 ] );\r
+                                                                               margin = plugin.utils.convertToPx( values[ 3 ] || values[ 1 ] || values [ 0 ] );\r
                                                                                margin = parseInt( margin, 10 );\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
+                                                                               listId !== previousListId && ( attrs[ 'cke:reset' ] = 1 );\r
+                                                                               previousListId = listId;\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
@@ -309,7 +368,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                        // Resolve how many level nested.\r
                                        while ( parent )\r
                                        {\r
-                                               parent.attributes && parent.attributes[ 'cke:list'] && indentLevel++;\r
+                                               parent.attributes && parent.attributes[ 'cke:list' ] && indentLevel++;\r
                                                parent = parent.parent;\r
                                        }\r
 \r
@@ -348,10 +407,29 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                                        }\r
 \r
                                                        child.name = 'cke:li';\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 = parseInt( plugin.utils.convertToPx( margin[ 0 ] ), 10 ) );\r
+                                                                       } ],\r
+                                                                       [ '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
+                                                                       } ]\r
+                                                               ] )( attributes.style );\r
+\r
                                                        attributes[ 'cke:indent' ] = indentLevel;\r
-                                                       previousListItemMargin = 0;\r
                                                        attributes[ 'cke:listtype' ] = element.name;\r
-                                                       listStyleType && child.addStyle( 'list-style-type', listStyleType, true );\r
+                                                       attributes[ 'cke:list-style-type' ] = listStyleType;\r
                                                }\r
                                        }\r
 \r
@@ -371,11 +449,19 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                        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
@@ -386,43 +472,128 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                                        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
@@ -435,13 +606,16 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                                        }\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
@@ -467,7 +641,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                                // html-encoded quote might be introduced by 'font-family'\r
                                                // from MS-Word which confused the following regexp. e.g.\r
                                                //'font-family: &quot;Lucida, Console&quot;'\r
-                                                styleText\r
+                                               ( styleText || '' )\r
                                                        .replace( /&quot;/g, '"' )\r
                                                        .replace( /\s*([^ :;]+)\s*:\s*([^;]+)\s*(?=;|$)/g,\r
                                                                 function( match, name, value )\r
@@ -755,6 +929,20 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
 \r
                                        'p' : function( element )\r
                                        {\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
                                                element.filterChildren();\r
 \r
                                                // Is the paragraph actually a list item?\r
@@ -807,8 +995,8 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
 \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
@@ -859,8 +1047,8 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
 \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
@@ -870,9 +1058,9 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                                        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
@@ -880,8 +1068,18 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                                        });\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
@@ -927,7 +1125,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                        {\r
                                                if ( element.getAncestor( /h\d/ ) && !config.pasteFromWordNumberedHeadingToList )\r
                                                        delete element.name;\r
-                                               }\r
+                                       }\r
                                },\r
 \r
                                attributeNames :\r
@@ -949,6 +1147,9 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                        // 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
@@ -1055,7 +1256,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                                        {\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
@@ -1078,7 +1279,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                        : 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