Click here to Skip to main content
13,145,068 members (55,714 online)
Click here to Skip to main content
Add your own
alternative version

Stats

3.3K views
47 downloads
5 bookmarked
Posted 8 Jul 2017

Popup Menu

, 8 Jul 2017
Rate this:
Please Sign up or sign in to vote.
Simple and very basic popup menu easy to implement in any page

Introduction

Starting from a code I found here, I developed a very simple context popup menu.

It has only one level (no nested menus) but could be good for 90% of the web project. The popup menu is implemented with JavaScript's 'function object', an "old fashion" development style to keep the code (and use) as simple as possible.

Background

To understand this code is enough:

  • to know how to implement an 'object' in JavaScript
  • have basic knowledge of jQuery
  • have a basic knowledge of CSS

Using the Code

The picture shows how the menu looks like. It is only an example you can do what you want, the only constraint you have is to use the tags <ul> <li>. You can use different tags but you must adapt the code in the function 'PopupMenu'.

Looking at the code you can find two different ways to use the object.

The 'jQuery' Way

Line 214 creates an instance of the 'PopupMenu' object where 'GroupB' is the selector for both the gray regions in the picture (so both have the same popup menu) and jQuery binds the events (from the menu items) with the managing function. Lines 216-219

The picture below shows the HTML referenced by the JavaScript code above.

The 'on line' Way:

This is the simplest way to use this object: it is enough to create an instance of 'PopupMenu: Line 266, providing the selector for the element to which you want to add the popup menu and the selector for the menu (the <ul>). In lines 248-250, there is the online definition of the 'onclick' events and in lines 268-268, the functions for the events.

The Full-page Code

You can also "Copy and paste" the code below in an HTML file and you will have a fully running example also with images (coded as base64).

The tag <script> as a link to e: http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.js or you can reference a copy of jQuery in your machine.

<!DOCTYPE html>

<html ><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">   
 
    <title>jQuery contextMenu</title>
        
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.js"></script>        

    <script type="text/javascript">    
        try{
            
            if (typeof jQuery != 'undefined') {  
                document.write
                ('<label style="color:green;">jQuery running version: </label><b>' + 
                jQuery.fn.jquery + '</b>');
            }
            else{
                document.write('<label style="color:red;"> ** ATTENTION ** </label>' + 
                               ' jQuery is not running!');
            }    
        }
        catch(jse){
            document.write(' ** ATTENTION **  ' + jse.message);
        }        
        
        document.write(' - "PopupMenu" is based on code found 
            <a href="https://stackoverflow.com/questions/4495626/
            making-custom-right-click-context-menus-for-my-web-app" 
            target="_blank">HERE</a>');
        
         
    </script>
    
    <!--<span class="code-comment"> CSS that makes popup menu run--></span>
    <style>        
        .custom-menu {
            /* structural css */
            display: none;
            z-index: 1000;
            position: absolute;
            overflow: hidden;
        }        
    </style>

    <!--<span class="code-comment"> the custom CSS with the custom style --></span>
    <style>    
        .custom-style{
            /* stylistical css */
            white-space: nowrap;
            font-family: verdana;
            font-size:13px;
            color: #333;
            border-radius: 2px;
            
            border: solid 1px #ddd;        
            background-color: #FFF;            
            padding: 0;            
            margin: 0;
            -webkit-box-shadow: 10px 10px 20px 0px rgba(119,119,119,1);
            -moz-box-shadow: 10px 10px 20px 0px rgba(119,119,119,1);
            box-shadow: 10px 10px 20px 0px rgba(119,119,119,1);            
        }

        .custom-style li {
            padding: 3px 15px 5px 30px;
            cursor: pointer;
            list-style-type: none;
        }

        .custom-style li:hover {
            background-color: #EEE; /* DEF */
        }
        
        .custom-style li.image{
            background-repeat: no-repeat;
            background-position: 8px 5px;
        }    
        
        .custom-style li.delete{
            background-image: url('data:image/png;base64,
            iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/
            xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC4xMkMEa+
            wAAABESURBVDhPY/j//z9FGEOgubn5Pz6Mrh6FA8JQRVgB0Qbgw+jqidKEC1PPABiGCoIBATZcz6gBw9MAY
            jCyHhQDSMf/GQAPPgrAR+lEmQAAAABJRU5ErkJggg==')
        }        
        .custom-style li.edit{
            background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/
            9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0ID
            QuMC4xMkMEa+wAAAEMSURBVDhPnZOhkoNAEETzxzgUDofCITE4HAoFDouiUFQh+AYMoo83y3JJLrkj11VvgWWmm
            ZlNbpI+Zp7n/eLubVmWReM4vmWapjMBuq7TMAy2d260bfuWvu8t2BvyQTgN6roWbNvG5g+t62pfJKZpmjMZbKmq
            SvBKmFKBj6GiXZYHtpRlKXgl2vPvqYB5YOIHaQZFUQieRen+HQY8k8gzxrucQZ7ngmfRK/skHH1bBez5Vswgyz
            LBveidgTH1++FiQCzt7HIGaZoKrggDYh8MkiQRXBEVEXucmjOI41hwRfweiD1OzRlEUSRgyn/B9Il9MAjDUOBP4
            zcon9jj2L9nEATBR/g/mBn8H92+AMRlSI4HRnCNAAAAAElFTkSuQmCC')
        }        
        .custom-style li.refresh{
		background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/
        9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABl0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC
		4xMkMEa+wAAACSSURBVDhPtZJLDsAgCEQ9tRfQw3gir0MziyEjxaafdPESeFCKxmJmn0jlEzxorVmEtVqr9d49V5ZkN0
		DdnNM98ABoI6AfY6QeeIAVtSk2Ano9zqmIvzFnjegmdF6MhR3/D+ARFH5weQS9RDpCT9JLBNqkm6gH9MADgEeSNapTDz
		xQsCKeL/M4QIcsH74hlfexcgDQkdsLtKMLtAAAAABJRU5ErkJggg==')
        }        
        .custom-style li.add{
            background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/
            9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABl0RVh0U29mdHdhcmUAcGFpbn
            QubmV0IDQuMC4xMkMEa+wAAABkSURBVDhPpc1bCkAhCEXR5j8qZ+ZFoTjCLsT7sSTNx3L3XzKYmXfpcCj
            JRAa6dKPDoSQTGejSjQ6HkkxkoEubNhMs3tDS8kG0mWrn8aILVfw9G0JrQZcObuWDaDPVzmMKi32+
            PhgFEhDFFe1qAAAAAElFTkSuQmCC')
        }
    </style>
    
    <!--<span class="code-comment"> /* CSS for the page */ --></span>
    <style>
        body{
            color: #444;
            font-family: verdana;
            font-size:13px;    
            padding: 20px;            
        }        
        
        span{ 
            border: dotted 1px #ccc; 
            background-color: #eee;
            margin: 10px 10px;
            width:140px;
            height:40px;
            padding-top:10px;
            display: inline-block;
            text-align:center;
        }
        
        div{
            border: dotted 1px #ccc; 
            margin: 30px 0px;
            padding:10px;
        }
        
    </style>
    
    <script type="text/javascript">
        // The code that implements the PopupMenu 'class'.
    
        // contextElement: the element we want have assigned a context popup menu.
        // popupElement:   the popping up menu.
        // both parameters are used by jQuery. 
        // They can be any valid selector or any jQuery element or any DOM element,
        // (the only thing this class expects id that the menu is made using 'ul'/'li' tags).
        function PopupMenu(contextElement, popupElement){
        
            // In that way, the "this" object is 'persisted'.
            var THIS = this;
            
            // Sends to the 'outside world' the DOM element that is using the popup menu 
            this.currentTarget;

            // The main purpose of this time is to maintain the menu visible also 
            // if the user leaves it accidentally (for a very short time)
            this.fadeLeaveTime = 300; // The time the menu takes to close after 
                                      // the user leaves without performing any click.
            this.fadeOpenTime  = 100; // The time the menu takes to open after a right click.        
            this.delayTime     = 300; // The time the menu remains visible if non used 
                                      // (no mouse_over on it) and before start to the fadeOut
            this.fadeCloseTyme = 100; // The time the menu takes to close after a click on a menu item.
            
            // this element is evaluated once (is used in many places)
            this.$popupElement = $(popupElement);
            
            // START =============================================================================== //
            // Manages the context menu for the provided element.
            // The actions to be performed (on the popup element) every time a contextmenu raises.
            
            $(contextElement)
            .contextmenu(function (jqEvent){
            
                // prevent the custom popup menu if the 'ctrl' key is pressed.
                if (jqEvent.ctrlKey){ return; }

                // Avoids the real one contextmenu
                jqEvent.preventDefault();
                
                // assigns the element that called the current popup.
                THIS.currentTarget = jqEvent.currentTarget;
                    
                THIS.$popupElement
                .stop(true, false)           // stops any pending effect            
                .fadeIn(THIS.fadeOpenTime)   // makes the menu visible.                    
                .delay(THIS.delayTime)       // waits before call the hover_in function.            
                .fadeOut(THIS.fadeLeaveTime) // close the menu if not used.        
                .css({                         // places the popup menu in the right position 
                    top:  (jqEvent.pageY - 0) + "px",
                    left: (jqEvent.pageX - 0) + "px"
                });
            });                
            // END  =============================================================================== //
            
            // START ============================================================================== //
            // The actions to be assigned once.
            
            function hover_in($element){        
                $element
                .stop(true, false)
                .fadeIn(THIS.fadeOpenTime);
            }    
            
            function hover_out($element){
                $element.delay(THIS.delayTime).fadeOut(THIS.fadeLeaveTime);
            }        
            
            // stops the context menu for the items of the popup menu and triggers the click event.
            function menuItem_contextmenu(jqEvent, $li){
                jqEvent.preventDefault();
                $li.trigger('click');
            }            
            
            this.$popupElement
            .hover(
                function(){hover_in ($(this))}, 
                function(){hover_out($(this))}
            )
            .find('li')
            .click(function(){                        
                $(this).closest('ul').fadeOut(THIS.fadeCloseTyme);
            })
            .contextmenu( function(jqEvent){
                menuItem_contextmenu(jqEvent, $(this));
            })
            // END  ================================================================================ //
            
            
        }
    </script>        
    
    <script type="text/javascript">
        
        // -------------------------------------------------------------------------- \\        
        
        // full jQuery use of the 'PopupMenu'
        jQuery(document).ready(function (){            

            var groupB = new PopupMenu('.groupB', "#pumB");            

            jQuery('#pumB li').click(function (){
                $(groupB.currentTarget)
                .text($(this).text());
            });            
        });    
        
        // look at the end of the page for the simplest use of the 'PopupMenu'
         
    </script>
    </head>
    <body>        
        
        <!--<span class="code-comment"> 
        =================================================================================== --></span>
        
        <!--<span class="code-comment"> the click event is managed by jQuery --></span>        
        <ul class='custom-menu custom-style' id="pumB">
          <li class="image edit"   >Edit B</li>
          <li class="image delete" >Delete B</li>
          <li class="image refresh">Refresh B</li>
          <li class="image add"    >Add new B</li>
        </ul>
        
        <div>            
            <p>These two elements share the same context popup menu, 
            the click event is managed by jQuery (look at the javascript code).</p>
            <span class="groupB" id="spnB1">Right click me</span>
            <span class="groupB" id="spnB2">Right click me</span>    
        </div>    
        
        <!--<span class="code-comment"> 
        ----------------------------------------------------------------------------------- 
        --></span>
        
        <!--<span class="code-comment"> on-line management of the click event --></span>
        <ul class='custom-menu custom-style' id="pumA">
          <li class="image edit"   onclick="liEditA_onclick()"  >Edit A</li>
          <li class="image delete" onclick="liDeleteA_onclick()">Delete A</li>
          <li class="image add"    onclick="liAddA_onclick()"   >Add new A</li>
        </ul>

        <div>
            <p>This element has its own, different, context popup menu and 
            the click event is managed on line (look at the HTML code).</p>
            <span id="spnA">Right click me</span> 
        </div>
        
        <!--<span class="code-comment"> 
        ======================================================================================== 
        --></span>
        
        <p>Hit the '<b>Ctrl</b>' key (while right click) 
        to show the 'real' context menu.</p>
        
    </body>
    
    <script type="text/javascript">    
        
        new PopupMenu('#spnA', "#pumA");
        
        function liEditA_onclick(){
            $('#spnA').text("Edit A");
        }
        
        function liDeleteA_onclick(){
            $('#spnA').text("Delete A");
        }

        function liAddA_onclick(){
            $('#spnA').text("Add A");
        }    
         
    </script>    
    
    <script type="text/javascript">    
        
        window.onerror = function() {
            document.write('<label style="color:red;">** ATTENTION ** 
            Something went wrong :-(</label>');
        };
    </script>
</html>

Points of Interest

There is an important "point of interest" in the code that is a kind of "ubiquity": the same 'onclick' event that occurs for each of the items (<li>) of the popup menu is managed in two different places:

  • In the implementation of the object, the onclick (where manages the fadeOut of the popup menu):

  • In the custom code section (where manages the action to perform on click on the menu):

Please note that the both the 'li' in the code shown in the pictures are the same DOM element.

History

  • 8th July, 2017: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Member 270861
Engineer ACME
United Kingdom United Kingdom
I like to find simple solution to general (software) problem.
Some I published here and hope you enjoy them

cheers

You may also be interested in...

Comments and Discussions

 
-- There are no messages in this forum --
Permalink | Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.170915.1 | Last Updated 8 Jul 2017
Article Copyright 2017 by Member 270861
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid