JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
vanilla ckeditor-3.6.3
[ckeditor.git] / _source / plugins / styles / plugin.js
index 9a4f13d..2c16b7e 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.\r
+Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.\r
 For licensing, see LICENSE.html or http://ckeditor.com/license\r
 */\r
 \r
@@ -79,8 +79,8 @@ CKEDITOR.STYLE_OBJECT = 3;
 \r
 (function()\r
 {\r
-       var blockElements       = { address:1,div:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,p:1,pre:1 },\r
-               objectElements  = { a:1,embed:1,hr:1,img:1,li:1,object:1,ol:1,table:1,td:1,tr:1,th:1,ul:1,dl:1,dt:1,dd:1,form:1};\r
+       var blockElements       = { address:1,div:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,p:1,pre:1,section:1,header:1,footer:1,nav:1,article:1,aside:1,figure:1,dialog:1,hgroup:1,time:1,meter:1,menu:1,command:1,keygen:1,output:1,progress:1,details:1,datagrid:1,datalist:1 },\r
+               objectElements  = { a:1,embed:1,hr:1,img:1,li:1,object:1,ol:1,table:1,td:1,tr:1,th:1,ul:1,dl:1,dt:1,dd:1,form:1,audio:1,video:1 };\r
 \r
        var semicolonFixRegex = /\s*(?:;\s*|$)/,\r
                varRegex = /#\((.+?)\)/g;\r
@@ -98,7 +98,9 @@ CKEDITOR.STYLE_OBJECT = 3;
                        replaceVariables( styleDefinition.styles, variablesValues );\r
                }\r
 \r
-               var element = this.element = ( styleDefinition.element || '*' ).toLowerCase();\r
+               var element = this.element = styleDefinition.element ?\r
+                               ( typeof styleDefinition.element == 'string' ? styleDefinition.element.toLowerCase() : styleDefinition.element )\r
+                               : '*';\r
 \r
                this.type =\r
                        blockElements[ element ] ?\r
@@ -108,6 +110,10 @@ CKEDITOR.STYLE_OBJECT = 3;
                        :\r
                                CKEDITOR.STYLE_INLINE;\r
 \r
+               // If the 'element' property is an object with a set of possible element, it will be applied like an object style: only to existing elements\r
+               if ( typeof this.element == 'object' )\r
+                       this.type = CKEDITOR.STYLE_OBJECT;\r
+\r
                this._ =\r
                {\r
                        definition : styleDefinition\r
@@ -179,9 +185,12 @@ CKEDITOR.STYLE_OBJECT = 3;
                                                          && ( element == elementPath.block || element == elementPath.blockLimit ) )\r
                                                        continue;\r
 \r
-                                               if( this.type == CKEDITOR.STYLE_OBJECT\r
-                                                        && !( element.getName() in objectElements ) )\r
+                                               if( this.type == CKEDITOR.STYLE_OBJECT )\r
+                                               {\r
+                                                       var name = element.getName();\r
+                                                       if ( !( typeof this.element == 'string' ? name == this.element : name in this.element ) )\r
                                                                continue;\r
+                                               }\r
 \r
                                                if ( this.checkElementRemovable( element, true ) )\r
                                                        return true;\r
@@ -213,14 +222,16 @@ CKEDITOR.STYLE_OBJECT = 3;
                // current style definition.\r
                checkElementRemovable : function( element, fullMatch )\r
                {\r
-                       if ( !element )\r
+                       var def = this._.definition;\r
+\r
+                       if ( !element || !def.ignoreReadonly && element.isReadOnly() )\r
                                return false;\r
 \r
-                       var def = this._.definition,\r
-                               attribs;\r
+                       var attribs,\r
+                               name = element.getName();\r
 \r
                        // If the element name is the same as the style name.\r
-                       if ( element.getName() == this.element )\r
+                       if ( typeof this.element == 'string' ? name == this.element : name in this.element )\r
                        {\r
                                // If no attributes are defined in the element.\r
                                if ( !fullMatch && !element.hasAttributes() )\r
@@ -288,7 +299,7 @@ CKEDITOR.STYLE_OBJECT = 3;
                },\r
 \r
                // Builds the preview HTML based on the styles definition.\r
-               buildPreview : function()\r
+               buildPreview : function( label )\r
                {\r
                        var styleDefinition = this._.definition,\r
                                html = [],\r
@@ -315,7 +326,7 @@ CKEDITOR.STYLE_OBJECT = 3;
                        if ( cssStyle )\r
                                html.push( ' style="', cssStyle, '"' );\r
 \r
-                       html.push( '>', styleDefinition.name, '</', elementName, '>' );\r
+                       html.push( '>', ( label || styleDefinition.name ), '</', elementName, '>' );\r
 \r
                        return html.join( '' );\r
                }\r
@@ -413,7 +424,8 @@ CKEDITOR.STYLE_OBJECT = 3;
                var isUnknownElement;\r
 \r
                // Indicates that fully selected read-only elements are to be included in the styling range.\r
-               var includeReadonly = def.includeReadonly;\r
+               var ignoreReadonly = def.ignoreReadonly,\r
+                       includeReadonly = ignoreReadonly || def.includeReadonly;\r
 \r
                // If the read-only inclusion is not available in the definition, try\r
                // to get it from the document data.\r
@@ -437,19 +449,22 @@ CKEDITOR.STYLE_OBJECT = 3;
 \r
                var styleRange;\r
 \r
-               // Check if the boundaries are inside non stylable elements.\r
-               var firstUnstylable = getUnstylableParent( firstNode ),\r
-                       lastUnstylable = getUnstylableParent( lastNode );\r
-\r
-               // If the first element can't be styled, we'll start processing right\r
-               // after its unstylable root.\r
-               if ( firstUnstylable )\r
-                       currentNode = firstUnstylable.getNextSourceNode( true );\r
-\r
-               // If the last element can't be styled, we'll stop processing on its\r
-               // unstylable root.\r
-               if ( lastUnstylable )\r
-                       lastNode = lastUnstylable;\r
+               if ( !ignoreReadonly )\r
+               {\r
+                       // Check if the boundaries are inside non stylable elements.\r
+                       var firstUnstylable = getUnstylableParent( firstNode ),\r
+                                       lastUnstylable = getUnstylableParent( lastNode );\r
+\r
+                       // If the first element can't be styled, we'll start processing right\r
+                       // after its unstylable root.\r
+                       if ( firstUnstylable )\r
+                               currentNode = firstUnstylable.getNextSourceNode( true );\r
+\r
+                       // If the last element can't be styled, we'll stop processing on its\r
+                       // unstylable root.\r
+                       if ( lastUnstylable )\r
+                               lastNode = lastUnstylable;\r
+               }\r
 \r
                // Do nothing if the current node now follows the last node to be processed.\r
                if ( currentNode.getPosition( lastNode ) == CKEDITOR.POSITION_FOLLOWING )\r
@@ -776,7 +791,7 @@ CKEDITOR.STYLE_OBJECT = 3;
                        breakNodes();\r
 \r
                        // Now, do the DFS walk.\r
-                       var currentNode = startNode.getNext();\r
+                       var currentNode = startNode;\r
                        while ( !currentNode.equals( endNode ) )\r
                        {\r
                                /*\r
@@ -815,7 +830,7 @@ CKEDITOR.STYLE_OBJECT = 3;
        {\r
                var root = range.getCommonAncestor( true, true ),\r
                        element = root.getAscendant( this.element, true );\r
-               element && setupElement( element, this );\r
+               element && !element.isReadOnly() && setupElement( element, this );\r
        }\r
 \r
        function removeObjectStyle( range )\r
@@ -829,7 +844,6 @@ CKEDITOR.STYLE_OBJECT = 3;
                var style = this,\r
                        def = style._.definition,\r
                        attributes = def.attributes;\r
-               var styles = CKEDITOR.style.getStyleText( def );\r
 \r
                // Remove all defined attributes.\r
                if ( attributes )\r
@@ -872,8 +886,11 @@ CKEDITOR.STYLE_OBJECT = 3;
 \r
                while ( ( block = iterator.getNextParagraph() ) )               // Only one =\r
                {\r
-                       var newBlock = getElement( this, doc, block );\r
-                       replaceBlock( block, newBlock );\r
+                       if ( !block.isReadOnly() )\r
+                       {\r
+                               var newBlock = getElement( this, doc, block );\r
+                               replaceBlock( block, newBlock );\r
+                       }\r
                }\r
 \r
                range.moveToBookmark( bookmark );\r
@@ -1115,8 +1132,9 @@ CKEDITOR.STYLE_OBJECT = 3;
        function removeFromElement( style, element )\r
        {\r
                var def = style._.definition,\r
-                       attributes = CKEDITOR.tools.extend( {}, def.attributes, getOverrides( style )[ element.getName() ] ),\r
+                       attributes = def.attributes,\r
                        styles = def.styles,\r
+                       overrides = getOverrides( style )[ element.getName() ],\r
                        // If the style is only about the element itself, we have to remove the element.\r
                        removeEmpty = CKEDITOR.tools.isEmpty( attributes ) && CKEDITOR.tools.isEmpty( styles );\r
 \r
@@ -1142,6 +1160,9 @@ CKEDITOR.STYLE_OBJECT = 3;
                        element.removeStyle( styleName );\r
                }\r
 \r
+               // Remove overrides, but don't remove the element if it's a block element\r
+               removeOverrides( element, overrides, blockElements[ element.getName() ] ) ;\r
+\r
                if ( removeEmpty )\r
                {\r
                        !CKEDITOR.dtd.$block[ element.getName() ] || style._.enterMode == CKEDITOR.ENTER_BR && !element.hasAttributes() ?\r
@@ -1183,8 +1204,9 @@ CKEDITOR.STYLE_OBJECT = 3;
         *  Note: Remove the element if no attributes remain.\r
         * @param {Object} element\r
         * @param {Object} overrides\r
+        * @param {Boolean} Don't remove the element\r
         */\r
-       function removeOverrides( element, overrides )\r
+       function removeOverrides( element, overrides, dontRemove )\r
        {\r
                var attributes = overrides && overrides.attributes ;\r
 \r
@@ -1212,7 +1234,8 @@ CKEDITOR.STYLE_OBJECT = 3;
                        }\r
                }\r
 \r
-               removeNoAttribsElement( element );\r
+               if ( !dontRemove )\r
+                       removeNoAttribsElement( element );\r
        }\r
 \r
        // If the element has no more attributes, remove it.\r
@@ -1446,6 +1469,16 @@ CKEDITOR.STYLE_OBJECT = 3;
                else\r
                        styleText = unparsedCssText;\r
 \r
+               // Normalize font-family property, ignore quotes and being case insensitive. (#7322)\r
+               // http://www.w3.org/TR/css3-fonts/#font-family-the-font-family-property\r
+               styleText = styleText.replace( /(font-family:)(.*?)(?=;|$)/, function ( match, prop, val )\r
+               {\r
+                       var names = val.split( ',' );\r
+                       for ( var i = 0; i < names.length; i++ )\r
+                               names[ i ] = CKEDITOR.tools.trim( names[ i ].replace( /["']/g, '' ) );\r
+                       return prop + names.join( ',' );\r
+               });\r
+\r
                // Shrinking white-spaces around colon and semi-colon (#4147).\r
                // Compensate tail semi-colon.\r
                return styleText.replace( /\s*([;:])\s*/, '$1' )\r
@@ -1497,6 +1530,8 @@ CKEDITOR.STYLE_OBJECT = 3;
        function applyStyle( document, remove )\r
        {\r
                var selection = document.getSelection(),\r
+                       // Bookmark the range so we can re-select it after processing.\r
+                       bookmarks = selection.createBookmarks( 1 ),\r
                        ranges = selection.getRanges(),\r
                        func = remove ? this.removeFromRange : this.applyToRange,\r
                        range;\r
@@ -1505,7 +1540,13 @@ CKEDITOR.STYLE_OBJECT = 3;
                while ( ( range = iterator.getNextRange() ) )\r
                        func.call( this, range );\r
 \r
-               selection.selectRanges( ranges );\r
+               if ( bookmarks.length == 1 && bookmarks[ 0 ].collapsed )\r
+               {\r
+                       selection.selectRanges( ranges );\r
+                       document.getById( bookmarks[ 0 ].startNode ).remove();\r
+               }\r
+               else\r
+                       selection.selectBookmarks( bookmarks );\r
 \r
                document.removeCustomData( 'doc_processing_style' );\r
        }\r