Merge fx-team to m-c a=merge
@ -1593,15 +1593,6 @@ pref("services.push.serverURL", "wss://push.services.mozilla.com/");
|
||||
|
||||
pref("social.sidebar.unload_timeout_ms", 10000);
|
||||
|
||||
// activation from inside of share panel is possible if activationPanelEnabled
|
||||
// is true. Pref'd off for release while usage testing is done through beta.
|
||||
#ifdef RELEASE_BUILD
|
||||
pref("social.share.activationPanelEnabled", false);
|
||||
#else
|
||||
pref("social.share.activationPanelEnabled", true);
|
||||
#endif
|
||||
pref("social.shareDirectory", "https://activations.cdn.mozilla.net/en-US/sharePanel.html");
|
||||
|
||||
pref("dom.identity.enabled", false);
|
||||
|
||||
// Block insecure active content on https pages
|
||||
|
@ -43,17 +43,12 @@
|
||||
|
||||
function parseQueryString() {
|
||||
let url = document.documentURI;
|
||||
var searchParams = new URLSearchParams(url);
|
||||
let queryString = url.replace(/^about:socialerror\??/, "");
|
||||
|
||||
let mode = searchParams.get("mode");
|
||||
config.directory = searchParams.get("directory");
|
||||
config.origin = searchParams.get("origin");
|
||||
let encodedURL = searchParams.get("url");
|
||||
let url = decodeURIComponent(encodedURL);
|
||||
if (config.directory) {
|
||||
let URI = Services.io.newURI(url, null, null);
|
||||
config.origin = Services.scriptSecurityManager.getNoAppCodebasePrincipal(URI).origin;
|
||||
}
|
||||
let modeMatch = queryString.match(/mode=([^&]+)/);
|
||||
let mode = modeMatch && modeMatch[1] ? modeMatch[1] : "";
|
||||
let originMatch = queryString.match(/origin=([^&]+)/);
|
||||
config.origin = originMatch && originMatch[1] ? decodeURIComponent(originMatch[1]) : "";
|
||||
|
||||
switch (mode) {
|
||||
case "compactInfo":
|
||||
@ -64,6 +59,10 @@
|
||||
document.getElementById("btnCloseSidebar").style.display = 'none';
|
||||
//intentional fall-through
|
||||
case "tryAgain":
|
||||
let urlMatch = queryString.match(/url=([^&]+)/);
|
||||
let encodedURL = urlMatch && urlMatch[1] ? urlMatch[1] : "";
|
||||
let url = decodeURIComponent(encodedURL);
|
||||
|
||||
config.tryAgainCallback = loadQueryURL;
|
||||
config.queryURL = url;
|
||||
break;
|
||||
@ -81,7 +80,7 @@
|
||||
|
||||
let productName = brandBundle.GetStringFromName("brandShortName");
|
||||
let provider = Social._getProviderFromOrigin(config.origin);
|
||||
let providerName = provider ? provider.name : config.origin;
|
||||
let providerName = provider && provider.name;
|
||||
|
||||
// Sets up the error message
|
||||
let msg = browserBundle.formatStringFromName("social.error.message", [productName, providerName], 2);
|
||||
|
@ -27,7 +27,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "PanelFrame", "resource:///modules/Panel
|
||||
}, true);
|
||||
};
|
||||
|
||||
PanelFrame.showPopup(window, PanelUI, event.target, "loop", null,
|
||||
PanelFrame.showPopup(window, event.target, "loop", null,
|
||||
"about:looppanel", null, callback);
|
||||
},
|
||||
|
||||
|
@ -119,7 +119,7 @@
|
||||
#endif
|
||||
<command id="History:UndoCloseTab" oncommand="undoCloseTab();"/>
|
||||
<command id="History:UndoCloseWindow" oncommand="undoCloseWindow();"/>
|
||||
<command id="Social:SharePage" oncommand="SocialShare.sharePage();"/>
|
||||
<command id="Social:SharePage" oncommand="SocialShare.sharePage();" disabled="true"/>
|
||||
<command id="Social:ToggleSidebar" oncommand="SocialSidebar.toggleSidebar();" hidden="true"/>
|
||||
<command id="Social:ToggleNotifications" oncommand="Social.toggleNotifications();" hidden="true"/>
|
||||
<command id="Social:Addons" oncommand="BrowserOpenAddonsMgr('addons://list/service');"/>
|
||||
|
@ -68,7 +68,7 @@ SocialUI = {
|
||||
Services.prefs.addObserver("social.toast-notifications.enabled", this, false);
|
||||
|
||||
gBrowser.addEventListener("ActivateSocialFeature", this._activationEventHandler.bind(this), true, true);
|
||||
PanelUI.panel.addEventListener("popupshown", SocialUI.updateState, true);
|
||||
PanelUI.panel.addEventListener("popupshown", SocialUI.updatePanelState, true);
|
||||
|
||||
// menupopups that list social providers. we only populate them when shown,
|
||||
// and if it has not been done already.
|
||||
@ -102,7 +102,7 @@ SocialUI = {
|
||||
|
||||
Services.prefs.removeObserver("social.toast-notifications.enabled", this);
|
||||
|
||||
PanelUI.panel.removeEventListener("popupshown", SocialUI.updateState, true);
|
||||
PanelUI.panel.removeEventListener("popupshown", SocialUI.updatePanelState, true);
|
||||
document.getElementById("viewSidebarMenu").removeEventListener("popupshowing", SocialSidebar.populateSidebarMenu, true);
|
||||
document.getElementById("social-statusarea-popup").removeEventListener("popupshowing", SocialSidebar.populateSidebarMenu, true);
|
||||
|
||||
@ -183,7 +183,7 @@ SocialUI = {
|
||||
// about:home or the share panel, we bypass the enable prompt. Any website
|
||||
// activation, such as from the activations directory or a providers website
|
||||
// will still get the prompt.
|
||||
_activationEventHandler: function SocialUI_activationHandler(e, options={}) {
|
||||
_activationEventHandler: function SocialUI_activationHandler(e, aBypassUserEnable=false) {
|
||||
let targetDoc;
|
||||
let node;
|
||||
if (e.target instanceof HTMLDocument) {
|
||||
@ -197,9 +197,7 @@ SocialUI = {
|
||||
if (!(targetDoc instanceof HTMLDocument))
|
||||
return;
|
||||
|
||||
// The share panel iframe will not match "content" so it passes a bypass
|
||||
// flag
|
||||
if (!options.bypassContentCheck && targetDoc.defaultView != content)
|
||||
if (!aBypassUserEnable && targetDoc.defaultView != content)
|
||||
return;
|
||||
|
||||
// If we are in PB mode, we silently do nothing (bug 829404 exists to
|
||||
@ -235,25 +233,11 @@ SocialUI = {
|
||||
if (provider.sidebarURL) {
|
||||
SocialSidebar.show(provider.origin);
|
||||
}
|
||||
if (provider.shareURL) {
|
||||
// make this new provider the selected provider. If the panel hasn't
|
||||
// been opened, we need to make the frame first.
|
||||
SocialShare._createFrame();
|
||||
SocialShare.iframe.setAttribute('src', 'data:text/plain;charset=utf8,');
|
||||
SocialShare.iframe.setAttribute('origin', provider.origin);
|
||||
// get the right button selected
|
||||
SocialShare.populateProviderMenu();
|
||||
if (SocialShare.panel.state == "open") {
|
||||
SocialShare.sharePage(provider.origin);
|
||||
}
|
||||
}
|
||||
if (provider.postActivationURL) {
|
||||
// if activated from an open share panel, we load the landing page in
|
||||
// a background tab
|
||||
gBrowser.loadOneTab(provider.postActivationURL, {inBackground: SocialShare.panel.state == "open"});
|
||||
openUILinkIn(provider.postActivationURL, "tab");
|
||||
}
|
||||
});
|
||||
}, options);
|
||||
}, aBypassUserEnable);
|
||||
},
|
||||
|
||||
showLearnMore: function() {
|
||||
@ -303,13 +287,21 @@ SocialUI = {
|
||||
return Social.providers.length > 0;
|
||||
},
|
||||
|
||||
updatePanelState :function(event) {
|
||||
// we only want to update when the panel is initially opened, not during
|
||||
// multiview changes
|
||||
if (event.target != PanelUI.panel)
|
||||
return;
|
||||
SocialUI.updateState();
|
||||
},
|
||||
|
||||
// called on tab/urlbar/location changes and after customization. Update
|
||||
// anything that is tab specific.
|
||||
updateState: function() {
|
||||
SocialShare.update();
|
||||
if (!SocialUI.enabled)
|
||||
return;
|
||||
SocialMarks.update();
|
||||
SocialShare.update();
|
||||
}
|
||||
}
|
||||
|
||||
@ -450,12 +442,6 @@ SocialFlyout = {
|
||||
}
|
||||
|
||||
SocialShare = {
|
||||
get _dynamicResizer() {
|
||||
delete this._dynamicResizer;
|
||||
this._dynamicResizer = new DynamicResizeWatcher();
|
||||
return this._dynamicResizer;
|
||||
},
|
||||
|
||||
// Share panel may be attached to the overflow or menu button depending on
|
||||
// customization, we need to manage open state of the anchor.
|
||||
get anchor() {
|
||||
@ -474,27 +460,15 @@ SocialShare = {
|
||||
return this.panel.lastChild;
|
||||
},
|
||||
|
||||
get activationPanelEnabled () {
|
||||
// ability to pref off for release
|
||||
return Services.prefs.getBoolPref("social.share.activationPanelEnabled");
|
||||
},
|
||||
|
||||
_activationHandler: function(event) {
|
||||
if (!SocialShare.activationPanelEnabled)
|
||||
return;
|
||||
SocialUI._activationEventHandler(event, { bypassContentCheck: true, bypassInstallPanel: true });
|
||||
},
|
||||
|
||||
uninit: function () {
|
||||
if (this.iframe) {
|
||||
this.iframe.removeEventListener("ActivateSocialFeature", this._activationHandler, true, true);
|
||||
this.iframe.remove();
|
||||
}
|
||||
},
|
||||
|
||||
_createFrame: function() {
|
||||
let panel = this.panel;
|
||||
if (this.iframe)
|
||||
if (!SocialUI.enabled || this.iframe)
|
||||
return;
|
||||
this.panel.hidden = false;
|
||||
// create and initialize the panel for this window
|
||||
@ -506,7 +480,6 @@ SocialShare = {
|
||||
iframe.setAttribute("disableglobalhistory", "true");
|
||||
iframe.setAttribute("flex", "1");
|
||||
panel.appendChild(iframe);
|
||||
this.iframe.addEventListener("ActivateSocialFeature", this._activationHandler, true, true);
|
||||
this.populateProviderMenu();
|
||||
},
|
||||
|
||||
@ -516,19 +489,11 @@ SocialShare = {
|
||||
if (lastProviderOrigin) {
|
||||
provider = Social._getProviderFromOrigin(lastProviderOrigin);
|
||||
}
|
||||
// if we are able to activate a provider we don't need to do anything fancy
|
||||
// here, the user will land on the activation panel if no previously
|
||||
// selected provider is available.
|
||||
if (this.activationPanelEnabled)
|
||||
return provider;
|
||||
|
||||
// if they have a provider selected in the sidebar use that for the initial
|
||||
// default in share
|
||||
if (!provider)
|
||||
provider = SocialSidebar.provider;
|
||||
// if our provider has no shareURL, select the first one that does. If we
|
||||
// have no selected provider and activation is available, default to that
|
||||
// panel.
|
||||
// if our provider has no shareURL, select the first one that does
|
||||
if (!provider || !provider.shareURL) {
|
||||
let providers = [p for (p of Social.providers) if (p.shareURL)];
|
||||
provider = providers.length > 0 && providers[0];
|
||||
@ -541,12 +506,17 @@ SocialShare = {
|
||||
return;
|
||||
let providers = [p for (p of Social.providers) if (p.shareURL)];
|
||||
let hbox = document.getElementById("social-share-provider-buttons");
|
||||
// remove everything before the add-share-provider button (which should also
|
||||
// be lastChild if any share providers were added)
|
||||
let addButton = document.getElementById("add-share-provider");
|
||||
while (hbox.firstChild != addButton) {
|
||||
// selectable providers are inserted before the provider-menu seperator,
|
||||
// remove any menuitems in that area
|
||||
while (hbox.firstChild) {
|
||||
hbox.removeChild(hbox.firstChild);
|
||||
}
|
||||
// reset our share toolbar
|
||||
// only show a selection if there is more than one
|
||||
if (!SocialUI.enabled || providers.length < 2) {
|
||||
this.panel.firstChild.hidden = true;
|
||||
return;
|
||||
}
|
||||
let selectedProvider = this.getSelectedProvider();
|
||||
for (let provider of providers) {
|
||||
let button = document.createElement("toolbarbutton");
|
||||
@ -556,16 +526,17 @@ SocialShare = {
|
||||
button.setAttribute("image", provider.iconURL);
|
||||
button.setAttribute("tooltiptext", provider.name);
|
||||
button.setAttribute("origin", provider.origin);
|
||||
button.setAttribute("oncommand", "SocialShare.sharePage(this.getAttribute('origin'));");
|
||||
button.setAttribute("oncommand", "SocialShare.sharePage(this.getAttribute('origin')); this.checked=true;");
|
||||
if (provider == selectedProvider) {
|
||||
this.defaultButton = button;
|
||||
}
|
||||
hbox.insertBefore(button, addButton);
|
||||
hbox.appendChild(button);
|
||||
}
|
||||
if (!this.defaultButton) {
|
||||
this.defaultButton = this.activationPanelEnabled ? addButton : hbox.firstChild;
|
||||
this.defaultButton = hbox.firstChild
|
||||
}
|
||||
this.defaultButton.setAttribute("checked", "true");
|
||||
this.panel.firstChild.hidden = false;
|
||||
},
|
||||
|
||||
get shareButton() {
|
||||
@ -597,8 +568,8 @@ SocialShare = {
|
||||
let shareButton = widget.forWindow(window).node;
|
||||
// hidden state is based on available share providers and location of
|
||||
// button. It's always visible and disabled in the customization palette.
|
||||
shareButton.hidden = !this.activationPanelEnabled && (!SocialUI.enabled || (widget.areaType &&
|
||||
[p for (p of Social.providers) if (p.shareURL)].length == 0));
|
||||
shareButton.hidden = !SocialUI.enabled || (widget.areaType &&
|
||||
[p for (p of Social.providers) if (p.shareURL)].length == 0);
|
||||
let disabled = !widget.areaType || shareButton.hidden || !this.canSharePage(gBrowser.currentURI);
|
||||
|
||||
// 1. update the relevent command's disabled state so the keyboard
|
||||
@ -614,9 +585,6 @@ SocialShare = {
|
||||
cmd.removeAttribute("disabled");
|
||||
shareButton.removeAttribute("disabled");
|
||||
}
|
||||
|
||||
// enable or disable the activation panel
|
||||
document.getElementById("add-share-provider").hidden = !this.activationPanelEnabled;
|
||||
},
|
||||
|
||||
_onclick: function() {
|
||||
@ -648,15 +616,10 @@ SocialShare = {
|
||||
if (!iframe)
|
||||
return;
|
||||
|
||||
let url;
|
||||
let origin = iframe.getAttribute("origin");
|
||||
if (!origin && this.activationPanelEnabled) {
|
||||
// directory site is down
|
||||
url = "about:socialerror?mode=tryAgainOnly&directory=1&url=" + encodeURIComponent(iframe.getAttribute("src"));
|
||||
} else {
|
||||
url = "about:socialerror?mode=compactInfo&origin=" + encodeURIComponent(origin);
|
||||
}
|
||||
iframe.webNavigation.loadURI(url, null, null, null, null);
|
||||
iframe.removeAttribute("src");
|
||||
iframe.webNavigation.loadURI("about:socialerror?mode=compactInfo&origin=" +
|
||||
encodeURIComponent(iframe.getAttribute("origin")),
|
||||
null, null, null, null);
|
||||
sizeSocialPanelToContent(this.panel, iframe);
|
||||
},
|
||||
|
||||
@ -666,6 +629,13 @@ SocialShare = {
|
||||
// will call sharePage with an origin for us to switch to.
|
||||
this._createFrame();
|
||||
let iframe = this.iframe;
|
||||
let provider;
|
||||
if (providerOrigin)
|
||||
provider = Social._getProviderFromOrigin(providerOrigin);
|
||||
else
|
||||
provider = this.getSelectedProvider();
|
||||
if (!provider || !provider.shareURL)
|
||||
return;
|
||||
|
||||
// graphData is an optional param that either defines the full set of data
|
||||
// to be shared, or partial data about the current page. It is set by a call
|
||||
@ -697,25 +667,20 @@ SocialShare = {
|
||||
}
|
||||
this.currentShare = pageData;
|
||||
|
||||
let provider;
|
||||
if (providerOrigin)
|
||||
provider = Social._getProviderFromOrigin(providerOrigin);
|
||||
else
|
||||
provider = this.getSelectedProvider();
|
||||
if (!provider || !provider.shareURL) {
|
||||
this.showDirectory();
|
||||
return;
|
||||
}
|
||||
// check the menu button
|
||||
let hbox = document.getElementById("social-share-provider-buttons");
|
||||
let btn = hbox.querySelector("[origin='" + provider.origin + "']");
|
||||
btn.checked = true;
|
||||
|
||||
let shareEndpoint = OpenGraphBuilder.generateEndpointURL(provider.shareURL, pageData);
|
||||
|
||||
let size = provider.getPageSize("share");
|
||||
if (size) {
|
||||
this._dynamicResizer.stop();
|
||||
if (this._dynamicResizer) {
|
||||
this._dynamicResizer.stop();
|
||||
this._dynamicResizer = null;
|
||||
}
|
||||
let {width, height} = size;
|
||||
width += this.panel.boxObject.width - iframe.boxObject.width;
|
||||
height += this.panel.boxObject.height - iframe.boxObject.height;
|
||||
this.panel.sizeTo(width, height);
|
||||
} else {
|
||||
this._dynamicResizer = new DynamicResizeWatcher();
|
||||
}
|
||||
|
||||
// if we've already loaded this provider/page share endpoint, we don't want
|
||||
@ -727,7 +692,7 @@ SocialShare = {
|
||||
reload = shareEndpoint != iframe.contentDocument.location.spec;
|
||||
}
|
||||
if (!reload) {
|
||||
if (!size)
|
||||
if (this._dynamicResizer)
|
||||
this._dynamicResizer.start(this.panel, iframe);
|
||||
iframe.docShell.isActive = true;
|
||||
iframe.docShell.isAppTab = true;
|
||||
@ -745,13 +710,7 @@ SocialShare = {
|
||||
// should close the window when done.
|
||||
iframe.contentWindow.opener = iframe.contentWindow;
|
||||
setTimeout(function() {
|
||||
if (size) {
|
||||
let panel = SocialShare.panel;
|
||||
let {width, height} = size;
|
||||
width += panel.boxObject.width - iframe.boxObject.width;
|
||||
height += panel.boxObject.height - iframe.boxObject.height;
|
||||
panel.sizeTo(width, height);
|
||||
} else {
|
||||
if (SocialShare._dynamicResizer) { // may go null if hidden quickly
|
||||
SocialShare._dynamicResizer.start(iframe.parentNode, iframe);
|
||||
}
|
||||
}, 0);
|
||||
@ -772,32 +731,10 @@ SocialShare = {
|
||||
let uri = Services.io.newURI(shareEndpoint, null, null);
|
||||
iframe.setAttribute("origin", provider.origin);
|
||||
iframe.setAttribute("src", shareEndpoint);
|
||||
this._openPanel();
|
||||
},
|
||||
|
||||
showDirectory: function() {
|
||||
let url = Services.prefs.getCharPref("social.shareDirectory");
|
||||
this._createFrame();
|
||||
let iframe = this.iframe;
|
||||
iframe.removeAttribute("origin");
|
||||
iframe.setAttribute("src", url);
|
||||
iframe.addEventListener("load", function panelBrowserOnload(e) {
|
||||
iframe.removeEventListener("load", panelBrowserOnload, true);
|
||||
SocialShare._dynamicResizer.start(iframe.parentNode, iframe);
|
||||
|
||||
iframe.addEventListener("unload", function panelBrowserOnload(e) {
|
||||
iframe.removeEventListener("unload", panelBrowserOnload, true);
|
||||
SocialShare._dynamicResizer.stop();
|
||||
}, true);
|
||||
|
||||
}, true);
|
||||
this._openPanel();
|
||||
},
|
||||
|
||||
_openPanel: function() {
|
||||
let anchor = document.getAnonymousElementByAttribute(this.anchor, "class", "toolbarbutton-icon");
|
||||
this.panel.openPopup(anchor, "bottomcenter topright", 0, 0, false, false);
|
||||
Social.setErrorListener(this.iframe, this.setErrorMessage.bind(this));
|
||||
Social.setErrorListener(iframe, this.setErrorMessage.bind(this));
|
||||
Services.telemetry.getHistogramById("SOCIAL_TOOLBAR_BUTTONS").add(0);
|
||||
}
|
||||
};
|
||||
@ -1345,7 +1282,7 @@ SocialStatus = {
|
||||
let origin = aToolbarButton.getAttribute("origin");
|
||||
let provider = Social._getProviderFromOrigin(origin);
|
||||
|
||||
PanelFrame.showPopup(window, PanelUI, aToolbarButton, "social", origin,
|
||||
PanelFrame.showPopup(window, aToolbarButton, "social", origin,
|
||||
provider.statusURL, provider.getPageSize("status"),
|
||||
(frame) => {
|
||||
frame.addEventListener("close", this._onclose, true);
|
||||
@ -1379,17 +1316,6 @@ SocialStatus = {
|
||||
*/
|
||||
SocialMarks = {
|
||||
update: function() {
|
||||
// signal each button to update itself
|
||||
let currentButtons = document.querySelectorAll('toolbarbutton[type="socialmark"]');
|
||||
for (let elt of currentButtons) {
|
||||
// make sure we can call update since the xbl is not completely bound if
|
||||
// the button is in overflow, until the button becomes visible.
|
||||
if (elt.update)
|
||||
elt.update();
|
||||
}
|
||||
},
|
||||
|
||||
updatePanelButtons: function() {
|
||||
// querySelectorAll does not work on the menu panel the panel, so we have to
|
||||
// do this the hard way.
|
||||
let providers = SocialMarks.getProviders();
|
||||
@ -1439,7 +1365,7 @@ SocialMarks = {
|
||||
for (let cfg of contextMenus) {
|
||||
this._populateContextPopup(cfg, providers);
|
||||
}
|
||||
this.updatePanelButtons();
|
||||
this.update();
|
||||
},
|
||||
|
||||
MENU_LIMIT: 3, // adjustable for testing
|
||||
|
@ -246,11 +246,7 @@
|
||||
onpopuphidden="SocialShare.onHidden()"
|
||||
hidden="true">
|
||||
<vbox class="social-share-toolbar">
|
||||
<arrowscrollbox id="social-share-provider-buttons" orient="vertical" flex="1">
|
||||
<toolbarbutton id="add-share-provider" class="toolbarbutton share-provider-button" type="radio"
|
||||
group="share-providers" tooltiptext="&findShareServices.label;"
|
||||
oncommand="SocialShare.showDirectory()"/>
|
||||
</arrowscrollbox>
|
||||
<arrowscrollbox id="social-share-provider-buttons" orient="vertical" flex="1"/>
|
||||
</vbox>
|
||||
</panel>
|
||||
|
||||
|
@ -221,14 +221,14 @@ let AboutHomeListener = {
|
||||
},
|
||||
|
||||
onPageHide: function(aEvent) {
|
||||
if (event.target.defaultView.frameElement) {
|
||||
if (aEvent.target.defaultView.frameElement) {
|
||||
return;
|
||||
}
|
||||
removeMessageListener("AboutHome:Update", this);
|
||||
removeEventListener("click", this, true);
|
||||
removeEventListener("pagehide", this, true);
|
||||
if (event.target.documentElement) {
|
||||
event.target.documentElement.removeAttribute("hasBrowserHandlers");
|
||||
if (aEvent.target.documentElement) {
|
||||
aEvent.target.documentElement.removeAttribute("hasBrowserHandlers");
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -334,7 +334,7 @@ nsContextMenu.prototype = {
|
||||
let shareEnabled = shareButton && !shareButton.disabled && !this.onSocial;
|
||||
let pageShare = shareEnabled && !(this.isContentSelected ||
|
||||
this.onTextInput || this.onLink || this.onImage ||
|
||||
this.onVideo || this.onAudio || this.onCanvas);
|
||||
this.onVideo || this.onAudio);
|
||||
this.showItem("context-sharepage", pageShare);
|
||||
this.showItem("context-shareselect", shareEnabled && this.isContentSelected);
|
||||
this.showItem("context-sharelink", shareEnabled && (this.onLink || this.onPlainTextLink) && !this.onMailtoLink);
|
||||
|
@ -776,16 +776,6 @@
|
||||
unifiedComplete.registerOpenPage(aLocation);
|
||||
this.mBrowser.registeredOpenURI = aLocation;
|
||||
}
|
||||
|
||||
// It's possible we've moved from a URL that we cannot load remotely
|
||||
// to one that we can. If so, switch to a remote browser. This will
|
||||
// cause us to re-enter this onLocationChange function, but next time,
|
||||
// updateBrowserRemotenessByURL will return false.
|
||||
if (gMultiProcessBrowser &&
|
||||
this.mTabBrowser.updateBrowserRemotenessByURL(this.mBrowser,
|
||||
aLocation.spec)) {
|
||||
this.mTabBrowser.loadURIWithFlags(aLocation.spec, aFlags);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.mBlank) {
|
||||
|
@ -89,7 +89,6 @@ function runTest(testNum) {
|
||||
},
|
||||
|
||||
function () {
|
||||
info("context menu for text");
|
||||
// Context menu for plain text
|
||||
plainTextItems = ["context-navigation", null,
|
||||
["context-back", false,
|
||||
@ -97,7 +96,6 @@ function runTest(testNum) {
|
||||
"context-reload", true,
|
||||
"context-bookmarkpage", true], null,
|
||||
"---", null,
|
||||
"context-sharepage", true,
|
||||
"context-savepage", true,
|
||||
"---", null,
|
||||
"context-viewbgimage", false,
|
||||
@ -112,7 +110,6 @@ function runTest(testNum) {
|
||||
},
|
||||
|
||||
function () {
|
||||
info("context menu for text link");
|
||||
// Context menu for text link
|
||||
if (perWindowPrivateBrowsing) {
|
||||
checkContextMenu(["context-openlinkintab", true,
|
||||
@ -120,7 +117,6 @@ function runTest(testNum) {
|
||||
"context-openlinkprivate", true,
|
||||
"---", null,
|
||||
"context-bookmarklink", true,
|
||||
"context-sharelink", true,
|
||||
"context-savelink", true,
|
||||
"context-copylink", true,
|
||||
"context-searchselect", true
|
||||
@ -130,7 +126,6 @@ function runTest(testNum) {
|
||||
"context-openlink", true,
|
||||
"---", null,
|
||||
"context-bookmarklink", true,
|
||||
"context-sharelink", true,
|
||||
"context-savelink", true,
|
||||
"context-copylink", true,
|
||||
"context-searchselect", true
|
||||
@ -141,7 +136,6 @@ function runTest(testNum) {
|
||||
},
|
||||
|
||||
function () {
|
||||
info("context menu for mailto link");
|
||||
// Context menu for text mailto-link
|
||||
checkContextMenu(["context-copyemail", true,
|
||||
"context-searchselect", true
|
||||
@ -151,14 +145,12 @@ function runTest(testNum) {
|
||||
},
|
||||
|
||||
function () {
|
||||
info("context menu for image");
|
||||
// Context menu for an image
|
||||
checkContextMenu(["context-viewimage", true,
|
||||
"context-copyimage-contents", true,
|
||||
"context-copyimage", true,
|
||||
"---", null,
|
||||
"context-saveimage", true,
|
||||
"context-shareimage", true,
|
||||
"context-sendimage", true,
|
||||
"context-setDesktopBackground", true,
|
||||
"context-viewimageinfo", true
|
||||
@ -168,7 +160,6 @@ function runTest(testNum) {
|
||||
},
|
||||
|
||||
function () {
|
||||
info("context menu for canvas");
|
||||
// Context menu for a canvas
|
||||
checkContextMenu(["context-viewimage", true,
|
||||
"context-saveimage", true,
|
||||
@ -179,7 +170,6 @@ function runTest(testNum) {
|
||||
},
|
||||
|
||||
function () {
|
||||
info("context menu for video_ok");
|
||||
// Context menu for a video (with a VALID media source)
|
||||
checkContextMenu(["context-media-play", true,
|
||||
"context-media-mute", true,
|
||||
@ -196,7 +186,6 @@ function runTest(testNum) {
|
||||
"context-copyvideourl", true,
|
||||
"---", null,
|
||||
"context-savevideo", true,
|
||||
"context-sharevideo", true,
|
||||
"context-video-saveimage", true,
|
||||
"context-sendvideo", true
|
||||
].concat(inspectItems));
|
||||
@ -205,7 +194,6 @@ function runTest(testNum) {
|
||||
},
|
||||
|
||||
function () {
|
||||
info("context menu for audio_in_video");
|
||||
// Context menu for a video (with an audio-only file)
|
||||
checkContextMenu(["context-media-play", true,
|
||||
"context-media-mute", true,
|
||||
@ -226,7 +214,6 @@ function runTest(testNum) {
|
||||
},
|
||||
|
||||
function () {
|
||||
info("context menu for video_bad");
|
||||
// Context menu for a video (with an INVALID media source)
|
||||
checkContextMenu(["context-media-play", false,
|
||||
"context-media-mute", false,
|
||||
@ -243,7 +230,6 @@ function runTest(testNum) {
|
||||
"context-copyvideourl", true,
|
||||
"---", null,
|
||||
"context-savevideo", true,
|
||||
"context-sharevideo", true,
|
||||
"context-video-saveimage", false,
|
||||
"context-sendvideo", true
|
||||
].concat(inspectItems));
|
||||
@ -252,7 +238,6 @@ function runTest(testNum) {
|
||||
},
|
||||
|
||||
function () {
|
||||
info("context menu for video_bad2");
|
||||
// Context menu for a video (with an INVALID media source)
|
||||
checkContextMenu(["context-media-play", false,
|
||||
"context-media-mute", false,
|
||||
@ -269,7 +254,6 @@ function runTest(testNum) {
|
||||
"context-copyvideourl", false,
|
||||
"---", null,
|
||||
"context-savevideo", false,
|
||||
"context-sharevideo", false,
|
||||
"context-video-saveimage", false,
|
||||
"context-sendvideo", false
|
||||
].concat(inspectItems));
|
||||
@ -278,7 +262,6 @@ function runTest(testNum) {
|
||||
},
|
||||
|
||||
function () {
|
||||
info("context menu for iframe");
|
||||
// Context menu for an iframe
|
||||
checkContextMenu(["context-navigation", null,
|
||||
["context-back", false,
|
||||
@ -286,7 +269,6 @@ function runTest(testNum) {
|
||||
"context-reload", true,
|
||||
"context-bookmarkpage", true], null,
|
||||
"---", null,
|
||||
"context-sharepage", true,
|
||||
"context-savepage", true,
|
||||
"---", null,
|
||||
"context-viewbgimage", false,
|
||||
@ -314,7 +296,6 @@ function runTest(testNum) {
|
||||
},
|
||||
|
||||
function () {
|
||||
info("context menu for video_in_iframe");
|
||||
// Context menu for a video in an iframe
|
||||
checkContextMenu(["context-media-play", true,
|
||||
"context-media-mute", true,
|
||||
@ -331,7 +312,6 @@ function runTest(testNum) {
|
||||
"context-copyvideourl", true,
|
||||
"---", null,
|
||||
"context-savevideo", true,
|
||||
"context-sharevideo", true,
|
||||
"context-video-saveimage", true,
|
||||
"context-sendvideo", true,
|
||||
"frame", null,
|
||||
@ -352,14 +332,12 @@ function runTest(testNum) {
|
||||
},
|
||||
|
||||
function () {
|
||||
info("context menu for image_in_iframe");
|
||||
// Context menu for an image in an iframe
|
||||
checkContextMenu(["context-viewimage", true,
|
||||
"context-copyimage-contents", true,
|
||||
"context-copyimage", true,
|
||||
"---", null,
|
||||
"context-saveimage", true,
|
||||
"context-shareimage", true,
|
||||
"context-sendimage", true,
|
||||
"context-setDesktopBackground", true,
|
||||
"context-viewimageinfo", true,
|
||||
@ -381,7 +359,6 @@ function runTest(testNum) {
|
||||
},
|
||||
|
||||
function () {
|
||||
info("context menu for textarea");
|
||||
// Context menu for textarea before spell check initialization finishes
|
||||
checkContextMenu(["context-undo", false,
|
||||
"---", null,
|
||||
@ -399,7 +376,6 @@ function runTest(testNum) {
|
||||
},
|
||||
|
||||
function () {
|
||||
info("context menu for textarea, wait for spell check");
|
||||
// Context menu for textarea after spell check initialization finishes
|
||||
checkContextMenu(["*chubbiness", true, // spelling suggestion
|
||||
"spell-add-to-dictionary", true,
|
||||
@ -425,7 +401,6 @@ function runTest(testNum) {
|
||||
},
|
||||
|
||||
function () {
|
||||
info("context menu for text");
|
||||
// Re-check context menu for plain text to make sure it hasn't changed
|
||||
checkContextMenu(plainTextItems);
|
||||
closeContextMenu();
|
||||
@ -433,7 +408,6 @@ function runTest(testNum) {
|
||||
},
|
||||
|
||||
function () {
|
||||
info("context menu for textarea after word added");
|
||||
// Context menu for textarea after a word has been added
|
||||
// to the dictionary
|
||||
checkContextMenu(["spell-undo-add-to-dictionary", true,
|
||||
@ -459,7 +433,6 @@ function runTest(testNum) {
|
||||
},
|
||||
|
||||
function () {
|
||||
info("context menu for contenteditable");
|
||||
// Context menu for contenteditable
|
||||
checkContextMenu(["spell-no-suggestions", false,
|
||||
"spell-add-to-dictionary", true,
|
||||
@ -485,14 +458,12 @@ function runTest(testNum) {
|
||||
},
|
||||
|
||||
function () {
|
||||
info("context menu for link");
|
||||
executeCopyCommand("cmd_copyLink", "http://mozilla.com/");
|
||||
closeContextMenu();
|
||||
openContextMenuFor(pagemenu); // Invoke context menu for next test.
|
||||
},
|
||||
|
||||
function () {
|
||||
info("context menu for pagemenu");
|
||||
// Context menu for element with assigned content context menu
|
||||
checkContextMenu(["context-navigation", null,
|
||||
["context-back", false,
|
||||
@ -520,7 +491,6 @@ function runTest(testNum) {
|
||||
"---", null,
|
||||
"+Checkbox", {type: "checkbox", icon: "", checked: false, disabled: false}], null,
|
||||
"---", null,
|
||||
"context-sharepage", true,
|
||||
"context-savepage", true,
|
||||
"---", null,
|
||||
"context-viewbgimage", false,
|
||||
@ -546,7 +516,6 @@ function runTest(testNum) {
|
||||
},
|
||||
|
||||
function () {
|
||||
info("context menu for fullscreen mode");
|
||||
// Context menu for DOM Fullscreen mode (NOTE: this is *NOT* on an img)
|
||||
checkContextMenu(["context-navigation", null,
|
||||
["context-back", false,
|
||||
@ -556,7 +525,6 @@ function runTest(testNum) {
|
||||
"---", null,
|
||||
"context-leave-dom-fullscreen", true,
|
||||
"---", null,
|
||||
"context-sharepage", true,
|
||||
"context-savepage", true,
|
||||
"---", null,
|
||||
"context-viewbgimage", false,
|
||||
@ -578,7 +546,6 @@ function runTest(testNum) {
|
||||
},
|
||||
|
||||
function () {
|
||||
info("context menu for element with assigned content context menu");
|
||||
// Context menu for element with assigned content context menu
|
||||
// The shift key should bypass content context menu processing
|
||||
checkContextMenu(["context-navigation", null,
|
||||
@ -587,7 +554,6 @@ function runTest(testNum) {
|
||||
"context-reload", true,
|
||||
"context-bookmarkpage", true], null,
|
||||
"---", null,
|
||||
"context-sharepage", true,
|
||||
"context-savepage", true,
|
||||
"---", null,
|
||||
"context-viewbgimage", false,
|
||||
@ -602,7 +568,6 @@ function runTest(testNum) {
|
||||
},
|
||||
|
||||
function () {
|
||||
info("context menu for text selection");
|
||||
// Context menu for selected text
|
||||
if (SpecialPowers.Services.appinfo.OS == "Darwin") {
|
||||
// This test is only enabled on Mac due to bug 736399.
|
||||
@ -610,7 +575,6 @@ function runTest(testNum) {
|
||||
"context-selectall", true,
|
||||
"---", null,
|
||||
"context-searchselect", true,
|
||||
"context-shareselect", true,
|
||||
"context-viewpartialsource-selection", true
|
||||
].concat(inspectItems));
|
||||
}
|
||||
@ -620,7 +584,6 @@ function runTest(testNum) {
|
||||
},
|
||||
|
||||
function () {
|
||||
info("context menu for text selection with url pattern");
|
||||
// Context menu for selected text which matches valid URL pattern
|
||||
if (SpecialPowers.Services.appinfo.OS == "Darwin") {
|
||||
// This test is only enabled on Mac due to bug 736399.
|
||||
@ -631,13 +594,11 @@ function runTest(testNum) {
|
||||
"context-openlinkprivate", true,
|
||||
"---", null,
|
||||
"context-bookmarklink", true,
|
||||
"context-sharelink", true,
|
||||
"context-savelink", true,
|
||||
"context-copy", true,
|
||||
"context-selectall", true,
|
||||
"---", null,
|
||||
"context-searchselect", true,
|
||||
"context-shareselect", true,
|
||||
"context-viewpartialsource-selection", true
|
||||
].concat(inspectItems));
|
||||
} else {
|
||||
@ -646,13 +607,11 @@ function runTest(testNum) {
|
||||
"context-openlink", true,
|
||||
"---", null,
|
||||
"context-bookmarklink", true,
|
||||
"context-sharelink", true,
|
||||
"context-savelink", true,
|
||||
"context-copy", true,
|
||||
"context-selectall", true,
|
||||
"---", null,
|
||||
"context-searchselect", true,
|
||||
"context-shareselect", true,
|
||||
"context-viewpartialsource-selection", true
|
||||
].concat(inspectItems));
|
||||
}
|
||||
@ -665,7 +624,6 @@ function runTest(testNum) {
|
||||
},
|
||||
|
||||
function () {
|
||||
info("context menu for imagelink");
|
||||
// Context menu for image link
|
||||
if (perWindowPrivateBrowsing) {
|
||||
checkContextMenu(["context-openlinkintab", true,
|
||||
@ -673,7 +631,6 @@ function runTest(testNum) {
|
||||
"context-openlinkprivate", true,
|
||||
"---", null,
|
||||
"context-bookmarklink", true,
|
||||
"context-sharelink", true,
|
||||
"context-savelink", true,
|
||||
"context-copylink", true,
|
||||
"---", null,
|
||||
@ -682,7 +639,6 @@ function runTest(testNum) {
|
||||
"context-copyimage", true,
|
||||
"---", null,
|
||||
"context-saveimage", true,
|
||||
"context-shareimage", true,
|
||||
"context-sendimage", true,
|
||||
"context-setDesktopBackground", true,
|
||||
"context-viewimageinfo", true
|
||||
@ -692,7 +648,6 @@ function runTest(testNum) {
|
||||
"context-openlink", true,
|
||||
"---", null,
|
||||
"context-bookmarklink", true,
|
||||
"context-sharelink", true,
|
||||
"context-savelink", true,
|
||||
"context-copylink", true,
|
||||
"---", null,
|
||||
@ -701,7 +656,6 @@ function runTest(testNum) {
|
||||
"context-copyimage", true,
|
||||
"---", null,
|
||||
"context-saveimage", true,
|
||||
"context-shareimage", true,
|
||||
"context-sendimage", true,
|
||||
"context-setDesktopBackground", true,
|
||||
"context-viewimageinfo", true
|
||||
@ -713,7 +667,6 @@ function runTest(testNum) {
|
||||
},
|
||||
|
||||
function () {
|
||||
info("context menu for select_inputtext");
|
||||
// Context menu for selected text in input
|
||||
checkContextMenu(["context-undo", false,
|
||||
"---", null,
|
||||
@ -733,7 +686,6 @@ function runTest(testNum) {
|
||||
},
|
||||
|
||||
function () {
|
||||
info("context menu for selected text in input[type='password']");
|
||||
// Context menu for selected text in input[type="password"]
|
||||
checkContextMenu(["context-undo", false,
|
||||
"---", null,
|
||||
@ -757,7 +709,6 @@ function runTest(testNum) {
|
||||
},
|
||||
|
||||
function () {
|
||||
info("context menu for click-to-play blocked plugin");
|
||||
// Context menu for click-to-play blocked plugin
|
||||
checkContextMenu(["context-navigation", null,
|
||||
["context-back", false,
|
||||
@ -768,7 +719,6 @@ function runTest(testNum) {
|
||||
"context-ctp-play", true,
|
||||
"context-ctp-hide", true,
|
||||
"---", null,
|
||||
"context-sharepage", true,
|
||||
"context-savepage", true,
|
||||
"---", null,
|
||||
"context-viewbgimage", false,
|
||||
@ -784,14 +734,12 @@ function runTest(testNum) {
|
||||
},
|
||||
|
||||
function () {
|
||||
info("context menu for image with longdesc");
|
||||
// Context menu for an image with longdesc
|
||||
checkContextMenu(["context-viewimage", true,
|
||||
"context-copyimage-contents", true,
|
||||
"context-copyimage", true,
|
||||
"---", null,
|
||||
"context-saveimage", true,
|
||||
"context-shareimage", true,
|
||||
"context-sendimage", true,
|
||||
"context-setDesktopBackground", true,
|
||||
"context-viewimageinfo", true,
|
||||
@ -802,7 +750,6 @@ function runTest(testNum) {
|
||||
},
|
||||
|
||||
function () {
|
||||
info("context menu for iframe with srcdoc attribute set");
|
||||
// Context menu for an iframe with srcdoc attribute set
|
||||
checkContextMenu(["context-navigation", null,
|
||||
["context-back", false,
|
||||
@ -810,7 +757,6 @@ function runTest(testNum) {
|
||||
"context-reload", true,
|
||||
"context-bookmarkpage", true], null,
|
||||
"---", null,
|
||||
"context-sharepage", true,
|
||||
"context-savepage", true,
|
||||
"---", null,
|
||||
"context-viewbgimage", false,
|
||||
@ -833,7 +779,6 @@ function runTest(testNum) {
|
||||
},
|
||||
|
||||
function () {
|
||||
info("context menu for text input field with spellcheck=false");
|
||||
// Context menu for text input field with spellcheck=false
|
||||
checkContextMenu(["context-undo", false,
|
||||
"---", null,
|
||||
|
@ -198,7 +198,6 @@ function runTest(testNum) {
|
||||
"context-reload", true,
|
||||
"context-bookmarkpage", true], null,
|
||||
"---", null,
|
||||
"context-sharepage", true,
|
||||
"context-savepage", true,
|
||||
"---", null,
|
||||
"context-viewbgimage", false,
|
||||
|
@ -11,7 +11,6 @@ support-files =
|
||||
opengraph/shorturl_linkrel.html
|
||||
microdata.html
|
||||
share.html
|
||||
share_activate.html
|
||||
social_activate.html
|
||||
social_activate_iframe.html
|
||||
social_chat.html
|
||||
|
@ -19,7 +19,7 @@ let snippet =
|
||||
' "iconURL": "chrome://branding/content/icon16.png",' +
|
||||
' "icon32URL": "chrome://branding/content/favicon32.png",' +
|
||||
' "icon64URL": "chrome://branding/content/icon64.png",' +
|
||||
' "sidebarURL": "https://example.com/browser/browser/base/content/test/social/social_sidebar_empty.html",' +
|
||||
' "sidebarURL": "https://example.com/browser/browser/base/content/test/social/social_sidebar.html",' +
|
||||
' "postActivationURL": "https://example.com/browser/browser/base/content/test/social/social_postActivation.html",' +
|
||||
' };' +
|
||||
' function activateProvider(node) {' +
|
||||
@ -41,7 +41,7 @@ let snippet2 =
|
||||
' "iconURL": "chrome://branding/content/icon16.png",' +
|
||||
' "icon32URL": "chrome://branding/content/favicon32.png",' +
|
||||
' "icon64URL": "chrome://branding/content/icon64.png",' +
|
||||
' "sidebarURL": "https://example.com/browser/browser/base/content/test/social/social_sidebar_empty.html",' +
|
||||
' "sidebarURL": "https://example.com/browser/browser/base/content/test/social/social_sidebar.html",' +
|
||||
' "postActivationURL": "https://example.com/browser/browser/base/content/test/social/social_postActivation.html",' +
|
||||
' "oneclick": true' +
|
||||
' };' +
|
||||
|
@ -10,46 +10,10 @@ let manifest = { // normal provider
|
||||
iconURL: "https://example.com/browser/browser/base/content/test/general/moz.png",
|
||||
shareURL: "https://example.com/browser/browser/base/content/test/social/share.html"
|
||||
};
|
||||
let activationPage = "https://example.com/browser/browser/base/content/test/social/share_activate.html";
|
||||
|
||||
function waitForProviderEnabled(cb) {
|
||||
Services.obs.addObserver(function providerSet(subject, topic, data) {
|
||||
Services.obs.removeObserver(providerSet, "social:provider-enabled");
|
||||
info("social:provider-enabled observer was notified");
|
||||
cb();
|
||||
}, "social:provider-enabled", false);
|
||||
}
|
||||
|
||||
function sendActivationEvent(callback) {
|
||||
// hack Social.lastEventReceived so we don't hit the "too many events" check.
|
||||
Social.lastEventReceived = 0;
|
||||
let doc = SocialShare.iframe.contentDocument;
|
||||
// if our test has a frame, use it
|
||||
let button = doc.getElementById("activation");
|
||||
ok(!!button, "got the activation button");
|
||||
EventUtils.synthesizeMouseAtCenter(button, {}, doc.defaultView);
|
||||
if (callback)
|
||||
executeSoon(callback);
|
||||
}
|
||||
|
||||
function waitForEvent(iframe, eventName, callback) {
|
||||
iframe.addEventListener(eventName, function load() {
|
||||
info("page load is "+iframe.contentDocument.location.href);
|
||||
if (iframe.contentDocument.location.href != "data:text/plain;charset=utf8,") {
|
||||
iframe.removeEventListener(eventName, load, true);
|
||||
executeSoon(callback);
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
Services.prefs.setCharPref("social.shareDirectory", activationPage);
|
||||
registerCleanupFunction(function () {
|
||||
Services.prefs.clearUserPref("social.directories");
|
||||
Services.prefs.clearUserPref("social.shareDirectory");
|
||||
Services.prefs.clearUserPref("social.share.activationPanelEnabled");
|
||||
});
|
||||
|
||||
runSocialTests(tests);
|
||||
}
|
||||
|
||||
@ -111,10 +75,11 @@ let corpus = [
|
||||
function loadURLInTab(url, callback) {
|
||||
info("Loading tab with "+url);
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab(url);
|
||||
waitForEvent(tab.linkedBrowser, "load", () => {
|
||||
tab.linkedBrowser.addEventListener("load", function listener() {
|
||||
is(tab.linkedBrowser.currentURI.spec, url, "tab loaded")
|
||||
callback(tab)
|
||||
});
|
||||
tab.linkedBrowser.removeEventListener("load", listener, true);
|
||||
executeSoon(function() { callback(tab) });
|
||||
}, true);
|
||||
}
|
||||
|
||||
function hasoptions(testOptions, options) {
|
||||
@ -145,6 +110,7 @@ var tests = {
|
||||
checkSocialUI();
|
||||
// share should not be enabled since we only have about:blank page
|
||||
let shareButton = SocialShare.shareButton;
|
||||
is(shareButton.disabled, true, "share button is disabled");
|
||||
// verify the attribute for proper css
|
||||
is(shareButton.getAttribute("disabled"), "true", "share button attribute is disabled");
|
||||
// button should be visible
|
||||
@ -162,6 +128,7 @@ var tests = {
|
||||
checkSocialUI();
|
||||
// share should not be enabled since we only have about:blank page
|
||||
let shareButton = SocialShare.shareButton;
|
||||
is(shareButton.disabled, false, "share button is enabled");
|
||||
// verify the attribute for proper css
|
||||
ok(!shareButton.hasAttribute("disabled"), "share button is enabled");
|
||||
// button should be visible
|
||||
@ -182,7 +149,7 @@ var tests = {
|
||||
function runOneTest() {
|
||||
loadURLInTab(testData.url, function(tab) {
|
||||
testTab = tab;
|
||||
SocialShare.sharePage(manifest.origin);
|
||||
SocialShare.sharePage();
|
||||
});
|
||||
}
|
||||
|
||||
@ -274,46 +241,5 @@ var tests = {
|
||||
SocialShare.sharePage(manifest.origin, null, target);
|
||||
});
|
||||
});
|
||||
},
|
||||
testSharePanelActivation: function(next) {
|
||||
let testTab;
|
||||
// cleared in the cleanup function
|
||||
Services.prefs.setCharPref("social.directories", "https://example.com");
|
||||
Services.prefs.setBoolPref("social.share.activationPanelEnabled", true);
|
||||
// make the iframe so we can wait on the load
|
||||
SocialShare._createFrame();
|
||||
let iframe = SocialShare.iframe;
|
||||
|
||||
waitForEvent(iframe, "load", () => {
|
||||
waitForCondition(() => {
|
||||
// sometimes the iframe is ready before the panel is open, we need to
|
||||
// wait for both conditions
|
||||
return SocialShare.panel.state == "open";
|
||||
}, () => {
|
||||
is(iframe.contentDocument.location.href, activationPage, "activation page loaded");
|
||||
waitForProviderEnabled(() => {
|
||||
let provider = Social._getProviderFromOrigin(manifest.origin);
|
||||
let port = provider.getWorkerPort();
|
||||
ok(!!port, "got port");
|
||||
port.onmessage = function (e) {
|
||||
let topic = e.data.topic;
|
||||
info("got topic "+topic+"\n");
|
||||
switch (topic) {
|
||||
case "got-share-data-message":
|
||||
ok(true, "share completed");
|
||||
gBrowser.removeTab(testTab);
|
||||
SocialService.uninstallProvider(manifest.origin, next);
|
||||
break;
|
||||
}
|
||||
}
|
||||
port.postMessage({topic: "test-init"});
|
||||
});
|
||||
sendActivationEvent();
|
||||
}, "share panel did not open and load share page");
|
||||
});
|
||||
loadURLInTab(activationPage, function(tab) {
|
||||
testTab = tab;
|
||||
SocialShare.sharePage();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ function openChat(provider, callback) {
|
||||
let port = provider.getWorkerPort();
|
||||
port.onmessage = function(e) {
|
||||
if (e.data.topic == "got-chatbox-message") {
|
||||
port.close();
|
||||
callback();
|
||||
}
|
||||
}
|
||||
@ -41,7 +42,6 @@ function openChat(provider, callback) {
|
||||
port.postMessage({topic: "test-init"});
|
||||
port.postMessage({topic: "test-worker-chat", data: url});
|
||||
gURLsNotRemembered.push(url);
|
||||
return port;
|
||||
}
|
||||
|
||||
function windowHasChats(win) {
|
||||
@ -172,9 +172,6 @@ var tests = {
|
||||
let num = 0;
|
||||
is(chatbar.childNodes.length, 0, "chatbar starting empty");
|
||||
is(chatbar.menupopup.childNodes.length, 0, "popup starting empty");
|
||||
let port = SocialSidebar.provider.getWorkerPort();
|
||||
ok(port, "provider has a port");
|
||||
port.postMessage({topic: "test-init"});
|
||||
|
||||
makeChat("normal", "first chat", function() {
|
||||
// got the first one.
|
||||
@ -198,7 +195,6 @@ var tests = {
|
||||
chatbar.selectedChat.close();
|
||||
is(chatbar.selectedChat, second, "second chat is selected");
|
||||
closeAllChats();
|
||||
port.close();
|
||||
next();
|
||||
});
|
||||
});
|
||||
@ -247,24 +243,24 @@ var tests = {
|
||||
|
||||
testMultipleProviderChat: function(next) {
|
||||
// test incomming chats from all providers
|
||||
let port0 = openChat(Social.providers[0], function() {
|
||||
let port1 = openChat(Social.providers[1], function() {
|
||||
let port2 = openChat(Social.providers[2], function() {
|
||||
openChat(Social.providers[0], function() {
|
||||
openChat(Social.providers[1], function() {
|
||||
openChat(Social.providers[2], function() {
|
||||
let chats = document.getElementById("pinnedchats");
|
||||
waitForCondition(function() chats.children.length == Social.providers.length,
|
||||
function() {
|
||||
ok(true, "one chat window per provider opened");
|
||||
// test logout of a single provider
|
||||
port2.postMessage({topic: "test-logout"});
|
||||
let provider = Social.providers[2];
|
||||
let port = provider.getWorkerPort();
|
||||
port.postMessage({topic: "test-logout"});
|
||||
waitForCondition(function() chats.children.length == Social.providers.length - 1,
|
||||
function() {
|
||||
closeAllChats();
|
||||
waitForCondition(function() chats.children.length == 0,
|
||||
function() {
|
||||
ok(!chats.selectedChat, "multiprovider chats are all closed");
|
||||
port0.close();
|
||||
port1.close();
|
||||
port2.close();
|
||||
port.close();
|
||||
next();
|
||||
},
|
||||
"chat windows didn't close");
|
||||
|
@ -36,16 +36,10 @@ function goOnline(callback) {
|
||||
function openPanel(url, panelCallback, loadCallback) {
|
||||
// open a flyout
|
||||
SocialFlyout.open(url, 0, panelCallback);
|
||||
// wait for both open and loaded before callback. Since the test doesn't close
|
||||
// the panel between opens, we cannot rely on events here. We need to ensure
|
||||
// popupshown happens before we finish out the tests.
|
||||
waitForCondition(function() {
|
||||
return SocialFlyout.panel.state == "open" &&
|
||||
SocialFlyout.iframe.contentDocument.readyState == "complete";
|
||||
},
|
||||
loadCallback,
|
||||
"flyout is open and loaded");
|
||||
|
||||
SocialFlyout.panel.firstChild.addEventListener("load", function panelLoad() {
|
||||
SocialFlyout.panel.firstChild.removeEventListener("load", panelLoad, true);
|
||||
loadCallback();
|
||||
}, true);
|
||||
}
|
||||
|
||||
function openChat(url, panelCallback, loadCallback) {
|
||||
@ -189,10 +183,6 @@ var tests = {
|
||||
// Ensure that the error listener survives the chat window being detached.
|
||||
let url = "https://example.com/browser/browser/base/content/test/social/social_chat.html";
|
||||
let panelCallbackCount = 0;
|
||||
// chatwindow tests throw errors, which muddy test output, if the worker
|
||||
// doesn't get test-init
|
||||
let port = SocialSidebar.provider.getWorkerPort();
|
||||
port.postMessage({topic: "test-init"});
|
||||
// open a chat while we are still online.
|
||||
openChat(
|
||||
url,
|
||||
@ -210,7 +200,6 @@ var tests = {
|
||||
waitForCondition(function() chat.contentDocument.location.href.indexOf("about:socialerror?")==0,
|
||||
function() {
|
||||
chat.close();
|
||||
port.close();
|
||||
next();
|
||||
},
|
||||
"error page didn't appear");
|
||||
|
@ -1,36 +0,0 @@
|
||||
<html>
|
||||
<!-- 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/. -->
|
||||
<head>
|
||||
<title>Activation test</title>
|
||||
</head>
|
||||
<script>
|
||||
|
||||
var data = {
|
||||
// currently required
|
||||
"name": "Demo Social Service",
|
||||
// browser_share.js serves this page from "https://example.com"
|
||||
"origin": "https://example.com",
|
||||
"iconURL": "chrome://branding/content/icon16.png",
|
||||
"icon32URL": "chrome://branding/content/favicon32.png",
|
||||
"icon64URL": "chrome://branding/content/icon64.png",
|
||||
"workerURL": "/browser/browser/base/content/test/social/social_worker.js",
|
||||
"shareURL": "/browser/browser/base/content/test/social/share.html"
|
||||
}
|
||||
|
||||
function activate(node) {
|
||||
node.setAttribute("data-service", JSON.stringify(data));
|
||||
var event = new CustomEvent("ActivateSocialFeature");
|
||||
node.dispatchEvent(event);
|
||||
}
|
||||
|
||||
</script>
|
||||
<body>
|
||||
|
||||
nothing to see here
|
||||
|
||||
<button id="activation" onclick="activate(this, true)">Activate the share provider</button>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -166,7 +166,6 @@ let CustomizableUIInternal = {
|
||||
"preferences-button",
|
||||
"add-ons-button",
|
||||
"developer-button",
|
||||
"social-share-button",
|
||||
];
|
||||
|
||||
if (gPalette.has("switch-to-metro-button")) {
|
||||
@ -208,6 +207,7 @@ let CustomizableUIInternal = {
|
||||
"downloads-button",
|
||||
"home-button",
|
||||
"loop-call-button",
|
||||
"social-share-button",
|
||||
],
|
||||
defaultCollapsed: false,
|
||||
}, true);
|
||||
|
@ -27,7 +27,7 @@ add_task(function testWrapUnwrap() {
|
||||
// Creating and destroying a widget should correctly deal with panel placeholders
|
||||
add_task(function testPanelPlaceholders() {
|
||||
let panel = document.getElementById(CustomizableUI.AREA_PANEL);
|
||||
is(panel.querySelectorAll(".panel-customization-placeholder").length, isInWin8() ? 3 : 1, "The number of placeholders should be correct.");
|
||||
is(panel.querySelectorAll(".panel-customization-placeholder").length, isInWin8() ? 1 : 2, "The number of placeholders should be correct.");
|
||||
CustomizableUI.createWidget({id: kTestWidget2, label: 'Pretty label', tooltiptext: 'Pretty tooltip', defaultArea: CustomizableUI.AREA_PANEL});
|
||||
let elem = document.getElementById(kTestWidget2);
|
||||
let wrapper = document.getElementById("wrapper-" + kTestWidget2);
|
||||
@ -35,7 +35,7 @@ add_task(function testPanelPlaceholders() {
|
||||
ok(wrapper, "There should be a wrapper");
|
||||
is(wrapper.firstChild.id, kTestWidget2, "Wrapper should have test widget");
|
||||
is(wrapper.parentNode, panel, "Wrapper should be in panel");
|
||||
is(panel.querySelectorAll(".panel-customization-placeholder").length, isInWin8() ? 2 : 3, "The number of placeholders should be correct.");
|
||||
is(panel.querySelectorAll(".panel-customization-placeholder").length, isInWin8() ? 3 : 1, "The number of placeholders should be correct.");
|
||||
CustomizableUI.destroyWidget(kTestWidget2);
|
||||
wrapper = document.getElementById("wrapper-" + kTestWidget2);
|
||||
ok(!wrapper, "There should be a wrapper");
|
||||
|
@ -22,8 +22,7 @@ add_task(function() {
|
||||
"find-button",
|
||||
"preferences-button",
|
||||
"add-ons-button",
|
||||
"developer-button",
|
||||
"social-share-button"];
|
||||
"developer-button"];
|
||||
addSwitchToMetroButtonInWindows8(placementsAfterMove);
|
||||
simulateItemDrag(zoomControls, printButton);
|
||||
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
|
||||
@ -49,8 +48,7 @@ add_task(function() {
|
||||
"find-button",
|
||||
"preferences-button",
|
||||
"add-ons-button",
|
||||
"developer-button",
|
||||
"social-share-button"];
|
||||
"developer-button"];
|
||||
addSwitchToMetroButtonInWindows8(placementsAfterMove);
|
||||
simulateItemDrag(zoomControls, savePageButton);
|
||||
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
|
||||
@ -74,8 +72,7 @@ add_task(function() {
|
||||
"find-button",
|
||||
"preferences-button",
|
||||
"add-ons-button",
|
||||
"developer-button",
|
||||
"social-share-button"];
|
||||
"developer-button"];
|
||||
addSwitchToMetroButtonInWindows8(placementsAfterMove);
|
||||
simulateItemDrag(zoomControls, newWindowButton);
|
||||
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
|
||||
@ -98,8 +95,7 @@ add_task(function() {
|
||||
"find-button",
|
||||
"preferences-button",
|
||||
"add-ons-button",
|
||||
"developer-button",
|
||||
"social-share-button"];
|
||||
"developer-button"];
|
||||
addSwitchToMetroButtonInWindows8(placementsAfterMove);
|
||||
simulateItemDrag(zoomControls, historyPanelMenu);
|
||||
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
|
||||
@ -126,8 +122,7 @@ add_task(function() {
|
||||
"find-button",
|
||||
"preferences-button",
|
||||
"add-ons-button",
|
||||
"developer-button",
|
||||
"social-share-button"];
|
||||
"developer-button"];
|
||||
addSwitchToMetroButtonInWindows8(placementsAfterMove);
|
||||
simulateItemDrag(zoomControls, preferencesButton);
|
||||
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
|
||||
@ -154,8 +149,7 @@ add_task(function() {
|
||||
"find-button",
|
||||
"preferences-button",
|
||||
"add-ons-button",
|
||||
"developer-button",
|
||||
"social-share-button"];
|
||||
"developer-button"];
|
||||
addSwitchToMetroButtonInWindows8(placementsAfterInsert);
|
||||
simulateItemDrag(openFileButton, zoomControls);
|
||||
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterInsert);
|
||||
@ -194,8 +188,7 @@ add_task(function() {
|
||||
"find-button",
|
||||
"preferences-button",
|
||||
"add-ons-button",
|
||||
"developer-button",
|
||||
"social-share-button"];
|
||||
"developer-button"];
|
||||
addSwitchToMetroButtonInWindows8(placementsAfterInsert);
|
||||
simulateItemDrag(openFileButton, editControls);
|
||||
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterInsert);
|
||||
@ -231,8 +224,7 @@ add_task(function() {
|
||||
"find-button",
|
||||
"preferences-button",
|
||||
"add-ons-button",
|
||||
"developer-button",
|
||||
"social-share-button"];
|
||||
"developer-button"];
|
||||
addSwitchToMetroButtonInWindows8(placementsAfterMove);
|
||||
simulateItemDrag(editControls, zoomControls);
|
||||
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
|
||||
@ -256,8 +248,7 @@ add_task(function() {
|
||||
"find-button",
|
||||
"preferences-button",
|
||||
"add-ons-button",
|
||||
"developer-button",
|
||||
"social-share-button"];
|
||||
"developer-button"];
|
||||
addSwitchToMetroButtonInWindows8(placementsAfterMove);
|
||||
simulateItemDrag(editControls, newWindowButton);
|
||||
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
|
||||
@ -284,8 +275,7 @@ add_task(function() {
|
||||
"find-button",
|
||||
"preferences-button",
|
||||
"add-ons-button",
|
||||
"developer-button",
|
||||
"social-share-button"];
|
||||
"developer-button"];
|
||||
addSwitchToMetroButtonInWindows8(placementsAfterMove);
|
||||
simulateItemDrag(editControls, privateBrowsingButton);
|
||||
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
|
||||
@ -312,8 +302,7 @@ add_task(function() {
|
||||
"find-button",
|
||||
"preferences-button",
|
||||
"add-ons-button",
|
||||
"developer-button",
|
||||
"social-share-button"];
|
||||
"developer-button"];
|
||||
addSwitchToMetroButtonInWindows8(placementsAfterMove);
|
||||
simulateItemDrag(editControls, savePageButton);
|
||||
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
|
||||
@ -339,8 +328,7 @@ add_task(function() {
|
||||
"preferences-button",
|
||||
"add-ons-button",
|
||||
"edit-controls",
|
||||
"developer-button",
|
||||
"social-share-button"];
|
||||
"developer-button"];
|
||||
addSwitchToMetroButtonInWindows8(placementsAfterMove);
|
||||
simulateItemDrag(editControls, panel);
|
||||
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
|
||||
@ -365,8 +353,7 @@ add_task(function() {
|
||||
"find-button",
|
||||
"preferences-button",
|
||||
"add-ons-button",
|
||||
"developer-button",
|
||||
"social-share-button"];
|
||||
"developer-button"];
|
||||
addSwitchToMetroButtonInWindows8(placementsAfterMove);
|
||||
let paletteChildElementCount = palette.childElementCount;
|
||||
simulateItemDrag(editControls, palette);
|
||||
@ -390,8 +377,7 @@ add_task(function() {
|
||||
yield startCustomizing();
|
||||
let editControls = document.getElementById("edit-controls");
|
||||
let panel = document.getElementById(CustomizableUI.AREA_PANEL);
|
||||
let numPlaceholders = isInWin8() ? 3 : 1;
|
||||
is(numPlaceholders, panel.getElementsByClassName("panel-customization-placeholder").length, "correct number of placeholders");
|
||||
let numPlaceholders = isInWin8() ? 1 : 2;
|
||||
for (let i = 0; i < numPlaceholders; i++) {
|
||||
// NB: We can't just iterate over all of the placeholders
|
||||
// because each drag-drop action recreates them.
|
||||
@ -407,8 +393,7 @@ add_task(function() {
|
||||
"preferences-button",
|
||||
"add-ons-button",
|
||||
"edit-controls",
|
||||
"developer-button",
|
||||
"social-share-button"];
|
||||
"developer-button"];
|
||||
addSwitchToMetroButtonInWindows8(placementsAfterMove);
|
||||
simulateItemDrag(editControls, placeholder);
|
||||
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
|
||||
@ -438,8 +423,6 @@ add_task(function() {
|
||||
yield startCustomizing();
|
||||
let editControls = document.getElementById("edit-controls");
|
||||
let panel = document.getElementById(CustomizableUI.AREA_PANEL);
|
||||
let numPlaceholders = isInWin8() ? 3 : 1;
|
||||
is(panel.getElementsByClassName("panel-customization-placeholder").length, numPlaceholders, "correct number of placeholders");
|
||||
let target = panel.getElementsByClassName("panel-customization-placeholder")[0];
|
||||
let placementsAfterMove = ["zoom-controls",
|
||||
"new-window-button",
|
||||
@ -452,22 +435,18 @@ add_task(function() {
|
||||
"preferences-button",
|
||||
"add-ons-button",
|
||||
"edit-controls",
|
||||
"developer-button",
|
||||
"social-share-button"];
|
||||
"developer-button"];
|
||||
addSwitchToMetroButtonInWindows8(placementsAfterMove);
|
||||
if (isInWin8()) {
|
||||
placementsAfterMove.splice(10, 1);
|
||||
placementsAfterMove.push("edit-controls");
|
||||
}
|
||||
simulateItemDrag(editControls, target);
|
||||
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
|
||||
let itemToDrag = "sync-button";
|
||||
let button = document.getElementById(itemToDrag);
|
||||
placementsAfterMove.splice(11, 0, itemToDrag);
|
||||
if (isInWin8()) {
|
||||
placementsAfterMove.push(itemToDrag);
|
||||
} else {
|
||||
placementsAfterMove.splice(10, 1, itemToDrag);
|
||||
placementsAfterMove.push("edit-controls");
|
||||
placementsAfterMove[10] = placementsAfterMove[11];
|
||||
placementsAfterMove[11] = placementsAfterMove[12];
|
||||
placementsAfterMove[12] = placementsAfterMove[13];
|
||||
placementsAfterMove[13] = "edit-controls";
|
||||
}
|
||||
simulateItemDrag(button, editControls);
|
||||
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
|
||||
|
@ -11,13 +11,15 @@ add_task(function() {
|
||||
yield startCustomizing();
|
||||
let btn = document.getElementById("open-file-button");
|
||||
let panel = document.getElementById(CustomizableUI.AREA_PANEL);
|
||||
let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
|
||||
|
||||
CustomizableUI.removeWidgetFromArea("social-share-button");
|
||||
if (isInWin8()) {
|
||||
CustomizableUI.removeWidgetFromArea("switch-to-metro-button");
|
||||
placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
|
||||
ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
|
||||
} else {
|
||||
ok(CustomizableUI.inDefaultState, "Should be in default state.");
|
||||
}
|
||||
let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
|
||||
ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
|
||||
|
||||
assertAreaPlacements(CustomizableUI.AREA_PANEL, placements);
|
||||
is(getVisiblePlaceholderCount(panel), 2, "Should only have 2 visible placeholders before exiting");
|
||||
@ -26,7 +28,6 @@ add_task(function() {
|
||||
yield startCustomizing();
|
||||
is(getVisiblePlaceholderCount(panel), 2, "Should only have 2 visible placeholders after re-entering");
|
||||
|
||||
CustomizableUI.addWidgetToArea("social-share-button", CustomizableUI.AREA_PANEL);
|
||||
if (isInWin8()) {
|
||||
CustomizableUI.addWidgetToArea("switch-to-metro-button", CustomizableUI.AREA_PANEL);
|
||||
}
|
||||
@ -38,7 +39,6 @@ add_task(function() {
|
||||
yield startCustomizing();
|
||||
let btn = document.getElementById("open-file-button");
|
||||
let panel = document.getElementById(CustomizableUI.AREA_PANEL);
|
||||
CustomizableUI.removeWidgetFromArea("social-share-button");
|
||||
let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
|
||||
|
||||
let placementsAfterAppend = placements;
|
||||
@ -49,7 +49,7 @@ add_task(function() {
|
||||
}
|
||||
|
||||
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend);
|
||||
ok(!CustomizableUI.inDefaultState, "Should not be in default state");
|
||||
is(CustomizableUI.inDefaultState, isInWin8(), "Should only be in default state if on Win8");
|
||||
is(getVisiblePlaceholderCount(panel), 1, "Should only have 1 visible placeholder before exiting");
|
||||
|
||||
yield endCustomizing();
|
||||
@ -63,24 +63,26 @@ add_task(function() {
|
||||
btn = document.getElementById("open-file-button");
|
||||
simulateItemDrag(btn, palette);
|
||||
}
|
||||
CustomizableUI.addWidgetToArea("social-share-button", CustomizableUI.AREA_PANEL);
|
||||
ok(CustomizableUI.inDefaultState, "Should be in default state again.");
|
||||
});
|
||||
|
||||
// Two orphaned items should have one placeholder next to them (case 2).
|
||||
add_task(function() {
|
||||
yield startCustomizing();
|
||||
let buttonsToMove = ["add-ons-button", "developer-button", "social-share-button"];
|
||||
if (isInWin8()) {
|
||||
buttonsToMove.push("switch-to-metro-button");
|
||||
}
|
||||
let btn = document.getElementById("add-ons-button");
|
||||
let btn2 = document.getElementById("developer-button");
|
||||
let btn3 = document.getElementById("switch-to-metro-button");
|
||||
let panel = document.getElementById(CustomizableUI.AREA_PANEL);
|
||||
let palette = document.getElementById("customization-palette");
|
||||
let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
|
||||
|
||||
let placementsAfterAppend = placements.filter(p => buttonsToMove.indexOf(p) < 0);
|
||||
for (let i in buttonsToMove) {
|
||||
CustomizableUI.removeWidgetFromArea(buttonsToMove[i]);
|
||||
let placementsAfterAppend = placements.filter(p => p != btn.id && p != btn2.id);
|
||||
simulateItemDrag(btn, palette);
|
||||
simulateItemDrag(btn2, palette);
|
||||
|
||||
if (isInWin8()) {
|
||||
placementsAfterAppend = placementsAfterAppend.filter(p => p != btn3.id);
|
||||
simulateItemDrag(btn3, palette);
|
||||
}
|
||||
|
||||
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend);
|
||||
@ -91,8 +93,11 @@ add_task(function() {
|
||||
yield startCustomizing();
|
||||
is(getVisiblePlaceholderCount(panel), 1, "Should only have 1 visible placeholder after re-entering");
|
||||
|
||||
for (let i in buttonsToMove) {
|
||||
CustomizableUI.addWidgetToArea(buttonsToMove[i], CustomizableUI.AREA_PANEL);
|
||||
simulateItemDrag(btn, panel);
|
||||
simulateItemDrag(btn2, panel);
|
||||
|
||||
if (isInWin8()) {
|
||||
simulateItemDrag(btn3, panel);
|
||||
}
|
||||
|
||||
assertAreaPlacements(CustomizableUI.AREA_PANEL, placements);
|
||||
@ -107,7 +112,6 @@ add_task(function() {
|
||||
let metroBtn = document.getElementById("switch-to-metro-button");
|
||||
let panel = document.getElementById(CustomizableUI.AREA_PANEL);
|
||||
let palette = document.getElementById("customization-palette");
|
||||
CustomizableUI.removeWidgetFromArea("social-share-button");
|
||||
let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
|
||||
|
||||
placements.pop();
|
||||
@ -129,7 +133,6 @@ add_task(function() {
|
||||
is(getVisiblePlaceholderCount(panel), 3, "Should have 3 visible placeholders after re-entering");
|
||||
|
||||
simulateItemDrag(developerButton, panel);
|
||||
CustomizableUI.addWidgetToArea("social-share-button", CustomizableUI.AREA_PANEL);
|
||||
if (isInWin8()) {
|
||||
simulateItemDrag(metroBtn, panel);
|
||||
}
|
||||
@ -138,10 +141,10 @@ add_task(function() {
|
||||
ok(CustomizableUI.inDefaultState, "Should be in default state again.");
|
||||
});
|
||||
|
||||
// The default placements should have one placeholder at the bottom (or 3 in metro-enabled win8).
|
||||
// The default placements should have two placeholders at the bottom (or 1 in win8).
|
||||
add_task(function() {
|
||||
yield startCustomizing();
|
||||
let numPlaceholders = isInWin8() ? 3 : 1;
|
||||
let numPlaceholders = isInWin8() ? 1 : 2;
|
||||
let panel = document.getElementById(CustomizableUI.AREA_PANEL);
|
||||
ok(CustomizableUI.inDefaultState, "Should be in default state.");
|
||||
is(getVisiblePlaceholderCount(panel), numPlaceholders, "Should have " + numPlaceholders + " visible placeholders before exiting");
|
||||
|
@ -263,7 +263,7 @@ loop.conversation = (function(OT, mozL10n) {
|
||||
*/
|
||||
declineAndBlock: function() {
|
||||
navigator.mozLoop.stopAlerting();
|
||||
var token = navigator.mozLoop.getLoopCharPref("loopToken");
|
||||
var token = this._conversation.get("callToken");
|
||||
this._client.deleteCallUrl(token, function(error) {
|
||||
// XXX The conversation window will be closed when this cb is triggered
|
||||
// figure out if there is a better way to report the error to the user
|
||||
|
@ -263,7 +263,7 @@ loop.conversation = (function(OT, mozL10n) {
|
||||
*/
|
||||
declineAndBlock: function() {
|
||||
navigator.mozLoop.stopAlerting();
|
||||
var token = navigator.mozLoop.getLoopCharPref("loopToken");
|
||||
var token = this._conversation.get("callToken");
|
||||
this._client.deleteCallUrl(token, function(error) {
|
||||
// XXX The conversation window will be closed when this cb is triggered
|
||||
// figure out if there is a better way to report the error to the user
|
||||
|
@ -170,10 +170,6 @@ loop.panel = (function(_, mozL10n) {
|
||||
* Returns a random 5 character string used to identify
|
||||
* the conversation.
|
||||
* XXX this will go away once the backend changes
|
||||
* @note:
|
||||
* - When we get back a callUrl we use setLoopCharPref to store the token
|
||||
* (the last fragment of the URL) so that it can be used to ignore&block
|
||||
* the call. The preference is used by the conversation router.
|
||||
*/
|
||||
conversationIdentifier: function() {
|
||||
return Math.random().toString(36).substring(5);
|
||||
@ -199,7 +195,6 @@ loop.panel = (function(_, mozL10n) {
|
||||
var token = callUrlData.callToken ||
|
||||
callUrl.pathname.split('/').pop();
|
||||
|
||||
navigator.mozLoop.setLoopCharPref('loopToken', token);
|
||||
this.setState({pending: false, copied: false, callUrl: callUrl.href});
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
|
@ -170,10 +170,6 @@ loop.panel = (function(_, mozL10n) {
|
||||
* Returns a random 5 character string used to identify
|
||||
* the conversation.
|
||||
* XXX this will go away once the backend changes
|
||||
* @note:
|
||||
* - When we get back a callUrl we use setLoopCharPref to store the token
|
||||
* (the last fragment of the URL) so that it can be used to ignore&block
|
||||
* the call. The preference is used by the conversation router.
|
||||
*/
|
||||
conversationIdentifier: function() {
|
||||
return Math.random().toString(36).substring(5);
|
||||
@ -199,7 +195,6 @@ loop.panel = (function(_, mozL10n) {
|
||||
var token = callUrlData.callToken ||
|
||||
callUrl.pathname.split('/').pop();
|
||||
|
||||
navigator.mozLoop.setLoopCharPref('loopToken', token);
|
||||
this.setState({pending: false, copied: false, callUrl: callUrl.href});
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
|
@ -32,8 +32,10 @@ loop.shared.models = (function() {
|
||||
// requires.
|
||||
callType: undefined, // The type of incoming call selected by
|
||||
// other peer ("audio" or "audio-video")
|
||||
selectedCallType: undefined // The selected type for the call that was
|
||||
selectedCallType: undefined, // The selected type for the call that was
|
||||
// initiated ("audio" or "audio-video")
|
||||
callToken: undefined // Incoming call token.
|
||||
// Used for blocking a call url
|
||||
},
|
||||
|
||||
/**
|
||||
@ -168,7 +170,8 @@ loop.shared.models = (function() {
|
||||
callId: sessionData.callId,
|
||||
progressURL: sessionData.progressURL,
|
||||
websocketToken: sessionData.websocketToken.toString(16),
|
||||
callType: sessionData.callType || "audio-video"
|
||||
callType: sessionData.callType || "audio-video",
|
||||
callToken: sessionData.callToken
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -120,6 +120,7 @@ describe("loop.conversation", function() {
|
||||
pendingCallTimeout: 1000,
|
||||
});
|
||||
sandbox.stub(client, "requestCallsInfo");
|
||||
sandbox.spy(conversation, "setIncomingSessionData");
|
||||
sandbox.stub(conversation, "setOutgoingSessionData");
|
||||
});
|
||||
|
||||
@ -201,7 +202,6 @@ describe("loop.conversation", function() {
|
||||
};
|
||||
|
||||
sandbox.stub(router, "_setupWebSocketAndCallView");
|
||||
sandbox.stub(conversation, "setIncomingSessionData");
|
||||
|
||||
client.requestCallsInfo.callsArgWith(1, null, [fakeSessionData]);
|
||||
});
|
||||
@ -436,10 +436,23 @@ describe("loop.conversation", function() {
|
||||
});
|
||||
|
||||
it("should call delete call", function() {
|
||||
var deleteCallUrl = sandbox.stub(loop.Client.prototype, "deleteCallUrl");
|
||||
sandbox.stub(conversation, "get").withArgs("callToken")
|
||||
.returns("fakeToken");
|
||||
var deleteCallUrl = sandbox.stub(loop.Client.prototype,
|
||||
"deleteCallUrl");
|
||||
router.declineAndBlock();
|
||||
|
||||
sinon.assert.calledOnce(deleteCallUrl);
|
||||
sinon.assert.calledWithExactly(deleteCallUrl, "fakeToken",
|
||||
sinon.match.func);
|
||||
});
|
||||
|
||||
it("should get callToken from conversation model", function() {
|
||||
sandbox.stub(conversation, "get");
|
||||
router.declineAndBlock();
|
||||
|
||||
sinon.assert.calledOnce(conversation.get);
|
||||
sinon.assert.calledWithExactly(conversation.get, "callToken");
|
||||
});
|
||||
|
||||
it("should trigger error handling in case of error", function() {
|
||||
|
@ -352,12 +352,6 @@ describe("loop.panel", function() {
|
||||
sinon.assert.calledWithExactly(notifier.errorL10n,
|
||||
"unable_retrieve_url");
|
||||
});
|
||||
|
||||
it("should set 'loopToken' with the callUrl token", function() {
|
||||
sinon.assert.calledOnce(navigator.mozLoop.setLoopCharPref);
|
||||
sinon.assert.calledWithExactly(navigator.mozLoop.setLoopCharPref,
|
||||
"loopToken", "fakeToken");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -26,7 +26,8 @@ describe("loop.shared.models", function() {
|
||||
sessionToken: "sessionToken",
|
||||
apiKey: "apiKey",
|
||||
callType: "callType",
|
||||
websocketToken: 123
|
||||
websocketToken: 123,
|
||||
callToken: "callToken"
|
||||
};
|
||||
fakeSession = _.extend({
|
||||
connect: function () {},
|
||||
@ -159,6 +160,7 @@ describe("loop.shared.models", function() {
|
||||
expect(conversation.get("sessionToken")).eql("sessionToken");
|
||||
expect(conversation.get("apiKey")).eql("apiKey");
|
||||
expect(conversation.get("callType")).eql("callType");
|
||||
expect(conversation.get("callToken")).eql("callToken");
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1228,6 +1228,7 @@ EventTooltip.prototype = {
|
||||
if (event.target.classList.contains("event-tooltip-debugger-icon")) {
|
||||
this._debugClicked(event);
|
||||
event.stopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
let doc = this._tooltip.doc;
|
||||
|
@ -53,10 +53,13 @@ function addTab(url) {
|
||||
return def.promise;
|
||||
}
|
||||
|
||||
function cleanup()
|
||||
function* cleanup()
|
||||
{
|
||||
gPanelWindow = null;
|
||||
while (gBrowser.tabs.length > 1) {
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
yield gDevTools.closeToolbox(target);
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
}
|
||||
}
|
||||
|
@ -140,18 +140,17 @@ These should match what Safari and other Apple applications use on OS X Lion. --
|
||||
<!ENTITY editThisBookmarkCmd.label "Edit This Bookmark">
|
||||
<!ENTITY bookmarkThisPageCmd.commandkey "d">
|
||||
<!ENTITY markPageCmd.commandkey "l">
|
||||
<!ENTITY findShareServices.label "Find more Share services…">
|
||||
<!ENTITY sharePageCmd.label "Share This Page">
|
||||
<!ENTITY sharePageCmd.commandkey "S">
|
||||
<!ENTITY sharePageCmd.accesskey "s">
|
||||
<!ENTITY shareLinkCmd.label "Share This Link">
|
||||
<!ENTITY shareLinkCmd.accesskey "h">
|
||||
<!ENTITY shareLinkCmd.accesskey "s">
|
||||
<!ENTITY shareImageCmd.label "Share This Image">
|
||||
<!ENTITY shareImageCmd.accesskey "r">
|
||||
<!ENTITY shareImageCmd.accesskey "s">
|
||||
<!ENTITY shareSelectCmd.label "Share Selection">
|
||||
<!ENTITY shareSelectCmd.accesskey "r">
|
||||
<!ENTITY shareSelectCmd.accesskey "s">
|
||||
<!ENTITY shareVideoCmd.label "Share This Video">
|
||||
<!ENTITY shareVideoCmd.accesskey "r">
|
||||
<!ENTITY shareVideoCmd.accesskey "s">
|
||||
<!ENTITY feedsMenu.label "Subscribe">
|
||||
<!ENTITY subscribeToPageMenupopup.label "Subscribe to This Page">
|
||||
<!ENTITY subscribeToPageMenuitem.label "Subscribe to This Page…">
|
||||
|
@ -18,6 +18,13 @@ XPCOMUtils.defineLazyModuleGetter(this, "Feeds",
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils",
|
||||
"resource://gre/modules/BrowserUtils.jsm");
|
||||
|
||||
const SIZES_TELEMETRY_ENUM = {
|
||||
NO_SIZES: 0,
|
||||
ANY: 1,
|
||||
DIMENSION: 2,
|
||||
INVALID: 3,
|
||||
};
|
||||
|
||||
this.ContentLinkHandler = {
|
||||
init: function(chromeGlobal) {
|
||||
chromeGlobal.addEventListener("DOMLinkAdded", (event) => {
|
||||
@ -72,6 +79,35 @@ this.ContentLinkHandler = {
|
||||
if (!uri)
|
||||
break;
|
||||
|
||||
// Telemetry probes for measuring the sizes attribute
|
||||
// usage and available dimensions.
|
||||
let sizeHistogramTypes = Services.telemetry.
|
||||
getHistogramById("LINK_ICON_SIZES_ATTR_USAGE");
|
||||
let sizeHistogramDimension = Services.telemetry.
|
||||
getHistogramById("LINK_ICON_SIZES_ATTR_DIMENSION");
|
||||
let sizesType;
|
||||
if (link.sizes.length) {
|
||||
for (let size of link.sizes) {
|
||||
if (size.toLowerCase() == "any") {
|
||||
sizesType = SIZES_TELEMETRY_ENUM.ANY;
|
||||
break;
|
||||
} else {
|
||||
let re = /^([1-9][0-9]*)x[1-9][0-9]*$/i;
|
||||
let values = re.exec(size);
|
||||
if (values && values.length > 1) {
|
||||
sizesType = SIZES_TELEMETRY_ENUM.DIMENSION;
|
||||
sizeHistogramDimension.add(parseInt(values[1]));
|
||||
} else {
|
||||
sizesType = SIZES_TELEMETRY_ENUM.INVALID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sizesType = SIZES_TELEMETRY_ENUM.NO_SIZES;
|
||||
}
|
||||
sizeHistogramTypes.add(sizesType);
|
||||
|
||||
[iconAdded] = chromeGlobal.sendSyncMessage("Link:SetIcon", {url: uri.spec});
|
||||
}
|
||||
break;
|
||||
|
@ -111,31 +111,20 @@ let PanelFrame = {
|
||||
* @param {Function} aCallback Optional, callback to be called with the iframe when it is
|
||||
* set up.
|
||||
*/
|
||||
showPopup: function(aWindow, aPanelUI, aToolbarButton, aType, aOrigin, aSrc, aSize, aCallback) {
|
||||
showPopup: function(aWindow, aToolbarButton, aType, aOrigin, aSrc, aSize, aCallback) {
|
||||
// if we're overflowed, our anchor needs to be the overflow button
|
||||
let widgetGroup = CustomizableUI.getWidget(aToolbarButton.getAttribute("id"));
|
||||
let widget = widgetGroup.forWindow(aWindow);
|
||||
// if we're a slice in the hamburger, our anchor will be the menu button,
|
||||
// this panel will replace the menu panel when the button is clicked on
|
||||
let anchorBtn = widget.anchor;
|
||||
|
||||
// if we're a slice in the hamburger, use that panel instead
|
||||
let panel, showingEvent, hidingEvent;
|
||||
let inMenuPanel = widgetGroup.areaType == CustomizableUI.TYPE_MENU_PANEL;
|
||||
if (inMenuPanel) {
|
||||
panel = aWindow.document.getElementById("PanelUI-" + aType + "api");
|
||||
PanelFrameInternal._attachNotificatonPanel(aWindow, panel, aToolbarButton, aType, aOrigin, aSrc, aSize);
|
||||
widget.node.setAttribute("closemenu", "none");
|
||||
showingEvent = "ViewShowing";
|
||||
hidingEvent = "ViewHiding";
|
||||
} else {
|
||||
panel = aWindow.document.getElementById(aType + "-notification-panel");
|
||||
PanelFrameInternal._attachNotificatonPanel(aWindow, panel, aToolbarButton, aType, aOrigin, aSrc, aSize);
|
||||
showingEvent = "popupshown";
|
||||
hidingEvent = "popuphidden";
|
||||
}
|
||||
let panel = aWindow.document.getElementById(aType + "-notification-panel");
|
||||
PanelFrameInternal._attachNotificatonPanel(aWindow, panel, aToolbarButton, aType, aOrigin, aSrc, aSize);
|
||||
|
||||
let notificationFrameId = aToolbarButton.getAttribute("notificationFrameId");
|
||||
let notificationFrame = aWindow.document.getElementById(notificationFrameId);
|
||||
|
||||
SharedFrame.setOwner(notificationFrameId, notificationFrame);
|
||||
|
||||
// Clear dimensions on all browsers so the panel size will
|
||||
// only use the selected browser.
|
||||
@ -153,21 +142,21 @@ let PanelFrame = {
|
||||
|
||||
// we only use a dynamic resizer when we're located the toolbar.
|
||||
let dynamicResizer;
|
||||
if (!inMenuPanel && notificationFrame.getAttribute("dynamicresizer") == "true") {
|
||||
if (notificationFrame.getAttribute("dynamicresizer") == "true") {
|
||||
dynamicResizer = PanelFrameInternal._dynamicResizer;
|
||||
}
|
||||
panel.addEventListener(hidingEvent, function onpopuphiding() {
|
||||
panel.removeEventListener(hidingEvent, onpopuphiding);
|
||||
if (!inMenuPanel)
|
||||
anchorBtn.removeAttribute("open");
|
||||
panel.addEventListener("popuphidden", function onpopuphiding() {
|
||||
panel.removeEventListener("popuphidden", onpopuphiding);
|
||||
anchorBtn.removeAttribute("open");
|
||||
if (dynamicResizer)
|
||||
dynamicResizer.stop();
|
||||
notificationFrame.docShell.isActive = false;
|
||||
dispatchPanelEvent(aType + "FrameHide");
|
||||
});
|
||||
|
||||
panel.addEventListener(showingEvent, function onpopupshown() {
|
||||
panel.removeEventListener(showingEvent, onpopupshown);
|
||||
panel.addEventListener("popupshown", function onpopupshown() {
|
||||
panel.removeEventListener("popupshown", onpopupshown);
|
||||
SharedFrame.setOwner(notificationFrameId, notificationFrame);
|
||||
// This attribute is needed on both the button and the
|
||||
// containing toolbaritem since the buttons on OS X have
|
||||
// moz-appearance:none, while their container gets
|
||||
@ -180,8 +169,7 @@ let PanelFrame = {
|
||||
dynamicResizer.start(panel, notificationFrame);
|
||||
dispatchPanelEvent(aType + "FrameShow");
|
||||
};
|
||||
if (!inMenuPanel)
|
||||
anchorBtn.setAttribute("open", "true");
|
||||
anchorBtn.setAttribute("open", "true");
|
||||
if (notificationFrame.contentDocument &&
|
||||
notificationFrame.contentDocument.readyState == "complete") {
|
||||
initFrameShow();
|
||||
@ -194,19 +182,14 @@ let PanelFrame = {
|
||||
}
|
||||
});
|
||||
|
||||
if (inMenuPanel) {
|
||||
aPanelUI.showSubView("PanelUI-" + aType + "api", widget.node,
|
||||
CustomizableUI.AREA_PANEL);
|
||||
} else {
|
||||
// in overflow, the anchor is a normal toolbarbutton, in toolbar it is a badge button
|
||||
let anchor = aWindow.document.getAnonymousElementByAttribute(anchorBtn, "class", "toolbarbutton-badge-container") ||
|
||||
aWindow.document.getAnonymousElementByAttribute(anchorBtn, "class", "toolbarbutton-icon");
|
||||
// Bug 849216 - open the popup asynchronously so we avoid the auto-rollup
|
||||
// handling from preventing it being opened in some cases.
|
||||
Services.tm.mainThread.dispatch(function() {
|
||||
panel.openPopup(anchor, "bottomcenter topright", 0, 0, false, false);
|
||||
}, Ci.nsIThread.DISPATCH_NORMAL);
|
||||
}
|
||||
// in overflow, the anchor is a normal toolbarbutton, in toolbar it is a badge button
|
||||
let anchor = aWindow.document.getAnonymousElementByAttribute(anchorBtn, "class", "toolbarbutton-badge-container") ||
|
||||
aWindow.document.getAnonymousElementByAttribute(anchorBtn, "class", "toolbarbutton-icon");
|
||||
// Bug 849216 - open the popup asynchronously so we avoid the auto-rollup
|
||||
// handling from preventing it being opened in some cases.
|
||||
Services.tm.mainThread.dispatch(function() {
|
||||
panel.openPopup(anchor, "bottomcenter topright", 0, 0, false, false);
|
||||
}, Ci.nsIThread.DISPATCH_NORMAL);
|
||||
|
||||
if (aCallback)
|
||||
aCallback(notificationFrame);
|
||||
|
@ -363,8 +363,7 @@ SocialErrorListener.prototype = {
|
||||
if (failure && aStatus != Components.results.NS_BINDING_ABORTED) {
|
||||
aRequest.cancel(Components.results.NS_BINDING_ABORTED);
|
||||
let provider = Social._getProviderFromOrigin(this.iframe.getAttribute("origin"));
|
||||
if (provider && !provider.errorState)
|
||||
provider.errorState = "content-error";
|
||||
provider.errorState = "content-error";
|
||||
this.setErrorMessage(aWebProgress.QueryInterface(Ci.nsIDocShell)
|
||||
.chromeEventHandler);
|
||||
}
|
||||
@ -374,7 +373,7 @@ SocialErrorListener.prototype = {
|
||||
if (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE) {
|
||||
aRequest.cancel(Components.results.NS_BINDING_ABORTED);
|
||||
let provider = Social._getProviderFromOrigin(this.iframe.getAttribute("origin"));
|
||||
if (provider && !provider.errorState)
|
||||
if (!provider.errorState)
|
||||
provider.errorState = "content-error";
|
||||
schedule(function() {
|
||||
this.setErrorMessage(aWebProgress.QueryInterface(Ci.nsIDocShell)
|
||||
|
@ -1313,11 +1313,6 @@ toolbar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-ic
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
#add-share-provider {
|
||||
list-style-image: url(chrome://browser/skin/menuPanel-small@2x.png);
|
||||
-moz-image-region: rect(0px, 192px, 32px, 160px);
|
||||
}
|
||||
|
||||
#loop-call-button > .toolbarbutton-badge-container {
|
||||
list-style-image: url("chrome://browser/skin/loop/toolbar@2x.png");
|
||||
-moz-image-region: rect(0, 36px, 36px, 0);
|
||||
|
@ -218,8 +218,3 @@ toolbarpaletteitem[place="palette"] > #zoom-controls > #zoom-out-button {
|
||||
toolbarpaletteitem[place="palette"] > #zoom-controls > #zoom-in-button {
|
||||
-moz-image-region: rect(0px, 96px, 16px, 80px);
|
||||
}
|
||||
|
||||
#add-share-provider {
|
||||
list-style-image: url(chrome://browser/skin/menuPanel-small.png);
|
||||
-moz-image-region: rect(0px, 96px, 16px, 80px);
|
||||
}
|
@ -450,11 +450,29 @@ public abstract class GeckoApp
|
||||
try {
|
||||
clearObj.put(clear, true);
|
||||
} catch(JSONException ex) {
|
||||
Log.i(LOGTAG, "Error adding clear object " + clear);
|
||||
Log.e(LOGTAG, "Error adding clear object " + clear, ex);
|
||||
}
|
||||
}
|
||||
|
||||
GeckoAppShell.notifyGeckoOfEvent(GeckoEvent.createBroadcastEvent("Browser:Quit", clearObj.toString()));
|
||||
final JSONObject res = new JSONObject();
|
||||
try {
|
||||
res.put("sanitize", clearObj);
|
||||
} catch(JSONException ex) {
|
||||
Log.e(LOGTAG, "Error adding sanitize object", ex);
|
||||
}
|
||||
|
||||
// If the user has opted out of session restore, and does want to clear history
|
||||
// we also want to prevent the current session info from being saved.
|
||||
if (clearObj.has("private.data.history")) {
|
||||
final String sessionRestore = getSessionRestorePreference();
|
||||
try {
|
||||
res.put("dontSaveSession", "quit".equals(sessionRestore));
|
||||
} catch(JSONException ex) {
|
||||
Log.e(LOGTAG, "Error adding session restore data", ex);
|
||||
}
|
||||
}
|
||||
|
||||
GeckoAppShell.notifyGeckoOfEvent(GeckoEvent.createBroadcastEvent("Browser:Quit", res.toString()));
|
||||
} else {
|
||||
GeckoAppShell.systemExit();
|
||||
}
|
||||
|
@ -6,6 +6,9 @@
|
||||
package org.mozilla.gecko;
|
||||
|
||||
import org.mozilla.gecko.mozglue.JNITarget;
|
||||
import org.mozilla.gecko.util.NativeEventListener;
|
||||
import org.mozilla.gecko.util.NativeJSObject;
|
||||
import org.mozilla.gecko.util.EventCallback;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
@ -31,7 +34,7 @@ import android.util.Log;
|
||||
* connection type defined in Network Information API version 3.
|
||||
*/
|
||||
|
||||
public class GeckoNetworkManager extends BroadcastReceiver {
|
||||
public class GeckoNetworkManager extends BroadcastReceiver implements NativeEventListener {
|
||||
private static final String LOGTAG = "GeckoNetworkManager";
|
||||
|
||||
static private final GeckoNetworkManager sInstance = new GeckoNetworkManager();
|
||||
@ -93,6 +96,8 @@ public class GeckoNetworkManager extends BroadcastReceiver {
|
||||
if (mShouldNotify) {
|
||||
startListening();
|
||||
}
|
||||
|
||||
EventDispatcher.getInstance().registerGeckoThreadListener((NativeEventListener)this, "Wifi:Enable");
|
||||
}
|
||||
|
||||
private void startListening() {
|
||||
@ -112,6 +117,25 @@ public class GeckoNetworkManager extends BroadcastReceiver {
|
||||
if (mShouldNotify) {
|
||||
stopListening();
|
||||
}
|
||||
|
||||
EventDispatcher.getInstance().unregisterGeckoThreadListener((NativeEventListener)this, "Wifi:Enable");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(final String event, final NativeJSObject message,
|
||||
final EventCallback callback) {
|
||||
if (event.equals("Wifi:Enable")) {
|
||||
final WifiManager mgr = (WifiManager) mApplicationContext.getSystemService(Context.WIFI_SERVICE);
|
||||
|
||||
if (!mgr.isWifiEnabled()) {
|
||||
mgr.setWifiEnabled(true);
|
||||
} else {
|
||||
// If Wifi is enabled, maybe you need to select a network
|
||||
Intent intent = new Intent(android.provider.Settings.ACTION_WIFI_SETTINGS);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
mApplicationContext.startActivity(intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void stopListening() {
|
||||
|
@ -1400,7 +1400,8 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
||||
+ " AND " + Bookmarks.URL + " IS NOT NULL)";
|
||||
|
||||
return deleteFavicons(uri, faviconSelection, null) +
|
||||
deleteThumbnails(uri, thumbnailSelection, null);
|
||||
deleteThumbnails(uri, thumbnailSelection, null) +
|
||||
URLMetadata.deleteUnused(getContext().getContentResolver());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -5,6 +5,8 @@
|
||||
*/
|
||||
package org.mozilla.gecko.db;
|
||||
|
||||
import org.mozilla.gecko.db.BrowserContract.Bookmarks;
|
||||
import org.mozilla.gecko.db.BrowserContract.History;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
import org.mozilla.gecko.Telemetry;
|
||||
|
||||
@ -187,4 +189,18 @@ public class URLMetadata {
|
||||
Log.e(LOGTAG, "error saving", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static int deleteUnused(final ContentResolver cr) {
|
||||
final String selection = URLMetadataTable.URL_COLUMN + " NOT IN "
|
||||
+ "(SELECT " + History.URL
|
||||
+ " FROM " + History.TABLE_NAME
|
||||
+ " WHERE " + History.IS_DELETED + " = 0"
|
||||
+ " UNION "
|
||||
+ " SELECT " + Bookmarks.URL
|
||||
+ " FROM " + Bookmarks.TABLE_NAME
|
||||
+ " WHERE " + Bookmarks.IS_DELETED + " = 0 "
|
||||
+ " AND " + Bookmarks.URL + " IS NOT NULL)";
|
||||
|
||||
return cr.delete(URLMetadataTable.CONTENT_URI, selection, null);
|
||||
}
|
||||
}
|
||||
|
@ -388,6 +388,7 @@ gbjar.sources += [
|
||||
'tabs/RemoteTabsPanel.java',
|
||||
'tabs/RemoteTabsSetupPanel.java',
|
||||
'tabs/RemoteTabsVerificationPanel.java',
|
||||
'tabs/TabCurve.java',
|
||||
'tabs/TabsPanel.java',
|
||||
'tabs/TabsTray.java',
|
||||
'TabsAccessor.java',
|
||||
@ -402,9 +403,11 @@ gbjar.sources += [
|
||||
'toolbar/CanvasDelegate.java',
|
||||
'toolbar/ForwardButton.java',
|
||||
'toolbar/PageActionLayout.java',
|
||||
'toolbar/PhoneTabsButton.java',
|
||||
'toolbar/ShapedButton.java',
|
||||
'toolbar/SiteIdentityPopup.java',
|
||||
'toolbar/TabCounter.java',
|
||||
'toolbar/TabletTabsButton.java',
|
||||
'toolbar/ToolbarDisplayLayout.java',
|
||||
'toolbar/ToolbarEditLayout.java',
|
||||
'toolbar/ToolbarEditText.java',
|
||||
|
Before Width: | Height: | Size: 507 B After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 397 B After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 842 B After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 929 B After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 385 B After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 333 B After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 608 B After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 672 B After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 586 B After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 504 B After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 959 B After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 3.3 KiB |
@ -3,18 +3,16 @@
|
||||
- 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/. -->
|
||||
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:gecko="http://schemas.android.com/apk/res-auto">
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<org.mozilla.gecko.toolbar.ShapedButton android:id="@+id/tabs"
|
||||
style="@style/UrlBar.ImageButton"
|
||||
android:layout_width="84dip"
|
||||
android:layout_alignParentLeft="true"
|
||||
gecko:curveTowards="left"
|
||||
android:background="@drawable/shaped_button"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingLeft="6dip"
|
||||
android:paddingRight="38dip"/>
|
||||
<org.mozilla.gecko.toolbar.TabletTabsButton android:id="@+id/tabs"
|
||||
style="@style/UrlBar.ImageButton"
|
||||
android:layout_width="84dip"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:background="@drawable/shaped_button"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingLeft="6dip"
|
||||
android:paddingRight="38dip"/>
|
||||
|
||||
<!-- The TextSwitcher should be shifted 28dp on the right, to avoid
|
||||
the curve. On a 56dp space, centering 24dp image will leave
|
||||
|
@ -3,8 +3,7 @@
|
||||
- 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/. -->
|
||||
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:gecko="http://schemas.android.com/apk/res-auto">
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<ImageButton android:id="@+id/back"
|
||||
style="@style/UrlBar.ImageButton.Unused"/>
|
||||
@ -66,13 +65,12 @@
|
||||
android:src="@drawable/menu_level"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<org.mozilla.gecko.toolbar.ShapedButton android:id="@+id/tabs"
|
||||
style="@style/UrlBar.ImageButton"
|
||||
android:layout_width="64dip"
|
||||
android:layout_toLeftOf="@id/menu"
|
||||
android:layout_alignWithParentIfMissing="true"
|
||||
gecko:curveTowards="right"
|
||||
android:background="@drawable/shaped_button"/>
|
||||
<org.mozilla.gecko.toolbar.PhoneTabsButton android:id="@+id/tabs"
|
||||
style="@style/UrlBar.ImageButton"
|
||||
android:layout_width="64dip"
|
||||
android:layout_toLeftOf="@id/menu"
|
||||
android:layout_alignWithParentIfMissing="true"
|
||||
android:background="@drawable/shaped_button"/>
|
||||
|
||||
<!-- The TextSwitcher should be shifted 24dp on the left, to avoid
|
||||
the curve. On a 48dp space, centering 24dp image will leave
|
||||
|
@ -8,7 +8,7 @@
|
||||
<style name="UrlBar.ImageButton.Forward">
|
||||
<item name="android:contentDescription">@string/forward</item>
|
||||
<item name="android:layout_width">45dip</item>
|
||||
<item name="android:layout_height">36dip</item>
|
||||
<item name="android:layout_height">37dip</item>
|
||||
<item name="android:paddingLeft">10dp</item>
|
||||
<item name="android:paddingTop">7dp</item>
|
||||
<item name="android:paddingBottom">7dp</item>
|
||||
|
@ -92,14 +92,6 @@
|
||||
<attr name="entryKeys" format="string"/>
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="BrowserToolbarCurve">
|
||||
<attr name="curveTowards">
|
||||
<flag name="none" value="0x00" />
|
||||
<flag name="left" value="0x01" />
|
||||
<flag name="right" value ="0x02" />
|
||||
</attr>
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="TabsTray">
|
||||
<attr name="tabs">
|
||||
<flag name="tabs_normal" value="0x00" />
|
||||
|
@ -53,7 +53,7 @@
|
||||
<dimen name="menu_item_more_offset">5dp</dimen>
|
||||
<dimen name="menu_popup_offset">12dp</dimen>
|
||||
<dimen name="menu_popup_width">256dp</dimen>
|
||||
<dimen name="nav_button_border_width">0.75dp</dimen>
|
||||
<dimen name="nav_button_border_width">1dp</dimen>
|
||||
<dimen name="prompt_service_group_padding_size">32dp</dimen>
|
||||
<dimen name="prompt_service_icon_size">36dp</dimen>
|
||||
<dimen name="prompt_service_icon_text_padding">10dp</dimen>
|
||||
|
68
mobile/android/base/tabs/TabCurve.java
Normal file
@ -0,0 +1,68 @@
|
||||
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
/* 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/. */
|
||||
|
||||
package org.mozilla.gecko.tabs;
|
||||
|
||||
import android.graphics.Path;
|
||||
|
||||
/**
|
||||
* Utility methods to draws Firefox's tab curve shape.
|
||||
*/
|
||||
public class TabCurve {
|
||||
|
||||
public enum Direction {
|
||||
LEFT(-1),
|
||||
RIGHT(1);
|
||||
|
||||
private final int value;
|
||||
|
||||
private Direction(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
// Curve's aspect ratio
|
||||
private static final float ASPECT_RATIO = 0.729f;
|
||||
|
||||
// Width multipliers
|
||||
private static final float W_M1 = 0.343f;
|
||||
private static final float W_M2 = 0.514f;
|
||||
private static final float W_M3 = 0.723f;
|
||||
|
||||
// Height multipliers
|
||||
private static final float H_M1 = 0.25f;
|
||||
private static final float H_M2 = 0.5f;
|
||||
private static final float H_M3 = 0.72f;
|
||||
private static final float H_M4 = 0.961f;
|
||||
|
||||
private TabCurve() {
|
||||
}
|
||||
|
||||
public static int getWidthForHeight(int height) {
|
||||
return (int) (height * ASPECT_RATIO);
|
||||
}
|
||||
|
||||
public static void drawFromTop(Path path, int from, int height, Direction dir) {
|
||||
final int width = getWidthForHeight(height);
|
||||
|
||||
path.cubicTo(from + width * W_M1 * dir.value, 0.0f,
|
||||
from + width * W_M2 * dir.value, height * H_M1,
|
||||
from + width * W_M2 * dir.value, height * H_M2);
|
||||
path.cubicTo(from + width * W_M2 * dir.value, height * H_M3,
|
||||
from + width * W_M3 * dir.value, height * H_M4,
|
||||
from + width * dir.value, height);
|
||||
}
|
||||
|
||||
public static void drawFromBottom(Path path, int from, int height, Direction dir) {
|
||||
final int width = getWidthForHeight(height);
|
||||
|
||||
path.cubicTo(from + width * (1f - W_M3) * dir.value, height * H_M4,
|
||||
from + width * (1f - W_M2) * dir.value, height * H_M3,
|
||||
from + width * (1f - W_M2) * dir.value, height * H_M2);
|
||||
path.cubicTo(from + width * (1f - W_M2) * dir.value, height * H_M1,
|
||||
from + width * (1f - W_M1) * dir.value, 0.0f,
|
||||
from + width * dir.value, 0.0f);
|
||||
}
|
||||
}
|
@ -17,25 +17,31 @@ import android.graphics.drawable.StateListDrawable;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
public class BackButton extends ShapedButton {
|
||||
private Path mPath;
|
||||
private Path mBorderPath;
|
||||
private Paint mBorderPaint;
|
||||
private Paint mBorderPrivatePaint;
|
||||
private final Path mBorderPath;
|
||||
private final Paint mBorderPaint;
|
||||
private final float mBorderWidth;
|
||||
|
||||
public BackButton(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
mBorderWidth = getResources().getDimension(R.dimen.nav_button_border_width);
|
||||
|
||||
// Paint to draw the border.
|
||||
mBorderPaint = new Paint();
|
||||
mBorderPaint.setAntiAlias(true);
|
||||
mBorderPaint.setColor(0xFF000000);
|
||||
mBorderPaint.setStrokeWidth(mBorderWidth);
|
||||
mBorderPaint.setStyle(Paint.Style.STROKE);
|
||||
|
||||
mBorderPrivatePaint = new Paint(mBorderPaint);
|
||||
|
||||
// Path is masked.
|
||||
mPath = new Path();
|
||||
mBorderPath = new Path();
|
||||
|
||||
setPrivateMode(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPrivateMode(boolean isPrivate) {
|
||||
super.setPrivateMode(isPrivate);
|
||||
mBorderPaint.setColor(isPrivate ? 0xFF363B40 : 0xFFB5B5B5);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -43,24 +49,10 @@ public class BackButton extends ShapedButton {
|
||||
super.onSizeChanged(width, height, oldWidth, oldHeight);
|
||||
|
||||
mPath.reset();
|
||||
mPath.addCircle(width/2, height/2, width/2, Path.Direction.CW);
|
||||
|
||||
float borderWidth = getContext().getResources().getDimension(R.dimen.nav_button_border_width);
|
||||
mBorderPaint.setStrokeWidth(borderWidth);
|
||||
mBorderPrivatePaint.setStrokeWidth(borderWidth);
|
||||
mPath.addCircle(width/2, height/2, width/2 - mBorderWidth, Path.Direction.CW);
|
||||
|
||||
mBorderPath.reset();
|
||||
mBorderPath.addCircle(width/2, height/2, (width/2) - borderWidth, Path.Direction.CW);
|
||||
|
||||
mBorderPaint.setShader(new LinearGradient(0, 0,
|
||||
0, height,
|
||||
0xFFB5BBC1, 0xFFFAFBFC,
|
||||
Shader.TileMode.CLAMP));
|
||||
|
||||
mBorderPrivatePaint.setShader(new LinearGradient(0, 0,
|
||||
0, height,
|
||||
0xFF040607, 0xFF0B0D0E,
|
||||
Shader.TileMode.CLAMP));
|
||||
mBorderPath.addCircle(width/2, height/2, (width/2) - mBorderWidth, Path.Direction.CW);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -68,7 +60,7 @@ public class BackButton extends ShapedButton {
|
||||
mCanvasDelegate.draw(canvas, mPath, getWidth(), getHeight());
|
||||
|
||||
// Draw the border on top.
|
||||
canvas.drawPath(mBorderPath, isPrivateMode() ? mBorderPrivatePaint : mBorderPaint);
|
||||
canvas.drawPath(mBorderPath, mBorderPaint);
|
||||
}
|
||||
|
||||
// The drawable is constructed as per @drawable/url_bar_nav_button.
|
||||
|
@ -17,45 +17,39 @@ import android.graphics.drawable.StateListDrawable;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
public class ForwardButton extends ShapedButton {
|
||||
private Path mBorderPath;
|
||||
private Paint mBorderPaint;
|
||||
private Paint mBorderPrivatePaint;
|
||||
private final Path mBorderPath;
|
||||
private final Paint mBorderPaint;
|
||||
private final float mBorderWidth;
|
||||
|
||||
public ForwardButton(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
mBorderWidth = getResources().getDimension(R.dimen.nav_button_border_width);
|
||||
|
||||
// Paint to draw the border.
|
||||
mBorderPaint = new Paint();
|
||||
mBorderPaint.setAntiAlias(true);
|
||||
mBorderPaint.setColor(0xFF000000);
|
||||
mBorderPaint.setStrokeWidth(mBorderWidth);
|
||||
mBorderPaint.setStyle(Paint.Style.STROKE);
|
||||
|
||||
mBorderPrivatePaint = new Paint(mBorderPaint);
|
||||
|
||||
mBorderPath = new Path();
|
||||
|
||||
setPrivateMode(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPrivateMode(boolean isPrivate) {
|
||||
super.setPrivateMode(isPrivate);
|
||||
mBorderPaint.setColor(isPrivate ? 0xFF363B40 : 0xFFBFBFBF);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
|
||||
super.onSizeChanged(width, height, oldWidth, oldHeight);
|
||||
|
||||
float borderWidth = getContext().getResources().getDimension(R.dimen.nav_button_border_width);
|
||||
mBorderPaint.setStrokeWidth(borderWidth);
|
||||
mBorderPrivatePaint.setStrokeWidth(borderWidth);
|
||||
|
||||
mBorderPath.reset();
|
||||
mBorderPath.moveTo(width - borderWidth, 0);
|
||||
mBorderPath.lineTo(width - borderWidth, height);
|
||||
|
||||
mBorderPaint.setShader(new LinearGradient(0, 0,
|
||||
0, height,
|
||||
0xFFB5BBC1, 0xFFFAFBFC,
|
||||
Shader.TileMode.CLAMP));
|
||||
|
||||
mBorderPrivatePaint.setShader(new LinearGradient(0, 0,
|
||||
0, height,
|
||||
0xFF040607, 0xFF0B0D0E,
|
||||
Shader.TileMode.CLAMP));
|
||||
mBorderPath.moveTo(width - mBorderWidth, 0);
|
||||
mBorderPath.lineTo(width - mBorderWidth, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -63,7 +57,7 @@ public class ForwardButton extends ShapedButton {
|
||||
super.draw(canvas);
|
||||
|
||||
// Draw the border on top.
|
||||
canvas.drawPath(mBorderPath, isPrivateMode() ? mBorderPrivatePaint : mBorderPaint);
|
||||
canvas.drawPath(mBorderPath, mBorderPaint);
|
||||
}
|
||||
|
||||
// The drawable is constructed as per @drawable/url_bar_nav_button.
|
||||
|
29
mobile/android/base/toolbar/PhoneTabsButton.java
Normal file
@ -0,0 +1,29 @@
|
||||
/* 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/. */
|
||||
|
||||
package org.mozilla.gecko.toolbar;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import org.mozilla.gecko.tabs.TabCurve;
|
||||
|
||||
public class PhoneTabsButton extends ShapedButton {
|
||||
public PhoneTabsButton(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
|
||||
super.onSizeChanged(width, height, oldWidth, oldHeight);
|
||||
|
||||
mPath.reset();
|
||||
|
||||
mPath.moveTo(0, 0);
|
||||
TabCurve.drawFromTop(mPath, 0, height, TabCurve.Direction.RIGHT);
|
||||
mPath.lineTo(width, height);
|
||||
mPath.lineTo(width, 0);
|
||||
mPath.lineTo(0, 0);
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@ import org.mozilla.gecko.GeckoApplication;
|
||||
import org.mozilla.gecko.LightweightTheme;
|
||||
import org.mozilla.gecko.LightweightThemeDrawable;
|
||||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.tabs.TabCurve;
|
||||
import org.mozilla.gecko.widget.ThemedImageButton;
|
||||
|
||||
import android.content.Context;
|
||||
@ -23,28 +24,13 @@ public class ShapedButton extends ThemedImageButton
|
||||
implements CanvasDelegate.DrawManager {
|
||||
protected final LightweightTheme mTheme;
|
||||
|
||||
private final Path mPath;
|
||||
private final CurveTowards mSide;
|
||||
|
||||
protected final Path mPath;
|
||||
protected final CanvasDelegate mCanvasDelegate;
|
||||
|
||||
private enum CurveTowards { NONE, LEFT, RIGHT };
|
||||
|
||||
public ShapedButton(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mTheme = ((GeckoApplication) context.getApplicationContext()).getLightweightTheme();
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BrowserToolbarCurve);
|
||||
int curveTowards = a.getInt(R.styleable.BrowserToolbarCurve_curveTowards, 0x00);
|
||||
a.recycle();
|
||||
|
||||
if (curveTowards == 0x00)
|
||||
mSide = CurveTowards.NONE;
|
||||
else if (curveTowards == 0x01)
|
||||
mSide = CurveTowards.LEFT;
|
||||
else
|
||||
mSide = CurveTowards.RIGHT;
|
||||
|
||||
// Path is clipped.
|
||||
mPath = new Path();
|
||||
mCanvasDelegate = new CanvasDelegate(this, Mode.DST_IN);
|
||||
@ -52,41 +38,9 @@ public class ShapedButton extends ThemedImageButton
|
||||
setWillNotDraw(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
|
||||
super.onSizeChanged(width, height, oldWidth, oldHeight);
|
||||
|
||||
if (mSide == CurveTowards.NONE)
|
||||
return;
|
||||
|
||||
mPath.reset();
|
||||
|
||||
if (mSide == CurveTowards.RIGHT) {
|
||||
mPath.moveTo(0, 0);
|
||||
mPath.cubicTo(height * 0.25f, 0.0f,
|
||||
height * 0.375f, height * 0.25f,
|
||||
height * 0.375f, height * 0.5f);
|
||||
mPath.cubicTo(height * 0.375f, height * 0.72f,
|
||||
height * 0.527f, height * 0.961f,
|
||||
height * 0.729f, height);
|
||||
mPath.lineTo(width, height);
|
||||
mPath.lineTo(width, 0);
|
||||
mPath.lineTo(0, 0);
|
||||
} else if (mSide == CurveTowards.LEFT) {
|
||||
final int curve = (int) (height * 1.125f);
|
||||
|
||||
mPath.moveTo(width, 0);
|
||||
mPath.cubicTo((width - (curve * 0.75f)), 0,
|
||||
(width - (curve * 0.25f)), height,
|
||||
(width - curve), height);
|
||||
mPath.lineTo(0, height);
|
||||
mPath.lineTo(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
if (mCanvasDelegate != null && mSide != CurveTowards.NONE)
|
||||
if (mCanvasDelegate != null)
|
||||
mCanvasDelegate.draw(canvas, mPath, getWidth(), getHeight());
|
||||
else
|
||||
defaultDraw(canvas);
|
||||
|
30
mobile/android/base/toolbar/TabletTabsButton.java
Normal file
@ -0,0 +1,30 @@
|
||||
/* 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/. */
|
||||
|
||||
package org.mozilla.gecko.toolbar;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
public class TabletTabsButton extends ShapedButton {
|
||||
public TabletTabsButton(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
|
||||
super.onSizeChanged(width, height, oldWidth, oldHeight);
|
||||
|
||||
final int curve = (int) (height * 1.125f);
|
||||
|
||||
mPath.reset();
|
||||
|
||||
mPath.moveTo(width, 0);
|
||||
mPath.cubicTo((width - (curve * 0.75f)), 0,
|
||||
(width - (curve * 0.25f)), height,
|
||||
(width - curve), height);
|
||||
mPath.lineTo(0, height);
|
||||
mPath.lineTo(0, 0);
|
||||
}
|
||||
}
|
@ -1124,7 +1124,7 @@ var BrowserApp = {
|
||||
aTab.browser.dispatchEvent(evt);
|
||||
},
|
||||
|
||||
quit: function quit(aClear = {}) {
|
||||
quit: function quit(aClear = { sanitize: {}, dontSaveSession: false }) {
|
||||
// Figure out if there's at least one other browser window around.
|
||||
let lastBrowser = true;
|
||||
let e = Services.wm.getEnumerator("navigator:browser");
|
||||
@ -1144,7 +1144,13 @@ var BrowserApp = {
|
||||
Services.obs.notifyObservers(null, "browser-lastwindow-close-granted", null);
|
||||
}
|
||||
|
||||
BrowserApp.sanitize(aClear, function() {
|
||||
// Tell session store to forget about this window
|
||||
if (aClear.dontSaveSession) {
|
||||
let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
|
||||
ss.removeWindow(window);
|
||||
}
|
||||
|
||||
BrowserApp.sanitize(aClear.sanitize, function() {
|
||||
window.QueryInterface(Ci.nsIDOMChromeWindow).minimize();
|
||||
window.close();
|
||||
});
|
||||
|
@ -299,7 +299,7 @@
|
||||
</div>
|
||||
<div id="errorDescriptionsContainer">
|
||||
<div id="ed_generic">&generic.longDesc;</div>
|
||||
<div id="ed_dnsNotFound">&dnsNotFound.longDesc2;</div>
|
||||
<div id="ed_dnsNotFound">&dnsNotFound.longDesc3;</div>
|
||||
<div id="ed_fileNotFound">&fileNotFound.longDesc;</div>
|
||||
<div id="ed_malformedURI">&malformedURI.longDesc;</div>
|
||||
<div id="ed_unknownProtocolFound">&unknownProtocolFound.longDesc;</div>
|
||||
@ -316,7 +316,7 @@
|
||||
|
||||
<div id="ed_netInterrupt">&netInterrupt.longDesc;</div>
|
||||
<div id="ed_deniedPortAccess">&deniedPortAccess.longDesc;</div>
|
||||
<div id="ed_proxyResolveFailure">&proxyResolveFailure.longDesc2;</div>
|
||||
<div id="ed_proxyResolveFailure">&proxyResolveFailure.longDesc3;</div>
|
||||
<div id="ed_proxyConnectFailure">&proxyConnectFailure.longDesc;</div>
|
||||
<div id="ed_contentEncodingError">&contentEncodingError.longDesc;</div>
|
||||
<div id="ed_unsafeContentType">&unsafeContentType.longDesc;</div>
|
||||
|
@ -14,7 +14,7 @@ interface nsIDOMNode;
|
||||
* tabs contained in them.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(5497d9a1-c378-47a9-9488-4c47a644131a)]
|
||||
[scriptable, uuid(da9ffc70-d444-47d4-b4ab-df3fb0fd24d0)]
|
||||
interface nsISessionStore : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -76,4 +76,11 @@ interface nsISessionStore : nsISupports
|
||||
* backup session file is read from.
|
||||
*/
|
||||
void restoreLastSession(in AString aSessionString);
|
||||
|
||||
/**
|
||||
* Removes a window from the current session history. Data from this window
|
||||
* won't be saved when its closed.
|
||||
* @param aWindow The window to remove
|
||||
*/
|
||||
void removeWindow(in nsIDOMWindow aWindow);
|
||||
};
|
||||
|
@ -453,7 +453,7 @@ SessionStore.prototype = {
|
||||
// indicate that there is no private data
|
||||
sendMessageToJava({
|
||||
type: "PrivateBrowsing:Data",
|
||||
session: (privateData.windows[0].tabs.length > 0) ? JSON.stringify(privateData) : null
|
||||
session: (privateData.windows.length > 0 && privateData.windows[0].tabs.length > 0) ? JSON.stringify(privateData) : null
|
||||
});
|
||||
|
||||
this._lastSaveTime = Date.now();
|
||||
@ -997,7 +997,18 @@ SessionStore.prototype = {
|
||||
}
|
||||
|
||||
Services.obs.notifyObservers(null, "sessionstore-windows-restored", notifyMessage);
|
||||
})
|
||||
}),
|
||||
|
||||
removeWindow: function ss_removeWindow(aWindow) {
|
||||
if (!aWindow || !aWindow.__SSID || !this._windows[aWindow.__SSID])
|
||||
return;
|
||||
|
||||
delete this._windows[aWindow.__SSID];
|
||||
delete aWindow.__SSID;
|
||||
|
||||
this.saveState();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SessionStore]);
|
||||
|
@ -5,7 +5,9 @@
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Messaging.jsm");
|
||||
Cu.import("resource://gre/modules/UITelemetry.jsm");
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["NetErrorHelper"];
|
||||
|
||||
@ -59,3 +61,73 @@ NetErrorHelper.prototype = {
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
handlers.wifi = {
|
||||
// This registers itself with the nsIObserverService as a weak ref,
|
||||
// so we have to implement GetWeakReference as well.
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
|
||||
GetWeakReference: function() {
|
||||
return Cu.getWeakReference(this);
|
||||
},
|
||||
|
||||
onPageShown: function(browser) {
|
||||
// If we have a connection, don't bother showing the wifi toggle.
|
||||
let network = Cc["@mozilla.org/network/network-link-service;1"].getService(Ci.nsINetworkLinkService);
|
||||
if (network.isLinkUp && network.linkStatusKnown) {
|
||||
let nodes = browser.contentDocument.querySelectorAll("#wifi");
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
nodes[i].style.display = "none";
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
handleClick: function(event) {
|
||||
let node = event.target;
|
||||
while(node && node.id !== "wifi") {
|
||||
node = node.parentNode;
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
UITelemetry.addEvent("neterror.1", "button", "wifitoggle");
|
||||
// Show indeterminate progress while we wait for the network.
|
||||
node.disabled = true;
|
||||
node.classList.add("inProgress");
|
||||
|
||||
this.node = Cu.getWeakReference(node);
|
||||
Services.obs.addObserver(this, "network:link-status-changed", true);
|
||||
|
||||
sendMessageToJava({
|
||||
type: "Wifi:Enable"
|
||||
});
|
||||
},
|
||||
|
||||
observe: function(subject, topic, data) {
|
||||
let node = this.node.get();
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove the progress bar
|
||||
node.disabled = false;
|
||||
node.classList.remove("inProgress");
|
||||
|
||||
let network = Cc["@mozilla.org/network/network-link-service;1"].getService(Ci.nsINetworkLinkService);
|
||||
if (network.isLinkUp && network.linkStatusKnown) {
|
||||
// If everything worked, reload the page
|
||||
UITelemetry.addEvent("neterror.1", "button", "wifitoggle.reload");
|
||||
Services.obs.removeObserver(this, "network:link-status-changed");
|
||||
|
||||
// Even at this point, Android sometimes lies about the real state of the network and this reload request fails.
|
||||
// Add a 500ms delay before refreshing the page.
|
||||
node.ownerDocument.defaultView.setTimeout(function() {
|
||||
node.ownerDocument.location.reload(false);
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,8 @@ body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
--moz-vertical-spacing: 10px;
|
||||
--moz-background-height: 32px;
|
||||
}
|
||||
|
||||
body {
|
||||
@ -14,7 +16,7 @@ body {
|
||||
background-image: linear-gradient(-45deg, #dfe8ee, #dfe8ee 33%,
|
||||
#ecf0f3 33%, #ecf0f3 66%,
|
||||
#dfe8ee 66%, #dfe8ee);
|
||||
background-size: 64px 32px;
|
||||
background-size: 64px var(--moz-background-height);
|
||||
background-repeat: repeat-x;
|
||||
|
||||
background-color: #f1f1f1;
|
||||
@ -30,15 +32,22 @@ body {
|
||||
ul {
|
||||
/* Shove the list indicator so that its left aligned, but use outside so that text
|
||||
* doesn't don't wrap the text around it */
|
||||
padding: 1em;
|
||||
padding: 0 1em;
|
||||
margin: 0;
|
||||
list-style: round outside none;
|
||||
}
|
||||
|
||||
li:not(:last-of-type),
|
||||
#errorLongDesc,
|
||||
#errorLongContent {
|
||||
padding-bottom: 10px;
|
||||
#errorShortDesc,
|
||||
li:not(:last-of-type) {
|
||||
/* Margins between the li and buttons below it won't be collapsed. Remove the bottom margin here. */
|
||||
margin: var(--moz-vertical-spacing) 0;
|
||||
}
|
||||
|
||||
li > button {
|
||||
/* Removing the normal padding on the li so this stretched edge to edge. */
|
||||
margin-left: -1em;
|
||||
margin-right: -1em;
|
||||
width: calc(100% + 2em);
|
||||
}
|
||||
|
||||
/* Push the #ignoreWarningButton to the bottom on the blocked site page */
|
||||
@ -47,7 +56,9 @@ li:not(:last-of-type),
|
||||
}
|
||||
|
||||
h1 {
|
||||
padding: 1rem 0;
|
||||
margin: 0;
|
||||
/* Since this has an underline, use padding for vertical spacing rather than margin */
|
||||
padding: var(--moz-vertical-spacing) 0;
|
||||
font-weight: 300;
|
||||
border-bottom: 1px solid #e0e2e5;
|
||||
}
|
||||
@ -55,27 +66,39 @@ h1 {
|
||||
h2 {
|
||||
font-size: small;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
margin: var(--moz-vertical-spacing) 0;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin: var(--moz-vertical-spacing) 0;
|
||||
}
|
||||
|
||||
button {
|
||||
/* Force buttons to display: block here to try and enfoce collapsing margins */
|
||||
display: block;
|
||||
width: 100%;
|
||||
border: none;
|
||||
padding: 1rem;
|
||||
font-family: sans-serif;
|
||||
background-color: #e0e2e5;
|
||||
font-size: 1rem; /* Not sure why this has to be specified. See bug 892843. */
|
||||
font-weight: 300;
|
||||
border-radius: 2px;
|
||||
background-image: none;
|
||||
margin: var(--moz-vertical-spacing) 0 0;
|
||||
}
|
||||
|
||||
button + button {
|
||||
margin-top: 1em;
|
||||
button.inProgress {
|
||||
background-image: linear-gradient(-45deg, #dfe8ee, #dfe8ee 33%,
|
||||
#ecf0f3 33%, #ecf0f3 66%,
|
||||
#dfe8ee 66%, #dfe8ee);
|
||||
background-size: 37px 5px;
|
||||
background-repeat: repeat-x;
|
||||
animation: progress 6s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes progress {
|
||||
from { background-position: 0 100%; }
|
||||
to { background-position: 100% 100%; }
|
||||
}
|
||||
|
||||
.certerror {
|
||||
@ -96,11 +119,11 @@ button + button {
|
||||
/* If the page is greater than 550px center the content.
|
||||
* This number should be kept in sync with the media query for tablets below */
|
||||
max-width: 550px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding-top: 1rem;
|
||||
margin: 0 auto;
|
||||
transform: translateY(var(--moz-background-height));
|
||||
padding-bottom: var(--moz-vertical-spacing);
|
||||
|
||||
min-height: calc(100% - 1rem);
|
||||
min-height: calc(100% - var(--moz-background-height) - var(--moz-vertical-spacing));
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
@ -113,7 +136,7 @@ button + button {
|
||||
*
|
||||
* This shows an arrow to the right of the h2 element, and hides the content when collapsed="true". */
|
||||
.expander {
|
||||
margin: 1rem 0;
|
||||
margin: var(--moz-vertical-spacing) 0;
|
||||
background-image: url("chrome://browser/skin/images/dropmarker.svg");
|
||||
background-repeat: no-repeat;
|
||||
/* dropmarker.svg is 10x7. Ensure that its centered in the middle of an 18x18 box */
|
||||
@ -122,12 +145,6 @@ button + button {
|
||||
padding-left: 18px;
|
||||
}
|
||||
|
||||
.expander:first-of-type {
|
||||
/* Double the margin here so that the space above the first expander
|
||||
* is the same as the space between multiple expanders */
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
div[collapsed="true"] > .expander {
|
||||
background-image: url("chrome://browser/skin/images/dropmarker-right.svg");
|
||||
/* dropmarker.svg is 7x10. Ensure that its centered in the middle of an 18x18 box */
|
||||
@ -174,10 +191,6 @@ div[collapsed="true"] > .expander + * {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
button + button {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* If the tablet is tall as well, add some padding to make content feel a bit more centered */
|
||||
@media (min-height: 550px) {
|
||||
#errorPageContainer {
|
||||
@ -185,6 +198,4 @@ div[collapsed="true"] > .expander + * {
|
||||
min-height: calc(100% - 64px);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -11,18 +11,20 @@
|
||||
<!-- Specific error messages -->
|
||||
|
||||
<!ENTITY connectionFailure.title "Unable to connect">
|
||||
<!ENTITY connectionFailure.longDesc "&sharedLongDesc2;">
|
||||
<!ENTITY connectionFailure.longDesc "&sharedLongDesc3;">
|
||||
|
||||
<!ENTITY deniedPortAccess.title "This address is restricted">
|
||||
<!ENTITY deniedPortAccess.longDesc "">
|
||||
|
||||
<!ENTITY dnsNotFound.title "Server not found">
|
||||
<!ENTITY dnsNotFound.longDesc2 "
|
||||
<!ENTITY dnsNotFound.longDesc3 "
|
||||
<ul>
|
||||
<li>Check the address for typing errors such as
|
||||
<strong>ww</strong>.example.com instead of
|
||||
<strong>www</strong>.example.com</li>
|
||||
<li>If you are unable to load any pages, check your device's data or Wi-Fi connection.</li>
|
||||
<li>If you are unable to load any pages, check your device's data or Wi-Fi connection.
|
||||
<button id='wifi'>Enable Wi-Fi</button>
|
||||
</li>
|
||||
</ul>
|
||||
">
|
||||
|
||||
@ -51,15 +53,17 @@
|
||||
">
|
||||
|
||||
<!ENTITY netInterrupt.title "The connection was interrupted">
|
||||
<!ENTITY netInterrupt.longDesc "&sharedLongDesc2;">
|
||||
<!ENTITY netInterrupt.longDesc "&sharedLongDesc3;">
|
||||
|
||||
<!ENTITY notCached.title "Document Expired">
|
||||
<!ENTITY notCached.longDesc "<p>The requested document is not available in &brandShortName;'s cache.</p><ul><li>As a security precaution, &brandShortName; does not automatically re-request sensitive documents.</li><li>Click Try Again to re-request the document from the website.</li></ul>">
|
||||
|
||||
<!ENTITY netOffline.title "Offline mode">
|
||||
<!ENTITY netOffline.longDesc2 "
|
||||
<!ENTITY netOffline.longDesc3 "
|
||||
<ul>
|
||||
<li>Try again. &brandShortName; will attempt to open a connection and reload the page.</li>
|
||||
<li>Try again. &brandShortName; will attempt to open a connection and reload the page.
|
||||
<button id='wifi'>Enable Wi-Fi</button>
|
||||
</li>
|
||||
</ul>
|
||||
">
|
||||
|
||||
@ -78,10 +82,10 @@
|
||||
">
|
||||
|
||||
<!ENTITY netReset.title "The connection was reset">
|
||||
<!ENTITY netReset.longDesc "&sharedLongDesc2;">
|
||||
<!ENTITY netReset.longDesc "&sharedLongDesc3;">
|
||||
|
||||
<!ENTITY netTimeout.title "The connection has timed out">
|
||||
<!ENTITY netTimeout.longDesc "&sharedLongDesc2;">
|
||||
<!ENTITY netTimeout.longDesc "&sharedLongDesc3;">
|
||||
|
||||
<!ENTITY unknownProtocolFound.title "The address wasn't understood">
|
||||
<!ENTITY unknownProtocolFound.longDesc "
|
||||
@ -100,10 +104,12 @@
|
||||
">
|
||||
|
||||
<!ENTITY proxyResolveFailure.title "Unable to find the proxy server">
|
||||
<!ENTITY proxyResolveFailure.longDesc2 "
|
||||
<!ENTITY proxyResolveFailure.longDesc3 "
|
||||
<ul>
|
||||
<li>Check the proxy settings to make sure that they are correct.</li>
|
||||
<li>Check to make sure your device has a working data or Wi-Fi connection.</li>
|
||||
<li>Check to make sure your device has a working data or Wi-Fi connection.
|
||||
<button id='wifi'>Enable Wi-Fi</button>
|
||||
</li>
|
||||
</ul>
|
||||
">
|
||||
|
||||
@ -142,10 +148,12 @@ be temporary, and you can try again later.</li>
|
||||
</ul>
|
||||
">
|
||||
|
||||
<!ENTITY sharedLongDesc2 "
|
||||
<!ENTITY sharedLongDesc3 "
|
||||
<ul>
|
||||
<li>The site could be temporarily unavailable or too busy. Try again in a few moments.</li>
|
||||
<li>If you are unable to load any pages, check your mobile device's data or Wi-Fi connection.</li>
|
||||
<li>If you are unable to load any pages, check your mobile device's data or Wi-Fi connection.
|
||||
<button id='wifi'>Enable Wi-Fi</button>
|
||||
</li>
|
||||
</ul>
|
||||
">
|
||||
|
||||
|
@ -549,21 +549,29 @@ AbstractFile.removeRecursive = function(path, options = {}) {
|
||||
* does not support security descriptors.
|
||||
*/
|
||||
AbstractFile.makeDir = function(path, options = {}) {
|
||||
if (!options.from) {
|
||||
let from = options.from;
|
||||
if (!from) {
|
||||
OS.File._makeDir(path, options);
|
||||
return;
|
||||
}
|
||||
if (!path.startsWith(options.from)) {
|
||||
throw new Error("Incorrect use of option |from|: " + path + " is not a descendant of " + options.from);
|
||||
if (!path.startsWith(from)) {
|
||||
// Apparently, `from` is not a parent of `path`. However, we may
|
||||
// have false negatives due to non-normalized paths, e.g.
|
||||
// "foo//bar" is a parent of "foo/bar/sna".
|
||||
path = Path.normalize(path);
|
||||
from = Path.normalize(from);
|
||||
if (!path.startsWith(from)) {
|
||||
throw new Error("Incorrect use of option |from|: " + path + " is not a descendant of " + from);
|
||||
}
|
||||
}
|
||||
let innerOptions = Object.create(options, {
|
||||
ignoreExisting: {
|
||||
value: true
|
||||
}
|
||||
});
|
||||
// Compute the elements that appear in |path| but not in |options.from|.
|
||||
let items = Path.split(path).components.slice(Path.split(options.from).components.length);
|
||||
let current = options.from;
|
||||
// Compute the elements that appear in |path| but not in |from|.
|
||||
let items = Path.split(path).components.slice(Path.split(from).components.length);
|
||||
let current = from;
|
||||
for (let item of items) {
|
||||
current = Path.join(current, item);
|
||||
OS.File._makeDir(current, innerOptions);
|
||||
|
@ -78,6 +78,9 @@ exports.dirname = dirname;
|
||||
* var path = OS.Path.join(tmpDir, "foo", "bar");
|
||||
*
|
||||
* Under Unix, this will return "/tmp/foo/bar".
|
||||
*
|
||||
* Empty components are ignored, i.e. `OS.Path.join("foo", "", "bar)` is the
|
||||
* same as `OS.Path.join("foo", "bar")`.
|
||||
*/
|
||||
let join = function(...path) {
|
||||
// If there is a path that starts with a "/", eliminate everything before
|
||||
@ -86,7 +89,9 @@ let join = function(...path) {
|
||||
if (subpath == null) {
|
||||
throw new TypeError("invalid path component");
|
||||
}
|
||||
if (subpath.length != 0 && subpath[0] == "/") {
|
||||
if (subpath.length == 0) {
|
||||
continue;
|
||||
} else if (subpath[0] == "/") {
|
||||
paths = [subpath];
|
||||
} else {
|
||||
paths.push(subpath);
|
||||
|
@ -135,6 +135,9 @@ exports.dirname = dirname;
|
||||
* var path = OS.Path.join(tmpDir, "foo", "bar");
|
||||
*
|
||||
* Under Windows, this will return "$TMP\foo\bar".
|
||||
*
|
||||
* Empty components are ignored, i.e. `OS.Path.join("foo", "", "bar)` is the
|
||||
* same as `OS.Path.join("foo", "bar")`.
|
||||
*/
|
||||
let join = function(...path) {
|
||||
let paths = [];
|
||||
@ -144,6 +147,9 @@ let join = function(...path) {
|
||||
if (subpath == null) {
|
||||
throw new TypeError("invalid path component");
|
||||
}
|
||||
if (subpath == "") {
|
||||
continue;
|
||||
}
|
||||
let drive = this.winGetDrive(subpath);
|
||||
if (drive) {
|
||||
root = drive;
|
||||
|
@ -120,4 +120,23 @@ add_task(function test_option_from() {
|
||||
do_check_true(!!exception);
|
||||
do_check_true(exception instanceof OS.File.Error);
|
||||
do_check_true(exception.becauseNoSuchFile);
|
||||
|
||||
// Test edge cases on paths
|
||||
|
||||
let dir3 = Path.join(profileDir, "d", "", "e", "f");
|
||||
do_check_false((yield OS.File.exists(dir3)));
|
||||
yield OS.File.makeDir(dir3, {from: profileDir});
|
||||
do_check_true((yield OS.File.exists(dir3)));
|
||||
|
||||
let dir4;
|
||||
if (OS.Constants.Win) {
|
||||
// Test that we can create a directory recursively even
|
||||
// if we have too many "\\".
|
||||
dir4 = profileDir + "\\\\g";
|
||||
} else {
|
||||
dir4 = profileDir + "////g";
|
||||
}
|
||||
do_check_false((yield OS.File.exists(dir4)));
|
||||
yield OS.File.makeDir(dir4, {from: profileDir});
|
||||
do_check_true((yield OS.File.exists(dir4)));
|
||||
});
|
||||
|
@ -585,24 +585,26 @@ this.SocialService = {
|
||||
action, [], options);
|
||||
},
|
||||
|
||||
installProvider: function(aDOMDocument, data, installCallback, options={}) {
|
||||
installProvider: function(aDOMDocument, data, installCallback, aBypassUserEnable=false) {
|
||||
let manifest;
|
||||
let installOrigin = aDOMDocument.nodePrincipal.origin;
|
||||
|
||||
let installType = getOriginActivationType(installOrigin);
|
||||
// if we get data, we MUST have a valid manifest generated from the data
|
||||
manifest = this._manifestFromData(installType, data, aDOMDocument.nodePrincipal);
|
||||
if (!manifest)
|
||||
throw new Error("SocialService.installProvider: service configuration is invalid from " + aDOMDocument.location.href);
|
||||
if (data) {
|
||||
let installType = getOriginActivationType(installOrigin);
|
||||
// if we get data, we MUST have a valid manifest generated from the data
|
||||
manifest = this._manifestFromData(installType, data, aDOMDocument.nodePrincipal);
|
||||
if (!manifest)
|
||||
throw new Error("SocialService.installProvider: service configuration is invalid from " + aDOMDocument.location.href);
|
||||
|
||||
let addon = new AddonWrapper(manifest);
|
||||
if (addon && addon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED)
|
||||
throw new Error("installProvider: provider with origin [" +
|
||||
installOrigin + "] is blocklisted");
|
||||
// manifestFromData call above will enforce correct origin. To support
|
||||
// activation from about: uris, we need to be sure to use the updated
|
||||
// origin on the manifest.
|
||||
installOrigin = manifest.origin;
|
||||
let addon = new AddonWrapper(manifest);
|
||||
if (addon && addon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED)
|
||||
throw new Error("installProvider: provider with origin [" +
|
||||
installOrigin + "] is blocklisted");
|
||||
// manifestFromData call above will enforce correct origin. To support
|
||||
// activation from about: uris, we need to be sure to use the updated
|
||||
// origin on the manifest.
|
||||
installOrigin = manifest.origin;
|
||||
}
|
||||
|
||||
let id = getAddonIDFromOrigin(installOrigin);
|
||||
AddonManager.getAddonByID(id, function(aAddon) {
|
||||
@ -611,7 +613,7 @@ this.SocialService = {
|
||||
aAddon.userDisabled = false;
|
||||
}
|
||||
schedule(function () {
|
||||
this._installProvider(aDOMDocument, manifest, options, aManifest => {
|
||||
this._installProvider(aDOMDocument, manifest, aBypassUserEnable, aManifest => {
|
||||
this._notifyProviderListeners("provider-installed", aManifest.origin);
|
||||
installCallback(aManifest);
|
||||
});
|
||||
@ -619,21 +621,43 @@ this.SocialService = {
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
_installProvider: function(aDOMDocument, manifest, options, installCallback) {
|
||||
if (!manifest)
|
||||
throw new Error("Cannot install provider without manifest data");
|
||||
_installProvider: function(aDOMDocument, manifest, aBypassUserEnable, installCallback) {
|
||||
let sourceURI = aDOMDocument.location.href;
|
||||
let installOrigin = aDOMDocument.nodePrincipal.origin;
|
||||
|
||||
let installType = getOriginActivationType(aDOMDocument.nodePrincipal.origin);
|
||||
if (installType == "foreign" && !Services.prefs.getBoolPref("social.remote-install.enabled"))
|
||||
throw new Error("Remote install of services is disabled");
|
||||
let installType = getOriginActivationType(installOrigin);
|
||||
let installer;
|
||||
switch(installType) {
|
||||
case "foreign":
|
||||
if (!Services.prefs.getBoolPref("social.remote-install.enabled"))
|
||||
throw new Error("Remote install of services is disabled");
|
||||
if (!manifest)
|
||||
throw new Error("Cannot install provider without manifest data");
|
||||
|
||||
let installer = new AddonInstaller(aDOMDocument.location.href, manifest, installCallback);
|
||||
let bypassPanel = options.bypassInstallPanel ||
|
||||
(installType == "internal" && manifest.oneclick);
|
||||
if (bypassPanel)
|
||||
installer.install();
|
||||
else
|
||||
this._showInstallNotification(aDOMDocument, installer);
|
||||
installer = new AddonInstaller(sourceURI, manifest, installCallback);
|
||||
this._showInstallNotification(aDOMDocument, installer);
|
||||
break;
|
||||
case "internal":
|
||||
// double check here since "builtin" falls through this as well.
|
||||
aBypassUserEnable = installType == "internal" && manifest.oneclick;
|
||||
case "directory":
|
||||
// a manifest is requried, and will have been vetted by reviewers. We
|
||||
// also handle in-product installations without the verification step.
|
||||
if (aBypassUserEnable) {
|
||||
installer = new AddonInstaller(sourceURI, manifest, installCallback);
|
||||
installer.install();
|
||||
return;
|
||||
}
|
||||
// a manifest is required, we'll catch a missing manifest below.
|
||||
if (!manifest)
|
||||
throw new Error("Cannot install provider without manifest data");
|
||||
installer = new AddonInstaller(sourceURI, manifest, installCallback);
|
||||
this._showInstallNotification(aDOMDocument, installer);
|
||||
break;
|
||||
default:
|
||||
throw new Error("SocialService.installProvider: Invalid install type "+installType+"\n");
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
createWrapper: function(manifest) {
|
||||
|
@ -3079,6 +3079,19 @@
|
||||
"n_buckets" : 100,
|
||||
"description": "PLACES: Size of favicon files without a specific file type probe, loaded from the web (Bytes)"
|
||||
},
|
||||
"LINK_ICON_SIZES_ATTR_USAGE": {
|
||||
"expires_in_version" : "never",
|
||||
"kind": "enumerated",
|
||||
"n_values": 4,
|
||||
"description": "The possible types of the 'sizes' attribute for <link rel=icon>. 0: Attribute not specified, 1: 'any', 2: Integer dimensions, 3: Invalid value."
|
||||
},
|
||||
"LINK_ICON_SIZES_ATTR_DIMENSION": {
|
||||
"expires_in_version" : "never",
|
||||
"kind": "linear",
|
||||
"high": 513,
|
||||
"n_buckets" : 64,
|
||||
"description": "The width dimension of the 'sizes' attribute for <link rel=icon>."
|
||||
},
|
||||
"FENNEC_DISTRIBUTION_REFERRER_INVALID": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "flag",
|
||||
|