C# and HTML5: drag and Drop elements

HTML5 API includes Drag and Drop (DnD) native functionality.

The event listener methods for all the drag and drop events accept Event object which has a readonly attribute called dataTransfer. The event.dataTransfer returns DataTransfer object associated with the event

This is the list of events fired during the different stages:

Event Description
dragstart Fires when the user starts dragging of the object.
dragenter Fired when the mouse is first moved over the target element while a drag is occuring. A listener for this event should indicate whether a drop is allowed over this location. If there are no listeners, or the listeners perform no operations, then a drop is not allowed by default.
dragover This event is fired as the mouse is moved over an element when a drag is occuring. Much of the time, the operation that occurs during a listener will be the same as the dragenter event.
dragleave This event is fired when the mouse leaves an element while a drag is occuring. Listeners should remove any highlighting or insertion markers used for drop feedback.
drag Fires every time the mouse is moved while the object is being dragged.
drop The drop event is fired on the element where the drop was occured at the end of the drag operation. A listener would be responsible for retrieving the data being dragged and inserting it at the drop location.
dragend Fires when the user releases the mouse button while dragging an object.

 

In this post we develop an application to handle the drag and drop events between two elements, and launch a HttpPost method in the server which will ends inserting the dragged value in database.

First of all we create an MVC project in C#. Under Controller folder in the HomeController we add this code:

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

namespace HTML5DragAndDrop.Controllers {
   public class HomeController : Controller {
      ITestDatabase _testDatabase = new TestDatabase();

      public ActionResult Index() {
         return View();
      }

      public ActionResult About() {
         ViewBag.Message = "Your application description page.";

         return View();
      }

      public ActionResult Contact() {
         ViewBag.Message = "Your contact page.";

         return View();
      }

      [HttpPost]
      public JsonResult InsertTestElements(string testElement) {
         int? insertResult = null;

         if (!string.IsNullOrEmpty(testElement)) {
            string[] elementData = testElement.Split(':');

            string symbol = elementData[0].Trim();
            string name = elementData[1].Trim();

            insertResult = _testDatabase.InsertElement(symbol, name);
         }

         return Json(insertResult);
      }
   }
}

Now we create a folder in the root of the project called Code. Under this folder we create two new files:

ITestDatabase.cs

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

public interface ITestDatabase {
   int InsertElement(string symbol, string name);
}   
 

TestDatabase.cs

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

public class TestDatabase : ITestDatabase {
   /// <summary>
   /// Save an element in the database and return the new ID
   /// </summary>
   /// <param name="symbol"></param>
   /// <param name="name"></param>
   /// <returns></returns>
   public int InsertElement(string symbol, string name) {
      // save the element in database
      // now it returns just a number: it will be the Id of the record
      return 1;
   }
}

The first step is the definition of the UXinterface, in sequence the display is this

DragAndDrop_App

We are adding h5utils.js file, with an implementation of AddEvent function to simplify our code:

h5utils.js

var AddEvent = (function () {
   if (document.addEventListener) {
      return function (el, type, fn) {
         if (el && el.nodeName || el === window) {
            el.addEventListener(type, fn, false);
         } else if (el && el.length) {
            for (var i = 0; i < el.length; i++) {
               AddEvent(el[i], type, fn);
            }
         }
      };
   } else {
      return function (el, type, fn) {
         if (el && el.nodeName || el === window) {
            el.attachEvent('on' + type, function () 
                  { 
                    return fn.call(el, window.event); 
                  });
         } else if (el && el.length) {
            for (var i = 0; i < el.length; i++) {
               AddEvent(el[i], type, fn);
            }
         }
      };
   }
})();

var pDragElement = document.createElement('p');
var chemicalElements = document.querySelectorAll('div > p'), el = null;
for (var i = 0; i < chemicalElements.length; i++) {
   el = chemicalElements[i];
   el.setAttribute('draggable', 'true');
   AddEvent(el, 'dragstart', dragStartElement);
   AddEvent(el, 'dragend', dragEndElement);
}

function dragStartElement(e) {
   e.dataTransfer.effectAllowed = 'copy';
   e.dataTransfer.setData('Text', this.id);
   e.dataTransfer.setData('Type', this.innerHTML);

   this.style.backgroundColor = "#ffa31a";
}

function dragEndElement(e) {
   this.style.backgroundColor = "#fff9f0";
}

var divBoxElements = document.querySelector('#divBoxElements');

AddEvent(divBoxElements, 'dragover', function (e) {
   if (e.preventDefault) e.preventDefault();
   e.dataTransfer.dropEffect = 'copy';
   return false;
});

AddEvent(divBoxElements, 'drop', function (e) {
   if (e.stopPropagation) e.stopPropagation();

   var element = e.dataTransfer.getData('Type');
   pDragElement.innerHTML = "Adding " + element + " element";

   var pClone = pDragElement.cloneNode(true);
   var newDiv = document.createElement("div");
   newDiv.appendChild(pClone);
   divBoxElements.appendChild(newDiv);
   InsertTestElement(element);

   return false;
});

In the Index.cshtml we change as following code:

Index.cshtml

@{
   ViewBag.Title = "Home Page";
}

<div class="jumbotron">
    <h1>Drag and drop example</h1>
    <p class="lead">HTML5 API includes Drag and Drop (DnD) 
    native functionality. The event listener methods for all the drag and 
    drop events accept Event object which has a readonly attribute called 
    dataTransfer. The event.dataTransfer returns DataTransfer object 
    associated with the event.</p>
    <p><a href="http://puresourcecode.com" 
    class="btn btn-primary btn-lg">Learn more »</a></p>
</div>

<div class="row">
    <p id="1A">1: A</p>
    <p id="2B">2: B</p>
    <p id="3C">3: C</p>
    <p id="4D">4: D</p>
    <p id="5E">5: E</p>
    <div id="divBoxElements 
       style="border: 1px solid #dcdcdc; width: 300px; height: 300px;"
    ></div>
</div>

@section scripts {
    <script src="~/Scripts/html5utils.js"></script>
    <script>
        <!--
        function InsertTestElement(element) {
            var url = '@Url.Action("InsertTestElements", "Home")';

            $.post(url, { testElement: element }, function (data) {
                switch (data) {
                    case 1:
                        divBoxElements.innerHTML = 
                             element + " inserted OK";
                        setTimeout(function () { 
                             divBoxElements.innerHTML = ""; }, 2000);
                        break;

                    default:
                        alert("Error inserting the element");
                }
            });
        }
        //-->
    </script>
}

Download or fork tthis code on Github.

Happy coding!

Insert spaces between words on a camel-cased token

Here's an extension method that I have used extensively for this kind of thing

public static string SplitCamelCase( this string str )
{
    return Regex.Replace( 
        Regex.Replace( 
            str, 
            @"(\P{Ll})(\P{Ll}\p{Ll})", 
            "$1 $2" 
        ), 
        @"(\p{Ll})(\P{Ll})", 
        "$1 $2" 
    );
}

It also handles strings like "FistName", converting it to "First Name".

Happy coding!

WebRole and WorkerRole Templates in VS 2015

Download the Azure SDK for Visual Studio 2015 from here: https://azure.microsoft.com/en-us/downloads/

It should force you to close Visual Studio, but if it doesn't, do so anyways. Once it's installed, you can reboot it.

When you go to add a new project, you can look under Cloud and then choose Azure Cloud Service.

Visual-Studio-2015-New-Project-Azure-Cloud-Service

This will give you the same old familiar screen, where you can choose a Web Role or Worker Role:

Visual-Studio-2015-New-Project-Azure-Cloud-Service

Microsoft Azure Storage Explorer for OS X, Linux, and Windows (and it's free)

microsoft-azure-storage-explorer-screenshot

Microsoft Azure Storage Explorer (Preview) is a standalone app from Microsoft that allows you to easily work with Azure Storage data. The Preview release currently supports Azure Blobs only. Tables, queues, and files are coming soon.

Features

  • Mac OS X, Linux, and Windows versions
  • Sign in to view your Storage Accounts – use your Org Account, Microsoft Account, 2FA, etc
  • Add Storage Accounts by account name and key, as well as custom endpoints
  • Add Storage Accounts for Azure China
  • Add blob containers with Shared Access Signatures (SAS) key
  • Local development storage (use storage emulator, Windows-only)
  • ARM and Classic resource support
  • Create and delete blobs, queues, or tables
  • Search for specific blobs, queues, or tables
  • Explore the contents of blob containers
  • View and navigate through directories
  • Upload, download, and delete blobs and folders
  • Open and view the contents text and picture blobs
  • View and edit blob properties and metadata
  • Generate SAS keys
  • Manage and create Stored Access Policies (SAP)
  • Search for blobs by prefix
  • Drag ‘n drop files to upload or download

Known Issues

  • Cannot view/take actions on Queues or Tables (coming soon!)
  • Linux install needs gcc version updated or upgraded – steps to upgrade are below:
    • sudo add-apt-repository ppa:ubuntu-toolchain-r/test
    • sudo apt-get update
    • sudo apt-get upgrade
    • sudo apt-get dist-upgrade
  • After reentering credentials, you may need to manually refresh Storage Explorer to show your Storage Accounts

Project Deco

Looking for the old open-source version? It's still available on GitHub!

Advertsing

125X125_06

TagCloud

MonthList

CommentList