toolkit/modules/PageMenu.jsm

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:b25bb8087a42
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/. */
4
5 this.EXPORTED_SYMBOLS = ["PageMenu"];
6
7 this.PageMenu = function PageMenu() {
8 }
9
10 PageMenu.prototype = {
11 PAGEMENU_ATTR: "pagemenu",
12 GENERATEDITEMID_ATTR: "generateditemid",
13
14 popup: null,
15 builder: null,
16
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 }
28
29 if (!pageMenu) {
30 return false;
31 }
32
33 var insertionPoint = this.getInsertionPoint(aPopup);
34 if (!insertionPoint) {
35 return false;
36 }
37
38 pageMenu.QueryInterface(Components.interfaces.nsIHTMLMenu);
39 pageMenu.sendShowEvent();
40 // the show event is not cancelable, so no need to check a result here
41
42 var fragment = aPopup.ownerDocument.createDocumentFragment();
43
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);
50
51 pageMenu.build(builder);
52
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 }
60
61 this.builder = builder;
62 this.popup = aPopup;
63
64 this.popup.addEventListener("command", this);
65 this.popup.addEventListener("popuphidden", this);
66
67 return true;
68 },
69
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);
77
78 this.popup.removeEventListener("popuphidden", this);
79 this.popup.removeEventListener("command", this);
80
81 this.popup = null;
82 this.builder = null;
83 }
84 },
85
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 },
96
97 getInsertionPoint: function(aPopup) {
98 if (aPopup.hasAttribute(this.PAGEMENU_ATTR))
99 return aPopup;
100
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 }
114
115 return null;
116 },
117
118 removeGeneratedContent: function(aPopup) {
119 var ungenerated = [];
120 ungenerated.push(aPopup);
121
122 var count;
123 while (0 != (count = ungenerated.length)) {
124 var last = count - 1;
125 var element = ungenerated[last];
126 ungenerated.splice(last, 1);
127
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 }

mercurial