Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

Drag Drop Portal Kickstart

5.00/5 (1 vote)
5 Jun 2009CPOL3 min read 36.5K   690  
A jumpstart tutorial on writing portal websites

Introduction

This tutorial serves as a basis for drag drop functionality, with a push in the direction of portal website development. I kept the code short and simple so it can be implemented in any coding environment.

NOTE!!!: This is not a fully functional portal CMS, just a small working example of drag drop Widget Zone functionality with a push in the right direction towards developing your own portal website.

Background

I worked with many tools for drag drop functionality (mainly not understanding their inner workings) including Telerik RadDock and Dropthings drag drop framework and my aim was to create similar functionality that was not dependant on a server side framework (the above mentioned being dependant on the Microsoft Ajax extensions framework). 

Recently, I found a very good and lightweight example here and found that it was a very good basis to run language independent drag drop interface with a minor change needed to be done in the drag drop script to return me the important values needed, namely (what widget move, to where it moved and into which position it moved). Calling the following function:

JavaScript
<script language="javascript" type="text/javascript">
        function moveWidget(elementid, parentid, index) {
            window.alert("element: " + elementid + " ,parent: " + 
		parentid + " ,index: " + index);
        }    
</script>	

Using the Code 

The script imports in the header are very important to assign drag drop functionality to the columns and the docklets, but primarily you'll be focused on the moveWidget function that will return you the values that are important. In .NET you can use Ajax, web method or a service to parse these values to the server side:

JavaScript
			    <!--Drag drop Functionality Scripts -->
    <script language="javascript" type="text/javascript">
        function moveWidget(elementid, parentid, index) {
            window.alert("element: " + elementid + " ,parent: " + 
				parentid + " ,index: " + index);
        }    
    </script>
    <script type="text/javascript" src="Scripts/prototype.js"></script>
    <script type="text/javascript" 
	src="Scripts/scriptaculous.js?load=effects,dragdrop"></script>
    <script type="text/javascript" src="Scripts/portal.js"></script>
    <script type="text/javascript">
        var settings = {};
        var portal;
        function init() {
            portal = new Portal();
            portal.applySettings(settings);
        }
        try {
            Event.observe(window, 'load', init, false);
        } catch (exception) { }
</script>	

To define a column/drag drop zone, use...

ASP.NET
class="portal-column" id="portal-column-0"
... naming each consecutive column with a different integer.

To define a Widget/Docking Container, use...

ASP.NET
<div class="block " id="block-archive-0">
                   <div class="handle">
                       Dock 1</div>
                   <div class="content">
                       <div>

                           Dock 1 content
                           <br />
                           <br />
                           <br />
                           <br />
                       </div>
                   </div>
               </div>

... naming each block archive id with a different id.

Here is an example:

ASP.NET
<td style="vertical-align:top;">
            <div class="portal-column" id="portal-column-0">
            <h2>
                Column 0</h2>
            <div class="block " id="block-archive-0">
                <div class="handle">
                    Dock 1</div>
                <div class="content">
                    <div>
                   
                        Dock 1 content
                        <br />
                        <br />
                        <br />
                        <br />
                    </div>
                </div>
            </div>
            <div class="block " id="block-archive-1">
                <div class="handle">
                    Dock2</div>
                <div class="content">
                    <div>
                   
                        Dock 2 content
                        <br />
                        <br />
                        <br />
                        <br />
                    </div>
                </div>
            </div>
            <div class="block " id="block-archive-2">
                <div class="handle">
                    Dock 3</div>
                <div class="content">
                    <div>
                  
                        Dock 3 content
                        <br />
                        <br />
                        <br />
                        <br />
                    </div>
                </div>
            </div>
        </div>
    </td>
    <td style="vertical-align:top;">
        <div class="portal-column" id="portal-column-1">
            <h2>
                Column 1</h2>
        </div>
    </td>
    <td style="vertical-align:top;">
        <div class="portal-column" id="portal-column-2">
            <h2>
                Column 2</h2>
        </div>
    </td>		

Moving Towards Server Side Driven Data

Below is a LINQ to SQL diagram of entity relations. It is still work in progress, but I wanted you to see how the entities should be mapped so widgets can be bound to a specific Zone, Page and Template, as well as the sequence property on the PortalWidget will be of main focus here.

Portal_Website

When a drag and drop occurs, you can use Ajax, web methods or web services to update the database. (Please secure these methods because a hacker can bomb your server with requests.)

Here's the snippet I use to update the database with the latest position data: 

C#
public static void PerformDragDrop(Guid widgetid, 
	Guid templateid, Guid pageid, string zoneID, int seq)
{                
     LINQ.DatabaseDataContext db = 
	new WebCMS.LINQ.DatabaseDataContext(LINQ.Connection.GetDBConnectionString());
     LINQ.PortalWidget movedWidget = 
	db.PortalWidgets.SingleOrDefault(p => p.WidgetID.Equals(widgetid)
	&&p.TemplateID.Equals(templateid)&&p.PageID.Equals(pageid));

     if (movedWidget != null)
     {
          var previousZoneWidgets = from p in movedWidget.PortalZone.PortalWidgets
                                    orderby p.Sequence ascending
                                    select p;
          int counter = 0;
          foreach (LINQ.PortalWidget widget in previousZoneWidgets)
          { //Re arrange previos zone widget resided
               if (!widget.Equals(movedWidget))
               {
                   widget.Sequence = counter;
                   counter++;
               }
          }
         //========Previous zone re-arranged============//
	//========Add Widget to new Zone ==============//
          counter = 0;
          var newZoneWidgets = from p in db.PortalWidgets
                               where p.ZoneID.Equals(zoneID)
                               orderby p.Sequence ascending
                               select p;
          movedWidget.Sequence = seq;
          movedWidget.ZoneID = zoneID;
          foreach (LINQ.PortalWidget widget in newZoneWidgets)
          {
               if (widget.Sequence >= seq)
               {
                   if (widget.Sequence == seq)
                   {
                        counter = seq + 1;
                        widget.Sequence = counter;
                   }
                   else
                   {
                        widget.Sequence = counter;
                        counter++;  
                   }
               }                                             
           }
           db.SubmitChanges();                          
      }               
}

This is the LINQ statement that works with the above mentioned diagram.

First I reorder the previous Zone the widget was in excluding the widget that was moved, then I loop through the widgets in the zone my widget moved to and insert the moved widget to the correct sequence.

Known Issues and Limitations

When dragging and dropping in the example, the widget might unexpectedly jump to the middle column. This is only because of the alert and when clicked, it suddenly jumps to the middle column because that marks as the last mouse position. This will go away once you don't alert in the moveWidget JavaScript function in the header. 

History

  • 5th June, 2009: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)