Toolbar System Codebase

Markup


<html>
<head>
  <link rel="stylesheet" type="text/css" href="/content/styles/menusyst.css" />
</head>
<body class="body-example">
  <div id="menu-content-wrapper"></div>
  <script type="text/javascript" src="/content/scripts/jquery-3.3.1.min.js"></script>
  <script type="text/javascript" src="/content/scripts/menusyst.js"></script>
  <script type="text/javascript" src="/content/scripts/menusyst-h.js"></script>
</body>
</html>

Javascript/JQuery


/*  ----------------------------
    /content/scripts/menusyst.js
    ---------------------------- */

var menusystObject = new function () {
    function createSubMenus(obj, markup) {
        var markup = "",
            menuitem = obj.item;
        if (menuitem && menuitem.length) {
            for (var i = 0; i < obj.item.length; i++) {
                menuitem = obj.item[i];
                if (menuitem.item) {
                    markup +=
                        '<div class="menu-parent"><a href="' + menuitem.url +
                        '" name="menusyst-' + menuitem.id + '" title="' + menuitem.title + '">' +
                        menuitem.menutext + '</a><div class="menu-dropdown" id="menusyst-' + menuitem.id + '">' +
                        createSubMenus(menuitem, markup) +
                        '</div></div>';
                } else {
                    markup +=
                        '<div><a href="' + menuitem.url +
                        '" title="' + menuitem.title + '">' + menuitem.menutext + '</a></div>';
                }
            }
        } else if (menuitem) {
            markup +=
                '<div><a href="' + menuitem.url +
                '" title="' + menuitem.title + '">' + menuitem.menutext + '</a></div>';
        }
        return markup;
    }

    function createRootMenus(obj, menutype) {
        var markup = "",
            menuitem = obj.item;
        if (menuitem) {
            markup +=
                '<div class="menu-content" id="menusyst"><div class="menu-toolbar ' +
                (menutype === 0 ? "menu-horizontal" : "menu-vertical") + '" id="menusyst-toolbar">';
            for (var i = 0; i < obj.item.length; i++) {
                menuitem = obj.item[i];
                if (menuitem.item) {
                    markup +=
                        '<div class="menu-parent"><a href="' + menuitem.url +
                        '" name="menusyst-' + menuitem.id + '" title="' + menuitem.title + '">' +
                        menuitem.menutext + '</a><div class="menu-dropdown" id="menusyst-' + menuitem.id + '">' +
                        createSubMenus(menuitem, markup) +
                        '</div></div>';
                } else {
                    markup +=
                        '<div><a href="' + menuitem.url + '" title="' + menuitem.title + '">' +
                        menuitem.menutext + '</a></div>';
                }
            }
            markup += '</div></div">';
        }
        return markup;
    };

    function parseMenusystMarkup(obj, wrapper, menutype) {
        var $menuLinks = null,
            $menuToolbar = null,
            $menuWrapper = $("#" + wrapper).first(),
            menuMarkup = createRootMenus(obj, (menutype === 1 ? 1 : 0));

        // insert, parse the menusyst markup
        if (menuMarkup.length) {
            $menuWrapper.html(menuMarkup),
            $menuToolbar = $menuWrapper.find("#menusyst-toolbar").first(),
            $menuLinks = $menuWrapper.find("a");

            // apply menusyst link object properties
            $menuLinks.each(function () {
                var $this = $(this),
                    $childMenu = $("#" + $this.attr("name")).first(),
                    $childMenuLinks = $childMenu.children("div").children("a"),
                    hasParentMenu = ($this.data("hasParentMenu") ? true : false);

                $childMenuLinks.each(function () {
                    $(this).data("hasParentMenu",  true);
                });

                $this.data("hasParentMenu", hasParentMenu);
                $this.data("childMenu", $childMenu);
                $this.on("mouseover", menuLinkMouseover);
            });

            // apply menusyst object properties
            menusyst = $menuWrapper.find("#menusyst")[0];
            menusyst.menutype = $menuToolbar.hasClass("menu-horizontal") ? "horizontal" : "vertical";
        }
    }

    function menuSystMouseout() {
        $(menusyst).off("mouseout");
        menusyst.tmr2 = setTimeout(function () {
            hideSiblingChildMenus();
        }, 400);
    }

    function hideSiblingChildMenus($el) {
        var $parentLinks = ($el ? $el.parent().parent() : $(menusyst)).find(".menu-parent > a");
        $parentLinks.each(function () {
            $(this).data("childMenu").css("display", "none");
        });
    }

    function positionElement($el, top, left) {
        $el
            .css("top", top + "px")
            .css("left", left + "px")
            .css("display", "block");
    }

    function menuLinkMouseover(e) {
        var $this = $(this),
            $childMenu = $this.data("childMenu");

        // kill timers and reset mouseout
        menusyst.tmr1 = clearTimeout(menusyst.tmr1);
        menusyst.tmr2 = clearTimeout(menusyst.tmr2);
        $(menusyst).on("mouseout", menuSystMouseout);

        // show, hide and position menus
        if (typeof $childMenu !== 'undefined') {
            var $parent = $this.parent(),
                $position = $parent.position(),
                isDroplist = !($this.data("hasParentMenu") || menusyst.menutype === "vertical"),
                left = $position.left + $parent.width(),
                top = $position.top;

            // position horizontal-toolbar menus
            if (isDroplist) {
                top = $position.top + $parent.height();
                left = $position.left;
            }

            hideSiblingChildMenus($this);
            positionElement($childMenu, top, left);
        } else {
            hideSiblingChildMenus($this);
        };

        e.CancelBubble = true;
        e.stopPropagation();
    }

    this.load = function (url, wrapper, menutype) {
        $.ajax({
            type: "GET",
            url: url,
            dataType: "json"
        }).done(function (data) {
            parseMenusystMarkup(data, wrapper, menutype);
        });
    }
};

$(function () {
    // horizontal toolbar
    menusystObject.load("/content/resources/menusyst.json", "menu-content-wrapper", 0);
    
    // vertical, slide-out toolbar
    // menusystObject.load("/content/resources/menusyst.json", "menu-content-wrapper", 1);
});

JSON


{
    "item": [
        {
            "id": "welcome",
            "url": "/welcome",
            "title": "ayespee.net: Home",
            "menutext": "Home"
        },
        {
            "id": "web-development",
            "url": "/web-development",
            "title": "ayespee.net: Web Development",
            "menutext": "Development",
            "item": [
                {
                    "id": "slideshow-module",
                    "url": "/slideshow-module",
                    "title": "Web Development: Slideshow",
                    "menutext": "Slideshow",
                    "item": [
                        {
                            "id": "slideshow-example",
                            "url": "/slideshow-example",
                            "title": "Slideshow: Slideshow Example",
                            "menutext": "Slideshow Example"
                        },
                        {
                            "id": "slideshow-code",
                            "url": "/slideshow-code",
                            "title": "Slideshow: Slideshow Code",
                            "menutext": "Slideshow Code"
                        }
                    ]
                },
                {
                    "id": "drop-menus",
                    "url": "/drop-menus",
                    "title": "Web Development: Dropmenus",
                    "menutext": "Dropmenus",
                    "item": [
                        {
                            "id": "slideout-menu",
                            "url": "/slide-out-menu",
                            "title": "Dropmenus: Drop-Menu Example",
                            "menutext": "Drop-Menu Example"
                        },
                        {
                            "id": "drop-menu-code",
                            "url": "/drop-menu-code",
                            "title": "Dropmenus: Drop-Menu Code",
                            "menutext": "Drop-Menu Code"
                        }
                    ]
                },
                {
                    "id": "css-image-sprites",
                    "url": "/css-image-sprites",
                    "title": "Web Development: CSS Image Sprites",
                    "menutext": "CSS Image Sprites",
                    "item": [
                        {
                            "id": "css-image-sprites-code",
                            "url": "/image-sprites-code",
                            "title": "Image Sprites Code",
                            "menutext": "Image Sprites Code"
                        }
                    ]
                }
            ]
        },
        {
            "id": "design-and-artwork",
            "url": "/design-and-artwork",
            "title": "ayespee.net: Design",
            "menutext": "Design",
            "item": [
                {
                    "id": "web-design-portfolio",
                    "url": "/web-design-portfolio",
                    "title": "Design: Web Design Portfolio",
                    "menutext": "Web Design Portfolio"
                },
                {
                    "id": "artwork-portfolio",
                    "url": "/artwork-portfolio",
                    "title": "Design: Artwork Portfolio",
                    "menutext": "Artwork Portfolio",
                    "item": [
                        {
                            "id": "sleeper-mixed-media",
                            "url": "/sleeper-mixed-media",
                            "title": "Artwork Portfolio: Sleeper (mixed-media)",
                            "menutext": "Sleeper (mixed-media)"
                        },
                        {
                            "id": "melissa-collage",
                            "url": "/melissa-collage",
                            "title": "Artwork Portfolio: Melissa (collage)",
                            "menutext": "Melissa (collage)"
                        },
                        {
                            "id": "arlene-drawing",
                            "url": "/arlene-drawing",
                            "title": "Artwork Portfolio: Arlene (drawing)",
                            "menutext": "Arlene (drawing)"
                        },
                        {
                            "id": "lovers-painting",
                            "url": "/lovers-painting",
                            "title": "Artwork Portfolio: Lovers (painting)",
                            "menutext": "Lovers (painting)"
                        },
                        {
                            "id": "old-boat-painting",
                            "url": "/old-boat-painting",
                            "title": "Artwork Portfolio: Old Boat (painting)",
                            "menutext": "Old Boat (painting)"
                        },
                        {
                            "id": "pike-place-paintin",
                            "url": "/pike-place-painting",
                            "title": "Artwork Portfolio: Pike Place (painting)",
                            "menutext": "Pike Place (painting)"
                        }
                    ]
                }
            ]
        },
        {
            "id": "sitemap",
            "url": "/sitemap",
            "title": "ayespee.net: Sitemap",
            "menutext": "Sitemap"
        }
    ]
}

CSS


/*  ----------------------------
    /content/styles/menusyst.css
    ---------------------------- */

.body-example   {
	margin: 0;
}

.body-example .menu-content  {
	font: bold .76em verdana !important;
}

.body-example #menu-content-wrapper  {
    display: block !important;
}

#menu-content-wrapper {
    display: inline-block;
}

.menu-content {
    box-sizing: border-box;
}

.menu-content a {
    display: block;
    color: #114477;
    white-space: nowrap;
    text-decoration: none;
    padding: 5px 15px 5px 7px;
    border-top: 1px solid #000;
    border-left: 1px solid #000;
}

.menu-content a:hover {
    color: #114477;
}

.menu-toolbar {
    display: inline-block;
    border-bottom: 1px solid #000;
    border-right: 1px solid #000;
}

.menu-toolbar.menu-vertical > div {
    min-width: 200px;
}

.menu-toolbar a {
    background-color: #fffcf0;
}

.menu-toolbar a:hover {
    background-color: #dcdcdc;
}

.menu-toolbar .menu-parent > a {
    background: url("/content/images/rightarrow.gif") no-repeat;
    background-position: center right;
    background-color: #fffcf0;
    padding-right: 35px;
}

.menu-toolbar .menu-parent > a:hover {
    background-color: #dcdcdc;
}

.menu-parent .menu-dropdown {
    display: none;
    animation: dropdownFadeIn ease 1200ms;
}

.menu-dropdown {
    position: absolute;
    left: -1000px;
    border-bottom: 1px solid #000;
    border-right: 1px solid #000;
}

.menu-dropdown a {
    border-top: 1px solid #000;
    border-left: 1px solid #000;
}

@keyframes dropdownFadeIn {
    0%   { 
        opacity: 0;
    }
    100% {
        opacity: 1;
    }
}

/* for horizontal only */ 
.menu-toolbar.menu-horizontal {
    display: block;
    background-color: #000;
    border-bottom-width: 0;
    border-right-width: 0;
}

.menu-toolbar.menu-horizontal > div {
    display: inline-block;
    min-width: inherit;
    padding: 0 2.5em 0 0;
}

.menu-toolbar.menu-horizontal > div > a,
.menu-toolbar.menu-horizontal > div.menu-parent > a {
    color: #fff;
    background: none;
    background-color: none;
    border: 0;
}

.menu-toolbar.menu-horizontal > div > a:hover,
.menu-toolbar.menu-horizontal > div.menu-parent > a:hover {
    color: #fff;
}

.content {
    margin-top: 26px;
}