Wednesday, February 1, 2012

Full Calendar with JSON data source using asp.net web service/ pagemethod/ webmethod

In this blog post we are going to discuss using full calendar plugin with JSON data source through asp.net webservice / pagemethod / webmethod. We can get the detail of the plugin here.

For using this plugin we need to add the reference of the following files-
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js" type="text/javascript"></script>
    <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.6/jquery-ui.min.js" type="text/javascript"></script>
    <link rel='stylesheet' type='text/css' href='http://arshaw.com/js/fullcalendar-1.5.2/fullcalendar/fullcalendar.css' />
    <script type='text/javascript' src='http://arshaw.com/js/fullcalendar-1.5.2/jquery/jquery-ui-1.8.11.custom.min.js'></script>
    <script type='text/javascript' src='http://arshaw.com/js/fullcalendar-1.5.2/fullcalendar/fullcalendar.min.js'></script>
Basic style HTML infrastructure using for this implementation is as follows-
        #loading
        {
            width: 600px;
            height: 550px;
            position: absolute;
            background-color: gray;
            color: white;
            text-align: center;
            vertical-align: middle;
            display: table-cell;
        }
        #fullcal
        {
            width: 600px;
            height: 600px;
            position: absolute;
            display: none;
        }
    <div>
        <div id="loading">
            <label style="top: 50%; position: relative">
                loading events....</label>
        </div>
        <div id="fullcal">
        </div>
    </div>
In the div with id fullcal we will be loading the calendar control. By default this div is marked as hidden, and a place holder div (with id loading) is added in the place. This is just to show while server data is getting loaded from server. Once the data is loaded on the calendar we will show back the calendar and hide the placeholder.

The script used for activating calendar is as follows-
    $('div[id*=fullcal]').fullCalendar({
        header: {
            left: 'prev,next today',
            center: 'title',
            right: 'month,agendaWeek,agendaDay'
        },
        editable: true,
        events: list of event here
    });
Now in full calendar the event object has lots of information. We can get more information about the event object here. Lets represent the event as a C# class as follows-
public class Event
{
    public int EventID { get; set; }
    public string EventName { get; set; }
    public string StartDate { get; set; }
    public string EndDate { get; set; }
}
There are many other properties for the event object. For the sack of implementation we are taking these only. And I think the class properties are self explanatory. We can get the data for the event from database. For this post we are creating in memory object for data source. The page method used for data retrieval is as follows-
   [WebMethod]
    public List GetEvents()
    {
        List events = new List();
        events.Add(new Event()
        {
            EventID = 1,
            EventName = "EventName 1",
            StartDate = DateTime.Now.ToString("MM-dd-yyyy"),
            EndDate = DateTime.Now.AddDays(2).ToString("MM-dd-yyyy")
        });
        events.Add(new Event()
        {
            EventID = 2,
            EventName = "EventName 2",
            StartDate = DateTime.Now.AddDays(4).ToString("MM-dd-yyyy"),
            EndDate = DateTime.Now.AddDays(5).ToString("MM-dd-yyyy")
        });
        events.Add(new Event()
        {
            EventID = 3,
            EventName = "EventName 3",
            StartDate = DateTime.Now.AddDays(10).ToString("MM-dd-yyyy"),
            EndDate = DateTime.Now.AddDays(11).ToString("MM-dd-yyyy")
        });
        events.Add(new Event()
        {
            EventID = 4,
            EventName = "EventName 4",
            StartDate = DateTime.Now.AddDays(22).ToString("MM-dd-yyyy"),
            EndDate = DateTime.Now.AddDays(25).ToString("MM-dd-yyyy")
        });
        return events;
    }
Now we can read the web service data using jQuery and fill the full calendar using server driven event list like following-
    $.ajax({
        type: "POST",
        contentType: "application/json",
        data: "{}",
        url: "FullcalenderwithWebservice.asmx/GetEvents",
        dataType: "json",
        success: function(data) {
            $('div[id*=fullcal]').fullCalendar({
                header: {
                    left: 'prev,next today',
                    center: 'title',
                    right: 'month,agendaWeek,agendaDay'
                },
                editable: true,
                events: data.d
     });
            $("div[id=loading]").hide();
            $("div[id=fullcal]").show();
        },
        error: function(XMLHttpRequest, textStatus, errorThrown) {
            debugger;
        }
    });
Now here is a slight problem, the calendar will get loaded but not the list of events returned. Few points we need to remember here-
  1.  The full calendar event object has certain naming like EventID should be id, EventName – title, StartDate – start, EndDate – end and so on. So, we have to map the returned object to full calendar’s desired object.
  2. One more thing that we need to remember is that the start and end need to be in date type. The proper conversation is as follows-
    $('div[id*=fullcal]').fullCalendar({
        header: {
            left: 'prev,next today',
            center: 'title',
            right: 'month,agendaWeek,agendaDay'
        },
        editable: true,
        events: $.map(data.d, function(item, i) {
                    var event = new Object();
                    event.id = item.EventID;
                    event.start = new Date(item.StartDate);
                    event.end = new Date(item.EndDate);
                    event.title = item.EventName;
                    return event;
                })
    });
We can note one more thing that we are returning the date in MM-dd-yyyy format (DateTime.Now.ToString("MM-dd-yyyy")). The reason is that we can pass such a string to Date constructor in JavaScript to create the date.

We can download the full source code from here.

Sunday, January 22, 2012

POST complex data to pagemethod or webservice using jQuery

In many occasion we need to post some complex data like class (object), array, list of objects to pagemethod, webmethod or web service. I have answered many such posts in asp.net forum. So, decided to list few posts here-

http://forums.asp.net/p/1688559/4454363.aspx/1?Re+Post+array+of+array+of+html+form. This post is used to post generic list of a class objects where the UI is represented as UL, LI. Each LI has a checkbox, a hidden filed and an input box. The underlying structure of the class is as-
public class ComplexData {
    public int id { get; set; }
    public bool flag { get; set; }
    public string note { get; set; }
}
http://forums.asp.net/p/1709268/4549152.aspx/1?Re+how+to+save+data+using+jquery+ajex. This post is used to post name id based class where the UI is represented as HTML table. The class structure is as-
public class NameIDData
{
    public int id { get; set; }
    public string name { get; set; }
}
http://forums.asp.net/p/1690207/4462756.aspx/1?Re+Problem+with+charset+ajax+request. This post is used to post a class which contains non English characters. The class structure is as-
public class PersonClass
{
    public Guid Userid { get; set; }
    public string Firstname { get; set; }
    public string Lastname { get; set; }
    public string Username { get; set; }
}
And input sample data is as-
            var jsonString = { "Userid": "eec756aa-56e0-4515-b3bb-70b6c31b3d8a",
                "Firstname": "сркшы",
                "Lastname": "сркшы",
                "Username": "russiantest"
            };
http://forums.asp.net/p/1694914/4482943.aspx/1?Re+Getting+form+Values+. This post is used to post some complex data with parent child relationship. The UI is little complex with field set as each row of data. And the content can be added dynamically. The class is represented as-
public class ParentChild
{
    public string Parent { get; set; }
    public string Child { get; set; }
}
http://forums.asp.net/p/1662319/4338617.aspx. This post is used to post a list of object from reading Grid View rows. The class structure goes like-
public class Screening
{
    public string ScreeningPropertyID { get; set; }
    public string ScreeningValue { get; set; }
}
http://forums.asp.net/p/1653108/4303194.aspx#4303194. This post deals with posting a string array to webmethod.

http://forums.asp.net/p/1650626/4292348.aspx#4292348. This post deals with reordering of HTML element and post the reordered list to the webmethod. The class structure goes like below-
public class DivsDetail {
    public int DivID { get; set; }
    public int Order { get; set; }
}

Friday, January 20, 2012

Validation summary popup UI modification

In this post we will discuss how to modify the UI of validation summary with some CSS and jQuery.

Problem
Suppose we have two fields named first name and last name. And we need to implement required field validation. If we use asp.net RequiredFieldValidator and ValidationSummary with ShowMessageBox="true", then we can get the following result if we are not providing any value for the text fields-

Now we know that we cannot modify the message box UI. But if we want to do so-

Solution
If we change the ValidationSummary a little by ShowMessageBox="false" ShowSummary="true" DisplayMode="BulletList", then we get the following UI-

If we check the UI created for the summary we can find the following HTML generated-
    <div style="color: red" id="vsInfo" headertext="Following error occurs:" displaymode="BulletList">
        Following error occurs:
        <ul>
            <li>Provide first name</li>
            <li>Provide last name</li></ul>
    </div>
What we can do is add a little trick here. We can use jQuery dialog to change the UI (I believe that we know how to use jQuery dialog. For reference check here).

The modified code goes here-
    <div id="dialog" style="display:none">
    </div>
    <div class="itemContent">
        <label></label>
        <div class="controls" style="display:none">
           <asp:ValidationSummary ID="vsInfo" runat="server" HeaderText="Following error occurs:"
                ShowMessageBox="false" ShowSummary="true" DisplayMode="BulletList"  />
        </div> 
    </div>   
    <script type="text/javascript">
        $(document).ready(function() {
            $("#btnSaveInfo").click(function() {
                document.TimeID = setTimeout("checkMessage()", 5);
            });
        });
        function checkMessage() {
            if ($("div#vsInfo").length > 0) {
                $("#dialog").empty();
                $("#dialog").append($("div#vsInfo UL"));
                $("#dialog").dialog({
                    title: $("div#vsInfo").text(), 
                    close: function(event, ui) {
                        clearTimeout(document.TimeID);
                    }
                });
                clearTimeout(document.TimeID);
            }
            else 
                document.TimeID = setTimeout("checkMessage()", 5);
            
        }
    </script>
What we are doing here is binding the click event to the save button, in the button click we are calling a function named checkMessage() periodically after every 5 milliseconds and checking whether a div with id vsInfo exists in the DOM. If exists, then copying the HTML of the ValidationSummary and putting it in the dialog div, opening the dialog and finally clearing the timer. So, final UI looks like-
That’s what we wanted. We can change the UI of the dialog as we need.

Download the code from here.

Wednesday, January 18, 2012

ppGallery - Lightbox Gallery with asp.net repeater

In this post, we will go through implementation of ppgallery image slider plug-in with asp.net repeater control. The plug-in information can be found here for download.

To start with this lets first see how ppgallery works. The basic implementation of goes as follows-
To use the plugin we need to take following file references-
<link href="http://www.ppplugins.com/demo/ppgallery/ppgallery/css/ppgallery.css" rel="stylesheet" type="text/css" />
<link href="http://www.ppplugins.com/demo/ppgallery/ppgallery/css/dark-hive/jquery-ui-1.8.6.custom.css" rel="stylesheet" type="text/css" />

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.6/jquery-ui.min.js"></script> 
<script type="text/javascript" src="http://www.ppplugins.com/demo/ppgallery/ppgallery/js/ppgallery.js"></script> 
We can download the CSS and JS file to your local system and take the reference from locally.
The HTML structure of the plug-in should be like this-
<ul id="gallery">
  <li><a href="big image URL" title="Title"><img src="Thumbnail URL"></a></li>
  <li><a href="big image URL" title="Title"><img src="Thumbnail URL"></a></li>
.
.
.
.
</ul>
For example-
<ul id="gallery">
  <li><a href="http://ppplugins.com/demo/ppgallery/images/l_01.jpg" title="Example of a title goes here."><img src="http://ppplugins.com/demo/ppgallery/images/s_01.jpg"></a></li>
  <li><a href="http://ppplugins.com/demo/ppgallery/images/l_02.jpg" title="Example of a title goes here."><img src="http://ppplugins.com/demo/ppgallery/images/s_02.jpg"></a></li>
  <li><a href="http://ppplugins.com/demo/ppgallery/images/l_03.jpg" title="Example of a title goes here."><img src="http://ppplugins.com/demo/ppgallery/images/s_03.jpg"></a></li>
  <li><a href="http://ppplugins.com/demo/ppgallery/images/l_28.jpg" title="Thanks for visiting PP Plugins"><img src="http://ppplugins.com/demo/ppgallery/images/s_28.jpg"></a></li>
</ul>
And we can implement the plug-in by calling the following script-
<script type="text/javascript">
$(document).ready(function() {
 $('#gallery').ppGallery();
});
</script>
Now we can integrate the image HTML in a repeater. And the code goes below-
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<link href="http://www.ppplugins.com/demo/ppgallery/ppgallery/css/ppgallery.css" rel="stylesheet" type="text/css" />
<link href="http://www.ppplugins.com/demo/ppgallery/ppgallery/css/dark-hive/jquery-ui-1.8.6.custom.css" rel="stylesheet" type="text/css" />

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.6/jquery-ui.min.js"></script> 
<script type="text/javascript" src="http://www.ppplugins.com/demo/ppgallery/ppgallery/js/ppgallery.js"></script> 
<script type="text/javascript">
$(document).ready(function() {
        $('#gallery').ppGallery();
});
</script>
</head>
<body>
    <form id="form1" runat="server">
    <asp:Repeater ID="Repeater1" runat="server">
        <HeaderTemplate>
            <ul id="gallery">
        </HeaderTemplate>
        <ItemTemplate>
            <li><a href='<%#Eval("URL") %>' title='<%#Eval("Title") %>'>
                <img src='<%#Eval("Thumb") %>'></a></li>
        </ItemTemplate>
        <FooterTemplate>
            </ul>
        </FooterTemplate>
    </asp:Repeater>
    </form>
</body>
</html>
    protected void Page_Load(object sender, EventArgs e)
    {
        var imageDataSource = (new[] { new { URL = "http://ppplugins.com/demo/ppgallery/images/l_01.jpg", 
                                    Thumb = "http://ppplugins.com/demo/ppgallery/images/s_01.jpg" Title= "Title 1"} }).ToList();
        imageDataSource.Add(new {URL = "http://ppplugins.com/demo/ppgallery/images/l_02.jpg", Thumb = "http://ppplugins.com/demo/ppgallery/images/s_02.jpg" Title= "Title 2"});
        imageDataSource.Add(new { URL = "http://ppplugins.com/demo/ppgallery/images/l_03.jpg", Thumb = "http://ppplugins.com/demo/ppgallery/images/s_03.jpg" Title= "Title 3" });
        imageDataSource.Add(new { URL = "http://ppplugins.com/demo/ppgallery/images/l_04.jpg", Thumb = "http://ppplugins.com/demo/ppgallery/images/s_04.jpg" Title= "Title 4" });
        imageDataSource.Add(new { URL = "http://ppplugins.com/demo/ppgallery/images/l_05.jpg", Thumb = "http://ppplugins.com/demo/ppgallery/images/s_05.jpg" Title= "Title 5" });
        imageDataSource.Add(new { URL = "http://ppplugins.com/demo/ppgallery/images/l_06.jpg", Thumb = "http://ppplugins.com/demo/ppgallery/images/s_06.jpg" Title= "Title 6" });
        imageDataSource.Add(new { URL = "http://ppplugins.com/demo/ppgallery/images/l_19.jpg", Thumb = "http://ppplugins.com/demo/ppgallery/images/s_19.jpg" Title= "Title 7" });
        imageDataSource.Add(new { URL = "http://ppplugins.com/demo/ppgallery/images/l_20.jpg", Thumb = "http://ppplugins.com/demo/ppgallery/images/s_20.jpg" Title= "Title 8" });
        imageDataSource.Add(new { URL = "http://ppplugins.com/demo/ppgallery/images/l_21.jpg", Thumb = "http://ppplugins.com/demo/ppgallery/images/s_21.jpg" Title= "Title 9" });
        imageDataSource.Add(new { URL = "http://ppplugins.com/demo/ppgallery/images/l_22.jpg", Thumb = "http://ppplugins.com/demo/ppgallery/images/s_22.jpg" Title= "Title 10" });
        imageDataSource.Add(new { URL = "http://ppplugins.com/demo/ppgallery/images/l_23.jpg", Thumb = "http://ppplugins.com/demo/ppgallery/images/s_23.jpg" Title= "Title 11" });
        imageDataSource.Add(new { URL = "http://ppplugins.com/demo/ppgallery/images/l_24.jpg", Thumb = "http://ppplugins.com/demo/ppgallery/images/s_24.jpg" Title= "Title 12" });
        imageDataSource.Add(new { URL = "http://ppplugins.com/demo/ppgallery/images/l_25.jpg", Thumb = "http://ppplugins.com/demo/ppgallery/images/s_25.jpg" Title= "Title 13" });
        imageDataSource.Add(new { URL = "http://ppplugins.com/demo/ppgallery/images/l_26.jpg", Thumb = "http://ppplugins.com/demo/ppgallery/images/s_26.jpg" Title= "Title 14" });
        imageDataSource.Add(new { URL = "http://ppplugins.com/demo/ppgallery/images/l_27.jpg", Thumb = "http://ppplugins.com/demo/ppgallery/images/s_27.jpg" Title= "Title 15" });
        imageDataSource.Add(new { URL = "http://ppplugins.com/demo/ppgallery/images/l_28.jpg", Thumb = "http://ppplugins.com/demo/ppgallery/images/s_28.jpg" Title= "Title 16" });
        Repeater1.DataSource = imageDataSource;
        Repeater1.DataBind(); 
    }
This is an in memory data source. We can replace the data source as we want.

Monday, January 16, 2012

Implement drag drop events from outside in Full Calender for an ajax based data source

Introduction
With this post I will try to describe Full Calender plugin with drag and drop feature where we can drag and drop events from an Ajax based event data source outside the calender. For this to implement we need to know basics about jQuery and full calender plugin. We can get the plugin detail form this URL.

Details goes here-
CSS used in this post goes here-
   <style type='text/css'>
        body
        {
            margin-top: 40px;
            text-align: center;
            font-size: 14px;
            font-family: "Lucida Grande" ,Helvetica,Arial,Verdana,sans-serif;
        }
        #wrap
        {
            width: 1100px;
            margin: 0 auto;
        }
        #external-events
        {
            float: left;
            width: 150px;
            padding: 0 10px;
            border: 1px solid #ccc;
            background: #eee;
            text-align: left;
        }
        #external-events h4
        {
            font-size: 16px;
            margin-top: 0;
            padding-top: 1em;
        }
        .external-event
        {
            margin: 10px 0;
            padding: 2px 4px;
            background: #3366CC;
            color: #fff;
            font-size: .85em;
            cursor: pointer;
        }
        #external-events p
        {
            margin: 1.5em 0;
            font-size: 11px;
            color: #666;
        }
        #external-events p input
        {
            margin: 0;
            vertical-align: middle;
        }
        #calendar
        {
            float: right;
            width: 900px;
        }
    </style>
For this to work we need to take some CSS and JS files as a reference as follows-
    <link rel='stylesheet' type='text/css' href='http://arshaw.com/js/fullcalendar-1.5.2/fullcalendar/fullcalendar.css' />
    <link rel='stylesheet' type='text/css' href='http://arshaw.com/js/fullcalendar-1.5.2/fullcalendar/fullcalendar.print.css'
        media='print' />

    <script type='text/javascript' src='http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.js'></script>

    <script type='text/javascript' src='http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.9/jquery-ui.js'></script>

    <script type='text/javascript' src='http://arshaw.com/js/fullcalendar-1.5.2/fullcalendar/fullcalendar.min.js'></script>
We can implement a full calender in a div like container as follows-
    <div id='calendar'>
    </div>
            $('#calendar').fullCalendar({
                header: {
                    left: 'prev,next today',
                    center: 'title',
                    right: 'month,agendaWeek,agendaDay'
                },
                editable: true,
                droppable: true,
                drop: function(date, allDay) {
                //drop functionality goes here
                }
            });
Now the basic construct for the problem is done. Lets add a div in the page as a container and list all the events on the div using Ajax. We will now implement drag and drop such that we can drag an event form the list of events and add the events to calender by dropping it into the full calender. To list the events in a div using Ajax we can use page method like below-
    <div id='external-events'>
        <h4>
            Draggable Events</h4>
        
        <p id="events">
            <input type='checkbox' id='drop-remove' />
            <label for='drop-remove'>
                remove after drop</label>
        </p>
    </div> 
            $.ajax({
                url: "Fill draggable events area of FullCalendar.aspx/GetEvents",
                type: "POST",
                dataType: "json",
                contentType: "application/json; charset=utf-8",
                success: function(data) {
                    $(data.d).each(function(i, item) {
                        $("#events").before($("<div class='external-event'></div>").html(item.EventName));
                    });
                },
                error: function(XMLHttpRequest, textStatus, errorThrown) {
                    debugger;
                    alert(textStatus);
                }
            });
    [System.Web.Services.WebMethod]
    public static object GetEvents()
    {
        var obj = new { EventName = "My Event 1"};
        var objList = (new[] { obj }).ToList();
        objList.Add(new { EventName = "My Event 2" });
        objList.Add(new { EventName = "My Event 3" });
        objList.Add(new { EventName = "My Event 4" });
        objList.Add(new { EventName = "My Event 5" });
        objList.Add(new { EventName = "My Event 6" });
        objList.Add(new { EventName = "My Event 7" });
        return objList;
    }
In the above code we have some in memory object as event datasource. We can change to any data source as we need.
Now we need to make the event divs, constructed in the above js code, as draggable. We can do this by implementing the draggable UI plugin by modifying the success method of the Ajax call like below-
                success: function(data) {
                    $(data.d).each(function(i, item) {
                        $("#events").before($("<div class='external-event'></div>").html(item.EventName));
                    });
                    $('#external-events div.external-event').each(function() {
                        var eventObject = {
                            title: $.trim($(this).text())
                        };

                        $(this).data('eventObject', eventObject);

                        $(this).draggable({
                            zIndex: 999,
                            revert: true,
                            revertDuration: 0
                        });
                    });
                }
And finally we can implement drop functionality of the full calender plugin to accept the draggable events and we can achieve this by modifying the full calender jquery call as below-
            $('#calendar').fullCalendar({
                header: {
                    left: 'prev,next today',
                    center: 'title',
                    right: 'month,agendaWeek,agendaDay'
                },
                editable: true,
                droppable: true,
                drop: function(date, allDay) {

                    var originalEventObject = $(this).data('eventObject');

                    var copiedEventObject = $.extend({}, originalEventObject);

                    copiedEventObject.start = date;
                    copiedEventObject.allDay = allDay;

                    $('#calendar').fullCalendar('renderEvent', copiedEventObject, true);

                    if ($('#drop-remove').is(':checked')) {
                        $(this).remove();
                    }

                }
            });

Tuesday, December 13, 2011

Modify DOM using jQuery contextMenu and dialog

Introduction
Recently we got a requirement to modify document object model with jQuery context menu  plugin. We could achieve this very easily with jQuery context menu plugin and jQuery dialog.

Details goes here-
For ease let us take a list of divs with some margin, padding and background color. The HTML for this goes here-
    <style>
        div.enableCtx
        {
            width:200px;
            background-color: Gray;
            margin: 5px 5px 5px 5px;
            padding: 5px 5px 5px 5px;
            color:White;
            font-size:15px;
        }
    </style>
    <div class="enableCtx"> data 1</div>
    <div class="enableCtx"> data 2</div>
    <div class="enableCtx"> data 3</div>
    <div class="enableCtx"> data 4</div>
    <div class="enableCtx"> data 5</div>
    <div class="enableCtx"> data 6</div>
    <div class="enableCtx"> data 7</div>
    <div class="enableCtx"> data 8</div>
    <div class="enableCtx"> data 9</div>
The requirement that we are going to implement here is as follows-
  • Use context menu jQuery plugin for this
  • The context menu should have options for add, edit and delete.
  • For adding and editing the data in each div we are going to use jQuery dialog.
  • The add functionality will add a similar div with with the added content next to the current div. 
Now to use contextMenu, we need the necessary JavaScript and CSS files. In this case we can use the following references-
    <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.js" type="text/javascript"></script>

    <script src="http://labs.abeautifulsite.net/archived/jquery-contextMenu/demo/jquery.contextMenu.js"
        type="text/javascript"></script>

    <link href="http://labs.abeautifulsite.net/archived/jquery-contextMenu/demo/jquery.contextMenu.css"
        rel="stylesheet" type="text/css" />
Next we need to create UI for context menu. And it goes like below-
    <ul id="myMenu" class="contextMenu">
        <li class="copy"><a href="#Add">Add</a></li>
        <li class="edit"><a href="#Edit">Edit</a></li>
        <li class="delete"><a href="#Delete">Delete</a></li>
        <li class="quit separator"><a href="#Cancel">Cancel</a></li>
    </ul>
Now we can enable context menu by calling the following JavaScript-
        $(document).ready(function() {
            EnableContext();
        });
        function EnableContext() {
            $("div.enableCtx").contextMenu({
                menu: 'myMenu'
            },
            function(action, el, pos) {
            });
        }
If we notice we can check that the contextMenu takes a function as a second parameter with three attributes called action, el and pos. action stands for what option we have selected from the menu potion. In this case these can be Add, Edit, Delete and Cancel. The value of this is taken from the href value except #. el stands for target element, in our case its one of the div we are right clicking. And the last parameter pos is the coordinate position of the mouse click.

Now what we can do is write a function for each of the operation with exactly the same name as in action and use eval for evaluating the function call. The code goes here-
     <script type="text/javascript">
        $(document).ready(function() {
            EnableContext();
        });
        function EnableContext() {
            $("div.enableCtx").contextMenu({
                menu: 'myMenu'
            },
            function(action, el, pos) {
                eval(action + "(el)");
            });
        }

        function Add(el) {
            //add implementation
        }
        function Edit(el) {
            //edit implementation
        }
        function Delete(el) {
            //delete implementation
        }
        function Cancel(el) {
            //cancel implementation
        }
     </script>
Here is the beauty of eval function. Suppose we have selected Add option from the context menu then it will evaluate the statement Add(el). That means its going to call the add function. Similarly for others.

Next comes the actual implementation of the functions. As we have decided to use jQuery dialog for add and edit purpose. So, we need to setup dialog. Here we are going to take dialog as a div with a text box for editing the content of the selected div. The dialog references and HTML goes here-
     <script src="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.9/jquery-ui.js" type="text/javascript"></script>
     <link href="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.9/themes/redmond/jquery-ui.css" rel="stylesheet" type="text/css" />
    <div style="display:none" id="dialog" title="Add content">
        Enter Text: <nput type="text" id="text" />
   </div>
Add function-
   
        function Add(el) {
            $("#text").val("");
            $("#dialog").dialog({
                model: true,
                buttons: {
                    add: function() {
                        el.after($("<div>").addClass("enableCtx").html($("#text").val()));
                        EnableContext();
                        $(this).dialog("close");
                    }
                }
            });
        }
What we are doing in the add function is setting the textbox inside the dialog to empty, opening the dialog with a button called add. And in the add button click handler we are creating a dynamic div with class enableCtx and adding the content of the div as the textbox value. We are then adding the dynamic div next to the current div(el). We are recalling the EnableContext() function to add the same context behavior to the added div. And finally closing the dialog.

Edit, delete and cancel functions-
 
        function Edit(el) {
            $("#text").val(el.html());
            $("#dialog").dialog({
                model: true,
                buttons: {
                    Edit: function() {
                        el.html($("#text").val());
                        $(this).dialog("close");
                    }
                }
            });
        }
        function Delete(el) {
            el.remove();
        }
        function Cancel(el) {
        }
Edit function is simple, we are first copying the div HTML to textbox inside dialog, replacing the current div(el) HTML with textbox changed value. and closing the dialog.

Delete function is simply removing the current div. And in case of cancel function we need to to implement anything as it will automatically close the context menu.

Source code is here.

Monday, January 24, 2011

Restricting to floating point number onkeypress

Very simple JavaScript code to restrict text box to have floating point number. Code is here-

<!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>
 <title>Untitled Page</title>
 <script type="text/javascript">
     function restrict(val, e) {
         var keyChar;
         if (window.event)
             keyChar = String.fromCharCode(window.event.keyCode);
         else if (e)
             keyChar = String.fromCharCode(e.which);
         else
             return true;
         var number = parseFloat(val + keyChar);
         if (number != val + keyChar)
             return false;
         else
             return true;
     }
</script>
</head>
<body>
 <input name="number" onkeypress="return restrict(this.value, event)">
</body>
</html>