From 65ca06e7eaf6226f779f69107830aa9e620870c7 Mon Sep 17 00:00:00 2001 From: Lars Jung Date: Sun, 29 Mar 2015 00:31:50 +0100 Subject: [PATCH] Add contextmenu. --- src/_h5ai/client/css/inc/context-menu.less | 31 ---- src/_h5ai/client/css/inc/contextmenu.less | 76 +++++++++ src/_h5ai/client/css/styles.less | 2 +- src/_h5ai/client/js/inc/ext/contextmenu.js | 173 +++++++++++++++++++++ 4 files changed, 250 insertions(+), 32 deletions(-) delete mode 100644 src/_h5ai/client/css/inc/context-menu.less create mode 100644 src/_h5ai/client/css/inc/contextmenu.less create mode 100644 src/_h5ai/client/js/inc/ext/contextmenu.js 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(); +});