From bc5b2f59537eba8af2d310e140c6929cee508792 Mon Sep 17 00:00:00 2001 From: Aysam Guerler Date: Mon, 5 Aug 2013 17:02:05 -0400 Subject: [PATCH] Unification and refactoring of front end templating for js-visualizations (trackster, circster, etc.) --- .../galaxy/controllers/visualization.py | 73 ++- static/scripts/galaxy.frame.js | 1 - static/scripts/libs/farbtastic.js | 6 +- .../scripts/libs/jquery/jquery.event.hover.js | 29 +- static/scripts/mvc/ui.js | 494 +++++++++++------- static/scripts/packed/libs/farbtastic.js | 2 +- .../packed/libs/jquery/jquery.event.hover.js | 2 +- static/scripts/packed/mvc/ui.js | 2 +- .../templates/compiled/panel_section.js | 2 +- .../packed/templates/compiled/tool_form.js | 2 +- .../packed/templates/compiled/tool_link.js | 2 +- .../packed/templates/compiled/tool_search.js | 2 +- static/scripts/packed/viz/trackster.js | 2 +- static/scripts/packed/viz/trackster/tracks.js | 2 +- static/scripts/packed/viz/trackster_ui.js | 2 +- .../scripts/templates/common-templates.html | 30 -- .../templates/compiled/panel_section.js | 35 +- .../scripts/templates/compiled/tool_form.js | 80 ++- .../scripts/templates/compiled/tool_link.js | 59 +-- .../scripts/templates/compiled/tool_search.js | 26 +- static/scripts/viz/circster.js | 90 +++- static/scripts/viz/trackster.js | 198 ++++++- static/scripts/viz/trackster/tracks.js | 22 +- static/scripts/viz/trackster_ui.js | 45 +- templates/base/base_panels.mako | 24 +- templates/webapps/galaxy/galaxy.masthead.mako | 253 +++++++++ templates/webapps/galaxy/galaxy.panels.mako | 280 ++++++++++ templates/webapps/galaxy/tracks/browser.mako | 191 ------- .../galaxy/visualization/circster.mako | 121 ----- .../webapps/galaxy/visualization/display.mako | 8 +- 30 files changed, 1335 insertions(+), 750 deletions(-) create mode 100644 templates/webapps/galaxy/galaxy.masthead.mako create mode 100644 templates/webapps/galaxy/galaxy.panels.mako delete mode 100644 templates/webapps/galaxy/tracks/browser.mako delete mode 100644 templates/webapps/galaxy/visualization/circster.mako diff --git a/lib/galaxy/webapps/galaxy/controllers/visualization.py b/lib/galaxy/webapps/galaxy/controllers/visualization.py index fca5922cddd..0e963a693dd 100644 --- a/lib/galaxy/webapps/galaxy/controllers/visualization.py +++ b/lib/galaxy/webapps/galaxy/controllers/visualization.py @@ -745,47 +745,58 @@ class VisualizationController( BaseUIController, SharableMixin, UsesAnnotations, @web.expose @web.require_login() - def trackster(self, trans, id=None, **kwargs): + def trackster(self, trans, **kwargs): """ Display browser for the visualization denoted by id and add the datasets listed in `dataset_ids`. """ - # Get dataset to add. + # define app configuration + app = { 'jscript' : "viz/trackster" } + + # get dataset to add + id = kwargs.get( "id", None ) + + # get dataset to add new_dataset_id = kwargs.get( "dataset_id", None ) - # Check for gene region - gene_region = GenomeRegion.from_str(kwargs.get("gene_region", "")) - - # Set up new browser if no id provided. + # set up new browser if no id provided if not id: - # Use dbkey from dataset to be added or from incoming parameter. + # use dbkey from dataset to be added or from incoming parameter dbkey = None if new_dataset_id: dbkey = self.get_dataset( trans, new_dataset_id ).dbkey if dbkey == '?': dbkey = kwargs.get( "dbkey", None ) - - # fill template - return trans.fill_template( "tracks/browser.mako", viewport_config=gene_region.__dict__, add_dataset=new_dataset_id, default_dbkey=dbkey ) + + # save database key + app['default_dbkey'] = dbkey + + # add url + app['new_browser'] = web.url_for( controller='visualization', action='new_browser', default_dbkey=dbkey ) + else: + # load saved visualization + vis = self.get_visualization( trans, id, check_ownership=False, check_accessible=True ) + app['viz_config'] = self.get_visualization_config( trans, vis ) + + # backup id + app['id'] = id; - # Display saved visualization. - vis = self.get_visualization( trans, id, check_ownership=False, check_accessible=True ) - viz_config = self.get_visualization_config( trans, vis ) - - # Update gene region of saved visualization if user parses a new gene region in the url + # add dataset id + app['add_dataset'] = new_dataset_id + + # check for gene region + gene_region = GenomeRegion.from_str(kwargs.get("gene_region", "")) + + # update gene region of saved visualization if user parses a new gene region in the url if gene_region.chrom is not None: - viz_config['viewport']['chrom'] = gene_region.chrom - viz_config['viewport']['start'] = gene_region.start - viz_config['viewport']['end'] = gene_region.end - - ''' - FIXME: - if new_dataset is not None: - if trans.security.decode_id(new_dataset) in [ d["dataset_id"] for d in viz_config.get("tracks") ]: - new_dataset = None # Already in browser, so don't add - ''' + app['gene_region'] = { + 'chrom' : gene_region.chrom, + 'start' : gene_region.start, + 'end' : gene_region.end + } + # fill template - return trans.fill_template( 'tracks/browser.mako', config=viz_config, add_dataset=new_dataset_id ) + return trans.fill_template('galaxy.panels.mako', config = {'right_panel' : True, 'app' : app}) @web.expose def circster( self, trans, id=None, hda_ldda=None, dataset_id=None, dbkey=None ): @@ -839,7 +850,15 @@ class VisualizationController( BaseUIController, SharableMixin, UsesAnnotations, if not isinstance( genome_data, str ): track[ 'preloaded_data' ] = genome_data - return trans.fill_template( 'visualization/circster.mako', viz_config=viz_config, genome=genome ) + # define app configuration for generic mako template + app = { + 'jscript' : "viz/circster", + 'viz_config' : viz_config, + 'genome' : genome + } + + # fill template + return trans.fill_template('galaxy.panels.mako', config = {'app' : app}) @web.expose def sweepster( self, trans, id=None, hda_ldda=None, dataset_id=None, regions=None ): diff --git a/static/scripts/galaxy.frame.js b/static/scripts/galaxy.frame.js index 99f0fca9f7c..6342d0cc0a7 100644 --- a/static/scripts/galaxy.frame.js +++ b/static/scripts/galaxy.frame.js @@ -4,7 +4,6 @@ // dependencies define(["utils/galaxy.css", "libs/backbone/backbone-relational"], function(css) { - // frame manager var GalaxyFrameManager = Backbone.View.extend( diff --git a/static/scripts/libs/farbtastic.js b/static/scripts/libs/farbtastic.js index 06882ddd8cd..7a495b844a3 100644 --- a/static/scripts/libs/farbtastic.js +++ b/static/scripts/libs/farbtastic.js @@ -98,7 +98,7 @@ $._farbtastic = function (container, options) { .find('div>*').css('position', 'absolute'); // IE Fix: Recreate canvas elements with doc.createElement and excanvas. - $.browser.msie && $('canvas', container).each(function () { + navigator.userAgent.match(/msie/i) && $('canvas', container).each(function () { // Fetch info. var attr = { 'class': $(this).attr('class'), style: this.getAttribute('style') }, e = document.createElement('canvas'); @@ -166,7 +166,7 @@ $._farbtastic = function (container, options) { // New color color2 = fb.pack(fb.HSLToRGB([d2, 1, 0.5])); if (i > 0) { - if ($.browser.msie) { + if (navigator.userAgent.match(/msie/i)) { // IE's gradient calculations mess up the colors. Correct along the diagonals. var corr = (1 + Math.min(Math.abs(Math.tan(angle1)), Math.abs(Math.tan(Math.PI / 2 - angle1)))) / n; color1 = fb.pack(fb.HSLToRGB([d1 - 0.15 * corr, 1, 0.5])); @@ -246,7 +246,7 @@ $._farbtastic = function (container, options) { fb.ctxMask.drawImage(buffer, 0, 0, sz + 1, sz + 1, -sq, -sq, sq * 2, sq * 2); } // Method #2: drawing commands (old Canvas). - else if (!$.browser.msie) { + else if (!navigator.userAgent.match(/msie/i)) { // Render directly at half-resolution var sz = Math.floor(size / 2); calculateMask(sz, sz, function (x, y, c, a) { diff --git a/static/scripts/libs/jquery/jquery.event.hover.js b/static/scripts/libs/jquery/jquery.event.hover.js index b2596f821d7..c607990ef59 100644 --- a/static/scripts/libs/jquery/jquery.event.hover.js +++ b/static/scripts/libs/jquery/jquery.event.hover.js @@ -1,20 +1,19 @@ ;(function($){ // secure $ jQuery alias /*******************************************************************************************/ -// jquery.event.hover.js - rev 5 +// jquery.event.hover.js // Copyright (c) 2008, Three Dub Media (http://threedubmedia.com) -// Liscensed under the MIT License (MIT-LICENSE.txt) +// Licensed under the MIT License (MIT-LICENSE.txt) // http://www.opensource.org/licenses/mit-license.php -// Created: 2008-06-02 | Updated: 2008-07-30 +// +// JQuery 1.9+ compatible version +// +// Optional settings : +// $.event.special.hover.delay = 100; +// Defines the delay (msec) while mouse is inside the element before checking the speed +// $.event.special.hover.speed = 100; +// Defines the maximum speed (px/sec) the mouse may be moving to trigger the hover event /*******************************************************************************************/ -// USE THESE PROPERTIES TO CUSTOMIZE SETTINGS... - -// $.event.special.hover.delay = 100; -// Defines the delay (msec) while mouse is inside the element before checking the speed - -// $.event.special.hover.speed = 100; -// Defines the maximum speed (px/sec) the mouse may be moving to trigger the hover event - // save the old jquery "hover" method $.fn._hover = $.fn.hover; @@ -47,8 +46,8 @@ function hoverHandler( event ){ data.dist2 = 0; // init mouse distance² data.event = event; // store the event event.type = "hoverstart"; // hijack event - if ( $.event.handle.call( this, event ) !== false ){ // handle "hoverstart" - data.elem = this; // ref to the current element + if($.event.dispatch.call(this, event) !== false) { + data.elem = this; // ref to the current element $.event.add( this, "mousemove", hoverHandler, data ); // track the mouse data.timer = setTimeout( compare, data.delay ); // start async compare } @@ -62,7 +61,7 @@ function hoverHandler( event ){ clearTimeout( data.timer ); // uncompare if ( data.hovered ){ event.type = "hoverend"; // hijack event - $.event.handle.call( this, event ); // handle "hoverend" + $.event.dispatch.call(this, event); // handle "hoverend" data.hovered--; // reset flag } else $.event.remove( data.elem, "mousemove", hoverHandler ); // untrack @@ -71,7 +70,7 @@ function hoverHandler( event ){ if ( data.dist2 <= Math.pow( data.speed*( data.delay/1e3 ), 2 ) ){ // speed acceptable $.event.remove( data.elem, "mousemove", hoverHandler ); // untrack data.event.type = "hover"; // hijack event - if ( $.event.handle.call( data.elem, data.event ) !== false ) // handle "hover" + if($.event.dispatch.call(data.elem, data.event) !== false) // handle "hover" data.hovered++; // flag for "hoverend" } else data.timer = setTimeout( compare, data.delay ); // async recurse diff --git a/static/scripts/mvc/ui.js b/static/scripts/mvc/ui.js index eb8602f2d49..59ab82c621c 100644 --- a/static/scripts/mvc/ui.js +++ b/static/scripts/mvc/ui.js @@ -1,101 +1,172 @@ /** - * -- Functions for creating large UI elements. -- + * necessary galaxy paths */ -// ============================================================================= -/** - * -- Utility models and views for Galaxy objects. -- - */ - -/** - * Clickable button represented as an icon. - */ -var IconButton = Backbone.Model.extend({ - defaults: { - title: "", - icon_class: "", - on_click: null, - menu_options: null, - tooltip_config: {}, - - isMenuButton : true, - id : null, - href : null, - target : null, - enabled : true, - visible : true +var GalaxyPaths = Backbone.Model.extend( +{ + defaults: + { + root_path: "", + image_path: "" } - - //validate : function( attributes ){ - //TODO: validate href or on_click - //TODO: validate icon_class - //} }); +/** + * functions for creating large ui elements + */ /** - * + * backbone model for icon buttons */ -var IconButtonView = Backbone.View.extend({ - - initialize : function(){ - // better rendering this way (for me anyway) +var IconButton = Backbone.Model.extend( +{ + defaults: + { + title : "", + icon_class : "", + on_click : null, + menu_options : null, + is_menu_button : true, + id : null, + href : null, + target : null, + enabled : true, + visible : true, + tooltip_config : {} + } +}); + +/** + * backbone view for icon buttons + */ +var IconButtonView = Backbone.View.extend( +{ + // initialize + initialize: function() + { + // better rendering this way this.model.attributes.tooltip_config = { placement : 'bottom' }; - this.model.bind( 'change', this.render, this ); + this.model.bind('change', this.render, this); }, - render : function(){ - //NOTE: not doing this hide will lead to disappearing buttons when they're both being hovered over & rendered - this.$el.tooltip( 'hide' ); + // render + render: function() + { + // hide tooltip + this.$el.tooltip('hide'); - // template in common-templates.html - var newElem = $( Handlebars.partials.iconButton( this.model.toJSON() ) ); - newElem.tooltip( this.model.get( 'tooltip_config' ) ); + // create element + var new_elem = this.template(this.model.attributes); - this.$el.replaceWith( newElem ); - this.setElement( newElem ); + // configure tooltip + new_elem.tooltip(this.model.get('tooltip_config')); + + // replace + this.$el.replaceWith(new_elem); + this.setElement(new_elem); + // return return this; }, - events : { + // events + events: + { 'click' : 'click' }, - click : function( event ){ + // click + click: function( event ) + { // if on_click pass to that function - if( this.model.attributes.on_click ){ - this.model.attributes.on_click( event ); + if(this.model.attributes.on_click) + { + this.model.attributes.on_click(event); return false; } + // otherwise, bubble up (to href or whatever) return true; + }, + + // generate html element + template: function(options) + { + // initialize + var buffer = 'title="' + options.title + '" class="icon-button'; + + // is menu button + if(options.is_menu_button) + buffer += ' menu-button'; + + // define tooltip + if(options.title) + buffer += ' tooltip'; + + // add icon class + buffer += ' ' + options.icon_class; + + // add enabled/disabled class + if(!options.enabled) + buffer += '_disabled'; + + // close class tag + buffer += '"'; + + // add id + if(options.id) + buffer += ' id="' + options.id + '"'; + + // add href + buffer += ' href="' + options.href + '"'; + + // add target for href + if(options.target) + buffer += ' target="' + options.target + '"'; + + // set visibility + if(!options.visible) + buffer += ' style="display: none;"'; + + // enabled/disabled + if (options.enabled) + buffer = ''; + else + buffer = ''; + + // return element + return $(buffer); } }); -//TODO: bc h.templates is gen. loaded AFTER ui, Handlebars.partials.iconButton === undefined -IconButtonView.templates = { - iconButton : Handlebars.partials.iconButton -}; -var IconButtonCollection = Backbone.Collection.extend({ +// define collection +var IconButtonCollection = Backbone.Collection.extend( +{ model: IconButton }); - -//------------------------------------------------------------------------------ /** - * Menu with multiple icon buttons. Views are not needed nor used for individual buttons. + * menu with multiple icon buttons + * views are not needed nor used for individual buttons */ -var IconButtonMenuView = Backbone.View.extend({ +var IconButtonMenuView = Backbone.View.extend( +{ + // tag tagName: 'div', - initialize: function() { + // initialize + initialize: function() + { this.render(); }, - render: function() { + // render + render: function() + { + // initialize icon buttons var self = this; - this.collection.each(function(button) { - // Create and add icon button to menu. + this.collection.each(function(button) + { + // create and add icon button to menu var elt = $('').attr('href', 'javascript:void(0)') .attr('title', button.attributes.title) @@ -104,17 +175,17 @@ var IconButtonMenuView = Backbone.View.extend({ .appendTo(self.$el) .click(button.attributes.on_click); - if (button.attributes.tooltip_config) { + // configure tooltip + if (button.attributes.tooltip_config) elt.tooltip(button.attributes.tooltip_config); - } - // If there are options, add popup menu to icon. + // add popup menu to icon var menu_options = button.get('options'); - if (menu_options) { + if (menu_options) make_popupmenu(elt, menu_options); - } - }); + + // return return this; } }); @@ -125,20 +196,23 @@ var IconButtonMenuView = Backbone.View.extend({ * defines an icon button. Each dictionary must have the following * elements: icon_class, title, and on_click. */ -var create_icon_buttons_menu = function(config, global_config) { - if (!global_config) { global_config = {}; } +var create_icon_buttons_menu = function(config, global_config) +{ + // initialize global configuration + if (!global_config) global_config = {}; - // Create and initialize menu. + // create and initialize menu var buttons = new IconButtonCollection( - _.map(config, function(button_config) { - return new IconButton(_.extend(button_config, global_config)); - }) - ); + _.map(config, function(button_config) + { + return new IconButton(_.extend(button_config, global_config)); + }) + ); + // return menu return new IconButtonMenuView( {collection: buttons} ); }; - // ============================================================================= /** * @@ -155,196 +229,232 @@ var GridView = Backbone.View.extend({ }); // ============================================================================= -/** - * Necessary Galaxy paths. - */ -var GalaxyPaths = Backbone.Model.extend({ - defaults: { - root_path: "", - image_path: "" - } -}); - - -// ============================================================================= -/** @class View for a popup menu - * @name PopupMenu - * - * @constructs +/** + * view for a popup menu */ var PopupMenu = Backbone.View.extend( -/** @lends PopupMenu.prototype */{ - +{ /* TODO: add submenus add hrefs test various html keys add make_popupmenus style - get template inside this file somehow */ /** 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. */ //TODO: include docs on special option keys (divider, checked, etc.) - initialize : function( $button, options ){ + initialize: function($button, options) + { // default settings - this.$button = $button || $( '
' ); + this.$button = $button || $('
'); this.options = options || []; // set up button click -> open menu behavior var menu = this; - this.$button.click( function( event ){ - menu._renderAndShow( event ); - //event.stopPropagation(); + this.$button.click(function(event) + { + menu._renderAndShow(event); return false; }); // attach this view as a data object on the button - for later access //TODO:?? memleak? - this.$button.data( 'PopupMenu', this ); - - // template loading is problematic - ui is loaded in base.mako - // and the template (prev.) needed to be loaded before ui + this.$button.data('PopupMenu', this); }, - /** Render the menu. NOTE: doesn't attach itself to the DOM. - * @see PopupMenu#_renderAndShow - */ - render : function(){ + // render the menu + // this menu doesn't attach itself to the DOM (see _renderAndShow) + render: function() + { + // link this popup var menu = this; // render the menu body - this.$el.addClass( 'popmenu-wrapper' ) - .css({ - position: 'absolute', - display: 'none' + this.$el.addClass('popmenu-wrapper') + .css( + { + position : 'absolute', + display : 'none' }); - //BUG: anchors within a.popupmenu-option render OUTSIDE the a.popupmenu-option!? - this.$el.html( PopupMenu.templates.menu({ - options : this.options, - // sets menu div id to '{{ id }}-menu' - id : this.$button.attr( 'id' ) - })); + // use template + this.$el.html(this.template(this.$button.attr('id'), this.options)); // set up behavior on each link/anchor elem - if( this.options.length ){ - this.$el.find( 'li' ).each( function( i, li ){ - var $li = $( li ), + if(this.options.length) + { + this.$el.find('li').each(function(i, li) + { + var $li = $(li), $anchor = $li.children( 'a.popupmenu-option' ), - menuFunc = menu.options[ i ].func; + menuFunc = menu.options[i].func; - if( $anchor.length && menuFunc ){ - $anchor.click( function( event ){ - menuFunc( event, menu.options[ i ] ); + // click event + if($anchor.length && menuFunc) + { + $anchor.click(function(event) + { + menuFunc(event, menu.options[i]); }); } // cache the anchor as a jq obj within the options obj - menu.options[ i ].$li = $li; + menu.options[i].$li = $li; }); } return this; }, - /** Get the absolute position/offset for the menu - */ - _getShownPosition : function( clickEvent ){ - var menuWidth = this.$el.width(), - // display menu horiz. centered on click... - x = clickEvent.pageX - menuWidth / 2 ; + // get the absolute position/offset for the menu + _getShownPosition : function( clickEvent ) + { + // get element width + var menuWidth = this.$el.width(); + + // display menu horiz. centered on click... + var x = clickEvent.pageX - menuWidth / 2 ; - // ...but adjust that to handle horiz. scroll and window dimensions (draw entirely on visible screen area) + // 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 return { top: clickEvent.pageY, left: x }; }, - /** Render the menu, append to the page body at the click position, and set up the 'click-away' handlers, show - */ - _renderAndShow : function( clickEvent ){ + // 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' ); - this.$el.css( this._getShownPosition( clickEvent ) ); + this.$el.appendTo('body'); + this.$el.css( this._getShownPosition(clickEvent)); this._setUpCloseBehavior(); this.$el.show(); }, - /** Bind an event handler to all available frames so that when anything is clicked - * * the menu is removed from the DOM - * * The event handler unbinds itself - */ - _setUpCloseBehavior : function(){ - var menu = this, - // function to close popup and unbind itself - closePopupWhenClicked = function( $elClicked ){ - $elClicked.bind( "click.close_popup", function(){ - menu.remove(); - $elClicked.unbind( "click.close_popup" ); - }); - }; + // 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() + { + // function to close popup and unbind itself + var menu = this; + var closePopupWhenClicked = function($elClicked) + { + $elClicked.bind("click.close_popup", function() + { + menu.remove(); + $elClicked.unbind("click.close_popup"); + }); + }; // bind to current, parent, and sibling frames - //TODO: (Assuming for now that this is the best way to do this...) - closePopupWhenClicked( $( window.document ) ); - closePopupWhenClicked( $( window.top.document ) ); - _.each( window.top.frames, function( siblingFrame ){ - closePopupWhenClicked( $( siblingFrame.document ) ); + closePopupWhenClicked($(window.document)); + closePopupWhenClicked($(window.top.document)); + _.each(window.top.frames, function(siblingFrame) + { + closePopupWhenClicked($(siblingFrame.document)); }); }, - /** Add a menu option/item at the given index - */ - addItem : function( item, index ){ + // 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 ); + 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 ); - } + // 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 it's html - */ - findIndexByHtml : function( html ){ - for( var i=0; i'; + + // check item number + if (options.length > 0) + { + // add option + for (var i in options) + { + // get item + var item = options[i]; + + // check for divider + if (item.divider) + { + // add divider + tmpl += '
  • '; + } else { + // identify header + if(item.header) + { + tmpl += '
  • ' + item.html + '
  • '; + } else { + // add href + if (item.href) + { + tmpl += '
  • '; } }); -PopupMenu.templates = { - menu : Handlebars.templates[ 'template-popupmenu-menu' ] -}; // ----------------------------------------------------------------------------- // the following class functions are bridges from the original make_popupmenu and make_popup_menus -// to the newer backbone.js PopupMenu +// 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. @@ -379,29 +489,33 @@ PopupMenu.make_popupmenu = function( button_element, initial_options ){ * @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 ); +PopupMenu.convertLinksToOptions = function( $parent, selector ) +{ + $parent = $($parent); selector = selector || 'a'; var options = []; - $parent.find( selector ).each( function( elem, i ){ - var option = {}, - $link = $( elem ); + $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( linkHref ){ + if( linkHref ) + { var linkHref = $link.attr( 'href' ), linkTarget = $link.attr( 'target' ), confirmText = $link.attr( 'confirm' ); - option.func = function(){ + 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: var f; - switch( linkTarget ){ + switch( linkTarget ) + { // relocate the center panel case '_parent': window.parent.location = linkHref; diff --git a/static/scripts/packed/libs/farbtastic.js b/static/scripts/packed/libs/farbtastic.js index b22657c05bc..54e153be53b 100644 --- a/static/scripts/packed/libs/farbtastic.js +++ b/static/scripts/packed/libs/farbtastic.js @@ -1 +1 @@ -(function(b){var a=false;b.fn.farbtastic=function(c){b.farbtastic(this,c);return this};b.farbtastic=function(c,d){var c=b(c)[0];return c.farbtastic||(c.farbtastic=new b._farbtastic(c,d))};b._farbtastic=function(c,d){var e=this;e.linkTo=function(f){if(typeof e.callback=="object"){b(e.callback).unbind("keyup",e.updateValue)}e.color=null;if(typeof f=="function"){e.callback=f}else{if(typeof f=="object"||typeof f=="string"){e.callback=b(f);e.callback.bind("keyup",e.updateValue);if(e.callback[0].value){e.setColor(e.callback[0].value)}}}return this};e.updateValue=function(f){if(this.value&&this.value!=e.color){e.setColor(this.value)}};e.setColor=function(f){var g=e.unpack(f);if(e.color!=f&&g){e.color=f;e.rgb=g;e.hsl=e.RGBToHSL(e.rgb);e.updateDisplay()}return this};e.setHSL=function(f){e.hsl=f;e.rgb=e.HSLToRGB(f);e.color=e.pack(e.rgb);e.updateDisplay();return this};e.initWidget=function(){var f={width:d.width,height:d.width};b(c).html('
    ').find("*").attr(f).css(f).end().find("div>*").css("position","absolute");b.browser.msie&&b("canvas",c).each(function(){var g={"class":b(this).attr("class"),style:this.getAttribute("style")},h=document.createElement("canvas");b(this).before(b(h).attr(g)).remove();G_vmlCanvasManager&&G_vmlCanvasManager.initElement(h);b(h).attr(f).css(f).css("position","absolute").find("*").attr(f).css(f)});e.radius=(d.width-d.wheelWidth)/2-1;e.square=Math.floor((e.radius-d.wheelWidth/2)*0.7)-1;e.mid=Math.floor(d.width/2);e.markerSize=d.wheelWidth*0.3;e.solidFill=b(".farbtastic-solid",c).css({width:e.square*2-1,height:e.square*2-1,left:e.mid-e.square,top:e.mid-e.square});e.cnvMask=b(".farbtastic-mask",c);e.ctxMask=e.cnvMask[0].getContext("2d");e.cnvOverlay=b(".farbtastic-overlay",c);e.ctxOverlay=e.cnvOverlay[0].getContext("2d");e.ctxMask.translate(e.mid,e.mid);e.ctxOverlay.translate(e.mid,e.mid);e.drawCircle();e.drawMask()};e.drawCircle=function(){var j=+(new Date());var s=24,q=e.radius,l=d.wheelWidth,p=8/q/s*Math.PI,t=e.ctxMask,g=0,z,B;t.save();t.lineWidth=l/q;t.scale(q,q);for(var v=0;v<=s;++v){var A=v/s,f=A*Math.PI*2,y=Math.sin(g),h=-Math.cos(g);x2=Math.sin(f),y2=-Math.cos(f),am=(g+f)/2,tan=1/Math.cos((f-g)/2),xm=Math.sin(am)*tan,ym=-Math.cos(am)*tan,color2=e.pack(e.HSLToRGB([A,1,0.5]));if(v>0){if(b.browser.msie){var o=(1+Math.min(Math.abs(Math.tan(g)),Math.abs(Math.tan(Math.PI/2-g))))/s;z=e.pack(e.HSLToRGB([B-0.15*o,1,0.5]));color2=e.pack(e.HSLToRGB([A+0.15*o,1,0.5]));var k=t.createLinearGradient(y,h,x2,y2);k.addColorStop(0,z);k.addColorStop(1,color2);t.fillStyle=k;var x=(q+l/2)/q,u=(q-l/2)/q;t.beginPath();t.moveTo(y*x,h*x);t.quadraticCurveTo(xm*x,ym*x,x2*x,y2*x);t.lineTo(x2*u,y2*u);t.quadraticCurveTo(xm*u,ym*u,y*u,h*u);t.fill()}else{var k=t.createLinearGradient(y,h,x2,y2);k.addColorStop(0,z);k.addColorStop(1,color2);t.strokeStyle=k;t.beginPath();t.moveTo(y,h);t.quadraticCurveTo(xm,ym,x2,y2);t.stroke()}}g=f-p;z=color2;B=A}t.restore();a&&b("body").append("
    drawCircle "+(+(new Date())-j)+"ms")};e.drawMask=function(){var p=+(new Date());var s=e.square*2,h=e.square;function g(D,B,t){var w=1/D,v=1/B;for(var A=0;A<=B;++A){var u=1-A*v;for(var E=0;E<=D;++E){var F=1-E*w;var C=1-2*Math.min(u*F,(1-u)*F);var z=(C>0)?((2*u-1+C)*0.5/C):0;t(E,A,z,C)}}}if(e.ctxMask.getImageData){var m=Math.floor(s/2);var k=document.createElement("canvas");k.width=k.height=m+1;var q=k.getContext("2d");var j=q.getImageData(0,0,m+1,m+1);var l=0;g(m,m,function(t,w,v,u){j.data[l++]=j.data[l++]=j.data[l++]=v*255;j.data[l++]=u*255});q.putImageData(j,0,0);e.ctxMask.drawImage(k,0,0,m+1,m+1,-h,-h,h*2,h*2)}else{if(!b.browser.msie){var m=Math.floor(s/2);g(m,m,function(t,w,v,u){v=Math.round(v*255);e.ctxMask.fillStyle="rgba("+v+", "+v+", "+v+", "+u+")";e.ctxMask.fillRect(t*2-h-1,w*2-h-1,2,2)})}else{var r,f,o=6;var n=Math.floor(s/o);g(n,6,function(B,w,u,A){if(B==0){r=f;f=[]}u=Math.round(u*255);A=Math.round(A*255);if(w>0){var E=r[B][0],t=r[B][1],D=e.packDX(E,t),C=e.packDX(u,A),z=Math.round(e.mid+((w-1)*0.333-1)*h),v=Math.round(e.mid+(w*0.333-1)*h);b("
    ").css({position:"absolute",filter:"progid:DXImageTransform.Microsoft.Gradient(StartColorStr="+D+", EndColorStr="+C+", GradientType=0)",top:z,height:v-z,left:e.mid+(B*o-h-1),width:o-(B==n?Math.round(o/2):0)}).appendTo(e.cnvMask)}f.push([u,A])})}}a&&b("body").append("
    drawMask "+(+(new Date())-p)+"ms")};e.drawMarkers=function(){var p=d.width,j=Math.ceil(e.markerSize/4),f=e.markerSize-j+1;var k=e.hsl[0]*6.28,h=Math.sin(k)*e.radius,s=-Math.cos(k)*e.radius,g=2*e.square*(0.5-e.hsl[1]),q=2*e.square*(0.5-e.hsl[2]),m=e.invert?"#fff":"#000",l=e.invert?"#000":"#fff";var n=[{x:h,y:s,r:f,c:"#000",lw:j+1},{x:h,y:s,r:e.markerSize,c:"#fff",lw:j},{x:g,y:q,r:f,c:l,lw:j+1},{x:g,y:q,r:e.markerSize,c:m,lw:j},];e.ctxOverlay.clearRect(-e.mid,-e.mid,p,p);for(i in n){var o=n[i];e.ctxOverlay.lineWidth=o.lw;e.ctxOverlay.strokeStyle=o.c;e.ctxOverlay.beginPath();e.ctxOverlay.arc(o.x,o.y,o.r,0,Math.PI*2,true);e.ctxOverlay.stroke()}};e.updateDisplay=function(){e.invert=(e.rgb[0]*0.3+e.rgb[1]*0.59+e.rgb[2]*0.11)<=0.6;e.solidFill.css("backgroundColor",e.pack(e.HSLToRGB([e.hsl[0],1,0.5])));e.drawMarkers();if(typeof e.callback=="object"){b(e.callback).css({backgroundColor:e.color,color:e.invert?"#fff":"#000"});b(e.callback).each(function(){if((typeof this.value=="string")&&this.value!=e.color){this.value=e.color}})}else{if(typeof e.callback=="function"){e.callback.call(e,e.color)}}};e.widgetCoords=function(f){return{x:f.pageX-e.offset.left-e.mid,y:f.pageY-e.offset.top-e.mid}};e.mousedown=function(f){if(!b._farbtastic.dragging){b(document).bind("mousemove",e.mousemove).bind("mouseup",e.mouseup);b._farbtastic.dragging=true}e.offset=b(c).offset();var g=e.widgetCoords(f);e.circleDrag=Math.max(Math.abs(g.x),Math.abs(g.y))>(e.square+2);e.mousemove(f);return false};e.mousemove=function(j){var k=e.widgetCoords(j);if(e.circleDrag){var h=Math.atan2(k.x,-k.y)/6.28;e.setHSL([(h+1)%1,e.hsl[1],e.hsl[2]])}else{var g=Math.max(0,Math.min(1,-(k.x/e.square/2)+0.5));var f=Math.max(0,Math.min(1,-(k.y/e.square/2)+0.5));e.setHSL([e.hsl[0],g,f])}return false};e.mouseup=function(){b(document).unbind("mousemove",e.mousemove);b(document).unbind("mouseup",e.mouseup);b._farbtastic.dragging=false};e.dec2hex=function(f){return(f<16?"0":"")+f.toString(16)};e.packDX=function(g,f){return"#"+e.dec2hex(f)+e.dec2hex(g)+e.dec2hex(g)+e.dec2hex(g)};e.pack=function(h){var k=Math.round(h[0]*255);var j=Math.round(h[1]*255);var f=Math.round(h[2]*255);return"#"+e.dec2hex(k)+e.dec2hex(j)+e.dec2hex(f)};e.unpack=function(g){if(g.length==7){function f(h){return parseInt(g.substring(h,h+2),16)/255}return[f(1),f(3),f(5)]}else{if(g.length==4){function f(h){return parseInt(g.substring(h,h+1),16)/15}return[f(1),f(2),f(3)]}}};e.HSLToRGB=function(o){var q,p,f,m,n;var k=o[0],t=o[1],j=o[2];p=(j<=0.5)?j*(t+1):j+t-j*t;q=j*2-p;return[this.hueToRGB(q,p,k+0.33333),this.hueToRGB(q,p,k),this.hueToRGB(q,p,k-0.33333)]};e.hueToRGB=function(g,f,j){j=(j+1)%1;if(j*6<1){return g+(f-g)*j*6}if(j*2<1){return f}if(j*3<2){return g+(f-g)*(0.66666-j)*6}return g};e.RGBToHSL=function(o){var f=o[0],n=o[1],p=o[2],k=Math.min(f,n,p),q=Math.max(f,n,p),t=q-k,m=0,u=0,j=(k+q)/2;if(j>0&&j<1){u=t/(j<0.5?(2*j):(2-2*j))}if(t>0){if(q==f&&q!=n){m+=(n-p)/t}if(q==n&&q!=p){m+=(2+(p-f)/t)}if(q==p&&q!=f){m+=(4+(f-n)/t)}m/=6}return[m,u,j]};if(!d.callback){d={callback:d}}d=b.extend({width:300,wheelWidth:(d.width||300)/10,callback:null,color:"#808080"},d);e.initWidget();b("canvas.farbtastic-overlay",c).mousedown(e.mousedown);if(d.callback){e.linkTo(d.callback)}e.setColor("#808080");e.setColor(d.color)}})(jQuery); \ No newline at end of file +(function(b){var a=false;b.fn.farbtastic=function(c){b.farbtastic(this,c);return this};b.farbtastic=function(c,d){var c=b(c)[0];return c.farbtastic||(c.farbtastic=new b._farbtastic(c,d))};b._farbtastic=function(c,d){var e=this;e.linkTo=function(f){if(typeof e.callback=="object"){b(e.callback).unbind("keyup",e.updateValue)}e.color=null;if(typeof f=="function"){e.callback=f}else{if(typeof f=="object"||typeof f=="string"){e.callback=b(f);e.callback.bind("keyup",e.updateValue);if(e.callback[0].value){e.setColor(e.callback[0].value)}}}return this};e.updateValue=function(f){if(this.value&&this.value!=e.color){e.setColor(this.value)}};e.setColor=function(f){var g=e.unpack(f);if(e.color!=f&&g){e.color=f;e.rgb=g;e.hsl=e.RGBToHSL(e.rgb);e.updateDisplay()}return this};e.setHSL=function(f){e.hsl=f;e.rgb=e.HSLToRGB(f);e.color=e.pack(e.rgb);e.updateDisplay();return this};e.initWidget=function(){var f={width:d.width,height:d.width};b(c).html('
    ').find("*").attr(f).css(f).end().find("div>*").css("position","absolute");navigator.userAgent.match(/msie/i)&&b("canvas",c).each(function(){var g={"class":b(this).attr("class"),style:this.getAttribute("style")},h=document.createElement("canvas");b(this).before(b(h).attr(g)).remove();G_vmlCanvasManager&&G_vmlCanvasManager.initElement(h);b(h).attr(f).css(f).css("position","absolute").find("*").attr(f).css(f)});e.radius=(d.width-d.wheelWidth)/2-1;e.square=Math.floor((e.radius-d.wheelWidth/2)*0.7)-1;e.mid=Math.floor(d.width/2);e.markerSize=d.wheelWidth*0.3;e.solidFill=b(".farbtastic-solid",c).css({width:e.square*2-1,height:e.square*2-1,left:e.mid-e.square,top:e.mid-e.square});e.cnvMask=b(".farbtastic-mask",c);e.ctxMask=e.cnvMask[0].getContext("2d");e.cnvOverlay=b(".farbtastic-overlay",c);e.ctxOverlay=e.cnvOverlay[0].getContext("2d");e.ctxMask.translate(e.mid,e.mid);e.ctxOverlay.translate(e.mid,e.mid);e.drawCircle();e.drawMask()};e.drawCircle=function(){var j=+(new Date());var s=24,q=e.radius,l=d.wheelWidth,p=8/q/s*Math.PI,t=e.ctxMask,g=0,z,B;t.save();t.lineWidth=l/q;t.scale(q,q);for(var v=0;v<=s;++v){var A=v/s,f=A*Math.PI*2,y=Math.sin(g),h=-Math.cos(g);x2=Math.sin(f),y2=-Math.cos(f),am=(g+f)/2,tan=1/Math.cos((f-g)/2),xm=Math.sin(am)*tan,ym=-Math.cos(am)*tan,color2=e.pack(e.HSLToRGB([A,1,0.5]));if(v>0){if(navigator.userAgent.match(/msie/i)){var o=(1+Math.min(Math.abs(Math.tan(g)),Math.abs(Math.tan(Math.PI/2-g))))/s;z=e.pack(e.HSLToRGB([B-0.15*o,1,0.5]));color2=e.pack(e.HSLToRGB([A+0.15*o,1,0.5]));var k=t.createLinearGradient(y,h,x2,y2);k.addColorStop(0,z);k.addColorStop(1,color2);t.fillStyle=k;var x=(q+l/2)/q,u=(q-l/2)/q;t.beginPath();t.moveTo(y*x,h*x);t.quadraticCurveTo(xm*x,ym*x,x2*x,y2*x);t.lineTo(x2*u,y2*u);t.quadraticCurveTo(xm*u,ym*u,y*u,h*u);t.fill()}else{var k=t.createLinearGradient(y,h,x2,y2);k.addColorStop(0,z);k.addColorStop(1,color2);t.strokeStyle=k;t.beginPath();t.moveTo(y,h);t.quadraticCurveTo(xm,ym,x2,y2);t.stroke()}}g=f-p;z=color2;B=A}t.restore();a&&b("body").append("
    drawCircle "+(+(new Date())-j)+"ms")};e.drawMask=function(){var p=+(new Date());var s=e.square*2,h=e.square;function g(D,B,t){var w=1/D,v=1/B;for(var A=0;A<=B;++A){var u=1-A*v;for(var E=0;E<=D;++E){var F=1-E*w;var C=1-2*Math.min(u*F,(1-u)*F);var z=(C>0)?((2*u-1+C)*0.5/C):0;t(E,A,z,C)}}}if(e.ctxMask.getImageData){var m=Math.floor(s/2);var k=document.createElement("canvas");k.width=k.height=m+1;var q=k.getContext("2d");var j=q.getImageData(0,0,m+1,m+1);var l=0;g(m,m,function(t,w,v,u){j.data[l++]=j.data[l++]=j.data[l++]=v*255;j.data[l++]=u*255});q.putImageData(j,0,0);e.ctxMask.drawImage(k,0,0,m+1,m+1,-h,-h,h*2,h*2)}else{if(!navigator.userAgent.match(/msie/i)){var m=Math.floor(s/2);g(m,m,function(t,w,v,u){v=Math.round(v*255);e.ctxMask.fillStyle="rgba("+v+", "+v+", "+v+", "+u+")";e.ctxMask.fillRect(t*2-h-1,w*2-h-1,2,2)})}else{var r,f,o=6;var n=Math.floor(s/o);g(n,6,function(B,w,u,A){if(B==0){r=f;f=[]}u=Math.round(u*255);A=Math.round(A*255);if(w>0){var E=r[B][0],t=r[B][1],D=e.packDX(E,t),C=e.packDX(u,A),z=Math.round(e.mid+((w-1)*0.333-1)*h),v=Math.round(e.mid+(w*0.333-1)*h);b("
    ").css({position:"absolute",filter:"progid:DXImageTransform.Microsoft.Gradient(StartColorStr="+D+", EndColorStr="+C+", GradientType=0)",top:z,height:v-z,left:e.mid+(B*o-h-1),width:o-(B==n?Math.round(o/2):0)}).appendTo(e.cnvMask)}f.push([u,A])})}}a&&b("body").append("
    drawMask "+(+(new Date())-p)+"ms")};e.drawMarkers=function(){var p=d.width,j=Math.ceil(e.markerSize/4),f=e.markerSize-j+1;var k=e.hsl[0]*6.28,h=Math.sin(k)*e.radius,s=-Math.cos(k)*e.radius,g=2*e.square*(0.5-e.hsl[1]),q=2*e.square*(0.5-e.hsl[2]),m=e.invert?"#fff":"#000",l=e.invert?"#000":"#fff";var n=[{x:h,y:s,r:f,c:"#000",lw:j+1},{x:h,y:s,r:e.markerSize,c:"#fff",lw:j},{x:g,y:q,r:f,c:l,lw:j+1},{x:g,y:q,r:e.markerSize,c:m,lw:j},];e.ctxOverlay.clearRect(-e.mid,-e.mid,p,p);for(i in n){var o=n[i];e.ctxOverlay.lineWidth=o.lw;e.ctxOverlay.strokeStyle=o.c;e.ctxOverlay.beginPath();e.ctxOverlay.arc(o.x,o.y,o.r,0,Math.PI*2,true);e.ctxOverlay.stroke()}};e.updateDisplay=function(){e.invert=(e.rgb[0]*0.3+e.rgb[1]*0.59+e.rgb[2]*0.11)<=0.6;e.solidFill.css("backgroundColor",e.pack(e.HSLToRGB([e.hsl[0],1,0.5])));e.drawMarkers();if(typeof e.callback=="object"){b(e.callback).css({backgroundColor:e.color,color:e.invert?"#fff":"#000"});b(e.callback).each(function(){if((typeof this.value=="string")&&this.value!=e.color){this.value=e.color}})}else{if(typeof e.callback=="function"){e.callback.call(e,e.color)}}};e.widgetCoords=function(f){return{x:f.pageX-e.offset.left-e.mid,y:f.pageY-e.offset.top-e.mid}};e.mousedown=function(f){if(!b._farbtastic.dragging){b(document).bind("mousemove",e.mousemove).bind("mouseup",e.mouseup);b._farbtastic.dragging=true}e.offset=b(c).offset();var g=e.widgetCoords(f);e.circleDrag=Math.max(Math.abs(g.x),Math.abs(g.y))>(e.square+2);e.mousemove(f);return false};e.mousemove=function(j){var k=e.widgetCoords(j);if(e.circleDrag){var h=Math.atan2(k.x,-k.y)/6.28;e.setHSL([(h+1)%1,e.hsl[1],e.hsl[2]])}else{var g=Math.max(0,Math.min(1,-(k.x/e.square/2)+0.5));var f=Math.max(0,Math.min(1,-(k.y/e.square/2)+0.5));e.setHSL([e.hsl[0],g,f])}return false};e.mouseup=function(){b(document).unbind("mousemove",e.mousemove);b(document).unbind("mouseup",e.mouseup);b._farbtastic.dragging=false};e.dec2hex=function(f){return(f<16?"0":"")+f.toString(16)};e.packDX=function(g,f){return"#"+e.dec2hex(f)+e.dec2hex(g)+e.dec2hex(g)+e.dec2hex(g)};e.pack=function(h){var k=Math.round(h[0]*255);var j=Math.round(h[1]*255);var f=Math.round(h[2]*255);return"#"+e.dec2hex(k)+e.dec2hex(j)+e.dec2hex(f)};e.unpack=function(g){if(g.length==7){function f(h){return parseInt(g.substring(h,h+2),16)/255}return[f(1),f(3),f(5)]}else{if(g.length==4){function f(h){return parseInt(g.substring(h,h+1),16)/15}return[f(1),f(2),f(3)]}}};e.HSLToRGB=function(o){var q,p,f,m,n;var k=o[0],t=o[1],j=o[2];p=(j<=0.5)?j*(t+1):j+t-j*t;q=j*2-p;return[this.hueToRGB(q,p,k+0.33333),this.hueToRGB(q,p,k),this.hueToRGB(q,p,k-0.33333)]};e.hueToRGB=function(g,f,j){j=(j+1)%1;if(j*6<1){return g+(f-g)*j*6}if(j*2<1){return f}if(j*3<2){return g+(f-g)*(0.66666-j)*6}return g};e.RGBToHSL=function(o){var f=o[0],n=o[1],p=o[2],k=Math.min(f,n,p),q=Math.max(f,n,p),t=q-k,m=0,u=0,j=(k+q)/2;if(j>0&&j<1){u=t/(j<0.5?(2*j):(2-2*j))}if(t>0){if(q==f&&q!=n){m+=(n-p)/t}if(q==n&&q!=p){m+=(2+(p-f)/t)}if(q==p&&q!=f){m+=(4+(f-n)/t)}m/=6}return[m,u,j]};if(!d.callback){d={callback:d}}d=b.extend({width:300,wheelWidth:(d.width||300)/10,callback:null,color:"#808080"},d);e.initWidget();b("canvas.farbtastic-overlay",c).mousedown(e.mousedown);if(d.callback){e.linkTo(d.callback)}e.setColor("#808080");e.setColor(d.color)}})(jQuery); \ No newline at end of file diff --git a/static/scripts/packed/libs/jquery/jquery.event.hover.js b/static/scripts/packed/libs/jquery/jquery.event.hover.js index 39324e434fa..cb172459cd3 100644 --- a/static/scripts/packed/libs/jquery/jquery.event.hover.js +++ b/static/scripts/packed/libs/jquery/jquery.event.hover.js @@ -1 +1 @@ -(function(c){c.fn._hover=c.fn.hover;c.fn.hover=function(f,e,d){if(d){this.bind("hoverstart",f)}if(e){this.bind("hoverend",d?d:e)}return !f?this.trigger("hover"):this.bind("hover",d?e:f)};var b=c.event.special.hover={delay:100,speed:100,setup:function(d){d=c.extend({speed:b.speed,delay:b.delay,hovered:0},d||{});c.event.add(this,"mouseenter mouseleave",a,d)},teardown:function(){c.event.remove(this,"mouseenter mouseleave",a)}};function a(d){var f=d.data||d;switch(d.type){case"mouseenter":f.dist2=0;f.event=d;d.type="hoverstart";if(c.event.handle.call(this,d)!==false){f.elem=this;c.event.add(this,"mousemove",a,f);f.timer=setTimeout(e,f.delay)}break;case"mousemove":f.dist2+=Math.pow(d.pageX-f.event.pageX,2)+Math.pow(d.pageY-f.event.pageY,2);f.event=d;break;case"mouseleave":clearTimeout(f.timer);if(f.hovered){d.type="hoverend";c.event.handle.call(this,d);f.hovered--}else{c.event.remove(f.elem,"mousemove",a)}break;default:if(f.dist2<=Math.pow(f.speed*(f.delay/1000),2)){c.event.remove(f.elem,"mousemove",a);f.event.type="hover";if(c.event.handle.call(f.elem,f.event)!==false){f.hovered++}}else{f.timer=setTimeout(e,f.delay)}f.dist2=0;break}function e(){a(f)}}})(jQuery); \ No newline at end of file +(function(c){c.fn._hover=c.fn.hover;c.fn.hover=function(f,e,d){if(d){this.bind("hoverstart",f)}if(e){this.bind("hoverend",d?d:e)}return !f?this.trigger("hover"):this.bind("hover",d?e:f)};var b=c.event.special.hover={delay:100,speed:100,setup:function(d){d=c.extend({speed:b.speed,delay:b.delay,hovered:0},d||{});c.event.add(this,"mouseenter mouseleave",a,d)},teardown:function(){c.event.remove(this,"mouseenter mouseleave",a)}};function a(d){var f=d.data||d;switch(d.type){case"mouseenter":f.dist2=0;f.event=d;d.type="hoverstart";if(c.event.dispatch.call(this,d)!==false){f.elem=this;c.event.add(this,"mousemove",a,f);f.timer=setTimeout(e,f.delay)}break;case"mousemove":f.dist2+=Math.pow(d.pageX-f.event.pageX,2)+Math.pow(d.pageY-f.event.pageY,2);f.event=d;break;case"mouseleave":clearTimeout(f.timer);if(f.hovered){d.type="hoverend";c.event.dispatch.call(this,d);f.hovered--}else{c.event.remove(f.elem,"mousemove",a)}break;default:if(f.dist2<=Math.pow(f.speed*(f.delay/1000),2)){c.event.remove(f.elem,"mousemove",a);f.event.type="hover";if(c.event.dispatch.call(f.elem,f.event)!==false){f.hovered++}}else{f.timer=setTimeout(e,f.delay)}f.dist2=0;break}function e(){a(f)}}})(jQuery); \ No newline at end of file diff --git a/static/scripts/packed/mvc/ui.js b/static/scripts/packed/mvc/ui.js index d1e0fcf036d..b93092f8610 100644 --- a/static/scripts/packed/mvc/ui.js +++ b/static/scripts/packed/mvc/ui.js @@ -1 +1 @@ -var IconButton=Backbone.Model.extend({defaults:{title:"",icon_class:"",on_click:null,menu_options:null,tooltip_config:{},isMenuButton:true,id:null,href:null,target:null,enabled:true,visible:true}});var IconButtonView=Backbone.View.extend({initialize:function(){this.model.attributes.tooltip_config={placement:"bottom"};this.model.bind("change",this.render,this)},render:function(){this.$el.tooltip("hide");var a=$(Handlebars.partials.iconButton(this.model.toJSON()));a.tooltip(this.model.get("tooltip_config"));this.$el.replaceWith(a);this.setElement(a);return this},events:{click:"click"},click:function(a){if(this.model.attributes.on_click){this.model.attributes.on_click(a);return false}return true}});IconButtonView.templates={iconButton:Handlebars.partials.iconButton};var IconButtonCollection=Backbone.Collection.extend({model:IconButton});var IconButtonMenuView=Backbone.View.extend({tagName:"div",initialize:function(){this.render()},render:function(){var a=this;this.collection.each(function(d){var b=$("").attr("href","javascript:void(0)").attr("title",d.attributes.title).addClass("icon-button menu-button").addClass(d.attributes.icon_class).appendTo(a.$el).click(d.attributes.on_click);if(d.attributes.tooltip_config){b.tooltip(d.attributes.tooltip_config)}var c=d.get("options");if(c){make_popupmenu(b,c)}});return this}});var create_icon_buttons_menu=function(b,a){if(!a){a={}}var c=new IconButtonCollection(_.map(b,function(d){return new IconButton(_.extend(d,a))}));return new IconButtonMenuView({collection:c})};var Grid=Backbone.Collection.extend({});var GridView=Backbone.View.extend({});var GalaxyPaths=Backbone.Model.extend({defaults:{root_path:"",image_path:""}});var PopupMenu=Backbone.View.extend({initialize:function(b,a){this.$button=b||$("
    ");this.options=a||[];var c=this;this.$button.click(function(d){c._renderAndShow(d);return false});this.$button.data("PopupMenu",this)},render:function(){var a=this;this.$el.addClass("popmenu-wrapper").css({position:"absolute",display:"none"});this.$el.html(PopupMenu.templates.menu({options:this.options,id:this.$button.attr("id")}));if(this.options.length){this.$el.find("li").each(function(c,b){var f=$(b),e=f.children("a.popupmenu-option"),d=a.options[c].func;if(e.length&&d){e.click(function(g){d(g,a.options[c])})}a.options[c].$li=f})}return this},_getShownPosition:function(b){var c=this.$el.width(),a=b.pageX-c/2;a=Math.min(a,$(document).scrollLeft()+$(window).width()-c-5);a=Math.max(a,$(document).scrollLeft()+5);return{top:b.pageY,left:a}},_renderAndShow:function(a){this.render();this.$el.appendTo("body");this.$el.css(this._getShownPosition(a));this._setUpCloseBehavior();this.$el.show()},_setUpCloseBehavior:function(){var b=this,a=function(c){c.bind("click.close_popup",function(){b.remove();c.unbind("click.close_popup")})};a($(window.document));a($(window.top.document));_.each(window.top.frames,function(c){a($(c.document))})},addItem:function(b,a){a=(a>=0)?(a):(this.options.length);this.options.splice(a,0,b);return this},removeItem:function(a){if(a>=0){this.options.splice(a,1)}return this},findIndexByHtml:function(b){for(var a=0;a"}else{a=""}return $(a)}});var IconButtonCollection=Backbone.Collection.extend({model:IconButton});var IconButtonMenuView=Backbone.View.extend({tagName:"div",initialize:function(){this.render()},render:function(){var a=this;this.collection.each(function(d){var b=$("").attr("href","javascript:void(0)").attr("title",d.attributes.title).addClass("icon-button menu-button").addClass(d.attributes.icon_class).appendTo(a.$el).click(d.attributes.on_click);if(d.attributes.tooltip_config){b.tooltip(d.attributes.tooltip_config)}var c=d.get("options");if(c){make_popupmenu(b,c)}});return this}});var create_icon_buttons_menu=function(b,a){if(!a){a={}}var c=new IconButtonCollection(_.map(b,function(d){return new IconButton(_.extend(d,a))}));return new IconButtonMenuView({collection:c})};var Grid=Backbone.Collection.extend({});var GridView=Backbone.View.extend({});var GalaxyPaths=Backbone.Model.extend({defaults:{root_path:"",image_path:""}});var PopupMenu=Backbone.View.extend({initialize:function(b,a){this.$button=b||$("
    ");this.options=a||[];var c=this;this.$button.click(function(d){c._renderAndShow(d);return false});this.$button.data("PopupMenu",this)},render:function(){var a=this;this.$el.addClass("popmenu-wrapper").css({position:"absolute",display:"none"});this.$el.html(PopupMenu.templates.menu({options:this.options,id:this.$button.attr("id")}));if(this.options.length){this.$el.find("li").each(function(c,b){var f=$(b),e=f.children("a.popupmenu-option"),d=a.options[c].func;if(e.length&&d){e.click(function(g){d(g,a.options[c])})}a.options[c].$li=f})}return this},_getShownPosition:function(b){var c=this.$el.width(),a=b.pageX-c/2;a=Math.min(a,$(document).scrollLeft()+$(window).width()-c-5);a=Math.max(a,$(document).scrollLeft()+5);return{top:b.pageY,left:a}},_renderAndShow:function(a){this.render();this.$el.appendTo("body");this.$el.css(this._getShownPosition(a));this._setUpCloseBehavior();this.$el.show()},_setUpCloseBehavior:function(){var b=this,a=function(c){c.bind("click.close_popup",function(){b.remove();c.unbind("click.close_popup")})};a($(window.document));a($(window.top.document));_.each(window.top.frames,function(c){a($(c.document))})},addItem:function(b,a){a=(a>=0)?(a):(this.options.length);this.options.splice(a,0,b);return this},removeItem:function(a){if(a>=0){this.options.splice(a,1)}return this},findIndexByHtml:function(b){for(var a=0;a\n ';h=d.name;c=h||n.name;if(typeof c===f){c=c.call(n,{hash:{}})}else{if(c===g){c=m.call(n,"name",{hash:{}})}}i+=j(c)+'\n
    \n