Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

jquery.projectPlugins.js 27KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972
  1. /**
  2. * @fileOverview Misc jQuery plugins maintained by the phpVirtualBox project for
  3. * the phpVirtualBox project. These are either solely authored by
  4. * the project or so heavily modified that they can no longer be
  5. * separately maintained
  6. * @author Ian Moore (imoore76 at yahoo dot com)
  7. * @version $Id: jquery.projectPlugins.js 595 2015-04-17 09:50:36Z imoore76 $
  8. * @copyright Copyright (C) 2010-2015 Ian Moore (imoore76 at yahoo dot com)
  9. *
  10. */
  11. /**
  12. * Override _title method of dialog to accept HTML
  13. *
  14. * http://stackoverflow.com/questions/14488774/using-html-in-a-dialogs-title-in-jquery-ui-1-10
  15. */
  16. $.widget("ui.dialog", $.extend({}, $.ui.dialog.prototype, {
  17. _title: function(title) {
  18. title.html(this.options.title ? this.options.title : " ");
  19. }
  20. }));
  21. /**
  22. * Adds deprecated enable/disableSelection to jquery.
  23. *
  24. * Taken from jQuery source.
  25. *
  26. */
  27. $.support.selectstart = "onselectstart" in document.createElement( "div" );
  28. $.fn.extend({
  29. disableSelection: function() {
  30. return this.on( ( $.support.selectstart ? "selectstart" : "mousedown" ) +
  31. ".ui-disableSelection", function( event ) {
  32. event.preventDefault();
  33. });
  34. },
  35. enableSelection: function() {
  36. return this.off( ".ui-disableSelection" );
  37. }
  38. });
  39. /**
  40. *
  41. * Add hover and hoverClass functionality to jquery
  42. *
  43. */
  44. (function($) {
  45. /* Mimic jquery hover function deprecated in jquery 1.9 */
  46. $.fn.hover = function(onenter, onleave) {
  47. this.each(function() {
  48. $(this).on("mouseenter", onenter).on("mouseleave", onleave);
  49. });
  50. return $(this);
  51. }
  52. /* Add / remove class onmouseenter/leave */
  53. $.fn.hoverClass = function(hclass) {
  54. this.each(function() {
  55. $(this).on("mouseenter",function(){
  56. $(this).addClass(hclass);
  57. }).on("mouseleave", function(){
  58. $(this).removeClass(hclass);
  59. });
  60. });
  61. return $(this);
  62. }
  63. })(jQuery);
  64. /**
  65. * Restore jQuery.browser functionality. Taken from:
  66. *
  67. * https://github.com/jquery/jquery-migrate/blob/master/src/core.js
  68. *
  69. */
  70. jQuery.uaMatch = function( ua ) {
  71. ua = ua.toLowerCase();
  72. var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
  73. /(webkit)[ \/]([\w.]+)/.exec( ua ) ||
  74. /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
  75. /(msie) ([\w.]+)/.exec( ua ) ||
  76. ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
  77. [];
  78. return {
  79. browser: match[ 1 ] || "",
  80. version: match[ 2 ] || "0"
  81. };
  82. };
  83. // Don't clobber any existing jQuery.browser in case it's different
  84. if ( !jQuery.browser ) {
  85. matched = jQuery.uaMatch( navigator.userAgent );
  86. browser = {};
  87. if ( matched.browser ) {
  88. browser[ matched.browser ] = true;
  89. browser.version = matched.version;
  90. }
  91. // Chrome is Webkit, but Webkit is also Safari.
  92. if ( browser.chrome ) {
  93. browser.webkit = true;
  94. } else if ( browser.webkit ) {
  95. browser.safari = true;
  96. }
  97. jQuery.browser = browser;
  98. }
  99. /**
  100. * Modified version of http://archive.plugins.jquery.com/project/TextFill
  101. */
  102. ;(function($) {
  103. $.fn.textFill = function(options) {
  104. var maxFontSize = options.maxFontPixels;
  105. var maxHeight = parseInt(options.height);
  106. var maxWidth = parseInt(options.width);
  107. var ourText = $(this);
  108. var fontSize = parseInt(ourText.css('font-size'));
  109. var fontSizeOrig = fontSize;
  110. var textHeight = $(ourText).outerHeight(true);
  111. var textWidth = $(ourText).outerWidth(true);
  112. do {
  113. ourText.css('font-size', fontSize++);
  114. textHeight = $(ourText).outerHeight(true);
  115. textWidth = $(ourText).outerWidth(true);
  116. } while(textHeight <= maxHeight && textWidth <= maxWidth && fontSize <= maxFontSize);
  117. fontSize--;
  118. return ourText.css({'font-size':(fontSize)+'px','top':(fontSize > fontSizeOrig ? '-1' : '0') + 'px'});
  119. };
  120. })(jQuery);
  121. /**
  122. *
  123. * phpVirtualBox tree view for snapshots
  124. *
  125. */
  126. (function($) {
  127. $.fn.vbtree = function(options, toplevel) {
  128. if(!toplevel)
  129. var toplevel = this;
  130. this.each(function() {
  131. $(this).addClass('vboxTreeView').children('li').each(function(i,li){
  132. // Change class
  133. /////////////////////
  134. var children = $(li).children('ul').length;
  135. var last = !$(this).next().is('li');
  136. var classadd = null;
  137. // Children and last
  138. if(children && !last) {
  139. classadd = 'collapsable';
  140. // Children but no last
  141. } else if(children && last) {
  142. classadd = 'lastCollapsable';
  143. } else if(!children && last) {
  144. classadd = 'last';
  145. }
  146. $(li).addClass(classadd);
  147. // Insert hitarea
  148. var d = document.createElement('div');
  149. $(d).addClass('hitarea').addClass((classadd ? classadd + '-hitarea' : '')).click(function(){
  150. if(!$(this).data('toggleClicked')) {
  151. $(this).data('toggleClicked', true);
  152. if($(this).hasClass('last-hitarea')) return;
  153. if($(this).hasClass('lastCollapsable-hitarea'))
  154. $(this).addClass('lastExpandable-hitarea').removeClass('lastCollapsable-hitarea').parent().parent().children('ul').css({'display':'none'});
  155. else
  156. $(this).addClass('expandable-hitarea').removeClass('collapsable-hitarea').parent().parent().children('ul').css({'display':'none'});
  157. } else {
  158. $(this).data('toggleClicked', false);
  159. if($(this).hasClass('last-hitarea')) return;
  160. if($(this).hasClass('lastExpandable-hitarea'))
  161. $(this).addClass('lastCollapsable-hitarea').removeClass('lastExpandable-hitarea').parent().parent().children('ul').css({'display':''});
  162. else
  163. $(this).addClass('collapsable-hitarea').removeClass('expandable-hitarea').parent().parent().children('ul').css({'display':''});
  164. }
  165. return false;
  166. });
  167. $(li).children('div').first().prepend(d);
  168. // Tree each UL under li one
  169. $(li).children('ul').vbtree({},toplevel);
  170. });
  171. });
  172. return this;
  173. };
  174. })(jQuery);
  175. /**
  176. *
  177. * phpVirtualBox medium (disk / CD image etc.) select box
  178. *
  179. * Copyright (C) 2010-2015 Ian Moore (imoore76 at yahoo dot com)
  180. *
  181. */
  182. (function($) {
  183. $.fn.mediumselect = function(options) {
  184. /* Public access to select medium */
  185. if(options.selectMedium) {
  186. $('#'+$(this).attr('id')+'-mediumselect-'+options.selectMedium).click();
  187. return;
  188. }
  189. /* Defaults */
  190. if(!options.type) options.type = 'HardDisk';
  191. if(!options.media) options.media = [];
  192. /* Internal Select Medium */
  193. function _selectmedium(d,sel) {
  194. if($(d).hasClass('vboxMediumReadOnly')) {
  195. $(sel).addClass('vboxMediumSelectReadOnly').addClass('vboxMediumReadOnly');
  196. } else {
  197. $(sel).removeClass('vboxMediumSelectReadOnly').removeClass('vboxMediumReadOnly');
  198. }
  199. // Set text
  200. $(sel).html(($(d).data('label') ? $(d).data('label') : ''));
  201. // Hide list
  202. $('#'+$(sel).attr('id')+'-list').hide();
  203. // Set hidden select box value and
  204. // trigger change
  205. var old = $('#'+$(sel).data('origId'));
  206. $(old).val($(d).data('id'));
  207. $(old).trigger('change',old);
  208. }
  209. /* Generate and return list item */
  210. function listItem(m,sel,old,children) {
  211. var li = document.createElement('li');
  212. var d = document.createElement('div');
  213. d.setAttribute('id',$(sel).attr('id')+'-'+m.attachedId);
  214. var opt = $(old).children('option[value='+m.attachedId+']');
  215. if($(opt).hasClass('vboxMediumReadOnly')) {
  216. $(d).addClass('vboxMediumReadOnly');
  217. $(li).addClass('vboxMediumReadOnly');
  218. }
  219. if($(opt).attr('title')) {
  220. $(d).attr('title',$(opt).attr('title'));
  221. $(d).tipped({'source':'title'});
  222. }
  223. $(d).addClass('vboxMediumSelectDiv').on("mouseenter",function(){$(this).addClass('vboxMediumSelectHover');}).on("mouseleave",function(){$(this).removeClass('vboxMediumSelectHover');});
  224. $(d).html(m.label);
  225. $(d).data('label',m.label);
  226. $(d).data('id',m.attachedId);
  227. $(d).click(function(){_selectmedium(this,sel);});
  228. $(li).append(d);
  229. // Traverse children
  230. if(children && m.children && m.children.length) {
  231. var ul = document.createElement('ul');
  232. for(var c = 0; c < m.children.length; c++) {
  233. $(ul).append(listItem(m.children[c],sel,old,true));
  234. }
  235. $(li).append(ul);
  236. }
  237. return li;
  238. }
  239. /* Show list */
  240. function showList(sel) {
  241. var list = $('#'+$(sel).attr('id')+'-list');
  242. var sTop = $(sel).offset().top + $(sel).outerHeight();
  243. var sLeft = $(sel).offset().left;
  244. var sWidth = $(sel).outerWidth() + $(sel).closest('table').find('.vboxMediumSelectImg').outerWidth();
  245. // Hide menu when clicking anywhere else
  246. $(document).one('click',function(){$(list).hide();});
  247. $(list).css({'left':sLeft+'px','top':sTop+'px','min-width':sWidth}).show();
  248. return false;
  249. }
  250. /*
  251. * Main
  252. */
  253. this.each(function() {
  254. // Generate select box replacement
  255. if(!$('#'+$(this).attr('id')+'-mediumselect').attr('id')) {
  256. var sel = document.createElement('div');
  257. $(sel).data('origId', $(this).attr('id'));
  258. $(sel).attr('id',$(this).attr('id')+'-mediumselect');
  259. $(sel).attr('class','vboxMediumSelect');
  260. $(sel).on('click',function(){
  261. if($('#'+$(this).data('origId')+'-table').hasClass('vboxDisabled')) return;
  262. return showList(this);
  263. });
  264. $(this).hide();
  265. var img = document.createElement('div');
  266. img.setAttribute('id',$(this).attr('id')+'-mediumselectimg');
  267. img.setAttribute('class','vboxMediumSelectImg');
  268. $(img).click(function(e){
  269. $(e.target).closest('table').find('div.vboxMediumSelect').trigger('click');
  270. return false;
  271. });
  272. var tbl = document.createElement('table');
  273. $(tbl).attr('id',$(this).attr('id')+'-table');
  274. $(tbl).attr('class','vboxMediumSelect');
  275. $(tbl).css({'padding':'0px','margin':'0px','border':'0px','width':'100%','border-spacing':'0px'});
  276. var tr = document.createElement('tr');
  277. var td = document.createElement('td');
  278. $(td).attr({'class':'vboxMediumSelectTableLeft'}).css({'padding':'0px','margin':'0px','width':'100%'});
  279. $(td).append(sel);
  280. $(tr).append(td);
  281. var td = document.createElement('td');
  282. $(td).attr({'class':'vboxMediumSelectTableRight'}).css({'padding':'0px','margin':'0px','width':'auto'});
  283. $(td).append(img);
  284. $(tr).append(td);
  285. $(tbl).append(tr);
  286. // Handle enabled / disabled
  287. $(tbl).on('enable',function(){
  288. $(this).removeClass('vboxDisabled');
  289. }).on('disable',function(){
  290. $(this).addClass('vboxDisabled');
  291. });
  292. $(this).before(tbl);
  293. var list = document.createElement('ul');
  294. $(list).attr('id',$(this).attr('id')+'-mediumselect-list');
  295. $(list).attr('class', 'vboxMediumSelect');
  296. $(list).css({'display':'none'});
  297. $('#vboxPane').append(list);
  298. }
  299. // Hide list if it exists
  300. $('#'+$(this).attr('id')+'-mediumselect-list').hide();
  301. $('#'+$(this).attr('id')+'-mediumselectimg').css({'background-image':'url(images/downArrow.png)'});
  302. // Compile list
  303. var list = $('#'+$(this).attr('id')+'-mediumselect-list');
  304. $(list).children().remove();
  305. var sel = $('#'+$(this).attr('id')+'-mediumselect');
  306. var old = this;
  307. for(var i = 0; i < options.media.length; i++) {
  308. if(options.media[i].base && options.media[i].id != options.media[i].base) continue;
  309. $(list).append(listItem(options.media[i],sel,old,options.showdiff));
  310. }
  311. // Set initial text and styles
  312. var oldopt = $(this).children('option:eq('+Math.max($(this).prop('selectedIndex'),0)+')');
  313. if(!$(oldopt).val()) {
  314. _selectmedium($(list).find('div').first(), sel, old);
  315. } else {
  316. _selectmedium($('#'+$(sel).attr('id')+'-'+$(oldopt).val()), sel, old);
  317. }
  318. }); // </ .each() >
  319. return this;
  320. }; // </mediumselect()>
  321. })(jQuery);
  322. //jQuery File Tree Plugin
  323. //
  324. // Version 1.01
  325. //
  326. // Cory S.N. LaViska
  327. // A Beautiful Site (http://abeautifulsite.net/)
  328. // 24 March 2008
  329. //
  330. // Visit http://abeautifulsite.net/notebook.php?article=58 for more information
  331. //
  332. // Usage: $('.fileTreeDemo').fileTree( options, callback )
  333. //
  334. // Options: root - root folder to display; default = /
  335. // script - location of the serverside AJAX file to use; default = jqueryFileTree.php
  336. // folderEvent - event to trigger expand/collapse; default = click
  337. // expandSpeed - default = 500 (ms); use -1 for no animation
  338. // collapseSpeed - default = 500 (ms); use -1 for no animation
  339. // expandEasing - easing function to use on expand (optional)
  340. // collapseEasing - easing function to use on collapse (optional)
  341. // multiFolder - whether or not to limit the browser to one subfolder at a time
  342. // loadMessage - Message to display while initial tree loads (can be HTML)
  343. //
  344. // History:
  345. //
  346. // 1.01 - updated to work with foreign characters in directory/file names (12 April 2008)
  347. // 1.00 - released (24 March 2008)
  348. //
  349. // TERMS OF USE
  350. //
  351. // This plugin is dual-licensed under the GNU General Public License and the MIT License and
  352. // is copyright 2008 A Beautiful Site, LLC.
  353. //
  354. // 2010-05-12 - Modified by Ian Moore for phpVirtualBox
  355. //
  356. //
  357. if(jQuery) (function($){
  358. $.extend($.fn, {
  359. fileTree: function(o, h) {
  360. // Defaults
  361. if( !o ) var o = {};
  362. if( o.root == undefined ) o.root = '/';
  363. if( o.script == undefined ) o.script = vboxEndpointConfig.filebrowser;
  364. if( o.expandSpeed == undefined ) o.expandSpeed= 500;
  365. if( o.collapseSpeed == undefined ) o.collapseSpeed= 500;
  366. if( o.expandEasing == undefined ) o.expandEasing = null;
  367. if( o.collapseEasing == undefined ) o.collapseEasing = null;
  368. if( o.multiFolder == undefined ) o.multiFolder = true;
  369. if( o.loadMessage == undefined ) o.loadMessage = trans('Loading ...','UIVMDesktop');
  370. if( o.scrollTo == undefined ) o.scrollTo = null;
  371. if( o.dirsOnly == undefined) o.dirsOnly = false;
  372. var top = this;
  373. $(this).each( function() {
  374. function showTree(c, t, fullpath) {
  375. // If a UL is not the target, find or create it
  376. if($(c).prop('tagName') != 'UL') {
  377. var target = $(c).children('UL').first();
  378. if(target.length) {
  379. c = $(target);
  380. } else {
  381. var rootList = $('<ul />').addClass("jqueryFileTree");
  382. $(c).append(rootList);
  383. c = rootList;
  384. }
  385. }
  386. // If data is already loaded, just show it
  387. if($(c).children().length) {
  388. $(c).slideDown({ duration: o.expandSpeed, easing: o.expandEasing });
  389. return;
  390. }
  391. $(c).append($('<li />').addClass("wait").text(o.loadMessage));
  392. $.post(o.script, JSON.stringify({ 'dir': t, 'dirsOnly' : (o.dirsOnly ? true : false), 'fullpath' : (fullpath ? true : false)}), function(data) {
  393. $(c).children('.wait').remove();
  394. $(c).append(toHTML(data));
  395. if(o.scrollTo) {
  396. var sto = $(o.scrollTo).find('a.vboxListItemSelected').first();
  397. if(sto.length) {
  398. $(o.scrollTo).scrollTo($(sto),{'axis':'y','offset':{'top':-15}});
  399. }
  400. }
  401. bindTree(c);
  402. }, "json");
  403. }
  404. function folderElement(data) {
  405. return $('<li/>').addClass("folder")
  406. .addClass(data.expanded ? 'expanded' : 'collapsed')
  407. .addClass('vboxListItem')
  408. .append(
  409. $('<a/>').attr({'href':'#','name':data.path,'rel':data.path})
  410. .addClass(data.selected ? 'vboxListItemSelected' : '')
  411. .text(data.name)
  412. );
  413. }
  414. function fileElement(data) {
  415. return $('<li/>').addClass('file file_' + data.ext +' vboxListItem')
  416. .append(
  417. $('<a/>').attr({'href':'#','name':data.path,'rel':data.path}).text(data.name)
  418. );
  419. }
  420. function toHTML(data) {
  421. data.sort(function(a,b){
  422. if(a.type == b.type)
  423. return strnatcasecmp(a.path, b.path);
  424. return a.type == 'folder' ? -1 : 1
  425. });
  426. var elms = [];
  427. for(var i = 0; i < data.length; i++) {
  428. // Folder
  429. if(data[i].type == 'folder') {
  430. var direlm = folderElement(data[i]);
  431. if(data[i].expanded) {
  432. var listelm = $('<ul/>').addClass('jqueryFileTree');
  433. var children = toHTML(data[i].children);
  434. for(var a = 0; a < children.length; a++) {
  435. $(listelm).append(children[a]);
  436. }
  437. $(direlm).append(listelm);
  438. }
  439. elms.push(direlm);
  440. // File
  441. } else {
  442. elms.push(fileElement(data[i]));
  443. }
  444. }
  445. return elms;
  446. }
  447. function bindTree(t) {
  448. // Expand / collapse
  449. $(t).find('LI A').on('dblclick', function(e) {
  450. e.preventDefault();
  451. // Folder
  452. if( $(this).parent().hasClass('folder') ) {
  453. // Is collapsed. Expand
  454. if( $(this).parent().hasClass('collapsed') ) {
  455. // Expand
  456. if( !o.multiFolder ) {
  457. $(top).find('UL').slideUp({ duration: o.collapseSpeed, easing: o.collapseEasing })
  458. $(top).find('LI.folder').removeClass('expanded').addClass('collapsed');
  459. }
  460. $(this).parent().removeClass('collapsed').addClass('expanded');
  461. showTree( $(this).parent(), $(this).attr('name') );
  462. // Is expanded. Collapse
  463. } else {
  464. // Collapse
  465. $(this).parent().removeClass('expanded').addClass('collapsed')
  466. .children('UL').slideUp({ duration: o.collapseSpeed, easing: o.collapseEasing });
  467. }
  468. } else {
  469. h($(this).attr('name'));
  470. }
  471. return false;
  472. }).on('click', function() {
  473. $(top).find('.vboxListItemSelected').removeClass('vboxListItemSelected');
  474. $(this).addClass('vboxListItemSelected');
  475. return false;
  476. });
  477. }
  478. // Loading message
  479. var rootList = $('<ul />').addClass("jqueryFileTree");
  480. $(this).empty().append(rootList);
  481. // Get the initial file list
  482. showTree( rootList, o.root, true);
  483. });
  484. return this;
  485. }
  486. });
  487. })(jQuery);
  488. /* jQuery Context Menu Plugin
  489. Version 1.01
  490. Cory S.N. LaViska
  491. A Beautiful Site (http://abeautifulsite.net/)
  492. More info: http://abeautifulsite.net/2008/09/jquery-context-menu-plugin/
  493. //
  494. // Terms of Use
  495. //
  496. // This plugin is dual-licensed under the GNU General Public License
  497. // and the MIT License and is copyright A Beautiful Site, LLC.
  498. //
  499. This jQuery plugin now hardly resembles the original.
  500. --Ian Moore
  501. */
  502. if(jQuery)( function() {
  503. $.extend($.fn, {
  504. contextMenu: function(o, callback) {
  505. // Defaults
  506. if( o.menu == undefined ) return false;
  507. if( o.inSpeed == undefined ) o.inSpeed = 150;
  508. if( o.outSpeed == undefined ) o.outSpeed = 75;
  509. // 0 needs to be -1 for expected results (no fade)
  510. if( o.inSpeed == 0 ) o.inSpeed = -1;
  511. if( o.outSpeed == 0 ) o.outSpeed = -1;
  512. if( o.button == undefined) o.button = 2;
  513. if( o.clickthrough == undefined) o.clickthrough = false;
  514. // Loop each context menu
  515. $(this).each( function() {
  516. var el = $(this);
  517. var menu = $('#'+o.menu);
  518. // Simulate a true click
  519. $(this).mousedown( function(e) {
  520. if( $(el).hasClass('disabled') ) return true;
  521. if(!( e.button == o.button || (o.button == 0 && e.button == 1 && $.browser.msie))) return;
  522. if(o.clickthrough) $(el).trigger('click');
  523. var evt = e;
  524. evt.stopPropagation();
  525. $(this).mouseup( function(e) {
  526. if( $(this).hasClass('disabled') ) return true;
  527. e.stopPropagation();
  528. var srcElement = $(this);
  529. $(this).off('mouseup');
  530. if( evt.button == o.button || (o.button == 0 && evt.button == 1 && $.browser.msie)) {
  531. // Menu setup function
  532. if(o.menusetup) {
  533. o.menusetup(el);
  534. }
  535. // Hide context menus that may be showing
  536. $("ul.contextMenu").hide();
  537. showMenu(srcElement, menu, o.mode, e);
  538. $(document).one('mouseup', function() {
  539. $(menu).fadeOut(o.outSpeed);
  540. $("ul.contextMenu").hide();
  541. });
  542. }
  543. });
  544. });
  545. /*
  546. * Initialize menu items
  547. *
  548. */
  549. var menuItems = function(menu, srcElement, level) {
  550. // When items are selected
  551. $(menu).addClass('contextMenu').data({'level':level}).disableSelection().children('li').off('mouseup').on('mouseup', function(e) {
  552. if($(this).hasClass('disabled')) {
  553. return;
  554. }
  555. $("ul.contextMenu").hide();
  556. // Callback
  557. if( callback ) {
  558. var aElm = $(this).children('a');
  559. if($(aElm)[0]) {
  560. callback( aElm.attr('href').substr(1), $(srcElement), null, aElm);
  561. } else {
  562. $(this).children('.vboxMenuAcceptClick').click();
  563. }
  564. }
  565. }).on("mouseenter", function(e, li) {
  566. $('#vboxPane').trigger('contextMenuShowLevel',
  567. {'level':$(this).parent().data('level'), 'id':$(this).parent().attr('id')}
  568. );
  569. $(menu).find('LI.vboxHover').removeClass('vboxHover');
  570. if($(this).hasClass('disabled')) return;
  571. $(this).addClass('vboxHover');
  572. var subMenuId = $(this).data('subId');
  573. if(subMenuId) showMenu($(this),$('#'+subMenuId),'submenu',e);
  574. }).on("mouseleave",function() {
  575. $(menu).find('LI.vboxHover').removeClass('vboxHover');
  576. }).children('a').off('click').on('click',function(e){
  577. e.preventDefault();
  578. return false;
  579. });
  580. // Sub menu initialization
  581. $(menu).children('li').children('ul').each(function() {
  582. var plink = $(this).siblings('a').first();
  583. var subId = $(this).attr('id');
  584. if(!subId) {
  585. var href = plink.attr('href').replace('#','');
  586. subId = href + '-Submenu';
  587. $(this).attr('id', subId);
  588. }
  589. $(this).addClass('contextMenu contextSubMenu').data({'level':level+1}).parent().addClass('contextMenuParent').data({'subId':subId,'level':level});
  590. var html = plink.html();
  591. plink.html('<table class="vboxInvisible" style="width:100%"><tr><td style="text-align:left">'+html+'</td><td style="text-align:right; width: 22px;"><img src="images/rightArrow.png" /></td></tr></table>');
  592. // Hide menus trigger
  593. var smenu = this;
  594. $('#vboxPane').on('contextMenuShowLevel',function(e,c){
  595. if($(smenu).data('level') >= c.level && $(smenu).attr('id') != c.id)
  596. $(smenu).hide();
  597. });
  598. // Reloop through setup
  599. menuItems($(this), srcElement, ++level);
  600. $(this).detach().appendTo($('#vboxPane'));
  601. });
  602. };
  603. /*
  604. *
  605. * Activate menu items
  606. *
  607. */
  608. var showMenu = function(srcElement, menu, mode, e) {
  609. // Check menu
  610. if(!$(menu)[0]) {
  611. return;
  612. }
  613. // Hide all other menus at this level
  614. $('#vboxPane').trigger('contextMenuShowLevel', {'level':$(menu).data('level'), 'id':$(menu).attr('id')});
  615. // Detect mouse position
  616. var d = {};
  617. var x = null;
  618. var y = null;
  619. if(mode == 'menu') {
  620. x = $(srcElement).offset().left;
  621. y = $(srcElement).offset().top + $(srcElement).outerHeight();
  622. } else if(mode == 'submenu') {
  623. y = $(srcElement).offset().top;
  624. x = $(srcElement).offset().left + $(srcElement).outerWidth();
  625. } else {
  626. if( self.innerHeight ) {
  627. d.pageYOffset = self.pageYOffset;
  628. d.pageXOffset = self.pageXOffset;
  629. d.innerHeight = self.innerHeight;
  630. d.innerWidth = self.innerWidth;
  631. } else if( document.documentElement &&
  632. document.documentElement.clientHeight ) {
  633. d.pageYOffset = document.documentElement.scrollTop;
  634. d.pageXOffset = document.documentElement.scrollLeft;
  635. d.innerHeight = document.documentElement.clientHeight;
  636. d.innerWidth = document.documentElement.clientWidth;
  637. } else if( document.body ) {
  638. d.pageYOffset = document.body.scrollTop;
  639. d.pageXOffset = document.body.scrollLeft;
  640. d.innerHeight = document.body.clientHeight;
  641. d.innerWidth = document.body.clientWidth;
  642. }
  643. $(menu).css({'left':0,'top':0});
  644. (e.pageX) ? x = e.pageX : x = e.clientX + d.scrollLeft;
  645. (e.pageY) ? y = e.pageY : y = e.clientY + d.scrollTop;
  646. }
  647. // shift left if submenu
  648. if($(menu).data('level')) x-=3;
  649. //adjust to ensure menu is inside viewable screen
  650. var right = x + $(menu).outerWidth();
  651. var bottom = y + $(menu).outerHeight();
  652. var windowWidth = $(window).width() + $(window).scrollLeft()-5;
  653. var windowHeight = $(window).height() + $(window).scrollTop()-5;
  654. x = (right > windowWidth) ? x - (right - windowWidth) : x;
  655. y = (bottom > windowHeight) ? y - (bottom - windowHeight) : y;
  656. $(menu).one('menuLoaded',function(){
  657. menuItems(menu, srcElement);
  658. });
  659. // Check for callback if nothing is present
  660. if($(menu).children().length == 0 && $(menu).data('callback')) {
  661. var m = window[$(menu).data('callback')](menu);
  662. // New menu returned?
  663. if(m) {
  664. $(m).addClass('contextSubMenu contextMenuLevel' + ($(menu).data('level')+1)).data('level',($(menu).data('level')+1));
  665. // Hide menus trigger
  666. $('#vboxPane').on('contextMenuShowLevel',function(e,c){
  667. if($(m).data('level') >= c.level && $(m).attr('id') != c.id) $(m).hide();
  668. });
  669. menuItems(m, srcElement, $(menu).data('level')+1);
  670. showMenu(srcElement, m, 'submenu', e);
  671. return;
  672. }
  673. } else {
  674. menuItems(menu, srcElement, $(menu).data('level'));
  675. }
  676. // Menu show
  677. $(menu).css({ top: y, left: x}).show();//.fadeIn(o.inSpeed);
  678. };
  679. // Setup menu
  680. menuItems(menu, el, 0);
  681. // Disable browser context menu (requires both selectors to work in IE/Safari + FF/Chrome)
  682. $(el).add($('UL.contextMenu')).on('contextmenu', function() { return false; });
  683. });
  684. return $(this);
  685. },
  686. // Disable context menu items on the fly
  687. disableContextMenuItems: function(o) {
  688. if( o == undefined ) {
  689. // Disable all
  690. $(this).find('LI').addClass('disabled');
  691. return( $(this) );
  692. }
  693. $(this).each( function() {
  694. if( o != undefined ) {
  695. var d = o.split(',');
  696. for( var i = 0; i < d.length; i++ ) {
  697. $(this).find('A[href="' + d[i] + '"]').closest('li').addClass('disabled');
  698. }
  699. }
  700. });
  701. return( $(this) );
  702. },
  703. // Enable context menu items on the fly
  704. enableContextMenuItems: function(o) {
  705. if( o == undefined ) {
  706. // Enable all
  707. $(this).find('LI.disabled').removeClass('disabled');
  708. return( $(this) );
  709. }
  710. $(this).each( function() {
  711. if( o != undefined ) {
  712. var d = o.split(',');
  713. for( var i = 0; i < d.length; i++ ) {
  714. $(this).find('A[href="' + d[i] + '"]').closest('li').removeClass('disabled');
  715. }
  716. }
  717. });
  718. return( $(this) );
  719. },
  720. // Disable context menu(s)
  721. disableContextMenu: function() {
  722. $(this).each( function() {
  723. $(this).addClass('disabled');
  724. });
  725. return( $(this) );
  726. },
  727. // Enable context menu(s)
  728. enableContextMenu: function() {
  729. $(this).each( function() {
  730. $(this).removeClass('disabled');
  731. });
  732. return( $(this) );
  733. },
  734. // Destroy context menu(s)
  735. destroyContextMenu: function() {
  736. // Destroy specified context menus
  737. $(this).each( function() {
  738. // Disable action
  739. $(this).off('mousedown').off('mouseup');
  740. });
  741. return( $(this) );
  742. }
  743. });
  744. })(jQuery);