Click here to Skip to main content
12,697,801 members (24,960 online)
Click here to Skip to main content
Articles » Web Development » Ajax » General » Downloads

Stats

762.4K views
2.5K downloads
251 bookmarked
Posted

Magic AJAX: Applying AJAX to your existing Web Pages

, 28 May 2007 MIT
How to apply AJAX technologies to your web pages without replacing ASP.NET controls and/or writing JavaScript code.
magicajax
Examples
ExampleSite (.NET 2.0 only)
Web.sitemap
webparts
images
first.GIF
last.GIF
next.gif
pow_by_aspnet2.0.gif
prev.GIF
examples
App_Data
App_Code
Docs
Core
script
bin
MagicAjax.dll
MagicAjax.dll
Web.sitemap
first.GIF
last.GIF
next.gif
pow_by_aspnet2.0.gif
prev.GIF
Web.sitemap
CVS
Root
Repository
Entries.Old
Entries
Entries.Extra.Old
Entries.Extra
first.GIF
last.GIF
next.gif
pow_by_aspnet2.0.gif
prev.GIF
CVS
Root
Repository
Entries.Old
Entries
Entries.Extra.Old
Entries.Extra
CVS
Root
Repository
Entries.Old
Entries
Entries.Extra.Old
Entries.Extra
CVS
Root
Repository
Entries.Old
Entries
Entries.Extra.Old
Entries.Extra
CVS
Root
Repository
Entries.Old
Entries
Entries.Extra.Old
Entries.Extra
CVS
Root
Repository
Entries
Entries.Extra
Entries.Old
Entries.Extra.Old
CVS
Root
Repository
Entries.Old
Entries.Extra.Old
Entries
Entries.Extra
CVS
Root
Repository
Entries
Entries.Extra
Entries.Old
Entries.Extra.Old
MagicAjax.snk
CVS
Root
Repository
Entries.Old
Entries.Extra.Old
Entries
Entries.Extra
UI
Design
CVS
Root
Repository
Entries.Old
Entries.Extra.Old
Entries
Entries.Extra
Controls
ClientEventControls
CVS
Root
Repository
Entries.Old
Entries
Entries.Extra.Old
Entries.Extra
CVS
Root
Repository
Entries.Extra
Entries.Old
Entries
Entries.Extra.Old
CVS
Root
Repository
Entries.Old
Entries.Extra.Old
Entries
Entries.Extra
Interfaces
CVS
Root
Repository
Entries.Old
Entries.Extra.Old
Entries
Entries.Extra
Configuration
CVS
Root
Repository
Entries.Old
Entries.Extra.Old
Entries
Entries.Extra
CVS
Root
Repository
Entries
Entries.Extra
Entries.Old
Entries.Extra.Old
CVS
Root
Repository
Entries.Old
Entries.Extra.Old
Entries
Entries.Extra
AJAXTest
AJAXTest.csproj.webinfo
Global.asax
Ajax
Ajax.csproj.user
Controls
Design
script
#region LGPL License
/*
MagicAjax.NET Framework
Copyright (C) 2005  MagicAjax Project Team

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#endregion

using System;
using System.Collections;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;

namespace MagicAjax
{
	/// <summary>
	/// Helper methods intented to be used internally be the framework.
	/// </summary>
	internal class Util
	{
		public const string ScriptPattern = "<script.[^>]*>";
		public const string FormElementPattern = @"<(?<tag>input|textarea|select)\s+(?<attribute>(?<attrname>[-\w]+)=(""(?<attrvalue>.*?)""\s*|'(?<attrvalue>.*?)'\s*|(?<attrvalue>[-\w]+)\s*))*.*?(/>|>((?<inner>.*?)</\k'tag'>)?)";
		public const string StyleElementPattern = @"<(?<tag>style|link)\s*(?<attribute>(?<attrname>[-\w]+)=((""|')(?<attrvalue>.*?)(""|')\s*|(?<attrvalue>[-\w]+)\s*))*.*?(/>|>(?<inner>.*?)</\k'tag'>)";

		#region Global Regular Expressions
		private static RegexOptions _options = RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.ExplicitCapture;
		public static Regex FormElementRegEx = new Regex(Util.FormElementPattern, _options);
		public static Regex FormElementOptionsRegEx = new Regex("<option\\s((?<attrname>[-\\w]+)=\"(?<attrvalue>.*?)\"\\s?)*\\s*>.*?</option>", _options);
		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 HeaderStyleTagsRegEx = new Regex(StyleElementPattern, _options);
		#endregion

		/// <summary>
		///	Gets the ClientID of the given Page's Form.
		/// </summary>
		/// <param name="page"></param>
		/// <returns></returns>
		public static string GetPageFormID(Page page)
		{
			string id = null;
#if NET_2_0
			if (page.Form != null)
				id = page.Form.ClientID;
#else
			foreach (Control con in page.Controls)
			{
				if (con is HtmlForm)
				{
					id = con.ClientID;
					break;
				}
			}
#endif
			return id;
		}

		/// <summary>
		/// Add 'defer' attribute to script tags excluding external script files.
		/// </summary>
		/// <remarks>
		/// IE has a weird bug and when document.write is called, it
		/// executes the scripts of the html BEFORE the external script files.
		/// So add 'defer' attribute to the scripts so that external script files
		/// are executed first.
		/// </remarks>
		/// <param name="html"></param>
		/// <returns></returns>
		public static string AddDeferToScriptTags (string html)
		{
			StringBuilder sb = new StringBuilder(html);

			Regex regEx = Util.ScriptPatternRegEx;
			MatchCollection scriptMatches = regEx.Matches(html);
			//MatchCollection scriptMatches = Regex.Matches(html, ScriptPattern, RegexOptions.IgnoreCase);

			int diff = 0;
			for (int i=0; i < scriptMatches.Count; i++)
			{
				Match match = scriptMatches[i];
				string tag = match.Value.ToLower(System.Globalization.CultureInfo.InvariantCulture);

				if (tag.IndexOf(" src=") == -1)
				{
					// It's script block, add 'defer' attribute
					tag = tag.Insert(tag.Length - 1, " defer");
				}

				if ( tag.Length != match.Value.Length )
				{
					int sbIndex = match.Index + diff;
					sb.Replace(match.Value, tag, sbIndex, match.Value.Length);
					diff += tag.Length - match.Value.Length;
				}
			}

			return sb.ToString();
		}

		/// <summary>
		/// Create a fingerprint string of an input html
		/// </summary>
		/// <param name="str"></param>
		/// <returns></returns>
		public static string GetFingerprint(string input)
		{
            input = GetHtmlWithClearedFormValues(input);

			MagicAjax.Configuration.OutputCompareMode compareMode = MagicAjaxContext.Current.Configuration.CompareMode;
			switch (compareMode)
			{
				case MagicAjax.Configuration.OutputCompareMode.FullHtml:
					return input;
				case MagicAjax.Configuration.OutputCompareMode.HashCode:
					return input.GetHashCode().ToString("X2");
				case MagicAjax.Configuration.OutputCompareMode.MD5:
					byte[] inputBytes = UnicodeEncoding.Default.GetBytes(input);
					byte[] hashedBytes = new MD5CryptoServiceProvider().ComputeHash(inputBytes);
					return Convert.ToBase64String(hashedBytes);
				default:
					return input;
			}
		}

		/// <summary>
		/// Parses all form input controls from the html, and clears their values.
		/// The return html is used to get a fingerprint that is not dependent on the
		/// actual value of a form input control.
		/// </summary>
		/// <param name="html"></param>
		/// <returns></returns>
		public static string GetHtmlWithClearedFormValues (string html)
		{
			StringBuilder strbuild = new StringBuilder(html);
			Regex regEx = Util.FormElementRegEx;
			MatchCollection matches = regEx.Matches(html);
			int diff = 0;
			for (int i=0; i<matches.Count; i++)
			{
				Match match = matches[i];
				CaptureCollection attributes = match.Groups["attribute"].Captures;
				CaptureCollection attrnames = match.Groups["attrname"].Captures;
				CaptureCollection attrvalues = match.Groups["attrvalue"].Captures;

				Hashtable attrCaptures = new Hashtable(attributes.Count);
				Hashtable attrNameValues = new Hashtable(attributes.Count);

				for (int j=0; j < attributes.Count; j++)
				{
					string attrname = attrnames[j].Value.ToLower(System.Globalization.CultureInfo.InvariantCulture);
					attrNameValues[attrname] = attrvalues[j].Value;
					attrCaptures[attrname] = attributes[j];
				}

				// If the form element has the MagicAjax 'ExcludeFromPost' attribute
				// set to 'true', ignore it. We will need its value for the fingerprint.
				if ( attrNameValues.ContainsKey("excludefrompost")
					&& (attrNameValues["excludefrompost"] as String).ToLower(System.Globalization.CultureInfo.InvariantCulture) == "true")
					continue;

				string tag = match.Groups["tag"].Value.ToLower(System.Globalization.CultureInfo.InvariantCulture);
				string name = (string)attrNameValues["name"];
				string clientID = (string)attrNameValues["id"];

				if (name == null || clientID == null)
					continue;

				switch (tag)
				{
						#region <input> tags

					case "input":
						string type = (string)attrNameValues["type"];
						if (type != null)
						{
							switch (type)
							{
								case "text":
									if (attrNameValues.ContainsKey("value"))
									{
										Capture attr = attrCaptures["value"] as Capture;
										int sbIndex = attr.Index - diff;
										strbuild.Remove (sbIndex, attr.Length);
										diff += attr.Length;
									}
									break;
								case "checkbox":
								case "radio":
									if (attrNameValues.ContainsKey("checked"))
									{
										Capture attr = attrCaptures["checked"] as Capture;
										int sbIndex = attr.Index - diff;
										strbuild.Remove (sbIndex, attr.Length);
										diff += attr.Length;
									}
									break;
							}
						}
						break;

						#endregion

						#region <textarea> tags

					case "textarea":
						Group inner = match.Groups["inner"];
						if (inner.Success)
						{
							int sbIndex = inner.Index - diff;
							strbuild.Remove (sbIndex, inner.Length);
							diff += inner.Length;
						}
						break;

						#endregion

						#region <select> tags

					case "select":
						Group selInner = match.Groups["inner"];
						Regex regExOpt = Util.FormElementOptionSelectedRegEx;

						//now remove the 'selected' attributes within this <select> tag
						MatchCollection matchesSelected = regExOpt.Matches(selInner.Value);
						for (int j = 0; j < matchesSelected.Count; j++)
						{
							Group selected = matchesSelected[j].Groups["selected"];
							int sbIndex = selInner.Index + selected.Index - diff;
							strbuild.Remove (sbIndex, selected.Length);
							diff += selected.Length;
						}
						break;
						#endregion
				}
			}

			return strbuild.ToString();
		}

		/// <summary>
		/// Resolves relative url's (starting with "~"). 
		/// Use this when Control.ResolveUrl() is not available.
		/// </summary>
		/// <param name="url"></param>
		/// <returns></returns>
		public static string ResolveUrl(string url)
		{
			if (url != null && url.StartsWith("~") && HttpContext.Current != null)
			{
				string appPath = HttpContext.Current.Request.ApplicationPath.Length > 1 ? HttpContext.Current.Request.ApplicationPath : string.Empty;
				url = appPath + url.Substring(1);
			}
			return url;
		}

		/// <summary>
		/// Call a private method from the given object.
		/// </summary>
		/// <param name="instance"></param>
		/// <param name="type"></param>
		/// <param name="methodName"></param>
		/// <param name="parameters"></param>
		/// <returns></returns>
		public static object CallPrivateMethod(object instance, Type type, string methodName, params object[] parameters)
		{
			return type.GetMethod(methodName, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic, null, GetTypesOfParameters(parameters), null).Invoke(instance, parameters);
		}

		public static void SetPrivateField (object instance, Type type, string fieldName, object value)
		{
			type.GetField(fieldName, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).SetValue(instance, value);
		}

		public static object GetPrivateField (object instance, Type type, string fieldName)
		{
			return type.GetField(fieldName, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(instance);
		}

		/// <summary>
		/// Copies all fields (private and public) from the source object to
		/// the destination object thereby performing shallow copy
		/// </summary>
		/// <param name="destination">object to copy fields on</param>
		/// <param name="source">object to copy fields from</param>
		public static void ForceShallowCopyOnObject(object destination, object source)
		{
			Type dstType = destination.GetType();
			Type srcType = source.GetType();
			// get all fields of source type
			// to get all private fields loop over all base classes.
			for (Type t = srcType; t != typeof(Object); t = t.BaseType)
			{
				System.Reflection.FieldInfo[] srcFields = t.GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public);
				foreach (System.Reflection.FieldInfo fld in srcFields)
				{
					string fldName = fld.Name;
					object fldValue = fld.GetValue(source);
					System.Reflection.FieldInfo dstFld = t.GetField(fldName, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public);
					dstFld.SetValue(destination, fldValue);
				}
			}
		}

		/// <summary>
		/// Gets all child controls of a specific type.
		/// </summary>
		/// <param name="parentControl">Control to search</param>
		/// <param name="searchType">The type to search for</param>
		/// <param name="notRecursiveType">If not null, the child controls of this type are not searched</param>
		/// <param name="onlyVisible">if true gets only the visible controls</param>
		/// <returns></returns>
		public static ArrayList GetChildControlsOfType (Control parentControl, Type searchType, Type notRecursiveType, bool onlyVisible)
		{
			ArrayList list = new ArrayList();

			for (int i=0; i < parentControl.Controls.Count; i++)
			{
				Control con = parentControl.Controls[i];
				if (onlyVisible && !con.Visible)
					continue;

				if ( searchType.IsInstanceOfType(con) )
					list.Add (con);

				if ( notRecursiveType == null || !notRecursiveType.IsInstanceOfType(con) )
					list.AddRange (GetChildControlsOfType(con, searchType, notRecursiveType, onlyVisible));
			}

			return list;
		}

		/// <summary>
		/// Returns an array of types from the input object array
		/// </summary>
		/// <param name="parameters"></param>
		/// <returns></returns>
		private static Type[] GetTypesOfParameters(object[] parameters)
		{
			if (parameters != null)
			{
				Type[] types = new Type[parameters.Length];
				for (int i = 0; i < parameters.Length; i++)
				{
					types[i] = parameters[i].GetType();
				}
				return types;
			}
			return null;
		}

		private Util()
		{
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The MIT License

Share

About the Author

Argiris Kirtzidis
Web Developer
Greece Greece
No Biography provided

You may also be interested in...

Pro
Pro
| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170118.1 | Last Updated 28 May 2007
Article Copyright 2005 by Argiris Kirtzidis
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid