PropertySheetManager
Camo’s custom CSS parser, the CamoPropertySheet (found inside of the camo.core.property package), goes well beyond the native StyleSheet class by supporting style inheritance, pseudo selectors, and merging styles on the fly. The goal of the CamoPropertySheet is to make styles something you can apply to any of your classes instead of just TextFields. CSS is a great way to define your class’s properties in an external file and Camo helps convert these css styles into property/value pairs you can apply to any Object.
Here is a simple CSS sheet:
Example CSS
/* This is a comment in the CSS file */
baseStyle {
x: 10px;
y: 10px;
width: 100px;
height: 100px;
padding: 5px;
margin: 10px;
}
baseStyle .Button{
x: 0px;
y: 0px;
background-color: #000000;
}
#playButton {
background-color: #FFFFFF;
background-image: url('/images/full_screen_background.jpg');
}
#fullScreenButton{
background-color: #FF0000;
background-image: url('/images/full_screen_background.jpg');
}
#playButton:over {
background-color: #333333;
}
interactive {
cursor: hand;
}
Parsing CSS
Once you have CSS that is ready to be parsed, either by loading it in from a URLLoader as text or by creating it as a string in your code at run time, you will need to call the CamoPropertySheet’s parseCSS method. This method has one parameter, compressCSS. By default this is set to true. The parser requires your CSS to be properly formatted by removing all unneeded spaces, tabs, returns, px, and comments. There are two ways of doing this, you can use server side compression or let the CamoPropertySheet handle the compression for you. Here is what the compressed css would look like:
Compressed CSS
Once the CSS is parsed, you can retrieve an Array of selector names by calling the selectedNames getter. A selector represents the name of the particular CSS style and it’s collection of values. The getSelector method will return the selector 4 and it’s properties as a PropertySelector 5. New selectors can be added to the CamoPropertySheet by calling newSelector and passing a selector name and a PropertySelector instance. Finally, you can duplicate a CamoPropertySheet by calling the clone method 6.
Inheritance
Selector inheritance is also supported by the CamoPropertySheet. From the previous CSS sample, lets look at the .Button style. As you can see the selector name in the CSS is "baseButton .Button". Its formatting tells the parser that .Button inherits properties from baseButton. We refer to .Button as the subject and baseButton would be an ancestor element. If you were to call getSelector for .Button the parser will automatically return a PropertySelector with merged properties from baseButton and .Button. Any conflicting properties will be overridden by the subject style. Here is what the .Button object would look like:
.BaseButton as an Object
{
selectorName: .BaseButton,
x: 0,
y: 0,
width: 100,
height: 100,
padding: 5,
margin: 10,
backgroundColor: #000000;
}
PropertySelectors created by the CSS parser have a reference to their selector name in the selctorName property. Also, it’s important to note that in this example the x and y values from .BaseButton overrode the ancestor’s values. In this case they are 0 and not 10 as defined in the baseStyle.
Class and ID Selectors
Class (.class) and ID (#id) selectors are supported by the CamoPropertySheet. There is no difference to the CSS parser between Classes, IDs, or regular selectors so when making a selector request it’s important to understand how to join them. In CSS, the inheritance rules dictate that a Base Styles is overridden by a Class Style that in turn is overridden by the ID Style. You can simulate this by passing in multiple selector names when calling the getSelector method. If we wanted to create a “play” button style that inherits the default Button class style and the base interactive style we would call getSelector and pass in "interactive",".BaseButton","#playButton" using commas to separate each style name. By combining the names of each selector by lowest priority to highest priority the getSelector method will automatically parse out each selector and merge them into a single PropertySelector. The last selector name becomes the PropertySelector’s selectorName value.
Pseudo-Selectors
When Pseudo-Selector are requested, their parent style’s properties will be added to the returned Object. Adding a colon (selector:pseudo-selector) to any style name will alert the parser that it needs to also inherit properties from the selector name to the left of the colon. In the above CSS example we request #playButton:over we will get back the following object:
#playButton:over as an Object
{
styleName: #playButton:over,
backgroundColor: #333333,
backgroundImage: url('/images/full_screen_background.jpg')
}
In this example the background-color and background-image properties are inherited from the #playButton selector but since #playButton:over has its own background-color the ancestor’s property is overridden.
It is important to keep in mind that there may be a performance hit when parsing large CSS files with lots of inherited selectors. Also, the compression used when parsing the CSS uses a complex RegEx pattern so it is better to do the compression on the server side instead of during run time. Outside of this limitation, the real power of the CSS parser comes into play when applying PropertySelectors to CamoDisplay classes.