merge autoland to mozilla-inbound. r=merge a=merge

MozReview-Commit-ID: 1gVeCMsyp4B
This commit is contained in:
Sebastian Hengst 2017-09-14 23:56:36 +02:00
Родитель 2c9a5993ac d249202ee5
Коммит dfb0dfbb5e
305 изменённых файлов: 9205 добавлений и 2641 удалений

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

@ -501,6 +501,9 @@ pref("browser.bookmarks.max_backups", 15);
pref("browser.bookmarks.showRecentlyBookmarked", true);
// Whether menu should close after Ctrl-click, middle-click, etc.
pref("browser.bookmarks.openInTabClosesMenu", true);
// Scripts & Windows prefs
pref("dom.disable_open_during_load", true);
pref("javascript.options.showInConsole", true);
@ -722,15 +725,9 @@ pref("browser.preferences.instantApply", true);
// Toggling Search bar on and off in about:preferences
pref("browser.preferences.search", true);
// Once the Storage Management is completed.
// (The Storage Management-related prefs are browser.storageManager.* )
// The Offline(Appcache) Group section in about:preferences will be hidden.
// And the task to clear appcache will be done by Storage Management.
#if defined(NIGHTLY_BUILD)
// We prefer the storage manager (see browser.storageManager.enabled)
// over the old offlineGroup UI. Removing the offline group UI is bug 1399808.
pref("browser.preferences.offlineGroup.enabled", false);
#else
pref("browser.preferences.offlineGroup.enabled", true);
#endif
pref("browser.preferences.defaultPerformanceSettings.enabled", true);
@ -1692,10 +1689,13 @@ pref("browser.crashReports.unsubmittedCheck.chancesUntilSuppress", 4);
pref("browser.crashReports.unsubmittedCheck.autoSubmit", false);
// Preferences for the form autofill system extension
// The value of "extensions.formautofill.available" can be "on", "off" and "detect".
// The "detect" means it's enabled if conditions defined in the extension are met.
// The truthy values of "extensions.formautofill.available" are "on" and "detect",
// any other value means autofill isn't available.
// "detect" means it's enabled if conditions defined in the extension are met.
#ifdef NIGHTLY_BUILD
pref("extensions.formautofill.available", "on");
#elif MOZ_UPDATE_CHANNEL == release
pref("extensions.formautofill.available", "staged-rollout");
#else
pref("extensions.formautofill.available", "detect");
#endif

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

@ -385,6 +385,7 @@
#endif
context="placesContext"
openInTabs="children"
onmouseup="BookmarksEventHandler.onMouseUp(event);"
oncommand="BookmarksEventHandler.onCommand(event);"
onclick="BookmarksEventHandler.onClick(event, this.parentNode._placesView);"
onpopupshowing="BookmarkingUI.onMainMenuPopupShowing(event);

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

@ -893,6 +893,22 @@ var BookmarksEventHandler = {
* @param aView
* The places view which aEvent should be associated with.
*/
onMouseUp(aEvent) {
// Handles left-click with modifier if not browser.bookmarks.openInTabClosesMenu.
if (aEvent.button != 0 || PlacesUIUtils.openInTabClosesMenu)
return;
let target = aEvent.originalTarget;
if (target.tagName != "menuitem")
return;
let modifKey = AppConstants.platform === "macosx" ? aEvent.metaKey
: aEvent.ctrlKey;
// Don't keep menu open for 'Open all in Tabs'.
if (modifKey && !target.classList.contains("openintabs-menuitem")) {
target.setAttribute("closemenu", "none");
}
},
onClick: function BEH_onClick(aEvent, aView) {
// Only handle middle-click or left-click with modifiers.
let modifKey;
@ -906,17 +922,22 @@ var BookmarksEventHandler = {
return;
var target = aEvent.originalTarget;
// If this event bubbled up from a menu or menuitem, close the menus.
// Do this before opening tabs, to avoid hiding the open tabs confirm-dialog.
if (target.localName == "menu" || target.localName == "menuitem") {
for (let node = target.parentNode; node; node = node.parentNode) {
if (node.localName == "menupopup")
node.hidePopup();
else if (node.localName != "menu" &&
node.localName != "hbox" &&
node.localName != "vbox" )
break;
}
// If this event bubbled up from a menu or menuitem,
// close the menus if browser.bookmarks.openInTabClosesMenu.
if ((PlacesUIUtils.openInTabClosesMenu && target.tagName == "menuitem") ||
target.tagName == "menu" ||
target.classList.contains("openintabs-menuitem")) {
closeMenus(aEvent.target);
}
// Command already precesssed so remove any closemenu attr set in onMouseUp.
if (aEvent.button == 0 &&
target.tagName == "menuitem" &&
target.getAttribute("closemenu") == "none") {
// On Mac we need to extend when we remove the flag, to avoid any pre-close
// animations.
setTimeout(() => {
target.removeAttribute("closemenu");
}, 500);
}
if (target._placesNode && PlacesUtils.nodeIsContainer(target._placesNode)) {
@ -1520,6 +1541,7 @@ var LibraryUI = {
libraryButton.getAttribute("cui-areatype") == "menu-panel" ||
libraryButton.getAttribute("overflowedItem") == "true" ||
!libraryButton.closest("#nav-bar") ||
!window.toolbar.visible ||
!this.COSMETIC_ANIMATIONS_ENABLED) {
return;
}

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

@ -64,18 +64,24 @@ var SidebarUI = {
},
uninit() {
let enumerator = Services.wm.getEnumerator(null);
// If this is the last browser window, persist various values that should be
// remembered for after a restart / reopening a browser window.
let enumerator = Services.wm.getEnumerator("navigator:browser");
enumerator.getNext();
if (!enumerator.hasMoreElements()) {
document.persist("sidebar-box", "sidebarcommand");
let xulStore = Cc["@mozilla.org/xul/xulstore;1"].getService(Ci.nsIXULStore);
if (this._box.hasAttribute("positionend")) {
document.persist("sidebar-box", "positionend");
} else {
xulStore.removeValue(document.documentURI, "sidebar-box", "positionend");
}
if (this._box.hasAttribute("checked")) {
document.persist("sidebar-box", "checked");
} else {
xulStore.removeValue(document.documentURI, "sidebar-box", "checked");
}
document.persist("sidebar-box", "width");
document.persist("sidebar-title", "value");
@ -180,13 +186,19 @@ var SidebarUI = {
// no source UI or no _box means we also can't adopt the state.
return false;
}
// Set sidebar command even if hidden, so that we keep the same sidebar
// even if it's currently closed.
let commandID = sourceUI._box.getAttribute("sidebarcommand");
if (commandID) {
this._box.setAttribute("sidebarcommand", commandID);
}
if (sourceUI._box.hidden) {
// just hidden means we have adopted the hidden state.
return true;
}
let commandID = sourceUI._box.getAttribute("sidebarcommand");
// dynamically generated sidebars will fail this check, but we still
// consider it adopted.
if (!document.getElementById(commandID)) {
@ -223,18 +235,22 @@ var SidebarUI = {
}
// If we're not adopting settings from a parent window, set them now.
let commandID = this._box.getAttribute("sidebarcommand");
if (!commandID) {
let wasOpen = this._box.getAttribute("checked");
if (!wasOpen) {
return;
}
if (document.getElementById(commandID)) {
let commandID = this._box.getAttribute("sidebarcommand");
if (commandID && document.getElementById(commandID)) {
this.showInitially(commandID);
} else {
this._box.removeAttribute("checked");
// Remove the |sidebarcommand| attribute, because the element it
// refers to no longer exists, so we should assume this sidebar
// panel has been uninstalled. (249883)
this._box.removeAttribute("sidebarcommand");
// We use setAttribute rather than removeAttribute so it persists
// correctly.
this._box.setAttribute("sidebarcommand", "");
// On a startup in which the startup cache was invalidated (e.g. app update)
// extensions will not be started prior to delayedLoad, thus the
// sidebarcommand element will not exist yet. Store the commandID so
@ -274,10 +290,9 @@ var SidebarUI = {
/**
* The ID of the current sidebar (ie, the ID of the broadcaster being used).
* This can be set even if the sidebar is hidden.
*/
get currentID() {
return this._box.getAttribute("sidebarcommand");
return this.isOpen ? this._box.getAttribute("sidebarcommand") : "";
},
get title() {
@ -308,8 +323,12 @@ var SidebarUI = {
*/
toggle(commandID = this.lastOpenedId, triggerNode) {
// First priority for a default value is this.lastOpenedId which is set during show()
// and not reset in hide(), unlike currentID. If show() hasn't been called or the command
// doesn't exist anymore, then fallback to a default sidebar.
// and not reset in hide(), unlike currentID. If show() hasn't been called and we don't
// have a persisted command either, or the command doesn't exist anymore, then
// fallback to a default sidebar.
if (!commandID) {
commandID = this._box.getAttribute("sidebarcommand");
}
if (!commandID || !this.getBroadcasterById(commandID)) {
commandID = this.DEFAULT_SIDEBAR_ID;
}
@ -456,7 +475,6 @@ var SidebarUI = {
this.browser.docShell.createAboutBlankContentViewer(null);
sidebarBroadcaster.removeAttribute("checked");
this._box.setAttribute("sidebarcommand", "");
this._box.removeAttribute("checked");
this._box.hidden = this._splitter.hidden = true;

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

@ -1017,6 +1017,7 @@
<hbox flex="1"
id="PlacesToolbar"
context="placesContext"
onmouseup="BookmarksEventHandler.onMouseUp(event);"
onclick="BookmarksEventHandler.onClick(event, this._placesView);"
oncommand="BookmarksEventHandler.onCommand(event);"
tooltip="bhTooltip"
@ -1094,6 +1095,7 @@
placespopup="true"
context="placesContext"
openInTabs="children"
onmouseup="BookmarksEventHandler.onMouseUp(event);"
oncommand="BookmarksEventHandler.onCommand(event);"
onclick="BookmarksEventHandler.onClick(event, this.parentNode._placesView);"
onpopupshowing="BookmarkingUI.onPopupShowing(event);

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

@ -155,10 +155,10 @@ add_task(async function test_ignoring_window_opener() {
"url(\"chrome://browser/skin/connection-secure.svg\")",
"Using expected icon image in the identity block");
is(securityViewBG,
"url(\"chrome://browser/skin/controlcenter/connection.svg#connection-secure\")",
"url(\"chrome://browser/skin/controlcenter/connection.svg\")",
"Using expected icon image in the Control Center main view");
is(securityContentBG,
"url(\"chrome://browser/skin/controlcenter/connection.svg#connection-secure\")",
"url(\"chrome://browser/skin/controlcenter/connection.svg\")",
"Using expected icon image in the Control Center subview");
ok(Array.every(document.querySelectorAll("[when-loginforms=insecure]"),

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

@ -232,9 +232,9 @@ async function assertMixedContentBlockingState(tabbrowser, states = {}) {
}
if (stateSecure) {
is(securityViewBG, "url(\"chrome://browser/skin/controlcenter/connection.svg#connection-secure\")",
is(securityViewBG, "url(\"chrome://browser/skin/controlcenter/connection.svg\")",
"CC using secure icon");
is(securityContentBG, "url(\"chrome://browser/skin/controlcenter/connection.svg#connection-secure\")",
is(securityContentBG, "url(\"chrome://browser/skin/controlcenter/connection.svg\")",
"CC using secure icon");
}
@ -245,15 +245,15 @@ async function assertMixedContentBlockingState(tabbrowser, states = {}) {
is(securityContentBG, "url(\"chrome://browser/skin/controlcenter/mcb-disabled.svg\")",
"CC using active loaded icon");
} else if (activeBlocked || passiveLoaded) {
is(securityViewBG, "url(\"chrome://browser/skin/controlcenter/connection.svg#connection-degraded\")",
is(securityViewBG, "url(\"chrome://browser/skin/controlcenter/connection.svg\")",
"CC using degraded icon");
is(securityContentBG, "url(\"chrome://browser/skin/controlcenter/connection.svg#connection-degraded\")",
is(securityContentBG, "url(\"chrome://browser/skin/controlcenter/connection.svg\")",
"CC using degraded icon");
} else {
// There is a case here with weak ciphers, but no bc tests are handling this yet.
is(securityViewBG, "url(\"chrome://browser/skin/controlcenter/connection.svg#connection-degraded\")",
is(securityViewBG, "url(\"chrome://browser/skin/controlcenter/connection.svg\")",
"CC using degraded icon");
is(securityContentBG, "url(\"chrome://browser/skin/controlcenter/connection.svg#connection-degraded\")",
is(securityContentBG, "url(\"chrome://browser/skin/controlcenter/connection.svg\")",
"CC using degraded icon");
}
}

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

@ -716,16 +716,16 @@
label="&historyMenu.label;"
closemenu="none"
oncommand="PanelUI.showSubView('PanelUI-history', this)"/>
<toolbarbutton id="appMenu-library-remotetabs-button"
class="subviewbutton subviewbutton-iconic subviewbutton-nav"
label="&appMenuRemoteTabs.label;"
closemenu="none"
oncommand="PanelUI.showSubView('PanelUI-remotetabs', this)"/>
<toolbarbutton id="appMenu-library-downloads-button"
class="subviewbutton subviewbutton-iconic subviewbutton-nav"
label="&libraryDownloads.label;"
closemenu="none"
oncommand="DownloadsSubview.show(this);"/>
<toolbarbutton id="appMenu-library-remotetabs-button"
class="subviewbutton subviewbutton-iconic subviewbutton-nav"
label="&appMenuRemoteTabs.label;"
closemenu="none"
oncommand="PanelUI.showSubView('PanelUI-remotetabs', this)"/>
</vbox>
</panelview>

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

@ -13,19 +13,19 @@ registerCleanupFunction(async function() {
}
});
var showSidebar = async function() {
let button = document.getElementById("sidebar-button");
let sidebarFocusedPromise = BrowserTestUtils.waitForEvent(document, "SidebarFocused");
EventUtils.synthesizeMouseAtCenter(button, {});
var showSidebar = async function(win = window) {
let button = win.document.getElementById("sidebar-button");
let sidebarFocusedPromise = BrowserTestUtils.waitForEvent(win.document, "SidebarFocused");
EventUtils.synthesizeMouseAtCenter(button, {}, win);
await sidebarFocusedPromise;
ok(SidebarUI.isOpen, "Sidebar is opened");
ok(win.SidebarUI.isOpen, "Sidebar is opened");
ok(button.hasAttribute("checked"), "Toolbar button is checked");
};
var hideSidebar = async function() {
let button = document.getElementById("sidebar-button");
EventUtils.synthesizeMouseAtCenter(button, {});
ok(!SidebarUI.isOpen, "Sidebar is closed");
var hideSidebar = async function(win = window) {
let button = win.document.getElementById("sidebar-button");
EventUtils.synthesizeMouseAtCenter(button, {}, win);
ok(!win.SidebarUI.isOpen, "Sidebar is closed");
ok(!button.hasAttribute("checked"), "Toolbar button isn't checked");
};
@ -40,4 +40,12 @@ add_task(async function() {
await hideSidebar();
await showSidebar();
is(SidebarUI.currentID, "viewHistorySidebar", "Selected sidebar remembered");
await hideSidebar();
let otherWin = await BrowserTestUtils.openNewBrowserWindow({opener: window});
await showSidebar(otherWin);
is(otherWin.SidebarUI.currentID, "viewHistorySidebar", "Selected sidebar remembered across windows");
await hideSidebar(otherWin);
await BrowserTestUtils.closeWindow(otherWin);
});

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

@ -130,8 +130,23 @@ const DownloadsButton = {
this._getAnchorInternal();
},
unhide() {
/**
* Unhide the button. Generally, this only needs to use the placeholder.
* However, when starting customize mode, if the button is in the palette,
* we need to unhide it before customize mode is entered, otherwise it
* gets ignored by customize mode. To do this, we pass true for
* `includePalette`. We don't always look in the palette because it's
* inefficient (compared to getElementById), shouldn't be necessary, and
* if _placeholder returned the node even if in the palette, other checks
* would break.
*
* @param includePalette whether to search the palette, too. Defaults to false.
*/
unhide(includePalette = false) {
let button = this._placeholder;
if (!button && includePalette) {
button = gNavToolbox.palette.querySelector("#downloads-button");
}
if (button && button.hasAttribute("hidden")) {
button.removeAttribute("hidden");
if (this._navBar.contains(button)) {
@ -190,7 +205,7 @@ const DownloadsButton = {
// during customization, even if requested using the getAnchor method.
this._customizing = true;
this._anchorRequested = false;
this.unhide();
this.unhide(true);
}
},
@ -308,7 +323,9 @@ const DownloadsIndicatorView = {
// If the view is initialized, we need to update the elements now that
// they are finally available in the document.
if (this._initialized) {
// We need to re-check for the placeholder because it might have
// disappeared since then.
if (this._initialized && DownloadsButton._placeholder) {
DownloadsCommon.getIndicatorData(window).refreshView(this);
}

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

@ -251,6 +251,41 @@ add_task(async function checkStateForDownloads() {
ok(!downloadsButton.hasAttribute("hidden"),
"Button should still not be hidden in the panel " +
"when downloads count reaches 0 after being non-0.");
CustomizableUI.reset();
});
/**
* Check that if the button is moved to the palette, we unhide it
* in customize mode even if it was always hidden. We use a new
* window to test this.
*/
add_task(async function checkStateWhenHiddenInPalette() {
ok(Services.prefs.getBoolPref(kDownloadAutoHidePref),
"Pref should be causing us to autohide");
gCustomizeMode.removeFromArea(document.getElementById("downloads-button"));
// In a new window, the button will have been hidden
let otherWin = await BrowserTestUtils.openNewBrowserWindow();
ok(!otherWin.document.getElementById("downloads-button"),
"Button shouldn't be visible in the window");
let paletteButton = otherWin.gNavToolbox.palette.querySelector("#downloads-button");
ok(paletteButton, "Button should exist in the palette");
if (paletteButton) {
ok(paletteButton.hidden, "Button will still have the hidden attribute");
await promiseCustomizeStart(otherWin);
ok(!paletteButton.hidden,
"Button should no longer be hidden in customize mode");
ok(otherWin.document.getElementById("downloads-button"),
"Button should be in the document now.");
await promiseCustomizeEnd(otherWin);
// We purposefully don't assert anything about what happens next.
// It doesn't really matter if the button remains unhidden in
// the palette, and if we move it we'll unhide it then (the other
// tests check this).
}
await BrowserTestUtils.closeWindow(otherWin);
CustomizableUI.reset();
});
function promiseCustomizeStart(aWindow = window) {

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

@ -499,18 +499,7 @@ class TabTracker extends TabTrackerBase {
let windowId = windowTracker.getId(nativeTab.ownerGlobal);
let tabId = this.getId(nativeTab);
// When addons run in-process, `window.close()` is synchronous. Most other
// addon-invoked calls are asynchronous since they go through a proxy
// context via the message manager. This includes event registrations such
// as `tabs.onRemoved.addListener`.
//
// So, even if `window.close()` were to be called (in-process) after calling
// `tabs.onRemoved.addListener`, then the tab would be closed before the
// event listener is registered. To make sure that the event listener is
// notified, we dispatch `tabs.onRemoved` asynchronously.
Services.tm.dispatchToMainThread(() => {
this.emit("tab-removed", {nativeTab, tabId, windowId, isWindowClosing});
});
this.emit("tab-removed", {nativeTab, tabId, windowId, isWindowClosing});
}
getBrowserData(browser) {

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

@ -248,6 +248,8 @@ add_task(async function testTabEventsSize() {
add_task(async function testTabRemovalEvent() {
async function background() {
let events = [];
function awaitLoad(tabId) {
return new Promise(resolve => {
browser.tabs.onUpdated.addListener(function listener(tabId_, changed, tab) {
@ -260,12 +262,13 @@ add_task(async function testTabRemovalEvent() {
}
chrome.tabs.onRemoved.addListener((tabId, info) => {
browser.test.assertEq(0, events.length, "No events recorded before onRemoved.");
events.push("onRemoved");
browser.test.log("Make sure the removed tab is not available in the tabs.query callback.");
chrome.tabs.query({}, tabs => {
for (let tab of tabs) {
browser.test.assertTrue(tab.id != tabId, "Tab query should not include removed tabId");
}
browser.test.notifyPass("tabs-events");
});
});
@ -274,6 +277,13 @@ add_task(async function testTabRemovalEvent() {
let tab = await browser.tabs.create({url: url});
await awaitLoad(tab.id);
chrome.tabs.onActivated.addListener(info => {
browser.test.assertEq(1, events.length, "One event recorded before onActivated.");
events.push("onActivated");
browser.test.assertEq("onRemoved", events[0], "onRemoved fired before onActivated.");
browser.test.notifyPass("tabs-events");
});
await browser.tabs.remove(tab.id);
} catch (e) {
browser.test.fail(`${e} :: ${e.stack}`);

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

@ -1576,6 +1576,8 @@ XPCOMUtils.defineLazyPreferenceGetter(PlacesUIUtils, "loadBookmarksInBackground"
PREF_LOAD_BOOKMARKS_IN_BACKGROUND, false);
XPCOMUtils.defineLazyPreferenceGetter(PlacesUIUtils, "loadBookmarksInTabs",
PREF_LOAD_BOOKMARKS_IN_TABS, false);
XPCOMUtils.defineLazyPreferenceGetter(PlacesUIUtils, "openInTabClosesMenu",
"browser.bookmarks.openInTabClosesMenu", false);
XPCOMUtils.defineLazyServiceGetter(this, "URIFixup",
"@mozilla.org/docshell/urifixup;1",

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

@ -94,6 +94,10 @@
<menupopup id="placesContext"
onpopupshowing="this._view = PlacesUIUtils.getViewForNode(document.popupNode);
if (!PlacesUIUtils.openInTabClosesMenu) {
document.getElementById ('placesContext_open:newtab')
.setAttribute('closemenu', 'single');
}
return this._view.buildContextMenu(this);"
onpopuphiding="this._view.destroyContextMenu();">
<menuitem id="placesContext_open"

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

@ -57,6 +57,7 @@ subsuite = clipboard
[browser_sidebarpanels_click.js]
skip-if = true # temporarily disabled for breaking the treeview - bug 658744
[browser_sort_in_library.js]
[browser_stayopenmenu.js]
[browser_toolbar_drop_text.js]
[browser_toolbar_overflow.js]
[browser_toolbarbutton_menu_context.js]

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

@ -0,0 +1,206 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Menus should stay open (if pref is set) after ctrl-click, middle-click,
// and contextmenu's "Open in a new tab" click.
async function locateBookmarkAndTestCtrlClick(menupopup) {
let menuitem = null;
for (let node of menupopup.childNodes) {
if (node.label == "Test1") {
menuitem = node;
let promiseTabOpened = BrowserTestUtils.waitForNewTab(gBrowser, null);
EventUtils.synthesizeMouseAtCenter(menuitem,
AppConstants.platform === "macosx" ? {metaKey: true} : {ctrlKey: true});
let newTab = await promiseTabOpened;
ok(true, "Bookmark ctrl-click opened new tab.");
await BrowserTestUtils.removeTab(newTab);
break;
}
}
return menuitem;
}
async function testContextmenu(menuitem) {
let doc = menuitem.ownerDocument;
let cm = doc.getElementById("placesContext");
let promiseEvent = BrowserTestUtils.waitForEvent(cm, "popupshown");
EventUtils.synthesizeMouseAtCenter(menuitem, {type: "contextmenu", button: 2});
await promiseEvent;
let promiseTabOpened = BrowserTestUtils.waitForNewTab(gBrowser, null);
EventUtils.synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
BrowserTestUtils.waitForEvent(menuitem, "DOMMenuItemActive");
EventUtils.synthesizeKey("KEY_ArrowDown", {code: "ArrowDown"});
BrowserTestUtils.waitForEvent(menuitem, "DOMMenuItemActive");
EventUtils.sendKey("return");
let newTab = await promiseTabOpened;
return newTab;
}
add_task(async function test_setup() {
// Ensure BMB is available in UI.
let origBMBlocation = CustomizableUI.getPlacementOfWidget("bookmarks-menu-button");
if (!origBMBlocation) {
CustomizableUI.addWidgetToArea("bookmarks-menu-button", CustomizableUI.AREA_NAVBAR);
}
await SpecialPowers.pushPrefEnv({
"set": [["browser.bookmarks.openInTabClosesMenu", false]]});
// Ensure menubar visible.
let menubar = document.getElementById("toolbar-menubar");
let menubarVisible = isToolbarVisible(menubar);
if (!menubarVisible) {
setToolbarVisibility(menubar, true);
info("Menubar made visible");
}
// Ensure Bookmarks Toolbar Visible.
let toolbar = document.getElementById("PersonalToolbar");
let toolbarHidden = toolbar.collapsed;
if (toolbarHidden) {
await promiseSetToolbarVisibility(toolbar, true);
info("Bookmarks toolbar made visible");
}
// Create our test bookmarks.
await PlacesUtils.bookmarks.insert({
parentGuid: PlacesUtils.bookmarks.menuGuid,
url: "http://example.com/",
title: "Test1"
});
let folder = await PlacesUtils.bookmarks.insert({
parentGuid: PlacesUtils.bookmarks.toolbarGuid,
type: PlacesUtils.bookmarks.TYPE_FOLDER,
title: "TEST_TITLE",
index: 0
});
await PlacesUtils.bookmarks.insert({
parentGuid: folder.guid,
url: "http://example.com/",
title: "Test1"
});
registerCleanupFunction(async function() {
await PlacesUtils.bookmarks.eraseEverything();
// if BMB was not originally in UI, remove it.
if (!origBMBlocation) {
CustomizableUI.removeWidgetFromArea("bookmarks-menu-button");
}
// Restore menubar to original visibility.
setToolbarVisibility(menubar, menubarVisible);
// Restore original bookmarks toolbar visibility.
if (toolbarHidden) {
await promiseSetToolbarVisibility(toolbar, false);
}
});
});
add_task(async function testStayopenBookmarksClicks() {
// Test Bookmarks Menu Button stayopen clicks - Ctrl-click.
let BMB = document.getElementById("bookmarks-menu-button");
let BMBpopup = document.getElementById("BMB_bookmarksPopup");
let promiseEvent = BrowserTestUtils.waitForEvent(BMBpopup, "popupshown");
EventUtils.synthesizeMouseAtCenter(BMB, {});
await promiseEvent;
info("Popupshown on Bookmarks-Menu-Button");
var menuitem = await locateBookmarkAndTestCtrlClick(BMBpopup);
ok(BMB.open, "Bookmarks Menu Button's Popup should still be open.");
// Test Bookmarks Menu Button stayopen clicks: middle-click.
let promiseTabOpened = BrowserTestUtils.waitForNewTab(gBrowser, null);
EventUtils.synthesizeMouseAtCenter(menuitem, {button: 1});
let newTab = await promiseTabOpened;
ok(true, "Bookmark middle-click opened new tab.");
await BrowserTestUtils.removeTab(newTab);
ok(BMB.open, "Bookmarks Menu Button's Popup should still be open.");
// Test Bookmarks Menu Button stayopen clicks - 'Open in new tab' on context menu.
newTab = await testContextmenu(menuitem);
ok(true, "Bookmark contextmenu opened new tab.");
ok(BMB.open, "Bookmarks Menu Button's Popup should still be open.");
promiseEvent = BrowserTestUtils.waitForEvent(BMBpopup, "popuphidden");
BMB.open = false;
await promiseEvent;
info("Closing menu");
await BrowserTestUtils.removeTab(newTab);
// Disable the rest of the tests on Mac due to Mac's handling of menus being
// slightly different to the other platforms.
if (AppConstants.platform === "macosx") {
return;
}
// Test Bookmarks Menu (menubar) stayopen clicks: Ctrl-click.
let BM = document.getElementById("bookmarksMenu");
let BMpopup = document.getElementById("bookmarksMenuPopup");
promiseEvent = BrowserTestUtils.waitForEvent(BMpopup, "popupshown");
EventUtils.synthesizeMouseAtCenter(BM, {});
await promiseEvent;
info("Popupshowing on Bookmarks Menu");
menuitem = await locateBookmarkAndTestCtrlClick(BMpopup);
ok(BM.open, "Bookmarks Menu's Popup should still be open.");
// Test Bookmarks Menu (menubar) stayopen clicks: middle-click.
promiseTabOpened = BrowserTestUtils.waitForNewTab(gBrowser, null);
EventUtils.synthesizeMouseAtCenter(menuitem, {button: 1});
newTab = await promiseTabOpened;
ok(true, "Bookmark middle-click opened new tab.");
await BrowserTestUtils.removeTab(newTab);
ok(BM.open, "Bookmarks Menu's Popup should still be open.");
// Test Bookmarks Menu (menubar) stayopen clicks: 'Open in new tab' on context menu.
newTab = await testContextmenu(menuitem);
ok(true, "Bookmark contextmenu opened new tab.");
await BrowserTestUtils.removeTab(newTab);
ok(BM.open, "Bookmarks Menu's Popup should still be open.");
promiseEvent = BrowserTestUtils.waitForEvent(BMpopup, "popuphidden");
BM.open = false;
await promiseEvent;
// Test Bookmarks Toolbar stayopen clicks - Ctrl-click.
let BT = document.getElementById("PlacesToolbarItems");
let toolbarbutton = BT.firstChild;
ok(toolbarbutton, "Folder should be first item on Bookmarks Toolbar.");
let buttonMenupopup = toolbarbutton.firstChild;
ok(buttonMenupopup.tagName == "menupopup", "Found toolbar button's menupopup.");
promiseEvent = BrowserTestUtils.waitForEvent(buttonMenupopup, "popupshown");
EventUtils.synthesizeMouseAtCenter(toolbarbutton, {});
await promiseEvent;
ok(true, "Bookmarks toolbar folder's popup is open.");
menuitem = buttonMenupopup.firstChild.nextSibling;
promiseTabOpened = BrowserTestUtils.waitForNewTab(gBrowser, null);
EventUtils.synthesizeMouseAtCenter(menuitem, {ctrlKey: true});
newTab = await promiseTabOpened;
ok(true, "Bookmark in folder on bookmark's toolbar ctrl-click opened new tab.");
ok(toolbarbutton.open, "Popup of folder on bookmark's toolbar should still be open.");
promiseEvent = BrowserTestUtils.waitForEvent(buttonMenupopup, "popuphidden");
toolbarbutton.open = false;
await promiseEvent;
await BrowserTestUtils.removeTab(newTab);
// Test Bookmarks Toolbar stayopen clicks: middle-click.
promiseEvent = BrowserTestUtils.waitForEvent(buttonMenupopup, "popupshown");
EventUtils.synthesizeMouseAtCenter(toolbarbutton, {});
await promiseEvent;
ok(true, "Bookmarks toolbar folder's popup is open.");
promiseTabOpened = BrowserTestUtils.waitForNewTab(gBrowser, null);
EventUtils.synthesizeMouseAtCenter(menuitem, {button: 1});
newTab = await promiseTabOpened;
ok(true, "Bookmark in folder on Bookmarks Toolbar middle-click opened new tab.");
ok(toolbarbutton.open, "Popup of folder on bookmark's toolbar should still be open.");
promiseEvent = BrowserTestUtils.waitForEvent(buttonMenupopup, "popuphidden");
toolbarbutton.open = false;
await promiseEvent;
await BrowserTestUtils.removeTab(newTab);
// Test Bookmarks Toolbar stayopen clicks: 'Open in new tab' on context menu.
promiseEvent = BrowserTestUtils.waitForEvent(buttonMenupopup, "popupshown");
EventUtils.synthesizeMouseAtCenter(toolbarbutton, {});
await promiseEvent;
ok(true, "Bookmarks toolbar folder's popup is open.");
newTab = await testContextmenu(menuitem);
ok(true, "Bookmark on Bookmarks Toolbar contextmenu opened new tab.");
ok(toolbarbutton.open, "Popup of folder on bookmark's toolbar should still be open.");
promiseEvent = BrowserTestUtils.waitForEvent(buttonMenupopup, "popuphidden");
toolbarbutton.open = false;
await promiseEvent;
await BrowserTestUtils.removeTab(newTab);
});

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

@ -38,7 +38,7 @@
accesskey="&searchFilter.accesskey;"/>
</hbox>
<separator class="thin"/>
<label control="cookiesList" id="cookiesIntro">&cookiesonsystem.label;</label>
<label control="cookiesList" id="cookiesIntro">&cookiesonsystem2.label;</label>
<separator class="thin"/>
<tree id="cookiesList" flex="1" style="height: 10em;"
onkeypress="gCookiesWindow.onCookieKeyPress(event)"

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

@ -12,6 +12,10 @@
name="browser.search.hiddenOneOffs"
type="unichar"/>
<preference id="browser.search.widget.inNavBar"
name="browser.search.widget.inNavBar"
type="bool"/>
</preferences>
<script type="application/javascript"
@ -26,6 +30,16 @@
<label class="header-name" flex="1">&paneSearch.title;</label>
</hbox>
<groupbox id="searchbarGroup" data-category="paneSearch">
<caption><label id="searchbarLabel">&searchBar.label;</label></caption>
<radiogroup id="searchBarVisibleGroup" aria-labelledby="searchbarLabel" preference="browser.search.widget.inNavBar">
<radio id="searchBarHiddenRadio" value="false" label="&searchBar.hidden.label;"/>
<image class="searchBarImage searchBarHiddenImage" role="presentation"/>
<radio id="searchBarShownRadio" value="true" label="&searchBar.shown.label;"/>
<image class="searchBarImage searchBarShownImage" role="presentation"/>
</radiogroup>
</groupbox>
<!-- Default Search Engine -->
<groupbox id="defaultEngineGroup" data-category="paneSearch">
<caption><label>&defaultSearchEngine.label;</label></caption>

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

@ -44,7 +44,7 @@
<separator />
<vbox flex="1">
<label>&siteTree.label;</label>
<label>&siteTree2.label;</label>
<separator class="thin"/>
<tree id="sitesTree" flex="1" seltype="single" hidecolumnpicker="true">
<treecols>

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

@ -30,7 +30,7 @@
<vbox class="largeDialogContainer">
<vbox class="contentPane" flex="1">
<label id="languagesLabel" control="permissionsTree">&noTranslationForLanguages.label;</label>
<label id="languagesLabel" control="permissionsTree">&noTranslationForLanguages2.label;</label>
<separator class="thin"/>
<tree id="languagesTree" flex="1" style="height: 12em;"
hidecolumnpicker="true"
@ -57,7 +57,7 @@
</hbox>
<separator/>
<vbox class="contentPane" flex="1">
<label id="languagesLabel" control="permissionsTree">&noTranslationForSites.label;</label>
<label id="languagesLabel" control="permissionsTree">&noTranslationForSites2.label;</label>
<separator class="thin"/>
<tree id="sitesTree" flex="1" style="height: 12em;"
hidecolumnpicker="true"

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

@ -3075,8 +3075,9 @@ var SessionStoreInternal = {
else if (winData.hidden)
delete winData.hidden;
var sidebar = aWindow.document.getElementById("sidebar-box").getAttribute("sidebarcommand");
if (sidebar)
let sidebarBox = aWindow.document.getElementById("sidebar-box");
let sidebar = sidebarBox.getAttribute("sidebarcommand");
if (sidebar && sidebarBox.getAttribute("checked") == "true")
winData.sidebar = sidebar;
else if (winData.sidebar)
delete winData.sidebar;
@ -4089,8 +4090,9 @@ var SessionStoreInternal = {
break;
}
}
var sidebar = aWindow.document.getElementById("sidebar-box");
if (sidebar.getAttribute("sidebarcommand") != aSidebar) {
let sidebarBox = aWindow.document.getElementById("sidebar-box");
if (aSidebar && (sidebarBox.getAttribute("sidebarcommand") != aSidebar ||
!sidebarBox.getAttribute("checked"))) {
aWindow.SidebarUI.showInitially(aSidebar);
}
// since resizing/moving a window brings it to the foreground,

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

@ -57,6 +57,7 @@ for (const type of [
"SAVE_SESSION_PERF_DATA",
"SAVE_TO_POCKET",
"SCREENSHOT_UPDATED",
"SEARCH_BOX_FOCUSED",
"SECTION_DEREGISTER",
"SECTION_DISABLE",
"SECTION_ENABLE",

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

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

@ -94,7 +94,7 @@ const globalImportContext = typeof Window === "undefined" ? BACKGROUND_PROCESS :
// UNINIT: "UNINIT"
// }
const actionTypes = {};
for (const type of ["BLOCK_URL", "BOOKMARK_URL", "DELETE_BOOKMARK_BY_ID", "DELETE_HISTORY_URL", "DELETE_HISTORY_URL_CONFIRM", "DIALOG_CANCEL", "DIALOG_OPEN", "INIT", "LOCALE_UPDATED", "MIGRATION_CANCEL", "MIGRATION_COMPLETED", "MIGRATION_START", "NEW_TAB_INIT", "NEW_TAB_INITIAL_STATE", "NEW_TAB_LOAD", "NEW_TAB_REHYDRATED", "NEW_TAB_STATE_REQUEST", "NEW_TAB_UNLOAD", "OPEN_LINK", "OPEN_NEW_WINDOW", "OPEN_PRIVATE_WINDOW", "PINNED_SITES_UPDATED", "PLACES_BOOKMARK_ADDED", "PLACES_BOOKMARK_CHANGED", "PLACES_BOOKMARK_REMOVED", "PLACES_HISTORY_CLEARED", "PLACES_LINK_BLOCKED", "PLACES_LINK_DELETED", "PREFS_INITIAL_VALUES", "PREF_CHANGED", "SAVE_SESSION_PERF_DATA", "SAVE_TO_POCKET", "SCREENSHOT_UPDATED", "SECTION_DEREGISTER", "SECTION_DISABLE", "SECTION_ENABLE", "SECTION_REGISTER", "SECTION_UPDATE", "SECTION_UPDATE_CARD", "SET_PREF", "SHOW_FIREFOX_ACCOUNTS", "SNIPPETS_DATA", "SNIPPETS_RESET", "SYSTEM_TICK", "TELEMETRY_IMPRESSION_STATS", "TELEMETRY_PERFORMANCE_EVENT", "TELEMETRY_UNDESIRED_EVENT", "TELEMETRY_USER_EVENT", "TOP_SITES_ADD", "TOP_SITES_PIN", "TOP_SITES_UNPIN", "TOP_SITES_UPDATED", "UNINIT"]) {
for (const type of ["BLOCK_URL", "BOOKMARK_URL", "DELETE_BOOKMARK_BY_ID", "DELETE_HISTORY_URL", "DELETE_HISTORY_URL_CONFIRM", "DIALOG_CANCEL", "DIALOG_OPEN", "INIT", "LOCALE_UPDATED", "MIGRATION_CANCEL", "MIGRATION_COMPLETED", "MIGRATION_START", "NEW_TAB_INIT", "NEW_TAB_INITIAL_STATE", "NEW_TAB_LOAD", "NEW_TAB_REHYDRATED", "NEW_TAB_STATE_REQUEST", "NEW_TAB_UNLOAD", "OPEN_LINK", "OPEN_NEW_WINDOW", "OPEN_PRIVATE_WINDOW", "PINNED_SITES_UPDATED", "PLACES_BOOKMARK_ADDED", "PLACES_BOOKMARK_CHANGED", "PLACES_BOOKMARK_REMOVED", "PLACES_HISTORY_CLEARED", "PLACES_LINK_BLOCKED", "PLACES_LINK_DELETED", "PREFS_INITIAL_VALUES", "PREF_CHANGED", "SAVE_SESSION_PERF_DATA", "SAVE_TO_POCKET", "SCREENSHOT_UPDATED", "SEARCH_BOX_FOCUSED", "SECTION_DEREGISTER", "SECTION_DISABLE", "SECTION_ENABLE", "SECTION_REGISTER", "SECTION_UPDATE", "SECTION_UPDATE_CARD", "SET_PREF", "SHOW_FIREFOX_ACCOUNTS", "SNIPPETS_DATA", "SNIPPETS_RESET", "SYSTEM_TICK", "TELEMETRY_IMPRESSION_STATS", "TELEMETRY_PERFORMANCE_EVENT", "TELEMETRY_UNDESIRED_EVENT", "TELEMETRY_USER_EVENT", "TOP_SITES_ADD", "TOP_SITES_PIN", "TOP_SITES_UNPIN", "TOP_SITES_UPDATED", "UNINIT"]) {
actionTypes[type] = type;
}
@ -1242,7 +1242,7 @@ const TopSites = props => {
intl: props.intl })),
placeholderCount > 0 && [...Array(placeholderCount)].map((_, i) => React.createElement(TopSitePlaceholder, { key: i }))
),
realTopSites.length > 0 && React.createElement(TopSitesEdit, props)
React.createElement(TopSitesEdit, props)
)
);
};
@ -1948,7 +1948,7 @@ module.exports.CheckPinTopSite = (site, index) => site.isPinned ? module.exports
const React = __webpack_require__(1);
const { connect } = __webpack_require__(3);
const { FormattedMessage, injectIntl } = __webpack_require__(2);
const { actionCreators: ac } = __webpack_require__(0);
const { actionCreators: ac, actionTypes: at } = __webpack_require__(0);
const { IS_NEWTAB } = __webpack_require__(20);
class Search extends React.Component {
@ -1991,6 +1991,14 @@ class Search extends React.Component {
// In the future, when activity stream is default about:home, this can be renamed
window.gContentSearchController = new ContentSearchUIController(input, input.parentNode, healthReportKey, searchSource);
addEventListener("ContentSearchClient", this);
// Focus the search box if we are on about:home
if (!IS_NEWTAB) {
input.focus();
// Tell the addon side that search box is focused in case the browser
// needs to be focused too.
this.props.dispatch(ac.SendToMain({ type: at.SEARCH_BOX_FOCUSED }));
}
} else {
window.gContentSearchController = null;
removeEventListener("ContentSearchClient", this);
@ -2719,14 +2727,20 @@ class Card extends React.Component {
link.description
)
),
icon && React.createElement(
React.createElement(
"div",
{ className: "card-context" },
React.createElement("span", { className: `card-context-icon icon icon-${icon}` }),
React.createElement(
icon && !link.context && React.createElement("span", { className: `card-context-icon icon icon-${icon}` }),
link.icon && link.context && React.createElement("span", { className: "card-context-icon icon", style: { backgroundImage: `url('${link.icon}')` } }),
intlID && !link.context && React.createElement(
"div",
{ className: "card-context-label" },
React.createElement(FormattedMessage, { id: intlID, defaultMessage: "Visited" })
),
link.context && React.createElement(
"div",
{ className: "card-context-label" },
link.context
)
)
)
@ -3351,6 +3365,10 @@ class SnippetsProvider {
throw new Error("No remote snippets were found in gSnippetsMap.");
}
if (typeof payload !== "string") {
throw new Error("Snippet payload was incorrectly formatted");
}
// Note that injecting snippets can throw if they're invalid XML.
snippetsEl.innerHTML = payload;

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

@ -969,14 +969,14 @@ main {
transition: box-shadow 150ms; }
.card-outer > a.active .card-title, .card-outer > a:focus .card-title {
color: #0060DF; }
.card-outer:hover, .card-outer:focus, .card-outer.active {
.card-outer:-moz-any(:hover, :focus, .active):not(.placeholder) {
outline: none;
box-shadow: 0 0 0 5px #D7D7DB;
transition: box-shadow 150ms; }
.card-outer:hover .context-menu-button, .card-outer:focus .context-menu-button, .card-outer.active .context-menu-button {
.card-outer:-moz-any(:hover, :focus, .active):not(.placeholder) .context-menu-button {
transform: scale(1);
opacity: 1; }
.card-outer:hover .card-title, .card-outer:focus .card-title, .card-outer.active .card-title {
.card-outer:-moz-any(:hover, :focus, .active):not(.placeholder) .card-title {
color: #0060DF; }
.card-outer .card-preview-image-outer {
position: relative;

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

@ -3727,6 +3727,36 @@
"time_label_hour": "{number} ម៉ោង",
"time_label_day": "{number} ថ្ងៃ"
},
"kn": {
"newtab_page_title": "ಹೊಸ ಹಾಳೆ",
"default_label_loading": "ಲೋಡ್ ಆಗುತ್ತಿದೆ…",
"header_top_sites": "ಪ್ರಮುಖ ತಾಣಗಳು",
"header_stories": "ಪ್ರಮುಖ ಸುದ್ದಿಗಳು",
"header_highlights": "ಮುಖ್ಯಾಂಶಗಳು",
"header_visit_again": "ಮತ್ತೆ ಭೇಟಿಕೊಡು",
"header_bookmarks": "ಇತ್ತೀಚಿಗೆ ಮಾಡಲಾದ ಬುಕ್‌ಮಾರ್ಕುಗಳು",
"header_stories_from": "ಯಿಂದ",
"type_label_visited": "ಭೇಟಿ ನೀಡಲಾದ‍",
"type_label_bookmarked": "ಪುಟಗುರುತು ಮಾಡಲಾದ",
"type_label_open": "ತೆರೆ",
"type_label_topic": "ವಿಷಯ",
"type_label_now": "ಈಗ",
"menu_action_bookmark": "ಪುಟ ಗುರುತು",
"menu_action_remove_bookmark": "ಪುಟ ಗುರುತು ತೆಗೆ",
"menu_action_copy_address": "ವಿಳಾಸವನ್ನು ನಕಲಿಸು",
"menu_action_email_link": "ಇಮೈಲ್ ಕೊಂಡಿ…",
"menu_action_open_new_window": "ಹೊಸ ಕಿಟಕಿಯಲ್ಲಿ ತೆರೆ",
"search_button": "ಹುಡುಕು",
"search_settings": "ಹುಡುಕು ಸಿದ್ಧತೆಗಳನ್ನು ಬದಲಾಯಿಸು",
"settings_pane_search_header": "ಹುಡುಕು",
"settings_pane_topsites_options_showmore": "ಎರಡು ಸಾಲುಗಳನ್ನು ಪ್ರದರ್ಶಿಸು",
"edit_topsites_button_text": "‍ತಿದ್ದು",
"edit_topsites_showmore_button": "‍ಹೆಚ್ಚು ತೋರಿಸು",
"edit_topsites_add_button": "ಸೇರಿಸು",
"topsites_form_add_button": "ಸೇರಿಸು",
"topsites_form_save_button": "ಉಳಿಸು",
"topsites_form_cancel_button": "ರದ್ದು ಮಾಡು"
},
"ko": {
"newtab_page_title": "새 탭",
"default_label_loading": "읽는 중…",
@ -4743,7 +4773,7 @@
"type_label_visited": "Odwiedzone",
"type_label_bookmarked": "Zakładka",
"type_label_synced": "Z innego urządzenia",
"type_label_recommended": "Polecane",
"type_label_recommended": "Na czasie",
"type_label_open": "Otwarte",
"type_label_topic": "Temat",
"type_label_now": "Teraz",

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

@ -8,7 +8,7 @@
<em:type>2</em:type>
<em:bootstrap>true</em:bootstrap>
<em:unpack>false</em:unpack>
<em:version>2017.09.12.1376-781e5de5</em:version>
<em:version>2017.09.14.0590-7fa80d82</em:version>
<em:name>Activity Stream</em:name>
<em:description>A rich visual history feed and a reimagined home page make it easier than ever to find exactly what you're looking for in Firefox.</em:description>
<em:multiprocessCompatible>true</em:multiprocessCompatible>

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

@ -62,9 +62,14 @@ const PREFS_CONFIG = new Map([
stories_referrer: "https://getpocket.com/recommendations",
info_link: "https://www.mozilla.org/privacy/firefox/#pocketstories",
topics_endpoint: `https://getpocket.cdn.mozilla.net/v3/firefox/trending-topics?version=2&consumer_key=$apiKey&locale_lang=${args.locale}`,
show_spocs: false,
personalized: false
})
}],
["filterAdult", {
title: "Remove adult pages from sites, highlights, etc.",
value: true
}],
["migrationExpired", {
title: "Boolean flag that decides whether to show the migration message or not.",
value: false
@ -113,6 +118,10 @@ const PREFS_CONFIG = new Map([
["telemetry.ping.endpoint", {
title: "Telemetry server endpoint",
value: "https://tiles.services.mozilla.com/v4/links/activity-stream"
}],
["aboutHome.autoFocus", {
title: "Focus the about:home search box on load",
value: true
}]
]);

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -13,6 +13,8 @@ const {SectionsManager} = Cu.import("resource://activity-stream/lib/SectionsMana
const {TOP_SITES_SHOWMORE_LENGTH} = Cu.import("resource://activity-stream/common/Reducers.jsm", {});
const {Dedupe} = Cu.import("resource://activity-stream/common/Dedupe.jsm", {});
XPCOMUtils.defineLazyModuleGetter(this, "filterAdult",
"resource://activity-stream/lib/FilterAdult.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NewTabUtils",
"resource://gre/modules/NewTabUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Screenshots",
@ -41,6 +43,7 @@ this.HighlightsFeed = class HighlightsFeed {
postInit() {
SectionsManager.enableSection(SECTION_ID);
this.fetchHighlights(true);
}
uninit() {
@ -48,12 +51,28 @@ this.HighlightsFeed = class HighlightsFeed {
}
async fetchHighlights(broadcast = false) {
// We need TopSites to have been initialised for deduping
if (!this.store.getState().TopSites.initialized) {
await new Promise(resolve => {
const unsubscribe = this.store.subscribe(() => {
if (this.store.getState().TopSites.initialized) {
unsubscribe();
resolve();
}
});
});
}
// Request more than the expected length to allow for items being removed by
// deduping against Top Sites or multiple history from the same domain, etc.
const manyPages = await NewTabUtils.activityStreamLinks.getHighlights({numItems: MANY_EXTRA_LENGTH});
// Remove adult highlights if we need to
const checkedAdult = this.store.getState().Prefs.values.filterAdult ?
filterAdult(manyPages) : manyPages;
// Remove any Highlights that are in Top Sites already
const deduped = this.dedupe.group(this.store.getState().TopSites.rows, manyPages)[1];
const [, deduped] = this.dedupe.group(this.store.getState().TopSites.rows, checkedAdult);
// Keep all "bookmark"s and at most one (most recent) "history" per host
this.highlights = [];

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

@ -37,6 +37,11 @@ this.NewTabInit = class NewTabInit {
this._queue.clear();
}
break;
case at.SEARCH_BOX_FOCUSED:
if (action._target.url === "about:home" && this.store.getState().Prefs.values["aboutHome.autoFocus"]) {
action._target.browser.focus();
}
break;
}
}
};

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

@ -201,9 +201,6 @@ this.TelemetryFeed = class TelemetryFeed {
perf: {load_trigger_type: "unexpected"}
};
if (url) {
session.page = url;
}
this.sessions.set(id, session);
return session;
}

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

@ -12,6 +12,8 @@ const {insertPinned, TOP_SITES_SHOWMORE_LENGTH} = Cu.import("resource://activity
const {Dedupe} = Cu.import("resource://activity-stream/common/Dedupe.jsm", {});
const {shortURL} = Cu.import("resource://activity-stream/lib/ShortURL.jsm", {});
XPCOMUtils.defineLazyModuleGetter(this, "filterAdult",
"resource://activity-stream/lib/FilterAdult.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NewTabUtils",
"resource://gre/modules/NewTabUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Screenshots",
@ -74,12 +76,17 @@ this.TopSitesFeed = class TopSitesFeed {
});
}
// Remove any duplicates from frecent and default sites then insert the
// original pinned sites into the deduped frecent ([1]) and defaults ([2])
const deduped = this.dedupe.group(pinned, frecent, notBlockedDefaultSites);
pinned = insertPinned([...deduped[1], ...deduped[2]], pinned);
// Remove any duplicates from frecent and default sites
const [, dedupedFrecent, dedupedDefaults] = this.dedupe.group(
pinned, frecent, notBlockedDefaultSites);
const dedupedUnpinned = [...dedupedFrecent, ...dedupedDefaults];
return pinned.slice(0, TOP_SITES_SHOWMORE_LENGTH);
// Remove adult sites if we need to
const checkedAdult = this.store.getState().Prefs.values.filterAdult ?
filterAdult(dedupedUnpinned) : dedupedUnpinned;
// Insert the original pinned sites into the deduped frecent and defaults
return insertPinned(checkedAdult, pinned).slice(0, TOP_SITES_SHOWMORE_LENGTH);
}
async refresh(target = null) {
if (!this._tippyTopProvider.initialized) {

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

@ -9,14 +9,14 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/NewTabUtils.jsm");
Cu.importGlobalProperties(["fetch"]);
const {actionTypes: at} = Cu.import("resource://activity-stream/common/Actions.jsm", {});
const {actionTypes: at, actionCreators: ac} = Cu.import("resource://activity-stream/common/Actions.jsm", {});
const {Prefs} = Cu.import("resource://activity-stream/lib/ActivityStreamPrefs.jsm", {});
const {shortURL} = Cu.import("resource://activity-stream/lib/ShortURL.jsm", {});
const {SectionsManager} = Cu.import("resource://activity-stream/lib/SectionsManager.jsm", {});
const {UserDomainAffinityProvider} = Cu.import("resource://activity-stream/lib/UserDomainAffinityProvider.jsm", {});
XPCOMUtils.defineLazyModuleGetter(this, "perfService", "resource://activity-stream/common/PerfService.jsm");
const STORIES_UPDATE_TIME = 30 * 60 * 1000; // 30 minutes
const TOPICS_UPDATE_TIME = 3 * 60 * 60 * 1000; // 3 hours
const DOMAIN_AFFINITY_UPDATE_TIME = 24 * 60 * 60 * 1000; // 24 hours
@ -24,32 +24,36 @@ const STORIES_NOW_THRESHOLD = 24 * 60 * 60 * 1000; // 24 hours
const SECTION_ID = "topstories";
this.TopStoriesFeed = class TopStoriesFeed {
init() {
constructor() {
this.storiesLastUpdated = 0;
this.topicsLastUpdated = 0;
this.affinityLastUpdated = 0;
SectionsManager.onceInitialized(this.parseOptions.bind(this));
this.spocsPerNewTabs = 0;
this.newTabsSinceSpoc = 0;
this.contentUpdateQueue = [];
}
parseOptions() {
SectionsManager.enableSection(SECTION_ID);
const options = SectionsManager.sections.get(SECTION_ID).options;
try {
const apiKey = this._getApiKeyFromPref(options.api_key_pref);
this.stories_endpoint = this._produceFinalEndpointUrl(options.stories_endpoint, apiKey);
this.topics_endpoint = this._produceFinalEndpointUrl(options.topics_endpoint, apiKey);
this.read_more_endpoint = options.read_more_endpoint;
this.stories_referrer = options.stories_referrer;
this.personalized = options.personalized;
this.maxHistoryQueryResults = options.maxHistoryQueryResults;
init() {
const initFeed = () => {
SectionsManager.enableSection(SECTION_ID);
try {
const options = SectionsManager.sections.get(SECTION_ID).options;
const apiKey = this.getApiKeyFromPref(options.api_key_pref);
this.stories_endpoint = this.produceFinalEndpointUrl(options.stories_endpoint, apiKey);
this.topics_endpoint = this.produceFinalEndpointUrl(options.topics_endpoint, apiKey);
this.read_more_endpoint = options.read_more_endpoint;
this.stories_referrer = options.stories_referrer;
this.personalized = options.personalized;
this.show_spocs = options.show_spocs;
this.maxHistoryQueryResults = options.maxHistoryQueryResults;
this.fetchStories();
this.fetchTopics();
} catch (e) {
Cu.reportError(`Problem initializing top stories feed: ${e.message}`);
}
this.fetchStories();
this.fetchTopics();
} catch (e) {
Cu.reportError(`Problem initializing top stories feed: ${e.message}`);
}
};
SectionsManager.onceInitialized(initFeed);
}
uninit() {
@ -62,38 +66,48 @@ this.TopStoriesFeed = class TopStoriesFeed {
}
try {
const response = await fetch(this.stories_endpoint);
if (!response.ok) {
throw new Error(`Stories endpoint returned unexpected status: ${response.status}`);
}
const body = await response.json();
this.updateDomainAffinities(body.settings);
this.updateSettings(body.settings);
this.stories = this.rotate(this.transform(body.recommendations));
this.spocs = this.show_spocs && this.transform(body.spocs).filter(s => s.score >= s.min_score);
const recommendations = body.recommendations
.filter(s => !NewTabUtils.blockedLinks.isBlocked({"url": s.url}))
.map(s => ({
"guid": s.id,
"hostname": shortURL(Object.assign({}, s, {url: s.url})),
"type": (Date.now() - (s.published_timestamp * 1000)) <= STORIES_NOW_THRESHOLD ? "now" : "trending",
"title": s.title,
"description": s.excerpt,
"image": this._normalizeUrl(s.image_src),
"referrer": this.stories_referrer,
"url": s.url,
"score": this.personalized ? this.affinityProvider.calculateItemRelevanceScore(s) : 1
}))
.sort(this.personalized ? this.compareScore : (a, b) => 0);
const rows = this.rotate(recommendations);
this.dispatchUpdateEvent(this.storiesLastUpdated, {rows});
this.dispatchUpdateEvent(this.storiesLastUpdated, {rows: this.stories});
this.storiesLastUpdated = Date.now();
// This is filtered so an update function can return true to retry on the next run
this.contentUpdateQueue = this.contentUpdateQueue.filter(update => update());
} catch (error) {
Cu.reportError(`Failed to fetch content: ${error.message}`);
}
}
transform(items) {
if (!items) {
return [];
}
return items
.filter(s => !NewTabUtils.blockedLinks.isBlocked({"url": s.url}))
.map(s => ({
"guid": s.id,
"hostname": shortURL(Object.assign({}, s, {url: s.url})),
"type": (Date.now() - (s.published_timestamp * 1000)) <= STORIES_NOW_THRESHOLD ? "now" : "trending",
"context": s.context,
"icon": s.icon,
"title": s.title,
"description": s.excerpt,
"image": this.normalizeUrl(s.image_src),
"referrer": this.stories_referrer,
"url": s.url,
"min_score": s.min_score || 0,
"score": this.personalized ? this.affinityProvider.calculateItemRelevanceScore(s) : 1
}))
.sort(this.personalized ? this.compareScore : (a, b) => 0);
}
async fetchTopics() {
if (!this.topics_endpoint) {
return;
@ -121,16 +135,24 @@ this.TopStoriesFeed = class TopStoriesFeed {
return b.score - a.score;
}
updateDomainAffinities(settings) {
updateSettings(settings) {
if (!this.personalized) {
return;
}
this.spocsPerNewTabs = settings.spocsPerNewTabs;
if (!this.affinityProvider || (Date.now() - this.affinityLastUpdated >= DOMAIN_AFFINITY_UPDATE_TIME)) {
const start = perfService.absNow();
this.affinityProvider = new UserDomainAffinityProvider(
settings.timeSegments,
settings.domainAffinityParameterSets,
this.maxHistoryQueryResults);
this.store.dispatch(ac.PerfEvent({
event: "topstories.domain.affinity.calculation.ms",
value: Math.round(perfService.absNow() - start)
}));
this.affinityLastUpdated = Date.now();
}
}
@ -153,7 +175,7 @@ this.TopStoriesFeed = class TopStoriesFeed {
return items;
}
_getApiKeyFromPref(apiKeyPref) {
getApiKeyFromPref(apiKeyPref) {
if (!apiKeyPref) {
return apiKeyPref;
}
@ -161,7 +183,7 @@ this.TopStoriesFeed = class TopStoriesFeed {
return new Prefs().get(apiKeyPref) || Services.prefs.getCharPref(apiKeyPref);
}
_produceFinalEndpointUrl(url, apiKey) {
produceFinalEndpointUrl(url, apiKey) {
if (!url) {
return url;
}
@ -173,13 +195,49 @@ this.TopStoriesFeed = class TopStoriesFeed {
// Need to remove parenthesis from image URLs as React will otherwise
// fail to render them properly as part of the card template.
_normalizeUrl(url) {
normalizeUrl(url) {
if (url) {
return url.replace(/\(/g, "%28").replace(/\)/g, "%29");
}
return url;
}
maybeAddSpoc(target) {
if (!this.show_spocs) {
return;
}
if (this.newTabsSinceSpoc === 0 || this.newTabsSinceSpoc === this.spocsPerNewTabs) {
const updateContent = () => {
if (!this.spocs || !this.spocs.length) {
// We have stories but no spocs so there's nothing to do and this update can be
// removed from the queue.
return false;
}
// Create a new array with a spoc inserted at index 2
// For now we're using the top scored spoc until we can support viewability based rotation
let rows = this.stories.slice(0, this.stories.length);
rows.splice(2, 0, this.spocs[0]);
// Send a content update to the target tab
const action = {type: at.SECTION_UPDATE, meta: {skipMain: true}, data: Object.assign({rows}, {id: SECTION_ID})};
this.store.dispatch(ac.SendToContent(action, target));
return false;
};
if (this.stories) {
updateContent();
} else {
// Delay updating tab content until initial data has been fetched
this.contentUpdateQueue.push(updateContent);
}
this.newTabsSinceSpoc = 0;
}
this.newTabsSinceSpoc++;
}
onAction(action) {
switch (action.type) {
case at.INIT:
@ -196,6 +254,9 @@ this.TopStoriesFeed = class TopStoriesFeed {
case at.UNINIT:
this.uninit();
break;
case at.NEW_TAB_REHYDRATED:
this.maybeAddSpoc(action.meta.fromTarget);
break;
}
}
};

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

@ -0,0 +1,45 @@
describe("filterAdult", () => {
let filterAdult;
let hashStub;
let hashValue;
beforeEach(() => {
hashStub = {
finish: sinon.stub().callsFake(() => hashValue),
init: sinon.stub(),
update: sinon.stub()
};
global.Components.classes["@mozilla.org/security/hash;1"] = {
createInstance() {
return hashStub;
}
};
filterAdult = require("lib/FilterAdult.jsm").filterAdult;
});
it("should default to include on unexpected urls", () => {
const empty = {};
const result = filterAdult([empty]);
assert.equal(result.length, 1);
assert.equal(result[0], empty);
});
it("should not filter out non-adult urls", () => {
const link = {url: "https://mozilla.org/"};
const result = filterAdult([link]);
assert.equal(result.length, 1);
assert.equal(result[0], link);
});
it("should filter out adult urls", () => {
// Use a hash value that is in the adult set
hashValue = "+/UCpAhZhz368iGioEO8aQ==";
const link = {url: "https://some-adult-site/"};
const result = filterAdult([link]);
assert.equal(result.length, 0);
});
});

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

@ -18,6 +18,7 @@ describe("Highlights Feed", () => {
let clock;
let fakeScreenshot;
let fakeNewTabUtils;
let filterAdultStub;
let sectionsManagerStub;
let shortURLStub;
@ -34,16 +35,29 @@ describe("Highlights Feed", () => {
sections: new Map([["highlights", {}]])
};
fakeScreenshot = {getScreenshotForURL: sandbox.spy(() => Promise.resolve(FAKE_IMAGE))};
filterAdultStub = sinon.stub().returns([]);
shortURLStub = sinon.stub().callsFake(site => site.url.match(/\/([^/]+)/)[1]);
globals.set("NewTabUtils", fakeNewTabUtils);
({HighlightsFeed, HIGHLIGHTS_UPDATE_TIME, SECTION_ID} = injector({
"lib/FilterAdult.jsm": {filterAdult: filterAdultStub},
"lib/ShortURL.jsm": {shortURL: shortURLStub},
"lib/SectionsManager.jsm": {SectionsManager: sectionsManagerStub},
"lib/Screenshots.jsm": {Screenshots: fakeScreenshot},
"common/Dedupe.jsm": {Dedupe}
}));
feed = new HighlightsFeed();
feed.store = {dispatch: sinon.spy(), getState() { return {TopSites: {rows: Array(12).fill(null).map((v, i) => ({url: `http://www.topsite${i}.com`}))}}; }};
feed.store = {
dispatch: sinon.spy(),
getState() { return this.state; },
state: {
Prefs: {values: {filterAdult: false}},
TopSites: {
initialized: true,
rows: Array(12).fill(null).map((v, i) => ({url: `http://www.topsite${i}.com`}))
}
},
subscribe: sinon.stub().callsFake(cb => { cb(); return () => {}; })
};
links = FAKE_LINKS;
clock = sinon.useFakeTimers();
});
@ -65,15 +79,34 @@ describe("Highlights Feed", () => {
assert.calledOnce(sectionsManagerStub.enableSection);
assert.calledWith(sectionsManagerStub.enableSection, SECTION_ID);
});
it("should *not* fetch highlights on init to avoid loading Places too early", () => {
it("should fetch highlights on postInit", () => {
feed.fetchHighlights = sinon.spy();
feed.onAction({type: at.INIT});
assert.notCalled(feed.fetchHighlights);
feed.postInit();
assert.calledOnce(feed.fetchHighlights);
});
});
describe("#fetchHighlights", () => {
it("should wait for TopSites to be initialised", async () => {
feed.store.getState = () => ({TopSites: {initialized: false}});
// Initially TopSites is uninitialised and fetchHighlights should wait
feed.fetchHighlights();
assert.calledOnce(feed.store.subscribe);
assert.notCalled(fakeNewTabUtils.activityStreamLinks.getHighlights);
// Initialisation causes the subscribe callback to be called and
// fetchHighlights should continue
feed.store.getState = () => ({TopSites: {initialized: true}});
const subscribeCallback = feed.store.subscribe.firstCall.args[0];
await subscribeCallback();
assert.calledOnce(fakeNewTabUtils.activityStreamLinks.getHighlights);
// If TopSites is initialised in the first place it shouldn't wait
feed.store.subscribe.reset();
fakeNewTabUtils.activityStreamLinks.getHighlights.reset();
feed.fetchHighlights();
assert.notCalled(feed.store.subscribe);
assert.calledOnce(fakeNewTabUtils.activityStreamLinks.getHighlights);
});
it("should add hostname and hasImage to each link", async () => {
links = [{url: "https://mozilla.org"}];
await feed.fetchHighlights();
@ -141,6 +174,20 @@ describe("Highlights Feed", () => {
await feed.fetchHighlights();
assert.equal(feed.imageCache.size, 0);
});
it("should not filter out adult pages when pref is false", async() => {
await feed.fetchHighlights();
assert.notCalled(filterAdultStub);
});
it("should filter out adult pages when pref is true", async() => {
feed.store.state.Prefs.values.filterAdult = true;
await feed.fetchHighlights();
// The stub filters out everything
assert.calledOnce(filterAdultStub);
assert.equal(feed.highlights.length, 0);
});
});
describe("#fetchImage", () => {
const FAKE_URL = "https://mozilla.org";

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

@ -59,4 +59,40 @@ describe("NewTabInit", () => {
instance.onAction({type: at.LOCALE_UPDATED});
assert.notCalled(store.dispatch);
});
it("should focus the content browser when SEARCH_BOX_FOCUSED", () => {
STATE.Prefs = {values: {"aboutHome.autoFocus": true}};
const action = {
type: at.SEARCH_BOX_FOCUSED,
_target: {
url: "about:home",
browser: {focus: sinon.spy()}
}
};
instance.onAction(action);
assert.calledOnce(action._target.browser.focus);
});
it("should NOT focus the content browser when SEARCH_BOX_FOCUSED for about:newtab", () => {
STATE.Prefs = {values: {"aboutHome.autoFocus": true}};
const action = {
type: at.SEARCH_BOX_FOCUSED,
_target: {
url: "about:newtab",
browser: {focus: sinon.spy()}
}
};
instance.onAction(action);
assert.notCalled(action._target.browser.focus);
});
it("should NOT focus the content browser when SEARCH_BOX_FOCUSED when autoFocus pref is off", () => {
STATE.Prefs = {values: {"aboutHome.autoFocus": false}};
const action = {
type: at.SEARCH_BOX_FOCUSED,
_target: {
url: "about:newtab",
browser: {focus: sinon.spy()}
}
};
instance.onAction(action);
assert.notCalled(action._target.browser.focus);
});
});

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

@ -29,6 +29,7 @@ describe("Top Sites Feed", () => {
let clock;
let fakeNewTabUtils;
let fakeScreenshot;
let filterAdultStub;
let shortURLStub;
beforeEach(() => {
@ -48,6 +49,7 @@ describe("Top Sites Feed", () => {
}
};
fakeScreenshot = {getScreenshotForURL: sandbox.spy(() => Promise.resolve(FAKE_SCREENSHOT))};
filterAdultStub = sinon.stub().returns([]);
shortURLStub = sinon.stub().callsFake(site => site.url);
const fakeDedupe = function() {};
globals.set("NewTabUtils", fakeNewTabUtils);
@ -56,12 +58,20 @@ describe("Top Sites Feed", () => {
"lib/ActivityStreamPrefs.jsm": {Prefs: FakePrefs},
"common/Dedupe.jsm": {Dedupe: fakeDedupe},
"common/Reducers.jsm": {insertPinned, TOP_SITES_SHOWMORE_LENGTH},
"lib/FilterAdult.jsm": {filterAdult: filterAdultStub},
"lib/Screenshots.jsm": {Screenshots: fakeScreenshot},
"lib/TippyTopProvider.jsm": {TippyTopProvider: FakeTippyTopProvider},
"lib/ShortURL.jsm": {shortURL: shortURLStub}
}));
feed = new TopSitesFeed();
feed.store = {dispatch: sinon.spy(), getState() { return {TopSites: {rows: Array(12).fill("site")}}; }};
feed.store = {
dispatch: sinon.spy(),
getState() { return this.state; },
state: {
Prefs: {values: {filterAdult: false}},
TopSites: {rows: Array(12).fill("site")}
}
};
feed.dedupe.group = (...sites) => sites;
links = FAKE_LINKS;
clock = sinon.useFakeTimers();
@ -130,6 +140,22 @@ describe("Top Sites Feed", () => {
assert.notEqual(result[1].url, links[1].url);
assert.notEqual(result[1].url, links[2].url);
});
it("should not filter out adult sites when pref is false", async() => {
await feed.getLinksWithDefaults();
assert.notCalled(filterAdultStub);
});
it("should filter out non-pinned adult sites when pref is true", async() => {
feed.store.state.Prefs.values.filterAdult = true;
fakeNewTabUtils.pinnedLinks.links = [{url: "https://foo.com/"}];
const result = await feed.getLinksWithDefaults();
// The stub filters out everything
assert.calledOnce(filterAdultStub);
assert.equal(result.length, 1);
assert.equal(result[0].url, fakeNewTabUtils.pinnedLinks.links[0].url);
});
it("should filter out the defaults that have been blocked", async () => {
// make sure we only have one top site, and we block the only default site we have to show
const url = "www.myonlytopsite.com";
@ -194,7 +220,7 @@ describe("Top Sites Feed", () => {
"lib/Screenshots.jsm": {Screenshots: fakeScreenshot}
}));
sandbox.stub(global.Services.eTLD, "getPublicSuffix").returns("com");
feed = new TopSitesFeed();
feed = Object.assign(new TopSitesFeed(), {store: feed.store});
});
it("should not dedupe pinned sites", async () => {
fakeNewTabUtils.pinnedLinks.links = [
@ -263,8 +289,7 @@ describe("Top Sites Feed", () => {
});
it("should reuse screenshots for existing links, and call feed.getScreenshot for others", async () => {
sandbox.stub(feed, "getScreenshot");
const rows = [{url: FAKE_LINKS[0].url, screenshot: "foo.jpg"}];
feed.store.getState = () => ({TopSites: {rows}});
feed.store.state.TopSites.rows = [{url: FAKE_LINKS[0].url, screenshot: "foo.jpg"}];
await feed.refresh(action);
const results = feed.store.dispatch.firstCall.args[0].data;

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

@ -141,18 +141,23 @@ describe("Top Stories Feed", () => {
"excerpt": "description",
"image_src": "image-url",
"url": "rec-url",
"published_timestamp": "123"
"published_timestamp": "123",
"context": "trending",
"icon": "icon"
}]
};
const stories = [{
"guid": "1",
"type": "now",
"title": "title",
"context": "trending",
"icon": "icon",
"description": "description",
"image": "image-url",
"referrer": "referrer",
"url": "rec-url",
"hostname": "rec-url",
"min_score": 0,
"score": 1
}];
@ -356,6 +361,108 @@ describe("Top Stories Feed", () => {
const rotated = instance.rotate(items);
assert.deepEqual(items, rotated);
});
it("should insert spoc at provided interval", async () => {
let fetchStub = globals.sandbox.stub();
globals.set("fetch", fetchStub);
globals.set("NewTabUtils", {blockedLinks: {isBlocked: globals.sandbox.spy()}});
const response = {
"settings": {"spocsPerNewTabs": 2},
"recommendations": [{"id": "rec1"}, {"id": "rec2"}, {"id": "rec3"}],
"spocs": [{"id": "spoc1"}, {"id": "spoc2"}]
};
instance.personalized = true;
instance.show_spocs = true;
instance.stories_endpoint = "stories-endpoint";
fetchStub.resolves({ok: true, status: 200, json: () => Promise.resolve(response)});
await instance.fetchStories();
instance.onAction({type: at.NEW_TAB_REHYDRATED, meta: {fromTarget: {}}});
assert.calledOnce(instance.store.dispatch);
let action = instance.store.dispatch.firstCall.args[0];
assert.equal(at.SECTION_UPDATE, action.type);
assert.equal(true, action.meta.skipMain);
assert.equal(action.data.rows[0].guid, "rec1");
assert.equal(action.data.rows[1].guid, "rec2");
assert.equal(action.data.rows[2].guid, "spoc1");
// Second new tab shouldn't trigger a section update event (spocsPerNewTab === 2)
instance.onAction({type: at.NEW_TAB_REHYDRATED, meta: {fromTarget: {}}});
assert.calledOnce(instance.store.dispatch);
instance.onAction({type: at.NEW_TAB_REHYDRATED, meta: {fromTarget: {}}});
assert.calledTwice(instance.store.dispatch);
action = instance.store.dispatch.secondCall.args[0];
assert.equal(at.SECTION_UPDATE, action.type);
assert.equal(true, action.meta.skipMain);
assert.equal(action.data.rows[0].guid, "rec1");
assert.equal(action.data.rows[1].guid, "rec2");
assert.equal(action.data.rows[2].guid, "spoc1");
});
it("should delay inserting spoc if stories haven't been fetched", async () => {
let fetchStub = globals.sandbox.stub();
globals.set("fetch", fetchStub);
globals.set("NewTabUtils", {blockedLinks: {isBlocked: globals.sandbox.spy()}});
const response = {
"settings": {"spocsPerNewTabs": 2},
"recommendations": [{"id": "rec1"}, {"id": "rec2"}, {"id": "rec3"}],
"spocs": [{"id": "spoc1"}, {"id": "spoc2"}]
};
instance.personalized = true;
instance.show_spocs = true;
instance.stories_endpoint = "stories-endpoint";
fetchStub.resolves({ok: true, status: 200, json: () => Promise.resolve(response)});
instance.onAction({type: at.NEW_TAB_REHYDRATED, meta: {fromTarget: {}}});
assert.notCalled(instance.store.dispatch);
assert.equal(instance.contentUpdateQueue.length, 1);
await instance.fetchStories();
assert.equal(instance.contentUpdateQueue.length, 0);
assert.calledOnce(instance.store.dispatch);
let action = instance.store.dispatch.firstCall.args[0];
assert.equal(action.type, at.SECTION_UPDATE);
});
it("should not insert spoc if preffed off", async () => {
let fetchStub = globals.sandbox.stub();
globals.set("fetch", fetchStub);
globals.set("NewTabUtils", {blockedLinks: {isBlocked: globals.sandbox.spy()}});
const response = {
"settings": {"spocsPerNewTabs": 2},
"recommendations": [{"id": "rec1"}, {"id": "rec2"}, {"id": "rec3"}],
"spocs": [{"id": "spoc1"}, {"id": "spoc2"}]
};
instance.show_spocs = false;
instance.stories_endpoint = "stories-endpoint";
fetchStub.resolves({ok: true, status: 200, json: () => Promise.resolve(response)});
await instance.fetchStories();
instance.onAction({type: at.NEW_TAB_REHYDRATED, meta: {fromTarget: {}}});
assert.notCalled(instance.store.dispatch);
});
it("should not fail if there is no spoc", async () => {
let fetchStub = globals.sandbox.stub();
globals.set("fetch", fetchStub);
globals.set("NewTabUtils", {blockedLinks: {isBlocked: globals.sandbox.spy()}});
const response = {
"settings": {"spocsPerNewTabs": 2},
"recommendations": [{"id": "rec1"}, {"id": "rec2"}, {"id": "rec3"}]
};
instance.show_spocs = true;
instance.stories_endpoint = "stories-endpoint";
fetchStub.resolves({ok: true, status: 200, json: () => Promise.resolve(response)});
await instance.fetchStories();
instance.onAction({type: at.NEW_TAB_REHYDRATED, meta: {fromTarget: {}}});
assert.notCalled(instance.store.dispatch);
});
});
describe("#update", () => {
it("should fetch stories after update interval", () => {
@ -384,12 +491,24 @@ describe("Top Stories Feed", () => {
const fakeSettings = {timeSegments: {}, parameterSets: {}};
instance.affinityProvider = {status: "not_changed"};
instance.updateDomainAffinities(fakeSettings);
instance.updateSettings(fakeSettings);
assert.equal("not_changed", instance.affinityProvider.status);
clock.tick(DOMAIN_AFFINITY_UPDATE_TIME);
instance.updateDomainAffinities(fakeSettings);
instance.updateSettings(fakeSettings);
assert.isUndefined(instance.affinityProvider.status);
});
it("should send performance telemetry when updating domain affinities", () => {
instance.init();
instance.personalized = true;
const fakeSettings = {timeSegments: {}, parameterSets: {}};
clock.tick(DOMAIN_AFFINITY_UPDATE_TIME);
instance.updateSettings(fakeSettings);
assert.calledOnce(instance.store.dispatch);
let action = instance.store.dispatch.firstCall.args[0];
assert.equal(action.type, at.TELEMETRY_PERFORMANCE_EVENT);
assert.equal(action.data.event, "topstories.domain.affinity.calculation.ms");
});
});
});

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

@ -62,8 +62,11 @@ overrider.set({
}
},
tm: {dispatchToMainThread: cb => cb()},
eTLD: {getPublicSuffix() {}},
io: {newURI() {}},
eTLD: {
getBaseDomain({spec}) { return spec.match(/\/([^/]+)/)[1]; },
getPublicSuffix() {}
},
io: {newURI(url) { return {spec: url}; }},
search: {
init(cb) { cb(); },
getVisibleEngines: () => [{identifier: "google"}, {identifier: "bing"}],

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

@ -589,6 +589,12 @@ FormAutofillHandler.prototype = {
delete data.creditCard;
}
// If both address and credit card exists, skip this metrics because it not a
// general case and each specific histogram might contains insufficient data set.
if (data.address && data.creditCard) {
this.timeStartedFillingMS = null;
}
return data;
},

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

@ -415,7 +415,7 @@ FormAutofillParent.prototype = {
}
},
async _onCreditCardSubmit(creditCard, target) {
async _onCreditCardSubmit(creditCard, target, timeStartedFillingMS) {
// We'll show the credit card doorhanger if:
// - User applys autofill and changed
// - User fills form manually
@ -423,13 +423,18 @@ FormAutofillParent.prototype = {
Object.keys(creditCard.record).every(key => creditCard.untouchedFields.includes(key))) {
// Add probe to record credit card autofill(without modification).
Services.telemetry.scalarAdd("formautofill.creditCards.fill_type_autofill", 1);
this._recordFormFillingTime("creditCard", "autofill", timeStartedFillingMS);
return;
}
// Add the probe to record credit card manual filling or autofill but modified case.
let ccScalar = creditCard.guid ? "formautofill.creditCards.fill_type_autofill_modified" :
"formautofill.creditCards.fill_type_manual";
Services.telemetry.scalarAdd(ccScalar, 1);
if (creditCard.guid) {
Services.telemetry.scalarAdd("formautofill.creditCards.fill_type_autofill_modified", 1);
this._recordFormFillingTime("creditCard", "autofill-update", timeStartedFillingMS);
} else {
Services.telemetry.scalarAdd("formautofill.creditCards.fill_type_manual", 1);
this._recordFormFillingTime("creditCard", "manual", timeStartedFillingMS);
}
let state = await FormAutofillDoorhanger.show(target, "creditCard");
if (state == "cancel") {
@ -452,7 +457,7 @@ FormAutofillParent.prototype = {
this._onAddressSubmit(address, target, timeStartedFillingMS);
}
if (creditCard) {
this._onCreditCardSubmit(creditCard, target);
this._onCreditCardSubmit(creditCard, target, timeStartedFillingMS);
}
},
/**
@ -463,10 +468,13 @@ FormAutofillParent.prototype = {
* 3 type of form (address/creditcard/address-creditcard).
* @param {string} fillingType
* 3 filling type (manual/autofill/autofill-update).
* @param {int} startedFillingMS
* Time that form started to filling in ms.
* @param {int|null} startedFillingMS
* Time that form started to filling in ms. Early return if start time is null.
*/
_recordFormFillingTime(formType, fillingType, startedFillingMS) {
if (!startedFillingMS) {
return;
}
let histogram = Services.telemetry.getKeyedHistogramById("FORM_FILLING_REQUIRED_TIME_MS");
histogram.add(`${formType}-${fillingType}`, Date.now() - startedFillingMS);
},

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

@ -10,6 +10,7 @@ DIRS += [
'clicktoplay-rollout',
'e10srollout',
'followonsearch',
'formautofill',
'onboarding',
'pdfjs',
'pocket',
@ -25,12 +26,6 @@ if not CONFIG['RELEASE_OR_BETA']:
'presentation',
]
# formautofill will be rolled out via balrog in release
if CONFIG['MOZ_UPDATE_CHANNEL'] != 'release':
DIRS += [
'formautofill',
]
# Only include the following system add-ons if building DevEdition or Nightly
if CONFIG['MOZ_DEV_EDITION'] or CONFIG['NIGHTLY_BUILD']:
DIRS += [

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

@ -4,7 +4,7 @@
<!ENTITY window.width "36em">
<!ENTITY cookiesonsystem.label "The following cookies are stored on your computer:">
<!ENTITY cookiesonsystem2.label "The following cookies are stored on your computer">
<!ENTITY cookiename.label "Cookie Name">
<!ENTITY cookiedomain.label "Site">

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

@ -2,6 +2,11 @@
- 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/. -->
<!ENTITY searchBar.label "Search Bar">
<!ENTITY searchBar.hidden.label "Use the address bar for search and navigation">
<!ENTITY searchBar.shown.label "Add search bar in toolbar">
<!ENTITY defaultSearchEngine.label "Default Search Engine">
<!ENTITY chooseYourDefaultSearchEngine2.label "Choose the default search engine to use in the address bar and search bar.">

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

@ -16,4 +16,4 @@
<!ENTITY cancel.accesskey "C">
<!ENTITY removingDialog.title "Removing Site Data">
<!ENTITY removingSelected.description "Removing site data will also remove related cookies and offline web content. This may log you out of websites. Are you sure you want to make the changes?">
<!ENTITY siteTree.label "The following website cookies will be removed:">
<!ENTITY siteTree2.label "The following website cookies will be removed">

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

@ -6,14 +6,14 @@
<!ENTITY window.width "36em">
<!ENTITY windowClose.key "w">
<!ENTITY noTranslationForLanguages.label "Translation will not be offered for the following languages:">
<!ENTITY noTranslationForLanguages2.label "Translation will not be offered for the following languages">
<!ENTITY treehead.languageName.label "Languages">
<!ENTITY removeLanguage.label "Remove Language">
<!ENTITY removeLanguage.accesskey "R">
<!ENTITY removeAllLanguages.label "Remove All Languages">
<!ENTITY removeAllLanguages.accesskey "e">
<!ENTITY noTranslationForSites.label "Translation will not be offered for the following sites:">
<!ENTITY noTranslationForSites2.label "Translation will not be offered for the following sites">
<!ENTITY treehead.siteName2.label "Websites">
<!ENTITY removeSite.label "Remove Site">
<!ENTITY removeSite.accesskey "S">

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

@ -296,16 +296,6 @@ menuitem.bookmark-item {
/* identity box */
#identity-box:-moz-locale-dir(ltr) {
border-top-left-radius: 1.5px;
border-bottom-left-radius: 1.5px;
}
#identity-box:-moz-locale-dir(rtl) {
border-top-right-radius: 1.5px;
border-bottom-right-radius: 1.5px;
}
#identity-box:not(:active):-moz-focusring {
outline: 1px dotted;
outline-offset: -3px;

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

@ -9,7 +9,7 @@ textbox,
description,
.tab-text,
caption > label {
font-size: 1.2rem;
font-size: 1.11rem;
}
/* Create a separate rule to unset these styles on .tree-input instead of

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

@ -4,6 +4,21 @@
%include ../../../shared/incontentprefs/preferences.inc.css
html *,
page *,
window * {
font-size: 1.11rem;
}
caption > label:not(.dialogTitle) {
font-size: 1.27rem;
}
.tip-caption,
.help-button {
font-size: 1rem;
}
.treecol-sortdirection {
/* override the Linux only toolkit rule */
-moz-appearance: none;

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

@ -358,16 +358,6 @@
%include ../shared/identity-block/identity-block.inc.css
#identity-box:-moz-locale-dir(ltr) {
border-top-left-radius: 2px;
border-bottom-left-radius: 2px;
}
#identity-box:-moz-locale-dir(rtl) {
border-top-right-radius: 2px;
border-bottom-right-radius: 2px;
}
#identity-box:not(:active):-moz-focusring {
box-shadow: var(--focus-ring-box-shadow);
border-inline-end-style: none;

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

@ -14,7 +14,7 @@ textbox,
description,
.tab-text,
caption > label {
font-size: 1.3rem;
font-size: 1.36rem;
}
/* Create a separate rule to unset these styles on .tree-input instead of

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

@ -4,6 +4,21 @@
%include ../../../shared/incontentprefs/preferences.inc.css
html *,
page *,
window * {
font-size: 1.36rem;
}
caption > label:not(.dialogTitle) {
font-size: 1.55rem;
}
.tip-caption,
.help-button {
font-size: 1.18rem;
}
.actionsMenu > .menulist-label-box > .menulist-icon {
margin-top: 2px;
margin-inline-start: 2px;

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

@ -7,9 +7,6 @@
%include ../../../../toolkit/themes/osx/global/shared.inc
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
@namespace html url("http://www.w3.org/1999/xhtml");
.windowDialog {
padding: 12px;
font: -moz-dialog;
@ -17,9 +14,6 @@
/* ----- APPLICATIONS PREFPANE ----- */
description {
font: small-caption;
font-weight: normal;
line-height: 1.3em;
margin-bottom: 4px !important;
}

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

@ -45,7 +45,7 @@
overflow: -moz-hidden-unscrollable;
max-height: 4em;
transition: min-height 170ms ease-out, max-height 170ms ease-out;
padding: 0 4px 1px;
padding: 0 6px 1px;
}
#navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar):not(#nav-bar)[collapsed=true] {

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

@ -1,29 +1,6 @@
<?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/. -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="24" height="24" viewBox="0 0 24 24">
#include ../icon-colors.inc.svg
<style>
svg > rect:not(:target) {
display: none;
}
</style>
<defs>
<rect id="shape-lock-clasp-outer" x="5" y="1" width="14" height="20" rx="7" ry="7" />
<rect id="shape-lock-clasp-inner" x="8" y="4" width="8" height="14" rx="4" ry="4" />
<rect id="shape-lock-base" x="3" y="10" width="18" height="13" rx="1.5" ry="1.5" />
<mask id="mask-clasp-cutout">
<rect width="24" height="24" fill="#000" />
<use xlink:href="#shape-lock-clasp-outer" fill="#fff" />
<use xlink:href="#shape-lock-clasp-inner" fill="#000" />
</mask>
<mask id="mask-lock">
<use xlink:href="#shape-lock-clasp-outer" mask="url(#mask-clasp-cutout)" fill="#fff"/>
<use xlink:href="#shape-lock-base" fill="#fff"/>
</mask>
</defs>
<rect id="connection-degraded" class="fieldtext" width="24" height="24" mask="url(#mask-lock)"/>
<rect id="connection-secure" width="24" height="24" mask="url(#mask-lock)" fill="context-fill"/>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="context-fill" fill-opacity="context-fill-opacity">
<path d="M18.75 9.977H18V7A6 6 0 0 0 6 7v2.977h-.75A2.25 2.25 0 0 0 3 12.227v7.523A2.25 2.25 0 0 0 5.25 22h13.5A2.25 2.25 0 0 0 21 19.75v-7.523a2.25 2.25 0 0 0-2.25-2.25zM9 7a3 3 0 0 1 6 0v2.977H9z"/>
</svg>

До

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

После

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

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

@ -1,34 +1,7 @@
<?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/. -->
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="24" height="24" viewBox="0 0 24 24">
#include ../icon-colors.inc.svg
<defs>
<rect id="shape-lock-clasp-outer" x="5" y="1" width="14" height="20" rx="7" ry="7" />
<rect id="shape-lock-clasp-inner" x="8" y="4" width="8" height="14" rx="4" ry="4" />
<rect id="shape-lock-base" x="3" y="10" width="18" height="13" rx="1.5" ry="1.5" />
<mask id="mask-clasp-cutout">
<rect width="24" height="24" fill="#000" />
<use xlink:href="#shape-lock-clasp-outer" fill="#fff" />
<use xlink:href="#shape-lock-clasp-inner" fill="#000" />
<line x1="3" y1="21" x2="21.5" y2="0.5" stroke="#000" stroke-width="3" />
<line x1="3" y1="25" x2="21.5" y2="4.5" stroke="#000" stroke-width="3" />
<rect x="3" y="10" width="18" height="13" rx="1.5" ry="1.5" />
</mask>
<mask id="mask-base-cutout">
<rect width="24" height="24" fill="#000" />
<use xlink:href="#shape-lock-base" fill="#fff" />
<line x1="2.25" y1="24.75" x2="21.5" y2="4.5" stroke="#000" stroke-width="3" />
</mask>
</defs>
<use class="fieldtext" xlink:href="#shape-lock-clasp-outer" mask="url(#mask-clasp-cutout)"/>
<use class="fieldtext" xlink:href="#shape-lock-base" mask="url(#mask-base-cutout)"/>
<line x1="2.25" y1="22.75" x2="21.5" y2="2.5" stroke="#d92d21" stroke-width="3" />
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="context-fill" fill-opacity="context-fill-opacity">
<path d="M18.75 9.977h-.727L6 22h12.75A2.25 2.25 0 0 0 21 19.75v-7.523a2.25 2.25 0 0 0-2.25-2.25zm-9.75 0V7a3 3 0 0 1 6 0v1.5l2.838-2.838A5.994 5.994 0 0 0 6 7v2.977h-.75A2.25 2.25 0 0 0 3 12.227v7.523a2.224 2.224 0 0 0 .105.645L13.523 9.977z"/>
<path d="M2.5 23a1.5 1.5 0 0 1-1.061-2.561l19-19A1.5 1.5 0 0 1 22.56 3.56l-19 19A1.5 1.5 0 0 1 2.5 23z" fill="#ff0039" fill-opacity="1"/>
</svg>

До

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

После

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

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

@ -235,7 +235,7 @@
}
#identity-popup[connection^=secure] #identity-popup-securityView,
#identity-popup[connection^=secure] #identity-popup-security-content {
background-image: url(chrome://browser/skin/controlcenter/connection.svg#connection-secure);
background-image: url(chrome://browser/skin/controlcenter/connection.svg);
-moz-context-properties: fill;
fill: #12BC00;
}
@ -244,7 +244,8 @@
#identity-popup[ciphers=weak] #identity-popup-security-content,
#identity-popup[mixedcontent~=passive-loaded][isbroken] #identity-popup-securityView,
#identity-popup[mixedcontent~=passive-loaded][isbroken] #identity-popup-security-content {
background-image: url(chrome://browser/skin/controlcenter/connection.svg#connection-degraded);
background-image: url(chrome://browser/skin/controlcenter/connection.svg);
-moz-context-properties: fill, fill-opacity;
}
#identity-popup[connection=secure-cert-user-overridden] #identity-popup-securityView,
@ -258,6 +259,7 @@
#identity-popup[mixedcontent~=active-loaded][isbroken] #identity-popup-securityView,
#identity-popup[mixedcontent~=active-loaded][isbroken] #identity-popup-security-content {
background-image: url(chrome://browser/skin/controlcenter/mcb-disabled.svg);
-moz-context-properties: fill, fill-opacity;
}
#identity-popup[connection=extension] #identity-popup-securityView,

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

@ -63,11 +63,15 @@
.customizationmode-checkbox,
.customizationmode-button {
color: rgb(71, 71, 71);
margin: 6px 10px;
padding: 2px 5px;
}
.customizationmode-checkbox:not(:-moz-lwtheme),
.customizationmode-button {
color: rgb(71, 71, 71);
}
#customization-reset-button,
#customization-undo-reset-button,
#customization-done-button {

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

@ -1,36 +1,7 @@
<?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/. -->
<svg xmlns="http://www.w3.org/2000/svg"
width="16" height="16" viewBox="0 0 16 16">
<defs>
<rect id="shape-lock-clasp-outer" x="4" y="2" width="8" height="10" rx="4" ry="4" />
<rect id="shape-lock-clasp-inner" x="6" y="4" width="4" height="6" rx="2" ry="2" />
<rect id="shape-lock-base" x="3" y="7" width="10" height="7" rx="1" ry="1" />
<mask id="mask-clasp-cutout">
<use href="#shape-lock-clasp-outer" fill="#fff"/>
<use href="#shape-lock-clasp-inner" fill="#000"/>
<line x1="2" y1="13" x2="14" y2="1.5" stroke="#000" stroke-width="2" />
<line x1="2" y1="15" x2="14" y2="3.5" stroke="#000" stroke-width="2" />
<rect x="3" y="7" width="10" height="7" rx="1" ry="1" fill="#000" />
</mask>
<mask id="mask-base-cutout">
<use href="#shape-lock-base" fill="#fff"/>
<line x1="2" y1="14.8" x2="14" y2="3.2" stroke="#000" stroke-width="1.8" />
</mask>
<g id="lock">
<use href="#shape-lock-clasp-outer" mask="url(#mask-clasp-cutout)"/>
<use href="#shape-lock-base" mask="url(#mask-base-cutout)"/>
</g>
<line id="strike-through-red" x1="2" y1="14.1" x2="14" y2="2.5" stroke="#d92d21" stroke-width="1.8"/>
</defs>
<use fill="context-fill" fill-opacity="context-fill-opacity" href="#lock"/>
<use href="#strike-through-red"/>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path d="M12.5 6.984h-.484L4 15h8.5a1.5 1.5 0 0 0 1.5-1.5V8.484a1.5 1.5 0 0 0-1.5-1.5zm-6.5 0V5a2 2 0 0 1 4 0v1l1.892-1.892A4 4 0 0 0 4 5v1.984h-.5a1.5 1.5 0 0 0-1.5 1.5V13.5a1.483 1.483 0 0 0 .07.43l6.946-6.946z" fill="context-fill" fill-opacity="context-fill-opacity"/>
<path d="M2 15a1 1 0 0 1-.707-1.707l12-12a1 1 0 0 1 1.414 1.414l-12 12A1 1 0 0 1 2 15z" fill="#ff0039"/>
</svg>

До

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

После

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

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

@ -1,34 +1,9 @@
<?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/. -->
<svg xmlns="http://www.w3.org/2000/svg"
width="16" height="16" viewBox="0 0 16 16">
<defs>
<rect id="shape-lock-clasp-outer" x="2" y="1" width="8" height="10" rx="4" ry="4" />
<rect id="shape-lock-clasp-inner" x="4" y="3" width="4" height="6" rx="2" ry="2" />
<rect id="shape-lock-base" x="1" y="6" width="10" height="7" rx="1" ry="1" />
<mask id="mask-clasp-cutout">
<rect width="16" height="16" fill="#000" />
<use href="#shape-lock-clasp-outer" fill="#fff"/>
<use href="#shape-lock-clasp-inner" fill="#000"/>
</mask>
<mask id="mask-lock">
<use href="#shape-lock-clasp-outer" mask="url(#mask-clasp-cutout)" fill="#fff"/>
<use href="#shape-lock-base" fill="#fff"/>
</mask>
<g id="warning-triangle">
<path fill="#fff" d="M10.5,5C9.8,5,9.1,5.4,8.8,6.2l-3.5,6.8c-0.4,0.7-0.4,1.4,0,2c0.4,0.6,1,1,1.8,1H14c0.8,0,1.4-0.4,1.8-1 c0.3-0.6,0.3-1.4,0-2l-3.5-6.8C11.9,5.4,11.2,5,10.5,5L10.5,5z"/>
<path fill="#ffbf00" d="M14.8,13.4l-3.5-6.8C11.2,6.2,10.9,6,10.5,6c-0.3,0-0.7,0.2-0.9,0.6l-3.5,6.8c-0.2,0.4-0.2,0.8,0,1.1C6.3,14.8,6.6,15,7,15 H14c0.4,0,0.7-0.2,0.9-0.5C15.1,14.2,15,13.8,14.8,13.4z"/>
<path fill="#fff" d="M10,8.5C10,8.2,10.2,8,10.5,8S11,8.2,11,8.5L10.8,11h-0.6L10,8.5z"/>
<circle fill="#fff" cx="10.5" cy="12.5" r=".75"/>
</g>
</defs>
<rect fill="context-fill" fill-opacity="context-fill-opacity" width="16" height="16" mask="url(#mask-lock)"/>
<use href="#warning-triangle"/>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path d="M8 1a4 4 0 0 0-4 4v1.984h-.5a1.5 1.5 0 0 0-1.5 1.5V13.5A1.5 1.5 0 0 0 3.5 15h2.535a2.274 2.274 0 0 1 .207-1.318L9.43 7.27a2.266 2.266 0 0 1 .2-.286H6V5a2 2 0 0 1 4 0v1.568A2.255 2.255 0 0 1 11.478 6a2.283 2.283 0 0 1 .522.073V5a4 4 0 0 0-4-4z" fill="context-fill" fill-opacity="context-fill-opacity"/>
<path d="M15.818 14.127l-3.189-6.411a1.285 1.285 0 0 0-2.3 0l-3.192 6.411A1.294 1.294 0 0 0 8.289 16h6.377a1.294 1.294 0 0 0 1.152-1.873z" fill="#ffbf00"/>
<path d="M11.478 8a.272.272 0 0 1 .256.161l3.188 6.412a.291.291 0 0 1-.013.291.275.275 0 0 1-.243.137H8.289a.275.275 0 0 1-.243-.137.29.29 0 0 1-.013-.291l3.188-6.412A.272.272 0 0 1 11.478 8m0-1a1.272 1.272 0 0 0-1.152.716l-3.189 6.411A1.294 1.294 0 0 0 8.289 16h6.377a1.294 1.294 0 0 0 1.152-1.873l-3.189-6.411A1.272 1.272 0 0 0 11.478 7z" fill="#d76e00" opacity=".35"/>
<path d="M11.5 12a.5.5 0 0 0 .5-.5v-2a.5.5 0 0 0-1 0v2a.5.5 0 0 0 .5.5zm0 .809a.691.691 0 1 0 .691.691.691.691 0 0 0-.691-.691z" fill="#fff"/>
</svg>

До

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

После

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

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

@ -17,13 +17,13 @@
}
#identity-box:hover:not(.no-hover):not([open=true]) {
background-color: hsla(240,5%,5%,.05);
background-color: hsla(0,0%,70%,.2);
fill-opacity: .8;
}
#identity-box:hover:active:not(.no-hover),
#identity-box[open=true] {
background-color: hsla(240,5%,5%,.1);
background-color: hsla(0,0%,70%,.3);
fill-opacity: .8;
}

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

@ -0,0 +1,4 @@
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg" width="631" height="36" viewBox="0 0 631 36"><style>.addressBarOutline{stroke:#b1b1b3;stroke-linejoin:round;stroke-width:1px}.addressBarIcons{fill:#b1b1b3;fill-rule:evenodd}</style><rect class="addressBarOutline" fill="#fff" x=".5" y=".5" width="630" height="35" rx="4" ry="4"/><rect class="addressBarOutline" fill="none" x="110.5" y="6.5" width="434" height="23" rx="4" ry="4"/><path class="addressBarIcons" d="M604 .5h.5v34h-.5V.5zM126.41 22l-3.09-3.085a3.881 3.881 0 0 0-.64-5.2 3.855 3.855 0 0 0-5.4 5.462 3.958 3.958 0 0 0 5.21.643l3.08 3.085a.622.622 0 0 0 .9 0 .677.677 0 0 0-.06-.9zm-6.23-2.764a2.571 2.571 0 1 1 2.57-2.57 2.652 2.652 0 0 1-2.57 2.574zM620.75 17.25h-7.5a.75.75 0 0 0 0 1.5h7.5a.75.75 0 0 0 0-1.5m0 3.75h-7.5a.75.75 0 0 0 0 1.5h7.5a.75.75 0 0 0 0-1.5m0-7.5h-7.5a.75.75 0 0 0 0 1.5h7.5a.75.75 0 0 0 0-1.5M585.77 13.5a.75.75 0 0 0-.52 1.28l3.18 3.22-3.18 3.22a.746.746 0 1 0 1.05 1.06l3.7-3.75a.774.774 0 0 0 0-1.06l-3.7-3.75a.754.754 0 0 0-.53-.22m4.44 0a.715.715 0 0 0-.52.22.754.754 0 0 0 0 1.06l3.17 3.22-3.17 3.22a.754.754 0 0 0 0 1.06.715.715 0 0 0 .52.22.754.754 0 0 0 .53-.22l3.69-3.75a.754.754 0 0 0 0-1.06l-3.69-3.75a.754.754 0 0 0-.53-.22M567.37 15.75h1.5a.375.375 0 1 0 0-.75h-1.5a.375.375 0 0 0 0 .75zm2.63-3h-9a1.5 1.5 0 0 0-1.5 1.5v7.5a1.5 1.5 0 0 0 1.5 1.5h9a1.5 1.5 0 0 0 1.5-1.5v-7.5a1.5 1.5 0 0 0-1.5-1.5zm-4.5 9H561v-7.5h4.5v7.5zm4.5 0h-3.75v-7.5H570v7.5zm-2.63-4.5h1.5a.375.375 0 1 0 0-.75h-1.5a.375.375 0 0 0 0 .75zm0 1.5h.75a.375.375 0 1 0 0-.75h-.75a.375.375 0 0 0 0 .75zM89.83 21.25a.375.375 0 1 1 .37-.375.356.356 0 0 1-.37.375m-2.6 1.5a.7.7 0 0 1-.742-.75v-4.95l2.961-3 2.97 3V22a.706.706 0 0 1-.74.75h-.74V19a.706.706 0 0 0-.74-.75h-1.49a.706.706 0 0 0-.74.75v3.75h-.739m2.219-10.5a.7.7 0 0 0-.51.225l-5.193 5.25a.738.738 0 1 0 1.037 1.05l.223-.225v4.2a1.5 1.5 0 0 0 1.482 1.5h5.931a1.491 1.491 0 0 0 1.48-1.5v-4.2l.22.225a.678.678 0 0 0 .52.225.663.663 0 0 0 .52-.225.725.725 0 0 0 0-1.05l-5.19-5.25a.709.709 0 0 0-.52-.225M70.375 13a.749.749 0 0 0-.75.75v1.808a5.245 5.245 0 1 0-.788 6.4.75.75 0 0 0-1.061-1.061 3.755 3.755 0 1 1 .776-4.151h-1.927a.75.75 0 0 0 0 1.5h3.75a.749.749 0 0 0 .75-.75v-3.75a.749.749 0 0 0-.75-.75M36.217 17.292h8.649l-3.206-3.2a.738.738 0 0 1 1.044-1.043l4.474 4.47a.72.72 0 0 1 0 1.043l-4.474 4.47a.72.72 0 0 1-1.044 0 .72.72 0 0 1 0-1.043l3.206-3.2h-8.649a.749.749 0 1 1 0-1.497z"/><circle class="addressBarOutline" fill="#f9f9fa" cx="18.5" cy="18" r="12"/><path class="addressBarIcons" d="M23.783 17.292h-8.649l3.206-3.2a.738.738 0 0 0-1.044-1.043l-4.474 4.47a.72.72 0 0 0 0 1.043l4.474 4.47a.72.72 0 0 0 1.044 0 .72.72 0 0 0 0-1.043l-3.206-3.2h8.649a.749.749 0 1 0 0-1.497z"/></svg>

После

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

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

@ -0,0 +1,4 @@
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg" width="631" height="36" viewBox="0 0 631 36"><style>.addressBarOutline{stroke:#b1b1b3;stroke-linejoin:round;stroke-width:1px}.addressBarIcons{fill:#b1b1b3}.addressBarIcons,.searchBarIcons{fill-rule:evenodd}.searchBarFill{fill:#0a84ff}.searchBarOutline{fill-opacity:.2;stroke:#0a84ff}</style><rect class="addressBarOutline" fill="#fff" x=".5" y=".5" width="630" height="35" rx="4" ry="4"/><rect class="addressBarOutline" fill="none" x="110.5" y="6.5" width="314" height="23" rx="4" ry="4"/><path class="addressBarIcons" d="M604 .5h.5v34h-.5V.5zM126.41 22l-3.09-3.085a3.881 3.881 0 0 0-.64-5.2 3.855 3.855 0 0 0-5.4 5.462 3.958 3.958 0 0 0 5.21.643l3.08 3.085a.622.622 0 0 0 .9 0 .677.677 0 0 0-.06-.9zm-6.23-2.764a2.571 2.571 0 1 1 2.57-2.57 2.652 2.652 0 0 1-2.57 2.574z"/><rect class="addressBarOutline searchBarFill searchBarOutline" x="429.5" y="6.5" width="115" height="23" rx="4" ry="4"/><path class="searchBarFill searchBarIcons" d="M445.41 22l-3.09-3.085a3.881 3.881 0 0 0-.64-5.2 3.855 3.855 0 0 0-5.4 5.462 3.958 3.958 0 0 0 5.21.643l3.08 3.085a.622.622 0 0 0 .9 0 .677.677 0 0 0-.06-.9zm-6.23-2.764a2.571 2.571 0 1 1 2.57-2.57 2.652 2.652 0 0 1-2.57 2.574z"/><path class="addressBarIcons" d="M620.75 17.25h-7.5a.75.75 0 0 0 0 1.5h7.5a.75.75 0 0 0 0-1.5m0 3.75h-7.5a.75.75 0 0 0 0 1.5h7.5a.75.75 0 0 0 0-1.5m0-7.5h-7.5a.75.75 0 0 0 0 1.5h7.5a.75.75 0 0 0 0-1.5M585.77 13.5a.75.75 0 0 0-.52 1.28l3.18 3.22-3.18 3.22a.746.746 0 1 0 1.05 1.06l3.7-3.75a.774.774 0 0 0 0-1.06l-3.7-3.75a.754.754 0 0 0-.53-.22m4.44 0a.715.715 0 0 0-.52.22.754.754 0 0 0 0 1.06l3.17 3.22-3.17 3.22a.754.754 0 0 0 0 1.06.715.715 0 0 0 .52.22.754.754 0 0 0 .53-.22l3.69-3.75a.754.754 0 0 0 0-1.06l-3.69-3.75a.754.754 0 0 0-.53-.22M567.37 15.75h1.5a.375.375 0 1 0 0-.75h-1.5a.375.375 0 0 0 0 .75zm2.63-3h-9a1.5 1.5 0 0 0-1.5 1.5v7.5a1.5 1.5 0 0 0 1.5 1.5h9a1.5 1.5 0 0 0 1.5-1.5v-7.5a1.5 1.5 0 0 0-1.5-1.5zm-4.5 9H561v-7.5h4.5v7.5zm4.5 0h-3.75v-7.5H570v7.5zm-2.63-4.5h1.5a.375.375 0 1 0 0-.75h-1.5a.375.375 0 0 0 0 .75zm0 1.5h.75a.375.375 0 1 0 0-.75h-.75a.375.375 0 0 0 0 .75zM89.83 21.25a.375.375 0 1 1 .37-.375.356.356 0 0 1-.37.375m-2.6 1.5a.7.7 0 0 1-.742-.75v-4.95l2.961-3 2.97 3V22a.706.706 0 0 1-.74.75h-.74V19a.706.706 0 0 0-.74-.75h-1.49a.706.706 0 0 0-.74.75v3.75h-.739m2.219-10.5a.7.7 0 0 0-.51.225l-5.193 5.25a.738.738 0 1 0 1.037 1.05l.223-.225v4.2a1.5 1.5 0 0 0 1.482 1.5h5.931a1.491 1.491 0 0 0 1.48-1.5v-4.2l.22.225a.678.678 0 0 0 .52.225.663.663 0 0 0 .52-.225.725.725 0 0 0 0-1.05l-5.19-5.25a.709.709 0 0 0-.52-.225M70.375 13a.749.749 0 0 0-.75.75v1.808a5.245 5.245 0 1 0-.788 6.4.75.75 0 0 0-1.061-1.061 3.755 3.755 0 1 1 .776-4.151h-1.927a.75.75 0 0 0 0 1.5h3.75a.749.749 0 0 0 .75-.75v-3.75a.749.749 0 0 0-.75-.75M36.217 17.292h8.649l-3.206-3.2a.738.738 0 0 1 1.044-1.043l4.474 4.47a.72.72 0 0 1 0 1.043l-4.474 4.47a.72.72 0 0 1-1.044 0 .72.72 0 0 1 0-1.043l3.206-3.2h-8.649a.749.749 0 1 1 0-1.497z"/><circle class="addressBarOutline" fill="#f9f9fa" cx="18.5" cy="18" r="12"/><path class="addressBarIcons" d="M23.783 17.292h-8.649l3.206-3.2a.738.738 0 0 0-1.044-1.043l-4.474 4.47a.72.72 0 0 0 0 1.043l4.474 4.47a.72.72 0 0 0 1.044 0 .72.72 0 0 0 0-1.043l-3.206-3.2h8.649a.749.749 0 1 0 0-1.497z"/></svg>

После

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

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

@ -2,9 +2,28 @@
* 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/. */
#defaultEngine {
margin-inline-start: 0;
}
.searchBarImage {
height: 36px;
width: 631px;
margin-left: 33px;
}
.searchBarHiddenImage {
list-style-image: url("chrome://browser/skin/preferences/in-content/no-search-bar.svg");
}
#searchBarShownRadio {
/* Allow a little visual space to separate the radio from the image above it. */
margin-top: 10px;
}
.searchBarShownImage {
list-style-image: url("chrome://browser/skin/preferences/in-content/search-bar.svg");
}
#defaultEngine {
margin-inline-start: 0;
}
#defaultEngine > .menulist-label-box > .menulist-icon {
height: 16px;

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

@ -21,8 +21,8 @@
skin/classic/browser/addons/addon-install-restart.svg (../shared/addons/addon-install-restart.svg)
skin/classic/browser/addons/addon-install-warning.svg (../shared/addons/addon-install-warning.svg)
* skin/classic/browser/controlcenter/conn-not-secure.svg (../shared/controlcenter/conn-not-secure.svg)
* skin/classic/browser/controlcenter/connection.svg (../shared/controlcenter/connection.svg)
* skin/classic/browser/controlcenter/mcb-disabled.svg (../shared/controlcenter/mcb-disabled.svg)
skin/classic/browser/controlcenter/connection.svg (../shared/controlcenter/connection.svg)
skin/classic/browser/controlcenter/mcb-disabled.svg (../shared/controlcenter/mcb-disabled.svg)
skin/classic/browser/controlcenter/extension.svg (../shared/controlcenter/extension.svg)
* skin/classic/browser/controlcenter/permissions.svg (../shared/controlcenter/permissions.svg)
* skin/classic/browser/controlcenter/tracking-protection.svg (../shared/controlcenter/tracking-protection.svg)
@ -97,10 +97,12 @@
skin/classic/browser/preferences/in-content/general.svg (../shared/incontentprefs/general.svg)
skin/classic/browser/preferences/in-content/logo-android.svg (../shared/incontentprefs/logo-android.svg)
skin/classic/browser/preferences/in-content/logo-ios.svg (../shared/incontentprefs/logo-ios.svg)
skin/classic/browser/preferences/in-content/no-search-bar.svg (../shared/incontentprefs/no-search-bar.svg)
skin/classic/browser/preferences/in-content/no-search-results.svg (../shared/incontentprefs/no-search-results.svg)
skin/classic/browser/preferences/in-content/privacy-security.svg (../shared/incontentprefs/privacy-security.svg)
skin/classic/browser/preferences/in-content/privacy.css (../shared/incontentprefs/privacy.css)
skin/classic/browser/preferences/in-content/search-arrow-indicator.svg (../shared/incontentprefs/search-arrow-indicator.svg)
skin/classic/browser/preferences/in-content/search-bar.svg (../shared/incontentprefs/search-bar.svg)
skin/classic/browser/preferences/in-content/search.css (../shared/incontentprefs/search.css)
skin/classic/browser/preferences/in-content/search.svg (../shared/incontentprefs/search.svg)
skin/classic/browser/preferences/in-content/siteDataSettings.css (../shared/incontentprefs/siteDataSettings.css)

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

@ -162,6 +162,10 @@
opacity: 1;
}
#TabsToolbar[brighttext] .tabbrowser-tab:not([visuallyselected=true]) {
--tab-loading-fill: #fff;
}
.tab-sharing-icon-overlay,
.tab-icon-image {
height: 16px;

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

@ -124,8 +124,6 @@ toolbar .toolbarbutton-1 > .toolbarbutton-text,
toolbar .toolbarbutton-1 > .toolbarbutton-badge-stack {
padding: var(--toolbarbutton-inner-padding);
border-radius: var(--toolbarbutton-border-radius);
transition-property: background-color, border-color, box-shadow;
transition-duration: var(--toolbarbutton-hover-transition-duration);
}
toolbar .toolbarbutton-1 > .toolbarbutton-icon {
@ -228,6 +226,8 @@ toolbar .toolbarbutton-1[checked]:not(:active):hover > .toolbarbutton-icon {
border-radius: 10000px;
width: 32px;
padding: 7px;
transition-property: box-shadow;
transition-duration: var(--toolbarbutton-hover-transition-duration);
}
:root[uidensity=touch] #back-button {

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

@ -14,6 +14,7 @@
padding: 0;
margin: 0 5px;
min-height: 30px;
overflow: -moz-hidden-unscrollable;
}
#urlbar:hover,
@ -180,12 +181,6 @@
padding: 7px;
}
.urlbar-icon,
.urlbar-icon-wrapper {
transition-property: background-color;
transition-duration: var(--toolbarbutton-hover-transition-duration);
}
.urlbar-icon:hover,
.urlbar-icon-wrapper:hover {
background-color: hsla(0,0%,80%,.4);
@ -194,7 +189,6 @@
.urlbar-icon:hover:active,
.urlbar-icon-wrapper:hover:active {
background-color: hsla(0,0%,80%,.45);
transition-duration: var(--toolbarbutton-active-transition-duration);
}
.urlbar-icon-wrapper > .urlbar-icon:hover,

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

@ -593,8 +593,6 @@ html|*.urlbar-input:-moz-lwtheme::placeholder,
outline-offset: -3px;
}
/* page proxy icon */
%include ../shared/identity-block/identity-block.inc.css
/* autocomplete */

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

@ -9,7 +9,7 @@ textbox,
description,
.tab-text,
caption > label {
font-size: 1.2rem;
font-size: 1.25rem;
}
/* Create a separate rule to unset these styles on .tree-input instead of

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

@ -4,6 +4,21 @@
%include ../../../shared/incontentprefs/preferences.inc.css
html *,
page *,
window * {
font-size: 1.25rem;
}
caption > label:not(.dialogTitle) {
font-size: 1.42rem;
}
.tip-caption,
.help-button {
font-size: 1.08rem;
}
.actionsMenu > .menulist-label-box > .menulist-icon {
margin-inline-end: 9px;
}

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

@ -827,13 +827,6 @@ SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt){
# define SQLITE_TCLAPI
#endif
/*
** Make sure that rand_s() is available on Windows systems with MSVC 2005
** or higher.
*/
#if defined(_MSC_VER) && _MSC_VER>=1400
# define _CRT_RAND_S
#endif
/*
** Include the header file used to customize the compiler options for MSVC.
@ -43927,9 +43920,6 @@ static int winRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
EntropyGatherer e;
UNUSED_PARAMETER(pVfs);
memset(zBuf, 0, nBuf);
#if defined(_MSC_VER) && _MSC_VER>=1400 && !SQLITE_OS_WINCE
rand_s((unsigned int*)zBuf); /* rand_s() is not available with MinGW */
#endif /* defined(_MSC_VER) && _MSC_VER>=1400 */
e.a = (unsigned char*)zBuf;
e.na = nBuf;
e.nXor = 0;

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

@ -43,39 +43,39 @@ module.exports = envConfig => {
{
test: /event-emitter/,
exclude: /node_modules/,
loaders: [path.join(__dirname, "./webpack/rewrite-event-emitter")],
loaders: ["rewrite-event-emitter"],
}, {
test: /client(\/|\\)inspector(\/|\\).*\.js$/,
loaders: [
// Replace all references to this.browserRequire() by require()
path.join(__dirname, "./webpack/rewrite-browser-require"),
"rewrite-browser-require",
// Replace all references to loader.lazyRequire() by require()
path.join(__dirname, "./webpack/rewrite-lazy-require"),
"rewrite-lazy-require",
],
}, {
test: /shared(\/|\\)inspector(\/|\\)css-logic\.js$/,
loaders: [
// Replace a very specific lazy importer, which should really be moved to
// /server ...
path.join(__dirname, "./webpack/rewrite-css-logic-importer"),
"rewrite-css-logic-importer",
],
}, {
test: /react-redux\.js$/,
loaders: [
// Replace dynamic paths in react-redux file
path.join(__dirname, "./webpack/rewrite-react-redux"),
"rewrite-react-redux",
],
}, {
// Replace all references sdk's lazyRequire by require()
test: /sdk(\/|\\).*\.js$/,
loaders: [path.join(__dirname, "./webpack/rewrite-sdk-lazy-require")],
loaders: ["rewrite-sdk-lazy-require"],
}
]
},
resolveLoader: {
root: [
path.resolve("./node_modules"),
path.resolve("./webpack"),
path.resolve("../shared/webpack"),
]
},
resolve: {

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

@ -17,6 +17,7 @@ const EventEmitter = require("devtools-modules/src/utils/event-emitter");
const { Services: { appinfo, pref }} = require("devtools-modules");
// Initialize preferences as early as possible
pref("devtools.theme", "light");
pref("devtools.cache.disabled", false);
pref("devtools.netmonitor.enabled", true);
pref("devtools.netmonitor.filters", "[\"all\"]");

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

@ -9,8 +9,8 @@
"codemirror": "^5.24.2",
"devtools-config": "=0.0.12",
"devtools-contextmenu": "=0.0.3",
"devtools-launchpad": "=0.0.88",
"devtools-modules": "=0.0.27",
"devtools-launchpad": "=0.0.96",
"devtools-modules": "=0.0.31",
"devtools-source-editor": "=0.0.3",
"immutable": "^3.8.1",
"jszip": "^3.1.3",

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

@ -18,11 +18,39 @@ let webpackConfig = {
},
module: {
loaders: [
rules: [
{
test: /\.(png|svg)$/,
loader: "file-loader?name=[path][name].[ext]",
},
{
/*
* The version of webpack used in the launchpad seems to have trouble
* with the require("raw!${file}") that we use for the properties
* file in l10.js.
* This loader goes through the whole code and remove the "raw!" prefix
* so the raw-loader declared in devtools-launchpad config can load
* those files.
*/
test: /\.js$/,
loader: "rewrite-raw",
},
{
test: /\.js$/,
loaders: [
// Replace all references to this.browserRequire() by require()
"rewrite-browser-require",
// Replace all references to loader.lazyRequire() by require()
"rewrite-lazy-require",
],
}
]
},
resolveLoader: {
modules: [
path.resolve("./node_modules"),
path.resolve("../shared/webpack"),
]
},
@ -33,16 +61,22 @@ let webpackConfig = {
libraryTarget: "umd",
},
// Fallback compatibility for npm link
resolve: {
fallback: path.join(__dirname, "node_modules"),
modules: [
// Make sure webpack is always looking for modules in
// `webconsole/node_modules` directory first.
path.resolve(__dirname, "node_modules"), "node_modules"
],
alias: {
"Services": "devtools-modules/src/Services",
"react": path.join(__dirname, "node_modules/react"),
"devtools/client/framework/devtools": path.join(__dirname, "../../client/shims/devtools"),
"devtools/client/framework/menu": "devtools-modules/src/menu",
"devtools/client/framework/menu-item": path.join(__dirname, "../../client/framework/menu-item"),
"devtools/client/locales": path.join(__dirname, "../../client/locales/en-US"),
"devtools/client/netmonitor/src/utils/menu": "devtools-contextmenu",
"devtools/client/shared/components/autocomplete-popup": path.join(__dirname, "../../client/shared/components/autocomplete-popup"),
"devtools/client/shared/components/reps/reps": path.join(__dirname, "../../client/shared/components/reps/reps"),
"devtools/client/shared/components/search-box": path.join(__dirname, "../../client/shared/components/search-box"),
@ -60,6 +94,7 @@ let webpackConfig = {
"devtools/client/shared/prefs": path.join(__dirname, "../../client/shared/prefs"),
"devtools/client/shared/scroll": path.join(__dirname, "../../client/shared/scroll"),
"devtools/client/shared/source-utils": path.join(__dirname, "../../client/shared/source-utils"),
"devtools/client/shared/theme": path.join(__dirname, "../../client/shared/theme"),
"devtools/client/shared/vendor/immutable": "immutable",
"devtools/client/shared/vendor/react": "react",
"devtools/client/shared/vendor/react-dom": "react-dom",
@ -71,7 +106,10 @@ let webpackConfig = {
"devtools/client/shared/widgets/tooltip/ImageTooltipHelper": path.join(__dirname, "../../client/shared/widgets/tooltip/ImageTooltipHelper"),
"devtools/client/shared/widgets/tooltip/TooltipToggle": path.join(__dirname, "../../client/shared/widgets/tooltip/TooltipToggle"),
"devtools/client/shared/widgets/Chart": path.join(__dirname, "../../client/shared/widgets/Chart"),
"devtools/client/sourceeditor/editor": "devtools-source-editor/src/source-editor",
"devtools/client/themes/variables.css": path.join(__dirname, "../../client/themes/variables.css"),
"devtools/shared/async-utils": path.join(__dirname, "../../shared/async-utils"),
"devtools/shared/defer": path.join(__dirname, "../../shared/defer"),
"devtools/shared/old-event-emitter": "devtools-modules/src/utils/event-emitter",
@ -80,9 +118,16 @@ let webpackConfig = {
"devtools/shared/locales": path.join(__dirname, "../../shared/locales/en-US"),
"devtools/shared/platform/clipboard": path.join(__dirname, "../../shared/platform/content/clipboard"),
"devtools/shared/plural-form": path.join(__dirname, "../../shared/plural-form"),
"devtools/shared/css/color": path.join(__dirname, "../../shared/css/color"),
"devtools/shared/css/color-db": path.join(__dirname, "../../shared/css/color-db"),
"devtools/shared/css/lexer": path.join(__dirname, "../../shared/css/lexer"),
"devtools/shared/css/parsing-utils": path.join(__dirname, "../../shared/css/parsing-utils"),
"devtools/shared/css/properties-db": path.join(__dirname, "../../shared/css/properties-db"),
"devtools/shared/css/generated/properties-db": path.join(__dirname, "../../shared/css/generated/properties-db"),
"devtools/shared/task": path.join(__dirname, "../../shared/task"),
"devtools/shim/locales": path.join(__dirname, "../../shared/locales/en-US"),
"toolkit/locales": path.join(__dirname, "../../../toolkit/locales/en-US"),
"Services": "devtools-modules/src/Services",
},
},
};
@ -114,19 +159,18 @@ const mappings = [
webpackConfig.plugins = mappings.map(([regex, res]) =>
new NormalModuleReplacementPlugin(regex, res));
// Exclude to transpile all scripts in devtools/ but not for this folder
const basePath = path.join(__dirname, "../../").replace(/\\/g, "\\\\");
const baseName = path.basename(__dirname);
webpackConfig.babelExcludes = new RegExp(`^${basePath}(.(?!${baseName}))*$`);
let config = toolboxConfig(webpackConfig, getConfig());
let config = toolboxConfig(webpackConfig, getConfig(), {
// Exclude to transpile all scripts in devtools/ but not for this folder
babelExcludes: new RegExp(`^${basePath}(.(?!${baseName}))*$`)
});
// Remove loaders from devtools-launchpad's webpack.config.js
// * For svg-inline loader:
// Netmonitor uses file loader to bundle image assets instead of svg-inline loader
// * For raw loader:
// devtools/shared/l10n has preloaded raw loader in require.context
config.module.loaders = config.module.loaders
.filter((loader) => !["svg-inline", "raw"].includes(loader.loader));
// Netmonitor uses file loader to bundle image assets instead of svg-inline-loader
config.module.rules = config.module.rules
.filter((rule) => !["svg-inline-loader"].includes(rule.loader));
module.exports = config;

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -11,7 +11,7 @@
const Services = require("Services");
const variableFileContents = require("raw!devtools/client/themes/variables.css");
const variableFileContents = require("theme-loader!devtools/client/themes/variables.css");
const THEME_SELECTOR_STRINGS = {
light: ":root.theme-light {",

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

@ -0,0 +1,29 @@
# Webpack Support
This directory contains modules intended to support and customize
DevTools source bundling.
DevTools use Webpack to generate bundles for individual tools,
which allow e.g. running them on top of the Launchpad (within
a browser tab).
Custom loaders implemented in this directory are mostly used to
rewrite existing code, so it's understandable for Webpack.
For example:
The following piece of code is using `lazyRequireGetter` that
is unknown to Webpack.
```
loader.lazyRequireGetter(this, "EventEmitter",
"devtools/shared/old-event-emitter");
```
In order to properly bundle `devtools/shared/old-event-emitter` module
the code needs to be translated into:
```
let EventEmitter = require("devtools/shared/old-event-emitter");
```
See more in `rewrite-lazy-require`

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

@ -0,0 +1,29 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
var fs = require("fs");
/**
* Make sure that content of the file is loaded as a text
* (no parsing by other loaders)
*
* Used e.g. for runtime access to colors defined in variables.css
*/
module.exports.pitch = function (remainingRequest, precedingRequest, data) {
if (this.cacheable) {
this.cacheable();
}
let request = remainingRequest.split("!");
let rawUrl = request[request.length - 1];
let content = fs.readFileSync(rawUrl, "utf8");
// Avoid mix of single & double quotes in a string
// (use only double quotes), so we can stringify.
content = content.replace("'", '"');
return "module.exports = " + JSON.stringify(content) + ";";
};

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

@ -235,5 +235,5 @@
}
.show-presets #toggle-presets {
filter: url(chrome://devtools/skin/images/filters.svg#checked-icon-state);
filter: var(--theme-icon-checked-filter);
}

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

@ -358,6 +358,7 @@ StyleSheetEditor.prototype = {
// We just applied an edit in the editor, so we can drop this
// notification.
this._isUpdating = false;
this.emit("style-applied");
} else if (this.sourceEditor) {
this._getSourceTextAndPrettify().then((newText) => {
this._justSetText = true;
@ -742,6 +743,9 @@ StyleSheetEditor.prototype = {
let decoder = new TextDecoder();
let text = decoder.decode(array);
// Ensure we don't re-fetch the text from the original source
// actor when we're notified that the style sheet changed.
this._isUpdating = true;
let relatedSheet = this.styleSheet.relatedStyleSheet;
relatedSheet.update(text, this.transitionsEnabled);
}, this.markLinkedFileBroken);

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

@ -38,6 +38,7 @@ support-files =
sourcemap-css/test-bootstrap-scss.css
sourcemap-css/test-stylus.css
sourcemap-sass/sourcemaps.scss
sourcemap-sass/sourcemaps.scss^headers^
sourcemap-sass/media-rules.scss
sourcemap-styl/test-stylus.styl
sourcemaps.html

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

@ -17,9 +17,9 @@ waitForExplicitFinish();
add_task(function* () {
Services.prefs.setBoolPref(MAP_PREF, true);
let { ui } = yield openStyleEditorForURL(TESTCASE_URI);
let { ui, onMediaListChanged } = yield openStyleEditorForURL(TESTCASE_URI);
yield listenForMediaChange(ui);
yield onMediaListChanged;
is(ui.editors.length, 1, "correct number of editors");
@ -58,14 +58,6 @@ function openEditor(editor) {
return editor.getSourceEditor();
}
function listenForMediaChange(UI) {
return new Promise(resolve => {
UI.once("media-list-changed", () => {
resolve();
});
});
}
function getLinkFor(editor) {
return editor.summary.querySelector(".stylesheet-name");
}

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

@ -73,6 +73,9 @@ add_task(function* () {
color = yield getComputedStyleProperty({selector: "div", name: "color"});
is(color, "rgb(0, 0, 255)", "div is blue after saving file");
// Ensure that the editor didn't revert. Bug 1346662.
is(editor.sourceEditor.getText(), CSS_TEXT, "edits remain applied");
});
function editSCSS(editor) {

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

@ -82,7 +82,15 @@ var openStyleEditor = Task.async(function* (tab) {
let panel = toolbox.getPanel("styleeditor");
let ui = panel.UI;
return { toolbox, panel, ui };
// This event is sometimes needed by tests, but may be emitted before the list
// animation is done. So we listen to it here so tests don't have to and can't miss it.
let onMediaListChanged = ui.once("media-list-changed");
// The stylesheet list appears with an animation. Let this animation finish.
let animations = ui._root.getAnimations({subtree: true});
yield Promise.all(animations.map(a => a.finished));
return { toolbox, panel, ui, onMediaListChanged };
});
/**

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

@ -0,0 +1,2 @@
X-Content-Type-Options: nosniff
Content-Type: text/plain

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

@ -536,12 +536,12 @@ body {
}
.animation-target .node-highlighter:hover {
filter: url(images/filters.svg#checked-icon-state);
filter: var(--theme-icon-checked-filter);
}
.animation-target .node-highlighter:active,
.animation-target .node-highlighter.selected {
filter: url(images/filters.svg#checked-icon-state) brightness(0.9);
filter: var(--theme-icon-checked-filter) brightness(0.9);
}
/* Inline keyframes info in the timeline */

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

@ -9,6 +9,8 @@
font: message-box;
--tab-line-selected-color: var(--blue-50);
/* Introduce a specific variable here to be able to special-case firebug theme */
--toolbar-icon-checked-filter: var(--theme-icon-checked-filter);
}
:root.theme-light {
@ -34,6 +36,9 @@
:root.theme-firebug {
--proportional-font-family: Lucida Grande, Tahoma, sans-serif;
/* Do not use filters for Firebug checked icons: they are images, not SVGs */
--toolbar-icon-checked-filter: none;
}
.devtools-monospace {
@ -310,7 +315,7 @@ checkbox:-moz-focusring {
.devtools-button.checked::before,
.devtools-toolbarbutton:not([label])[checked=true] > image,
.devtools-toolbarbutton:not([label])[open=true] > image {
filter: var(--theme-icon-checked-filter);
filter: var(--toolbar-icon-checked-filter);
}
/* Button states */

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

@ -601,14 +601,14 @@
}
.ruleview-selectorhighlighter:hover {
filter: url(images/filters.svg#checked-icon-state);
filter: var(--theme-icon-checked-filter);
}
.ruleview-grid.active,
.ruleview-selectorhighlighter:active,
.ruleview-selectorhighlighter.highlighted,
.ruleview-shape.active {
filter: url(images/filters.svg#checked-icon-state) brightness(0.9);
filter: var(--theme-icon-checked-filter) brightness(0.9);
}
#ruleview-add-rule-button::before {

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

@ -229,7 +229,7 @@
/* Icon filters */
--theme-icon-filter: none;
--theme-icon-selected-filter: none;
--theme-icon-checked-filter: none;
--theme-icon-checked-filter: url(chrome://devtools/skin/images/filters.svg#icon-checked-light);
/* Font size */
--theme-toolbar-font-size: 12px;

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