/toolkit/content/PageMenu.jsm

http://github.com/zpao/v8monkey · Unknown · 170 lines · 145 code · 25 blank · 0 comment · 0 complexity · db3c56cbe3556f6983825cf27bf775e9 MD5 · raw file

  1. # ***** BEGIN LICENSE BLOCK *****
  2. # Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3. #
  4. # The contents of this file are subject to the Mozilla Public License Version
  5. # 1.1 (the "License"); you may not use this file except in compliance with
  6. # the License. You may obtain a copy of the License at
  7. # http://www.mozilla.org/MPL/
  8. #
  9. # Software distributed under the License is distributed on an "AS IS" basis,
  10. # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11. # for the specific language governing rights and limitations under the
  12. # License.
  13. #
  14. # The Original Code is Mozilla code.
  15. #
  16. # The Initial Developer of the Original Code is Mozilla Foundation
  17. # Portions created by the Initial Developer are Copyright (C) 2011
  18. # the Initial Developer. All Rights Reserved.
  19. #
  20. # Contributor(s):
  21. #
  22. # Alternatively, the contents of this file may be used under the terms of
  23. # either the GNU General Public License Version 2 or later (the "GPL"), or
  24. # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  25. # in which case the provisions of the GPL or the LGPL are applicable instead
  26. # of those above. If you wish to allow use of your version of this file only
  27. # under the terms of either the GPL or the LGPL, and not to allow others to
  28. # use your version of this file under the terms of the MPL, indicate your
  29. # decision by deleting the provisions above and replace them with the notice
  30. # and other provisions required by the LGPL or the GPL. If you do not delete
  31. # the provisions above, a recipient may use your version of this file under
  32. # the terms of any one of the MPL, the GPL or the LGPL.
  33. #
  34. # ***** END LICENSE BLOCK ***** -->
  35. let EXPORTED_SYMBOLS = ["PageMenu"];
  36. function PageMenu() {
  37. }
  38. PageMenu.prototype = {
  39. PAGEMENU_ATTR: "pagemenu",
  40. GENERATEDITEMID_ATTR: "generateditemid",
  41. popup: null,
  42. builder: null,
  43. maybeBuildAndAttachMenu: function(aTarget, aPopup) {
  44. var pageMenu = null;
  45. var target = aTarget;
  46. while (target) {
  47. var contextMenu = target.contextMenu;
  48. if (contextMenu) {
  49. pageMenu = contextMenu;
  50. break;
  51. }
  52. target = target.parentNode;
  53. }
  54. if (!pageMenu) {
  55. return false;
  56. }
  57. var insertionPoint = this.getInsertionPoint(aPopup);
  58. if (!insertionPoint) {
  59. return false;
  60. }
  61. pageMenu.QueryInterface(Components.interfaces.nsIHTMLMenu);
  62. pageMenu.sendShowEvent();
  63. // the show event is not cancelable, so no need to check a result here
  64. var fragment = aPopup.ownerDocument.createDocumentFragment();
  65. var builder = pageMenu.createBuilder();
  66. if (!builder) {
  67. return false;
  68. }
  69. builder.QueryInterface(Components.interfaces.nsIXULContextMenuBuilder);
  70. builder.init(fragment, this.GENERATEDITEMID_ATTR);
  71. pageMenu.build(builder);
  72. var pos = insertionPoint.getAttribute(this.PAGEMENU_ATTR);
  73. if (pos == "start") {
  74. insertionPoint.insertBefore(fragment,
  75. insertionPoint.firstChild);
  76. } else {
  77. insertionPoint.appendChild(fragment);
  78. }
  79. this.builder = builder;
  80. this.popup = aPopup;
  81. this.popup.addEventListener("command", this);
  82. this.popup.addEventListener("popuphidden", this);
  83. return true;
  84. },
  85. handleEvent: function(event) {
  86. var type = event.type;
  87. var target = event.target;
  88. if (type == "command" && target.hasAttribute(this.GENERATEDITEMID_ATTR)) {
  89. this.builder.click(target.getAttribute(this.GENERATEDITEMID_ATTR));
  90. } else if (type == "popuphidden" && this.popup == target) {
  91. this.removeGeneratedContent(this.popup);
  92. this.popup.removeEventListener("popuphidden", this);
  93. this.popup.removeEventListener("command", this);
  94. this.popup = null;
  95. this.builder = null;
  96. }
  97. },
  98. getImmediateChild: function(element, tag) {
  99. var child = element.firstChild;
  100. while (child) {
  101. if (child.localName == tag) {
  102. return child;
  103. }
  104. child = child.nextSibling;
  105. }
  106. return null;
  107. },
  108. getInsertionPoint: function(aPopup) {
  109. if (aPopup.hasAttribute(this.PAGEMENU_ATTR))
  110. return aPopup;
  111. var element = aPopup.firstChild;
  112. while (element) {
  113. if (element.localName == "menu") {
  114. var popup = this.getImmediateChild(element, "menupopup");
  115. if (popup) {
  116. var result = this.getInsertionPoint(popup);
  117. if (result) {
  118. return result;
  119. }
  120. }
  121. }
  122. element = element.nextSibling;
  123. }
  124. return null;
  125. },
  126. removeGeneratedContent: function(aPopup) {
  127. var ungenerated = [];
  128. ungenerated.push(aPopup);
  129. var count;
  130. while (0 != (count = ungenerated.length)) {
  131. var last = count - 1;
  132. var element = ungenerated[last];
  133. ungenerated.splice(last, 1);
  134. var i = element.childNodes.length;
  135. while (i-- > 0) {
  136. var child = element.childNodes[i];
  137. if (!child.hasAttribute(this.GENERATEDITEMID_ATTR)) {
  138. ungenerated.push(child);
  139. continue;
  140. }
  141. element.removeChild(child);
  142. }
  143. }
  144. }
  145. }