From: Argiris K. <be...@us...> - 2005-12-09 01:25:21
|
Update of /cvsroot/magicajax/magicajax/Core/UI/Controls In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv28740/Core/UI/Controls Modified Files: Tag: STABLE AjaxPanel.cs Log Message: Copied changes from HEAD. Index: AjaxPanel.cs =================================================================== RCS file: /cvsroot/magicajax/magicajax/Core/UI/Controls/AjaxPanel.cs,v retrieving revision 1.28 retrieving revision 1.28.2.1 diff -C2 -d -r1.28 -r1.28.2.1 *** AjaxPanel.cs 4 Dec 2005 03:25:15 -0000 1.28 --- AjaxPanel.cs 9 Dec 2005 01:25:06 -0000 1.28.2.1 *************** *** 23,26 **** --- 23,27 ---- using System.ComponentModel; using System.Collections; + using System.Collections.Specialized; using System.Web; using System.Web.UI; *************** *** 29,32 **** --- 30,34 ---- using System.Globalization; using System.Text; + using System.Text.RegularExpressions; namespace MagicAjax.UI.Controls *************** *** 243,251 **** } ! if (IsPageNoStoreMode) ! { ! //disabling clientside validation inside AjaxPanels (not yet handled correctly) ! DisableClientValidators(); ! } } #endregion --- 245,255 ---- } ! //disabling clientside validation inside AjaxPanels (not yet handled correctly) ! // Clientside validation throws errors when a validator becomes invisible ! // during an AjaxCall (the validator is gone while the script checking for ! // it remains). ! // TODO: Find a way to avoid problems of scripts that invisible controls ! // leave behind. ! DisableClientValidators(); } #endregion *************** *** 274,278 **** protected override void AddedControl(Control control, int index) { ! if ( control is WebControl ) { if ( IsPageNoStoreMode ) --- 278,282 ---- protected override void AddedControl(Control control, int index) { ! if ( IsHtmlHolder(control) ) { if ( IsPageNoStoreMode ) *************** *** 299,303 **** protected override void RemovedControl(Control control) { ! if ( control is WebControl ) { if (_addedControls.Contains(control)) --- 303,307 ---- protected override void RemovedControl(Control control) { ! if ( IsHtmlHolder(control) ) { if (_addedControls.Contains(control)) *************** *** 334,341 **** Control con = Controls[i]; ! // Put inside span tag only WebControls ! bool isWebControl = ( con is WebControl ); ! if ( isWebControl ) { writer.WriteBeginTag ("span"); --- 338,345 ---- Control con = Controls[i]; ! // Put inside span tag only html holder controls ! bool isHtmlHolder = IsHtmlHolder(con); ! if ( isHtmlHolder ) { writer.WriteBeginTag ("span"); *************** *** 354,358 **** string html = sb.ToString(); ! if ( isWebControl ) { _controlHtmlFingerprints[con] = Util.GetFingerprint(html); --- 358,362 ---- string html = sb.ToString(); ! if ( isHtmlHolder ) { _controlHtmlFingerprints[con] = Util.GetFingerprint(html); *************** *** 401,405 **** foreach (Control con in this.Controls) { ! if ( con is WebControl ) { if (_controlState.ControlHtmlFingerprints.ContainsKey(con.ClientID)) --- 405,409 ---- foreach (Control con in this.Controls) { ! if ( IsHtmlHolder(con) ) { if (_controlState.ControlHtmlFingerprints.ContainsKey(con.ClientID)) *************** *** 420,423 **** --- 424,870 ---- } + /// <summary> + /// Parses all form input controls from the html, and checks if + /// their values were updated (i.e. different from the current Request.Form values) + /// and sends javascript commands to update the client's form values if necessary. + /// </summary> + /// <param name="html"></param> + protected void ReflectUpdatedFormValues(string html) + { + NameValueCollection form = Context.Request.Form; + RegexOptions options = RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Compiled; + + Regex regEx = new System.Text.RegularExpressions.Regex(@"<(?<tag>input|textarea|select)\s((?<attrname>[-\w]+)=""(?<attrvalue>.*?)""\s?)*.*?(?:/>|>(?<inner>.*?)</(?:textarea|select)>)", options); + MatchCollection matches = regEx.Matches(html); + for (int i=0; i<matches.Count; i++) + { + Match match = matches[i]; + CaptureCollection attrnames = match.Groups["attrname"].Captures; + CaptureCollection attrvalues = match.Groups["attrvalue"].Captures; + + Hashtable attrNameValues = new Hashtable(); + for (int j=0; j< attrnames.Count; j++) + { + attrNameValues.Add(attrnames[j].Value.ToLower(), attrvalues[j].Value); + } + + // If the form element has the MagicAjax 'ExcludeFromPost' attribute + // set to 'true', ignore it. + if ( attrNameValues.ContainsKey("excludefrompost") + && (attrNameValues["excludefrompost"] as String).ToLower() == "true") + continue; + + string tag = match.Groups["tag"].Value.ToLower(); + string name = (string)attrNameValues["name"]; + string clientID = (string)attrNameValues["id"]; + + if ( name == null ) + continue; + + switch (tag) + { + #region <input> tags + + case "input": + string type = (string)attrNameValues["type"]; + if (type != null) + { + string value = attrNameValues.ContainsKey("value") ? (string)attrNameValues["value"] : String.Empty; + bool isChecked = attrNameValues.ContainsKey("checked"); + + switch (type) + { + case "text": + case "password": + if (value != form[name]) + AjaxCallHelper.WriteSetFieldScript (name, value); + break; + case "checkbox": + if (isChecked != (form[name] != null)) + AjaxCallHelper.WriteFormat ("document.forms[0][\"{0}\"].checked={1};\r\n", name, (isChecked) ? "true" : "false"); + break; + case "radio": + if ( isChecked && form[name] != value ) + { + AjaxCallHelper.WriteFormat ("document.forms[0][\"{0}\"].checked=true;\r\n", clientID); + } + else if ( !isChecked && form[name] == value ) + { + AjaxCallHelper.WriteFormat ("document.forms[0][\"{0}\"].checked=false;\r\n", clientID); + } + break; + } + } + break; + + #endregion + + #region <textarea> tags + + case "textarea": + string text = match.Groups["inner"].Value; + if (text != form[name]) + AjaxCallHelper.WriteSetFieldScript (name, text); + break; + + #endregion + + #region <select> tags + + case "select": + Regex regExOpt = new System.Text.RegularExpressions.Regex("<option\\s((?<attrname>[-\\w]+)=\"(?<attrvalue>.*?)\"\\s?)*\\s*>.*?</option>", options); + bool multiple = attrNameValues.ContainsKey("multiple"); + + ArrayList serverOptions = new ArrayList(); + ArrayList serverSelected = new ArrayList(); + string oneSelection = null; + + //now match the options within this <select> tag + MatchCollection matchesOptions = regExOpt.Matches(match.Groups["inner"].Value); + for (int j = 0; j < matchesOptions.Count; j++) + { + Match matchOption = matchesOptions[j]; + + CaptureCollection attrnamesOption = matchOption.Groups["attrname"].Captures; + CaptureCollection attrvaluesOption = matchOption.Groups["attrvalue"].Captures; + + Hashtable attrNameValuesOption = new Hashtable(); + for (int k = 0; k < attrnamesOption.Count; k++) + { + attrNameValuesOption.Add(attrnamesOption[k].Value.ToLower(), attrvaluesOption[k].Value); + } + + string optValue = (string)attrNameValuesOption["value"]; //TODO: check value encodings etc. + bool optSelected = attrNameValuesOption.ContainsKey("selected"); + + if (optSelected && optValue != null) + { + if ( multiple ) + { + serverSelected.Add (optValue); + } + else + { + oneSelection = optValue; + break; + } + } + + serverOptions.Add (optValue); + } + + if ( ! multiple ) + { + if ( oneSelection != form[name] ) + AjaxCallHelper.WriteSetFieldScript (name, oneSelection); + } + else + { + string[] selections = form.GetValues(name); + if ( selections == null ) + selections = new string[0]; + bool elemWritten = false; + + // Make selections + for (int j=0; j < serverSelected.Count; j++) + { + if (Array.IndexOf(selections, serverSelected[j]) == -1) + { + if ( ! elemWritten ) + { + AjaxCallHelper.WriteFormat ("o=document.forms[0][\"{0}\"].options;\r\n", name); + elemWritten = true; + } + AjaxCallHelper.WriteFormat ("o[{0}].selected=true;\r\n", serverOptions.IndexOf(serverSelected[j])); + } + } + + // Make unselections + for (int j=0; j < selections.Length; j++) + { + if ( ! serverSelected.Contains(selections[j])) + { + if ( ! elemWritten ) + { + AjaxCallHelper.WriteFormat ("o=document.forms[0][\"{0}\"];\r\n", name); + elemWritten = true; + } + AjaxCallHelper.WriteFormat ("o[{0}].selected=false;\r\n", serverOptions.IndexOf(selections[j])); + } + } + } + break; + #endregion + } + + } + } + + /// <summary> + /// Determines whether the AjaxPanel should treat the given control as a separate + /// 'html holder' to compare and 'reflect' its html rendering. + /// </summary> + /// <remarks> + /// Only WebControls, excluding RenderedByScriptControls, are considered html holders. + /// </remarks> + /// <param name="control"></param> + /// <returns></returns> + protected virtual bool IsHtmlHolder (Control control) + { + return ( control is WebControl && !(control is RenderedByScriptControl) ); + } + + protected void ReflectContainedFormControls (Control container) + { + ArrayList elems = new ArrayList(); + if ( container is IPostBackDataHandler ) + elems.Add (container); + elems.AddRange (Util.GetChildControlsOfType(container, typeof(IPostBackDataHandler), typeof(RenderedByScriptControl), true)); + + for (int i=0; i < elems.Count; i++) + ReflectFormControl (elems[i] as Control); + } + + protected void ReflectLiteralFormControls() + { + for (int i=0; i < this.Controls.Count; i++) + { + if ( ! IsHtmlHolder(this.Controls[i]) ) + ReflectContainedFormControls (this.Controls[i]); + } + } + + #region ReflectFormControl + /// <summary> + /// Compares the value of the form control with the value of the client's + /// form element and sends javascript command to corrent the client's element + /// if necessary. + /// </summary> + /// <param name="control"></param> + protected virtual void ReflectFormControl (Control control) + { + NameValueCollection form = Context.Request.Form; + + if ( control is WebControl ) + { + #region Reflecting for WebControls + + string id = control.UniqueID; + + if ( control is RadioButton ) + { + RadioButton radio = control as RadioButton; + int index = radio.UniqueID.LastIndexOf(':'); + string uniqueGroupName = radio.UniqueID.Substring(0, index + 1) + radio.GroupName; + if ( radio.Checked && form[uniqueGroupName] != radio.ID ) + { + AjaxCallHelper.WriteFormat ("document.forms[0][\"{0}\"].checked=true;\r\n", control.ClientID); + } + else if ( !radio.Checked && form[uniqueGroupName] == radio.ID ) + { + AjaxCallHelper.WriteFormat ("document.forms[0][\"{0}\"].checked=false;\r\n", control.ClientID); + } + } + else if ( control is CheckBox ) + { + if ( !(control.Parent is CheckBoxList) ) + { + CheckBox chkbox = control as CheckBox; + if ( chkbox.Checked != (form[id] != null) ) + AjaxCallHelper.WriteFormat ("document.forms[0][\"{0}\"].checked={1};\r\n", id, (chkbox.Checked) ? "true" : "false"); + } + } + else if ( control is CheckBoxList ) + { + CheckBoxList chklist = control as CheckBoxList; + for (int i=0; i < chklist.Items.Count; i++) + { + string itemid = String.Format("{0}:{1}", id, i); + if ( chklist.Items[i].Selected != (form[itemid] != null) ) + AjaxCallHelper.WriteFormat ("document.forms[0][\"{0}\"].checked={1};\r\n", itemid, (chklist.Items[i].Selected) ? "true" : "false"); + } + } + else if ( control is DropDownList ) + { + DropDownList ddlist = control as DropDownList; + if ( (ddlist.SelectedIndex == -1 && form[id] != null) + || ddlist.SelectedValue != form[id] ) + AjaxCallHelper.WriteSetFieldScript (id, ddlist.SelectedValue); + } + else if ( control is ListBox ) + { + ListBox lstbox = control as ListBox; + if ( ListSelectionMode.Single == lstbox.SelectionMode ) + { + if ( (lstbox.SelectedIndex == -1 && form[id] != null) + || lstbox.SelectedValue != form[id] ) + AjaxCallHelper.WriteSetFieldScript (id, lstbox.SelectedValue); + } + else + { + string[] selections = form.GetValues(id); + bool elemWritten = false; + + // Make selections + for (int i=0; i < lstbox.Items.Count; i++) + { + if (lstbox.Items[i].Selected && Array.IndexOf(selections, lstbox.Items[i].Value) == -1) + { + if ( ! elemWritten ) + { + AjaxCallHelper.WriteFormat ("elem=document.forms[0][\"{0}\"];\r\n", id); + elemWritten = true; + } + AjaxCallHelper.WriteFormat ("elem.options[{0}].selected=true;\r\n", i); + } + } + + // Make unselections + for (int i=0; i < selections.Length; i++) + { + for (int itemi=0; itemi < lstbox.Items.Count; itemi++) + { + if ( lstbox.Items[itemi].Value == selections[i] ) + { + if ( ! lstbox.Items[itemi].Selected ) + { + if ( ! elemWritten ) + { + AjaxCallHelper.WriteFormat ("elem=document.forms[0][\"{0}\"];\r\n", id); + elemWritten = true; + } + AjaxCallHelper.WriteFormat ("elem.options[{0}].selected=false;\r\n", itemi); + } + break; + } + } + } + } + } + else if ( control is RadioButtonList ) + { + RadioButtonList rblist = control as RadioButtonList; + if ( rblist.SelectedIndex == -1 && form[id] != null ) + { + // Clear selection + for (int i=0; i < rblist.Items.Count; i++) + { + if (rblist.Items[i].Value == form[id]) + { + AjaxCallHelper.WriteFormat ("document.forms[0][\"{0}\"].checked=false;\r\n", String.Format("{0}_{1}", control.ClientID, i)); + break; + } + } + } + else if ( rblist.SelectedIndex != -1 && rblist.SelectedValue != form[id] ) + { + // Make selection + AjaxCallHelper.WriteFormat ("document.forms[0][\"{0}\"].checked=true;\r\n", String.Format("{0}_{1}", control.ClientID, rblist.SelectedIndex)); + } + } + else if ( control is TextBox ) + { + TextBox txtbox = control as TextBox; + if ( txtbox.Text != form[id] ) + AjaxCallHelper.WriteSetFieldScript (id, txtbox.Text); + } + + #endregion + } + else if ( control is HtmlControl ) + { + #region Reflecting for HtmlControls + + if ( control is HtmlInputCheckBox ) + { + HtmlInputCheckBox chkbox = control as HtmlInputCheckBox; + if ( chkbox.Checked != (form[chkbox.Name] != null) ) + AjaxCallHelper.WriteFormat ("document.forms[0][\"{0}\"].checked={1};\r\n", chkbox.Name, (chkbox.Checked) ? "true" : "false"); + } + else if ( control is HtmlInputRadioButton ) + { + HtmlInputRadioButton radio = control as HtmlInputRadioButton; + if ( radio.Name != String.Empty ) + { + int index = radio.UniqueID.LastIndexOf(':'); + string uniqueName = radio.UniqueID.Substring(0, index + 1) + radio.Name; + if ( radio.Checked && form[uniqueName] != radio.ID ) + { + AjaxCallHelper.WriteFormat ("document.forms[0][\"{0}\"].checked=true;\r\n", control.ClientID); + } + else if ( !radio.Checked && form[uniqueName] == radio.ID ) + { + AjaxCallHelper.WriteFormat ("document.forms[0][\"{0}\"].checked=false;\r\n", control.ClientID); + } + } + } + else if ( control is HtmlInputText ) + { + HtmlInputText txtbox = control as HtmlInputText; + if ( txtbox.Value != form[txtbox.Name] ) + AjaxCallHelper.WriteSetFieldScript (txtbox.Name, txtbox.Value); + } + else if ( control is HtmlSelect ) + { + HtmlSelect sel = control as HtmlSelect; + if ( ! sel.Multiple ) + { + if ( (sel.SelectedIndex == -1 && form[sel.Name] != null) + || sel.Value != form[sel.Name] ) + AjaxCallHelper.WriteSetFieldScript (sel.Name, sel.Value); + } + else + { + string[] selections = form.GetValues(sel.Name); + bool elemWritten = false; + + // Make selections + for (int i=0; i < sel.Items.Count; i++) + { + if (sel.Items[i].Selected && Array.IndexOf(selections, sel.Items[i].Value) == -1) + { + if ( ! elemWritten ) + { + AjaxCallHelper.WriteFormat ("elem=document.forms[0][\"{0}\"];\r\n", sel.Name); + elemWritten = true; + } + AjaxCallHelper.WriteFormat ("elem.options[{0}].selected=true;\r\n", i); + } + } + + // Make unselections + for (int i=0; i < selections.Length; i++) + { + for (int itemi=0; itemi < sel.Items.Count; itemi++) + { + if ( sel.Items[itemi].Value == selections[i] ) + { + if ( ! sel.Items[itemi].Selected ) + { + if ( ! elemWritten ) + { + AjaxCallHelper.WriteFormat ("elem=document.forms[0][\"{0}\"];\r\n", sel.Name); + elemWritten = true; + } + AjaxCallHelper.WriteFormat ("elem.options[{0}].selected=false;\r\n", itemi); + } + break; + } + } + } + } + } + else if ( control is HtmlTextArea ) + { + HtmlTextArea txtbox = control as HtmlTextArea; + if ( txtbox.Value != form[txtbox.Name] ) + AjaxCallHelper.WriteSetFieldScript (txtbox.Name, txtbox.Value); + } + + #endregion + } + } + #endregion + #region override PutTagOnPageForAjaxCall /// <summary> *************** *** 479,486 **** Control con = Controls[i]; ! // Put inside span tag only WebControls ! bool isWebControl = ( con is WebControl ); ! if ( isWebControl ) { fullwriter.WriteBeginTag ("span"); --- 926,933 ---- Control con = Controls[i]; ! // Put inside span tag only html holder controls ! bool isHtmlHolder = IsHtmlHolder(con); ! if ( isHtmlHolder ) { fullwriter.WriteBeginTag ("span"); *************** *** 498,502 **** string html = sb.ToString(); ! if ( isWebControl ) { fullwriter.WriteEndTag ("span"); --- 945,949 ---- string html = sb.ToString(); ! if ( isHtmlHolder ) { fullwriter.WriteEndTag ("span"); *************** *** 524,528 **** // Increase script writing level because we want literal content to // be rendered before the child controls renderings ! AjaxCallHelper.IncreaseWritingLevel(); foreach (Control con in _removedControls) --- 971,975 ---- // Increase script writing level because we want literal content to // be rendered before the child controls renderings ! AjaxCallHelper.IncreaseWritingLevel(); foreach (Control con in _removedControls) *************** *** 535,542 **** Control con = Controls[i]; ! // Only WebControls are inside a span tag ! bool isWebControl = ( con is WebControl ); ! if ( isWebControl ) { literalwriter.WriteBeginTag ("span"); --- 982,989 ---- Control con = Controls[i]; ! // Only html holder controls are inside a span tag ! bool isHtmlHolder = IsHtmlHolder(con); ! if ( isHtmlHolder ) { literalwriter.WriteBeginTag ("span"); *************** *** 550,554 **** sbFull.Length = sb.Length = 0; ! if ( isWebControl && _addedControls.Contains(con) ) { // It's a new control, create it on the client at the appropriate place. --- 997,1001 ---- sbFull.Length = sb.Length = 0; ! if ( isHtmlHolder && _addedControls.Contains(con) ) { // It's a new control, create it on the client at the appropriate place. *************** *** 575,585 **** html = sb.ToString(); ! if ( isWebControl ) { string htmlFingerprint = Util.GetFingerprint(html); ! ! // If it's html rendering fingerprint is the same, ignore it. ! if (htmlFingerprint != (string)_controlHtmlFingerprints[con]) { ExtendedWriteSetHtmlOfElementScript(html, GetAjaxElemID(con)); _controlHtmlFingerprints[con] = htmlFingerprint; --- 1022,1039 ---- html = sb.ToString(); ! if ( isHtmlHolder ) { string htmlFingerprint = Util.GetFingerprint(html); ! if (htmlFingerprint == (string)_controlHtmlFingerprints[con]) ! { ! // Its html rendering fingerprint is the same, ignore the ! // html and "reflect" the form elements that it contains ! // on client's page if they're different. ! ReflectUpdatedFormValues (html); ! } ! else { + // Its html rendering fingerprint has changed, + // "reflect" its html on client. ExtendedWriteSetHtmlOfElementScript(html, GetAjaxElemID(con)); _controlHtmlFingerprints[con] = htmlFingerprint; *************** *** 602,606 **** string literalhtml = sbLiteral.ToString(); string literalFingerprint = Util.GetFingerprint(literalhtml); ! if ( _controlState.LiteralFingerprint != literalFingerprint ) { ExtendedWriteSetHtmlOfElementScript (literalhtml, this.ClientID); --- 1056,1067 ---- string literalhtml = sbLiteral.ToString(); string literalFingerprint = Util.GetFingerprint(literalhtml); ! if ( literalFingerprint == _controlState.LiteralFingerprint ) ! { ! // Its html rendering fingerprint is the same, ignore the ! // html and "reflect" the form elements that it contains ! // on client's page if they're different. ! ReflectUpdatedFormValues (literalhtml); ! } ! else { ExtendedWriteSetHtmlOfElementScript (literalhtml, this.ClientID); *************** *** 765,769 **** private void InitValidators() { ! ArrayList validators = Util.GetChildControlsOfType(this, typeof(BaseValidator), true); foreach (BaseValidator validator in validators) { --- 1226,1230 ---- private void InitValidators() { ! ArrayList validators = Util.GetChildControlsOfType(this, typeof(BaseValidator), typeof(RenderedByScriptControl), true); foreach (BaseValidator validator in validators) { *************** *** 776,780 **** private void DisableClientValidators() { ! ArrayList validators = Util.GetChildControlsOfType(this, typeof(BaseValidator), true); foreach (BaseValidator validator in validators) { --- 1237,1241 ---- private void DisableClientValidators() { ! ArrayList validators = Util.GetChildControlsOfType(this, typeof(BaseValidator), typeof(RenderedByScriptControl), true); foreach (BaseValidator validator in validators) { |