private static void ProcessCss(TemplateControl rootControl, string strRawCss) { // has this template been processed before? string strControlType = rootControl.GetType().FullName; bool bIsNewStyleSet = false; Dictionary hash_xidsToCssClasses = (Dictionary)_hash_processedCss[strControlType] ?? null; if (hash_xidsToCssClasses == null) { hash_xidsToCssClasses = new Dictionary(); bIsNewStyleSet = true; } ////// // rewrite css rules if this is the first time loading this control. if (bIsNewStyleSet) { string strProcessedCss = strRawCss; // rerewrite element id references strProcessedCss = strProcessedCss.ReplaceRegex( new RegularExpression(@"#[a-zA-Z]\w*", "g"), delegate(string s) { string sSub = s.Substr(1); // if #this if (sSub == "this") { hash_xidsToCssClasses[sSub] = (string)hash_xidsToCssClasses[sSub] ?? GenerateNewAutoCssClass(); #if DEBUG return "." + (string)hash_xidsToCssClasses[sSub] + "/* " + s + " */"; #else return "." + (string)hash_xidsToCssClasses[sSub]; #endif } // if #someLocalId (element) jQueryObject jqElement = (jQueryObject)rootControl._hash_oNamedChildElements[sSub] ?? null; if (jqElement != null) { hash_xidsToCssClasses[sSub] = (string)hash_xidsToCssClasses[sSub] ?? GenerateNewAutoCssClass(); #if DEBUG return "." + (string)hash_xidsToCssClasses[sSub] + "/* " + s + " */"; #else return "." + (string)hash_xidsToCssClasses[sSub]; #endif } // if #someLocalId (control) TemplateControl oControl = (TemplateControl)rootControl._hash_oNamedChildControls[sSub] ?? null; if (oControl != null) { hash_xidsToCssClasses[sSub] = (string)hash_xidsToCssClasses[sSub] ?? GenerateNewAutoCssClass(); #if DEBUG return "." + (string)hash_xidsToCssClasses[sSub] + "/* " + s + " */"; #else return "." + (string)hash_xidsToCssClasses[sSub]; #endif } // unknown. keep. return s; } ); // rewrite url paths bool isIE = jQuery.Browser.MSIE; string cssBaseUrl = BaseUrlImages; if (cssBaseUrl.Length > 0 || isIE) { RegularExpression rxUrl = new RegularExpression(@"url\w*\((.*)\)", "i"); Func<string, bool> fnIsAbsolute = delegate(string url) { return url.StartsWith("http://") || url.StartsWith("https://"); }; string currentProtocolDomain; { Location loc = Window.Location; currentProtocolDomain = loc.Protocol + "//" + loc.HostnameAndPort + "/" ; } strProcessedCss = strProcessedCss.ReplaceRegex( new RegularExpression(@":\w*url\w*\(""?.*""?\)", "ig"), delegate(string s) { string[] matches = rxUrl.Exec(s); Debug.Assert(matches.Length == 2); string url = matches[1]; if (fnIsAbsolute(url)) { // already absolute. no change needed. return s; } // prepend base url url = CombinePaths(cssBaseUrl, url); if (isIE && !fnIsAbsolute(url)) { // rewrite url()'s to be absolute (workaround for IE7/8/9 bug with relative paths in dynamically added css in iframes). url = CombinePaths(currentProtocolDomain, url); } return string.Format(@":url(""{0}"")", url); } ); } _processedCss = _processedCss + " " + strProcessedCss; // update global style jQueryObject jqHead = jQuery.Select("head"); jQueryObject jqStyle; if (jQuery.Browser.MSIE) { // if IE, we need to concat all style rules (otherwise hit a max css node limit in ie) // is there an existing global css node? jqStyle = jQuery.Select("#" + CssGlobalNodeId); Number ieVersion = Number.ParseDouble(jQuery.Browser.Version); // setting inner html does not work on IE8. so we do a string concat here instead. if (Number.IsFinite(ieVersion) && ieVersion <= 8) { // remove existing global style node if exists. if (jqStyle.Length != 0) { jqStyle.Remove(); } // build new global style node. jqStyle = jQuery.FromHtml(@"<style type=""text/css"">" + _processedCss + @"</style>"); jqStyle.Attribute("id", CssGlobalNodeId); jqHead.Append(jqStyle); } else { // create new global style node if missing. if (jqStyle.Length == 0) { jqStyle = jQuery.FromHtml(@"<style type=""text/css""></style>"); jqStyle.Attribute("id", CssGlobalNodeId); jqHead.Append(jqStyle); } // modify global style node. jqStyle.Text(_processedCss); } } else { // in non-ie, just append another css node. jqStyle = jQuery.FromHtml(@"<style type=""text/css""></style>"); jqStyle.Html(strProcessedCss); jqHead.Append(jqStyle); } // save rewrite rules _hash_processedCss[strControlType] = hash_xidsToCssClasses; } ////// // apply classes to named elements foreach (DictionaryEntry kvp in hash_xidsToCssClasses) { string key = kvp.Key; if (key == "this") { rootControl._jqRootElement.AddClass((string)kvp.Value); continue; } // is it an element? jQueryObject jqElement = (jQueryObject)rootControl._hash_oNamedChildElements[key] ?? null; if (jqElement != null) { jqElement.AddClass((string)kvp.Value); continue; } // is it a control? TemplateControl oControl = (TemplateControl)rootControl._hash_oNamedChildControls[key] ?? null; if (oControl != null) { oControl.RootElement.AddClass((string)kvp.Value); continue; } #if DEBUG throw new Exception("CSS rule found for no corresponding element/control."); #endif } }
/// <summary> /// For the given template control, retrieve its html template. /// </summary> /// <param name="templateControl"></param> /// <returns></returns> private static string FindTemplate(TemplateControl templateControl) { string templateTypeName = templateControl.GetType().FullName; if (!_hash_templateCache.ContainsKey(templateTypeName)) { string strTemplate = (string)Type.GetField(templateControl, "template"); if (!string.IsNullOrEmpty(strTemplate)) { _hash_templateCache[templateTypeName] = strTemplate; } else { // search for a private/obfuscated field foreach (DictionaryEntry kvp in Dictionary.GetDictionary(templateControl)) { if (!(kvp.Value is string)) { continue; } if (!kvp.Key.StartsWith("$")) { continue; } string strTmp = ((string)kvp.Value).Trim(); // todo: avoid a trim. if (strTmp.StartsWith("<")) { _hash_templateCache[templateTypeName] = kvp.Value; } } } } return (string)(_hash_templateCache[templateTypeName] ?? null); }