-1

I have html images with hot spots (HTML Area elements). And I have code which can show a context menu when a hot spot is right clicked because in some cases the hot spot can logically navigate to one than more destination.

I have some nice working code based on the W3C planets example. My menu appears close to the hot spot and the styles work nice. And if I click on an item it will navigate through.

The menu is dynamic and will in fact be piopulated by Angular code and JSON. For the time being the menu is hardcoded with a mock function.

If an item is clicked the menu dismisses (and the navigation follows). I know my hide menu code works because I have a hide menu button for testing.

My problem is once the menu is showing I cannot figure out how to let the user dismiss the menu $('body').click(hideMenu) [line 130] does not work in that it is not accepting the function as a pointer (sorry if wrong term) for executing later; instead it executes it immediately, even though I have omitted the brackets.

The code is available here at JSFiddle http://jsfiddle.net/simonmeaden/98mukrff/8/ although it is not working in the fiddle. What does work works launched from Visual Studio.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <link href="contextMenus.css" rel="stylesheet" />
    <title></title>
</head>
<body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
    <script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
    <script src="JavaScript1.js"></script>

    <table>
        <tr>
            <td>Some text to shift image along</td>
            <td>
                <img id="planets" src="http://www.w3schools.com/tags/planets.gif" usemap="#planetmap">
                <map name="planetmap" width="145" height="126" alt="Planets">
                    <area id="planetmap_AreaSun" shape="rect" coords="0,0,82,126" href="http://www.w3schools.com/tags/sun.htm" alt="Sun">
                    <area id="planetmap_AreaMercury" shape="circle" coords="90,58,3" href="http://www.w3schools.com/tags/mercur.htm" alt="Mercury">
                    <area id="planetmap_AreaVenus" shape="circle" coords="124,58,8" href="http://www.w3schools.com/tags/venus.htm" alt="Venus">
                </map>
            </td>
        </tr>
        <tr>
            <td>
                <ul class="context-menu" id="my_custom_menu">
                    <!--style="display:none;"-->
                    <li>Strawberry</li>
                    <li>Raspberry</li>
                </ul>
            </td>
        </tr>
    </table>
        <!--<button id="button_ShowMenu2" onclick="setMenu('my_custom_menu', this, dynamicMenu())" type="button">Show Menu</button> -->
        <button id="button_ShowMenu" type="button">Show Menu</button>
        <button id="button_HideMenu" onclick="hideMenu()" type="button">Hide Menu</button>

</body>

</html>

the styles

.context-menu {
    /*position: absolute;*/
    display: block;
    background-color: #f2f2f2;
    border-radius: 4px;
    font-family: Arial, sans-serif;
    font-size: 14px;
    min-width: 150px;
    border: 1px solid #d4d4d4;
    z-index:1200;
    list-style-type: none;
    text-decoration: none;
}
.context-menu ul {
    list-style-type: none;
    margin: 4px 0px;
    padding: 0px;
    cursor: default;
}
.context-menu ul li {
    padding: 4px 16px;
}
.context-menu ul li:hover {
    background-color: #4677f8;
    color: #fefefe;
}


a {
    text-decoration: none;
}

.context-menu ul li a {
    text-decoration: none;
}

.context-menu ul li:hover a {
    text-decoration: none;
}

.context-menu ul li a:hover, a:hover span {
    background-color: #4677f8;
    color: #fefefe;
}

the javascript

function hideMenu() {
    console.log("hideMenu entered");
    var sMenuId = $('body').data('data-activeMenu');
    if (sMenuId !== '') {
        var jqMenu = $('#' + sMenuId);

        if (jqMenu) {
            jqMenu.css('display', 'none');
        } else {
            alert("menu (ul) id '" + sMenuId + "' not found!");
        }
    } else {
        alert("menu id '" + sMenuId + "' is null!");
    }
}

$(document).ready(function () {

    wireUpContextMenu('#planetmap_AreaVenus');
    wireUpButton();
    var gMousepos = [0, 0];
    document.onmousemove = function (evt) {
        evt = evt || window.event;
        if (typeof evt.pageX != 'undefined') {
            // Firefox support
            gMousepos = [evt.pageX, evt.pageY];
        } else {
            // IE support
            var scrollpos = getDocScrollPos();
            gMousepos = [evt.clientX + scrollpos[0], evt.clientY + scrollpos[1]];
        };
    };


    //alert("run");

    function dynamicMenu() {
        var fruits = [{
            itemText: "Apple",
            href: "http:\/\/images.clipartpanda.com\/teacher-apple-clipart-apple-clipartclipart---simple-red-apple-3e7q8rci.png"
        }, {
            itemText: "Orange",
            href: "http:\/\/www.google.com"
        }, {
            itemText: "Banana",
            href: "http:\/\/www.bbc.co.uk"
        }, {
            itemText: "Grape",
            href: "http:\/\/www.hotmail.com"
        }];
        return fruits;
    }


    function wireUpContextMenu(elementId) {
        var elementForMenuLaunch = $(elementId);
        if (elementForMenuLaunch) {
            elementForMenuLaunch.bind('contextmenu', function (e) {
                e.preventDefault();
                var jqElement = $(this);
                //var mousepos=getMousePos();
                var position = jqElement.position();
                var lPixelLeft =  gMousepos[0];//position.left;
                var lPixelTop = gMousepos[1];//position.top;
                setMenuInner('my_custom_menu', lPixelLeft, lPixelTop, dynamicMenu());

                //alert('The eventhandler will make sure, that the contextmenu doesn\'t appear.');
            });

        } else {
            alert("elementForMenuLaunch '" + elementId + "'is not found!");
        }
    };

    //function getMousePos() {
    //}

    function getDocScrollPos() {
        var x = document.body.scrollLeft ||
                document.documentElement.scrollLeft ||
                window.pageXOffset || 0,
            y = document.body.scrollTop ||
                document.documentElement.scrollTop ||
                window.pageYOffset || 0;
        return [x, y];
    }

    function isIE(userAgent) {
        userAgent = userAgent || navigator.userAgent;
        return userAgent.indexOf("MSIE ") > -1 || userAgent.indexOf("Trident/") > -1;
    }

    function navigateTo(e) {
        console.log("hideMenu entered");
        hideMenu();
        var href = jQuery.data(this, 'data-href');
        console.log("called navigateTo " + href);
        window.location.href = href;  
    }




    function setMenuInner(sMenuId, lPixelLeft, lPixelTop, jsonItems) {
        //console.log("setMenu entered");
        if (sMenuId !== '') {
            var jqMenu = $('#' + sMenuId);

            if (jqMenu) {
                jqMenu.empty();


                //jQuery.data(document.body, 'data-activeMenu', sMenuId);

                //hideMenu();
                //$('body').click(hideMenu());

                var lItemCount = jsonItems.length;
                for (var i = 0; i < lItemCount; i++) {
                    var jqListItemNew = $("<li data-href='" + jsonItems[i].href + "'></li>").appendTo(jqMenu);
                    var jqAnchor = $("<a href='#'></a>" ).appendTo(jqListItemNew);
                    var jqSpan = $("<span data-href='" + jsonItems[i].href + "'>" + jsonItems[i].itemText + "</span>").appendTo(jqAnchor);
                    jqSpan.data('data-href', jsonItems[i].href);
                    jqSpan.click(navigateTo);
                }
                $('body').data('data-activeMenu', '');
                if ($('body').data('data-activeMenu') != '') {
                    alert('failed to clear data-activeMenu on Body');
                };
                //[Line 130 in fiddle screen]$('body').click(hideMenu)
                $('body').data('data-activeMenu', sMenuId);
                if ($('body').data('data-activeMenu') != sMenuId) {
                    alert('failed to set data-activeMenu on Body');
                };


                jqMenu.css('position', 'absolute');
                jqMenu.css('left', lPixelLeft + 'px');
                jqMenu.css('top', lPixelTop + 'px');
                jqMenu.css('display', 'block');
            } else {
                alert("menu (ul) id '" + sMenuId + "' not found!");
            }

        } else {
            alert("menu id '" + sMenuId + "' is null!");
        }
    }

    function wireUpButton() {
        var sButtonId = '#button_ShowMenu';
        var buttonMoveList = $(sButtonId);
        if (buttonMoveList) {
            buttonMoveList.click(function () {
                setMenuInner('my_custom_menu', 400, 100, dynamicMenu());
            });
        } else {
            alert("button element id '" + sButtonId + "' not found!");
        }


    };
});
S Meaden
  • 8,050
  • 3
  • 34
  • 65

1 Answers1

2

Firstly, jsFiddle was defining your hideMenu function too late, because jsFiddle runs JavaScript on load by default. I changed the JSFiddle option to "no wrap - in head" and it started working fine. Secondly, I created functionality that closes the menu when you click outside of it using code from this answer.

Working Live Demo:

function hideMenu() {
    console.log("hideMenu entered");
    var sMenuId = $('body').data('data-activeMenu');
    if (sMenuId !== '') {
        var jqMenu = $('#' + sMenuId);

        if (jqMenu) {
            jqMenu.css('display', 'none');
        } else {
            alert("menu (ul) id '" + sMenuId + "' not found!");
        }
    } else {
        alert("menu id '" + sMenuId + "' is null!");
    }
}

$(document).ready(function () {

    $(document).mouseup(function (e)
    {
        var container = $("#my_custom_menu");

        if (!container.is(e.target) // if the target of the click isn't the container...
            && container.has(e.target).length === 0) // ... nor a descendant of the container
        {
            container.hide();
        }
    });
    
    wireUpContextMenu('#planetmap_AreaVenus');
    wireUpButton();
    //alert("run");

    function dynamicMenu() {
        var fruits = [{
            itemText: "Apple",
            href: "http:\/\/images.clipartpanda.com\/teacher-apple-clipart-apple-clipartclipart---simple-red-apple-3e7q8rci.png"
        }, {
            itemText: "Orange",
            href: "http:\/\/www.google.com"
        }, {
            itemText: "Banana",
            href: "http:\/\/www.bbc.co.uk"
        }, {
            itemText: "Grape",
            href: "http:\/\/www.hotmail.com"
        }];
        return fruits;
    }


    function wireUpContextMenu(elementId) {
        var elementForMenuLaunch = $(elementId);
        if (elementForMenuLaunch) {
            elementForMenuLaunch.bind('contextmenu', function (e) {
                e.preventDefault();
                var lPixelLeft = this.offsetLeft;
                var lPixelTop = this.offsetTop;
                setMenuInner('my_custom_menu', lPixelLeft, lPixelTop, dynamicMenu());
                
                //alert('The eventhandler will make sure, that the contextmenu doesn\'t appear.');
            });

        } else {
            alert("elementForMenuLaunch '" + elementId + "'is not found!");
        }
    };

    function navigateTo(e) {
        console.log("hideMenu entered");
        hideMenu();
        var href = jQuery.data(this, 'data-href');
        console.log("called navigateTo " + href);
        window.location.href = href;  
    }




    function setMenuInner(sMenuId, lPixelLeft, lPixelTop, jsonItems) {
        //console.log("setMenu entered");
        if (sMenuId !== '') {
            var jqMenu = $('#' + sMenuId);

            if (jqMenu) {
                jqMenu.empty();


                //jQuery.data(document.body, 'data-activeMenu', sMenuId);

                //hideMenu();
                //$('body').click(hideMenu());

                var lItemCount = jsonItems.length;
                for (var i = 0; i < lItemCount; i++) {
                    var jqListItemNew = $("<li data-href='" + jsonItems[i].href + "'></li>").appendTo(jqMenu);
                    var jqAnchor = $("<a href='#'></a>" ).appendTo(jqListItemNew);
                    var jqSpan = $("<span data-href='" + jsonItems[i].href + "'>" + jsonItems[i].itemText + "</span>").appendTo(jqAnchor);
                    jqSpan.data('data-href', jsonItems[i].href);
                    jqSpan.click(navigateTo);
                }
                $('body').data('data-activeMenu', '');
                if ($('body').data('data-activeMenu') != '') {
                    alert('failed to clear data-activeMenu on Body');
                };
                //$('body').click(hideMenu)
                $('body').data('data-activeMenu', sMenuId);
                if ($('body').data('data-activeMenu') != sMenuId) {
                    alert('failed to set data-activeMenu on Body');
                };


                jqMenu.css('position', 'absolute');
                jqMenu.css('left', lPixelLeft + 'px');
                jqMenu.css('top', lPixelTop + 'px');
                jqMenu.css('display', 'block');
            } else {
                alert("menu (ul) id '" + sMenuId + "' not found!");
            }

        } else {
            alert("menu id '" + sMenuId + "' is null!");
        }
    }

    function wireUpButton() {
        var sButtonId = '#button_ShowMenu';
        var buttonMoveList = $(sButtonId);
        if (buttonMoveList) {
            buttonMoveList.click(function () {
                setMenuInner('my_custom_menu', 400, 100, dynamicMenu());
            });
        } else {
            alert("button element id '" + sButtonId + "' not found!");
        }


    };
});
.context-menu {
    /*position: absolute;*/
    display: block;
    background-color: #f2f2f2;
    border-radius: 4px;
    font-family: Arial, sans-serif;
    font-size: 14px;
    min-width: 150px;
    border: 1px solid #d4d4d4;
    z-index:1200;
    list-style-type: none
}
.context-menu ul {
    list-style-type: none;
    margin: 4px 0px;
    padding: 0px;
    cursor: default;
}
.context-menu ul li {
    padding: 4px 16px;
}
.context-menu ul li:hover {
    background-color: #4677f8;
    color: #fefefe;
}

a:hover, a:hover span {
    color:#9A1A4A;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
    <script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
    <script src="JavaScript1.js"></script>
    <img id="planets" src="http://www.w3schools.com/tags/planets.gif" usemap="#planetmap">
    <map name="planetmap" width="145" height="126" alt="Planets">
        <area id="planetmap_AreaSun" shape="rect" coords="0,0,82,126" href="http://www.w3schools.com/tags/sun.htm" alt="Sun">
        <area id="planetmap_AreaMercury" shape="circle" coords="90,58,3" href="http://www.w3schools.com/tags/mercur.htm" alt="Mercury">
        <area id="planetmap_AreaVenus" shape="circle" coords="124,58,8" href="http://www.w3schools.com/tags/venus.htm" alt="Venus">
    </map>
    <table>
        <tr>
            <td>
                <ul class="context-menu" id="my_custom_menu" style="display:none;">
                    <!--style="display:none;"-->
                    <li>Strawberry</li>
                    <li>Raspberry</li>
                </ul>
            </td>
        </tr>
    </table>
        <!--<button id="button_ShowMenu2" onclick="setMenu('my_custom_menu', this, dynamicMenu())" type="button">Show Menu</button> -->
        <button id="button_ShowMenu" type="button">Show Menu</button>
        <button id="button_HideMenu" onclick="hideMenu()" type="button">Hide Menu</button>
Community
  • 1
  • 1
Maximillian Laumeister
  • 19,884
  • 8
  • 59
  • 78