diff --git a/browser/base/content/test/newtab/browser_newtab_bug991111.js b/browser/base/content/test/newtab/browser_newtab_bug991111.js
index e9932094ca88..ce36ef2bc29a 100644
--- a/browser/base/content/test/newtab/browser_newtab_bug991111.js
+++ b/browser/base/content/test/newtab/browser_newtab_bug991111.js
@@ -1,9 +1,15 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
+const PREF_NEWTAB_ROWS = "browser.newtabpage.rows";
+
function runTests() {
+ // set max rows to 1, to avoid scroll events by clicking middle button
+ Services.prefs.setIntPref(PREF_NEWTAB_ROWS, 1);
yield setLinks("-1");
yield addNewTabPageTab();
+ // we need a second newtab to honor max rows
+ yield addNewTabPageTab();
// Remember if the click handler was triggered
let cell = getCell(0);
@@ -16,4 +22,5 @@ function runTests() {
// Send a middle-click and make sure it happened
yield EventUtils.synthesizeMouseAtCenter(cell.node, {button: 1}, getContentWindow());
ok(clicked, "middle click triggered click listener");
+ Services.prefs.clearUserPref(PREF_NEWTAB_ROWS);
}
diff --git a/browser/base/content/test/newtab/browser_newtab_bug998387.js b/browser/base/content/test/newtab/browser_newtab_bug998387.js
index d2e51e7d1bd5..04ff21294ab4 100644
--- a/browser/base/content/test/newtab/browser_newtab_bug998387.js
+++ b/browser/base/content/test/newtab/browser_newtab_bug998387.js
@@ -1,9 +1,15 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
+const PREF_NEWTAB_ROWS = "browser.newtabpage.rows";
+
function runTests() {
+ // set max rows to 1, to avoid scroll events by clicking middle button
+ Services.prefs.setIntPref(PREF_NEWTAB_ROWS, 1);
yield setLinks("0");
yield addNewTabPageTab();
+ // we need a second newtab to honor max rows
+ yield addNewTabPageTab();
// Remember if the click handler was triggered
let {site} = getCell(0);
@@ -22,4 +28,5 @@ function runTests() {
// Make sure the cell didn't actually get blocked
checkGrid("0");
+ Services.prefs.clearUserPref(PREF_NEWTAB_ROWS);
}
diff --git a/browser/base/content/test/newtab/browser_newtab_focus.js b/browser/base/content/test/newtab/browser_newtab_focus.js
index a423e3397801..82d9b4237bc8 100644
--- a/browser/base/content/test/newtab/browser_newtab_focus.js
+++ b/browser/base/content/test/newtab/browser_newtab_focus.js
@@ -10,7 +10,8 @@ function runTests() {
// Focus count in new tab page.
// 30 = 9 * 3 + 3 = 9 sites, each with link, pin and remove buttons; search
- // bar; search button; and toggle button.
+ // bar; search button; and toggle button. Additionaly there may or may not be
+ // a scroll bar caused by fix to 1180387, which will eat an extra focus
let FOCUS_COUNT = 30;
// Create a new tab page.
@@ -42,7 +43,9 @@ function countFocus(aExpectedCount) {
let focusedElement = document.commandDispatcher.focusedElement;
if (focusedElement && focusedElement.classList.contains("urlbar-input")) {
window.removeEventListener("focus", onFocus, true);
- is(focusCount, aExpectedCount, "Validate focus count in the new tab page.");
+ // account for a potential presence of a scroll bar
+ ok(focusCount == aExpectedCount || focusCount == (aExpectedCount + 1),
+ "Validate focus count in the new tab page.");
executeSoon(TestRunner.next);
} else {
if (focusedElement && focusedElement.ownerDocument == contentDoc &&
diff --git a/browser/base/content/test/newtab/head.js b/browser/base/content/test/newtab/head.js
index e936ad75b0dd..6eb54ebf03f9 100644
--- a/browser/base/content/test/newtab/head.js
+++ b/browser/base/content/test/newtab/head.js
@@ -587,7 +587,8 @@ function createExternalDropIframe() {
iframe.style.position = "absolute";
iframe.style.zIndex = 50;
- let margin = doc.getElementById("newtab-margin-top");
+ // the frame has to be attached to a visible element
+ let margin = doc.getElementById("newtab-search-container");
margin.appendChild(iframe);
iframe.addEventListener("load", function onLoad() {
diff --git a/browser/components/migration/MigrationUtils.jsm b/browser/components/migration/MigrationUtils.jsm
index 862a65777059..e0febf7da9ff 100644
--- a/browser/components/migration/MigrationUtils.jsm
+++ b/browser/components/migration/MigrationUtils.jsm
@@ -457,6 +457,7 @@ this.MigrationUtils = Object.freeze({
*
* @param aKey internal name of the migration source.
* Supported values: ie (windows),
+ * edge (windows),
* safari (mac/windows),
* canary (mac/windows),
* chrome (mac/windows/linux),
diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in
index e68059c1e7a6..a9ce916744c5 100644
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -489,6 +489,7 @@
@RESPATH@/browser/components/FirefoxProfileMigrator.js
#ifdef XP_WIN
@RESPATH@/browser/components/360seProfileMigrator.js
+@RESPATH@/browser/components/EdgeProfileMigrator.js
@RESPATH@/browser/components/IEProfileMigrator.js
@RESPATH@/browser/components/SafariProfileMigrator.js
#endif
diff --git a/browser/themes/linux/browser.css b/browser/themes/linux/browser.css
index 95c3d8ac5eac..759cca1bb97d 100644
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -61,6 +61,10 @@
background-color: ThreeDShadow;
}
+#navigator-toolbox:-moz-lwtheme::after {
+ background-color: rgba(0,0,0,.3);
+}
+
#navigator-toolbox > toolbar:not(:-moz-lwtheme):not(#toolbar-menubar):not(#TabsToolbar) {
-moz-appearance: none;
border-style: none;
diff --git a/browser/themes/windows/browser.css b/browser/themes/windows/browser.css
index be2e3dc41903..021fca9b6855 100644
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -107,19 +107,23 @@
@media (-moz-windows-default-theme) {
@media (-moz-os-version: windows-vista),
(-moz-os-version: windows-win7) {
- #navigator-toolbox:not(:-moz-lwtheme)::after {
+ #navigator-toolbox::after {
background-color: #aabccf;
}
}
@media (-moz-os-version: windows-win8),
(-moz-os-version: windows-win10) {
- #navigator-toolbox:not(:-moz-lwtheme)::after {
+ #navigator-toolbox::after {
background-color: #c2c2c2;
}
}
}
+#navigator-toolbox:-moz-lwtheme::after {
+ background-color: rgba(0,0,0,.3);
+}
+
#navigator-toolbox > toolbar {
-moz-appearance: none;
border-style: none;
diff --git a/mobile/android/base/db/BrowserContract.java b/mobile/android/base/db/BrowserContract.java
index 7cc275984123..f764310508e5 100644
--- a/mobile/android/base/db/BrowserContract.java
+++ b/mobile/android/base/db/BrowserContract.java
@@ -415,7 +415,7 @@ public class BrowserContract {
public static final String DEFAULT_SORT_ORDER = CLIENT_LAST_MODIFIED + " DESC";
- public static final String[] DEFAULT_PROJECTION = new String[] { _ID, URL, TITLE, EXCERPT, WORD_COUNT };
+ public static final String[] DEFAULT_PROJECTION = new String[] { _ID, URL, TITLE, EXCERPT, WORD_COUNT, IS_UNREAD };
// Minimum fields required to create a reading list item.
public static final String[] REQUIRED_FIELDS = { ReadingListItems.URL, ReadingListItems.TITLE };
diff --git a/mobile/android/base/db/LocalReadingListAccessor.java b/mobile/android/base/db/LocalReadingListAccessor.java
index 850e313943b8..ed468339cbb3 100644
--- a/mobile/android/base/db/LocalReadingListAccessor.java
+++ b/mobile/android/base/db/LocalReadingListAccessor.java
@@ -189,6 +189,14 @@ public class LocalReadingListAccessor implements ReadingListAccessor {
cr.update(mReadingListUriWithProfile, values, ReadingListItems._ID + " = " + itemID, null);
}
+ @Override
+ public void markAsUnread(ContentResolver cr, long itemID) {
+ final ContentValues values = new ContentValues();
+ values.put(ReadingListItems.IS_UNREAD, 1);
+
+ cr.update(mReadingListUriWithProfile, values, ReadingListItems._ID + " = " + itemID, null);
+ }
+
@Override
public void updateContent(ContentResolver cr, long itemID, String resolvedTitle, String resolvedURL, String excerpt) {
final ContentValues values = new ContentValues();
diff --git a/mobile/android/base/db/ReadingListAccessor.java b/mobile/android/base/db/ReadingListAccessor.java
index b1ff8fdc2cd3..66682f6ab368 100644
--- a/mobile/android/base/db/ReadingListAccessor.java
+++ b/mobile/android/base/db/ReadingListAccessor.java
@@ -37,6 +37,7 @@ public interface ReadingListAccessor {
void registerContentObserver(Context context, ContentObserver observer);
void markAsRead(ContentResolver cr, long itemID);
+ void markAsUnread(ContentResolver cr, long itemID);
void updateContent(ContentResolver cr, long itemID, String resolvedTitle, String resolvedURL, String excerpt);
void deleteItem(ContentResolver cr, long itemID);
}
diff --git a/mobile/android/base/db/StubBrowserDB.java b/mobile/android/base/db/StubBrowserDB.java
index 877074cf7269..8cf55767c63d 100644
--- a/mobile/android/base/db/StubBrowserDB.java
+++ b/mobile/android/base/db/StubBrowserDB.java
@@ -73,6 +73,10 @@ class StubReadingListAccessor implements ReadingListAccessor {
public void markAsRead(ContentResolver cr, long itemID) {
}
+ @Override
+ public void markAsUnread(ContentResolver cr, long itemID) {
+ }
+
@Override
public void updateContent(ContentResolver cr, long itemID, String resolvedTitle, String resolvedURL, String excerpt) {
}
diff --git a/mobile/android/base/home/HomeContextMenuInfo.java b/mobile/android/base/home/HomeContextMenuInfo.java
index cfdce3ee4e22..c0ba23a83fe0 100644
--- a/mobile/android/base/home/HomeContextMenuInfo.java
+++ b/mobile/android/base/home/HomeContextMenuInfo.java
@@ -25,6 +25,7 @@ public class HomeContextMenuInfo extends AdapterContextMenuInfo {
public int historyId = -1;
public int bookmarkId = -1;
public int readingListItemId = -1;
+ public boolean isUnread;
public RemoveItemType itemType = null;
// Item type to be handled with "Remove" selection.
diff --git a/mobile/android/base/home/HomeFragment.java b/mobile/android/base/home/HomeFragment.java
index f6fbdd2fa154..15775a87dd9f 100644
--- a/mobile/android/base/home/HomeFragment.java
+++ b/mobile/android/base/home/HomeFragment.java
@@ -155,6 +155,9 @@ public abstract class HomeFragment extends Fragment {
if (!RestrictedProfiles.isAllowed(view.getContext(), Restriction.DISALLOW_PRIVATE_BROWSING)) {
menu.findItem(R.id.home_open_private_tab).setVisible(false);
}
+
+ menu.findItem(R.id.mark_read).setVisible(info.isInReadingList() && info.isUnread);
+ menu.findItem(R.id.mark_unread).setVisible(info.isInReadingList() && !info.isUnread);
}
@Override
@@ -253,6 +256,22 @@ public abstract class HomeFragment extends Fragment {
return true;
}
+ if (itemId == R.id.mark_read) {
+ GeckoProfile
+ .get(context)
+ .getDB()
+ .getReadingListAccessor()
+ .markAsRead(context.getContentResolver(), info.id);
+ }
+
+ if (itemId == R.id.mark_unread) {
+ GeckoProfile
+ .get(context)
+ .getDB()
+ .getReadingListAccessor()
+ .markAsUnread(context.getContentResolver(), info.id);
+ }
+
return false;
}
diff --git a/mobile/android/base/home/ReadingListPanel.java b/mobile/android/base/home/ReadingListPanel.java
index 9a826596a23b..64575f240ea5 100644
--- a/mobile/android/base/home/ReadingListPanel.java
+++ b/mobile/android/base/home/ReadingListPanel.java
@@ -90,6 +90,8 @@ public class ReadingListPanel extends HomeFragment {
// This item is a TwoLinePageRow, so we allow switch-to-tab.
mUrlOpenListener.onUrlOpen(url, EnumSet.of(OnUrlOpenListener.Flags.ALLOW_SWITCH_TO_TAB));
+
+ markAsRead(id);
}
});
@@ -100,6 +102,7 @@ public class ReadingListPanel extends HomeFragment {
info.url = cursor.getString(cursor.getColumnIndexOrThrow(ReadingListItems.URL));
info.title = cursor.getString(cursor.getColumnIndexOrThrow(ReadingListItems.TITLE));
info.readingListItemId = cursor.getInt(cursor.getColumnIndexOrThrow(ReadingListItems._ID));
+ info.isUnread = cursor.getInt(cursor.getColumnIndexOrThrow(ReadingListItems.IS_UNREAD)) == 1;
info.itemType = RemoveItemType.READING_LIST;
return info;
}
@@ -107,6 +110,15 @@ public class ReadingListPanel extends HomeFragment {
registerForContextMenu(mList);
}
+ private void markAsRead(long id) {
+ final Context context = getActivity();
+
+ GeckoProfile.get(context).getDB().getReadingListAccessor().markAsRead(
+ context.getContentResolver(),
+ id
+ );
+ }
+
@Override
public void onDestroyView() {
super.onDestroyView();
diff --git a/mobile/android/base/home/ReadingListRow.java b/mobile/android/base/home/ReadingListRow.java
index 03659fe80615..a32739b112f3 100644
--- a/mobile/android/base/home/ReadingListRow.java
+++ b/mobile/android/base/home/ReadingListRow.java
@@ -18,6 +18,7 @@ import android.database.Cursor;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
+import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -28,6 +29,7 @@ public class ReadingListRow extends LinearLayout {
private final TextView title;
private final TextView excerpt;
private final TextView readTime;
+ private final ImageView indicator;
// Average reading speed in words per minute.
private static final int AVERAGE_READING_SPEED = 250;
@@ -50,6 +52,7 @@ public class ReadingListRow extends LinearLayout {
title = (TextView) findViewById(R.id.title);
excerpt = (TextView) findViewById(R.id.excerpt);
readTime = (TextView) findViewById(R.id.read_time);
+ indicator = (ImageView) findViewById(R.id.indicator);
}
public void updateFromCursor(Cursor cursor) {
@@ -57,13 +60,19 @@ public class ReadingListRow extends LinearLayout {
return;
}
+ final boolean isUnread = cursor.getInt(cursor.getColumnIndexOrThrow(ReadingListItems.IS_UNREAD)) == 1;
+
final String url = cursor.getString(cursor.getColumnIndexOrThrow(ReadingListItems.URL));
final String titleText = cursor.getString(cursor.getColumnIndexOrThrow(ReadingListItems.TITLE));
title.setText(TextUtils.isEmpty(titleText) ? StringUtils.stripCommonSubdomains(StringUtils.stripScheme(url)) : titleText);
+ title.setTextAppearance(getContext(), isUnread ? R.style.Widget_ReadingListRow_Title_Unread : R.style.Widget_ReadingListRow_Title_Read);
final String excerptText = cursor.getString(cursor.getColumnIndexOrThrow(ReadingListItems.EXCERPT));
excerpt.setText(TextUtils.isEmpty(excerptText) ? url : excerptText);
+ excerpt.setTextAppearance(getContext(), isUnread ? R.style.Widget_ReadingListRow_Title_Unread : R.style.Widget_ReadingListRow_Title_Read);
+
+ indicator.setImageResource(isUnread ? R.drawable.reading_list_indicator_unread : R.drawable.reading_list_indicator_read);
/* Disabled until UX issues are fixed (see bug 1110461).
final int lengthIndex = cursor.getColumnIndexOrThrow(ReadingListItems.LENGTH);
diff --git a/mobile/android/base/locales/en-US/android_strings.dtd b/mobile/android/base/locales/en-US/android_strings.dtd
index d3a8c548d3c8..22ef325f1cb0 100644
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -391,6 +391,8 @@ size. -->
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mobile/android/base/resources/drawable/reading_list_indicator_unread.xml b/mobile/android/base/resources/drawable/reading_list_indicator_unread.xml
new file mode 100644
index 000000000000..f052902efc67
--- /dev/null
+++ b/mobile/android/base/resources/drawable/reading_list_indicator_unread.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
diff --git a/mobile/android/base/resources/layout/reading_list_row_view.xml b/mobile/android/base/resources/layout/reading_list_row_view.xml
index 6bb799d6cbe4..a8ded1dfeef7 100644
--- a/mobile/android/base/resources/layout/reading_list_row_view.xml
+++ b/mobile/android/base/resources/layout/reading_list_row_view.xml
@@ -5,11 +5,16 @@
+
+
diff --git a/mobile/android/base/resources/menu/home_contextmenu.xml b/mobile/android/base/resources/menu/home_contextmenu.xml
index 294b8aee5086..5fb6964765b6 100644
--- a/mobile/android/base/resources/menu/home_contextmenu.xml
+++ b/mobile/android/base/resources/menu/home_contextmenu.xml
@@ -29,6 +29,12 @@
+
+
+
+
diff --git a/mobile/android/base/resources/values/dimens.xml b/mobile/android/base/resources/values/dimens.xml
index f2fa452d702d..1487a12240cd 100644
--- a/mobile/android/base/resources/values/dimens.xml
+++ b/mobile/android/base/resources/values/dimens.xml
@@ -86,7 +86,6 @@
128dp
- 15dp
10dp
diff --git a/mobile/android/base/resources/values/styles.xml b/mobile/android/base/resources/values/styles.xml
index 577e5d93bbc2..baa1fa8bcf39 100644
--- a/mobile/android/base/resources/values/styles.xml
+++ b/mobile/android/base/resources/values/styles.xml
@@ -137,6 +137,14 @@
- end
+
+
+
+
+
+
+
+
diff --git a/mobile/android/base/strings.xml.in b/mobile/android/base/strings.xml.in
index bb8353bc2a90..659af713ed75 100644
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -360,6 +360,8 @@
&contextmenu_top_sites_pin;
&contextmenu_top_sites_unpin;
&contextmenu_add_search_engine;
+ &contextmenu_mark_read;
+ &contextmenu_mark_unread;
&doorhanger_login_no_username;
&doorhanger_login_edit_title;
diff --git a/mobile/android/locales/en-US/chrome/aboutPrivateBrowsing.dtd b/mobile/android/locales/en-US/chrome/aboutPrivateBrowsing.dtd
index 7e29d554e1ee..95fec647497e 100644
--- a/mobile/android/locales/en-US/chrome/aboutPrivateBrowsing.dtd
+++ b/mobile/android/locales/en-US/chrome/aboutPrivateBrowsing.dtd
@@ -8,9 +8,15 @@
is used as a title, with the privatebrowsingpage.title string preceding it but on a separate line.
So the final line will say "Private Browsing + Tracking Protection". -->
+
+