ContextMenu and Element Selection

by vikikamath

HTML

<nav class="context-menu collapse">
  <ul class="flex flex-col items">
    <li id="view" class="item">View Component</li>
    <li id="edit" class="item">Edit Component</li>
    <li id="delete" class="item">Delete Component</li>
  </ul>
</nav>
<main>
  <div class="flex flex-row flex-wrap">
    <div id="1" class="post blue flex flex-row flex-wrap" data-attr="INVESTMENT_ACCOUNT.accountNameLabel">
      <div id="1.1" class="post yellow"></div>
      <div id="1.2" class="post yellow flex flex-row flex-wrap">
        <div id="1.2.1" class="post green"></div>
        <div id="1.2.2" class="post green"></div>
        <div id="1.2.3" class="post green"></div>
      </div>
    </div>
    <div id="2" class="post blue" data-attr="INVESTMENT_ACCOUNT.accountNameLabel"></div>
    <div id="3" class="post blue flex flex-row flex-wrap" data-attr="INVESTMENT_ACCOUNT.accountNameLabel">
      <div id="3.1" class="post yellow flex flex-row flex-wrap">
        <div id="3.1.1" class="post green"></div>
        <div id="3.1.2" class="post green"></div>
        <div id="3.1.3" class="post green"></div>
      </div>
    </div>
    <div id="4" class="post blue flex flex-row flex-wrap" data-attr="INVESTMENT_ACCOUNT.accountNameLabel">
      <div id="4.1" class="post yellow flex flex-row flex-wrap">
        <div id="4.1.1" class="post green"></div>
        <div id="4.1.2" class="post green"></div>
        <div id="4.1.3" class="post green"></div>
      </div>
      <div id="4.2" class="post yellow flex flex-row flex-wrap">
        <div id="4.2.1" class="post green"></div>
        <div id="4.2.2" class="post green"></div>
        <div id="4.2.3" class="post green"></div>
      </div>
    </div>
    <div id="5" class="post blue" data-attr="INVESTMENT_ACCOUNT.accountNameLabel"></div>
    <div id="6" class="post blue flex flex-row flex-wrap" data-attr="INVESTMENT_ACCOUNT.accountNameLabel">
      <div id="6.1" class="post yellow">
        <div id="6.1.1" class="post green"></div>
        <div...

CSS

* {
  box-sizing: border-box;
}

body {
  font: 16px 'Helvetica Neue', sans-serif;
}

.context-menu {
  /* position: absolute; */
  z-index: 1000;
  background: #fff;
  border: 1px solid #ccc;
  box-shadow: 5px 2px 2px gray;
  color: #000;
  padding: 0.3rem;
  max-width: 10rem;
  text-align: center;
}

.collapse {
  display: none;
}

.items {
  list-style: none;
  padding: 0.2rem 0.2rem;
  margin: 0;
}

.item {
  padding: 0.3rem 0;
  border-bottom: 1px solid #c0c0c0;
}

.item:hover {
  border-bottom: 4px solid #b54637;
}

.flex {
  display: flex;
}

.flex-col {
  flex-direction: column;
}

.flex-row {
  flex-direction: row;
}

.flex-wrap {
  flex-wrap: wrap
}

.post {
  width: 250px;
  height: 250px;
  margin: 10px;
}

.blue {
  background: orange;
  color: white
}

.green {
  width: 20px;
  height: 20px;
  background: yellowgreen;
  color: white;
}

.yellow {
  width: 100px;
  height: 100px;
  background: yellow;
  color: black;
}

.selected {
  box-shadow: 5px 2px 2px red;
}

JavaScript

var ctxMenu = document.querySelector('.context-menu');


var Component = (function() {
  var selectedElement;
  var selectedComponent;
  var getComponentName = function(node) {
  	if (node.dataset && node.dataset.attr) return node.dataset.attr;
    else getComponentName(node.parentNode)
  };
  return {
  	setSelected: function() {
    	var arr = document.querySelectorAll(':hover');
      selectedElement = arr.length ? arr[arr.length - 1]: undefined;
      selectedComponent = getComponentName(selectedElement);
    },
    getSelected: function() {
    	return selectedElement;
    },
  	getName: function() {
    	return selectedComponent;
    }
  };
})();


document.addEventListener('contextmenu', function(e) {
  e.preventDefault();
  e.stopPropagation();
  ctxMenu.style.top = '' + e.offsetY + 'px';
  ctxMenu.style.left = '' + e.offsetX + 'px';
  Component.setSelected();
  Component.getSelected().classList.add('selected');
  //console.log(document.querySelectorAll( ":hover" ));
  //console.log('before:', comp.getSelected());
  ctxMenu.classList.remove('collapse');
})

ctxMenu.addEventListener('mouseleave', function() {
  ctxMenu.classList.add('collapse');
  Component.getSelected().classList.remove('selected');
})

ctxMenu.addEventListener('click', function(e) {
  //console.log(e.target.id);
  //console.log('current Mouse pos', e.offsetX, e.offsetY);
  console.log(e.target.id, " component:", Component.getSelected());
  console.log(e.target.id, " component:", Component.getName());
})