]> granicus.if.org Git - transmission/commitdiff
#4866: Replace existing menus with jQueryUI menu
authorMike Gelfand <mikedld@mikedld.com>
Thu, 30 Apr 2015 05:20:48 +0000 (05:20 +0000)
committerMike Gelfand <mikedld@mikedld.com>
Thu, 30 Apr 2015 05:20:48 +0000 (05:20 +0000)
14 files changed:
web/index.html
web/javascript/common.js
web/javascript/jquery/Makefile.am
web/javascript/jquery/jquery.contextmenu.min.js [deleted file]
web/javascript/jquery/jquery.contextmenu.r2.js [deleted file]
web/javascript/jquery/jquery.transmenu.js
web/javascript/jquery/jquery.transmenu.min.js
web/javascript/jquery/jquery.ui-contextmenu.js [new file with mode: 0644]
web/javascript/jquery/jquery.ui-contextmenu.min.js [new file with mode: 0644]
web/javascript/transmission.js
web/style/transmission/common.css
web/style/transmission/common.scss
web/style/transmission/mobile.css
web/style/transmission/mobile.scss

index 471360455e241bd42da760148391fe6f96b99a4d..0a78fdcb17618c66197416f3acab0e1c2f7110f5 100755 (executable)
@@ -11,6 +11,7 @@
                <script type="text/javascript" src="./javascript/jquery/jquery.min.js"></script>
                <script type="text/javascript" src="./javascript/jquery/jquery-migrate.min.js"></script>
                <script type="text/javascript" src="./javascript/jquery/jquery-ui.min.js"></script>
+               <script type="text/javascript" src="./javascript/jquery/jquery.ui-contextmenu.min.js"></script>
                <link rel="stylesheet" href="./style/jqueryui/jquery-ui.min.css" type="text/css" media="all" />
 <!--
                <link media="screen" href="./style/transmission/mobile.css" type= "text/css" rel="stylesheet" />
@@ -21,7 +22,6 @@
                <link media="screen" href="./style/transmission/common.css" type="text/css" rel="stylesheet" />
                <![endif]-->
                <script type="text/javascript" src="./javascript/jquery/jquery.transmenu.min.js"></script>
-               <script type="text/javascript" src="./javascript/jquery/jquery.contextmenu.min.js"></script>
                <script type="text/javascript" src="./javascript/jquery/json2.min.js"></script>
                <script type="text/javascript" src="./javascript/common.js"></script>
                <script type="text/javascript" src="./javascript/inspector.js"></script>
                </div>
 
                <div class="torrent_footer">
-                       <ul id="settings_menu" title="Settings Menu">
-                               <li id="button">&nbsp;
-                                       <ul id="footer_super_menu">
-                                               <li id="about-button">About</li>
-                                               <li class="separator"></li>
-                                               <li id="homepage">Transmission Homepage</li>
-                                               <li id="tipjar">Transmission Tip Jar</li>
-                                               <li class="separator"></li>
-                                               <li id="statistics">Statistics</li>
-                                               <li class="ui-helper-hidden" id="toggle_notifications">Notifcations</li>
-                                               <li class="separator"></li>
-                                               <li>Total Download Rate
-                                                       <ul id="footer_download_rate_menu">
-                                                               <li id="unlimited_download_rate">Unlimited</li>
-                                                               <li id="limited_download_rate">Limit (10 kB/s)</li>
-                                                               <li class="separator"></li>
-                                                               <li class='download-speed'>5 kB/s</li>
-                                                               <li class='download-speed'>10 kB/s</li>
-                                                               <li class='download-speed'>20 kB/s</li>
-                                                               <li class='download-speed'>30 kB/s</li>
-                                                               <li class='download-speed'>40 kB/s</li>
-                                                               <li class='download-speed'>50 kB/s</li>
-                                                               <li class='download-speed'>75 kB/s</li>
-                                                               <li class='download-speed'>100 kB/s</li>
-                                                               <li class='download-speed'>150 kB/s</li>
-                                                               <li class='download-speed'>200 kB/s</li>
-                                                               <li class='download-speed'>250 kB/s</li>
-                                                               <li class='download-speed'>500 kB/s</li>
-                                                               <li class='download-speed'>750 kB/s</li>
-                                                       </ul>
-                                               </li>
-                                               <li>Total Upload Rate
-                                                       <ul id="footer_upload_rate_menu">
-                                                               <li id="unlimited_upload_rate">Unlimited</li>
-                                                               <li id="limited_upload_rate">Limit (10 kB/s)</li>
-                                                               <li class="separator"></li>
-                                                               <li class='upload-speed'>5 kB/s</li>
-                                                               <li class='upload-speed'>10 kB/s</li>
-                                                               <li class='upload-speed'>20 kB/s</li>
-                                                               <li class='upload-speed'>30 kB/s</li>
-                                                               <li class='upload-speed'>40 kB/s</li>
-                                                               <li class='upload-speed'>50 kB/s</li>
-                                                               <li class='upload-speed'>75 kB/s</li>
-                                                               <li class='upload-speed'>100 kB/s</li>
-                                                               <li class='upload-speed'>150 kB/s</li>
-                                                               <li class='upload-speed'>200 kB/s</li>
-                                                               <li class='upload-speed'>250 kB/s</li>
-                                                               <li class='upload-speed'>500 kB/s</li>
-                                                               <li class='upload-speed'>750 kB/s</li>
-                                                       </ul>
-                                               </li>
-                                               <li class="separator"></li>
-                                               <li>Sort Transfers By
-                                                       <ul id="footer_sort_menu">
-                                                               <li class='sort-mode' id="sort_by_queue_order">Queue Order</li>
-                                                               <li class='sort-mode' id="sort_by_activity">Activity</li>
-                                                               <li class='sort-mode' id="sort_by_age">Age</li>
-                                                               <li class='sort-mode' id="sort_by_name">Name</li>
-                                                               <li class='sort-mode' id="sort_by_percent_completed">Progress</li>
-                                                               <li class='sort-mode' id="sort_by_ratio">Ratio</li>
-                                                               <li class='sort-mode' id="sort_by_size">Size</li>
-                                                               <li class='sort-mode' id="sort_by_state">State</li>
-                                                               <li class="separator"></li>
-                                                               <li id="reverse_sort_order">Reverse Sort Order</li>
-                                                       </ul>
-                                               </li>
-                                       </ul>
-                               </li>
-                       </ul>
+                       <div id="settings_menu" title="Settings Menu">&nbsp;</div>
                        <div id="prefs-button" title="Edit Preferences…">&nbsp;</div>
                        <div id="turtle-button" title="Alternative Speed Limits">&nbsp;</div>
                        <div id="compact-button" title="Compact View">&nbsp;</div>
-               </div>
 
-               <div class="contextMenu" id="torrent_context_menu">
-                       <ul>
-                               <li id="context_pause_selected" class="disabled context_pause_selected">Pause</li>
-                               <li id="context_resume_selected" class="disabled context_resume_selected">Resume</li>
-                               <li id="context_resume_now_selected" class="disabled context_resume_selected">Resume Now</li>
-                               <li class="separator"></li>
-                               <li id="context_move_top">Move to Top</li>
-                               <li id="context_move_up">Move Up</li>
-                               <li id="context_move_down">Move Down</li>
-                               <li id="context_move_bottom">Move to Bottom</li>
-                               <li class="separator"></li>
-                               <li id="context_remove">Remove From List…</li>
-                               <li id="context_removedata">Trash Data and Remove From List…</li>
-                               <li class="separator"></li>
-                               <li id="context_verify">Verify Local Data</li>
-                               <li id="context_move">Set Location…</li>
-                               <li id="context_rename">Rename…</li>
-                               <li class="separator"></li>
-                               <li id="context_reannounce">Ask tracker for more peers</li>
-                               <li class="separator"></li>
-                               <li id="context_select_all">Select All</li>
-                               <li id="context_deselect_all">Deselect All</li>
+                       <ul class="ui-helper-hidden" id="footer_super_menu">
+                               <li id="about-button">About</li>
+                               <li>---</li>
+                               <li id="homepage">Transmission Homepage</li>
+                               <li id="tipjar">Transmission Tip Jar</li>
+                               <li>---</li>
+                               <li id="statistics">Statistics</li>
+                               <!--
+                               <li id="toggle_notifications">Notifcations</li>
+                               -->
+                               <li>---</li>
+                               <li>Total Download Rate
+                                       <ul id="footer_download_rate_menu">
+                                               <li radio-group="download-rate" id="unlimited_download_rate"><span class='ui-icon ui-icon-bullet'></span>Unlimited</li>
+                                               <li radio-group="download-rate" id="limited_download_rate">Limit (10 kB/s)</li>
+                                               <li>---</li>
+                                               <li class='download-speed'>5 kB/s</li>
+                                               <li class='download-speed'>10 kB/s</li>
+                                               <li class='download-speed'>20 kB/s</li>
+                                               <li class='download-speed'>30 kB/s</li>
+                                               <li class='download-speed'>40 kB/s</li>
+                                               <li class='download-speed'>50 kB/s</li>
+                                               <li class='download-speed'>75 kB/s</li>
+                                               <li class='download-speed'>100 kB/s</li>
+                                               <li class='download-speed'>150 kB/s</li>
+                                               <li class='download-speed'>200 kB/s</li>
+                                               <li class='download-speed'>250 kB/s</li>
+                                               <li class='download-speed'>500 kB/s</li>
+                                               <li class='download-speed'>750 kB/s</li>
+                                       </ul>
+                               </li>
+                               <li>Total Upload Rate
+                                       <ul id="footer_upload_rate_menu">
+                                               <li radio-group="upload-rate" id="unlimited_upload_rate"><span class='ui-icon ui-icon-bullet'></span>Unlimited</li>
+                                               <li radio-group="upload-rate" id="limited_upload_rate">Limit (10 kB/s)</li>
+                                               <li>---</li>
+                                               <li class='upload-speed'>5 kB/s</li>
+                                               <li class='upload-speed'>10 kB/s</li>
+                                               <li class='upload-speed'>20 kB/s</li>
+                                               <li class='upload-speed'>30 kB/s</li>
+                                               <li class='upload-speed'>40 kB/s</li>
+                                               <li class='upload-speed'>50 kB/s</li>
+                                               <li class='upload-speed'>75 kB/s</li>
+                                               <li class='upload-speed'>100 kB/s</li>
+                                               <li class='upload-speed'>150 kB/s</li>
+                                               <li class='upload-speed'>200 kB/s</li>
+                                               <li class='upload-speed'>250 kB/s</li>
+                                               <li class='upload-speed'>500 kB/s</li>
+                                               <li class='upload-speed'>750 kB/s</li>
+                                       </ul>
+                               </li>
+                               <li>---</li>
+                               <li>Sort Transfers By
+                                       <ul id="footer_sort_menu">
+                                               <li radio-group="sort-mode" id="sort_by_queue_order">Queue Order</li>
+                                               <li radio-group="sort-mode" id="sort_by_activity">Activity</li>
+                                               <li radio-group="sort-mode" id="sort_by_age">Age</li>
+                                               <li radio-group="sort-mode" id="sort_by_name">Name</li>
+                                               <li radio-group="sort-mode" id="sort_by_percent_completed">Progress</li>
+                                               <li radio-group="sort-mode" id="sort_by_ratio">Ratio</li>
+                                               <li radio-group="sort-mode" id="sort_by_size">Size</li>
+                                               <li radio-group="sort-mode" id="sort_by_state">State</li>
+                                               <li>---</li>
+                                               <li id="reverse_sort_order">Reverse Sort Order</li>
+                                       </ul>
+                               </li>
                        </ul>
                </div>
 
+               <ul class="ui-helper-hidden" id="torrent_context_menu">
+                       <li data-command="pause_selected">Pause</li>
+                       <li data-command="resume_selected">Resume</li>
+                       <li data-command="resume_now_selected">Resume Now</li>
+                       <li>---</li>
+                       <li data-command="move_top">Move to Top</li>
+                       <li data-command="move_up">Move Up</li>
+                       <li data-command="move_down">Move Down</li>
+                       <li data-command="move_bottom">Move to Bottom</li>
+                       <li>---</li>
+                       <li data-command="remove">Remove From List…</li>
+                       <li data-command="remove_data">Trash Data and Remove From List…</li>
+                       <li>---</li>
+                       <li data-command="verify">Verify Local Data</li>
+                       <li data-command="move">Set Location…</li>
+                       <li data-command="rename">Rename…</li>
+                       <li>---</li>
+                       <li data-command="reannounce">Ask tracker for more peers</li>
+                       <li>---</li>
+                       <li data-command="select_all">Select All</li>
+                       <li data-command="deselect_all">Deselect All</li>
+               </ul>
+
                <iframe name="torrent_upload_frame" id="torrent_upload_frame" src="about:blank" ></iframe>
        </body>
 </html>
index 5eccb4d03b6e4d578d5d23da0755544bc5501679..f21dbbaf08ae507eff60ceed4b0f6e98dee41077 100644 (file)
@@ -64,11 +64,7 @@ $(document).ready(function() {
                $("label[for=torrent_upload_url]").text("URL: ");
        } else {
                // Fix for non-Safari-3 browsers: dark borders to replace shadows.
-               // Opera messes up the menu if we use a border on .trans_menu
-               // div.outerbox so use ul instead
-               $('.trans_menu ul, div#jqContextMenu, div.dialog_container div.dialog_window').css('border', '1px solid #777');
-               // and this kills the border we used to have
-               $('.trans_menu div.outerbox').css('border', 'none');
+               $('div.dialog_container div.dialog_window').css('border', '1px solid #777');
        }
 
        // Initialise the dialog controller
index a0627b8c3e36553376b62eec59f6d387efe3da40..34970f86890aa3c717c16775b812fe891073d22a 100644 (file)
@@ -4,6 +4,6 @@ dist_data_DATA = \
   jquery-ui.min.js \
   jquery-migrate.min.js \
   jquery.min.js \
-  jquery.contextmenu.min.js \
+  jquery.ui-contextmenu.min.js \
   jquery.transmenu.min.js \
   json2.min.js
diff --git a/web/javascript/jquery/jquery.contextmenu.min.js b/web/javascript/jquery/jquery.contextmenu.min.js
deleted file mode 100644 (file)
index e90df8c..0000000
+++ /dev/null
@@ -1 +0,0 @@
-(function(a){function i(d,h,i,k){var l=f[d],m=i[l.eventPosY],n=i[l.eventPosX];e=a("#"+l.id).find("ul:first").clone(!0),e.css(l.menuStyle).find("li").css(l.itemStyle).hover(function(){a(this).css(l.itemHoverStyle)},function(){a(this).css(l.itemStyle)}).find("img").css({verticalAlign:"middle",paddingRight:"2px"}),b.html(e),!l.onShowMenu||(b=l.onShowMenu(i,b)),a.each(l.bindings,function(c,d){a("#"+c,b).bind("click",function(a){j(),d(h,g)})}),m+b.height()>a(window).height()&&(m=m-b.height()),n+b.width()>a(window).width()&&(n=n-b.width()),b.css({left:n,top:m}).show(),l.shadow&&c.css({width:b.width(),height:b.height(),left:i.pageX+2,top:i.pageY+2}).show(),setTimeout(function(){a(document).click(function(){return a(document).unbind("click"),j(),!1})},0)}function j(){b.hide(),c.hide()}var b,c,d,e,f,g,h={menuStyle:{listStyle:"none",padding:"1px",margin:"0px",backgroundColor:"#fff",border:"1px solid #999",width:"100px"},itemStyle:{margin:"0px",color:"#000",display:"block",cursor:"default",padding:"3px",border:"1px solid #fff",backgroundColor:"transparent"},itemHoverStyle:{border:"1px solid #0a246a",backgroundColor:"#b6bdd2"},eventPosX:"pageX",eventPosY:"pageY",shadow:!0,onContextMenu:null,onShowMenu:null};a.fn.contextMenu=function(d,e){b||(b=a('<div id="jqContextMenu"></div>').hide().css({position:"absolute",zIndex:"500"}).appendTo("body").bind("click",function(a){a.stopPropagation()})),c||(c=a("<div></div>").css({backgroundColor:"#000",position:"absolute",opacity:.2,zIndex:499}).appendTo("body").hide()),f=f||[],f.push({id:d,menuStyle:a.extend({},h.menuStyle,e.menuStyle||{}),itemStyle:a.extend({},h.itemStyle,e.itemStyle||{}),itemHoverStyle:a.extend({},h.itemHoverStyle,e.itemHoverStyle||{}),bindings:e.bindings||{},shadow:e.shadow||e.shadow===!1?e.shadow:h.shadow,onContextMenu:e.onContextMenu||h.onContextMenu,onShowMenu:e.onShowMenu||h.onShowMenu,eventPosX:e.eventPosX||h.eventPosX,eventPosY:e.eventPosY||h.eventPosY});var g=f.length-1;return a(this).bind("contextmenu",function(a){var b=f[g].onContextMenu?f[g].onContextMenu(a):!0;return b&&i(g,this,a,e),!1}),this},a.contextMenu={defaults:function(b){a.each(b,function(b,c){typeof c=="object"&&h[b]?a.extend(h[b],c):h[b]=c})}}})(jQuery),$(function(){$("div.contextMenu").hide()})
\ No newline at end of file
diff --git a/web/javascript/jquery/jquery.contextmenu.r2.js b/web/javascript/jquery/jquery.contextmenu.r2.js
deleted file mode 100644 (file)
index a026a0f..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-/*\r
- * ContextMenu - jQuery plugin for right-click context menus\r
- *\r
- * Author: Chris Domigan\r
- * Contributors: Dan G. Switzer, II\r
- * Parts of this plugin are inspired by Joern Zaefferer's Tooltip plugin\r
- *\r
- * Dual licensed under the MIT and GPL licenses:\r
- *   http://www.opensource.org/licenses/mit-license.php\r
- *   http://www.gnu.org/licenses/gpl.html\r
- *\r
- * Version: r2\r
- * Date: 16 July 2007\r
- *\r
- * For documentation visit http://www.trendskitchens.co.nz/jquery/contextmenu/\r
- *\r
- */\r
-\r
-(function($) {\r
-\r
-       var menu, shadow, trigger, content, hash, currentTarget;\r
-  var defaults = {\r
-    menuStyle: {\r
-      listStyle: 'none',\r
-      padding: '1px',\r
-      margin: '0px',\r
-      backgroundColor: '#fff',\r
-      border: '1px solid #999',\r
-      width: '100px'\r
-    },\r
-    itemStyle: {\r
-      margin: '0px',\r
-      color: '#000',\r
-      display: 'block',\r
-      cursor: 'default',\r
-      padding: '3px',\r
-      border: '1px solid #fff',\r
-      backgroundColor: 'transparent'\r
-    },\r
-    itemHoverStyle: {\r
-      border: '1px solid #0a246a',\r
-      backgroundColor: '#b6bdd2'\r
-    },\r
-    eventPosX: 'pageX',\r
-    eventPosY: 'pageY',\r
-    shadow : true,\r
-    onContextMenu: null,\r
-    onShowMenu: null\r
-       };\r
-\r
-  $.fn.contextMenu = function(id, options) {\r
-    if (!menu) {                                      // Create singleton menu\r
-      menu = $('<div id="jqContextMenu"></div>')\r
-               .hide()\r
-               .css({position:'absolute', zIndex:'500'})\r
-               .appendTo('body')\r
-               .bind('click', function(e) {\r
-                 e.stopPropagation();\r
-               });\r
-    }\r
-    if (!shadow) {\r
-      shadow = $('<div></div>')\r
-                 .css({backgroundColor:'#000',position:'absolute',opacity:0.2,zIndex:499})\r
-                 .appendTo('body')\r
-                 .hide();\r
-    }\r
-    hash = hash || [];\r
-    hash.push({\r
-      id : id,\r
-      menuStyle: $.extend({}, defaults.menuStyle, options.menuStyle || {}),\r
-      itemStyle: $.extend({}, defaults.itemStyle, options.itemStyle || {}),\r
-      itemHoverStyle: $.extend({}, defaults.itemHoverStyle, options.itemHoverStyle || {}),\r
-      bindings: options.bindings || {},\r
-      shadow: options.shadow || options.shadow === false ? options.shadow : defaults.shadow,\r
-      onContextMenu: options.onContextMenu || defaults.onContextMenu,\r
-      onShowMenu: options.onShowMenu || defaults.onShowMenu,\r
-      eventPosX: options.eventPosX || defaults.eventPosX,\r
-      eventPosY: options.eventPosY || defaults.eventPosY\r
-    });\r
-\r
-    var index = hash.length - 1;\r
-    $(this).bind('contextmenu', function(e) {\r
-      // Check if onContextMenu() defined\r
-      var bShowContext = (!!hash[index].onContextMenu) ? hash[index].onContextMenu(e) : true;\r
-      if (bShowContext) display(index, this, e, options);\r
-      return false;\r
-    });\r
-    return this;\r
-  };\r
-\r
-  function display(index, trigger, e, options) {\r
-    var cur = hash[index];\r
-    var top = e[cur.eventPosY];\r
-    var left = e[cur.eventPosX];\r
-    content = $('#'+cur.id).find('ul:first').clone(true);\r
-    content.css(cur.menuStyle).find('li').css(cur.itemStyle).hover(\r
-      function() {\r
-        $(this).css(cur.itemHoverStyle);\r
-      },\r
-      function(){\r
-        $(this).css(cur.itemStyle);\r
-      }\r
-    ).find('img').css({verticalAlign:'middle',paddingRight:'2px'});\r
-\r
-    // Send the content to the menu\r
-    menu.html(content);\r
-\r
-    // if there's an onShowMenu, run it now -- must run after content has been added\r
-               // if you try to alter the content variable before the menu.html(), IE6 has issues\r
-               // updating the content\r
-    if (!!cur.onShowMenu) menu = cur.onShowMenu(e, menu);\r
-\r
-    $.each(cur.bindings, function(id, func) {\r
-      $('#'+id, menu).bind('click', function(e) {\r
-        hide();\r
-        func(trigger, currentTarget);\r
-      });\r
-    });\r
-\r
-\r
-    if( top + menu.height() > $(window).height() ) top = top - menu.height();\r
-    if( left + menu.width() > $(window).width() ) left = left - menu.width();\r
-    menu.css({'left':left,'top':top}).show();\r
-    if (cur.shadow) shadow.css({width:menu.width(),height:menu.height(),left:e.pageX+2,top:e.pageY+2}).show();\r
-    \r
-    setTimeout( function() { // Delay for Mozilla\r
-               $(document).click( function() {\r
-                       $(document).unbind('click');\r
-                       hide();\r
-                       return false;\r
-               });\r
-       }, 0);\r
-  }\r
-\r
-  function hide() {\r
-    menu.hide();\r
-    shadow.hide();\r
-  }\r
-\r
-  // Apply defaults\r
-  $.contextMenu = {\r
-    defaults : function(userDefaults) {\r
-      $.each(userDefaults, function(i, val) {\r
-        if (typeof val == 'object' && defaults[i]) {\r
-          $.extend(defaults[i], val);\r
-        }\r
-        else defaults[i] = val;\r
-      });\r
-    }\r
-  };\r
-\r
-})(jQuery);\r
-\r
-$(function() {\r
-  $('div.contextMenu').hide();\r
-});
\ No newline at end of file
index e05e91d4bb254b18264fc9e7318c6c87bdbf31be..764c847ff654efa9b2b00a73ab84cb4665ab1ae4 100644 (file)
-/* transMenu - v0.1.5 (2007-07-07)\r
- * Copyright (c) 2007 Roman Weich\r
- * http://p.sohei.org\r
- *\r
- */\r
-\r
-(function($)\r
-{\r
-       var defaults = {\r
-               onClick: function(){\r
-                       $(this).find('>a').each(function(){\r
-                               if ( this.href )\r
-                               {\r
-                                       window.location = this.href;\r
-                               }\r
-                       });\r
-               },\r
-               arrow_char: '&#x25BA;',\r
-               selected_char: '&#x2713;',\r
-               subDelay: 300,\r
-               direction: 'down',\r
-               mainDelay: 10\r
-       };\r
-       \r
-       var transMenuSettings;\r
-\r
-       $.fn.transMenu = function(options) \r
-       {\r
-               var shown = false;\r
-               var liOffset = 2;\r
-\r
-               transMenuSettings = $.extend({}, defaults, options);\r
-\r
-               var hideDIV = function(div, delay) {\r
-                       //a timer running to show the div?\r
-                       if ( div.timer && !div.isVisible ) {\r
-                               clearTimeout(div.timer);\r
-                       } else if (div.timer) {\r
-                               return; //hide-timer already running\r
-                       }\r
-                       if ( div.isVisible ) {\r
-                               div.timer = setTimeout( function() {\r
-                                       //remove events\r
-                                       $(div).find('ul li').unbind('mouseover', liHoverIn).unbind('mouseout', liHoverOut).unbind('click', transMenuSettings.onClick);\r
-                                       $(div).hide();\r
-                                       div.isVisible = false;\r
-                                       div.timer = null;\r
-                               }, delay);\r
-                       }\r
-               };\r
-\r
-               var showDIV = function(div, delay) {\r
-                       if ( div.timer ) {\r
-                               clearTimeout(div.timer);\r
-                       }\r
-                       if ( !div.isVisible ) {\r
-                               div.timer = setTimeout( function() {\r
-                                       //check if the mouse is still over the parent item - if not dont show the submenu\r
-                                       if (! $(div).parent().is('.hover')) {\r
-                                               return;\r
-                                       }\r
-                                       //assign events to all div>ul>li-elements\r
-                                       $(div).find('ul li').mouseover(liHoverIn).mouseout(liHoverOut).click(transMenuSettings.onClick);\r
-                                       //positioning\r
-                                       if (! $(div).parent().is('.main')) {\r
-                                               $(div).css('left', $(div).parent().parent().width() - liOffset);\r
-                                       }\r
-                                       \r
-                                       if (transMenuSettings.direction == 'up') {\r
-                                               $(div).css('top', ($(div).height() * -1) + $(div).parent().parent().height());\r
-                                       }\r
-                                       \r
-                                       div.isVisible = true; //we use this over :visible to speed up traversing\r
-                                       $(div).show();\r
-                                       div.timer = null;\r
-                               }, delay);\r
-                       }\r
-               };\r
-\r
-               //same as hover.handlehover in jquery - just can't use hover() directly - need the ability to unbind only the one hover event\r
-               var testHandleHover = function(e) {\r
-                       // Check if mouse(over|out) are still within the same parent element\r
-                       var p = (e.type == "mouseover" ? e.fromElement : e.toElement) || e.relatedTarget;\r
-                       // Traverse up the tree\r
-                       while ( p && p != this ) {\r
-                               try { \r
-                                       p = p.parentNode;\r
-                               } catch(e) { \r
-                                       p = this;\r
-                               }\r
-                       }\r
-                       // If we actually just moused on to a sub-element, ignore it\r
-                       if ( p == this ) {\r
-                               return false;\r
-                       }\r
-                       return true;\r
-               };\r
-               \r
-               var mainHoverIn = function(e) {\r
-                       $(this).addClass('hover').siblings('li.hover').removeClass('hover');\r
-                       if ( shown ) {\r
-                               hoverIn(this, transMenuSettings.mainDelay);\r
-                       }\r
-               };\r
-\r
-               var liHoverIn = function(e) {\r
-                       if ( !testHandleHover(e) ) {\r
-                               return false;\r
-                       }\r
-                       if ( e.target != this ) {\r
-                               //look whether the target is a direct child of this (maybe an image)\r
-                               if ( !isChild(this, e.target) ) {\r
-                                       return;\r
-                               }\r
-                       }\r
-                       hoverIn(this, transMenuSettings.subDelay);\r
-               };\r
-\r
-               var hoverIn = function(li, delay) {\r
-                       //stop running timers from the other menus on the same level - a little faster than $('>*>div', li.parentNode)\r
-                       var n = li.parentNode.firstChild;\r
-                       for ( ; n; n = n.nextSibling ) {\r
-                               if ( n.nodeType == 1 && n.nodeName.toUpperCase() == 'LI' ) {\r
-                                       var div = getOneChild(n, 'DIV');\r
-                                       //clear show-div timer\r
-                                       if ( div && div.timer && !div.isVisible ) {\r
-                                               clearTimeout(div.timer);\r
-                                               div.timer = null;\r
-                                       }\r
-                               }\r
-                       }\r
-                       //is there a timer running to hide one of the parent divs? stop it\r
-                       var pNode = li.parentNode;\r
-                       for ( ; pNode; pNode = pNode.parentNode ) {\r
-                               if ( pNode.nodeType == 1 && pNode.nodeName.toUpperCase() == 'DIV' ) {\r
-                                       if (pNode.timer) {\r
-                                               clearTimeout(pNode.timer);\r
-                                               pNode.timer = null;\r
-                                               $(pNode.parentNode).addClass('hover');\r
-                                       }\r
-                               }\r
-                       }\r
-                       //highlight the current element\r
-                       $(li).addClass('hover');\r
-                       var innerDiv = $(li).children('div');\r
-                       innerDiv = innerDiv.length ? innerDiv[0] : null;\r
-                       //is the submenu already visible?\r
-                       if ( innerDiv && innerDiv.isVisible ) {\r
-                               //hide-timer running?\r
-                               if ( innerDiv.timer ) {\r
-                                       clearTimeout(innerDiv.timer);\r
-                                       innerDiv.timer = null;\r
-                               } else {\r
-                                       return;\r
-                               }\r
-                       }\r
-                       //hide all open menus on the same level and below and unhighlight the li item (but not the current submenu!)\r
-                       $(li.parentNode.getElementsByTagName('DIV')).each( function() {\r
-                               if ( this != innerDiv && this.isVisible ) {\r
-                                       hideDIV(this, delay);\r
-                                       $(this.parentNode).removeClass('hover');\r
-                               }\r
-                       });\r
-                       //show the submenu, if there is one\r
-                       if ( innerDiv ) {\r
-                               showDIV(innerDiv, delay);\r
-                       }\r
-               };\r
-\r
-               var liHoverOut = function(e) {\r
-                       if ( !testHandleHover(e) ) {\r
-                               return false;\r
-                       }\r
-                       if ( e.target != this ) {\r
-                               //return only if the target is no direct child of this\r
-                               if ( !isChild(this, e.target) )  {\r
-                                       return;\r
-                               }\r
-                       }\r
-                       // Remove the hover from the submenu item, if the mouse is hovering out of the \r
-                       // menu (this is only for the last open (levelwise) (sub-)menu)\r
-                       var div = getOneChild(this, 'DIV');\r
-                       if ( !div ) {\r
-                               $(this).removeClass('hover');\r
-                       } else  {\r
-                               if ( !div.isVisible ) {\r
-                                       $(this).removeClass('hover');\r
-                               }\r
-                       }\r
-               };\r
-\r
-               var mainHoverOut = function(e) {\r
-                       //no need to test e.target==this, as no child has the same event bound\r
-                       var div = getOneChild(this, 'DIV');\r
-                       var relTarget = e.relatedTarget || e.toElement; //this is undefined sometimes (e.g. when the mouse moves out of the window), so dont remove hover then\r
-                       var p;\r
-                       if ( !shown ) {\r
-                               $(this).removeClass('hover');\r
-                               \r
-                       //menuitem has no submenu, so dont remove the hover if the mouse goes outside the menu  \r
-                       } else if ( !div && relTarget ) {\r
-                               p = $(e.target).parents('UL.trans_menu');\r
-                               if ( p.contains(relTarget)) {\r
-                                       $(this).removeClass('hover');\r
-                               }\r
-                       } else if ( relTarget ) {\r
-                               //remove hover only when moving to anywhere inside the trans_menu\r
-                               p = $(e.target).parents('UL.trans_menu');\r
-                               if ( !div.isVisible && (p.contains(relTarget)) ) {\r
-                                       $(this).removeClass('hover');\r
-                               }\r
-                       }\r
-               };\r
-\r
-               var mainClick = function() {\r
-                       var div = getOneChild(this, 'DIV');\r
-                       //clicked on an open main-menu-item\r
-                       if ( div && div.isVisible ) {\r
-                               clean();\r
-                               $(this).addClass('hover');\r
-                       } else {\r
-                               hoverIn(this, transMenuSettings.mainDelay);\r
-                               shown = true;\r
-                               $('ul.trans_menu li').addClass('active');\r
-                               $(document).bind('mousedown', checkMouse);\r
-                       }\r
-               };\r
-\r
-               var checkMouse = function(e) {\r
-                       //is the mouse inside a trans_menu? if yes, is it an open (the current) one?\r
-                       var vis = false;\r
-                       $(e.target).parents('UL.trans_menu').find('div').each( function(){\r
-                               if ( this.isVisible ) {\r
-                                       vis = true;\r
-                               }\r
-                       });\r
-                       if ( !vis ) {\r
-                               clean();\r
-                       }\r
-               };\r
-\r
-               var clean = function() {\r
-                       //remove timeout and hide the divs\r
-                       $('ul.trans_menu div.outerbox').each(function(){\r
-                               if ( this.timer ) {\r
-                                       clearTimeout(this.timer);\r
-                                       this.timer = null;\r
-                               }\r
-                               if ( this.isVisible ) {\r
-                                       $(this).hide();\r
-                                       this.isVisible = false;\r
-                               }\r
-                       });\r
-                       $('ul.trans_menu li').removeClass('hover');\r
-                       //remove events\r
-                       $('ul.trans_menu>li li').unbind('mouseover', liHoverIn).unbind('mouseout', liHoverOut).unbind('click', transMenuSettings.onClick);\r
-                       $(document).unbind('mousedown', checkMouse);\r
-                       shown = false;\r
-                       $('ul.trans_menu li').removeClass('active');\r
-               };\r
-\r
-               var getOneChild = function(elem, name) {\r
-                       if ( !elem ) {\r
-                               return null;\r
-                       }\r
-                       var n = elem.firstChild;\r
-                       for ( ; n; n = n.nextSibling )  {\r
-                               if ( n.nodeType == 1 && n.nodeName.toUpperCase() == name ) {\r
-                                       return n;\r
-                               }\r
-                       }\r
-                       return null;\r
-               };\r
-               \r
-               var isChild = function(elem, childElem) {\r
-                       var n = elem.firstChild;\r
-                       for ( ; n; n = n.nextSibling ) {\r
-                               if ( n == childElem ) {\r
-                                       return true;\r
-                               }\r
-                       }\r
-                       return false;\r
-               };\r
-\r
-           return this.each(function() {\r
-                       //add .contains() to mozilla - http://www.quirksmode.org/blog/archives/2006/01/contains_for_mo.html\r
-                       if (window.Node && Node.prototype && !Node.prototype.contains) {\r
-                               Node.prototype.contains = function(arg)  {\r
-                                       return !!(this.compareDocumentPosition(arg) & 16);\r
-                               };\r
-                       }\r
-                       if (! $(this).is('.trans_menu')) {\r
-                               $(this).addClass('trans_menu');\r
-                       }\r
-                       //add shadows\r
-                       $('ul', this).shadowBox();\r
-                       \r
-                       //assign events\r
-                       $(this).bind('closemenu', function(){clean();}); //assign closemenu-event, through wich the menu can be closed from outside the plugin\r
-                       //add click event handling, if there are any elements inside the main menu\r
-                       var liElems = $(this).children('li');\r
-                       for ( var j = 0; j < liElems.length; j++ ) {\r
-                               if ( getOneChild(getOneChild(getOneChild(liElems[j], 'DIV'), 'UL'), 'LI') ) {\r
-                                       $(liElems[j]).click(mainClick);\r
-                               }\r
-                       }\r
-                       //add hover event handling and assign classes\r
-                       $(liElems).hover(mainHoverIn, mainHoverOut).addClass('main').find('>div').addClass('inner');\r
-                       //add the little arrow before each submenu\r
-                       if ( transMenuSettings.arrow_char ) {\r
-                               var arrow_markup = $("<span class='arrow'>" + transMenuSettings.arrow_char + '</span>');\r
-                               // Mozilla float/position hack\r
-                               if ($.browser.mozilla && +$.browser.version.replace(/\./g,'').slice(0,3) < 191) {\r
-                                       arrow_markup.css('margin-top', '-13px');\r
-                               }\r
-                               $('div.inner div.outerbox', this).before(arrow_markup);\r
-                       }\r
-\r
-                       //the floating list elements are destroying the layout..so make it nice again..\r
-                       $(this).wrap('<div class="main_container"></div>').after('<div style="clear: both; visibility: hidden;"></div>');\r
-           });\r
-       };\r
-       \r
-       $.fn.transMenu.setDefaults = function(o) {\r
-               $.extend(defaults, o);\r
-       };\r
-\r
-       $.fn.shadowBox = function() {\r
-           return this.each(function() {\r
-                       var outer = $('<div class="outerbox"></div>').get(0);\r
-                       if ( $(this).css('position') == 'absolute' ) {\r
-                               //if the child(this) is positioned abolute, we have to use relative positioning and shrink the outerbox accordingly to the innerbox\r
-                               $(outer).css({position:'relative', width:this.offsetWidth, height:this.offsetHeight});\r
-                       } else {\r
-                               //shrink the outerbox\r
-                               $(outer).css('position', 'absolute');\r
-                       }\r
-                       //add the boxes\r
-                       $(this).addClass('innerBox').wrap(outer).\r
-                                       before('<div class="shadowbox1"></div><div class="shadowbox2"></div><div class="shadowbox3"></div>');\r
-           });\r
-       };\r
-       \r
-       $.fn.selectMenuItem = function() {\r
-               if (this.find('span.selected').length == 0) {\r
-                       this.prepend($("<span class='selected'>" + transMenuSettings.selected_char + "</span>"));\r
-               }\r
-           return this;\r
-       };\r
-       \r
-       $.fn.deselectMenuItem = function() {\r
-               return this.find('span.selected').remove();\r
-       };\r
-       \r
-       $.fn.menuItemIsSelected = function() {\r
-               return (this.find('span.selected').length > 0);\r
-       };\r
-       \r
-       $.fn.deselectMenuSiblings = function() {\r
-               this.parent().find('span.selected').remove();\r
-           this.selectMenuItem();\r
-               return this; \r
-       };\r
-})(jQuery);\r
+/*
+ * This file Copyright (C) 2015 Mnemosyne LLC
+ *
+ * It may be used under the GNU GPL versions 2 or 3
+ * or any future license endorsed by Mnemosyne LLC.
+ */
+
+$.widget('tr.transMenu', $.ui.menu, {
+       options: {
+               open: null,
+               close: null
+       },
+
+       _create: function() {
+               this.selectImpl = this.options.select;
+               this.options.select = $.proxy(this._select, this);
+               this.element.hide();
+               this._superApply(arguments);
+       },
+
+       _select: function(event, ui) {
+               if (ui.item.is("[aria-haspopup='true']"))
+                       return;
+               ui.id = ui.item.attr("id");
+               ui.group = ui.item.attr("radio-group");
+               ui.target = $(event.currentTarget);
+               if (this.selectImpl(event, ui) !== false)
+                       this.close();
+       },
+
+       open: function(event) {
+               this.element.show();
+               this.element.css({ position: "absolute", left: 4, top: -this.element.height() - 4 });
+
+               $(document).bind("keydown" + this.eventNamespace, $.proxy(function(event) {
+                       if (event.which === $.ui.keyCode.ESCAPE)
+                               this.close();
+               }, this));
+               $(document).bind("mousedown" + this.eventNamespace + " touchstart" + this.eventNamespace, $.proxy(function(event) {
+                       if (!$(event.target).closest(".ui-menu-item").length)
+                               this.close();
+               }, this));
+
+               this._trigger("open", event);
+       },
+
+       close: function(event) {
+               $(document).unbind("keydown" + this.eventNamespace);
+               $(document).unbind("mousedown" + this.eventNamespace);
+               $(document).unbind("touchstart" + this.eventNamespace);
+
+               this._close(this.element);
+               this.element.hide();
+
+               this._trigger("close", event);
+       }
+});
+
+(function($)
+{
+       function indicatorClass(type)
+       {
+               return ['ui-icon', 'ui-icon-' + type];
+       }
+
+       function findIndicator(item, type)
+       {
+               return $(item).find('span.' + indicatorClass(type).join('.'));
+       }
+
+       function createIndicator(item, type)
+       {
+               $(item).prepend($("<span class='" + indicatorClass(type).join(' ') + "'></span>"));
+       }
+
+       function indicatorType(item)
+       {
+               var group = item.attr('radio-group');
+               return { type: group !== undefined ? 'bullet' : 'check', group: group };
+       }
+
+       $.fn.selectMenuItem = function() {
+               var t = indicatorType(this);
+               if (t.type == 'bullet')
+                       this.parent().find('li[radio-group=' + t.group + '] span.' + indicatorClass(t.type).join('.')).remove();
+               if (findIndicator(this, t.type).length == 0)
+                       createIndicator(this, t.type);
+               return this;
+       };
+
+       $.fn.deselectMenuItem = function() {
+               var t = indicatorType(this);
+               return findIndicator(this, t.type).remove();
+       };
+
+       $.fn.menuItemIsSelected = function() {
+               return findIndicator(this, 'bullet').length > 0 || findIndicator(this, 'check').length > 0;
+       };
+})(jQuery);
index dce01452c4fb2f21f9a854b5285cbddae063c74d..6398f91333ee07a04503beeadefd73b365a1fd53 100644 (file)
@@ -1 +1 @@
-(function(a){var b={onClick:function(){a(this).find(">a").each(function(){this.href&&(window.location=this.href)})},arrow_char:"&#x25BA;",selected_char:"&#x2713;",subDelay:300,direction:"down",mainDelay:10},c;a.fn.transMenu=function(d){var e=!1,f=2;c=a.extend({},b,d);var g=function(b,d){if(b.timer&&!b.isVisible)clearTimeout(b.timer);else if(b.timer)return;b.isVisible&&(b.timer=setTimeout(function(){a(b).find("ul li").unbind("mouseover",k).unbind("mouseout",m).unbind("click",c.onClick),a(b).hide(),b.isVisible=!1,b.timer=null},d))},h=function(b,d){b.timer&&clearTimeout(b.timer),b.isVisible||(b.timer=setTimeout(function(){if(!a(b).parent().is(".hover"))return;a(b).find("ul li").mouseover(k).mouseout(m).click(c.onClick),a(b).parent().is(".main")||a(b).css("left",a(b).parent().parent().width()-f),c.direction=="up"&&a(b).css("top",a(b).height()*-1+a(b).parent().parent().height()),b.isVisible=!0,a(b).show(),b.timer=null},d))},i=function(a){var b=(a.type=="mouseover"?a.fromElement:a.toElement)||a.relatedTarget;while(b&&b!=this)try{b=b.parentNode}catch(a){b=this}return b==this?!1:!0},j=function(b){a(this).addClass("hover").siblings("li.hover").removeClass("hover"),e&&l(this,c.mainDelay)},k=function(a){if(!i(a))return!1;if(a.target!=this&&!s(this,a.target))return;l(this,c.subDelay)},l=function(b,c){var d=b.parentNode.firstChild;for(;d;d=d.nextSibling)if(d.nodeType==1&&d.nodeName.toUpperCase()=="LI"){var e=r(d,"DIV");e&&e.timer&&!e.isVisible&&(clearTimeout(e.timer),e.timer=null)}var f=b.parentNode;for(;f;f=f.parentNode)f.nodeType==1&&f.nodeName.toUpperCase()=="DIV"&&f.timer&&(clearTimeout(f.timer),f.timer=null,a(f.parentNode).addClass("hover"));a(b).addClass("hover");var i=a(b).children("div");i=i.length?i[0]:null;if(i&&i.isVisible)if(i.timer)clearTimeout(i.timer),i.timer=null;else return;a(b.parentNode.getElementsByTagName("DIV")).each(function(){this!=i&&this.isVisible&&(g(this,c),a(this.parentNode).removeClass("hover"))}),i&&h(i,c)},m=function(b){if(!i(b))return!1;if(b.target!=this&&!s(this,b.target))return;var c=r(this,"DIV");c?c.isVisible||a(this).removeClass("hover"):a(this).removeClass("hover")},n=function(b){var c=r(this,"DIV"),d=b.relatedTarget||b.toElement,f;e?!c&&d?(f=a(b.target).parents("UL.trans_menu"),f.contains(d)&&a(this).removeClass("hover")):d&&(f=a(b.target).parents("UL.trans_menu"),!c.isVisible&&f.contains(d)&&a(this).removeClass("hover")):a(this).removeClass("hover")},o=function(){var b=r(this,"DIV");b&&b.isVisible?(q(),a(this).addClass("hover")):(l(this,c.mainDelay),e=!0,a("ul.trans_menu li").addClass("active"),a(document).bind("mousedown",p))},p=function(b){var c=!1;a(b.target).parents("UL.trans_menu").find("div").each(function(){this.isVisible&&(c=!0)}),c||q()},q=function(){a("ul.trans_menu div.outerbox").each(function(){this.timer&&(clearTimeout(this.timer),this.timer=null),this.isVisible&&(a(this).hide(),this.isVisible=!1)}),a("ul.trans_menu li").removeClass("hover"),a("ul.trans_menu>li li").unbind("mouseover",k).unbind("mouseout",m).unbind("click",c.onClick),a(document).unbind("mousedown",p),e=!1,a("ul.trans_menu li").removeClass("active")},r=function(a,b){if(!a)return null;var c=a.firstChild;for(;c;c=c.nextSibling)if(c.nodeType==1&&c.nodeName.toUpperCase()==b)return c;return null},s=function(a,b){var c=a.firstChild;for(;c;c=c.nextSibling)if(c==b)return!0;return!1};return this.each(function(){window.Node&&Node.prototype&&!Node.prototype.contains&&(Node.prototype.contains=function(a){return!!(this.compareDocumentPosition(a)&16)}),a(this).is(".trans_menu")||a(this).addClass("trans_menu"),a("ul",this).shadowBox(),a(this).bind("closemenu",function(){q()});var b=a(this).children("li");for(var d=0;d<b.length;d++)r(r(r(b[d],"DIV"),"UL"),"LI")&&a(b[d]).click(o);a(b).hover(j,n).addClass("main").find(">div").addClass("inner");if(c.arrow_char){var e=a("<span class='arrow'>"+c.arrow_char+"</span>");a.browser.mozilla&&+a.browser.version.replace(/\./g,"").slice(0,3)<191&&e.css("margin-top","-13px"),a("div.inner div.outerbox",this).before(e)}a(this).wrap('<div class="main_container"></div>').after('<div style="clear: both; visibility: hidden;"></div>')})},a.fn.transMenu.setDefaults=function(c){a.extend(b,c)},a.fn.shadowBox=function(){return this.each(function(){var b=a('<div class="outerbox"></div>').get(0);a(this).css("position")=="absolute"?a(b).css({position:"relative",width:this.offsetWidth,height:this.offsetHeight}):a(b).css("position","absolute"),a(this).addClass("innerBox").wrap(b).before('<div class="shadowbox1"></div><div class="shadowbox2"></div><div class="shadowbox3"></div>')})},a.fn.selectMenuItem=function(){return this.find("span.selected").length==0&&this.prepend(a("<span class='selected'>"+c.selected_char+"</span>")),this},a.fn.deselectMenuItem=function(){return this.find("span.selected").remove()},a.fn.menuItemIsSelected=function(){return this.find("span.selected").length>0},a.fn.deselectMenuSiblings=function(){return this.parent().find("span.selected").remove(),this.selectMenuItem(),this}})(jQuery)
\ No newline at end of file
+$.widget("tr.transMenu",$.ui.menu,{options:{open:null,close:null},_create:function(){this.selectImpl=this.options.select,this.options.select=$.proxy(this._select,this),this.element.hide(),this._superApply(arguments)},_select:function(e,t){t.item.is("[aria-haspopup='true']")||(t.id=t.item.attr("id"),t.group=t.item.attr("radio-group"),t.target=$(e.currentTarget),this.selectImpl(e,t)!==!1&&this.close())},open:function(e){this.element.show(),this.element.css({position:"absolute",left:4,top:-this.element.height()-4}),$(document).bind("keydown"+this.eventNamespace,$.proxy(function(e){e.which===$.ui.keyCode.ESCAPE&&this.close()},this)),$(document).bind("mousedown"+this.eventNamespace+" touchstart"+this.eventNamespace,$.proxy(function(e){$(e.target).closest(".ui-menu-item").length||this.close()},this)),this._trigger("open",e)},close:function(e){$(document).unbind("keydown"+this.eventNamespace),$(document).unbind("mousedown"+this.eventNamespace),$(document).unbind("touchstart"+this.eventNamespace),this._close(this.element),this.element.hide(),this._trigger("close",e)}}),function($){function e(e){return["ui-icon","ui-icon-"+e]}function t(t,n){return $(t).find("span."+e(n).join("."))}function n(t,n){$(t).prepend($("<span class='"+e(n).join(" ")+"'></span>"))}function i(e){var t=e.attr("radio-group");return{type:void 0!==t?"bullet":"check",group:t}}$.fn.selectMenuItem=function(){var s=i(this);return"bullet"==s.type&&this.parent().find("li[radio-group="+s.group+"] span."+e(s.type).join(".")).remove(),0==t(this,s.type).length&&n(this,s.type),this},$.fn.deselectMenuItem=function(){var e=i(this);return t(this,e.type).remove()},$.fn.menuItemIsSelected=function(){return t(this,"bullet").length>0||t(this,"check").length>0}}(jQuery);
\ No newline at end of file
diff --git a/web/javascript/jquery/jquery.ui-contextmenu.js b/web/javascript/jquery/jquery.ui-contextmenu.js
new file mode 100644 (file)
index 0000000..f824542
--- /dev/null
@@ -0,0 +1,469 @@
+/*******************************************************************************
+ * jquery.ui-contextmenu.js plugin.
+ *
+ * jQuery plugin that provides a context menu (based on the jQueryUI menu widget).
+ *
+ * @see https://github.com/mar10/jquery-ui-contextmenu
+ *
+ * Copyright (c) 2013-2015, Martin Wendt (http://wwWendt.de). Licensed MIT.
+ */
+
+(function( factory ) {
+       "use strict";
+       if ( typeof define === "function" && define.amd ) {
+               // AMD. Register as an anonymous module.
+               define([ "jquery", "jquery-ui/menu" ], factory );
+       } else {
+               // Browser globals
+               factory( jQuery );
+       }
+}(function( $ ) {
+
+"use strict";
+
+var supportSelectstart = "onselectstart" in document.createElement("div"),
+       match = $.ui.menu.version.match(/^(\d)\.(\d+)/),
+       uiVersion = {
+               major: parseInt(match[1], 10),
+               minor: parseInt(match[2], 10)
+       },
+       isLTE110 = ( uiVersion.major < 2 && uiVersion.minor < 11 );
+
+$.widget("moogle.contextmenu", {
+       version: "@VERSION",
+       options: {
+               addClass: "ui-contextmenu",  // Add this class to the outer <ul>
+               autoFocus: false,      // Set keyboard focus to first entry on open
+               autoTrigger: true,    // open menu on browser's `contextmenu` event
+               delegate: null,       // selector
+               hide: { effect: "fadeOut", duration: "fast" },
+               ignoreParentSelect: true, // Don't trigger 'select' for sub-menu parents
+               menu: null,           // selector or jQuery pointing to <UL>, or a definition hash
+               position: null,       // popup positon
+               preventContextMenuForPopup: false, // prevent opening the browser's system
+                                                                                  // context menu on menu entries
+               preventSelect: false, // disable text selection of target
+               show: { effect: "slideDown", duration: "fast" },
+               taphold: false,       // open menu on taphold events (requires external plugins)
+               uiMenuOptions: {},        // Additional options, used when UI Menu is created
+               // Events:
+               beforeOpen: $.noop,   // menu about to open; return `false` to prevent opening
+               blur: $.noop,         // menu option lost focus
+               close: $.noop,        // menu was closed
+               create: $.noop,       // menu was initialized
+               createMenu: $.noop,   // menu was initialized (original UI Menu)
+               focus: $.noop,        // menu option got focus
+               open: $.noop,         // menu was opened
+               select: $.noop        // menu option was selected; return `false` to prevent closing
+       },
+       /** Constructor */
+       _create: function() {
+               var cssText, eventNames, targetId,
+                       opts = this.options;
+
+               this.$headStyle = null;
+               this.$menu = null;
+               this.menuIsTemp = false;
+               this.currentTarget = null;
+               this.previousFocus = null;
+
+               if (opts.preventSelect) {
+                       // Create a global style for all potential menu targets
+                       // If the contextmenu was bound to `document`, we apply the
+                       // selector relative to the <body> tag instead
+                       targetId = ($(this.element).is(document) ? $("body")
+                               : this.element).uniqueId().attr("id");
+                       cssText = "#" + targetId + " " + opts.delegate + " { " +
+                                       "-webkit-user-select: none; " +
+                                       "-khtml-user-select: none; " +
+                                       "-moz-user-select: none; " +
+                                       "-ms-user-select: none; " +
+                                       "user-select: none; " +
+                                       "}";
+                       this.$headStyle = $("<style class='moogle-contextmenu-style' />")
+                               .prop("type", "text/css")
+                               .appendTo("head");
+
+                       try {
+                               this.$headStyle.html(cssText);
+                       } catch ( e ) {
+                               // issue #47: fix for IE 6-8
+                               this.$headStyle[0].styleSheet.cssText = cssText;
+                       }
+                       // TODO: the selectstart is not supported by FF?
+                       if (supportSelectstart) {
+                               this.element.delegate(opts.delegate, "selectstart" + this.eventNamespace,
+                                                                         function(event) {
+                                       event.preventDefault();
+                               });
+                       }
+               }
+               this._createUiMenu(opts.menu);
+
+               eventNames = "contextmenu" + this.eventNamespace;
+               if (opts.taphold) {
+                       eventNames += " taphold" + this.eventNamespace;
+               }
+               this.element.delegate(opts.delegate, eventNames, $.proxy(this._openMenu, this));
+       },
+       /** Destructor, called on $().contextmenu("destroy"). */
+       _destroy: function() {
+               this.element.undelegate(this.eventNamespace);
+
+               this._createUiMenu(null);
+
+               if (this.$headStyle) {
+                       this.$headStyle.remove();
+                       this.$headStyle = null;
+               }
+       },
+       /** (Re)Create jQuery UI Menu. */
+       _createUiMenu: function(menuDef) {
+               var ct,
+                       opts = this.options;
+
+               // Remove temporary <ul> if any
+               if (this.isOpen()) {
+                       // #58: 'replaceMenu' in beforeOpen causing select: to lose ui.target
+                       ct = this.currentTarget;
+                       // close without animation, to force async mode
+                       this._closeMenu(true);
+                       this.currentTarget = ct;
+               }
+               if (this.menuIsTemp) {
+                       this.$menu.remove(); // this will also destroy ui.menu
+               } else if (this.$menu) {
+                       this.$menu
+                               .menu("destroy")
+                               .removeClass(this.options.addClass)
+                               .hide();
+               }
+               this.$menu = null;
+               this.menuIsTemp = false;
+               // If a menu definition array was passed, create a hidden <ul>
+               // and generate the structure now
+               if ( !menuDef ) {
+                       return;
+               } else if ($.isArray(menuDef)) {
+                       this.$menu = $.moogle.contextmenu.createMenuMarkup(menuDef);
+                       this.menuIsTemp = true;
+               }else if ( typeof menuDef === "string" ) {
+                       this.$menu = $(menuDef);
+               } else {
+                       this.$menu = menuDef;
+               }
+               // Create - but hide - the jQuery UI Menu widget
+               this.$menu
+                       .hide()
+                       .addClass(opts.addClass)
+                       // Create a menu instance that delegates events to our widget
+                       .menu($.extend(true, {}, opts.uiMenuOptions, {
+                               blur: $.proxy(opts.blur, this),
+                               create: $.proxy(opts.createMenu, this),
+                               focus: $.proxy(opts.focus, this),
+                               select: $.proxy(function(event, ui) {
+                                       // User selected a menu entry
+                                       var retval,
+                                               isParent = $.moogle.contextmenu.isMenu(ui.item),
+                                               actionHandler = ui.item.data("actionHandler");
+
+                                       ui.cmd = ui.item.attr("data-command");
+                                       ui.target = $(this.currentTarget);
+                                       // ignore clicks, if they only open a sub-menu
+                                       if ( !isParent || !opts.ignoreParentSelect) {
+                                               retval = this._trigger.call(this, "select", event, ui);
+                                               if ( actionHandler ) {
+                                                       retval = actionHandler.call(this, event, ui);
+                                               }
+                                               if ( retval !== false ) {
+                                                       this._closeMenu.call(this);
+                                               }
+                                               event.preventDefault();
+                                       }
+                               }, this)
+                       }));
+       },
+       /** Open popup (called on 'contextmenu' event). */
+       _openMenu: function(event, recursive) {
+               var res, promise,
+                       opts = this.options,
+                       posOption = opts.position,
+                       self = this,
+                       manualTrigger = !!event.isTrigger,
+                       ui = { menu: this.$menu, target: $(event.target),
+                                  extraData: event.extraData, originalEvent: event,
+                                  result: null };
+
+               if ( !opts.autoTrigger && !manualTrigger ) {
+                       // ignore browser's `contextmenu` events
+                       return;
+               }
+
+               // Prevent browser from opening the system context menu
+               event.preventDefault();
+
+               this.currentTarget = event.target;
+
+               if ( !recursive ) {
+                       res = this._trigger("beforeOpen", event, ui);
+                       promise = (ui.result && $.isFunction(ui.result.promise)) ? ui.result : null;
+                       ui.result = null;
+                       if ( res === false ) {
+                               this.currentTarget = null;
+                               return false;
+                       } else if ( promise ) {
+                               // Handler returned a Deferred or Promise. Delay menu open until
+                               // the promise is resolved
+                               promise.done(function() {
+                                       self._openMenu(event, true);
+                               });
+                               this.currentTarget = null;
+                               return false;
+                       }
+                       ui.menu = this.$menu; // Might have changed in beforeOpen
+               }
+
+               // Register global event handlers that close the dropdown-menu
+               $(document).bind("keydown" + this.eventNamespace, function(event) {
+                       if ( event.which === $.ui.keyCode.ESCAPE ) {
+                               self._closeMenu();
+                       }
+               }).bind("mousedown" + this.eventNamespace + " touchstart" + this.eventNamespace,
+                               function(event) {
+                       // Close menu when clicked outside menu
+                       if ( !$(event.target).closest(".ui-menu-item").length ) {
+                               self._closeMenu();
+                       }
+               });
+
+               // required for custom positioning (issue #18 and #13).
+               if ($.isFunction(posOption)) {
+                       posOption = posOption(event, ui);
+               }
+               posOption = $.extend({
+                       my: "left top",
+                       at: "left bottom",
+                       // if called by 'open' method, event does not have pageX/Y
+                       of: (event.pageX === undefined) ? event.target : event,
+                       collision: "fit"
+               }, posOption);
+
+               // Finally display the popup
+               this.$menu
+                       .show() // required to fix positioning error
+                       .css({
+                               position: "absolute",
+                               left: 0,
+                               top: 0
+                       }).position(posOption)
+                       .hide(); // hide again, so we can apply nice effects
+
+               if ( opts.preventContextMenuForPopup ) {
+                       this.$menu.bind("contextmenu" + this.eventNamespace, function(event) {
+                               event.preventDefault();
+                       });
+               }
+               this._show(this.$menu, opts.show, function() {
+                       // Set focus to first active menu entry
+                       if ( opts.autoFocus ) {
+                               // var $first = self.$menu.children(".ui-menu-item:enabled:first");
+                               // self.$menu.menu("focus", event, $first).focus();
+                               self.$menu.focus();
+                               self.previousFocus = $(event.target);
+                       }
+                       self._trigger.call(self, "open", event, ui);
+               });
+       },
+       /** Close popup. */
+       _closeMenu: function(immediately) {
+               var self = this,
+                       hideOpts = immediately ? false : this.options.hide;
+
+               // Note: we don't want to unbind the 'contextmenu' event
+               $(document)
+                       .unbind("mousedown" + this.eventNamespace)
+                       .unbind("touchstart" + this.eventNamespace)
+                       .unbind("keydown" + this.eventNamespace);
+
+               self.currentTarget = null; // issue #44 after hide animation is too late
+               if ( this.$menu ) { // #88: widget might have been destroyed already
+                       this.$menu
+                               .unbind("contextmenu" + this.eventNamespace);
+                       this._hide(this.$menu, hideOpts, function() {
+                               if ( self.previousFocus ) {
+                                       self.previousFocus.focus();
+                                       self.previousFocus = null;
+                               }
+                               self._trigger("close");
+                       });
+               } else {
+                       self._trigger("close");
+               }
+       },
+       /** Handle $().contextmenu("option", key, value) calls. */
+       _setOption: function(key, value) {
+               switch (key) {
+               case "menu":
+                       this.replaceMenu(value);
+                       break;
+               }
+               $.Widget.prototype._setOption.apply(this, arguments);
+       },
+       /** Return ui-menu entry (<LI> tag). */
+       _getMenuEntry: function(cmd) {
+               return this.$menu.find("li[data-command=" + cmd + "]");
+       },
+       /** Close context menu. */
+       close: function() {
+               if (this.isOpen()) {
+                       this._closeMenu();
+               }
+       },
+       /** Enable or disable the menu command. */
+       enableEntry: function(cmd, flag) {
+               this._getMenuEntry(cmd).toggleClass("ui-state-disabled", (flag === false));
+       },
+       /** Return Menu element (UL). */
+       getMenu: function() {
+               return this.$menu;
+       },
+       /** Return true if menu is open. */
+       isOpen: function() {
+//            return this.$menu && this.$menu.is(":visible");
+               return !!this.$menu && !!this.currentTarget;
+       },
+       /** Open context menu on a specific target (must match options.delegate)
+        *  Optional `extraData` is passed to event handlers as `ui.extraData`.
+        */
+       open: function(target, extraData) {
+               // Fake a 'contextmenu' event
+               extraData = extraData || {};
+               var e = jQuery.Event("contextmenu", { target: target.get(0), extraData: extraData });
+               return this.element.trigger(e);
+       },
+       /** Replace the menu altogether. */
+       replaceMenu: function(data) {
+               this._createUiMenu(data);
+       },
+       /** Redefine menu entry (title or all of it). */
+       setEntry: function(cmd, entry) {
+               var $ul,
+                       $entryLi = this._getMenuEntry(cmd);
+
+               if (typeof entry === "string") {
+                       $.moogle.contextmenu.updateTitle($entryLi, entry);
+               } else {
+                       $entryLi.empty();
+                       entry.cmd = entry.cmd || cmd;
+                       $.moogle.contextmenu.createEntryMarkup(entry, $entryLi);
+                       if ($.isArray(entry.children)) {
+                               $ul = $("<ul/>").appendTo($entryLi);
+                               $.moogle.contextmenu.createMenuMarkup(entry.children, $ul);
+                       }
+                       this.getMenu().menu("refresh");
+               }
+       },
+       /** Show or hide the menu command. */
+       showEntry: function(cmd, flag) {
+               this._getMenuEntry(cmd).toggle(flag !== false);
+       }
+});
+
+/*
+ * Global functions
+ */
+$.extend($.moogle.contextmenu, {
+       /** Convert a menu description into a into a <li> content. */
+       createEntryMarkup: function(entry, $parentLi) {
+               var $a = null;
+
+               if ( !/[^\-\u2014\u2013\s]/.test( entry.title ) ) {
+                       // hyphen, em dash, en dash: separator as defined by UI Menu 1.10
+                       $parentLi.text(entry.title);
+               } else {
+                       if ( isLTE110 ) {
+                               // jQuery UI Menu 1.10 or before required an `<a>` tag
+                               $parentLi.attr("data-command", entry.cmd);
+                               $a = $("<a/>", {
+                                               html: "" + entry.title,
+                                               href: "#"
+                                       }).appendTo($parentLi);
+
+                               if ( entry.uiIcon ) {
+                                       $a.append($("<span class='ui-icon' />").addClass(entry.uiIcon));
+                               }
+
+                       } else {
+                               // jQuery UI Menu 1.11+ preferes to avoid `<a>` tags
+                               $parentLi
+                                       .attr("data-command", entry.cmd)
+                                       .html("" + entry.title);
+                               if ( $.isFunction(entry.action) ) {
+                                       $parentLi.data("actionHandler", entry.action);
+                               }
+                               if ( entry.uiIcon ) {
+                                       $parentLi
+                                               .append($("<span class='ui-icon' />")
+                                               .addClass(entry.uiIcon));
+                               }
+                       }
+                       if ( $.isFunction(entry.action) ) {
+                               $parentLi.data("actionHandler", entry.action);
+                       }
+                       if ( entry.disabled ) {
+                               $parentLi.addClass("ui-state-disabled");
+                       }
+                       if ( entry.addClass ) {
+                               $parentLi.addClass(entry.addClass);
+                       }
+                       if ( $.isPlainObject(entry.data) ) {
+                               $parentLi.data(entry.data);
+                       }
+               }
+       },
+       /** Convert a nested array of command objects into a <ul> structure. */
+       createMenuMarkup: function(options, $parentUl) {
+               var i, menu, $ul, $li;
+               if ( $parentUl == null ) {
+                       $parentUl = $("<ul class='ui-helper-hidden' />").appendTo("body");
+               }
+               for (i = 0; i < options.length; i++) {
+                       menu = options[i];
+                       $li = $("<li/>").appendTo($parentUl);
+
+                       $.moogle.contextmenu.createEntryMarkup(menu, $li);
+
+                       if ( $.isArray(menu.children) ) {
+                               $ul = $("<ul/>").appendTo($li);
+                               $.moogle.contextmenu.createMenuMarkup(menu.children, $ul);
+                       }
+               }
+               return $parentUl;
+       },
+       /** Returns true if the menu item has child menu items */
+       isMenu: function(item) {
+               if ( isLTE110 ) {
+                       return item.has(">a[aria-haspopup='true']").length > 0;
+               } else {
+                       return item.is("[aria-haspopup='true']");
+               }
+       },
+       /** Replaces the value of elem's first text node child */
+       replaceFirstTextNodeChild: function(elem, text) {
+               elem
+                       .contents()
+                       .filter(function() { return this.nodeType === 3; })
+                       .first()
+                       .replaceWith(text);
+       },
+       /** Updates the menu item's title */
+       updateTitle: function(item, title) {
+               if ( isLTE110 ) {
+                       $.moogle.contextmenu.replaceFirstTextNodeChild($("a", item), title);
+               } else {
+                       $.moogle.contextmenu.replaceFirstTextNodeChild(item, title);
+               }
+       }
+});
+
+}));
diff --git a/web/javascript/jquery/jquery.ui-contextmenu.min.js b/web/javascript/jquery/jquery.ui-contextmenu.min.js
new file mode 100644 (file)
index 0000000..2a98778
--- /dev/null
@@ -0,0 +1,4 @@
+/*! jQuery UI context menu plugin - v1.9.0 - 2015-04-20 |  https://github.com/mar10/jquery-ui-contextmenu |  Copyright (c) 2015 Martin Wendt; Licensed MIT */
+
+!function(a){"use strict";"function"==typeof define&&define.amd?define(["jquery","jquery-ui/menu"],a):a(jQuery)}(function(a){"use strict";var b="onselectstart"in document.createElement("div"),c=a.ui.menu.version.match(/^(\d)\.(\d+)/),d={major:parseInt(c[1],10),minor:parseInt(c[2],10)},e=d.major<2&&d.minor<11;a.widget("moogle.contextmenu",{version:"@VERSION",options:{addClass:"ui-contextmenu",autoFocus:!1,autoTrigger:!0,delegate:null,hide:{effect:"fadeOut",duration:"fast"},ignoreParentSelect:!0,menu:null,position:null,preventContextMenuForPopup:!1,preventSelect:!1,show:{effect:"slideDown",duration:"fast"},taphold:!1,uiMenuOptions:{},beforeOpen:a.noop,blur:a.noop,close:a.noop,create:a.noop,createMenu:a.noop,focus:a.noop,open:a.noop,select:a.noop},_create:function(){var c,d,e,f=this.options;if(this.$headStyle=null,this.$menu=null,this.menuIsTemp=!1,this.currentTarget=null,this.previousFocus=null,f.preventSelect){e=(a(this.element).is(document)?a("body"):this.element).uniqueId().attr("id"),c="#"+e+" "+f.delegate+" { -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; }",this.$headStyle=a("<style class='moogle-contextmenu-style' />").prop("type","text/css").appendTo("head");try{this.$headStyle.html(c)}catch(g){this.$headStyle[0].styleSheet.cssText=c}b&&this.element.delegate(f.delegate,"selectstart"+this.eventNamespace,function(a){a.preventDefault()})}this._createUiMenu(f.menu),d="contextmenu"+this.eventNamespace,f.taphold&&(d+=" taphold"+this.eventNamespace),this.element.delegate(f.delegate,d,a.proxy(this._openMenu,this))},_destroy:function(){this.element.undelegate(this.eventNamespace),this._createUiMenu(null),this.$headStyle&&(this.$headStyle.remove(),this.$headStyle=null)},_createUiMenu:function(b){var c,d=this.options;this.isOpen()&&(c=this.currentTarget,this._closeMenu(!0),this.currentTarget=c),this.menuIsTemp?this.$menu.remove():this.$menu&&this.$menu.menu("destroy").removeClass(this.options.addClass).hide(),this.$menu=null,this.menuIsTemp=!1,b&&(a.isArray(b)?(this.$menu=a.moogle.contextmenu.createMenuMarkup(b),this.menuIsTemp=!0):this.$menu="string"==typeof b?a(b):b,this.$menu.hide().addClass(d.addClass).menu(a.extend(!0,{},d.uiMenuOptions,{blur:a.proxy(d.blur,this),create:a.proxy(d.createMenu,this),focus:a.proxy(d.focus,this),select:a.proxy(function(b,c){var e,f=a.moogle.contextmenu.isMenu(c.item),g=c.item.data("actionHandler");c.cmd=c.item.attr("data-command"),c.target=a(this.currentTarget),f&&d.ignoreParentSelect||(e=this._trigger.call(this,"select",b,c),g&&(e=g.call(this,b,c)),e!==!1&&this._closeMenu.call(this),b.preventDefault())},this)})))},_openMenu:function(b,c){var d,e,f=this.options,g=f.position,h=this,i=!!b.isTrigger,j={menu:this.$menu,target:a(b.target),extraData:b.extraData,originalEvent:b,result:null};if(f.autoTrigger||i){if(b.preventDefault(),this.currentTarget=b.target,!c){if(d=this._trigger("beforeOpen",b,j),e=j.result&&a.isFunction(j.result.promise)?j.result:null,j.result=null,d===!1)return this.currentTarget=null,!1;if(e)return e.done(function(){h._openMenu(b,!0)}),this.currentTarget=null,!1;j.menu=this.$menu}a(document).bind("keydown"+this.eventNamespace,function(b){b.which===a.ui.keyCode.ESCAPE&&h._closeMenu()}).bind("mousedown"+this.eventNamespace+" touchstart"+this.eventNamespace,function(b){a(b.target).closest(".ui-menu-item").length||h._closeMenu()}),a.isFunction(g)&&(g=g(b,j)),g=a.extend({my:"left top",at:"left bottom",of:void 0===b.pageX?b.target:b,collision:"fit"},g),this.$menu.show().css({position:"absolute",left:0,top:0}).position(g).hide(),f.preventContextMenuForPopup&&this.$menu.bind("contextmenu"+this.eventNamespace,function(a){a.preventDefault()}),this._show(this.$menu,f.show,function(){f.autoFocus&&(h.$menu.focus(),h.previousFocus=a(b.target)),h._trigger.call(h,"open",b,j)})}},_closeMenu:function(b){var c=this,d=b?!1:this.options.hide;a(document).unbind("mousedown"+this.eventNamespace).unbind("touchstart"+this.eventNamespace).unbind("keydown"+this.eventNamespace),c.currentTarget=null,this.$menu?(this.$menu.unbind("contextmenu"+this.eventNamespace),this._hide(this.$menu,d,function(){c.previousFocus&&(c.previousFocus.focus(),c.previousFocus=null),c._trigger("close")})):c._trigger("close")},_setOption:function(b,c){switch(b){case"menu":this.replaceMenu(c)}a.Widget.prototype._setOption.apply(this,arguments)},_getMenuEntry:function(a){return this.$menu.find("li[data-command="+a+"]")},close:function(){this.isOpen()&&this._closeMenu()},enableEntry:function(a,b){this._getMenuEntry(a).toggleClass("ui-state-disabled",b===!1)},getMenu:function(){return this.$menu},isOpen:function(){return!!this.$menu&&!!this.currentTarget},open:function(a,b){b=b||{};var c=jQuery.Event("contextmenu",{target:a.get(0),extraData:b});return this.element.trigger(c)},replaceMenu:function(a){this._createUiMenu(a)},setEntry:function(b,c){var d,e=this._getMenuEntry(b);"string"==typeof c?a.moogle.contextmenu.updateTitle(e,c):(e.empty(),c.cmd=c.cmd||b,a.moogle.contextmenu.createEntryMarkup(c,e),a.isArray(c.children)&&(d=a("<ul/>").appendTo(e),a.moogle.contextmenu.createMenuMarkup(c.children,d)),this.getMenu().menu("refresh"))},showEntry:function(a,b){this._getMenuEntry(a).toggle(b!==!1)}}),a.extend(a.moogle.contextmenu,{createEntryMarkup:function(b,c){var d=null;/[^\-\u2014\u2013\s]/.test(b.title)?(e?(c.attr("data-command",b.cmd),d=a("<a/>",{html:""+b.title,href:"#"}).appendTo(c),b.uiIcon&&d.append(a("<span class='ui-icon' />").addClass(b.uiIcon))):(c.attr("data-command",b.cmd).html(""+b.title),a.isFunction(b.action)&&c.data("actionHandler",b.action),b.uiIcon&&c.append(a("<span class='ui-icon' />").addClass(b.uiIcon))),a.isFunction(b.action)&&c.data("actionHandler",b.action),b.disabled&&c.addClass("ui-state-disabled"),b.addClass&&c.addClass(b.addClass),a.isPlainObject(b.data)&&c.data(b.data)):c.text(b.title)},createMenuMarkup:function(b,c){var d,e,f,g;for(null==c&&(c=a("<ul class='ui-helper-hidden' />").appendTo("body")),d=0;d<b.length;d++)e=b[d],g=a("<li/>").appendTo(c),a.moogle.contextmenu.createEntryMarkup(e,g),a.isArray(e.children)&&(f=a("<ul/>").appendTo(g),a.moogle.contextmenu.createMenuMarkup(e.children,f));return c},isMenu:function(a){return e?a.has(">a[aria-haspopup='true']").length>0:a.is("[aria-haspopup='true']")},replaceFirstTextNodeChild:function(a,b){a.contents().filter(function(){return 3===this.nodeType}).first().replaceWith(b)},updateTitle:function(b,c){e?a.moogle.contextmenu.replaceFirstTextNodeChild(a("a",b),c):a.moogle.contextmenu.replaceFirstTextNodeChild(b,c)}})});
+//# sourceMappingURL=jquery.ui-contextmenu.min.js.map
\ No newline at end of file
index 6c7c4c66753d4376bb15cbfcdd6a85c56fcc19e3..e7552ffb044d88f6e5c2a6e2fa3ace034a3e7b94 100644 (file)
@@ -180,52 +180,58 @@ Transmission.prototype =
        createContextMenu: function() {
                var tr = this;
                var bindings = {
-                       context_pause_selected:       function() { tr.stopSelectedTorrents(); },
-                       context_resume_selected:      function() { tr.startSelectedTorrents(false); },
-                       context_resume_now_selected:  function() { tr.startSelectedTorrents(true); },
-                       context_move:                 function() { tr.moveSelectedTorrents(false); },
-                       context_remove:               function() { tr.removeSelectedTorrents(); },
-                       context_removedata:           function() { tr.removeSelectedTorrentsAndData(); },
-                       context_verify:               function() { tr.verifySelectedTorrents(); },
-                       context_rename:               function() { tr.renameSelectedTorrents(); },
-                       context_reannounce:           function() { tr.reannounceSelectedTorrents(); },
-                       context_move_top:             function() { tr.moveTop(); },
-                       context_move_up:              function() { tr.moveUp(); },
-                       context_move_down:            function() { tr.moveDown(); },
-                       context_move_bottom:          function() { tr.moveBottom(); },
-                       context_select_all:           function() { tr.selectAll(); },
-                       context_deselect_all:         function() { tr.deselectAll(); }
+                       pause_selected:       function() { tr.stopSelectedTorrents(); },
+                       resume_selected:      function() { tr.startSelectedTorrents(false); },
+                       resume_now_selected:  function() { tr.startSelectedTorrents(true); },
+                       move:                 function() { tr.moveSelectedTorrents(false); },
+                       remove:               function() { tr.removeSelectedTorrents(); },
+                       remove_data:          function() { tr.removeSelectedTorrentsAndData(); },
+                       verify:               function() { tr.verifySelectedTorrents(); },
+                       rename:               function() { tr.renameSelectedTorrents(); },
+                       reannounce:           function() { tr.reannounceSelectedTorrents(); },
+                       move_top:             function() { tr.moveTop(); },
+                       move_up:              function() { tr.moveUp(); },
+                       move_down:            function() { tr.moveDown(); },
+                       move_bottom:          function() { tr.moveBottom(); },
+                       select_all:           function() { tr.selectAll(); },
+                       deselect_all:         function() { tr.deselectAll(); }
                };
 
                // Set up the context menu
-               $('ul#torrent_list').contextMenu('torrent_context_menu', {
-                       bindings:          bindings,
-                       menuStyle:         { width: '310px', backgroundColor: '#fff', border: 'none', padding: '5px 0', textAlign: 'left' },
-                       itemStyle:         { backgroundColor: 'transparent', margin: '0', padding: '3px 10px 3px 20px', color: '#000', cursor: 'default', border: 'none'},
-                       itemHoverStyle:    { backgroundColor: '#24e', color: '#fff', border: 'none'},
-                       shadow:            false,
-                       boundingElement:   $('div#torrent_container'),
-                       boundingRightPad:  20,
-                       boundingBottomPad: 5,
-                       onContextMenu: function(ev) {
-                               var element = $(ev.target).closest('.torrent')[0];
+               $("ul#torrent_list").contextmenu({
+                       delegate: ".torrent",
+                       menu: "#torrent_context_menu",
+                       preventSelect: true,
+                       taphold: true,
+                       show: { effect: "none" },
+                       hide: { effect: "none" },
+                       select: function(event, ui) { bindings[ui.cmd](); },
+                       beforeOpen: $.proxy(function(event, ui) {
+                               var element = $(event.currentTarget);
                                var i = $('#torrent_list > li').index(element);
-                               if ((i!==-1) && !tr._rows[i].isSelected())
-                                       tr.setSelectedRow(tr._rows[i]);
-                               return true;
-                       }
+                               if ((i!==-1) && !this._rows[i].isSelected())
+                                       this.setSelectedRow(this._rows[i]);
+
+                               this.calculateTorrentStates(function(s) {
+                                       var tl = $(event.target);
+                                       tl.contextmenu("enableEntry", "pause_selected", s.activeSel > 0);
+                                       tl.contextmenu("enableEntry", "resume_selected", s.pausedSel > 0);
+                                       tl.contextmenu("enableEntry", "resume_now_selected", s.pausedSel > 0);
+                                       tl.contextmenu("enableEntry", "rename", s.sel == 1);
+                               });
+                       }, this)
                });
        },
 
        createSettingsMenu: function() {
-               $('#settings_menu').transMenu({
-                       selected_char: '&#x2714;',
-                       direction: 'up',
-                       onClick: $.proxy(this.onMenuClicked,this)
+               $("#footer_super_menu").transMenu({
+                       open: function() { $("#settings_menu").addClass("selected"); },
+                       close: function() { $("#settings_menu").removeClass("selected"); },
+                       select: $.proxy(this.onMenuClicked, this)
+               });
+               $("#settings_menu").click(function(event) {
+                       $("#footer_super_menu").transMenu("open");
                });
-
-               $('#unlimited_download_rate').selectMenuItem();
-               $('#unlimited_upload_rate').selectMenuItem();
        },
 
        /****
@@ -650,32 +656,29 @@ Transmission.prototype =
                this.refilter(true);
        },
 
-       onMenuClicked: function(ev)
+       onMenuClicked: function(event, ui)
        {
                var o, dir,
-                   id = ev.target.id,
+                   id = ui.id,
                    remote = this.remote,
-                   element = $(ev.target);
+                   element = ui.target;
 
-               if (element.hasClass('sort-mode'))
+               if (ui.group == 'sort-mode')
                {
-                       element.parent().find('.sort-mode').each(function() {
-                               element.parent().deselectMenuItem();
-                       });
                        element.selectMenuItem();
                        this.setSortMethod(id.replace(/sort_by_/, ''));
                }
                else if (element.hasClass('upload-speed'))
                {
                        o = {};
-                       o[RPC._UpSpeedLimit] = parseInt(ev.target.innerHTML);
+                       o[RPC._UpSpeedLimit] = parseInt(element.text());
                        o[RPC._UpSpeedLimited] = true;
                        remote.savePrefs(o);
                }
                else if (element.hasClass('download-speed'))
                {
                        o = {};
-                       o[RPC._DownSpeedLimit] = parseInt(ev.target.innerHTML);
+                       o[RPC._DownSpeedLimit] = parseInt(element.text());
                        o[RPC._DownSpeedLimited] = true;
                        remote.savePrefs(o);
                }
@@ -747,8 +750,6 @@ Transmission.prototype =
                                break;
 
                }
-               $('#settings_menu').trigger('closemenu');
-               ev.stopImmediatePropagation();
        },
 
 
@@ -859,8 +860,6 @@ Transmission.prototype =
                // Prevents click carrying to parent element
                // which deselects all on click
                ev.stopPropagation();
-               // but still hide the context menu if it is showing
-               $('#jqContextMenu').hide();
 
                if (isMobileDevice) {
                        if (row.isSelected())
@@ -1201,7 +1200,7 @@ Transmission.prototype =
        {
                var limit, limited, e, b, text,
                     fmt = Transmission.fmt,
-                    menu = $('#settings_menu');
+                    menu = $('#footer_super_menu');
 
                this.serverVersion = o.version;
 
@@ -1232,7 +1231,7 @@ Transmission.prototype =
 
                         if (!limited)
                                e = menu.find('#unlimited_download_rate');
-                        e.deselectMenuSiblings().selectMenuItem();
+                       e.selectMenuItem();
                }
 
                if (this.isMenuEnabled && (RPC._UpSpeedLimited in o)
@@ -1246,7 +1245,7 @@ Transmission.prototype =
 
                         if (!limited)
                                e = menu.find('#unlimited_upload_rate');
-                        e.deselectMenuSiblings().selectMenuItem();
+                       e.selectMenuItem();
                }
        },
 
@@ -1318,14 +1317,16 @@ Transmission.prototype =
                }
        },
 
-       updateButtonStates: function()
+       calculateTorrentStates: function(callback)
        {
-               var e = this.elements,
-                   haveActive = false,
-                   havePaused = false,
-                   haveSel = false,
-                   haveActiveSel = false,
-                   havePausedSel = false;
+               var stats = {
+                       total: 0,
+                       active: 0,
+                       paused: 0,
+                       sel: 0,
+                       activeSel: 0,
+                       pausedSel: 0
+               };
 
                clearTimeout(this.buttonRefreshTimer);
                delete this.buttonRefreshTimer;
@@ -1333,16 +1334,26 @@ Transmission.prototype =
                for (var i=0, row; row=this._rows[i]; ++i) {
                        var isStopped = row.getTorrent().isStopped();
                        var isSelected = row.isSelected();
-                       if (!isStopped) haveActive = true;
-                       if (isStopped) havePaused = true;
-                       if (isSelected) haveSel = true;
-                       if (isSelected && !isStopped) haveActiveSel = true;
-                       if (isSelected && isStopped) havePausedSel = true;
+                       ++stats.total;
+                       if (!isStopped) ++stats.active;
+                       if (isStopped) ++stats.paused;
+                       if (isSelected) ++stats.sel;
+                       if (isSelected && !isStopped) ++stats.activeSel;
+                       if (isSelected && isStopped) ++stats.pausedSel;
                }
 
-               this.setEnabled(e.toolbar_pause_button,  haveActiveSel);
-               this.setEnabled(e.toolbar_start_button,  havePausedSel);
-               this.setEnabled(e.toolbar_remove_button, haveSel);
+               callback(stats);
+       },
+
+       updateButtonStates: function()
+       {
+               var tr = this,
+               e = this.elements;
+               this.calculateTorrentStates(function(s) {
+                       tr.setEnabled(e.toolbar_pause_button, s.activeSel > 0);
+                       tr.setEnabled(e.toolbar_start_button, s.pausedSel > 0);
+                       tr.setEnabled(e.toolbar_remove_button, s.sel > 0);
+               });
        },
 
        /****
index 96dc53a5790f66765adf83fbdb7843529c81a4be..1f6d8d82d70de4acf3b343d3f1ccd164740f7db1 100644 (file)
@@ -794,7 +794,7 @@ div.torrent_footer {
   background-image: -ms-linear-gradient(top, #dddddd, #bbbbbb);
   background-image: -o-linear-gradient(top, #dddddd, #bbbbbb);
   background-image: linear-gradient(top, #dddddd, #bbbbbb); }
-  div.torrent_footer > * {
+  div.torrent_footer > div {
     float: left;
     margin: 2px 4px;
     width: 18px;
@@ -804,7 +804,7 @@ div.torrent_footer {
     border: 1px solid #888;
     -moz-user-select: none;
     -webkit-user-select: none; }
-  div.torrent_footer div.main_container {
+  div.torrent_footer #settings_menu {
     -moz-border-radius: 5px;
     border-radius: 5px;
     background-color: #dddddd;
@@ -822,7 +822,7 @@ div.torrent_footer {
     /* Opera 11.10+ */
     background-position: center;
     background-repeat: no-repeat; }
-    div.torrent_footer div.main_container:active, div.torrent_footer div.main_container.selected {
+    div.torrent_footer #settings_menu:active, div.torrent_footer #settings_menu.selected {
       background-color: #e6e6ff;
       background-image: url("images/settings.png");
       /* fallback */
@@ -1079,94 +1079,11 @@ iframe#torrent_upload_frame {
 *****  POPUP MENU
 *****
 ****/
-.trans_menu {
-  margin: 0;
-  padding: 0; }
-
-.trans_menu,
-.trans_menu ul {
-  list-style: none; }
-
-.trans_menu ul {
-  /* place it right above the button */
-  position: relative;
-  bottom: 18px;
-  min-width: 210px;
-  background-color: white;
-  padding: 5px 0;
+.ui-menu-item {
   text-align: left;
-  list-style: none;
-  -webkit-border-radius: 5px;
-  -webkit-box-shadow: 0 10px 25px rgba(0, 0, 0, 0.4); }
-
-.trans_menu ul ul {
-  min-width: 150px; }
-
-.trans_menu ul ul#footer_sort_menu {
-  min-width: 175px; }
-
-.trans_menu > * li {
-  margin: 0;
-  padding: 3px 10px 3px 20px !important;
-  color: #000;
-  cursor: default;
-  text-indent: auto !important;
-  width: inherit; }
-
-.trans_menu li.separator,
-.trans_menu li.separator.hover {
-  border-top: 1px solid #ddd;
-  margin: 5px 0;
-  padding: 0px;
-  background: transparent; }
-
-.trans_menu li span.arrow {
-  float: right; }
-
-.trans_menu li.hover li.hover span.arrow, .trans_menu li.hover li.hover li.hover span.selected {
-  color: white; }
-
-.trans_menu span.selected {
-  margin: 0 3px 0 -15px;
-  color: #666;
-  float: left; }
+  white-space: nowrap; }
 
-.trans_menu div.outerbox {
-  display: none;
-  background: transparent;
-  border: 1px solid rgba(0, 0, 0, 0.1);
-  -webkit-border-radius: 5px; }
-
-.trans_menu div.inner {
-  left: 0;
-  margin: 0; }
-
-.trans_menu li.main li {
-  z-index: 2;
-  min-width: 78px; }
-
-.trans_menu a {
-  text-decoration: none;
-  cursor: default; }
-
-/*--------------------------------------
- *
- * C O N T E X T   M E N U
- *
- *--------------------------------------*/
-div#jqContextMenu {
-  -webkit-border-radius: 5px;
-  border: 1px solid rgba(0, 0, 0, 0.1);
-  -moz-user-select: none;
-  -webkit-user-select: none; }
-  div#jqContextMenu ul {
-    filter: alpha(opacity=98);
-    -moz-opacity: .98;
-    opacity: .98;
-    -webkit-box-shadow: 0 10px 25px rgba(0, 0, 0, 0.4);
-    -webkit-border-radius: 5px; }
-  div#jqContextMenu li.separator, div#jqContextMenu div#jqContextMenu li.separator:hover {
-    background: inherit !important;
-    border-top: 1px solid #ddd !important;
-    margin: 5px 0 !important;
-    padding: 0px; }
+#torrent_context_menu,
+#footer_super_menu {
+  font-size: 1em;
+  z-index: 3; }
index efc4b12c4d50681607e6c56d066974a3ce205849..11094b1f1905e26aa35fb095ca8f8c1dfb05a960 100644 (file)
@@ -766,7 +766,7 @@ div.torrent_footer
 
        @include verticalGradient($statusbar-gradient-top, $statusbar-gradient-bottom);
 
-       > * {
+       > div {
                float: left;
                margin: 2px 4px;
                width: 18px;
@@ -783,7 +783,7 @@ div.torrent_footer
        $active-color-top: $selected-gradient-top;
        $active-color-bottom: $selected-gradient-bottom;
 
-       div.main_container {
+       #settings_menu {
                @include roundedBox(5px);
                @include buttonImage('images/settings.png', $idle-color-top, $idle-color-bottom, $active-color-top, $active-color-bottom);
        }
@@ -955,116 +955,13 @@ iframe#torrent_upload_frame {
 *****
 ****/
 
-.trans_menu {
-       margin: 0;
-       padding: 0;
-}
-
-.trans_menu,
-.trans_menu ul {
-       list-style: none;
-}
-
-.trans_menu ul {
-       /* place it right above the button */
-       position: relative;
-       bottom: 18px;
-
-       min-width: 210px;
-       background-color: white;
-       padding: 5px 0;
+.ui-menu-item {
        text-align: left;
-       list-style: none;
-       -webkit-border-radius: 5px;
-       -webkit-box-shadow: 0 10px 25px rgba(0,0,0,0.4);
-}
-
-.trans_menu ul ul {
-       min-width: 150px;
-}
-
-.trans_menu ul ul#footer_sort_menu {
-       min-width: 175px;
-}
-
-.trans_menu > * li {
-       margin: 0;
-       padding: 3px 10px 3px 20px !important;
-       color: #000;
-       cursor: default;
-       text-indent: auto !important;
-       width: inherit;
-}
-
-.trans_menu li.separator,
-.trans_menu li.separator.hover {
-       border-top: 1px solid #ddd;
-       margin: 5px 0;
-       padding: 0px;
-       background: transparent;
-}
-
-.trans_menu li span.arrow {
-       float: right;
-}
-
-.trans_menu li.hover li.hover span.arrow, .trans_menu li.hover li.hover li.hover span.selected {
-       color: white;
-}
-
-.trans_menu span.selected {
-       margin: 0 3px 0 -15px;
-       color: #666;
-       float: left;
-}
-
-.trans_menu div.outerbox {
-       display: none;
-       background: transparent;
-       border: 1px solid rgba(0,0,0,0.1);
-       -webkit-border-radius: 5px;
-}
-
-.trans_menu div.inner {
-       left: 0;
-       margin: 0;
-}
-
-.trans_menu li.main li {
-       z-index: 2;
-       min-width: 78px;
-}
-
-.trans_menu a {
-       text-decoration: none;
-       cursor: default;
+       white-space: nowrap;
 }
 
-/*--------------------------------------
- *
- * C O N T E X T   M E N U
- *
- *--------------------------------------*/
-
-div#jqContextMenu
-{
-       -webkit-border-radius: 5px;
-       border: 1px solid rgba(0,0,0,0.1);
-       -moz-user-select: none;
-       -webkit-user-select: none;
-
-       ul {
-               filter: alpha(opacity=98);
-               -moz-opacity: .98;
-               opacity: .98;
-               -webkit-box-shadow: 0 10px 25px rgba(0,0,0,0.4);
-               -webkit-border-radius: 5px;
-       }
-
-       li.separator, div#jqContextMenu li.separator:hover {
-               background: inherit !important;
-               border-top: 1px solid #ddd !important;
-               margin: 5px 0 !important;
-               padding: 0px;
-       }
+#torrent_context_menu,
+#footer_super_menu {
+       font-size: 1em;
+       z-index: 3;
 }
index 0267e3cbd99f8d5f4682a3b9b19b88b492a8e620..9fe95f2ae42524703c7b7bb83d47e86d9a709008 100644 (file)
@@ -744,7 +744,7 @@ div.torrent_footer {
   background-image: -ms-linear-gradient(top, #dddddd, #bbbbbb);
   background-image: -o-linear-gradient(top, #dddddd, #bbbbbb);
   background-image: linear-gradient(top, #dddddd, #bbbbbb); }
-  div.torrent_footer > * {
+  div.torrent_footer > div {
     position: relative;
     float: left;
     margin: 2px 4px;
@@ -755,8 +755,7 @@ div.torrent_footer {
     border: 1px solid #888;
     -moz-user-select: none;
     -webkit-user-select: none; }
-  div.torrent_footer div.main_container,
-  div.torrent_footer ul#settings_menu {
+  div.torrent_footer #settings_menu {
     display: none; }
   div.torrent_footer #prefs-button {
     -moz-border-radius: 5px;
@@ -933,8 +932,13 @@ div.dialog_container a {
   margin: 10px 0 20px 150px;
   text-align: left; }
 
-div#torrent_context_menu {
-  display: none; }
+.ui-menu-item {
+  text-align: left;
+  white-space: nowrap; }
+
+#torrent_context_menu {
+  font-size: 1em;
+  z-index: 3; }
 
 iframe#torrent_upload_frame {
   display: block;
index 690c4cf3bf0d8730c1189c45bf9194cb8664b48c..a7e56e31ea606382e63fc631e4ce9e0e53425087 100644 (file)
@@ -694,7 +694,7 @@ div.torrent_footer
 
        @include verticalGradient($statusbar-gradient-top, $statusbar-gradient-bottom);
 
-       > * {
+       > div {
                position: relative;
                float: left;
                margin: 2px 4px;
@@ -712,8 +712,7 @@ div.torrent_footer
        $active-color-top: $selected-gradient-top;
        $active-color-bottom: $selected-gradient-bottom;
 
-       div.main_container,
-       ul#settings_menu {
+       #settings_menu {
                display: none;
        }
 
@@ -808,9 +807,14 @@ div.dialog_container a {
 }
 
 
-// no context menu in the mobile version...
-div#torrent_context_menu {
-       display: none;
+.ui-menu-item {
+  text-align: left;
+  white-space: nowrap;
+}
+
+#torrent_context_menu {
+  font-size: 1em;
+  z-index: 3;
 }
 
 iframe#torrent_upload_frame {