JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
vanilla ckeditor-3.6
[ckeditor.git] / _source / plugins / stylesheetparser / plugin.js
diff --git a/_source/plugins/stylesheetparser/plugin.js b/_source/plugins/stylesheetparser/plugin.js
new file mode 100644 (file)
index 0000000..92624d9
--- /dev/null
@@ -0,0 +1,143 @@
+/*\r
+Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.\r
+For licensing, see LICENSE.html or http://ckeditor.com/license\r
+*/\r
+\r
+/**\r
+ * @stylesheetParser plugin.\r
+ */\r
+\r
+(function()\r
+{\r
+       // We want to extract only the elements with classes defined in the stylesheets:\r
+       function parseClasses( aRules, skipSelectors, validSelectors )\r
+       {\r
+               // aRules are just the different rules in the style sheets\r
+               // We want to merge them and them split them by commas, so we end up with only\r
+               // the selectors\r
+               var s = aRules.join(' ');\r
+               // Remove selectors splitting the elements, leave only the class selector (.)\r
+               s = s.replace( /(,|>|\+|~)/g, ' ' );\r
+               // Remove attribute selectors: table[border="0"]\r
+               s = s.replace( /\[[^\]]*/g, '' );\r
+               // Remove Ids: div#main\r
+               s = s.replace( /#[^\s]*/g, '' );\r
+               // Remove pseudo-selectors and pseudo-elements: :hover :nth-child(2n+1) ::before\r
+               s = s.replace( /\:{1,2}[^\s]*/g, '' );\r
+\r
+               s = s.replace( /\s+/g, ' ' );\r
+\r
+               var aSelectors = s.split( ' ' ),\r
+                       aClasses = [];\r
+\r
+               for ( var i = 0; i < aSelectors.length ; i++ )\r
+               {\r
+                       var selector = aSelectors[ i ];\r
+\r
+                       if ( validSelectors.test( selector ) && !skipSelectors.test( selector ) )\r
+                       {\r
+                               // If we still don't know about this one, add it\r
+                               if ( CKEDITOR.tools.indexOf( aClasses, selector ) == -1 )\r
+                                       aClasses.push( selector );\r
+                       }\r
+               }\r
+\r
+               return aClasses;\r
+       }\r
+\r
+       function LoadStylesCSS( theDoc, skipSelectors, validSelectors )\r
+       {\r
+               var styles = [],\r
+                       // It will hold all the rules of the applied stylesheets (except those internal to CKEditor)\r
+                       aRules = [],\r
+                       i;\r
+\r
+               for ( i = 0; i < theDoc.styleSheets.length; i++ )\r
+               {\r
+                       var sheet = theDoc.styleSheets[ i ],\r
+                               node = sheet.ownerNode || sheet.owningElement;\r
+\r
+                       // Skip the internal stylesheets\r
+                       if ( node.getAttribute( 'data-cke-temp' ) )\r
+                               continue;\r
+\r
+                       // Exclude stylesheets injected by extensions\r
+                       if ( sheet.href && sheet.href.substr(0, 9) == 'chrome://' )\r
+                               continue;\r
+\r
+                       var sheetRules = sheet.cssRules || sheet.rules;\r
+                       for ( var j = 0; j < sheetRules.length; j++ )\r
+                               aRules.push( sheetRules[ j ].selectorText );\r
+               }\r
+\r
+               var aClasses = parseClasses( aRules, skipSelectors, validSelectors );\r
+\r
+               // Add each style to our "Styles" collection.\r
+               for ( i = 0; i < aClasses.length; i++ )\r
+               {\r
+                       var oElement = aClasses[ i ].split( '.' ),\r
+                               element = oElement[ 0 ].toLowerCase(),\r
+                               sClassName = oElement[ 1 ];\r
+\r
+                       styles.push( {\r
+                               name : element + '.' + sClassName,\r
+                               element : element,\r
+                               attributes : {'class' : sClassName}\r
+                       });\r
+               }\r
+\r
+               return styles;\r
+       }\r
+\r
+       // Register a plugin named "stylesheetparser".\r
+       CKEDITOR.plugins.add( 'stylesheetparser',\r
+       {\r
+               requires: [ 'styles' ],\r
+               onLoad : function()\r
+               {\r
+                       var obj = CKEDITOR.editor.prototype;\r
+                       obj.getStylesSet = CKEDITOR.tools.override( obj.getStylesSet,  function( org )\r
+                       {\r
+                               return function( callback )\r
+                               {\r
+                                       var self = this;\r
+                                       org.call( this, function( definitions )\r
+                                       {\r
+                                               // Rules that must be skipped\r
+                                               var skipSelectors = self.config.stylesheetParser_skipSelectors || ( /(^body\.|^\.)/i ),\r
+                                                       // Rules that are valid\r
+                                                       validSelectors = self.config.stylesheetParser_validSelectors || ( /\w+\.\w+/ );\r
+\r
+                                               callback( ( self._.stylesDefinitions = definitions.concat( LoadStylesCSS( self.document.$, skipSelectors, validSelectors ) ) ) );\r
+                                       });\r
+                               };\r
+                       });\r
+\r
+               }\r
+       });\r
+})();\r
+\r
+\r
+/**\r
+ * Regular Expression to check if a css rule must be skipped by\r
+ * the stylesheet parser plugin (so it's ignored and not available)\r
+ * @name CKEDITOR.config.stylesheetParser_skipSelectors\r
+ * @type RegExp\r
+ * @default /(^body\.|^\.)/i\r
+ * @since 3.6\r
+ * @example\r
+ * // Ignore rules for body, caption, only a class or classes starting with "high".\r
+ * config.stylesheetParser_skipSelectors = /(^body\.|^caption\.|\.high|^\.)/i;\r
+ */\r
+\r
+ /**\r
+ * Regular Expression to check if a css rule must be allowed by\r
+ * the stylesheet parser plugin\r
+ * @name CKEDITOR.config.stylesheetParser_validSelectors\r
+ * @type RegExp\r
+ * @default /\w+\.\w+/\r
+ * @since 3.6\r
+ * @example\r
+ * // Add only rules for p and span elements.\r
+ * config.stylesheetParser_validSelectors = /\^(p|span)\.\w+/;\r
+ */\r