You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by jw...@apache.org on 2007/05/28 21:37:49 UTC

svn commit: r542304 - /myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/util/CSSGenerationUtils.java

Author: jwaldman
Date: Mon May 28 12:37:49 2007
New Revision: 542304

URL: http://svn.apache.org/viewvc?view=rev&rev=542304
Log:
TRINIDAD-18 wild-carded skinning pseudo classes incorrectly transformed to CSS-2
Changed CSSGenerationUtils.java to parse the :foo to .p_AFFoo correctly.
It was working only when in a namespaced selector.

Modified:
    myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/util/CSSGenerationUtils.java

Modified: myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/util/CSSGenerationUtils.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/util/CSSGenerationUtils.java?view=diff&rev=542304&r1=542303&r2=542304
==============================================================================
--- myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/util/CSSGenerationUtils.java (original)
+++ myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/util/CSSGenerationUtils.java Mon May 28 12:37:49 2007
@@ -6,9 +6,9 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- * 
+ *
  *  http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -44,17 +44,17 @@
  *
  * @version $Name:  $ ($Revision: adfrt/faces/adf-faces-impl/src/main/java/oracle/adfinternal/view/faces/style/util/CSSUtils.java#0 $) $Date: 10-nov-2005.18:58:49 $
  */
- 
+
 public class CSSGenerationUtils
 {
 
 
   /**
-    * Converts the specified set of StyleNodes to CSS. We output either full styleclass names or 
+    * Converts the specified set of StyleNodes to CSS. We output either full styleclass names or
     * compressed styleclass names.
    *
    * @param context The current StyleContext
-   * @param styleSheetName The stylesheet name that is registered with the skin. 
+   * @param styleSheetName The stylesheet name that is registered with the skin.
    *     e.g. skins/purple/purpleSkin.css
    * @param styles The style nodes to convert
    * @param out The PrintWriter to write to
@@ -102,14 +102,14 @@
 
     // We track styles with matching properties in the following HashMap
     // which maps property strings to StyleNode[]s.
-    HashMap<String, StyleNode[]> matchingStylesMap = 
+    HashMap<String, StyleNode[]> matchingStylesMap =
       new HashMap<String, StyleNode[]>(101);
 
     // We also keep an array of the property strings that we generate
     // during this pass, since we need these strings during the second
     // pass to find matching StyleNodes.
     String[] propertyStrings = new String[styles.length];
-     // Keep track of the number of selectors written out. The reason? IE has a 4095 limit, 
+     // Keep track of the number of selectors written out. The reason? IE has a 4095 limit,
      // and we want to warn when we get to that limit.
      int numberSelectorsWritten = 0;
 
@@ -158,10 +158,10 @@
     // We'll start writing the CSS file now.  First
     // write out the header with a time stamp
     Date date = new Date();
-    out.println("/* CSS file generated on " + date + " */");
+    out.println("/* This CSS file generated on " + date + " */");
 
     // This is the second pass in which we write out the style rules
-    // Get the baseURI up front so we don't have to recalculate it every time we find 
+    // Get the baseURI up front so we don't have to recalculate it every time we find
     // a property value that contains url() and need to resolve the uri.
     String baseURI = CSSUtils.getBaseSkinStyleSheetURI(styleSheetName);
     for (int i = 0; i < styles.length; i++)
@@ -189,16 +189,9 @@
           // We should always have a selector at this point
           assert (selector != null);
 
-          // map selectors, if needed
-          // any of the selectors that start with a namespace prefix will
-          // be mapped.
-          // e.g., "af|menuPath::step" maps to "af|menuPath A"
-          // if the selector does not need to be 'mapped', it will be returned
-          // untouched. e.g., .AFInstructionText maps to .AFInstructionText
-          String mappedSelector = _getMappedNSSelector(afSelectorMap,
-                                                       namespacePrefixArray,
-                                                       selector,
-                                                       false);
+          String mappedSelector = _getMappedSelector(afSelectorMap,
+                                                     namespacePrefixArray,
+                                                     selector);
 
           String validFullNameSelector = null;
 
@@ -210,7 +203,7 @@
           {
             validFullNameSelector =
               _getValidFullNameSelector(mappedSelector, namespacePrefixArray);
-             
+
             if (validFullNameSelector != null)
             {
               out.print(validFullNameSelector);
@@ -219,36 +212,43 @@
           }
 
 
-          // shorten all the css-2 style class selectors (those that start with 
+          // shorten all the css-2 style class selectors (those that start with
           // '.' and don't have a namespace prefix in it)
           // and return the shortened string.
           // e.g., selector of '.OraBulletedList A' is shortened to '.xj A'
           // e.g., selector of af|inputText::content is not shortened since
           // it has no css-2 style class selector piece that starts with '.'.
-          // e.g., selector of af|foo.Bar will shorten the '.Bar' piece 
+          // e.g., selector of af|foo.Bar will shorten the '.Bar' piece
           // af|foo.xz
           // e.g., .Foo:hover -> .x0:hover
           if (compressStyles)
           {
-            String shortenedSelector = _getShortSelector(mappedSelector,
-                                                        shortStyleClassMap);
+            String shortSelector = _getShortSelector(mappedSelector,
+                                                     shortStyleClassMap);
 
             // run it through a shortener one more time to shorten any
             // of the af component selectors.
             // e.g., 'af|menuPath' is shortened to '.x11'
-            String shortSelector =
-              _getMappedNSSelector(shortStyleClassMap,
-                                   namespacePrefixArray,
-                                   shortenedSelector,
-                                   true);
+
+            if (_hasNamespacePrefix(shortSelector, namespacePrefixArray))
+            {
+              String[] shortSelectorArray  = shortSelector.split("\\s");
+
+              shortSelector =
+                _getMappedNSSelector(shortStyleClassMap,
+                                     namespacePrefixArray,
+                                     shortSelector,
+                                     shortSelectorArray,
+                                     true);
+            }
 
             // if the transformed full name is different than the shortSelector
             // then write out the shortSelector, too.
             if (shortSelector != null)
-            {          
+            {
               String validShortSelector =
                 _getValidFullNameSelector(shortSelector, namespacePrefixArray);
-                    
+
               // if we wrote out a full style, check to see if we need to write out the short, too.
               // if it is something different, write out the short, too.
               if (validFullNameSelector != null)
@@ -306,7 +306,7 @@
 
             out.print(propName);
             out.print(":");
-            String resolvedPropValue = 
+            String resolvedPropValue =
               CSSUtils.resolvePropertyValue(styleSheetName, baseURI, propName, propValue);
             out.print(resolvedPropValue);
 
@@ -317,10 +317,10 @@
       }
     }
     out.println("/* The number of CSS selectors in this file is " + numberSelectorsWritten + " */");
-    if (numberSelectorsWritten > 4095 && 
+    if (numberSelectorsWritten > 4095 &&
       (TrinidadAgent.APPLICATION_IEXPLORER == context.getAgent().getAgentApplication()))
     {
-      
+
       out.println("/* ERROR: The number of CSS selectors is more than IE's limit of 4095. " +
       "The selectors after that will be ignored. */");
       if (_LOG.isWarning())
@@ -333,8 +333,8 @@
 
   /**
    * Tests whether the specified selector is a single style class
-   * selector. A single style class selector is something like 
-   * ".AFInstructionText". Examples that are not single style class 
+   * selector. A single style class selector is something like
+   * ".AFInstructionText". Examples that are not single style class
    * selectors are "af|inputText" or ".AFFoo .AFBar" or ".foo:hover"
    */
   public static boolean isSingleStyleClassSelector(String selector)
@@ -444,9 +444,8 @@
     String              namespace,
     Map<String, String> afSelectorMap)
   {
-    if (selector == null)
+	if (selector == null)
       return null;
-
     int afIndex = selector.indexOf(namespace);
 
     // no namespace in the selector, so just return null
@@ -460,11 +459,9 @@
 
     // split the string into the spaces
     String base = selector.substring(afIndex);
-    String[] afSelectors;
-    String[] spacerArray = base.split("\\s");
-    afSelectors = 
-        _orderPseudoElementsAndClasses(spacerArray);
-        
+    String[] afSelectors =
+        _orderPseudoElementsAndClasses(base);
+
     // loop through each of the af| parts.
     for (int i=0; i < afSelectors.length; i++)
     {
@@ -472,7 +469,7 @@
       {
         // get the component selector, which is just the main part, nothing
         // that includes a '.' ':', or a ' '.
-        String afComponentSelector = 
+        String afComponentSelector =
           _getNSComponentSelector(afSelectors[i], false);
         afUnmappedSelectorList.add(afComponentSelector);
       }
@@ -518,7 +515,7 @@
     return afSelectorList.iterator();
 
   }
-  
+
   /**
    * Add to the namespacePrefixes Set any namespace prefixes found in this selector.
    * @param namespacePrefixes
@@ -526,10 +523,10 @@
    */
   public static void getNamespacePrefixes(
     Set<String> namespacePrefixes,
-    String selector) 
+    String selector)
   {
 
-    int length = selector.length();  
+    int length = selector.length();
     int startSubstringIndex = 0;
     // Loop through each character of the selector looking for namespace prefixes.
     for (int i = 0; i < length; i++)
@@ -541,7 +538,7 @@
         startSubstringIndex = i+1;
         // protect against just | in the prefix by checking length.
         if (prefix.length() > 1)
-          namespacePrefixes.add(prefix); 
+          namespacePrefixes.add(prefix);
       }
       else if(!_isStyleClassTerminator(c))
       {
@@ -557,7 +554,7 @@
   }
 
   /**
-   * Called from getNamespacedSelectors. 
+   * Called from getNamespacedSelectors.
    * Given a single selector that begins with a namespace prefix (most likely
    * af|), return the main portion -- the prefix+component+pseudo-element.
    * Styleclasses and pseudo-classes and anything after a space will be ignored,
@@ -623,11 +620,11 @@
   {
     if (shortStyleClassMap == null)
       return null;
-          
+
     // This will see if the selector is a single styleClass, and if so,
     // it will run it through the shortStyleClassMap and return the shortened
-    // style class. A single style class selector is something like 
-    // ".AFInstructionText". Examples that are not single style class 
+    // style class. A single style class selector is something like
+    // ".AFInstructionText". Examples that are not single style class
     // selectors are "af|inputText" or ".AFFoo .AFBar" or ".foo:hover"
     if (isSingleStyleClassSelector(selector))
     {
@@ -637,7 +634,7 @@
     }
 
     // This will run if we do not have a one class selector definition
-    // but a af|XXX class or a command class like .AFXYZ .AFzzz or 
+    // but a af|XXX class or a command class like .AFXYZ .AFzzz or
     // ".foo:hover" It shortens all the .xxx pieces.
     boolean isShorter = false;
     int length = selector.length();
@@ -674,7 +671,7 @@
             end = true;
           }
         }
-        
+
         if (end)
         {
 
@@ -682,11 +679,11 @@
           // see if we've got a shorter version
           String styleClass = selector.substring(styleClassStartIndex + 1, i);
           String shortStyleClass = null;
-          // don't shorten the styles that contain a namespace, because we 
+          // don't shorten the styles that contain a namespace, because we
           // do this in another step.
           if (styleClass.indexOf('|') == -1)
             shortStyleClass = shortStyleClassMap.get(styleClass);
- 
+
 
           if (shortStyleClass == null)
           {
@@ -701,7 +698,7 @@
           // Don't forget the terminator character
           if (i < (length - 1))
             buffer.append(c);
-          // if c is ., then this means we've found another styleclass            
+          // if c is ., then this means we've found another styleclass
           if (c == '.')
             styleClassStartIndex = i;
           else
@@ -713,9 +710,8 @@
     // return the original selector if this isn't shorter.
     return isShorter ? buffer.toString() : selector;
   }
-
   /**
-   * Runs a selector through a map. It returns the selector unchanged if 
+   * Runs a selector through a map. It returns the selector unchanged if
    * there is no namespace in the selector.
    * This could be a map to convert the
    * public no-html selector to an internal selector that has html-specifics
@@ -734,35 +730,66 @@
    * @param shorten     if true, then we'll add the "." to the mapped selector.
    * @return            the selector, mapped.
    */
-  private static String _getMappedNSSelector (
-    Map<String, String> map,
-    String[]            nsPrefixArray,
-    String              selector,
-    boolean             shorten)
+  private static String _getMappedSelector (
+    Map<String, String> afSelectorMap,
+    String[]            namespacePrefixArray,
+    String              selector)
   {
-    // break apart by spaces; map each piece;
-    // if a namespace is not in the piece, it will remain unchanged
-    // piece back together.
-    
-    
-    // quick check; null or no namespace in the selector,
-    // return the selector unchanged.
-     if ((selector == null) || (!_hasNamespacePrefix(selector, nsPrefixArray)))
-       return selector;
-
-    // split the string into the spaces
-    String[] selectorArray;
-    if (!shorten)
+    String mappedSelector;
+    if (_hasNamespacePrefix(selector, namespacePrefixArray))
     {
-      String[] spacerArray = selector.split("\\s");
-      selectorArray = 
-        _orderPseudoElementsAndClasses(spacerArray);
+      String[] selectorArray =
+        _orderPseudoElementsAndClasses(selector);
+
+      // map selectors, if needed
+      // any of the selectors that start with a namespace prefix will
+      // be mapped.
+      // e.g., "af|menuPath::step" maps to "af|menuPath A"
+      // if the selector does not need to be 'mapped', it will be returned
+      // untouched. e.g., .AFInstructionText maps to .AFInstructionText
+      mappedSelector = _getMappedNSSelector(afSelectorMap,
+                                            namespacePrefixArray,
+                                            selector,
+                                            selectorArray,
+                                            false);
 
     }
     else
     {
-      selectorArray = selector.split("\\s"); 
+      // there are no namespaces in this selector. TODO We still need to convert the pseudo-classes
+      mappedSelector = _convertPseudoClassesInSelector(selector);
     }
+    return mappedSelector;
+  }
+  /**
+   * Runs a namespaced selector through a map.
+   * This could be a map to convert the
+   * public no-html selector to an internal selector that has html-specifics
+   * (e.g., 'af|menuPath::step:hover' -> 'af|menuPath A:hover')
+   * or it could be a map to shorten the selector
+   * (e.g., 'af|menuPath A:hover' -> '.x11 A:hover')
+   * We call this method first with the public->internal map, and then
+   * to shorten it.
+   * Only the pieces of the selector that start with the namespace are mapped.
+   * @param map         if shortenPass is true, then this map shortens the
+   *                    af| selector. else, it maps the public af| selector
+   *                    to the internal selector.
+   * @param namespace   most likely, "af|". The selectors with this namespace
+   *                    are the ones we map.
+   * @param selector    selector to map.
+   * @param selectorArray selectorArray is the selector split into pieces based on the ' '
+   * @param shorten     if true, then we'll add the "." to the mapped selector.
+   * @return            the selector, mapped.
+   */
+  private static String _getMappedNSSelector (
+    Map<String, String> map,
+    String[]            nsPrefixArray,
+    String              selector,
+    String[]            selectorArray,
+    boolean             shorten)
+  {
+    // selectorArray is the selector broken into pieces.
+    // Map each piece, then put back together.
 
     for (int i=0; i < selectorArray.length; i++)
     {
@@ -775,7 +802,7 @@
       {
        nsIndex = selectorArray[i].indexOf(nsPrefixArray[j]);
       }
-      
+
       if (nsIndex > -1)
       {
         selectorArray[i] = _getEachMappedSelector(map,
@@ -795,24 +822,20 @@
     String              selector,
     boolean             shorten)
   {
-    // break apart the selector into 3 parts:
-    // main
-    // pseudo-classes (e.g., :hover, :disabled, :readOnly)
-    // end (anything including and after '.')
-    // map the main and the pseudo-classes cuz the pseudo-classes could be
-    // our internal pseudo-classes.
+    // break apart the selector into 2 parts:
+    // main (af|foo::pseudo-element)
+    // end (anything after, ':' or including and after '.')
+    // map the main and the ending (pseudo-classes could be mapped to private
+    // styleclasses, :disabled -> .p_AFDisabled
     // piece  back together.
-    // should I bother mapping pseudo-classes if shorten=true, since they
-    // won't be in the map anyway? TODO
     if (indexOfNSPrefix == -1)
      return selector;
     if (map == null)
       return selector;
-    
-    
-    String wholeAfSelector = selector.substring(indexOfNSPrefix);    
-    SelectorPieces pieces = new SelectorPieces();
-    
+
+
+    String wholeAfSelector = selector.substring(indexOfNSPrefix);
+
     // get main piece
     int colonIndex = wholeAfSelector.indexOf("::");
 
@@ -843,49 +866,27 @@
       c = afterDoubleColon.charAt(endIndex);
       end = (Character.isWhitespace(c)) || (c == '.') || (c == ':');
     }
+
+    // Set the main piece in the pieces object
+    String mainSelector;
     if (endIndex == afterLength)
     {
-      String mainSelector = wholeAfSelector.substring(0, colonIndex + endIndex);
-      pieces.setMain(mainSelector);
+      mainSelector = wholeAfSelector.substring(0, colonIndex + endIndex);
     }
     else
     {
+      mainSelector = wholeAfSelector.substring(0, colonIndex + endIndex-1);
+    }
+    String afterMain = null;
+    if (endIndex != afterLength)
+    {
       // If I got here, that means there are characters after the 'main' part
       // of the selector.
-      String mainSelector = wholeAfSelector.substring(0, colonIndex + endIndex-1);
-      pieces.setMain(mainSelector);    
-      String afterMain = wholeAfSelector.substring(colonIndex + endIndex-1);
-      // afterMain includes the : or the .
-      // if I get a :, I know I'm in a pseudo-class. Keep getting characters
-      // until I'm at the end, or I get another : or .
-      boolean inPseudoClass = false;
-      StringBuffer pseudoClassBuffer = new StringBuffer();
-      for (int i=0; i < afterMain.length(); i++)
-      {
-        char x = afterMain.charAt(i);
-        if (x == '.')
-        {
-          inPseudoClass = false;
-          pieces.setEnd(afterMain.substring(i));
-          break;
-        }
-        else if (x == ':')
-        {
-          if (inPseudoClass)
-          {
-            // if I'm in a pseudo-class already, and I get a ':', that means
-            // i've got another pseudo-class. End the first one.
-            pieces.addPseudoClass(pseudoClassBuffer.toString());
-            pseudoClassBuffer = new StringBuffer();           
-          }
-          inPseudoClass = true;
-          pseudoClassBuffer.append(x);
-        }
-        else
-          pseudoClassBuffer.append(x);
-      }
-      if (pseudoClassBuffer.length() > 0)
-        pieces.addPseudoClass(pseudoClassBuffer.toString());
+      afterMain = wholeAfSelector.substring(colonIndex + endIndex-1);
+      // map the afterMain part. It includes styleclasses and pseudo-classes.
+      // we don't need to convert the pseudo-classes if we are shortening.
+      if (!shorten)
+        afterMain = _convertPseudoClassesInSelector(afterMain);
     }
 
     // piece back together the string
@@ -900,41 +901,18 @@
     }
     else if (shorten)
       buffer.append('.');
-      
-    // now I have the pieces of the selector. I'll need to map each piece,
-    // then piece back together.
-    String mappedMain = map.get(pieces.getMain());
-    if (mappedMain != null)
-      buffer.append(mappedMain);
-    else
-      buffer.append(pieces.getMain());
-    
-    // Convert the pseudo-classes if they aren't CSS2 pseudo-classes.
-    // We never want to shorten the converted pseudo-classes.
-    // pseudo-classes represent state and the state can be added or removed
-    // on the client with javascript and it is easiest if the states
-    // converted styleclass is not shortened, otherwise we'd have to
-    // send the shortened styleclass map for the states to the client.
-    List <String> pseudoClasses = pieces.getPseudoClasses();
-    for (String pseudoClass : pseudoClasses )
-    {
-      String mappedPseudoClass = _convertPseudoClass(pseudoClass);
-      buffer.append(mappedPseudoClass);
-    }
-
-    String endPiece = pieces.getEnd();
-    // don't map end piece. (the piece that starts with '.')
-    if(endPiece != null)
-    {
-      buffer.append(endPiece);
-    }
 
-    
-    return buffer.toString(); 
+    // map the mainSelector, and append the afterMain part.
+    buffer.append(_runThroughMap(map, mainSelector));
+    if (afterMain != null)
+      buffer.append(afterMain);
+
+
+    return buffer.toString();
   }
-  
+
   private static boolean _hasNamespacePrefix(
-    String   selector, 
+    String   selector,
     String[] nsPrefixArray)
   {
     boolean hasNamespacePrefix = false;
@@ -944,7 +922,7 @@
         hasNamespacePrefix = true;
     return hasNamespacePrefix;
   }
-  
+
   /*
    * Returns a string representation of the contents of the specified array
    * where adjacent elements are separated a space (" ").
@@ -956,7 +934,7 @@
     int length = stringArray.length;
     // if only one thing in the array, just return it to save some time.
     if (stringArray.length == 1) return stringArray[0];
-    
+
     // get the bufferSize
     int bufferSize = 0;
     for (int i=0; i < length; i++)
@@ -973,7 +951,7 @@
     }
     return returnString.toString();
   }
-  
+
   /*
    * if I see this: af|foo:class:class::element, return this
    * af|foo:class:class and af|foo::element in a String array.
@@ -984,13 +962,15 @@
    * af|foo::p-element.StyleClass (leave alone).
    */
   private static String[]  _orderPseudoElementsAndClasses(
-    String[] input)
+    String selector)
   {
+    String[] input = selector.split("\\s");
+
     List<String> output = new ArrayList<String>();
     for (int i=0; i < input.length; i++)
     {
 
-      int indexOfDoubleColon = input[i].indexOf("::");         
+      int indexOfDoubleColon = input[i].indexOf("::");
       if (indexOfDoubleColon == -1)
       {
         // no double colon (aka pseudo-element)
@@ -998,21 +978,21 @@
       }
       else
       {
-        // you have a double colon index. Now look to see if we need to 
+        // you have a double colon index. Now look to see if we need to
         // reorder. We have to reorder if the pseudo-element comes after
         // the pseudo-class or composite style classes.
         int indexOfFirstColon = input[i].indexOf(':');
         int indexOfDot = input[i].indexOf('.');
 
-        boolean pseudoClassBeforePseudoElement = 
+        boolean pseudoClassBeforePseudoElement =
           (indexOfFirstColon < indexOfDoubleColon);
         boolean styleClassBeforePseudoElement =
           (indexOfDot != -1 && indexOfDot < indexOfDoubleColon);
-          
+
         if (!(pseudoClassBeforePseudoElement ||
               styleClassBeforePseudoElement))
         {
-          output.add(input[i]);  
+          output.add(input[i]);
         }
         else
         {
@@ -1037,13 +1017,13 @@
           output.add(main + end);
         }
       }
-     
-    }  
+
+    }
     return output.toArray(new String[output.size()]);
   }
 
-  
-  
+
+
   /**
    * get rid of the | and :: that browsers don't like, and add the
    * '.' where needed to make the af| component selector
@@ -1057,7 +1037,7 @@
   {
     if (selector.indexOf('|') == -1)
       return selector;
-      
+
     // split on spaces.
     String[] spacerArray = selector.split("\\s");
 
@@ -1073,7 +1053,7 @@
           {
             spacerArray[i] = ".".concat(spacerArray[i]);
             break;
-          }       
+          }
         }
       }
     }
@@ -1095,9 +1075,9 @@
   private static String _getSortedPropertyString(StyleNode style)
   {
     // First, pull the properties out of the StyleNode
-    // -= Simon Lessard =- 
+    // -= Simon Lessard =-
     // TODO: Check if synchronization is needed, otherwise uses
-    //       an ArrayList instead. Even if synchronization is needed 
+    //       an ArrayList instead. Even if synchronization is needed
     //       Collections.synchronizedList(ArrayList) would probably be
     //       a better choice.
     Vector<PropertyNode> v = new Vector<PropertyNode>();
@@ -1154,41 +1134,76 @@
 
     return buffer.toString();
   }
-  /* inner class used to store the pieces of a selector:
-   * the main piece, the pseudo-classes, and anything after the pseudo-classes
+
+  /**
+   * Given a selector, convert the pseudo-classes. Non css-2 pseudo-classes
+   * get converted to styleclasses so they don't get passed through to the generated css.
+   * @param selector String input selector. The assumption is there are no spaces.
+   * If the original selector has spaces, then break the selector up into the pieces before
+   * calling this method.
+   * @return String the selector with the pseudo-classes converted, if needed.
+   * e.g., .StyleClass:error:active -> .StyleClass.p_AFError:active
    */
-  private static class SelectorPieces
+  private static String _convertPseudoClassesInSelector(String selector)
   {
-    private String _main;
-    private List<String>  _pseudo_classes = new ArrayList<String>();
-    private String _end;
-    
-    public void setMain(String main)
-    {
-      _main = main;
-    }
-    public String getMain()
-    {
-      return _main;
-    }  
-    public void addPseudoClass(String pseudoClass)
+    if (selector == null) return selector;
+
+    StringBuffer completeBuffer = new StringBuffer();
+    StringBuffer pseudoClassBuffer = new StringBuffer();
+    boolean inPseudoClass = false;
+
+    for (int i=0; i < selector.length(); i++)
     {
-      _pseudo_classes.add(pseudoClass);
+      char x = selector.charAt(i);
+
+      if ((x == ':') || (x == '.'))
+      {
+        if (inPseudoClass)
+        {
+          // if we are in a pseudo-class already, and we get a ':' or '.' that means
+          // this pseudo-class is complete. Get ready for another one.
+          String convertedPseudoClass = _convertPseudoClass(pseudoClassBuffer.toString());
+          completeBuffer.append(convertedPseudoClass);
+          pseudoClassBuffer = new StringBuffer();
+          inPseudoClass = false;
+        }
+        if (x == ':')
+        {
+          inPseudoClass = true;
+          pseudoClassBuffer.append(x);
+        }
+        else if (x == '.')
+        {
+          completeBuffer.append(x);
+        }
+
+      }
+      else
+      {
+        if (!inPseudoClass)
+          completeBuffer.append(x);
+        else
+          pseudoClassBuffer.append(x);
+      }
+
     }
-    public List <String> getPseudoClasses()
-    {
-      return _pseudo_classes;
-    }  
-    public void setEnd(String end)
+    if (inPseudoClass)
     {
-      _end = end;
+      String mappedPseudoClass = _convertPseudoClass(pseudoClassBuffer.toString());
+      completeBuffer.append(mappedPseudoClass);
+
     }
-    public String getEnd()
-    {
-      return _end;
-    }  
+    return completeBuffer.toString();
+  }
+
+  // run through the map. If it's not in the map, return the selector unchanged.
+  private static String _runThroughMap(Map<String, String> map, String selector)
+  {
+    String mappedSelector = map.get(selector);
+    return (mappedSelector != null) ? mappedSelector : selector;
   }
-  
+
+
   // Comparator that sorts PropertyNodes by name
   private static class PropertyNodeComparator implements Comparator<PropertyNode>
   {
@@ -1217,10 +1232,10 @@
 
     private PropertyNodeComparator() {}
 
-    private static final Comparator<PropertyNode> _sInstance = 
+    private static final Comparator<PropertyNode> _sInstance =
       new PropertyNodeComparator();
   }
-  
+
   static private String _convertPseudoClass(String pseudoClass)
   {
     if (_BUILT_IN_PSEUDO_CLASSES.contains(pseudoClass))