From: Dion O. <dol...@us...> - 2006-01-08 21:14:11
|
Update of /cvsroot/magicajax/magicajax/Core In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21156/magicajax/Core Modified Files: AjaxCallHelper.cs MagicAjaxModule.cs PageFilter.cs Util.cs Log Message: Added functionality to MagicAjaxModule to track all script blocks, and write back to the client the script blocks that were added on a callback. Same for hidden fields, except the hidden fields starting with "__" (these are considered system hidden fields) Index: PageFilter.cs =================================================================== RCS file: /cvsroot/magicajax/magicajax/Core/PageFilter.cs,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -d -r1.8 -r1.9 *** PageFilter.cs 20 Dec 2005 23:51:40 -0000 1.8 --- PageFilter.cs 8 Jan 2006 21:14:02 -0000 1.9 *************** *** 36,67 **** private Stream _memStream; private MagicAjaxContext _magicAjaxContext; ! public PageFilter(Stream _responseStream) ! { ! this._responseStream = _responseStream; ! this._memStream = new MemoryStream(); ! this._magicAjaxContext = MagicAjaxContext.Current; ! } ! ! public string GetViewStateFieldValue() { ! //TODO: use regular expression (much faster) ! #if NET_2_0 ! string search = "<input type=\"hidden\" name=\"__VIEWSTATE\" id=\"__VIEWSTATE\" value=\""; ! #else ! string search = "<input type=\"hidden\" name=\"__VIEWSTATE\" value=\""; ! #endif ! string html = GetHtmlPage(); ! int si = html.IndexOf(search); ! if (si == -1) ! return null; ! ! si += search.Length; ! int ei = html.IndexOf('\"', si); ! if (ei == -1) ! return null; ! ! return html.Substring(si, ei - si); } #if NET_2_0 --- 36,55 ---- private Stream _memStream; private MagicAjaxContext _magicAjaxContext; + private bool _forceMemoryStreamWriting = false; ! /// <summary> ! /// Filters the response stream, and stores everyting in a memorystream ! /// </summary> ! /// <param name="_responseStream"></param> ! /// <param name="forceMemoryStreamWriting">Force writing to memory, no mather if in ajaxcall or not</param> ! public PageFilter(Stream responseStream, bool forceMemoryStreamWriting) { ! _responseStream = responseStream; ! _memStream = new MemoryStream(); ! _magicAjaxContext = MagicAjaxContext.Current; ! _forceMemoryStreamWriting = forceMemoryStreamWriting; } + + public PageFilter(Stream _responseStream): this(_responseStream, false) {} #if NET_2_0 *************** *** 74,85 **** string html = GetHtmlPage(); ! // Look for webpartmanager object creation script ! string searchWPManager = "<script type=\"text\\/javascript\">\\r\\n\\r\\n__wpm = new WebPartManager\\(\\);\\r\\n(?<WPManagerScript>.*?)<\\/script>"; ! Regex regExWPManager = new Regex(searchWPManager, RegexOptions.Singleline | RegexOptions.Compiled); ! Match match = regExWPManager.Match(html); ! // If no webpartmanager script exists in html -> exit ! if (!match.Success) ! return null; // Stringbuilder to hold the output script --- 62,73 ---- string html = GetHtmlPage(); ! //// Look for webpartmanager object creation script ! //string searchWPManager = "<script type=\"text\\/javascript\">\\r\\n\\r\\n__wpm = new WebPartManager\\(\\);\\r\\n(?<WPManagerScript>.*?)<\\/script>"; ! //Regex regExWPManager = new Regex(searchWPManager, RegexOptions.Singleline | RegexOptions.Compiled); ! //Match match = regExWPManager.Match(html); ! //// If no webpartmanager script exists in html -> exit ! //if (!match.Success) ! // return null; // Stringbuilder to hold the output script *************** *** 98,112 **** } ! // Now append the WebpartManager script ! wpmScript.AppendLine(match.Groups["WPManagerScript"].Value); ! // Now append the webpart menu scripts ! string searchWPMenus = "<script type=\"text\\/javascript\">\\r\\n(?<MenuScript>var menuWebPart_.*?)<\\/script>"; ! Regex regExMenuScripts = new Regex(searchWPMenus, RegexOptions.Singleline | RegexOptions.Compiled); ! MatchCollection matches = regExMenuScripts.Matches(html); //ei ! for (int i = 0; i < matches.Count; i++) ! { ! wpmScript.AppendLine(matches[i].Groups["MenuScript"].Value); ! } return wpmScript.ToString(); --- 86,100 ---- } ! //// Now append the WebpartManager script ! //wpmScript.AppendLine(match.Groups["WPManagerScript"].Value); ! //// Now append the webpart menu scripts ! //string searchWPMenus = "<script type=\"text\\/javascript\">\\r\\n(?<MenuScript>var menuWebPart_.*?)<\\/script>"; ! //Regex regExMenuScripts = new Regex(searchWPMenus, RegexOptions.Singleline | RegexOptions.Compiled); ! //MatchCollection matches = regExMenuScripts.Matches(html); //ei ! //for (int i = 0; i < matches.Count; i++) ! //{ ! // wpmScript.AppendLine(matches[i].Groups["MenuScript"].Value); ! //} return wpmScript.ToString(); *************** *** 183,186 **** --- 171,180 ---- public override void Write(byte[] buffer, int offset, int count) { + if (_forceMemoryStreamWriting) + { + _memStream.Write(buffer, offset, count); + return; + } + if (_magicAjaxContext.IsAjaxCall) { Index: AjaxCallHelper.cs =================================================================== RCS file: /cvsroot/magicajax/magicajax/Core/AjaxCallHelper.cs,v retrieving revision 1.17 retrieving revision 1.18 diff -C2 -d -r1.17 -r1.18 *** AjaxCallHelper.cs 22 Dec 2005 23:06:51 -0000 1.17 --- AjaxCallHelper.cs 8 Jan 2006 21:14:02 -0000 1.18 *************** *** 25,28 **** --- 25,29 ---- using System.Web.UI; using System.Collections; + using System.Collections.Specialized; using System.Text; *************** *** 270,274 **** /// <summary> ! /// Produces the javascript that will a new element on the page. /// </summary> /// <param name="parentID">The id of the element that will contain the new element</param> --- 271,275 ---- /// <summary> ! /// Produces the javascript that will add a new element on the page. /// </summary> /// <param name="parentID">The id of the element that will contain the new element</param> *************** *** 278,285 **** public static void WriteAddElementScript(string parentID, string tagName, string elementID, string html, string beforeElemID) { string before = (beforeElemID != null) ? String.Format("\"{0}\"", beforeElemID) : "null"; ! Write( String.Format("AJAXCbo.AddElement(\"{0}\",\"{1}\",\"{2}\",{3},{4});\r\n", parentID, tagName, elementID, EncodeString(html), before) ); } /// <summary> /// Provides the javascript that will remove an existing element from the page. --- 279,310 ---- public static void WriteAddElementScript(string parentID, string tagName, string elementID, string html, string beforeElemID) { + parentID = parentID.StartsWith("document.") ? parentID : string.Format("\"{0}\"", parentID); string before = (beforeElemID != null) ? String.Format("\"{0}\"", beforeElemID) : "null"; ! Write( String.Format("AJAXCbo.AddElement({0},\"{1}\",\"{2}\",{3},{4});\r\n", parentID, tagName, elementID, EncodeString(html), before) ); ! } ! ! /// <summary> ! /// Produces the javascript that will add a script element to the page. ! /// </summary> ! /// <param name="scriptText">The script text</param> ! /// <param name="scriptText">The script attributes</param> ! public static void WriteAddScriptElementScript(string scriptText, NameValueCollection scriptAttributes) ! { ! StringBuilder sbuilder = new StringBuilder("new Array("); ! for (int i=0; i<scriptAttributes.Count; i++) ! { ! if (i>0) ! sbuilder.Append(","); ! sbuilder.AppendFormat("\"{0}\",\"{1}\"", scriptAttributes.Keys[i], scriptAttributes[i]); ! } ! sbuilder.Append(")"); ! Write(String.Format("AJAXCbo.AddScript({0},{1});\r\n", EncodeString(scriptText), sbuilder.ToString())); } + public static void WriteAddHiddenFieldScript(string elementName, string elementValue) + { + Write(String.Format("AJAXCbo.AddHiddenField(\"{0}\",{1});\r\n", elementName, EncodeString(elementValue))); + } + /// <summary> /// Provides the javascript that will remove an existing element from the page. *************** *** 421,430 **** throw new MagicAjaxException("Script writing level should be 0 at the end of AjaxCall. IncreaseWritingLevel calls do not match DecreaseWritingLevel calls."); - WriteEndSignature(); - HttpResponse hr = HttpContext.Current.Response; hr.Clear(); MergeNextWritingLevelRecursive (0); hr.Write ((_sbWritingLevels[0] as StringBuilder).ToString()); --- 446,456 ---- throw new MagicAjaxException("Script writing level should be 0 at the end of AjaxCall. IncreaseWritingLevel calls do not match DecreaseWritingLevel calls."); HttpResponse hr = HttpContext.Current.Response; hr.Clear(); MergeNextWritingLevelRecursive (0); + + WriteEndSignature(); + hr.Write ((_sbWritingLevels[0] as StringBuilder).ToString()); Index: Util.cs =================================================================== RCS file: /cvsroot/magicajax/magicajax/Core/Util.cs,v retrieving revision 1.21 retrieving revision 1.22 diff -C2 -d -r1.21 -r1.22 *** Util.cs 7 Jan 2006 08:03:47 -0000 1.21 --- Util.cs 8 Jan 2006 21:14:02 -0000 1.22 *************** *** 44,47 **** --- 44,49 ---- public static Regex FormElementOptionSelectedRegEx = new Regex(@"<option.*?(?<selected>selected=(""|'|)selected(""|'|)(\s+|(?=>))).*?>", _options); public static Regex ScriptPatternRegEx = new Regex(Util.ScriptPattern, RegexOptions.IgnoreCase); + public static Regex ScriptTagsRegEx = new Regex("<script\\s((?<attrname>[-\\w]+)=\"(?<attrvalue>.*?)\"\\s?)*\\s*>(?<script>.*?)</script>", _options); + public static Regex HiddenInputTagsRegEx = new Regex("<input type=\"hidden\" name=\"(?<name>[-\\w]+)\"\\s.*?\\svalue=\"(?<value>[-\\w]*)\" />", _options); #endregion *************** *** 95,99 **** public static string GetFingerprint(string input) { ! input = GetHtmlWithClearedFormValues(input); MagicAjax.Configuration.OutputCompareMode compareMode = MagicAjaxContext.Current.Configuration.CompareMode; --- 97,101 ---- public static string GetFingerprint(string input) { ! input = GetHtmlWithClearedFormValues(input); MagicAjax.Configuration.OutputCompareMode compareMode = MagicAjaxContext.Current.Configuration.CompareMode; Index: MagicAjaxModule.cs =================================================================== RCS file: /cvsroot/magicajax/magicajax/Core/MagicAjaxModule.cs,v retrieving revision 1.55 retrieving revision 1.56 diff -C2 -d -r1.55 -r1.56 *** MagicAjaxModule.cs 6 Jan 2006 00:58:37 -0000 1.55 --- MagicAjaxModule.cs 8 Jan 2006 21:14:02 -0000 1.56 *************** *** 151,154 **** --- 151,157 ---- } } + + // Register hidden field to hold script fingerprints + page.RegisterHiddenField("__MAGICAJAX_SCRIPT_FINGERPRINTS", string.Empty); // Save to page any changes that may occured to Configuration *************** *** 445,450 **** { return; //if this wasn't a .aspx request, don't process ! } ! string pageKey = _request.QueryString["__AJAX_PAGEUNLOAD"]; if (pageKey != null) --- 448,453 ---- { return; //if this wasn't a .aspx request, don't process ! } ! string pageKey = _request.QueryString["__AJAX_PAGEUNLOAD"]; if (pageKey != null) *************** *** 456,463 **** application.CompleteRequest(); } // Continue only if it is a postback or an AjaxCall ! if ("GET" == _request.HttpMethod) return; Page currentPage = HttpContext.Current.Handler as Page; --- 459,481 ---- application.CompleteRequest(); } + + _magicAjaxContext.IsAjaxCall = (_request.Form["__AJAXCALL"] != null); + + // Set the pagefilter for non-ajax calls, so we can find the script blocks + // written to the client, and also write fingerprints for them. + // This way, on a callback we can see which script blocks were added since + // last call. + //HACK: it would be better to only set a filter when page contains AjaxPanels + if (!_magicAjaxContext.IsAjaxCall) + { + _filter = new PageFilter(_response.Filter, true); + _response.Filter = _filter; + } // Continue only if it is a postback or an AjaxCall ! if (_request.HttpMethod == "GET") ! { return; + } Page currentPage = HttpContext.Current.Handler as Page; *************** *** 472,477 **** } #endif ! ! _magicAjaxContext.IsAjaxCall = (_request.Form["__AJAXCALL"] != null); string configState = _request.Form["__MAGICAJAX_CONFIG"]; if (configState != null) --- 490,494 ---- } #endif ! string configState = _request.Form["__MAGICAJAX_CONFIG"]; if (configState != null) *************** *** 497,500 **** --- 514,522 ---- AjaxCallHelper.Init(); + + // Increase writing level just after Init. So in ApplicationEndRequest we + // can decrease it to write script before all scripts already written. + //HACK: replace this with a more elegant solution + AjaxCallHelper.IncreaseWritingLevel(); try *************** *** 588,591 **** --- 610,618 ---- AjaxCallHelper.Init(); + // Increase writing level just after Init. So in ApplicationEndRequest we + // can decrease it to write script before all scripts already written. + //HACK: replace this with a more elegant solution + AjaxCallHelper.IncreaseWritingLevel(); + try { *************** *** 622,640 **** try { ! if ( _magicAjaxContext.IsAjaxCall ) { ! if ( _processedAjaxCall ) { ! // If the ViewState wasn't excluded from the post data, retrieve ! // it and send it to client. ! if ( _magicAjaxContext.IsPageNoStoreMode && _request.Form["__VIEWSTATE"] != null ) { ! string vsValue = _filter.GetViewStateFieldValue(); ! if (vsValue != null && _request.Form["__VIEWSTATE"] != vsValue) { ! AjaxCallHelper.WriteSetFieldScript("__VIEWSTATE", vsValue); } } #if NET_2_0 Page currentPage = HttpContext.Current.Handler as Page; --- 649,721 ---- try { ! string html = _filter.GetHtmlPage(); ! ! #region Reflect new/updated script elements ! ArrayList previousScriptFPs = new ArrayList(); ! if (_request["__MAGICAJAX_SCRIPT_FINGERPRINTS"] != null) { ! previousScriptFPs.AddRange(_request["__MAGICAJAX_SCRIPT_FINGERPRINTS"].Split(';')); ! } ! ! string scriptfingerprintSearch = "id=\"__MAGICAJAX_SCRIPT_FINGERPRINTS\" value=\""; ! ! // Find all scripts, and send fingerprints to client (in a hidden field) ! StringBuilder sbuilder = new StringBuilder(); ! MatchCollection matches = Util.ScriptTagsRegEx.Matches(html); ! for (int i = 0; i < matches.Count; i++) ! { ! Match match = matches[i]; ! string fullScript = match.Value; ! string scriptFP = Util.GetFingerprint(fullScript); ! ! if (i == 0) ! sbuilder.Append(";"); ! sbuilder.Append(scriptFP); ! ! if (_magicAjaxContext.IsAjaxCall && _processedAjaxCall) { ! // If this is a new script block, create call to create script ! // on client ! if (!previousScriptFPs.Contains(scriptFP)) { ! CaptureCollection attrnamesOption = match.Groups["attrname"].Captures; ! CaptureCollection attrvaluesOption = match.Groups["attrvalue"].Captures; ! ! NameValueCollection scriptAttributes = new NameValueCollection(); ! for (int j = 0; j < attrnamesOption.Count; j++) { ! scriptAttributes.Add(attrnamesOption[j].Value, attrvaluesOption[j].Value); } + + string scriptText = match.Groups["script"].Value; + + AjaxCallHelper.WriteAddScriptElementScript(scriptText, scriptAttributes); } + } + } + string scriptFPs = sbuilder.ToString(); + if (!_magicAjaxContext.IsAjaxCall) + { + // This is a non-ajax request. Add a hidden field to the output html that contains + // the fingerprints of all script elements. + html = html.Replace(scriptfingerprintSearch, scriptfingerprintSearch + scriptFPs); + _response.Write(html); + _response.End(); + } + else if (_processedAjaxCall) + { + AjaxCallHelper.WriteSetFieldScript("__MAGICAJAX_SCRIPT_FINGERPRINTS", scriptFPs); + } + #endregion + + if ( _magicAjaxContext.IsAjaxCall ) + { + // Decrease writing level to write script before all scripts already written. + //HACK: replace this with a more elegant solution + AjaxCallHelper.DecreaseWritingLevel(); + + if ( _processedAjaxCall ) + { #if NET_2_0 Page currentPage = HttpContext.Current.Handler as Page; *************** *** 655,661 **** } #endif ! AjaxCallHelper.End(); } else if ( _threadAbortExceptionThrown && !_magicAjaxContext.CompletedAjaxCall ) --- 736,764 ---- } #endif + #region Reflect hidden fields added on callback + if ( _magicAjaxContext.IsPageNoStoreMode) + { + //reflect hidden fields newly added on callback + MatchCollection hiddenFieldMatches = Util.HiddenInputTagsRegEx.Matches(html); + for (int i = 0; i < hiddenFieldMatches.Count; i++) + { + Match hiddenFieldMatch = hiddenFieldMatches[i]; + string name = hiddenFieldMatch.Groups["name"].Value; + string value = hiddenFieldMatch.Groups["value"].Value; ! // Don't reflect system hidden fields (starting with "__"). ! // However, do send "__VIEWSTATE" if it wasn't excluded from the post data ! if (!name.StartsWith("__") || (name == "__VIEWSTATE" && _request.Form["__VIEWSTATE"] != null)) ! { ! if (_request.Form[name] == null) ! AjaxCallHelper.WriteAddHiddenFieldScript(name, value); ! else ! AjaxCallHelper.WriteSetFieldScript(name, value); ! } ! } ! } ! #endregion + AjaxCallHelper.End(); } else if ( _threadAbortExceptionThrown && !_magicAjaxContext.CompletedAjaxCall ) *************** *** 672,676 **** // Handle Server.Transfer AjaxCallHelper.Init(); - string html = _filter.GetHtmlPage(); if (_request.Browser != null && _request.Browser.Browser == "IE") { --- 775,778 ---- |