Showing posts with label jQuery UI. Show all posts
Showing posts with label jQuery UI. Show all posts

Monday, June 10, 2013

jQuery UI Drag and Drop with FunScript

If you've been keeping up with activity in the F# world, you have no doubt seen great strides in a number of areas such as expansion of support for F# on different platforms and an ever increasing number of libraries and frameworks. One of these libraries that I've been playing with of late is named FunScript.

What is FunScript?


The FunScript website provides a nice definition.
FunScript is a lightweight F# library that lets you rapidly develop single-page applications. You can connect to external data sources and call REST APIs with intellisense, produce dashboards using JavaScript visualization libraries and write asynchronous computations easily without explicit callbacks.
One of the cool features that FunScript provides is a TypeScript type provider that allows any TypeScript definition file to be used to generate strongly typed access to the associated JavaScript lib. Let's look at an example of how to do this.

jQuery UI Drag/Drop Example


In this example, we create a simple TODO type of application using jQuery UI, FunScript, and the TypeScript type provider that FunScript provides. You can find the full example with detailed comments on the FunScript GitHub site.

Sunday, August 14, 2011

Another CoffeeScript and jQuery UI Example

In a previous post, I showed a few examples of jQuery UI demos ported to CoffeeScript. While I prefer the approach that was shown in that post, there is another way that I could have done it. In this post, I'll show a different jQuery UI example (one of the the Slider demos) written using the CoffeeScript class structure.

You can find the full example (F# + ASP.NET MVC + CoffeeScript + jQuery UI) on my GitHub: https://github.com/dmohl/FsCoffeeScriptjQueryUIExample.
class Slider 
    constructor: ->
        $('#master').slider 
            value: 60 
            orientation: "horizontal" 
            range: "min" 
            animate: true

        $('#eq > span').each -> 
            value = parseInt $(this).text(), 10
            $(this).empty().slider
                value: value
                range: "min"
                animate: true
                orientation: "vertical" 

window.slider = new Slider()

Sunday, July 31, 2011

jQuery UI Examples in CoffeeScript

Recently, I've been playing with CoffeeScript and have found it to be a lot of fun. I'm a big fan of JavaScript and CoffeeScript has only added to the enjoyment of writing client-side code by taking away a few of the "bad parts" and reducing syntactic noise. To help learn the language, I took a few of the jQuery UI examples and re-wrote them in CoffeeScript. You can find the full solution (F# + ASP.NET MVC (Razor) + CoffeeScript) at https://github.com/dmohl/FsCoffeeScriptjQueryUIExample. (Note: You will need to install the Mindscape Web Workbench Visual Studio 2010 extension to make the CoffeeScript aspects work correctly. Visit this post by Scott Hanselman for information on getting started with this extension).

Here are the before and after examples:

This simple Portlets example comes from the jQuery UI demo found at http://jqueryui.com/demos/sortable/#portlets.

The JavaScript Version:

(function (portlets, undefined) {
    portlets.init = function() {
        $(".column").sortable({
            connectWith: ".column"
        });

        $(".portlet")
	        .addClass("ui-widget ui-widget-content ui-helper-clearfix ui-corner-all")
	        .find(".portlet-header").addClass("ui-widget-header ui-corner-all")
	        .prepend("<span class='ui-icon ui-icon-minusthick'></span>")
	        .end().find(".portlet-content");

        $(".portlet-header .ui-icon").click(function () {
            $(this).toggleClass("ui-icon-minusthick").toggleClass("ui-icon-plusthick");
            $(this).parents(".portlet:first").find(".portlet-content").toggle();
        });

        $(".column").disableSelection();
    };

} (window.portlets = window.portlets || {}));

The CoffeeScript Version:

((portlets) ->
  portlets.init = ->  
    $(".column").sortable(connectWith: ".column").disableSelection()

    $(".portlet")
      .addClass("ui-widget ui-widget-content ui-helper-clearfix ui-corner-all")
      .find(".portlet-header").addClass("ui-widget-header ui-corner-all")
      .prepend("<span class='ui-icon ui-icon-minusthick'></span>")
      .end().find ".portlet-content"

    $(".portlet-header .ui-icon").click -> 
      $(this).toggleClass("ui-icon-minusthick").toggleClass "ui-icon-plusthick"
      $(this).parents(".portlet:first").find(".portlet-content").toggle()
) window.portlets = window.portlets or {}

This simple Photo Manager example comes from the jQuery UI demo found at  http://jqueryui.com/demos/droppable/#photo-manager.

The JavaScript Version:

(function (pictureManager, undefined) {
    pictureManager.init = function() {
        var $gallery = $("#gallery"),
		    $trash = $("#trash");

	    $( "li", $gallery ).draggable({
		    cancel: "a.ui-icon",
		    revert: "invalid", 
		    containment: $( "#demo-frame" ).length ? "#demo-frame" : "document", 
		    helper: "clone",
		    cursor: "move"
	    });

	    $trash.droppable({
		    accept: "#gallery > li",
		    activeClass: "ui-state-highlight",
		    drop: function( event, ui ) {
			    deleteImage( ui.draggable );
		    }
	    });

	    $gallery.droppable({
		    accept: "#trash li",
		    activeClass: "custom-state-active",
		    drop: function( event, ui ) {
			    recycleImage( ui.draggable );
		    }
	    });

        $("ul.gallery > li").click(function (event) {
            var $item = $(this), $target = $(event.target);
            if ($target.is("a.ui-icon-trash")) {
                deleteImage($item);
            } else if ($target.is("a.ui-icon-zoomin")) {
                viewLargerImage($target);
            } else if ($target.is("a.ui-icon-refresh")) {
                recycleImage($item);
            }
            return false;
        });

        var recycle_icon = "<a href='link/to/recycle/script/when/we/have/js/off' title='Recycle this image' class='ui-icon ui-icon-refresh'>Recycle image</a>";
        function deleteImage($item) {
            $item.fadeOut(function () {
                var $list = $("ul", $trash).length ?
				$("ul", $trash) :
				$("<ul class='gallery ui-helper-reset'/>").appendTo($trash);

                $item.find("a.ui-icon-trash").remove();
                $item.append(recycle_icon).appendTo($list).fadeIn(function () {
                    $item
					.animate({ width: "48px" })
					.find("img")
						.animate({ height: "36px" });
                });
            });
        }

        var trash_icon = "<a href='link/to/trash/script/when/we/have/js/off' title='Delete this image' class='ui-icon ui-icon-trash'>Delete image</a>";
        function recycleImage($item) {
            $item.fadeOut(function () {
                $item
				.find("a.ui-icon-refresh")
					.remove()
				.end()
				.css("width", "96px")
				.append(trash_icon)
				.find("img")
					.css("height", "72px")
				.end()
				.appendTo($gallery)
				.fadeIn();
            });
        }

        function viewLargerImage($link) {
            var src = $link.attr("href"),
			title = $link.siblings("img").attr("alt"),
			$modal = $("img[src$='" + src + "']");

            if ($modal.length) {
                $modal.dialog("open");
            } else {
                var img = $("<img alt='" + title + "' width='384' height='288' style='display: none; padding: 8px;' />")
				.attr("src", src).appendTo("body");
                setTimeout(function () {
                    img.dialog({
                        title: title,
                        width: 400,
                        modal: true
                    });
                }, 1);
            }
        }
    };
} (window.pictureManager = window.pictureManager || {}));

The CoffeeScript Version:

((pictureManager) ->
  pictureManager.init = ->
    $gallery = $("#gallery")
    $trash = $("#trash")
    recycle_icon = "<a href='link/to/recycle/script/when/we/have/js/off'  
                            title='Recycle this image' 
                            class='ui-icon ui-icon-refresh'>Recycle image</a>"
    trash_icon = "<a href='link/to/trash/script/when/we/have/js/off' 
                         title='Delete this image' 
                         class='ui-icon ui-icon-trash'>Delete image</a>"

    deleteImage = ($item) ->
      $item.fadeOut ->
        $list = if $("ul", $trash).length then $("ul", $trash) else $("<ul class='gallery ui-helper-reset'/>").appendTo $trash
        $item.find("a.ui-icon-trash").remove()
        $item.append(recycle_icon).appendTo($list).fadeIn ->
          $item.animate(width: "48px").find("img").animate height: "36px"

    recycleImage = ($item) ->
      $item.fadeOut ->
        $item.find("a.ui-icon-refresh").remove().end()
          .css("width", "96px").append(trash_icon).find("img")
          .css("height", "72px").end().appendTo($gallery).fadeIn()

    viewLargerImage = ($link) ->
      src = $link.attr "href"
      title = $link.siblings("img").attr "alt"
      $modal = $("img[src$='#{src}']")
      if $modal.length
        $modal.dialog "open"
      else
        img = $("<img alt='#{title}' width='384' height='288' 
               style='display: none; padding: 8px;' />")
               .attr("src", src).appendTo "body"
        setTimeout (->
          img.dialog 
            title: title
            width: 400
            modal: true
        ), 1

    $("li", $gallery).draggable 
      cancel: "a.ui-icon"
      revert: "invalid"
      containment: if $("#demo-frame").length then "#demo-frame" else "document"
      helper: "clone"
      cursor: "move"
    
    $trash.droppable 
      accept: "#gallery > li"
      activeClass: "ui-state-highlight"
      drop: (event, ui) ->
        deleteImage ui.draggable
    
    $gallery.droppable 
      accept: "#trash li"
      activeClass: "custom-state-active"
      drop: (event, ui) ->
        recycleImage ui.draggable
    
    $("ul.gallery > li").click (event) ->
      $item = $(this)
      $target = $(event.target)
      if $target.is "a.ui-icon-trash"
        deleteImage $item
      else if $target.is "a.ui-icon-zoomin"
        viewLargerImage $target
      else recycleImage $item  if $target.is "a.ui-icon-refresh"
      false    
) window.pictureManager = window.pictureManager or {}

This simple User Manager example comes from the jQuery UI demo found at  http://jqueryui.com/demos/dialog/#modal-form.

The JavaScript Version:

(function (userManager, undefined) {
    userManager.init = function () {
        $("#dialog:ui-dialog").dialog("destroy");

        var name = $("#name"),
			email = $("#email"),
			password = $("#password"),
			allFields = $([]).add(name).add(email).add(password),
			tips = $(".validateTips");

        function updateTips(t) {
            tips
				.text(t)
				.addClass("ui-state-highlight");
            setTimeout(function () {
                tips.removeClass("ui-state-highlight", 1500);
            }, 500);
        }

        function checkLength(o, n, min, max) {
            if (o.val().length > max || o.val().length < min) {
                o.addClass("ui-state-error");
                updateTips("Length of " + n + " must be between " +
					min + " and " + max + ".");
                return false;
            } else {
                return true;
            }
        }

        function checkRegexp(o, regexp, n) {
            if (!(regexp.test(o.val()))) {
                o.addClass("ui-state-error");
                updateTips(n);
                return false;
            } else {
                return true;
            }
        }

        $("#dialog-form").dialog({
            autoOpen: false,
            height: 300,
            width: 350,
            modal: true,
            buttons: {
                "Create an account": function () {
                    var bValid = true;
                    allFields.removeClass("ui-state-error");

                    bValid = bValid && checkLength(name, "username", 3, 16);
                    bValid = bValid && checkLength(email, "email", 6, 80);
                    bValid = bValid && checkLength(password, "password", 5, 16);

                    bValid = bValid && checkRegexp(name, /^[a-z]([0-9a-z_])+$/i, "Username may consist of a-z, 0-9, underscores, begin with a letter.");
                    bValid = bValid && checkRegexp(email, /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i, "eg. ui@jquery.com");
                    bValid = bValid && checkRegexp(password, /^([0-9a-zA-Z])+$/, "Password field only allow : a-z 0-9");

                    if (bValid) {
                        $("#users tbody").append("<tr>" +
							"<td>" + name.val() + "</td>" +
							"<td>" + email.val() + "</td>" +
							"<td>" + password.val() + "</td>" +
						"</tr>");
                        $(this).dialog("close");
                    }
                },
                Cancel: function () {
                    $(this).dialog("close");
                }
            },
            close: function () {
                allFields.val("").removeClass("ui-state-error");
            }
        });

        $("#create-user")
			.button()
			.click(function () {
			    $("#dialog-form").dialog("open");
			});        
    };
} (window.userManager = window.userManager || {}));

The CoffeeScript Version:

((userManager) ->
  userManager.init = ->
    name = $("#name")
    email = $("#email")
    password = $("#password")
    allFields = $([]).add(name).add(email).add password
    tips = $(".validateTips")

    updateTips = (t) ->
      tips.text(t).addClass "ui-state-highlight"
      setTimeout (->
        tips.removeClass "ui-state-highlight", 1500
      ), 500

    checkLength = (o, n, min, max) ->
      if o.val().length > max or o.val().length < min
        o.addClass "ui-state-error"
        updateTips "Length of #{n} must be between #{min} and #{max}."
        false
      else true

    checkRegexp = (o, regexp, n) ->
      unless regexp.test o.val()
        o.addClass "ui-state-error"
        updateTips n
        false
      else true

    $("#dialog-form").dialog 
      autoOpen: false
      height: 300
      width: 350
      modal: true
      buttons: 
        "Create an account": ->
          bValid = true
          allFields.removeClass "ui-state-error"
          bValid = bValid and checkLength name, "username", 3, 16
          bValid = bValid and checkLength email, "email", 6, 80
          bValid = bValid and checkLength password, "password", 5, 16
          bValid = bValid and checkRegexp name, /^[a-z]([0-9a-z_])+$/i, "Username may consist of a-z, 0-9, underscores, begin with a letter."
          bValid = bValid and checkRegexp email, /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i, "eg. ui@jquery.com"
          bValid = bValid and checkRegexp password, /^([0-9a-zA-Z])+$/, "Password field only allow : a-z 0-9"
          if bValid
            $("#users tbody").append "<tr>" + "<td>" + name.val() + "</td>" + "<td>" + email.val() + "</td>" + "<td>" + password.val() + "</td>" + "</tr>"
            $(this).dialog "close"
        
        Cancel: ->
          $(this).dialog "close"
      
      close: ->
        allFields.val("").removeClass "ui-state-error"
    
    $("#dialog:ui-dialog").dialog "destroy"

    $("#create-user").button().click ->
      $("#dialog-form").dialog "open"
) window.userManager = window.userManager or {}