Thursday, 13 February 2014

Complete HTML5 portlet management system


Last day I had a discussion with one of my friend regarding portlets. He asked me whether it is possible to have a portlet management system completely on the client side. In this article I shall try to find out a client only solution (which you may or may not agree).

Java Portlets, Liferay portlets

You may be already knowing about portlets in Java, JSF and Liferay. JavaScript cannot compete with any of these as it is processed on the server side. JavaScript does not have the power of permanent storage too. The only option left to us is the use of localStorage or file API (which is not yet implemented in many of the browsers).

Portlets using Drag and Drop API and LocalStorage

Copy paste the following code to your favorite editor and open it in the (HTML5 compliant) browser.
    <title>Complete HTML5 portlet management system</title>
    <style type="text/css">
        header{color:#000;text-shadow:#000 0 1px;font-size:20px;text-align:center}[draggable]{-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;user-select:none;-khtml-user-drag:element;-webkit-user-drag:element}.slot{height:15%;width:95%;background-color:silver;text-align:center;margin:1%}.slot.drgbl{border:3px dashed #00f}.slot.over{border:3px dashed red}.component input,.component select{height:70%;width:50%;border:1% solid #000;border-radius:4%;-webkit-border-radius:4%;-ms-border-radius:4%;-moz-border-radius:4%;margin:1%}.toolbar{background-color:orange;text-align:right}
    <script id="tpl1" type="text/template">
        <div id="com1" class="component">
    <script id="tpl2" type="text/template">
        <div id="com2" class="component">
            <input type="submit" 
    <script id="tpl3" type="text/template">
        <div id="com3" class="component">
            <input type="email" name="email" required 
    <script id="tpl4" type="text/template">
        <div id="com4" class="component">
            <input name="q" placeholder="Go to a Website"/>            
        <header>Complete HTML5 portlet management system</header>
        <div id="slot1" class="slot" draggable="true"></div>
        <div id="slot2" class="slot" draggable="true"></div>
        <div id="slot3" class="slot" draggable="true"></div>
        <div id="slot4" class="slot" draggable="true"></div>
        <footer class="toolbar">
                <button id="rearrange">Rearrange</button>
                <button id="save" disabled="true">Save</button>

        window.onload = function() {
            var slots = document.querySelectorAll('.slot');
            var dragSrcEl = null;

            function handleDragStart(e) {
                    return false;
       = '0.4';  // this / is the source node.
                dragSrcEl = this;
                e.dataTransfer.effectAllowed = 'move';
                e.dataTransfer.setData('text/html', this.innerHTML);

            function handleDragEnter(e) {
                // this / is the current hover target.

            function handleDragOver(e) {
                if (e.preventDefault) {
                    e.preventDefault(); // Necessary. Allows us to drop.
                e.dataTransfer.dropEffect = 'move'; 
                return false;

            function handleDragLeave(e) {
                  this.classList.remove('over');  // this / is previous target element.

            function handleDrop(e) {
                    return false;
                // this/ is current target element.

                if (e.stopPropagation) {
                    e.stopPropagation(); // Stops some browsers from redirecting.

                if (dragSrcEl != this) {
                    dragSrcEl.innerHTML = this.innerHTML;
                    this.innerHTML = e.dataTransfer.getData('text/html');

                return false;

            function handleDragEnd(e) {
                // this/ is the source node.
                [], function (slot) {
           = 1;

            [], function(slot) {
              slot.addEventListener('dragstart', handleDragStart, false);
              slot.addEventListener('dragenter', handleDragEnter, false)
              slot.addEventListener('dragover', handleDragOver, false);
              slot.addEventListener('dragleave', handleDragLeave, false);
              slot.addEventListener('drop', handleDrop, false);
              slot.addEventListener('dragend', handleDragEnd, false);
            var rearrange = document.getElementById("rearrange");
            var save = document.getElementById("save");
            rearrange.addEventListener('click', rearrangeAction, false);
            save.addEventListener('click', saveAction, false);
            var draggable = false;
            function rearrangeAction(e){
                [], function(slot) {
                rearrange.disabled = true;
                save.disabled = false;
                draggable = true;                                    

            function saveAction(e) {
                [], function(slot) {
                rearrange.disabled = false;
                save.disabled = true;
                draggable = false;

            function loadTemplates(){
                [], function(slot) {
                    slot.innerHTML = document.querySelector("#tpl"+getOrder(;

            function getOrder(id){
                if(localStorage && localStorage[id]){
                    return localStorage[id].substring(3);    
                } else {
                    return id.substring(4);

            function saveOrder(){
                if(localStorage) {
                    [], function(slot) {
                        localStorage[] = slot.children[0].id;

If you inspect the HTML code, you can see that there are 4 slots which are draggable. During onload event these slots will be filled with the templates based on the order which are saved in localStorage. Each template is a UI component. Elements can be dragged into different slots when user clicks on "rearrange" button. On "save" click, the data is stored onto the LocalStorage in the form of key(slot id) -value(component id) pair.
Now refresh your page or reopen. You can find the UI components in the order you saved.

You can find the same on jsfiffle.



1 comment: