1 /* 2 Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. 3 For licensing, see LICENSE.html or http://ckeditor.com/license 4 */ 5 6 /** 7 * @stylesheetParser plugin. 8 */ 9 10 (function() 11 { 12 // We want to extract only the elements with classes defined in the stylesheets: 13 function parseClasses( aRules, skipSelectors, validSelectors ) 14 { 15 // aRules are just the different rules in the style sheets 16 // We want to merge them and them split them by commas, so we end up with only 17 // the selectors 18 var s = aRules.join(' '); 19 // Remove selectors splitting the elements, leave only the class selector (.) 20 s = s.replace( /(,|>|\+|~)/g, ' ' ); 21 // Remove attribute selectors: table[border="0"] 22 s = s.replace( /\[[^\]]*/g, '' ); 23 // Remove Ids: div#main 24 s = s.replace( /#[^\s]*/g, '' ); 25 // Remove pseudo-selectors and pseudo-elements: :hover :nth-child(2n+1) ::before 26 s = s.replace( /\:{1,2}[^\s]*/g, '' ); 27 28 s = s.replace( /\s+/g, ' ' ); 29 30 var aSelectors = s.split( ' ' ), 31 aClasses = []; 32 33 for ( var i = 0; i < aSelectors.length ; i++ ) 34 { 35 var selector = aSelectors[ i ]; 36 37 if ( validSelectors.test( selector ) && !skipSelectors.test( selector ) ) 38 { 39 // If we still don't know about this one, add it 40 if ( CKEDITOR.tools.indexOf( aClasses, selector ) == -1 ) 41 aClasses.push( selector ); 42 } 43 } 44 45 return aClasses; 46 } 47 48 function LoadStylesCSS( theDoc, skipSelectors, validSelectors ) 49 { 50 var styles = [], 51 // It will hold all the rules of the applied stylesheets (except those internal to CKEditor) 52 aRules = [], 53 i; 54 55 for ( i = 0; i < theDoc.styleSheets.length; i++ ) 56 { 57 var sheet = theDoc.styleSheets[ i ], 58 node = sheet.ownerNode || sheet.owningElement; 59 60 // Skip the internal stylesheets 61 if ( node.getAttribute( 'data-cke-temp' ) ) 62 continue; 63 64 // Exclude stylesheets injected by extensions 65 if ( sheet.href && sheet.href.substr(0, 9) == 'chrome://' ) 66 continue; 67 68 var sheetRules = sheet.cssRules || sheet.rules; 69 for ( var j = 0; j < sheetRules.length; j++ ) 70 aRules.push( sheetRules[ j ].selectorText ); 71 } 72 73 var aClasses = parseClasses( aRules, skipSelectors, validSelectors ); 74 75 // Add each style to our "Styles" collection. 76 for ( i = 0; i < aClasses.length; i++ ) 77 { 78 var oElement = aClasses[ i ].split( '.' ), 79 element = oElement[ 0 ].toLowerCase(), 80 sClassName = oElement[ 1 ]; 81 82 styles.push( { 83 name : element + '.' + sClassName, 84 element : element, 85 attributes : {'class' : sClassName} 86 }); 87 } 88 89 return styles; 90 } 91 92 // Register a plugin named "stylesheetparser". 93 CKEDITOR.plugins.add( 'stylesheetparser', 94 { 95 requires: [ 'styles' ], 96 onLoad : function() 97 { 98 var obj = CKEDITOR.editor.prototype; 99 obj.getStylesSet = CKEDITOR.tools.override( obj.getStylesSet, function( org ) 100 { 101 return function( callback ) 102 { 103 var self = this; 104 org.call( this, function( definitions ) 105 { 106 // Rules that must be skipped 107 var skipSelectors = self.config.stylesheetParser_skipSelectors || ( /(^body\.|^\.)/i ), 108 // Rules that are valid 109 validSelectors = self.config.stylesheetParser_validSelectors || ( /\w+\.\w+/ ); 110 111 callback( ( self._.stylesDefinitions = definitions.concat( LoadStylesCSS( self.document.$, skipSelectors, validSelectors ) ) ) ); 112 }); 113 }; 114 }); 115 116 } 117 }); 118 })(); 119 120 121 /** 122 * A regular expression that defines whether a CSS rule will be 123 * skipped by the Stylesheet Parser plugin. A CSS rule matching 124 * the regular expression will be ignored and will not be available 125 * in the Styles drop-down list. 126 * @name CKEDITOR.config.stylesheetParser_skipSelectors 127 * @type RegExp 128 * @default /(^body\.|^\.)/i 129 * @since 3.6 130 * @see CKEDITOR.config.stylesheetParser_validSelectors 131 * @example 132 * // Ignore rules for body and caption elements, classes starting with "high", and any class defined for no specific element. 133 * config.stylesheetParser_skipSelectors = /(^body\.|^caption\.|\.high|^\.)/i; 134 */ 135 136 /** 137 * A regular expression that defines which CSS rules will be used 138 * by the Stylesheet Parser plugin. A CSS rule matching the regular 139 * expression will be available in the Styles drop-down list. 140 * @name CKEDITOR.config.stylesheetParser_validSelectors 141 * @type RegExp 142 * @default /\w+\.\w+/ 143 * @since 3.6 144 * @see CKEDITOR.config.stylesheetParser_skipSelectors 145 * @example 146 * // Only add rules for p and span elements. 147 * config.stylesheetParser_validSelectors = /\^(p|span)\.\w+/; 148 */ 149