mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Client build: modularize popup menu from ui.js
This commit is contained in:
@@ -3,7 +3,11 @@
|
||||
jQuery.ajaxSettings.traditional = true;
|
||||
|
||||
// dependencies
|
||||
define(['mvc/grid/grid-model', 'mvc/grid/grid-template', 'mvc/ui'], function(GridModel, Templates) {
|
||||
define([
|
||||
'mvc/grid/grid-model',
|
||||
'mvc/grid/grid-template',
|
||||
"mvc/ui/popup-menu"
|
||||
], function(GridModel, Templates, PopupMenu) {
|
||||
|
||||
// grid view
|
||||
return Backbone.View.extend({
|
||||
@@ -661,4 +665,4 @@ return Backbone.View.extend({
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,6 +8,7 @@ define([
|
||||
"mvc/tags",
|
||||
"mvc/annotations",
|
||||
"jq-plugins/ui/fa-icon-button",
|
||||
"mvc/ui/popup-menu",
|
||||
"utils/localization"
|
||||
], function(
|
||||
HPANEL,
|
||||
@@ -19,6 +20,7 @@ define([
|
||||
TAGS,
|
||||
ANNOTATIONS,
|
||||
faIconButton,
|
||||
PopupMenu,
|
||||
_l
|
||||
){
|
||||
/* =============================================================================
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
define([
|
||||
"mvc/ui/popup-menu",
|
||||
"mvc/base-mvc",
|
||||
"utils/localization"
|
||||
], function( BASE_MVC, _l ){
|
||||
], function( PopupMenu, BASE_MVC, _l ){
|
||||
// ============================================================================
|
||||
var menu = [
|
||||
{
|
||||
|
||||
@@ -169,320 +169,3 @@ var create_icon_buttons_menu = function(config, global_config)
|
||||
// return menu
|
||||
return new IconButtonMenuView( {collection: buttons} );
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
/**
|
||||
*
|
||||
*/
|
||||
var Grid = Backbone.Collection.extend({
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
var GridView = Backbone.View.extend({
|
||||
|
||||
});
|
||||
|
||||
// =============================================================================
|
||||
/**
|
||||
* view for a popup menu
|
||||
*/
|
||||
var 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.
|
||||
*/
|
||||
initialize: function( $button, options ){
|
||||
// default settings
|
||||
this.$button = $button;
|
||||
if( !this.$button.size() ){
|
||||
this.$button = $( '<div/>' );
|
||||
}
|
||||
this.options = options || [];
|
||||
|
||||
// set up button click -> open menu behavior
|
||||
var menu = this;
|
||||
this.$button.click( function( event ){
|
||||
// if there's already a menu open, remove it
|
||||
$( '.popmenu-wrapper' ).remove();
|
||||
menu._renderAndShow( event );
|
||||
return false;
|
||||
});
|
||||
},
|
||||
|
||||
// render the menu, append to the page body at the click position, and set up the 'click-away' handlers, show
|
||||
_renderAndShow: function( clickEvent ){
|
||||
this.render();
|
||||
this.$el.appendTo( 'body' ).css( this._getShownPosition( clickEvent )).show();
|
||||
this._setUpCloseBehavior();
|
||||
},
|
||||
|
||||
// render the menu
|
||||
// this menu doesn't attach itself to the DOM ( see _renderAndShow )
|
||||
render: function(){
|
||||
// render the menu body absolute and hidden, fill with template
|
||||
this.$el.addClass( 'popmenu-wrapper' ).hide()
|
||||
.css({ position : 'absolute' })
|
||||
.html( this.template( this.$button.attr( 'id' ), this.options ));
|
||||
|
||||
// set up behavior on each link/anchor elem
|
||||
if( this.options.length ){
|
||||
var menu = this;
|
||||
//precondition: there should be one option per li
|
||||
this.$el.find( 'li' ).each( function( i, li ){
|
||||
var option = menu.options[i];
|
||||
|
||||
// if the option has 'func', call that function when the anchor is clicked
|
||||
if( option.func ){
|
||||
$( this ).children( 'a.popupmenu-option' ).click( function( event ){
|
||||
option.func.call( menu, event, option );
|
||||
// bubble up so that an option click will call the close behavior
|
||||
//return false;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
template : function( id, options ){
|
||||
return [
|
||||
'<ul id="', id, '-menu" class="dropdown-menu">', this._templateOptions( options ), '</ul>'
|
||||
].join( '' );
|
||||
},
|
||||
|
||||
_templateOptions : function( options ){
|
||||
if( !options.length ){
|
||||
return '<li>(no options)</li>';
|
||||
}
|
||||
return _.map( options, function( option ){
|
||||
if( option.divider ){
|
||||
return '<li class="divider"></li>';
|
||||
} else if( option.header ){
|
||||
return [ '<li class="head"><a href="javascript:void(0);">', option.html, '</a></li>' ].join( '' );
|
||||
}
|
||||
var href = option.href || 'javascript:void(0);',
|
||||
target = ( option.target )?( ' target="' + option.target + '"' ):( '' ),
|
||||
check = ( option.checked )?( '<span class="fa fa-check"></span>' ):( '' );
|
||||
return [
|
||||
'<li><a class="popupmenu-option" href="', href, '"', target, '>',
|
||||
check, option.html,
|
||||
'</a></li>'
|
||||
].join( '' );
|
||||
}).join( '' );
|
||||
},
|
||||
|
||||
// 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 ;
|
||||
|
||||
// adjust to handle horiz. scroll and window dimensions ( draw entirely on visible screen area )
|
||||
x = Math.min( x, $( document ).scrollLeft() + $( window ).width() - menuWidth - 5 );
|
||||
x = Math.max( x, $( document ).scrollLeft() + 5 );
|
||||
return {
|
||||
top: clickEvent.pageY,
|
||||
left: x
|
||||
};
|
||||
},
|
||||
|
||||
// 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 ){
|
||||
$( document ).off( 'click.close_popup' );
|
||||
if( window.parent !== window ){
|
||||
try {
|
||||
$( window.parent.document ).off( "click.close_popup" );
|
||||
} catch( err ){}
|
||||
} else {
|
||||
try {
|
||||
$( 'iframe#galaxy_main' ).contents().off( "click.close_popup" );
|
||||
} catch( err ){}
|
||||
}
|
||||
menu.remove();
|
||||
}
|
||||
|
||||
$( 'html' ).one( "click.close_popup", closePopup );
|
||||
if( window.parent !== window ){
|
||||
try {
|
||||
$( window.parent.document ).find( 'html' ).one( "click.close_popup", closePopup );
|
||||
} catch( err ){}
|
||||
} else {
|
||||
try {
|
||||
$( 'iframe#galaxy_main' ).contents().one( "click.close_popup", closePopup );
|
||||
} catch( err ){}
|
||||
}
|
||||
},
|
||||
|
||||
// add a menu option/item at the given index
|
||||
addItem: function( item, index ){
|
||||
// append to end if no index
|
||||
index = ( index >= 0 ) ? index : this.options.length;
|
||||
this.options.splice( index, 0, item );
|
||||
return this;
|
||||
},
|
||||
|
||||
// remove a menu option/item at the given index
|
||||
removeItem: function( index ){
|
||||
if( index >=0 ){
|
||||
this.options.splice( index, 1 );
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
// search for a menu option by its html
|
||||
findIndexByHtml: function( html ){
|
||||
for( var i = 0; i < this.options.length; i++ ){
|
||||
if( _.has( this.options[i], 'html' ) && ( this.options[i].html === html )){
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
// search for a menu option by its html
|
||||
findItemByHtml: function( html ){
|
||||
return this.options[( this.findIndexByHtml( html ))];
|
||||
},
|
||||
|
||||
// string representation
|
||||
toString: function(){
|
||||
return 'PopupMenu';
|
||||
}
|
||||
});
|
||||
/** shortcut to new for when you don't need to preserve the ref */
|
||||
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 = function( button_element, initial_options ){
|
||||
var convertedOptions = [];
|
||||
_.each( initial_options, function( 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( jQuery.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 = function( $parent, selector ){
|
||||
$parent = $( $parent );
|
||||
selector = selector || 'a';
|
||||
var options = [];
|
||||
$parent.find( selector ).each( function( elem, i ){
|
||||
var option = {}, $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' ),
|
||||
linkTarget = $link.attr( 'target' ),
|
||||
confirmText = $link.attr( 'confirm' );
|
||||
|
||||
option.func = function(){
|
||||
// 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 = function( $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 = function( 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 || function( $menuElement, parent ){
|
||||
return '#' + $menuElement.attr( 'popupmenu' );
|
||||
};
|
||||
|
||||
// aggregate and return all PopupMenus
|
||||
var popupMenusCreated = [];
|
||||
$( parent ).find( menuSelector ).each( function(){
|
||||
var $menuElement = $( this ),
|
||||
$buttonElement = $( parent ).find( buttonSelectorBuildFn( $menuElement, parent ) );
|
||||
popupMenusCreated.push( PopupMenu.fromDom( $buttonElement, $menuElement ) );
|
||||
$buttonElement.addClass( 'popup' );
|
||||
});
|
||||
return popupMenusCreated;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,311 @@
|
||||
define([
|
||||
//jquery
|
||||
//backbone
|
||||
], function(){
|
||||
// =============================================================================
|
||||
/**
|
||||
* view for a popup menu
|
||||
*/
|
||||
var 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.
|
||||
*/
|
||||
initialize: function( $button, options ){
|
||||
// default settings
|
||||
this.$button = $button;
|
||||
if( !this.$button.size() ){
|
||||
this.$button = $( '<div/>' );
|
||||
}
|
||||
this.options = options || [];
|
||||
|
||||
// set up button click -> open menu behavior
|
||||
var menu = this;
|
||||
this.$button.click( function( event ){
|
||||
// if there's already a menu open, remove it
|
||||
$( '.popmenu-wrapper' ).remove();
|
||||
menu._renderAndShow( event );
|
||||
return false;
|
||||
});
|
||||
},
|
||||
|
||||
// render the menu, append to the page body at the click position, and set up the 'click-away' handlers, show
|
||||
_renderAndShow: function( clickEvent ){
|
||||
this.render();
|
||||
this.$el.appendTo( 'body' ).css( this._getShownPosition( clickEvent )).show();
|
||||
this._setUpCloseBehavior();
|
||||
},
|
||||
|
||||
// render the menu
|
||||
// this menu doesn't attach itself to the DOM ( see _renderAndShow )
|
||||
render: function(){
|
||||
// render the menu body absolute and hidden, fill with template
|
||||
this.$el.addClass( 'popmenu-wrapper' ).hide()
|
||||
.css({ position : 'absolute' })
|
||||
.html( this.template( this.$button.attr( 'id' ), this.options ));
|
||||
|
||||
// set up behavior on each link/anchor elem
|
||||
if( this.options.length ){
|
||||
var menu = this;
|
||||
//precondition: there should be one option per li
|
||||
this.$el.find( 'li' ).each( function( i, li ){
|
||||
var option = menu.options[i];
|
||||
|
||||
// if the option has 'func', call that function when the anchor is clicked
|
||||
if( option.func ){
|
||||
$( this ).children( 'a.popupmenu-option' ).click( function( event ){
|
||||
option.func.call( menu, event, option );
|
||||
// bubble up so that an option click will call the close behavior
|
||||
//return false;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
template : function( id, options ){
|
||||
return [
|
||||
'<ul id="', id, '-menu" class="dropdown-menu">', this._templateOptions( options ), '</ul>'
|
||||
].join( '' );
|
||||
},
|
||||
|
||||
_templateOptions : function( options ){
|
||||
if( !options.length ){
|
||||
return '<li>(no options)</li>';
|
||||
}
|
||||
return _.map( options, function( option ){
|
||||
if( option.divider ){
|
||||
return '<li class="divider"></li>';
|
||||
} else if( option.header ){
|
||||
return [ '<li class="head"><a href="javascript:void(0);">', option.html, '</a></li>' ].join( '' );
|
||||
}
|
||||
var href = option.href || 'javascript:void(0);',
|
||||
target = ( option.target )?( ' target="' + option.target + '"' ):( '' ),
|
||||
check = ( option.checked )?( '<span class="fa fa-check"></span>' ):( '' );
|
||||
return [
|
||||
'<li><a class="popupmenu-option" href="', href, '"', target, '>',
|
||||
check, option.html,
|
||||
'</a></li>'
|
||||
].join( '' );
|
||||
}).join( '' );
|
||||
},
|
||||
|
||||
// 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 ;
|
||||
|
||||
// adjust to handle horiz. scroll and window dimensions ( draw entirely on visible screen area )
|
||||
x = Math.min( x, $( document ).scrollLeft() + $( window ).width() - menuWidth - 5 );
|
||||
x = Math.max( x, $( document ).scrollLeft() + 5 );
|
||||
return {
|
||||
top: clickEvent.pageY,
|
||||
left: x
|
||||
};
|
||||
},
|
||||
|
||||
// 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 ){
|
||||
$( document ).off( 'click.close_popup' );
|
||||
if( window.parent !== window ){
|
||||
try {
|
||||
$( window.parent.document ).off( "click.close_popup" );
|
||||
} catch( err ){}
|
||||
} else {
|
||||
try {
|
||||
$( 'iframe#galaxy_main' ).contents().off( "click.close_popup" );
|
||||
} catch( err ){}
|
||||
}
|
||||
menu.remove();
|
||||
}
|
||||
|
||||
$( 'html' ).one( "click.close_popup", closePopup );
|
||||
if( window.parent !== window ){
|
||||
try {
|
||||
$( window.parent.document ).find( 'html' ).one( "click.close_popup", closePopup );
|
||||
} catch( err ){}
|
||||
} else {
|
||||
try {
|
||||
$( 'iframe#galaxy_main' ).contents().one( "click.close_popup", closePopup );
|
||||
} catch( err ){}
|
||||
}
|
||||
},
|
||||
|
||||
// add a menu option/item at the given index
|
||||
addItem: function( item, index ){
|
||||
// append to end if no index
|
||||
index = ( index >= 0 ) ? index : this.options.length;
|
||||
this.options.splice( index, 0, item );
|
||||
return this;
|
||||
},
|
||||
|
||||
// remove a menu option/item at the given index
|
||||
removeItem: function( index ){
|
||||
if( index >=0 ){
|
||||
this.options.splice( index, 1 );
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
// search for a menu option by its html
|
||||
findIndexByHtml: function( html ){
|
||||
for( var i = 0; i < this.options.length; i++ ){
|
||||
if( _.has( this.options[i], 'html' ) && ( this.options[i].html === html )){
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
// search for a menu option by its html
|
||||
findItemByHtml: function( html ){
|
||||
return this.options[( this.findIndexByHtml( html ))];
|
||||
},
|
||||
|
||||
// string representation
|
||||
toString: function(){
|
||||
return 'PopupMenu';
|
||||
}
|
||||
});
|
||||
/** shortcut to new for when you don't need to preserve the ref */
|
||||
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 = function( button_element, initial_options ){
|
||||
var convertedOptions = [];
|
||||
_.each( initial_options, function( 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( jQuery.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 = function( $parent, selector ){
|
||||
$parent = $( $parent );
|
||||
selector = selector || 'a';
|
||||
var options = [];
|
||||
$parent.find( selector ).each( function( elem, i ){
|
||||
var option = {}, $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' ),
|
||||
linkTarget = $link.attr( 'target' ),
|
||||
confirmText = $link.attr( 'confirm' );
|
||||
|
||||
option.func = function(){
|
||||
// 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 = function( $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 = function( 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 || function( $menuElement, parent ){
|
||||
return '#' + $menuElement.attr( 'popupmenu' );
|
||||
};
|
||||
|
||||
// aggregate and return all PopupMenus
|
||||
var popupMenusCreated = [];
|
||||
$( parent ).find( menuSelector ).each( function(){
|
||||
var $menuElement = $( this ),
|
||||
$buttonElement = $( parent ).find( buttonSelectorBuildFn( $menuElement, parent ) );
|
||||
popupMenusCreated.push( PopupMenu.fromDom( $buttonElement, $menuElement ) );
|
||||
$buttonElement.addClass( 'popup' );
|
||||
});
|
||||
return popupMenusCreated;
|
||||
};
|
||||
|
||||
|
||||
// =============================================================================
|
||||
return PopupMenu;
|
||||
});
|
||||
|
||||
@@ -3,7 +3,11 @@
|
||||
jQuery.ajaxSettings.traditional = true;
|
||||
|
||||
// dependencies
|
||||
define(['mvc/grid/grid-model', 'mvc/grid/grid-template', 'mvc/ui'], function(GridModel, Templates) {
|
||||
define([
|
||||
'mvc/grid/grid-model',
|
||||
'mvc/grid/grid-template',
|
||||
"mvc/ui/popup-menu"
|
||||
], function(GridModel, Templates, PopupMenu) {
|
||||
|
||||
// grid view
|
||||
return Backbone.View.extend({
|
||||
@@ -661,4 +665,4 @@ return Backbone.View.extend({
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,6 +8,7 @@ define([
|
||||
"mvc/tags",
|
||||
"mvc/annotations",
|
||||
"jq-plugins/ui/fa-icon-button",
|
||||
"mvc/ui/popup-menu",
|
||||
"utils/localization"
|
||||
], function(
|
||||
HPANEL,
|
||||
@@ -19,6 +20,7 @@ define([
|
||||
TAGS,
|
||||
ANNOTATIONS,
|
||||
faIconButton,
|
||||
PopupMenu,
|
||||
_l
|
||||
){
|
||||
/* =============================================================================
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
define([
|
||||
"mvc/ui/popup-menu",
|
||||
"mvc/base-mvc",
|
||||
"utils/localization"
|
||||
], function( BASE_MVC, _l ){
|
||||
], function( PopupMenu, BASE_MVC, _l ){
|
||||
// ============================================================================
|
||||
var menu = [
|
||||
{
|
||||
|
||||
@@ -169,320 +169,3 @@ var create_icon_buttons_menu = function(config, global_config)
|
||||
// return menu
|
||||
return new IconButtonMenuView( {collection: buttons} );
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
/**
|
||||
*
|
||||
*/
|
||||
var Grid = Backbone.Collection.extend({
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
var GridView = Backbone.View.extend({
|
||||
|
||||
});
|
||||
|
||||
// =============================================================================
|
||||
/**
|
||||
* view for a popup menu
|
||||
*/
|
||||
var 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.
|
||||
*/
|
||||
initialize: function( $button, options ){
|
||||
// default settings
|
||||
this.$button = $button;
|
||||
if( !this.$button.size() ){
|
||||
this.$button = $( '<div/>' );
|
||||
}
|
||||
this.options = options || [];
|
||||
|
||||
// set up button click -> open menu behavior
|
||||
var menu = this;
|
||||
this.$button.click( function( event ){
|
||||
// if there's already a menu open, remove it
|
||||
$( '.popmenu-wrapper' ).remove();
|
||||
menu._renderAndShow( event );
|
||||
return false;
|
||||
});
|
||||
},
|
||||
|
||||
// render the menu, append to the page body at the click position, and set up the 'click-away' handlers, show
|
||||
_renderAndShow: function( clickEvent ){
|
||||
this.render();
|
||||
this.$el.appendTo( 'body' ).css( this._getShownPosition( clickEvent )).show();
|
||||
this._setUpCloseBehavior();
|
||||
},
|
||||
|
||||
// render the menu
|
||||
// this menu doesn't attach itself to the DOM ( see _renderAndShow )
|
||||
render: function(){
|
||||
// render the menu body absolute and hidden, fill with template
|
||||
this.$el.addClass( 'popmenu-wrapper' ).hide()
|
||||
.css({ position : 'absolute' })
|
||||
.html( this.template( this.$button.attr( 'id' ), this.options ));
|
||||
|
||||
// set up behavior on each link/anchor elem
|
||||
if( this.options.length ){
|
||||
var menu = this;
|
||||
//precondition: there should be one option per li
|
||||
this.$el.find( 'li' ).each( function( i, li ){
|
||||
var option = menu.options[i];
|
||||
|
||||
// if the option has 'func', call that function when the anchor is clicked
|
||||
if( option.func ){
|
||||
$( this ).children( 'a.popupmenu-option' ).click( function( event ){
|
||||
option.func.call( menu, event, option );
|
||||
// bubble up so that an option click will call the close behavior
|
||||
//return false;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
template : function( id, options ){
|
||||
return [
|
||||
'<ul id="', id, '-menu" class="dropdown-menu">', this._templateOptions( options ), '</ul>'
|
||||
].join( '' );
|
||||
},
|
||||
|
||||
_templateOptions : function( options ){
|
||||
if( !options.length ){
|
||||
return '<li>(no options)</li>';
|
||||
}
|
||||
return _.map( options, function( option ){
|
||||
if( option.divider ){
|
||||
return '<li class="divider"></li>';
|
||||
} else if( option.header ){
|
||||
return [ '<li class="head"><a href="javascript:void(0);">', option.html, '</a></li>' ].join( '' );
|
||||
}
|
||||
var href = option.href || 'javascript:void(0);',
|
||||
target = ( option.target )?( ' target="' + option.target + '"' ):( '' ),
|
||||
check = ( option.checked )?( '<span class="fa fa-check"></span>' ):( '' );
|
||||
return [
|
||||
'<li><a class="popupmenu-option" href="', href, '"', target, '>',
|
||||
check, option.html,
|
||||
'</a></li>'
|
||||
].join( '' );
|
||||
}).join( '' );
|
||||
},
|
||||
|
||||
// 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 ;
|
||||
|
||||
// adjust to handle horiz. scroll and window dimensions ( draw entirely on visible screen area )
|
||||
x = Math.min( x, $( document ).scrollLeft() + $( window ).width() - menuWidth - 5 );
|
||||
x = Math.max( x, $( document ).scrollLeft() + 5 );
|
||||
return {
|
||||
top: clickEvent.pageY,
|
||||
left: x
|
||||
};
|
||||
},
|
||||
|
||||
// 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 ){
|
||||
$( document ).off( 'click.close_popup' );
|
||||
if( window.parent !== window ){
|
||||
try {
|
||||
$( window.parent.document ).off( "click.close_popup" );
|
||||
} catch( err ){}
|
||||
} else {
|
||||
try {
|
||||
$( 'iframe#galaxy_main' ).contents().off( "click.close_popup" );
|
||||
} catch( err ){}
|
||||
}
|
||||
menu.remove();
|
||||
}
|
||||
|
||||
$( 'html' ).one( "click.close_popup", closePopup );
|
||||
if( window.parent !== window ){
|
||||
try {
|
||||
$( window.parent.document ).find( 'html' ).one( "click.close_popup", closePopup );
|
||||
} catch( err ){}
|
||||
} else {
|
||||
try {
|
||||
$( 'iframe#galaxy_main' ).contents().one( "click.close_popup", closePopup );
|
||||
} catch( err ){}
|
||||
}
|
||||
},
|
||||
|
||||
// add a menu option/item at the given index
|
||||
addItem: function( item, index ){
|
||||
// append to end if no index
|
||||
index = ( index >= 0 ) ? index : this.options.length;
|
||||
this.options.splice( index, 0, item );
|
||||
return this;
|
||||
},
|
||||
|
||||
// remove a menu option/item at the given index
|
||||
removeItem: function( index ){
|
||||
if( index >=0 ){
|
||||
this.options.splice( index, 1 );
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
// search for a menu option by its html
|
||||
findIndexByHtml: function( html ){
|
||||
for( var i = 0; i < this.options.length; i++ ){
|
||||
if( _.has( this.options[i], 'html' ) && ( this.options[i].html === html )){
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
// search for a menu option by its html
|
||||
findItemByHtml: function( html ){
|
||||
return this.options[( this.findIndexByHtml( html ))];
|
||||
},
|
||||
|
||||
// string representation
|
||||
toString: function(){
|
||||
return 'PopupMenu';
|
||||
}
|
||||
});
|
||||
/** shortcut to new for when you don't need to preserve the ref */
|
||||
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 = function( button_element, initial_options ){
|
||||
var convertedOptions = [];
|
||||
_.each( initial_options, function( 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( jQuery.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 = function( $parent, selector ){
|
||||
$parent = $( $parent );
|
||||
selector = selector || 'a';
|
||||
var options = [];
|
||||
$parent.find( selector ).each( function( elem, i ){
|
||||
var option = {}, $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' ),
|
||||
linkTarget = $link.attr( 'target' ),
|
||||
confirmText = $link.attr( 'confirm' );
|
||||
|
||||
option.func = function(){
|
||||
// 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 = function( $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 = function( 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 || function( $menuElement, parent ){
|
||||
return '#' + $menuElement.attr( 'popupmenu' );
|
||||
};
|
||||
|
||||
// aggregate and return all PopupMenus
|
||||
var popupMenusCreated = [];
|
||||
$( parent ).find( menuSelector ).each( function(){
|
||||
var $menuElement = $( this ),
|
||||
$buttonElement = $( parent ).find( buttonSelectorBuildFn( $menuElement, parent ) );
|
||||
popupMenusCreated.push( PopupMenu.fromDom( $buttonElement, $menuElement ) );
|
||||
$buttonElement.addClass( 'popup' );
|
||||
});
|
||||
return popupMenusCreated;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,311 @@
|
||||
define([
|
||||
//jquery
|
||||
//backbone
|
||||
], function(){
|
||||
// =============================================================================
|
||||
/**
|
||||
* view for a popup menu
|
||||
*/
|
||||
var 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.
|
||||
*/
|
||||
initialize: function( $button, options ){
|
||||
// default settings
|
||||
this.$button = $button;
|
||||
if( !this.$button.size() ){
|
||||
this.$button = $( '<div/>' );
|
||||
}
|
||||
this.options = options || [];
|
||||
|
||||
// set up button click -> open menu behavior
|
||||
var menu = this;
|
||||
this.$button.click( function( event ){
|
||||
// if there's already a menu open, remove it
|
||||
$( '.popmenu-wrapper' ).remove();
|
||||
menu._renderAndShow( event );
|
||||
return false;
|
||||
});
|
||||
},
|
||||
|
||||
// render the menu, append to the page body at the click position, and set up the 'click-away' handlers, show
|
||||
_renderAndShow: function( clickEvent ){
|
||||
this.render();
|
||||
this.$el.appendTo( 'body' ).css( this._getShownPosition( clickEvent )).show();
|
||||
this._setUpCloseBehavior();
|
||||
},
|
||||
|
||||
// render the menu
|
||||
// this menu doesn't attach itself to the DOM ( see _renderAndShow )
|
||||
render: function(){
|
||||
// render the menu body absolute and hidden, fill with template
|
||||
this.$el.addClass( 'popmenu-wrapper' ).hide()
|
||||
.css({ position : 'absolute' })
|
||||
.html( this.template( this.$button.attr( 'id' ), this.options ));
|
||||
|
||||
// set up behavior on each link/anchor elem
|
||||
if( this.options.length ){
|
||||
var menu = this;
|
||||
//precondition: there should be one option per li
|
||||
this.$el.find( 'li' ).each( function( i, li ){
|
||||
var option = menu.options[i];
|
||||
|
||||
// if the option has 'func', call that function when the anchor is clicked
|
||||
if( option.func ){
|
||||
$( this ).children( 'a.popupmenu-option' ).click( function( event ){
|
||||
option.func.call( menu, event, option );
|
||||
// bubble up so that an option click will call the close behavior
|
||||
//return false;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
template : function( id, options ){
|
||||
return [
|
||||
'<ul id="', id, '-menu" class="dropdown-menu">', this._templateOptions( options ), '</ul>'
|
||||
].join( '' );
|
||||
},
|
||||
|
||||
_templateOptions : function( options ){
|
||||
if( !options.length ){
|
||||
return '<li>(no options)</li>';
|
||||
}
|
||||
return _.map( options, function( option ){
|
||||
if( option.divider ){
|
||||
return '<li class="divider"></li>';
|
||||
} else if( option.header ){
|
||||
return [ '<li class="head"><a href="javascript:void(0);">', option.html, '</a></li>' ].join( '' );
|
||||
}
|
||||
var href = option.href || 'javascript:void(0);',
|
||||
target = ( option.target )?( ' target="' + option.target + '"' ):( '' ),
|
||||
check = ( option.checked )?( '<span class="fa fa-check"></span>' ):( '' );
|
||||
return [
|
||||
'<li><a class="popupmenu-option" href="', href, '"', target, '>',
|
||||
check, option.html,
|
||||
'</a></li>'
|
||||
].join( '' );
|
||||
}).join( '' );
|
||||
},
|
||||
|
||||
// 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 ;
|
||||
|
||||
// adjust to handle horiz. scroll and window dimensions ( draw entirely on visible screen area )
|
||||
x = Math.min( x, $( document ).scrollLeft() + $( window ).width() - menuWidth - 5 );
|
||||
x = Math.max( x, $( document ).scrollLeft() + 5 );
|
||||
return {
|
||||
top: clickEvent.pageY,
|
||||
left: x
|
||||
};
|
||||
},
|
||||
|
||||
// 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 ){
|
||||
$( document ).off( 'click.close_popup' );
|
||||
if( window.parent !== window ){
|
||||
try {
|
||||
$( window.parent.document ).off( "click.close_popup" );
|
||||
} catch( err ){}
|
||||
} else {
|
||||
try {
|
||||
$( 'iframe#galaxy_main' ).contents().off( "click.close_popup" );
|
||||
} catch( err ){}
|
||||
}
|
||||
menu.remove();
|
||||
}
|
||||
|
||||
$( 'html' ).one( "click.close_popup", closePopup );
|
||||
if( window.parent !== window ){
|
||||
try {
|
||||
$( window.parent.document ).find( 'html' ).one( "click.close_popup", closePopup );
|
||||
} catch( err ){}
|
||||
} else {
|
||||
try {
|
||||
$( 'iframe#galaxy_main' ).contents().one( "click.close_popup", closePopup );
|
||||
} catch( err ){}
|
||||
}
|
||||
},
|
||||
|
||||
// add a menu option/item at the given index
|
||||
addItem: function( item, index ){
|
||||
// append to end if no index
|
||||
index = ( index >= 0 ) ? index : this.options.length;
|
||||
this.options.splice( index, 0, item );
|
||||
return this;
|
||||
},
|
||||
|
||||
// remove a menu option/item at the given index
|
||||
removeItem: function( index ){
|
||||
if( index >=0 ){
|
||||
this.options.splice( index, 1 );
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
// search for a menu option by its html
|
||||
findIndexByHtml: function( html ){
|
||||
for( var i = 0; i < this.options.length; i++ ){
|
||||
if( _.has( this.options[i], 'html' ) && ( this.options[i].html === html )){
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
// search for a menu option by its html
|
||||
findItemByHtml: function( html ){
|
||||
return this.options[( this.findIndexByHtml( html ))];
|
||||
},
|
||||
|
||||
// string representation
|
||||
toString: function(){
|
||||
return 'PopupMenu';
|
||||
}
|
||||
});
|
||||
/** shortcut to new for when you don't need to preserve the ref */
|
||||
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 = function( button_element, initial_options ){
|
||||
var convertedOptions = [];
|
||||
_.each( initial_options, function( 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( jQuery.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 = function( $parent, selector ){
|
||||
$parent = $( $parent );
|
||||
selector = selector || 'a';
|
||||
var options = [];
|
||||
$parent.find( selector ).each( function( elem, i ){
|
||||
var option = {}, $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' ),
|
||||
linkTarget = $link.attr( 'target' ),
|
||||
confirmText = $link.attr( 'confirm' );
|
||||
|
||||
option.func = function(){
|
||||
// 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 = function( $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 = function( 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 || function( $menuElement, parent ){
|
||||
return '#' + $menuElement.attr( 'popupmenu' );
|
||||
};
|
||||
|
||||
// aggregate and return all PopupMenus
|
||||
var popupMenusCreated = [];
|
||||
$( parent ).find( menuSelector ).each( function(){
|
||||
var $menuElement = $( this ),
|
||||
$buttonElement = $( parent ).find( buttonSelectorBuildFn( $menuElement, parent ) );
|
||||
popupMenusCreated.push( PopupMenu.fromDom( $buttonElement, $menuElement ) );
|
||||
$buttonElement.addClass( 'popup' );
|
||||
});
|
||||
return popupMenusCreated;
|
||||
};
|
||||
|
||||
|
||||
// =============================================================================
|
||||
return PopupMenu;
|
||||
});
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
define(["mvc/base-mvc","utils/localization"],function(a,d){var e=[{html:d("History Lists"),header:true},{html:d("Saved Histories"),href:"history/list"},{html:d("Histories Shared with Me"),href:"history/list_shared"},{html:d("Current History"),header:true,anon:true},{html:d("Create New"),func:function(){if(Galaxy&&Galaxy.currHistoryPanel){Galaxy.currHistoryPanel.createNewHistory()}}},{html:d("Copy History"),href:"history/copy"},{html:d("Copy Datasets"),href:"dataset/copy_datasets"},{html:d("Share or Publish"),href:"history/sharing"},{html:d("Extract Workflow"),href:"workflow/build_from_current_history"},{html:d("Dataset Security"),href:"root/history_set_default_permissions"},{html:d("Resume Paused Jobs"),href:"history/resume_paused_jobs?current=True",anon:true},{html:d("Collapse Expanded Datasets"),func:function(){if(Galaxy&&Galaxy.currHistoryPanel){Galaxy.currHistoryPanel.collapseAll()}}},{html:d("Unhide Hidden Datasets"),confirm:d("Really unhide all hidden datasets?"),href:"history/unhide_datasets?current=True",anon:true},{html:d("Delete Hidden Datasets"),confirm:d("Really delete all hidden datasets?"),href:"history/delete_hidden_datasets",anon:true},{html:d("Purge Deleted Datasets"),confirm:d("Really delete all deleted datasets permanently? This cannot be undone."),href:"history/purge_deleted_datasets",purge:true,anon:true},{html:d("Show Structure"),href:"history/display_structured",anon:true},{html:d("Export Citations"),href:"history/citations",anon:true},{html:d("Export to File"),href:"history/export_archive?preview=True",anon:true},{html:d("Delete"),confirm:d("Really delete the current history?"),href:"history/delete_current"},{html:d("Delete Permanently"),confirm:d("Really delete the current history permanently? This cannot be undone."),href:"history/delete_current?purge=True",purge:true,anon:true},{html:d("Other Actions"),header:true},{html:d("Import from File"),href:"history/import_archive"}];function c(h,g,f){return _.clone(e).filter(function(i){if(h&&!i.anon){return false}if(!g&&i.purge){return false}if(i.href){i.href=f+i.href;i.target="galaxy_main"}if(i.confirm){i.func=function(){if(confirm(i.confirm)){galaxy_main.location=i.href}}}return true})}var b=function(i,g){g=g||{};var j=g.anonymous===undefined?true:g.anonymous,h=g.purgeAllowed||false,f=g.root||((Galaxy&&Galaxy.options)?Galaxy.options.root:"/"),k=c(j,h,f);return new PopupMenu(i,k)};return b});
|
||||
define(["mvc/ui/popup-menu","mvc/base-mvc","utils/localization"],function(b,a,e){var f=[{html:e("History Lists"),header:true},{html:e("Saved Histories"),href:"history/list"},{html:e("Histories Shared with Me"),href:"history/list_shared"},{html:e("Current History"),header:true,anon:true},{html:e("Create New"),func:function(){if(Galaxy&&Galaxy.currHistoryPanel){Galaxy.currHistoryPanel.createNewHistory()}}},{html:e("Copy History"),href:"history/copy"},{html:e("Copy Datasets"),href:"dataset/copy_datasets"},{html:e("Share or Publish"),href:"history/sharing"},{html:e("Extract Workflow"),href:"workflow/build_from_current_history"},{html:e("Dataset Security"),href:"root/history_set_default_permissions"},{html:e("Resume Paused Jobs"),href:"history/resume_paused_jobs?current=True",anon:true},{html:e("Collapse Expanded Datasets"),func:function(){if(Galaxy&&Galaxy.currHistoryPanel){Galaxy.currHistoryPanel.collapseAll()}}},{html:e("Unhide Hidden Datasets"),confirm:e("Really unhide all hidden datasets?"),href:"history/unhide_datasets?current=True",anon:true},{html:e("Delete Hidden Datasets"),confirm:e("Really delete all hidden datasets?"),href:"history/delete_hidden_datasets",anon:true},{html:e("Purge Deleted Datasets"),confirm:e("Really delete all deleted datasets permanently? This cannot be undone."),href:"history/purge_deleted_datasets",purge:true,anon:true},{html:e("Show Structure"),href:"history/display_structured",anon:true},{html:e("Export Citations"),href:"history/citations",anon:true},{html:e("Export to File"),href:"history/export_archive?preview=True",anon:true},{html:e("Delete"),confirm:e("Really delete the current history?"),href:"history/delete_current"},{html:e("Delete Permanently"),confirm:e("Really delete the current history permanently? This cannot be undone."),href:"history/delete_current?purge=True",purge:true,anon:true},{html:e("Other Actions"),header:true},{html:e("Import from File"),href:"history/import_archive"}];function d(i,h,g){return _.clone(f).filter(function(j){if(i&&!j.anon){return false}if(!h&&j.purge){return false}if(j.href){j.href=g+j.href;j.target="galaxy_main"}if(j.confirm){j.func=function(){if(confirm(j.confirm)){galaxy_main.location=j.href}}}return true})}var c=function(j,h){h=h||{};var k=h.anonymous===undefined?true:h.anonymous,i=h.purgeAllowed||false,g=h.root||((Galaxy&&Galaxy.options)?Galaxy.options.root:"/"),l=d(k,i,g);return new b(j,l)};return c});
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
define([],function(){var a=Backbone.View.extend({initialize:function(d,c){this.$button=d;if(!this.$button.size()){this.$button=$("<div/>")}this.options=c||[];var e=this;this.$button.click(function(f){$(".popmenu-wrapper").remove();e._renderAndShow(f);return false})},_renderAndShow:function(c){this.render();this.$el.appendTo("body").css(this._getShownPosition(c)).show();this._setUpCloseBehavior()},render:function(){this.$el.addClass("popmenu-wrapper").hide().css({position:"absolute"}).html(this.template(this.$button.attr("id"),this.options));if(this.options.length){var c=this;this.$el.find("li").each(function(e,d){var f=c.options[e];if(f.func){$(this).children("a.popupmenu-option").click(function(g){f.func.call(c,g,f)})}})}return this},template:function(d,c){return['<ul id="',d,'-menu" class="dropdown-menu">',this._templateOptions(c),"</ul>"].join("")},_templateOptions:function(c){if(!c.length){return"<li>(no options)</li>"}return _.map(c,function(f){if(f.divider){return'<li class="divider"></li>'}else{if(f.header){return['<li class="head"><a href="javascript:void(0);">',f.html,"</a></li>"].join("")}}var e=f.href||"javascript:void(0);",g=(f.target)?(' target="'+f.target+'"'):(""),d=(f.checked)?('<span class="fa fa-check"></span>'):("");return['<li><a class="popupmenu-option" href="',e,'"',g,">",d,f.html,"</a></li>"].join("")}).join("")},_getShownPosition:function(d){var e=this.$el.width();var c=d.pageX-e/2;c=Math.min(c,$(document).scrollLeft()+$(window).width()-e-5);c=Math.max(c,$(document).scrollLeft()+5);return{top:d.pageY,left:c}},_setUpCloseBehavior:function(){var e=this;function c(g){$(document).off("click.close_popup");if(window.parent!==window){try{$(window.parent.document).off("click.close_popup")}catch(f){}}else{try{$("iframe#galaxy_main").contents().off("click.close_popup")}catch(f){}}e.remove()}$("html").one("click.close_popup",c);if(window.parent!==window){try{$(window.parent.document).find("html").one("click.close_popup",c)}catch(d){}}else{try{$("iframe#galaxy_main").contents().one("click.close_popup",c)}catch(d){}}},addItem:function(d,c){c=(c>=0)?c:this.options.length;this.options.splice(c,0,d);return this},removeItem:function(c){if(c>=0){this.options.splice(c,1)}return this},findIndexByHtml:function(d){for(var c=0;c<this.options.length;c++){if(_.has(this.options[c],"html")&&(this.options[c].html===d)){return c}}return null},findItemByHtml:function(c){return this.options[(this.findIndexByHtml(c))]},toString:function(){return"PopupMenu"}});a.create=function b(d,c){return new a(d,c)};a.make_popupmenu=function(d,e){var c=[];_.each(e,function(h,f){var g={html:f};if(h===null){g.header=true}else{if(jQuery.type(h)==="function"){g.func=h}}c.push(g)});return new a($(d),c)};a.convertLinksToOptions=function(e,c){e=$(e);c=c||"a";var d=[];e.find(c).each(function(j,g){var h={},f=$(j);h.html=f.text();if(f.attr("href")){var l=f.attr("href"),m=f.attr("target"),k=f.attr("confirm");h.func=function(){if((k)&&(!confirm(k))){return}switch(m){case"_parent":window.parent.location=l;break;case"_top":window.top.location=l;break;default:window.location=l}}}d.push(h)});return d};a.fromExistingDom=function(f,e,c){f=$(f);e=$(e);var d=a.convertLinksToOptions(e,c);e.remove();return new a(f,d)};a.make_popup_menus=function(e,d,f){e=e||document;d=d||"div[popupmenu]";f=f||function(g,h){return"#"+g.attr("popupmenu")};var c=[];$(e).find(d).each(function(){var g=$(this),h=$(e).find(f(g,e));c.push(a.fromDom(h,g));h.addClass("popup")});return c};return a});
|
||||
Reference in New Issue
Block a user