mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Merge pull request #8001 from WilliamHolden/dont_close_menu_on_dropdown_header_click
Don't close popup menu if header item is clicked
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
import $ from "jquery";
|
||||
import _ from "underscore";
|
||||
import Backbone from "backbone";
|
||||
var PopupMenu = Backbone.View.extend({
|
||||
const PopupMenu = Backbone.View.extend({
|
||||
//TODO: maybe better as singleton off the Galaxy obj
|
||||
/** Cache the desired button element and options, set up the button click handler
|
||||
* NOTE: attaches this view as HTML/jQ data on the button for later use.
|
||||
@@ -20,11 +20,10 @@ var PopupMenu = Backbone.View.extend({
|
||||
this.$button.data("popupmenu", this);
|
||||
|
||||
// set up button click -> open menu behavior
|
||||
var menu = this;
|
||||
this.$button.click(event => {
|
||||
// if there's already a menu open, remove it
|
||||
$(".popmenu-wrapper").remove();
|
||||
menu._renderAndShow(event);
|
||||
this._renderAndShow(event);
|
||||
return false;
|
||||
});
|
||||
},
|
||||
@@ -51,13 +50,12 @@ var PopupMenu = Backbone.View.extend({
|
||||
|
||||
// set up behavior on each link/anchor elem
|
||||
if (this.options.length) {
|
||||
var menu = this;
|
||||
this.$(".popupmenu-option").each(function(i) {
|
||||
var option = menu.options[i];
|
||||
this.$(".popupmenu-option").each((i, el) => {
|
||||
const option = this.options[i];
|
||||
// if the option has 'func', call that function when the anchor is clicked
|
||||
if (option.func) {
|
||||
$(this).click(event => {
|
||||
option.func.call(menu, event, option);
|
||||
$(el).click(event => {
|
||||
option.func.call(this, event, option);
|
||||
// We must preventDefault otherwise clicking "cancel"
|
||||
// on a purge or something still navigates and causes
|
||||
// the action.
|
||||
@@ -86,9 +84,9 @@ var PopupMenu = Backbone.View.extend({
|
||||
} else if (option.header) {
|
||||
return `<div class="popupmenu-option dropdown-header">${option.html}</div>`;
|
||||
}
|
||||
var href = option.href || "javascript:void(0);";
|
||||
var target = option.target ? `target="${option.target}"` : "";
|
||||
var check = option.checked ? '<span class="fa fa-check mr-1"/>' : "";
|
||||
const href = option.href || "javascript:void(0);";
|
||||
const target = option.target ? `target="${option.target}"` : "";
|
||||
const check = option.checked ? '<span class="fa fa-check mr-1"/>' : "";
|
||||
return `<a class="popupmenu-option dropdown-item" href="${href}" ${target}>${check}${option.html}</a>`;
|
||||
}).join("");
|
||||
},
|
||||
@@ -96,8 +94,8 @@ var PopupMenu = Backbone.View.extend({
|
||||
// get the absolute position/offset for the menu
|
||||
_getShownPosition: function(clickEvent) {
|
||||
// display menu horiz. centered on click...
|
||||
var menuWidth = this.$el.width();
|
||||
var x = clickEvent.pageX - menuWidth / 2;
|
||||
const menuWidth = this.$el.width();
|
||||
let x = clickEvent.pageX - menuWidth / 2;
|
||||
|
||||
// adjust to handle horiz. scroll and window dimensions ( draw entirely on visible screen area )
|
||||
x = Math.min(x, $(document).scrollLeft() + $(window).width() - menuWidth - 5);
|
||||
@@ -111,11 +109,14 @@ var PopupMenu = Backbone.View.extend({
|
||||
// bind an event handler to all available frames so that when anything is clicked
|
||||
// the menu is removed from the DOM and the event handler unbinds itself
|
||||
_setUpCloseBehavior: function() {
|
||||
var menu = this;
|
||||
//TODO: alternately: focus hack, blocking overlay, jquery.blockui
|
||||
|
||||
// function to close popup and unbind itself
|
||||
function closePopup(event) {
|
||||
const closePopup = event => {
|
||||
//do nothing if header item is clicked
|
||||
if (event.target.classList.contains("dropdown-header")) {
|
||||
return;
|
||||
}
|
||||
$(document).off("click.close_popup");
|
||||
try {
|
||||
if (window && window.parent !== window) {
|
||||
@@ -134,19 +135,19 @@ var PopupMenu = Backbone.View.extend({
|
||||
console.debug(err);
|
||||
}
|
||||
}
|
||||
menu.remove();
|
||||
}
|
||||
this.remove();
|
||||
};
|
||||
|
||||
$("html").one("click.close_popup", closePopup);
|
||||
$("html").on("click.close_popup", closePopup);
|
||||
try {
|
||||
if (window && window.parent !== window) {
|
||||
$(window.parent.document)
|
||||
.find("html")
|
||||
.one("click.close_popup", closePopup);
|
||||
.on("click.close_popup", closePopup);
|
||||
} else {
|
||||
$("iframe#galaxy_main")
|
||||
.contents()
|
||||
.one("click.close_popup", closePopup);
|
||||
.on("click.close_popup", closePopup);
|
||||
}
|
||||
} catch (err) {
|
||||
if (err instanceof DOMException) {
|
||||
@@ -177,7 +178,7 @@ var PopupMenu = Backbone.View.extend({
|
||||
|
||||
// search for a menu option by its html
|
||||
findIndexByHtml: function(html) {
|
||||
for (var i = 0; i < this.options.length; i++) {
|
||||
for (let i = 0; i < this.options.length; i++) {
|
||||
if (_.has(this.options[i], "html") && this.options[i].html === html) {
|
||||
return i;
|
||||
}
|
||||
@@ -200,134 +201,5 @@ PopupMenu.create = function _create($button, options) {
|
||||
return new PopupMenu($button, options);
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// the following class functions are bridges from the original make_popupmenu and make_popup_menus
|
||||
// to the newer backbone.js PopupMenu
|
||||
|
||||
/** Create a PopupMenu from simple map initial_options activated by clicking button_element.
|
||||
* Converts initial_options to object array used by PopupMenu.
|
||||
* @param {jQuery|DOMElement} button_element element which, when clicked, activates menu
|
||||
* @param {Object} initial_options map of key -> values, where
|
||||
* key is option text, value is fn to call when option is clicked
|
||||
* @returns {PopupMenu} the PopupMenu created
|
||||
*/
|
||||
PopupMenu.make_popupmenu = (button_element, initial_options) => {
|
||||
var convertedOptions = [];
|
||||
_.each(initial_options, (optionVal, optionKey) => {
|
||||
var newOption = { html: optionKey };
|
||||
|
||||
// keys with null values indicate: header
|
||||
if (optionVal === null) {
|
||||
// !optionVal? (null only?)
|
||||
newOption.header = true;
|
||||
|
||||
// keys with function values indicate: a menu option
|
||||
} else if ($.type(optionVal) === "function") {
|
||||
newOption.func = optionVal;
|
||||
}
|
||||
//TODO:?? any other special optionVals?
|
||||
// there was no divider option originally
|
||||
convertedOptions.push(newOption);
|
||||
});
|
||||
return new PopupMenu($(button_element), convertedOptions);
|
||||
};
|
||||
|
||||
/** Find all anchors in $parent (using selector) and covert anchors into a PopupMenu options map.
|
||||
* @param {jQuery} $parent the element that contains the links to convert to options
|
||||
* @param {String} selector jq selector string to find links
|
||||
* @returns {Object[]} the options array to initialize a PopupMenu
|
||||
*/
|
||||
//TODO: lose parent and selector, pass in array of links, use map to return options
|
||||
PopupMenu.convertLinksToOptions = ($parent, selector) => {
|
||||
$parent = $($parent);
|
||||
selector = selector || "a";
|
||||
var options = [];
|
||||
$parent.find(selector).each((elem, i) => {
|
||||
var option = {};
|
||||
var $link = $(elem);
|
||||
|
||||
// convert link text to the option text (html) and the href into the option func
|
||||
option.html = $link.text();
|
||||
if ($link.attr("href")) {
|
||||
var linkHref = $link.attr("href");
|
||||
var linkTarget = $link.attr("target");
|
||||
var confirmText = $link.attr("confirm");
|
||||
|
||||
option.func = () => {
|
||||
// if there's a "confirm" attribute, throw up a confirmation dialog, and
|
||||
// if the user cancels - do nothing
|
||||
if (confirmText && !confirm(confirmText)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if there's no confirm attribute, or the user accepted the confirm dialog:
|
||||
switch (linkTarget) {
|
||||
// relocate the center panel
|
||||
case "_parent":
|
||||
window.parent.location = linkHref;
|
||||
break;
|
||||
|
||||
// relocate the entire window
|
||||
case "_top":
|
||||
window.top.location = linkHref;
|
||||
break;
|
||||
|
||||
// relocate this panel
|
||||
default:
|
||||
window.location = linkHref;
|
||||
}
|
||||
};
|
||||
}
|
||||
options.push(option);
|
||||
});
|
||||
return options;
|
||||
};
|
||||
|
||||
/** Create a single popupmenu from existing DOM button and anchor elements
|
||||
* @param {jQuery} $buttonElement the element that when clicked will open the menu
|
||||
* @param {jQuery} $menuElement the element that contains the anchors to convert into a menu
|
||||
* @param {String} menuElementLinkSelector jq selector string used to find anchors to be made into menu options
|
||||
* @returns {PopupMenu} the PopupMenu (Backbone View) that can render, control the menu
|
||||
*/
|
||||
PopupMenu.fromExistingDom = ($buttonElement, $menuElement, menuElementLinkSelector) => {
|
||||
$buttonElement = $($buttonElement);
|
||||
$menuElement = $($menuElement);
|
||||
var options = PopupMenu.convertLinksToOptions($menuElement, menuElementLinkSelector);
|
||||
// we're done with the menu (having converted it to an options map)
|
||||
$menuElement.remove();
|
||||
return new PopupMenu($buttonElement, options);
|
||||
};
|
||||
|
||||
/** Create all popupmenus within a document or a more specific element
|
||||
* @param {DOMElement} parent the DOM element in which to search for popupmenus to build (defaults to document)
|
||||
* @param {String} menuSelector jq selector string to find popupmenu menu elements (defaults to "div[popupmenu]")
|
||||
* @param {Function} buttonSelectorBuildFn the function to build the jq button selector.
|
||||
* Will be passed $menuElement, parent.
|
||||
* (Defaults to return '#' + $menuElement.attr( 'popupmenu' ); )
|
||||
* @returns {PopupMenu[]} array of popupmenus created
|
||||
*/
|
||||
PopupMenu.make_popup_menus = (parent, menuSelector, buttonSelectorBuildFn) => {
|
||||
parent = parent || document;
|
||||
// orig. Glx popupmenu menus have a (non-std) attribute 'popupmenu'
|
||||
// which contains the id of the button that activates the menu
|
||||
menuSelector = menuSelector || "div[popupmenu]";
|
||||
// default to (orig. Glx) matching button to menu by using the popupmenu attr of the menu as the id of the button
|
||||
buttonSelectorBuildFn = buttonSelectorBuildFn || (($menuElement, parent) => `#${$menuElement.attr("popupmenu")}`);
|
||||
|
||||
// aggregate and return all PopupMenus
|
||||
var popupMenusCreated = [];
|
||||
$(parent)
|
||||
.find(menuSelector)
|
||||
.each(function() {
|
||||
var $menuElement = $(this);
|
||||
|
||||
var $buttonElement = $(parent).find(buttonSelectorBuildFn($menuElement, parent));
|
||||
|
||||
popupMenusCreated.push(PopupMenu.fromDom($buttonElement, $menuElement));
|
||||
$buttonElement.addClass("popup");
|
||||
});
|
||||
return popupMenusCreated;
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
export default PopupMenu;
|
||||
|
||||
Reference in New Issue
Block a user