Create project on Google API Console here

  • Create new project
  • Activate the calendar API under “All services”
  • Agree to Google Api “terms of service”
  • Click the “Overview” link at right top
    • Click “Register” link in front of “Project ID”
    • Write “googlecalendarapidemo” or any text as the project ID and register
    • Click “API Access”  and click “Create an oAuth 2.0 clientID”
    • Choose a product name, logo and Home page url
    • Choose web application as Application type
    • Click ‘more options’ and type the address of the page where you will receive the result of google calendar registration
    • For testing purpose, type the address of your visual studio assigned port i.e http://localhost:58392/GoogleCalandarDemo/Default.aspx
      • To restrict Visual studio to assign a specific port
        • Click on project name in solution explorer
        • Click f4 to show its properties
        • Select false for “Use dynamic ports”
      • For deployment use the appropriate registered address (Google does not allow IP address based address e.g http://192.168.0.1:58392/GoogleCalandarDemo/Default.aspx
    • Click create client ID
    • Save the ClientID and ClientSecret values in web.config to be used later
    • You can change the Redirect URL by clicking the edit settings link at left side

Add the following files in your new website project

——————————-Default.aspx————————————

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <asp:HiddenField runat="server" ID="HdnEventID" Value="" />
    <div style="margin-bottom: 20px">
        <asp:Label runat="server" ID="LblMessage"></asp:Label>
    </div>
    <div>
        <asp:Panel runat="server" ID="PnlLogin">
            UserName:<asp:TextBox ID="TxtBoxUserName" runat="server"></asp:TextBox>
            <br />
            Pwd:<asp:TextBox ID="TxtBoxPwd" runat="server"></asp:TextBox>
            <br />
            <asp:Button runat="server" ID="BtnLogin" Text="Login" OnClick="BtnLogin_Click" />
        </asp:Panel>
        <asp:Panel runat="server" ID="PnlRegister">
            <asp:Button runat="server" ID="BtnRegisterWithGoogleCalendar" Text="Register With Google Calendar"
                OnClick="BtnRegisterWithGoogleCalendar_Click" />
        </asp:Panel>
        <asp:Panel runat="server" ID="PnlEvents">
            <%--<asp:DropDownList runat="server" ID="DDLEvent" AutoPostBack="true" 
                onselectedindexchanged="DDLEvent_SelectedIndexChanged">
                <asp:ListItem Enabled="true" Text="-Select-"></asp:ListItem>
            </asp:DropDownList>--%>
            <div id="DivEventDescription">
                Title:
                <asp:TextBox runat="server" ID="TxtTitle"></asp:TextBox>
                <asp:RequiredFieldValidator ID="RequiredFieldValidator0" ControlToValidate="TxtTitle"
                    ErrorMessage="*" ToolTip="Required" runat="server"></asp:RequiredFieldValidator>
                <br />
                Start Time:
                <asp:TextBox runat="server" ID="TxtStartTime" Enabled="false"></asp:TextBox>
                <asp:RequiredFieldValidator ID="RequiredFieldValidator1" ControlToValidate="TxtStartTime"
                    ErrorMessage="*" ToolTip="Required" runat="server"></asp:RequiredFieldValidator>
                <br />
                End Time:
                <asp:TextBox runat="server" ID="TxtEndTime" Enabled="false"></asp:TextBox>
                <asp:RequiredFieldValidator ID="RequiredFieldValidator2" ControlToValidate="TxtEndTime"
                    ErrorMessage="*" ToolTip="Required" runat="server"></asp:RequiredFieldValidator>
                <br />
                Details:
                <br />
                <asp:TextBox runat="server" ID="TxtEventDetails" TextMode="MultiLine"></asp:TextBox>
                <asp:RequiredFieldValidator ID="RequiredFieldValidator3" ControlToValidate="TxtEventDetails"
                    ErrorMessage="*" ToolTip="Required" runat="server"></asp:RequiredFieldValidator>
                <br />
                <asp:Button ID="BtnCreateEvent" Text="Create / Update Event" runat="server" OnClick="BtnCreateUpdateEvent_Click" />
            </div>
            <br />
            <br />
            <asp:Button ID="BtnRevoke" Text="Revoke google calendar rights" runat="server" OnClick="BtnRevoke_Click" />
        </asp:Panel>
    </div>
    </form>
</body>
</html>

——————————-Default.aspx.cs————————————

using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml;
using Google.AccessControl;
using Google.GData;
using Google.GData.Calendar;
using Google.GData.AccessControl;
using Google.GData.Client;
public partial class _Default : System.Web.UI.Page
{
    XmlDocument XmlDoc = new XmlDocument();

    static string UserID = "UserID";
    static string UserName = "UserName";
    static string Password = "Password";
    static string AccessToken = "AccessToken";
    static string RefreshToken = "RefreshToken";

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            try
            {
                if (XmlDoc.HasChildNodes == false)
                {
                    XmlDoc.Load(AppDomain.CurrentDomain.BaseDirectory + "App_Data\\XMLfile.xml");
                }
                //check if the user has logged in
                if (Session[UserID] != null && string.IsNullOrEmpty(Session[UserID].ToString()) == false)
                {
                    //if the user is registered
                    if (string.IsNullOrEmpty(XmlDoc.DocumentElement.ChildNodes[0].Attributes[AccessToken].Value.ToString()) == false)
                    {
                        PnlLogin.Visible = false;
                        PnlRegister.Visible = false;
                        PnlEvents.Visible = true;

                        TxtStartTime.Text = DateTime.Now.ToString();
                        TxtEndTime.Text = DateTime.Now.AddHours(2).ToString();
                    }
                    else
                    {
                        PnlLogin.Visible = false;
                        PnlRegister.Visible = true;
                        PnlEvents.Visible = false;
                    }
                }

                else
                {
                    PnlLogin.Visible = true;
                    PnlRegister.Visible = false;
                    PnlEvents.Visible = false;

                    LblMessage.Text = "Please login";
                }
            }
            catch { }
        }
    }
    protected void BtnLogin_Click(object sender, EventArgs e)
    {
        if (XmlDoc.HasChildNodes == false)
        {
            XmlDoc.Load(AppDomain.CurrentDomain.BaseDirectory + "App_Data\\XMLfile.xml");
        }

        //check the user credentials
        if (string.IsNullOrEmpty(XmlDoc.DocumentElement.ChildNodes[0].Attributes[UserName].Value.ToString()) == false
         && XmlDoc.DocumentElement.ChildNodes[0].Attributes[UserName].Value.ToLower() == TxtBoxUserName.Text.ToLower()
         && string.IsNullOrEmpty(XmlDoc.DocumentElement.ChildNodes[0].Attributes[Password].Value.ToString()) == false
         && XmlDoc.DocumentElement.ChildNodes[0].Attributes[Password].Value.ToLower() == TxtBoxPwd.Text.ToLower())
        {
            Session[UserID] = XmlDoc.DocumentElement.ChildNodes[0].Attributes[UserID].Value.ToLower();

            //check if the user is registered or not
            //if not then ask the user to register
            if (string.IsNullOrEmpty(XmlDoc.DocumentElement.ChildNodes[0].Attributes[AccessToken].Value.ToString()) == true ||
            string.IsNullOrEmpty(XmlDoc.DocumentElement.ChildNodes[0].Attributes[RefreshToken].Value.ToString()) == true)
            {
                PnlLogin.Visible = false;
                PnlRegister.Visible = true;
                PnlEvents.Visible = false;

                LblMessage.Text = "Login Successful. Please click the register button to register with google calendar ";
            }

            else
            {
                PnlLogin.Visible = false;
                PnlRegister.Visible = false;
                PnlEvents.Visible = true;

                //PopulateDDLEvent();
            }
        }
        else
        {
            LblMessage.Text = "Login UnSuccessful. Please provide the correct credentials";
        }
    }
    protected void BtnRegisterWithGoogleCalendar_Click(object sender, EventArgs e)
    {
        string GoogleReturnPageAddress = System.Configuration.ConfigurationManager.AppSettings["GoogleReturnPageAddress"];

        Response.Redirect(GoogleCalendarManager.GenerateGoogleOAuthURL());
    }
    protected void BtnRevoke_Click(object sender, EventArgs e)
    {
        if (XmlDoc.HasChildNodes == false)
        {
            XmlDoc.Load(AppDomain.CurrentDomain.BaseDirectory + "App_Data\\XMLfile.xml");
        }

        string Access_Token = XmlDoc.DocumentElement.SelectSingleNode("//User[@UserID='1']").Attributes[AccessToken].Value;
        string Refresh_Token = XmlDoc.DocumentElement.SelectSingleNode("//User[@UserID='1']").Attributes[RefreshToken].Value;

        //Attempt the revoke from google
        //if successful then do a db / xml delete as well
        if (GoogleCalendarManager.RevokeAccessToken(Access_Token, Refresh_Token) == true)
        {
            XmlDoc.DocumentElement.SelectSingleNode("//User[@UserID='1']").Attributes[AccessToken].Value = "";
            XmlDoc.DocumentElement.SelectSingleNode("//User[@UserID='1']").Attributes[RefreshToken].Value = "";

            XmlDoc.Save(AppDomain.CurrentDomain.BaseDirectory + "App_Data\\XMLfile.xml");
        }
    }
    protected void BtnCreateUpdateEvent_Click(object sender, EventArgs e)
    {
        List<GoogleCalendarAppointmentModel> GoogleCalendarAppointmentModelList = new List<GoogleCalendarAppointmentModel>();
        List<GoogleTokenModel> GoogleTokenModelList = new List<GoogleTokenModel>();

        GoogleCalendarAppointmentModel GoogleCalendarAppointmentModelObj = new GoogleCalendarAppointmentModel();
        GoogleTokenModel GoogleTokenModelObj = new GoogleTokenModel();

        #region populate GoogleAppointment values

        GoogleCalendarAppointmentModelObj.EventID = "1";
        GoogleCalendarAppointmentModelObj.EventTitle = "New Event from google api";
        GoogleCalendarAppointmentModelObj.EventStartTime = DateTime.Now;
        GoogleCalendarAppointmentModelObj.EventEndTime.AddHours(2);
        GoogleCalendarAppointmentModelObj.EventLocation = "New Location";
        GoogleCalendarAppointmentModelObj.EventDetails = "New Details";
        #endregion

        #region populate GoogleToken values

        GoogleTokenModelObj.Access_Token = XmlDoc.DocumentElement.SelectSingleNode("//User[@UserID='1']").Attributes[AccessToken].Value;
        GoogleTokenModelObj.Refresh_Token = XmlDoc.DocumentElement.SelectSingleNode("//User[@UserID='1']").Attributes[RefreshToken].Value;
        GoogleTokenModelList.Add(GoogleTokenModelObj);

        #endregion
        #region Add event to google calendar

        if (GoogleCalendarManager.AddUpdateDeleteEvent(GoogleTokenModelList, GoogleCalendarAppointmentModelList, 0) == true)
        {
            if (XmlDoc.HasChildNodes == false)
            {
                XmlDoc.Load(AppDomain.CurrentDomain.BaseDirectory + "App_Data\\XMLfile.xml");
            }

            //save data in DB / xml
            XmlDoc.DocumentElement.SelectSingleNode("//Event").Attributes["EventTitle"].Value = GoogleCalendarAppointmentModelObj.EventTitle;
            XmlDoc.DocumentElement.SelectSingleNode("//Event").Attributes["StartTime"].Value = GoogleCalendarAppointmentModelObj.EventStartTime.ToString();
            XmlDoc.DocumentElement.SelectSingleNode("//Event").Attributes["EndTime"].Value = GoogleCalendarAppointmentModelObj.EventEndTime.ToString();
            XmlDoc.DocumentElement.SelectSingleNode("//Event").Attributes["EventLocation"].Value = GoogleCalendarAppointmentModelObj.EventLocation;

            XmlDoc.Save(AppDomain.CurrentDomain.BaseDirectory + "App_Data\\XMLfile.xml");
        }
        #endregion

    }
    //private void PopulateDDLEvent()
    //{
    //    if (XmlDoc.HasChildNodes == false)
    //    {
    //        XmlDoc.Load(AppDomain.CurrentDomain.BaseDirectory + "App_Data\\XMLfile.xml");
    //    }
    //    XmlNodeList AllEventNodes = XmlDoc.DocumentElement.SelectNodes("//Events/Event");
    //    if (AllEventNodes != null && AllEventNodes.Count > 0)
    //    {
    //        foreach (XmlNode XmlNodeObj in AllEventNodes)
    //        {
    //            DDLEvent.Items.Add(new ListItem(XmlNodeObj.Attributes["EventTitle"].Value, XmlNodeObj.Attributes["EventID"].Value));
    //        }
    //    }
    //}
    //protected void DDLEvent_SelectedIndexChanged(object sender, EventArgs e)
    //{
    //    if (DDLEvent.SelectedIndex != 0)
    //    {
    //        HdnEventID.Value = DDLEvent.SelectedValue;
    //    }
    //}
}

——————————-GoogleCalendarRegistration.aspx———————

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <asp:Label runat="server" ID="LblMessage"></asp:Label>
    <br /><br />
    <asp:HyperLink NavigateUrl="~/Default.aspx" Text="Go to main page" runat="server"></asp:HyperLink>
    </div>
    </form>
</body>
</html>

——————————-GoogleCalendarRegistration.aspx.cs——————

'
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

using System.Web.Script.Serialization;
using Google.GData.Client;
using Google.GData.Calendar;
using Google.GData.Extensions;
using System.Net;
using System.Text;
using System.IO;
using System.Xml;

public partial class GoogleCalendarRegistration : System.Web.UI.Page
{
    private static string ReturnUrl = @System.Configuration.ConfigurationManager.AppSettings["GoogleReturnPageAddress"].ToString();

    private static string OwnCalendarFeed = @"http://www.google.com/calendar/feeds/default/owncalendars/full";
    private static string AllCalendarFeed = @"http://www.google.com/calendar/feeds/default/allcalendars/full";
    private static string PrivateFeed = @"http://www.google.com/calendar/feeds/default/private/full";

    private static string ClientID = System.Configuration.ConfigurationManager.AppSettings["GoogleCalendarApplicationClientID"].ToString();

    private static string ClientSecret = System.Configuration.ConfigurationManager.AppSettings["GoogleCalendarApplicationClientSecret"].ToString();

    private string AllCalendarFeedURL = @"https://www.google.com/calendar/feeds/default/allcalendars/full";
    protected void Page_Load(object sender, EventArgs e)
    {
        if (IsPostBack == false)
        {
            if (string.IsNullOrEmpty(Request.QueryString["code"]) == false)
            {
                GoogleTokenModel TokenData = new GoogleTokenModel();
                string Result = "";
                try
                {
                    TokenData = ExchangeCodeWithAccessAndRefreshToken();
                }
                catch
                {
                    Result = "?Error=Internet connectivity problem. Please try later";
                }

                //If no proper response is given
                if (string.IsNullOrEmpty(TokenData.Access_Token) == true)
                {
                    Result = "?Error=Some problem with google registration. Please try later or use a different gmail account to register";
                }

                //If the gmail account is already registered
                else if (string.IsNullOrEmpty(TokenData.Access_Token) == false && string.IsNullOrEmpty(TokenData.Refresh_Token) == true)
                {
                    Result = "?Error=This gmail account is already registered with this application. Please use a different gmail account to register";
                }
                //Check if the some error is thrown
                if (string.IsNullOrEmpty(Result) == false)
                {
                    LblMessage.Text = Result;
                    return;

                }

                //If proper token data is acquired
                else if (string.IsNullOrEmpty(TokenData.Access_Token) == false && string.IsNullOrEmpty(TokenData.Refresh_Token) == false)
                {
                    LblMessage.Text = "Registration Complete";

                    XmlDocument XmlDoc = new XmlDocument();
                    XmlDoc.Load(AppDomain.CurrentDomain.BaseDirectory + "App_Data\\XMLfile.xml");
                    XmlDoc.DocumentElement.SelectSingleNode("//User[@UserID='1']").Attributes["AccessToken"].Value = TokenData.Access_Token;
                    XmlDoc.DocumentElement.SelectSingleNode("//User[@UserID='1']").Attributes["RefreshToken"].Value = TokenData.Refresh_Token;

                    XmlDoc.Save(AppDomain.CurrentDomain.BaseDirectory + "App_Data\\XMLfile.xml");
                }
            }
            else
            {
                //if access denied 
                if (Request.QueryString["error"] != null)
                {
                    LblMessage.Text = "Access is Denied. Please grant access to continue to google calendar registration";
                }
                else
                {

                }
            }
        }
    }

    public static string GenerateGoogleOAuthURL()
    {
        string Url = "https://accounts.google.com/o/oauth2/auth?scope={0}&redirect_uri={1}&response_type={2}&client_id={3}&state={4}&access_type={5}&approval_prompt={6}";
        //string scope = UrlEncodeForGoogle("http://www.google.com/calendar/feeds/default/private/full").Replace("%20", "+");
        string scope = UrlEncodeForGoogle(PrivateFeed).Replace("%20", "+");
        string redirect_uri_encode = UrlEncodeForGoogle(ReturnUrl);
        string response_type = "code";
        string state = "";
        string access_type = "offline";
        string approval_prompt = "auto";
        return string.Format(Url, scope, redirect_uri_encode, response_type, ClientID, state, access_type, approval_prompt);
    }
    private static string UrlEncodeForGoogle(string url)
    {

        string UnReservedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";
        var result = new StringBuilder();

        foreach (char symbol in url)
        {
            if (UnReservedChars.IndexOf(symbol) != -1)
            {
                result.Append(symbol);
            }
            else
            {
                result.Append('%' + String.Format("{0:X2}", (int)symbol));
            }
        }
        return result.ToString();
    }
    private GoogleTokenModel ExchangeCodeWithAccessAndRefreshToken()
    {
        string Url = "https://accounts.google.com/o/oauth2/token";
        string grant_type = "authorization_code";
        string redirect_uri_encode = UrlEncodeForGoogle(ReturnUrl);
        string data = "code={0}&client_id={1}&client_secret={2}&redirect_uri={3}&grant_type={4}";
        string Code = Request.QueryString["Code"];

        HttpWebRequest request = HttpWebRequest.Create(Url) as HttpWebRequest;
        string result = null;
        request.Method = "POST";
        request.KeepAlive = true;
        request.ContentType = "application/x-www-form-urlencoded";
        string param = string.Format(data, Code, ClientID, ClientSecret, redirect_uri_encode, grant_type);
        var bs = Encoding.UTF8.GetBytes(param);
        using (Stream reqStream = request.GetRequestStream())
        {
            reqStream.Write(bs, 0, bs.Length);
        }

        using (WebResponse response = request.GetResponse())
        {
            var sr = new StreamReader(response.GetResponseStream());
            result = sr.ReadToEnd();
            sr.Close();
        }

        var jsonSerializer = new JavaScriptSerializer();
        var tokenData = jsonSerializer.Deserialize<GoogleTokenModel>(result);

        return tokenData;

    }

    private bool GetNewAccessToken(GoogleTokenModel GoogleTokenModelObj)
    {
        try
        {
            string Url = "https://accounts.google.com/o/oauth2/token";
            string grant_type = "refresh_token";
            string redirect_uri_encode = UrlEncodeForGoogle(ReturnUrl);
            string data = "client_id={0}&client_secret={1}&refresh_token={2}&grant_type={3}";

            HttpWebRequest request = HttpWebRequest.Create(Url) as HttpWebRequest;
            string result = null;
            request.Method = "POST";
            request.KeepAlive = true;
            request.ContentType = "application/x-www-form-urlencoded";
            string param = string.Format(data, ClientID, ClientSecret, GoogleTokenModelObj.Refresh_Token, grant_type);
            var bs = Encoding.UTF8.GetBytes(param);
            using (Stream reqStream = request.GetRequestStream())
            {
                reqStream.Write(bs, 0, bs.Length);
            }

            using (WebResponse response = request.GetResponse())
            {
                var sr = new StreamReader(response.GetResponseStream());
                result = sr.ReadToEnd();
                sr.Close();
            }

            var jsonSerializer = new JavaScriptSerializer();
            var TokenData = jsonSerializer.Deserialize<GoogleTokenModel>(result);

            GoogleTokenModelObj.Access_Token = TokenData.Access_Token;
            if (TokenData.Refresh_Token != null)
                GoogleTokenModelObj.Refresh_Token = TokenData.Refresh_Token;
            //GoogleTokenModelObj.LastAccessDateTime = DateTime.Now;

            //Update the refresh and access token in DB for next login usage
            //GoogleCalendarManager.UpdateRefreshTokenInGoogleAppointmentOAuth(GoogleTokenModelObj);
            XmlDocument XmlDoc = new XmlDocument();
            XmlDoc.Load(AppDomain.CurrentDomain.BaseDirectory + "App_Data\\XMLfile.xml");
            XmlDoc.DocumentElement.SelectSingleNode("//User[@UserID='1']").Attributes["AccessToken"].Value = TokenData.Access_Token;
            XmlDoc.DocumentElement.SelectSingleNode("//User[@UserID='1']").Attributes["RefreshToken"].Value = TokenData.Refresh_Token;
            XmlDoc.Save(AppDomain.CurrentDomain.BaseDirectory + "App_Data\\XMLfile.xml");

            return true;

        }
        catch
        {
            return false;
        }
    }
}

——————————-Web.config————————————

<?xml version="1.0"?>
<!--
  For more information on how to configure your ASP.NET application, please visit

http://go.microsoft.com/fwlink/?LinkId=169433

  -->
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0"/>
  </system.web>
  <appSettings>
    <add key="GoogleCalendarApplicationClientID" value=""/>
    <add key="GoogleCalendarApplicationClientSecret" value=""/>
    <add key="GoogleReturnPageAddress" value="http://localhost:58392/GoogleCalandarDemo/GoogleCalendarRegistration.aspx"/>
  </appSettings>
</configuration>

——————————AppData -> XMLFile.xml (This file serves as a DB here)————————–

  • You can change your login credentials. Currently they are set to UserName=Waqas, POwd = 111
  • When you register with google calendar, you will get a new AccessToken and RefreshToken which will be saved here
  • When you create / update an event, its details are stored here.
  • When you delete event, these details are removed, as you can see below that there are no values for the event attributes
  • When you revoke rights your AccessToken and RefreshToken are removed from here
  • YOU DON”T NEED TO EDIT THIS FILE MANUALLY, EXCEPT THE USERNAME, PWD AS THIS MAY RESULT IN EXCEPTIONS
<?xml version="1.0" encoding="utf-8"?>
<UsersAndEvents>
  <User UserID="1" UserName="Waqas" Password="111" AccessToken="" RefreshToken="">
  </User>
  <Event EventID="1" EventTitle="" EventStartTime="" EventEndTime="" EventLocation="">
  </Event>
</UsersAndEvents>

——————————AppCode -> GoogleCalendarAppointmentModel.cs———————————–

public class GoogleCalendarAppointmentModel
{
    public DateTime EventStartTime;
    public DateTime EventEndTime;
    public bool DeleteAppointment;
    public string EventID;
    public string EventLocation;
    public string EventTitle;
    public string EventDetails;
}

—————————–AppCode -> GoogleCalendarManager.cs———————————–

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Google.GData.Client;
using Google.GData.Calendar;
using Google.GData.AccessControl;
using Google.GData.Extensions;
using System.Net;
using System.IO;

public class GoogleCalendarManager
{

    private static string ReturnUrl = @System.Configuration.ConfigurationSettings.AppSettings["GoogleReturnPageAddress"].ToString();

    private static string ClientID = System.Configuration.ConfigurationSettings.AppSettings["GoogleCalendarApplicationClientID"].ToString();

    private static string ClientSecret = System.Configuration.ConfigurationSettings.AppSettings["GoogleCalendarApplicationClientSecret"].ToString();

    private static string PrivateFeed = @"http://www.google.com/calendar/feeds/default/private/full";
    private static string OwnCalendarFeed = @"http://www.google.com/calendar/feeds/default/owncalendars/full";
    private static string AllCalendarFeed = @"http://www.google.com/calendar/feeds/default/allcalendars/full";

    private static String userName, userPassword, feedUri;

    /// <summary>
    /// Prints a list of the user's calendars.
    /// </summary>
    /// <param name="service">The authenticated CalendarService object.</param>

    #region Currently Required Functions

    public static string GenerateGoogleOAuthURL()
    {
        string Url = "https://accounts.google.com/o/oauth2/auth?scope={0}&redirect_uri={1}&response_type={2}&client_id={3}&state={4}&access_type={5}&approval_prompt={6}";
        //string scope = UrlEncodeForGoogle("http://www.google.com/calendar/feeds/default/private/full").Replace("%20", "+");
        string scope = UrlEncodeForGoogle(PrivateFeed).Replace("%20", "+");
        string redirect_uri_encode = UrlEncodeForGoogle(ReturnUrl);
        string response_type = "code";
        string state = "";
        string access_type = "offline";
        string approval_prompt = "auto";
        return string.Format(Url, scope, redirect_uri_encode, response_type, ClientID, state, access_type, approval_prompt);
    }

    private static string GetCalendarID(CalendarService CalService)
    {
        Uri postUri = new Uri(AllCalendarFeed);
        CalendarQuery CalendarQuery = new CalendarQuery();

        CalendarQuery.Uri = postUri;

        CalendarFeed calFeed = CalService.Query(CalendarQuery);

        string CalendarID = "";

        if (calFeed != null && calFeed.Entries.Count > 0)
        {
            foreach (CalendarEntry CalEntry in calFeed.Entries)
            {
                //Commented to post the new appointments on the main calendar instead of cleverfox calendar
                //if (CalEntry.Title.Text.Contains("Cleverfox") == true)
                //{
                //CalendarID = CalEntry.Title.Text;
                CalendarID = CalEntry.EditUri.ToString().Substring(CalEntry.EditUri.ToString().LastIndexOf("/") + 1);
                break;
                //}
            }
        }

        #region Commented to post the new appointments on the main calendar instead of cleverfox calendar
        /*if (string.IsNullOrEmpty(CalendarID) == false)
            {

            }
            else
            {
                Google.GData.Client.AtomEntry cal = new AtomEntry();
                cal.Title.Text = "Cleverfox";

                CalService.Insert(new Uri(OwnCalendarFeed), cal);
            }
            calFeed = CalService.Query(CalendarQuery);

            //if search contains result then update
            if (calFeed != null && calFeed.Entries.Count > 0)
            {
                foreach (CalendarEntry CalEntry in calFeed.Entries)
                {
                    if (CalEntry.Title.Text.Contains("Cleverfox") == true)
                    {
                        //CalendarName = CalEntry.Title.Text;
                        CalendarID = CalEntry.EditUri.ToString().Substring(CalEntry.EditUri.ToString().LastIndexOf("/") + 1);
                        //if (CalEntry.TimeZone != "Canada/Vancouver")
                        //{
                        //    CalEntry.TimeZone = "(GMT-07:00) Arizona";
                        //    CalEntry.Update();
                        //}
                        if (CalEntry.TimeZone != MerchantTimeZone)
                        {
                            CalEntry.TimeZone = MerchantTimeZone;
                            CalEntry.Update();
                        }
                        break;
                    }
                }
            }*/
        #endregion
        return CalendarID;
    }
    public static CalendarService GetCalendarService(GoogleTokenModel GoogleTokenModelObj)
    {
        GAuthSubRequestFactory authFactory = new GAuthSubRequestFactory("cl", "API Project");
        authFactory.Token = GoogleTokenModelObj.Access_Token;
        authFactory.KeepAlive = true;

        CalendarService service = new CalendarService("cl");
        service.RequestFactory = authFactory;

        return service;
    }
    public static bool AddUpdateDeleteEvent(List<GoogleTokenModel> GoogleTokenModelList, List<GoogleCalendarAppointmentModel> GoogleCalendarAppointmentModelList, double TimeOffset)
    {
        bool result = false;
        foreach (GoogleTokenModel GoogleAppointmentOAuthDetailsObj in GoogleTokenModelList)
        {
            //Get the calendar service for a user to add/update/delete events
            CalendarService CalService = GetCalendarService(GoogleAppointmentOAuthDetailsObj);
            //get the calendar id for this user to add/update/delete events
            string CalendarID = GetCalendarID(CalService);

            EventEntry InsertedEntry = new EventEntry();

            if (GoogleCalendarAppointmentModelList != null && GoogleCalendarAppointmentModelList.Count > 0)
            {
                foreach (GoogleCalendarAppointmentModel GoogleCalendarAppointmentModelObj in GoogleCalendarAppointmentModelList)
                {
                    //to restrict the appointment for specific staff only
                    //Delete this appointment from google calendar
                    if (GoogleCalendarAppointmentModelObj.DeleteAppointment == true)
                    {
                        Google.GData.Calendar.EventEntry Entry = new Google.GData.Calendar.EventEntry();

                        ExtendedProperty oExtendedProperty = new ExtendedProperty();
                        oExtendedProperty.Name = "EventID";
                        oExtendedProperty.Value = GoogleCalendarAppointmentModelObj.EventID;

                        //search the calendar so to update or add appointment in it
                        string ThisFeedUri = "http://www.google.com/calendar/feeds/" + CalendarID + "/private/full";
                        Uri postUri = new Uri(ThisFeedUri);
                        EventQuery Query = new EventQuery(ThisFeedUri);
                        Query.ExtraParameters = "extq=[EventID:" + GoogleCalendarAppointmentModelObj.EventID + "]";
                        Query.Uri = postUri;
                        Entry.ExtensionElements.Add(oExtendedProperty);
                        EventFeed calFeed = CalService.Query(Query);

                        //if search contains result then update
                        if (calFeed != null && calFeed.Entries.Count > 0)
                        {
                            foreach (EventEntry SearchedEntry in calFeed.Entries)
                            {
                                SearchedEntry.Delete();
                                result = true;
                                break;
                            }
                            //return null;
                        }
                    }
                    //Add if not found OR update if appointment already present on google calendar
                    else
                    {
                        Google.GData.Calendar.EventEntry Entry = new Google.GData.Calendar.EventEntry();
                        // Set the title and content of the entry.
                        Entry.Title.Text = "Event generated through google api";

                        System.Text.StringBuilder EventDetails = new System.Text.StringBuilder();
                        EventDetails.Append(GoogleCalendarAppointmentModelObj.EventDetails);                        
                        Entry.Content.Content = EventDetails.ToString();

                        When EventTime = new When();
                        EventTime.StartTime = GoogleCalendarAppointmentModelObj.EventStartTime.AddMinutes(-TimeOffset);
                        EventTime.EndTime = GoogleCalendarAppointmentModelObj.EventEndTime.AddMinutes(-TimeOffset);

                        Entry.Times.Add(EventTime);

                        // Set a location for the event.
                        Where eventLocation = new Where();
                        if (string.IsNullOrEmpty(GoogleCalendarAppointmentModelObj.EventLocation) == false)
                        {
                            eventLocation.ValueString = GoogleCalendarAppointmentModelObj.EventLocation;
                            Entry.Locations.Add(eventLocation);
                        }
                        //Add appointment ID to update/ delete the appointment afterwards
                        ExtendedProperty oExtendedProperty = new ExtendedProperty();
                        oExtendedProperty.Name = "EventID";
                        oExtendedProperty.Value = GoogleCalendarAppointmentModelObj.EventID;
                        Entry.ExtensionElements.Add(oExtendedProperty);

                        //search the calendar so to update or add appointment in it
                        string ThisFeedUri = "http://www.google.com/calendar/feeds/" + CalendarID + "/private/full";
                        Uri postUri = new Uri(ThisFeedUri);
                        EventQuery Query = new EventQuery(ThisFeedUri);
                        Query.ExtraParameters = "extq=[EventID:" + GoogleCalendarAppointmentModelObj.EventID + "]";
                        Query.Uri = postUri;
                        Entry.ExtensionElements.Add(oExtendedProperty);
                        EventFeed calFeed = CalService.Query(Query);

                        //if search contains result then update
                        if (calFeed != null && calFeed.Entries.Count > 0)
                        {
                            foreach (EventEntry SearchedEntry in calFeed.Entries)
                            {
                                SearchedEntry.Content = Entry.Content;
                                SearchedEntry.Title = Entry.Title;
                                SearchedEntry.Times.RemoveAt(0);
                                SearchedEntry.Times.Add(EventTime);
                                SearchedEntry.Locations.RemoveAt(0);
                                SearchedEntry.Locations.Add(eventLocation);

                                CalService.Update(SearchedEntry);
                                result = true;
                                break;
                            }
                        }
                        //otherwise add the entry
                        else
                        {
                            InsertedEntry = CalService.Insert(postUri, Entry);
                            result = true;
                        }
                    }
                }
            }
        }
        return result ;
    }
    public static bool RevokeAccessToken(string Access_Token, string Refresh_Token)
    {
        try
        {
            //check and revoke right from google if staff is registered i.e. he has proper acccess token
            if (string.IsNullOrEmpty(Access_Token) == false)
            {
                string Url = "https://accounts.google.com/o/oauth2/revoke?token=" + Refresh_Token;

                string redirect_uri_encode = UrlEncodeForGoogle(ReturnUrl);
                string data = "refresh_token={0}";

                HttpWebRequest request = HttpWebRequest.Create(Url) as HttpWebRequest;
                string result = null;
                request.Method = "POST";
                request.KeepAlive = true;
                request.ContentType = "application/x-www-form-urlencoded";
                string param = string.Format(data, Refresh_Token);
                var bs = Encoding.UTF8.GetBytes(param);
                using (Stream reqStream = request.GetRequestStream())
                {
                    //reqStream.Write(bs, 0, bs.Length);
                }

                using (WebResponse response = request.GetResponse())
                {
                    var sr = new StreamReader(response.GetResponseStream());
                    result = sr.ReadToEnd();
                    sr.Close();
                }
            }

            return true;
        }
        catch
        {
            //GoogleCalendarManager.DeleteGoogleAppointmentOAuthDetailsRecord(GoogleAppointmentOAuthDetailsObj.ID);
            return false;
        }

    }

    #region Utility functions
    public static string UrlEncodeForGoogle(string url)
    {

        string UnReservedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";
        var result = new StringBuilder();

        foreach (char symbol in url)
        {
            if (UnReservedChars.IndexOf(symbol) != -1)
            {
                result.Append(symbol);
            }
            else
            {
                result.Append('%' + String.Format("{0:X2}", (int)symbol));
            }
        }

        return result.ToString();
    }
    #endregion

    #endregion

    #region Other functions which are not used now
    static void PrintUserCalendars(CalendarService service)
    {
        FeedQuery query = new FeedQuery();
        query.Uri = new Uri("http://www.google.com/calendar/feeds/default");

        // Tell the service to query:
        AtomFeed calFeed = service.Query(query);

        Console.WriteLine("Your calendars:");
        Console.WriteLine();
        for (int i = 0; i < calFeed.Entries.Count; i++)
        {
            Console.WriteLine(calFeed.Entries[i].Title.Text);
        }
        Console.WriteLine();
    }

    /// <summary>
    /// Prints the titles of all events on the specified calendar.
    /// </summary>
    /// <param name="service">The authenticated CalendarService object.</param>
    static void PrintAllEvents(CalendarService service)
    {
        EventQuery myQuery = new EventQuery(feedUri);
        EventFeed myResultsFeed = service.Query(myQuery) as EventFeed;

        Console.WriteLine("All events on your calendar:");
        Console.WriteLine();
        for (int i = 0; i < myResultsFeed.Entries.Count; i++)
        {
            Console.WriteLine(myResultsFeed.Entries[i].Title.Text);
        }
        Console.WriteLine();
    }

    /// <summary>
    /// Prints the titles of all events matching a full-text query.
    /// </summary>
    /// <param name="service">The authenticated CalendarService object.</param>
    /// <param name="queryString">The text for which to query.</param>
    static void FullTextQuery(CalendarService service, String queryString)
    {
        EventQuery myQuery = new EventQuery(feedUri);
        myQuery.Query = queryString;

        EventFeed myResultsFeed = service.Query(myQuery) as EventFeed;

        Console.WriteLine("Events matching \"{0}\":", queryString);
        Console.WriteLine();
        for (int i = 0; i < myResultsFeed.Entries.Count; i++)
        {
            Console.WriteLine(myResultsFeed.Entries[i].Title.Text);
        }
        Console.WriteLine();
    }

    /// <summary>
    /// Prints the titles of all events in a specified date/time range.
    /// </summary>
    /// <param name="service">The authenticated CalendarService object.</param>
    /// <param name="startTime">Start time (inclusive) of events to print.</param>
    /// <param name="endTime">End time (exclusive) of events to print.</param>
    static void DateRangeQuery(CalendarService service, DateTime startTime, DateTime endTime)
    {
        EventQuery myQuery = new EventQuery(feedUri);
        myQuery.StartTime = startTime;
        myQuery.EndTime = endTime;

        EventFeed myResultsFeed = service.Query(myQuery) as EventFeed;

        Console.WriteLine("Matching events from {0} to {1}:",
                          startTime.ToShortDateString(),
                          endTime.ToShortDateString());
        Console.WriteLine();
        for (int i = 0; i < myResultsFeed.Entries.Count; i++)
        {
            Console.WriteLine(myResultsFeed.Entries[i].Title.Text);
        }
        Console.WriteLine();
    }

    /// <summary>
    /// Helper method to create either single-instance or recurring events.
    /// For simplicity, some values that might normally be passed as parameters
    /// (such as author name, email, etc.) are hard-coded.
    /// </summary>
    /// <param name="service">The authenticated CalendarService object.</param>
    /// <param name="entryTitle">Title of the event to create.</param>
    /// <param name="recurData">Recurrence value for the event, or null for
    ///                         single-instance events.</param>
    /// <returns>The newly-created EventEntry on the calendar.</returns>
    public static Service GetService(string SessionToken)
    {
        GAuthSubRequestFactory authFactory = new GAuthSubRequestFactory("cl", "CalendarSampleApp");
        authFactory.Token = SessionToken;
        Service service = new Service("cl", authFactory.ApplicationName);
        service.RequestFactory = authFactory;

        return service;
    }

    /// <summary>
    /// Creates a single-instance event on a calendar.
    /// </summary>
    /// <param name="service">The authenticated CalendarService object.</param>
    /// <param name="entryTitle">Title of the event to create.</param>
    /// <returns>The newly-created EventEntry on the calendar.</returns>
    public static EventEntry CreateSingleEvent(CalendarService service, String entryTitle)
    {
        //return AddUpdateDeleteEvent(service, entryTitle, null, null, null);
        return new EventEntry();
    }

    /// <summary>
    /// Creates a recurring event on a calendar. In this example, the event
    /// occurs every Tuesday from May 1, 2007 through September 4, 2007. Note
    /// that we are using iCal (RFC 2445) syntax; see http://www.ietf.org/rfc/rfc2445.txt
    /// for more information.
    /// </summary>
    /// <param name="service">The authenticated CalendarService object.</param>
    /// <param name="entryTitle">Title of the event to create.</param>
    /// <returns>The newly-created EventEntry on the calendar.</returns>
    static EventEntry CreateRecurringEvent(CalendarService service, String entryTitle)
    {
        String recurData =
          "DTSTART;VALUE=DATE:20070501\r\n" +
          "DTEND;VALUE=DATE:20070502\r\n" +
          "RRULE:FREQ=WEEKLY;BYDAY=Tu;UNTIL=20070904\r\n";

        //return AddUpdateDeleteEvent(service, entryTitle, recurData, null, null);
        return new EventEntry();
    }

    /// <summary>
    /// Updates the title of an existing calendar event.
    /// </summary>
    /// <param name="entry">The event to update.</param>
    /// <param name="newTitle">The new title for this event.</param>
    /// <returns>The updated EventEntry object.</returns>
    static EventEntry UpdateTitle(EventEntry entry, String newTitle)
    {
        entry.Title.Text = newTitle;
        return (EventEntry)entry.Update();
    }

    /// <summary>
    /// Adds a reminder to a calendar event.
    /// </summary>
    /// <param name="entry">The event to update.</param>
    /// <param name="numMinutes">Reminder time, in minutes.</param>
    /// <returns>The updated EventEntry object.</returns>
    static EventEntry AddReminder(EventEntry entry, int numMinutes)
    {
        Reminder reminder = new Reminder();
        reminder.Minutes = numMinutes;
        entry.Reminder = reminder;

        return (EventEntry)entry.Update();
    }

    /// <summary>
    /// Adds an extended property to a calendar event.
    /// </summary>
    /// <param name="entry">The event to update.</param>
    /// <returns>The updated EventEntry object.</returns>
    static EventEntry AddExtendedProperty(EventEntry entry)
    {
        ExtendedProperty property = new ExtendedProperty();
        property.Name = "http://www.example.com/schemas/2005#mycal.id";
        property.Value = "1234";

        entry.ExtensionElements.Add(property);

        return (EventEntry)entry.Update();
    }

    /// <summary>
    /// Retrieves and prints the access control lists of all
    /// of the authenticated user's calendars.
    /// </summary>
    /// <param name="service">The authenticated CalendarService object.</param>
    static void RetrieveAcls(CalendarService service)
    {
        FeedQuery query = new FeedQuery();
        query.Uri = new Uri("http://www.google.com/calendar/feeds/default");
        AtomFeed calFeed = service.Query(query);

        Console.WriteLine();
        Console.WriteLine("Sharing permissions for your calendars:");

        // Retrieve the meta-feed of all calendars.
        foreach (AtomEntry calendarEntry in calFeed.Entries)
        {
            Console.WriteLine("Calendar: {0}", calendarEntry.Title.Text);
            AtomLink link = calendarEntry.Links.FindService(
                AclNameTable.LINK_REL_ACCESS_CONTROL_LIST, null);

            // For each calendar, retrieve its ACL feed.
            if (link != null)
            {
                AclFeed feed = service.Query(new AclQuery(link.HRef.ToString()));
                foreach (AclEntry aclEntry in feed.Entries)
                {
                    Console.WriteLine("\tScope: Type={0} ({1})", aclEntry.Scope.Type,
                        aclEntry.Scope.Value);
                    Console.WriteLine("\tRole: {0}", aclEntry.Role.Value);
                }
            }
        }
    }

    /// <summary>
    /// Shares a calendar with the specified user.  Note that this method
    /// will not run by default.
    /// </summary>
    /// <param name="service">The authenticated CalendarService object.</param>
    /// <param name="aclFeedUri">the ACL feed URI of the calendar being shared.</param>
    /// <param name="userEmail">The email address of the user with whom to share.</param>
    /// <param name="role">The role of the user with whom to share.</param>
    /// <returns>The AclEntry returned by the server.</returns>
    static AclEntry AddAccessControl(CalendarService service, string aclFeedUri,
        string userEmail, AclRole role)
    {
        AclEntry entry = new AclEntry();

        entry.Scope = new AclScope();
        entry.Scope.Type = AclScope.SCOPE_USER;
        entry.Scope.Value = userEmail;

        entry.Role = role;

        Uri aclUri =
            new Uri("http://www.google.com/calendar/feeds/gdata.ops.test@gmail.com/acl/full");

        AclEntry insertedEntry = service.Insert(aclUri, entry);
        Console.WriteLine("Added user {0}", insertedEntry.Scope.Value);

        return insertedEntry;
    }

    /// <summary>
    /// Updates a user to have new access permissions over a calendar.
    /// Note that this method will not run by default.
    /// </summary>
    /// <param name="entry">An existing AclEntry representing sharing permissions.</param>
    /// <param name="newRole">The new role (access permissions) for the user.</param>
    /// <returns>The updated AclEntry.</returns>
    static AclEntry UpdateEntry(AclEntry entry, AclRole newRole)
    {
        entry.Role = newRole;
        AclEntry updatedEntry = entry.Update() as AclEntry;

        Console.WriteLine("Updated {0} to have role {1}", updatedEntry.Scope.Value,
            entry.Role.Value);
        return updatedEntry;
    }

    /// <summary>
    /// Deletes a user from a calendar's access control list, preventing
    /// that user from accessing the calendar.  Note that this method will
    /// not run by default.
    /// </summary>
    /// <param name="entry">An existing AclEntry representing sharing permissions.</param>
    static void DeleteEntry(AclEntry entry)
    {
        entry.Delete();
    }
    #endregion
}

—————————–AppCode -> GoogleTokenModel.cs————————————–

public class GoogleTokenModel
{
    public string Access_Token { get; set; }
    public string Refresh_Token { get; set; }
    public string Expires_In { get; set; }
    public string Token_Type { get; set; }

}

——————————Bin folder————————–

These dlls need to be added in Bin folder.

Google.GData.Client
Google.GData.Calendar
Google.GData.AccessControl
Google.GData.Extensions

  • Download Google Data API
  • install the MSi
  • get the above files from C:\Program Files\Google\Google Data API SDK\Samples

——————————Useful Links————————–

To refresh access token

To revoke rights access token

2012 in review

Posted: January 2, 2013 in Uncategorized

The WordPress.com stats helper monkeys prepared a 2012 annual report for this blog.

Here’s an excerpt:

600 people reached the top of Mt. Everest in 2012. This blog got about 3,900 views in 2012. If every person who reached the top of Mt. Everest viewed this blog, it would have taken 7 years to get that many views.

Click here to see the complete report.


//Required Files (Download file internet and adjust src accordingly)

//—————————ASPX (copy the code from ‘html xmlns… ‘ till end)

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="AjaxUpdateJquery.aspx.cs"
    Inherits="JQuery_Exploration.AjaxUpdateJquery" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script src="js/jquery-1.8.0.min.js" type="text/javascript"></script>
    <style type="text/css">
        .RedText
        {
            color: Red;
        }
    </style>
    <script type="text/javascript">
        $(document).ready(function () {
            $('#<% =btn1.ClientID%>').click(function () {
                alert('btn 1 clicked, attached to btn1');
                $('#lbl').fadeOut("fast").fadeIn("fast").html('This button 1 click event will get fired only 1st time after page load as it is bind using click function<br/> so the event is attached to <span class="RedText"> button id </span>and will get changed after the ajax call');
            });

            $('#<% =btn2.ClientID%>').live("click", function () {
                alert('btn 2 clicked, attached to body');
                $('#lbl').fadeOut("fast").fadeIn("fast").html('This button 2 click event will get fired every time as it is bind using live function, so the event is attached to <span class="RedText"> body </span> and doesn\'t change after ajax call');
            });

            $('body').delegate('#<% =btn3.ClientID%>', "click", function () {
                alert('btn 3 clicked, attached to btn3 itself');
                $('#lbl').fadeOut("fast").fadeIn("fast").html('This button 3 click event will work every time as it is attached to <span class="RedText">body </span > using delegate function<br/> so it will not change after ajax call');
            });

            $('#OuterDiv').delegate('#<% =btn3.ClientID%>', "click", function () {
                alert('btn 3 clicked, attached to OuterDiv');
                $('#lbl').fadeOut("fast").fadeIn("fast").html('This button 3 click event will work every time as it is attached to <span class="RedText">OuterDiv</span> using delegate function');
            });

            $('#AjaxInnerDiv').delegate('#<% =btn3.ClientID%>', "click", function () {
                alert('btn 3 clicked, attached to AjaxInnerDiv');
                $('#lbl').fadeOut("fast").fadeIn("fast").html('This button 3 click event will work every time as it is attached to <span class="RedText">AjaxInnerDiv</span> using delegate function<br/> and the contents will change after ajax call');
            });

            $('#<% =btn4.ClientID%>').on("click", function () {
                alert('btn 4 click event fired, attached to button 4 id');
                $('#lbl').fadeOut("fast").fadeIn("fast").html('This button 4 click will work 1st time after page load as it is attached to <span class="RedText">btn 4</span> id which gets change after ajax call');
            });

            $('#AjaxInnerDiv').on("click", '#<% =btn4.ClientID%>', function () {
                alert('btn 4 click event fired, attached to AjaxInnerDiv');
                $('#lbl').fadeOut("fast").fadeIn("fast").html('This button 4 click will work 1st time after page load as it is attached to <span class="RedText">AjaxInnerDiv</span> which gets change after ajax call');
            });

            $('#OuterDiv').on("click", '#<% =btn4.ClientID%>', function () {
                alert('btn 4 click event fired, attached to Outer Div');
                $('#lbl').fadeOut("fast").fadeIn("fast").html('This button 4 click event attached to <span class="RedText">OuterDiv</span> will work every time as it doesn\'t change after ajax call');
            });
        });
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <h1>
        Asp.net update panel working with jquery (bind, live, delegate, on)</h1>
    <h2>
        OuterDiv</h2>
    <%--events attached to this div will get fired always as the contents don't change after ajax call--%>
    <div id="OuterDiv" style="border: 1px solid Black; padding: 10px">
        Click each button after refreshing the page to see all the events attached (the
        reason being the contents inside update panel get change after the ajax call)
        <br />
        After 1st button click only those events will get fired which didn't change after
        the ajax call
        <hr />
        <p id="lbl">
        </p>
        <div>
            <asp:ScriptManager runat="server">
            </asp:ScriptManager>
            <asp:UpdatePanel runat="server">
                <ContentTemplate>
                    <%--events attached to this div will not get fired after ajax call as
                because the contents are changed after ajax call--%>
                    <h3>
                        AjaxInnerDiv</h3>
                    <div id="AjaxInnerDiv" style="border: 1px dotted Red">
                        <asp:Button runat="server" ID="btn1" Text="Bind" />
                        <asp:Button runat="server" ID="btn2" Text="Live" />
                        <asp:Button runat="server" ID="btn3" Text="Delegate" />
                        <asp:Button runat="server" ID="btn4" Text="On" />
                    </div>
                </ContentTemplate>
            </asp:UpdatePanel>
        </div>
    </div>
    </form>
</body>
</html>

JQuery Bind, Live Difference

Posted: September 25, 2012 in JQuery
Tags: , , ,

//Required Files (Download file internet and adjust src accordingly)

//—————————ASPX (you can copy the code from ‘html xmlns… ‘ till end)

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Selectors.aspx.cs" Inherits="JQuery_Exploration.Selectors" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Practice JQuery Bind, Delegate, Live</title>
    <script src="js/jquery-1.8.0.min.js" type="text/javascript"></script>
    <style type="text/css">
        .DivBind
        {
            color: Red;
        }
        .DivLive
        {
            color: Green;
        }
    </style>
    <script type="text/javascript">
        $(document).ready(function () {
            $("#btn1").bind("click", function () {
                alert(jQuery("#btn1").attr("value") + ", using bind");
            });
            $("#txt1").live("change", function () {
                alert("Text is :" + $("#txt1").val() + ", using live");
            });
            jQuery(".DivBind").bind("click", function () {
                jQuery(this).after("<p class='DivBind'><b>div added using bind</b></p>");
            });

            jQuery(".DivLive").live("click", function () {
                jQuery(this).after("<p class='DivLive'><i>div added using live</i></p>");
            });
        });
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <p>
            <b>JQuery Bind, Live Difference</b></p>
        An alert will show the contents of 'value:attribute' when the button is clicked,
        using bind
        <button id="btn1" value="Btn1Value">
            Button1</button>
        <br />
        An alert will show if the value in the text box is changed, using live(v 1.4.3 +)
        <input type="text" id="txt1" value="Text" />
        <hr />
        <p class="DivBind">
            Click the text to add div dynamically using bind (the dynamically added div won't
            get bind to this event as it binds on element level)</p>
        <p class="DivLive">
            Click the button to add div dynamically using live (all the new divs will be attached
            with the click event as it binds on DOM level)</p>
        <hr />
    </div>
    </form>
</body>
</html>

—————————————-
Useful link:

JQuery watermark

Posted: September 18, 2012 in JQuery
Tags: ,

//Required Files (Download file internet and adjust src accordingly)

//—————————ASPX

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="TestWatermark.aspx.cs"
    Inherits="JQuery_Exploration.TestWatermark" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script src="js/jquery-1.4.1.min.js" type="text/javascript"></script>
    <script src="js/jquery.watermark.js" type="text/javascript"></script>
    <style type="text/css">
        .myClassName
        {
            color: gray;
        }
    </style>
    <script type="text/javascript">
        $(document).ready(function () {
            $('#<%=inputId.ClientID %>').watermark('Required information', { className: 'myClassName' });

        });
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:TextBox runat="server" ID="inputId"></asp:TextBox>
    </div>
    </form>
</body>
</html>

Useful link:
http://code.google.com/p/jquery-watermark/


———————————————Master Page

<%@ Master Language="C#" AutoEventWireup="true" CodeFile="MasterPage.master.cs" Inherits="MasterPage" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script type="text/javascript">
        function CallService() {
            WebService.HelloWorld("Waqas, ", Callback);
        }

        function Callback(result) {
            var outDiv = document.getElementById("outputDiv");
            outDiv.innerText = result + ' from MasterPage';
        }
    </script>
    <asp:ContentPlaceHolder ID="head" runat="server">
    </asp:ContentPlaceHolder>
</head>
<body>
    <form id="form1" runat="server">
    <div style="border: 1px dotted red">
        Master Page Contents Starts Here
        <br />
        <asp:scriptmanager id="ScriptManager1" runat="server">
            <services>
                <asp:ServiceReference Path="WebService.asmx" />
            </services>
        </asp:scriptmanager>
        <div>
            <asp:button id="Button1" runat="server" onclientclick="CallService();return false;"
                text="Button" />
            <div id="outputDiv" style="width: 100px; height: 100px">
            </div>
        </div>
        <br />
        Master Page Contents End here
    </div>
    </form>
    <div>
        <asp:contentplaceholder id="ContentPlaceHolder1" runat="server">
        </asp:contentplaceholder>
    </div>
    </form>
</body>
</html>

———————————————Content Page

<%@ Page Title="" Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true" CodeFile="TryFromMaster.aspx.cs" Inherits="TryFromMaster" %>

<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
This is the content from content page
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
</asp:Content>

———————————————Web Service.asmx

<%@ WebService Language="C#" CodeBehind="~/App_Code/WebService.cs" Class="WebService" %>

———————————————Web Service.asmx.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;

/// <summary>
/// Summary description for WebService
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
 [System.Web.Script.Services.ScriptService]
public class WebService : System.Web.Services.WebService {

    public WebService () {

        //Uncomment the following line if using designed components 
        //InitializeComponent(); 
    }

    [WebMethod]
    public string HelloWorld(string ToSomeone)
    {
        return "Hello " + ToSomeone;
    }
    
}

Useful link:
http://dotnetbyexample.blogspot.com/2007/10/calling-asmx-web-services-directly-from.html

JQuery Allow Decimal input

Posted: September 13, 2012 in JQuery
Tags: ,

//Required Files (Download file internet and adjust src accordingly)

  • autoNumeric-1.7.5.js(attached)
  • jquery-1.4.1.min.js (download from internet)

//—————————ASPX

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="AllowDecimal.aspx.cs" Inherits="JQuery_Exploration.AllowDecimal" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script src="js/jquery-1.4.1.min.js" type="text/javascript"></script>
    <script src="js/autoNumeric-1.7.5.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(document).ready(function () {
            $('#<%= txtDecimal.ClientID%>').autoNumeric({ aSep: '', aDec: '.' });
        });
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:TextBox ID="txtDecimal" runat="server"></asp:TextBox>
    </div>
    </form>
</body>
</html>

//—————————autoNumeric-1.7.5.js

/**
* autoNumeric.js
* @author: Bob Knothe
* @author: Sokolov Yura aka funny_falcon
* @version: 1.7.5
*
* Created by Robert J. Knothe on 2010-10-25. Please report any bug at http://www.decorplanit.com/plugin/
* Created by Sokolov Yura on 2010-11-07. http://github.com/funny_falcon
*
* Copyright (c) 2011 Robert J. Knothe  http://www.decorplanit.com/plugin/
* Copyright (c) 2011 Sokolov Yura aka funny_falcon
*
* The MIT License (http://www.opensource.org/licenses/mit-license.php)
*
* 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.
*/
(function ($) {
	/**
	* Cross browser routin for getting selected range/cursor position
	*/
	function getElementSelection(that) {
		var position = {};
		if (that.selectionStart === undefined) {
			that.focus();
			var select = document.selection.createRange();
			position.length = select.text.length;
			select.moveStart('character', -that.value.length);
			position.end = select.text.length;
			position.start = position.end - position.length;
		} else {
			position.start = that.selectionStart;
			position.end = that.selectionEnd;
			position.length = position.end - position.start;
		}
		return position;
	}
	/**
	* Cross browser routin for setting selected range/cursor position
	*/
	function setElementSelection(that, start, end) {
		if (that.selectionStart === undefined) {
			that.focus();
			var r = that.createTextRange();
			r.collapse(true);
			r.moveEnd('character', end);
			r.moveStart('character', start);
			r.select();
		} else {
			that.selectionStart = start;
			that.selectionEnd = end;
		}
	}
	/**
	* run callbacks in parameters if any
	* any parameter could be a callback:
	* - a function, which invoked with jQuery element, parameters and this parameter name and returns parameter value
	* - a name of function, attached to $.autoNumeric, which called as previous
	* - a css selector recognized by jQuery - value of input is taken as a parameter value
	*/
	function runCallbacks($this, io) {
		/**
		* loops through the io object (option array) to find the following
		* k = option name example k=aNum
		* val = option value example val=0123456789
		*/
		$.each(io, function (k, val) {
			if (typeof (val) === 'function') {
				io[k] = val($this, io, k);
			} else if (typeof (val) === 'string') {
				var kind = val.substr(0, 4);
				if (kind === 'fun:') {
					var fun = $.autoNumeric[val.substr(4)];
					if (typeof (fun) === 'function') {
						/**
						* calls the attached function from meta="{aSign:'fun:functionName'}"
						* example: $autoNumeric.functionName($this, io, optionName);
						*/
						io[k] = $.autoNumeric[val.substr(4)]($this, io, k);
					} else {
						io[k] = null;
					}
				} else if (kind === 'css:') {
					/**
					* retrieves the value by css selector meta="{mDec:'css:#decimal'}"
					* example: would assign the value to io[k] = $('#decimal').val();
					*/
					io[k] = $(val.substr(4)).val();
				}
			}
		});
	}
	function convertKeyToNumber(io, key) {
		if (typeof (io[key]) === 'string') {
			io[key] *= 1;
		}
	}
	/**
	* Preparing user defined options for further usage
	* merge them with defaults appropriatly
	*/
	function autoCode($this, options) {
		var io = $.extend({}, $.fn.autoNumeric.defaults, options);
		if ($.metadata) { /** consider declared metadata on input */
			io = $.extend(io, $this.metadata());
		}
		runCallbacks($this, io);
		var vmax = io.vMax.toString().split('.');
		var vmin = (!io.vMin && io.vMin !== 0) ? [] : io.vMin.toString().split('.');
		convertKeyToNumber(io, 'vMax');
		convertKeyToNumber(io, 'vMin');
		convertKeyToNumber(io, 'mDec');
		io.aNeg = io.vMin < 0 ? '-' : ''; /** set mDec, if not defained by user */
		if (typeof (io.mDec) !== 'number') {
			io.mDec = Math.max((vmax[1] ? vmax[1] : '').length, (vmin[1] ? vmin[1] : '').length);
		} /** set alternative decimal separator key */
		if (io.altDec === null && io.mDec > 0) {
			if (io.aDec === '.' && io.aSep !== ',') {
				io.altDec = ',';
			} else if (io.aDec === ',' && io.aSep !== '.') {
				io.altDec = '.';
			}
		} /** cache regexps for autoStrip */
		var aNegReg = io.aNeg ? '([-\\' + io.aNeg + ']?)' : '(-?)';
		io._aNegReg = aNegReg;
		io._skipFirst = new RegExp(aNegReg + '[^-' + (io.aNeg ? '\\' + io.aNeg : '') + '\\' + io.aDec + '\\d]' + '.*?(\\d|\\' + io.aDec + '\\d)');
		io._skipLast = new RegExp('(\\d\\' + io.aDec + '?)[^\\' + io.aDec + '\\d]\\D*$');
		var allowed = (io.aNeg ? io.aNeg : '-') + io.aNum + '\\' + io.aDec;
		if (io.altDec && io.altDec !== io.aSep) {
			allowed += io.altDec;
		}
		io._allowed = new RegExp('[^' + allowed + ']', 'gi');
		io._numReg = new RegExp(aNegReg + '(?:\\' + io.aDec + '?(\\d+\\' + io.aDec + '\\d+)|(\\d*(?:\\' + io.aDec + '\\d*)?))');
		return io;
	}
	/**
	* strip all unwanted characters and leave only a number
	*/
	function autoStrip(s, io, strip_zero) {
		if (io.aSign) { /** remove currency sign */
			while (s.indexOf(io.aSign) > -1) {
				s = s.replace(io.aSign, '');
			}
		}
		s = s.replace(io._skipFirst, '$1$2'); /** first replace anything before digits */
		s = s.replace(io._skipLast, '$1'); /** then replace anything after digits */
		s = s.replace(io._allowed, ''); /** then remove any uninterested characters */
		if (io.altDec) {
			s = s.replace(io.altDec, io.aDec);
		} /** get only number string */
		var m = s.match(io._numReg);
		s = m ? [m[1], m[2], m[3]].join('') : ''; /** strip zero if need */
		if (strip_zero) {
			var strip_reg = '^' + io._aNegReg + '0*(\\d' + (strip_zero === 'leading' ? ')' : '|$)');
			strip_reg = new RegExp(strip_reg);
			s = s.replace(strip_reg, '$1$2');
		}
		return s;
	}
	/**
	* truncate decimal part of a number
	*/
	function truncateDecimal(s, aDec, mDec) {
		if (aDec && mDec) {
			var parts = s.split(aDec);
			/** truncate decimal part to satisfying length
			* cause we would round it anyway */
			if (parts[1] && parts[1].length > mDec) {
				if (mDec > 0) {
					parts[1] = parts[1].substring(0, mDec);
					s = parts.join(aDec);
				} else {
					s = parts[0];
				}
			}
		}
		return s;
	}
	/**
	* prepare number string to be converted to real number
	*/
	function fixNumber(s, aDec, aNeg) {
		if (aDec && aDec !== '.') {
			s = s.replace(aDec, '.');
		}
		if (aNeg && aNeg !== '-') {
			s = s.replace(aNeg, '-');
		}
		if (!s.match(/\d/)) {
			s += '0';
		}
		return s;
	}
	/**
	* prepare real number to be converted to our format
	*/
	function presentNumber(s, aDec, aNeg) {
		if (aNeg && aNeg !== '-') {
			s = s.replace('-', aNeg);
		}
		if (aDec && aDec !== '.') {
			s = s.replace('.', aDec);
		}
		return s;
	}
	/**
	* checking that number satisfy format conditions
	* and lays between io.vMin and io.vMax
	*/
	function autoCheck(s, io) {
		s = autoStrip(s, io);
		s = truncateDecimal(s, io.aDec, io.mDec);
		s = fixNumber(s, io.aDec, io.aNeg);
		var value = +s;
		return value >= io.vMin && value <= io.vMax;
	}
	/**
	* private function to check for empty value
	*/
	function checkEmpty(iv, io, signOnEmpty) {
		if (iv === '' || iv === io.aNeg) {
			if (io.wEmpty === 'zero') {
				return iv + '0';
			} else if (io.wEmpty === 'sign' || signOnEmpty) {
				return iv + io.aSign;
			} else {
				return iv;
			}
		}
		return null;
	}
	/**
	* private function that formats our number
	*/
	function autoGroup(iv, io) {
		iv = autoStrip(iv, io);
		var empty = checkEmpty(iv, io, true);
		if (empty !== null) {
			return empty;
		}
		var digitalGroup = '';
		if (io.dGroup === 2) {
			digitalGroup = /(\d)((\d)(\d{2}?)+)$/;
		} else if (io.dGroup === 4) {
			digitalGroup = /(\d)((\d{4}?)+)$/;
		} else {
			digitalGroup = /(\d)((\d{3}?)+)$/;
		} /** splits the string at the decimal string */
		var ivSplit = iv.split(io.aDec);
		if (io.altDec && ivSplit.length === 1) {
			ivSplit = iv.split(io.altDec);
		} /** assigns the whole number to the a varibale (s) */
		var s = ivSplit[0];
		if (io.aSep) {
			while (digitalGroup.test(s)) { /**  re-inserts the thousand sepparator via a regualer expression */
				s = s.replace(digitalGroup, '$1' + io.aSep + '$2');
			}
		}
		if (io.mDec !== 0 && ivSplit.length > 1) {
			if (ivSplit[1].length > io.mDec) {
				ivSplit[1] = ivSplit[1].substring(0, io.mDec);
			} /** joins the whole number with the deciaml value */
			iv = s + io.aDec + ivSplit[1];
		} else { /** if whole numers only */
			iv = s;
		}
		if (io.aSign) {
			var has_aNeg = iv.indexOf(io.aNeg) !== -1;
			iv = iv.replace(io.aNeg, '');
			iv = io.pSign === 'p' ? io.aSign + iv : iv + io.aSign;
			if (has_aNeg) {
				iv = io.aNeg + iv;
			}
		}
		return iv;
	}
	/**
	* round number after setting by pasting or $().autoNumericSet()
	* private function for round the number
	* please note this handled as text - Javascript math function can return inaccurate values
	* also this offers multiple rounding metods that are not easily accomplished in javascript
	*/
	function autoRound(iv, mDec, mRound, aPad) { /** value to string */
		iv = (iv === '') ? '0' : iv.toString();
		var ivRounded = '';
		var i = 0;
		var nSign = '';
		var rDec = (typeof (aPad) === 'boolean' || aPad === null) ? (aPad ? mDec : 0) : +aPad;
		var truncateZeros = function (ivRounded) { /** truncate not needed zeros */
			var regex = rDec === 0 ? (/(\.[1-9]*)0*$/) : rDec === 1 ? (/(\.\d[1-9]*)0*$/) : new RegExp('(\\.\\d{' + rDec + '}[1-9]*)0*$');
			ivRounded = ivRounded.replace(regex, '$1'); /** If there are no decimal places, we don't need a decimal point at the end */
			if (rDec === 0) {
				ivRounded = ivRounded.replace(/\.$/, '');
			}
			return ivRounded;
		};
		if (iv.charAt(0) === '-') { /** Checks if the iv (input Value)is a negative value */
			nSign = '-'; /** removes the negative sign will be added back later if required */
			iv = iv.replace('-', '');
		} /** prepend a zero if first character is not a digit (then it is likely to be a dot)*/
		if (!iv.match(/^\d/)) {
			iv = '0' + iv;
		} /** determines if the value is zero - if zero no negative sign */
		if (nSign === '-' && +iv === 0) {
			nSign = '';
		} /** trims leading zero's if needed */
		if ((+iv) > 0) {
			iv = iv.replace(/^0*(\d)/, '$1');
		} /** decimal postion as an integer */
		var dPos = iv.lastIndexOf('.'); /** virtual decimal position */
		var vdPos = dPos === -1 ? iv.length - 1 : dPos; /** checks decimal places to determine if rounding is required */
		var cDec = (iv.length - 1) - vdPos; /** check if no rounding is required */
		if (cDec <= mDec) {
			ivRounded = iv; /** check if we need to pad with zeros */
			if (cDec < rDec) {
				if (dPos === -1) {
					ivRounded += '.';
				}
				while (cDec < rDec) {
					var zeros = '000000'.substring(0, rDec - cDec);
					ivRounded += zeros;
					cDec += zeros.length;
				}
			} else if (cDec > rDec) {
				ivRounded = truncateZeros(ivRounded);
			} else if (cDec === 0 && rDec === 0) {
				ivRounded = ivRounded.replace(/\.$/, '');
			}
			return nSign + ivRounded;
		} /** rounded length of the string after rounding  */
		var rLength = dPos + mDec; /** test round */
		var tRound = +iv.charAt(rLength + 1);
		var ivArray = iv.substring(0, rLength + 1).split('');
		var odd = (iv.charAt(rLength) === '.') ? (iv.charAt(rLength - 1) % 2) : (iv.charAt(rLength) % 2);
		if ((tRound > 4 && mRound === 'S') || (tRound > 4 && mRound === 'A' && nSign === '') || (tRound > 5 && mRound === 'A' && nSign === '-') || (tRound > 5 && mRound === 's') || (tRound > 5 && mRound === 'a' && nSign === '') || (tRound > 4 && mRound === 'a' && nSign === '-') || (tRound > 5 && mRound === 'B') || (tRound === 5 && mRound === 'B' && odd === 1) || (tRound > 0 && mRound === 'C' && nSign === '') || (tRound > 0 && mRound === 'F' && nSign === '-') || (tRound > 0 && mRound === 'U')) {
			/** Round up the last digit if required, and continue until no more 9's are found */
			for (i = (ivArray.length - 1); i >= 0; i -= 1) {
				if (ivArray[i] !== '.') {
					ivArray[i] = +ivArray[i] + 1;
					if (ivArray[i] < 10) {
						break;
					} else if (i > 0) {
						ivArray[i] = '0';
					}
				}
			}
		} /** Reconstruct the string, converting any 10's to 0's */
		ivArray = ivArray.slice(0, rLength + 1);
		ivRounded = truncateZeros(ivArray.join('')); /** return rounded value */
		return nSign + ivRounded;
	}
	/**
	* Holder object for field properties
	*/
	function autoNumericHolder(that, options) {
		this.options = options;
		this.that = that;
		this.$that = $(that);
		this.formatted = false;
		this.io = autoCode(this.$that, this.options);
		this.value = that.value;
	}
	autoNumericHolder.prototype = {
		init: function (e) {
			this.value = this.that.value;
			this.io = autoCode(this.$that, this.options);
			this.ctrlKey = e.ctrlKey;
			this.cmdKey = e.metaKey;
			this.shiftKey = e.shiftKey;
			this.selection = getElementSelection(this.that); /** keypress event overwrites meaningfull value of e.keyCode */
			if (e.type === 'keydown' || e.type === 'keyup') {
				this.kdCode = e.keyCode;
			}
			this.which = e.which;
			this.processed = false;
			this.formatted = false;
		},
		setSelection: function (start, end, setReal) {
			start = Math.max(start, 0);
			end = Math.min(end, this.that.value.length);
			this.selection = {
				start: start,
				end: end,
				length: end - start
			};
			if (setReal === undefined || setReal) {
				setElementSelection(this.that, start, end);
			}
		},
		setPosition: function (pos, setReal) {
			this.setSelection(pos, pos, setReal);
		},
		getBeforeAfter: function () {
			var value = this.value;
			var left = value.substring(0, this.selection.start);
			var right = value.substring(this.selection.end, value.length);
			return [left, right];
		},
		getBeforeAfterStriped: function () {
			var parts = this.getBeforeAfter();
			parts[0] = autoStrip(parts[0], this.io);
			parts[1] = autoStrip(parts[1], this.io);
			return parts;
		},
		/**
		* strip parts from excess characters and leading zeroes
		*/
		normalizeParts: function (left, right) {
			var io = this.io;
			right = autoStrip(right, io); /** if right is not empty and first character is not aDec, */
			/** we could strip all zeros, otherwise only leading */
			var strip = right.match(/^\d/) ? true : 'leading';
			left = autoStrip(left, io, strip); /** strip leading zeros from right part if left part has no digits */
			if ((left === '' || left === io.aNeg)) {
				if (right > '') {
					right = right.replace(/^0*(\d)/, '$1');
				}
			}
			var new_value = left + right; /** insert zero if has leading dot */
			if (io.aDec) {
				var m = new_value.match(new RegExp('^' + io._aNegReg + '\\' + io.aDec));
				if (m) {
					left = left.replace(m[1], m[1] + '0');
					new_value = left + right;
				}
			} /** insert zero if number is empty and io.wEmpty == 'zero' */
			if (io.wEmpty === 'zero' && (new_value === io.aNeg || new_value === '')) {
				left += '0';
			}
			return [left, right];
		},
		/**
		* set part of number to value keeping position of cursor
		*/
		setValueParts: function (left, right) {
			var io = this.io;
			var parts = this.normalizeParts(left, right);
			var new_value = parts.join('');
			var position = parts[0].length;
			if (autoCheck(new_value, io)) {
				new_value = truncateDecimal(new_value, io.aDec, io.mDec);
				if (position > new_value.length) {
					position = new_value.length;
				}
				this.value = new_value;
				this.setPosition(position, false);
				return true;
			}
			return false;
		},
		/**
		* helper function for expandSelectionOnSign
		* returns sign position of a formatted value
		*/
		signPosition: function () {
			var io = this.io, aSign = io.aSign, that = this.that;
			if (aSign) {
				var aSignLen = aSign.length;
				if (io.pSign === 'p') {
					var hasNeg = io.aNeg && that.value && that.value.charAt(0) === io.aNeg;
					return hasNeg ? [1, aSignLen + 1] : [0, aSignLen];
				} else {
					var valueLen = that.value.length;
					return [valueLen - aSignLen, valueLen];
				}
			} else {
				return [1000, -1];
			}
		},
		/**
		* expands selection to cover whole sign
		* prevents partial deletion/copying/overwritting of a sign
		*/
		expandSelectionOnSign: function (setReal) {
			var sign_position = this.signPosition();
			var selection = this.selection;
			if (selection.start < sign_position[1] && selection.end > sign_position[0]) { /** if selection catches something except sign and catches only space from sign */
				if ((selection.start < sign_position[0] || selection.end > sign_position[1]) && this.value.substring(Math.max(selection.start, sign_position[0]), Math.min(selection.end, sign_position[1])).match(/^\s*$/)) { /** then select without empty space */
					if (selection.start < sign_position[0]) {
						this.setSelection(selection.start, sign_position[0], setReal);
					} else {
						this.setSelection(sign_position[1], selection.end, setReal);
					}
				} else { /** else select with whole sign */
					this.setSelection(Math.min(selection.start, sign_position[0]), Math.max(selection.end, sign_position[1]), setReal);
				}
			}
		},
		/**
		* try to strip pasted value to digits
		*/
		checkPaste: function () {
			if (this.valuePartsBeforePaste !== undefined) {
				var parts = this.getBeforeAfter();
				var oldParts = this.valuePartsBeforePaste;
				delete this.valuePartsBeforePaste; /* try to strip pasted value first */
				parts[0] = parts[0].substr(0, oldParts[0].length) + autoStrip(parts[0].substr(oldParts[0].length), this.io);
				if (!this.setValueParts(parts[0], parts[1])) {
					this.value = oldParts.join('');
					this.setPosition(oldParts[0].length, false);
				}
			}
		},
		/**
		* process pasting, cursor moving and skipping of not interesting keys
		* if returns true, futher processing is not performed
		*/
		skipAllways: function (e) {
			var kdCode = this.kdCode, which = this.which, ctrlKey = this.ctrlKey, cmdKey = this.cmdKey; /** catch the ctrl up on ctrl-v */
			if (kdCode === 17 && e.type === 'keyup' && this.valuePartsBeforePaste !== undefined) {
				this.checkPaste();
				return false;
			}
			/** codes are taken from http://www.cambiaresearch.com/c4/702b8cd1-e5b0-42e6-83ac-25f0306e3e25/Javascript-Char-Codes-Key-Codes.aspx
			* skip Fx keys, windows keys, other special keys */
			if ((kdCode >= 112 && kdCode <= 123) || (kdCode >= 91 && kdCode <= 93) || (kdCode >= 9 && kdCode <= 31) || (kdCode < 8 && (which === 0 || which === kdCode)) || kdCode === 144 || kdCode === 145 || kdCode === 45) {
				return true;
			} /** if select all (a=65)*/
			if ((ctrlKey || cmdKey) && kdCode === 65) {
				return true;
			} /** if copy (c=67) paste (v=86) or cut (x=88) */
			if ((ctrlKey || cmdKey) && (kdCode === 67 || kdCode === 86 || kdCode === 88)) { /** replace or cut whole sign */
				if (e.type === 'keydown') {
					this.expandSelectionOnSign();
				} /** try to prevent wrong paste */
				if (kdCode === 86) {
					if (e.type === 'keydown' || e.type === 'keypress') {
						if (this.valuePartsBeforePaste === undefined) {
							this.valuePartsBeforePaste = this.getBeforeAfter();
						}
					} else {
						this.checkPaste();
					}
				}
				return e.type === 'keydown' || e.type === 'keypress' || kdCode === 67;
			}
			if (ctrlKey || cmdKey) {
				return true;
			}
			if (kdCode === 37 || kdCode === 39) { /** jump over thousand separator */
				var aSep = this.io.aSep, start = this.selection.start, value = this.that.value;
				if (e.type === 'keydown' && aSep && !this.shiftKey) {
					if (kdCode === 37 && value.charAt(start - 2) === aSep) {
						this.setPosition(start - 1);
					} else if (kdCode === 39 && value.charAt(start) === aSep) {
						this.setPosition(start + 1);
					}
				}
				return true;
			}
			if (kdCode >= 34 && kdCode <= 40) {
				return true;
			}
			return false;
		},
		/**
		* process deletion of characters alert
		* returns true if processing performed
		*/
		processAllways: function () {
			var parts; /** process backspace or delete */
			if (this.kdCode === 8 || this.kdCode === 46) {
				if (!this.selection.length) {
					parts = this.getBeforeAfterStriped();
					if (this.kdCode === 8) {
						parts[0] = parts[0].substring(0, parts[0].length - 1);
					} else {
						parts[1] = parts[1].substring(1, parts[1].length);
					}
					this.setValueParts(parts[0], parts[1]);
				} else {
					this.expandSelectionOnSign(false);
					parts = this.getBeforeAfterStriped();
					this.setValueParts(parts[0], parts[1]);
				}
				return true;
			}
			return false;
		},
		/**
		* process insertion of characters
		* returns true if processing performed
		*/
		processKeypress: function () {
			var io = this.io;
			var cCode = String.fromCharCode(this.which);
			var parts = this.getBeforeAfterStriped();
			var left = parts[0], right = parts[1]; /** start rules when the decimal charactor key is pressed */
			/** always use numeric pad dot to insert decimal separator */
			if (cCode === io.aDec || (io.altDec && cCode === io.altDec) || ((cCode === '.' || cCode === ',') && this.kdCode === 110)) { /** do not allow decimal character if no decimal part allowed */
				if (!io.mDec || !io.aDec) {
					return true;
				} /** do not allow decimal character before aNeg character */
				if (io.aNeg && right.indexOf(io.aNeg) > -1) {
					return true;
				} /** do not allow decimal character if other decimal character present */
				if (left.indexOf(io.aDec) > -1) {
					return true;
				}
				if (right.indexOf(io.aDec) > 0) {
					return true;
				}
				if (right.indexOf(io.aDec) === 0) {
					right = right.substr(1);
				}
				this.setValueParts(left + io.aDec, right);
				return true;
			} /** start rule on negative sign */
			if (cCode === '-' || cCode === '+') { /** prevent minus if not allowed */
				if (!io.aNeg) {
					return true;
				} /** carret is always after minus */
				if (left === '' && right.indexOf(io.aNeg) > -1) {
					left = io.aNeg;
					right = right.substring(1, right.length);
				} /** change sign of number, remove part if should */
				if (left.charAt(0) === io.aNeg) {
					left = left.substring(1, left.length);
				} else {
					left = (cCode === '-') ? io.aNeg + left : left;
				}
				this.setValueParts(left, right);
				return true;
			} /** digits */
			if (cCode >= '0' && cCode <= '9') { /** if try to insert digit before minus */
				if (io.aNeg && left === '' && right.indexOf(io.aNeg) > -1) {
					left = io.aNeg;
					right = right.substring(1, right.length);
				}
				this.setValueParts(left + cCode, right);
				return true;
			} /** prevent any other character */
			return true;
		},
		/**
		* formatting of just processed value with keeping of cursor position
		*/
		formatQuick: function () {
			var io = this.io;
			var parts = this.getBeforeAfterStriped();
			var value = autoGroup(this.value, this.io);
			var position = value.length;
			if (value) {
				/** prepare regexp which searches for cursor position from unformatted left part */
				var left_ar = parts[0].split('');
				var i;
				for (i = 0; i < left_ar.length; i += 1) { /** thanks Peter Kovari */
					if (!left_ar[i].match('\\d')) {
						left_ar[i] = '\\' + left_ar[i];
					}
				}
				var leftReg = new RegExp('^.*?' + left_ar.join('.*?'));
				/** search cursor position in formatted value */
				var newLeft = value.match(leftReg);
				if (newLeft) {
					position = newLeft[0].length;
					/** if we are just before sign which is in prefix position */
					if (((position === 0 && value.charAt(0) !== io.aNeg) || (position === 1 && value.charAt(0) === io.aNeg)) && io.aSign && io.pSign === 'p') {
						/** place carret after prefix sign */
						position = this.io.aSign.length + (value.charAt(0) === '-' ? 1 : 0);
					}
				} else if (io.aSign && io.pSign === 's') {
					/** if we could not find a place for cursor and have a sign as a suffix */
					/** place carret before suffix currency sign */
					position -= io.aSign.length;
				}
			}
			this.that.value = value;
			this.setPosition(position);
			this.formatted = true;
		}
	};
	function getData($that) {
		var data = $that.data('autoNumeric');
		if (!data) {
			data = {};
			$that.data('autoNumeric', data);
		}
		return data;
	}
	function getHolder($that, options) {
		var data = getData($that);
		var holder = data.holder;
		if (holder === undefined && options) {
			holder = new autoNumericHolder($that.get(0), options);
			data.holder = holder;
		}
		return holder;
	}
	function getOptions($that) {
		var data = $that.data('autoNumeric');
		if (data && data.holder) {
			return data.holder.options;
		}
		return {};
	}
	function onInit(options) {
		options = options || {};
		var iv = $(this), holder = getHolder(iv, options);
		if (holder.io.aForm && (this.value || holder.io.wEmpty !== 'empty')) {
			iv.autoNumericSet(iv.autoNumericGet(options), options);
		}
	}
	function onKeyDown(e) {
		var iv = $(e.target), holder = getHolder(iv);
		holder.init(e);
		if (holder.skipAllways(e)) {
			holder.processed = true;
			return true;
		}
		if (holder.processAllways()) {
			holder.processed = true;
			holder.formatQuick();
			e.preventDefault();
			return false;
		} else {
			holder.formatted = false;
		}
		return true;
	}
	function onKeyPress(e) {
		var iv = $(e.target), holder = getHolder(iv);
		var processed = holder.processed;
		holder.init(e);
		if (holder.skipAllways(e)) {
			return true;
		}
		if (processed) {
			e.preventDefault();
			return false;
		}
		if (holder.processAllways() || holder.processKeypress()) {
			holder.formatQuick();
			e.preventDefault();
			return false;
		} else {
			holder.formatted = false;
		}
	}
	function onKeyUp(e) {
		var iv = $(e.target), holder = getHolder(iv);
		holder.init(e);
		var skip = holder.skipAllways(e);
		holder.kdCode = 0;
		delete holder.valuePartsBeforePaste;
		if (skip) {
			return true;
		}
		if (this.value === '') {
			return true;
		}
		if (!holder.formatted) {
			holder.formatQuick();
		}
	}
	function onFocusIn(e) {
		var iv = $(e.target), holder = getHolder(iv);
		holder.inVal = iv.val();
		var onempty = checkEmpty(holder.inVal, holder.io, true);
		if (onempty !== null) {
			iv.val(onempty);
		}
	}
	/** start change - thanks to Javier P. corrected the inline onChange event  added focusout version 1.55*/
	function onFocusOut(e) {
		var iv = $(e.target), holder = getHolder(iv);
		var io = holder.io, value = iv.val(), origValue = value;
		if (value !== '') {
			value = autoStrip(value, io);
			if (checkEmpty(value, io) === null && autoCheck(value, io)) {
				value = fixNumber(value, io.aDec, io.aNeg);
				value = autoRound(value, io.mDec, io.mRound, io.aPad);
				value = presentNumber(value, io.aDec, io.aNeg);
			} else {
				value = '';
			}
		}
		var groupedValue = checkEmpty(value, io, false);
		if (groupedValue === null) {
			groupedValue = autoGroup(value, io);
		}
		if (groupedValue !== origValue) {
			iv.val(groupedValue);
		}
		if (groupedValue !== holder.inVal) {
			iv.change();
			delete holder.inVal;
		}
	}
	$.fn.autoNumeric = function (options) {
		return this.each(function () {
			onInit.call(this, options);
		}).unbind('.autoNumeric').bind({
			'keydown.autoNumeric': onKeyDown,
			'keypress.autoNumeric': onKeyPress,
			'keyup.autoNumeric': onKeyUp,
			'focusin.autoNumeric': onFocusIn,
			'focusout.autoNumeric': onFocusOut
		});
	};
	/** thanks to Anthony & Evan C */
    function autoGet(obj) {
		if (typeof (obj) === 'string') {
			obj = obj.replace(/\[/g, "\\[").replace(/\]/g, "\\]");
			obj = '#' + obj.replace(/(:|\.)/g, '\\$1');
		}
		return $(obj);
	}
	$.autoNumeric = {};
	/**
	* public function that stripes the format and converts decimal seperator to a period
	* as of 1.7.2 `options` argument is deprecated, options are taken from initializer
	*/
	$.autoNumeric.Strip = function (ii) {
		var $that = autoGet(ii);
		var options = getOptions($that);
		if (arguments[1] && typeof (arguments[1]) === 'object') {
			options = $.extend({}, options, arguments[1]);
		}
		var io = autoCode($that, options);
		var iv = autoGet(ii).val();
		iv = autoStrip(iv, io);
		iv = fixNumber(iv, io.aDec, io.aNeg);
		if (+iv === 0) {
			iv = '0';
		}
		return iv;
	};
	/**
	* public function that recieves a numeric string and formats to the target input field
	* as of 1.7.2 `options` argument is deprecated, options are taken from initializer
	*/
	$.autoNumeric.Format = function (ii, iv) {
		var $that = autoGet(ii);
		var options = getOptions($that);
		if (arguments[2] && typeof (arguments[2]) === 'object') {
			options = $.extend({}, options, arguments[2]);
		}
		iv.toString();
		var io = autoCode($that, options);
		iv = autoRound(iv, io.mDec, io.mRound, io.aPad);
		iv = presentNumber(iv, io.aDec, io.aNeg);
		if (!autoCheck(iv, io)) {
			iv = autoRound('', io.mDec, io.mRound, io.aPad);
		}
		return autoGroup(iv, io);
	};
	/**
	* get a number (as a number) from a field.
	* as of 1.7.2 argument is deprecated, options are taken from initializer
	* $('input#my').autoNumericGet()
	*/
	$.fn.autoNumericGet = function () {
		if (arguments[0]) {
			return $.autoNumeric.Strip(this, arguments[0]);
		}
		return $.autoNumeric.Strip(this);
	};
	/**
	* set a number to a field, formatting it appropriatly
	* as of 1.7.2 second argument is deprecated, options are taken from initializer
	* $('input#my').autoNumericSet(2.423)
	*/
	$.fn.autoNumericSet = function (iv) {
		if (arguments[1]) {
			return this.val($.autoNumeric.Format(this, iv, arguments[1]));
		}
		return this.val($.fn.autoNumeric.Format(this, iv));
	};
	/**
	* plugin defaults
	*/
	$.autoNumeric.defaults = {
		/**  allowed  numeric values
		* please do not modify
		*/
		aNum: '0123456789',
		/** allowed thousand separator characters
		* comma = ','
		* period "full stop" = '.'
		* apostrophe is escaped = '\''
		* space = ' '
		* none = ''
		* NOTE: do not use numeric characters
		*/
		aSep: ',',
		/** digital grouping for the thousand separator used in Format
		* dGroup: '2', results in 99,99,99,999 common in India
		* dGroup: '3', results in 999,999,999 default
		* dGroup: '4', results in 9999,9999,9999 used in some Asian countries
		*/
		dGroup: '3',
		/** allowed decimal separator characters
		* period "full stop" = '.'
		* comma = ','
		*/
		aDec: '.',
		/** allow to declare alternative decimal separator which is automatically replaced by aDec
		* developed for countries the use a comma ',' as the decimal character
		* and have keyboards\numeric pads that have a period 'full stop' as the decimal characters (Spain is an example)
		*/
		altDec: null,
		/** allowed currency symbol
		* Must be in quotes aSign: '$',
		*/
		aSign: '',
		/** placement of currency sign
		* for prefix  pSign: 'p',
		* for suffix pSign: 's',
		*/
		pSign: 'p',
		/** maximum possible value
		* value must be enclosed in quotes and use the period for the decimal point
		* value must be larger than vMin
		*/
		vMax: '999999999.99',
		/** minimum possible value
		* value must be enclosed in quotes and use the period for the decimal point
		* value must be smaller than vMax
		*/
		vMin: '0.00',
		/** max number of decimal places = used to overide deciaml places set by the vMin & vMax values
		* value must be enclosed in quotes example mDec: '3',
		* This can also set the value via a call back function mDec: 'css:#
		*/
		mDec: null,
		/** method used for rounding
		* mRound: 'S', Round-Half-Up Symmetric (default)
		* mRound: 'A', Round-Half-Up Asymmetric
		* mRound: 's', Round-Half-Down Symmetric (lower case s)
		* mRound: 'a', Round-Half-Down Asymmetric (lower case a)
		* mRound: 'B', Round-Half-Even "Bankers Rounding"
		* mRound: 'U', Round Up "Round-Away-From-Zero"
		* mRound: 'D', Round Down "Round-Toward-Zero" - same as trancate
		* mRound: 'C', Round to Ceiling "Toward Positive Infinity"
		* mRound: 'F', Round to Floor "Toward Negative Infinity"
		*/
		mRound: 'S',
		/** controls decimal padding
		* aPad: true - always Pad decimals with zeros
		* aPad: false - does not pad with zeros.
		* aPad: `some number` - pad decimals with zero to number different from mDec
		* thanks to Jonas Johansson for the suggestion
		*/
		aPad: true,
		/** Displayed on empty string
		* wEmpty: 'empty', - input can be blank
		* wEmpty: 'zero', - displays zero
		* wEmpty: 'sign', - displays the currency sign
		*/
		wEmpty: 'empty',
		/** atomatically format value "###########.##" in form
		* Please note this is a little buggy due to how each browser handles refresh
		* use with caution
		*/
		aForm: false
	}; /** deprecated way to access defaults and helper functions */
	$.fn.autoNumeric.defaults = $.autoNumeric.defaults;
	$.fn.autoNumeric.Strip = $.autoNumeric.Strip;
	$.fn.autoNumeric.Format = $.autoNumeric.Format;
})(jQuery);