Merge mozilla-central to mozilla-inbound r=merge a=merge on a CLOSED TREE

This commit is contained in:
Andreea Pavel 2017-12-22 11:59:03 +02:00
Родитель 2e497a02f6 78bc55ae1f
Коммит e2b89c47ae
258 изменённых файлов: 2298 добавлений и 2521 удалений

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

@ -6609,7 +6609,7 @@ var CanvasPermissionPromptHelper = {
let message = gNavigatorBundle.getFormattedString("canvas.siteprompt", [ uri.asciiHost ]);
function setCanvasPermission(aURI, aPerm, aPersistent) {
Services.perms.add(aURI, "canvas/extractData", aPerm,
Services.perms.add(aURI, "canvas", aPerm,
aPersistent ? Ci.nsIPermissionManager.EXPIRE_NEVER
: Ci.nsIPermissionManager.EXPIRE_SESSION);
}

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

@ -815,6 +815,8 @@
tooltiptext="&urlbar.persistentStorageBlocked.tooltip;"/>
<image data-permission-id="popup" class="blocked-permission-icon popup-icon" role="button"
tooltiptext="&urlbar.popupBlocked.tooltip;"/>
<image data-permission-id="canvas" class="blocked-permission-icon canvas-icon" role="button"
tooltiptext="&urlbar.canvasBlocked.tooltip;"/>
</box>
<box id="notification-popup-box"
hidden="true"

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

@ -8,7 +8,7 @@
const kUrl = "https://example.com/";
const kPrincipal = Services.scriptSecurityManager.createCodebasePrincipal(Services.io.newURI(kUrl), {});
const kPermission = "canvas/extractData";
const kPermission = "canvas";
function initTab() {
let contentWindow = content.wrappedJSObject;

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

@ -1053,9 +1053,11 @@ this.PanelMultiView = class {
let keyCode = event.code;
switch (keyCode) {
case "ArrowDown":
case "ArrowUp": {
case "ArrowUp":
case "Tab": {
stop();
let isDown = (keyCode == "ArrowDown");
let isDown = (keyCode == "ArrowDown") ||
(keyCode == "Tab" && !event.shiftKey);
let button = this._updateSelectedKeyNav(navMap, buttons, isDown);
button.focus();
break;

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

@ -142,3 +142,97 @@ add_task(async function testLeftRightKeys() {
await promise;
});
add_task(async function testTabKey() {
let promise = promisePanelShown(window);
PanelUI.show();
await promise;
let buttons = gHelperInstance._getNavigableElements(PanelUI.mainView);
for (let button of buttons) {
if (button.disabled)
continue;
EventUtils.synthesizeKey("KEY_Tab", { code: "Tab" });
Assert.equal(document.commandDispatcher.focusedElement, button,
"The correct button should be focused after tabbing");
}
EventUtils.synthesizeKey("KEY_Tab", { code: "Tab" });
Assert.equal(document.commandDispatcher.focusedElement, buttons[0],
"Pressing tab should cycle around and select the first button again");
for (let i = buttons.length - 1; i >= 0; --i) {
let button = buttons[i];
if (button.disabled)
continue;
EventUtils.synthesizeKey("Tab", { code: "Tab", shiftKey: true });
Assert.equal(document.commandDispatcher.focusedElement, button,
"The correct button should be focused after shift + tabbing");
}
EventUtils.synthesizeKey("KEY_Tab", { code: "Tab", shiftKey: true });
Assert.equal(document.commandDispatcher.focusedElement, buttons[buttons.length - 1],
"Pressing shift + tab should cycle around and select the last button again");
promise = promisePanelHidden(window);
PanelUI.hide();
await promise;
});
add_task(async function testInterleavedTabAndArrowKeys() {
let promise = promisePanelShown(window);
PanelUI.show();
await promise;
let buttons = gHelperInstance._getNavigableElements(PanelUI.mainView);
let tab = false;
for (let button of buttons) {
if (button.disabled)
continue;
if (tab) {
EventUtils.synthesizeKey("KEY_Tab", { code: "Tab" });
} else {
EventUtils.synthesizeKey("KEY_ArrowDown", { code: "ArrowDown" });
}
tab = !tab;
}
Assert.equal(document.commandDispatcher.focusedElement, buttons[buttons.length - 1],
"The last button should be focused after a mix of Tab and ArrowDown");
promise = promisePanelHidden(window);
PanelUI.hide();
await promise;
});
add_task(async function testSpaceDownAfterTabNavigation() {
let promise = promisePanelShown(window);
PanelUI.show();
await promise;
let buttons = gHelperInstance._getNavigableElements(PanelUI.mainView);
let button;
for (button of buttons) {
if (button.disabled)
continue;
EventUtils.synthesizeKey("KEY_Tab", { code: "Tab" });
if (button.id == kHelpButtonId) {
break;
}
}
Assert.equal(document.commandDispatcher.focusedElement, button,
"Help button should be focused after tabbing to it.");
// Pressing down space on a button that points to a subview should navigate us
// there, before keyup.
promise = BrowserTestUtils.waitForEvent(PanelUI.helpView, "ViewShown");
EventUtils.synthesizeKey(" ", { code: "Space", type: "keydown" });
await promise;
promise = promisePanelHidden(window);
PanelUI.hide();
await promise;
});

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

@ -33,18 +33,7 @@ async function testThemeWithInvalidProperties(invalidProps) {
});
let extension = ExtensionTestUtils.loadExtension({manifest});
SimpleTest.waitForExplicitFinish();
let waitForConsole = new Promise(resolve => {
SimpleTest.monitorConsole(resolve, [{
message: /Reading manifest: Themes defined in the manifest may only contain static resources/,
}]);
});
await Assert.rejects(extension.startup(), null, "Theme should fail to load if it contains invalid properties");
SimpleTest.endMonitorConsole();
await waitForConsole;
}
add_task(async function test_that_theme_with_invalid_properties_fails_to_load() {

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

@ -14,8 +14,6 @@ export MOZILLA_OFFICIAL=1
# Enable Telemetry
export MOZ_TELEMETRY_REPORTING=1
ac_add_options --disable-stdcxx-compat
# Don't autoclobber l10n, as this can lead to missing binaries and broken builds
# Bug 1283438
mk_add_options AUTOCLOBBER=

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

@ -14,8 +14,6 @@ export MOZILLA_OFFICIAL=1
# Enable Telemetry
export MOZ_TELEMETRY_REPORTING=1
ac_add_options --disable-stdcxx-compat
# Don't autoclobber l10n, as this can lead to missing binaries and broken builds
# Bug 1283438
mk_add_options AUTOCLOBBER=

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

@ -9,8 +9,6 @@ export MOZILLA_OFFICIAL=1
# Enable Telemetry
export MOZ_TELEMETRY_REPORTING=1
ac_add_options --disable-stdcxx-compat
# Don't autoclobber l10n, as this can lead to missing binaries and broken builds
# Bug 1283438
mk_add_options AUTOCLOBBER=

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

@ -9,8 +9,6 @@ export MOZILLA_OFFICIAL=1
# Enable Telemetry
export MOZ_TELEMETRY_REPORTING=1
ac_add_options --disable-stdcxx-compat
# Don't autoclobber l10n, as this can lead to missing binaries and broken builds
# Bug 1283438
mk_add_options AUTOCLOBBER=

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

@ -10,7 +10,7 @@ ac_add_options --enable-valgrind
. $topsrcdir/build/unix/mozconfig.fuzzing
ac_add_options --enable-fuzzing
ac_add_options --disable-stdcxx-compat
unset MOZ_STDCXX_COMPAT
export PKG_CONFIG_LIBDIR=/usr/lib64/pkgconfig:/usr/share/pkgconfig
. $topsrcdir/build/unix/mozconfig.gtk

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

@ -78,9 +78,9 @@ for (const type of [
"TELEMETRY_PERFORMANCE_EVENT",
"TELEMETRY_UNDESIRED_EVENT",
"TELEMETRY_USER_EVENT",
"TOP_SITES_ADD",
"TOP_SITES_CANCEL_EDIT",
"TOP_SITES_EDIT",
"TOP_SITES_INSERT",
"TOP_SITES_PIN",
"TOP_SITES_UNPIN",
"TOP_SITES_UPDATED",

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

@ -51,7 +51,7 @@ this.PrerenderData = new _PrerenderData({
"migrationExpired": true,
"showTopSites": true,
"showSearch": true,
"topSitesCount": 6,
"topSitesCount": 12,
"collapseTopSites": false,
"section.highlights.collapsed": false,
"section.topstories.collapsed": false,
@ -67,6 +67,7 @@ this.PrerenderData = new _PrerenderData({
validation: [
"showTopSites",
"showSearch",
"topSitesCount",
"collapseTopSites",
"section.highlights.collapsed",
"section.topstories.collapsed",

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

@ -28,7 +28,7 @@ const INITIAL_STATE = {
// context menu to TopSitesEdit.
editForm: {
visible: false,
site: null
index: -1
}
},
Prefs: {
@ -95,7 +95,7 @@ function TopSites(prevState = INITIAL_STATE.TopSites, action) {
}
return Object.assign({}, prevState, {initialized: true, rows: action.data});
case at.TOP_SITES_EDIT:
return Object.assign({}, prevState, {editForm: {visible: true, site: action.data}});
return Object.assign({}, prevState, {editForm: {visible: true, index: action.data.index}});
case at.TOP_SITES_CANCEL_EDIT:
return Object.assign({}, prevState, {editForm: {visible: false}});
case at.SCREENSHOT_UPDATED:

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

@ -242,9 +242,8 @@ main {
.top-sites-list {
list-style: none;
margin: 0;
margin: 0 -16px;
margin-bottom: -18px;
margin-inline-end: -32px;
padding: 0; }
@media (max-width: 416px) {
.top-sites-list :nth-child(2n+1) .context-menu {
@ -290,17 +289,18 @@ main {
offset-inline-start: auto; } }
.top-sites-list li {
display: inline-block;
margin: 0 0 8px;
margin-inline-end: 32px; }
margin: 0 0 8px; }
.top-sites-list .top-site-outer {
position: relative; }
.top-sites-list .top-site-outer > a {
color: inherit;
display: block;
outline: none; }
.top-sites-list .top-site-outer > a:-moz-any(.active, :focus) .tile {
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1), 0 0 0 5px #D7D7DB;
transition: box-shadow 150ms; }
padding: 0 16px; }
.top-sites-list .top-site-outer .top-site-inner {
position: relative; }
.top-sites-list .top-site-outer .top-site-inner > a {
color: inherit;
display: block;
outline: none; }
.top-sites-list .top-site-outer .top-site-inner > a:-moz-any(.active, :focus) .tile {
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1), 0 0 0 5px #D7D7DB;
transition: box-shadow 150ms; }
.top-sites-list .top-site-outer .context-menu-button {
background-clip: padding-box;
background-color: #FFF;
@ -347,10 +347,6 @@ main {
text-transform: uppercase; }
.top-sites-list .top-site-outer .tile::before {
content: attr(data-fallback); }
.top-sites-list .top-site-outer.placeholder .tile {
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1); }
.top-sites-list .top-site-outer.placeholder .screenshot {
display: none; }
.top-sites-list .top-site-outer .screenshot {
background-color: #FFF;
background-position: top left;
@ -446,6 +442,13 @@ main {
border-right: 0; }
.top-sites-list .top-site-outer .edit-menu button:first-child:dir(rtl) {
border-right: 0; }
.top-sites-list .top-site-outer.placeholder .tile {
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1); }
.top-sites-list .top-site-outer.placeholder .screenshot {
display: none; }
.top-sites-list .top-site-outer.placeholder .edit-menu:last-child button {
background-size: 13px;
width: 23px; }
.edit-topsites-wrapper .edit-topsites-button {
border-right: 1px solid #D7D7DB;

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

@ -242,9 +242,8 @@ main {
.top-sites-list {
list-style: none;
margin: 0;
margin: 0 -16px;
margin-bottom: -18px;
margin-inline-end: -32px;
padding: 0; }
@media (max-width: 416px) {
.top-sites-list :nth-child(2n+1) .context-menu {
@ -290,17 +289,18 @@ main {
offset-inline-start: auto; } }
.top-sites-list li {
display: inline-block;
margin: 0 0 8px;
margin-inline-end: 32px; }
margin: 0 0 8px; }
.top-sites-list .top-site-outer {
position: relative; }
.top-sites-list .top-site-outer > a {
color: inherit;
display: block;
outline: none; }
.top-sites-list .top-site-outer > a:-moz-any(.active, :focus) .tile {
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1), 0 0 0 5px #D7D7DB;
transition: box-shadow 150ms; }
padding: 0 16px; }
.top-sites-list .top-site-outer .top-site-inner {
position: relative; }
.top-sites-list .top-site-outer .top-site-inner > a {
color: inherit;
display: block;
outline: none; }
.top-sites-list .top-site-outer .top-site-inner > a:-moz-any(.active, :focus) .tile {
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1), 0 0 0 5px #D7D7DB;
transition: box-shadow 150ms; }
.top-sites-list .top-site-outer .context-menu-button {
background-clip: padding-box;
background-color: #FFF;
@ -347,10 +347,6 @@ main {
text-transform: uppercase; }
.top-sites-list .top-site-outer .tile::before {
content: attr(data-fallback); }
.top-sites-list .top-site-outer.placeholder .tile {
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1); }
.top-sites-list .top-site-outer.placeholder .screenshot {
display: none; }
.top-sites-list .top-site-outer .screenshot {
background-color: #FFF;
background-position: top left;
@ -446,6 +442,13 @@ main {
border-right: 0; }
.top-sites-list .top-site-outer .edit-menu button:first-child:dir(rtl) {
border-right: 0; }
.top-sites-list .top-site-outer.placeholder .tile {
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1); }
.top-sites-list .top-site-outer.placeholder .screenshot {
display: none; }
.top-sites-list .top-site-outer.placeholder .edit-menu:last-child button {
background-size: 13px;
width: 23px; }
.edit-topsites-wrapper .edit-topsites-button {
border-right: 1px solid #D7D7DB;

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

@ -242,9 +242,8 @@ main {
.top-sites-list {
list-style: none;
margin: 0;
margin: 0 -16px;
margin-bottom: -18px;
margin-inline-end: -32px;
padding: 0; }
@media (max-width: 416px) {
.top-sites-list :nth-child(2n+1) .context-menu {
@ -290,17 +289,18 @@ main {
offset-inline-start: auto; } }
.top-sites-list li {
display: inline-block;
margin: 0 0 8px;
margin-inline-end: 32px; }
margin: 0 0 8px; }
.top-sites-list .top-site-outer {
position: relative; }
.top-sites-list .top-site-outer > a {
color: inherit;
display: block;
outline: none; }
.top-sites-list .top-site-outer > a:-moz-any(.active, :focus) .tile {
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1), 0 0 0 5px #D7D7DB;
transition: box-shadow 150ms; }
padding: 0 16px; }
.top-sites-list .top-site-outer .top-site-inner {
position: relative; }
.top-sites-list .top-site-outer .top-site-inner > a {
color: inherit;
display: block;
outline: none; }
.top-sites-list .top-site-outer .top-site-inner > a:-moz-any(.active, :focus) .tile {
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1), 0 0 0 5px #D7D7DB;
transition: box-shadow 150ms; }
.top-sites-list .top-site-outer .context-menu-button {
background-clip: padding-box;
background-color: #FFF;
@ -347,10 +347,6 @@ main {
text-transform: uppercase; }
.top-sites-list .top-site-outer .tile::before {
content: attr(data-fallback); }
.top-sites-list .top-site-outer.placeholder .tile {
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1); }
.top-sites-list .top-site-outer.placeholder .screenshot {
display: none; }
.top-sites-list .top-site-outer .screenshot {
background-color: #FFF;
background-position: top left;
@ -446,6 +442,13 @@ main {
border-right: 0; }
.top-sites-list .top-site-outer .edit-menu button:first-child:dir(rtl) {
border-right: 0; }
.top-sites-list .top-site-outer.placeholder .tile {
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1); }
.top-sites-list .top-site-outer.placeholder .screenshot {
display: none; }
.top-sites-list .top-site-outer.placeholder .edit-menu:last-child button {
background-size: 13px;
width: 23px; }
.edit-topsites-wrapper .edit-topsites-button {
border-right: 1px solid #D7D7DB;

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

@ -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", "DISABLE_ONBOARDING", "INIT", "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", "PAGE_PRERENDERED", "PLACES_BOOKMARK_ADDED", "PLACES_BOOKMARK_CHANGED", "PLACES_BOOKMARK_REMOVED", "PLACES_HISTORY_CLEARED", "PLACES_LINKS_DELETED", "PLACES_LINK_BLOCKED", "PREFS_INITIAL_VALUES", "PREF_CHANGED", "RICH_ICON_MISSING", "SAVE_SESSION_PERF_DATA", "SAVE_TO_POCKET", "SCREENSHOT_UPDATED", "SECTION_DEREGISTER", "SECTION_DISABLE", "SECTION_ENABLE", "SECTION_OPTIONS_CHANGED", "SECTION_REGISTER", "SECTION_UPDATE", "SECTION_UPDATE_CARD", "SETTINGS_CLOSE", "SETTINGS_OPEN", "SET_PREF", "SHOW_FIREFOX_ACCOUNTS", "SNIPPETS_BLOCKLIST_UPDATED", "SNIPPETS_DATA", "SNIPPETS_RESET", "SNIPPET_BLOCKED", "SYSTEM_TICK", "TELEMETRY_IMPRESSION_STATS", "TELEMETRY_PERFORMANCE_EVENT", "TELEMETRY_UNDESIRED_EVENT", "TELEMETRY_USER_EVENT", "TOP_SITES_ADD", "TOP_SITES_CANCEL_EDIT", "TOP_SITES_EDIT", "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", "DISABLE_ONBOARDING", "INIT", "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", "PAGE_PRERENDERED", "PLACES_BOOKMARK_ADDED", "PLACES_BOOKMARK_CHANGED", "PLACES_BOOKMARK_REMOVED", "PLACES_HISTORY_CLEARED", "PLACES_LINKS_DELETED", "PLACES_LINK_BLOCKED", "PREFS_INITIAL_VALUES", "PREF_CHANGED", "RICH_ICON_MISSING", "SAVE_SESSION_PERF_DATA", "SAVE_TO_POCKET", "SCREENSHOT_UPDATED", "SECTION_DEREGISTER", "SECTION_DISABLE", "SECTION_ENABLE", "SECTION_OPTIONS_CHANGED", "SECTION_REGISTER", "SECTION_UPDATE", "SECTION_UPDATE_CARD", "SETTINGS_CLOSE", "SETTINGS_OPEN", "SET_PREF", "SHOW_FIREFOX_ACCOUNTS", "SNIPPETS_BLOCKLIST_UPDATED", "SNIPPETS_DATA", "SNIPPETS_RESET", "SNIPPET_BLOCKED", "SYSTEM_TICK", "TELEMETRY_IMPRESSION_STATS", "TELEMETRY_PERFORMANCE_EVENT", "TELEMETRY_UNDESIRED_EVENT", "TELEMETRY_USER_EVENT", "TOP_SITES_CANCEL_EDIT", "TOP_SITES_EDIT", "TOP_SITES_INSERT", "TOP_SITES_PIN", "TOP_SITES_UNPIN", "TOP_SITES_UPDATED", "UNINIT"]) {
actionTypes[type] = type;
}
@ -368,7 +368,7 @@ const INITIAL_STATE = {
// context menu to TopSitesEdit.
editForm: {
visible: false,
site: null
index: -1
}
},
Prefs: {
@ -437,7 +437,7 @@ function TopSites(prevState = INITIAL_STATE.TopSites, action) {
}
return Object.assign({}, prevState, { initialized: true, rows: action.data });
case at.TOP_SITES_EDIT:
return Object.assign({}, prevState, { editForm: { visible: true, site: action.data } });
return Object.assign({}, prevState, { editForm: { visible: true, index: action.data.index } });
case at.TOP_SITES_CANCEL_EDIT:
return Object.assign({}, prevState, { editForm: { visible: false } });
case at.SCREENSHOT_UPDATED:
@ -884,12 +884,12 @@ const LinkMenuOptions = {
}),
userEvent: "SAVE_TO_POCKET"
}),
EditTopSite: site => ({
EditTopSite: (site, index) => ({
id: "edit_topsites_button_text",
icon: "edit",
action: {
type: Actions["actionTypes"].TOP_SITES_EDIT,
data: { url: site.url, label: site.label }
data: { index }
}
}),
CheckBookmark: site => site.bookmarkGuid ? LinkMenuOptions.RemoveBookmark(site) : LinkMenuOptions.AddBookmark(site),
@ -902,7 +902,7 @@ const LinkMenuOptions = {
const DEFAULT_SITE_MENU_OPTIONS = ["CheckPinTopSite", "Separator", "OpenInNewWindow", "OpenInPrivateWindow", "Separator", "BlockUrl"];
const DEFAULT_SITE_MENU_OPTIONS = ["CheckPinTopSite", "EditTopSite", "Separator", "OpenInNewWindow", "OpenInPrivateWindow", "Separator", "BlockUrl"];
class LinkMenu__LinkMenu extends external__React__default.a.PureComponent {
getOptions() {
@ -2502,71 +2502,125 @@ var _extends = Object.assign || function (target) { for (var i = 1; i < argument
const TopSiteLink = props => {
const { link, title } = props;
const topSiteOuterClassName = `top-site-outer${props.className ? ` ${props.className}` : ""}`;
const { tippyTopIcon, faviconSize } = link;
const letterFallback = title[0];
let imageClassName;
let imageStyle;
let showSmallFavicon = false;
let smallFaviconStyle;
let smallFaviconFallback;
if (tippyTopIcon || faviconSize >= MIN_RICH_FAVICON_SIZE) {
// styles and class names for top sites with rich icons
imageClassName = "top-site-icon rich-icon";
imageStyle = {
backgroundColor: link.backgroundColor,
backgroundImage: `url(${tippyTopIcon || link.favicon})`
};
} else {
// styles and class names for top sites with screenshot + small icon in top left corner
imageClassName = `screenshot${link.screenshot ? " active" : ""}`;
imageStyle = { backgroundImage: link.screenshot ? `url(${link.screenshot})` : "none" };
// only show a favicon in top left if it's greater than 16x16
if (faviconSize >= MIN_CORNER_FAVICON_SIZE) {
showSmallFavicon = true;
smallFaviconStyle = { backgroundImage: `url(${link.favicon})` };
} else if (link.screenshot) {
// Don't show a small favicon if there is no screenshot, because that
// would result in two fallback icons
showSmallFavicon = true;
smallFaviconFallback = true;
class TopSite_TopSiteLink extends external__React__default.a.PureComponent {
constructor(props) {
super(props);
this.onDragEvent = this.onDragEvent.bind(this);
}
/*
* Helper to determine whether the drop zone should allow a drop. We only allow
* dropping top sites for now.
*/
_allowDrop(e, index) {
let draggedIndex = parseInt(e.dataTransfer.getData("text/topsite-index"), 10);
if (!isNaN(draggedIndex) && draggedIndex !== index) {
return true;
}
return false;
}
onDragEvent(event) {
switch (event.type) {
case "dragstart":
event.dataTransfer.effectAllowed = "move";
event.dataTransfer.setData("text/topsite-index", this.props.index);
event.target.blur();
this.props.onDragEvent(event, this.props.index, this.props.link, this.props.title);
break;
case "dragend":
this.props.onDragEvent(event);
break;
case "dragover":
case "dragenter":
case "dragleave":
case "drop":
if (this._allowDrop(event, this.props.index)) {
event.preventDefault();
this.props.onDragEvent(event, this.props.index);
}
break;
}
}
return external__React__default.a.createElement(
"li",
{ className: topSiteOuterClassName, key: link.guid || link.url },
external__React__default.a.createElement(
"a",
{ href: link.url, onClick: props.onClick },
render() {
const { children, className, isDraggable, link, onClick, title } = this.props;
const topSiteOuterClassName = `top-site-outer${className ? ` ${className}` : ""}`;
const { tippyTopIcon, faviconSize } = link;
const letterFallback = title[0];
let imageClassName;
let imageStyle;
let showSmallFavicon = false;
let smallFaviconStyle;
let smallFaviconFallback;
if (tippyTopIcon || faviconSize >= MIN_RICH_FAVICON_SIZE) {
// styles and class names for top sites with rich icons
imageClassName = "top-site-icon rich-icon";
imageStyle = {
backgroundColor: link.backgroundColor,
backgroundImage: `url(${tippyTopIcon || link.favicon})`
};
} else {
// styles and class names for top sites with screenshot + small icon in top left corner
imageClassName = `screenshot${link.screenshot ? " active" : ""}`;
imageStyle = { backgroundImage: link.screenshot ? `url(${link.screenshot})` : "none" };
// only show a favicon in top left if it's greater than 16x16
if (faviconSize >= MIN_CORNER_FAVICON_SIZE) {
showSmallFavicon = true;
smallFaviconStyle = { backgroundImage: `url(${link.favicon})` };
} else if (link.screenshot) {
// Don't show a small favicon if there is no screenshot, because that
// would result in two fallback icons
showSmallFavicon = true;
smallFaviconFallback = true;
}
}
let draggableProps = {};
if (isDraggable) {
draggableProps = {
draggable: true,
onDragStart: this.onDragEvent,
onDragEnd: this.onDragEvent
};
}
return external__React__default.a.createElement(
"li",
_extends({ className: topSiteOuterClassName, key: link.guid || link.url, onDrop: this.onDragEvent, onDragOver: this.onDragEvent, onDragEnter: this.onDragEvent, onDragLeave: this.onDragEvent }, draggableProps),
external__React__default.a.createElement(
"div",
{ className: "tile", "aria-hidden": true, "data-fallback": letterFallback },
external__React__default.a.createElement("div", { className: imageClassName, style: imageStyle }),
showSmallFavicon && external__React__default.a.createElement("div", {
className: "top-site-icon default-icon",
"data-fallback": smallFaviconFallback && letterFallback,
style: smallFaviconStyle })
),
external__React__default.a.createElement(
"div",
{ className: `title ${link.isPinned ? "pinned" : ""}` },
link.isPinned && external__React__default.a.createElement("div", { className: "icon icon-pin-small" }),
{ className: "top-site-inner" },
external__React__default.a.createElement(
"span",
{ dir: "auto" },
title
)
"a",
{ href: link.url, onClick: onClick },
external__React__default.a.createElement(
"div",
{ className: "tile", "aria-hidden": true, "data-fallback": letterFallback },
external__React__default.a.createElement("div", { className: imageClassName, style: imageStyle }),
showSmallFavicon && external__React__default.a.createElement("div", {
className: "top-site-icon default-icon",
"data-fallback": smallFaviconFallback && letterFallback,
style: smallFaviconStyle })
),
external__React__default.a.createElement(
"div",
{ className: `title ${link.isPinned ? "pinned" : ""}` },
link.isPinned && external__React__default.a.createElement("div", { className: "icon icon-pin-small" }),
external__React__default.a.createElement(
"span",
{ dir: "auto" },
title
)
)
),
children
)
),
props.children
);
};
TopSiteLink.defaultProps = {
);
}
}
TopSite_TopSiteLink.defaultProps = {
title: "",
link: {}
link: {},
isDraggable: true
};
class TopSite_TopSite extends external__React__default.a.PureComponent {
@ -2579,6 +2633,7 @@ class TopSite_TopSite extends external__React__default.a.PureComponent {
this.onDismissButtonClick = this.onDismissButtonClick.bind(this);
this.onPinButtonClick = this.onPinButtonClick.bind(this);
this.onEditButtonClick = this.onEditButtonClick.bind(this);
this.onDragEvent = this.onDragEvent.bind(this);
}
toggleContextMenu(event, index) {
this.setState({
@ -2641,14 +2696,23 @@ class TopSite_TopSite extends external__React__default.a.PureComponent {
onEditButtonClick() {
this.props.onEdit(this.props.index);
}
onDragEvent(event, index, link, title) {
if (event.type === "dragstart") {
this.setState({
activeTile: null,
showContextMenu: false
});
}
this.props.onDragEvent(event, index, link, title);
}
render() {
const { props } = this;
const { link } = props;
const isContextMenuOpen = this.state.showContextMenu && this.state.activeTile === props.index;
const title = link.label || link.hostname;
return external__React__default.a.createElement(
TopSiteLink,
_extends({}, props, { onClick: this.onLinkClick, className: isContextMenuOpen ? "active" : "", title: title }),
TopSite_TopSiteLink,
_extends({}, props, { onClick: this.onLinkClick, onDragEvent: this.onDragEvent, className: isContextMenuOpen ? "active" : "", title: title }),
!props.onEdit && external__React__default.a.createElement(
"div",
null,
@ -2689,29 +2753,180 @@ class TopSite_TopSite extends external__React__default.a.PureComponent {
);
}
}
TopSite_TopSite.defaultProps = { link: {} };
const TopSitePlaceholder = () => external__React__default.a.createElement(TopSiteLink, { className: "placeholder" });
const TopSiteList = props => {
const topSites = props.TopSites.rows.slice(0, props.TopSitesCount);
const topSitesUI = [];
for (let i = 0, l = props.TopSitesCount; i < l; i++) {
const link = topSites[i];
topSitesUI.push(!link ? external__React__default.a.createElement(TopSitePlaceholder, { key: i }) : external__React__default.a.createElement(TopSite_TopSite, {
key: link.guid || link.url,
dispatch: props.dispatch,
link: link,
index: i,
intl: props.intl,
onEdit: props.onEdit }));
}
return external__React__default.a.createElement(
"ul",
{ className: "top-sites-list" },
topSitesUI
);
TopSite_TopSite.defaultProps = {
link: {},
onDragStart() {}
};
class TopSite_TopSitePlaceholder extends external__React__default.a.PureComponent {
constructor(props) {
super(props);
this.onEditButtonClick = this.onEditButtonClick.bind(this);
}
onEditButtonClick() {
this.props.dispatch({
type: Actions["actionTypes"].TOP_SITES_EDIT,
data: { index: this.props.index }
});
}
render() {
return external__React__default.a.createElement(
TopSite_TopSiteLink,
_extends({ className: "placeholder", isDraggable: false }, this.props),
external__React__default.a.createElement(
"div",
{ className: "edit-menu" },
external__React__default.a.createElement("button", {
className: "icon icon-edit",
title: this.props.intl.formatMessage({ id: "edit_topsites_edit_button" }),
onClick: this.onEditButtonClick })
)
);
}
}
class TopSite__TopSiteList extends external__React__default.a.PureComponent {
constructor(props) {
super(props);
this.state = this.DEFAULT_STATE = {
draggedIndex: null,
draggedSite: null,
draggedTitle: null,
topSitesPreview: null
};
this.onDragEvent = this.onDragEvent.bind(this);
}
componentWillUpdate(nextProps) {
if (this.state.draggedSite) {
const prevTopSites = this.props.TopSites && this.props.TopSites.rows;
const newTopSites = nextProps.TopSites && nextProps.TopSites.rows;
if (prevTopSites && prevTopSites[this.state.draggedIndex] && prevTopSites[this.state.draggedIndex].url === this.state.draggedSite.url && (!newTopSites[this.state.draggedIndex] || newTopSites[this.state.draggedIndex].url !== this.state.draggedSite.url)) {
// We got the new order from the redux store via props. We can clear state now.
this.setState(this.DEFAULT_STATE);
}
}
}
userEvent(event, index) {
this.props.dispatch(Actions["actionCreators"].UserEvent({
event,
source: TOP_SITES_SOURCE,
action_position: index
}));
}
onDragEvent(event, index, link, title) {
switch (event.type) {
case "dragstart":
this.setState({
draggedIndex: index,
draggedSite: link,
draggedTitle: title
});
this.userEvent("DRAG", index);
break;
case "dragend":
this.setState(this.DEFAULT_STATE);
break;
case "dragenter":
this.setState({ topSitesPreview: this._makeTopSitesPreview(index) });
break;
case "dragleave":
this.setState({ topSitesPreview: null });
break;
case "drop":
this.props.dispatch(Actions["actionCreators"].SendToMain({
type: Actions["actionTypes"].TOP_SITES_INSERT,
data: { site: { url: this.state.draggedSite.url, label: this.state.draggedTitle }, index }
}));
this.userEvent("DROP", index);
break;
default:
break;
}
}
_getTopSites() {
return this.props.TopSites.rows.slice(0, this.props.TopSitesCount);
}
/**
* Make a preview of the topsites that will be the result of dropping the currently
* dragged site at the specified index.
*/
_makeTopSitesPreview(index) {
const preview = this._getTopSites();
this._fillOrLeaveHole(preview, this.state.draggedIndex);
this._insertSite(preview, Object.assign({}, this.state.draggedSite, { isPinned: true }), index);
return preview;
}
/**
* Fill in the slot at the specified index with a non pinned site further down the
* list, if any. Otherwise leave an empty slot.
*/
_fillOrLeaveHole(sites, index) {
let slotIndex = index;
sites[slotIndex] = null;
for (let i = slotIndex + 1; i < sites.length; i++) {
const site = sites[i];
if (site && !site.isPinned) {
sites[i] = null;
sites[slotIndex] = site;
// Update the index to fill to be the spot we just grabbed a site from
slotIndex = i;
}
}
}
/**
* Insert the given site in the slot at the specified index. If the slot is occupied,
* move it appropriately.
*/
_insertSite(sites, site, index) {
const replacedSite = sites[index];
if (replacedSite && index < this.props.TopSitesCount - 1) {
if (replacedSite.isPinned) {
// If the replaced site is pinned, it goes into the next slot no matter what.
this._insertSite(sites, replacedSite, index + 1);
} else {
// If the replaced site isn't pinned, it goes into the next slot that doesn't havea pinned site;
for (let i = index + 1, l = sites.length; i < l; i++) {
if (!sites[i] || !sites[i].isPinned) {
this._insertSite(sites, replacedSite, i);
break;
}
}
}
}
sites[index] = site;
}
render() {
const { props } = this;
const topSites = this.state.topSitesPreview || this._getTopSites();
const topSitesUI = [];
const commonProps = {
onDragEvent: this.onDragEvent,
dispatch: props.dispatch,
intl: props.intl
};
for (let i = 0, l = props.TopSitesCount; i < l; i++) {
const link = topSites[i];
const slotProps = {
key: i,
index: i
};
topSitesUI.push(!link ? external__React__default.a.createElement(TopSite_TopSitePlaceholder, _extends({}, slotProps, commonProps)) : external__React__default.a.createElement(TopSite_TopSite, _extends({
link: link,
onEdit: props.onEdit
}, slotProps, commonProps)));
}
return external__React__default.a.createElement(
"ul",
{ className: "top-sites-list" },
topSitesUI
);
}
}
const TopSiteList = Object(external__ReactIntl_["injectIntl"])(TopSite__TopSiteList);
// CONCATENATED MODULE: ./system-addon/content-src/components/TopSites/TopSiteForm.jsx
@ -2753,7 +2968,7 @@ class TopSiteForm_TopSiteForm extends external__React__default.a.PureComponent {
site.label = this.state.label;
}
this.props.dispatch(Actions["actionCreators"].SendToMain({
type: Actions["actionTypes"].TOP_SITES_ADD,
type: Actions["actionTypes"].TOP_SITES_INSERT,
data: { site }
}));
this.props.dispatch(Actions["actionCreators"].UserEvent({
@ -2956,12 +3171,13 @@ class TopSitesEdit__TopSitesEdit extends external__React__default.a.PureComponen
}));
}
render() {
const showEditForm = this.props.TopSites.editForm && this.props.TopSites.editForm.visible || this.state.showEditModal && this.state.showEditForm;
const { editForm } = this.props.TopSites;
const showEditForm = editForm && editForm.visible || this.state.showEditModal && this.state.showEditForm;
let editIndex = this.state.editIndex;
if (showEditForm && this.props.TopSites.editForm.visible) {
const targetURL = this.props.TopSites.editForm.site.url;
editIndex = this.props.TopSites.rows.findIndex(s => s.url === targetURL);
if (editIndex < 0 && editForm) {
editIndex = editForm.index;
}
const editSite = this.props.TopSites.rows[editIndex] || {};
return external__React__default.a.createElement(
"div",
{ className: "edit-topsites-wrapper" },
@ -3038,8 +3254,8 @@ class TopSitesEdit__TopSitesEdit extends external__React__default.a.PureComponen
"div",
{ className: "modal" },
external__React__default.a.createElement(TopSiteForm_TopSiteForm, {
label: this.props.TopSites.rows[editIndex].label || this.props.TopSites.rows[editIndex].hostname,
url: this.props.TopSites.rows[editIndex].url,
label: editSite.label || editSite.hostname || "",
url: editSite.url || "",
index: editIndex,
editMode: true,
onClose: this.onFormClose,
@ -3341,7 +3557,7 @@ var PrerenderData = new _PrerenderData({
"migrationExpired": true,
"showTopSites": true,
"showSearch": true,
"topSitesCount": 6,
"topSitesCount": 12,
"collapseTopSites": false,
"section.highlights.collapsed": false,
"section.topstories.collapsed": false,
@ -3354,7 +3570,7 @@ var PrerenderData = new _PrerenderData({
// too different for the prerendered version to be used. Unfortunately, this
// will result in users who have modified some of their preferences not being
// able to get the benefits of prerendering.
validation: ["showTopSites", "showSearch", "collapseTopSites", "section.highlights.collapsed", "section.topstories.collapsed",
validation: ["showTopSites", "showSearch", "topSitesCount", "collapseTopSites", "section.highlights.collapsed", "section.topstories.collapsed",
// This means if either of these are set to their default values,
// prerendering can be used.
{ oneOf: ["feeds.section.topstories", "feeds.section.highlights"] }],

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

@ -8,7 +8,7 @@
<em:type>2</em:type>
<em:bootstrap>true</em:bootstrap>
<em:unpack>false</em:unpack>
<em:version>2017.12.20.1328-00d79b97</em:version>
<em:version>2017.12.22.0055-8fe1055e</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>

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

@ -108,7 +108,7 @@ const PREFS_CONFIG = new Map([
}],
["topSitesCount", {
title: "Number of Top Sites to display",
value: 6
value: 12
}],
["telemetry", {
title: "Enable system error and usage data collection",

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

@ -241,6 +241,13 @@ this.TopSitesFeed = class TopSitesFeed {
* Insert a site to pin at a position shifting over any other pinned sites.
*/
_insertPin(site, index) {
// Don't insert any pins past the end of the visible top sites. Otherwise,
// we can end up with a bunch of pinned sites that can never be unpinned again
// from the UI.
if (index >= this.store.getState().Prefs.values.topSitesCount) {
return;
}
// For existing sites, recursively push it and others to the next positions
let pinned = NewTabUtils.pinnedLinks.links;
if (pinned.length > index && pinned[index]) {
@ -250,12 +257,12 @@ this.TopSitesFeed = class TopSitesFeed {
}
/**
* Handle an add action of a site.
* Handle an insert (drop/add) action of a site.
*/
add(action) {
// Adding a top site pins it in the first slot, pushing over any link already
// pinned in the slot.
this._insertPin(action.data.site, 0);
insert(action) {
// Inserting a top site pins it in the specified slot, pushing over any link already
// pinned in the slot (unless it's the last slot, then it replaces).
this._insertPin(action.data.site, action.data.index || 0);
this._broadcastPinnedSitesUpdated();
}
@ -293,8 +300,8 @@ this.TopSitesFeed = class TopSitesFeed {
case at.TOP_SITES_UNPIN:
this.unpin(action);
break;
case at.TOP_SITES_ADD:
this.add(action);
case at.TOP_SITES_INSERT:
this.insert(action);
break;
case at.UNINIT:
this.uninit();

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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