Skip to content

Instantly share code, notes, and snippets.

@BraynStorm
Last active April 29, 2016 06:16
Show Gist options
  • Save BraynStorm/2361fadb56b03b1222668a06bd0a6de8 to your computer and use it in GitHub Desktop.
Save BraynStorm/2361fadb56b03b1222668a06bd0a6de8 to your computer and use it in GitHub Desktop.
JS Context-menu helper
.context-menu{
position: absolute;
top: 0;
left: 0;
width: 150px;
padding: 5px;
border-radius: 5px;
background: #ededed;
font: 12px Verdana;
}
.context-menu-choice{
height: 20px;
padding-left: 15px;
}
.context-menu-choice:first-child{
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}
.context-menu-choice:last-child{
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
}
.context-menu-choice:hover{
background: rgba(255,255,255,1);
background: -moz-linear-gradient(top, rgba(255,255,255,1) 0%, rgba(246,246,246,1) 47%, rgba(237,237,237,1) 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(255,255,255,1)), color-stop(47%, rgba(246,246,246,1)), color-stop(100%, rgba(237,237,237,1)));
background: -webkit-linear-gradient(top, rgba(255,255,255,1) 0%, rgba(246,246,246,1) 47%, rgba(237,237,237,1) 100%);
background: -o-linear-gradient(top, rgba(255,255,255,1) 0%, rgba(246,246,246,1) 47%, rgba(237,237,237,1) 100%);
background: -ms-linear-gradient(top, rgba(255,255,255,1) 0%, rgba(246,246,246,1) 47%, rgba(237,237,237,1) 100%);
background: linear-gradient(to bottom, rgba(255,255,255,1) 0%, rgba(246,246,246,1) 47%, rgba(237,237,237,1) 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#ededed', GradientType=0 );
}
.context-menu-separator{
width: 100%;
height: 1px;
margin: 2px 0 2px 0;
background: #aaa;
}
.no-select {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor: default;
}
/**
* Created by Braynstorm on 10.4.2016 г..
*/
'use strict';
class ContextMenu {
constructor (id) {
this.choices = new Set();
this.isOpen = false;
this.holder = id.addClass("context-menu").css({display: "none"});
this.holder.innerHTML = ""; // "Tabula rasa".
this.currentTimeout = undefined;
this.holder.onMouseOver(() => {
this.isOpen = true;
clearTimeout(this.currentTimeout);
this.currentTimeout = setTimeout(() => {
this.refresh();
}, 500);
});
this.holder.onMouseOut(() => {
this.isOpen = false;
clearTimeout(this.currentTimeout);
this.currentTimeout = setTimeout(() => {
this.refresh();
}, 500);
});
}
addListChoice (text, callback) {
var div = $createDiv({
'class': 'context-menu-choice no-select'
});
div.onMouseUp((e) => {
close();
return callback(this.data, e);
});
div.innerHTML = text;
this.choices.add(div);
this.remakeHtml();
}
addSeparator () {
var div = $createDiv({
'class': 'context-menu-separator'
});
this.choices.add(div);
this.remakeHtml();
}
remakeHtml () {
this.holder.innerHTML = ""; // "Tabula rasa".
this.choices.forEach(choice => {
this.holder.appendChild(choice);
});
}
setPosition (x, y) {
this.x = x;
this.y = y;
this.refresh();
}
// TODO should it be like this, or just pass a ContextMenu instance on open along with the data??? Drawer-Entry -> RMB -> Questions Game what menu to open?
open (mouseEvent, data) {
this.isOpen = true;
clearTimeout(this.currentTimeout);
if (typeof mouseEvent !== 'undefined') {
this.setPosition(mouseEvent.pageX - 5, mouseEvent.pageY - 5);
}
this.data = data;
this.refresh();
}
close () {
this.isOpen = false;
clearTimeout(this.currentTimeout);
this.refresh();
}
refresh () {
this.holder.css({
display: (this.isOpen ? 'block' : 'none')
});
this.holder.cacheCurrentStyle();
if (this.x + Utils.stripPx(this.holder.getCachedStyle().width) > window.innerWidth)
this.x = window.innerWidth - Utils.stripPx(this.holder.getCachedStyle().width);
if (this.y + Utils.stripPx(this.holder.getCachedStyle().height) > window.innerHeight)
this.y = window.innerHeight - Utils.stripPx(this.holder.getCachedStyle().height);
this.holder.css({
top : this.y + "px",
left: this.x + "px"
})
}
}
class ContextMenuManager {
static init () {
this.menus = new Map();
}
static addMenu (name, menu) {
if (this.menus.has(name))
return false;
this.menus.set(name, menu);
}
static removeMenu (name) {
this.menus.delete(name);
}
static getMenu (name) {
return this.menus.get(name);
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Context Menu JS Test</title>
<link href="context-menu.css" rel="stylesheet"/>
<script src="../crude-jquery/crude-jquery.js"></script>
<script src="context-menu.js"></script>
<script>
'use strict';
var stuff = {};
function f (e) {
debug(e);
}
function main () {
stuff.menu1 = new ContextMenu("#context-menu");
stuff.menu1.addListChoice("Invite to room", f);
stuff.menu1.addListChoice("Freak out", f);
stuff.menu1.addListChoice("Chat", f);
stuff.menu1.addSeparator();
stuff.menu1.addListChoice("Broadcast", f);
stuff.menu1.addListChoice("Smite!", f);
var playerName = $("#clickMe");
playerName.onContextMenu(function (e) {
stuff.menu1.setPosition(e.pageX - 5, e.pageY - 5);
stuff.menu1.open();
e.preventDefault();
return false;
});
}
</script>
<style>
#clickMe {
width: 100px;
height: 100px;
background: yellow;
}
</style>
</head>
<body onload="main()">
<div id="clickMe">Click Me!</div>
<div id="context-menu"></div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment