From a3aebb169d682bf3689e961098b068765604dc05 Mon Sep 17 00:00:00 2001 From: Maaz Syed Adeeb Date: Sun, 30 Oct 2016 07:36:57 +0530 Subject: [PATCH 01/15] Removing clear cache and clear site data options from the history menu --- app/browser/menu.js | 12 +----------- app/extensions/brave/locales/en-US/menu.properties | 1 + app/locale.js | 1 + 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/app/browser/menu.js b/app/browser/menu.js index 48dba98dae9..7842c2709e9 100644 --- a/app/browser/menu.js +++ b/app/browser/menu.js @@ -322,21 +322,11 @@ const createHistorySubmenu = () => { CommonMenu.separatorMenuItem, */ { - label: locale.translation('clearHistory'), + label: locale.translation('clearBrowsingData'), accelerator: 'Shift+CmdOrCtrl+Delete', click: function (item, focusedWindow) { CommonMenu.sendToFocusedWindow(focusedWindow, [messages.SHORTCUT_OPEN_CLEAR_BROWSING_DATA_PANEL, {browserHistory: true}]) } - }, { - label: locale.translation('clearCache'), - click: function (item, focusedWindow) { - CommonMenu.sendToFocusedWindow(focusedWindow, [messages.SHORTCUT_OPEN_CLEAR_BROWSING_DATA_PANEL, {cachedImagesAndFiles: true}]) - } - }, { - label: locale.translation('clearSiteData'), - click: function (item, focusedWindow) { - CommonMenu.sendToFocusedWindow(focusedWindow, [messages.SHORTCUT_OPEN_CLEAR_BROWSING_DATA_PANEL, {allSiteCookies: true, cachedImagesAndFiles: true}]) - } } ] submenu = submenu.concat(menuUtil.createRecentlyClosedMenuItems(Immutable.fromJS(Object.keys(closedFrames).map(key => closedFrames[key])))) diff --git a/app/extensions/brave/locales/en-US/menu.properties b/app/extensions/brave/locales/en-US/menu.properties index 64477cb4540..5319c9dcadf 100644 --- a/app/extensions/brave/locales/en-US/menu.properties +++ b/app/extensions/brave/locales/en-US/menu.properties @@ -51,6 +51,7 @@ back=Back forward=Forward reopenLastClosedWindow=Reopen Last Closed Window showAllHistory=Show History +clearBrowsingData=Clear Browsing Data… clearHistory=Clear History… clearCache=Clear Cache… clearSiteData=Clear All Cookies and Site Data… diff --git a/app/locale.js b/app/locale.js index 1ebb663147b..cb963ed3740 100644 --- a/app/locale.js +++ b/app/locale.js @@ -121,6 +121,7 @@ var rendererIdentifiers = function () { 'clearCache', 'clearHistory', 'clearSiteData', + 'clearBrowsingData', 'recentlyClosed', 'recentlyVisited', 'bookmarks', From 472463a1fd9db9280d9669565be1e7e41b73cfee Mon Sep 17 00:00:00 2001 From: Aubrey Keus Date: Sun, 30 Oct 2016 16:39:04 -0400 Subject: [PATCH 02/15] Insert virtual history items for sites like www.google.ca When a site is visted for a deep linked page or with parameters the history item is stored with the complete parameters and links. Often after a user visits the site a number of times, the expectation shifts such that the simple domain should be the first suggestion in the url bar suggestion list. The canonical example is when a user searches Google a number of times via the url bar. After three searches www.google.com will be added as a virtual history item in the search results. Auditors: @bbondy, @bradrichter Test Plan: 1. Clear history 2. End three searchs from the url bar without accessing www.google.com 3. Open a new tab and type goog - ensure a history item for www.google.com is displayed Fixes: #5067 --- app/renderer/lib/suggestion.js | 63 ++++++++++++++++++++++++++++++ js/components/urlBarSuggestions.js | 29 ++++++++------ test/unit/lib/urlSuggestionTest.js | 35 +++++++++++++++++ 3 files changed, 116 insertions(+), 11 deletions(-) diff --git a/app/renderer/lib/suggestion.js b/app/renderer/lib/suggestion.js index 9be2dc7bc97..7d65971dc64 100644 --- a/app/renderer/lib/suggestion.js +++ b/app/renderer/lib/suggestion.js @@ -4,6 +4,8 @@ const urlParser = require('url') const appConfig = require('../../../js/constants/appConfig') +const _ = require('underscore') +const Immutable = require('immutable') const sigmoid = (t) => { return 1 / (1 + Math.pow(Math.E, -t)) @@ -112,3 +114,64 @@ module.exports.normalizeLocation = (location) => { location = location.replace(/^https:\/\//, '') return location } + +/* + * return a site representing the simple location for a + * set of related sites without a history item for the + * simple location. + * + * This is used to show a history suggestion for something + * like www.google.com if it has not been visited but + * there are two or more locations with that prefix containing + * path info or parameters + * + * @param {Array[Object]} sites - array of similar sites + */ +var virtualSite = (sites) => { + // array of sites without paths or query params + var simple = sites.filter((parsed) => { + return (parsed.hash === null && parsed.search === null && parsed.query === null && parsed.pathname === '/') + }) + // if there are no simple locations then we will build and return one + if (simple.length === 0) { + // we need to create a virtual history item + return Immutable.Map({ + location: sites[0].protocol + '//' + sites[0].host, + count: 0, + title: sites[0].host, + lastAccessedTime: (new Date()).getTime() + }) + } else { + return + } +} + +/* + * Create an array of simple locations from history + * The simple locations will be the root domain for a location + * without parameters or path + * + * @param {ImmutableList[ImmutableMap]} - history + */ +module.exports.createVirtualHistoryItems = (historySites) => { + // parse each history item + var parsedHistorySites = historySites.map((site) => { + return urlParser.parse(site.get('location')) + }).toArray() + // group them by host + var grouped = _.groupBy(parsedHistorySites, (parsedSite) => { + return parsedSite.host || 'unknown' + }) + // find groups with more than 2 of the same host + var multiGroupKeys = _.filter(_.keys(grouped), (k) => { + return grouped[k].length > 2 + }) + // potentially create virtual history items + var virtualHistorySites = _.map(multiGroupKeys, (location) => { + return virtualSite(grouped[location]) + }) + virtualHistorySites = _.filter(virtualHistorySites, (site) => { + return !!site + }) + return virtualHistorySites +} diff --git a/js/components/urlBarSuggestions.js b/js/components/urlBarSuggestions.js index 0b794eb6b65..f67061146c5 100644 --- a/js/components/urlBarSuggestions.js +++ b/js/components/urlBarSuggestions.js @@ -281,10 +281,26 @@ class UrlBarSuggestions extends ImmutableComponent { } } + const historyFilter = (site) => { + const title = site.get('title') || '' + const location = site.get('location') || '' + // Note: Bookmark sites are now included in history. This will allow + // sites to appear in the auto-complete regardless of their bookmark + // status. If history is turned off, bookmarked sites will appear + // in the bookmark section. + return (title.toLowerCase().includes(urlLocationLower) || + location.toLowerCase().includes(urlLocationLower)) + } + var historySites = props.sites.filter(historyFilter) + + // potentially append virtual history items (such as www.google.com when + // searches have been made but the root site has not been visited) + historySites = historySites.concat(suggestion.createVirtualHistoryItems(historySites)) + // history if (getSetting(settings.HISTORY_SUGGESTIONS)) { suggestions = suggestions.concat(mapListToElements({ - data: props.sites, + data: historySites, maxResults: config.urlBarSuggestions.maxHistorySites, type: suggestionTypes.HISTORY, clickHandler: navigateClickHandler((site) => { @@ -293,16 +309,7 @@ class UrlBarSuggestions extends ImmutableComponent { sortHandler: sortBasedOnLocationPos, formatTitle: (site) => site.get('title'), formatUrl: (site) => site.get('location'), - filterValue: (site) => { - const title = site.get('title') || '' - const location = site.get('location') || '' - return (title.toLowerCase().includes(urlLocationLower) || - location.toLowerCase().includes(urlLocationLower)) - // Note: Bookmkark sites are now included in history. This will allow - // sites to appear in the auto-complete regardless of their bookmark - // status. If history is turned off, bookmarked sites will appear - // in the bookmark section. - } + filterValue: historyFilter })) } diff --git a/test/unit/lib/urlSuggestionTest.js b/test/unit/lib/urlSuggestionTest.js index 9bc5e62adaf..f6bb9055138 100644 --- a/test/unit/lib/urlSuggestionTest.js +++ b/test/unit/lib/urlSuggestionTest.js @@ -26,3 +26,38 @@ describe('suggestion', function () { assert.ok(suggestion.simpleDomainNameValue(siteComplex) === 0, 'complex site returns 0') }) }) + +const site1 = Immutable.Map({ + location: 'http://www.foo.com/1', + count: 0, + lastAccessedTime: 0, + title: 'www.foo/com/1' +}) + +const site2 = Immutable.Map({ + location: 'http://www.foo.com/2', + count: 0, + lastAccessedTime: 0, + title: 'www.foo/com/2' +}) + +const site3 = Immutable.Map({ + location: 'http://www.foo.com/3', + count: 0, + lastAccessedTime: 0, + title: 'www.foo/com/3' +}) + +describe('suggestion', function () { + it('shows virtual history item', function () { + var history = Immutable.List([site1, site2, site3]) + var virtual = suggestion.createVirtualHistoryItems(history) + assert.ok(virtual.length > 0, 'virtual location created') + assert.ok(virtual[0].get('location') === 'http://www.foo.com') + assert.ok(virtual[0].get('title') === 'www.foo.com') + assert.ok(virtual[0].get('lastAccessedTime') > 0) + history = Immutable.List([site1, site2]) + virtual = suggestion.createVirtualHistoryItems(history) + assert.ok(virtual.length === 0, 'virtual location not created') + }) +}) From 14d30c68191c1e0d338e2603956cfa0ea7908575 Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Sun, 30 Oct 2016 22:38:06 -0400 Subject: [PATCH 03/15] Add search autocomplete for startpage Fix #5281 Auditors: @darkdh --- app/extensions/brave/index-dev.html | 2 +- app/extensions/brave/index.html | 2 +- js/data/searchProviders.js | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/extensions/brave/index-dev.html b/app/extensions/brave/index-dev.html index 9adb7a5f2b3..83eeb787e35 100644 --- a/app/extensions/brave/index-dev.html +++ b/app/extensions/brave/index-dev.html @@ -7,7 +7,7 @@ - + Brave diff --git a/app/extensions/brave/index.html b/app/extensions/brave/index.html index 1a51d61ca3b..2be45b22e13 100644 --- a/app/extensions/brave/index.html +++ b/app/extensions/brave/index.html @@ -7,7 +7,7 @@ - + Brave diff --git a/js/data/searchProviders.js b/js/data/searchProviders.js index e89630f3499..7d57be250c4 100644 --- a/js/data/searchProviders.js +++ b/js/data/searchProviders.js @@ -79,7 +79,8 @@ module.exports = { "providers" : { "name" : "StartPage", "image" : "https://www.startpage.com/graphics/favicon/sp-favicon-16x16.png", - "search" : "https://startpage.com/do/dsearch?query={searchTerms}&cat=web&pl=opensearch", + "search" : "https://www.startpage.com/do/dsearch?query={searchTerms}&cat=web&pl=opensearch", + "autocomplete": "https://www.startpage.com/cgi-bin/csuggest?query={searchTerms}&limit=10&format=json", "shortcut" : ":sp" } ] From ebc19be91e58fd2758b64cda185fc56fc51065a3 Mon Sep 17 00:00:00 2001 From: Ayumi Yu Date: Sun, 30 Oct 2016 21:51:21 -0700 Subject: [PATCH 04/15] Set preferences moment locale to navigator.language Fix #4787 Auditors: @@luixxiul Test Plan: 1. Set language to non English. restart if needed. 2. See Preferences > Payments, "Contribution due date: {due date}" due date should be localized 3. Try 1+2 for another language --- js/about/preferences.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/about/preferences.js b/js/about/preferences.js index 08ad33c65c8..44a2c2d18fd 100644 --- a/js/about/preferences.js +++ b/js/about/preferences.js @@ -27,8 +27,9 @@ const getSetting = require('../settings').getSetting const SortableTable = require('../components/sortableTable') const Button = require('../components/button') const searchProviders = require('../data/searchProviders') -const moment = require('moment') const punycode = require('punycode') +const moment = require('moment') +moment.locale(navigator.language) const adblock = appConfig.resourceNames.ADBLOCK const cookieblock = appConfig.resourceNames.COOKIEBLOCK From 35c5b97b64eef9d87a9581c8f8c6e3f58ac05c00 Mon Sep 17 00:00:00 2001 From: Brian Clifton Date: Mon, 31 Oct 2016 01:24:05 -0700 Subject: [PATCH 05/15] Favicon is now updated in session after visiting site Required to make sure we get the latest favicons for the new about:newtab page, our bookmarks toolbar, and also the about:bookmarks page. Before, the favicon was only being updated: - when site is bookmarked / rebookmarked - when site is pinned Auditors: @darkdh @cezaraugusto Fixes https://github.com/brave/browser-laptop/issues/4860 Test Plan: 1. Import bookmarks from Chrome or HTML... OR manually create a new bookmark (from about:bookmarks) 2. Show the bookmarks toolbar and notice the favicon is not loaded 3. Load/visit one of the bookmarks which does NOT have a favicon yet 4. After visiting the page, notice that the favicon is updated Fixes https://github.com/brave/browser-laptop/issues/2747 Test Plan: 1. Open a new tab 2. Per issue description, visit tokyo.cawaii.media/gisele/ 3. Go back to the empty tab by pressing the back button 4. Press and hold the forward button to display the pulldown --- js/state/siteUtil.js | 30 ++++++++++++++++++++++++++++++ js/stores/appStore.js | 3 +++ test/unit/state/siteUtilTest.js | 22 ++++++++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/js/state/siteUtil.js b/js/state/siteUtil.js index 6993e849899..96b6f1b84bd 100644 --- a/js/state/siteUtil.js +++ b/js/state/siteUtil.js @@ -319,6 +319,36 @@ module.exports.getDetailFromFrame = function (frame, tag) { }) } +/** + * Update the favicon URL for all entries in the sites list + * which match a given location. Currently, there should only be + * one match, but this will handle multiple. + * + * @param sites The application state's Immutable sites list + * @param location URL for the entry needing an update + * @param favicon favicon URL + */ +module.exports.updateSiteFavicon = function (sites, location, favicon) { + const matchingIndices = [] + + sites.filter((site, index) => { + if (site.get('location') === location) { + matchingIndices.push(index) + return true + } + return false + }) + + if (!matchingIndices.length) return sites + + let updatedSites = sites + matchingIndices.forEach((index) => { + updatedSites = updatedSites.setIn([index, 'favicon'], favicon) + }) + + return updatedSites +} + /** * Converts a siteDetail to frameOpts format * @param {Object} siteDetail - A site detail as per app state diff --git a/js/stores/appStore.js b/js/stores/appStore.js index 9ada8cd2729..9206535249a 100644 --- a/js/stores/appStore.js +++ b/js/stores/appStore.js @@ -770,6 +770,9 @@ const handleAppAction = (action) => { case AppConstants.APP_DEFAULT_BROWSER_CHECK_COMPLETE: appState = appState.set('defaultBrowserCheckComplete', {}) break + case WindowConstants.WINDOW_SET_FAVICON: + appState = appState.set('sites', siteUtil.updateSiteFavicon(appState.get('sites'), action.frameProps.get('location'), action.favicon)) + break default: } diff --git a/test/unit/state/siteUtilTest.js b/test/unit/state/siteUtilTest.js index 219ee6ad43c..82797848f18 100644 --- a/test/unit/state/siteUtilTest.js +++ b/test/unit/state/siteUtilTest.js @@ -470,6 +470,28 @@ describe('siteUtil', function () { describe('moveSite', function () { }) + describe('updateSiteFavicon', function () { + it('updates the favicon for all matching entries', function () { + const siteDetail1 = Immutable.fromJS({ + tags: [siteTags.BOOKMARK], + location: testUrl1, + title: 'bookmarked site' + }) + const siteDetail2 = Immutable.fromJS({ + tags: [], + location: testUrl1, + title: 'bookmarked site' + }) + const sites = Immutable.fromJS([siteDetail1, siteDetail2]) + const processedSites = siteUtil.updateSiteFavicon(sites, testUrl1, 'https://brave.com/favicon.ico') + const updatedSiteDetail1 = siteDetail1.set('favicon', 'https://brave.com/favicon.ico') + const updatedSiteDetail2 = siteDetail2.set('favicon', 'https://brave.com/favicon.ico') + const expectedSites = Immutable.fromJS([updatedSiteDetail1, updatedSiteDetail2]) + + assert.deepEqual(processedSites.toJS(), expectedSites.toJS()) + }) + }) + describe('getDetailFromFrame', function () { it('returns an Immutable object with all expected properties', function () { const frame = Immutable.fromJS({ From 170a14ec99f091ab9e28e5238d5b12f44f7f0ab5 Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Mon, 31 Oct 2016 09:28:28 -0400 Subject: [PATCH 06/15] Navigating to new page should reset find state, but keep last text Fix #5286 Auditors: @diracdeltas --- app/sessionStore.js | 1 + js/components/frame.js | 2 +- js/components/main.js | 5 ++++- test/components/frameTest.js | 33 ++++++++++++++++++++++++++++++++ test/fixtures/find_in_page2.html | 9 +++++++++ 5 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 test/fixtures/find_in_page2.html diff --git a/app/sessionStore.js b/app/sessionStore.js index cbbe31c711e..7cebbf0591c 100644 --- a/app/sessionStore.js +++ b/app/sessionStore.js @@ -176,6 +176,7 @@ module.exports.cleanPerWindowData = (perWindowData, isShutdown) => { if (frame.findDetail) { delete frame.findDetail.numberOfMatches delete frame.findDetail.activeMatchOrdinal + delete frame.findDetail.internalFindStatePresent } delete frame.findbarShown // Don't restore full screen state diff --git a/js/components/frame.js b/js/components/frame.js index 11f031132ed..327c70e8597 100644 --- a/js/components/frame.js +++ b/js/components/frame.js @@ -996,7 +996,7 @@ class Frame extends ImmutableComponent { this.webview.addEventListener('did-navigate', (e) => { if (this.props.findbarShown) { - windowActions.setFindbarShown(this.frame, false) + this.props.onFindHide() } for (let message in this.notificationCallbacks) { diff --git a/js/components/main.js b/js/components/main.js index 26178993314..30cf76171a1 100644 --- a/js/components/main.js +++ b/js/components/main.js @@ -716,7 +716,9 @@ class Main extends ImmutableComponent { windowActions.setFindbarShown(activeFrame, false) webviewActions.stopFindInPage() windowActions.setFindDetail(activeFrame, Immutable.fromJS({ - internalFindStatePresent: false + internalFindStatePresent: false, + numberOfMatches: -1, + activeMatchOrdinal: 0 })) } @@ -1203,6 +1205,7 @@ class Main extends ImmutableComponent { ledgerInfo={this.props.appState.get('ledgerInfo') || new Immutable.Map()} publisherInfo={this.props.appState.get('publisherInfo') || new Immutable.Map()} frameSiteSettings={this.frameSiteSettings(frame.get('location'))} + onFindHide={this.onFindHide} enableNoScript={this.enableNoScript(this.frameSiteSettings(frame.get('location')))} isPreview={frame.get('key') === this.props.windowState.get('previewFrameKey')} isActive={FrameStateUtil.isFrameKeyActive(this.props.windowState, frame.get('key'))} diff --git a/test/components/frameTest.js b/test/components/frameTest.js index f8d40027217..c6aadbf41b5 100644 --- a/test/components/frameTest.js +++ b/test/components/frameTest.js @@ -128,6 +128,39 @@ describe('findbar', function () { assert.equal(match, '2 of 2') }) + it('findbar input remembered but no active ordinals after navigation until RETURN key', function * () { + const url2 = Brave.server.url('find_in_page2.html') + yield this.app.client + .showFindbar() + .waitForElementFocus(findBarInput) + .setValue(findBarInput, 'Brad') + .waitUntil(function () { + return this.getValue(findBarInput).then((val) => val === 'Brad') + }) + let match = yield this.app.client.getText(findBarMatches) + assert.equal(match, '0 matches') + + yield this.app.client + .waitForVisible(findBarMatches) + .tabByUrl(Brave.newTabUrl) + .url(url2) + .waitForUrl(url2) + .windowParentByUrl(url2) + .waitUntil(function () { + return this.getAttribute('webview[data-frame-key="1"]', 'src').then((src) => src === url2) + }) + // No findbar + .waitForVisible(findBarInput, 500, true) + .showFindbar() + .waitForElementFocus(findBarInput) + // Matches shouldn't be shown until enter is pressed + .waitForVisible(findBarMatches, 500, true) + .keys(Brave.keys.RETURN) + .waitForVisible(findBarMatches) + match = yield this.app.client.getText(findBarMatches) + assert.equal(match, '1 of 1') + }) + it('remembers findbar input when switching frames', function * () { const url = Brave.server.url('find_in_page.html') yield this.app.client diff --git a/test/fixtures/find_in_page2.html b/test/fixtures/find_in_page2.html new file mode 100644 index 00000000000..d5c00cc5673 --- /dev/null +++ b/test/fixtures/find_in_page2.html @@ -0,0 +1,9 @@ + + + + Find in page2 + + + Brad hates prime numbers. + + From e10a69807a6050443b5970b03aefbcc474f521a7 Mon Sep 17 00:00:00 2001 From: Anthony Tseng Date: Mon, 31 Oct 2016 10:59:33 -0400 Subject: [PATCH 07/15] Disable autofill management button when autofill is disabled fix #5146 Auditors: @bsclifton Test Plan: 1. Go to about:preferences#security 2. Toggle "Enable Autofill" off 3. Manage Autofill Data button should be disabled --- js/about/preferences.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/about/preferences.js b/js/about/preferences.js index 44a2c2d18fd..730363b435a 100644 --- a/js/about/preferences.js +++ b/js/about/preferences.js @@ -1528,7 +1528,7 @@ class SecurityTab extends ImmutableComponent {