Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 this.EXPORTED_SYMBOLS = ["PageMenu"];
7 this.PageMenu = function PageMenu() {
8 }
10 PageMenu.prototype = {
11 PAGEMENU_ATTR: "pagemenu",
12 GENERATEDITEMID_ATTR: "generateditemid",
14 popup: null,
15 builder: null,
17 maybeBuildAndAttachMenu: function(aTarget, aPopup) {
18 var pageMenu = null;
19 var target = aTarget;
20 while (target) {
21 var contextMenu = target.contextMenu;
22 if (contextMenu) {
23 pageMenu = contextMenu;
24 break;
25 }
26 target = target.parentNode;
27 }
29 if (!pageMenu) {
30 return false;
31 }
33 var insertionPoint = this.getInsertionPoint(aPopup);
34 if (!insertionPoint) {
35 return false;
36 }
38 pageMenu.QueryInterface(Components.interfaces.nsIHTMLMenu);
39 pageMenu.sendShowEvent();
40 // the show event is not cancelable, so no need to check a result here
42 var fragment = aPopup.ownerDocument.createDocumentFragment();
44 var builder = pageMenu.createBuilder();
45 if (!builder) {
46 return false;
47 }
48 builder.QueryInterface(Components.interfaces.nsIXULContextMenuBuilder);
49 builder.init(fragment, this.GENERATEDITEMID_ATTR);
51 pageMenu.build(builder);
53 var pos = insertionPoint.getAttribute(this.PAGEMENU_ATTR);
54 if (pos == "start") {
55 insertionPoint.insertBefore(fragment,
56 insertionPoint.firstChild);
57 } else {
58 insertionPoint.appendChild(fragment);
59 }
61 this.builder = builder;
62 this.popup = aPopup;
64 this.popup.addEventListener("command", this);
65 this.popup.addEventListener("popuphidden", this);
67 return true;
68 },
70 handleEvent: function(event) {
71 var type = event.type;
72 var target = event.target;
73 if (type == "command" && target.hasAttribute(this.GENERATEDITEMID_ATTR)) {
74 this.builder.click(target.getAttribute(this.GENERATEDITEMID_ATTR));
75 } else if (type == "popuphidden" && this.popup == target) {
76 this.removeGeneratedContent(this.popup);
78 this.popup.removeEventListener("popuphidden", this);
79 this.popup.removeEventListener("command", this);
81 this.popup = null;
82 this.builder = null;
83 }
84 },
86 getImmediateChild: function(element, tag) {
87 var child = element.firstChild;
88 while (child) {
89 if (child.localName == tag) {
90 return child;
91 }
92 child = child.nextSibling;
93 }
94 return null;
95 },
97 getInsertionPoint: function(aPopup) {
98 if (aPopup.hasAttribute(this.PAGEMENU_ATTR))
99 return aPopup;
101 var element = aPopup.firstChild;
102 while (element) {
103 if (element.localName == "menu") {
104 var popup = this.getImmediateChild(element, "menupopup");
105 if (popup) {
106 var result = this.getInsertionPoint(popup);
107 if (result) {
108 return result;
109 }
110 }
111 }
112 element = element.nextSibling;
113 }
115 return null;
116 },
118 removeGeneratedContent: function(aPopup) {
119 var ungenerated = [];
120 ungenerated.push(aPopup);
122 var count;
123 while (0 != (count = ungenerated.length)) {
124 var last = count - 1;
125 var element = ungenerated[last];
126 ungenerated.splice(last, 1);
128 var i = element.childNodes.length;
129 while (i-- > 0) {
130 var child = element.childNodes[i];
131 if (!child.hasAttribute(this.GENERATEDITEMID_ATTR)) {
132 ungenerated.push(child);
133 continue;
134 }
135 element.removeChild(child);
136 }
137 }
138 }
139 }