Merge f-t to m-c, a=merge
|
@ -141,16 +141,6 @@ function initResponsiveDesign() {
|
||||||
|
|
||||||
// Enable touch events
|
// Enable touch events
|
||||||
responsive.enableTouch();
|
responsive.enableTouch();
|
||||||
|
|
||||||
// Automatically toggle responsive design mode
|
|
||||||
let width = 320, height = 480;
|
|
||||||
// We have to take into account padding and border introduced with the
|
|
||||||
// device look'n feel:
|
|
||||||
width += 15*2; // Horizontal padding
|
|
||||||
width += 1*2; // Vertical border
|
|
||||||
height += 60; // Top Padding
|
|
||||||
height += 1; // Top border
|
|
||||||
responsive.setSize(width, height);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1359,7 +1359,7 @@ var BookmarkingUI = {
|
||||||
PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
|
PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
|
||||||
.asyncExecuteLegacyQueries([query], 1, options, {
|
.asyncExecuteLegacyQueries([query], 1, options, {
|
||||||
handleResult: function (aResultSet) {
|
handleResult: function (aResultSet) {
|
||||||
let onItemClick = function (aEvent) {
|
let onItemCommand = function (aEvent) {
|
||||||
let item = aEvent.target;
|
let item = aEvent.target;
|
||||||
openUILink(item.getAttribute("targetURI"), aEvent);
|
openUILink(item.getAttribute("targetURI"), aEvent);
|
||||||
CustomizableUI.hidePanelForNode(item);
|
CustomizableUI.hidePanelForNode(item);
|
||||||
|
@ -1379,7 +1379,7 @@ var BookmarkingUI = {
|
||||||
item.setAttribute("targetURI", uri);
|
item.setAttribute("targetURI", uri);
|
||||||
item.setAttribute("class", "menuitem-iconic menuitem-with-favicon bookmark-item " +
|
item.setAttribute("class", "menuitem-iconic menuitem-with-favicon bookmark-item " +
|
||||||
extraCSSClass);
|
extraCSSClass);
|
||||||
item.addEventListener("click", onItemClick);
|
item.addEventListener("command", onItemCommand);
|
||||||
if (icon) {
|
if (icon) {
|
||||||
let iconURL = "moz-anno:favicon:" + icon;
|
let iconURL = "moz-anno:favicon:" + icon;
|
||||||
item.setAttribute("image", iconURL);
|
item.setAttribute("image", iconURL);
|
||||||
|
|
|
@ -259,8 +259,6 @@ SocialUI = {
|
||||||
// called on tab/urlbar/location changes and after customization. Update
|
// called on tab/urlbar/location changes and after customization. Update
|
||||||
// anything that is tab specific.
|
// anything that is tab specific.
|
||||||
updateState: function() {
|
updateState: function() {
|
||||||
if (location == "about:customizing")
|
|
||||||
return;
|
|
||||||
goSetCommandEnabled("Social:PageShareOrMark", this.canShareOrMarkPage(gBrowser.currentURI));
|
goSetCommandEnabled("Social:PageShareOrMark", this.canShareOrMarkPage(gBrowser.currentURI));
|
||||||
if (!SocialUI.enabled)
|
if (!SocialUI.enabled)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -183,9 +183,6 @@ if (AppConstants.MOZ_SAFE_BROWSING) {
|
||||||
"resource://gre/modules/SafeBrowsing.jsm");
|
"resource://gre/modules/SafeBrowsing.jsm");
|
||||||
}
|
}
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "gCustomizationTabPreloader",
|
|
||||||
"resource:///modules/CustomizationTabPreloader.jsm", "CustomizationTabPreloader");
|
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
|
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
|
||||||
"resource://gre/modules/PrivateBrowsingUtils.jsm");
|
"resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||||
|
|
||||||
|
@ -2344,10 +2341,12 @@ function URLBarSetURI(aURI) {
|
||||||
// 2. if remote newtab is enabled and it's the default remote newtab page
|
// 2. if remote newtab is enabled and it's the default remote newtab page
|
||||||
let defaultRemoteURL = gAboutNewTabService.remoteEnabled &&
|
let defaultRemoteURL = gAboutNewTabService.remoteEnabled &&
|
||||||
uri.spec === gAboutNewTabService.newTabURL;
|
uri.spec === gAboutNewTabService.newTabURL;
|
||||||
if (gInitialPages.includes(uri.spec) || defaultRemoteURL)
|
if ((gInitialPages.includes(uri.spec) || defaultRemoteURL) &&
|
||||||
value = gBrowser.selectedBrowser.hasContentOpener ? uri.spec : "";
|
checkEmptyPageOrigin(gBrowser.selectedBrowser, uri)) {
|
||||||
else
|
value = "";
|
||||||
|
} else {
|
||||||
value = losslessDecodeURI(uri);
|
value = losslessDecodeURI(uri);
|
||||||
|
}
|
||||||
|
|
||||||
valid = !isBlankPageURL(uri.spec);
|
valid = !isBlankPageURL(uri.spec);
|
||||||
}
|
}
|
||||||
|
@ -4327,7 +4326,7 @@ var XULBrowserWindow = {
|
||||||
// Do not update urlbar if there was a subframe navigation
|
// Do not update urlbar if there was a subframe navigation
|
||||||
|
|
||||||
if (aWebProgress.isTopLevel) {
|
if (aWebProgress.isTopLevel) {
|
||||||
if ((location == "about:blank" && !gBrowser.selectedBrowser.hasContentOpener) ||
|
if ((location == "about:blank" && checkEmptyPageOrigin()) ||
|
||||||
location == "") { // Second condition is for new tabs, otherwise
|
location == "") { // Second condition is for new tabs, otherwise
|
||||||
// reload function is enabled until tab is refreshed.
|
// reload function is enabled until tab is refreshed.
|
||||||
this.reloadCommand.setAttribute("disabled", "true");
|
this.reloadCommand.setAttribute("disabled", "true");
|
||||||
|
@ -4339,7 +4338,7 @@ var XULBrowserWindow = {
|
||||||
URLBarSetURI(aLocationURI);
|
URLBarSetURI(aLocationURI);
|
||||||
|
|
||||||
BookmarkingUI.onLocationChange();
|
BookmarkingUI.onLocationChange();
|
||||||
SocialUI.updateState(location);
|
SocialUI.updateState();
|
||||||
UITour.onLocationChange(location);
|
UITour.onLocationChange(location);
|
||||||
gTabletModePageCounter.inc();
|
gTabletModePageCounter.inc();
|
||||||
}
|
}
|
||||||
|
@ -4387,12 +4386,11 @@ var XULBrowserWindow = {
|
||||||
|
|
||||||
// Try not to instantiate gCustomizeMode as much as possible,
|
// Try not to instantiate gCustomizeMode as much as possible,
|
||||||
// so don't use CustomizeMode.jsm to check for URI or customizing.
|
// so don't use CustomizeMode.jsm to check for URI or customizing.
|
||||||
let customizingURI = "about:customizing";
|
if (location == "about:blank" &&
|
||||||
if (location == customizingURI) {
|
gBrowser.selectedTab.hasAttribute("customizemode")) {
|
||||||
gCustomizeMode.enter();
|
gCustomizeMode.enter();
|
||||||
} else if (location != customizingURI &&
|
} else if (CustomizationHandler.isEnteringCustomizeMode ||
|
||||||
(CustomizationHandler.isEnteringCustomizeMode ||
|
CustomizationHandler.isCustomizing()) {
|
||||||
CustomizationHandler.isCustomizing())) {
|
|
||||||
gCustomizeMode.exit();
|
gCustomizeMode.exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6390,11 +6388,14 @@ function isTabEmpty(aTab) {
|
||||||
if (aTab.hasAttribute("busy"))
|
if (aTab.hasAttribute("busy"))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (aTab.hasAttribute("customizemode"))
|
||||||
|
return false;
|
||||||
|
|
||||||
let browser = aTab.linkedBrowser;
|
let browser = aTab.linkedBrowser;
|
||||||
if (!isBlankPageURL(browser.currentURI.spec))
|
if (!isBlankPageURL(browser.currentURI.spec))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (browser.hasContentOpener)
|
if (!checkEmptyPageOrigin(browser))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (browser.canGoForward || browser.canGoBack)
|
if (browser.canGoForward || browser.canGoBack)
|
||||||
|
@ -6403,6 +6404,56 @@ function isTabEmpty(aTab) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether a page can be considered as 'empty', that its URI
|
||||||
|
* reflects its origin, and that if it's loaded in a tab, that tab
|
||||||
|
* could be considered 'empty' (e.g. like the result of opening
|
||||||
|
* a 'blank' new tab).
|
||||||
|
*
|
||||||
|
* We have to do more than just check the URI, because especially
|
||||||
|
* for things like about:blank, it is possible that the opener or
|
||||||
|
* some other page has control over the contents of the page.
|
||||||
|
*
|
||||||
|
* @param browser {Browser}
|
||||||
|
* The browser whose page we're checking (the selected browser
|
||||||
|
* in this window if omitted).
|
||||||
|
* @param uri {nsIURI}
|
||||||
|
* The URI against which we're checking (the browser's currentURI
|
||||||
|
* if omitted).
|
||||||
|
*
|
||||||
|
* @return false if the page was opened by or is controlled by arbitrary web
|
||||||
|
* content, unless that content corresponds with the URI.
|
||||||
|
* true if the page is blank and controlled by a principal matching
|
||||||
|
* that URI (or the system principal if the principal has no URI)
|
||||||
|
*/
|
||||||
|
function checkEmptyPageOrigin(browser = gBrowser.selectedBrowser,
|
||||||
|
uri = browser.currentURI) {
|
||||||
|
// If another page opened this page with e.g. window.open, this page might
|
||||||
|
// be controlled by its opener - return false.
|
||||||
|
if (browser.hasContentOpener) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let contentPrincipal = browser.contentPrincipal;
|
||||||
|
if (gMultiProcessBrowser && browser.isRemoteBrowser &&
|
||||||
|
!contentPrincipal && uri.spec == "about:blank") {
|
||||||
|
// Need to specialcase this because of how stopping an about:blank
|
||||||
|
// load from chrome on e10s causes a permanently null contentPrincipal,
|
||||||
|
// see bug 1249362.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Not all principals have URIs...
|
||||||
|
if (contentPrincipal.URI) {
|
||||||
|
if (uri.spec == "about:blank" && contentPrincipal.isNullPrincipal) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return contentPrincipal.URI.equals(uri);
|
||||||
|
}
|
||||||
|
// ... so for those that don't have them, enforce that the page has the
|
||||||
|
// system principal (this matches e.g. on about:home).
|
||||||
|
let ssm = Services.scriptSecurityManager;
|
||||||
|
return ssm.isSystemPrincipal(contentPrincipal);
|
||||||
|
}
|
||||||
|
|
||||||
function BrowserOpenSyncTabs() {
|
function BrowserOpenSyncTabs() {
|
||||||
if (Services.prefs.getBoolPref("services.sync.syncedTabsUIRefresh")) {
|
if (Services.prefs.getBoolPref("services.sync.syncedTabsUIRefresh")) {
|
||||||
gSyncUI.openSyncedTabsPanel();
|
gSyncUI.openSyncedTabsPanel();
|
||||||
|
@ -7292,7 +7343,6 @@ function switchToTabHavingURI(aURI, aOpenNew, aOpenParams={}) {
|
||||||
// window being in private browsing mode:
|
// window being in private browsing mode:
|
||||||
const kPrivateBrowsingWhitelist = new Set([
|
const kPrivateBrowsingWhitelist = new Set([
|
||||||
"about:addons",
|
"about:addons",
|
||||||
"about:customizing",
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let ignoreFragment = aOpenParams.ignoreFragment;
|
let ignoreFragment = aOpenParams.ignoreFragment;
|
||||||
|
|
|
@ -1398,6 +1398,11 @@
|
||||||
|
|
||||||
crop = "center";
|
crop = "center";
|
||||||
|
|
||||||
|
} else if (aTab.hasAttribute("customizemode")) {
|
||||||
|
let brandBundle = document.getElementById("bundle_brand");
|
||||||
|
let brandShortName = brandBundle.getString("brandShortName");
|
||||||
|
title = gNavigatorBundle.getFormattedString("customizeMode.tabTitle",
|
||||||
|
[ brandShortName ]);
|
||||||
} else // Still no title? Fall back to our untitled string.
|
} else // Still no title? Fall back to our untitled string.
|
||||||
title = this.mStringBundle.getString("tabs.emptyTabTitle");
|
title = this.mStringBundle.getString("tabs.emptyTabTitle");
|
||||||
}
|
}
|
||||||
|
@ -1926,11 +1931,6 @@
|
||||||
|
|
||||||
b.droppedLinkHandler = handleDroppedLink;
|
b.droppedLinkHandler = handleDroppedLink;
|
||||||
|
|
||||||
// Swap in a preloaded customize tab, if available.
|
|
||||||
if (aURI == "about:customizing") {
|
|
||||||
usingPreloadedContent = gCustomizationTabPreloader.newTab(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dispatch a new tab notification. We do this once we're
|
// Dispatch a new tab notification. We do this once we're
|
||||||
// entirely done, so that things are in a consistent state
|
// entirely done, so that things are in a consistent state
|
||||||
// even if the event listener opens or closes tabs.
|
// even if the event listener opens or closes tabs.
|
||||||
|
@ -2474,33 +2474,6 @@
|
||||||
</body>
|
</body>
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
<method name="swapNewTabWithBrowser">
|
|
||||||
<parameter name="aNewTab"/>
|
|
||||||
<parameter name="aBrowser"/>
|
|
||||||
<body>
|
|
||||||
<![CDATA[
|
|
||||||
// The browser must be standalone.
|
|
||||||
if (aBrowser.getTabBrowser())
|
|
||||||
throw Cr.NS_ERROR_INVALID_ARG;
|
|
||||||
|
|
||||||
// The tab is definitely not loading.
|
|
||||||
aNewTab.removeAttribute("busy");
|
|
||||||
if (aNewTab.selected) {
|
|
||||||
this.mIsBusy = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._swapBrowserDocShells(aNewTab, aBrowser);
|
|
||||||
|
|
||||||
// Update the new tab's title.
|
|
||||||
this.setTabTitle(aNewTab);
|
|
||||||
|
|
||||||
if (aNewTab.selected) {
|
|
||||||
this.updateCurrentBrowser(true);
|
|
||||||
}
|
|
||||||
]]>
|
|
||||||
</body>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="swapBrowsersAndCloseOther">
|
<method name="swapBrowsersAndCloseOther">
|
||||||
<parameter name="aOurTab"/>
|
<parameter name="aOurTab"/>
|
||||||
<parameter name="aOtherTab"/>
|
<parameter name="aOtherTab"/>
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
[browser_urlbar_blanking.js]
|
||||||
|
support-files =
|
||||||
|
file_blank_but_not_blank.html
|
|
@ -0,0 +1,35 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
add_task(function*() {
|
||||||
|
for (let page of gInitialPages) {
|
||||||
|
if (page == "about:newtab") {
|
||||||
|
// New tab preloading makes this a pain to test, so skip
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, page);
|
||||||
|
ok(!gURLBar.value, "The URL bar should be empty if we load a plain " + page + " page.");
|
||||||
|
yield BrowserTestUtils.removeTab(tab);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(function*() {
|
||||||
|
const URI = "http://www.example.com/browser/browser/base/content/test/urlbar/file_blank_but_not_blank.html";
|
||||||
|
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, URI);
|
||||||
|
is(gURLBar.value, URI, "The URL bar should match the URI");
|
||||||
|
let browserLoaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||||
|
ContentTask.spawn(tab.linkedBrowser, null, function() {
|
||||||
|
content.document.querySelector('a').click();
|
||||||
|
});
|
||||||
|
yield browserLoaded;
|
||||||
|
ok(gURLBar.value.startsWith("javascript"), "The URL bar should have the JS URI");
|
||||||
|
// When reloading, the javascript: uri we're using will throw an exception.
|
||||||
|
// That's deliberate, so we need to tell mochitest to ignore it:
|
||||||
|
SimpleTest.expectUncaughtException(true);
|
||||||
|
yield ContentTask.spawn(tab.linkedBrowser, null, function*() {
|
||||||
|
// This is sync, so by the time we return we should have changed the URL bar.
|
||||||
|
content.location.reload();
|
||||||
|
});
|
||||||
|
ok(!!gURLBar.value, "URL bar should not be blank.");
|
||||||
|
yield BrowserTestUtils.removeTab(tab);
|
||||||
|
SimpleTest.expectUncaughtException(false);
|
||||||
|
});
|
|
@ -0,0 +1,2 @@
|
||||||
|
<script>var q = 1;</script>
|
||||||
|
<a href="javascript:q">Click me</a>
|
|
@ -23,6 +23,7 @@ BROWSER_CHROME_MANIFESTS += [
|
||||||
'content/test/popupNotifications/browser.ini',
|
'content/test/popupNotifications/browser.ini',
|
||||||
'content/test/referrer/browser.ini',
|
'content/test/referrer/browser.ini',
|
||||||
'content/test/social/browser.ini',
|
'content/test/social/browser.ini',
|
||||||
|
'content/test/urlbar/browser.ini',
|
||||||
]
|
]
|
||||||
|
|
||||||
DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION']
|
DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION']
|
||||||
|
|
|
@ -99,8 +99,6 @@ static RedirEntry kRedirMap[] = {
|
||||||
#endif
|
#endif
|
||||||
{ "accounts", "chrome://browser/content/aboutaccounts/aboutaccounts.xhtml",
|
{ "accounts", "chrome://browser/content/aboutaccounts/aboutaccounts.xhtml",
|
||||||
nsIAboutModule::ALLOW_SCRIPT },
|
nsIAboutModule::ALLOW_SCRIPT },
|
||||||
{ "customizing", "chrome://browser/content/customizableui/aboutCustomizing.xul",
|
|
||||||
nsIAboutModule::ALLOW_SCRIPT },
|
|
||||||
{ "loopconversation", "chrome://loop/content/panels/conversation.html",
|
{ "loopconversation", "chrome://loop/content/panels/conversation.html",
|
||||||
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
||||||
nsIAboutModule::ALLOW_SCRIPT |
|
nsIAboutModule::ALLOW_SCRIPT |
|
||||||
|
|
|
@ -107,7 +107,6 @@ static const mozilla::Module::ContractIDEntry kBrowserContracts[] = {
|
||||||
#ifdef MOZ_SERVICES_HEALTHREPORT
|
#ifdef MOZ_SERVICES_HEALTHREPORT
|
||||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "healthreport", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "healthreport", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||||
#endif
|
#endif
|
||||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "customizing", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
|
||||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "looppanel", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "looppanel", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "loopconversation", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "loopconversation", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "reader", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "reader", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||||
|
|
|
@ -203,7 +203,7 @@ const CustomizableWidgets = [
|
||||||
PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
|
PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
|
||||||
.asyncExecuteLegacyQueries([query], 1, options, {
|
.asyncExecuteLegacyQueries([query], 1, options, {
|
||||||
handleResult: function (aResultSet) {
|
handleResult: function (aResultSet) {
|
||||||
let onItemClick = function (aEvent) {
|
let onItemCommand = function (aEvent) {
|
||||||
let item = aEvent.target;
|
let item = aEvent.target;
|
||||||
win.openUILink(item.getAttribute("targetURI"), aEvent);
|
win.openUILink(item.getAttribute("targetURI"), aEvent);
|
||||||
CustomizableUI.hidePanelForNode(item);
|
CustomizableUI.hidePanelForNode(item);
|
||||||
|
@ -219,7 +219,7 @@ const CustomizableWidgets = [
|
||||||
item.setAttribute("label", title || uri);
|
item.setAttribute("label", title || uri);
|
||||||
item.setAttribute("targetURI", uri);
|
item.setAttribute("targetURI", uri);
|
||||||
item.setAttribute("class", "subviewbutton");
|
item.setAttribute("class", "subviewbutton");
|
||||||
item.addEventListener("click", onItemClick);
|
item.addEventListener("command", onItemCommand);
|
||||||
if (icon) {
|
if (icon) {
|
||||||
let iconURL = "moz-anno:favicon:" + icon;
|
let iconURL = "moz-anno:favicon:" + icon;
|
||||||
item.setAttribute("image", iconURL);
|
item.setAttribute("image", iconURL);
|
||||||
|
|
|
@ -11,7 +11,6 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||||
const kPrefCustomizationDebug = "browser.uiCustomization.debug";
|
const kPrefCustomizationDebug = "browser.uiCustomization.debug";
|
||||||
const kPrefCustomizationAnimation = "browser.uiCustomization.disableAnimation";
|
const kPrefCustomizationAnimation = "browser.uiCustomization.disableAnimation";
|
||||||
const kPaletteId = "customization-palette";
|
const kPaletteId = "customization-palette";
|
||||||
const kAboutURI = "about:customizing";
|
|
||||||
const kDragDataTypePrefix = "text/toolbarwrapper-id/";
|
const kDragDataTypePrefix = "text/toolbarwrapper-id/";
|
||||||
const kPlaceholderClass = "panel-customization-placeholder";
|
const kPlaceholderClass = "panel-customization-placeholder";
|
||||||
const kSkipSourceNodePref = "browser.uiCustomization.skipSourceNodeCheck";
|
const kSkipSourceNodePref = "browser.uiCustomization.skipSourceNodeCheck";
|
||||||
|
@ -36,6 +35,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "BrowserUITelemetry",
|
||||||
"resource:///modules/BrowserUITelemetry.jsm");
|
"resource:///modules/BrowserUITelemetry.jsm");
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
|
XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
|
||||||
"resource://gre/modules/LightweightThemeManager.jsm");
|
"resource://gre/modules/LightweightThemeManager.jsm");
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, "SessionStore",
|
||||||
|
"resource:///modules/sessionstore/SessionStore.jsm");
|
||||||
|
|
||||||
let gDebug;
|
let gDebug;
|
||||||
XPCOMUtils.defineLazyGetter(this, "log", () => {
|
XPCOMUtils.defineLazyGetter(this, "log", () => {
|
||||||
|
@ -56,6 +57,23 @@ var gDisableAnimation = null;
|
||||||
|
|
||||||
var gDraggingInToolbars;
|
var gDraggingInToolbars;
|
||||||
|
|
||||||
|
var gTab;
|
||||||
|
|
||||||
|
function closeGlobalTab() {
|
||||||
|
let win = gTab.ownerGlobal;
|
||||||
|
if (win.gBrowser.browsers.length == 1) {
|
||||||
|
win.BrowserOpenTab();
|
||||||
|
}
|
||||||
|
win.gBrowser.removeTab(gTab);
|
||||||
|
}
|
||||||
|
|
||||||
|
function unregisterGlobalTab() {
|
||||||
|
gTab.removeEventListener("TabClose", unregisterGlobalTab);
|
||||||
|
gTab.ownerGlobal.removeEventListener("unload", unregisterGlobalTab);
|
||||||
|
gTab.removeAttribute("customizemode");
|
||||||
|
gTab = null;
|
||||||
|
}
|
||||||
|
|
||||||
function CustomizeMode(aWindow) {
|
function CustomizeMode(aWindow) {
|
||||||
if (gDisableAnimation === null) {
|
if (gDisableAnimation === null) {
|
||||||
gDisableAnimation = Services.prefs.getPrefType(kPrefCustomizationAnimation) == Ci.nsIPrefBranch.PREF_BOOL &&
|
gDisableAnimation = Services.prefs.getPrefType(kPrefCustomizationAnimation) == Ci.nsIPrefBranch.PREF_BOOL &&
|
||||||
|
@ -140,6 +158,36 @@ CustomizeMode.prototype = {
|
||||||
lwthemeIcon.style.backgroundImage = "url(" + imageURL + ")";
|
lwthemeIcon.style.backgroundImage = "url(" + imageURL + ")";
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setTab: function(aTab) {
|
||||||
|
if (gTab == aTab) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gTab) {
|
||||||
|
closeGlobalTab();
|
||||||
|
}
|
||||||
|
|
||||||
|
gTab = aTab;
|
||||||
|
|
||||||
|
gTab.setAttribute("customizemode", "true");
|
||||||
|
SessionStore.persistTabAttribute("customizemode");
|
||||||
|
|
||||||
|
gTab.linkedBrowser.stop();
|
||||||
|
|
||||||
|
let win = gTab.ownerGlobal;
|
||||||
|
|
||||||
|
win.gBrowser.setTabTitle(gTab);
|
||||||
|
win.gBrowser.setIcon(gTab,
|
||||||
|
"chrome://browser/skin/customizableui/customizeFavicon.ico");
|
||||||
|
|
||||||
|
gTab.addEventListener("TabClose", unregisterGlobalTab);
|
||||||
|
win.addEventListener("unload", unregisterGlobalTab);
|
||||||
|
|
||||||
|
if (gTab.selected) {
|
||||||
|
win.gCustomizeMode.enter();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
enter: function() {
|
enter: function() {
|
||||||
this._wantToBeInCustomizeMode = true;
|
this._wantToBeInCustomizeMode = true;
|
||||||
|
|
||||||
|
@ -154,13 +202,18 @@ CustomizeMode.prototype = {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!gTab) {
|
||||||
// We don't need to switch to kAboutURI, or open a new tab at
|
this.setTab(this.browser.loadOneTab("about:blank",
|
||||||
// kAboutURI if we're already on it.
|
{ inBackground: false,
|
||||||
if (this.browser.selectedBrowser.currentURI.spec != kAboutURI) {
|
forceNotRemote: true,
|
||||||
this.window.switchToTabHavingURI(kAboutURI, true, {
|
skipAnimation: true }));
|
||||||
skipTabAnimation: true,
|
return;
|
||||||
});
|
}
|
||||||
|
if (!gTab.selected) {
|
||||||
|
gTab.ownerGlobal.gBrowser.selectedTab = gTab;
|
||||||
|
}
|
||||||
|
gTab.ownerGlobal.focus();
|
||||||
|
if (gTab.ownerDocument != this.document) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,10 +366,6 @@ CustomizeMode.prototype = {
|
||||||
delete this._enableOutlinesTimeout;
|
delete this._enableOutlinesTimeout;
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
// It's possible that we didn't enter customize mode via the menu panel,
|
|
||||||
// meaning we didn't kick off about:customizing preloading. If that's
|
|
||||||
// the case, let's kick it off for the next time we load this mode.
|
|
||||||
window.gCustomizationTabPreloader.ensurePreloading();
|
|
||||||
if (!this._wantToBeInCustomizeMode) {
|
if (!this._wantToBeInCustomizeMode) {
|
||||||
this.exit();
|
this.exit();
|
||||||
}
|
}
|
||||||
|
@ -402,31 +451,14 @@ CustomizeMode.prototype = {
|
||||||
|
|
||||||
Services.obs.removeObserver(this, "lightweight-theme-window-updated", false);
|
Services.obs.removeObserver(this, "lightweight-theme-window-updated", false);
|
||||||
|
|
||||||
let browser = document.getElementById("browser");
|
if (this.browser.selectedTab == gTab) {
|
||||||
if (this.browser.selectedBrowser.currentURI.spec == kAboutURI) {
|
if (gTab.linkedBrowser.currentURI.spec == "about:blank") {
|
||||||
let custBrowser = this.browser.selectedBrowser;
|
closeGlobalTab();
|
||||||
if (custBrowser.canGoBack) {
|
|
||||||
// If there's history to this tab, just go back.
|
|
||||||
// Note that this throws an exception if the previous document has a
|
|
||||||
// problematic URL (e.g. about:idontexist)
|
|
||||||
try {
|
|
||||||
custBrowser.goBack();
|
|
||||||
} catch (ex) {
|
|
||||||
log.error(ex);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// If we can't go back, we're removing the about:customization tab.
|
unregisterGlobalTab();
|
||||||
// We only do this if we're the top window for this window (so not
|
|
||||||
// a dialog window, for example).
|
|
||||||
if (window.getTopWin(true) == window) {
|
|
||||||
let customizationTab = this.browser.selectedTab;
|
|
||||||
if (this.browser.browsers.length == 1) {
|
|
||||||
window.BrowserOpenTab();
|
|
||||||
}
|
|
||||||
this.browser.removeTab(customizationTab);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let browser = document.getElementById("browser");
|
||||||
browser.parentNode.selectedPanel = browser;
|
browser.parentNode.selectedPanel = browser;
|
||||||
let customizer = document.getElementById("customization-container");
|
let customizer = document.getElementById("customization-container");
|
||||||
customizer.hidden = true;
|
customizer.hidden = true;
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<!-- 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/. -->
|
|
||||||
|
|
||||||
<!DOCTYPE window [
|
|
||||||
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
|
|
||||||
%brandDTD;
|
|
||||||
<!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd">
|
|
||||||
%browserDTD;
|
|
||||||
]>
|
|
||||||
|
|
||||||
<window id="aboutCustomizingWindow"
|
|
||||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
|
||||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
|
||||||
title="&customizeMode.tabTitle;">
|
|
||||||
<html:head>
|
|
||||||
<html:link rel="icon" type="image/x-icon"
|
|
||||||
href="chrome://browser/skin/customizableui/customizeFavicon.ico"/>
|
|
||||||
</html:head>
|
|
||||||
</window>
|
|
|
@ -3,7 +3,6 @@
|
||||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
browser.jar:
|
browser.jar:
|
||||||
content/browser/customizableui/aboutCustomizing.xul
|
|
||||||
content/browser/customizableui/panelUI.css
|
content/browser/customizableui/panelUI.css
|
||||||
content/browser/customizableui/panelUI.js
|
content/browser/customizableui/panelUI.js
|
||||||
content/browser/customizableui/panelUI.xml
|
content/browser/customizableui/panelUI.xml
|
||||||
|
|
|
@ -157,10 +157,6 @@ const PanelUI = {
|
||||||
|
|
||||||
this.panel.addEventListener("popupshown", function onPopupShown() {
|
this.panel.addEventListener("popupshown", function onPopupShown() {
|
||||||
this.removeEventListener("popupshown", onPopupShown);
|
this.removeEventListener("popupshown", onPopupShown);
|
||||||
// As an optimization for the customize mode transition, we preload
|
|
||||||
// about:customizing in the background once the menu panel is first
|
|
||||||
// shown.
|
|
||||||
gCustomizationTabPreloader.ensurePreloading();
|
|
||||||
deferred.resolve();
|
deferred.resolve();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,6 @@ skip-if = os == "mac"
|
||||||
[browser_886323_buildArea_removable_nodes.js]
|
[browser_886323_buildArea_removable_nodes.js]
|
||||||
[browser_887438_currentset_shim.js]
|
[browser_887438_currentset_shim.js]
|
||||||
[browser_888817_currentset_updating.js]
|
[browser_888817_currentset_updating.js]
|
||||||
[browser_889120_customize_tab_merging.js]
|
|
||||||
[browser_890140_orphaned_placeholders.js]
|
[browser_890140_orphaned_placeholders.js]
|
||||||
[browser_890262_destroyWidget_after_add_to_panel.js]
|
[browser_890262_destroyWidget_after_add_to_panel.js]
|
||||||
[browser_892955_isWidgetRemovable_for_removed_widgets.js]
|
[browser_892955_isWidgetRemovable_for_removed_widgets.js]
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
/* 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/. */
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
const kTestToolbarId = "test-empty-drag";
|
|
||||||
|
|
||||||
// Attempting to switch quickly from one tab to another to see whether the state changes
|
|
||||||
// correctly.
|
|
||||||
add_task(function* CheckBasicCustomizeMode() {
|
|
||||||
yield startCustomizing();
|
|
||||||
ok(CustomizationHandler.isCustomizing(), "We should be in customize mode");
|
|
||||||
yield endCustomizing();
|
|
||||||
ok(!CustomizationHandler.isCustomizing(), "We should not be in customize mode");
|
|
||||||
});
|
|
||||||
add_task(function* CheckQuickCustomizeModeSwitch() {
|
|
||||||
let tab1 = gBrowser.addTab("about:newtab");
|
|
||||||
gBrowser.selectedTab = tab1;
|
|
||||||
let tab2 = gBrowser.addTab("about:customizing");
|
|
||||||
let tab3 = gBrowser.addTab("about:newtab");
|
|
||||||
gBrowser.selectedTab = tab2;
|
|
||||||
try {
|
|
||||||
yield waitForCondition(() => CustomizationHandler.isEnteringCustomizeMode);
|
|
||||||
} catch (ex) {
|
|
||||||
Cu.reportError(ex);
|
|
||||||
}
|
|
||||||
ok(CustomizationHandler.isEnteringCustomizeMode, "Should be entering customize mode");
|
|
||||||
gBrowser.selectedTab = tab3;
|
|
||||||
try {
|
|
||||||
yield waitForCondition(() => !CustomizationHandler.isEnteringCustomizeMode && !CustomizationHandler.isCustomizing());
|
|
||||||
} catch (ex) {
|
|
||||||
Cu.reportError(ex);
|
|
||||||
}
|
|
||||||
ok(!CustomizationHandler.isCustomizing(), "Should not be entering customize mode");
|
|
||||||
gBrowser.removeTab(tab1);
|
|
||||||
gBrowser.removeTab(tab2);
|
|
||||||
gBrowser.removeTab(tab3);
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(function* asyncCleanup() {
|
|
||||||
yield endCustomizing();
|
|
||||||
});
|
|
||||||
|
|
|
@ -199,7 +199,7 @@ function endCustomizing(aWindow=window) {
|
||||||
newTabBrowser.stop();
|
newTabBrowser.stop();
|
||||||
|
|
||||||
// If we stop early enough, this might actually be about:blank.
|
// If we stop early enough, this might actually be about:blank.
|
||||||
if (newTabBrowser.contentDocument.location.href == "about:blank") {
|
if (newTabBrowser.currentURI.spec == "about:blank") {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,7 +209,7 @@ function endCustomizing(aWindow=window) {
|
||||||
deferredLoadNewTab.resolve();
|
deferredLoadNewTab.resolve();
|
||||||
}
|
}
|
||||||
newTabBrowser.addEventListener("load", onNewTabLoaded, true);
|
newTabBrowser.addEventListener("load", onNewTabLoaded, true);
|
||||||
newTabBrowser.contentDocument.location.replace("about:blank");
|
newTabBrowser.loadURI("about:blank");
|
||||||
return deferredLoadNewTab.promise;
|
return deferredLoadNewTab.promise;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,12 @@ DistributionCustomizer.prototype = {
|
||||||
return this._locale;
|
return this._locale;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
get _language() {
|
||||||
|
let language = this._locale.split("-")[0];
|
||||||
|
this.__defineGetter__("_language", () => language);
|
||||||
|
return this._language;
|
||||||
|
},
|
||||||
|
|
||||||
get _prefSvc() {
|
get _prefSvc() {
|
||||||
let svc = Cc["@mozilla.org/preferences-service;1"].
|
let svc = Cc["@mozilla.org/preferences-service;1"].
|
||||||
getService(Ci.nsIPrefService);
|
getService(Ci.nsIPrefService);
|
||||||
|
@ -112,6 +118,8 @@ DistributionCustomizer.prototype = {
|
||||||
|
|
||||||
if (keys.indexOf(key + "." + this._locale) >= 0) {
|
if (keys.indexOf(key + "." + this._locale) >= 0) {
|
||||||
key += "." + this._locale;
|
key += "." + this._locale;
|
||||||
|
} else if (keys.indexOf(key + "." + this._language) >= 0) {
|
||||||
|
key += "." + this._language;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!items[itemIndex])
|
if (!items[itemIndex])
|
||||||
|
@ -323,6 +331,8 @@ DistributionCustomizer.prototype = {
|
||||||
try {
|
try {
|
||||||
if (globalPrefs["about." + this._locale]) {
|
if (globalPrefs["about." + this._locale]) {
|
||||||
partnerAbout.data = this._ini.getString("Global", "about." + this._locale);
|
partnerAbout.data = this._ini.getString("Global", "about." + this._locale);
|
||||||
|
} else if (globalPrefs["about." + this._language]) {
|
||||||
|
partnerAbout.data = this._ini.getString("Global", "about." + this._language);
|
||||||
} else {
|
} else {
|
||||||
partnerAbout.data = this._ini.getString("Global", "about");
|
partnerAbout.data = this._ini.getString("Global", "about");
|
||||||
}
|
}
|
||||||
|
@ -367,6 +377,17 @@ DistributionCustomizer.prototype = {
|
||||||
try {
|
try {
|
||||||
let value = eval(this._ini.getString("LocalizablePreferences", key));
|
let value = eval(this._ini.getString("LocalizablePreferences", key));
|
||||||
value = value.replace(/%LOCALE%/g, this._locale);
|
value = value.replace(/%LOCALE%/g, this._locale);
|
||||||
|
value = value.replace(/%LANGUAGE%/g, this._language);
|
||||||
|
localizedStr.data = "data:text/plain," + key + "=" + value;
|
||||||
|
defaults.setComplexValue(key, Ci.nsIPrefLocalizedString, localizedStr);
|
||||||
|
} catch (e) { /* ignore bad prefs and move on */ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sections["LocalizablePreferences-" + this._language]) {
|
||||||
|
for (let key of enumerate(this._ini.getKeys("LocalizablePreferences-" + this._language))) {
|
||||||
|
try {
|
||||||
|
let value = eval(this._ini.getString("LocalizablePreferences-" + this._language, key));
|
||||||
localizedStr.data = "data:text/plain," + key + "=" + value;
|
localizedStr.data = "data:text/plain," + key + "=" + value;
|
||||||
defaults.setComplexValue(key, Ci.nsIPrefLocalizedString, localizedStr);
|
defaults.setComplexValue(key, Ci.nsIPrefLocalizedString, localizedStr);
|
||||||
} catch (e) { /* ignore bad prefs and move on */ }
|
} catch (e) { /* ignore bad prefs and move on */ }
|
||||||
|
|
|
@ -632,7 +632,7 @@ global.WindowManager = {
|
||||||
convert(extension, window, getInfo) {
|
convert(extension, window, getInfo) {
|
||||||
let result = {
|
let result = {
|
||||||
id: this.getId(window),
|
id: this.getId(window),
|
||||||
focused: window == WindowManager.topWindow,
|
focused: window.document.hasFocus(),
|
||||||
top: window.screenY,
|
top: window.screenY,
|
||||||
left: window.screenX,
|
left: window.screenX,
|
||||||
width: window.outerWidth,
|
width: window.outerWidth,
|
||||||
|
|
|
@ -58,9 +58,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "WebappManager",
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs",
|
XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs",
|
||||||
"resource://gre/modules/PageThumbs.jsm");
|
"resource://gre/modules/PageThumbs.jsm");
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "CustomizationTabPreloader",
|
|
||||||
"resource:///modules/CustomizationTabPreloader.jsm");
|
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "PdfJs",
|
XPCOMUtils.defineLazyModuleGetter(this, "PdfJs",
|
||||||
"resource://pdf.js/PdfJs.jsm");
|
"resource://pdf.js/PdfJs.jsm");
|
||||||
|
|
||||||
|
@ -1072,7 +1069,6 @@ BrowserGlue.prototype = {
|
||||||
|
|
||||||
SelfSupportBackend.uninit();
|
SelfSupportBackend.uninit();
|
||||||
|
|
||||||
CustomizationTabPreloader.uninit();
|
|
||||||
WebappManager.uninit();
|
WebappManager.uninit();
|
||||||
|
|
||||||
NewTabPrefsProvider.prefs.uninit();
|
NewTabPrefsProvider.prefs.uninit();
|
||||||
|
@ -1812,10 +1808,16 @@ BrowserGlue.prototype = {
|
||||||
_migrateUI: function BG__migrateUI() {
|
_migrateUI: function BG__migrateUI() {
|
||||||
const UI_VERSION = 36;
|
const UI_VERSION = 36;
|
||||||
const BROWSER_DOCURL = "chrome://browser/content/browser.xul";
|
const BROWSER_DOCURL = "chrome://browser/content/browser.xul";
|
||||||
let currentUIVersion = 0;
|
|
||||||
try {
|
let currentUIVersion;
|
||||||
|
if (Services.prefs.prefHasUserValue("browser.migration.version")) {
|
||||||
currentUIVersion = Services.prefs.getIntPref("browser.migration.version");
|
currentUIVersion = Services.prefs.getIntPref("browser.migration.version");
|
||||||
} catch(ex) {}
|
} else {
|
||||||
|
// This is a new profile, nothing to migrate.
|
||||||
|
Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (currentUIVersion >= UI_VERSION)
|
if (currentUIVersion >= UI_VERSION)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,10 @@ Components.utils.import("resource://gre/modules/FileUtils.jsm");
|
||||||
Components.utils.import("resource://gre/modules/Task.jsm");
|
Components.utils.import("resource://gre/modules/Task.jsm");
|
||||||
Components.utils.import("resource:///modules/ShellService.jsm");
|
Components.utils.import("resource:///modules/ShellService.jsm");
|
||||||
Components.utils.import("resource:///modules/TransientPrefs.jsm");
|
Components.utils.import("resource:///modules/TransientPrefs.jsm");
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
||||||
|
"resource://gre/modules/osfile.jsm");
|
||||||
|
|
||||||
#ifdef E10S_TESTING_ONLY
|
#ifdef E10S_TESTING_ONLY
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
|
XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
|
||||||
"resource://gre/modules/UpdateUtils.jsm");
|
"resource://gre/modules/UpdateUtils.jsm");
|
||||||
|
@ -101,7 +105,6 @@ var gMainPane = {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MOZ_DEV_EDITION
|
#ifdef MOZ_DEV_EDITION
|
||||||
Cu.import("resource://gre/modules/osfile.jsm");
|
|
||||||
let uAppData = OS.Constants.Path.userApplicationDataDir;
|
let uAppData = OS.Constants.Path.userApplicationDataDir;
|
||||||
let ignoreSeparateProfile = OS.Path.join(uAppData, "ignore-dev-edition-profile");
|
let ignoreSeparateProfile = OS.Path.join(uAppData, "ignore-dev-edition-profile");
|
||||||
|
|
||||||
|
@ -185,6 +188,16 @@ var gMainPane = {
|
||||||
Cu.reportError("Failed to toggle separate profile mode: " + error);
|
Cu.reportError("Failed to toggle separate profile mode: " + error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function createOrRemoveSpecialDevEditionFile(onSuccess) {
|
||||||
|
let uAppData = OS.Constants.Path.userApplicationDataDir;
|
||||||
|
let ignoreSeparateProfile = OS.Path.join(uAppData, "ignore-dev-edition-profile");
|
||||||
|
|
||||||
|
if (separateProfileModeCheckbox.checked) {
|
||||||
|
OS.File.remove(ignoreSeparateProfile).then(onSuccess, revertCheckbox);
|
||||||
|
} else {
|
||||||
|
OS.File.writeAtomic(ignoreSeparateProfile, new Uint8Array()).then(onSuccess, revertCheckbox);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const Cc = Components.classes, Ci = Components.interfaces;
|
const Cc = Components.classes, Ci = Components.interfaces;
|
||||||
let separateProfileModeCheckbox = document.getElementById("separateProfileMode");
|
let separateProfileModeCheckbox = document.getElementById("separateProfileMode");
|
||||||
|
@ -194,8 +207,25 @@ var gMainPane = {
|
||||||
"featureEnableRequiresRestart" : "featureDisableRequiresRestart",
|
"featureEnableRequiresRestart" : "featureDisableRequiresRestart",
|
||||||
[brandName]);
|
[brandName]);
|
||||||
let title = bundle.getFormattedString("shouldRestartTitle", [brandName]);
|
let title = bundle.getFormattedString("shouldRestartTitle", [brandName]);
|
||||||
let shouldProceed = Services.prompt.confirm(window, title, msg)
|
let check = {value: false};
|
||||||
if (shouldProceed) {
|
let prompts = Services.prompt;
|
||||||
|
let flags = prompts.BUTTON_POS_0 * prompts.BUTTON_TITLE_IS_STRING +
|
||||||
|
prompts.BUTTON_POS_1 * prompts.BUTTON_TITLE_CANCEL +
|
||||||
|
prompts.BUTTON_POS_2 * prompts.BUTTON_TITLE_IS_STRING;
|
||||||
|
let button0Title = bundle.getString("restartNowButton");
|
||||||
|
let button2Title = bundle.getString("restartLaterButton");
|
||||||
|
let button_index = prompts.confirmEx(window, title, msg, flags,
|
||||||
|
button0Title, null, button2Title, null, check)
|
||||||
|
let RESTART_NOW_BUTTON_INDEX = 0;
|
||||||
|
let CANCEL_BUTTON_INDEX = 1;
|
||||||
|
let RESTART_LATER_BUTTON_INDEX = 2;
|
||||||
|
|
||||||
|
switch (button_index) {
|
||||||
|
case CANCEL_BUTTON_INDEX:
|
||||||
|
revertCheckbox();
|
||||||
|
return;
|
||||||
|
case RESTART_NOW_BUTTON_INDEX:
|
||||||
|
let shouldProceed = false;
|
||||||
let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"]
|
let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"]
|
||||||
.createInstance(Ci.nsISupportsPRBool);
|
.createInstance(Ci.nsISupportsPRBool);
|
||||||
Services.obs.notifyObservers(cancelQuit, "quit-application-requested",
|
Services.obs.notifyObservers(cancelQuit, "quit-application-requested",
|
||||||
|
@ -203,21 +233,17 @@ var gMainPane = {
|
||||||
shouldProceed = !cancelQuit.data;
|
shouldProceed = !cancelQuit.data;
|
||||||
|
|
||||||
if (shouldProceed) {
|
if (shouldProceed) {
|
||||||
Cu.import("resource://gre/modules/osfile.jsm");
|
createOrRemoveSpecialDevEditionFile(quitApp);
|
||||||
let uAppData = OS.Constants.Path.userApplicationDataDir;
|
|
||||||
let ignoreSeparateProfile = OS.Path.join(uAppData, "ignore-dev-edition-profile");
|
|
||||||
|
|
||||||
if (separateProfileModeCheckbox.checked) {
|
|
||||||
OS.File.remove(ignoreSeparateProfile).then(quitApp, revertCheckbox);
|
|
||||||
} else {
|
|
||||||
OS.File.writeAtomic(ignoreSeparateProfile, new Uint8Array()).then(quitApp, revertCheckbox);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Revert the checkbox in case we didn't quit
|
// Revert the checkbox in case we didn't quit
|
||||||
revertCheckbox();
|
revertCheckbox();
|
||||||
|
return;
|
||||||
|
case RESTART_LATER_BUTTON_INDEX:
|
||||||
|
createOrRemoveSpecialDevEditionFile();
|
||||||
|
return;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onGetStarted: function (aEvent) {
|
onGetStarted: function (aEvent) {
|
||||||
|
|
|
@ -425,19 +425,6 @@ var gSyncPane = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Called whenever one of the sync engine preferences is changed.
|
|
||||||
onPreferenceChanged: function() {
|
|
||||||
let prefElts = document.querySelectorAll("#syncEnginePrefs > preference");
|
|
||||||
let syncEnabled = false;
|
|
||||||
for (let elt of prefElts) {
|
|
||||||
if (elt.name.startsWith("services.sync.") && elt.value) {
|
|
||||||
syncEnabled = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Services.prefs.setBoolPref("services.sync.enabled", syncEnabled);
|
|
||||||
},
|
|
||||||
|
|
||||||
startOver: function (showDialog) {
|
startOver: function (showDialog) {
|
||||||
if (showDialog) {
|
if (showDialog) {
|
||||||
let flags = Services.prompt.BUTTON_POS_0 * Services.prompt.BUTTON_TITLE_IS_STRING +
|
let flags = Services.prompt.BUTTON_POS_0 * Services.prompt.BUTTON_TITLE_IS_STRING +
|
||||||
|
|
|
@ -4,8 +4,7 @@
|
||||||
|
|
||||||
<!-- Sync panel -->
|
<!-- Sync panel -->
|
||||||
|
|
||||||
<preferences id="syncEnginePrefs" hidden="true" data-category="paneSync"
|
<preferences id="syncEnginePrefs" hidden="true" data-category="paneSync">
|
||||||
onchange="gSyncPane.onPreferenceChanged();">
|
|
||||||
<preference id="engine.addons"
|
<preference id="engine.addons"
|
||||||
name="services.sync.engine.addons"
|
name="services.sync.engine.addons"
|
||||||
type="bool"/>
|
type="bool"/>
|
||||||
|
|
|
@ -801,6 +801,8 @@ var SessionStoreInternal = {
|
||||||
tab.label = activePageData.url;
|
tab.label = activePageData.url;
|
||||||
tab.crop = "center";
|
tab.crop = "center";
|
||||||
}
|
}
|
||||||
|
} else if (tab.hasAttribute("customizemode")) {
|
||||||
|
win.gCustomizeMode.setTab(tab);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore the tab icon.
|
// Restore the tab icon.
|
||||||
|
@ -3299,6 +3301,10 @@ var SessionStoreInternal = {
|
||||||
* optional load arguments used for loadURI()
|
* optional load arguments used for loadURI()
|
||||||
*/
|
*/
|
||||||
restoreTabContent: function (aTab, aLoadArguments = null) {
|
restoreTabContent: function (aTab, aLoadArguments = null) {
|
||||||
|
if (aTab.hasAttribute("customizemode")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let browser = aTab.linkedBrowser;
|
let browser = aTab.linkedBrowser;
|
||||||
let window = aTab.ownerDocument.defaultView;
|
let window = aTab.ownerDocument.defaultView;
|
||||||
let tabbrowser = window.gBrowser;
|
let tabbrowser = window.gBrowser;
|
||||||
|
|
|
@ -6,50 +6,138 @@
|
||||||
|
|
||||||
this.EXPORTED_SYMBOLS = ["LanguageDetector"];
|
this.EXPORTED_SYMBOLS = ["LanguageDetector"];
|
||||||
|
|
||||||
|
Components.utils.import("resource://gre/modules/Timer.jsm");
|
||||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
// Since Emscripten can handle heap growth, but not heap shrinkage, we
|
||||||
"resource://gre/modules/Promise.jsm");
|
// need to refresh the worker after we've processed a particularly large
|
||||||
|
// string in order to prevent unnecessary resident memory growth.
|
||||||
|
//
|
||||||
|
// These values define the cut-off string length and the idle timeout
|
||||||
|
// (in milliseconds) before destroying a worker. Once a string of the
|
||||||
|
// maximum size has been processed, the worker is marked for
|
||||||
|
// destruction, and is terminated as soon as it has been idle for the
|
||||||
|
// given timeout.
|
||||||
|
//
|
||||||
|
// 1.5MB. This is the approximate string length that forces heap growth
|
||||||
|
// for a 2MB heap.
|
||||||
|
var LARGE_STRING = 1.5 * 1024 * 1024;
|
||||||
|
var IDLE_TIMEOUT = 10 * 1000;
|
||||||
|
|
||||||
const WORKER_URL = "resource:///modules/translation/cld-worker.js";
|
const WORKER_URL = "resource:///modules/translation/cld-worker.js";
|
||||||
|
|
||||||
var detectionQueue = [];
|
var workerManager = {
|
||||||
|
detectionQueue: [],
|
||||||
|
|
||||||
var workerReady = false;
|
detectLanguage(aParams) {
|
||||||
var pendingStrings = [];
|
return this.workerReady.then(worker => {
|
||||||
|
return new Promise(resolve => {
|
||||||
XPCOMUtils.defineLazyGetter(this, "worker", () => {
|
this.detectionQueue.push({resolve});
|
||||||
let worker = new Worker(WORKER_URL);
|
worker.postMessage(aParams);
|
||||||
worker.onmessage = function(aMsg) {
|
|
||||||
if (aMsg.data == "ready") {
|
|
||||||
workerReady = true;
|
|
||||||
for (let string of pendingStrings)
|
|
||||||
worker.postMessage(string);
|
|
||||||
pendingStrings = [];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
detectionQueue.shift().resolve(aMsg.data);
|
|
||||||
}
|
|
||||||
return worker;
|
|
||||||
});
|
});
|
||||||
|
}).then(result => {
|
||||||
|
// We have our asynchronous result from the worker.
|
||||||
|
//
|
||||||
|
// Determine if our input was large enough to trigger heap growth,
|
||||||
|
// or if we're already waiting to destroy the worker when it's
|
||||||
|
// idle. If so, schedule termination after the idle timeout.
|
||||||
|
if (aParams.text.length >= LARGE_STRING || this._idleTimeout != null)
|
||||||
|
this.flushWorker();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
_worker: null,
|
||||||
|
_workerReadyPromise: null,
|
||||||
|
|
||||||
|
get workerReady() {
|
||||||
|
if (!this._workerReadyPromise)
|
||||||
|
this._workerReadyPromise = new Promise(resolve => {
|
||||||
|
let worker = new Worker(WORKER_URL);
|
||||||
|
worker.onmessage = (aMsg) => {
|
||||||
|
if (aMsg.data == "ready")
|
||||||
|
resolve(worker);
|
||||||
|
else
|
||||||
|
this.detectionQueue.shift().resolve(aMsg.data);
|
||||||
|
};
|
||||||
|
this._worker = worker;
|
||||||
|
});
|
||||||
|
|
||||||
|
return this._workerReadyPromise;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Holds the ID of the current pending idle cleanup setTimeout.
|
||||||
|
_idleTimeout: null,
|
||||||
|
|
||||||
|
// Schedule the current worker to be terminated after the idle timeout.
|
||||||
|
flushWorker() {
|
||||||
|
if (this._idleTimeout != null)
|
||||||
|
clearTimeout(this._idleTimeout);
|
||||||
|
|
||||||
|
this._idleTimeout = setTimeout(this._flushWorker.bind(this), IDLE_TIMEOUT);
|
||||||
|
},
|
||||||
|
|
||||||
|
// Immediately terminate the worker, as long as there no pending
|
||||||
|
// results. Otherwise, reschedule termination until after the next
|
||||||
|
// idle timeout.
|
||||||
|
_flushWorker() {
|
||||||
|
if (this.detectionQueue.length)
|
||||||
|
this.flushWorker();
|
||||||
|
else {
|
||||||
|
if (this._worker)
|
||||||
|
this._worker.terminate();
|
||||||
|
|
||||||
|
this._worker = null;
|
||||||
|
this._workerReadyPromise = null;
|
||||||
|
this._idleTimeout = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
this.LanguageDetector = {
|
this.LanguageDetector = {
|
||||||
/**
|
/**
|
||||||
* Detect the language of a given string
|
* Detect the language of a given string.
|
||||||
*
|
*
|
||||||
* @returns {Promise}
|
* The argument may be either a string containing the text to analyze,
|
||||||
|
* or an object with the following properties:
|
||||||
|
*
|
||||||
|
* - 'text' The text to analyze.
|
||||||
|
*
|
||||||
|
* - 'isHTML' (optional) A boolean, indicating whether the text
|
||||||
|
* should be analyzed as HTML rather than plain text.
|
||||||
|
*
|
||||||
|
* - 'language' (optional) A string indicating the expected language.
|
||||||
|
* For text extracted from HTTP documents, this is expected to
|
||||||
|
* come from the Content-Language header.
|
||||||
|
*
|
||||||
|
* - 'tld' (optional) A string indicating the top-level domain of the
|
||||||
|
* document the text was extracted from.
|
||||||
|
*
|
||||||
|
* - 'encoding' (optional) A string describing the encoding of the
|
||||||
|
* document the string was extracted from. Note that, regardless
|
||||||
|
* of the value of this property, the 'text' property must be a
|
||||||
|
* UTF-16 JavaScript string.
|
||||||
|
*
|
||||||
|
* @returns {Promise<Object>}
|
||||||
* @resolves When detection is finished, with a object containing
|
* @resolves When detection is finished, with a object containing
|
||||||
* these fields:
|
* these fields:
|
||||||
* - 'language' (string with a language code)
|
* - 'language' (string with a language code)
|
||||||
* - 'confident' (boolean).
|
* - 'confident' (boolean) Whether the detector is confident of the
|
||||||
|
* result.
|
||||||
|
* - 'languages' (array) An array of up to three elements, containing
|
||||||
|
* the most prevalent languages detected. It contains a
|
||||||
|
* 'languageCode' property, containing the ISO language code of
|
||||||
|
* the language, and a 'percent' property, describing the
|
||||||
|
* approximate percentage of the input which is in that language.
|
||||||
|
* For text of an unknown language, the result may contain an
|
||||||
|
* entry with the languge code 'un', indicating the percent of
|
||||||
|
* the text which is unknown.
|
||||||
*/
|
*/
|
||||||
detectLanguage: function(aString) {
|
detectLanguage: function(aParams) {
|
||||||
let deferred = Promise.defer();
|
if (typeof aParams == "string")
|
||||||
detectionQueue.push(deferred);
|
aParams = { text: aParams };
|
||||||
if (worker && workerReady)
|
|
||||||
worker.postMessage(aString);
|
return workerManager.detectLanguage(aParams);
|
||||||
else
|
},
|
||||||
pendingStrings.push(aString);
|
|
||||||
return deferred.promise;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,8 +1,29 @@
|
||||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
# 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,
|
# 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/. */
|
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
CC=emcc
|
PYTHON2 ?= python2
|
||||||
|
|
||||||
|
EMSCRIPTEN_ROOT := $(shell if which emcc >/dev/null 2>&1; \
|
||||||
|
then dirname `which emcc`; \
|
||||||
|
else echo /usr/lib/emscripten; \
|
||||||
|
fi)
|
||||||
|
|
||||||
|
EMCC ?= $(EMSCRIPTEN_ROOT)/emcc
|
||||||
|
|
||||||
|
WEBIDL ?= $(PYTHON2) $(EMSCRIPTEN_ROOT)/tools/webidl_binder.py
|
||||||
|
|
||||||
|
# A 2MB heap is to analyze most web pages. For the outliers, we need to either
|
||||||
|
# allow for heap growth, or allocate an unreasonable amount of memory at the
|
||||||
|
# outset.
|
||||||
|
# Unfortunately, once the heap has been enlarged, there is no shrinking, so
|
||||||
|
# analyzing one 20MB web page gives us a 30-40MB heap for the life of the
|
||||||
|
# worker.
|
||||||
|
FLAGS=-s -O3 -s INLINING_LIMIT=1 -s NO_FILESYSTEM=1 -s NO_EXIT_RUNTIME=1 -s INVOKE_RUN=0 \
|
||||||
|
-s TOTAL_STACK=8192 -s TOTAL_MEMORY=2097152 -s ALLOW_MEMORY_GROWTH=1 \
|
||||||
|
--llvm-lto 1 --memory-init-file 1 --closure 1
|
||||||
|
|
||||||
|
export EMCC_CLOSURE_ARGS = --language_in ECMASCRIPT6 --language_out ES5_STRICT
|
||||||
|
|
||||||
SOURCES= \
|
SOURCES= \
|
||||||
internal/cldutil.cc \
|
internal/cldutil.cc \
|
||||||
|
@ -32,13 +53,22 @@ SOURCES= \
|
||||||
cldapp.cc \
|
cldapp.cc \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
%.o: %.cc
|
OBJECTS=$(SOURCES:.cc=.o)
|
||||||
$(CC) -Os -I. -o $@ $<
|
|
||||||
|
|
||||||
FLAGS=-s USE_TYPED_ARRAYS=2 -O3 -s INLINING_LIMIT=1 --llvm-lto 1 --memory-init-file 1 --closure 1
|
default: all
|
||||||
|
|
||||||
all: $(SOURCES:.cc=.o)
|
%.o: %.cc Makefile
|
||||||
$(CC) $(FLAGS) -I. -o cld-worker.js $^ --post-js post.js -s EXPORTED_FUNCTIONS="['_detectLangCode', '_lastResultReliable']"
|
$(EMCC) -Os -I. -o $@ $<
|
||||||
|
|
||||||
|
cldapp.o: cld.cpp
|
||||||
|
|
||||||
|
%.cpp %.js: %.idl
|
||||||
|
$(WEBIDL) $< $*
|
||||||
|
|
||||||
|
all: cld-worker.js
|
||||||
|
|
||||||
|
cld-worker.js: $(OBJECTS) post.js cld.js
|
||||||
|
$(EMCC) $(FLAGS) -I. -o cld-worker.js $(OBJECTS) --post-js cld.js --post-js post.js
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(SOURCES:.cc=.o)
|
rm -f $(OBJECTS) cld.cpp cld.js before.js
|
||||||
|
|
Двоичные данные
browser/components/translation/cld2/cld-worker.js.mem
|
@ -0,0 +1,47 @@
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
// Note: This is a variant of WebIDL, but its semantics differ from our
|
||||||
|
// internal WebIDL implementation. Some particular differences that are
|
||||||
|
// relevent here include:
|
||||||
|
//
|
||||||
|
// - Attribute declarations refer directly to member variables of the
|
||||||
|
// underlying class, and are not forwarded to explicit getter methods.
|
||||||
|
//
|
||||||
|
// - Attribute declarations also do not create getters on the JavaScript
|
||||||
|
// wrapper object, but instead generate "get_foo()" and "set_foo()"
|
||||||
|
// methods, which must be called in order to access the value. In the case
|
||||||
|
// of array attributes, the callers must also pass the index they wish to
|
||||||
|
// access.
|
||||||
|
//
|
||||||
|
// - Method overloading is fairly crude. Only explicitly declared variants
|
||||||
|
// are supported, and selection is based entirely on index of the first
|
||||||
|
// parameter whose value is undefined.
|
||||||
|
//
|
||||||
|
// - DOMString attributes are nullable by default. Null values are not
|
||||||
|
// converted to empty strings, and non-null values are converted to
|
||||||
|
// null-terminated, UTF-8 byte arrays.
|
||||||
|
|
||||||
|
interface Language {
|
||||||
|
[Const] DOMString getLanguageCode();
|
||||||
|
};
|
||||||
|
|
||||||
|
interface LanguageGuess {
|
||||||
|
byte getPercent();
|
||||||
|
};
|
||||||
|
|
||||||
|
interface LanguageInfo {
|
||||||
|
static LanguageInfo detectLanguage(DOMString buffer, boolean isPlainText);
|
||||||
|
|
||||||
|
static LanguageInfo detectLanguage(DOMString buffer, boolean isPlainText,
|
||||||
|
DOMString? tldHint, long encodingHint,
|
||||||
|
DOMString? languageHint);
|
||||||
|
|
||||||
|
boolean getIsReliable();
|
||||||
|
|
||||||
|
[BoundsChecked,Const] readonly attribute LanguageGuess[] languages;
|
||||||
|
};
|
||||||
|
|
||||||
|
LanguageGuess implements Language;
|
||||||
|
LanguageInfo implements Language;
|
|
@ -4,20 +4,104 @@
|
||||||
|
|
||||||
#include "public/compact_lang_det.h"
|
#include "public/compact_lang_det.h"
|
||||||
|
|
||||||
extern "C" {
|
#define MAX_RESULTS 3
|
||||||
|
|
||||||
using namespace CLD2;
|
class Language {
|
||||||
|
public:
|
||||||
|
Language(CLD2::Language lang) : mLang(lang) {}
|
||||||
|
|
||||||
bool g_is_reliable;
|
const char* getLanguageCode() const
|
||||||
|
{
|
||||||
const char* detectLangCode(const char* src) {
|
return CLD2::LanguageCode(mLang);
|
||||||
return LanguageCode(DetectLanguage(src, strlen(src),
|
|
||||||
true /* is_plain_text */,
|
|
||||||
&g_is_reliable));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lastResultReliable(void) {
|
private:
|
||||||
return g_is_reliable;
|
const CLD2::Language mLang;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LanguageGuess : public Language {
|
||||||
|
public:
|
||||||
|
LanguageGuess(CLD2::Language lang, char percent) :
|
||||||
|
Language(lang), mPercent(percent) {}
|
||||||
|
|
||||||
|
char getPercent() const
|
||||||
|
{
|
||||||
|
return mPercent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char mPercent;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class LanguageInfo : public Language {
|
||||||
|
public:
|
||||||
|
static LanguageInfo* detectLanguage(const char* buffer, bool isPlainText)
|
||||||
|
{
|
||||||
|
CLD2::Language languages[MAX_RESULTS] = {};
|
||||||
|
int percentages[MAX_RESULTS] = {};
|
||||||
|
bool isReliable = false;
|
||||||
|
|
||||||
|
// This is ignored.
|
||||||
|
int textBytes;
|
||||||
|
|
||||||
|
CLD2::Language bestGuess = DetectLanguageSummary(
|
||||||
|
buffer, strlen(buffer), isPlainText,
|
||||||
|
languages, percentages, &textBytes,
|
||||||
|
&isReliable);
|
||||||
|
|
||||||
|
return new LanguageInfo(isReliable, bestGuess, languages, percentages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static LanguageInfo* detectLanguage(const char* buffer, bool isPlainText,
|
||||||
|
const char* tldHint, int encodingHint,
|
||||||
|
const char* languageHint)
|
||||||
|
{
|
||||||
|
CLD2::CLDHints hints = {languageHint, tldHint, encodingHint, CLD2::UNKNOWN_LANGUAGE};
|
||||||
|
|
||||||
|
CLD2::Language languages[MAX_RESULTS] = {};
|
||||||
|
int percentages[MAX_RESULTS] = {};
|
||||||
|
bool isReliable = false;
|
||||||
|
|
||||||
|
// These are ignored.
|
||||||
|
double scores[MAX_RESULTS];
|
||||||
|
int textBytes;
|
||||||
|
|
||||||
|
CLD2::Language bestGuess = ExtDetectLanguageSummary(
|
||||||
|
buffer, strlen(buffer), isPlainText,
|
||||||
|
&hints, 0,
|
||||||
|
languages, percentages, scores,
|
||||||
|
nullptr, &textBytes, &isReliable);
|
||||||
|
|
||||||
|
return new LanguageInfo(isReliable, bestGuess, languages, percentages);
|
||||||
|
}
|
||||||
|
|
||||||
|
~LanguageInfo()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < MAX_RESULTS; i++) {
|
||||||
|
delete languages[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getIsReliable() const
|
||||||
|
{
|
||||||
|
return mIsReliable;
|
||||||
|
}
|
||||||
|
|
||||||
|
const LanguageGuess* languages[MAX_RESULTS];
|
||||||
|
|
||||||
|
private:
|
||||||
|
LanguageInfo(bool isReliable, CLD2::Language bestGuess,
|
||||||
|
CLD2::Language languageIDs[MAX_RESULTS],
|
||||||
|
int percentages[MAX_RESULTS]) :
|
||||||
|
Language(bestGuess), mIsReliable(isReliable)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < MAX_RESULTS; i++) {
|
||||||
|
languages[i] = new LanguageGuess(languageIDs[i], percentages[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool mIsReliable;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "cld.cpp"
|
||||||
|
|
|
@ -2,31 +2,170 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
* 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/. */
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
// The WebIDL binder places static methods on the prototype, rather than
|
||||||
|
// on the constructor, which is a bit clumsy, and is definitely not
|
||||||
|
// idiomatic.
|
||||||
|
LanguageInfo.detectLanguage = LanguageInfo.prototype.detectLanguage;
|
||||||
|
|
||||||
|
// Closure is overzealous in its function call optimization, and tries
|
||||||
|
// to turn these singleton methods into unbound function calls.
|
||||||
|
ensureCache.alloc = ensureCache.alloc.bind(ensureCache);
|
||||||
|
ensureCache.prepare = ensureCache.prepare.bind(ensureCache);
|
||||||
|
|
||||||
|
// From public/encodings.h. Unfortunately, the WebIDL binder doesn't
|
||||||
|
// allow us to define or automatically derive these in the IDL.
|
||||||
|
var Encodings = {
|
||||||
|
'ISO_8859_1' : 0,
|
||||||
|
'ISO_8859_2' : 1,
|
||||||
|
'ISO_8859_3' : 2,
|
||||||
|
'ISO_8859_4' : 3,
|
||||||
|
'ISO_8859_5' : 4,
|
||||||
|
'ISO_8859_6' : 5,
|
||||||
|
'ISO_8859_7' : 6,
|
||||||
|
'ISO_8859_8' : 7,
|
||||||
|
'ISO_8859_9' : 8,
|
||||||
|
'ISO_8859_10' : 9,
|
||||||
|
'JAPANESE_EUC_JP' : 10,
|
||||||
|
'EUC_JP' : 10,
|
||||||
|
'JAPANESE_SHIFT_JIS' : 11,
|
||||||
|
'SHIFT_JIS' : 11,
|
||||||
|
'JAPANESE_JIS' : 12,
|
||||||
|
'JIS' : 12,
|
||||||
|
'CHINESE_BIG5' : 13,
|
||||||
|
'BIG5' : 13,
|
||||||
|
'CHINESE_GB' : 14,
|
||||||
|
'CHINESE_EUC_CN' : 15,
|
||||||
|
'EUC_CN' : 15,
|
||||||
|
'KOREAN_EUC_KR' : 16,
|
||||||
|
'EUC_KR' : 16,
|
||||||
|
'UNICODE_UNUSED' : 17,
|
||||||
|
'CHINESE_EUC_DEC' : 18,
|
||||||
|
'EUC_DEC' : 18,
|
||||||
|
'CHINESE_CNS' : 19,
|
||||||
|
'CNS' : 19,
|
||||||
|
'CHINESE_BIG5_CP950' : 20,
|
||||||
|
'BIG5_CP950' : 20,
|
||||||
|
'JAPANESE_CP932' : 21,
|
||||||
|
'CP932' : 21,
|
||||||
|
'UTF8' : 22,
|
||||||
|
'UNKNOWN_ENCODING' : 23,
|
||||||
|
'ASCII_7BIT' : 24,
|
||||||
|
'RUSSIAN_KOI8_R' : 25,
|
||||||
|
'KOI8_R' : 25,
|
||||||
|
'RUSSIAN_CP1251' : 26,
|
||||||
|
'CP1251' : 26,
|
||||||
|
'MSFT_CP1252' : 27,
|
||||||
|
'CP1252' : 27,
|
||||||
|
'RUSSIAN_KOI8_RU' : 28,
|
||||||
|
'KOI8_RU' : 28,
|
||||||
|
'MSFT_CP1250' : 29,
|
||||||
|
'CP1250' : 29,
|
||||||
|
'ISO_8859_15' : 30,
|
||||||
|
'MSFT_CP1254' : 31,
|
||||||
|
'CP1254' : 31,
|
||||||
|
'MSFT_CP1257' : 32,
|
||||||
|
'CP1257' : 32,
|
||||||
|
'ISO_8859_11' : 33,
|
||||||
|
'MSFT_CP874' : 34,
|
||||||
|
'CP874' : 34,
|
||||||
|
'MSFT_CP1256' : 35,
|
||||||
|
'CP1256' : 35,
|
||||||
|
'MSFT_CP1255' : 36,
|
||||||
|
'CP1255' : 36,
|
||||||
|
'ISO_8859_8_I' : 37,
|
||||||
|
'HEBREW_VISUAL' : 38,
|
||||||
|
'CZECH_CP852' : 39,
|
||||||
|
'CP852' : 39,
|
||||||
|
'CZECH_CSN_369103' : 40,
|
||||||
|
'CSN_369103' : 40,
|
||||||
|
'MSFT_CP1253' : 41,
|
||||||
|
'CP1253' : 41,
|
||||||
|
'RUSSIAN_CP866' : 42,
|
||||||
|
'CP866' : 42,
|
||||||
|
'ISO_8859_13' : 43,
|
||||||
|
'ISO_2022_KR' : 44,
|
||||||
|
'GBK' : 45,
|
||||||
|
'GB18030' : 46,
|
||||||
|
'BIG5_HKSCS' : 47,
|
||||||
|
'ISO_2022_CN' : 48,
|
||||||
|
'TSCII' : 49,
|
||||||
|
'TAMIL_MONO' : 50,
|
||||||
|
'TAMIL_BI' : 51,
|
||||||
|
'JAGRAN' : 52,
|
||||||
|
'MACINTOSH_ROMAN' : 53,
|
||||||
|
'UTF7' : 54,
|
||||||
|
'BHASKAR' : 55,
|
||||||
|
'HTCHANAKYA' : 56,
|
||||||
|
'UTF16BE' : 57,
|
||||||
|
'UTF16LE' : 58,
|
||||||
|
'UTF32BE' : 59,
|
||||||
|
'UTF32LE' : 60,
|
||||||
|
'BINARYENC' : 61,
|
||||||
|
'HZ_GB_2312' : 62,
|
||||||
|
'UTF8UTF8' : 63,
|
||||||
|
'TAM_ELANGO' : 64,
|
||||||
|
'TAM_LTTMBARANI' : 65,
|
||||||
|
'TAM_SHREE' : 66,
|
||||||
|
'TAM_TBOOMIS' : 67,
|
||||||
|
'TAM_TMNEWS' : 68,
|
||||||
|
'TAM_WEBTAMIL' : 69,
|
||||||
|
'KDDI_SHIFT_JIS' : 70,
|
||||||
|
'DOCOMO_SHIFT_JIS' : 71,
|
||||||
|
'SOFTBANK_SHIFT_JIS' : 72,
|
||||||
|
'KDDI_ISO_2022_JP' : 73,
|
||||||
|
'ISO_2022_JP' : 73,
|
||||||
|
'SOFTBANK_ISO_2022_JP' : 74,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Accept forms both with and without underscores/hypens.
|
||||||
|
for (let code of Object.keys(Encodings)) {
|
||||||
|
if (code['includes']("_"))
|
||||||
|
Encodings[code.replace(/_/g, "")] = Encodings[code];
|
||||||
|
}
|
||||||
|
|
||||||
addOnPreMain(function() {
|
addOnPreMain(function() {
|
||||||
|
|
||||||
onmessage = function(aMsg){
|
onmessage = function(aMsg){
|
||||||
|
let data = aMsg['data'];
|
||||||
|
|
||||||
// Convert the string to an array of UTF8 bytes.
|
let langInfo;
|
||||||
var encoder = new TextEncoder();
|
if (data['tld'] == undefined && data['encoding'] == undefined && data['language'] == undefined) {
|
||||||
encoder['encoding'] = "utf-8";
|
langInfo = LanguageInfo.detectLanguage(data['text'], !data['isHTML']);
|
||||||
var utf8Array = encoder['encode'](aMsg.data);
|
} else {
|
||||||
|
// Do our best to find the given encoding in the encodings table.
|
||||||
|
// Otherwise, just fall back to unknown.
|
||||||
|
let enc = String(data['encoding']).toUpperCase().replace(/[_-]/g, "");
|
||||||
|
|
||||||
// Copy the UTF8 byte array to the heap.
|
let encoding;
|
||||||
var strLength = utf8Array.length;
|
if (Encodings.hasOwnProperty(enc))
|
||||||
var ptr = Module['_malloc'](strLength + 1);
|
encoding = Encodings[enc];
|
||||||
var heap = Module['HEAPU8'];
|
else
|
||||||
new Uint8Array(heap.buffer, ptr, strLength).set(utf8Array);
|
encoding = Encodings['UNKNOWN_ENCODING'];
|
||||||
// Add a \0 at the end of the C string.
|
|
||||||
heap[ptr + strLength] = 0;
|
|
||||||
|
|
||||||
var lang = Pointer_stringify(_detectLangCode(ptr));
|
langInfo = LanguageInfo.detectLanguage(data['text'], !data['isHTML'],
|
||||||
var confident = !!Module['ccall']("lastResultReliable", "number");
|
data['tld'] || null,
|
||||||
postMessage({'language': lang,
|
encoding,
|
||||||
'confident': confident});
|
data['language'] || null);
|
||||||
|
}
|
||||||
|
|
||||||
Module['_free'](ptr);
|
postMessage({
|
||||||
|
'language': langInfo.getLanguageCode(),
|
||||||
|
'confident': langInfo.getIsReliable(),
|
||||||
|
|
||||||
|
'languages': new Array(3).fill(0).map((_, index) => {
|
||||||
|
let lang = langInfo.get_languages(index);
|
||||||
|
return {
|
||||||
|
'languageCode': lang.getLanguageCode(),
|
||||||
|
'percent': lang.getPercent(),
|
||||||
|
};
|
||||||
|
}).filter(lang => {
|
||||||
|
// Ignore empty results.
|
||||||
|
return lang['languageCode'] != "un" || lang['percent'] > 0;
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
Module.destroy(langInfo);
|
||||||
};
|
};
|
||||||
|
|
||||||
postMessage("ready");
|
postMessage("ready");
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -308,7 +308,7 @@ const kTestPairs = [
|
||||||
["bg", "BULGARIAN", kTeststr_bg_Cyrl],
|
["bg", "BULGARIAN", kTeststr_bg_Cyrl],
|
||||||
["ca", "CATALAN", kTeststr_ca_Latn],
|
["ca", "CATALAN", kTeststr_ca_Latn],
|
||||||
["ceb", "CEBUANO", kTeststr_ceb_Latn],
|
["ceb", "CEBUANO", kTeststr_ceb_Latn],
|
||||||
["hr", "CROATIAN", kTeststr_hr_Latn],
|
["hr", "CROATIAN", kTeststr_hr_Latn, [false, 0, "el", 4]],
|
||||||
["cs", "CZECH", kTeststr_cs_Latn],
|
["cs", "CZECH", kTeststr_cs_Latn],
|
||||||
["da", "DANISH", kTeststr_da_Latn],
|
["da", "DANISH", kTeststr_da_Latn],
|
||||||
["nl", "DUTCH", kTeststr_nl_Latn],
|
["nl", "DUTCH", kTeststr_nl_Latn],
|
||||||
|
@ -335,7 +335,7 @@ const kTestPairs = [
|
||||||
["mk", "MACEDONIAN", kTeststr_mk_Cyrl],
|
["mk", "MACEDONIAN", kTeststr_mk_Cyrl],
|
||||||
["ms", "MALAY", kTeststr_ms_Latn],
|
["ms", "MALAY", kTeststr_ms_Latn],
|
||||||
["mt", "MALTESE", kTeststr_mt_Latn],
|
["mt", "MALTESE", kTeststr_mt_Latn],
|
||||||
["mr", "MARATHI", kTeststr_mr_Deva],
|
["mr", "MARATHI", kTeststr_mr_Deva, [false, 0, "te", 3]],
|
||||||
["ne", "NEPALI", kTeststr_ne_Deva],
|
["ne", "NEPALI", kTeststr_ne_Deva],
|
||||||
["no", "NORWEGIAN", kTeststr_no_Latn],
|
["no", "NORWEGIAN", kTeststr_no_Latn],
|
||||||
["fa", "PERSIAN", kTeststr_fa_Arab],
|
["fa", "PERSIAN", kTeststr_fa_Arab],
|
||||||
|
@ -370,11 +370,11 @@ const kTestPairs = [
|
||||||
["bs", "BOSNIAN", kTeststr_bs_Latn],
|
["bs", "BOSNIAN", kTeststr_bs_Latn],
|
||||||
|
|
||||||
// 2 statistically-close languages
|
// 2 statistically-close languages
|
||||||
["id", "INDONESIAN", kTeststr_id_close, true],
|
["id", "INDONESIAN", kTeststr_id_close, [true, 80], []],
|
||||||
["ms", "MALAY", kTeststr_ms_close],
|
["ms", "MALAY", kTeststr_ms_close],
|
||||||
|
|
||||||
// Simple intermixed French/English text
|
// Simple intermixed French/English text
|
||||||
["fr", "FRENCH", kTeststr_fr_en_Latn],
|
["fr", "FRENCH", kTeststr_fr_en_Latn, [false, 80, "en", 32]],
|
||||||
|
|
||||||
// Cross-check the main quadgram table build date
|
// Cross-check the main quadgram table build date
|
||||||
// Change the expected language each time it is rebuilt
|
// Change the expected language each time it is rebuilt
|
||||||
|
@ -382,14 +382,92 @@ const kTestPairs = [
|
||||||
["az", "AZERBAIJANI", kTeststr_version] // 2014.01.31
|
["az", "AZERBAIJANI", kTeststr_version] // 2014.01.31
|
||||||
];
|
];
|
||||||
|
|
||||||
Components.utils.import("resource:///modules/translation/LanguageDetector.jsm");
|
Components.utils.import("resource://gre/modules/Timer.jsm");
|
||||||
|
let detectorModule = Components.utils.import("resource:///modules/translation/LanguageDetector.jsm");
|
||||||
|
|
||||||
add_task(function test_pairs() {
|
function check_result(result, langCode, expected) {
|
||||||
for (let pair of kTestPairs) {
|
equal(result.language, langCode, "Expected language code");
|
||||||
let result = yield LanguageDetector.detectLanguage(pair[2]);
|
|
||||||
do_check_eq(result.language, pair[0]);
|
// Round percentage up to the nearest 5%, since most strings are
|
||||||
do_check_eq(result.confident, !pair[3]);
|
// detected at slightly less than 100%, and we don't want to
|
||||||
|
// encode each exact value.
|
||||||
|
let percent = result.languages[0].percent;
|
||||||
|
percent = Math.ceil(percent / 20) * 20;
|
||||||
|
|
||||||
|
equal(result.languages[0].languageCode, langCode, "Expected first guess language code");
|
||||||
|
equal(percent, expected[1] || 100, "Expected first guess language percent");
|
||||||
|
|
||||||
|
if (expected.length < 3) {
|
||||||
|
// We're not expecting a second language.
|
||||||
|
equal(result.languages.length, 1, "Expected only one language result");
|
||||||
|
} else {
|
||||||
|
equal(result.languages.length, 2, "Expected two language results");
|
||||||
|
|
||||||
|
equal(result.languages[1].languageCode, expected[2], "Expected second guess language code");
|
||||||
|
equal(result.languages[1].percent, expected[3], "Expected second guess language percent");
|
||||||
|
}
|
||||||
|
|
||||||
|
equal(result.confident, !expected[0], "Expected confidence");
|
||||||
|
}
|
||||||
|
|
||||||
|
add_task(function* test_pairs() {
|
||||||
|
for (let item of kTestPairs) {
|
||||||
|
let params = [item[2],
|
||||||
|
{ text: item[2], tld: "com", language: item[0], encoding: "utf-8" }]
|
||||||
|
|
||||||
|
for (let [i, param] of params.entries()) {
|
||||||
|
// For test items with different expected results when using the
|
||||||
|
// language hint, use those for the hinted version of the API.
|
||||||
|
// Otherwise, fall back to the first set of expected values.
|
||||||
|
let expected = item[3 + i] || item[3] || [];
|
||||||
|
|
||||||
|
let result = yield LanguageDetector.detectLanguage(param);
|
||||||
|
check_result(result, item[0], expected);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var run_test = run_next_test;
|
// Test that the worker is flushed shortly after processing a large
|
||||||
|
// string.
|
||||||
|
add_task(function* test_worker_flush() {
|
||||||
|
let test_string = kTeststr_fr_en_Latn;
|
||||||
|
let test_item = kTestPairs.find(item => item[2] == test_string);
|
||||||
|
|
||||||
|
// Set shorter timeouts and lower string lengths to make things easier
|
||||||
|
// on the test infrastructure.
|
||||||
|
detectorModule.LARGE_STRING = test_string.length - 1;
|
||||||
|
detectorModule.IDLE_TIMEOUT = 1000;
|
||||||
|
|
||||||
|
equal(detectorModule.workerManager._idleTimeout, null,
|
||||||
|
"Should have no idle timeout to start with");
|
||||||
|
|
||||||
|
let result = yield LanguageDetector.detectLanguage(test_string);
|
||||||
|
|
||||||
|
// Make sure the results are still correct.
|
||||||
|
check_result(result, test_item[0], test_item[3]);
|
||||||
|
|
||||||
|
// We should have an idle timeout after processing the string.
|
||||||
|
ok(detectorModule.workerManager._idleTimeout != null,
|
||||||
|
"Should have an idle timeout");
|
||||||
|
ok(detectorModule.workerManager._worker != null,
|
||||||
|
"Should have a worker instance");
|
||||||
|
ok(detectorModule.workerManager._workerReadyPromise != null,
|
||||||
|
"Should have a worker promise");
|
||||||
|
|
||||||
|
// Wait for the idle timeout to elapse.
|
||||||
|
yield new Promise(resolve => setTimeout(resolve, detectorModule.IDLE_TIMEOUT));
|
||||||
|
|
||||||
|
equal(detectorModule.workerManager._idleTimeout, null,
|
||||||
|
"Should have no idle timeout after it has elapsed");
|
||||||
|
equal(detectorModule.workerManager._worker, null,
|
||||||
|
"Should have no worker instance after idle timeout");
|
||||||
|
equal(detectorModule.workerManager._workerReadyPromise, null,
|
||||||
|
"Should have no worker promise after idle timeout");
|
||||||
|
|
||||||
|
// We should still be able to use the language detector after its
|
||||||
|
// worker has been flushed.
|
||||||
|
result = yield LanguageDetector.detectLanguage(test_string);
|
||||||
|
|
||||||
|
// Make sure the results are still correct.
|
||||||
|
check_result(result, test_item[0], test_item[3]);
|
||||||
|
});
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
This is the pdf.js project output, https://github.com/mozilla/pdf.js
|
This is the pdf.js project output, https://github.com/mozilla/pdf.js
|
||||||
|
|
||||||
Current extension version is: 1.4.64
|
Current extension version is: 1.4.83
|
||||||
|
|
|
@ -72,9 +72,15 @@ function getFindBar(domWindow) {
|
||||||
tab = tabbrowser.getTabForBrowser(browser);
|
tab = tabbrowser.getTabForBrowser(browser);
|
||||||
return tabbrowser.getFindBar(tab);
|
return tabbrowser.getFindBar(tab);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
try {
|
||||||
// FF22 has no _getTabForBrowser, and FF24 has no getFindBar
|
// FF22 has no _getTabForBrowser, and FF24 has no getFindBar
|
||||||
var chromeWindow = browser.ownerDocument.defaultView;
|
var chromeWindow = browser.ownerDocument.defaultView;
|
||||||
return chromeWindow.gFindBar;
|
return chromeWindow.gFindBar;
|
||||||
|
} catch (ex) {
|
||||||
|
// Suppress errors for PDF files opened in the bookmark sidebar, see
|
||||||
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=1248959.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,7 +358,7 @@ ChromeActions.prototype = {
|
||||||
|
|
||||||
// ... or when the new find events code exists.
|
// ... or when the new find events code exists.
|
||||||
var findBar = getFindBar(this.domWindow);
|
var findBar = getFindBar(this.domWindow);
|
||||||
return findBar && ('updateControlState' in findBar);
|
return !!findBar && ('updateControlState' in findBar);
|
||||||
},
|
},
|
||||||
supportsDocumentFonts: function() {
|
supportsDocumentFonts: function() {
|
||||||
var prefBrowser = getIntPref('browser.display.use_document_fonts', 1);
|
var prefBrowser = getIntPref('browser.display.use_document_fonts', 1);
|
||||||
|
|
|
@ -28,8 +28,8 @@ factory((root.pdfjsDistBuildPdf = {}));
|
||||||
// Use strict in our context only - users might not want it
|
// Use strict in our context only - users might not want it
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var pdfjsVersion = '1.4.64';
|
var pdfjsVersion = '1.4.83';
|
||||||
var pdfjsBuild = '2f145d8';
|
var pdfjsBuild = '0629fd0';
|
||||||
|
|
||||||
var pdfjsFilePath =
|
var pdfjsFilePath =
|
||||||
typeof document !== 'undefined' && document.currentScript ?
|
typeof document !== 'undefined' && document.currentScript ?
|
||||||
|
@ -1629,7 +1629,7 @@ AnnotationElementFactory.prototype =
|
||||||
return new StrikeOutAnnotationElement(parameters);
|
return new StrikeOutAnnotationElement(parameters);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new Error('Unimplemented annotation type "' + subtype + '"');
|
return new AnnotationElement(parameters);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1639,15 +1639,18 @@ AnnotationElementFactory.prototype =
|
||||||
* @alias AnnotationElement
|
* @alias AnnotationElement
|
||||||
*/
|
*/
|
||||||
var AnnotationElement = (function AnnotationElementClosure() {
|
var AnnotationElement = (function AnnotationElementClosure() {
|
||||||
function AnnotationElement(parameters) {
|
function AnnotationElement(parameters, isRenderable) {
|
||||||
|
this.isRenderable = isRenderable || false;
|
||||||
this.data = parameters.data;
|
this.data = parameters.data;
|
||||||
this.layer = parameters.layer;
|
this.layer = parameters.layer;
|
||||||
this.page = parameters.page;
|
this.page = parameters.page;
|
||||||
this.viewport = parameters.viewport;
|
this.viewport = parameters.viewport;
|
||||||
this.linkService = parameters.linkService;
|
this.linkService = parameters.linkService;
|
||||||
|
|
||||||
|
if (isRenderable) {
|
||||||
this.container = this._createContainer();
|
this.container = this._createContainer();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AnnotationElement.prototype = /** @lends AnnotationElement.prototype */ {
|
AnnotationElement.prototype = /** @lends AnnotationElement.prototype */ {
|
||||||
/**
|
/**
|
||||||
|
@ -1761,7 +1764,7 @@ var AnnotationElement = (function AnnotationElementClosure() {
|
||||||
*/
|
*/
|
||||||
var LinkAnnotationElement = (function LinkAnnotationElementClosure() {
|
var LinkAnnotationElement = (function LinkAnnotationElementClosure() {
|
||||||
function LinkAnnotationElement(parameters) {
|
function LinkAnnotationElement(parameters) {
|
||||||
AnnotationElement.call(this, parameters);
|
AnnotationElement.call(this, parameters, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Util.inherit(LinkAnnotationElement, AnnotationElement, {
|
Util.inherit(LinkAnnotationElement, AnnotationElement, {
|
||||||
|
@ -1843,7 +1846,9 @@ var LinkAnnotationElement = (function LinkAnnotationElementClosure() {
|
||||||
*/
|
*/
|
||||||
var TextAnnotationElement = (function TextAnnotationElementClosure() {
|
var TextAnnotationElement = (function TextAnnotationElementClosure() {
|
||||||
function TextAnnotationElement(parameters) {
|
function TextAnnotationElement(parameters) {
|
||||||
AnnotationElement.call(this, parameters);
|
var isRenderable = !!(parameters.data.hasPopup ||
|
||||||
|
parameters.data.title || parameters.data.contents);
|
||||||
|
AnnotationElement.call(this, parameters, isRenderable);
|
||||||
}
|
}
|
||||||
|
|
||||||
Util.inherit(TextAnnotationElement, AnnotationElement, {
|
Util.inherit(TextAnnotationElement, AnnotationElement, {
|
||||||
|
@ -1897,7 +1902,9 @@ var TextAnnotationElement = (function TextAnnotationElementClosure() {
|
||||||
*/
|
*/
|
||||||
var WidgetAnnotationElement = (function WidgetAnnotationElementClosure() {
|
var WidgetAnnotationElement = (function WidgetAnnotationElementClosure() {
|
||||||
function WidgetAnnotationElement(parameters) {
|
function WidgetAnnotationElement(parameters) {
|
||||||
AnnotationElement.call(this, parameters);
|
var isRenderable = !parameters.data.hasAppearance &&
|
||||||
|
!!parameters.data.fieldValue;
|
||||||
|
AnnotationElement.call(this, parameters, isRenderable);
|
||||||
}
|
}
|
||||||
|
|
||||||
Util.inherit(WidgetAnnotationElement, AnnotationElement, {
|
Util.inherit(WidgetAnnotationElement, AnnotationElement, {
|
||||||
|
@ -1964,7 +1971,8 @@ var WidgetAnnotationElement = (function WidgetAnnotationElementClosure() {
|
||||||
*/
|
*/
|
||||||
var PopupAnnotationElement = (function PopupAnnotationElementClosure() {
|
var PopupAnnotationElement = (function PopupAnnotationElementClosure() {
|
||||||
function PopupAnnotationElement(parameters) {
|
function PopupAnnotationElement(parameters) {
|
||||||
AnnotationElement.call(this, parameters);
|
var isRenderable = !!(parameters.data.title || parameters.data.contents);
|
||||||
|
AnnotationElement.call(this, parameters, isRenderable);
|
||||||
}
|
}
|
||||||
|
|
||||||
Util.inherit(PopupAnnotationElement, AnnotationElement, {
|
Util.inherit(PopupAnnotationElement, AnnotationElement, {
|
||||||
|
@ -2154,7 +2162,7 @@ var PopupElement = (function PopupElementClosure() {
|
||||||
var HighlightAnnotationElement = (
|
var HighlightAnnotationElement = (
|
||||||
function HighlightAnnotationElementClosure() {
|
function HighlightAnnotationElementClosure() {
|
||||||
function HighlightAnnotationElement(parameters) {
|
function HighlightAnnotationElement(parameters) {
|
||||||
AnnotationElement.call(this, parameters);
|
AnnotationElement.call(this, parameters, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Util.inherit(HighlightAnnotationElement, AnnotationElement, {
|
Util.inherit(HighlightAnnotationElement, AnnotationElement, {
|
||||||
|
@ -2181,7 +2189,7 @@ var HighlightAnnotationElement = (
|
||||||
var UnderlineAnnotationElement = (
|
var UnderlineAnnotationElement = (
|
||||||
function UnderlineAnnotationElementClosure() {
|
function UnderlineAnnotationElementClosure() {
|
||||||
function UnderlineAnnotationElement(parameters) {
|
function UnderlineAnnotationElement(parameters) {
|
||||||
AnnotationElement.call(this, parameters);
|
AnnotationElement.call(this, parameters, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Util.inherit(UnderlineAnnotationElement, AnnotationElement, {
|
Util.inherit(UnderlineAnnotationElement, AnnotationElement, {
|
||||||
|
@ -2207,7 +2215,7 @@ var UnderlineAnnotationElement = (
|
||||||
*/
|
*/
|
||||||
var SquigglyAnnotationElement = (function SquigglyAnnotationElementClosure() {
|
var SquigglyAnnotationElement = (function SquigglyAnnotationElementClosure() {
|
||||||
function SquigglyAnnotationElement(parameters) {
|
function SquigglyAnnotationElement(parameters) {
|
||||||
AnnotationElement.call(this, parameters);
|
AnnotationElement.call(this, parameters, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Util.inherit(SquigglyAnnotationElement, AnnotationElement, {
|
Util.inherit(SquigglyAnnotationElement, AnnotationElement, {
|
||||||
|
@ -2234,7 +2242,7 @@ var SquigglyAnnotationElement = (function SquigglyAnnotationElementClosure() {
|
||||||
var StrikeOutAnnotationElement = (
|
var StrikeOutAnnotationElement = (
|
||||||
function StrikeOutAnnotationElementClosure() {
|
function StrikeOutAnnotationElementClosure() {
|
||||||
function StrikeOutAnnotationElement(parameters) {
|
function StrikeOutAnnotationElement(parameters) {
|
||||||
AnnotationElement.call(this, parameters);
|
AnnotationElement.call(this, parameters, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Util.inherit(StrikeOutAnnotationElement, AnnotationElement, {
|
Util.inherit(StrikeOutAnnotationElement, AnnotationElement, {
|
||||||
|
@ -2281,7 +2289,7 @@ var AnnotationLayer = (function AnnotationLayerClosure() {
|
||||||
|
|
||||||
for (var i = 0, ii = parameters.annotations.length; i < ii; i++) {
|
for (var i = 0, ii = parameters.annotations.length; i < ii; i++) {
|
||||||
var data = parameters.annotations[i];
|
var data = parameters.annotations[i];
|
||||||
if (!data || !data.hasHtml) {
|
if (!data) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2293,8 +2301,10 @@ var AnnotationLayer = (function AnnotationLayerClosure() {
|
||||||
linkService: parameters.linkService
|
linkService: parameters.linkService
|
||||||
};
|
};
|
||||||
var element = annotationElementFactory.create(properties);
|
var element = annotationElementFactory.create(properties);
|
||||||
|
if (element.isRenderable) {
|
||||||
parameters.div.appendChild(element.render());
|
parameters.div.appendChild(element.render());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -6565,7 +6575,7 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
|
||||||
* title: string,
|
* title: string,
|
||||||
* bold: boolean,
|
* bold: boolean,
|
||||||
* italic: boolean,
|
* italic: boolean,
|
||||||
* color: rgb array,
|
* color: rgb Uint8Array,
|
||||||
* dest: dest obj,
|
* dest: dest obj,
|
||||||
* url: string,
|
* url: string,
|
||||||
* items: array of more items like this
|
* items: array of more items like this
|
||||||
|
|
|
@ -27,12 +27,12 @@ See https://github.com/adobe-type-tools/cmap-resources
|
||||||
<title>PDF.js viewer</title>
|
<title>PDF.js viewer</title>
|
||||||
|
|
||||||
<!-- This snippet is used in the Firefox extension (included from viewer.html) -->
|
<!-- This snippet is used in the Firefox extension (included from viewer.html) -->
|
||||||
<base href="resource://pdf.js/web/" />
|
<base href="resource://pdf.js/web/">
|
||||||
<script src="l10n.js"></script>
|
<script src="l10n.js"></script>
|
||||||
<script src="../build/pdf.js"></script>
|
<script src="../build/pdf.js"></script>
|
||||||
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="viewer.css"/>
|
<link rel="stylesheet" href="viewer.css">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -279,7 +279,7 @@ See https://github.com/adobe-type-tools/cmap-resources
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<!-- The type="password" attribute is set via script, to prevent warnings in Firefox for all http:// documents. -->
|
<!-- The type="password" attribute is set via script, to prevent warnings in Firefox for all http:// documents. -->
|
||||||
<input id="password" class="toolbarField" />
|
<input id="password" class="toolbarField">
|
||||||
</div>
|
</div>
|
||||||
<div class="buttonRow">
|
<div class="buttonRow">
|
||||||
<button id="passwordCancel" class="overlayButton"><span data-l10n-id="password_cancel">Cancel</span></button>
|
<button id="passwordCancel" class="overlayButton"><span data-l10n-id="password_cancel">Cancel</span></button>
|
||||||
|
|
|
@ -34,6 +34,7 @@ RequestExecutionLevel user
|
||||||
Var TmpVal
|
Var TmpVal
|
||||||
Var InstallType
|
Var InstallType
|
||||||
Var AddStartMenuSC
|
Var AddStartMenuSC
|
||||||
|
Var AddTaskbarSC
|
||||||
Var AddQuickLaunchSC
|
Var AddQuickLaunchSC
|
||||||
Var AddDesktopSC
|
Var AddDesktopSC
|
||||||
Var InstallMaintenanceService
|
Var InstallMaintenanceService
|
||||||
|
@ -395,10 +396,12 @@ Section "-Application" APP_IDX
|
||||||
|
|
||||||
; If we are writing to HKLM and create either the desktop or start menu
|
; If we are writing to HKLM and create either the desktop or start menu
|
||||||
; shortcuts set IconsVisible to 1 otherwise to 0.
|
; shortcuts set IconsVisible to 1 otherwise to 0.
|
||||||
|
; Taskbar shortcuts imply having a start menu shortcut.
|
||||||
${StrFilter} "${FileMainEXE}" "+" "" "" $R9
|
${StrFilter} "${FileMainEXE}" "+" "" "" $R9
|
||||||
StrCpy $0 "Software\Clients\StartMenuInternet\$R9\InstallInfo"
|
StrCpy $0 "Software\Clients\StartMenuInternet\$R9\InstallInfo"
|
||||||
${If} $AddDesktopSC == 1
|
${If} $AddDesktopSC == 1
|
||||||
${OrIf} $AddStartMenuSC == 1
|
${OrIf} $AddStartMenuSC == 1
|
||||||
|
${OrIf} $AddTaskbarSC == 1
|
||||||
WriteRegDWORD HKLM "$0" "IconsVisible" 1
|
WriteRegDWORD HKLM "$0" "IconsVisible" 1
|
||||||
${Else}
|
${Else}
|
||||||
WriteRegDWORD HKLM "$0" "IconsVisible" 0
|
WriteRegDWORD HKLM "$0" "IconsVisible" 0
|
||||||
|
@ -412,10 +415,12 @@ Section "-Application" APP_IDX
|
||||||
|
|
||||||
; If we create either the desktop or start menu shortcuts, then
|
; If we create either the desktop or start menu shortcuts, then
|
||||||
; set IconsVisible to 1 otherwise to 0.
|
; set IconsVisible to 1 otherwise to 0.
|
||||||
|
; Taskbar shortcuts imply having a start menu shortcut.
|
||||||
${StrFilter} "${FileMainEXE}" "+" "" "" $R9
|
${StrFilter} "${FileMainEXE}" "+" "" "" $R9
|
||||||
StrCpy $0 "Software\Clients\StartMenuInternet\$R9\InstallInfo"
|
StrCpy $0 "Software\Clients\StartMenuInternet\$R9\InstallInfo"
|
||||||
${If} $AddDesktopSC == 1
|
${If} $AddDesktopSC == 1
|
||||||
${OrIf} $AddStartMenuSC == 1
|
${OrIf} $AddStartMenuSC == 1
|
||||||
|
${OrIf} $AddTaskbarSC == 1
|
||||||
WriteRegDWORD HKCU "$0" "IconsVisible" 1
|
WriteRegDWORD HKCU "$0" "IconsVisible" 1
|
||||||
${Else}
|
${Else}
|
||||||
WriteRegDWORD HKCU "$0" "IconsVisible" 0
|
WriteRegDWORD HKCU "$0" "IconsVisible" 0
|
||||||
|
@ -601,12 +606,10 @@ Section "-InstallEndCleanup"
|
||||||
UAC::ExecCodeSegment $0
|
UAC::ExecCodeSegment $0
|
||||||
${EndIf}
|
${EndIf}
|
||||||
${EndIf}
|
${EndIf}
|
||||||
; Adds a pinned Task Bar shortcut (see MigrateTaskBarShortcut for details).
|
|
||||||
${MigrateTaskBarShortcut}
|
|
||||||
${EndUnless}
|
${EndUnless}
|
||||||
|
|
||||||
${GetShortcutsLogPath} $0
|
; Adds a pinned Task Bar shortcut (see MigrateTaskBarShortcut for details).
|
||||||
WriteIniStr "$0" "TASKBAR" "Migrated" "true"
|
${MigrateTaskBarShortcut}
|
||||||
|
|
||||||
; Add the Firewall entries during install
|
; Add the Firewall entries during install
|
||||||
Call AddFirewallEntries
|
Call AddFirewallEntries
|
||||||
|
|
|
@ -1130,6 +1130,10 @@ ${EndIf}
|
||||||
ClearErrors
|
ClearErrors
|
||||||
WriteIniStr "$0" "TASKBAR" "Migrated" "true"
|
WriteIniStr "$0" "TASKBAR" "Migrated" "true"
|
||||||
${If} ${AtLeastWin7}
|
${If} ${AtLeastWin7}
|
||||||
|
; If we didn't run the stub installer, AddTaskbarSC will be empty.
|
||||||
|
; We determine whether to pin based on whether we're the default
|
||||||
|
; browser, or if we're on win8 or later, we always pin.
|
||||||
|
${If} $AddTaskbarSC == ""
|
||||||
; No need to check the default on Win8 and later
|
; No need to check the default on Win8 and later
|
||||||
${If} ${AtMostWin2008R2}
|
${If} ${AtMostWin2008R2}
|
||||||
; Check if the Firefox is the http handler for this user
|
; Check if the Firefox is the http handler for this user
|
||||||
|
@ -1143,6 +1147,9 @@ ${EndIf}
|
||||||
${OrIf} ${AtLeastWin8}
|
${OrIf} ${AtLeastWin8}
|
||||||
${PinToTaskBar}
|
${PinToTaskBar}
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
${ElseIf} $AddTaskbarSC == "1"
|
||||||
|
${PinToTaskBar}
|
||||||
|
${EndIf}
|
||||||
${EndIf}
|
${EndIf}
|
||||||
${EndIf}
|
${EndIf}
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
@ -1486,7 +1493,7 @@ Function SetAsDefaultAppUserHKCU
|
||||||
${EndUnless}
|
${EndUnless}
|
||||||
${EndIf}
|
${EndIf}
|
||||||
${RemoveDeprecatedKeys}
|
${RemoveDeprecatedKeys}
|
||||||
${PinToTaskBar}
|
${MigrateTaskBarShortcut}
|
||||||
FunctionEnd
|
FunctionEnd
|
||||||
|
|
||||||
; Helper for updating the shortcut application model IDs.
|
; Helper for updating the shortcut application model IDs.
|
||||||
|
|
|
@ -1564,6 +1564,14 @@ Function OnDownload
|
||||||
WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "InstallDirectoryPath" "$INSTDIR"
|
WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "InstallDirectoryPath" "$INSTDIR"
|
||||||
; Don't create the QuickLaunch or Taskbar shortcut from the launched installer
|
; Don't create the QuickLaunch or Taskbar shortcut from the launched installer
|
||||||
WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "QuickLaunchShortcut" "false"
|
WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "QuickLaunchShortcut" "false"
|
||||||
|
|
||||||
|
; Either avoid or force adding a taskbar pin based on the checkbox value:
|
||||||
|
${If} $CheckboxShortcutOnBar == 0
|
||||||
|
WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "TaskbarShortcut" "false"
|
||||||
|
${Else}
|
||||||
|
WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "TaskbarShortcut" "true"
|
||||||
|
${EndIf}
|
||||||
|
|
||||||
${If} $CheckboxShortcutOnDesktop == 1
|
${If} $CheckboxShortcutOnDesktop == 1
|
||||||
WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "DesktopShortcut" "true"
|
WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "DesktopShortcut" "true"
|
||||||
${Else}
|
${Else}
|
||||||
|
@ -1586,14 +1594,10 @@ Function OnDownload
|
||||||
WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "MaintenanceService" "false"
|
WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "MaintenanceService" "false"
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
; Write migrated to the shortcuts.ini file to prevent the installer
|
; Delete the taskbar shortcut history to ensure we do the right thing based on
|
||||||
; from creating a taskbar shortcut (Bug 791613).
|
; the config file above.
|
||||||
${GetShortcutsLogPath} $0
|
${GetShortcutsLogPath} $0
|
||||||
Delete "$0"
|
Delete "$0"
|
||||||
; Workaround to prevent pinning to the taskbar.
|
|
||||||
${If} $CheckboxShortcutOnBar == 0
|
|
||||||
WriteIniStr "$0" "TASKBAR" "Migrated" "true"
|
|
||||||
${EndIf}
|
|
||||||
|
|
||||||
GetFunctionAddress $0 RemoveFileProgressCallback
|
GetFunctionAddress $0 RemoveFileProgressCallback
|
||||||
${RemovePrecompleteEntries} $0
|
${RemovePrecompleteEntries} $0
|
||||||
|
|
|
@ -844,7 +844,6 @@ you can use these alternative items. Otherwise, their values should be empty. -
|
||||||
<!ENTITY social.directory.introText "Click on a service to add it to &brandShortName;.">
|
<!ENTITY social.directory.introText "Click on a service to add it to &brandShortName;.">
|
||||||
<!ENTITY social.directory.viewmore.text "View More">
|
<!ENTITY social.directory.viewmore.text "View More">
|
||||||
|
|
||||||
<!ENTITY customizeMode.tabTitle "Customize &brandShortName;">
|
|
||||||
<!ENTITY customizeMode.menuAndToolbars.header2 "Additional Tools and Features">
|
<!ENTITY customizeMode.menuAndToolbars.header2 "Additional Tools and Features">
|
||||||
<!ENTITY customizeMode.menuAndToolbars.empty "Want more tools?">
|
<!ENTITY customizeMode.menuAndToolbars.empty "Want more tools?">
|
||||||
<!ENTITY customizeMode.menuAndToolbars.emptyLink "Choose from thousands of add-ons">
|
<!ENTITY customizeMode.menuAndToolbars.emptyLink "Choose from thousands of add-ons">
|
||||||
|
|
|
@ -689,6 +689,9 @@ customizeTips.tip0 = %1$S: You can customize %2$S to work the way you do. Simply
|
||||||
customizeTips.tip0.hint = Hint
|
customizeTips.tip0.hint = Hint
|
||||||
customizeTips.tip0.learnMore = Learn more
|
customizeTips.tip0.learnMore = Learn more
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (customizeMode.tabTitle): %S is brandShortName
|
||||||
|
customizeMode.tabTitle = Customize %S
|
||||||
|
|
||||||
# LOCALIZATION NOTE(appmenu.*.description, appmenu.*.label): these are used for
|
# LOCALIZATION NOTE(appmenu.*.description, appmenu.*.label): these are used for
|
||||||
# the appmenu labels and buttons that appear when an update is staged for
|
# the appmenu labels and buttons that appear when an update is staged for
|
||||||
# installation or a background update has failed and a manual download is required.
|
# installation or a background update has failed and a manual download is required.
|
||||||
|
|
|
@ -171,6 +171,9 @@ featureEnableRequiresRestart=%S must restart to enable this feature.
|
||||||
featureDisableRequiresRestart=%S must restart to disable this feature.
|
featureDisableRequiresRestart=%S must restart to disable this feature.
|
||||||
shouldRestartTitle=Restart %S
|
shouldRestartTitle=Restart %S
|
||||||
|
|
||||||
|
restartNow=Restart Now
|
||||||
|
restartLater=Restart Later
|
||||||
|
|
||||||
#### e10S
|
#### e10S
|
||||||
# LOCALIZATION NOTE (e10sFeedbackAfterRestart): This message appears when the user
|
# LOCALIZATION NOTE (e10sFeedbackAfterRestart): This message appears when the user
|
||||||
# unchecks "Enable multi-process" on the "General" preferences tab.
|
# unchecks "Enable multi-process" on the "General" preferences tab.
|
||||||
|
|
|
@ -1,173 +0,0 @@
|
||||||
/* 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/. */
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
this.EXPORTED_SYMBOLS = ["CustomizationTabPreloader"];
|
|
||||||
|
|
||||||
const Cu = Components.utils;
|
|
||||||
const Cc = Components.classes;
|
|
||||||
const Ci = Components.interfaces;
|
|
||||||
|
|
||||||
Cu.import("resource://gre/modules/Services.jsm");
|
|
||||||
Cu.import("resource://gre/modules/Promise.jsm");
|
|
||||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "HiddenFrame",
|
|
||||||
"resource:///modules/HiddenFrame.jsm");
|
|
||||||
|
|
||||||
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
|
||||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
|
||||||
const XUL_PAGE = "data:application/vnd.mozilla.xul+xml;charset=utf-8,<window%20id='win'/>";
|
|
||||||
const CUSTOMIZATION_URL = "about:customizing";
|
|
||||||
|
|
||||||
// The interval between swapping in a preload docShell and kicking off the
|
|
||||||
// next preload in the background.
|
|
||||||
const PRELOADER_INTERVAL_MS = 600;
|
|
||||||
|
|
||||||
function createTimer(obj, delay) {
|
|
||||||
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
|
||||||
timer.init(obj, delay, Ci.nsITimer.TYPE_ONE_SHOT);
|
|
||||||
return timer;
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearTimer(timer) {
|
|
||||||
if (timer) {
|
|
||||||
timer.cancel();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.CustomizationTabPreloader = {
|
|
||||||
uninit: function () {
|
|
||||||
CustomizationTabPreloaderInternal.uninit();
|
|
||||||
},
|
|
||||||
|
|
||||||
newTab: function (aTab) {
|
|
||||||
return CustomizationTabPreloaderInternal.newTab(aTab);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ensurePreloading starts the preloading of the about:customizing
|
|
||||||
* content page. This function is idempotent (until a call to uninit),
|
|
||||||
* so multiple calls to it are fine.
|
|
||||||
*/
|
|
||||||
ensurePreloading: function() {
|
|
||||||
CustomizationTabPreloaderInternal.ensurePreloading();
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
Object.freeze(CustomizationTabPreloader);
|
|
||||||
|
|
||||||
this.CustomizationTabPreloaderInternal = {
|
|
||||||
_browser: null,
|
|
||||||
|
|
||||||
uninit: function () {
|
|
||||||
if (this._browser) {
|
|
||||||
this._browser.destroy();
|
|
||||||
this._browser = null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
newTab: function (aTab) {
|
|
||||||
let win = aTab.ownerDocument.defaultView;
|
|
||||||
if (win.gBrowser && this._browser) {
|
|
||||||
return this._browser.swapWithNewTab(aTab);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
ensurePreloading: function () {
|
|
||||||
if (!this._browser) {
|
|
||||||
this._browser = new HiddenBrowser();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function HiddenBrowser() {
|
|
||||||
this._createBrowser();
|
|
||||||
}
|
|
||||||
|
|
||||||
HiddenBrowser.prototype = {
|
|
||||||
_timer: null,
|
|
||||||
_hiddenFrame: null,
|
|
||||||
|
|
||||||
get isPreloaded() {
|
|
||||||
return this._browser &&
|
|
||||||
this._browser.contentDocument &&
|
|
||||||
this._browser.contentDocument.readyState === "complete" &&
|
|
||||||
this._browser.currentURI.spec === CUSTOMIZATION_URL;
|
|
||||||
},
|
|
||||||
|
|
||||||
swapWithNewTab: function (aTab) {
|
|
||||||
if (!this.isPreloaded || this._timer) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let win = aTab.ownerDocument.defaultView;
|
|
||||||
let tabbrowser = win.gBrowser;
|
|
||||||
|
|
||||||
if (!tabbrowser) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Swap docShells.
|
|
||||||
tabbrowser.swapNewTabWithBrowser(aTab, this._browser);
|
|
||||||
|
|
||||||
// Load all default frame scripts attached to the target window.
|
|
||||||
let mm = aTab.linkedBrowser.messageManager;
|
|
||||||
let scripts = win.getGroupMessageManager("browsers").getDelayedFrameScripts();
|
|
||||||
Array.forEach(scripts, ([script, runGlobal]) => mm.loadFrameScript(script, true, runGlobal));
|
|
||||||
|
|
||||||
// Remove the browser, it will be recreated by a timer.
|
|
||||||
this._removeBrowser();
|
|
||||||
|
|
||||||
// Start a timer that will kick off preloading the next page.
|
|
||||||
this._timer = createTimer(this, PRELOADER_INTERVAL_MS);
|
|
||||||
|
|
||||||
// Signal that we swapped docShells.
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
observe: function () {
|
|
||||||
this._timer = null;
|
|
||||||
|
|
||||||
// Start pre-loading the customization page.
|
|
||||||
this._createBrowser();
|
|
||||||
},
|
|
||||||
|
|
||||||
destroy: function () {
|
|
||||||
this._removeBrowser();
|
|
||||||
if (this._hiddenFrame) {
|
|
||||||
this._hiddenFrame.destroy();
|
|
||||||
this._hiddenFrame = null;
|
|
||||||
}
|
|
||||||
this._timer = clearTimer(this._timer);
|
|
||||||
},
|
|
||||||
|
|
||||||
_createBrowser: function () {
|
|
||||||
if (!this._hiddenFrame) {
|
|
||||||
this._hiddenFrame = new HiddenFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
this._hiddenFrame.get().then(aFrame => {
|
|
||||||
let doc = aFrame.document;
|
|
||||||
this._browser = doc.createElementNS(XUL_NS, "browser");
|
|
||||||
this._browser.permanentKey = {};
|
|
||||||
this._browser.setAttribute("type", "content");
|
|
||||||
this._browser.setAttribute("src", CUSTOMIZATION_URL);
|
|
||||||
this._browser.style.width = "400px";
|
|
||||||
this._browser.style.height = "400px";
|
|
||||||
doc.getElementById("win").appendChild(this._browser);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
_removeBrowser: function () {
|
|
||||||
if (this._browser) {
|
|
||||||
this._browser.remove();
|
|
||||||
this._browser = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -22,7 +22,6 @@ EXTRA_JS_MODULES += [
|
||||||
'ContentObservers.jsm',
|
'ContentObservers.jsm',
|
||||||
'ContentSearch.jsm',
|
'ContentSearch.jsm',
|
||||||
'ContentWebRTC.jsm',
|
'ContentWebRTC.jsm',
|
||||||
'CustomizationTabPreloader.jsm',
|
|
||||||
'DirectoryLinksProvider.jsm',
|
'DirectoryLinksProvider.jsm',
|
||||||
'E10SUtils.jsm',
|
'E10SUtils.jsm',
|
||||||
'Feeds.jsm',
|
'Feeds.jsm',
|
||||||
|
|
|
@ -75,7 +75,7 @@
|
||||||
--chrome-secondary-background-color: #f5f6f7;
|
--chrome-secondary-background-color: #f5f6f7;
|
||||||
--chrome-navigator-toolbox-separator-color: #cccccc;
|
--chrome-navigator-toolbox-separator-color: #cccccc;
|
||||||
--chrome-nav-bar-separator-color: #B6B6B8;
|
--chrome-nav-bar-separator-color: #B6B6B8;
|
||||||
--chrome-nav-buttons-background: #fcfcfc;
|
--chrome-nav-buttons-background: #ffffff; /* --theme-body-background */
|
||||||
--chrome-nav-buttons-hover-background: #DADBDB;
|
--chrome-nav-buttons-hover-background: #DADBDB;
|
||||||
--chrome-nav-bar-controls-border-color: #ccc;
|
--chrome-nav-bar-controls-border-color: #ccc;
|
||||||
--chrome-selection-color: #f5f7fa;
|
--chrome-selection-color: #f5f7fa;
|
||||||
|
@ -85,9 +85,7 @@
|
||||||
--tab-hover-background-color: #D7D8DA;
|
--tab-hover-background-color: #D7D8DA;
|
||||||
--tab-selection-color: #f5f7fa;
|
--tab-selection-color: #f5f7fa;
|
||||||
--tab-selection-background-color: #4c9ed9;
|
--tab-selection-background-color: #4c9ed9;
|
||||||
--tab-selection-box-shadow: 0 2px 0 #9FDFFF inset,
|
--tab-selection-box-shadow: none;
|
||||||
0 -2px 0 rgba(0,0,0,.05) inset,
|
|
||||||
0 -1px 0 rgba(0,0,0,.2) inset;
|
|
||||||
--pinned-tab-glow: radial-gradient(22px at center calc(100% - 2px), rgba(76,158,217,0.9) 13%, transparent 16%);
|
--pinned-tab-glow: radial-gradient(22px at center calc(100% - 2px), rgba(76,158,217,0.9) 13%, transparent 16%);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ function test() {
|
||||||
// Focus the console and add event listener to track whether it loses focus
|
// Focus the console and add event listener to track whether it loses focus
|
||||||
// (Must happen after generateMouseClickInTab() call)
|
// (Must happen after generateMouseClickInTab() call)
|
||||||
let consoleLostFocus = false;
|
let consoleLostFocus = false;
|
||||||
jsterm.inputNode.focus();
|
jsterm.focus();
|
||||||
jsterm.inputNode.addEventListener('blur', () => {consoleLostFocus = true;});
|
jsterm.inputNode.addEventListener('blur', () => {consoleLostFocus = true;});
|
||||||
|
|
||||||
is(gThreadClient.paused, true,
|
is(gThreadClient.paused, true,
|
||||||
|
|
|
@ -1049,7 +1049,7 @@ InspectorPanel.prototype = {
|
||||||
let jsterm = panel.hud.jsterm;
|
let jsterm = panel.hud.jsterm;
|
||||||
|
|
||||||
jsterm.execute("inspect($0)");
|
jsterm.execute("inspect($0)");
|
||||||
jsterm.inputNode.focus();
|
jsterm.focus();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
max-width: 150px;
|
max-width: 150px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.inspector-tabpanel {
|
.inspector-tabpanel > * {
|
||||||
/*
|
/*
|
||||||
* Override `-moz-user-focus:ignore;` from toolkit/content/minimal-xul.css
|
* Override `-moz-user-focus:ignore;` from toolkit/content/minimal-xul.css
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -98,6 +98,8 @@ skip-if = e10s # Bug 1039528: "inspect element" contextual-menu doesn't work wit
|
||||||
[browser_rules_edit-property_08.js]
|
[browser_rules_edit-property_08.js]
|
||||||
[browser_rules_edit-property_09.js]
|
[browser_rules_edit-property_09.js]
|
||||||
[browser_rules_edit-selector-click.js]
|
[browser_rules_edit-selector-click.js]
|
||||||
|
[browser_rules_edit-selector-click-on-scrollbar.js]
|
||||||
|
skip-if = os == "mac" # Bug 1245996 : click on scrollbar not working on OSX
|
||||||
[browser_rules_edit-selector-commit.js]
|
[browser_rules_edit-selector-commit.js]
|
||||||
[browser_rules_edit-selector_01.js]
|
[browser_rules_edit-selector_01.js]
|
||||||
[browser_rules_edit-selector_02.js]
|
[browser_rules_edit-selector_02.js]
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Testing ruleview inplace-editor is not blurred when clicking on the ruleview
|
||||||
|
// container scrollbar.
|
||||||
|
|
||||||
|
const TEST_URI = `
|
||||||
|
<style type="text/css">
|
||||||
|
div.testclass {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
.a {
|
||||||
|
color: #aaa;
|
||||||
|
}
|
||||||
|
.b {
|
||||||
|
color: #bbb;
|
||||||
|
}
|
||||||
|
.c {
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
.d {
|
||||||
|
color: #ddd;
|
||||||
|
}
|
||||||
|
.e {
|
||||||
|
color: #eee;
|
||||||
|
}
|
||||||
|
.f {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="testclass a b c d e f">Styled Node</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
add_task(function*() {
|
||||||
|
info("Toolbox height should be small enough to force scrollbars to appear");
|
||||||
|
yield new Promise(done => {
|
||||||
|
let options = {"set": [
|
||||||
|
["devtools.toolbox.footer.height", 200],
|
||||||
|
]};
|
||||||
|
SpecialPowers.pushPrefEnv(options, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
|
||||||
|
let {inspector, view} = yield openRuleView();
|
||||||
|
yield selectNode(".testclass", inspector);
|
||||||
|
|
||||||
|
info("Check we have an overflow on the ruleview container.");
|
||||||
|
let container = view.element;
|
||||||
|
let hasScrollbar = container.offsetHeight < container.scrollHeight;
|
||||||
|
ok(hasScrollbar, "The rule view container should have a vertical scrollbar.");
|
||||||
|
|
||||||
|
info("Focusing an existing selector name in the rule-view.");
|
||||||
|
let ruleEditor = getRuleViewRuleEditor(view, 1);
|
||||||
|
let editor = yield focusEditableField(view, ruleEditor.selectorText);
|
||||||
|
is(inplaceEditor(ruleEditor.selectorText), editor,
|
||||||
|
"The selector editor is focused.");
|
||||||
|
|
||||||
|
info("Click on the scrollbar element.");
|
||||||
|
yield clickOnRuleviewScrollbar(view);
|
||||||
|
|
||||||
|
is(editor.input, view.styleDocument.activeElement,
|
||||||
|
"The editor input should still be focused.");
|
||||||
|
|
||||||
|
info("Check a new value can still be committed in the editable field");
|
||||||
|
let newValue = ".testclass.a.b.c.d.e.f";
|
||||||
|
let onRuleViewChanged = once(view, "ruleview-changed");
|
||||||
|
|
||||||
|
info("Enter new value and commit.");
|
||||||
|
editor.input.value = newValue;
|
||||||
|
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||||
|
yield onRuleViewChanged;
|
||||||
|
ok(getRuleViewRule(view, newValue), "Rule with '" + newValue + " 'exists.");
|
||||||
|
});
|
||||||
|
|
||||||
|
function* clickOnRuleviewScrollbar(view) {
|
||||||
|
let container = view.element;
|
||||||
|
let onScroll = once(container, "scroll");
|
||||||
|
let rect = container.getBoundingClientRect();
|
||||||
|
// click 5 pixels before the bottom-right corner should hit the scrollbar
|
||||||
|
EventUtils.synthesizeMouse(container, rect.width - 5, rect.height - 5,
|
||||||
|
{}, view.styleWindow);
|
||||||
|
yield onScroll;
|
||||||
|
|
||||||
|
ok(true, "The rule view container scrolled after clicking on the scrollbar.");
|
||||||
|
}
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
const { setTheme } = require("devtools/client/shared/theme");
|
const { setTheme } = require("devtools/client/shared/theme");
|
||||||
|
|
||||||
const LIGHT_BG = "#fcfcfc";
|
const LIGHT_BG = "white";
|
||||||
const DARK_BG = "#14171a";
|
const DARK_BG = "#14171a";
|
||||||
|
|
||||||
setTheme("dark");
|
setTheme("dark");
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
%sourceEditorStrings;
|
%sourceEditorStrings;
|
||||||
]>
|
]>
|
||||||
|
|
||||||
<page xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" class="theme-body">
|
<page xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" class="theme-body theme-light">
|
||||||
|
|
||||||
<script type="application/javascript" src="chrome://global/content/globalOverlay.js"/>
|
<script type="application/javascript" src="chrome://global/content/globalOverlay.js"/>
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,8 @@ support-files =
|
||||||
skip-if = true # Bug 1173950
|
skip-if = true # Bug 1173950
|
||||||
[browser_projecteditor_delete_file.js]
|
[browser_projecteditor_delete_file.js]
|
||||||
skip-if = e10s # Frequent failures in e10s - Bug 1020027
|
skip-if = e10s # Frequent failures in e10s - Bug 1020027
|
||||||
[browser_projecteditor_rename_file.js]
|
[browser_projecteditor_rename_file_01.js]
|
||||||
|
[browser_projecteditor_rename_file_02.js]
|
||||||
[browser_projecteditor_editing_01.js]
|
[browser_projecteditor_editing_01.js]
|
||||||
[browser_projecteditor_editors_image.js]
|
[browser_projecteditor_editors_image.js]
|
||||||
[browser_projecteditor_external_change.js]
|
[browser_projecteditor_external_change.js]
|
||||||
|
|
|
@ -1,82 +0,0 @@
|
||||||
/* vim: set ts=2 et sw=2 tw=80: */
|
|
||||||
/* Any copyright is dedicated to the Public Domain.
|
|
||||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
// Test file rename functionality
|
|
||||||
|
|
||||||
add_task(function*() {
|
|
||||||
let projecteditor = yield addProjectEditorTabForTempDirectory();
|
|
||||||
ok(true, "ProjectEditor has loaded");
|
|
||||||
|
|
||||||
let root = [...projecteditor.project.allStores()][0].root;
|
|
||||||
is(root.path, TEMP_PATH, "The root store is set to the correct temp path.");
|
|
||||||
for (let child of root.children) {
|
|
||||||
yield renameWithContextMenu(projecteditor,
|
|
||||||
projecteditor.projectTree.getViewContainer(child),
|
|
||||||
".renamed");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(function*() {
|
|
||||||
let projecteditor = yield addProjectEditorTabForTempDirectory();
|
|
||||||
ok(true, "ProjectEditor has loaded");
|
|
||||||
|
|
||||||
let root = [...projecteditor.project.allStores()][0].root;
|
|
||||||
is(root.path, TEMP_PATH, "The root store is set to the correct temp path.");
|
|
||||||
|
|
||||||
let childrenList = new Array();
|
|
||||||
for (let child of root.children) {
|
|
||||||
yield renameWithContextMenu(projecteditor,
|
|
||||||
projecteditor.projectTree.getViewContainer(child),
|
|
||||||
".ren\u0061\u0308med");
|
|
||||||
childrenList.push(child.basename + ".ren\u0061\u0308med");
|
|
||||||
}
|
|
||||||
for (let child of root.children) {
|
|
||||||
is (childrenList.indexOf(child.basename) == -1, false,
|
|
||||||
"Failed to update tree with non-ascii character");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function openContextMenuOn(node) {
|
|
||||||
EventUtils.synthesizeMouseAtCenter(
|
|
||||||
node,
|
|
||||||
{button: 2, type: "contextmenu"},
|
|
||||||
node.ownerDocument.defaultView
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function renameWithContextMenu(projecteditor, container, newName) {
|
|
||||||
let defer = promise.defer();
|
|
||||||
let popup = projecteditor.contextMenuPopup;
|
|
||||||
let resource = container.resource;
|
|
||||||
info ("Going to attempt renaming for: " + resource.path);
|
|
||||||
|
|
||||||
onPopupShow(popup).then(function () {
|
|
||||||
let renameCommand = popup.querySelector("[command=cmd-rename]");
|
|
||||||
ok (renameCommand, "Rename command exists in popup");
|
|
||||||
is (renameCommand.getAttribute("hidden"), "", "Rename command is visible");
|
|
||||||
is (renameCommand.getAttribute("disabled"), "", "Rename command is enabled");
|
|
||||||
|
|
||||||
projecteditor.project.on("refresh-complete", function refreshComplete() {
|
|
||||||
projecteditor.project.off("refresh-complete", refreshComplete);
|
|
||||||
OS.File.stat(resource.path + newName).then(() => {
|
|
||||||
ok (true, "File is renamed");
|
|
||||||
defer.resolve();
|
|
||||||
}, (ex) => {
|
|
||||||
ok (false, "Failed to rename file");
|
|
||||||
defer.resolve();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
renameCommand.click();
|
|
||||||
popup.hidePopup();
|
|
||||||
let input = container.elt.childNodes[0].childNodes[1];
|
|
||||||
input.value = resource.basename + newName;
|
|
||||||
EventUtils.synthesizeKey("VK_RETURN", {}, projecteditor.window);
|
|
||||||
});
|
|
||||||
|
|
||||||
openContextMenuOn(container.label);
|
|
||||||
return defer.promise;
|
|
||||||
}
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Test file rename functionality
|
||||||
|
|
||||||
|
add_task(function*() {
|
||||||
|
let projecteditor = yield addProjectEditorTabForTempDirectory();
|
||||||
|
ok(true, "ProjectEditor has loaded");
|
||||||
|
|
||||||
|
let root = [...projecteditor.project.allStores()][0].root;
|
||||||
|
is(root.path, TEMP_PATH, "The root store is set to the correct temp path.");
|
||||||
|
for (let child of root.children) {
|
||||||
|
yield renameWithContextMenu(projecteditor,
|
||||||
|
projecteditor.projectTree.getViewContainer(child), ".renamed");
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,26 @@
|
||||||
|
/* vim: set ts=2 et sw=2 tw=80: */
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Test file rename functionality with non ascii characters
|
||||||
|
|
||||||
|
add_task(function*() {
|
||||||
|
let projecteditor = yield addProjectEditorTabForTempDirectory();
|
||||||
|
ok(true, "ProjectEditor has loaded");
|
||||||
|
|
||||||
|
let root = [...projecteditor.project.allStores()][0].root;
|
||||||
|
is(root.path, TEMP_PATH, "The root store is set to the correct temp path.");
|
||||||
|
|
||||||
|
let childrenList = [];
|
||||||
|
for (let child of root.children) {
|
||||||
|
yield renameWithContextMenu(projecteditor,
|
||||||
|
projecteditor.projectTree.getViewContainer(child), ".ren\u0061\u0308med");
|
||||||
|
childrenList.push(child.basename + ".ren\u0061\u0308med");
|
||||||
|
}
|
||||||
|
for (let child of root.children) {
|
||||||
|
is(childrenList.indexOf(child.basename) == -1, false,
|
||||||
|
"Failed to update tree with non-ascii character");
|
||||||
|
}
|
||||||
|
});
|
|
@ -284,6 +284,46 @@ function* getFileData(file) {
|
||||||
return def.promise;
|
return def.promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rename the resource of the provided container using the context menu.
|
||||||
|
*
|
||||||
|
* @param {ProjectEditor} projecteditor the current project editor instance
|
||||||
|
* @param {Shell} container for the resource to rename
|
||||||
|
* @param {String} newName the name to use for renaming the resource
|
||||||
|
* @return {Promise} a promise that resolves when the resource has been renamed
|
||||||
|
*/
|
||||||
|
var renameWithContextMenu = Task.async(function* (projecteditor,
|
||||||
|
container, newName) {
|
||||||
|
let popup = projecteditor.contextMenuPopup;
|
||||||
|
let resource = container.resource;
|
||||||
|
info("Going to attempt renaming for: " + resource.path);
|
||||||
|
|
||||||
|
let waitForPopupShow = onPopupShow(popup);
|
||||||
|
openContextMenu(container.label);
|
||||||
|
yield waitForPopupShow;
|
||||||
|
|
||||||
|
let renameCommand = popup.querySelector("[command=cmd-rename]");
|
||||||
|
ok(renameCommand, "Rename command exists in popup");
|
||||||
|
is(renameCommand.getAttribute("hidden"), "", "Rename command is visible");
|
||||||
|
is(renameCommand.getAttribute("disabled"), "", "Rename command is enabled");
|
||||||
|
|
||||||
|
renameCommand.click();
|
||||||
|
popup.hidePopup();
|
||||||
|
let input = container.elt.childNodes[0].childNodes[1];
|
||||||
|
input.value = resource.basename + newName;
|
||||||
|
|
||||||
|
let waitForProjectRefresh = onceProjectRefreshed(projecteditor);
|
||||||
|
EventUtils.synthesizeKey("VK_RETURN", {}, projecteditor.window);
|
||||||
|
yield waitForProjectRefresh;
|
||||||
|
|
||||||
|
try {
|
||||||
|
yield OS.File.stat(resource.path + newName);
|
||||||
|
ok(true, "File is renamed");
|
||||||
|
} catch (e) {
|
||||||
|
ok(false, "Failed to rename file");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function onceEditorCreated(projecteditor) {
|
function onceEditorCreated(projecteditor) {
|
||||||
let def = promise.defer();
|
let def = promise.defer();
|
||||||
projecteditor.once("onEditorCreated", (editor) => {
|
projecteditor.once("onEditorCreated", (editor) => {
|
||||||
|
@ -316,6 +356,15 @@ function onceEditorSave(projecteditor) {
|
||||||
return def.promise;
|
return def.promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onceProjectRefreshed(projecteditor) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
projecteditor.project.on("refresh-complete", function refreshComplete() {
|
||||||
|
projecteditor.project.off("refresh-complete", refreshComplete);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function onPopupShow(menu) {
|
function onPopupShow(menu) {
|
||||||
let defer = promise.defer();
|
let defer = promise.defer();
|
||||||
menu.addEventListener("popupshown", function onpopupshown() {
|
menu.addEventListener("popupshown", function onpopupshown() {
|
||||||
|
@ -333,3 +382,11 @@ function onPopupHidden(menu) {
|
||||||
});
|
});
|
||||||
return defer.promise;
|
return defer.promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function openContextMenu(node) {
|
||||||
|
EventUtils.synthesizeMouseAtCenter(
|
||||||
|
node,
|
||||||
|
{button: 2, type: "contextmenu"},
|
||||||
|
node.ownerDocument.defaultView
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -8,10 +8,10 @@
|
||||||
since they aren't loaded in this context (within commandlineoutput.xhtml
|
since they aren't loaded in this context (within commandlineoutput.xhtml
|
||||||
and commandlinetooltip.xhtml). */
|
and commandlinetooltip.xhtml). */
|
||||||
:root[devtoolstheme="light"] {
|
:root[devtoolstheme="light"] {
|
||||||
--gcli-background-color: #ebeced; /* --theme-tab-toolbar-background */
|
--gcli-background-color: #fcfcfc; /* --theme-tab-toolbar-background */
|
||||||
--gcli-input-focused-background: #f7f7f7; /* --theme-sidebar-background */
|
--gcli-input-focused-background: #ffffff; /* --theme-sidebar-background */
|
||||||
--gcli-input-color: #18191a; /* --theme-body-color */
|
--gcli-input-color: #393f4c; /* --theme-body-color */
|
||||||
--gcli-border-color: #aaaaaa; /* --theme-splitter-color */
|
--gcli-border-color: #dde1e4; /* --theme-splitter-color */
|
||||||
}
|
}
|
||||||
|
|
||||||
:root[devtoolstheme="dark"] {
|
:root[devtoolstheme="dark"] {
|
||||||
|
|
|
@ -10,11 +10,11 @@
|
||||||
We are copy/pasting variables from light-theme and dark-theme,
|
We are copy/pasting variables from light-theme and dark-theme,
|
||||||
since they aren't loaded in this context (within browser.css). */
|
since they aren't loaded in this context (within browser.css). */
|
||||||
:root[devtoolstheme="light"] #developer-toolbar {
|
:root[devtoolstheme="light"] #developer-toolbar {
|
||||||
--gcli-background-color: #ebeced; /* --theme-tab-toolbar-background */
|
--gcli-background-color: #fcfcfc; /* --theme-tab-toolbar-background */
|
||||||
--gcli-input-background: #f0f1f2; /* --theme-toolbar-background */
|
--gcli-input-background: #fcfcfc; /* --theme-toolbar-background */
|
||||||
--gcli-input-focused-background: #f7f7f7; /* --theme-sidebar-background */
|
--gcli-input-focused-background: #ffffff; /* --theme-sidebar-background */
|
||||||
--gcli-input-color: #18191a; /* --theme-body-color */
|
--gcli-input-color: #393f4c; /* --theme-body-color */
|
||||||
--gcli-border-color: #aaaaaa; /* --theme-splitter-color */
|
--gcli-border-color: #dde1e4; /* --theme-splitter-color */
|
||||||
--selection-background: #4c9ed9; /* --theme-selection-background */
|
--selection-background: #4c9ed9; /* --theme-selection-background */
|
||||||
--selection-color: #f5f7fa; /* --theme-selection-color */
|
--selection-color: #f5f7fa; /* --theme-selection-color */
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,13 +68,13 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-gutter {
|
.theme-gutter {
|
||||||
background-color: #0f171f;
|
background-color: var(--theme-tab-toolbar-background);
|
||||||
color: var(--theme-content-color3);
|
color: var(--theme-content-color3);
|
||||||
border-color: #303b47;
|
border-color: var(--theme-splitter-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-separator { /* grey */
|
.theme-separator {
|
||||||
border-color: #303b47;
|
border-color: var(--theme-splitter-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-fg-color1,
|
.theme-fg-color1,
|
||||||
|
|
|
@ -2,6 +2,6 @@
|
||||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
- 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/. -->
|
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||||
<svg width="7" xmlns="http://www.w3.org/2000/svg" height="12" viewBox="0 0 7 12">
|
<svg width="7" xmlns="http://www.w3.org/2000/svg" height="12" viewBox="0 0 7 12">
|
||||||
<path fill="#f7f7f7" d="M7,11.6 7,.4 1.5,6z"/>
|
<path fill="#ffffff" d="M7,11.6 7,.4 1.5,6z"/>
|
||||||
<path fill="#ababab" d="M7,0 6,0 0,6 6,12 7,12 7,11.6 1.5,6 7,.4z"/>
|
<path fill="#dde1e4" d="M7,0 6,0 0,6 6,12 7,12 7,11.6 1.5,6 7,.4z"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
До Ширина: | Высота: | Размер: 421 B После Ширина: | Высота: | Размер: 421 B |
|
@ -2,6 +2,6 @@
|
||||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
- 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/. -->
|
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||||
<svg width="7" xmlns="http://www.w3.org/2000/svg" height="12" viewBox="0 0 7 12">
|
<svg width="7" xmlns="http://www.w3.org/2000/svg" height="12" viewBox="0 0 7 12">
|
||||||
<path fill="#f7f7f7" d="M0,11.6 0,.4 5.5,6z"/>
|
<path fill="#ffffff" d="M0,11.6 0,.4 5.5,6z"/>
|
||||||
<path fill="#ababab" d="M1,0 0,0 0,.4 5.5,6 0,11.6 0,12 1,12 7,6z"/>
|
<path fill="#dde1e4" d="M1,0 0,0 0,.4 5.5,6 0,11.6 0,12 1,12 7,6z"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
До Ширина: | Высота: | Размер: 421 B После Ширина: | Высота: | Размер: 421 B |
|
@ -67,9 +67,9 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-gutter {
|
.theme-gutter {
|
||||||
background-color: hsl(0,0%,90%);
|
background-color: var(--theme-tab-toolbar-background);
|
||||||
color: var(--theme-content-color3);
|
color: var(--theme-content-color3);
|
||||||
border-color: hsl(0,0%,65%);
|
border-color: var(--theme-splitter-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-separator { /* grey */
|
.theme-separator { /* grey */
|
||||||
|
@ -173,7 +173,7 @@ body {
|
||||||
.devtools-sidebar-tabs tabs,
|
.devtools-sidebar-tabs tabs,
|
||||||
.devtools-sidebar-alltabs,
|
.devtools-sidebar-alltabs,
|
||||||
.cm-s-mozilla .CodeMirror-dialog { /* General toolbar styling */
|
.cm-s-mozilla .CodeMirror-dialog { /* General toolbar styling */
|
||||||
color: var(--theme-body-color-alt);
|
color: var(--theme-body-color);
|
||||||
background-color: var(--theme-toolbar-background);
|
background-color: var(--theme-toolbar-background);
|
||||||
border-color: var(--theme-splitter-color);
|
border-color: var(--theme-splitter-color);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,6 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
:root {
|
|
||||||
color: #18191a;
|
|
||||||
}
|
|
||||||
|
|
||||||
.view-project-detail {
|
.view-project-detail {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,21 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
/* Splitters */
|
/* Splitters */
|
||||||
|
:root[devtoolstheme="light"] .devtools-horizontal-splitter {
|
||||||
|
/* These variables are used in browser.xul but inside the toolbox they are overridden by --theme-splitter-color */
|
||||||
|
--devtools-splitter-color: #dde1e4;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root[devtoolstheme="dark"] .devtools-horizontal-splitter {
|
||||||
|
--devtools-splitter-color: #42484f;
|
||||||
|
}
|
||||||
|
|
||||||
.devtools-horizontal-splitter {
|
.devtools-horizontal-splitter {
|
||||||
-moz-appearance: none;
|
-moz-appearance: none;
|
||||||
background-image: none;
|
background-image: none;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
border: 0;
|
border: 0;
|
||||||
border-bottom: 1px solid rgba(118, 121, 125, .5);
|
border-bottom: 1px solid var(--devtools-splitter-color);
|
||||||
min-height: 3px;
|
min-height: 3px;
|
||||||
height: 3px;
|
height: 3px;
|
||||||
margin-top: -3px;
|
margin-top: -3px;
|
||||||
|
@ -20,7 +29,7 @@
|
||||||
background-image: none;
|
background-image: none;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
border: 0;
|
border: 0;
|
||||||
-moz-border-end: 1px solid rgba(118, 121, 125, .5);
|
-moz-border-end: 1px solid var(--devtools-splitter-color);
|
||||||
min-width: 3px;
|
min-width: 3px;
|
||||||
width: 3px;
|
width: 3px;
|
||||||
-moz-margin-start: -3px;
|
-moz-margin-start: -3px;
|
||||||
|
|
|
@ -818,10 +818,6 @@
|
||||||
border-bottom-color: var(--theme-splitter-color);
|
border-bottom-color: var(--theme-splitter-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-light .devtools-tabbar {
|
|
||||||
box-shadow: 0 -2px 0 rgba(170,170,170,.1) inset;
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-dark .devtools-tabbar {
|
.theme-dark .devtools-tabbar {
|
||||||
box-shadow: 0 -2px 0 rgba(0,0,0,.1) inset;
|
box-shadow: 0 -2px 0 rgba(0,0,0,.1) inset;
|
||||||
}
|
}
|
||||||
|
@ -920,12 +916,6 @@
|
||||||
0 -2px 0 rgba(0,0,0,.2) inset;
|
0 -2px 0 rgba(0,0,0,.2) inset;
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-light .devtools-tabbar .devtools-tab[selected] {
|
|
||||||
box-shadow: 0 2px 0 #d7f1ff inset,
|
|
||||||
0 8px 3px -5px #2b82bf inset,
|
|
||||||
0 -2px 0 rgba(0,0,0,.06) inset;
|
|
||||||
}
|
|
||||||
|
|
||||||
#toolbox-tabs .devtools-tab[selected],
|
#toolbox-tabs .devtools-tab[selected],
|
||||||
#toolbox-tabs .devtools-tab[highlighted] {
|
#toolbox-tabs .devtools-tab[highlighted] {
|
||||||
border-width: 0;
|
border-width: 0;
|
||||||
|
|
|
@ -15,19 +15,19 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
:root.theme-light {
|
:root.theme-light {
|
||||||
--theme-body-background: #fcfcfc;
|
--theme-body-background: white;
|
||||||
--theme-sidebar-background: #f7f7f7;
|
--theme-sidebar-background: white;
|
||||||
--theme-contrast-background: #e6b064;
|
--theme-contrast-background: #e6b064;
|
||||||
|
|
||||||
--theme-tab-toolbar-background: #ebeced;
|
--theme-tab-toolbar-background: #fcfcfc;
|
||||||
--theme-toolbar-background: #f0f1f2;
|
--theme-toolbar-background: #fcfcfc;
|
||||||
--theme-selection-background: #4c9ed9;
|
--theme-selection-background: #4c9ed9;
|
||||||
--theme-selection-background-semitransparent: rgba(76, 158, 217, .23);
|
--theme-selection-background-semitransparent: rgba(76, 158, 217, 0.15);
|
||||||
--theme-selection-color: #f5f7fa;
|
--theme-selection-color: #f5f7fa;
|
||||||
--theme-splitter-color: #aaaaaa;
|
--theme-splitter-color: #dde1e4;
|
||||||
--theme-comment: #757873;
|
--theme-comment: #696969;
|
||||||
|
|
||||||
--theme-body-color: #18191a;
|
--theme-body-color: #393f4c;
|
||||||
--theme-body-color-alt: #585959;
|
--theme-body-color-alt: #585959;
|
||||||
--theme-content-color1: #292e33;
|
--theme-content-color1: #292e33;
|
||||||
--theme-content-color2: #8fa1b2;
|
--theme-content-color2: #8fa1b2;
|
||||||
|
|
|
@ -6,14 +6,12 @@
|
||||||
.theme-dark {
|
.theme-dark {
|
||||||
--table-splitter-color: rgba(255,255,255,0.15);
|
--table-splitter-color: rgba(255,255,255,0.15);
|
||||||
--table-zebra-background: rgba(255,255,255,0.05);
|
--table-zebra-background: rgba(255,255,255,0.05);
|
||||||
--smw-margin: #000;
|
|
||||||
--smw-item-top-border: rgba(0,0,0,0.2);
|
--smw-item-top-border: rgba(0,0,0,0.2);
|
||||||
--smw-item-bottom-border: rgba(128,128,128,0.15);
|
--smw-item-bottom-border: rgba(128,128,128,0.15);
|
||||||
}
|
}
|
||||||
.theme-light {
|
.theme-light {
|
||||||
--table-splitter-color: rgba(0,0,0,0.15);
|
--table-splitter-color: rgba(0,0,0,0.15);
|
||||||
--table-zebra-background: rgba(0,0,0,0.05);
|
--table-zebra-background: rgba(0,0,0,0.05);
|
||||||
--smw-margin: #aaa;
|
|
||||||
--smw-item-top-border: rgba(128,128,128,0.15);
|
--smw-item-top-border: rgba(128,128,128,0.15);
|
||||||
--smw-item-bottom-border: transparent;
|
--smw-item-bottom-border: transparent;
|
||||||
}
|
}
|
||||||
|
@ -357,12 +355,12 @@
|
||||||
|
|
||||||
.side-menu-widget-container:-moz-locale-dir(ltr),
|
.side-menu-widget-container:-moz-locale-dir(ltr),
|
||||||
.side-menu-widget-empty-text:-moz-locale-dir(ltr) {
|
.side-menu-widget-empty-text:-moz-locale-dir(ltr) {
|
||||||
box-shadow: inset -1px 0 0 var(--smw-margin);
|
box-shadow: inset -1px 0 0 var(--theme-splitter-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.side-menu-widget-container:-moz-locale-dir(rtl),
|
.side-menu-widget-container:-moz-locale-dir(rtl),
|
||||||
.side-menu-widget-empty-text:-moz-locale-dir(rtl) {
|
.side-menu-widget-empty-text:-moz-locale-dir(rtl) {
|
||||||
box-shadow: inset 1px 0 0 var(--smw-margin);
|
box-shadow: inset 1px 0 0 var(--theme-splitter-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.side-menu-widget-group {
|
.side-menu-widget-group {
|
||||||
|
|
|
@ -106,8 +106,7 @@ function* populateInputHistory(hud) {
|
||||||
*/
|
*/
|
||||||
function* testNaviatingHistoryInUI(hud) {
|
function* testNaviatingHistoryInUI(hud) {
|
||||||
let jsterm = hud.jsterm;
|
let jsterm = hud.jsterm;
|
||||||
let {inputNode} = jsterm;
|
jsterm.focus();
|
||||||
inputNode.focus();
|
|
||||||
|
|
||||||
// Count backwards from original input and make sure that pressing up
|
// Count backwards from original input and make sure that pressing up
|
||||||
// restores this.
|
// restores this.
|
||||||
|
|
|
@ -21,8 +21,6 @@ add_task(function* () {
|
||||||
function testClosingAfterCompletion(hud, browser) {
|
function testClosingAfterCompletion(hud, browser) {
|
||||||
let deferred = promise.defer();
|
let deferred = promise.defer();
|
||||||
|
|
||||||
let inputNode = hud.jsterm.inputNode;
|
|
||||||
|
|
||||||
let errorWhileClosing = false;
|
let errorWhileClosing = false;
|
||||||
function errorListener() {
|
function errorListener() {
|
||||||
errorWhileClosing = true;
|
errorWhileClosing = true;
|
||||||
|
@ -30,8 +28,8 @@ function testClosingAfterCompletion(hud, browser) {
|
||||||
|
|
||||||
browser.addEventListener("error", errorListener, false);
|
browser.addEventListener("error", errorListener, false);
|
||||||
|
|
||||||
// Focus the inputNode and perform the keycombo to close the WebConsole.
|
// Focus the jsterm and perform the keycombo to close the WebConsole.
|
||||||
inputNode.focus();
|
hud.jsterm.focus();
|
||||||
|
|
||||||
gDevTools.once("toolbox-destroyed", function() {
|
gDevTools.once("toolbox-destroyed", function() {
|
||||||
browser.removeEventListener("error", errorListener, false);
|
browser.removeEventListener("error", errorListener, false);
|
||||||
|
|
|
@ -25,7 +25,7 @@ function setup(HUD) {
|
||||||
jsterm = HUD.jsterm;
|
jsterm = HUD.jsterm;
|
||||||
inputNode = jsterm.inputNode;
|
inputNode = jsterm.inputNode;
|
||||||
|
|
||||||
inputNode.focus();
|
jsterm.focus();
|
||||||
|
|
||||||
ok(!jsterm.getInputValue(), "jsterm.getInputValue() is empty");
|
ok(!jsterm.getInputValue(), "jsterm.getInputValue() is empty");
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ function test() {
|
||||||
|
|
||||||
yield executeJS();
|
yield executeJS();
|
||||||
yield clickMessageAndShowVariablesView();
|
yield clickMessageAndShowVariablesView();
|
||||||
jsterm.inputNode.focus();
|
jsterm.focus();
|
||||||
|
|
||||||
yield testHideVariablesViewAfterEscape();
|
yield testHideVariablesViewAfterEscape();
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ function test() {
|
||||||
deferred.resolve();
|
deferred.resolve();
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
jsterm.inputNode.focus();
|
jsterm.focus();
|
||||||
jsterm.setInputValue("document.location.");
|
jsterm.setInputValue("document.location.");
|
||||||
EventUtils.sendKey("TAB", hud.iframeWindow);
|
EventUtils.sendKey("TAB", hud.iframeWindow);
|
||||||
|
|
||||||
|
|
|
@ -577,7 +577,7 @@ WebConsoleFrame.prototype = {
|
||||||
this._addFocusCallback(this.outputNode, (evt) => {
|
this._addFocusCallback(this.outputNode, (evt) => {
|
||||||
if ((evt.target.nodeName.toLowerCase() != "a") &&
|
if ((evt.target.nodeName.toLowerCase() != "a") &&
|
||||||
(evt.target.parentNode.nodeName.toLowerCase() != "a")) {
|
(evt.target.parentNode.nodeName.toLowerCase() != "a")) {
|
||||||
this.jsterm.inputNode.focus();
|
this.jsterm.focus();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -589,7 +589,7 @@ WebConsoleFrame.prototype = {
|
||||||
});
|
});
|
||||||
|
|
||||||
// focus input node
|
// focus input node
|
||||||
this.jsterm.inputNode.focus();
|
this.jsterm.focus();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -607,7 +607,7 @@ WebConsoleFrame.prototype = {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_onPanelSelected: function() {
|
_onPanelSelected: function() {
|
||||||
this.jsterm.inputNode.focus();
|
this.jsterm.focus();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3090,9 +3090,8 @@ JSTerm.prototype = {
|
||||||
},
|
},
|
||||||
|
|
||||||
focus: function() {
|
focus: function() {
|
||||||
let inputNode = this.inputNode;
|
if (!this.inputNode.getAttribute("focused")) {
|
||||||
if (!inputNode.getAttribute("focused")) {
|
this.inputNode.focus();
|
||||||
inputNode.focus();
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -3461,7 +3460,7 @@ JSTerm.prototype = {
|
||||||
}
|
}
|
||||||
|
|
||||||
this._sidebarDestroy();
|
this._sidebarDestroy();
|
||||||
this.inputNode.focus();
|
this.focus();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -3854,7 +3853,7 @@ JSTerm.prototype = {
|
||||||
// Ctrl-N is also used to focus the Network category button on
|
// Ctrl-N is also used to focus the Network category button on
|
||||||
// MacOSX. The preventDefault() call doesn't prevent the focus
|
// MacOSX. The preventDefault() call doesn't prevent the focus
|
||||||
// from moving away from the input.
|
// from moving away from the input.
|
||||||
inputNode.focus();
|
this.focus();
|
||||||
}
|
}
|
||||||
this.clearCompletion();
|
this.clearCompletion();
|
||||||
break;
|
break;
|
||||||
|
@ -3870,7 +3869,7 @@ JSTerm.prototype = {
|
||||||
// Ctrl-P may also be used to focus some category button on MacOSX.
|
// Ctrl-P may also be used to focus some category button on MacOSX.
|
||||||
// The preventDefault() call doesn't prevent the focus from moving
|
// The preventDefault() call doesn't prevent the focus from moving
|
||||||
// away from the input.
|
// away from the input.
|
||||||
inputNode.focus();
|
this.focus();
|
||||||
}
|
}
|
||||||
this.clearCompletion();
|
this.clearCompletion();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -10853,6 +10853,24 @@ nsIDocument::ObsoleteSheet(const nsAString& aSheetURI, ErrorResult& rv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
already_AddRefed<nsIURI>
|
||||||
|
nsIDocument::GetMozDocumentURIIfNotForErrorPages()
|
||||||
|
{
|
||||||
|
if (mFailedChannel) {
|
||||||
|
nsCOMPtr<nsIURI> failedURI;
|
||||||
|
if (NS_SUCCEEDED(mFailedChannel->GetURI(getter_AddRefs(failedURI)))) {
|
||||||
|
return failedURI.forget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIURI> uri = GetDocumentURIObject();
|
||||||
|
if (!uri) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return uri.forget();
|
||||||
|
}
|
||||||
|
|
||||||
nsIHTMLCollection*
|
nsIHTMLCollection*
|
||||||
nsIDocument::Children()
|
nsIDocument::Children()
|
||||||
{
|
{
|
||||||
|
|
|
@ -2601,6 +2601,8 @@ public:
|
||||||
|
|
||||||
void ObsoleteSheet(const nsAString& aSheetURI, mozilla::ErrorResult& rv);
|
void ObsoleteSheet(const nsAString& aSheetURI, mozilla::ErrorResult& rv);
|
||||||
|
|
||||||
|
already_AddRefed<nsIURI> GetMozDocumentURIIfNotForErrorPages();
|
||||||
|
|
||||||
// ParentNode
|
// ParentNode
|
||||||
nsIHTMLCollection* Children();
|
nsIHTMLCollection* Children();
|
||||||
uint32_t ChildElementCount();
|
uint32_t ChildElementCount();
|
||||||
|
|
|
@ -6,7 +6,7 @@ support-files =
|
||||||
plugin_no_scroll_div.html
|
plugin_no_scroll_div.html
|
||||||
|
|
||||||
[browser_bug1163570.js]
|
[browser_bug1163570.js]
|
||||||
skip-if = (!e10s || os != "win")
|
skip-if = true # Bug 1249878
|
||||||
[browser_bug1196539.js]
|
[browser_bug1196539.js]
|
||||||
skip-if = (!e10s || os != "win")
|
skip-if = (!e10s || os != "win")
|
||||||
[browser_tabswitchbetweenplugins.js]
|
[browser_tabswitchbetweenplugins.js]
|
||||||
|
|
|
@ -39,20 +39,18 @@ function promiseWaitForEvent(object, eventName, capturing = false, chrome = fals
|
||||||
|
|
||||||
add_task(function* () {
|
add_task(function* () {
|
||||||
registerCleanupFunction(function () {
|
registerCleanupFunction(function () {
|
||||||
Services.prefs.clearUserPref("browser.uiCustomization.disableAnimation");
|
|
||||||
window.focus();
|
window.focus();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
add_task(function* () {
|
add_task(function* () {
|
||||||
Services.prefs.setBoolPref("browser.uiCustomization.disableAnimation", true);
|
|
||||||
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
|
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
|
||||||
|
|
||||||
let pluginTab = gBrowser.selectedTab = gBrowser.addTab();
|
let pluginTab = gBrowser.selectedTab = gBrowser.addTab();
|
||||||
let customizeTab = gBrowser.addTab();
|
let prefTab = gBrowser.addTab();
|
||||||
|
|
||||||
yield promiseTabLoad(pluginTab, gTestRoot + "plugin_test.html");
|
yield promiseTabLoad(pluginTab, gTestRoot + "plugin_test.html");
|
||||||
yield promiseTabLoad(customizeTab, "about:customizing");
|
yield promiseTabLoad(prefTab, "about:preferences");
|
||||||
|
|
||||||
let result = yield ContentTask.spawn(gBrowser.selectedBrowser, null, function*() {
|
let result = yield ContentTask.spawn(gBrowser.selectedBrowser, null, function*() {
|
||||||
let doc = content.document;
|
let doc = content.document;
|
||||||
|
@ -62,10 +60,8 @@ add_task(function* () {
|
||||||
|
|
||||||
is(result, true, "plugin is loaded");
|
is(result, true, "plugin is loaded");
|
||||||
|
|
||||||
let cpromise = promiseWaitForEvent(window.gNavToolbox, "customizationready");
|
|
||||||
let ppromise = promiseWaitForEvent(window, "MozAfterPaint");
|
let ppromise = promiseWaitForEvent(window, "MozAfterPaint");
|
||||||
gBrowser.selectedTab = customizeTab;
|
gBrowser.selectedTab = prefTab;
|
||||||
yield cpromise;
|
|
||||||
yield ppromise;
|
yield ppromise;
|
||||||
|
|
||||||
// We're going to switch tabs using actual mouse clicks, which helps
|
// We're going to switch tabs using actual mouse clicks, which helps
|
||||||
|
@ -77,13 +73,11 @@ add_task(function* () {
|
||||||
info("-> " + tabStripContainer.firstChild.tagName); // tab
|
info("-> " + tabStripContainer.firstChild.tagName); // tab
|
||||||
info("-> " + tabStripContainer.childNodes[0].label); // test harness tab
|
info("-> " + tabStripContainer.childNodes[0].label); // test harness tab
|
||||||
info("-> " + tabStripContainer.childNodes[1].label); // plugin tab
|
info("-> " + tabStripContainer.childNodes[1].label); // plugin tab
|
||||||
info("-> " + tabStripContainer.childNodes[2].label); // customize tab
|
info("-> " + tabStripContainer.childNodes[2].label); // preferences tab
|
||||||
|
|
||||||
for (let iteration = 0; iteration < 5; iteration++) {
|
for (let iteration = 0; iteration < 5; iteration++) {
|
||||||
cpromise = promiseWaitForEvent(window.gNavToolbox, "aftercustomization");
|
|
||||||
ppromise = promiseWaitForEvent(window, "MozAfterPaint");
|
ppromise = promiseWaitForEvent(window, "MozAfterPaint");
|
||||||
EventUtils.synthesizeMouseAtCenter(tabStripContainer.childNodes[1], {}, window);
|
EventUtils.synthesizeMouseAtCenter(tabStripContainer.childNodes[1], {}, window);
|
||||||
yield cpromise;
|
|
||||||
yield ppromise;
|
yield ppromise;
|
||||||
|
|
||||||
result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
|
result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
|
||||||
|
@ -94,10 +88,8 @@ add_task(function* () {
|
||||||
|
|
||||||
is(result, true, "plugin is visible");
|
is(result, true, "plugin is visible");
|
||||||
|
|
||||||
cpromise = promiseWaitForEvent(window.gNavToolbox, "customizationready");
|
|
||||||
ppromise = promiseWaitForEvent(window, "MozAfterPaint");
|
ppromise = promiseWaitForEvent(window, "MozAfterPaint");
|
||||||
EventUtils.synthesizeMouseAtCenter(tabStripContainer.childNodes[2], {}, window);
|
EventUtils.synthesizeMouseAtCenter(tabStripContainer.childNodes[2], {}, window);
|
||||||
yield cpromise;
|
|
||||||
yield ppromise;
|
yield ppromise;
|
||||||
|
|
||||||
result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
|
result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
|
||||||
|
@ -108,11 +100,6 @@ add_task(function* () {
|
||||||
is(result, false, "plugin is hidden");
|
is(result, false, "plugin is hidden");
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for customize view to shutdown cleanly otherwise we get
|
gBrowser.removeTab(prefTab);
|
||||||
// a ton of error spew on shutdown.
|
|
||||||
cpromise = promiseWaitForEvent(window.gNavToolbox, "aftercustomization");
|
|
||||||
gBrowser.removeTab(customizeTab);
|
|
||||||
yield cpromise;
|
|
||||||
|
|
||||||
gBrowser.removeTab(pluginTab);
|
gBrowser.removeTab(pluginTab);
|
||||||
});
|
});
|
||||||
|
|
|
@ -373,6 +373,10 @@ partial interface Document {
|
||||||
[ChromeOnly] readonly attribute DOMString contentLanguage;
|
[ChromeOnly] readonly attribute DOMString contentLanguage;
|
||||||
|
|
||||||
[ChromeOnly] readonly attribute nsILoadGroup? documentLoadGroup;
|
[ChromeOnly] readonly attribute nsILoadGroup? documentLoadGroup;
|
||||||
|
|
||||||
|
// like documentURI, except that for error pages, it returns the URI we were
|
||||||
|
// trying to load when we hit an error, rather than the error page's own URI.
|
||||||
|
[ChromeOnly] readonly attribute URI? mozDocumentURIIfNotForErrorPages;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Extension to give chrome JS the ability to determine when a document was
|
// Extension to give chrome JS the ability to determine when a document was
|
||||||
|
|
|
@ -228,7 +228,7 @@ nsTextBoxFrame::UpdateAttributes(nsIAtom* aAttribute,
|
||||||
if (aAttribute == nullptr || aAttribute == nsGkAtoms::crop) {
|
if (aAttribute == nullptr || aAttribute == nsGkAtoms::crop) {
|
||||||
static nsIContent::AttrValuesArray strings[] =
|
static nsIContent::AttrValuesArray strings[] =
|
||||||
{&nsGkAtoms::left, &nsGkAtoms::start, &nsGkAtoms::center,
|
{&nsGkAtoms::left, &nsGkAtoms::start, &nsGkAtoms::center,
|
||||||
&nsGkAtoms::right, &nsGkAtoms::end, nullptr};
|
&nsGkAtoms::right, &nsGkAtoms::end, &nsGkAtoms::none, nullptr};
|
||||||
CroppingStyle cropType;
|
CroppingStyle cropType;
|
||||||
switch (mContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::crop,
|
switch (mContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::crop,
|
||||||
strings, eCaseMatters)) {
|
strings, eCaseMatters)) {
|
||||||
|
@ -243,9 +243,12 @@ nsTextBoxFrame::UpdateAttributes(nsIAtom* aAttribute,
|
||||||
case 4:
|
case 4:
|
||||||
cropType = CropRight;
|
cropType = CropRight;
|
||||||
break;
|
break;
|
||||||
default:
|
case 5:
|
||||||
cropType = CropNone;
|
cropType = CropNone;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
cropType = CropAuto;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cropType != mCropType) {
|
if (cropType != mCropType) {
|
||||||
|
@ -647,6 +650,7 @@ nsTextBoxFrame::CalculateTitleForWidth(nsRenderingContext& aRenderingContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
const nsDependentString& kEllipsis = nsContentUtils::GetLocalizedEllipsis();
|
const nsDependentString& kEllipsis = nsContentUtils::GetLocalizedEllipsis();
|
||||||
|
if (mCropType != CropNone) {
|
||||||
// start with an ellipsis
|
// start with an ellipsis
|
||||||
mCroppedTitle.Assign(kEllipsis);
|
mCroppedTitle.Assign(kEllipsis);
|
||||||
|
|
||||||
|
@ -666,12 +670,17 @@ nsTextBoxFrame::CalculateTitleForWidth(nsRenderingContext& aRenderingContext,
|
||||||
return titleWidth;
|
return titleWidth;
|
||||||
|
|
||||||
aWidth -= titleWidth;
|
aWidth -= titleWidth;
|
||||||
|
} else {
|
||||||
|
mCroppedTitle.Truncate(0);
|
||||||
|
titleWidth = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// XXX: This whole block should probably take surrogates into account
|
// XXX: This whole block should probably take surrogates into account
|
||||||
// XXX and clusters!
|
// XXX and clusters!
|
||||||
// ok crop things
|
// ok crop things
|
||||||
switch (mCropType)
|
switch (mCropType)
|
||||||
{
|
{
|
||||||
|
case CropAuto:
|
||||||
case CropNone:
|
case CropNone:
|
||||||
case CropRight:
|
case CropRight:
|
||||||
{
|
{
|
||||||
|
@ -1126,7 +1135,7 @@ nsTextBoxFrame::GetMinSize(nsBoxLayoutState& aBoxLayoutState)
|
||||||
DISPLAY_MIN_SIZE(this, size);
|
DISPLAY_MIN_SIZE(this, size);
|
||||||
|
|
||||||
// if there is cropping our min width becomes our border and padding
|
// if there is cropping our min width becomes our border and padding
|
||||||
if (mCropType != CropNone) {
|
if (mCropType != CropNone && mCropType != CropAuto) {
|
||||||
if (GetWritingMode().IsVertical()) {
|
if (GetWritingMode().IsVertical()) {
|
||||||
size.height = 0;
|
size.height = 0;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -26,7 +26,7 @@ public:
|
||||||
NS_IMETHOD DoLayout(nsBoxLayoutState& aBoxLayoutState) override;
|
NS_IMETHOD DoLayout(nsBoxLayoutState& aBoxLayoutState) override;
|
||||||
virtual void MarkIntrinsicISizesDirty() override;
|
virtual void MarkIntrinsicISizesDirty() override;
|
||||||
|
|
||||||
enum CroppingStyle { CropNone, CropLeft, CropRight, CropCenter };
|
enum CroppingStyle { CropNone, CropLeft, CropRight, CropCenter, CropAuto };
|
||||||
|
|
||||||
friend nsIFrame* NS_NewTextBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
|
friend nsIFrame* NS_NewTextBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
|
||||||
|
|
||||||
|
|
|
@ -424,7 +424,7 @@ public class BrowserApp extends GeckoApp
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showBookmarkRemovedSnackbar() {
|
private void showBookmarkRemovedSnackbar() {
|
||||||
SnackbarHelper.showSnackbar(this, getResources().getString(R.string.bookmark_removed), Snackbar.LENGTH_SHORT);
|
SnackbarHelper.showSnackbar(this, getResources().getString(R.string.bookmark_removed), Snackbar.LENGTH_LONG);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showSwitchToReadingListSnackbar(String message) {
|
private void showSwitchToReadingListSnackbar(String message) {
|
||||||
|
@ -456,7 +456,7 @@ public class BrowserApp extends GeckoApp
|
||||||
public void onRemovedFromReadingList(String url) {
|
public void onRemovedFromReadingList(String url) {
|
||||||
SnackbarHelper.showSnackbar(this,
|
SnackbarHelper.showSnackbar(this,
|
||||||
getResources().getString(R.string.reading_list_removed),
|
getResources().getString(R.string.reading_list_removed),
|
||||||
Snackbar.LENGTH_SHORT);
|
Snackbar.LENGTH_LONG);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -2016,7 +2016,7 @@ public class BrowserApp extends GeckoApp
|
||||||
if (Tabs.getInstance().getDisplayCount() == 0)
|
if (Tabs.getInstance().getDisplayCount() == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
hideFirstrunPager(TelemetryContract.Method.TABSTRAY);
|
hideFirstrunPager(TelemetryContract.Method.BUTTON);
|
||||||
|
|
||||||
if (ensureTabsPanelExists()) {
|
if (ensureTabsPanelExists()) {
|
||||||
// If we've just inflated the tabs panel, only show it once the current
|
// If we've just inflated the tabs panel, only show it once the current
|
||||||
|
|
|
@ -219,7 +219,7 @@ public class EditBookmarkDialog {
|
||||||
public void onPostExecute(Void result) {
|
public void onPostExecute(Void result) {
|
||||||
SnackbarHelper.showSnackbar((Activity) context,
|
SnackbarHelper.showSnackbar((Activity) context,
|
||||||
context.getString(R.string.bookmark_updated),
|
context.getString(R.string.bookmark_updated),
|
||||||
Snackbar.LENGTH_SHORT);
|
Snackbar.LENGTH_LONG);
|
||||||
}
|
}
|
||||||
}).execute();
|
}).execute();
|
||||||
}
|
}
|
||||||
|
|
|
@ -576,7 +576,7 @@ public abstract class GeckoApp
|
||||||
ThreadUtils.postToUiThread(new Runnable() {
|
ThreadUtils.postToUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
SnackbarHelper.showSnackbar(GeckoApp.this, getString(resId), Snackbar.LENGTH_SHORT);
|
SnackbarHelper.showSnackbar(GeckoApp.this, getString(resId), Snackbar.LENGTH_LONG);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1014,12 +1014,12 @@ public abstract class GeckoApp
|
||||||
File dcimDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
|
File dcimDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
|
||||||
|
|
||||||
if (!dcimDir.mkdirs() && !dcimDir.isDirectory()) {
|
if (!dcimDir.mkdirs() && !dcimDir.isDirectory()) {
|
||||||
SnackbarHelper.showSnackbar(this, getString(R.string.set_image_path_fail), Snackbar.LENGTH_SHORT);
|
SnackbarHelper.showSnackbar(this, getString(R.string.set_image_path_fail), Snackbar.LENGTH_LONG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String path = Media.insertImage(getContentResolver(),image, null, null);
|
String path = Media.insertImage(getContentResolver(),image, null, null);
|
||||||
if (path == null) {
|
if (path == null) {
|
||||||
SnackbarHelper.showSnackbar(this, getString(R.string.set_image_path_fail), Snackbar.LENGTH_SHORT);
|
SnackbarHelper.showSnackbar(this, getString(R.string.set_image_path_fail), Snackbar.LENGTH_LONG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final Intent intent = new Intent(Intent.ACTION_ATTACH_DATA);
|
final Intent intent = new Intent(Intent.ACTION_ATTACH_DATA);
|
||||||
|
@ -1036,7 +1036,7 @@ public abstract class GeckoApp
|
||||||
};
|
};
|
||||||
ActivityHandlerHelper.startIntentForActivity(this, chooser, handler);
|
ActivityHandlerHelper.startIntentForActivity(this, chooser, handler);
|
||||||
} else {
|
} else {
|
||||||
SnackbarHelper.showSnackbar(this, getString(R.string.set_image_fail), Snackbar.LENGTH_SHORT);
|
SnackbarHelper.showSnackbar(this, getString(R.string.set_image_fail), Snackbar.LENGTH_LONG);
|
||||||
}
|
}
|
||||||
} catch(OutOfMemoryError ome) {
|
} catch(OutOfMemoryError ome) {
|
||||||
Log.e(LOGTAG, "Out of Memory when converting to byte array", ome);
|
Log.e(LOGTAG, "Out of Memory when converting to byte array", ome);
|
||||||
|
|
|
@ -2670,7 +2670,7 @@ public class GeckoAppShell
|
||||||
private static final void showImageShareFailureSnackbar() {
|
private static final void showImageShareFailureSnackbar() {
|
||||||
SnackbarHelper.showSnackbar((Activity) getContext(),
|
SnackbarHelper.showSnackbar((Activity) getContext(),
|
||||||
getApplicationContext().getString(R.string.share_image_failed),
|
getApplicationContext().getString(R.string.share_image_failed),
|
||||||
Snackbar.LENGTH_SHORT
|
Snackbar.LENGTH_LONG
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ import java.nio.charset.Charset;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
@ -48,6 +49,7 @@ public final class GeckoProfile {
|
||||||
|
|
||||||
// The path in the profile to the file containing the client ID.
|
// The path in the profile to the file containing the client ID.
|
||||||
private static final String CLIENT_ID_FILE_PATH = "datareporting/state.json";
|
private static final String CLIENT_ID_FILE_PATH = "datareporting/state.json";
|
||||||
|
private static final String FHR_CLIENT_ID_FILE_PATH = "healthreport/state.json";
|
||||||
// In the client ID file, the attribute title in the JSON object containing the client ID value.
|
// In the client ID file, the attribute title in the JSON object containing the client ID value.
|
||||||
private static final String CLIENT_ID_JSON_ATTR = "clientID";
|
private static final String CLIENT_ID_JSON_ATTR = "clientID";
|
||||||
|
|
||||||
|
@ -599,7 +601,8 @@ public final class GeckoProfile {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the Gecko client ID from the filesystem.
|
* Retrieves the Gecko client ID from the filesystem. If the client ID does not exist, we attempt to migrate and
|
||||||
|
* persist it from FHR and, if that fails, we attempt to create a new one ourselves.
|
||||||
*
|
*
|
||||||
* This method assumes the client ID is located in a file at a hard-coded path within the profile. The format of
|
* This method assumes the client ID is located in a file at a hard-coded path within the profile. The format of
|
||||||
* this file is a JSONObject which at the bottom level contains a String -> String mapping containing the client ID.
|
* this file is a JSONObject which at the bottom level contains a String -> String mapping containing the client ID.
|
||||||
|
@ -608,21 +611,84 @@ public final class GeckoProfile {
|
||||||
* robust way to access it. However, we don't want to rely on Gecko running in order to get
|
* robust way to access it. However, we don't want to rely on Gecko running in order to get
|
||||||
* the client ID so instead we access the file this module accesses directly. However, it's
|
* the client ID so instead we access the file this module accesses directly. However, it's
|
||||||
* possible the format of this file (and the access calls in the jsm) will change, leaving
|
* possible the format of this file (and the access calls in the jsm) will change, leaving
|
||||||
* this code to fail.
|
* this code to fail. There are tests in TestGeckoProfile to verify the file format but be
|
||||||
*
|
* warned: THIS IS NOT FOOLPROOF.
|
||||||
* TODO: Write tests to prevent regressions. Mention them here. Test both file location and file format.
|
|
||||||
*
|
*
|
||||||
* [1]: https://mxr.mozilla.org/mozilla-central/source/toolkit/modules/ClientID.jsm
|
* [1]: https://mxr.mozilla.org/mozilla-central/source/toolkit/modules/ClientID.jsm
|
||||||
|
*
|
||||||
|
* @throws IOException if the client ID could not be retrieved.
|
||||||
*/
|
*/
|
||||||
|
// Mimics ClientID.jsm – _doLoadClientID.
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
public String getClientId() throws IOException {
|
public String getClientId() throws IOException {
|
||||||
final JSONObject obj = readJSONObjectFromFile(CLIENT_ID_FILE_PATH);
|
|
||||||
try {
|
try {
|
||||||
return obj.getString(CLIENT_ID_JSON_ATTR);
|
return getValidClientIdFromDisk(CLIENT_ID_FILE_PATH);
|
||||||
} catch (final JSONException e) {
|
} catch (final IOException e) {
|
||||||
// Don't log to avoid leaking data in JSONObject.
|
// Avoid log spam: don't log the full Exception w/ the stack trace.
|
||||||
throw new IOException("Client ID does not exist in JSONObject");
|
Log.d(LOGTAG, "Could not get client ID - attempting to migrate ID from FHR: " + e.getLocalizedMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String clientIdToWrite;
|
||||||
|
try {
|
||||||
|
clientIdToWrite = getValidClientIdFromDisk(FHR_CLIENT_ID_FILE_PATH);
|
||||||
|
} catch (final IOException e) {
|
||||||
|
// Avoid log spam: don't log the full Exception w/ the stack trace.
|
||||||
|
Log.d(LOGTAG, "Could not migrate client ID from FHR – creating a new one: " + e.getLocalizedMessage());
|
||||||
|
clientIdToWrite = UUID.randomUUID().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// There is a possibility Gecko is running and the Gecko telemetry implementation decided it's time to generate
|
||||||
|
// the client ID, writing client ID underneath us. Since it's highly unlikely (e.g. we run in onStart before
|
||||||
|
// Gecko is started), we don't handle that possibility besides writing the ID and then reading from the file
|
||||||
|
// again (rather than just returning the value we generated before writing).
|
||||||
|
//
|
||||||
|
// In the event it does happen, any discrepancy will be resolved after a restart. In the mean time, both this
|
||||||
|
// implementation and the Gecko implementation could upload documents with inconsistent IDs.
|
||||||
|
//
|
||||||
|
// In any case, if we get an exception, intentionally throw - there's nothing more to do here.
|
||||||
|
persistClientId(clientIdToWrite);
|
||||||
|
return getValidClientIdFromDisk(CLIENT_ID_FILE_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return a valid client ID
|
||||||
|
* @throws IOException if a valid client ID could not be retrieved
|
||||||
|
*/
|
||||||
|
@WorkerThread
|
||||||
|
private String getValidClientIdFromDisk(final String filePath) throws IOException {
|
||||||
|
final JSONObject obj = readJSONObjectFromFile(filePath);
|
||||||
|
final String clientId = obj.optString(CLIENT_ID_JSON_ATTR);
|
||||||
|
if (isClientIdValid(clientId)) {
|
||||||
|
return clientId;
|
||||||
|
}
|
||||||
|
throw new IOException("Received client ID is invalid: " + clientId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@WorkerThread
|
||||||
|
private void persistClientId(final String clientId) throws IOException {
|
||||||
|
if (!ensureParentDirs(CLIENT_ID_FILE_PATH)) {
|
||||||
|
throw new IOException("Could not create client ID parent directories");
|
||||||
|
}
|
||||||
|
|
||||||
|
final JSONObject obj = new JSONObject();
|
||||||
|
try {
|
||||||
|
obj.put(CLIENT_ID_JSON_ATTR, clientId);
|
||||||
|
} catch (final JSONException e) {
|
||||||
|
throw new IOException("Could not create client ID JSON object", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClientID.jsm overwrites the file to store the client ID so it's okay if we do it too.
|
||||||
|
Log.d(LOGTAG, "Attempting to write new client ID");
|
||||||
|
writeFile(CLIENT_ID_FILE_PATH, obj.toString()); // Logs errors within function: ideally we'd throw.
|
||||||
|
}
|
||||||
|
|
||||||
|
// From ClientID.jsm - isValidClientID.
|
||||||
|
public static boolean isClientIdValid(final String clientId) {
|
||||||
|
// We could use UUID.fromString but, for consistency, we take the implementation from ClientID.jsm.
|
||||||
|
if (TextUtils.isEmpty(clientId)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return clientId.matches("(?i:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -702,6 +768,20 @@ public final class GeckoProfile {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures the parent director(y|ies) of the given filename exist by making them
|
||||||
|
* if they don't already exist..
|
||||||
|
*
|
||||||
|
* @param filename The path to the file whose parents should be made directories
|
||||||
|
* @return true if the parent directory exists, false otherwise
|
||||||
|
*/
|
||||||
|
@WorkerThread
|
||||||
|
protected boolean ensureParentDirs(final String filename) {
|
||||||
|
final File file = new File(getDir(), filename);
|
||||||
|
final File parentFile = file.getParentFile();
|
||||||
|
return parentFile.mkdirs() || parentFile.isDirectory();
|
||||||
|
}
|
||||||
|
|
||||||
public void writeFile(final String filename, final String data) {
|
public void writeFile(final String filename, final String data) {
|
||||||
File file = new File(getDir(), filename);
|
File file = new File(getDir(), filename);
|
||||||
BufferedWriter bufferedWriter = null;
|
BufferedWriter bufferedWriter = null;
|
||||||
|
|
|
@ -188,8 +188,8 @@ public interface TelemetryContract {
|
||||||
// Action triggered from a suggestion provided to the user.
|
// Action triggered from a suggestion provided to the user.
|
||||||
SUGGESTION("suggestion"),
|
SUGGESTION("suggestion"),
|
||||||
|
|
||||||
// Action triggered from the Tabs tray.
|
// Action triggered from an OS system action.
|
||||||
TABSTRAY("tabstray"),
|
SYSTEM("system"),
|
||||||
|
|
||||||
// Action triggered from a SuperToast.
|
// Action triggered from a SuperToast.
|
||||||
// Note: Only used in JavaScript for now, but here for completeness.
|
// Note: Only used in JavaScript for now, but here for completeness.
|
||||||
|
|
|
@ -419,7 +419,7 @@ public abstract class HomeFragment extends Fragment {
|
||||||
public void onPostExecute(Void result) {
|
public void onPostExecute(Void result) {
|
||||||
SnackbarHelper.showSnackbar((Activity) mContext,
|
SnackbarHelper.showSnackbar((Activity) mContext,
|
||||||
mContext.getString(R.string.page_removed),
|
mContext.getString(R.string.page_removed),
|
||||||
Snackbar.LENGTH_SHORT);
|
Snackbar.LENGTH_LONG);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -655,7 +655,7 @@ OnSharedPreferenceChangeListener
|
||||||
|
|
||||||
SnackbarHelper.showSnackbar(GeckoPreferences.this,
|
SnackbarHelper.showSnackbar(GeckoPreferences.this,
|
||||||
getString(stringRes),
|
getString(stringRes),
|
||||||
Snackbar.LENGTH_SHORT);
|
Snackbar.LENGTH_LONG);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
|
Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
|
||||||
|
|
|
@ -94,7 +94,7 @@ public class SearchEnginePreference extends CustomListPreference {
|
||||||
|
|
||||||
SnackbarHelper.showSnackbar(activity,
|
SnackbarHelper.showSnackbar(activity,
|
||||||
activity.getString(R.string.pref_search_last_toast),
|
activity.getString(R.string.pref_search_last_toast),
|
||||||
Snackbar.LENGTH_SHORT);
|
Snackbar.LENGTH_LONG);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,8 +172,7 @@ public class TelemetryUploadService extends BackgroundService {
|
||||||
try {
|
try {
|
||||||
clientId = profile.getClientId();
|
clientId = profile.getClientId();
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
// Don't log the exception to avoid leaking the profile path.
|
Log.w(LOGTAG, "Unable to get client ID to generate core ping: returning.", e);
|
||||||
Log.w(LOGTAG, "Unable to get client ID to generate core ping: returning.");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
До Ширина: | Высота: | Размер: 46 KiB После Ширина: | Высота: | Размер: 18 KiB |
До Ширина: | Высота: | Размер: 38 KiB После Ширина: | Высота: | Размер: 16 KiB |
|
@ -348,7 +348,7 @@ var ActionBarHandler = {
|
||||||
clipboard.copyString(selectedText);
|
clipboard.copyString(selectedText);
|
||||||
|
|
||||||
let msg = Strings.browser.GetStringFromName("selectionHelper.textCopied");
|
let msg = Strings.browser.GetStringFromName("selectionHelper.textCopied");
|
||||||
Snackbars.show(msg, Snackbars.LENGTH_SHORT);
|
Snackbars.show(msg, Snackbars.LENGTH_LONG);
|
||||||
|
|
||||||
// Then cut the selection text.
|
// Then cut the selection text.
|
||||||
ActionBarHandler._getSelection(element, win).deleteFromDocument();
|
ActionBarHandler._getSelection(element, win).deleteFromDocument();
|
||||||
|
@ -383,7 +383,7 @@ var ActionBarHandler = {
|
||||||
clipboard.copyString(selectedText);
|
clipboard.copyString(selectedText);
|
||||||
|
|
||||||
let msg = Strings.browser.GetStringFromName("selectionHelper.textCopied");
|
let msg = Strings.browser.GetStringFromName("selectionHelper.textCopied");
|
||||||
Snackbars.show(msg, Snackbars.LENGTH_SHORT);
|
Snackbars.show(msg, Snackbars.LENGTH_LONG);
|
||||||
|
|
||||||
ActionBarHandler._uninit();
|
ActionBarHandler._uninit();
|
||||||
UITelemetry.addEvent("action.1", "actionbar", null, "copy");
|
UITelemetry.addEvent("action.1", "actionbar", null, "copy");
|
||||||
|
|
|
@ -63,7 +63,7 @@ var MasterPassword = {
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
dump("MasterPassword.removePassword: " + e + "\n");
|
dump("MasterPassword.removePassword: " + e + "\n");
|
||||||
}
|
}
|
||||||
Snackbars.show(Strings.browser.GetStringFromName("masterPassword.incorrect"), Snackbars.LENGTH_SHORT);
|
Snackbars.show(Strings.browser.GetStringFromName("masterPassword.incorrect"), Snackbars.LENGTH_LONG);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -180,7 +180,7 @@ var Reader = {
|
||||||
|
|
||||||
case "Reader:ToolbarHidden":
|
case "Reader:ToolbarHidden":
|
||||||
if (!this._hasUsedToolbar) {
|
if (!this._hasUsedToolbar) {
|
||||||
Snackbars.show(Strings.browser.GetStringFromName("readerMode.toolbarTip"), Snackbars.LENGTH_SHORT);
|
Snackbars.show(Strings.browser.GetStringFromName("readerMode.toolbarTip"), Snackbars.LENGTH_LONG);
|
||||||
Services.prefs.setBoolPref("reader.has_used_toolbar", true);
|
Services.prefs.setBoolPref("reader.has_used_toolbar", true);
|
||||||
this._hasUsedToolbar = true;
|
this._hasUsedToolbar = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1090,7 +1090,7 @@ var SelectionHandler = {
|
||||||
if (selectedText.length) {
|
if (selectedText.length) {
|
||||||
let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper);
|
let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper);
|
||||||
clipboard.copyString(selectedText);
|
clipboard.copyString(selectedText);
|
||||||
Snackbars.show(Strings.browser.GetStringFromName("selectionHelper.textCopied"), Snackbars.LENGTH_SHORT);
|
Snackbars.show(Strings.browser.GetStringFromName("selectionHelper.textCopied"), Snackbars.LENGTH_LONG);
|
||||||
}
|
}
|
||||||
this._closeSelection();
|
this._closeSelection();
|
||||||
},
|
},
|
||||||
|
|
|
@ -31,10 +31,10 @@ function copyStringShowSnackbar(string, notifyString) {
|
||||||
try {
|
try {
|
||||||
let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper);
|
let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper);
|
||||||
clipboard.copyString(string);
|
clipboard.copyString(string);
|
||||||
Snackbars.show(notifyString, Snackbars.LENGTH_SHORT);
|
Snackbars.show(notifyString, Snackbars.LENGTH_LONG);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debug("Error copying from about:logins");
|
debug("Error copying from about:logins");
|
||||||
Snackbars.show(gStringBundle.GetStringFromName("loginsDetails.copyFailed"), Snackbars.LENGTH_SHORT);
|
Snackbars.show(gStringBundle.GetStringFromName("loginsDetails.copyFailed"), Snackbars.LENGTH_LONG);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,7 +291,7 @@ var Logins = {
|
||||||
if ((newUsername === origUsername) &&
|
if ((newUsername === origUsername) &&
|
||||||
(newPassword === origPassword) &&
|
(newPassword === origPassword) &&
|
||||||
(newDomain === origDomain) ) {
|
(newDomain === origDomain) ) {
|
||||||
Snackbars.show(gStringBundle.GetStringFromName("editLogin.saved1"), Snackbars.LENGTH_SHORT);
|
Snackbars.show(gStringBundle.GetStringFromName("editLogin.saved1"), Snackbars.LENGTH_LONG);
|
||||||
this._showList();
|
this._showList();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -310,10 +310,10 @@ var Logins = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Snackbars.show(gStringBundle.GetStringFromName("editLogin.couldNotSave"), Snackbars.LENGTH_SHORT);
|
Snackbars.show(gStringBundle.GetStringFromName("editLogin.couldNotSave"), Snackbars.LENGTH_LONG);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Snackbars.show(gStringBundle.GetStringFromName("editLogin.saved1"), Snackbars.LENGTH_SHORT);
|
Snackbars.show(gStringBundle.GetStringFromName("editLogin.saved1"), Snackbars.LENGTH_LONG);
|
||||||
this._showList();
|
this._showList();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|