From 06592aa38d4f4bb9f50fa858503c336ad9b7b024 Mon Sep 17 00:00:00 2001 From: Clemente Gomez Date: Wed, 11 Nov 2009 18:39:54 -0500 Subject: [PATCH 1/2] initial upload --- .../fcss/stylesheets/FStyleSheet.as | 1 + .../fcss/stylesheets/StyleSheet.as | 1 - .../fcss/stylesheets/StyleSheetCollection.as | 6 +- .../flashartofwar/fcss/utils/CSSTidyUtil.as | 13 + tools/FCSSEditor/src/FCSSEditor-app.xml | 135 +++++++ tools/FCSSEditor/src/FCSSEditor.css | 9 + tools/FCSSEditor/src/FCSSEditor.mxml | 329 ++++++++++++++++++ tools/FCSSEditor/src/FCSSSpeedTest-app.xml | 135 +++++++ tools/FCSSEditor/src/Test-app.xml | 135 +++++++ tools/FCSSEditor/src/Test.mxml | 8 + 10 files changed, 768 insertions(+), 4 deletions(-) create mode 100644 src/com/flashartofwar/fcss/stylesheets/FStyleSheet.as delete mode 100644 src/com/flashartofwar/fcss/stylesheets/StyleSheet.as create mode 100644 tools/FCSSEditor/src/FCSSEditor-app.xml create mode 100644 tools/FCSSEditor/src/FCSSEditor.css create mode 100644 tools/FCSSEditor/src/FCSSEditor.mxml create mode 100644 tools/FCSSEditor/src/FCSSSpeedTest-app.xml create mode 100644 tools/FCSSEditor/src/Test-app.xml create mode 100644 tools/FCSSEditor/src/Test.mxml diff --git a/src/com/flashartofwar/fcss/stylesheets/FStyleSheet.as b/src/com/flashartofwar/fcss/stylesheets/FStyleSheet.as new file mode 100644 index 0000000..2e9b3fa --- /dev/null +++ b/src/com/flashartofwar/fcss/stylesheets/FStyleSheet.as @@ -0,0 +1 @@ + /** *

Original Author: jessefreeman

*

Class File: StyleSheet.as

* *

Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions:

* *

The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software.

* *

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE.

* *

Licensed under The MIT License

*

Redistributions of files must retain the above copyright notice.

* *

Revisions
* 1.0 Initial version Aug 28, 2009

* */ package com.flashartofwar.fcss.stylesheets { import com.flashartofwar.fcss.styles.Style; import com.flashartofwar.fcss.utils.CSSTidyUtil; /** * @author jessefreeman */ public class FStyleSheet implements IStyleSheet { protected static const CSS_BLOCKS:RegExp = /[^{]*\{([^}]*)*}/g; protected static const CSS_VAR_PATTERN:RegExp = /var\(([\w'-]+)\)/g; protected static const FIND_A_HREF_CLASS:RegExp = /a\.([^\:]+)/gi; protected static const STYLE_SHEET:String = "style-sheet"; protected static const STYLE_SHEET_CAMEL:String = "styleSheet"; protected var cssText:String; protected var styleIndex:Array = []; // holds a lookup table for all parsed CSS classes protected var relatedstyleIndex:Array = []; // holds arrays for related classes base on Class's Name ID protected var cachedstyles:Array = []; protected var _styleNames:Array = []; /** * * @return * */ public function get styleNames():Array { return _styleNames.slice(); } /** *

Class constructor.

*/ public function FStyleSheet() { super(); } /** *

Check to see if style exists.

* * @param styleName * @return * */ public function hasStyle(name:String):Boolean { return (_styleNames.indexOf(name) == -1) ? false : true; } /** *

Returns a list of related styles.

* @param styleName * @return * */ public function relatedStyle(name:String):Array { return relatedstyleIndex[name].slice(); } /** * * @return * */ public function toString():String { return cssText; } /** * * */ public function clear():void { cssText = ""; cachedstyles.length = 0; _styleNames.length = 0; } /** * * @param cssTest * */ public function parseCSS(cssTest:String, useCSSTidy:Boolean = true):void { cachedstyles.length = 0; cssText = useCSSTidy ? tidy(cssTest) : cssTest; indexCSS(cssText); // Force @variables to cache var style:Style = getStyle("@variables"); } /** *

This looks up a style and returns an object. To help support style * inheritance you can also pass in an comma delimited string and have * the list merged into one style based on the order of the list. The * first item being lower all the way up to the last in the list.

* * @param styleName * @return * */ public function getStyle(... styleNames):Style { // Split styles and get the total related classes var total:Number = styleNames.length; var baseProperties:Style = createEmptyStyle(); // Loop through styles and merges them into a single style. for (var i:Number = 0; i < total; i++) { if (hasStyle(styleNames[i])) { var currentPropertiesID:String = styleNames[i]; var tempProperties:Style = styleLookup(currentPropertiesID); baseProperties.merge(tempProperties); } } // Returns megred style return baseProperties; } /** * * @param styleName * @param propertystyle * */ public function newStyle(name:String, style:Style):void { if (_styleNames.indexOf(name) == -1) _styleNames.push(name); if(style.styleName != name) style.styleName = name; cachedstyles[name] = style; } /** *

Creates a style sheet string from supplied style names. You can combine * Properties into a larger style sheet by separating styles by a comma. * If no styleName is provided the entire set of styles will be included * in the new styleSheet.

* *

Its important to note that this is incredibly expensive to perform * on large CamoStyeSheets. To avoid this, make sure you pass in only * the styles you need.

* * @param styleName comma separated list of styles that will be used * to create a style sheet string. * @return String style sheet from passed in styles * */ public function clone(... styleNames):FStyleSheet { var tempStyleSheet:FStyleSheet = new FStyleSheet(); var total:Number = styleNames.length; if (total == 0) { tempStyleSheet.parseCSS(cssText.toString()); } else { var tempCSSText:String = ""; //TODO right now this just combines styles into one string, need to add support for style inheritance. // Loop through styles and merges them into a single style. for (var i:Number = 0; i < total; i++) { if ((hasStyle(styleNames[i]) && (styleNames[i] is String))) { tempCSSText += getStyle(styleNames[i]).toString(); } } // Strip classes from a styles tempCSSText = tempCSSText.replace(FIND_A_HREF_CLASS, "a"); tempStyleSheet.parseCSS(tempCSSText, false); } return tempStyleSheet; } /** * * @return * */ protected function createEmptyStyle():Style { return new Style(); } /** * * @param cssTest * @return * */ protected function tidy(cssTest:String):String { return CSSTidyUtil.tidy(cssTest); } /** *

Does a preliminary run through of the css styles and indexes them. * This is only done once and to helps speed up the retrieval of the raw * css style cssText. Its important to note that this index is only for * the style and its string content. Any CSS props inside of the * style are not parsed here. This is simply used as a lookup table * for the raw cssText.

* * @param css * */ protected function indexCSS(css:String):void { // Use RegEx to get all css blocks - anything inside of { } along with the style (name) var blocks:Array = css.match(CSS_BLOCKS); // get reference of the total blocks found to speed up for i loop var total:Number = blocks.length; // Loop through all styles, get the style name and its cssText, then store it in the index for (var i:int = 0; i < total; i++) { parseStyleBlock(blocks[i]); } } /** *

This splits up a CSS style from its cssText. By doing the split on * the "{" we can assume anything in index 0 of the array is the style's * name, and the rest is the css props. Also we cut off the last character * (in this case the trailing "}") to make sure we get a clean reference * to the css properties inside.

* * @param cssClass * @return * */ protected function parseStyleBlock(cssClass:String):void { var splitBlock:Array = cssClass.split("{"); var related:Array = String(splitBlock[0]).split(" "); var styleName:String = related.pop(); var indexOfColon:Number = styleName.indexOf(":"); if (indexOfColon != -1) { var pseudoBasePropertiesID:String = styleName.substring(0, indexOfColon); related.push(pseudoBasePropertiesID); } var styleBlock:String = String(splitBlock[1]).substr(0, String(splitBlock[1]).length - 1); if (_styleNames.indexOf(styleName) != -1) { styleIndex[styleName] = String(styleIndex[styleName]).concat(styleBlock); clearCachedClass(styleName); } else { _styleNames.push(styleName); styleIndex[styleName] = styleBlock; } // Save out array of left over classes if (!relatedstyleIndex[styleName]) { relatedstyleIndex[styleName] = related; } } /** * * @param styleName */ protected function clearCachedClass(styleName:String):void { if (cachedstyles[styleName]) { delete cachedstyles[styleName]; } } /** *

This goes through a style's name and looks for any related * classes separated by a space. With this we can keep an index of related * classes based on the class's id as a key. This lets us quickly * reference any related class names on the fly without having to re-loop * through the css cssText.

* * @param classes * @param index * @return * */ protected function relatedClasses(classes:String):String { // Split out names of classes var related:Array = classes.split(" "); var classID:String = related.pop(); var indexOfColon:Number = classID.indexOf(":"); if (indexOfColon != -1) { var pseudoBasePropertiesID:String = classID.substring(0, indexOfColon); related.push(pseudoBasePropertiesID); } // Save out array of left over classes relatedstyleIndex[classID] = related; // Return what was found return classID; } /** *

Core lookup function and is responsible for parsing out css * styles, finding related classes, and putting them all together * into a clean Properties.

* *

The first step is to look for a cached version of the class already * requested. If that does not exist it looks up the class id from the * cssIndex. Once the cssText is found it can start looping through related * classes to build a base css object for the desired class to inherit * then override. Once this is done, it is cached in the cachedProperties * dictionary and the created object is returned.

* * @param styleName * @return * */ protected function styleLookup(styleName:String):Style { var tempProperties:Style = (cachedstyles[styleName]) ? cachedstyles[styleName] : null; if (!tempProperties) { tempProperties = createEmptyStyle(); if (hasStyle(styleName)) { // Begin CSS lookup var styleData:String = styleIndex[styleName]; var subjectProperties:Style = convertStringListToProperties(styleData); var ancestors:Array = relatedstyleIndex[styleName]; var totalAncestors:Number = ancestors.length; var ancestorProperties:Style; for (var i:int = 0; i < totalAncestors; i++) { ancestorProperties = styleLookup(ancestors[i]); tempProperties.merge(ancestorProperties); } tempProperties.merge(subjectProperties); tempProperties.styleName = styleName; newStyle(styleName, tempProperties); } } return tempProperties.clone() as Style; } /** *

This function converts a String list to an object. Used to help * split up complex, string lists form css cssText.

* * @param cssText * @param propDelim * @param listDelim */ protected function convertStringListToProperties(cssText:String, propDelim:String = ":", listDelim:String = ";"):Style { // Start - Test for Variables if(cachedstyles["@variables"]) { // If we have a cached variable style run it through the replacer cssText = replaceVaribales(cssText, cachedstyles["@variables"]); } // End - Test for Variables var tempObject:Style = createEmptyStyle(); var list:Array = cssText.split(listDelim); var total:int = list.length; var i:int; // Loop through properties for (i = 0; i < total; i++) { var delimLocation:Number = list[i].indexOf(propDelim); var prop:String = cleanUpProp(list[i].slice(0, delimLocation)); if (prop != "") { var value:String = cleanUpValue(prop, list[i].slice(delimLocation + 1)); tempObject[prop] = value; } } return tempObject; } /** * * @param prop * @return * */ protected function cleanUpProp(prop:String):String { return prop; } /** * * @param prop * @param value * @return * */ protected function cleanUpValue(prop:String, value:String):String { switch (prop) { case STYLE_SHEET: case STYLE_SHEET_CAMEL: var styleNames:Array = value.split(","); return buildStyleSheetString.apply(null, styleNames); break; default: return value; break; } } /** * * @param styleNames * @return * */ protected function buildStyleSheetString(... styleNames):String { var cssTest:String = clone.apply(null, styleNames).toString(); return cssTest; } /** * This util will take a string, search for var(tokens) and replace them * with the values in the supplied object. * * @param text - text you would like to search for tokens * @param paramObj - an object to use to find and replace tokens with * @return * */ protected function replaceVaribales(text:String, paramObj: Object) : String{ return text.replace(CSS_VAR_PATTERN,function():*{return paramObj[arguments[1]];}); } } } \ No newline at end of file diff --git a/src/com/flashartofwar/fcss/stylesheets/StyleSheet.as b/src/com/flashartofwar/fcss/stylesheets/StyleSheet.as deleted file mode 100644 index a237bfa..0000000 --- a/src/com/flashartofwar/fcss/stylesheets/StyleSheet.as +++ /dev/null @@ -1 +0,0 @@ - /** *

Original Author: jessefreeman

*

Class File: StyleSheet.as

* *

Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions:

* *

The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software.

* *

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE.

* *

Licensed under The MIT License

*

Redistributions of files must retain the above copyright notice.

* *

Revisions
* 1.0 Initial version Aug 28, 2009

* */ package com.flashartofwar.fcss.stylesheets { import com.flashartofwar.fcss.styles.Style; import com.flashartofwar.fcss.utils.CSSTidyUtil; /** * @author jessefreeman */ public class StyleSheet implements IStyleSheet { protected static const CSS_BLOCKS:RegExp = /[^{]*\{([^}]*)*}/g; protected static const CSS_VAR_PATTERN:RegExp = /var\(([\w'-]+)\)/g; protected static const FIND_A_HREF_CLASS:RegExp = /a\.([^\:]+)/gi; protected static const STYLE_SHEET:String = "style-sheet"; protected static const STYLE_SHEET_CAMEL:String = "styleSheet"; protected var cssText:String; protected var styleIndex:Array = []; // holds a lookup table for all parsed CSS classes protected var relatedstyleIndex:Array = []; // holds arrays for related classes base on Class's Name ID protected var cachedstyles:Array = []; protected var _styleNames:Array = []; /** * * @return * */ public function get styleNames():Array { return _styleNames.slice(); } /** *

Class constructor.

*/ public function StyleSheet() { super(); } /** *

Check to see if style exists.

* * @param styleName * @return * */ public function hasStyle(name:String):Boolean { return (_styleNames.indexOf(name) == -1) ? false : true; } /** *

Returns a list of related styles.

* @param styleName * @return * */ public function relatedStyle(name:String):Array { return relatedstyleIndex[name].slice(); } /** * * @return * */ public function toString():String { return cssText; } /** * * */ public function clear():void { cssText = ""; cachedstyles.length = 0; _styleNames.length = 0; } /** * * @param cssTest * */ public function parseCSS(cssTest:String, useCSSTidy:Boolean = true):void { cachedstyles.length = 0; cssText = useCSSTidy ? tidy(cssTest) : cssTest; indexCSS(cssText); // Force @variables to cache var style:Style = getStyle("@variables"); } /** *

This looks up a style and returns an object. To help support style * inheritance you can also pass in an comma delimited string and have * the list merged into one style based on the order of the list. The * first item being lower all the way up to the last in the list.

* * @param styleName * @return * */ public function getStyle(... styleNames):Style { // Split styles and get the total related classes var total:Number = styleNames.length; var baseProperties:Style = createEmptyStyle(); // Loop through styles and merges them into a single style. for (var i:Number = 0; i < total; i++) { if (hasStyle(styleNames[i])) { var currentPropertiesID:String = styleNames[i]; var tempProperties:Style = styleLookup(currentPropertiesID); baseProperties.merge(tempProperties); } } // Returns megred style return baseProperties; } /** * * @param styleName * @param propertystyle * */ public function newStyle(name:String, style:Style):void { if (_styleNames.indexOf(name) == -1) _styleNames.push(name); if(style.styleName != name) style.styleName = name; cachedstyles[name] = style; } /** *

Creates a style sheet string from supplied style names. You can combine * Properties into a larger style sheet by separating styles by a comma. * If no styleName is provided the entire set of styles will be included * in the new styleSheet.

* *

Its important to note that this is incredibly expensive to perform * on large CamoStyeSheets. To avoid this, make sure you pass in only * the styles you need.

* * @param styleName comma separated list of styles that will be used * to create a style sheet string. * @return String style sheet from passed in styles * */ public function clone(... styleNames):StyleSheet { var tempStyleSheet:StyleSheet = new StyleSheet(); var total:Number = styleNames.length; if (total == 0) { tempStyleSheet.parseCSS(cssText.toString()); } else { var tempCSSText:String = ""; //TODO right now this just combines styles into one string, need to add support for style inheritance. // Loop through styles and merges them into a single style. for (var i:Number = 0; i < total; i++) { if ((hasStyle(styleNames[i]) && (styleNames[i] is String))) { tempCSSText += getStyle(styleNames[i]).toString(); } } // Strip classes from a styles tempCSSText = tempCSSText.replace(FIND_A_HREF_CLASS, "a"); tempStyleSheet.parseCSS(tempCSSText, false); } return tempStyleSheet; } /** * * @return * */ protected function createEmptyStyle():Style { return new Style(); } /** * * @param cssTest * @return * */ protected function tidy(cssTest:String):String { return CSSTidyUtil.tidy(cssTest); } /** *

Does a preliminary run through of the css styles and indexes them. * This is only done once and to helps speed up the retrieval of the raw * css style cssText. Its important to note that this index is only for * the style and its string content. Any CSS props inside of the * style are not parsed here. This is simply used as a lookup table * for the raw cssText.

* * @param css * */ protected function indexCSS(css:String):void { // Use RegEx to get all css blocks - anything inside of { } along with the style (name) var blocks:Array = css.match(CSS_BLOCKS); // get reference of the total blocks found to speed up for i loop var total:Number = blocks.length; // Loop through all styles, get the style name and its cssText, then store it in the index for (var i:int = 0; i < total; i++) { parseStyleBlock(blocks[i]); } } /** *

This splits up a CSS style from its cssText. By doing the split on * the "{" we can assume anything in index 0 of the array is the style's * name, and the rest is the css props. Also we cut off the last character * (in this case the trailing "}") to make sure we get a clean reference * to the css properties inside.

* * @param cssClass * @return * */ protected function parseStyleBlock(cssClass:String):void { var splitBlock:Array = cssClass.split("{"); var related:Array = String(splitBlock[0]).split(" "); var styleName:String = related.pop(); var indexOfColon:Number = styleName.indexOf(":"); if (indexOfColon != -1) { var pseudoBasePropertiesID:String = styleName.substring(0, indexOfColon); related.push(pseudoBasePropertiesID); } var styleBlock:String = String(splitBlock[1]).substr(0, String(splitBlock[1]).length - 1); if (_styleNames.indexOf(styleName) != -1) { styleIndex[styleName] = String(styleIndex[styleName]).concat(styleBlock); clearCachedClass(styleName); } else { _styleNames.push(styleName); styleIndex[styleName] = styleBlock; } // Save out array of left over classes if (!relatedstyleIndex[styleName]) { relatedstyleIndex[styleName] = related; } } /** * * @param styleName */ protected function clearCachedClass(styleName:String):void { if (cachedstyles[styleName]) { delete cachedstyles[styleName]; } } /** *

This goes through a style's name and looks for any related * classes separated by a space. With this we can keep an index of related * classes based on the class's id as a key. This lets us quickly * reference any related class names on the fly without having to re-loop * through the css cssText.

* * @param classes * @param index * @return * */ protected function relatedClasses(classes:String):String { // Split out names of classes var related:Array = classes.split(" "); var classID:String = related.pop(); var indexOfColon:Number = classID.indexOf(":"); if (indexOfColon != -1) { var pseudoBasePropertiesID:String = classID.substring(0, indexOfColon); related.push(pseudoBasePropertiesID); } // Save out array of left over classes relatedstyleIndex[classID] = related; // Return what was found return classID; } /** *

Core lookup function and is responsible for parsing out css * styles, finding related classes, and putting them all together * into a clean Properties.

* *

The first step is to look for a cached version of the class already * requested. If that does not exist it looks up the class id from the * cssIndex. Once the cssText is found it can start looping through related * classes to build a base css object for the desired class to inherit * then override. Once this is done, it is cached in the cachedProperties * dictionary and the created object is returned.

* * @param styleName * @return * */ protected function styleLookup(styleName:String):Style { var tempProperties:Style = (cachedstyles[styleName]) ? cachedstyles[styleName] : null; if (!tempProperties) { tempProperties = createEmptyStyle(); if (hasStyle(styleName)) { // Begin CSS lookup var styleData:String = styleIndex[styleName]; var subjectProperties:Style = convertStringListToProperties(styleData); var ancestors:Array = relatedstyleIndex[styleName]; var totalAncestors:Number = ancestors.length; var ancestorProperties:Style; for (var i:int = 0; i < totalAncestors; i++) { ancestorProperties = styleLookup(ancestors[i]); tempProperties.merge(ancestorProperties); } tempProperties.merge(subjectProperties); tempProperties.styleName = styleName; newStyle(styleName, tempProperties); } } return tempProperties.clone() as Style; } /** *

This function converts a String list to an object. Used to help * split up complex, string lists form css cssText.

* * @param cssText * @param propDelim * @param listDelim */ protected function convertStringListToProperties(cssText:String, propDelim:String = ":", listDelim:String = ";"):Style { // Start - Test for Variables if(cachedstyles["@variables"]) { // If we have a cached variable style run it through the replacer cssText = replaceVaribales(cssText, cachedstyles["@variables"]); } // End - Test for Variables var tempObject:Style = createEmptyStyle(); var list:Array = cssText.split(listDelim); var total:int = list.length; var i:int; // Loop through properties for (i = 0; i < total; i++) { var delimLocation:Number = list[i].indexOf(propDelim); var prop:String = cleanUpProp(list[i].slice(0, delimLocation)); if (prop != "") { var value:String = cleanUpValue(prop, list[i].slice(delimLocation + 1)); tempObject[prop] = value; } } return tempObject; } /** * * @param prop * @return * */ protected function cleanUpProp(prop:String):String { return prop; } /** * * @param prop * @param value * @return * */ protected function cleanUpValue(prop:String, value:String):String { switch (prop) { case STYLE_SHEET: case STYLE_SHEET_CAMEL: var styleNames:Array = value.split(","); return buildStyleSheetString.apply(null, styleNames); break; default: return value; break; } } /** * * @param styleNames * @return * */ protected function buildStyleSheetString(... styleNames):String { var cssTest:String = clone.apply(null, styleNames).toString(); return cssTest; } /** * This util will take a string, search for var(tokens) and replace them * with the values in the supplied object. * * @param text - text you would like to search for tokens * @param paramObj - an object to use to find and replace tokens with * @return * */ protected function replaceVaribales(text:String, paramObj: Object) : String{ return text.replace(CSS_VAR_PATTERN,function():*{return paramObj[arguments[1]];}); } } } \ No newline at end of file diff --git a/src/com/flashartofwar/fcss/stylesheets/StyleSheetCollection.as b/src/com/flashartofwar/fcss/stylesheets/StyleSheetCollection.as index de9970f..dfa280b 100644 --- a/src/com/flashartofwar/fcss/stylesheets/StyleSheetCollection.as +++ b/src/com/flashartofwar/fcss/stylesheets/StyleSheetCollection.as @@ -78,7 +78,7 @@ package com.flashartofwar.fcss.stylesheets public function get baseStyleSheet():IStyleSheet { if (!styleSheets[baseStyleSheetName]) - addStyleSheet(baseStyleSheetName, new StyleSheet()); + addStyleSheet(baseStyleSheetName, new FStyleSheet()); return styleSheets[baseStyleSheetName]; } @@ -148,7 +148,7 @@ package com.flashartofwar.fcss.stylesheets */ public function parseCSS(CSSText:String, compressText:Boolean = true):void { - var styleSheet:StyleSheet = new StyleSheet(); + var styleSheet:FStyleSheet = new FStyleSheet(); styleSheet.parseCSS(CSSText, compressText); addStyleSheet(defaultSheetName + (totalStyleSheets + 1), styleSheet); @@ -172,7 +172,7 @@ package com.flashartofwar.fcss.stylesheets */ public function removeStyleSheet(id:String):IStyleSheet { - var styleSheet:StyleSheet = styleSheets[id]; + var styleSheet:FStyleSheet = styleSheets[id]; delete styleSheets[id]; _totalSheets--; return styleSheet; diff --git a/src/com/flashartofwar/fcss/utils/CSSTidyUtil.as b/src/com/flashartofwar/fcss/utils/CSSTidyUtil.as index efe191d..0e86207 100644 --- a/src/com/flashartofwar/fcss/utils/CSSTidyUtil.as +++ b/src/com/flashartofwar/fcss/utils/CSSTidyUtil.as @@ -16,6 +16,10 @@ package com.flashartofwar.fcss.utils { protected static const COMPRESS_CSS:RegExp = /\s*([@{}:;,]|\)\s|\s\()\s*|\/\*([^*\\\\]|\*(?!\/))+\*\/|[\n\r\t]|(px)|(%)/g; + protected static const OPENING_BRACKET:RegExp = /({)/g; + protected static const SINGLE_CSS_LINE:RegExp = /(;)/g; + protected static const CSS_PROPERTY_DIVIDER:RegExp = /(:)/g; + protected static const CLOSING_BRACKET:RegExp = /\t(})/g; /** *

This uses regex to remove spaces, breaks, "px" and other items @@ -29,6 +33,15 @@ package com.flashartofwar.fcss.utils { return cssText.replace(COMPRESS_CSS, "$1"); } + + public static function format(cssText:String):String + { + var unTidyText:String = cssText.replace(OPENING_BRACKET, "\n$1\n\t"); + unTidyText = unTidyText.replace(SINGLE_CSS_LINE, "$1\n\t"); + unTidyText = unTidyText.replace(CSS_PROPERTY_DIVIDER, " $1 "); + unTidyText = unTidyText.replace(CLOSING_BRACKET, "$1\n\n"); + return unTidyText; + } } } diff --git a/tools/FCSSEditor/src/FCSSEditor-app.xml b/tools/FCSSEditor/src/FCSSEditor-app.xml new file mode 100644 index 0000000..ff64f97 --- /dev/null +++ b/tools/FCSSEditor/src/FCSSEditor-app.xml @@ -0,0 +1,135 @@ + + + + + + + FCSSEditor + + + FCSSEditor + + + FCSSEditor + + + v1 + + + + + + + + + + + + [This value will be overwritten by Flash Builder in the output app.xml] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/FCSSEditor/src/FCSSEditor.css b/tools/FCSSEditor/src/FCSSEditor.css new file mode 100644 index 0000000..5fd92a6 --- /dev/null +++ b/tools/FCSSEditor/src/FCSSEditor.css @@ -0,0 +1,9 @@ +/* CSS file */ +@namespace s "library://ns.adobe.com/flex/spark"; +@namespace mx "library://ns.adobe.com/flex/halo"; + + +global +{ + fontFamily: Arial; +} \ No newline at end of file diff --git a/tools/FCSSEditor/src/FCSSEditor.mxml b/tools/FCSSEditor/src/FCSSEditor.mxml new file mode 100644 index 0000000..e50222f --- /dev/null +++ b/tools/FCSSEditor/src/FCSSEditor.mxml @@ -0,0 +1,329 @@ + + + + + 0) + results.push({time:styleRequestTime, name:styleName}); + + requestTimes += styleRequestTime; + + } + t = (getTimer()-t); + strDebug = "\n\tTotal time to request "+(total-1)+" styles time: " + t + " ms"; + speedText += (strDebug); + + speedText += "\n\t"+(styles.length - results.length)+"/"+styles.length+" styles took 0 ms"; + + var average:Number = results.length/styles.length; + + speedText += ("\n\tAverage Style Request Time", average, "ms"); + results.sortOn("time", Array.NUMERIC | Array.DESCENDING); + + var average2:Number = ((requestTimes/total-1) < 0) ? 0 : (requestTimes/total-1); + + speedText += ("\n\tShortest Request",results[results.length - 1].time, results[results.length - 1].name," (Styles that take 0 ms do not count.)"); + speedText += ("\n\tLongest Request",results[0].time, results[0].name); + + var oneSecondRequests:Number = 0; + var longerStyles:String =""; + for(i = 0; i < results.length; i++) + { + if(results[i].time > 1) + longerStyles += "\n\tStyle '"+results[i].name+"' - "+results[i].time+" ms"; + else + oneSecondRequests ++; + } + + speedText += ("\n\t"+oneSecondRequests+" styles took 1 ms"); + + speedText += ("\n\tStyle requests > 1 ms:"); + speedText += (longerStyles); + } + + private function runTest(event : Event):void + { + if((event.target as TabNavigator).selectedIndex == 2 && cssEditorField.text != "") + { + startSpeedTest(cssEditorField.text); + } + } + + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/FCSSEditor/src/FCSSSpeedTest-app.xml b/tools/FCSSEditor/src/FCSSSpeedTest-app.xml new file mode 100644 index 0000000..94f8340 --- /dev/null +++ b/tools/FCSSEditor/src/FCSSSpeedTest-app.xml @@ -0,0 +1,135 @@ + + + + + + + FCSSSpeedTest + + + FCSSSpeedTest + + + FCSSSpeedTest + + + v1 + + + + + + + + + + + + [This value will be overwritten by Flash Builder in the output app.xml] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/FCSSEditor/src/Test-app.xml b/tools/FCSSEditor/src/Test-app.xml new file mode 100644 index 0000000..cdabf13 --- /dev/null +++ b/tools/FCSSEditor/src/Test-app.xml @@ -0,0 +1,135 @@ + + + + + + + Test + + + Test + + + Test + + + v1 + + + + + + + + + + + + [This value will be overwritten by Flash Builder in the output app.xml] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/FCSSEditor/src/Test.mxml b/tools/FCSSEditor/src/Test.mxml new file mode 100644 index 0000000..47376f5 --- /dev/null +++ b/tools/FCSSEditor/src/Test.mxml @@ -0,0 +1,8 @@ + + + + + + From 7e8c3f91f6595affa241b152902138993838c7e7 Mon Sep 17 00:00:00 2001 From: Clemente Gomez Date: Mon, 16 Nov 2009 13:40:55 -0500 Subject: [PATCH 2/2] Updated Editor --- tools/FCSSEditor/src/FCSSEditor.mxml | 250 ++++++++++++++++++++++++++- 1 file changed, 242 insertions(+), 8 deletions(-) diff --git a/tools/FCSSEditor/src/FCSSEditor.mxml b/tools/FCSSEditor/src/FCSSEditor.mxml index e50222f..6855450 100644 --- a/tools/FCSSEditor/src/FCSSEditor.mxml +++ b/tools/FCSSEditor/src/FCSSEditor.mxml @@ -19,6 +19,10 @@ import mx.containers.TabNavigator; import mx.containers.VBox; import mx.controls.Alert; + import mx.controls.textClasses.TextRange; + + import net.anirudh.as3syntaxhighlight.CodePrettyPrint; + import net.anirudh.as3syntaxhighlight.PseudoThread; import spark.components.NavigatorContent; @@ -52,6 +56,11 @@ fileInputField.text = file.nativePath; } + /** + * + * Load a CSS file from the system. + * + **/ private function loadFromFile():void { cssFile.addEventListener(Event.COMPLETE, onFileLoaded, false, 0 , true); @@ -59,6 +68,11 @@ isURL = true; } + /** + * + * Load CSS file from a url. + * + **/ private function loadFromURL(url : String):void { if(url == null) Alert.show("Please Enter the URL to the CSS file for select one from your computer.", "Oops No File Specified."); @@ -75,6 +89,11 @@ cssText = css; } + /** + * + * Save the file to the file system. + * + **/ private function saveFile():void { var savedCSSFile : File = new File(); @@ -82,14 +101,22 @@ if(tidyFlag.selected) { - savedCSSFile.save(CSSTidyUtil.tidy(cssEditorField.text), "editedCSS.css"); + savedCSSFile.save(CSSTidyUtil.tidy(cssText), "editedCSS.css"); } else { - savedCSSFile.save(cssEditorField.text, "editedCSS.css"); + savedCSSFile.save(cssText, "editedCSS.css"); } } + /** + * + * Checks if the CSS being loaded is compressed. If so, it will be uncompressed. + * + * @param cssData CSS file to be checked. + * @return String Uncompressed CSS + * + **/ private function checkCSS(cssData:String):String { var regEx:RegExp = /(\s)/; @@ -107,6 +134,13 @@ return css; } + /** + * + * Fills in the Selector window. + * + * @param css CSS that is used to populate the selector window. + * + **/ private function populateSelectors(css:String):void { var stylesSheet:FStyleSheet = new FStyleSheet(); @@ -122,19 +156,24 @@ { trace(styles[i]); addField(styles[i]); - } } + } + /** + * + * Adds a new VBox to the Selector Window. + * + * @param name Labelfor the VBox. + * + **/ private function addField(name : String):void { var container:VBox = new VBox(); - //var dataGrid:DataGrid = new DataGrid(); container.label = name; container.width = selectorsField.width; container.height = 10; - //form.addChild(dataGrid); selectorsField.addChild(container); } @@ -188,6 +227,14 @@ fileInputField.text = ""; startSpeedTest(css); populateEditorPane(css); + populateSelectors(css); + } + + protected function onUpdateText(event : Event):void + { + cssText = cssEditorField.text; + codeHighlight(); + trace("updated"); } @@ -283,10 +330,197 @@ private function runTest(event : Event):void { - if((event.target as TabNavigator).selectedIndex == 2 && cssEditorField.text != "") + if((event.target as TabNavigator).selectedIndex == 2 && cssText != "") + { + startSpeedTest(cssText); + } + } + + + + + private var cssString:String =".spl {font-family:sandboxcode;color: #4f94cd;} .str { font-family:sandboxcode; color: #880000; } .kwd { font-family:sandboxcode; color: #000088; } .com { font-family:sandboxcode; color: #008800; } .typ { font-family:sandboxcode; color: #0068CF; } .lit { font-family:sandboxcode; color: #006666; } .pun { font-family:sandboxcode; color: #666600; } .pln { font-family:sandboxcode; color: #222222; } .tag { font-family:sandboxcode; color: #000088; } .atn { font-family:sandboxcode; color: #660066; } .atv { font-family:sandboxcode; color: #880000; } .dec { font-family:sandboxcode; color: #660066; } "; + private var codeStyle:StyleSheet; + private var codePrettyPrint:CodePrettyPrint; + private var codeTimer:Timer; + private var asyncStop:Boolean; + private var asyncRunning:Boolean; + private var codeStylePF:StyleSheet; + private var srclenPF:int; + private var arrPF:Array; + private var lenPF:int; + private var firstNodePF:Boolean; + private var firstIndexPF:int; + private var pfasyncrunning:Boolean; + private var pfasyncstop:Boolean; + private var desclenPF:int; + private var colorThread:PseudoThread; + [Bindable] + private var asyncCodeState:String; + + private function codeHighlight():void + { + if ( !codeTimer ) + { + codeTimer = new Timer(200,1); + codeTimer.addEventListener(TimerEvent.TIMER, doPrettyPrint); + + } + + if ( codeTimer.running ) + { + codeTimer.stop(); + } + codeTimer.reset(); + // wait for some time to see if we need to highlight or not + codeTimer.start(); + } + + private function doPrettyPrint(event:TimerEvent=null):void + { + if ( !codeStyle ) + { + codeStyle = new StyleSheet(); + codePrettyPrint = new CodePrettyPrint(); + codeStyle.parseCSS(cssString); + } + + if ( codePrettyPrint.asyncRunning ) { - startSpeedTest(cssEditorField.text); + codePrettyPrint.prettyPrintStopAsyc = true; + callLater(doPrettyPrint); + return; } + + if ( pfasyncrunning ) + { + pfasyncstop = true; + callLater(doPrettyPrint); + return; + } + codeHighlightInPlace(); + + } + + private function pfinit(startIdx:int, endIdx:int):void + { + codeStylePF = codeStyle; + srclenPF = endIdx - startIdx; + arrPF = codePrettyPrint.mainDecorations; + lenPF = arrPF.length; + desclenPF = cssText.length; + firstNodePF = false; + firstIndexPF = 0; + pfasyncrunning = false; + pfasyncstop = false; + } + + private function processFormattedCodeAsync(startIdx:int, endIdx:int, completeFn:Function, optIdx:int=0):Boolean + { + trace("process"); + if ( pfasyncstop ) + { + pfasyncrunning = false; + pfasyncstop = false; + return false; + } + pfasyncrunning = true; + if ( arrPF == null || srclenPF < 1 ) + { + pfasyncrunning = false; + return false; + } + trace("color worker " + optIdx); + var tr:TextRange; + var thecolor:Object; + var i:int = optIdx; + if ( i > 0 && i % 5 == 0 ) + { + asyncCodeState = "Coloring (" + int((i / lenPF) * 100) + "%)..."; + } + if ( i < lenPF ) + { + /* find first node */ + if ( arrPF[i] == 0 && firstNodePF == false ) + { + firstNodePF = true; + return true; + } + else if ( arrPF[i] == 0 && firstNodePF == true ) + { + firstNodePF = false; + firstIndexPF = i; + + } + if ( i - 2 > 0 ) + { + if ( arrPF[i-2] != arrPF[i] && arrPF[i] < cssText.length ) + { + tr = new TextRange(cssEditorField, false, arrPF[i-2] + startIdx, arrPF[i] + startIdx); + thecolor = codeStylePF.getStyle("." + arrPF[i-1]).color; + tr.color = thecolor; + } + + } + return true; + + + } + if ( i > 0 ) + { + i -= 2; + if ( arrPF[i] + startIdx < endIdx ) + { + tr = new TextRange(cssEditorField, false, arrPF[i] + startIdx, endIdx); + thecolor = codeStylePF.getStyle("." + arrPF[i+1]).color; + var totlen:int = cssText.length; + if ( totlen >= endIdx ) + tr.color = thecolor; + + } + } + if ( completeFn != null ) + completeFn(); + trace("color worker done"); + pfasyncrunning = false; + return false; + + } + + private function codePFComplete():void + { + asyncCodeState = ""; + } + + private function codeInPlaceComplete():void + { + asyncCodeState = "Coloring..."; + if ( pfasyncrunning ) + { + pfasyncstop = true; + callLater(codeInPlaceComplete); + return; + } + asyncRunning = false; + + pfinit(0, cssText.length); + colorThread = new PseudoThread(this.systemManager, processFormattedCodeAsync, this, [0, cssText.length, codePFComplete, 0], 3, 2); + } + + private function lexInt(idx:int, total:int):void + { + if ( idx > 0 && idx % 5 == 0 ) + { + asyncCodeState = "Lexing (" + int((idx / total) * 100) + "%)..."; + } + } + + private function codeHighlightInPlace():void + { + asyncRunning = true; + asyncCodeState = "Lexing..."; + codePrettyPrint.prettyPrintAsync(cssText, null, codeInPlaceComplete, lexInt, this.systemManager); + } ]]> @@ -314,7 +548,7 @@ + verticalScrollPolicy="auto" change="onUpdateText(event)"/>