1
1

jquery.contextmenu.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. (function($) {
  2. function returnfalse() { return false; };
  3. $.fn.contextmenu = function(option) {
  4. option = $.extend({ alias: "cmroot", width: 150 }, option);
  5. var ruleName = null, target = null,
  6. groups = {}, mitems = {}, actions = {}, showGroups = [],
  7. itemTpl = "<div class='b-m-$[type]' unselectable=on><nobr unselectable=on><span unselectable=on>$[text]</span></nobr></div>";
  8. var gTemplet = $("<div/>").addClass("b-m-mpanel").attr("unselectable", "on").css("display", "none");
  9. var iTemplet = $("<div/>").addClass("b-m-item").attr("unselectable", "on");
  10. var sTemplet = $("<div/>").addClass("b-m-split");
  11. //build group item, which has sub items
  12. var buildGroup = function(obj) {
  13. groups[obj.alias] = this;
  14. this.gidx = obj.alias;
  15. this.id = obj.alias;
  16. if (obj.disable) {
  17. this.disable = obj.disable;
  18. this.className = "b-m-idisable";
  19. }
  20. $(this).width(obj.width).click(returnfalse).mousedown(returnfalse).appendTo($("body"));
  21. obj = null;
  22. return this;
  23. };
  24. var buildItem = function(obj) {
  25. var T = this;
  26. T.idx = obj.alias;
  27. T.gidx = obj.gidx;
  28. T.data = obj;
  29. T.innerHTML = itemTpl.replace(/\$\[([^\]]+)\]/g, function() {
  30. return obj[arguments[1]];
  31. });
  32. if (obj.id)
  33. T.setAttribute('id', obj.id);
  34. if (obj.disable) {
  35. T.disable = obj.disable;
  36. T.className = "b-m-idisable";
  37. }
  38. obj.items && (T.group = true);
  39. obj.action && (actions[obj.alias] = obj.action);
  40. mitems[obj.alias] = T;
  41. T = obj = null;
  42. return this;
  43. };
  44. //add new items
  45. var addItems = function(gidx, items) {
  46. var tmp = null;
  47. for (var i = 0; i < items.length; i++) {
  48. if (items[i].type == "splitLine") {
  49. //split line
  50. tmp = sTemplet.clone()[0];
  51. } else {
  52. items[i].gidx = gidx;
  53. if (items[i].type == "group") {
  54. //group
  55. buildGroup.apply(gTemplet.clone()[0], [items[i]]);
  56. arguments.callee(items[i].alias, items[i].items);
  57. items[i].type = "arrow";
  58. tmp = buildItem.apply(iTemplet.clone()[0], [items[i]]);
  59. } else {
  60. //normal item
  61. items[i].type = "ibody";
  62. tmp = buildItem.apply(iTemplet.clone()[0], [items[i]]);
  63. $(tmp).click(function(e) {
  64. if (!this.disable) {
  65. if ($.isFunction(actions[this.idx])) {
  66. actions[this.idx].call(this, target);
  67. }
  68. hideMenuPane();
  69. }
  70. return false;
  71. });
  72. } //end if
  73. $(tmp).bind("contextmenu", returnfalse).hover(overItem, outItem);
  74. }
  75. groups[gidx].appendChild(tmp);
  76. tmp = items[i] = items[i].items = null;
  77. } //end for
  78. gidx = items = null;
  79. };
  80. var overItem = function(e) {
  81. //menu item is disabled
  82. if (this.disable)
  83. return false;
  84. hideMenuPane.call(groups[this.gidx]);
  85. //has sub items
  86. if (this.group) {
  87. var pos = $(this).offset();
  88. var width = $(this).outerWidth();
  89. showMenuGroup.apply(groups[this.idx], [pos, width]);
  90. }
  91. this.className = "b-m-ifocus";
  92. return false;
  93. };
  94. //menu loses focus
  95. var outItem = function(e) {
  96. //disabled item
  97. if (this.disable )
  98. return false;
  99. if (!this.group) {
  100. //normal item
  101. this.className = "b-m-item";
  102. } //Endif
  103. return false;
  104. };
  105. //show menu group at specified position
  106. var reversed = false;
  107. var showMenuGroup = function(pos, width) {
  108. var bwidth = $("body").width();
  109. var bheight = document.documentElement.clientHeight;
  110. var mwidth = $(this).outerWidth();
  111. var mheight = $(this).outerHeight();
  112. var originalPosTop = pos.top;
  113. pos.left = (pos.left + width + mwidth > bwidth) ? (pos.left - mwidth < 0 ? 0 : pos.left - mwidth) : pos.left + width;
  114. pos.top = (pos.top + mheight > bheight) ? (pos.top - mheight + (width > 0 ? 25 : 0) < 0 ? 0 : pos.top - mheight + (width > 0 ? 25 : 0)) : pos.top;
  115. var needsReversed = originalPosTop > pos.top;
  116. var $this = $(this);
  117. if (reversed != needsReversed)
  118. $this.children().each(function(i, child) { $this.prepend(child); });
  119. reversed = needsReversed;
  120. $(this).css(pos).show();
  121. showGroups.push(this.gidx);
  122. };
  123. //to hide menu
  124. var hideMenuPane = function() {
  125. var alias = null;
  126. for (var i = showGroups.length - 1; i >= 0; i--) {
  127. if (showGroups[i] == this.gidx)
  128. break;
  129. alias = showGroups.pop();
  130. groups[alias].style.display = "none";
  131. mitems[alias] && (mitems[alias].className = "b-m-item");
  132. } //Endfor
  133. //CollectGarbage();
  134. };
  135. function applyRule(rule) {
  136. if (ruleName && ruleName == rule.name)
  137. return false;
  138. for (var i in mitems)
  139. disable(i, !rule.disable);
  140. for (var i = 0; i < rule.items.length; i++)
  141. disable(rule.items[i], rule.disable);
  142. ruleName = rule.name;
  143. };
  144. function disable(alias, disabled) {
  145. var item = mitems[alias];
  146. item.className = (item.disable = item.lastChild.disabled = disabled) ? "b-m-idisable" : "b-m-item";
  147. };
  148. /* to show menu */
  149. function showMenu(e, menutarget) {
  150. target = menutarget;
  151. showMenuGroup.call(groups.cmroot, { left: e.pageX, top: e.pageY }, 0);
  152. $(document).one('mousedown', hideMenuPane);
  153. }
  154. var $root = $("#" + option.alias);
  155. var root = null;
  156. if ($root.length == 0) {
  157. root = buildGroup.apply(gTemplet.clone()[0], [option]);
  158. root.applyrule = applyRule;
  159. root.showMenu = showMenu;
  160. addItems(option.alias, option.items);
  161. }
  162. else {
  163. root = $root[0];
  164. }
  165. var me = $(this).each(function() {
  166. return $(this).bind('contextmenu', function(e) {
  167. var bShowContext = (option.onContextMenu && $.isFunction(option.onContextMenu)) ? option.onContextMenu.call(this, e) : true;
  168. if (bShowContext) {
  169. if (option.onShow && $.isFunction(option.onShow)) {
  170. option.onShow.call(this, root);
  171. }
  172. root.showMenu(e, this);
  173. }
  174. return false;
  175. });
  176. });
  177. //to apply rule
  178. if (option.rule) {
  179. applyRule(option.rule);
  180. }
  181. gTemplet = iTemplet = sTemplet = itemTpl = buildGroup = buildItem = null;
  182. addItems = overItem = outItem = null;
  183. //CollectGarbage();
  184. return me;
  185. }
  186. })(jQuery);