Bottom Menu Builder (HTML5)

Bottom Menu Builder (HTML5)

0 30480
Bottom Menu Builder (HTML5)

Bottom Menu Builder (HTML5)

Bottom navigation website menu. I am sure that you have seen it many times (at different websites). As usual, this is three-four columns menu with different links. Today I would like to show you a builder, which you can use to build that bottom menu. Main purpose of this builder – prepare static HTML code (as cache file) for embedding into bottom of your website. If you like that idea, you are welcome to play with it, and I will tell you about creation of nice user friendly menu builder. This tutorial is separated into 2 parts, today I will tell you about first side: user interface with drag and drop possibility.

As the first, I would suggest you to download the source files and keep the demo opened in a tab for better understanding.

Live Demo
download result

So, lets start


Step 1. HTML

index.html

<div class="actions">
    Actions:
    <button id="preview" disabled>Preview</button>
    <button id="add_col">Add Column</button>
</div>
<div class="actions">Columns (with active elements)</div>
<div class="columns">
    <div class="column" id="drop_1" droppable="true"><img src="images/delete.png" onclick="removeColumn(this)" /></div>
    <div class="column" id="drop_2" droppable="true"><img src="images/delete.png" onclick="removeColumn(this)" /></div>
    <div class="column" id="drop_3" droppable="true"><img src="images/delete.png" onclick="removeColumn(this)" /></div>
</div>
<div style="clear:both"></div>
<div class="actions">All (inactive) elements. You can drag these elements into columns.</div>
<div class="inactive" droppable="true">
    <a id="1" draggable="true">Link 1</a>
    <a id="2" draggable="true">Link 2</a>
    <a id="3" draggable="true">Link 3</a>
    <a id="4" draggable="true">Link 4</a>
    <a id="5" draggable="true">Link 5</a>
    <a id="6" draggable="true">Link 6</a>
    <a id="7" draggable="true">Link 7</a>
    <a id="8" draggable="true">Link 8</a>
    <a id="9" draggable="true">Link 9</a>
    <a id="10" draggable="true">Link 10</a>
    <a id="11" draggable="true">Link 11</a>
    <a id="12" draggable="true">Link 12</a>
</div>
<script src="js/main.js"></script>

There are three main sections: block with actions, block with active columns and block with inactive elements. All the elements we can drag and drop between columns. Also we can add and remove our columns.

Step 2. CSS

Now, it’s time to style our menu builder page:

css/main.css

/* menu builder styles */
.actions {
    border: 1px solid #CCCCCC;
    font-size: 24px;
    margin: 20px auto 5px;
    overflow: hidden;
    padding: 10px;
    width: 900px;
    /* CSS3 Box sizing property */
    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
    -o-box-sizing: border-box;
    box-sizing: border-box;
}
.actions button {
    cursor: pointer;
    font-size: 20px;
    padding: 5px;
}
.actions #add_col {
    float: right;
}
.inactive {
    border: 1px dashed #ccc;
    margin: 0 auto;
    width: 900px;
}
.inactive a {
    border-color: #FFFFFF;
    border-style: solid;
    border-width: 8px 8px 20px;
    cursor: pointer;
    display: inline-block;
    font-size: 20px;
    height: 20px;
    margin: 10px;
    opacity: 1;
    position: relative;
    text-align: center;
    width: 180px;
    -khtml-user-drag: element;
    /* CSS3 Prevent selections */
    -moz-user-select: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    user-select: none;
    /* CSS3 Box Shadow */
    -webkit-box-shadow: 2px 2px 4px #444;
    -o-box-shadow: 2px 2px 4px #444;
    box-shadow: 2px 2px 4px #444;
}
.inactive a.hidden {
    height: 0;
    margin: 0;
    opacity: 0;
    width: 0;
}
.columns {
    margin: 0 auto;
    overflow: hidden;
    width: 900px;
}
.column {
    border: 2px dashed #ccc;
    float: left;
    min-height: 100px;
    padding: 10px;
    position: relative;
    width: 33.3%;
    /* CSS3 Box sizing property */
    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
    -o-box-sizing: border-box;
    box-sizing: border-box;
}
.column a {
    border-color: #FFFFFF;
    border-style: solid;
    border-width: 4px 4px 10px;
    cursor: pointer;
    display: block;
    font-size: 16px;
    height: 30px;
    margin-bottom: 15px;
    opacity: 1;
    position: relative;
    text-align: center;
    -khtml-user-drag: element;
    -webkit-user-drag: element;
    /* CSS3 Prevent selections */
    -moz-user-select: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    user-select: none;
    /* CSS3 Box Shadow */
    -webkit-box-shadow: 2px 2px 4px #444;
    -o-box-shadow: 2px 2px 4px #444;
    box-shadow: 2px 2px 4px #444;
    /* CSS3 Box sizing property */
    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
    -o-box-sizing: border-box;
    box-sizing: border-box;
}
.column img {
    cursor: pointer;
    position: absolute;
    right: 2px;
    top: 2px;
    z-index: 5;
}

Step 3. JS

js/main.js

// add event handler realization
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);
        }
      }
    };
  }
})();
// update handlers for draggable objects
function updateHandlerDrag() {
    var dragItems = document.querySelectorAll('[draggable=true]');
    for (var i = 0; i < dragItems.length; i++) {
        // dragstart event handler
        addEvent(dragItems[i], 'dragstart', function (event) {
            event.dataTransfer.setData('obj_id', this.id);
            return false;
        });
    }
}
// update handlers for droppable objects
function updateHandlerDrop() {
    var dropAreas = document.querySelectorAll('[droppable=true]');
    // dragover event handler
    addEvent(dropAreas, 'dragover', function (event) {
        if (event.preventDefault) event.preventDefault();
        this.style.borderColor = "#000";
        return false;
    });
    // dragleave event handler
    addEvent(dropAreas, 'dragleave', function (event) {
        if (event.preventDefault) event.preventDefault();
        this.style.borderColor = "#ccc";
        return false;
    });
    // dragenter event handler
    addEvent(dropAreas, 'dragenter', function (event) {
        if (event.preventDefault) event.preventDefault();
        return false;
    });
    // drop event handler
    addEvent(dropAreas, 'drop', function (event) {
        if (event.preventDefault) event.preventDefault();
        // get dropped object
        var iObj = event.dataTransfer.getData('obj_id');
        var oldObj = document.getElementById(iObj);
        // get inner text
        var linkText = oldObj.innerHTML;
        oldObj.className += 'hidden';
        // remove object from DOM
        oldObj.parentNode.removeChild(oldObj);
        // add similar object in another place
        this.innerHTML += '<a id="'+iObj+'" draggable="true">'+linkText+'</a>';
        // and update event handlers
        updateHandlerDrag();
        this.style.borderColor = "#ccc";
        return false;
    });
}
// add column button
var addColBtn = document.querySelectorAll('#add_col');
addEvent(addColBtn, 'click', function (event) {
    if (event.preventDefault) event.preventDefault();
    // recalculate widths for columns
    var oCols = document.querySelector('div.columns');
    var iChilds = oCols.childElementCount + 1;
    var dWidth = 100 / iChilds;
    // add single column
    oCols.innerHTML += '<div class="column" id="drop_'+(iChilds+1)+'" droppable="true"><img src="images/delete.png" onclick="removeColumn(this)" /></div>';
    // set new widths
    for (var i = 0; i < iChilds; i++) {
        oCols.children[i].style.width = dWidth + '%';
    }
    // update handlers
    updateHandlerDrop();
    return false;
});
// remove columns
function removeColumn(obj) {
    var oParent = obj.parentNode;
    // move object to inactive area
    var oInactive = document.querySelector('div.inactive');
    for (var i = 0; i < oParent.childNodes.length; i++) {
        if (oParent.childNodes[i].nodeType == document.ELEMENT_NODE && oParent.childNodes[i].tagName == 'A') {
            oInactive.innerHTML += '<a id="'+oParent.childNodes[i].id+'" draggable="true">'+oParent.childNodes[i].innerHTML+'</a>';
        }
    }
    // remove column
    oParent.parentElement.removeChild(oParent);
    // recalculate widths for columns
    var oCols = document.querySelector('div.columns');
    var iChilds = oCols.childElementCount;
    var dWidth = 100 / iChilds;
    // set new widths
    for (var i = 0; i < iChilds; i++) {
        oCols.children[i].id = 'drop_' + (i + 1);
        oCols.children[i].style.width = dWidth + '%';
    }
    // update handlers
    updateHandlerDrop();
    updateHandlerDrag();
}
// update handlers
updateHandlerDrag();
updateHandlerDrop();

There are a lot of event handlers (in order to make that html5 drag and drop). In the beginning, the script updates different handlers for all draggable and dropable objects. During dragging between blocks (drop areas) we should recreate objects and update handlers. In case when we need to remove column, we should move all the object of active column back to inactive area (with list of all possible elements). Tomorrow we will teach our builder to generate results.


Live Demo
download result

Conclusion

That’s all, today we have implemented first half of our bottom menu builder with native Drag and Drop functionality. Hope that our tutorial has helped you. Feel free to share our tutorials with your friends. Good luck!

SIMILAR ARTICLES

Understanding Closures

0 24610

NO COMMENTS

Leave a Reply