This commit is contained in:
Phil Ringnalda 2016-02-20 17:25:14 -08:00
Родитель 9f638a1e8e 693a23497c
Коммит 1a1ec5b8bb
115 изменённых файлов: 4365 добавлений и 3673 удалений

Просмотреть файл

@ -141,16 +141,6 @@ function initResponsiveDesign() {
// Enable touch events
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)
.asyncExecuteLegacyQueries([query], 1, options, {
handleResult: function (aResultSet) {
let onItemClick = function (aEvent) {
let onItemCommand = function (aEvent) {
let item = aEvent.target;
openUILink(item.getAttribute("targetURI"), aEvent);
CustomizableUI.hidePanelForNode(item);
@ -1379,7 +1379,7 @@ var BookmarkingUI = {
item.setAttribute("targetURI", uri);
item.setAttribute("class", "menuitem-iconic menuitem-with-favicon bookmark-item " +
extraCSSClass);
item.addEventListener("click", onItemClick);
item.addEventListener("command", onItemCommand);
if (icon) {
let iconURL = "moz-anno:favicon:" + icon;
item.setAttribute("image", iconURL);

Просмотреть файл

@ -259,8 +259,6 @@ SocialUI = {
// called on tab/urlbar/location changes and after customization. Update
// anything that is tab specific.
updateState: function() {
if (location == "about:customizing")
return;
goSetCommandEnabled("Social:PageShareOrMark", this.canShareOrMarkPage(gBrowser.currentURI));
if (!SocialUI.enabled)
return;

Просмотреть файл

@ -183,9 +183,6 @@ if (AppConstants.MOZ_SAFE_BROWSING) {
"resource://gre/modules/SafeBrowsing.jsm");
}
XPCOMUtils.defineLazyModuleGetter(this, "gCustomizationTabPreloader",
"resource:///modules/CustomizationTabPreloader.jsm", "CustomizationTabPreloader");
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
"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
let defaultRemoteURL = gAboutNewTabService.remoteEnabled &&
uri.spec === gAboutNewTabService.newTabURL;
if (gInitialPages.includes(uri.spec) || defaultRemoteURL)
value = gBrowser.selectedBrowser.hasContentOpener ? uri.spec : "";
else
if ((gInitialPages.includes(uri.spec) || defaultRemoteURL) &&
checkEmptyPageOrigin(gBrowser.selectedBrowser, uri)) {
value = "";
} else {
value = losslessDecodeURI(uri);
}
valid = !isBlankPageURL(uri.spec);
}
@ -4327,7 +4326,7 @@ var XULBrowserWindow = {
// Do not update urlbar if there was a subframe navigation
if (aWebProgress.isTopLevel) {
if ((location == "about:blank" && !gBrowser.selectedBrowser.hasContentOpener) ||
if ((location == "about:blank" && checkEmptyPageOrigin()) ||
location == "") { // Second condition is for new tabs, otherwise
// reload function is enabled until tab is refreshed.
this.reloadCommand.setAttribute("disabled", "true");
@ -4339,7 +4338,7 @@ var XULBrowserWindow = {
URLBarSetURI(aLocationURI);
BookmarkingUI.onLocationChange();
SocialUI.updateState(location);
SocialUI.updateState();
UITour.onLocationChange(location);
gTabletModePageCounter.inc();
}
@ -4387,12 +4386,11 @@ var XULBrowserWindow = {
// Try not to instantiate gCustomizeMode as much as possible,
// so don't use CustomizeMode.jsm to check for URI or customizing.
let customizingURI = "about:customizing";
if (location == customizingURI) {
if (location == "about:blank" &&
gBrowser.selectedTab.hasAttribute("customizemode")) {
gCustomizeMode.enter();
} else if (location != customizingURI &&
(CustomizationHandler.isEnteringCustomizeMode ||
CustomizationHandler.isCustomizing())) {
} else if (CustomizationHandler.isEnteringCustomizeMode ||
CustomizationHandler.isCustomizing()) {
gCustomizeMode.exit();
}
}
@ -6390,11 +6388,14 @@ function isTabEmpty(aTab) {
if (aTab.hasAttribute("busy"))
return false;
if (aTab.hasAttribute("customizemode"))
return false;
let browser = aTab.linkedBrowser;
if (!isBlankPageURL(browser.currentURI.spec))
return false;
if (browser.hasContentOpener)
if (!checkEmptyPageOrigin(browser))
return false;
if (browser.canGoForward || browser.canGoBack)
@ -6403,6 +6404,56 @@ function isTabEmpty(aTab) {
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() {
if (Services.prefs.getBoolPref("services.sync.syncedTabsUIRefresh")) {
gSyncUI.openSyncedTabsPanel();
@ -7292,7 +7343,6 @@ function switchToTabHavingURI(aURI, aOpenNew, aOpenParams={}) {
// window being in private browsing mode:
const kPrivateBrowsingWhitelist = new Set([
"about:addons",
"about:customizing",
]);
let ignoreFragment = aOpenParams.ignoreFragment;

Просмотреть файл

@ -1398,6 +1398,11 @@
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.
title = this.mStringBundle.getString("tabs.emptyTabTitle");
}
@ -1926,11 +1931,6 @@
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
// entirely done, so that things are in a consistent state
// even if the event listener opens or closes tabs.
@ -2474,33 +2474,6 @@
</body>
</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">
<parameter name="aOurTab"/>
<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/referrer/browser.ini',
'content/test/social/browser.ini',
'content/test/urlbar/browser.ini',
]
DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION']

Просмотреть файл

@ -99,8 +99,6 @@ static RedirEntry kRedirMap[] = {
#endif
{ "accounts", "chrome://browser/content/aboutaccounts/aboutaccounts.xhtml",
nsIAboutModule::ALLOW_SCRIPT },
{ "customizing", "chrome://browser/content/customizableui/aboutCustomizing.xul",
nsIAboutModule::ALLOW_SCRIPT },
{ "loopconversation", "chrome://loop/content/panels/conversation.html",
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
nsIAboutModule::ALLOW_SCRIPT |

Просмотреть файл

@ -107,7 +107,6 @@ static const mozilla::Module::ContractIDEntry kBrowserContracts[] = {
#ifdef MOZ_SERVICES_HEALTHREPORT
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "healthreport", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
#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 "loopconversation", &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)
.asyncExecuteLegacyQueries([query], 1, options, {
handleResult: function (aResultSet) {
let onItemClick = function (aEvent) {
let onItemCommand = function (aEvent) {
let item = aEvent.target;
win.openUILink(item.getAttribute("targetURI"), aEvent);
CustomizableUI.hidePanelForNode(item);
@ -219,7 +219,7 @@ const CustomizableWidgets = [
item.setAttribute("label", title || uri);
item.setAttribute("targetURI", uri);
item.setAttribute("class", "subviewbutton");
item.addEventListener("click", onItemClick);
item.addEventListener("command", onItemCommand);
if (icon) {
let iconURL = "moz-anno:favicon:" + icon;
item.setAttribute("image", iconURL);

Просмотреть файл

@ -11,7 +11,6 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
const kPrefCustomizationDebug = "browser.uiCustomization.debug";
const kPrefCustomizationAnimation = "browser.uiCustomization.disableAnimation";
const kPaletteId = "customization-palette";
const kAboutURI = "about:customizing";
const kDragDataTypePrefix = "text/toolbarwrapper-id/";
const kPlaceholderClass = "panel-customization-placeholder";
const kSkipSourceNodePref = "browser.uiCustomization.skipSourceNodeCheck";
@ -36,6 +35,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "BrowserUITelemetry",
"resource:///modules/BrowserUITelemetry.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
"resource://gre/modules/LightweightThemeManager.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SessionStore",
"resource:///modules/sessionstore/SessionStore.jsm");
let gDebug;
XPCOMUtils.defineLazyGetter(this, "log", () => {
@ -56,6 +57,23 @@ var gDisableAnimation = null;
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) {
if (gDisableAnimation === null) {
gDisableAnimation = Services.prefs.getPrefType(kPrefCustomizationAnimation) == Ci.nsIPrefBranch.PREF_BOOL &&
@ -140,6 +158,36 @@ CustomizeMode.prototype = {
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() {
this._wantToBeInCustomizeMode = true;
@ -154,13 +202,18 @@ CustomizeMode.prototype = {
return;
}
// We don't need to switch to kAboutURI, or open a new tab at
// kAboutURI if we're already on it.
if (this.browser.selectedBrowser.currentURI.spec != kAboutURI) {
this.window.switchToTabHavingURI(kAboutURI, true, {
skipTabAnimation: true,
});
if (!gTab) {
this.setTab(this.browser.loadOneTab("about:blank",
{ inBackground: false,
forceNotRemote: true,
skipAnimation: true }));
return;
}
if (!gTab.selected) {
gTab.ownerGlobal.gBrowser.selectedTab = gTab;
}
gTab.ownerGlobal.focus();
if (gTab.ownerDocument != this.document) {
return;
}
@ -313,10 +366,6 @@ CustomizeMode.prototype = {
delete this._enableOutlinesTimeout;
}, 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) {
this.exit();
}
@ -402,31 +451,14 @@ CustomizeMode.prototype = {
Services.obs.removeObserver(this, "lightweight-theme-window-updated", false);
let browser = document.getElementById("browser");
if (this.browser.selectedBrowser.currentURI.spec == kAboutURI) {
let custBrowser = this.browser.selectedBrowser;
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);
}
if (this.browser.selectedTab == gTab) {
if (gTab.linkedBrowser.currentURI.spec == "about:blank") {
closeGlobalTab();
} else {
// If we can't go back, we're removing the about:customization tab.
// 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);
}
unregisterGlobalTab();
}
}
let browser = document.getElementById("browser");
browser.parentNode.selectedPanel = browser;
let customizer = document.getElementById("customization-container");
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/.
browser.jar:
content/browser/customizableui/aboutCustomizing.xul
content/browser/customizableui/panelUI.css
content/browser/customizableui/panelUI.js
content/browser/customizableui/panelUI.xml

Просмотреть файл

@ -157,10 +157,6 @@ const PanelUI = {
this.panel.addEventListener("popupshown", function 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();
});

Просмотреть файл

@ -25,7 +25,6 @@ skip-if = os == "mac"
[browser_886323_buildArea_removable_nodes.js]
[browser_887438_currentset_shim.js]
[browser_888817_currentset_updating.js]
[browser_889120_customize_tab_merging.js]
[browser_890140_orphaned_placeholders.js]
[browser_890262_destroyWidget_after_add_to_panel.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();
// 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;
}
@ -209,7 +209,7 @@ function endCustomizing(aWindow=window) {
deferredLoadNewTab.resolve();
}
newTabBrowser.addEventListener("load", onNewTabLoaded, true);
newTabBrowser.contentDocument.location.replace("about:blank");
newTabBrowser.loadURI("about:blank");
return deferredLoadNewTab.promise;
});
}

Просмотреть файл

@ -70,6 +70,12 @@ DistributionCustomizer.prototype = {
return this._locale;
},
get _language() {
let language = this._locale.split("-")[0];
this.__defineGetter__("_language", () => language);
return this._language;
},
get _prefSvc() {
let svc = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefService);
@ -112,6 +118,8 @@ DistributionCustomizer.prototype = {
if (keys.indexOf(key + "." + this._locale) >= 0) {
key += "." + this._locale;
} else if (keys.indexOf(key + "." + this._language) >= 0) {
key += "." + this._language;
}
if (!items[itemIndex])
@ -323,6 +331,8 @@ DistributionCustomizer.prototype = {
try {
if (globalPrefs["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 {
partnerAbout.data = this._ini.getString("Global", "about");
}
@ -367,6 +377,17 @@ DistributionCustomizer.prototype = {
try {
let value = eval(this._ini.getString("LocalizablePreferences", key));
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;
defaults.setComplexValue(key, Ci.nsIPrefLocalizedString, localizedStr);
} catch (e) { /* ignore bad prefs and move on */ }

Просмотреть файл

@ -632,7 +632,7 @@ global.WindowManager = {
convert(extension, window, getInfo) {
let result = {
id: this.getId(window),
focused: window == WindowManager.topWindow,
focused: window.document.hasFocus(),
top: window.screenY,
left: window.screenX,
width: window.outerWidth,

Просмотреть файл

@ -58,9 +58,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "WebappManager",
XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs",
"resource://gre/modules/PageThumbs.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "CustomizationTabPreloader",
"resource:///modules/CustomizationTabPreloader.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PdfJs",
"resource://pdf.js/PdfJs.jsm");
@ -1072,7 +1069,6 @@ BrowserGlue.prototype = {
SelfSupportBackend.uninit();
CustomizationTabPreloader.uninit();
WebappManager.uninit();
NewTabPrefsProvider.prefs.uninit();
@ -1812,10 +1808,16 @@ BrowserGlue.prototype = {
_migrateUI: function BG__migrateUI() {
const UI_VERSION = 36;
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");
} catch(ex) {}
} else {
// This is a new profile, nothing to migrate.
Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
return;
}
if (currentUIVersion >= UI_VERSION)
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:///modules/ShellService.jsm");
Components.utils.import("resource:///modules/TransientPrefs.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "OS",
"resource://gre/modules/osfile.jsm");
#ifdef E10S_TESTING_ONLY
XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
"resource://gre/modules/UpdateUtils.jsm");
@ -101,7 +105,6 @@ var gMainPane = {
#endif
#ifdef MOZ_DEV_EDITION
Cu.import("resource://gre/modules/osfile.jsm");
let uAppData = OS.Constants.Path.userApplicationDataDir;
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);
}
}
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;
let separateProfileModeCheckbox = document.getElementById("separateProfileMode");
@ -194,8 +207,25 @@ var gMainPane = {
"featureEnableRequiresRestart" : "featureDisableRequiresRestart",
[brandName]);
let title = bundle.getFormattedString("shouldRestartTitle", [brandName]);
let shouldProceed = Services.prompt.confirm(window, title, msg)
if (shouldProceed) {
let check = {value: false};
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"]
.createInstance(Ci.nsISupportsPRBool);
Services.obs.notifyObservers(cancelQuit, "quit-application-requested",
@ -203,21 +233,17 @@ var gMainPane = {
shouldProceed = !cancelQuit.data;
if (shouldProceed) {
Cu.import("resource://gre/modules/osfile.jsm");
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);
}
createOrRemoveSpecialDevEditionFile(quitApp);
return;
}
}
// Revert the checkbox in case we didn't quit
revertCheckbox();
return;
case RESTART_LATER_BUTTON_INDEX:
createOrRemoveSpecialDevEditionFile();
return;
}
},
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) {
if (showDialog) {
let flags = Services.prompt.BUTTON_POS_0 * Services.prompt.BUTTON_TITLE_IS_STRING +

Просмотреть файл

@ -4,8 +4,7 @@
<!-- Sync panel -->
<preferences id="syncEnginePrefs" hidden="true" data-category="paneSync"
onchange="gSyncPane.onPreferenceChanged();">
<preferences id="syncEnginePrefs" hidden="true" data-category="paneSync">
<preference id="engine.addons"
name="services.sync.engine.addons"
type="bool"/>

Просмотреть файл

@ -801,6 +801,8 @@ var SessionStoreInternal = {
tab.label = activePageData.url;
tab.crop = "center";
}
} else if (tab.hasAttribute("customizemode")) {
win.gCustomizeMode.setTab(tab);
}
// Restore the tab icon.
@ -3299,6 +3301,10 @@ var SessionStoreInternal = {
* optional load arguments used for loadURI()
*/
restoreTabContent: function (aTab, aLoadArguments = null) {
if (aTab.hasAttribute("customizemode")) {
return;
}
let browser = aTab.linkedBrowser;
let window = aTab.ownerDocument.defaultView;
let tabbrowser = window.gBrowser;

Просмотреть файл

@ -6,50 +6,138 @@
this.EXPORTED_SYMBOLS = ["LanguageDetector"];
Components.utils.import("resource://gre/modules/Timer.jsm");
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/Promise.jsm");
// Since Emscripten can handle heap growth, but not heap shrinkage, we
// 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";
var detectionQueue = [];
var workerManager = {
detectionQueue: [],
var workerReady = false;
var pendingStrings = [];
XPCOMUtils.defineLazyGetter(this, "worker", () => {
let worker = new Worker(WORKER_URL);
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;
detectLanguage(aParams) {
return this.workerReady.then(worker => {
return new Promise(resolve => {
this.detectionQueue.push({resolve});
worker.postMessage(aParams);
});
}).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 = {
/**
* 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
* these fields:
* - '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) {
let deferred = Promise.defer();
detectionQueue.push(deferred);
if (worker && workerReady)
worker.postMessage(aString);
else
pendingStrings.push(aString);
return deferred.promise;
}
detectLanguage: function(aParams) {
if (typeof aParams == "string")
aParams = { text: aParams };
return workerManager.detectLanguage(aParams);
},
};

Просмотреть файл

@ -1,8 +1,29 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/. */
# 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= \
internal/cldutil.cc \
@ -32,13 +53,22 @@ SOURCES= \
cldapp.cc \
$(NULL)
%.o: %.cc
$(CC) -Os -I. -o $@ $<
OBJECTS=$(SOURCES:.cc=.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)
$(CC) $(FLAGS) -I. -o cld-worker.js $^ --post-js post.js -s EXPORTED_FUNCTIONS="['_detectLangCode', '_lastResultReliable']"
%.o: %.cc Makefile
$(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:
rm -rf $(SOURCES:.cc=.o)
rm -f $(OBJECTS) cld.cpp cld.js before.js

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Двоичный файл не отображается.

Просмотреть файл

@ -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"
extern "C" {
#define MAX_RESULTS 3
using namespace CLD2;
class Language {
public:
Language(CLD2::Language lang) : mLang(lang) {}
bool g_is_reliable;
const char* detectLangCode(const char* src) {
return LanguageCode(DetectLanguage(src, strlen(src),
true /* is_plain_text */,
&g_is_reliable));
const char* getLanguageCode() const
{
return CLD2::LanguageCode(mLang);
}
bool lastResultReliable(void) {
return g_is_reliable;
private:
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,
* 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() {
onmessage = function(aMsg){
let data = aMsg['data'];
// Convert the string to an array of UTF8 bytes.
var encoder = new TextEncoder();
encoder['encoding'] = "utf-8";
var utf8Array = encoder['encode'](aMsg.data);
let langInfo;
if (data['tld'] == undefined && data['encoding'] == undefined && data['language'] == undefined) {
langInfo = LanguageInfo.detectLanguage(data['text'], !data['isHTML']);
} 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.
var strLength = utf8Array.length;
var ptr = Module['_malloc'](strLength + 1);
var heap = Module['HEAPU8'];
new Uint8Array(heap.buffer, ptr, strLength).set(utf8Array);
// Add a \0 at the end of the C string.
heap[ptr + strLength] = 0;
let encoding;
if (Encodings.hasOwnProperty(enc))
encoding = Encodings[enc];
else
encoding = Encodings['UNKNOWN_ENCODING'];
var lang = Pointer_stringify(_detectLangCode(ptr));
var confident = !!Module['ccall']("lastResultReliable", "number");
postMessage({'language': lang,
'confident': confident});
langInfo = LanguageInfo.detectLanguage(data['text'], !data['isHTML'],
data['tld'] || null,
encoding,
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");
});

Просмотреть файл

@ -308,7 +308,7 @@ const kTestPairs = [
["bg", "BULGARIAN", kTeststr_bg_Cyrl],
["ca", "CATALAN", kTeststr_ca_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],
["da", "DANISH", kTeststr_da_Latn],
["nl", "DUTCH", kTeststr_nl_Latn],
@ -335,7 +335,7 @@ const kTestPairs = [
["mk", "MACEDONIAN", kTeststr_mk_Cyrl],
["ms", "MALAY", kTeststr_ms_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],
["no", "NORWEGIAN", kTeststr_no_Latn],
["fa", "PERSIAN", kTeststr_fa_Arab],
@ -370,11 +370,11 @@ const kTestPairs = [
["bs", "BOSNIAN", kTeststr_bs_Latn],
// 2 statistically-close languages
["id", "INDONESIAN", kTeststr_id_close, true],
["id", "INDONESIAN", kTeststr_id_close, [true, 80], []],
["ms", "MALAY", kTeststr_ms_close],
// 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
// Change the expected language each time it is rebuilt
@ -382,14 +382,92 @@ const kTestPairs = [
["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() {
for (let pair of kTestPairs) {
let result = yield LanguageDetector.detectLanguage(pair[2]);
do_check_eq(result.language, pair[0]);
do_check_eq(result.confident, !pair[3]);
function check_result(result, langCode, expected) {
equal(result.language, langCode, "Expected language code");
// Round percentage up to the nearest 5%, since most strings are
// 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
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);
return tabbrowser.getFindBar(tab);
} catch (e) {
try {
// FF22 has no _getTabForBrowser, and FF24 has no getFindBar
var chromeWindow = browser.ownerDocument.defaultView;
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.
var findBar = getFindBar(this.domWindow);
return findBar && ('updateControlState' in findBar);
return !!findBar && ('updateControlState' in findBar);
},
supportsDocumentFonts: function() {
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';
var pdfjsVersion = '1.4.64';
var pdfjsBuild = '2f145d8';
var pdfjsVersion = '1.4.83';
var pdfjsBuild = '0629fd0';
var pdfjsFilePath =
typeof document !== 'undefined' && document.currentScript ?
@ -1629,7 +1629,7 @@ AnnotationElementFactory.prototype =
return new StrikeOutAnnotationElement(parameters);
default:
throw new Error('Unimplemented annotation type "' + subtype + '"');
return new AnnotationElement(parameters);
}
}
};
@ -1639,15 +1639,18 @@ AnnotationElementFactory.prototype =
* @alias AnnotationElement
*/
var AnnotationElement = (function AnnotationElementClosure() {
function AnnotationElement(parameters) {
function AnnotationElement(parameters, isRenderable) {
this.isRenderable = isRenderable || false;
this.data = parameters.data;
this.layer = parameters.layer;
this.page = parameters.page;
this.viewport = parameters.viewport;
this.linkService = parameters.linkService;
if (isRenderable) {
this.container = this._createContainer();
}
}
AnnotationElement.prototype = /** @lends AnnotationElement.prototype */ {
/**
@ -1761,7 +1764,7 @@ var AnnotationElement = (function AnnotationElementClosure() {
*/
var LinkAnnotationElement = (function LinkAnnotationElementClosure() {
function LinkAnnotationElement(parameters) {
AnnotationElement.call(this, parameters);
AnnotationElement.call(this, parameters, true);
}
Util.inherit(LinkAnnotationElement, AnnotationElement, {
@ -1843,7 +1846,9 @@ var LinkAnnotationElement = (function LinkAnnotationElementClosure() {
*/
var TextAnnotationElement = (function TextAnnotationElementClosure() {
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, {
@ -1897,7 +1902,9 @@ var TextAnnotationElement = (function TextAnnotationElementClosure() {
*/
var WidgetAnnotationElement = (function WidgetAnnotationElementClosure() {
function WidgetAnnotationElement(parameters) {
AnnotationElement.call(this, parameters);
var isRenderable = !parameters.data.hasAppearance &&
!!parameters.data.fieldValue;
AnnotationElement.call(this, parameters, isRenderable);
}
Util.inherit(WidgetAnnotationElement, AnnotationElement, {
@ -1964,7 +1971,8 @@ var WidgetAnnotationElement = (function WidgetAnnotationElementClosure() {
*/
var PopupAnnotationElement = (function PopupAnnotationElementClosure() {
function PopupAnnotationElement(parameters) {
AnnotationElement.call(this, parameters);
var isRenderable = !!(parameters.data.title || parameters.data.contents);
AnnotationElement.call(this, parameters, isRenderable);
}
Util.inherit(PopupAnnotationElement, AnnotationElement, {
@ -2154,7 +2162,7 @@ var PopupElement = (function PopupElementClosure() {
var HighlightAnnotationElement = (
function HighlightAnnotationElementClosure() {
function HighlightAnnotationElement(parameters) {
AnnotationElement.call(this, parameters);
AnnotationElement.call(this, parameters, true);
}
Util.inherit(HighlightAnnotationElement, AnnotationElement, {
@ -2181,7 +2189,7 @@ var HighlightAnnotationElement = (
var UnderlineAnnotationElement = (
function UnderlineAnnotationElementClosure() {
function UnderlineAnnotationElement(parameters) {
AnnotationElement.call(this, parameters);
AnnotationElement.call(this, parameters, true);
}
Util.inherit(UnderlineAnnotationElement, AnnotationElement, {
@ -2207,7 +2215,7 @@ var UnderlineAnnotationElement = (
*/
var SquigglyAnnotationElement = (function SquigglyAnnotationElementClosure() {
function SquigglyAnnotationElement(parameters) {
AnnotationElement.call(this, parameters);
AnnotationElement.call(this, parameters, true);
}
Util.inherit(SquigglyAnnotationElement, AnnotationElement, {
@ -2234,7 +2242,7 @@ var SquigglyAnnotationElement = (function SquigglyAnnotationElementClosure() {
var StrikeOutAnnotationElement = (
function StrikeOutAnnotationElementClosure() {
function StrikeOutAnnotationElement(parameters) {
AnnotationElement.call(this, parameters);
AnnotationElement.call(this, parameters, true);
}
Util.inherit(StrikeOutAnnotationElement, AnnotationElement, {
@ -2281,7 +2289,7 @@ var AnnotationLayer = (function AnnotationLayerClosure() {
for (var i = 0, ii = parameters.annotations.length; i < ii; i++) {
var data = parameters.annotations[i];
if (!data || !data.hasHtml) {
if (!data) {
continue;
}
@ -2293,8 +2301,10 @@ var AnnotationLayer = (function AnnotationLayerClosure() {
linkService: parameters.linkService
};
var element = annotationElementFactory.create(properties);
if (element.isRenderable) {
parameters.div.appendChild(element.render());
}
}
},
/**
@ -6565,7 +6575,7 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
* title: string,
* bold: boolean,
* italic: boolean,
* color: rgb array,
* color: rgb Uint8Array,
* dest: dest obj,
* url: string,
* 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>
<!-- 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="../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 class="row">
<!-- 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 class="buttonRow">
<button id="passwordCancel" class="overlayButton"><span data-l10n-id="password_cancel">Cancel</span></button>

Просмотреть файл

@ -34,6 +34,7 @@ RequestExecutionLevel user
Var TmpVal
Var InstallType
Var AddStartMenuSC
Var AddTaskbarSC
Var AddQuickLaunchSC
Var AddDesktopSC
Var InstallMaintenanceService
@ -395,10 +396,12 @@ Section "-Application" APP_IDX
; If we are writing to HKLM and create either the desktop or start menu
; shortcuts set IconsVisible to 1 otherwise to 0.
; Taskbar shortcuts imply having a start menu shortcut.
${StrFilter} "${FileMainEXE}" "+" "" "" $R9
StrCpy $0 "Software\Clients\StartMenuInternet\$R9\InstallInfo"
${If} $AddDesktopSC == 1
${OrIf} $AddStartMenuSC == 1
${OrIf} $AddTaskbarSC == 1
WriteRegDWORD HKLM "$0" "IconsVisible" 1
${Else}
WriteRegDWORD HKLM "$0" "IconsVisible" 0
@ -412,10 +415,12 @@ Section "-Application" APP_IDX
; If we create either the desktop or start menu shortcuts, then
; set IconsVisible to 1 otherwise to 0.
; Taskbar shortcuts imply having a start menu shortcut.
${StrFilter} "${FileMainEXE}" "+" "" "" $R9
StrCpy $0 "Software\Clients\StartMenuInternet\$R9\InstallInfo"
${If} $AddDesktopSC == 1
${OrIf} $AddStartMenuSC == 1
${OrIf} $AddTaskbarSC == 1
WriteRegDWORD HKCU "$0" "IconsVisible" 1
${Else}
WriteRegDWORD HKCU "$0" "IconsVisible" 0
@ -601,12 +606,10 @@ Section "-InstallEndCleanup"
UAC::ExecCodeSegment $0
${EndIf}
${EndIf}
; Adds a pinned Task Bar shortcut (see MigrateTaskBarShortcut for details).
${MigrateTaskBarShortcut}
${EndUnless}
${GetShortcutsLogPath} $0
WriteIniStr "$0" "TASKBAR" "Migrated" "true"
; Adds a pinned Task Bar shortcut (see MigrateTaskBarShortcut for details).
${MigrateTaskBarShortcut}
; Add the Firewall entries during install
Call AddFirewallEntries

Просмотреть файл

@ -1130,6 +1130,10 @@ ${EndIf}
ClearErrors
WriteIniStr "$0" "TASKBAR" "Migrated" "true"
${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
${If} ${AtMostWin2008R2}
; Check if the Firefox is the http handler for this user
@ -1143,6 +1147,9 @@ ${EndIf}
${OrIf} ${AtLeastWin8}
${PinToTaskBar}
${EndIf}
${ElseIf} $AddTaskbarSC == "1"
${PinToTaskBar}
${EndIf}
${EndIf}
${EndIf}
${EndIf}
@ -1486,7 +1493,7 @@ Function SetAsDefaultAppUserHKCU
${EndUnless}
${EndIf}
${RemoveDeprecatedKeys}
${PinToTaskBar}
${MigrateTaskBarShortcut}
FunctionEnd
; Helper for updating the shortcut application model IDs.

Просмотреть файл

@ -1564,6 +1564,14 @@ Function OnDownload
WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "InstallDirectoryPath" "$INSTDIR"
; Don't create the QuickLaunch or Taskbar shortcut from the launched installer
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
WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "DesktopShortcut" "true"
${Else}
@ -1586,14 +1594,10 @@ Function OnDownload
WriteINIStr "$PLUGINSDIR\${CONFIG_INI}" "Install" "MaintenanceService" "false"
!endif
; Write migrated to the shortcuts.ini file to prevent the installer
; from creating a taskbar shortcut (Bug 791613).
; Delete the taskbar shortcut history to ensure we do the right thing based on
; the config file above.
${GetShortcutsLogPath} $0
Delete "$0"
; Workaround to prevent pinning to the taskbar.
${If} $CheckboxShortcutOnBar == 0
WriteIniStr "$0" "TASKBAR" "Migrated" "true"
${EndIf}
GetFunctionAddress $0 RemoveFileProgressCallback
${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.viewmore.text "View More">
<!ENTITY customizeMode.tabTitle "Customize &brandShortName;">
<!ENTITY customizeMode.menuAndToolbars.header2 "Additional Tools and Features">
<!ENTITY customizeMode.menuAndToolbars.empty "Want more tools?">
<!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.learnMore = Learn more
# LOCALIZATION NOTE (customizeMode.tabTitle): %S is brandShortName
customizeMode.tabTitle = Customize %S
# LOCALIZATION NOTE(appmenu.*.description, appmenu.*.label): these are used 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.

Просмотреть файл

@ -171,6 +171,9 @@ featureEnableRequiresRestart=%S must restart to enable this feature.
featureDisableRequiresRestart=%S must restart to disable this feature.
shouldRestartTitle=Restart %S
restartNow=Restart Now
restartLater=Restart Later
#### e10S
# LOCALIZATION NOTE (e10sFeedbackAfterRestart): This message appears when the user
# 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',
'ContentSearch.jsm',
'ContentWebRTC.jsm',
'CustomizationTabPreloader.jsm',
'DirectoryLinksProvider.jsm',
'E10SUtils.jsm',
'Feeds.jsm',

Просмотреть файл

@ -75,7 +75,7 @@
--chrome-secondary-background-color: #f5f6f7;
--chrome-navigator-toolbox-separator-color: #cccccc;
--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-bar-controls-border-color: #ccc;
--chrome-selection-color: #f5f7fa;
@ -85,9 +85,7 @@
--tab-hover-background-color: #D7D8DA;
--tab-selection-color: #f5f7fa;
--tab-selection-background-color: #4c9ed9;
--tab-selection-box-shadow: 0 2px 0 #9FDFFF inset,
0 -2px 0 rgba(0,0,0,.05) inset,
0 -1px 0 rgba(0,0,0,.2) inset;
--tab-selection-box-shadow: none;
--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
// (Must happen after generateMouseClickInTab() call)
let consoleLostFocus = false;
jsterm.inputNode.focus();
jsterm.focus();
jsterm.inputNode.addEventListener('blur', () => {consoleLostFocus = true;});
is(gThreadClient.paused, true,

Просмотреть файл

@ -1049,7 +1049,7 @@ InspectorPanel.prototype = {
let jsterm = panel.hud.jsterm;
jsterm.execute("inspect($0)");
jsterm.inputNode.focus();
jsterm.focus();
});
},

Просмотреть файл

@ -27,7 +27,7 @@
max-width: 150px;
}
.inspector-tabpanel {
.inspector-tabpanel > * {
/*
* 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_09.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_01.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 LIGHT_BG = "#fcfcfc";
const LIGHT_BG = "white";
const DARK_BG = "#14171a";
setTheme("dark");

Просмотреть файл

@ -19,7 +19,7 @@
%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"/>

Просмотреть файл

@ -13,7 +13,8 @@ support-files =
skip-if = true # Bug 1173950
[browser_projecteditor_delete_file.js]
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_editors_image.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;
}
/**
* 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) {
let def = promise.defer();
projecteditor.once("onEditorCreated", (editor) => {
@ -316,6 +356,15 @@ function onceEditorSave(projecteditor) {
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) {
let defer = promise.defer();
menu.addEventListener("popupshown", function onpopupshown() {
@ -333,3 +382,11 @@ function onPopupHidden(menu) {
});
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
and commandlinetooltip.xhtml). */
:root[devtoolstheme="light"] {
--gcli-background-color: #ebeced; /* --theme-tab-toolbar-background */
--gcli-input-focused-background: #f7f7f7; /* --theme-sidebar-background */
--gcli-input-color: #18191a; /* --theme-body-color */
--gcli-border-color: #aaaaaa; /* --theme-splitter-color */
--gcli-background-color: #fcfcfc; /* --theme-tab-toolbar-background */
--gcli-input-focused-background: #ffffff; /* --theme-sidebar-background */
--gcli-input-color: #393f4c; /* --theme-body-color */
--gcli-border-color: #dde1e4; /* --theme-splitter-color */
}
:root[devtoolstheme="dark"] {

Просмотреть файл

@ -10,11 +10,11 @@
We are copy/pasting variables from light-theme and dark-theme,
since they aren't loaded in this context (within browser.css). */
:root[devtoolstheme="light"] #developer-toolbar {
--gcli-background-color: #ebeced; /* --theme-tab-toolbar-background */
--gcli-input-background: #f0f1f2; /* --theme-toolbar-background */
--gcli-input-focused-background: #f7f7f7; /* --theme-sidebar-background */
--gcli-input-color: #18191a; /* --theme-body-color */
--gcli-border-color: #aaaaaa; /* --theme-splitter-color */
--gcli-background-color: #fcfcfc; /* --theme-tab-toolbar-background */
--gcli-input-background: #fcfcfc; /* --theme-toolbar-background */
--gcli-input-focused-background: #ffffff; /* --theme-sidebar-background */
--gcli-input-color: #393f4c; /* --theme-body-color */
--gcli-border-color: #dde1e4; /* --theme-splitter-color */
--selection-background: #4c9ed9; /* --theme-selection-background */
--selection-color: #f5f7fa; /* --theme-selection-color */
}

Просмотреть файл

@ -68,13 +68,13 @@ body {
}
.theme-gutter {
background-color: #0f171f;
background-color: var(--theme-tab-toolbar-background);
color: var(--theme-content-color3);
border-color: #303b47;
border-color: var(--theme-splitter-color);
}
.theme-separator { /* grey */
border-color: #303b47;
.theme-separator {
border-color: var(--theme-splitter-color);
}
.theme-fg-color1,

Просмотреть файл

@ -2,6 +2,6 @@
- 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/. -->
<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="#ababab" d="M7,0 6,0 0,6 6,12 7,12 7,11.6 1.5,6 7,.4z"/>
<path fill="#ffffff" d="M7,11.6 7,.4 1.5,6z"/>
<path fill="#dde1e4" d="M7,0 6,0 0,6 6,12 7,12 7,11.6 1.5,6 7,.4z"/>
</svg>

До

Ширина:  |  Высота:  |  Размер: 421 B

После

Ширина:  |  Высота:  |  Размер: 421 B

Просмотреть файл

@ -2,6 +2,6 @@
- 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/. -->
<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="#ababab" d="M1,0 0,0 0,.4 5.5,6 0,11.6 0,12 1,12 7,6z"/>
<path fill="#ffffff" d="M0,11.6 0,.4 5.5,6z"/>
<path fill="#dde1e4" d="M1,0 0,0 0,.4 5.5,6 0,11.6 0,12 1,12 7,6z"/>
</svg>

До

Ширина:  |  Высота:  |  Размер: 421 B

После

Ширина:  |  Высота:  |  Размер: 421 B

Просмотреть файл

@ -67,9 +67,9 @@ body {
}
.theme-gutter {
background-color: hsl(0,0%,90%);
background-color: var(--theme-tab-toolbar-background);
color: var(--theme-content-color3);
border-color: hsl(0,0%,65%);
border-color: var(--theme-splitter-color);
}
.theme-separator { /* grey */
@ -173,7 +173,7 @@ body {
.devtools-sidebar-tabs tabs,
.devtools-sidebar-alltabs,
.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);
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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
:root {
color: #18191a;
}
.view-project-detail {
overflow: auto;
}

Просмотреть файл

@ -3,12 +3,21 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* 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 {
-moz-appearance: none;
background-image: none;
background-color: transparent;
border: 0;
border-bottom: 1px solid rgba(118, 121, 125, .5);
border-bottom: 1px solid var(--devtools-splitter-color);
min-height: 3px;
height: 3px;
margin-top: -3px;
@ -20,7 +29,7 @@
background-image: none;
background-color: transparent;
border: 0;
-moz-border-end: 1px solid rgba(118, 121, 125, .5);
-moz-border-end: 1px solid var(--devtools-splitter-color);
min-width: 3px;
width: 3px;
-moz-margin-start: -3px;

Просмотреть файл

@ -818,10 +818,6 @@
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 {
box-shadow: 0 -2px 0 rgba(0,0,0,.1) inset;
}
@ -920,12 +916,6 @@
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[highlighted] {
border-width: 0;

Просмотреть файл

@ -15,19 +15,19 @@
*/
:root.theme-light {
--theme-body-background: #fcfcfc;
--theme-sidebar-background: #f7f7f7;
--theme-body-background: white;
--theme-sidebar-background: white;
--theme-contrast-background: #e6b064;
--theme-tab-toolbar-background: #ebeced;
--theme-toolbar-background: #f0f1f2;
--theme-tab-toolbar-background: #fcfcfc;
--theme-toolbar-background: #fcfcfc;
--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-splitter-color: #aaaaaa;
--theme-comment: #757873;
--theme-splitter-color: #dde1e4;
--theme-comment: #696969;
--theme-body-color: #18191a;
--theme-body-color: #393f4c;
--theme-body-color-alt: #585959;
--theme-content-color1: #292e33;
--theme-content-color2: #8fa1b2;

Просмотреть файл

@ -6,14 +6,12 @@
.theme-dark {
--table-splitter-color: rgba(255,255,255,0.15);
--table-zebra-background: rgba(255,255,255,0.05);
--smw-margin: #000;
--smw-item-top-border: rgba(0,0,0,0.2);
--smw-item-bottom-border: rgba(128,128,128,0.15);
}
.theme-light {
--table-splitter-color: rgba(0,0,0,0.15);
--table-zebra-background: rgba(0,0,0,0.05);
--smw-margin: #aaa;
--smw-item-top-border: rgba(128,128,128,0.15);
--smw-item-bottom-border: transparent;
}
@ -357,12 +355,12 @@
.side-menu-widget-container:-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-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 {

Просмотреть файл

@ -106,8 +106,7 @@ function* populateInputHistory(hud) {
*/
function* testNaviatingHistoryInUI(hud) {
let jsterm = hud.jsterm;
let {inputNode} = jsterm;
inputNode.focus();
jsterm.focus();
// Count backwards from original input and make sure that pressing up
// restores this.

Просмотреть файл

@ -21,8 +21,6 @@ add_task(function* () {
function testClosingAfterCompletion(hud, browser) {
let deferred = promise.defer();
let inputNode = hud.jsterm.inputNode;
let errorWhileClosing = false;
function errorListener() {
errorWhileClosing = true;
@ -30,8 +28,8 @@ function testClosingAfterCompletion(hud, browser) {
browser.addEventListener("error", errorListener, false);
// Focus the inputNode and perform the keycombo to close the WebConsole.
inputNode.focus();
// Focus the jsterm and perform the keycombo to close the WebConsole.
hud.jsterm.focus();
gDevTools.once("toolbox-destroyed", function() {
browser.removeEventListener("error", errorListener, false);

Просмотреть файл

@ -25,7 +25,7 @@ function setup(HUD) {
jsterm = HUD.jsterm;
inputNode = jsterm.inputNode;
inputNode.focus();
jsterm.focus();
ok(!jsterm.getInputValue(), "jsterm.getInputValue() is empty");

Просмотреть файл

@ -30,7 +30,7 @@ function test() {
yield executeJS();
yield clickMessageAndShowVariablesView();
jsterm.inputNode.focus();
jsterm.focus();
yield testHideVariablesViewAfterEscape();
@ -144,7 +144,7 @@ function test() {
deferred.resolve();
}, false);
jsterm.inputNode.focus();
jsterm.focus();
jsterm.setInputValue("document.location.");
EventUtils.sendKey("TAB", hud.iframeWindow);

Просмотреть файл

@ -577,7 +577,7 @@ WebConsoleFrame.prototype = {
this._addFocusCallback(this.outputNode, (evt) => {
if ((evt.target.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
this.jsterm.inputNode.focus();
this.jsterm.focus();
},
/**
@ -607,7 +607,7 @@ WebConsoleFrame.prototype = {
* @private
*/
_onPanelSelected: function() {
this.jsterm.inputNode.focus();
this.jsterm.focus();
},
/**
@ -3090,9 +3090,8 @@ JSTerm.prototype = {
},
focus: function() {
let inputNode = this.inputNode;
if (!inputNode.getAttribute("focused")) {
inputNode.focus();
if (!this.inputNode.getAttribute("focused")) {
this.inputNode.focus();
}
},
@ -3461,7 +3460,7 @@ JSTerm.prototype = {
}
this._sidebarDestroy();
this.inputNode.focus();
this.focus();
event.stopPropagation();
},
@ -3854,7 +3853,7 @@ JSTerm.prototype = {
// Ctrl-N is also used to focus the Network category button on
// MacOSX. The preventDefault() call doesn't prevent the focus
// from moving away from the input.
inputNode.focus();
this.focus();
}
this.clearCompletion();
break;
@ -3870,7 +3869,7 @@ JSTerm.prototype = {
// Ctrl-P may also be used to focus some category button on MacOSX.
// The preventDefault() call doesn't prevent the focus from moving
// away from the input.
inputNode.focus();
this.focus();
}
this.clearCompletion();
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*
nsIDocument::Children()
{

Просмотреть файл

@ -2601,6 +2601,8 @@ public:
void ObsoleteSheet(const nsAString& aSheetURI, mozilla::ErrorResult& rv);
already_AddRefed<nsIURI> GetMozDocumentURIIfNotForErrorPages();
// ParentNode
nsIHTMLCollection* Children();
uint32_t ChildElementCount();

Просмотреть файл

@ -6,7 +6,7 @@ support-files =
plugin_no_scroll_div.html
[browser_bug1163570.js]
skip-if = (!e10s || os != "win")
skip-if = true # Bug 1249878
[browser_bug1196539.js]
skip-if = (!e10s || os != "win")
[browser_tabswitchbetweenplugins.js]

Просмотреть файл

@ -39,20 +39,18 @@ function promiseWaitForEvent(object, eventName, capturing = false, chrome = fals
add_task(function* () {
registerCleanupFunction(function () {
Services.prefs.clearUserPref("browser.uiCustomization.disableAnimation");
window.focus();
});
});
add_task(function* () {
Services.prefs.setBoolPref("browser.uiCustomization.disableAnimation", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED, "Test Plug-in");
let pluginTab = gBrowser.selectedTab = gBrowser.addTab();
let customizeTab = gBrowser.addTab();
let prefTab = gBrowser.addTab();
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 doc = content.document;
@ -62,10 +60,8 @@ add_task(function* () {
is(result, true, "plugin is loaded");
let cpromise = promiseWaitForEvent(window.gNavToolbox, "customizationready");
let ppromise = promiseWaitForEvent(window, "MozAfterPaint");
gBrowser.selectedTab = customizeTab;
yield cpromise;
gBrowser.selectedTab = prefTab;
yield ppromise;
// 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.childNodes[0].label); // test harness 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++) {
cpromise = promiseWaitForEvent(window.gNavToolbox, "aftercustomization");
ppromise = promiseWaitForEvent(window, "MozAfterPaint");
EventUtils.synthesizeMouseAtCenter(tabStripContainer.childNodes[1], {}, window);
yield cpromise;
yield ppromise;
result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
@ -94,10 +88,8 @@ add_task(function* () {
is(result, true, "plugin is visible");
cpromise = promiseWaitForEvent(window.gNavToolbox, "customizationready");
ppromise = promiseWaitForEvent(window, "MozAfterPaint");
EventUtils.synthesizeMouseAtCenter(tabStripContainer.childNodes[2], {}, window);
yield cpromise;
yield ppromise;
result = yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
@ -108,11 +100,6 @@ add_task(function* () {
is(result, false, "plugin is hidden");
}
// wait for customize view to shutdown cleanly otherwise we get
// a ton of error spew on shutdown.
cpromise = promiseWaitForEvent(window.gNavToolbox, "aftercustomization");
gBrowser.removeTab(customizeTab);
yield cpromise;
gBrowser.removeTab(prefTab);
gBrowser.removeTab(pluginTab);
});

Просмотреть файл

@ -373,6 +373,10 @@ partial interface Document {
[ChromeOnly] readonly attribute DOMString contentLanguage;
[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

Просмотреть файл

@ -228,7 +228,7 @@ nsTextBoxFrame::UpdateAttributes(nsIAtom* aAttribute,
if (aAttribute == nullptr || aAttribute == nsGkAtoms::crop) {
static nsIContent::AttrValuesArray strings[] =
{&nsGkAtoms::left, &nsGkAtoms::start, &nsGkAtoms::center,
&nsGkAtoms::right, &nsGkAtoms::end, nullptr};
&nsGkAtoms::right, &nsGkAtoms::end, &nsGkAtoms::none, nullptr};
CroppingStyle cropType;
switch (mContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::crop,
strings, eCaseMatters)) {
@ -243,9 +243,12 @@ nsTextBoxFrame::UpdateAttributes(nsIAtom* aAttribute,
case 4:
cropType = CropRight;
break;
default:
case 5:
cropType = CropNone;
break;
default:
cropType = CropAuto;
break;
}
if (cropType != mCropType) {
@ -647,6 +650,7 @@ nsTextBoxFrame::CalculateTitleForWidth(nsRenderingContext& aRenderingContext,
}
const nsDependentString& kEllipsis = nsContentUtils::GetLocalizedEllipsis();
if (mCropType != CropNone) {
// start with an ellipsis
mCroppedTitle.Assign(kEllipsis);
@ -666,12 +670,17 @@ nsTextBoxFrame::CalculateTitleForWidth(nsRenderingContext& aRenderingContext,
return titleWidth;
aWidth -= titleWidth;
} else {
mCroppedTitle.Truncate(0);
titleWidth = 0;
}
// XXX: This whole block should probably take surrogates into account
// XXX and clusters!
// ok crop things
switch (mCropType)
{
case CropAuto:
case CropNone:
case CropRight:
{
@ -1126,7 +1135,7 @@ nsTextBoxFrame::GetMinSize(nsBoxLayoutState& aBoxLayoutState)
DISPLAY_MIN_SIZE(this, size);
// if there is cropping our min width becomes our border and padding
if (mCropType != CropNone) {
if (mCropType != CropNone && mCropType != CropAuto) {
if (GetWritingMode().IsVertical()) {
size.height = 0;
} else {

Просмотреть файл

@ -26,7 +26,7 @@ public:
NS_IMETHOD DoLayout(nsBoxLayoutState& aBoxLayoutState) 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);

Просмотреть файл

@ -424,7 +424,7 @@ public class BrowserApp extends GeckoApp
}
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) {
@ -456,7 +456,7 @@ public class BrowserApp extends GeckoApp
public void onRemovedFromReadingList(String url) {
SnackbarHelper.showSnackbar(this,
getResources().getString(R.string.reading_list_removed),
Snackbar.LENGTH_SHORT);
Snackbar.LENGTH_LONG);
}
@Override
@ -2016,7 +2016,7 @@ public class BrowserApp extends GeckoApp
if (Tabs.getInstance().getDisplayCount() == 0)
return;
hideFirstrunPager(TelemetryContract.Method.TABSTRAY);
hideFirstrunPager(TelemetryContract.Method.BUTTON);
if (ensureTabsPanelExists()) {
// 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) {
SnackbarHelper.showSnackbar((Activity) context,
context.getString(R.string.bookmark_updated),
Snackbar.LENGTH_SHORT);
Snackbar.LENGTH_LONG);
}
}).execute();
}

Просмотреть файл

@ -576,7 +576,7 @@ public abstract class GeckoApp
ThreadUtils.postToUiThread(new Runnable() {
@Override
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);
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;
}
String path = Media.insertImage(getContentResolver(),image, null, 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;
}
final Intent intent = new Intent(Intent.ACTION_ATTACH_DATA);
@ -1036,7 +1036,7 @@ public abstract class GeckoApp
};
ActivityHandlerHelper.startIntentForActivity(this, chooser, handler);
} 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) {
Log.e(LOGTAG, "Out of Memory when converting to byte array", ome);

Просмотреть файл

@ -2670,7 +2670,7 @@ public class GeckoAppShell
private static final void showImageShareFailureSnackbar() {
SnackbarHelper.showSnackbar((Activity) getContext(),
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.HashMap;
import java.util.Hashtable;
import java.util.UUID;
import java.util.regex.Matcher;
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.
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.
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 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
* 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
* this code to fail.
*
* TODO: Write tests to prevent regressions. Mention them here. Test both file location and file format.
* this code to fail. There are tests in TestGeckoProfile to verify the file format but be
* warned: THIS IS NOT FOOLPROOF.
*
* [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
public String getClientId() throws IOException {
final JSONObject obj = readJSONObjectFromFile(CLIENT_ID_FILE_PATH);
try {
return obj.getString(CLIENT_ID_JSON_ATTR);
} catch (final JSONException e) {
// Don't log to avoid leaking data in JSONObject.
throw new IOException("Client ID does not exist in JSONObject");
return getValidClientIdFromDisk(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 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;
}
/**
* 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) {
File file = new File(getDir(), filename);
BufferedWriter bufferedWriter = null;

Просмотреть файл

@ -188,8 +188,8 @@ public interface TelemetryContract {
// Action triggered from a suggestion provided to the user.
SUGGESTION("suggestion"),
// Action triggered from the Tabs tray.
TABSTRAY("tabstray"),
// Action triggered from an OS system action.
SYSTEM("system"),
// Action triggered from a SuperToast.
// 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) {
SnackbarHelper.showSnackbar((Activity) mContext,
mContext.getString(R.string.page_removed),
Snackbar.LENGTH_SHORT);
Snackbar.LENGTH_LONG);
}
}
}

Просмотреть файл

@ -655,7 +655,7 @@ OnSharedPreferenceChangeListener
SnackbarHelper.showSnackbar(GeckoPreferences.this,
getString(stringRes),
Snackbar.LENGTH_SHORT);
Snackbar.LENGTH_LONG);
}
} catch (Exception e) {
Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);

Просмотреть файл

@ -94,7 +94,7 @@ public class SearchEnginePreference extends CustomListPreference {
SnackbarHelper.showSnackbar(activity,
activity.getString(R.string.pref_search_last_toast),
Snackbar.LENGTH_SHORT);
Snackbar.LENGTH_LONG);
return;
}

Просмотреть файл

@ -172,8 +172,7 @@ public class TelemetryUploadService extends BackgroundService {
try {
clientId = profile.getClientId();
} 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.");
Log.w(LOGTAG, "Unable to get client ID to generate core ping: returning.", e);
return;
}

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 46 KiB

После

Ширина:  |  Высота:  |  Размер: 18 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 38 KiB

После

Ширина:  |  Высота:  |  Размер: 16 KiB

Просмотреть файл

@ -348,7 +348,7 @@ var ActionBarHandler = {
clipboard.copyString(selectedText);
let msg = Strings.browser.GetStringFromName("selectionHelper.textCopied");
Snackbars.show(msg, Snackbars.LENGTH_SHORT);
Snackbars.show(msg, Snackbars.LENGTH_LONG);
// Then cut the selection text.
ActionBarHandler._getSelection(element, win).deleteFromDocument();
@ -383,7 +383,7 @@ var ActionBarHandler = {
clipboard.copyString(selectedText);
let msg = Strings.browser.GetStringFromName("selectionHelper.textCopied");
Snackbars.show(msg, Snackbars.LENGTH_SHORT);
Snackbars.show(msg, Snackbars.LENGTH_LONG);
ActionBarHandler._uninit();
UITelemetry.addEvent("action.1", "actionbar", null, "copy");

Просмотреть файл

@ -63,7 +63,7 @@ var MasterPassword = {
} catch(e) {
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;
}
};

Просмотреть файл

@ -180,7 +180,7 @@ var Reader = {
case "Reader:ToolbarHidden":
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);
this._hasUsedToolbar = true;
}

Просмотреть файл

@ -1090,7 +1090,7 @@ var SelectionHandler = {
if (selectedText.length) {
let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper);
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();
},

Просмотреть файл

@ -31,10 +31,10 @@ function copyStringShowSnackbar(string, notifyString) {
try {
let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper);
clipboard.copyString(string);
Snackbars.show(notifyString, Snackbars.LENGTH_SHORT);
Snackbars.show(notifyString, Snackbars.LENGTH_LONG);
} catch (e) {
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) &&
(newPassword === origPassword) &&
(newDomain === origDomain) ) {
Snackbars.show(gStringBundle.GetStringFromName("editLogin.saved1"), Snackbars.LENGTH_SHORT);
Snackbars.show(gStringBundle.GetStringFromName("editLogin.saved1"), Snackbars.LENGTH_LONG);
this._showList();
return;
}
@ -310,10 +310,10 @@ var Logins = {
}
}
} catch (e) {
Snackbars.show(gStringBundle.GetStringFromName("editLogin.couldNotSave"), Snackbars.LENGTH_SHORT);
Snackbars.show(gStringBundle.GetStringFromName("editLogin.couldNotSave"), Snackbars.LENGTH_LONG);
return;
}
Snackbars.show(gStringBundle.GetStringFromName("editLogin.saved1"), Snackbars.LENGTH_SHORT);
Snackbars.show(gStringBundle.GetStringFromName("editLogin.saved1"), Snackbars.LENGTH_LONG);
this._showList();
},

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше