mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-21 01:05:45 +00:00
674e1b96fb
MozReview-Commit-ID: 8w1vfF2yRui --HG-- extra : rebase_source : 222d8e9d3b9543552ff5b08967375fa46d62b896
736 lines
23 KiB
JavaScript
736 lines
23 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
var BrowserPageActions = {
|
|
/**
|
|
* The main page action button in the urlbar (DOM node)
|
|
*/
|
|
get mainButtonNode() {
|
|
delete this.mainButtonNode;
|
|
return this.mainButtonNode = document.getElementById("pageActionButton");
|
|
},
|
|
|
|
/**
|
|
* The main page action panel DOM node (DOM node)
|
|
*/
|
|
get panelNode() {
|
|
delete this.panelNode;
|
|
return this.panelNode = document.getElementById("pageActionPanel");
|
|
},
|
|
|
|
/**
|
|
* The photonmultiview node in the main page action panel (DOM node)
|
|
*/
|
|
get multiViewNode() {
|
|
delete this.multiViewNode;
|
|
return this.multiViewNode = document.getElementById("pageActionPanelMultiView");
|
|
},
|
|
|
|
/**
|
|
* The main panelview node in the main page action panel (DOM node)
|
|
*/
|
|
get mainViewNode() {
|
|
delete this.mainViewNode;
|
|
return this.mainViewNode = document.getElementById("pageActionPanelMainView");
|
|
},
|
|
|
|
/**
|
|
* The vbox body node in the main panelview node (DOM node)
|
|
*/
|
|
get mainViewBodyNode() {
|
|
delete this.mainViewBodyNode;
|
|
return this.mainViewBodyNode = this.mainViewNode.querySelector(".panel-subview-body");
|
|
},
|
|
|
|
/**
|
|
* Inits. Call to init.
|
|
*/
|
|
init() {
|
|
for (let action of PageActions.actions) {
|
|
this.placeAction(action, PageActions.insertBeforeActionIDInUrlbar(action));
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Adds or removes as necessary DOM nodes for the given action.
|
|
*
|
|
* @param action (PageActions.Action, required)
|
|
* The action to place.
|
|
* @param panelInsertBeforeID (string, required)
|
|
* The ID of the action in the panel before which the given action
|
|
* action should be inserted.
|
|
* @param urlbarInsertBeforeID (string, required)
|
|
* If the action is shown in the urlbar, then this is ID of the action
|
|
* in the urlbar before which the given action should be inserted.
|
|
*/
|
|
placeAction(action, panelInsertBeforeID, urlbarInsertBeforeID) {
|
|
if (action.__isSeparator) {
|
|
this._appendPanelSeparator(action);
|
|
return;
|
|
}
|
|
this.placeActionInPanel(action, panelInsertBeforeID);
|
|
this.placeActionInUrlbar(action, urlbarInsertBeforeID);
|
|
},
|
|
|
|
/**
|
|
* Adds or removes as necessary DOM nodes for the action in the panel.
|
|
*
|
|
* @param action (PageActions.Action, required)
|
|
* The action to place.
|
|
* @param insertBeforeID (string, required)
|
|
* The ID of the action in the panel before which the given action
|
|
* action should be inserted.
|
|
*/
|
|
placeActionInPanel(action, insertBeforeID) {
|
|
let id = this._panelButtonNodeIDForActionID(action.id);
|
|
let node = document.getElementById(id);
|
|
if (!node) {
|
|
let panelViewNode;
|
|
[node, panelViewNode] = this._makePanelButtonNodeForAction(action);
|
|
node.id = id;
|
|
let insertBeforeNode = null;
|
|
if (insertBeforeID) {
|
|
let insertBeforeNodeID =
|
|
this._panelButtonNodeIDForActionID(insertBeforeID);
|
|
insertBeforeNode = document.getElementById(insertBeforeNodeID);
|
|
}
|
|
this.mainViewBodyNode.insertBefore(node, insertBeforeNode);
|
|
action.onPlacedInPanel(node);
|
|
if (panelViewNode) {
|
|
action.subview.onPlaced(panelViewNode);
|
|
}
|
|
}
|
|
return node;
|
|
},
|
|
|
|
_makePanelButtonNodeForAction(action) {
|
|
let buttonNode = document.createElement("toolbarbutton");
|
|
buttonNode.classList.add(
|
|
"subviewbutton",
|
|
"subviewbutton-iconic",
|
|
"pageAction-panel-button"
|
|
);
|
|
buttonNode.setAttribute("label", action.title);
|
|
if (action.iconURL) {
|
|
buttonNode.style.listStyleImage = `url('${action.iconURL}')`;
|
|
}
|
|
if (action.nodeAttributes) {
|
|
for (let name in action.nodeAttributes) {
|
|
buttonNode.setAttribute(name, action.nodeAttributes[name]);
|
|
}
|
|
}
|
|
let panelViewNode = null;
|
|
if (action.subview) {
|
|
buttonNode.classList.add("subviewbutton-nav");
|
|
panelViewNode = this._makePanelViewNodeForAction(action, false);
|
|
this.multiViewNode._panelViews = null;
|
|
this.multiViewNode.appendChild(panelViewNode);
|
|
}
|
|
buttonNode.addEventListener("command", event => {
|
|
if (panelViewNode) {
|
|
action.subview.onShowing(panelViewNode);
|
|
this.multiViewNode.showSubView(panelViewNode, buttonNode);
|
|
return;
|
|
}
|
|
if (action.wantsIframe) {
|
|
this._toggleTempPanelForAction(action);
|
|
return;
|
|
}
|
|
this.panelNode.hidePopup();
|
|
action.onCommand(event, buttonNode);
|
|
});
|
|
return [buttonNode, panelViewNode];
|
|
},
|
|
|
|
_makePanelViewNodeForAction(action, forUrlbar) {
|
|
let panelViewNode = document.createElement("panelview");
|
|
panelViewNode.id = this._panelViewNodeIDForActionID(action.id, forUrlbar);
|
|
panelViewNode.classList.add("PanelUI-subView");
|
|
let bodyNode = document.createElement("vbox");
|
|
bodyNode.id = panelViewNode.id + "-body";
|
|
bodyNode.classList.add("panel-subview-body");
|
|
panelViewNode.appendChild(bodyNode);
|
|
for (let button of action.subview.buttons) {
|
|
let buttonNode = document.createElement("toolbarbutton");
|
|
buttonNode.id =
|
|
this._panelViewButtonNodeIDForActionID(action.id, button.id, forUrlbar);
|
|
buttonNode.classList.add("subviewbutton", "subviewbutton-iconic");
|
|
buttonNode.setAttribute("label", button.title);
|
|
if (button.shortcut) {
|
|
buttonNode.setAttribute("shortcut", button.shortcut);
|
|
}
|
|
if (button.disabled) {
|
|
buttonNode.setAttribute("disabled", "true");
|
|
}
|
|
buttonNode.addEventListener("command", event => {
|
|
button.onCommand(event, buttonNode);
|
|
});
|
|
bodyNode.appendChild(buttonNode);
|
|
}
|
|
return panelViewNode;
|
|
},
|
|
|
|
_toggleTempPanelForAction(action) {
|
|
let panelNodeID = this._tempPanelID;
|
|
let panelNode = document.getElementById(panelNodeID);
|
|
if (panelNode) {
|
|
panelNode.hidePopup();
|
|
return;
|
|
}
|
|
|
|
panelNode = document.createElement("panel");
|
|
panelNode.id = panelNodeID;
|
|
panelNode.classList.add("cui-widget-panel");
|
|
panelNode.setAttribute("role", "group");
|
|
panelNode.setAttribute("type", "arrow");
|
|
panelNode.setAttribute("flip", "slide");
|
|
panelNode.setAttribute("noautofocus", "true");
|
|
panelNode.setAttribute("tabspecific", "true");
|
|
|
|
let panelViewNode = null;
|
|
let iframeNode = null;
|
|
|
|
if (action.subview) {
|
|
let multiViewNode = document.createElement("photonpanelmultiview");
|
|
panelViewNode = this._makePanelViewNodeForAction(action, true);
|
|
multiViewNode.appendChild(panelViewNode);
|
|
panelNode.appendChild(multiViewNode);
|
|
} else if (action.wantsIframe) {
|
|
iframeNode = document.createElement("iframe");
|
|
iframeNode.setAttribute("type", "content");
|
|
panelNode.appendChild(iframeNode);
|
|
}
|
|
|
|
let popupSet = document.getElementById("mainPopupSet");
|
|
popupSet.appendChild(panelNode);
|
|
panelNode.addEventListener("popuphidden", () => {
|
|
panelNode.remove();
|
|
}, { once: true });
|
|
|
|
if (panelViewNode) {
|
|
action.subview.onPlaced(panelViewNode);
|
|
action.subview.onShowing(panelViewNode);
|
|
}
|
|
|
|
this.panelNode.hidePopup();
|
|
|
|
let urlbarNodeID = this._urlbarButtonNodeIDForActionID(action.id);
|
|
let anchorNode =
|
|
document.getElementById(urlbarNodeID) || this.mainButtonNode;
|
|
panelNode.openPopup(anchorNode, "bottomcenter topright");
|
|
|
|
if (iframeNode) {
|
|
action.onIframeShown(iframeNode, panelNode);
|
|
}
|
|
},
|
|
|
|
get _tempPanelID() {
|
|
return "pageActionTempPanel";
|
|
},
|
|
|
|
/**
|
|
* Adds or removes as necessary a DOM node for the given action in the urlbar.
|
|
*
|
|
* @param action (PageActions.Action, required)
|
|
* The action to place.
|
|
* @param insertBeforeID (string, required)
|
|
* If the action is shown in the urlbar, then this is ID of the action
|
|
* in the urlbar before which the given action should be inserted.
|
|
*/
|
|
placeActionInUrlbar(action, insertBeforeID) {
|
|
let id = this._urlbarButtonNodeIDForActionID(action.id);
|
|
let node = document.getElementById(id);
|
|
|
|
if (!action.shownInUrlbar) {
|
|
if (node) {
|
|
if (action.__urlbarNodeInMarkup) {
|
|
node.hidden = true;
|
|
} else {
|
|
node.remove();
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
let newlyPlaced = false;
|
|
if (action.__urlbarNodeInMarkup) {
|
|
newlyPlaced = node && node.hidden;
|
|
node.hidden = false;
|
|
} else if (!node) {
|
|
newlyPlaced = true;
|
|
node = this._makeUrlbarButtonNode(action);
|
|
node.id = id;
|
|
}
|
|
|
|
if (newlyPlaced) {
|
|
let parentNode = this.mainButtonNode.parentNode;
|
|
let insertBeforeNode = null;
|
|
if (insertBeforeID) {
|
|
let insertBeforeNodeID =
|
|
this._urlbarButtonNodeIDForActionID(insertBeforeID);
|
|
insertBeforeNode = document.getElementById(insertBeforeNodeID);
|
|
}
|
|
parentNode.insertBefore(node, insertBeforeNode);
|
|
action.onPlacedInUrlbar(node);
|
|
|
|
// urlbar buttons should always have tooltips, so if the node doesn't have
|
|
// one, then as a last resort use the label of the corresponding panel
|
|
// button. Why not set tooltiptext to action.title when the node is
|
|
// created? Because the consumer may set a title dynamically.
|
|
if (!node.hasAttribute("tooltiptext")) {
|
|
let panelNodeID = this._panelButtonNodeIDForActionID(action.id);
|
|
let panelNode = document.getElementById(panelNodeID);
|
|
if (panelNode) {
|
|
node.setAttribute("tooltiptext", panelNode.getAttribute("label"));
|
|
}
|
|
}
|
|
}
|
|
|
|
return node;
|
|
},
|
|
|
|
_makeUrlbarButtonNode(action) {
|
|
let buttonNode = document.createElement("image");
|
|
buttonNode.classList.add("urlbar-icon");
|
|
if (action.tooltip) {
|
|
buttonNode.setAttribute("tooltiptext", action.tooltip);
|
|
}
|
|
if (action.iconURL) {
|
|
buttonNode.style.listStyleImage = `url('${action.iconURL}')`;
|
|
}
|
|
buttonNode.setAttribute("context", "pageActionPanelContextMenu");
|
|
buttonNode.addEventListener("contextmenu", event => {
|
|
BrowserPageActions.onContextMenu(event);
|
|
});
|
|
if (action.nodeAttributes) {
|
|
for (let name in action.nodeAttributes) {
|
|
buttonNode.setAttribute(name, action.nodeAttributes[name]);
|
|
}
|
|
}
|
|
buttonNode.addEventListener("click", event => {
|
|
if (event.button != 0) {
|
|
return;
|
|
}
|
|
if (action.subview || action.wantsIframe) {
|
|
this._toggleTempPanelForAction(action);
|
|
return;
|
|
}
|
|
action.onCommand(event, buttonNode);
|
|
});
|
|
return buttonNode;
|
|
},
|
|
|
|
_appendPanelSeparator(action) {
|
|
let node = document.createElement("toolbarseparator");
|
|
node.id = this._panelButtonNodeIDForActionID(action.id);
|
|
this.mainViewBodyNode.appendChild(node);
|
|
},
|
|
|
|
/**
|
|
* Removes all the DOM nodes of the given action.
|
|
*
|
|
* @param action (PageActions.Action, required)
|
|
* The action to remove.
|
|
*/
|
|
removeAction(action) {
|
|
this._removeActionFromPanel(action);
|
|
this._removeActionFromUrlbar(action);
|
|
},
|
|
|
|
_removeActionFromPanel(action) {
|
|
let id = this._panelButtonNodeIDForActionID(action.id);
|
|
let node = document.getElementById(id);
|
|
if (node) {
|
|
node.remove();
|
|
}
|
|
if (action.subview) {
|
|
let panelViewNodeID = this._panelViewNodeIDForActionID(action.id, false);
|
|
let panelViewNode = document.getElementById(panelViewNodeID);
|
|
if (panelViewNode) {
|
|
panelViewNode.remove();
|
|
}
|
|
}
|
|
// If there are now no more non-built-in actions, remove the separator
|
|
// between the built-ins and non-built-ins.
|
|
if (!PageActions.nonBuiltInActions.length) {
|
|
let separator = document.getElementById(
|
|
this._panelButtonNodeIDForActionID(
|
|
PageActions.ACTION_ID_BUILT_IN_SEPARATOR
|
|
)
|
|
);
|
|
if (separator) {
|
|
separator.remove();
|
|
}
|
|
}
|
|
},
|
|
|
|
_removeActionFromUrlbar(action) {
|
|
let id = this._urlbarButtonNodeIDForActionID(action.id);
|
|
let node = document.getElementById(id);
|
|
if (node) {
|
|
node.remove();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Updates the DOM nodes of an action to reflect its changed iconURL.
|
|
*
|
|
* @param action (PageActions.Action, required)
|
|
* The action to update.
|
|
*/
|
|
updateActionIconURL(action) {
|
|
let url = action.iconURL ? `url('${action.iconURL}')` : null;
|
|
let nodeIDs = [
|
|
this._panelButtonNodeIDForActionID(action.id),
|
|
this._urlbarButtonNodeIDForActionID(action.id),
|
|
];
|
|
for (let nodeID of nodeIDs) {
|
|
let node = document.getElementById(nodeID);
|
|
if (node) {
|
|
if (url) {
|
|
node.style.listStyleImage = url;
|
|
} else {
|
|
node.style.removeProperty("list-style-image");
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Updates the DOM nodes of an action to reflect its changed title.
|
|
*
|
|
* @param action (PageActions.Action, required)
|
|
* The action to update.
|
|
*/
|
|
updateActionTitle(action) {
|
|
let id = this._panelButtonNodeIDForActionID(action.id);
|
|
let node = document.getElementById(id);
|
|
if (node) {
|
|
node.setAttribute("label", action.title);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Returns the action for a node.
|
|
*
|
|
* @param node (DOM node, required)
|
|
* A button DOM node, either one that's shown in the page action panel
|
|
* or the urlbar.
|
|
* @return (PageAction.Action) The node's related action, or null if none.
|
|
*/
|
|
actionForNode(node) {
|
|
if (!node) {
|
|
return null;
|
|
}
|
|
let actionID = this._actionIDForNodeID(node.id);
|
|
let action = PageActions.actionForID(actionID);
|
|
if (!action) {
|
|
// The given node may be an ancestor of a node corresponding to an action,
|
|
// like how #star-button is contained in #star-button-box, the latter
|
|
// being the bookmark action's node. Look up the ancestor chain.
|
|
for (let n = node.parentNode; n && !action; n = n.parentNode) {
|
|
if (n.id == "urlbar-icons" || n.localName == "panelview") {
|
|
// We reached the urlbar icons container or the panelview container.
|
|
// Stop looking; no acton was found.
|
|
break;
|
|
}
|
|
actionID = this._actionIDForNodeID(n.id);
|
|
action = PageActions.actionForID(actionID);
|
|
}
|
|
}
|
|
return action;
|
|
},
|
|
|
|
// The ID of the given action's top-level button in the panel.
|
|
_panelButtonNodeIDForActionID(actionID) {
|
|
return `pageAction-panel-${actionID}`;
|
|
},
|
|
|
|
// The ID of the given action's button in the urlbar.
|
|
_urlbarButtonNodeIDForActionID(actionID) {
|
|
let action = PageActions.actionForID(actionID);
|
|
if (action && action.urlbarIDOverride) {
|
|
return action.urlbarIDOverride;
|
|
}
|
|
return `pageAction-urlbar-${actionID}`;
|
|
},
|
|
|
|
// The ID of the given action's panelview.
|
|
_panelViewNodeIDForActionID(actionID, forUrlbar) {
|
|
let placementID = forUrlbar ? "urlbar" : "panel";
|
|
return `pageAction-${placementID}-${actionID}-subview`;
|
|
},
|
|
|
|
// The ID of the given button in the given action's panelview.
|
|
_panelViewButtonNodeIDForActionID(actionID, buttonID, forUrlbar) {
|
|
let placementID = forUrlbar ? "urlbar" : "panel";
|
|
return `pageAction-${placementID}-${actionID}-${buttonID}`;
|
|
},
|
|
|
|
// The ID of the action corresponding to the given top-level button in the
|
|
// panel or button in the urlbar.
|
|
_actionIDForNodeID(nodeID) {
|
|
if (!nodeID) {
|
|
return null;
|
|
}
|
|
let match = nodeID.match(/^pageAction-(?:panel|urlbar)-(.+)$/);
|
|
if (match) {
|
|
return match[1];
|
|
}
|
|
// Check all the urlbar ID overrides.
|
|
for (let action of PageActions.actions) {
|
|
if (action.urlbarIDOverride && action.urlbarIDOverride == nodeID) {
|
|
return action.id;
|
|
}
|
|
}
|
|
return null;
|
|
},
|
|
|
|
/**
|
|
* Call this when the main page action button in the urlbar is activated.
|
|
*
|
|
* @param event (DOM event, required)
|
|
* The click or whatever event.
|
|
*/
|
|
mainButtonClicked(event) {
|
|
event.stopPropagation();
|
|
if ((event.type == "click" && event.button != 0) ||
|
|
(event.type == "keypress" && event.charCode != KeyEvent.DOM_VK_SPACE &&
|
|
event.keyCode != KeyEvent.DOM_VK_RETURN)) {
|
|
return;
|
|
}
|
|
|
|
// If the temp panel is open and anchored to the main button, close it.
|
|
let tempPanel = document.getElementById(this._tempPanelID);
|
|
if (tempPanel && tempPanel.anchorNode.id == this.mainButtonNode.id) {
|
|
tempPanel.hidePopup();
|
|
return;
|
|
}
|
|
|
|
if (this.panelNode.state == "open") {
|
|
this.panelNode.hidePopup();
|
|
} else if (this.panelNode.state == "closed") {
|
|
this.showPanel(event);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Show the page action panel
|
|
*
|
|
* @param event (DOM event, optional)
|
|
* The event that triggers showing the panel. (such as a mouse click,
|
|
* if the user clicked something to open the panel)
|
|
*/
|
|
showPanel(event = null) {
|
|
for (let action of PageActions.actions) {
|
|
let buttonNodeID = this._panelButtonNodeIDForActionID(action.id);
|
|
let buttonNode = document.getElementById(buttonNodeID);
|
|
action.onShowingInPanel(buttonNode);
|
|
}
|
|
|
|
this.panelNode.hidden = false;
|
|
this.panelNode.openPopup(this.mainButtonNode, {
|
|
position: "bottomcenter topright",
|
|
triggerEvent: event,
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Call this on the contextmenu event. Note that this is called before
|
|
* onContextMenuShowing.
|
|
*
|
|
* @param event (DOM event, required)
|
|
* The contextmenu event.
|
|
*/
|
|
onContextMenu(event) {
|
|
let node = event.originalTarget;
|
|
this._contextAction = this.actionForNode(node);
|
|
},
|
|
|
|
/**
|
|
* Call this on the context menu's popupshowing event.
|
|
*
|
|
* @param event (DOM event, required)
|
|
* The popupshowing event.
|
|
* @param popup (DOM node, required)
|
|
* The context menu popup DOM node.
|
|
*/
|
|
onContextMenuShowing(event, popup) {
|
|
if (event.target != popup) {
|
|
return;
|
|
}
|
|
// Right now there's only one item in the context menu, to toggle the
|
|
// context action's shown-in-urlbar state. Update it now.
|
|
let toggleItem = popup.firstChild;
|
|
let toggleItemLabel = null;
|
|
if (this._contextAction) {
|
|
toggleItem.disabled = false;
|
|
if (this._contextAction.shownInUrlbar) {
|
|
toggleItemLabel = toggleItem.getAttribute("remove-label");
|
|
}
|
|
}
|
|
if (!toggleItemLabel) {
|
|
toggleItemLabel = toggleItem.getAttribute("add-label");
|
|
}
|
|
toggleItem.label = toggleItemLabel;
|
|
},
|
|
|
|
/**
|
|
* Call this from the context menu's toggle menu item.
|
|
*/
|
|
toggleShownInUrlbarForContextAction() {
|
|
if (!this._contextAction) {
|
|
return;
|
|
}
|
|
this._contextAction.shownInUrlbar = !this._contextAction.shownInUrlbar;
|
|
},
|
|
|
|
_contextAction: null,
|
|
|
|
/**
|
|
* A bunch of strings (labels for actions and the like) are defined in DTD,
|
|
* but actions are created in JS. So what we do is add a bunch of attributes
|
|
* to the page action panel's definition in the markup, whose values hold
|
|
* these DTD strings. Then when each built-in action is set up, we get the
|
|
* related strings from the panel node and set up the action's node with them.
|
|
*
|
|
* The convention is to set for example the "title" property in an action's JS
|
|
* definition to the name of the attribute on the panel node that holds the
|
|
* actual title string. Then call this function, passing the action's related
|
|
* DOM node and the name of the attribute that you are setting on the DOM
|
|
* node -- "label" or "title" in this example (either will do).
|
|
*
|
|
* @param node (DOM node, required)
|
|
* The node of an action you're setting up.
|
|
* @param attrName (string, required)
|
|
* The name of the attribute *on the node you're setting up*.
|
|
*/
|
|
takeNodeAttributeFromPanel(node, attrName) {
|
|
let panelAttrName = node.getAttribute(attrName);
|
|
if (!panelAttrName && attrName == "title") {
|
|
attrName = "label";
|
|
panelAttrName = node.getAttribute(attrName);
|
|
}
|
|
if (panelAttrName) {
|
|
let attrValue = this.panelNode.getAttribute(panelAttrName);
|
|
if (attrValue) {
|
|
node.setAttribute(attrName, attrValue);
|
|
}
|
|
}
|
|
},
|
|
};
|
|
|
|
|
|
// built-in actions below //////////////////////////////////////////////////////
|
|
|
|
// bookmark
|
|
BrowserPageActions.bookmark = {
|
|
onShowingInPanel(buttonNode) {
|
|
// Update the button label via the bookmark observer.
|
|
BookmarkingUI.updateBookmarkPageMenuItem();
|
|
},
|
|
|
|
onCommand(event, buttonNode) {
|
|
BrowserPageActions.panelNode.hidePopup();
|
|
BookmarkingUI.onStarCommand(event);
|
|
},
|
|
|
|
onUrlbarNodeClicked(event) {
|
|
if (event.type == "click" && event.button != 0) {
|
|
return;
|
|
}
|
|
BookmarkingUI.onStarCommand(event);
|
|
},
|
|
};
|
|
|
|
// copy URL
|
|
BrowserPageActions.copyURL = {
|
|
onPlacedInPanel(buttonNode) {
|
|
BrowserPageActions.takeNodeAttributeFromPanel(buttonNode, "title");
|
|
},
|
|
|
|
onCommand(event, buttonNode) {
|
|
BrowserPageActions.panelNode.hidePopup();
|
|
Cc["@mozilla.org/widget/clipboardhelper;1"]
|
|
.getService(Ci.nsIClipboardHelper)
|
|
.copyString(gBrowser.selectedBrowser.currentURI.spec);
|
|
},
|
|
};
|
|
|
|
// email link
|
|
BrowserPageActions.emailLink = {
|
|
onPlacedInPanel(buttonNode) {
|
|
BrowserPageActions.takeNodeAttributeFromPanel(buttonNode, "title");
|
|
},
|
|
|
|
onCommand(event, buttonNode) {
|
|
BrowserPageActions.panelNode.hidePopup();
|
|
MailIntegration.sendLinkForBrowser(gBrowser.selectedBrowser);
|
|
},
|
|
};
|
|
|
|
// send to device
|
|
BrowserPageActions.sendToDevice = {
|
|
onPlacedInPanel(buttonNode) {
|
|
BrowserPageActions.takeNodeAttributeFromPanel(buttonNode, "title");
|
|
},
|
|
|
|
onSubviewPlaced(panelViewNode) {
|
|
let bodyNode = panelViewNode.firstChild;
|
|
for (let node of bodyNode.childNodes) {
|
|
BrowserPageActions.takeNodeAttributeFromPanel(node, "title");
|
|
BrowserPageActions.takeNodeAttributeFromPanel(node, "shortcut");
|
|
}
|
|
},
|
|
|
|
onShowingInPanel(buttonNode) {
|
|
let browser = gBrowser.selectedBrowser;
|
|
let url = browser.currentURI.spec;
|
|
if (gSync.isSendableURI(url)) {
|
|
buttonNode.removeAttribute("disabled");
|
|
} else {
|
|
buttonNode.setAttribute("disabled", "true");
|
|
}
|
|
},
|
|
|
|
onShowingSubview(panelViewNode) {
|
|
let browser = gBrowser.selectedBrowser;
|
|
let url = browser.currentURI.spec;
|
|
let title = browser.contentTitle;
|
|
|
|
let bodyNode = panelViewNode.firstChild;
|
|
|
|
// This is on top because it also clears the device list between state
|
|
// changes.
|
|
gSync.populateSendTabToDevicesMenu(bodyNode, url, title, (clientId, name, clientType) => {
|
|
if (!name) {
|
|
return document.createElement("toolbarseparator");
|
|
}
|
|
let item = document.createElement("toolbarbutton");
|
|
item.classList.add("pageAction-sendToDevice-device", "subviewbutton");
|
|
if (clientId) {
|
|
item.classList.add("subviewbutton-iconic");
|
|
}
|
|
item.setAttribute("tooltiptext", name);
|
|
return item;
|
|
});
|
|
|
|
bodyNode.removeAttribute("state");
|
|
// In the first ~10 sec after startup, Sync may not be loaded and the list
|
|
// of devices will be empty.
|
|
if (gSync.syncConfiguredAndLoading) {
|
|
bodyNode.setAttribute("state", "notready");
|
|
// Force a background Sync
|
|
Services.tm.dispatchToMainThread(async () => {
|
|
await Weave.Service.sync([]); // [] = clients engine only
|
|
// There's no way Sync is still syncing at this point, but we check
|
|
// anyway to avoid infinite looping.
|
|
if (!window.closed && !gSync.syncConfiguredAndLoading) {
|
|
this.onShowingSubview(panelViewNode);
|
|
}
|
|
});
|
|
}
|
|
},
|
|
};
|