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() {
10 PageMenu.prototype = {
11 PAGEMENU_ATTR: "pagemenu",
12 GENERATEDITEMID_ATTR: "generateditemid",
17 maybeBuildAndAttachMenu: function(aTarget, aPopup) {
21 var contextMenu = target.contextMenu;
23 pageMenu = contextMenu;
26 target = target.parentNode;
33 var insertionPoint = this.getInsertionPoint(aPopup);
34 if (!insertionPoint) {
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();
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);
55 insertionPoint.insertBefore(fragment,
56 insertionPoint.firstChild);
57 } else if (pos.startsWith("#")) {
58 insertionPoint.insertBefore(fragment, insertionPoint.querySelector(pos));
60 insertionPoint.appendChild(fragment);
63 this.builder = builder;
66 this.popup.addEventListener("command", this);
67 this.popup.addEventListener("popuphidden", this);
72 handleEvent: function(event) {
73 var type = event.type;
74 var target = event.target;
75 if (type == "command" && target.hasAttribute(this.GENERATEDITEMID_ATTR)) {
76 this.builder.click(target.getAttribute(this.GENERATEDITEMID_ATTR));
77 } else if (type == "popuphidden" && this.popup == target) {
78 this.removeGeneratedContent(this.popup);
80 this.popup.removeEventListener("popuphidden", this);
81 this.popup.removeEventListener("command", this);
88 getImmediateChild: function(element, tag) {
89 var child = element.firstChild;
91 if (child.localName == tag) {
94 child = child.nextSibling;
99 getInsertionPoint: function(aPopup) {
100 if (aPopup.hasAttribute(this.PAGEMENU_ATTR))
103 var element = aPopup.firstChild;
105 if (element.localName == "menu") {
106 var popup = this.getImmediateChild(element, "menupopup");
108 var result = this.getInsertionPoint(popup);
114 element = element.nextSibling;
120 removeGeneratedContent: function(aPopup) {
121 var ungenerated = [];
122 ungenerated.push(aPopup);
125 while (0 != (count = ungenerated.length)) {
126 var last = count - 1;
127 var element = ungenerated[last];
128 ungenerated.splice(last, 1);
130 var i = element.childNodes.length;
132 var child = element.childNodes[i];
133 if (!child.hasAttribute(this.GENERATEDITEMID_ATTR)) {
134 ungenerated.push(child);
137 element.removeChild(child);