diff --git a/src/_h5ai/client/css/inc/context-menu.less b/src/_h5ai/client/css/inc/context-menu.less
deleted file mode 100644
index e38849e8..00000000
--- a/src/_h5ai/client/css/inc/context-menu.less
+++ /dev/null
@@ -1,31 +0,0 @@
-
-#view .context-menu {
-
- display: block;
- position: absolute;
- right: 0;
- top: 0;
- background-color: @col-widget-back;
- border: @border-widget;
- color: #999;
- z-index: 10;
-
- ul {
- margin: 0;
- padding: 0;
- list-style: none;
- text-align: left;
-
- li {
- padding: 8px 12px 10px 12px;
- white-space: nowrap;
- border-top: @border-widget-sep;
- .transition(all 0.2s ease-in-out);
-
- &:hover {
- color: @col-hover;
- background-color: @col-widget-back-hover;
- }
- }
- }
-}
diff --git a/src/_h5ai/client/css/inc/contextmenu.less b/src/_h5ai/client/css/inc/contextmenu.less
new file mode 100644
index 00000000..eca856be
--- /dev/null
+++ b/src/_h5ai/client/css/inc/contextmenu.less
@@ -0,0 +1,76 @@
+
+.cm-overlay {
+ display: none;
+ position: fixed;
+ left: 0;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ overflow: hidden;
+ z-index: 200;
+ // background: rgba(0,0,0,0.1);
+ // background: rgba(255,255,255,0.6);
+}
+
+
+.cm-panel {
+ display: block;
+ position: absolute;
+ left: 100px;
+ top: 100px;
+ background: #fff;
+ color: @col;
+ z-index: 10;
+ box-shadow: 0 0 20px 0 rgba(0,0,0,0.2);
+ overflow: auto;
+ min-width: 200px;
+
+ ul {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ text-align: left;
+
+ .cm-label {
+ padding: 8px 16px;
+ white-space: nowrap;
+ font-weight: bold;
+ }
+
+ .cm-entry {
+ padding: 8px 16px;
+ white-space: nowrap;
+ cursor: pointer;
+
+ &:hover {
+ color: @col-hover;
+ background: rgba(0,0,0,0.05);
+ }
+
+ .cm-icon {
+ position: relative;
+ top: -2px;
+
+ img {
+ width: 20px;
+ height: 20px;
+ }
+
+ &.no-icon {
+ opacity: 0;
+ }
+ }
+
+ .cm-text {
+ margin: 0 0 0 12px;
+ }
+ }
+
+ .cm-sep {
+ height: 1px;
+ margin: 8px 0;
+ padding: 0;
+ border-top: 1px solid rgba(0,0,0,0.08);
+ }
+ }
+}
diff --git a/src/_h5ai/client/css/styles.less b/src/_h5ai/client/css/styles.less
index 0bc46a8a..148ad2da 100644
--- a/src/_h5ai/client/css/styles.less
+++ b/src/_h5ai/client/css/styles.less
@@ -22,7 +22,7 @@
@import "inc/view-details";
@import "inc/view-icons";
@import "inc/view-grid";
-// @import "inc/context-menu";
+@import "inc/contextmenu";
@import "inc/fallback";
@import "inc/responsive";
diff --git a/src/_h5ai/client/js/inc/ext/contextmenu.js b/src/_h5ai/client/js/inc/ext/contextmenu.js
new file mode 100644
index 00000000..b71c2fa8
--- /dev/null
+++ b/src/_h5ai/client/js/inc/ext/contextmenu.js
@@ -0,0 +1,173 @@
+modulejs.define('ext/contextmenu', ['$', '_', 'core/resource'], function ($, _, resource) {
+
+
+ var templateOverlay = '
';
+ var templatePanel = '';
+ var templateSep = '';
+ var templateEntry = '
';
+ var templateLabel = '';
+
+
+ function createOverlay(callback) {
+
+ var $overlay = $(templateOverlay);
+
+ $overlay
+ .on('click contextmenu', function (ev) {
+
+ ev.stopPropagation();
+ ev.preventDefault();
+
+ var cmId = $(ev.target).closest('.cm-entry').data('cm-id');
+
+ if (ev.target === $overlay[0] || cmId !== undefined) {
+ $overlay.remove();
+ callback(cmId);
+ }
+ });
+
+ return $overlay;
+ }
+
+ function createPanel(menu) {
+
+ var $panel = $(templatePanel);
+ var $ul = $panel.find('ul');
+ var $li;
+
+ _.each(menu, function (entry) {
+
+ if (entry.type === '-') {
+ $(templateSep).appendTo($ul);
+ }
+
+ else if (entry.type === 'l') {
+ $(templateLabel)
+ .find('.cm-text').text(entry.text).end()
+ .appendTo($ul);
+ }
+
+ else if (entry.type === 'e') {
+ $li = $(templateEntry)
+ .data('cm-id', entry.id)
+ .find('.cm-text').text(entry.text).end()
+ .appendTo($ul);
+
+ if (entry.icon) {
+ $li.find('.cm-icon img').attr('src', resource.icon(entry.icon));
+ } else {
+ $li.find('.cm-icon').addClass('no-icon');
+ }
+ }
+ });
+
+ return $panel;
+ }
+
+ function positionPanel($overlay, $panel, x, y) {
+
+ var margin = 4;
+
+ $panel.css({
+ left: 0,
+ top: 0,
+ opacity: 0
+ });
+ $overlay.show();
+
+ var overlayOffset = $overlay.offset();
+ var overlayLeft = overlayOffset.left;
+ var overlayTop = overlayOffset.top;
+ var overlayWidth = $overlay.outerWidth(true);
+ var overlayHeight = $overlay.outerHeight(true);
+
+ var panelOffset = $panel.offset();
+ var panelLeft = panelOffset.left;
+ var panelTop = panelOffset.top;
+ var panelWidth = $panel.outerWidth(true);
+ var panelHeight = $panel.outerHeight(true);
+
+ var posLeft = x;
+ var posTop = y;
+
+ if (panelWidth > overlayWidth - 2 * margin) {
+ posLeft = margin;
+ panelWidth = overlayWidth - 2 * margin;
+ }
+
+ if (panelHeight > overlayHeight - 2 * margin) {
+ posTop = margin;
+ panelHeight = overlayHeight - 2 * margin;
+ }
+
+ if (posLeft < overlayLeft + margin) {
+ posLeft = overlayLeft + margin;
+ }
+
+ if (posLeft + panelWidth > overlayLeft + overlayWidth - margin) {
+ posLeft = overlayLeft + overlayWidth - margin - panelWidth;
+ }
+
+ if (posTop < overlayTop + margin) {
+ posTop = overlayTop + margin;
+ }
+
+ if (posTop + panelHeight > overlayTop + overlayHeight - margin) {
+ posTop = overlayTop + overlayHeight - margin - panelHeight;
+ }
+
+ $panel.css({
+ left: posLeft,
+ top: posTop,
+ width: panelWidth,
+ height: panelHeight,
+ opacity: 1
+ });
+ }
+
+ function showMenuAt(x, y, menu, callback) {
+
+ var $overlay = createOverlay(callback);
+ var $panel = createPanel(menu);
+ $overlay.append($panel).appendTo('body');
+ positionPanel($overlay, $panel, x, y);
+ }
+
+ function init() {
+
+ $(document).on('contextmenu', function (ev) {
+
+ ev.stopPropagation();
+ ev.preventDefault();
+ $(ev.target).trigger($.Event('h5ai-contextmenu', {
+ originalEvent: ev,
+ showMenu: function (menu, callback) {
+
+ showMenuAt(ev.pageX, ev.pageY, menu, callback);
+ }
+ }));
+ });
+
+ // var menu = [
+ // {type: 'e', id: 'e1', text: 'testing context menus'},
+ // {type: 'e', id: 'e2', text: 'another entry'},
+ // {type: 'e', id: 'e3', text: 'one with icon', icon: 'folder'},
+ // {type: '-'},
+ // {type: 'e', id: 'e4', text: 'one with icon', icon: 'x'},
+ // {type: 'e', id: 'e5', text: 'one with icon', icon: 'img'}
+ // ];
+ // var callback = function (res) {
+
+ // window.console.log('>> CB-RESULT >> ' + res);
+ // };
+
+ // $(document).on('h5ai-contextmenu', '#items .item.folder', function (ev) {
+
+ // window.console.log('CM', ev);
+ // ev.showMenu(menu, callback);
+ // });
+ }
+
+
+ init();
+});