Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bring a context menu on clicking to a more button using css

My requirement is to show a menu on clicking to the more button on the tree node. It should be near to the clicked node. You can see the more options icon only hover on the tree node. Following are the HTML and CSS codes which I am using now.

.tree ul {
    margin-left: 20px;
}

.tree li {
    list-style-type: none;
    margin:15px;
    position: relative;
    cursor: pointer;
}

.tree li .submenuBtn{
    margin-left:8px;
    display: none;
    font-weight:bolder;
}

.tree li a:hover .submenuBtn{
    display: inline-block;
}

.tree li img::clicked + #contextMenu{
    display: inline-block;
}

.tree li::before {
    content: "";
    position: absolute;
    top:-7px;
    left:-20px;
    border-left: 1px solid #ccc;
    border-bottom:1px solid #ccc;
    border-radius:0 0 0 0px;
    width:20px;
    height:15px;
}

.tree li::after {
    position:absolute;
    content:"";
    top:8px;
    left:-20px;
    border-left: 1px solid #ccc;
    border-top:1px solid #ccc;
    border-radius:0px 0 0 0;
    width:20px;
    height:100%;
}

.tree li:last-child::after  {
    display:none;
}

.tree li:last-child:before{
    border-radius: 0 0 0 5px;
}

ul.tree>li:first-child::before {
    display:none;
}

ul.tree>li:first-child::after {
    border-radius:5px 0 0 0;
}

.tree li a {
    border: 1px #ccc solid;
    border-radius: 5px;
    padding:5px 10px;
}

.tree li a:hover, .tree li a:hover+ul li a,
.tree li a:focus, .tree li a:focus+ul li a {
    background: #ccc; color: #000; 
    /*border: 1px solid #000;*/
    text-decoration: none;
}

.tree li a:hover+ul li::after, .tree li a:focus+ul li::after,
.tree li a:hover+ul li::before, .tree li a:focus+ul li::before 
.tree li a:hover+ul::before, .tree li a:focus+ul::before 
.tree li a:hover+ul ul::before, .tree li a:focus+ul ul::before{
    /*border-color:  #000; */
    /*connector color on hover*/
}
<ul class="tree">
            <li><a>Parent 1 <div class="submenuBtn">:</div></a></li>
            <li><a>Parent 2<div class="submenuBtn">:</div></a></li>
            <li>
                <a>Parent 3<div class="submenuBtn">:</div></a>
                <ul>
                    <li>
                        <a>1st Child of 3<div class="submenuBtn">:</div></a>
                        <ul>
                            <li><a>1st grandchild<div class="submenuBtn">:</div></a></li>
                            <li><a>2nd grandchild<div class="submenuBtn">:</div></a></li>
                        </ul>
                    </li>
                    <li><a>2nd Child of 3<div class="submenuBtn">:</div></a></li>
                    <li><a>3rd Child of 3<div class="submenuBtn">:</div></a></li>
                </ul>
            </li>
            <li>
                <a>Parent 4<div class="submenuBtn">:</div></a>
                <ul><li><a>Parent 4's only child<div class="submenuBtn">:</div></a></li></ul>
            </li>
        </ul>

Is it possible to reuse a single context menu for this purpose or I need to add the menus along with each node.

like image 904
Libin C Jacob Avatar asked Jun 19 '18 09:06

Libin C Jacob


1 Answers

Re-using a context menu via a template is of course more efficient, as opposed to repeating the menu as a child element for each node.

Javascript is the way to go.

There's many ways to do templating in JS. You could look at templating systems like Mustache, Handlebars or Underscore, especially if you need templating all over the place, like in a single-page app.

If your templating need is a one-off thing, then you can do a plain Javascript solution like the following:

1. Define the template

Option 1 - Store the template completely in JS:

var myTemplate = '<h1>MENU</h1><div class="menu_links"><a href="link1.html" class="menu_link">Link 1</a><a href="link2.html" class="menu_link">Link 2</a></div>';

Option 2 - Store the template in the page:

As a HTML element, hidden from view with CSS, but still in the page DOM...

<div id="template_menu" style="visibility: hidden;"><h1>MENU</h1><div class="menu_links"><a href="link1.html" class="menu_link">Link 1</a><a href="link2.html" class="menu_link">Link 2</a></div></div>

... or in a script tag, which completely hides it from the page DOM, no CSS required, but is still accessible by JS:

<script id="template_menu" type="x-template">
    <h1>MENU</h1><div class="menu_links"><a href="link1.html" class="menu_link">Link 1</a><a href="link2.html" class="menu_link">Link 2</a></div>
</script>

Option 2 cont'd: In either case, if the template is stored in the page, you'd need to declare the element in JS:

var myTemplate = document.getElementById("template_menu");

2. Use the menu template in JS

Ultimately something like this is how you'd use the template, in addition to a bunch of other JS functions and listeners to get a complete experience:

function openSubMenu(e) {

    // First, make a new element
    var newElement = document.createElement("div");

    // Apply the contents of the template to your new element
    newElement.innerHTML = myTemplate.innerHTML;  

    // Append the new element into the DOM. Here I'm adding it to the parent of the clicked element, but it's up to you how you want to structure things.
    e.parentElement.appendChild(newElement);
}

Ultimately there may be a clever, clunky CSS-only solution, perhaps using HTML5 data attributes and hidden checkboxes, but at the sacrifice of some bells and whistles. When it comes to templates and popups Javascript has relatively unlimited potential in comparison.

On a side note, I would avoid any 'hover' features as any touchscreen user will have an issue with that and you'll have more states to manage in JS. If you do implement hover features, you may find it's better to manage it all in JS, alongside your other listeners, rather than mentally juggling between CSS :hover and JS.

like image 61
MarsAndBack Avatar answered Oct 05 '22 11:10

MarsAndBack