diff --git a/app/browser/api/topSites.js b/app/browser/api/topSites.js
index 48f3c9ccfce..a4fc6329a65 100644
--- a/app/browser/api/topSites.js
+++ b/app/browser/api/topSites.js
@@ -7,39 +7,33 @@
const Immutable = require('immutable')
const appActions = require('../../../js/actions/appActions')
const debounce = require('../../../js/lib/debounce')
-const siteUtil = require('../../../js/state/siteUtil')
+const historyState = require('../../common/state/historyState')
const {isSourceAboutUrl} = require('../../../js/lib/appUrlUtil')
-const aboutNewTabMaxEntries = 100
+const aboutNewTabMaxEntries = 18
let appStore
let minCountOfTopSites
let minAccessOfTopSites
-const compareSites = (site1, site2) => {
- if (!site1 || !site2) return false
- return site1.get('location') === site2.get('location') &&
- site1.get('partitionNumber') === site2.get('partitionNumber')
-}
-
const pinnedTopSites = (state) => {
- return (state.getIn(['about', 'newtab', 'pinnedTopSites']) || Immutable.List()).setSize(18)
+ return state.getIn(['about', 'newtab', 'pinnedTopSites'], Immutable.List())
}
const ignoredTopSites = (state) => {
- return state.getIn(['about', 'newtab', 'ignoredTopSites']) || Immutable.List()
+ return state.getIn(['about', 'newtab', 'ignoredTopSites'], Immutable.List())
}
-const isPinned = (state, siteProps) => {
- return pinnedTopSites(state).filter((site) => compareSites(site, siteProps)).size > 0
+const isPinned = (state, siteKey) => {
+ return pinnedTopSites(state).find(site => site.get('key') === siteKey)
}
-const isIgnored = (state, siteProps) => {
- return ignoredTopSites(state).filter((site) => compareSites(site, siteProps)).size > 0
+const isIgnored = (state, siteKey) => {
+ return ignoredTopSites(state).includes(siteKey)
}
const sortCountDescending = (left, right) => {
- const leftCount = left.get('count') || 0
- const rightCount = right.get('count') || 0
+ const leftCount = left.get('count', 0)
+ const rightCount = right.get('count', 0)
if (leftCount < rightCount) {
return 1
}
@@ -55,25 +49,6 @@ const sortCountDescending = (left, right) => {
return 0
}
-const removeDuplicateDomains = (list) => {
- const siteDomains = new Set()
- return list.filter((site) => {
- if (!site.get('location')) {
- return false
- }
- try {
- const hostname = require('../../common/urlParse')(site.get('location')).hostname
- if (!siteDomains.has(hostname)) {
- siteDomains.add(hostname)
- return true
- }
- } catch (e) {
- console.log('Error parsing hostname: ', e)
- }
- return false
- })
-}
-
const calculateTopSites = (clearCache) => {
if (clearCache) {
clearTopSiteCacheData()
@@ -91,18 +66,21 @@ const startCalculatingTopSiteData = debounce(() => {
}
const state = appStore.getState()
// remove folders; sort by visit count; enforce a max limit
- const sites = (state.get('sites') ? state.get('sites').toList() : new Immutable.List())
- .filter((site) => !siteUtil.isFolder(site) &&
- !siteUtil.isImportedBookmark(site) &&
- !isSourceAboutUrl(site.get('location')) &&
+ const sites = historyState.getSites(state)
+ .filter((site, key) => !isSourceAboutUrl(site.get('location')) &&
+ !isPinned(state, key) &&
+ !isIgnored(state, key) &&
(minCountOfTopSites === undefined || (site.get('count') || 0) >= minCountOfTopSites) &&
- (minAccessOfTopSites === undefined || (site.get('lastAccessedTime') || 0) >= minAccessOfTopSites))
+ (minAccessOfTopSites === undefined || (site.get('lastAccessedTime') || 0) >= minAccessOfTopSites)
+ )
.sort(sortCountDescending)
.slice(0, aboutNewTabMaxEntries)
+ .map((site, key) => site.set('key', key))
+ .toList()
for (let i = 0; i < sites.size; i++) {
- const count = sites.getIn([i, 'count']) || 0
- const access = sites.getIn([i, 'lastAccessedTime']) || 0
+ const count = sites.getIn([i, 'count'], 0)
+ const access = sites.getIn([i, 'lastAccessedTime'], 0)
if (minCountOfTopSites === undefined || count < minCountOfTopSites) {
minCountOfTopSites = count
}
@@ -111,32 +89,7 @@ const startCalculatingTopSiteData = debounce(() => {
}
}
- // Filter out pinned and ignored sites
- let unpinnedSites = sites.filter((site) => !(isPinned(state, site) || isIgnored(state, site)))
- unpinnedSites = removeDuplicateDomains(unpinnedSites)
-
- // Merge the pinned and unpinned lists together
- // Pinned items have priority because the position is important
- let gridSites = pinnedTopSites(state).map((pinnedSite) => {
- // Fetch latest siteDetail objects from appState.sites using location/partition
- if (pinnedSite) {
- const matches = sites.filter((site) => compareSites(site, pinnedSite))
- if (matches.size > 0) return matches.first()
- }
- // Default to unpinned items
- const firstSite = unpinnedSites.first()
- unpinnedSites = unpinnedSites.shift()
- return firstSite
- })
-
- // Include up to [aboutNewTabMaxEntries] entries so that folks
- // can ignore sites and have new items fill those empty spaces
- if (unpinnedSites.size > 0) {
- gridSites = gridSites.concat(unpinnedSites)
- }
-
- const finalData = gridSites.filter((site) => site != null)
- appActions.topSiteDataAvailable(finalData)
+ appActions.topSiteDataAvailable(sites)
}, 5 * 1000)
const clearTopSiteCacheData = () => {
diff --git a/app/browser/bookmarksExporter.js b/app/browser/bookmarksExporter.js
index 598501ed3da..572f85328c7 100644
--- a/app/browser/bookmarksExporter.js
+++ b/app/browser/bookmarksExporter.js
@@ -11,15 +11,23 @@ const electron = require('electron')
const dialog = electron.dialog
const app = electron.app
const BrowserWindow = electron.BrowserWindow
-const getSetting = require('../../js/settings').getSetting
+
+// State
+const bookmarksState = require('../common/state/bookmarksState')
+
+// Constants
const settings = require('../../js/constants/settings')
-const siteTags = require('../../js/constants/siteTags')
-const siteUtil = require('../../js/state/siteUtil')
-const isWindows = process.platform === 'win32'
+
+// Utils
+const {getSetting} = require('../../js/settings')
+const platformUtil = require('../common/lib/platformUtil')
+const bookmarkFoldersUtil = require('../common/lib/bookmarkFoldersUtil')
+const bookmarkUtil = require('../common/lib/bookmarkUtil')
+
const indentLength = 2
const indentType = ' '
-function showDialog (sites) {
+const showDialog = (state) => {
const focusedWindow = BrowserWindow.getFocusedWindow()
const fileName = moment().format('DD_MM_YYYY') + '.html'
const defaultPath = path.join(getSetting(settings.DEFAULT_DOWNLOAD_SAVE_PATH) || app.getPath('downloads'), fileName)
@@ -34,17 +42,15 @@ function showDialog (sites) {
}]
}, (fileName) => {
if (fileName) {
- personal = createBookmarkArray(sites)
- other = createBookmarkArray(sites, -1, false)
+ personal = createBookmarkArray(state)
+ other = createBookmarkArray(state, -1, false)
fs.writeFileSync(fileName, createBookmarkHTML(personal, other))
}
})
}
-function createBookmarkArray (sites, parentFolderId, first = true, depth = 1) {
- const filteredBookmarks = parentFolderId
- ? sites.filter((site) => site.get('parentFolderId') === parentFolderId)
- : sites.filter((site) => !site.get('parentFolderId'))
+const createBookmarkArray = (state, parentFolderId = 0, first = true, depth = 1) => {
+ const bookmarks = bookmarksState.getBookmarksWithFolders(state, parentFolderId)
let payload = []
let title
let indentFirst = indentType.repeat(depth * indentLength)
@@ -52,16 +58,13 @@ function createBookmarkArray (sites, parentFolderId, first = true, depth = 1) {
if (first) payload.push(`${indentFirst}
`)
- filteredBookmarks.forEach((site) => {
- if (site.get('tags').includes(siteTags.BOOKMARK) && site.get('location')) {
- title = site.get('customTitle') || site.get('title') || site.get('location')
+ bookmarks.forEach((site) => {
+ if (bookmarkUtil.isBookmark(site) && site.get('location')) {
+ title = site.get('title', site.get('location'))
payload.push(`${indentNext}
- ${title}`)
- } else if (siteUtil.isFolder(site)) {
- const folderId = site.get('folderId')
-
- title = site.get('customTitle') || site.get('title')
- payload.push(`${indentNext}
${title}
`)
- payload = payload.concat(createBookmarkArray(sites, folderId, true, (depth + 1)))
+ } else if (bookmarkFoldersUtil.isFolder(site)) {
+ payload.push(`${indentNext}${site.get('title')}
`)
+ payload = payload.concat(createBookmarkArray(state, site.get('folderId'), true, (depth + 1)))
}
})
@@ -70,8 +73,8 @@ function createBookmarkArray (sites, parentFolderId, first = true, depth = 1) {
return payload
}
-function createBookmarkHTML (personal, other) {
- const breakTag = (isWindows) ? '\r\n' : '\n'
+const createBookmarkHTML = (personal, other) => {
+ const breakTag = (platformUtil.isWindows()) ? '\r\n' : '\n'
const title = 'Bookmarks'
return `
diff --git a/app/browser/menu.js b/app/browser/menu.js
index a5b550a8619..b83a907d51d 100644
--- a/app/browser/menu.js
+++ b/app/browser/menu.js
@@ -17,7 +17,6 @@ const appConstants = require('../../js/constants/appConstants')
const windowConstants = require('../../js/constants/windowConstants')
const messages = require('../../js/constants/messages')
const settings = require('../../js/constants/settings')
-const siteTags = require('../../js/constants/siteTags')
// State
const {getByTabId} = require('../common/state/tabState')
@@ -35,8 +34,8 @@ const frameStateUtil = require('../../js/state/frameStateUtil')
const menuUtil = require('../common/lib/menuUtil')
const {getSetting} = require('../../js/settings')
const locale = require('../locale')
-const {isLocationBookmarked} = require('../../js/state/siteUtil')
const platformUtil = require('../common/lib/platformUtil')
+const bookmarkUtil = require('../common/lib/bookmarkUtil')
const isDarwin = platformUtil.isDarwin()
const isLinux = platformUtil.isLinux()
const isWindows = platformUtil.isWindows()
@@ -376,7 +375,7 @@ const updateRecentlyClosedMenuItems = (state) => {
}
const isCurrentLocationBookmarked = (state) => {
- return isLocationBookmarked(state, currentLocation)
+ return bookmarkUtil.isLocationBookmarked(state, currentLocation)
}
const createBookmarksSubmenu = (state) => {
@@ -406,7 +405,7 @@ const createBookmarksSubmenu = (state) => {
CommonMenu.exportBookmarksMenuItem()
]
- const bookmarks = menuUtil.createBookmarkTemplateItems(state.get('sites'))
+ const bookmarks = menuUtil.createBookmarkTemplateItems(state)
if (bookmarks.length > 0) {
submenu.push(CommonMenu.separatorMenuItem)
submenu = submenu.concat(bookmarks)
@@ -693,38 +692,14 @@ const doAction = (state, action) => {
}
break
}
- case appConstants.APP_APPLY_SITE_RECORDS:
- if (action.records && action.records.find((record) => record.objectData === 'bookmark')) {
- createMenu(state)
- }
- break
- case appConstants.APP_ADD_SITE:
case appConstants.APP_ADD_BOOKMARK:
case appConstants.APP_EDIT_BOOKMARK:
- {
- if (action.tag === siteTags.BOOKMARK || action.tag === siteTags.BOOKMARK_FOLDER) {
- createMenu(state)
- } else if (action.siteDetail && action.siteDetail.constructor === Immutable.List && action.tag === undefined) {
- let shouldRebuild = false
- action.siteDetail.forEach((site) => {
- const tag = site.getIn(['tags', 0])
- if (tag === siteTags.BOOKMARK || tag === siteTags.BOOKMARK_FOLDER) {
- shouldRebuild = true
- }
- })
- if (shouldRebuild) {
- createMenu(state)
- }
- }
- break
- }
- case appConstants.APP_REMOVE_SITE:
- {
- if (action.tag === siteTags.BOOKMARK || action.tag === siteTags.BOOKMARK_FOLDER) {
- createMenu(state)
- }
- break
- }
+ case appConstants.APP_REMOVE_BOOKMARK:
+ case appConstants.APP_ADD_BOOKMARK_FOLDER:
+ case appConstants.APP_EDIT_BOOKMARK_FOLDER:
+ case appConstants.APP_REMOVE_BOOKMARK_FOLDER:
+ createMenu(state)
+ break
case appConstants.APP_ON_CLEAR_BROWSING_DATA:
{
const defaults = state.get('clearBrowsingDataDefaults')
diff --git a/app/browser/reducers/bookmarkFoldersReducer.js b/app/browser/reducers/bookmarkFoldersReducer.js
new file mode 100644
index 00000000000..365bae4ca32
--- /dev/null
+++ b/app/browser/reducers/bookmarkFoldersReducer.js
@@ -0,0 +1,88 @@
+/* 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/. */
+
+const Immutable = require('immutable')
+
+// State
+const bookmarkFoldersState = require('../../common/state/bookmarkFoldersState')
+
+// Constants
+const appConstants = require('../../../js/constants/appConstants')
+
+// Utils
+const {makeImmutable} = require('../../common/state/immutableUtil')
+const syncUtil = require('../../../js/state/syncUtil')
+
+const bookmarkFoldersReducer = (state, action, immutableAction) => {
+ action = immutableAction || makeImmutable(action)
+ switch (action.get('actionType')) {
+ case appConstants.APP_ADD_BOOKMARK_FOLDER:
+ {
+ const closestKey = action.get('closestKey')
+ let folder = action.get('folderDetails')
+
+ if (folder == null) {
+ break
+ }
+
+ if (Immutable.List.isList(folder)) {
+ action.get('folderDetails', Immutable.List()).forEach((folder) => {
+ state = bookmarkFoldersState.addFolder(state, folder, closestKey)
+
+ if (syncUtil.syncEnabled()) {
+ state = syncUtil.updateSiteCache(state, folder)
+ }
+ })
+ } else {
+ state = bookmarkFoldersState.addFolder(state, folder, closestKey)
+
+ if (syncUtil.syncEnabled()) {
+ state = syncUtil.updateSiteCache(state, folder)
+ }
+ }
+ break
+ }
+ case appConstants.APP_EDIT_BOOKMARK_FOLDER:
+ {
+ let folder = action.get('folderDetails')
+
+ if (folder == null) {
+ break
+ }
+
+ state = bookmarkFoldersState.editFolder(state, folder, action.get('editKey'))
+
+ if (syncUtil.syncEnabled()) {
+ state = syncUtil.updateSiteCache(state, folder)
+ }
+
+ break
+ }
+ case appConstants.APP_MOVE_BOOKMARK_FOLDER:
+ {
+ state = bookmarkFoldersState.moveFolder(
+ state,
+ action.get('folderKey'),
+ action.get('destinationKey'),
+ action.get('append'),
+ action.get('moveIntoParent')
+ )
+
+ if (syncUtil.syncEnabled()) {
+ const destinationDetail = state.getIn(['sites', action.get('destinationKey')])
+ state = syncUtil.updateSiteCache(state, destinationDetail)
+ }
+ break
+ }
+ case appConstants.APP_REMOVE_BOOKMARK_FOLDER:
+ {
+ state = bookmarkFoldersState.removeFolder(state, action.get('folderKey'))
+ break
+ }
+ }
+
+ return state
+}
+
+module.exports = bookmarkFoldersReducer
diff --git a/app/browser/reducers/bookmarksReducer.js b/app/browser/reducers/bookmarksReducer.js
new file mode 100644
index 00000000000..d6271bcfc4b
--- /dev/null
+++ b/app/browser/reducers/bookmarksReducer.js
@@ -0,0 +1,97 @@
+/* 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/. */
+
+const Immutable = require('immutable')
+
+// State
+const bookmarksState = require('../../common/state/bookmarksState')
+
+// Constants
+const appConstants = require('../../../js/constants/appConstants')
+
+// Utils
+const {makeImmutable} = require('../../common/state/immutableUtil')
+const syncUtil = require('../../../js/state/syncUtil')
+const bookmarkUtil = require('../../common/lib/bookmarkUtil')
+const siteCache = require('../../common/state/siteCache')
+
+const bookmarksReducer = (state, action, immutableAction) => {
+ action = immutableAction || makeImmutable(action)
+ switch (action.get('actionType')) {
+ case appConstants.APP_SET_STATE:
+ state = siteCache.loadLocationSiteKeysCache(state)
+ break
+ case appConstants.APP_ADD_BOOKMARK:
+ {
+ const closestKey = action.get('closestKey')
+ let bookmark = action.get('siteDetail')
+
+ if (bookmark == null) {
+ break
+ }
+
+ if (Immutable.List.isList(bookmark)) {
+ action.get('siteDetail', Immutable.List()).forEach((bookmark) => {
+ state = bookmarksState.addBookmark(state, bookmark, closestKey)
+
+ if (syncUtil.syncEnabled()) {
+ state = syncUtil.updateSiteCache(state, bookmark)
+ }
+ })
+ } else {
+ state = bookmarksState.addBookmark(state, bookmark, closestKey)
+
+ if (syncUtil.syncEnabled()) {
+ state = syncUtil.updateSiteCache(state, bookmark)
+ }
+ }
+
+ state = bookmarkUtil.updateActiveTabBookmarked(state)
+ break
+ }
+ case appConstants.APP_EDIT_BOOKMARK:
+ {
+ let bookmark = action.get('siteDetail')
+
+ if (bookmark == null) {
+ break
+ }
+
+ state = bookmarksState.editBookmark(state, bookmark, action.get('editKey'))
+
+ if (syncUtil.syncEnabled()) {
+ state = syncUtil.updateSiteCache(state, bookmark)
+ }
+
+ state = bookmarkUtil.updateActiveTabBookmarked(state)
+ break
+ }
+ case appConstants.APP_MOVE_BOOKMARK:
+ {
+ state = bookmarksState.moveBookmark(
+ state,
+ action.get('bookmarkKey'),
+ action.get('destinationKey'),
+ action.get('append'),
+ action.get('moveIntoParent')
+ )
+
+ if (syncUtil.syncEnabled()) {
+ const destinationDetail = state.getIn(['sites', action.get('destinationKey')])
+ state = syncUtil.updateSiteCache(state, destinationDetail)
+ }
+ break
+ }
+ case appConstants.APP_REMOVE_BOOKMARK:
+ {
+ state = bookmarksState.removeBookmark(state, action.get('bookmarkKey'))
+ state = bookmarkUtil.updateActiveTabBookmarked(state)
+ break
+ }
+ }
+
+ return state
+}
+
+module.exports = bookmarksReducer
diff --git a/app/browser/reducers/historyReducer.js b/app/browser/reducers/historyReducer.js
new file mode 100644
index 00000000000..20e7ccb51ba
--- /dev/null
+++ b/app/browser/reducers/historyReducer.js
@@ -0,0 +1,70 @@
+/* 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/. */
+
+const Immutable = require('immutable')
+
+// State
+const historyState = require('../../common/state/historyState')
+
+// Actions
+const appActions = require('../../../js/actions/appActions')
+const syncActions = require('../../../js/actions/syncActions')
+
+// Constants
+const appConstants = require('../../../js/constants/appConstants')
+
+// Utils
+const {makeImmutable} = require('../../common/state/immutableUtil')
+const syncUtil = require('../../../js/state/syncUtil')
+const siteUtil = require('../../../js/state/siteUtil')
+const filtering = require('../../filtering')
+
+const historyReducer = (state, action, immutableAction) => {
+ action = immutableAction || makeImmutable(action)
+ switch (action.get('actionType')) {
+ case appConstants.APP_ON_CLEAR_BROWSING_DATA:
+ {
+ const defaults = state.get('clearBrowsingDataDefaults')
+ const temp = state.get('tempClearBrowsingData', Immutable.Map())
+ const clearData = defaults ? defaults.merge(temp) : temp
+ if (clearData.get('browserHistory')) {
+ state = historyState.clearSites()
+ filtering.clearHistory()
+ }
+ break
+ }
+ case appConstants.APP_ADD_HISTORY_SITE:
+ {
+ const isSyncEnabled = syncUtil.syncEnabled()
+ state = historyState.addSite(state, action.get('siteDetail'))
+ if (isSyncEnabled) {
+ state = syncUtil.updateSiteCache(state, action.get('siteDetail'))
+ }
+ break
+ }
+
+ case appConstants.APP_ADD_HISTORY_SITES:
+ {
+ // TODO we need to do it like this until we implement action inside actions
+ action.get('historyList', Immutable.List()).forEach(site => appActions.addHistorySite(site))
+ break
+ }
+
+ case appConstants.APP_REMOVE_HISTORY_SITE:
+ {
+ const siteKey = siteUtil.getSiteKey(action.siteDetail)
+ state = historyState.removeSite(state, siteKey)
+
+ if (syncUtil.syncEnabled()) {
+ syncActions.removeSite(historyState.getSite(state, siteKey))
+ state = syncUtil.updateSiteCache(state, action.siteDetail)
+ }
+ break
+ }
+ }
+
+ return state
+}
+
+module.exports = historyReducer
diff --git a/app/browser/reducers/pinnedSitesReducer.js b/app/browser/reducers/pinnedSitesReducer.js
new file mode 100644
index 00000000000..a371c42c672
--- /dev/null
+++ b/app/browser/reducers/pinnedSitesReducer.js
@@ -0,0 +1,72 @@
+/* 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/. */
+
+// State
+const pinnedSitesState = require('../../common/state/pinnedSitesState')
+const tabState = require('../../common/state/tabState')
+
+// Constants
+const appConstants = require('../../../js/constants/appConstants')
+
+// Utils
+const {makeImmutable} = require('../../common/state/immutableUtil')
+const syncUtil = require('../../../js/state/syncUtil')
+const pinnedSitesUtil = require('../../common/lib/pinnedSitesUtil')
+
+const historyReducer = (state, action, immutableAction) => {
+ action = immutableAction || makeImmutable(action)
+ switch (action.get('actionType')) {
+ case appConstants.APP_TAB_UPDATED:
+ {
+ if (action.getIn(['changeInfo', 'pinned']) != null) {
+ const pinned = action.getIn(['changeInfo', 'pinned'])
+ const tabId = action.getIn(['tabValue', 'tabId'])
+ const tab = tabState.getByTabId(state, tabId)
+ if (!tab) {
+ console.warn('Trying to pin a tabId which does not exist:', tabId, 'tabs: ', state.get('tabs').toJS())
+ break
+ }
+ const sites = pinnedSitesState.getSites(state)
+ const siteDetail = pinnedSitesUtil.getDetailsFromTab(sites, tab)
+ if (pinned) {
+ state = pinnedSitesState.addPinnedSite(state, siteDetail)
+ } else {
+ state = pinnedSitesState.removePinnedSite(state, siteDetail)
+ }
+ if (syncUtil.syncEnabled()) {
+ state = syncUtil.updateSiteCache(state, siteDetail)
+ }
+ }
+ break
+ }
+ case appConstants.APP_CREATE_TAB_REQUESTED:
+ {
+ const createProperties = action.get('createProperties')
+ if (createProperties.get('pinned')) {
+ state = pinnedSitesUtil.addPinnedSite(state, pinnedSitesUtil.getDetailFromProperties(createProperties))
+ }
+ break
+ }
+ case appConstants.APP_ON_PINNED_TAB_REORDER:
+ {
+ state = pinnedSitesState.reOrderSite(
+ state,
+ action.siteKey,
+ action.destinationKey,
+ action.prepend
+ )
+
+ // TODO do we need this for pinned sites?
+ if (syncUtil.syncEnabled()) {
+ const newSite = state.getIn(['pinnedSites', action.siteKey])
+ state = syncUtil.updateSiteCache(state, newSite)
+ }
+ break
+ }
+ }
+
+ return state
+}
+
+module.exports = historyReducer
diff --git a/app/browser/reducers/sitesReducer.js b/app/browser/reducers/sitesReducer.js
deleted file mode 100644
index 6f5035404bf..00000000000
--- a/app/browser/reducers/sitesReducer.js
+++ /dev/null
@@ -1,192 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-'use strict'
-
-const appConstants = require('../../../js/constants/appConstants')
-const filtering = require('../../filtering')
-const siteCache = require('../../common/state/siteCache')
-const siteTags = require('../../../js/constants/siteTags')
-const siteUtil = require('../../../js/state/siteUtil')
-const syncActions = require('../../../js/actions/syncActions')
-const syncUtil = require('../../../js/state/syncUtil')
-const Immutable = require('immutable')
-const settings = require('../../../js/constants/settings')
-const {getSetting} = require('../../../js/settings')
-const writeActions = require('../../../js/constants/sync/proto').actions
-const tabState = require('../../common/state/tabState')
-
-const syncEnabled = () => {
- return getSetting(settings.SYNC_ENABLED) === true
-}
-
-const updateTabBookmarked = (state, tabValue) => {
- if (!tabValue || !tabValue.get('tabId')) {
- return state
- }
- const bookmarked = siteUtil.isLocationBookmarked(state, tabValue.get('url'))
- return tabState.updateTabValue(state, tabValue.set('bookmarked', bookmarked))
-}
-
-const updateActiveTabBookmarked = (state) => {
- const tab = tabState.getActiveTab(state)
- if (!tab) {
- return state
- }
- return updateTabBookmarked(state, tab)
-}
-
-const sitesReducer = (state, action, immutableAction) => {
- switch (action.actionType) {
- case appConstants.APP_SET_STATE:
- state = siteCache.loadLocationSiteKeysCache(state)
- break
- case appConstants.APP_ON_CLEAR_BROWSING_DATA:
- {
- const defaults = state.get('clearBrowsingDataDefaults')
- const temp = state.get('tempClearBrowsingData', Immutable.Map())
- const clearData = defaults ? defaults.merge(temp) : temp
- if (clearData.get('browserHistory')) {
- state = state.set('sites', siteUtil.clearHistory(state.get('sites')))
- filtering.clearHistory()
- }
- break
- }
- case appConstants.APP_ADD_SITE:
- {
- const isSyncEnabled = syncEnabled()
- if (Immutable.List.isList(action.siteDetail)) {
- action.siteDetail.forEach((s) => {
- state = siteUtil.addSite(state, s, action.tag, action.skipSync)
- if (isSyncEnabled) {
- state = syncUtil.updateSiteCache(state, s)
- }
- })
- } else {
- let sites = state.get('sites')
- if (!action.siteDetail.get('folderId') && siteUtil.isFolder(action.siteDetail)) {
- action.siteDetail = action.siteDetail.set('folderId', siteUtil.getNextFolderId(sites))
- }
- state = siteUtil.addSite(state, action.siteDetail, action.tag, action.skipSync)
- if (isSyncEnabled) {
- state = syncUtil.updateSiteCache(state, action.siteDetail)
- }
- }
- break
- }
- case appConstants.APP_ADD_BOOKMARK:
- case appConstants.APP_EDIT_BOOKMARK:
- {
- const isSyncEnabled = syncEnabled()
- const sites = state.get('sites')
- const closestKey = action.closestKey
- let site = action.siteDetail
-
- if (site == null || action.tag == null) {
- break
- }
-
- if (!site.get('folderId') && action.tag === siteTags.BOOKMARK_FOLDER) {
- site = site.set('folderId', siteUtil.getNextFolderId(sites))
- }
-
- state = siteUtil.addSite(state, site, action.tag, action.editKey)
-
- if (closestKey != null) {
- const sourceKey = siteUtil.getSiteKey(site)
- state = siteUtil.moveSite(state, sourceKey, closestKey, false, false, true)
- }
-
- if (isSyncEnabled) {
- state = syncUtil.updateSiteCache(state, site)
- }
-
- state = updateActiveTabBookmarked(state)
- break
- }
- case appConstants.APP_REMOVE_SITE:
- const removeSiteSyncCallback = action.skipSync ? undefined : syncActions.removeSite
- state = siteUtil.removeSite(state, action.siteDetail, action.tag, true, removeSiteSyncCallback)
- if (syncEnabled()) {
- state = syncUtil.updateSiteCache(state, action.siteDetail)
- }
- state = updateActiveTabBookmarked(state)
- break
- case appConstants.APP_MOVE_SITE:
- state = siteUtil.moveSite(state,
- action.sourceKey, action.destinationKey, action.prepend,
- action.destinationIsParent, false)
- state = state.set('sites', state.get('sites').sort(siteUtil.siteSort))
- if (syncEnabled()) {
- const destinationDetail = state.getIn(['sites', action.destinationKey])
- state = syncUtil.updateSiteCache(state, destinationDetail)
- }
- break
- case appConstants.APP_APPLY_SITE_RECORDS:
- let nextFolderId = siteUtil.getNextFolderId(state.get('sites'))
- // Ensure that all folders are assigned folderIds
- action.records.forEach((record, i) => {
- if (record.action !== writeActions.DELETE &&
- record.bookmark && record.bookmark.isFolder &&
- record.bookmark.site &&
- typeof record.bookmark.site.folderId !== 'number') {
- record.bookmark.site.folderId = nextFolderId
- action.records.set(i, record)
- nextFolderId = nextFolderId + 1
- }
- })
- action.records.forEach((record) => {
- if (record.action === writeActions.DELETE) {
- state = siteUtil.removeSiteByObjectId(state, record.objectId, record.objectData)
- } else {
- const siteData = syncUtil.getSiteDataFromRecord(record, state, action.records)
- const tag = siteData.tag
- let siteDetail = siteData.siteDetail
- switch (record.action) {
- case writeActions.CREATE:
- state = siteUtil.addSite(state, siteDetail, tag, undefined, true)
- break
- case writeActions.UPDATE:
- state = siteUtil.addSite(state, siteDetail, tag, siteData.existingObjectData, true)
- break
- }
- state = syncUtil.updateSiteCache(state, siteDetail)
- }
- })
- break
- case appConstants.APP_TAB_UPDATED:
- if (immutableAction.getIn(['changeInfo', 'pinned']) != null) {
- const pinned = immutableAction.getIn(['changeInfo', 'pinned'])
- const tabId = immutableAction.getIn(['tabValue', 'tabId'])
- const tab = state.get('tabs').find((tab) => tab.get('tabId') === tabId)
- if (!tab) {
- console.warn('Trying to pin a tabId which does not exist:', tabId, 'tabs: ', state.get('tabs').toJS())
- break
- }
- const sites = state.get('sites')
- const siteDetail = siteUtil.getDetailFromTab(tab, siteTags.PINNED, sites)
- if (pinned) {
- state = siteUtil.addSite(state, siteDetail, siteTags.PINNED)
- } else {
- state = siteUtil.removeSite(state, siteDetail, siteTags.PINNED)
- }
- if (syncEnabled()) {
- state = syncUtil.updateSiteCache(state, siteDetail)
- }
- }
- state = updateTabBookmarked(state, action.tabValue)
- break
- case appConstants.APP_CREATE_TAB_REQUESTED: {
- const createProperties = immutableAction.get('createProperties')
- if (createProperties.get('pinned')) {
- state = siteUtil.addSite(state,
- siteUtil.getDetailFromCreateProperties(createProperties), siteTags.PINNED)
- }
- break
- }
- }
- return state
-}
-
-module.exports = sitesReducer
diff --git a/app/browser/reducers/urlBarSuggestionsReducer.js b/app/browser/reducers/urlBarSuggestionsReducer.js
index 8873091a9ad..b69c594a0ef 100644
--- a/app/browser/reducers/urlBarSuggestionsReducer.js
+++ b/app/browser/reducers/urlBarSuggestionsReducer.js
@@ -4,16 +4,18 @@
'use strict'
+const Immutable = require('immutable')
const appConstants = require('../../../js/constants/appConstants')
const {generateNewSuggestionsList, generateNewSearchXHRResults} = require('../../common/lib/suggestion')
const {init, add} = require('../../common/lib/siteSuggestions')
-const Immutable = require('immutable')
const {makeImmutable} = require('../../common/state/immutableUtil')
const tabState = require('../../common/state/tabState')
+const historyState = require('../../common/state/historyState')
+const bookmarksState = require('../../common/state/bookmarksState')
const urlBarSuggestionsReducer = (state, action) => {
switch (action.actionType) {
- case appConstants.APP_ADD_SITE:
+ case appConstants.APP_ADD_HISTORY_SITE:
case appConstants.APP_ADD_BOOKMARK:
case appConstants.APP_EDIT_BOOKMARK:
if (Immutable.List.isList(action.siteDetail)) {
@@ -25,7 +27,9 @@ const urlBarSuggestionsReducer = (state, action) => {
}
break
case appConstants.APP_SET_STATE:
- init(Object.values(action.appState.get('sites').toJS()))
+ const bookmarks = bookmarksState.getBookmarks(action.appState)
+ const history = historyState.getSites(action.appState)
+ init(Object.values(bookmarks.concat(history).toJS()))
break
case appConstants.APP_URL_BAR_TEXT_CHANGED:
generateNewSuggestionsList(state, action.windowId, action.tabId, action.input)
diff --git a/app/browser/tabs.js b/app/browser/tabs.js
index d2e87933b1e..4e03c422565 100644
--- a/app/browser/tabs.js
+++ b/app/browser/tabs.js
@@ -22,12 +22,15 @@ const messages = require('../../js/constants/messages')
const aboutHistoryState = require('../common/state/aboutHistoryState')
const appStore = require('../../js/stores/appStore')
const appConfig = require('../../js/constants/appConfig')
-const siteTags = require('../../js/constants/siteTags')
const {newTabMode} = require('../common/constants/settingsEnums')
const {cleanupWebContents, currentWebContents, getWebContents, updateWebContents} = require('./webContentsCache')
const {FilterOptions} = require('ad-block')
const {isResourceEnabled} = require('../filtering')
const autofill = require('../autofill')
+const bookmarksState = require('../common/state/bookmarksState')
+const bookmarkFoldersState = require('../common/state/bookmarkFoldersState')
+const historyState = require('../common/state/historyState')
+const bookmarkOrderCache = require('../common/cache/bookmarkOrderCache')
let currentPartitionNumber = 0
const incrementPartitionNumber = () => ++currentPartitionNumber
@@ -134,21 +137,12 @@ ipcMain.on(messages.ABOUT_COMPONENT_INITIALIZED, (e) => {
})
})
-const getBookmarksData = function (state) {
- let bookmarkSites = new Immutable.OrderedMap()
- let bookmarkFolderSites = new Immutable.OrderedMap()
- state.get('sites').forEach((site, siteKey) => {
- const tags = site.get('tags')
- if (tags.includes(siteTags.BOOKMARK)) {
- bookmarkSites = bookmarkSites.set(siteKey, site)
- }
- if (tags.includes(siteTags.BOOKMARK_FOLDER)) {
- bookmarkFolderSites = bookmarkFolderSites.set(siteKey, site)
- }
- })
- const bookmarks = bookmarkSites.toList().toJS()
- const bookmarkFolders = bookmarkFolderSites.toList().toJS()
- return {bookmarks, bookmarkFolders}
+const getBookmarksData = (state) => {
+ return {
+ bookmarks: bookmarksState.getBookmarks(state).toJS(),
+ bookmarkFolders: bookmarkFoldersState.getFolders(state).toJS(),
+ bookmarkOrder: bookmarkOrderCache.getOrderCache(state).toJS()
+ }
}
const updateAboutDetails = (tab, tabValue) => {
@@ -812,7 +806,7 @@ const api = {
getHistoryEntries: (state, action) => {
const tab = getWebContents(action.get('tabId'))
- const sites = state ? state.get('sites') : null
+ const sites = state ? historyState.getSites(state) : null
if (tab && !tab.isDestroyed()) {
let history = {
@@ -836,7 +830,7 @@ const api = {
// TODO: return brave lion (or better: get icon from extension if possible as data URI)
} else {
if (sites) {
- const site = sites.find(function (element) { return element.get('location') === url })
+ const site = sites.find((element) => element.get('location') === url)
if (site) {
entry.icon = site.get('favicon')
}
diff --git a/app/browser/windows.js b/app/browser/windows.js
index 028aee44eed..fec40cd6d14 100644
--- a/app/browser/windows.js
+++ b/app/browser/windows.js
@@ -9,14 +9,14 @@ const debounce = require('../../js/lib/debounce')
const {getSetting} = require('../../js/settings')
const locale = require('../locale')
const LocalShortcuts = require('../localShortcuts')
-const {getPinnedSiteProps} = require('../common/lib/windowsUtil')
const {makeImmutable} = require('../common/state/immutableUtil')
const {getPinnedTabsByWindowId} = require('../common/state/tabState')
const messages = require('../../js/constants/messages')
const settings = require('../../js/constants/settings')
-const siteTags = require('../../js/constants/siteTags')
const windowState = require('../common/state/windowState')
const Immutable = require('immutable')
+const pinnedSitesState = require('../common/state/pinnedSitesState')
+const pinnedSitesUtil = require('../common/lib/pinnedSitesUtil')
// TODO(bridiver) - set window uuid
let currentWindows = {}
@@ -69,8 +69,7 @@ const updatePinnedTabs = (win) => {
const appStore = require('../../js/stores/appStore')
const state = appStore.getState()
const windowId = win.id
- const pinnedSites = state.get('sites').toList().filter((site) =>
- site.get('tags').includes(siteTags.PINNED)).map(site => getPinnedSiteProps(site))
+ const pinnedSites = pinnedSitesState.getSites(state).map(site => pinnedSitesUtil.getPinnedSiteProps(site))
const pinnedTabs = getPinnedTabsByWindowId(state, windowId)
pinnedSites.filter((site) =>
diff --git a/app/common/cache/bookmarkOrderCache.js b/app/common/cache/bookmarkOrderCache.js
new file mode 100644
index 00000000000..3b47e30fa27
--- /dev/null
+++ b/app/common/cache/bookmarkOrderCache.js
@@ -0,0 +1,131 @@
+const Immutable = require('immutable')
+const siteTags = require('../../../js/constants/siteTags')
+const bookmarkFoldersUtil = require('../lib/bookmarkFoldersUtil')
+
+const setOrder = (cache, key, tag, destinationKey, append = true) => {
+ let newCache = Immutable.List()
+ let i = 0
+
+ for (let item of cache) {
+ if (item.get('key') === destinationKey) {
+ if (append) {
+ newCache = newCache.push(item.set('order', i))
+ i++
+ newCache = newCache.push(Immutable.fromJS({
+ key: key,
+ order: i,
+ type: tag
+ }))
+ } else {
+ newCache = newCache.push(Immutable.fromJS({
+ key: key,
+ order: i,
+ type: tag
+ }))
+ i++
+ newCache = newCache.push(item.set('order', i))
+ }
+ } else if (item.get('key') === key) {
+ continue
+ } else {
+ newCache = newCache.push(item.set('order', i))
+ }
+ i++
+ }
+
+ return newCache
+}
+
+const addCacheItem = (state, parentId = 0, key, destinationKey, tag, append) => {
+ parentId = parentId.toString()
+ key = key.toString()
+ // cache with this parentId doesn't exist yet
+ if (!state.hasIn(['bookmarkOrderCache', parentId])) {
+ return state.setIn(['bookmarkOrderCache', parentId], Immutable.fromJS([
+ {
+ key: key,
+ order: 0,
+ type: tag
+ }
+ ]))
+ }
+
+ const cache = state.getIn(['bookmarkOrderCache', parentId])
+ // destination key is not provided
+ if (destinationKey == null) {
+ return state.setIn(['bookmarkOrderCache', parentId], cache.push(Immutable.fromJS(
+ {
+ key: key,
+ order: cache.size,
+ type: tag
+ }
+ )))
+ }
+
+ // destination key is given
+ const newCache = setOrder(cache, key, tag, destinationKey, append)
+ return state.setIn(['bookmarkOrderCache', parentId], newCache)
+}
+
+const addBookmarkToCache = (state, parentId, key, destinationKey, append) => {
+ return addCacheItem(state, parentId, key, destinationKey, siteTags.BOOKMARK, append)
+}
+
+const addFolderToCache = (state, parentId, key, destinationKey, append) => {
+ return addCacheItem(state, parentId, key, destinationKey, siteTags.BOOKMARK_FOLDER, append)
+}
+
+const getFoldersByParentId = (state, parentId) => {
+ return state.getIn(['bookmarkOrderCache', parentId.toString()], Immutable.List())
+ .filter(item => bookmarkFoldersUtil.isFolder(item))
+}
+
+const getBookmarksByParentId = (state, parentId = 0) => {
+ return state.getIn(['bookmarkOrderCache', parentId.toString()], Immutable.List())
+ .filter(item => bookmarkFoldersUtil.isFolder(item))
+}
+
+const getBookmarksWithFolders = (state, parentId) => {
+ return state.getIn(['bookmarkOrderCache', parentId.toString()], Immutable.List())
+}
+
+const removeCacheKey = (state, parentId, key) => {
+ parentId = parentId.toString()
+ key = key.toString()
+ const cache = state.getIn(['bookmarkOrderCache', parentId])
+
+ if (cache == null) {
+ return state
+ }
+
+ let newCache = Immutable.List()
+ let i = 0
+
+ for (let item of cache) {
+ if (item.get('key') !== key) {
+ newCache = newCache.push(item.set('order', i))
+ i++
+ }
+ }
+
+ return state.setIn(['bookmarkOrderCache', parentId], newCache)
+}
+
+const removeCacheParent = (state, parentId) => {
+ return state.deleteIn(['bookmarkOrderCache', parentId.toString()])
+}
+
+const getOrderCache = (state) => {
+ return state.get('bookmarkOrderCache', Immutable.Map())
+}
+
+module.exports = {
+ addBookmarkToCache,
+ addFolderToCache,
+ removeCacheKey,
+ getFoldersByParentId,
+ getBookmarksByParentId,
+ getBookmarksWithFolders,
+ removeCacheParent,
+ getOrderCache
+}
diff --git a/app/common/lib/bookmarkFoldersUtil.js b/app/common/lib/bookmarkFoldersUtil.js
new file mode 100644
index 00000000000..9afde39b0cb
--- /dev/null
+++ b/app/common/lib/bookmarkFoldersUtil.js
@@ -0,0 +1,62 @@
+/* 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/. */
+
+const siteTags = require('../../../js/constants/siteTags')
+
+const isFolderNameValid = (title) => {
+ return title != null && title.trim().length > 0
+}
+
+const getNextFolderIdItem = (folders) =>
+ folders.max((folderA, folderB) => {
+ const folderIdA = folderA.get('folderId')
+ const folderIdB = folderB.get('folderId')
+ if (folderIdA === folderIdB) {
+ return 0
+ }
+ if (folderIdA === undefined) {
+ return false
+ }
+ if (folderIdB === undefined) {
+ return true
+ }
+ return folderIdA > folderIdB
+ })
+
+const getNextFolderId = (folders) => {
+ const defaultFolderId = 0
+ if (!folders) {
+ return defaultFolderId
+ }
+ const maxIdItem = getNextFolderIdItem(folders)
+ return (maxIdItem ? (maxIdItem.get('folderId') || 0) : 0) + 1
+}
+
+const getNextFolderName = (folders, name) => {
+ if (!folders) {
+ return name
+ }
+ const site = folders.find((site) => site.get('title') === name)
+ if (!site) {
+ return name
+ }
+ const filenameFormat = /(.*) \((\d+)\)/
+ let result = filenameFormat.exec(name)
+ if (!result) {
+ return getNextFolderName(folders, name + ' (1)')
+ }
+
+ const nextNum = parseInt(result[2]) + 1
+ return getNextFolderName(folders, result[1] + ' (' + nextNum + ')')
+}
+
+const isFolder = (folder) => {
+ return folder.get('type') === siteTags.BOOKMARK_FOLDER
+}
+
+module.exports = {
+ isFolderNameValid,
+ getNextFolderId,
+ getNextFolderName,
+ isFolder
+}
diff --git a/app/common/lib/bookmarkUtil.js b/app/common/lib/bookmarkUtil.js
index a8c399db21f..ef68614c403 100644
--- a/app/common/lib/bookmarkUtil.js
+++ b/app/common/lib/bookmarkUtil.js
@@ -4,25 +4,24 @@
const Immutable = require('immutable')
+// State
+const bookmarksState = require('../state/bookmarksState')
+const tabState = require('../state/tabState')
+
// Constants
const dragTypes = require('../../../js/constants/dragTypes')
const {bookmarksToolbarMode} = require('../constants/settingsEnums')
const settings = require('../../../js/constants/settings')
+const siteTags = require('../../../js/constants/siteTags')
// Utils
const domUtil = require('../../renderer/lib/domUtil')
-const siteUtil = require('../../../js/state/siteUtil')
+const siteCache = require('../state/siteCache')
const {calculateTextWidth} = require('../../../js/lib/textCalculator')
const {iconSize} = require('../../../js/constants/config')
const {getSetting} = require('../../../js/settings')
-function bookmarkHangerHeading (editMode, isFolder, isAdded) {
- if (isFolder) {
- return editMode
- ? 'bookmarkFolderEditing'
- : 'bookmarkFolderAdding'
- }
-
+const bookmarkHangerHeading = (editMode, isAdded) => {
if (isAdded) {
return 'bookmarkAdded'
}
@@ -32,19 +31,8 @@ function bookmarkHangerHeading (editMode, isFolder, isAdded) {
: 'bookmarkCreateNew'
}
-const displayBookmarkName = (detail) => {
- const customTitle = detail.get('customTitle')
- if (customTitle !== undefined && customTitle !== '') {
- return customTitle || ''
- }
- return detail.get('title') || ''
-}
-
-const isBookmarkNameValid = (title, location, isFolder, customTitle) => {
- const newTitle = title || customTitle
- return isFolder
- ? (newTitle != null && newTitle !== 0) && newTitle.trim().length > 0
- : location != null && location.trim().length > 0
+const isBookmarkNameValid = (location) => {
+ return location != null && location.trim().length > 0
}
const showOnlyFavicon = () => {
@@ -65,23 +53,21 @@ const getDNDBookmarkData = (state, bookmarkKey) => {
return data.get('draggingOverKey') === bookmarkKey ? data : Immutable.Map()
}
-let oldSites
+let oldBookmarks
let lastValue
let lastWidth
const getToolbarBookmarks = (state) => {
- const sites = state.get('sites', Immutable.List())
+ const bookmarks = bookmarksState.getBookmarksWithFolders(state)
const windowWidth = window.innerWidth
- if (sites === oldSites &&
+ if (bookmarks === oldBookmarks &&
lastWidth === windowWidth &&
- lastValue) {
+ lastValue
+ ) {
return lastValue
}
- oldSites = sites
+ oldBookmarks = bookmarks
lastWidth = windowWidth
- const noParentItems = siteUtil.getBookmarks(sites)
- .filter((bookmark) => !bookmark.get('parentFolderId'))
- .sort(siteUtil.siteSort)
let widthAccountedFor = 0
const overflowButtonWidth = 25
const onlyFavicon = showOnlyFavicon()
@@ -104,7 +90,7 @@ const getToolbarBookmarks = (state) => {
// Loop through until we fill up the entire bookmark toolbar width
let i = 0
- for (let bookmark of noParentItems) {
+ for (let bookmark of bookmarks) {
const current = bookmark[1]
let iconWidth = favicon ? iconSize : 0
// font-awesome file icons are 3px smaller
@@ -115,7 +101,7 @@ const getToolbarBookmarks = (state) => {
if (favicon && onlyFavicon) {
widthAccountedFor += padding + iconWidth + currentChevronWidth
} else {
- const text = current.get('customTitle') || current.get('title') || current.get('location')
+ const text = current.get('title') || current.get('location')
widthAccountedFor += Math.min(calculateTextWidth(text, `${fontSize} ${fontFamily}`) + padding + iconWidth + currentChevronWidth, maxWidth)
}
widthAccountedFor += margin
@@ -125,20 +111,99 @@ const getToolbarBookmarks = (state) => {
i++
}
- lastValue = {
- visibleBookmarks: noParentItems.take(i).map((item, index) => index).toList(),
+ return {
+ visibleBookmarks: bookmarks.take(i).map((item, index) => index).toList(),
// Show at most 100 items in the overflow menu
- hiddenBookmarks: noParentItems.skip(i).take(100).map((item, index) => index).toList()
+ hiddenBookmarks: bookmarks.skip(i).take(100).map((item, index) => index).toList()
+ }
+}
+
+const getDetailFromFrame = (frame) => {
+ return Immutable.fromJS({
+ location: frame.get('location'),
+ title: frame.get('title'),
+ partitionNumber: frame.get('partitionNumber'),
+ favicon: frame.get('icon'),
+ themeColor: frame.get('themeColor') || frame.get('computedThemeColor')
+ })
+}
+
+/**
+ * Checks if a location is bookmarked.
+ *
+ * @param state The application state Immutable map
+ * @param {string} location
+ * @return {boolean}
+ */
+const isLocationBookmarked = (state, location) => {
+ const bookmarks = bookmarksState.getBookmarks(state)
+ const siteKeys = siteCache.getLocationSiteKeys(state, location)
+
+ if (!siteKeys || siteKeys.length === 0) {
+ return false
+ }
+
+ return siteKeys.some(key => bookmarks.has(key))
+}
+
+/**
+ * Converts a siteDetail to createProperties format
+ * @param {Object} bookmark - A bookmark detail as per app state
+ * @return {Object} A createProperties plain JS object, not ImmutableJS
+ */
+const toCreateProperties = (bookmark) => {
+ return {
+ url: bookmark.get('location'),
+ partitionNumber: bookmark.get('partitionNumber')
+ }
+}
+
+/**
+ * Filters bookmarks relative to a parent folder
+ * @param state - The application state
+ * @param folderKey The folder key to filter to
+ */
+const getBookmarksByParentId = (state, folderKey) => {
+ const bookmarks = bookmarksState.getBookmarks(state)
+ if (!folderKey) {
+ return bookmarks
+ }
+
+ return bookmarks.filter((bookmark) => bookmark.get('parentFolderId') === folderKey)
+}
+
+const isBookmark = (bookmark) => {
+ return bookmark.get('type') === siteTags.BOOKMARK
+}
+
+const updateTabBookmarked = (state, tabValue) => {
+ if (!tabValue || !tabValue.get('tabId')) {
+ return state
+ }
+ const bookmarked = isLocationBookmarked(state, tabValue.get('url'))
+ return tabState.updateTabValue(state, tabValue.set('bookmarked', bookmarked))
+}
+
+const updateActiveTabBookmarked = (state) => {
+ const tab = tabState.getActiveTab(state)
+ if (!tab) {
+ return state
}
- return lastValue
+ return updateTabBookmarked(state, tab)
}
module.exports = {
bookmarkHangerHeading,
- displayBookmarkName,
isBookmarkNameValid,
showOnlyFavicon,
showFavicon,
getDNDBookmarkData,
- getToolbarBookmarks
+ getToolbarBookmarks,
+ getDetailFromFrame,
+ isLocationBookmarked,
+ toCreateProperties,
+ getBookmarksByParentId,
+ isBookmark,
+ updateTabBookmarked,
+ updateActiveTabBookmarked
}
diff --git a/app/common/lib/historyUtil.js b/app/common/lib/historyUtil.js
index c3cade0a637..e769b492e04 100644
--- a/app/common/lib/historyUtil.js
+++ b/app/common/lib/historyUtil.js
@@ -8,15 +8,13 @@ const {makeImmutable} = require('../state/immutableUtil')
const siteUtil = require('../../../js/state/siteUtil')
const aboutHistoryMaxEntries = 500
-module.exports.maxEntries = aboutHistoryMaxEntries
-
const sortTimeDescending = (left, right) => {
if (left.get('lastAccessedTime') < right.get('lastAccessedTime')) return 1
if (left.get('lastAccessedTime') > right.get('lastAccessedTime')) return -1
return 0
}
-module.exports.getHistory = (sites) => {
+const getHistory = (sites) => {
sites = makeImmutable(sites) ? makeImmutable(sites).toList() : new Immutable.List()
return sites.filter((site) => siteUtil.isHistoryEntry(site))
.sort(sortTimeDescending)
@@ -30,7 +28,7 @@ const getDayString = (entry, locale) => {
: ''
}
-module.exports.groupEntriesByDay = (history, locale) => {
+const groupEntriesByDay = (history, locale) => {
const reduced = history.reduce((previousValue, currentValue, currentIndex, array) => {
const result = currentIndex === 1 ? [] : previousValue
if (currentIndex === 1) {
@@ -60,7 +58,7 @@ module.exports.groupEntriesByDay = (history, locale) => {
* Return an array with ALL entries.
* Format is expected to be array containing one array per day.
*/
-module.exports.totalEntries = (entriesByDay) => {
+const totalEntries = (entriesByDay) => {
entriesByDay = makeImmutable(entriesByDay) || new Immutable.List()
let result = new Immutable.List()
@@ -69,3 +67,61 @@ module.exports.totalEntries = (entriesByDay) => {
})
return result
}
+
+const prepareHistoryEntry = (siteDetail) => {
+ return makeImmutable({
+ lastAccessedTime: new Date().getTime(),
+ objectId: undefined,
+ title: siteDetail.get('title'),
+ location: siteDetail.get('location'),
+ themeColor: siteDetail.get('themeColor'),
+ favicon: siteDetail.get('favicon', siteDetail.get('icon')),
+ count: 1
+ })
+}
+
+const mergeSiteDetails = (oldDetail, newDetail) => {
+ const objectId = newDetail.has('objectId') ? newDetail.get('objectId') : oldDetail.get('objectId', undefined)
+
+ let site = makeImmutable({
+ title: newDetail.get('title'),
+ location: newDetail.get('location'),
+ count: ~~oldDetail.get('count', 0) + 1,
+ lastAccessedTime: new Date().getTime(),
+ objectId
+ })
+
+ const themeColor = newDetail.has('themeColor') ? newDetail.get('themeColor') : oldDetail.get('themeColor')
+ if (themeColor) {
+ site = site.set('themeColor', themeColor)
+ }
+
+ // we need to have a fallback to icon, because frame has icon for it
+ const favicon = (newDetail.has('favicon') || newDetail.has('icon'))
+ ? newDetail.get('favicon', newDetail.get('icon'))
+ : oldDetail.get('favicon')
+ if (favicon) {
+ site = site.set('favicon', favicon)
+ }
+
+ return site
+}
+
+const getDetailFromFrame = (frame) => {
+ return makeImmutable({
+ location: frame.get('location'),
+ title: frame.get('title'),
+ partitionNumber: frame.get('partitionNumber'),
+ favicon: frame.get('icon'),
+ themeColor: frame.get('themeColor') || frame.get('computedThemeColor')
+ })
+}
+
+module.exports = {
+ getHistory,
+ groupEntriesByDay,
+ totalEntries,
+ prepareHistoryEntry,
+ mergeSiteDetails,
+ getDetailFromFrame
+}
diff --git a/app/common/lib/menuUtil.js b/app/common/lib/menuUtil.js
index 65f24d89987..b68bb4e53ea 100644
--- a/app/common/lib/menuUtil.js
+++ b/app/common/lib/menuUtil.js
@@ -4,16 +4,25 @@
'use strict'
const MenuItem = require('electron').MenuItem
+
+// Constants
+const config = require('../../../js/constants/config')
+
+// State
+const bookmarksState = require('../state/bookmarksState')
+
+// Actions
+const appActions = require('../../../js/actions/appActions')
+const windowActions = require('../../../js/actions/windowActions')
+
+// Utils
const {makeImmutable} = require('../../common/state/immutableUtil')
const CommonMenu = require('../../common/commonMenu')
-const siteTags = require('../../../js/constants/siteTags')
const eventUtil = require('../../../js/lib/eventUtil')
-const siteUtil = require('../../../js/state/siteUtil')
const locale = require('../../locale')
-const appActions = require('../../../js/actions/appActions')
-const config = require('../../../js/constants/config')
const {separatorMenuItem} = require('../../common/commonMenu')
-const windowActions = require('../../../js/actions/windowActions')
+const bookmarkUtil = require('./bookmarkUtil')
+const bookmarkFoldersUtil = require('./bookmarkFoldersUtil')
/**
* Get the an electron MenuItem object from a Menu based on its label
@@ -73,14 +82,12 @@ module.exports.setTemplateItemChecked = (template, label, checked) => {
return null
}
-const createBookmarkTemplateItems = (bookmarks, parentFolderId) => {
- const filteredBookmarks = parentFolderId
- ? bookmarks.filter((bookmark) => bookmark.get('parentFolderId') === parentFolderId)
- : bookmarks.filter((bookmark) => !bookmark.get('parentFolderId'))
+const createBookmarkTemplateItems = (state, parentFolderId) => {
+ const bookmarks = bookmarksState.getBookmarksWithFolders(state, parentFolderId)
const payload = []
- filteredBookmarks.forEach((site) => {
- if (site.get('tags').includes(siteTags.BOOKMARK) && site.get('location')) {
+ bookmarks.forEach((site) => {
+ if (bookmarkUtil.isBookmark(site)) {
payload.push({
// TODO include label made from favicon. It needs to be of type NativeImage
// which can be made using a Buffer / DataURL / local image
@@ -89,7 +96,7 @@ const createBookmarkTemplateItems = (bookmarks, parentFolderId) => {
// and as such there may need to be another mechanism or cache
//
// see: https://github.com/brave/browser-laptop/issues/3050
- label: site.get('customTitle') || site.get('title') || site.get('location'),
+ label: site.get('title', site.get('location')),
click: (item, focusedWindow, e) => {
if (eventUtil.isForSecondaryAction(e)) {
appActions.createTabRequested({
@@ -102,12 +109,10 @@ const createBookmarkTemplateItems = (bookmarks, parentFolderId) => {
}
}
})
- } else if (siteUtil.isFolder(site)) {
- const folderId = site.get('folderId')
- const submenuItems = bookmarks.filter((bookmark) => bookmark.get('parentFolderId') === folderId)
+ } else if (bookmarkFoldersUtil.isFolder(site)) {
payload.push({
- label: site.get('customTitle') || site.get('title'),
- submenu: submenuItems.count() > 0 ? createBookmarkTemplateItems(bookmarks, folderId) : null
+ label: site.get('title'),
+ submenu: createBookmarkTemplateItems(state, site.get('folderId'))
})
}
})
@@ -117,10 +122,10 @@ const createBookmarkTemplateItems = (bookmarks, parentFolderId) => {
/**
* Used to create bookmarks and bookmark folder entries for the "Bookmarks" menu
*
- * @param sites The application state's Immutable sites list
+ * @param state The application state
*/
-module.exports.createBookmarkTemplateItems = (sites) => {
- return createBookmarkTemplateItems(siteUtil.getBookmarks(sites))
+module.exports.createBookmarkTemplateItems = (state) => {
+ return createBookmarkTemplateItems(state)
}
/**
diff --git a/app/common/lib/pinnedSitesUtil.js b/app/common/lib/pinnedSitesUtil.js
new file mode 100644
index 00000000000..d9662763128
--- /dev/null
+++ b/app/common/lib/pinnedSitesUtil.js
@@ -0,0 +1,115 @@
+/* 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/. */
+
+const Immutable = require('immutable')
+const siteUtil = require('../../../js/state/siteUtil')
+const {makeImmutable} = require('../state/immutableUtil')
+
+const getSitesBySubkey = (sites, siteKey) => {
+ if (!sites || !siteKey) {
+ return makeImmutable([])
+ }
+ const splitKey = siteKey.split('|', 2)
+ const partialKey = splitKey.join('|')
+ const matches = sites.filter((site, key) => {
+ return key.indexOf(partialKey) > -1
+ })
+ return matches.toList()
+}
+
+const getDetailsFromTab = (sites, tab) => {
+ let location = tab.get('url')
+ const partitionNumber = tab.get('partitionNumber')
+ let parentFolderId
+
+ // TODO check if needed https://github.com/brave/browser-laptop/pull/8588
+ // we need to find which sites should be send in, I am guessing bookmarks
+
+ // if site map is available, look up extra information:
+ // - original url (if redirected)
+ // - parent folder id
+ if (sites) {
+ // get all sites matching URL and partition (disregarding parentFolderId)
+ let siteKey = siteUtil.getSiteKey(makeImmutable({location, partitionNumber}))
+ let results = getSitesBySubkey(sites, siteKey)
+
+ // only check for provisional location if entry is not found
+ if (results.size === 0) {
+ // if provisional location is different, grab any results which have that URL
+ // this may be different if the site was redirected
+ const provisionalLocation = tab.getIn(['frame', 'provisionalLocation'])
+ if (provisionalLocation && provisionalLocation !== location) {
+ siteKey = siteUtil.getSiteKey(makeImmutable({
+ location: provisionalLocation,
+ partitionNumber
+ }))
+ results = results.merge(getSitesBySubkey(sites, siteKey))
+ }
+ }
+
+ // update details which get returned below
+ if (results.size > 0) {
+ location = results.getIn([0, 'location'])
+ parentFolderId = results.getIn([0, 'parentFolderId'])
+ }
+ }
+
+ const siteDetail = {
+ location: location,
+ title: tab.get('title')
+ }
+
+ // TODO I think that we don't need this one
+ if (partitionNumber) {
+ siteDetail.partitionNumber = partitionNumber
+ }
+
+ if (parentFolderId) {
+ siteDetail.parentFolderId = parentFolderId
+ }
+
+ return makeImmutable(siteDetail)
+}
+
+const getDetailFromProperties = (createProperties) => {
+ const siteDetail = {
+ location: createProperties.get('url')
+ }
+
+ if (createProperties.get('partitionNumber') !== undefined) {
+ siteDetail.partitionNumber = createProperties.get('partitionNumber')
+ }
+ return makeImmutable(siteDetail)
+}
+
+const getDetailFromFrame = (frame) => {
+ const pinnedLocation = frame.get('pinnedLocation')
+ let location = frame.get('location')
+ if (pinnedLocation !== 'about:blank') {
+ location = pinnedLocation
+ }
+
+ return makeImmutable({
+ location,
+ title: frame.get('title'),
+ partitionNumber: frame.get('partitionNumber'),
+ favicon: frame.get('icon'),
+ themeColor: frame.get('themeColor') || frame.get('computedThemeColor')
+ })
+}
+
+const getPinnedSiteProps = site => {
+ return Immutable.fromJS({
+ location: site.get('location'),
+ order: site.get('order'),
+ partitionNumber: site.get('partitionNumber', 0)
+ })
+}
+
+module.exports = {
+ getDetailsFromTab,
+ getDetailFromProperties,
+ getDetailFromFrame,
+ getPinnedSiteProps
+}
diff --git a/app/common/lib/siteSuggestions.js b/app/common/lib/siteSuggestions.js
index 229d1bb4841..e2c40e21255 100644
--- a/app/common/lib/siteSuggestions.js
+++ b/app/common/lib/siteSuggestions.js
@@ -61,11 +61,8 @@ const tokenizeInput = (data) => {
return []
}
url = data.location
- if (data.customTitle) {
- parts = getPartsFromNonUrlInput(data.customTitle)
- }
if (data.title) {
- parts = parts.concat(getPartsFromNonUrlInput(data.title))
+ parts = getPartsFromNonUrlInput(data.title)
}
if (data.tags) {
parts = parts.concat(data.tags.map(getTagToken))
diff --git a/app/common/lib/windowsUtil.js b/app/common/lib/windowsUtil.js
deleted file mode 100644
index 4141a5a060d..00000000000
--- a/app/common/lib/windowsUtil.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const Immutable = require('immutable')
-
-const getPinnedSiteProps = site => {
- return Immutable.fromJS({
- location: site.get('location'),
- order: site.get('order'),
- partitionNumber: site.get('partitionNumber') || 0
- })
-}
-
-module.exports = {
- getPinnedSiteProps
-}
diff --git a/app/common/state/aboutHistoryState.js b/app/common/state/aboutHistoryState.js
index 6f9048993e6..f52a4fede69 100644
--- a/app/common/state/aboutHistoryState.js
+++ b/app/common/state/aboutHistoryState.js
@@ -2,7 +2,9 @@
* 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/. */
+const Immutable = require('immutable')
const {makeImmutable} = require('./immutableUtil')
+const historyState = require('./historyState')
const historyUtil = require('../lib/historyUtil')
const aboutHistoryState = {
@@ -10,10 +12,17 @@ const aboutHistoryState = {
state = makeImmutable(state)
return state.getIn(['about', 'history'])
},
+
setHistory: (state) => {
state = makeImmutable(state)
- state = state.setIn(['about', 'history', 'entries'],
- historyUtil.getHistory(state.get('sites')))
+ const sites = historyState.getSites(state)
+ state = state.setIn(['about', 'history', 'entries'], historyUtil.getHistory(sites))
+ return state.setIn(['about', 'history', 'updatedStamp'], new Date().getTime())
+ },
+
+ clearHistory: (state) => {
+ state = makeImmutable(state)
+ state = state.setIn(['about', 'history', 'entries'], Immutable.Map())
return state.setIn(['about', 'history', 'updatedStamp'], new Date().getTime())
}
}
diff --git a/app/common/state/aboutNewTabState.js b/app/common/state/aboutNewTabState.js
index ea855edaf04..ac9a551bdd2 100644
--- a/app/common/state/aboutNewTabState.js
+++ b/app/common/state/aboutNewTabState.js
@@ -31,6 +31,13 @@ const aboutNewTabState = {
topSites = makeImmutable(topSites)
state = state.setIn(['about', 'newtab', 'sites'], topSites)
return state.setIn(['about', 'newtab', 'updatedStamp'], new Date().getTime())
+ },
+
+ clearTopSites: (state) => {
+ state = makeImmutable(state)
+
+ state = state.setIn(['about', 'newtab', 'sites'], makeImmutable([]))
+ return state.setIn(['about', 'newtab', 'updatedStamp'], new Date().getTime())
}
}
diff --git a/app/common/state/bookmarkFoldersState.js b/app/common/state/bookmarkFoldersState.js
new file mode 100644
index 00000000000..2a551fb90ee
--- /dev/null
+++ b/app/common/state/bookmarkFoldersState.js
@@ -0,0 +1,176 @@
+/* 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/. */
+
+const assert = require('assert')
+const Immutable = require('immutable')
+
+// Actions
+const syncActions = require('../../../js/actions/syncActions')
+
+// Constants
+const settings = require('../../../js/constants/settings')
+const siteTags = require('../../../js/constants/siteTags')
+
+// State
+const bookmarkOrderCache = require('../cache/bookmarkOrderCache')
+
+// Utils
+const bookmarkFoldersUtil = require('../lib/bookmarkFoldersUtil')
+const siteUtil = require('../../../js/state/siteUtil')
+const {makeImmutable, isMap} = require('./immutableUtil')
+const {getSetting} = require('../../../js/settings')
+
+const validateState = function (state) {
+ state = makeImmutable(state)
+ assert.ok(isMap(state), 'state must be an Immutable.Map')
+ assert.ok(isMap(state.get('bookmarkFolders')), 'state must contain an Immutable.Map of bookmarkFolders')
+ return state
+}
+
+const bookmarkFoldersState = {
+ getFolders: (state) => {
+ state = validateState(state)
+ return state.get('bookmarkFolders', Immutable.Map())
+ },
+
+ getFolder: (state, folderKey) => {
+ state = validateState(state)
+ folderKey = folderKey.toString()
+ return state.getIn(['bookmarkFolders', folderKey], Immutable.Map())
+ },
+
+ getFoldersByParentId: (state, parentFolderId) => {
+ state = validateState(state)
+
+ const folders = bookmarkOrderCache.getFoldersByParentId(state, parentFolderId)
+ return folders.map(folder => bookmarkFoldersState.getFolder(state, folder.get('key')))
+ },
+
+ addFolder: (state, folderDetails, destinationKey) => {
+ state = validateState(state)
+ folderDetails = makeImmutable(folderDetails)
+ let folders = bookmarkFoldersState.getFolders(state)
+ let key = folderDetails.get('folderId')
+
+ if (!folderDetails.has('folderId')) {
+ key = bookmarkFoldersUtil.getNextFolderId(folders)
+ }
+
+ const newFolder = makeImmutable({
+ title: folderDetails.get('title'),
+ folderId: ~~key,
+ parentFolderId: ~~folderDetails.get('parentFolderId', 0),
+ partitionNumber: ~~folderDetails.get('partitionNumber', 0),
+ objectId: null,
+ type: siteTags.BOOKMARK_FOLDER
+ })
+
+ state = state.setIn(['bookmarkFolders', key.toString()], newFolder)
+ state = bookmarkOrderCache.addFolderToCache(state, newFolder.get('parentFolderId'), key, destinationKey)
+ return state
+ },
+
+ editFolder: (state, folderDetails, editKey) => {
+ state = validateState(state)
+ const oldFolder = bookmarkFoldersState.getFolder(state, editKey)
+
+ const newFolder = oldFolder.merge(makeImmutable({
+ title: folderDetails.get('title'),
+ parentFolderId: ~~folderDetails.get('parentFolderId', 0)
+ }))
+
+ if (oldFolder.get('parentFolderId') !== newFolder.get('parentFolderId')) {
+ state = bookmarkOrderCache.removeCacheKey(state, oldFolder.get('parentFolderId'), editKey)
+ state = bookmarkOrderCache.addFolderToCache(state, newFolder.get('parentFolderId'), editKey)
+ }
+
+ state = state.setIn(['bookmarkFolders', editKey.toString()], newFolder)
+ return state
+ },
+
+ removeFolder: (state, folderKey) => {
+ const bookmarksState = require('./bookmarksState')
+ const folders = bookmarkFoldersState.getFolders(state)
+ const folder = bookmarkFoldersState.getFolder(state, folderKey)
+
+ if (folder.isEmpty()) {
+ return state
+ }
+
+ if (getSetting(settings.SYNC_ENABLED) === true) {
+ syncActions.removeSite(folder)
+ }
+
+ folders.filter(folder => folder.get('parentFolderId') === ~~folderKey)
+ .map(folder => {
+ state = bookmarksState.removeBookmarksByParentId(state, folder.get('folderId'))
+ state = bookmarkFoldersState.removeFolder(state, folder.get('folderId'))
+ state = bookmarkOrderCache.removeCacheParent(state, folder.get('folderId'))
+ state = bookmarkOrderCache.removeCacheKey(state, folder.get('parentFolderId'), folderKey)
+ })
+
+ state = bookmarksState.removeBookmarksByParentId(state, folderKey)
+ state = bookmarkOrderCache.removeCacheParent(state, folderKey)
+ state = bookmarkOrderCache.removeCacheKey(state, folder.get('parentFolderId'), folderKey)
+ return state.deleteIn(['bookmarkFolders', folderKey.toString()])
+ },
+
+ getFoldersWithoutKey: (state, folderKey, parentFolderId = 0, labelPrefix = '') => {
+ let folders = []
+ const results = bookmarkFoldersState.getFoldersByParentId(state, parentFolderId)
+
+ const resultSize = results.size
+ for (let i = 0; i < resultSize; i++) {
+ const folder = results.get(i)
+ if (folder.get('folderId') === folderKey) {
+ continue
+ }
+
+ const label = labelPrefix + folder.get('title')
+ folders.push({
+ folderId: folder.get('folderId'),
+ label
+ })
+ const subSites = bookmarkFoldersState.getFoldersWithoutKey(state, folderKey, folder.get('folderId'), (label || '') + ' / ')
+ folders = folders.concat(subSites)
+ }
+
+ return folders
+ },
+
+ moveFolder: (state, folderKey, destinationKey, append, moveIntoParent) => {
+ const bookmarksState = require('./bookmarksState')
+ let folder = bookmarkFoldersState.getFolder(state, folderKey)
+ let destinationItem = bookmarksState.findBookmark(state, destinationKey)
+
+ if (folder.isEmpty()) {
+ return state
+ }
+
+ if (moveIntoParent || destinationItem.get('parentFolderId') !== folder.get('parentFolderId')) {
+ const parentFolderId = destinationItem.get('type') === siteTags.BOOKMARK
+ ? destinationItem.get('parentFolderId')
+ : destinationItem.get('folderId')
+
+ state = bookmarkOrderCache.removeCacheKey(state, folder.get('parentFolderId'), folderKey)
+ folder = folder.set('parentFolderId', ~~parentFolderId)
+ const newKey = siteUtil.getSiteKey(folder)
+ state = state.deleteIn(['bookmarkFolders', folderKey])
+ state = bookmarkOrderCache.addFolderToCache(state, folder.get('parentFolderId'), newKey)
+ return state.setIn(['bookmarkFolders', newKey.toString()], folder)
+ }
+
+ state = bookmarkOrderCache.removeCacheKey(state, folder.get('parentFolderId'), folderKey)
+ state = bookmarkOrderCache.addFolderToCache(
+ state,
+ folder.get('parentFolderId'),
+ folderKey,
+ destinationKey,
+ append
+ )
+ return state
+ }
+}
+
+module.exports = bookmarkFoldersState
diff --git a/app/common/state/bookmarksState.js b/app/common/state/bookmarksState.js
new file mode 100644
index 00000000000..0ef921d1a3c
--- /dev/null
+++ b/app/common/state/bookmarksState.js
@@ -0,0 +1,237 @@
+/* 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/. */
+
+const assert = require('assert')
+const Immutable = require('immutable')
+
+// Constants
+const settings = require('../../../js/constants/settings')
+const siteTags = require('../../../js/constants/siteTags')
+
+// State
+const historyState = require('./historyState')
+const bookmarkOrderCache = require('../cache/bookmarkOrderCache')
+const bookmarkFoldersState = require('./bookmarkFoldersState')
+
+// Actions
+const syncActions = require('../../../js/actions/syncActions')
+
+// Utils
+const siteUtil = require('../../../js/state/siteUtil')
+const UrlUtil = require('../../../js/lib/urlutil')
+const siteCache = require('./siteCache')
+const {getSetting} = require('../../../js/settings')
+const {makeImmutable, isMap} = require('./immutableUtil')
+
+const validateState = function (state) {
+ state = makeImmutable(state)
+ assert.ok(isMap(state), 'state must be an Immutable.Map')
+ assert.ok(isMap(state.get('bookmarks')), 'state must contain an Immutable.Map of bookmarks')
+ return state
+}
+
+const bookmarksState = {
+ getBookmarks: (state) => {
+ state = validateState(state)
+ return state.get('bookmarks')
+ },
+
+ getBookmark: (state, key) => {
+ state = validateState(state)
+ return state.getIn(['bookmarks', key], Immutable.Map())
+ },
+
+ /**
+ * Use this function if you only have a key and don't know if key is for folder or regular bookmark
+ * @param state
+ * @param key
+ */
+ findBookmark: (state, key) => {
+ state = validateState(state)
+ let bookmark = bookmarksState.getBookmark(state, key)
+ if (bookmark.isEmpty()) {
+ bookmark = bookmarkFoldersState.getFolder(state, key)
+ }
+
+ return bookmark
+ },
+
+ getBookmarksWithFolders: (state, parentFolderId = 0) => {
+ state = validateState(state)
+
+ const cache = bookmarkOrderCache.getBookmarksWithFolders(state, parentFolderId)
+ let bookmarks = Immutable.OrderedMap()
+
+ for (let item of cache) {
+ if (item.get('type') === siteTags.BOOKMARK) {
+ bookmarks = bookmarks.set(item.get('key'), bookmarksState.getBookmark(state, item.get('key')))
+ } else {
+ bookmarks = bookmarks.set(item.get('key'), bookmarkFoldersState.getFolder(state, item.get('key')))
+ }
+ }
+
+ return bookmarks
+ },
+
+ addBookmark: (state, bookmarkDetail, destinationKey) => {
+ state = validateState(state)
+
+ bookmarkDetail = makeImmutable(bookmarkDetail)
+ let location
+ if (bookmarkDetail.has('location')) {
+ location = UrlUtil.getLocationIfPDF(bookmarkDetail.get('location'))
+ bookmarkDetail = bookmarkDetail.set('location', location)
+ }
+
+ const key = siteUtil.getSiteKey(bookmarkDetail)
+ const historyItem = historyState.getSite(state, key)
+
+ let bookmark = makeImmutable({
+ title: bookmarkDetail.get('title', ' '),
+ location: bookmarkDetail.get('location'),
+ parentFolderId: ~~bookmarkDetail.get('parentFolderId', 0),
+ partitionNumber: ~~historyItem.get('partitionNumber', 0),
+ objectId: null,
+ favicon: historyItem.get('favicon'),
+ themeColor: historyItem.get('themeColor'),
+ type: siteTags.BOOKMARK
+ })
+
+ if (key === null) {
+ return state
+ }
+
+ state = state.setIn(['bookmarks', key], bookmark)
+ state = siteCache.addLocationSiteKey(state, location, key)
+ state = bookmarkOrderCache.addBookmarkToCache(state, bookmark.get('parentFolderId'), key, destinationKey)
+ return state
+ },
+
+ editBookmark: (state, bookmarkDetail, editKey) => {
+ state = validateState(state)
+
+ const oldBookmark = bookmarksState.getBookmark(state, editKey)
+ let newBookmark = oldBookmark.merge(bookmarkDetail)
+
+ let location
+ if (newBookmark.has('location')) {
+ location = UrlUtil.getLocationIfPDF(newBookmark.get('location'))
+ newBookmark = newBookmark.set('location', location)
+ }
+
+ state = siteCache.removeLocationSiteKey(state, oldBookmark.get('location'), editKey)
+
+ const newKey = siteUtil.getSiteKey(newBookmark)
+ if (newKey === null) {
+ return state
+ }
+
+ if (editKey !== newKey) {
+ state = state.deleteIn(['bookmarks', editKey])
+ state = bookmarkOrderCache.removeCacheKey(state, oldBookmark.get('parentFolderId'), editKey)
+ state = bookmarkOrderCache.addBookmarkToCache(state, newBookmark.get('parentFolderId'), newKey)
+ }
+
+ state = state.setIn(['bookmarks', newKey], newBookmark)
+ state = siteCache.addLocationSiteKey(state, location, newKey)
+ return state
+ },
+
+ removeBookmark: (state, bookmarkKey) => {
+ state = validateState(state)
+
+ const bookmark = bookmarksState.getBookmark(state, bookmarkKey)
+
+ if (bookmark.isEmpty()) {
+ return state
+ }
+
+ if (getSetting(settings.SYNC_ENABLED) === true) {
+ syncActions.removeSite(bookmark)
+ }
+
+ state = siteCache.removeLocationSiteKey(state, bookmark.get('location'), bookmarkKey)
+ state = bookmarkOrderCache.removeCacheKey(state, bookmark.get('parentFolderId'), bookmarkKey)
+
+ return state.deleteIn(['bookmarks', bookmarkKey])
+ },
+
+ /**
+ * Removes bookmarks based on the parent ID
+ * Cache is cleared in the function that is calling this one
+ * @param state - App state
+ * @param parentFolderId - parent id of the folder that we are deleting
+ */
+ removeBookmarksByParentId: (state, parentFolderId) => {
+ state = validateState(state)
+
+ const bookmarks = bookmarksState.getBookmarks(state)
+ .filter(bookmark => bookmark.get('parentFolderId') !== ~~parentFolderId)
+
+ return state.set('bookmarks', bookmarks)
+ },
+
+ /**
+ * Update the favicon URL for all entries in the state sites
+ * which match a given location. Currently, there should only be
+ * one match, but this will handle multiple.
+ *
+ * @param state The application state
+ * @param location URL for the entry needing an update
+ * @param favicon favicon URL
+ */
+ updateSiteFavicon: (state, location, favicon) => {
+ state = validateState(state)
+
+ if (UrlUtil.isNotURL(location)) {
+ return state
+ }
+
+ const siteKeys = siteCache.getLocationSiteKeys(state, location)
+ if (!siteKeys || siteKeys.length === 0) {
+ return state
+ }
+
+ siteKeys.forEach((siteKey) => {
+ state = state.setIn(['bookmarks', siteKey, 'favicon'], favicon)
+ })
+ return state
+ },
+
+ moveBookmark: (state, bookmarkKey, destinationKey, append, moveIntoParent) => {
+ let bookmark = bookmarksState.getBookmark(state, bookmarkKey)
+ let destinationItem = bookmarksState.findBookmark(state, destinationKey)
+
+ if (bookmark.isEmpty()) {
+ return state
+ }
+
+ // move bookmark into a new folder
+ if (moveIntoParent || destinationItem.get('parentFolderId') !== bookmark.get('parentFolderId')) {
+ const parentFolderId = destinationItem.get('type') === siteTags.BOOKMARK
+ ? destinationItem.get('parentFolderId')
+ : destinationItem.get('folderId')
+
+ state = bookmarkOrderCache.removeCacheKey(state, bookmark.get('parentFolderId'), bookmarkKey)
+ bookmark = bookmark.set('parentFolderId', ~~parentFolderId)
+ const newKey = siteUtil.getSiteKey(bookmark)
+ state = state.deleteIn(['bookmarks', bookmarkKey])
+ state = bookmarkOrderCache.addBookmarkToCache(state, bookmark.get('parentFolderId'), newKey)
+ return state.setIn(['bookmarks', newKey.toString()], bookmark)
+ }
+
+ // move bookmark to another place
+ state = bookmarkOrderCache.removeCacheKey(state, bookmark.get('parentFolderId'), bookmarkKey)
+ state = bookmarkOrderCache.addBookmarkToCache(
+ state,
+ bookmark.get('parentFolderId'),
+ bookmarkKey,
+ destinationKey,
+ append
+ )
+ return state
+ }
+}
+
+module.exports = bookmarksState
diff --git a/app/common/state/historyState.js b/app/common/state/historyState.js
new file mode 100644
index 00000000000..29a65d6c172
--- /dev/null
+++ b/app/common/state/historyState.js
@@ -0,0 +1,67 @@
+/* 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/. */
+
+const assert = require('assert')
+const Immutable = require('immutable')
+const siteUtil = require('../../../js/state/siteUtil')
+const historyUtil = require('../lib/historyUtil')
+const urlUtil = require('../../../js/lib/urlutil')
+const siteCache = require('./siteCache')
+const {makeImmutable, isMap} = require('./immutableUtil')
+
+const validateState = function (state) {
+ state = makeImmutable(state)
+ assert.ok(isMap(state), 'state must be an Immutable.Map')
+ assert.ok(isMap(state.get('historySites')), 'state must contain an Immutable.Map of historySites')
+ return state
+}
+
+const historyState = {
+ getSites: (state) => {
+ state = validateState(state)
+ return state.get('historySites', Immutable.Map())
+ },
+
+ getSite: (state, key) => {
+ state = validateState(state)
+ return state.getIn(['historySites', key], Immutable.Map())
+ },
+
+ addSite: (state, siteDetail) => {
+ let sites = historyState.getSites(state)
+ let siteKey = siteUtil.getSiteKey(siteDetail)
+ siteDetail = makeImmutable(siteDetail)
+
+ const oldSite = sites.get(siteKey)
+ let site
+ if (oldSite) {
+ site = historyUtil.mergeSiteDetails(oldSite, siteDetail)
+ } else {
+ let location
+ if (siteDetail.has('location')) {
+ location = urlUtil.getLocationIfPDF(siteDetail.get('location'))
+ siteDetail = siteDetail.set('location', location)
+ }
+
+ siteKey = siteUtil.getSiteKey(siteDetail)
+ site = historyUtil.prepareHistoryEntry(siteDetail)
+ state = siteCache.addLocationSiteKey(state, location, siteKey)
+ }
+
+ state = state.setIn(['historySites', siteKey], site)
+ return state
+ },
+
+ removeSite: (state, siteKey) => {
+ // TODO should we remove this only when a tab with this siteKey is not opened
+ // if not, we are deleting data that is use for bookmarking
+ state = state.deleteIn(['historySites', siteKey])
+ },
+
+ clearSites: (state) => {
+ return state.set('historySites', Immutable.Map())
+ }
+}
+
+module.exports = historyState
diff --git a/app/common/state/pinnedSitesState.js b/app/common/state/pinnedSitesState.js
new file mode 100644
index 00000000000..b231d780a53
--- /dev/null
+++ b/app/common/state/pinnedSitesState.js
@@ -0,0 +1,125 @@
+/* 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/. */
+
+const assert = require('assert')
+const Immutable = require('immutable')
+const siteCache = require('./siteCache')
+const siteUtil = require('../../../js/state/siteUtil')
+const urlUtil = require('../../../js/lib/urlutil')
+const {makeImmutable, isMap} = require('./immutableUtil')
+
+const validateState = function (state) {
+ state = makeImmutable(state)
+ assert.ok(isMap(state), 'state must be an Immutable.Map')
+ assert.ok(isMap(state.get('pinnedSites')), 'state must contain an Immutable.Map of pinnedSites')
+ return state
+}
+
+const pinnedSiteState = {
+ getSites: (state) => {
+ state = validateState(state)
+ return state.get('pinnedSites')
+ },
+
+ /**
+ * Adds the specified siteDetail in appState.pinnedSites.
+ * @param {Immutable.Map} state The application state Immutable map
+ * @param {Immutable.Map} site The siteDetail that we want to add
+ */
+ addPinnedSite: (state, site) => {
+ state = validateState(state)
+ const sites = pinnedSiteState.getSites(state) || Immutable.Map()
+ let location
+ if (site.has('location')) {
+ location = urlUtil.getLocationIfPDF(site.get('location'))
+ site = site.set('location', location)
+ }
+
+ site = site.set('order', sites.size)
+
+ const key = siteUtil.getSiteKey(site)
+ if (key === null) {
+ return state
+ }
+
+ state = state.setIn(['pinnedSites', key], site)
+ state = siteCache.addLocationSiteKey(state, location, key)
+ return state
+ },
+
+ /**
+ * Removes the given pinned site from the pinnedSites
+ *
+ * @param {Immutable.Map} state The application state Immutable map
+ * @param {Immutable.Map} siteDetail The siteDetail to be removed
+ * @return {Immutable.Map} The new state Immutable object
+ */
+ removePinnedSite: (state, siteDetail) => {
+ state = validateState(state)
+ const key = siteUtil.getSiteKey(siteDetail)
+ if (!key) {
+ return state
+ }
+
+ const location = siteDetail.get('location')
+ state = siteCache.removeLocationSiteKey(state, location, key)
+
+ const stateKey = ['pinnedSites', key]
+ let site = state.getIn(stateKey)
+ if (!site) {
+ return state
+ }
+
+ // TODO update order, so that is up to date
+
+ return state.deleteIn(stateKey, site)
+ },
+
+ /**
+ * Moves the specified pinned site from one location to another
+ *
+ * @param state The application state Immutable map
+ * @param sourceKey The site key to move
+ * @param destinationKey The site key to move to
+ * @param prepend Whether the destination detail should be prepended or not
+ * @return The new state Immutable object
+ */
+ reOrderSite: (state, sourceKey, destinationKey, prepend) => {
+ state = validateState(state)
+ let sites = state.get('pinnedSites')
+ let sourceSite = sites.get(sourceKey, Immutable.Map())
+ const destinationSite = sites.get(destinationKey, Immutable.Map())
+
+ if (sourceSite.isEmpty()) {
+ return state
+ }
+
+ const sourceSiteIndex = sourceSite.get('order')
+ const destinationSiteIndex = destinationSite.get('order')
+ let newIndex = destinationSiteIndex + (prepend ? 0 : 1)
+ if (destinationSiteIndex > sourceSiteIndex) {
+ --newIndex
+ }
+
+ state = state.set('pinnedSites', state.get('pinnedSites').map((site, index) => {
+ const siteOrder = site.get('order')
+ if (index === sourceKey) {
+ return site
+ }
+
+ if (siteOrder >= newIndex && siteOrder < sourceSiteIndex) {
+ return site.set('order', siteOrder + 1)
+ } else if (siteOrder <= newIndex && siteOrder > sourceSiteIndex) {
+ return site.set('order', siteOrder - 1)
+ }
+
+ return site
+ }))
+
+ sourceSite = sourceSite.set('order', newIndex)
+ return state.setIn(['pinnedSites', sourceKey], sourceSite)
+ }
+}
+
+module.exports = pinnedSiteState
diff --git a/app/common/state/siteCache.js b/app/common/state/siteCache.js
index beb1a207928..a436daae1f9 100644
--- a/app/common/state/siteCache.js
+++ b/app/common/state/siteCache.js
@@ -7,6 +7,8 @@ const siteUtil = require('../../../js/state/siteUtil')
const appUrlUtil = require('../../../js/lib/appUrlUtil')
const UrlUtil = require('../../../js/lib/urlutil')
+// TODO what to do with this file?
+
const createLocationSiteKeysCache = (state) => {
state = state.set('locationSiteKeysCache', new Immutable.Map())
state.get('sites').forEach((site, siteKey) => {
diff --git a/app/common/state/siteState.js b/app/common/state/siteState.js
deleted file mode 100644
index 0f74f8390a6..00000000000
--- a/app/common/state/siteState.js
+++ /dev/null
@@ -1,18 +0,0 @@
-const assert = require('assert')
-const {makeImmutable, isMap, isList} = require('./immutableUtil')
-
-const validateState = function (state) {
- state = makeImmutable(state)
- assert.ok(isMap(state), 'state must be an Immutable.Map')
- assert.ok(isList(state.get('sites')), 'state must contain an Immutable.List of sites')
- return state
-}
-
-const siteState = {
- getSites: (state) => {
- state = validateState(state)
- return state.get('sites')
- }
-}
-
-module.exports = siteState
diff --git a/app/common/state/tabState.js b/app/common/state/tabState.js
index 4cc5ece7b24..965125eaac2 100644
--- a/app/common/state/tabState.js
+++ b/app/common/state/tabState.js
@@ -13,7 +13,6 @@ const windowState = require('./windowState')
const { makeImmutable, isMap, isList } = require('./immutableUtil')
// this file should eventually replace frameStateUtil
const frameStateUtil = require('../../../js/state/frameStateUtil')
-const {isLocationBookmarked} = require('../../../js/state/siteUtil')
const validateId = function (propName, id) {
assert.ok(id, `${propName} cannot be null`)
@@ -239,6 +238,13 @@ const tabState = {
return state.get('tabs').filter((tab) => !!tab.get('pinned'))
},
+ isTabPinned: (state, tabId) => {
+ state = validateState(state)
+ tabId = validateId('tabId', tabId)
+ const tab = tabState.getByTabId(state, tabId)
+ return tab != null ? !!tab.get('pinned') : false
+ },
+
getNonPinnedTabs: (state) => {
state = validateState(state)
return state.get('tabs').filter((tab) => !tab.get('pinned'))
@@ -447,8 +453,9 @@ const tabState = {
return state
}
+ const bookmarkUtil = require('../lib/bookmarkUtil')
const frameLocation = action.getIn(['frame', 'location'])
- const frameBookmarked = isLocationBookmarked(state, frameLocation)
+ const frameBookmarked = bookmarkUtil.isLocationBookmarked(state, frameLocation)
const frameValue = action.get('frame').set('bookmarked', frameBookmarked)
tabValue = tabValue.set('frame', makeImmutable(frameValue))
return tabState.updateTabValue(state, tabValue)
diff --git a/app/importer.js b/app/importer.js
index b88c47d7fac..aecf9d29004 100644
--- a/app/importer.js
+++ b/app/importer.js
@@ -10,21 +10,32 @@ const importer = electron.importer
const dialog = electron.dialog
const BrowserWindow = electron.BrowserWindow
const session = electron.session
-const siteUtil = require('../js/state/siteUtil')
-const AppStore = require('../js/stores/appStore')
-const siteTags = require('../js/constants/siteTags')
-const appActions = require('../js/actions/appActions')
+
+// Store
+const appStore = require('../js/stores/appStore')
+
+// State
+const tabState = require('./common/state/tabState')
+const bookmarksState = require('./common/state/bookmarksState')
+const bookmarkFoldersState = require('./common/state/bookmarkFoldersState')
+
+// Constants
const messages = require('../js/constants/messages')
const settings = require('../js/constants/settings')
-const getSetting = require('../js/settings').getSetting
+
+// Actions
+const appActions = require('../js/actions/appActions')
+
+// Utils
+const {getSetting} = require('../js/settings')
const locale = require('./locale')
const tabMessageBox = require('./browser/tabMessageBox')
const {makeImmutable} = require('./common/state/immutableUtil')
-const tabState = require('./common/state/tabState')
+const bookmarkFoldersUtil = require('./common/lib/bookmarkFoldersUtil')
-var isImportingBookmarks = false
-var hasBookmarks
-var importedSites
+let isImportingBookmarks = false
+let hasBookmarks
+// let importedSites
exports.init = () => {
importer.initialize()
@@ -33,10 +44,8 @@ exports.init = () => {
exports.importData = (selected) => {
if (selected.get('favorites')) {
isImportingBookmarks = true
- const sites = AppStore.getState().get('sites')
- hasBookmarks = sites.find(
- (site) => siteUtil.isBookmark(site) || siteUtil.isFolder(site)
- )
+ const state = appStore.getState()
+ hasBookmarks = bookmarksState.getBookmarks(state).size > 0 || bookmarkFoldersState.getFolders(state).size > 0
}
if (selected !== undefined) {
importer.importData(selected.toJS())
@@ -45,10 +54,8 @@ exports.importData = (selected) => {
exports.importHTML = (selected) => {
isImportingBookmarks = true
- const sites = AppStore.getState().get('sites')
- hasBookmarks = sites.find(
- (site) => siteUtil.isBookmark(site) || siteUtil.isFolder(site)
- )
+ const state = appStore.getState()
+ hasBookmarks = bookmarksState.getBookmarks(state).size > 0 || bookmarkFoldersState.getFolders(state).size > 0
const files = dialog.showOpenDialog({
properties: ['openFile'],
filters: [{
@@ -69,7 +76,7 @@ importer.on('update-supported-browsers', (e, detail) => {
}
})
-importer.on('add-history-page', (e, history, visitSource) => {
+importer.on('add-history-page', (e, history) => {
let sites = []
for (let i = 0; i < history.length; ++i) {
const site = {
@@ -79,80 +86,70 @@ importer.on('add-history-page', (e, history, visitSource) => {
}
sites.push(site)
}
- appActions.addSite(makeImmutable(sites))
+ appActions.addHistorySite(makeImmutable(sites))
})
importer.on('add-homepage', (e, detail) => {
})
-const getParentFolderId = (path, pathMap, sites, topLevelFolderId, nextFolderIdObject) => {
+const getParentFolderId = (path, pathMap, folders, topLevelFolderId, nextFolderIdObject) => {
const pathLen = path.length
if (!pathLen) {
return topLevelFolderId
}
+
const parentFolder = path.pop()
let parentFolderId = pathMap[parentFolder]
if (parentFolderId === undefined) {
parentFolderId = nextFolderIdObject.id++
pathMap[parentFolder] = parentFolderId
- const folder = {
- customTitle: parentFolder,
+ folders.push({
+ title: parentFolder,
folderId: parentFolderId,
- parentFolderId: getParentFolderId(path, pathMap, sites, topLevelFolderId, nextFolderIdObject),
- lastAccessedTime: 0,
- creationTime: (new Date()).getTime(),
- tags: [siteTags.BOOKMARK_FOLDER]
- }
- sites.push(folder)
+ parentFolderId: getParentFolderId(path, pathMap, folders, topLevelFolderId, nextFolderIdObject)
+ })
}
return parentFolderId
}
-importer.on('add-bookmarks', (e, bookmarks, topLevelFolder) => {
- let nextFolderId = siteUtil.getNextFolderId(AppStore.getState().get('sites'))
+importer.on('add-bookmarks', (e, importedBookmarks, topLevelFolder) => {
+ const state = appStore.getState()
+ const bookmarkFolders = bookmarkFoldersState.getFolders(state)
+ let nextFolderId = bookmarkFoldersUtil.getNextFolderId(bookmarkFolders)
let nextFolderIdObject = { id: nextFolderId }
let pathMap = {}
- let sites = []
- let topLevelFolderId = 0
- topLevelFolderId = nextFolderIdObject.id++
- sites.push({
- customTitle: siteUtil.getNextFolderName(AppStore.getState().get('sites'), topLevelFolder),
+ let folders = []
+ let bookmarks = []
+ let topLevelFolderId = nextFolderIdObject.id++
+
+ folders.push({
+ title: bookmarkFoldersUtil.getNextFolderName(bookmarkFolders, topLevelFolder),
folderId: topLevelFolderId,
- parentFolderId: 0,
- lastAccessedTime: 0,
- creationTime: (new Date()).getTime(),
- tags: [siteTags.BOOKMARK_FOLDER]
+ parentFolderId: 0
})
- for (let i = 0; i < bookmarks.length; ++i) {
- let path = bookmarks[i].path
- let parentFolderId = getParentFolderId(path, pathMap, sites, topLevelFolderId, nextFolderIdObject)
- if (bookmarks[i].is_folder) {
+
+ for (let i = 0; i < importedBookmarks.length; ++i) {
+ let path = importedBookmarks[i].path
+ let parentFolderId = getParentFolderId(path, pathMap, folders, topLevelFolderId, nextFolderIdObject)
+ if (importedBookmarks[i].is_folder) {
const folderId = nextFolderIdObject.id++
- pathMap[bookmarks[i].title] = folderId
- const folder = {
- customTitle: bookmarks[i].title,
+ pathMap[importedBookmarks[i].title] = folderId
+ folders.push({
+ title: importedBookmarks[i].title,
folderId: folderId,
- parentFolderId: parentFolderId,
- lastAccessedTime: 0,
- creationTime: bookmarks[i].creation_time * 1000,
- tags: [siteTags.BOOKMARK_FOLDER]
- }
- sites.push(folder)
+ parentFolderId: parentFolderId
+ })
} else {
- const site = {
- title: bookmarks[i].title,
- customTitle: bookmarks[i].title,
- location: bookmarks[i].url,
- parentFolderId: parentFolderId,
- lastAccessedTime: 0,
- creationTime: bookmarks[i].creation_time * 1000,
- tags: [siteTags.BOOKMARK]
- }
- sites.push(site)
+ bookmarks.push({
+ title: importedBookmarks[i].title,
+ location: importedBookmarks[i].url,
+ parentFolderId: parentFolderId
+ })
}
}
- importedSites = makeImmutable(sites)
- appActions.addSite(makeImmutable(sites))
+
+ appActions.addBookmarkFolder(makeImmutable(folders))
+ appActions.addBookmark(makeImmutable(bookmarks))
})
importer.on('add-favicons', (e, detail) => {
@@ -168,7 +165,9 @@ importer.on('add-favicons', (e, detail) => {
}
}
})
- let sites = importedSites
+// TODO what should be done here? update all bookmarks with new fav icons?
+ /*
+ let sites = importedSites
sites = sites.map((site) => {
if ((site.get('favicon') === undefined && site.get('location') !== undefined &&
faviconMap[site.get('location')] !== undefined) ||
@@ -179,6 +178,7 @@ importer.on('add-favicons', (e, detail) => {
}
})
appActions.addSite(sites)
+ */
})
importer.on('add-keywords', (e, templateUrls, uniqueOnHostAndPath) => {
@@ -208,7 +208,7 @@ importer.on('add-cookies', (e, cookies) => {
})
const getActiveTabId = () => {
- return tabState.getActiveTabId(AppStore.getState())
+ return tabState.getActiveTabId(appStore.getState())
}
const showImportWarning = function () {
diff --git a/app/index.js b/app/index.js
index 2ee37e47f22..262fd96253a 100644
--- a/app/index.js
+++ b/app/index.js
@@ -159,6 +159,7 @@ app.on('ready', () => {
appActions.networkDisconnected()
})
+ // TODO what should we do here
loadAppStatePromise.then((initialState) => {
// Do this after loading the state
// For tests we always want to load default app state
@@ -301,7 +302,7 @@ app.on('ready', () => {
})
ipcMain.on(messages.EXPORT_BOOKMARKS, () => {
- BookmarksExporter.showDialog(appStore.getState().get('sites'))
+ BookmarksExporter.showDialog(appStore.getState())
})
// DO NOT TO THIS LIST - see above
@@ -330,7 +331,7 @@ app.on('ready', () => {
})
process.on(messages.EXPORT_BOOKMARKS, () => {
- BookmarksExporter.showDialog(appStore.getState().get('sites'))
+ BookmarksExporter.showDialog(appStore.getState())
})
ready = true
diff --git a/app/renderer/about/bookmarks/bookmarkFolderItem.js b/app/renderer/about/bookmarks/bookmarkFolderItem.js
index f2a31c5d9a4..55bf62d4bd5 100644
--- a/app/renderer/about/bookmarks/bookmarkFolderItem.js
+++ b/app/renderer/about/bookmarks/bookmarkFolderItem.js
@@ -10,9 +10,11 @@ const ImmutableComponent = require('../../components/immutableComponent')
// Actions
const aboutActions = require('../../../../js/about/aboutActions')
+const appActions = require('../../../../js/actions/appActions')
// Constants
const dragTypes = require('../../../../js/constants/dragTypes')
+const siteTags = require('../../../../js/constants/siteTags')
// Utils
const dndData = require('../../../../js/dndData')
@@ -31,7 +33,7 @@ class BookmarkFolderItem extends ImmutableComponent {
e.dataTransfer.effectAllowed = 'all'
dndData.setupDataTransferURL(e.dataTransfer,
this.props.bookmarkFolder.get('location'),
- this.props.bookmarkFolder.get('customTitle') || this.props.bookmarkFolder.get('title'))
+ this.props.bookmarkFolder.get('title'))
dndData.setupDataTransferBraveData(e.dataTransfer, dragTypes.BOOKMARK, this.props.bookmarkFolder)
}
}
@@ -54,11 +56,22 @@ class BookmarkFolderItem extends ImmutableComponent {
moveBookmark (e, bookmark) {
if (siteUtil.isMoveAllowed(this.props.allBookmarkFolders, bookmark, this.props.bookmarkFolder)) {
const bookmarkSiteKey = siteUtil.getSiteKey(bookmark)
- const bookmarkFolderSiteKey = siteUtil.getSiteKey(this.props.bookmarkFolder)
- aboutActions.moveSite(bookmarkSiteKey,
- bookmarkFolderSiteKey,
- dndData.shouldPrependVerticalItem(e.target, e.clientY),
- true)
+
+ if (bookmark.get('type') === siteTags.BOOKMARK_FOLDER) {
+ appActions.moveBookmarkFolder(
+ bookmarkSiteKey,
+ this.props.bookmarkFolder.get('folderId'),
+ dndData.shouldPrependVerticalItem(e.target, e.clientY),
+ true
+ )
+ } else {
+ appActions.moveBookmark(
+ bookmarkSiteKey,
+ this.props.bookmarkFolder.get('folderId'),
+ dndData.shouldPrependVerticalItem(e.target, e.clientY),
+ true
+ )
+ }
}
}
clearSelection () {
@@ -86,17 +99,27 @@ class BookmarkFolderItem extends ImmutableComponent {
this.clearSelection()
}
}
+
+ get childBookmarkFolders () {
+ const cached = this.props.bookmarkOrder.get(this.props.bookmarkFolder.get('folderId').toString())
+
+ if (cached == null) {
+ return Immutable.Map()
+ }
+ return cached
+ .filter(item => item.get('type') === siteTags.BOOKMARK_FOLDER)
+ .map(folder => this.props.allBookmarkFolders.get(folder.get('key').toString()))
+ }
+
render () {
const BookmarkFolderList = require('./bookmarkFolderList')
- const childBookmarkFolders = this.props.allBookmarkFolders
- .filter((bookmarkFolder) => (bookmarkFolder.get('parentFolderId') || 0) === this.props.bookmarkFolder.get('folderId'))
return
- {this.props.bookmarkFolder.get('customTitle') || this.props.bookmarkFolder.get('title')}
+ {this.props.bookmarkFolder.get('title')}
{
- childBookmarkFolders.size > 0
+ !this.childBookmarkFolders.isEmpty()
?
: null
}
diff --git a/app/renderer/about/bookmarks/bookmarkFolderList.js b/app/renderer/about/bookmarks/bookmarkFolderList.js
index ee918f34731..4f13f12ae06 100644
--- a/app/renderer/about/bookmarks/bookmarkFolderList.js
+++ b/app/renderer/about/bookmarks/bookmarkFolderList.js
@@ -35,6 +35,7 @@ class BookmarkFolderList extends ImmutableComponent {
allBookmarkFolders={this.props.allBookmarkFolders}
selectedFolderId={this.props.selectedFolderId}
bookmarkFolder={Immutable.fromJS({folderId: 0, tags: [siteTags.BOOKMARK_FOLDER]})}
+ bookmarkOrder={this.props.bookmarkOrder}
/>
: null
}
@@ -50,6 +51,7 @@ class BookmarkFolderList extends ImmutableComponent {
selected={!this.props.search && this.props.selectedFolderId === bookmarkFolder.get('folderId')}
selectedFolderId={this.props.selectedFolderId}
onChangeSelectedFolder={this.props.onChangeSelectedFolder}
+ bookmarkOrder={this.props.bookmarkOrder}
/>
)
}
@@ -65,6 +67,7 @@ class BookmarkFolderList extends ImmutableComponent {
allBookmarkFolders={this.props.allBookmarkFolders}
selectedFolderId={this.props.selectedFolderId}
bookmarkFolder={Immutable.fromJS({folderId: -1, tags: [siteTags.BOOKMARK_FOLDER]})}
+ bookmarkOrder={this.props.bookmarkOrder}
/>
: null
}
diff --git a/app/renderer/about/bookmarks/bookmarkTitleCell.js b/app/renderer/about/bookmarks/bookmarkTitleCell.js
index f2c99d121e6..ef09e57f44c 100644
--- a/app/renderer/about/bookmarks/bookmarkTitleCell.js
+++ b/app/renderer/about/bookmarks/bookmarkTitleCell.js
@@ -11,14 +11,14 @@ const ImmutableComponent = require('../../components/immutableComponent')
const {iconSize} = require('../../../../js/constants/config')
// Utils
-const siteUtil = require('../../../../js/state/siteUtil')
const cx = require('../../../../js/lib/classSet')
+const bookmarkFoldersUtil = require('../../../common/lib/bookmarkFoldersUtil')
class BookmarkTitleCell extends ImmutableComponent {
render () {
let iconStyle
const icon = this.props.siteDetail.get('favicon')
- if (!siteUtil.isFolder(this.props.siteDetail)) {
+ if (!bookmarkFoldersUtil.isFolder(this.props.siteDetail)) {
if (icon) {
iconStyle = {
minWidth: iconSize,
@@ -30,7 +30,7 @@ class BookmarkTitleCell extends ImmutableComponent {
}
}
- const bookmarkTitle = this.props.siteDetail.get('customTitle') || this.props.siteDetail.get('title')
+ const bookmarkTitle = this.props.siteDetail.get('title')
const bookmarkLocation = this.props.siteDetail.get('location')
const defaultIcon = 'fa fa-file-o'
diff --git a/app/renderer/about/bookmarks/bookmarkTitleHeader.js b/app/renderer/about/bookmarks/bookmarkTitleHeader.js
index 953ca91de7f..9cdad907cba 100644
--- a/app/renderer/about/bookmarks/bookmarkTitleHeader.js
+++ b/app/renderer/about/bookmarks/bookmarkTitleHeader.js
@@ -11,9 +11,6 @@ const ImmutableComponent = require('../../components/immutableComponent')
// Actions
const windowActions = require('../../../../js/actions/windowActions')
-// Constants
-const siteTags = require('../../../../js/constants/siteTags')
-
class BookmarkTitleHeader extends ImmutableComponent {
constructor () {
super()
@@ -21,8 +18,7 @@ class BookmarkTitleHeader extends ImmutableComponent {
}
addBookmark () {
const newBookmark = Immutable.fromJS({
- parentFolderId: this.props.selectedFolderId,
- tags: [siteTags.BOOKMARK]
+ parentFolderId: this.props.selectedFolderId
})
windowActions.addBookmark(newBookmark)
}
diff --git a/app/renderer/about/bookmarks/bookmarks.js b/app/renderer/about/bookmarks/bookmarks.js
index 936af4a748a..3dd745d30d3 100644
--- a/app/renderer/about/bookmarks/bookmarks.js
+++ b/app/renderer/about/bookmarks/bookmarks.js
@@ -38,6 +38,7 @@ class Bookmarks extends React.Component {
this.state = {
bookmarks: Immutable.Map(),
bookmarkFolders: Immutable.Map(),
+ bookmarkOrder: Immutable.Map(),
selectedFolderId: 0,
search: ''
}
@@ -46,7 +47,8 @@ class Bookmarks extends React.Component {
const detail = handle.memory()
this.setState({
bookmarks: Immutable.fromJS((detail && detail.bookmarks) || {}),
- bookmarkFolders: Immutable.fromJS((detail && detail.bookmarkFolders) || {})
+ bookmarkFolders: Immutable.fromJS((detail && detail.bookmarkFolders) || {}),
+ bookmarkOrder: Immutable.fromJS((detail && detail.bookmarkOrder) || {})
})
})
}
@@ -86,13 +88,25 @@ class Bookmarks extends React.Component {
searchedBookmarks (searchTerm, bookmarks) {
return bookmarks.filter((bookmark) => {
- const title = bookmark.get('customTitle') + bookmark.get('title') + bookmark.get('location')
+ const title = bookmark.get('title') + bookmark.get('location')
return title.match(new RegExp(searchTerm, 'gi'))
})
}
get bookmarksInFolder () {
- return this.state.bookmarks.filter((bookmark) => (bookmark.get('parentFolderId') || 0) === this.state.selectedFolderId)
+ const cached = this.state.bookmarkOrder.get(this.state.selectedFolderId.toString())
+
+ if (cached == null) {
+ return Immutable.Map()
+ }
+
+ return cached
+ .filter(item => item.get('type') === siteTags.BOOKMARK)
+ .map(bookmark => this.state.bookmarks.get(bookmark.get('key')))
+ }
+
+ get bookmarkFolders () {
+ return this.state.bookmarkFolders.filter((bookmark) => bookmark.get('parentFolderId') === -1)
}
importBrowserData () {
@@ -104,11 +118,9 @@ class Bookmarks extends React.Component {
}
addBookmarkFolder () {
- const newFolder = Immutable.fromJS({
- parentFolderId: this.state.selectedFolderId,
- tags: [siteTags.BOOKMARK_FOLDER]
- })
- windowActions.addBookmark(newFolder)
+ windowActions.addBookmarkFolder(Immutable.fromJS({
+ parentFolderId: this.state.selectedFolderId
+ }))
}
clearSelection () {
@@ -146,11 +158,12 @@ class Bookmarks extends React.Component {
bookmark.get('parentFolderId') === -1)}
+ bookmarkFolders={this.bookmarkFolders}
allBookmarkFolders={this.state.bookmarkFolders}
isRoot
selectedFolderId={this.state.selectedFolderId}
- search={this.state.search} />
+ search={this.state.search}
+ bookmarkOrder={this.state.bookmarkOrder} />
folder.get('folderId') === siteDetail.get('parentFolderId'))
- : Immutable.fromJS({folderId: 0, tags: [siteTags.BOOKMARK_FOLDER]})
- destinationIsParent = true
- }
-
- if (siteUtil.isMoveAllowed(this.props.allBookmarkFolders, bookmark, siteDetail)) {
- const bookmarkSiteKey = siteUtil.getSiteKey(bookmark.toJS())
- const siteKey = siteUtil.getSiteKey(siteDetail.toJS())
+ const bookmarkSiteKey = siteUtil.getSiteKey(bookmark)
+ const siteKey = siteUtil.getSiteKey(siteDetail)
- aboutActions.moveSite(bookmarkSiteKey,
- siteKey,
- dndData.shouldPrependVerticalItem(e.target, e.clientY),
- destinationIsParent)
- }
+ appActions.moveBookmark(
+ bookmarkSiteKey,
+ siteKey,
+ dndData.shouldPrependVerticalItem(e.target, e.clientY),
+ destinationIsParent
+ )
}
/**
* Bookmark (one or multiple) or BookmarkFolderItem object was dropped
@@ -124,7 +117,7 @@ class BookmarksList extends ImmutableComponent {
rows={this.props.bookmarks.map((entry) => [
{
cell: ,
- value: entry.get('customTitle') || entry.get('title') || entry.get('location')
+ value: entry.get('title', entry.get('location'))
},
{
html: formatUtil.toLocaleString(entry.get('lastAccessedTime'), ''),
diff --git a/app/renderer/components/bookmarks/addEditBookmarkFolder.js b/app/renderer/components/bookmarks/addEditBookmarkFolder.js
new file mode 100644
index 00000000000..2bed10a30f0
--- /dev/null
+++ b/app/renderer/components/bookmarks/addEditBookmarkFolder.js
@@ -0,0 +1,103 @@
+/* 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/. */
+
+const React = require('react')
+const Immutable = require('immutable')
+const {StyleSheet, css} = require('aphrodite/no-important')
+
+// Components
+const ReduxComponent = require('../reduxComponent')
+const Dialog = require('../common/dialog')
+const AddEditBookmarkFolderForm = require('./addEditBookmarkFolderForm')
+const {CommonFormBookmarkHanger} = require('../common/commonForm')
+
+// State
+const bookmarkFoldersState = require('../../../common/state/bookmarkFoldersState')
+const bookmarksState = require('../../../common/state/bookmarksState')
+
+// Actions
+const windowActions = require('../../../../js/actions/windowActions')
+
+// Utils
+const cx = require('../../../../js/lib/classSet')
+const bookmarkFoldersUtil = require('../../../common/lib/bookmarkFoldersUtil')
+
+// Styles
+const globalStyles = require('../styles/global')
+
+class AddEditBookmarkFolder extends React.Component {
+ constructor (props) {
+ super(props)
+ this.onClose = this.onClose.bind(this)
+ this.onClick = this.onClick.bind(this)
+ }
+
+ onClose () {
+ windowActions.onBookmarkFolderClose()
+ }
+
+ onClick (e) {
+ e.stopPropagation()
+ }
+
+ mergeProps (state, ownProps) {
+ const currentWindow = state.get('currentWindow')
+ const bookmarkDetail = currentWindow.get('bookmarkFolderDetail', Immutable.Map())
+ const folderDetails = bookmarkDetail.get('folderDetails') || Immutable.Map()
+ const editMode = bookmarkDetail.has('editKey')
+
+ const props = {}
+ // used in renderer
+ props.heading = editMode
+ ? 'bookmarkFolderEditing'
+ : 'bookmarkFolderAdding'
+ props.parentFolderId = folderDetails.get('parentFolderId')
+ props.partitionNumber = folderDetails.get('partitionNumber')
+ props.folderName = folderDetails.get('title')
+ props.isFolderNameValid = bookmarkFoldersUtil.isFolderNameValid(folderDetails.get('title'))
+ props.folders = bookmarkFoldersState.getFoldersWithoutKey(state, folderDetails.get('folderId')) // TODO (nejc) improve, primitives only
+ props.editKey = bookmarkDetail.get('editKey', null)
+ props.closestKey = bookmarkDetail.get('closestKey', null)
+ props.hasBookmarks = bookmarksState.getBookmarks(state).size > 0 || bookmarkFoldersState.getFolders(state).size > 0
+
+ return props
+ }
+
+ render () {
+ return
+ }
+}
+
+const styles = StyleSheet.create({
+ // Copied from commonForm.js
+ commonFormSection: {
+ // PR #7985
+ margin: `${globalStyles.spacing.dialogInsideMargin} 30px`
+ },
+ commonFormTitle: {
+ color: globalStyles.color.braveOrange,
+ fontSize: '1.2em'
+ }
+})
+
+module.exports = ReduxComponent.connect(AddEditBookmarkFolder)
diff --git a/app/renderer/components/bookmarks/addEditBookmarkFolderForm.js b/app/renderer/components/bookmarks/addEditBookmarkFolderForm.js
new file mode 100644
index 00000000000..614daa610f3
--- /dev/null
+++ b/app/renderer/components/bookmarks/addEditBookmarkFolderForm.js
@@ -0,0 +1,235 @@
+/* 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/. */
+
+const React = require('react')
+const Immutable = require('immutable')
+const {StyleSheet, css} = require('aphrodite/no-important')
+
+// Components
+const BrowserButton = require('../common/browserButton')
+const {
+ CommonFormSection,
+ CommonFormDropdown,
+ CommonFormButtonWrapper,
+ commonFormStyles
+} = require('../common/commonForm')
+
+// Actions
+const appActions = require('../../../../js/actions/appActions')
+const windowActions = require('../../../../js/actions/windowActions')
+
+// Constants
+const KeyCodes = require('../../../common/constants/keyCodes')
+const settings = require('../../../../js/constants/settings')
+
+// Utils
+const UrlUtil = require('../../../../js/lib/urlutil')
+const {getSetting} = require('../../../../js/settings')
+const bookmarkFoldersUtil = require('../../../common/lib/bookmarkFoldersUtil')
+
+// Styles
+const globalStyles = require('../styles/global')
+const commonStyles = require('../styles/commonStyles')
+
+class AddEditBookmarkFolderForm extends React.Component {
+ constructor (props) {
+ super(props)
+ this.onNameChange = this.onNameChange.bind(this)
+ this.onParentFolderChange = this.onParentFolderChange.bind(this)
+ this.onKeyDown = this.onKeyDown.bind(this)
+ this.onClose = this.onClose.bind(this)
+ this.onSave = this.onSave.bind(this)
+ this.onFolderRemove = this.onFolderRemove.bind(this)
+ this.state = {
+ title: props.folderName,
+ parentFolderId: props.parentFolderId,
+ isDisabled: props.isDisabled
+ }
+ }
+
+ componentDidMount () {
+ setImmediate(() => {
+ this.folderName.select()
+ })
+ }
+
+ onKeyDown (e) {
+ switch (e.keyCode) {
+ case KeyCodes.ENTER:
+ this.onSave()
+ break
+ case KeyCodes.ESC:
+ this.onClose()
+ break
+ }
+ }
+
+ onClose () {
+ windowActions.onBookmarkFolderClose()
+ }
+
+ updateButtonStatus (newValue) {
+ if (newValue !== this.state.isDisabled) {
+ this.setState({
+ isDisabled: newValue
+ })
+ }
+ }
+
+ onNameChange (e) {
+ let title = e.target.value
+
+ this.setState({
+ title: title
+ })
+
+ this.updateButtonStatus(!bookmarkFoldersUtil.isFolderNameValid(title))
+ }
+
+ onParentFolderChange (e) {
+ this.setState({
+ parentFolderId: ~~e.target.value
+ })
+ }
+
+ onSave () {
+ // First check if the title of the bookmarkDetail is set
+ if (this.state.isDisabled) {
+ return false
+ }
+
+ // show bookmark if hidden
+ if (!this.props.hasBookmarks && !getSetting(settings.SHOW_BOOKMARKS_TOOLBAR)) {
+ appActions.changeSetting(settings.SHOW_BOOKMARKS_TOOLBAR, true)
+ }
+
+ let data = Immutable.fromJS({
+ parentFolderId: this.state.parentFolderId
+ })
+
+ if (this.props.editKey != null) {
+ data = data.set('folderId', this.props.editKey)
+ }
+
+ // handle title input
+ let title = this.state.title
+ if (typeof title === 'string' && UrlUtil.isURL(title)) {
+ const punycodeUrl = UrlUtil.getPunycodeUrl(title)
+ if (punycodeUrl.replace(/\/$/, '') !== title) {
+ title = punycodeUrl
+ }
+ }
+ data = data.set('title', title)
+
+ if (this.props.editKey != null) {
+ appActions.editBookmarkFolder(data, this.props.editKey)
+ } else {
+ appActions.addBookmarkFolder(data, this.props.closestKey)
+ }
+
+ this.onClose()
+ }
+
+ onFolderRemove () {
+ appActions.removeBookmarkFolder(Immutable.fromJS({
+ parentFolderId: this.props.parentFolderId,
+ partitionNumber: this.props.partitionNumber,
+ folderId: this.props.editKey
+ }))
+ this.onClose()
+ }
+
+ render () {
+ return
+
+
+
+
+
+
+
+ {
+ this.props.folders.map((folder) => )
+ }
+
+
+
+
+
+ {
+ this.props.editKey != null
+ ?
+ :
+ }
+
+
+
+ }
+}
+
+const styles = StyleSheet.create({
+ bookmarkHanger__label: {
+ display: 'block',
+ marginBottom: `calc(${globalStyles.spacing.dialogInsideMargin} / 3)`
+ },
+ bookmarkHanger__marginRow: {
+ marginTop: `calc(${globalStyles.spacing.dialogInsideMargin} / 2)`
+ },
+
+ bookmark__sectionWrapper: {
+ display: 'flex',
+ flexFlow: 'column nowrap'
+ }
+})
+
+module.exports = AddEditBookmarkFolderForm
diff --git a/app/renderer/components/bookmarks/addEditBookmarkForm.js b/app/renderer/components/bookmarks/addEditBookmarkForm.js
index a744a8d50f4..2dd64b19ea4 100644
--- a/app/renderer/components/bookmarks/addEditBookmarkForm.js
+++ b/app/renderer/components/bookmarks/addEditBookmarkForm.js
@@ -22,7 +22,6 @@ const windowActions = require('../../../../js/actions/windowActions')
// Constants
const KeyCodes = require('../../../common/constants/keyCodes')
-const siteTags = require('../../../../js/constants/siteTags')
const settings = require('../../../../js/constants/settings')
// Utils
@@ -45,7 +44,7 @@ class AddEditBookmarkForm extends React.Component {
this.onSave = this.onSave.bind(this)
this.onRemoveBookmark = this.onRemoveBookmark.bind(this)
this.state = {
- title: props.bookmarkName,
+ title: props.title,
location: props.location,
parentFolderId: props.parentFolderId,
isDisabled: props.isDisabled
@@ -87,8 +86,6 @@ class AddEditBookmarkForm extends React.Component {
this.setState({
title: title
})
-
- this.updateButtonStatus(!isBookmarkNameValid(title, this.state.location, this.props.isFolder))
}
onLocationChange (e) {
@@ -98,7 +95,7 @@ class AddEditBookmarkForm extends React.Component {
location: location
})
- this.updateButtonStatus(!isBookmarkNameValid(this.state.title, location, this.props.isFolder))
+ this.updateButtonStatus(!isBookmarkNameValid(location))
}
onParentFolderChange (e) {
@@ -118,16 +115,10 @@ class AddEditBookmarkForm extends React.Component {
appActions.changeSetting(settings.SHOW_BOOKMARKS_TOOLBAR, true)
}
- const tag = this.props.isFolder ? siteTags.BOOKMARK_FOLDER : siteTags.BOOKMARK
let data = Immutable.fromJS({
- parentFolderId: this.state.parentFolderId,
- title: this.props.currentTitle
+ parentFolderId: this.state.parentFolderId
})
- if (this.props.isFolder && this.props.editKey != null) {
- data = data.set('folderId', this.props.editKey)
- }
-
// handle title input
let title = this.state.title
if (typeof title === 'string' && UrlUtil.isURL(title)) {
@@ -136,10 +127,7 @@ class AddEditBookmarkForm extends React.Component {
title = punycodeUrl
}
}
-
- if (this.props.currentTitle !== title || !title) {
- data = data.set('customTitle', title || 0)
- }
+ data = data.set('title', title)
// handle location input
let location = this.state.location
@@ -152,23 +140,16 @@ class AddEditBookmarkForm extends React.Component {
data = data.set('location', location)
if (this.props.editKey != null) {
- appActions.editBookmark(data, this.props.editKey, tag)
+ appActions.editBookmark(data, this.props.editKey)
} else {
- appActions.addBookmark(data, tag, this.props.closestKey)
+ appActions.addBookmark(data, this.props.closestKey)
}
this.onClose()
}
onRemoveBookmark () {
- const tag = this.props.isFolder ? siteTags.BOOKMARK_FOLDER : siteTags.BOOKMARK
- // TODO check if you need to add folderId as prop or you can use editKey
- appActions.removeSite(Immutable.fromJS({
- parentFolderId: this.props.parentFolderId,
- location: this.props.location,
- partitionNumber: this.props.partitionNumber,
- folderId: this.props.isFolder ? this.props.editKey : null
- }), tag)
+ appActions.removeBookmark(this.props.editKey)
this.onClose()
}
@@ -203,7 +184,7 @@ class AddEditBookmarkForm extends React.Component {
{
- !this.props.isFolder && !this.props.isAdded
+ !this.props.isAdded
?
siteUtil.isBookmark(site) || siteUtil.isFolder(site)
- )
+ props.hasBookmarks = bookmarksState.getBookmarks(state).size > 0 || bookmarkFoldersState.getFolders(state).size > 0
return props
}
@@ -132,14 +123,12 @@ class AddEditBookmarkHanger extends React.Component {
[css(styles.commonFormTitle)]: true
})} data-l10n-id={this.props.heading} />
0) {
Array.from(e.dataTransfer.items).forEach((item) => {
- item.getAsString((name) => appActions.addSite({ location: item.type, title: name }, siteTags.BOOKMARK))
+ item.getAsString((name) => appActions.addBookmark(Immutable.fromJS({
+ location: item.type,
+ title: name
+ })))
})
return
}
@@ -92,7 +101,7 @@ class BookmarksToolbar extends React.Component {
.map((x) => x.trim())
.filter((x) => !x.startsWith('#') && x.length > 0)
.forEach((url) =>
- appActions.addSite({ location: url }, siteTags.BOOKMARK))
+ appActions.addBookmark(Immutable.fromJS({ location: url })))
}
onDragEnter (e) {
diff --git a/app/renderer/components/frame/frame.js b/app/renderer/components/frame/frame.js
index 5ad3ef64eff..00b1af41a15 100644
--- a/app/renderer/components/frame/frame.js
+++ b/app/renderer/components/frame/frame.js
@@ -30,7 +30,6 @@ const tabMessageBoxState = require('../../../common/state/tabMessageBoxState')
// Utils
const frameStateUtil = require('../../../../js/state/frameStateUtil')
-const siteUtil = require('../../../../js/state/siteUtil')
const UrlUtil = require('../../../../js/lib/urlutil')
const cx = require('../../../../js/lib/classSet')
const urlParse = require('../../../common/urlParse')
@@ -49,6 +48,7 @@ const {isFocused} = require('../../currentWindow')
const debounce = require('../../../../js/lib/debounce')
const locale = require('../../../../js/l10n')
const imageUtil = require('../../../../js/lib/imageUtil')
+const historyUtil = require('../../../common/lib/historyUtil')
// Constants
const settings = require('../../../../js/constants/settings')
@@ -624,7 +624,7 @@ class Frame extends React.Component {
// with setTitle. We either need to delay this call until the title is
// or add a way to update it
setTimeout(() => {
- appActions.addSite(siteUtil.getDetailFromFrame(this.frame))
+ appActions.addHistorySite(historyUtil.getDetailFromFrame(this.frame))
}, 250)
}
@@ -668,7 +668,7 @@ class Frame extends React.Component {
url: e.validatedURL
})
appActions.loadURLRequested(this.props.tabId, 'about:error')
- appActions.removeSite(siteUtil.getDetailFromFrame(this.frame))
+ appActions.removeHistorySite(historyUtil.getDetailFromFrame(this.frame))
} else if (isAborted(e.errorCode)) {
// just stay put
} else if (provisionLoadFailure) {
diff --git a/app/renderer/components/main/main.js b/app/renderer/components/main/main.js
index 5504295141d..c93ce69aed8 100644
--- a/app/renderer/components/main/main.js
+++ b/app/renderer/components/main/main.js
@@ -33,6 +33,7 @@ const WidevinePanel = require('./widevinePanel')
const AutofillAddressPanel = require('../autofill/autofillAddressPanel')
const AutofillCreditCardPanel = require('../autofill/autofillCreditCardPanel')
const AddEditBookmarkHanger = require('../bookmarks/addEditBookmarkHanger')
+const AddEditBookmarkFolder = require('../bookmarks/addEditBookmarkFolder')
const LoginRequired = require('./loginRequired')
const ReleaseNotes = require('./releaseNotes')
const BookmarksToolbar = require('../bookmarks/bookmarksToolbar')
@@ -534,21 +535,22 @@ class Main extends React.Component {
props.isFullScreen = activeFrame.get('isFullScreen', false)
props.isMaximized = isMaximized() || isFullScreen()
props.captionButtonsVisible = isWindows
- props.showContextMenu = !!currentWindow.get('contextMenuDetail')
- props.showPopupWindow = !!currentWindow.get('popupWindowDetail')
+ props.showContextMenu = currentWindow.has('contextMenuDetail')
+ props.showPopupWindow = currentWindow.has('popupWindowDetail')
props.showSiteInfo = currentWindow.getIn(['ui', 'siteInfo', 'isVisible']) &&
!isSourceAboutUrl(activeFrame.get('location'))
props.showBravery = shieldState.braveShieldsEnabled(activeFrame) &&
!!currentWindow.get('braveryPanelDetail')
- props.showClearData = !!currentWindow.getIn(['ui', 'isClearBrowsingDataPanelVisible'])
- props.showImportData = !!currentWindow.get('importBrowserDataDetail')
+ props.showClearData = currentWindow.hasIn(['ui', 'isClearBrowsingDataPanelVisible'])
+ props.showImportData = currentWindow.has('importBrowserDataDetail')
props.showWidevine = currentWindow.getIn(['widevinePanelDetail', 'shown']) && !isLinux
- props.showAutoFillAddress = !!currentWindow.get('autofillAddressDetail')
- props.showAutoFillCC = !!currentWindow.get('autofillCreditCardDetail')
+ props.showAutoFillAddress = currentWindow.has('autofillAddressDetail')
+ props.showAutoFillCC = currentWindow.has('autofillCreditCardDetail')
props.showLogin = !!loginRequiredDetails
- props.showBookmarkHanger = currentWindow.get('bookmarkDetail') &&
+ props.showBookmarkHanger = currentWindow.has('bookmarkDetail') &&
!currentWindow.getIn(['bookmarkDetail', 'isBookmarkHanger'])
- props.showNoScript = currentWindow.getIn(['ui', 'noScriptInfo', 'isVisible']) &&
+ props.showBookmarkFolderDialog = currentWindow.has('bookmarkFolderDetail')
+ props.showNoScript = currentWindow.hasIn(['ui', 'noScriptInfo', 'isVisible']) &&
siteUtil.getOrigin(activeFrame.get('location'))
props.showReleaseNotes = currentWindow.getIn(['ui', 'releaseNotes', 'isVisible'])
props.showCheckDefault = isFocused() && defaultBrowserState.shouldDisplayDialog(state)
@@ -657,6 +659,11 @@ class Main extends React.Component {
?
: null
}
+ {
+ this.props.showBookmarkFolderDialog
+ ?
+ : null
+ }
{
this.props.showNoScript
?
diff --git a/app/renderer/components/navigation/navigationBar.js b/app/renderer/components/navigation/navigationBar.js
index 59cb062677b..c7ae1abe9f9 100644
--- a/app/renderer/components/navigation/navigationBar.js
+++ b/app/renderer/components/navigation/navigationBar.js
@@ -52,7 +52,7 @@ class NavigationBar extends React.Component {
if (editing) {
windowActions.editBookmark(true, this.props.bookmarkKey)
} else {
- windowActions.onBookmarkAdded(true, this.props.bookmarkKey)
+ windowActions.onBookmarkAdded(true)
}
}
diff --git a/app/renderer/components/navigation/urlBar.js b/app/renderer/components/navigation/urlBar.js
index 8c8c2bc5b68..93d674942c0 100644
--- a/app/renderer/components/navigation/urlBar.js
+++ b/app/renderer/components/navigation/urlBar.js
@@ -167,7 +167,8 @@ class UrlBar extends React.Component {
if (e.shiftKey) {
const selectedIndex = this.props.urlbarLocationSuffix.length > 0 ? 1 : this.props.selectedIndex
if (selectedIndex !== undefined) {
- appActions.removeSite({ location: this.props.suggestionLocation })
+ // TODO double check if this is correct
+ appActions.removeHistorySite({ location: this.props.suggestionLocation })
}
} else {
this.hideAutoComplete()
diff --git a/app/renderer/components/tabs/content/closeTabIcon.js b/app/renderer/components/tabs/content/closeTabIcon.js
index 577350c99cc..34bc48fa5bb 100644
--- a/app/renderer/components/tabs/content/closeTabIcon.js
+++ b/app/renderer/components/tabs/content/closeTabIcon.js
@@ -50,8 +50,9 @@ class CloseTabIcon extends React.Component {
mergeProps (state, ownProps) {
const currentWindow = state.get('currentWindow')
const frameKey = ownProps.frameKey
- const isPinnedTab = frameStateUtil.isPinned(currentWindow, frameKey)
const frame = frameStateUtil.getFrameByKey(currentWindow, frameKey) || Immutable.Map()
+ const tabId = frame.get('tabId', tabState.TAB_ID_NONE)
+ const isPinnedTab = tabState.isTabPinned(state, tabId)
const props = {}
// used in renderer
@@ -64,7 +65,7 @@ class CloseTabIcon extends React.Component {
// used in functions
props.frameKey = frameKey
props.fixTabWidth = ownProps.fixTabWidth
- props.tabId = frame.get('tabId', tabState.TAB_ID_NONE)
+ props.tabId = tabId
props.hasFrame = !frame.isEmpty()
return props
diff --git a/app/renderer/components/tabs/content/favIcon.js b/app/renderer/components/tabs/content/favIcon.js
index 354088de059..181300b4fb7 100644
--- a/app/renderer/components/tabs/content/favIcon.js
+++ b/app/renderer/components/tabs/content/favIcon.js
@@ -12,6 +12,7 @@ const TabIcon = require('./tabIcon')
// State
const tabContentState = require('../../../../common/state/tabContentState')
+const tabState = require('../../../../common/state/tabState')
// Utils
const frameStateUtil = require('../../../../../js/state/frameStateUtil')
@@ -34,12 +35,13 @@ class Favicon extends React.Component {
const frameKey = ownProps.frameKey
const frame = frameStateUtil.getFrameByKey(currentWindow, frameKey) || Immutable.Map()
const isTabLoading = tabContentState.isTabLoading(currentWindow, frameKey)
+ const tabId = frame.get('tabId', tabState.TAB_ID_NONE)
const props = {}
// used in renderer
props.isTabLoading = isTabLoading
props.favicon = !isTabLoading && frame.get('icon')
- props.isPinnedTab = frameStateUtil.isPinned(currentWindow, frameKey)
+ props.isPinnedTab = tabState.isTabPinned(state, tabId)
props.tabIconColor = tabContentState.getTabIconColor(currentWindow, frameKey)
props.isNarrowestView = tabContentState.isNarrowestView(currentWindow, frameKey)
diff --git a/app/renderer/components/tabs/pinnedTabs.js b/app/renderer/components/tabs/pinnedTabs.js
index 5615a69b1b5..4a9cc6b81b4 100644
--- a/app/renderer/components/tabs/pinnedTabs.js
+++ b/app/renderer/components/tabs/pinnedTabs.js
@@ -18,7 +18,6 @@ const windowActions = require('../../../../js/actions/windowActions')
const windowStore = require('../../../../js/stores/windowStore')
// Constants
-const siteTags = require('../../../../js/constants/siteTags')
const dragTypes = require('../../../../js/constants/dragTypes')
// Utils
@@ -26,6 +25,7 @@ const siteUtil = require('../../../../js/state/siteUtil')
const dnd = require('../../../../js/dnd')
const dndData = require('../../../../js/dndData')
const frameStateUtil = require('../../../../js/state/frameStateUtil')
+const pinnedSitesUtil = require('../../../common/lib/pinnedSitesUtil')
const {isIntermediateAboutPage} = require('../../../../js/lib/appUrlUtil')
class PinnedTabs extends React.Component {
@@ -58,12 +58,14 @@ class PinnedTabs extends React.Component {
if (!sourceDragData.get('pinnedLocation')) {
appActions.tabPinned(sourceDragData.get('tabId'), true)
} else {
- const sourceDetails = siteUtil.getDetailFromFrame(sourceDragData, siteTags.PINNED)
+ const sourceDetails = pinnedSitesUtil.getDetailFromFrame(sourceDragData)
const droppedOnFrame = this.dropFrame(droppedOnTab.props.frameKey)
- const destinationDetails = siteUtil.getDetailFromFrame(droppedOnFrame, siteTags.PINNED)
- appActions.moveSite(siteUtil.getSiteKey(sourceDetails),
+ const destinationDetails = pinnedSitesUtil.getDetailFromFrame(droppedOnFrame)
+ appActions.onPinnedTabReorder(
+ siteUtil.getSiteKey(sourceDetails),
siteUtil.getSiteKey(destinationDetails),
- isLeftSide)
+ isLeftSide
+ )
}
}
}, 0)
diff --git a/app/renderer/components/tabs/tab.js b/app/renderer/components/tabs/tab.js
index ebac3a874b5..d7a85e975c6 100644
--- a/app/renderer/components/tabs/tab.js
+++ b/app/renderer/components/tabs/tab.js
@@ -225,6 +225,7 @@ class Tab extends React.Component {
const partition = typeof frame.get('partitionNumber') === 'string'
? frame.get('partitionNumber').replace(/^partition-/i, '')
: frame.get('partitionNumber')
+ const tabId = frame.get('tabId', tabState.TAB_ID_NONE)
const props = {}
// used in renderer
@@ -234,7 +235,7 @@ class Tab extends React.Component {
props.notificationBarActive = notificationBarActive
props.isActive = frameStateUtil.isFrameKeyActive(currentWindow, props.frameKey)
props.tabWidth = currentWindow.getIn(['ui', 'tabs', 'fixTabWidth'])
- props.isPinnedTab = frameStateUtil.isPinned(currentWindow, props.frameKey)
+ props.isPinnedTab = tabState.isTabPinned(state, tabId)
props.canPlayAudio = tabContentState.canPlayAudio(currentWindow, props.frameKey)
props.themeColor = tabContentState.getThemeColor(currentWindow, props.frameKey)
props.isNarrowView = tabContentState.isNarrowView(currentWindow, props.frameKey)
@@ -256,7 +257,7 @@ class Tab extends React.Component {
props.totalTabs = state.get('tabs').size
props.dragData = state.getIn(['dragData', 'type']) === dragTypes.TAB && state.get('dragData')
props.hasTabInFullScreen = tabContentState.hasTabInFullScreen(currentWindow)
- props.tabId = frame.get('tabId', tabState.TAB_ID_NONE)
+ props.tabId = tabId
return props
}
diff --git a/app/renderer/reducers/contextMenuReducer.js b/app/renderer/reducers/contextMenuReducer.js
index 36f3795b6a6..8a81000e92a 100644
--- a/app/renderer/reducers/contextMenuReducer.js
+++ b/app/renderer/reducers/contextMenuReducer.js
@@ -20,6 +20,7 @@ const appStoreRenderer = require('../../../js/stores/appStoreRenderer')
// State
const contextMenuState = require('../../common/state/contextMenuState')
+const bookmarksState = require('../../common/state/bookmarksState')
// Actions
const appActions = require('../../../js/actions/appActions')
@@ -37,6 +38,8 @@ const menuUtil = require('../../common/lib/menuUtil')
const urlUtil = require('../../../js/lib/urlutil')
const frameStateUtil = require('../../../js/state/frameStateUtil')
const dndData = require('../../../js/dndData')
+const bookmarkFoldersUtil = require('../../common/lib/bookmarkFoldersUtil')
+const historyState = require('../../common/state/historyState')
const {makeImmutable, isMap} = require('../../common/state/immutableUtil')
const {getCurrentWindow} = require('../../renderer/currentWindow')
const {getSetting} = require('../../../js/settings')
@@ -237,18 +240,18 @@ const addFolderMenuItem = (closestDestinationDetail, isParent) => {
return {
label: locale.translation('addFolder'),
click: () => {
- let siteDetail = Immutable.fromJS({ tags: [siteTags.BOOKMARK_FOLDER] })
let closestKey = null
+ let folderDetails = Immutable.Map()
if (closestDestinationDetail) {
closestKey = siteUtil.getSiteKey(closestDestinationDetail)
if (isParent) {
- siteDetail = siteDetail.set('parentFolderId', (closestDestinationDetail.get('folderId') || closestDestinationDetail.get('parentFolderId')))
+ folderDetails = folderDetails.set('parentFolderId', (closestDestinationDetail.get('folderId') || closestDestinationDetail.get('parentFolderId')))
}
}
- windowActions.addBookmark(siteDetail, closestKey)
+ windowActions.addBookmarkFolder(folderDetails, closestKey)
}
}
}
@@ -273,52 +276,48 @@ const openAllInNewTabsMenuItem = (folderDetail) => {
}
}
-const siteDetailTemplateInit = (state, siteKey) => {
- let isHistoryEntry = false
- let multipleHistoryEntries = false
- let multipleBookmarks = false
- let isFolder = false
- let isSystemFolder = false
- let deleteLabel
- let deleteTag
- let siteDetail = appStoreRenderer.state.getIn(['sites', siteKey], Immutable.Map())
- const activeFrame = frameStateUtil.getActiveFrame(state) || Immutable.Map()
+const getLabel = (siteDetail, activeFrame, type) => {
+ let label = ''
- // TODO(bsclifton): pull this out to a method
- if (siteUtil.isBookmark(siteDetail) && activeFrame) {
- deleteLabel = 'deleteBookmark'
- deleteTag = siteTags.BOOKMARK
- } else if (siteUtil.isFolder(siteDetail)) {
- isFolder = true
- isSystemFolder = siteDetail.get('folderId') === 0 ||
- siteDetail.get('folderId') === -1
- deleteLabel = 'deleteFolder'
- deleteTag = siteTags.BOOKMARK_FOLDER
- } else if (siteUtil.isHistoryEntry(siteDetail)) {
- isHistoryEntry = true
- deleteLabel = 'deleteHistoryEntry'
+ if (type === siteTags.BOOKMARK && activeFrame) {
+ label = 'deleteBookmark'
+ } else if (type === siteTags.BOOKMARK_FOLDER) {
+ label = 'deleteFolder'
+ } else if (type === siteTags.HISTORY) {
+ label = 'deleteHistoryEntry'
} else if (Immutable.List.isList(siteDetail)) {
// Multiple bookmarks OR history entries selected
- multipleHistoryEntries = true
+ /* multipleHistoryEntries = true
multipleBookmarks = true
siteDetail.forEach((site) => {
if (!siteUtil.isBookmark(site)) multipleBookmarks = false
if (!siteUtil.isHistoryEntry(site)) multipleHistoryEntries = false
})
if (multipleBookmarks) {
- deleteLabel = 'deleteBookmarks'
+ label = 'deleteBookmarks'
deleteTag = siteTags.BOOKMARK
} else if (multipleHistoryEntries) {
- deleteLabel = 'deleteHistoryEntries'
- }
- } else {
- deleteLabel = ''
+ label = 'deleteHistoryEntries'
+ } */
}
+ return label
+}
+
+// TODO check when we send in multiple siteKeys
+const siteDetailTemplateInit = (state, siteKey, type) => {
+ let isFolder = type === siteTags.BOOKMARK_FOLDER
+ let siteDetail = bookmarksState.findBookmark(appStoreRenderer.state, siteKey)
+ if (siteDetail.isEmpty()) {
+ siteDetail = historyState.getSite(state, siteKey)
+ }
+ let multiple = Immutable.List.isList(siteDetail)
+ const activeFrame = frameStateUtil.getActiveFrame(state) || Immutable.Map()
const template = []
+ const label = getLabel(siteDetail, activeFrame, type)
- if (!isFolder) {
- if (!Immutable.List.isList(siteDetail)) {
+ if (type !== siteTags.BOOKMARK_FOLDER) {
+ if (!multiple) {
const location = siteDetail.get('location')
template.push(
@@ -348,52 +347,62 @@ const siteDetailTemplateInit = (state, siteKey) => {
template.push(openAllInNewTabsMenuItem(siteDetail), CommonMenu.separatorMenuItem)
}
- if (!isSystemFolder) {
+ if (siteDetail.get('folderId') !== 0 && siteDetail.get('folderId') !== -1) {
// Picking this menu item pops up the AddEditBookmark modal
// - History can be deleted but not edited
// - Multiple bookmarks cannot be edited at once
// - "Bookmarks Toolbar" and "Other Bookmarks" folders cannot be deleted
- if (!isHistoryEntry && !multipleHistoryEntries && !multipleBookmarks) {
+ if (type !== siteTags.HISTORY && !multiple) {
template.push(
{
label: locale.translation(isFolder ? 'editFolder' : 'editBookmark'),
click: () => {
const editKey = siteUtil.getSiteKey(siteDetail)
- windowActions.editBookmark(false, editKey)
+ if (isFolder) {
+ windowActions.editBookmarkFolder(editKey)
+ } else {
+ windowActions.editBookmark(false, editKey)
+ }
}
},
- CommonMenu.separatorMenuItem)
+ CommonMenu.separatorMenuItem
+ )
}
template.push(
{
- label: locale.translation(deleteLabel),
+ label: locale.translation(label),
click: () => {
- if (Immutable.List.isList(siteDetail)) {
- siteDetail.forEach((site) => appActions.removeSite(site, deleteTag))
- } else {
- appActions.removeSite(siteDetail, deleteTag)
+ // TODO implement multiple
+ const key = siteUtil.getSiteKey(siteDetail)
+ if (type === siteTags.HISTORY) {
+ appActions.removeHistorySite(siteDetail)
+ } else if (type === siteTags.BOOKMARK) {
+ appActions.removeBookmark(key)
+ } else if (type === siteTags.BOOKMARK_FOLDER) {
+ appActions.removeBookmarkFolder(key)
}
}
})
}
- if (!isHistoryEntry && !multipleHistoryEntries) {
+ if (type !== siteTags.HISTORY) {
if (template[template.length - 1] !== CommonMenu.separatorMenuItem) {
template.push(CommonMenu.separatorMenuItem)
}
template.push(
- addBookmarkMenuItem('addBookmark', siteUtil.getDetailFromFrame(activeFrame, siteTags.BOOKMARK), siteDetail, true),
- addFolderMenuItem(siteDetail, true))
+ addBookmarkMenuItem('addBookmark', bookmarkUtil.getDetailFromFrame(activeFrame), siteDetail, true),
+ addFolderMenuItem(siteDetail, true)
+ )
}
return menuUtil.sanitizeTemplateItems(template)
}
-const onSiteDetailMenu = (state, siteKey) => {
+const onSiteDetailMenu = (state, siteKey, type) => {
state = validateState(state)
- const template = siteDetailTemplateInit(state, siteKey)
+ const template = siteDetailTemplateInit(state, siteKey, type)
const menu = Menu.buildFromTemplate(template)
menu.popup(getCurrentWindow())
@@ -402,9 +411,7 @@ const onSiteDetailMenu = (state, siteKey) => {
const showBookmarkFolderInit = (state, parentBookmarkFolderKey) => {
const appState = appStoreRenderer.state
- const allBookmarkItems = siteUtil.getBookmarks(appState.get('sites', Immutable.List()))
- const parentBookmarkFolder = appState.getIn(['sites', parentBookmarkFolderKey])
- const items = siteUtil.filterSitesRelativeTo(allBookmarkItems, parentBookmarkFolder)
+ const items = bookmarksState.getBookmarksWithFolders(appState, parentBookmarkFolderKey)
if (items.size === 0) {
return [{
l10nLabelId: 'emptyFolderItem',
@@ -417,8 +424,11 @@ const showBookmarkFolderInit = (state, parentBookmarkFolderKey) => {
e.preventDefault()
const bookmark = dnd.prepareBookmarkDataFromCompatible(e.dataTransfer)
if (bookmark) {
- const bookmarkSiteKey = siteUtil.getSiteKey(bookmark)
- appActions.moveSite(bookmarkSiteKey, parentBookmarkFolderKey, false, true)
+ if (bookmark.get('type') === siteTags.BOOKMARK_FOLDER) {
+ appActions.moveBookmarkFolder(bookmark.get('key'), parentBookmarkFolderKey, false, true)
+ } else {
+ appActions.moveBookmark(bookmark.get('key'), parentBookmarkFolderKey, false, true)
+ }
}
}
}]
@@ -433,7 +443,7 @@ const bookmarkItemsInit = (state, items) => {
for (let item of items) {
const site = item[1]
const siteKey = item[0]
- const isFolder = siteUtil.isFolder(site)
+ const isFolder = bookmarkFoldersUtil.isFolder(site)
let faIcon
if (showFavicon && !site.get('favicon')) {
faIcon = isFolder ? 'fa-folder-o' : 'fa-file-o'
@@ -441,11 +451,11 @@ const bookmarkItemsInit = (state, items) => {
const templateItem = {
bookmark: site,
draggable: true,
- label: site.get('customTitle', site.get('title', site.get('location'))),
+ label: site.get('title', site.get('location')),
icon: showFavicon ? site.get('favicon') : undefined,
faIcon,
contextMenu: function () {
- windowActions.onSiteDetailMenu(siteKey)
+ windowActions.onSiteDetailMenu(siteKey, isFolder ? siteTags.BOOKMARK_FOLDER : siteTags.BOOKMARK)
},
dragEnd: function () {
dnd.onDragEnd()
@@ -453,8 +463,9 @@ const bookmarkItemsInit = (state, items) => {
dragStart: function (e) {
dnd.onDragStart(dragTypes.BOOKMARK, Immutable.fromJS({
location: site.get('location'),
- title: site.get('customTitle', site.get('title')),
- bookmarkKey: siteKey
+ title: site.get('title'),
+ key: siteKey,
+ type: isFolder ? siteTags.BOOKMARK_FOLDER : siteTags.BOOKMARK
}), e)
},
dragOver: function (e) {
@@ -465,11 +476,23 @@ const bookmarkItemsInit = (state, items) => {
e.preventDefault()
const bookmarkItem = dnd.prepareBookmarkDataFromCompatible(e.dataTransfer)
if (bookmarkItem) {
- appActions.moveSite(bookmarkItem.get('bookmarkKey'), siteKey, dndData.shouldPrependVerticalItem(e.target, e.clientY))
+ if (bookmarkItem.get('type') === siteTags.BOOKMARK_FOLDER) {
+ appActions.moveBookmarkFolder(
+ bookmarkItem.get('key'),
+ siteKey,
+ dndData.shouldPrependVerticalItem(e.target, e.clientY)
+ )
+ } else {
+ appActions.moveBookmark(
+ bookmarkItem.get('key'),
+ siteKey,
+ dndData.shouldPrependVerticalItem(e.target, e.clientY)
+ )
+ }
}
},
click: function (e) {
- bookmarkActions.clickBookmarkItem(siteKey, activeFrame.get('tabId'), e)
+ bookmarkActions.clickBookmarkItem(siteKey, activeFrame.get('tabId'), isFolder, e)
}
}
if (isFolder) {
@@ -485,14 +508,14 @@ const onMoreBookmarksMenu = (state, action) => {
action = validateAction(action)
state = validateState(state)
- const sites = appStoreRenderer.state.get('sites')
- let newSites = {}
+ const appState = appStoreRenderer.state
+ let newSites = Immutable.OrderedMap()
- for (let siteKey of action.get('bookmarks')) {
- newSites[siteKey] = sites.get(siteKey)
+ for (let key of action.get('bookmarks')) {
+ newSites.set(key, bookmarksState.findBookmark(appState, key))
}
- const menuTemplate = bookmarkItemsInit(state, Immutable.fromJS(newSites))
+ const menuTemplate = bookmarkItemsInit(state, newSites)
menuTemplate.push({
l10nLabelId: 'moreBookmarks',
@@ -651,7 +674,7 @@ const contextMenuReducer = (windowState, action) => {
windowState = onShowBookmarkFolderMenu(windowState, action)
break
case windowConstants.WINDOW_ON_SITE_DETAIL_MENU:
- windowState = onSiteDetailMenu(windowState, action.bookmarkKey)
+ windowState = onSiteDetailMenu(windowState, action.bookmarkKey, action.type)
break
}
return windowState
diff --git a/app/renderer/reducers/frameReducer.js b/app/renderer/reducers/frameReducer.js
index cfe38fcc3d6..a10fac339eb 100644
--- a/app/renderer/reducers/frameReducer.js
+++ b/app/renderer/reducers/frameReducer.js
@@ -10,7 +10,6 @@ const Immutable = require('immutable')
const appConstants = require('../../../js/constants/appConstants')
const windowConstants = require('../../../js/constants/windowConstants')
const config = require('../../../js/constants/config')
-const siteTags = require('../../../js/constants/siteTags')
// Actions
const appActions = require('../../../js/actions/appActions')
@@ -20,7 +19,7 @@ const frameStateUtil = require('../../../js/state/frameStateUtil')
const {getCurrentWindowId} = require('../currentWindow')
const {getSourceAboutUrl, getSourceMagnetUrl} = require('../../../js/lib/appUrlUtil')
const {isURL, isPotentialPhishingUrl, getUrlFromInput} = require('../../../js/lib/urlutil')
-const siteUtil = require('../../../js/state/siteUtil')
+const bookmarkUtil = require('../../common/lib/bookmarkUtil')
const setFullScreen = (state, action) => {
const index = frameStateUtil.getIndexByTabId(state, action.tabId)
@@ -229,8 +228,8 @@ const frameReducer = (state, action, immutableAction) => {
// TODO make this an appAction that gets the bookmark data from tabState
const frameProps = frameStateUtil.getFrameByTabId(state, action.tabId)
if (frameProps) {
- const bookmark = siteUtil.getDetailFromFrame(frameProps, siteTags.BOOKMARK)
- appActions.addSite(bookmark, siteTags.BOOKMARK)
+ const bookmark = bookmarkUtil.getDetailFromFrame(frameProps)
+ appActions.addBookmark(bookmark)
}
break
}
diff --git a/app/sessionStore.js b/app/sessionStore.js
index 852fbc3cb33..f45e7b19b22 100644
--- a/app/sessionStore.js
+++ b/app/sessionStore.js
@@ -17,39 +17,32 @@ const path = require('path')
const electron = require('electron')
const os = require('os')
const app = electron.app
-const locale = require('./locale')
+
+// Constants
const UpdateStatus = require('../js/constants/updateStatus')
const settings = require('../js/constants/settings')
+const siteTags = require('../js/constants/siteTags')
const downloadStates = require('../js/constants/downloadStates')
+
+// State
+const tabState = require('./common/state/tabState')
+const windowState = require('./common/state/windowState')
+
+// Utils
+const locale = require('./locale')
const siteUtil = require('../js/state/siteUtil')
-const { topSites, pinnedTopSites } = require('../js/data/newTabData')
-const { defaultSiteSettingsList } = require('../js/data/siteSettingsList')
-const sessionStorageVersion = 1
+const {pinnedTopSites} = require('../js/data/newTabData')
+const {defaultSiteSettingsList} = require('../js/data/siteSettingsList')
const filtering = require('./filtering')
const autofill = require('./autofill')
const {navigatableTypes} = require('../js/lib/appUrlUtil')
const Channel = require('./channel')
-const { makeImmutable } = require('./common/state/immutableUtil')
-const tabState = require('./common/state/tabState')
-const windowState = require('./common/state/windowState')
-
+const {makeImmutable} = require('./common/state/immutableUtil')
+const {getSetting} = require('../js/settings')
const platformUtil = require('./common/lib/platformUtil')
-const getSetting = require('../js/settings').getSetting
-const sessionStorageName = `session-store-${sessionStorageVersion}`
-const getTopSiteMap = () => {
- if (Array.isArray(topSites) && topSites.length) {
- let siteMap = {}
- let order = 0
- topSites.forEach((site) => {
- let key = siteUtil.getSiteKey(Immutable.fromJS(site))
- site.order = order++
- siteMap[key] = site
- })
- return siteMap
- }
- return {}
-}
+const sessionStorageVersion = 1
+const sessionStorageName = `session-store-${sessionStorageVersion}`
const getTempStoragePath = (filename) => {
const epochTimestamp = (new Date()).getTime().toString()
@@ -329,7 +322,7 @@ module.exports.cleanAppData = (data, isShutdown) => {
if (data.sites) {
const clearHistory = isShutdown && getSetting(settings.SHUTDOWN_CLEAR_HISTORY) === true
if (clearHistory) {
- data.sites = siteUtil.clearHistory(Immutable.fromJS(data.sites)).toJS()
+ data.historySites = {}
if (data.about) {
delete data.about.history
delete data.about.newtab
@@ -498,6 +491,115 @@ module.exports.runPreMigrations = (data) => {
}
}
+ // TODO remove this second level additional checks
+ if (data.sites) {
+ // pinned sites
+ if (!data.pinnedSites) {
+ data.pinnedSites = {}
+ for (let key of Object.keys(data.sites)) {
+ const site = data.sites[key]
+ if (site.tags && site.tags.includes('pinned')) {
+ delete site.tags
+ data.pinnedSites[key] = site
+ }
+ }
+ }
+
+ // default sites
+ let newTab = data.about.newtab
+
+ // TODO remove this pinnedSites check
+ if (newTab && !data.pinnedSites) {
+ const ignoredSites = []
+ const pinnedSites = []
+
+ if (newTab.ignoredTopSites) {
+ for (let site of newTab.ignoredTopSites) {
+ if (site) {
+ ignoredSites.push(`${site.location}|0|0`)
+ }
+ }
+ data.about.newtab.ignoredTopSites = ignoredSites
+ }
+
+ if (newTab.pinnedTopSites) {
+ for (let site of newTab.pinnedTopSites) {
+ if (site) {
+ site.key = `${site.location}|0|0`
+ pinnedSites.push(site)
+ }
+ }
+ data.about.newtab.pinnedTopSites = pinnedSites
+ }
+
+ data.about.newtab.sites = []
+ }
+
+ // bookmark folders
+ if (!data.bookmarkFolders) {
+ data.bookmarkFolders = {}
+
+ for (let key of Object.keys(data.sites)) {
+ const folder = data.sites[key]
+ if (folder.tags && folder.tags.includes(siteTags.BOOKMARK_FOLDER)) {
+ delete folder.tags
+
+ if (folder.customTitle) {
+ folder.title = folder.customTitle
+ delete folder.customTitle
+ }
+
+ if (folder.parentFolderId == null) {
+ folder.parentFolderId = 0
+ }
+
+ folder.type = siteTags.BOOKMARK_FOLDER
+ data.bookmarkFolders['' + key + ''] = folder
+ }
+ }
+ }
+
+ // bookmarks
+ if (!data.bookmarks) {
+ data.bookmarks = {}
+
+ for (let key of Object.keys(data.sites)) {
+ const bookmark = data.sites[key]
+ if (bookmark.tags && bookmark.tags.includes(siteTags.BOOKMARK)) {
+ delete bookmark.tags
+
+ if (bookmark.customTitle) {
+ bookmark.title = bookmark.customTitle
+ delete bookmark.customTitle
+ }
+
+ if (bookmark.parentFolderId == null) {
+ bookmark.parentFolderId = 0
+ }
+
+ bookmark.type = siteTags.BOOKMARK
+ data.bookmarks[key] = bookmark
+ }
+ }
+ }
+ // TODO sort newly added bookmarks and folders, add bookmarkOrderCache
+
+ // history
+ if (!data.historySites) {
+ data.historySites = {}
+
+ for (let key of Object.keys(data.sites)) {
+ const site = data.sites[key]
+ if (site.lastAccessedTime || !site.tags || site.tags.length === 0) {
+ data.historySites[key] = site
+ }
+ }
+ }
+
+ // TODO enable this delete when everything is done
+ // delete data.sites
+ }
+
return data
}
@@ -634,7 +736,12 @@ module.exports.defaultAppState = () => {
lastConfirmedRecordTimestamp: 0
},
locationSiteKeysCache: undefined,
- sites: getTopSiteMap(),
+ sites: {},
+ pinnedSites: {},
+ bookmarks: {},
+ bookmarkFolders: {},
+ bookmarkOrderCache: {},
+ historySites: {},
tabs: [],
windows: [],
extensions: {},
@@ -658,7 +765,7 @@ module.exports.defaultAppState = () => {
about: {
newtab: {
gridLayoutSize: 'small',
- sites: topSites,
+ sites: [],
ignoredTopSites: [],
pinnedTopSites: pinnedTopSites
},
diff --git a/app/sync.js b/app/sync.js
index 05122a0fc51..f5ebcc05c78 100644
--- a/app/sync.js
+++ b/app/sync.js
@@ -19,13 +19,14 @@ const appActions = require('../js/actions/appActions')
const syncConstants = require('../js/constants/syncConstants')
const appDispatcher = require('../js/dispatcher/appDispatcher')
const AppStore = require('../js/stores/appStore')
-const siteUtil = require('../js/state/siteUtil')
const syncUtil = require('../js/state/syncUtil')
const syncPendState = require('./common/state/syncPendState')
const getSetting = require('../js/settings').getSetting
const settings = require('../js/constants/settings')
const extensions = require('./extensions')
const {unescapeJSONPointer} = require('./common/lib/jsonUtil')
+const bookmarkFoldersState = require('./common/state/bookmarkFoldersState')
+const bookmarksState = require('./common/state/bookmarksState')
const CATEGORY_MAP = syncUtil.CATEGORY_MAP
const CATEGORY_NAMES = Object.keys(categories)
@@ -33,7 +34,7 @@ const SYNC_ACTIONS = Object.values(syncConstants)
// Fields that should trigger a sync SEND when changed
const SYNC_FIELDS = {
- sites: ['location', 'customTitle', 'folderId', 'parentFolderId', 'tags'],
+ sites: ['location', 'title', 'folderId', 'parentFolderId', 'tags'],
siteSettings: Object.keys(syncUtil.siteSettingDefaults)
}
@@ -260,7 +261,8 @@ module.exports.onSyncReady = (isFirstRun, e) => {
sendSyncRecords(e.sender, writeActions.CREATE, [deviceRecord])
deviceIdSent = true
}
- const sites = appState.get('sites') || new Immutable.List()
+ const bookmarks = bookmarksState.getBookmarks(appState)
+ const bookmarkFolders = bookmarkFoldersState.getFolders(appState)
const seed = appState.get('seed') || new Immutable.List()
/**
@@ -273,38 +275,34 @@ module.exports.onSyncReady = (isFirstRun, e) => {
*/
const folderToObjectId = {}
const bookmarksToSync = []
- const shouldSyncBookmark = (site) => {
- if (!site) {
- return false
- }
- if (siteUtil.isSiteBookmarked(sites, site) !== true && siteUtil.isFolder(site) !== true) {
- return false
- }
+
+ const shouldSyncBookmark = (bookmark) => {
// originalSeed is set on reset to prevent synced bookmarks on a device
// from being re-synced.
- const originalSeed = site.get('originalSeed')
- if (site.get('objectId') && (!originalSeed || seed.equals(originalSeed))) {
+ const originalSeed = bookmark.get('originalSeed')
+ if (bookmark.get('objectId') && (!originalSeed || seed.equals(originalSeed))) {
return false
}
- if (folderToObjectId[site.get('folderId')]) { return false }
- return syncUtil.isSyncable('bookmark', site)
+
+ return !folderToObjectId[bookmark.get('folderId')]
}
- const syncBookmark = (site) => {
- const siteJS = site.toJS()
- const parentFolderId = site.get('parentFolderId')
+ const syncBookmark = (bookmark) => {
+ const bookmarkJS = bookmark.toJS()
+
+ const parentFolderId = bookmark.get('parentFolderId')
if (typeof parentFolderId === 'number') {
if (!folderToObjectId[parentFolderId]) {
- const folderResult = siteUtil.getFolder(sites, parentFolderId)
+ const folderResult = bookmarkFolders.get(parentFolderId)
if (folderResult) {
syncBookmark(folderResult[1])
}
}
- siteJS.parentFolderObjectId = folderToObjectId[parentFolderId]
+ bookmarkJS.parentFolderObjectId = folderToObjectId[parentFolderId]
}
- const record = syncUtil.createSiteData(siteJS, appState)
- const folderId = site.get('folderId')
+ const record = syncUtil.createSiteData(bookmarkJS, appState)
+ const folderId = bookmark.get('folderId')
if (typeof folderId === 'number') {
folderToObjectId[folderId] = record.objectId
}
@@ -313,12 +311,16 @@ module.exports.onSyncReady = (isFirstRun, e) => {
}
// Sync bookmarks that have not been synced yet.
- sites.forEach((site) => {
- if (shouldSyncBookmark(site) !== true) {
+ bookmarks.forEach((bookmark) => {
+ if (shouldSyncBookmark(bookmark) !== true) {
return
}
- syncBookmark(site)
+
+ syncBookmark(bookmark)
})
+
+ // TODO add bookamrkFolder sync as well
+
sendSyncRecords(e.sender, writeActions.CREATE, bookmarksToSync)
// Sync site settings that have not been synced yet
@@ -490,7 +492,7 @@ module.exports.init = function (appState) {
}
if (!bookmarksToolbarShown && isFirstRun) {
// syncing for the first time
- const bookmarks = siteUtil.getBookmarks(AppStore.getState().get('sites'))
+ const bookmarks = bookmarksState.getBookmarks(AppStore.getState())
if (!bookmarks.size) {
for (const record of records) {
if (record && record.objectData === 'bookmark') {
diff --git a/docs/state.md b/docs/state.md
index cf2a9e3bd44..7c77232c4ac 100644
--- a/docs/state.md
+++ b/docs/state.md
@@ -53,6 +53,28 @@ AppStore
timestamp: number
}
},
+ bookmarks: {
+ [bookmarkKey]: {
+ favicon: string, // URL of the favicon
+ location: string,
+ objectId: Array.,
+ originalSeed: Array., // bookmarks that have been synced before a sync profile reset
+ parentFolderId: number,
+ partitionNumber: number, // optionally specifies a specific session
+ skipSync: boolean,
+ title: string
+ }
+ },
+ bookmarkFolders: {
+ [folderKey]: {
+ folderId: number,
+ objectId: Array.,
+ originalSeed: Array., // only set for bookmarks that have been synced before a sync profile reset
+ parentFolderId: number, // set for bookmarks and bookmark folders only
+ skipSync: boolean, // Set for objects FETCHed by sync
+ title: string
+ }
+ },
clearBrowsingDataDefaults: {
allSiteCookies: boolean,
autocompleteData: boolean,
@@ -118,6 +140,18 @@ AppStore
flash: {
enabled: boolean // enable flash
},
+ historySites: {
+ [siteKey]: {
+ favicon: string, // URL of the favicon
+ lastAccessedTime: number, // datetime.getTime()
+ location: string,
+ objectId: Array.,
+ partitionNumber: number, // optionally specifies a specific session
+ skipSync: boolean, // Set for objects FETCHed by sync
+ title: string,
+ themeColor: string
+ }
+ },
menu: {
template: object // used on Windows and by our tests: template object with Menubar control
},
@@ -156,6 +190,13 @@ AppStore
origin: string, // origin of the form
username: string
}],
+ pinnedSites: {
+ [siteKey]: {
+ location: string,
+ title: string,
+ order: number
+ }
+ },
settings: {
// See defaults in js/constants/appConfig.js
'adblock.customRules': string, // custom rules in ABP filter syntax
@@ -230,24 +271,6 @@ AppStore
'tabs.switch-to-new-tabs': boolean, // true if newly opened tabs should be focused immediately
'tabs.tabs-per-page': number // number of tabs per tab page
},
- sites: {
- [siteKey]: {
- creationTime: number, //creation time of bookmark
- customTitle: string, // User provided title for bookmark; overrides title
- favicon: string, // URL of the favicon
- folderId: number, // set for bookmark folders only
- lastAccessedTime: number, // datetime.getTime()
- location: string,
- objectId: Array.,
- originalSeed: Array., // only set for bookmarks that have been synced before a sync profile reset
- parentFolderId: number, // set for bookmarks and bookmark folders only
- partitionNumber: number, // optionally specifies a specific session
- skipSync: boolean, // Set for objects FETCHed by sync
- tags: [string], // empty, 'bookmark', 'bookmark-folder', 'default', or 'reader'
- themeColor: string, // CSS compatible color string
- title: string
- } // folder: folderId; bookmark/history: location + partitionNumber + parentFolderId
- },
locationSiteKeyCache: {
[location]: Array. // location -> site keys
},
diff --git a/js/about/aboutActions.js b/js/about/aboutActions.js
index 1992015338f..f231492ae89 100644
--- a/js/about/aboutActions.js
+++ b/js/about/aboutActions.js
@@ -192,16 +192,6 @@ const aboutActions = {
ipc.sendToHost(messages.CONTEXT_MENU_OPENED, nodeProps, contextMenuType)
},
- moveSite: function (sourceKey, destinationKey, prepend, destinationIsParent) {
- aboutActions.dispatchAction({
- actionType: appConstants.APP_MOVE_SITE,
- sourceKey,
- destinationKey,
- prepend,
- destinationIsParent
- })
- },
-
downloadRevealed: function (downloadId) {
aboutActions.dispatchAction({
actionType: appConstants.APP_DOWNLOAD_REVEALED,
diff --git a/js/about/newtab.js b/js/about/newtab.js
index e9a2b83010b..ab8cb493904 100644
--- a/js/about/newtab.js
+++ b/js/about/newtab.js
@@ -5,26 +5,35 @@
const path = require('path')
const React = require('react')
const Immutable = require('immutable')
-const messages = require('../constants/messages')
-const HTML5Backend = require('react-dnd-html5-backend')
const {DragDropContext} = require('react-dnd')
+const HTML5Backend = require('react-dnd-html5-backend')
+
+// Components
const Stats = require('./newTabComponents/stats')
const Clock = require('./newTabComponents/clock')
const Block = require('./newTabComponents/block')
const SiteRemovalNotification = require('./newTabComponents/siteRemovalNotification')
const FooterInfo = require('./newTabComponents/footerInfo')
-const aboutActions = require('./aboutActions')
-const siteUtil = require('../state/siteUtil')
-const urlutils = require('../lib/urlutil')
-const siteTags = require('../constants/siteTags')
-const config = require('../constants/config')
-const backgrounds = require('../data/backgrounds')
-const {random} = require('../../app/common/lib/randomUtil')
const NewPrivateTab = require('./newprivatetab')
+
+// Constants
+const messages = require('../constants/messages')
+const config = require('../constants/config')
+
+// Actions
+const aboutActions = require('./aboutActions')
const windowActions = require('../actions/windowActions')
+// Data
+const backgrounds = require('../data/backgrounds')
+const newTabData = require('../data/newTabData')
+
+// Utils
+const urlutils = require('../lib/urlutil')
+const {random} = require('../../app/common/lib/randomUtil')
const ipc = window.chrome.ipcRenderer
+// Styles
require('../../less/about/newtab.less')
require('../../node_modules/font-awesome/css/font-awesome.css')
@@ -32,15 +41,17 @@ class NewTabPage extends React.Component {
constructor (props) {
super(props)
this.state = {
- showSiteRemovalNotification: false,
+ showNotification: false,
imageLoadFailed: false,
updatedStamp: undefined,
showEmptyPage: true,
showImages: false,
backgroundImage: undefined
}
- ipc.on(messages.NEWTAB_DATA_UPDATED, (e, newTabData) => {
- const data = Immutable.fromJS(newTabData || {})
+ this.staticData = Immutable.fromJS(newTabData.topSites)
+
+ ipc.on(messages.NEWTAB_DATA_UPDATED, (e, newData) => {
+ let data = Immutable.fromJS(newData || {})
const updatedStamp = data.getIn(['newTabDetail', 'updatedStamp'])
// Only update if the data has changed.
@@ -50,6 +61,18 @@ class NewTabPage extends React.Component {
return
}
+ const topSites = data.getIn(['newTabDetail', 'sites'], Immutable.List())
+ if (topSites.size < 18) {
+ const pinned = data.getIn(['newTabDetail', 'pinnedTopSites'], Immutable.List())
+ const ignored = data.getIn(['newTabDetail', 'ignoredTopSites'], Immutable.List())
+ const preDefined = this.staticData
+ .filter((site) => {
+ const key = site.get('key')
+ return !pinned.find(site => site.get('key') === key) && !ignored.includes(key)
+ })
+ data = data.setIn(['newTabDetail', 'sites'], topSites.concat(preDefined))
+ }
+
const showEmptyPage = !!data.get('showEmptyPage')
const showImages = !!data.get('showImages') && !showEmptyPage
this.setState({
@@ -63,83 +86,79 @@ class NewTabPage extends React.Component {
})
})
}
+
get showImages () {
return this.state.showImages && !!this.state.backgroundImage
}
+
get randomBackgroundImage () {
const image = Object.assign({}, backgrounds[Math.floor(random() * backgrounds.length)])
image.style = {backgroundImage: 'url(' + image.source + ')'}
return image
}
+
get fallbackImage () {
const image = Object.assign({}, config.newtab.fallbackImage)
const pathToImage = path.join(__dirname, '..', '..', image.source)
image.style = {backgroundImage: 'url(' + `${pathToImage}` + ')'}
return image
}
+
get topSites () {
- return this.state.newTabData.getIn(['newTabDetail', 'sites']) || Immutable.List()
+ return this.state.newTabData.getIn(['newTabDetail', 'sites'])
}
+
get pinnedTopSites () {
- return (this.state.newTabData.getIn(['newTabDetail', 'pinnedTopSites']) || Immutable.List()).setSize(18)
+ return this.state.newTabData.getIn(['newTabDetail', 'pinnedTopSites'], Immutable.List())
}
+
get ignoredTopSites () {
- return this.state.newTabData.getIn(['newTabDetail', 'ignoredTopSites']) || Immutable.List()
+ return this.state.newTabData.getIn(['newTabDetail', 'ignoredTopSites'], Immutable.List())
}
+
get gridLayoutSize () {
- return this.state.newTabData.getIn(['newTabDetail', 'gridLayoutSize']) || 'small'
+ return this.state.newTabData.getIn(['newTabDetail', 'gridLayoutSize'], 'small')
}
- isPinned (siteProps) {
- return this.pinnedTopSites.filter((site) => {
- if (!site || !site.get) return false
- return site.get('location') === siteProps.get('location') &&
- site.get('partitionNumber') === siteProps.get('partitionNumber')
- }).size > 0
+
+ isPinned (siteKey) {
+ return this.pinnedTopSites.find(site => site.get('key') === siteKey)
}
- isBookmarked (siteProps) {
- return siteUtil.isBookmark(siteProps)
+
+ isBookmarked (siteKey) {
+ // TODO add bookmark status to site that are send here
+ return false // siteUtil.isBookmark(null)
}
+
get gridLayout () {
const sizeToCount = {large: 18, medium: 12, small: 6}
const count = sizeToCount[this.gridLayoutSize]
- return this.topSites.take(count)
+
+ let sites = this.pinnedTopSites.take(count)
+
+ if (sites.size < count) {
+ sites = sites.concat(this.topSites.take(count - sites.size))
+ }
+
+ return sites
}
- showSiteRemovalNotification () {
+
+ showNotification () {
this.setState({
- showSiteRemovalNotification: true
+ showNotification: true
})
}
+
hideSiteRemovalNotification () {
this.setState({
- showSiteRemovalNotification: false
+ showNotification: false
})
}
- /**
- * save number of rows on store. gridsLayout starts with 3 rows (large).
- * Rows are reduced at each click and then reset to three again
- */
- onChangeGridLayout () {
- const gridLayoutSize = this.gridLayoutSize
- const changeGridSizeTo = (size) => aboutActions.setNewTabDetail({gridLayoutSize: size})
-
- if (gridLayoutSize === 'large') {
- changeGridSizeTo('medium')
- } else if (gridLayoutSize === 'medium') {
- changeGridSizeTo('small')
- } else if (gridLayoutSize === 'small') {
- changeGridSizeTo('large')
- } else {
- changeGridSizeTo('large')
- }
-
- return gridLayoutSize
- }
-
- onDraggedSite (currentId, finalId) {
+ // TODO fix this function
+ onDraggedSite (siteKey, destinationKey) {
let gridSites = this.topSites
- const currentPosition = gridSites.filter((site) => site.get('location') === currentId).get(0)
- const finalPosition = gridSites.filter((site) => site.get('location') === finalId).get(0)
+ const currentPosition = gridSites.get(siteKey)
+ const finalPosition = gridSites.get(destinationKey)
const currentPositionIndex = gridSites.indexOf(currentPosition)
const finalPositionIndex = gridSites.indexOf(finalPosition)
@@ -154,63 +173,59 @@ class NewTabPage extends React.Component {
pinnedTopSites = pinnedTopSites.splice(finalPositionIndex, 0, currentPosition)
// If site is pinned, update pinnedTopSites list
- const newTabState = {}
+ const newTabState = Immutable.Map()
if (this.isPinned(currentPosition)) {
- newTabState.pinnedTopSites = pinnedTopSites
+ newTabState.set('pinnedTopSites', pinnedTopSites)
}
- newTabState.sites = gridSites
+ newTabState.set('sites', gridSites)
// Only update if there was an actual change
- const stateDiff = Immutable.fromJS(newTabState)
const existingState = this.state.newTabData || Immutable.fromJS({})
- const proposedState = existingState.mergeIn(['newTabDetail'], stateDiff)
+ const proposedState = existingState.mergeIn(['newTabDetail'], newTabState)
if (!proposedState.isSubset(existingState)) {
- aboutActions.setNewTabDetail(stateDiff)
+ aboutActions.setNewTabDetail(newTabState)
}
}
- onToggleBookmark (siteProps) {
- const siteDetail = siteUtil.getDetailFromFrame(siteProps, siteTags.BOOKMARK)
- const editing = this.isBookmarked(siteProps)
- const key = siteUtil.getSiteKey(siteDetail)
+ onToggleBookmark (site) {
+ const editing = this.isBookmarked(site.get('key'))
if (editing) {
- windowActions.editBookmark(false, key)
+ windowActions.editBookmark(false, site.get('key'))
} else {
- windowActions.onBookmarkAdded(false, key)
+ windowActions.onBookmarkAdded(false, site)
}
}
- onPinnedTopSite (siteProps) {
- const currentPosition = this.topSites.filter((site) => siteProps.get('location') === site.get('location')).get(0)
- const currentPositionIndex = this.topSites.indexOf(currentPosition)
+ onPinnedTopSite (siteKey) {
+ let pinnedTopSites = this.pinnedTopSites
+ const siteProps = this.topSites.find(site => site.get('key') === siteKey)
- // If pinned, leave it null. Otherwise stores site on ignoredTopSites list, retaining the same position
- let pinnedTopSites = this.pinnedTopSites.splice(currentPositionIndex, 1, this.isPinned(siteProps) ? null : siteProps)
+ if (this.isPinned(siteKey)) {
+ pinnedTopSites = pinnedTopSites.filter(site => site.get('key') !== siteKey)
+ } else {
+ pinnedTopSites = pinnedTopSites.push(siteProps)
+ }
aboutActions.setNewTabDetail({pinnedTopSites: pinnedTopSites})
}
- onIgnoredTopSite (siteProps) {
- this.showSiteRemovalNotification()
+ onIgnoredTopSite (siteKey) {
+ this.showNotification(siteKey)
// If a pinnedTopSite is ignored, remove it from the pinned list as well
const newTabState = {}
- if (this.isPinned(siteProps)) {
- const gridSites = this.topSites
- const currentPosition = gridSites.filter((site) => siteProps.get('location') === site.get('location')).get(0)
- const currentPositionIndex = gridSites.indexOf(currentPosition)
- const pinnedTopSites = this.pinnedTopSites.splice(currentPositionIndex, 1, null)
- newTabState.pinnedTopSites = pinnedTopSites
+ if (this.isPinned(siteKey)) {
+ newTabState.pinnedTopSites = this.pinnedTopSites.filter(site => site.get('key') !== siteKey)
}
- newTabState.ignoredTopSites = this.ignoredTopSites.push(siteProps)
+ newTabState.ignoredTopSites = this.ignoredTopSites.push(siteKey)
aboutActions.setNewTabDetail(newTabState, true)
}
onUndoIgnoredTopSite () {
// Remove last List's entry
- const ignoredTopSites = this.ignoredTopSites.splice(-1, 1)
+ const ignoredTopSites = this.ignoredTopSites.pop()
aboutActions.setNewTabDetail({ignoredTopSites: ignoredTopSites}, true)
this.hideSiteRemovalNotification()
}
@@ -236,6 +251,12 @@ class NewTabPage extends React.Component {
})
}
+ getLetterFromUrl (url) {
+ const hostname = urlutils.getHostname(url.get('location'), true)
+ const name = url.get('title') || hostname || '?'
+ return name.charAt(0).toUpperCase()
+ }
+
render () {
// don't render if user prefers an empty page
if (this.state.showEmptyPage && !this.props.isIncognito) {
@@ -250,11 +271,6 @@ class NewTabPage extends React.Component {
if (!this.state.newTabData) {
return null
}
- const getLetterFromUrl = (url) => {
- const hostname = urlutils.getHostname(url.get('location'), true)
- const name = url.get('title') || hostname || '?'
- return name.charAt(0).toUpperCase()
- }
const gridLayout = this.gridLayout
const backgroundProps = {}
let gradientClassName = 'gradient'
@@ -278,24 +294,24 @@ class NewTabPage extends React.Component {
{
- this.state.showSiteRemovalNotification
+ this.state.showNotification
? } records
- */
- applySiteRecords: function (records) {
- dispatch({
- actionType: appConstants.APP_APPLY_SITE_RECORDS,
- records
- })
- },
-
/**
* Dispatch to populate the sync object id -> appState key path mapping cache
*/
@@ -1472,24 +1444,72 @@ const appActions = {
})
},
- addBookmark: function (siteDetail, tag, closestKey) {
+ addBookmark: function (siteDetail, closestKey) {
dispatch({
actionType: appConstants.APP_ADD_BOOKMARK,
siteDetail,
- tag,
closestKey
})
},
- editBookmark: function (siteDetail, editKey, tag) {
+ editBookmark: function (siteDetail, editKey) {
dispatch({
actionType: appConstants.APP_EDIT_BOOKMARK,
siteDetail,
- tag,
editKey
})
},
+ moveBookmark: function (bookmarkKey, destinationKey, append, moveIntoParent) {
+ dispatch({
+ actionType: appConstants.APP_MOVE_BOOKMARK,
+ bookmarkKey,
+ destinationKey,
+ append,
+ moveIntoParent
+ })
+ },
+
+ removeBookmark: function (bookmarkKey) {
+ dispatch({
+ actionType: appConstants.APP_REMOVE_BOOKMARK,
+ bookmarkKey
+ })
+ },
+
+ addBookmarkFolder: function (folderDetails, closestKey) {
+ dispatch({
+ actionType: appConstants.APP_ADD_BOOKMARK_FOLDER,
+ folderDetails,
+ closestKey
+ })
+ },
+
+ editBookmarkFolder: function (folderDetails, editKey) {
+ dispatch({
+ actionType: appConstants.APP_EDIT_BOOKMARK_FOLDER,
+ folderDetails,
+ editKey
+ })
+ },
+
+ moveBookmarkFolder: function (folderKey, destinationKey, append, moveIntoParent) {
+ dispatch({
+ actionType: appConstants.APP_MOVE_BOOKMARK_FOLDER,
+ folderKey,
+ destinationKey,
+ append,
+ moveIntoParent
+ })
+ },
+
+ removeBookmarkFolder: function (folderKey) {
+ dispatch({
+ actionType: appConstants.APP_REMOVE_BOOKMARK_FOLDER,
+ folderKey
+ })
+ },
+
noReportStateModeClicked: function (windowId) {
dispatch({
actionType: appConstants.APP_DEBUG_NO_REPORT_STATE_MODE_CLICKED,
@@ -1529,6 +1549,15 @@ const appActions = {
name,
version
})
+ },
+
+ onPinnedTabReorder: function (siteKey, destinationKey, prepend) {
+ dispatch({
+ actionType: appConstants.APP_ON_PINNED_TAB_REORDER,
+ siteKey,
+ destinationKey,
+ prepend
+ })
}
}
diff --git a/js/actions/bookmarkActions.js b/js/actions/bookmarkActions.js
index 51152a2f38b..583fb158180 100644
--- a/js/actions/bookmarkActions.js
+++ b/js/actions/bookmarkActions.js
@@ -4,33 +4,31 @@
'use strict'
-const Immutable = require('immutable')
-const siteUtil = require('../state/siteUtil')
const appActions = require('./appActions')
const windowActions = require('./windowActions')
const eventUtil = require('../lib/eventUtil')
const appStoreRenderer = require('../stores/appStoreRenderer')
+const bookmarksUtil = require('../../app/common/lib/bookmarkUtil')
+const bookmarksState = require('../../app/common/state/bookmarksState')
+const bookmarkFoldersSate = require('../../app/common/state/bookmarkFoldersState')
const {SWITCH_TO_NEW_TABS} = require('../constants/settings')
-const getSetting = require('../settings').getSetting
+const {getSetting} = require('../settings')
const bookmarkActions = {
openBookmarksInFolder: function (folderDetail) {
- const allBookmarkItems = siteUtil.getBookmarks(appStoreRenderer.state.get('sites'))
- // We have a middle clicked folder
- const bookmarks = allBookmarkItems
- .filter((bookmark) => (bookmark.get('parentFolderId') || 0) === (folderDetail.get('folderId') || 0) && siteUtil.isBookmark(bookmark))
+ const bookmarks = bookmarksUtil.getBookmarksByParentId(appStoreRenderer.state, folderDetail.get('folderId'))
// Only load the first 25 tabs as loaded
bookmarks
.forEach((bookmark, i) => {
if (i <= 25) {
appActions.createTabRequested(
- Object.assign(siteUtil.toCreateProperties(bookmark), {
+ Object.assign(bookmarksUtil.toCreateProperties(bookmark), {
active: false
}), getSetting(SWITCH_TO_NEW_TABS))
} else {
appActions.createTabRequested({
- location: bookmark.get('location'),
+ url: bookmark.get('location'),
partitionNumber: bookmark.get('partitionNumber'),
discarded: true
}, false)
@@ -42,26 +40,30 @@ const bookmarkActions = {
* Performs an action based on the passed in event to the bookmark item
* @return true if an action was performed
*/
- clickBookmarkItem: function (bookmarkKey, tabId, e) {
- const bookmarkItem = appStoreRenderer.state.getIn(['sites', bookmarkKey], Immutable.Map())
- const isFolder = siteUtil.isFolder(bookmarkItem)
+ clickBookmarkItem: function (key, tabId, isFolder, e) {
+ const isSecondary = eventUtil.isForSecondaryAction(e)
+
if (!isFolder) {
- if (eventUtil.isForSecondaryAction(e)) {
+ const bookmarkItem = bookmarksState.getBookmark(appStoreRenderer.state, key)
+ if (isSecondary) {
appActions.createTabRequested({
url: bookmarkItem.get('location'),
- partitionNumber: (bookmarkItem && bookmarkItem.get && bookmarkItem.get('partitionNumber')) || undefined,
+ partitionNumber: bookmarkItem.get('partitionNumber') || undefined,
active: !!e.shiftKey || getSetting(SWITCH_TO_NEW_TABS)
})
} else {
appActions.loadURLRequested(tabId, bookmarkItem.get('location'))
}
+
windowActions.setContextMenuDetail()
return true
- } else if (eventUtil.isForSecondaryAction(e)) {
- this.openBookmarksInFolder(bookmarkItem)
+ } else if (isSecondary) {
+ const folderItem = bookmarkFoldersSate.getFolder(appStoreRenderer.state, key)
+ this.openBookmarksInFolder(folderItem)
windowActions.setContextMenuDetail()
return true
}
+
return false
}
}
diff --git a/js/actions/windowActions.js b/js/actions/windowActions.js
index 9f8c5f73149..0fc58cd6f0b 100644
--- a/js/actions/windowActions.js
+++ b/js/actions/windowActions.js
@@ -512,11 +512,16 @@ const windowActions = {
})
},
- onBookmarkAdded: function (isHanger, editKey, siteDetail) {
+ /**
+ * Used for adding bookmark site directly and then allowing to
+ * edit it right afterwords
+ * @param isHanger
+ * @param bookmarkDetail - bookmark data, if empty active frame will be used
+ */
+ onBookmarkAdded: function (isHanger, bookmarkDetail) {
dispatch({
actionType: windowConstants.WINDOW_ON_BOOKMARK_ADDED,
- siteDetail,
- editKey,
+ bookmarkDetail,
isHanger
})
},
@@ -530,6 +535,38 @@ const windowActions = {
})
},
+ /**
+ * Used for displaying bookmark folder dialog
+ * when adding bookmark site or folder
+ */
+ addBookmarkFolder: function (folderDetails, closestKey) {
+ dispatch({
+ actionType: windowConstants.WINDOW_ON_ADD_BOOKMARK_FOLDER,
+ folderDetails,
+ closestKey
+ })
+ },
+
+ /**
+ * Used for displaying bookmark folder dialog
+ * when editing bookmark site or folder
+ */
+ editBookmarkFolder: function (editKey) {
+ dispatch({
+ actionType: windowConstants.WINDOW_ON_EDIT_BOOKMARK_FOLDER,
+ editKey
+ })
+ },
+
+ /**
+ * Used for closing a bookmark dialog
+ */
+ onBookmarkFolderClose: function () {
+ dispatch({
+ actionType: windowConstants.WINDOW_ON_BOOKMARK_FOLDER_CLOSE
+ })
+ },
+
/**
* Dispatches a message to set context menu detail.
* If set, also indicates that the context menu is shown.
@@ -1202,10 +1239,11 @@ const windowActions = {
})
},
- onSiteDetailMenu: function (bookmarkKey) {
+ onSiteDetailMenu: function (bookmarkKey, type) {
dispatch({
actionType: windowConstants.WINDOW_ON_SITE_DETAIL_MENU,
- bookmarkKey
+ bookmarkKey,
+ type
})
}
}
diff --git a/js/constants/appConstants.js b/js/constants/appConstants.js
index f8e12793899..afd249ec9a5 100644
--- a/js/constants/appConstants.js
+++ b/js/constants/appConstants.js
@@ -13,11 +13,10 @@ const appConstants = {
APP_WINDOW_UPDATED: _,
APP_TAB_CLOSED: _,
APP_TAB_UPDATED: _,
- APP_ADD_SITE: _,
+ APP_ADD_HISTORY_SITE: _,
+ APP_ADD_HISTORY_SITES: _,
APP_SET_STATE: _,
- APP_REMOVE_SITE: _,
- APP_MOVE_SITE: _,
- APP_APPLY_SITE_RECORDS: _,
+ APP_REMOVE_HISTORY_SITE: _,
APP_MERGE_DOWNLOAD_DETAIL: _, // Sets an individual download detail
APP_CLEAR_COMPLETED_DOWNLOADS: _, // Removes all completed downloads
APP_DEFAULT_WINDOW_PARAMS_CHANGED: _,
@@ -144,7 +143,14 @@ const appConstants = {
APP_SPELLING_SUGGESTED: _,
APP_LEARN_SPELLING: _,
APP_FORGET_LEARNED_SPELLING: _,
- APP_SET_VERSION_INFO: _
+ APP_SET_VERSION_INFO: _,
+ APP_ON_PINNED_TAB_REORDER: _,
+ APP_ADD_BOOKMARK_FOLDER: _,
+ APP_EDIT_BOOKMARK_FOLDER: _,
+ APP_REMOVE_BOOKMARK_FOLDER: _,
+ APP_REMOVE_BOOKMARK: _,
+ APP_MOVE_BOOKMARK_FOLDER: _,
+ APP_MOVE_BOOKMARK: _
}
module.exports = mapValuesByKeys(appConstants)
diff --git a/js/constants/siteTags.js b/js/constants/siteTags.js
index 4a86ba2fa59..e4b1338131d 100644
--- a/js/constants/siteTags.js
+++ b/js/constants/siteTags.js
@@ -6,11 +6,9 @@ const mapValuesByKeys = require('../lib/functional').mapValuesByKeys
const _ = null
const siteTags = {
- DEFAULT: _,
BOOKMARK: _,
BOOKMARK_FOLDER: _,
- PINNED: _,
- READING_LIST: _
+ HISTORY: _
}
module.exports = mapValuesByKeys(siteTags)
diff --git a/js/constants/windowConstants.js b/js/constants/windowConstants.js
index 002f927062f..7186fbf9f51 100644
--- a/js/constants/windowConstants.js
+++ b/js/constants/windowConstants.js
@@ -111,7 +111,10 @@ const windowConstants = {
WINDOW_ON_ADD_BOOKMARK: _,
WINDOW_ON_EDIT_BOOKMARK: _,
WINDOW_ON_BOOKMARK_CLOSE: _,
- WINDOW_ON_BOOKMARK_ADDED: _
+ WINDOW_ON_BOOKMARK_ADDED: _,
+ WINDOW_ON_ADD_BOOKMARK_FOLDER: _,
+ WINDOW_ON_EDIT_BOOKMARK_FOLDER: _,
+ WINDOW_ON_BOOKMARK_FOLDER_CLOSE: _
}
module.exports = mapValuesByKeys(windowConstants)
diff --git a/js/contextMenus.js b/js/contextMenus.js
index 50079596af9..9d38cbb7cba 100644
--- a/js/contextMenus.js
+++ b/js/contextMenus.js
@@ -26,17 +26,21 @@ const locale = require('../js/l10n')
const {getSetting} = require('./settings')
const settings = require('./constants/settings')
const textUtils = require('./lib/text')
-const {getPartitionFromNumber, getActiveFrame} = require('./state/frameStateUtil')
const {isIntermediateAboutPage, isUrl, aboutUrls} = require('./lib/appUrlUtil')
const {getBase64FromImageUrl} = require('./lib/imageUtil')
const urlParse = require('../app/common/urlParse')
const {getCurrentWindow} = require('../app/renderer/currentWindow')
const extensionState = require('../app/common/state/extensionState')
const extensionActions = require('../app/common/actions/extensionActions')
+const bookmarkUtil = require('../app/common/lib/bookmarkUtil')
+const bookmarksState = require('../app/common/state/bookmarksState')
+const historyState = require('../app/common/state/historyState')
+const frameStateUtil = require('./state/frameStateUtil')
+const platformUtil = require('../app/common/lib/platformUtil')
const {makeImmutable} = require('../app/common/state/immutableUtil')
-const isDarwin = process.platform === 'darwin'
-const isLinux = process.platform === 'linux'
+const isDarwin = platformUtil.isDarwin()
+const isLinux = platformUtil.isLinux()
/**
* Obtains an add bookmark menu item
@@ -70,18 +74,18 @@ const addFolderMenuItem = (closestDestinationDetail, isParent) => {
return {
label: locale.translation('addFolder'),
click: () => {
- let siteDetail = Immutable.fromJS({ tags: [siteTags.BOOKMARK_FOLDER] })
let closestKey = null
+ let folderDetails = Immutable.Map()
if (closestDestinationDetail) {
closestKey = siteUtil.getSiteKey(closestDestinationDetail)
if (isParent) {
- siteDetail = siteDetail.set('parentFolderId', (closestDestinationDetail.get('folderId') || closestDestinationDetail.get('parentFolderId')))
+ folderDetails = folderDetails.set('parentFolderId', (closestDestinationDetail.get('folderId') || closestDestinationDetail.get('parentFolderId')))
}
}
- windowActions.addBookmark(siteDetail, closestKey)
+ windowActions.addBookmarkFolder(folderDetails, closestKey)
}
}
}
@@ -133,8 +137,7 @@ function tabsToolbarTemplateInit (bookmarkTitle, bookmarkLink, closestDestinatio
template.push(addBookmarkMenuItem('addBookmark', {
title: bookmarkTitle,
- location: bookmarkLink,
- tags: [siteTags.BOOKMARK]
+ location: bookmarkLink
}, closestDestinationDetail, isParent))
template.push(addFolderMenuItem(closestDestinationDetail, isParent))
@@ -225,58 +228,58 @@ function downloadsToolbarTemplateInit (downloadId, downloadItem) {
return menuUtil.sanitizeTemplateItems(template)
}
-function siteDetailTemplateInit (siteDetail, activeFrame) {
- let isHistoryEntry = false
- let multipleHistoryEntries = false
- let multipleBookmarks = false
- let isFolder = false
- let isSystemFolder = false
- let deleteLabel
- let deleteTag
-
- // TODO(bsclifton): pull this out to a method
- if (siteUtil.isBookmark(siteDetail) && activeFrame) {
- deleteLabel = 'deleteBookmark'
- deleteTag = siteTags.BOOKMARK
- } else if (siteUtil.isFolder(siteDetail)) {
- isFolder = true
- isSystemFolder = siteDetail.get('folderId') === 0 ||
- siteDetail.get('folderId') === -1
- deleteLabel = 'deleteFolder'
- deleteTag = siteTags.BOOKMARK_FOLDER
- } else if (siteUtil.isHistoryEntry(siteDetail)) {
- isHistoryEntry = true
- deleteLabel = 'deleteHistoryEntry'
+const getLabel = (siteDetail, activeFrame, type) => {
+ let label = ''
+
+ if (type === siteTags.BOOKMARK && activeFrame) {
+ label = 'deleteBookmark'
+ } else if (type === siteTags.BOOKMARK_FOLDER) {
+ label = 'deleteFolder'
+ } else if (type === siteTags.HISTORY) {
+ label = 'deleteHistoryEntry'
} else if (Immutable.List.isList(siteDetail)) {
// Multiple bookmarks OR history entries selected
- multipleHistoryEntries = true
- multipleBookmarks = true
- siteDetail.forEach((site) => {
- if (!siteUtil.isBookmark(site)) multipleBookmarks = false
- if (!siteUtil.isHistoryEntry(site)) multipleHistoryEntries = false
- })
- if (multipleBookmarks) {
- deleteLabel = 'deleteBookmarks'
- deleteTag = siteTags.BOOKMARK
- } else if (multipleHistoryEntries) {
- deleteLabel = 'deleteHistoryEntries'
- }
- } else {
- deleteLabel = ''
+ /* multipleHistoryEntries = true
+ multipleBookmarks = true
+ siteDetail.forEach((site) => {
+ if (!siteUtil.isBookmark(site)) multipleBookmarks = false
+ if (!siteUtil.isHistoryEntry(site)) multipleHistoryEntries = false
+ })
+ if (multipleBookmarks) {
+ label = 'deleteBookmarks'
+ deleteTag = siteTags.BOOKMARK
+ } else if (multipleHistoryEntries) {
+ label = 'deleteHistoryEntries'
+ } */
}
+ return label
+}
+
+// TODO check when we send in multiple siteKeys
+const siteDetailTemplateInit = (state, siteKey, type) => {
+ let isFolder = type === siteTags.BOOKMARK_FOLDER
+ let siteDetail = bookmarksState.findBookmark(appStoreRenderer.state, siteKey)
+ if (siteDetail.isEmpty()) {
+ siteDetail = historyState.getSite(state, siteKey)
+ }
+ let multiple = Immutable.List.isList(siteDetail)
+ const activeFrame = frameStateUtil.getActiveFrame(state) || Immutable.Map()
const template = []
+ const label = getLabel(siteDetail, activeFrame, type)
- if (!isFolder) {
- if (!Immutable.List.isList(siteDetail)) {
+ if (type !== siteTags.BOOKMARK_FOLDER) {
+ if (!multiple) {
const location = siteDetail.get('location')
- template.push(openInNewTabMenuItem(location, undefined, siteDetail.get('partitionNumber')),
+ template.push(
+ openInNewTabMenuItem(location, undefined, siteDetail.get('partitionNumber')),
openInNewPrivateTabMenuItem(location),
openInNewWindowMenuItem(location, undefined, siteDetail.get('partitionNumber')),
openInNewSessionTabMenuItem(location),
copyAddressMenuItem('copyLinkAddress', location),
- CommonMenu.separatorMenuItem)
+ CommonMenu.separatorMenuItem
+ )
} else {
let locations = []
let partitionNumbers = []
@@ -285,53 +288,64 @@ function siteDetailTemplateInit (siteDetail, activeFrame) {
partitionNumbers.push(site.get('partitionNumber'))
})
- template.push(openInNewTabMenuItem(locations, undefined, partitionNumbers),
+ template.push(
+ openInNewTabMenuItem(locations, undefined, partitionNumbers),
openInNewPrivateTabMenuItem(locations),
openInNewSessionTabMenuItem(locations),
- CommonMenu.separatorMenuItem)
+ CommonMenu.separatorMenuItem
+ )
}
} else {
- template.push(openAllInNewTabsMenuItem(appStoreRenderer.state.get('sites'), siteDetail),
- CommonMenu.separatorMenuItem)
+ template.push(openAllInNewTabsMenuItem(siteDetail), CommonMenu.separatorMenuItem)
}
- if (!isSystemFolder) {
+ if (siteDetail.get('folderId') !== 0 && siteDetail.get('folderId') !== -1) {
// Picking this menu item pops up the AddEditBookmark modal
// - History can be deleted but not edited
// - Multiple bookmarks cannot be edited at once
// - "Bookmarks Toolbar" and "Other Bookmarks" folders cannot be deleted
- if (!isHistoryEntry && !multipleHistoryEntries && !multipleBookmarks) {
+ if (type !== siteTags.HISTORY && !multiple) {
template.push(
{
label: locale.translation(isFolder ? 'editFolder' : 'editBookmark'),
click: () => {
const editKey = siteUtil.getSiteKey(siteDetail)
- windowActions.editBookmark(false, editKey)
+ if (isFolder) {
+ windowActions.editBookmarkFolder(editKey)
+ } else {
+ windowActions.editBookmark(editKey)
+ }
}
},
- CommonMenu.separatorMenuItem)
+ CommonMenu.separatorMenuItem
+ )
}
template.push(
{
- label: locale.translation(deleteLabel),
+ label: locale.translation(label),
click: () => {
- if (Immutable.List.isList(siteDetail)) {
- siteDetail.forEach((site) => appActions.removeSite(site, deleteTag))
- } else {
- appActions.removeSite(siteDetail, deleteTag)
+ // TODO implement multiple
+ const key = siteUtil.getSiteKey(siteDetail)
+ if (type === siteTags.HISTORY) {
+ appActions.removeHistorySite(siteDetail)
+ } else if (type === siteTags.BOOKMARK) {
+ appActions.removeBookmark(key)
+ } else if (type === siteTags.BOOKMARK_FOLDER) {
+ appActions.removeBookmarkFolder(key)
}
}
})
}
- if (!isHistoryEntry && !multipleHistoryEntries) {
+ if (type !== siteTags.HISTORY) {
if (template[template.length - 1] !== CommonMenu.separatorMenuItem) {
template.push(CommonMenu.separatorMenuItem)
}
template.push(
- addBookmarkMenuItem('addBookmark', siteUtil.getDetailFromFrame(activeFrame, siteTags.BOOKMARK), siteDetail, true),
- addFolderMenuItem(siteDetail, true))
+ addBookmarkMenuItem('addBookmark', bookmarkUtil.getDetailFromFrame(activeFrame), siteDetail, true),
+ addFolderMenuItem(siteDetail, true)
+ )
}
return menuUtil.sanitizeTemplateItems(template)
@@ -724,11 +738,11 @@ const openInNewTabMenuItem = (url, isPrivate, partitionNumber, openerTabId) => {
}
}
-const openAllInNewTabsMenuItem = (allSites, folderDetail) => {
+const openAllInNewTabsMenuItem = (folderDetail) => {
return {
label: locale.translation('openAllInTabs'),
click: () => {
- bookmarkActions.openBookmarksInFolder(allSites, folderDetail)
+ bookmarkActions.openBookmarksInFolder(folderDetail)
}
}
}
@@ -920,7 +934,7 @@ function mainTemplateInit (nodeProps, frame, tab) {
appActions.createTabRequested({
url: nodeProps.srcURL,
openerTabId: frame.get('tabId'),
- partition: getPartitionFromNumber(frame.get('partitionNumber'), isPrivate),
+ partition: frameStateUtil.getPartitionFromNumber(frame.get('partitionNumber'), isPrivate),
active: active
})
}
@@ -1009,8 +1023,7 @@ function mainTemplateInit (nodeProps, frame, tab) {
)
if (isLink) {
template.push(addBookmarkMenuItem('bookmarkLink', {
- location: nodeProps.linkURL,
- tags: [siteTags.BOOKMARK]
+ location: nodeProps.linkURL
}, false))
}
}
@@ -1024,8 +1037,7 @@ function mainTemplateInit (nodeProps, frame, tab) {
if (!isImage) {
if (isLink) {
template.push(addBookmarkMenuItem('bookmarkLink', {
- location: nodeProps.linkURL,
- tags: [siteTags.BOOKMARK]
+ location: nodeProps.linkURL
}, false))
} else {
template.push(
@@ -1055,7 +1067,7 @@ function mainTemplateInit (nodeProps, frame, tab) {
}
},
CommonMenu.separatorMenuItem,
- addBookmarkMenuItem('bookmarkPage', siteUtil.getDetailFromFrame(frame, siteTags.BOOKMARK), false))
+ addBookmarkMenuItem('bookmarkPage', bookmarkUtil.getDetailFromFrame(frame), false))
if (!isAboutPage) {
template.push({
@@ -1204,8 +1216,7 @@ function mainTemplateInit (nodeProps, frame, tab) {
template.push(
CommonMenu.separatorMenuItem,
addBookmarkMenuItem('addBookmark', {
- location: nodeProps.linkURL,
- tags: [siteTags.BOOKMARK]
+ location: nodeProps.linkURL
}),
addFolderMenuItem()
)
@@ -1226,11 +1237,11 @@ function onHamburgerMenu (location, e) {
}
function onMainContextMenu (nodeProps, frame, tab, contextMenuType) {
- if (contextMenuType === 'bookmark' || contextMenuType === 'bookmark-folder') {
+ if (contextMenuType === siteTags.BOOKMARK || contextMenuType === siteTags.BOOKMARK_FOLDER) {
const activeFrame = Immutable.fromJS({ location: '', title: '', partitionNumber: frame.get('partitionNumber') })
- onSiteDetailContextMenu(Immutable.fromJS(nodeProps), activeFrame)
- } else if (contextMenuType === 'history') {
- onSiteDetailContextMenu(Immutable.fromJS(nodeProps))
+ onSiteDetailContextMenu(Immutable.fromJS(nodeProps), contextMenuType, activeFrame)
+ } else if (contextMenuType === siteTags.HISTORY) {
+ onSiteDetailContextMenu(Immutable.fromJS(nodeProps), contextMenuType)
} else if (contextMenuType === 'synopsis') {
onLedgerContextMenu(nodeProps.location, nodeProps.hostPattern)
} else if (contextMenuType === 'download') {
@@ -1281,7 +1292,7 @@ function onUrlBarContextMenu (e) {
e.stopPropagation()
const searchDetail = appStoreRenderer.state.get('searchDetail')
const windowState = windowStore.getState()
- const activeFrame = getActiveFrame(windowState)
+ const activeFrame = frameStateUtil.getActiveFrame(windowState)
const inputMenu = Menu.buildFromTemplate(urlBarTemplateInit(searchDetail, activeFrame, e))
inputMenu.popup(getCurrentWindow())
}
diff --git a/js/data/newTabData.js b/js/data/newTabData.js
index ccc0b4e286c..94431f18e7e 100644
--- a/js/data/newTabData.js
+++ b/js/data/newTabData.js
@@ -5,75 +5,64 @@
const {getBraveExtUrl} = require('../lib/appUrlUtil')
const iconPath = getBraveExtUrl('img/newtab/defaultTopSitesIcon')
-const now = 1
-
module.exports.pinnedTopSites = [
- {
- "count": 1,
- "favicon": `${iconPath}/twitter.png`,
- "lastAccessedTime": now,
- "location": "https://twitter.com/brave",
- "partitionNumber": 0,
- "tags": ['default'],
- "themeColor": "rgb(255, 255, 255)",
- "title": "Brave Software (@brave) | Twitter"
+ {
+ 'key': 'https://twitter.com/brave/|0|0',
+ 'count': 0,
+ 'favicon': `${iconPath}/twitter.png`,
+ 'location': 'https://twitter.com/brave/',
+ 'themeColor': 'rgb(255, 255, 255)',
+ 'title': 'Brave Software (@brave) | Twitter'
}
]
module.exports.topSites = [
{
- "count": 1,
- "favicon": `${iconPath}/twitter.png`,
- "lastAccessedTime": now,
- "location": "https://twitter.com/brave",
- "partitionNumber": 0,
- "tags": ['default'],
- "themeColor": "rgb(255, 255, 255)",
- "title": "Brave Software (@brave) | Twitter"
- }, {
- "count": 1,
- "favicon": `${iconPath}/facebook.png`,
- "lastAccessedTime": now,
- "location": "https://www.facebook.com/BraveSoftware/",
- "partitionNumber": 0,
- "tags": ['default'],
- "themeColor": "rgb(59, 89, 152)",
- "title": "Brave Software | Facebook"
- }, {
- "count": 1,
- "favicon": `${iconPath}/youtube.png`,
- "lastAccessedTime": now,
- "location": "https://www.youtube.com/bravesoftware",
- "partitionNumber": 0,
- "tags": ['default'],
- "themeColor": "#E62117",
- "title": "Brave Browser - YouTube"
- }, {
- "count": 1,
- "favicon": `${iconPath}/brave.ico`,
- "lastAccessedTime": now,
- "location": "https://brave.com/",
- "partitionNumber": 0,
- "tags": ['default'],
- "themeColor": "rgb(255, 255, 255)",
- "title": "Brave Software | Building a Better Web"
- }, {
- "count": 1,
- "favicon": `${iconPath}/appstore.png`,
- "lastAccessedTime": now,
- "location": "https://itunes.apple.com/app/brave-web-browser/id1052879175?mt=8",
- "partitionNumber": 0,
- "tags": ['default'],
- "themeColor": "rgba(255, 255, 255, 1)",
- "title": "Brave Web Browser: Fast with built-in adblock on the App Store"
- }, {
- "count": 1,
- "favicon": `${iconPath}/playstore.png`,
- "lastAccessedTime": now,
- "location": "https://play.google.com/store/apps/details?id=com.brave.browser",
- "partitionNumber": 0,
- "tags": ['default'],
- "themeColor": "rgb(241, 241, 241)",
- "title": "Brave Browser: Fast AdBlock – Apps para Android no Google Play"
+ 'key': 'https://twitter.com/brave/|0|0',
+ 'count': 0,
+ 'favicon': `${iconPath}/twitter.png`,
+ 'location': 'https://twitter.com/brave',
+ 'themeColor': 'rgb(255, 255, 255)',
+ 'title': 'Brave Software (@brave) | Twitter'
+ },
+ {
+ 'key': 'https://www.facebook.com/BraveSoftware/|0|0',
+ 'count': 0,
+ 'favicon': `${iconPath}/facebook.png`,
+ 'location': 'https://www.facebook.com/BraveSoftware/',
+ 'themeColor': 'rgb(59, 89, 152)',
+ 'title': 'Brave Software | Facebook'
+ },
+ {
+ 'key': 'https://www.youtube.com/bravesoftware/|0|0',
+ 'count': 0,
+ 'favicon': `${iconPath}/youtube.png`,
+ 'location': 'https://www.youtube.com/bravesoftware/',
+ 'themeColor': '#E62117',
+ 'title': 'Brave Browser - YouTube'
+ },
+ {
+ 'key': 'https://brave.com/|0|0',
+ 'count': 0,
+ 'favicon': `${iconPath}/brave.ico`,
+ 'location': 'https://brave.com/',
+ 'themeColor': 'rgb(255, 255, 255)',
+ 'title': 'Brave Software | Building a Better Web'
+ },
+ {
+ 'key': 'https://itunes.apple.com/app/brave-web-browser/id1052879175?mt=8|0|0',
+ 'count': 0,
+ 'favicon': `${iconPath}/appstore.png`,
+ 'location': 'https://itunes.apple.com/app/brave-web-browser/id1052879175?mt=8',
+ 'themeColor': 'rgba(255, 255, 255, 1)',
+ 'title': 'Brave Web Browser: Fast with built-in adblock on the App Store'
+ },
+ {
+ 'key': 'https://play.google.com/store/apps/details?id=com.brave.browser|0|0',
+ 'count': 0,
+ 'favicon': `${iconPath}/playstore.png`,
+ 'location': 'https://play.google.com/store/apps/details?id=com.brave.browser',
+ 'themeColor': 'rgb(241, 241, 241)',
+ 'title': 'Brave Browser: Fast AdBlock – Apps para Android no Google Play'
}
]
diff --git a/js/lib/importer.js b/js/lib/importer.js
index b0925cff8b2..7d336b86925 100644
--- a/js/lib/importer.js
+++ b/js/lib/importer.js
@@ -4,15 +4,15 @@
const fs = require('fs')
const appActions = require('../actions/appActions')
-const siteTags = require('../constants/siteTags')
-const siteUtil = require('../state/siteUtil')
const Immutable = require('immutable')
const appStoreRenderer = require('../stores/appStoreRenderer')
+const bookmarFoldersUtil = require('../../app/common/lib/bookmarkFoldersUtil')
+const bookmarkFoldersState = require('../../app/common/state/bookmarkFoldersState')
/**
* Processes a single node from an exported HTML file from Firefox or Chrome
* @param {Object} parserState - the current parser state
- * @param {Object} node - The current DOM node which is being processed
+ * @param {Object} domNode - The current DOM node which is being processed
*/
function processBookmarkNode (parserState, domNode) {
switch (domNode.tagName) {
@@ -38,12 +38,11 @@ function processBookmarkNode (parserState, domNode) {
title: domNode.innerText,
folderId: parserState.nextFolderId,
parentFolderId: parserState.parentFolderId,
- lastAccessedTime: (domNode.getAttribute('LAST_MODIFIED') || domNode.getAttribute('ADD_DATE') || 0) * 1000,
- tags: [siteTags.BOOKMARK_FOLDER]
+ lastAccessedTime: (domNode.getAttribute('LAST_MODIFIED') || domNode.getAttribute('ADD_DATE') || 0) * 1000
}
parserState.lastFolderId = parserState.nextFolderId
parserState.nextFolderId++
- parserState.sites.push(folder)
+ parserState.bookmarkFolders.push(folder)
} else {
parserState.lastFolderId = 0
parserState.foundBookmarksToolbar = true
@@ -54,15 +53,13 @@ function processBookmarkNode (parserState, domNode) {
if (domNode.href.startsWith('place:')) {
break
}
- const site = {
+ const bookmarks = {
title: domNode.innerText,
location: domNode.href,
favicon: domNode.getAttribute('ICON'),
- parentFolderId: parserState.parentFolderId,
- lastAccessedTime: (domNode.getAttribute('LAST_MODIFIED') || domNode.getAttribute('ADD_DATE') || 0) * 1000,
- tags: [siteTags.BOOKMARK]
+ parentFolderId: parserState.parentFolderId
}
- parserState.sites.push(site)
+ parserState.bookmarks.push(bookmarks)
break
}
}
@@ -91,17 +88,19 @@ module.exports.importFromHTML = (path) => {
// Each window's appStoreRenderer holds a copy of the app state, but it's not
// mutable, so this is only used for getting the current list of sites.
const parserState = {
- nextFolderId: siteUtil.getNextFolderId(appStoreRenderer.state.get('sites')),
+ nextFolderId: bookmarFoldersUtil.getNextFolderId(bookmarkFoldersState.getFolders(appStoreRenderer.state)),
lastFolderId: -1,
parentFolderId: -1,
- sites: []
+ bookmarks: [],
+ bookmarkFolders: []
}
// Process each of the nodes starting with the first node which is either DL or DT
processBookmarkNode(parserState, doc.querySelector('dl, dt'))
// Add the sites to the app store in the main process
- appActions.addSite(Immutable.fromJS(parserState.sites))
+ appActions.addBookmark(Immutable.fromJS(parserState.bookmarks))
+ appActions.addBookmarkFolder(Immutable.fromJS(parserState.bookmarkFolders))
resolve({importCount: parserState.sites.length})
})
})
diff --git a/js/lib/textCalculator.js b/js/lib/textCalculator.js
index 8068219c1f4..c543d340b83 100644
--- a/js/lib/textCalculator.js
+++ b/js/lib/textCalculator.js
@@ -2,8 +2,8 @@
* 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/. */
-const ctx = document.createElement('canvas').getContext('2d')
module.exports.calculateTextWidth = (text, font = '11px Arial') => {
+ const ctx = document.createElement('canvas').getContext('2d')
ctx.font = font
return ctx.measureText(text).width
}
diff --git a/js/state/frameStateUtil.js b/js/state/frameStateUtil.js
index b71f871694e..e6a2e422142 100644
--- a/js/state/frameStateUtil.js
+++ b/js/state/frameStateUtil.js
@@ -58,6 +58,7 @@ function getSortedFrameKeys (state) {
.map(frame => frame.get('key'))
}
+// TODO check if order is preserved, could be a bug
function getPinnedFrames (state) {
return state.get('frames').filter((frame) => frame.get('pinnedLocation'))
}
diff --git a/js/state/siteUtil.js b/js/state/siteUtil.js
index 5320b15a9c7..60b5b7806e1 100644
--- a/js/state/siteUtil.js
+++ b/js/state/siteUtil.js
@@ -2,17 +2,11 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict'
-const Immutable = require('immutable')
-const siteCache = require('../../app/common/state/siteCache')
const siteTags = require('../constants/siteTags')
-const settings = require('../constants/settings')
-const getSetting = require('../settings').getSetting
const UrlUtil = require('../lib/urlutil')
const urlParse = require('../../app/common/urlParse')
-const {makeImmutable} = require('../../app/common/state/immutableUtil')
-
-const defaultTags = new Immutable.List([siteTags.DEFAULT])
+// TODO remove
const isBookmark = (tags) => {
if (!tags) {
return false
@@ -20,6 +14,7 @@ const isBookmark = (tags) => {
return tags.includes(siteTags.BOOKMARK)
}
+// TODO remove
const isBookmarkFolder = (tags) => {
if (!tags) {
return false
@@ -28,25 +23,6 @@ const isBookmarkFolder = (tags) => {
(tags && typeof tags !== 'string' && tags.includes(siteTags.BOOKMARK_FOLDER))
}
-const isPinnedTab = (tags) => {
- if (!tags) {
- return false
- }
- return tags.includes(siteTags.PINNED)
-}
-module.exports.isPinnedTab = isPinnedTab
-
-const reorderSite = (sites, order) => {
- sites = sites.map((site) => {
- const siteOrder = site.get('order')
- if (siteOrder > order) {
- return site.set('order', siteOrder - 1)
- }
- return site
- })
- return sites
-}
-
/**
* Sort comparator for sort function
*/
@@ -109,227 +85,13 @@ module.exports.getLocationFromSiteKey = function (siteKey) {
* @param siteDetail The site to check if it's in the specified tag
* @return true if the location is already bookmarked
*/
+// TODO remove this when sync is updated
module.exports.isSiteBookmarked = function (sites, siteDetail) {
const siteKey = module.exports.getSiteKey(siteDetail)
const siteTags = sites.getIn([siteKey, 'tags'])
return isBookmark(siteTags)
}
-/**
- * Checks if a location is bookmarked.
- *
- * @param state The application state Immutable map
- * @param {string} location
- * @return {boolean}
- */
-module.exports.isLocationBookmarked = function (state, location) {
- const sites = state.get('sites')
- const siteKeys = siteCache.getLocationSiteKeys(state, location)
- if (!siteKeys || siteKeys.length === 0) {
- return false
- }
- return siteKeys.some(key => {
- const site = sites.get(key)
- if (!site) {
- return false
- }
- return isBookmark(site.get('tags'))
- })
-}
-
-const getNextFolderIdItem = (sites) =>
- sites.max((siteA, siteB) => {
- const folderIdA = siteA.get('folderId')
- const folderIdB = siteB.get('folderId')
- if (folderIdA === folderIdB) {
- return 0
- }
- if (folderIdA === undefined) {
- return false
- }
- if (folderIdB === undefined) {
- return true
- }
- return folderIdA > folderIdB
- })
-
-module.exports.getNextFolderId = (sites) => {
- const defaultFolderId = 0
- if (!sites) {
- return defaultFolderId
- }
- const maxIdItem = getNextFolderIdItem(sites)
- return (maxIdItem ? (maxIdItem.get('folderId') || 0) : 0) + 1
-}
-
-module.exports.getNextFolderName = (sites, name) => {
- if (!sites) {
- return name
- }
- const site = sites.find((site) =>
- isBookmarkFolder(site.get('tags')) &&
- site.get('customTitle') === name
- )
- if (!site) {
- return name
- }
- const filenameFormat = /(.*) \((\d+)\)/
- let result = filenameFormat.exec(name)
- if (!result) {
- return module.exports.getNextFolderName(sites, name + ' (1)')
- }
- const nextNum = parseInt(result[2]) + 1
- return module.exports.getNextFolderName(sites, result[1] + ' (' + nextNum + ')')
-}
-
-const mergeSiteLastAccessedTime = (oldSiteDetail, newSiteDetail, tag) => {
- const newTime = newSiteDetail && newSiteDetail.get('lastAccessedTime')
- const oldTime = oldSiteDetail && oldSiteDetail.get('lastAccessedTime')
- if (!isBookmark(tag) && !isBookmarkFolder(tag)) {
- return newTime || new Date().getTime()
- }
- if (newTime && newTime !== 0) {
- return newTime
- } else if (oldTime && oldTime !== 0) {
- return oldTime
- } else {
- return 0
- }
-}
-
-// Some details can be copied from the existing siteDetail if null
-// ex: parentFolderId, partitionNumber, and favicon
-const mergeSiteDetails = (oldSiteDetail, newSiteDetail, tag, folderId, order) => {
- let tags = (oldSiteDetail && oldSiteDetail.get('tags')) || new Immutable.List()
- if (tag) {
- tags = tags.toSet().add(tag).toList()
- }
-
- const customTitle = typeof newSiteDetail.get('customTitle') === 'string'
- ? newSiteDetail.get('customTitle')
- : (newSiteDetail.get('customTitle') || (oldSiteDetail && oldSiteDetail.get('customTitle')))
-
- const lastAccessedTime = mergeSiteLastAccessedTime(oldSiteDetail, newSiteDetail, tag)
-
- let site = makeImmutable({
- lastAccessedTime,
- tags,
- objectId: newSiteDetail.get('objectId') || (oldSiteDetail ? oldSiteDetail.get('objectId') : undefined),
- title: newSiteDetail.get('title'),
- order
- })
-
- if (oldSiteDetail && oldSiteDetail.get('order') !== undefined) {
- site = site.set('order', oldSiteDetail.get('order'))
- }
-
- if (newSiteDetail.get('location')) {
- site = site.set('location', newSiteDetail.get('location'))
- }
- if (folderId) {
- site = site.set('folderId', Number(folderId))
- }
- if (typeof customTitle === 'string') {
- site = site.set('customTitle', customTitle)
- }
- if (newSiteDetail.get('parentFolderId') !== undefined || (oldSiteDetail && oldSiteDetail.get('parentFolderId'))) {
- let parentFolderId = newSiteDetail.get('parentFolderId') !== undefined
- ? newSiteDetail.get('parentFolderId') : oldSiteDetail.get('parentFolderId')
- site = site.set('parentFolderId', Number(parentFolderId))
- }
- if (newSiteDetail.get('partitionNumber') !== undefined || (oldSiteDetail && oldSiteDetail.get('partitionNumber'))) {
- let partitionNumber = newSiteDetail.get('partitionNumber') !== undefined
- ? newSiteDetail.get('partitionNumber') : oldSiteDetail.get('partitionNumber')
- site = site.set('partitionNumber', Number(partitionNumber))
- }
- if (newSiteDetail.get('favicon') || (oldSiteDetail && oldSiteDetail.get('favicon'))) {
- site = site.set('favicon', newSiteDetail.get('favicon') || oldSiteDetail.get('favicon'))
- }
- if (newSiteDetail.get('themeColor') || (oldSiteDetail && oldSiteDetail.get('themeColor'))) {
- site = site.set('themeColor', newSiteDetail.get('themeColor') || oldSiteDetail.get('themeColor'))
- }
- if (site.get('tags').size === 0) {
- // Increment the visit count for history items
- site = site.set('count', ((oldSiteDetail || site).get('count') || 0) + 1)
- }
-
- return site
-}
-
-/**
- * Adds the specified siteDetail in appState.sites.
- *
- * Examples of updating:
- * - editing bookmark in add/edit modal
- * - when timestamp is added (history entry)
- * - moving bookmark to/from a folder
- *
- * @param state - The application state
- * @param siteDetail - The site details object to add or update
- * @param tag - The tag to add for this site
- * See siteTags.js for supported types. No tag means just a history item
- * @param oldKey - key of a changed site
- * @param {boolean} skipSync - True if this site was downloaded by sync and
- * does not to be re-uploaded
- * @return The new state Immutable object
- */
-module.exports.addSite = function (state, siteDetail, tag, oldKey, skipSync) {
- let sites = state.get('sites')
- // Get tag from siteDetail object if not passed via tag param
- if (tag === undefined) {
- tag = siteDetail.getIn(['tags', 0])
- }
-
- if (!oldKey) {
- oldKey = module.exports.getSiteKey(siteDetail)
- }
-
- const oldSite = oldKey !== null ? sites.get(oldKey) : null
- let folderId = siteDetail.get('folderId')
-
- if (tag === siteTags.BOOKMARK_FOLDER) {
- if (!oldSite && folderId) {
- // Remove duplicate folder (needed for import)
- const dupFolder = sites.find((site) => isBookmarkFolder(site.get('tags')) &&
- site.get('parentFolderId') === siteDetail.get('parentFolderId') &&
- site.get('customTitle') === siteDetail.get('customTitle'))
- if (dupFolder) {
- state = module.exports.removeSite(state, dupFolder, siteTags.BOOKMARK_FOLDER, true)
- }
- } else if (!folderId) {
- // Assign an id if this is a new folder
- folderId = module.exports.getNextFolderId(sites)
- }
- }
-
- let site = mergeSiteDetails(oldSite, siteDetail, tag, folderId, sites.size)
- if (oldSite) {
- sites = sites.delete(oldKey)
- }
-
- let location
- if (site.has('location')) {
- location = UrlUtil.getLocationIfPDF(site.get('location'))
- site = site.set('location', location)
- }
-
- const oldLocation = (oldSite && oldSite.get('location')) || site.get('location')
- state = siteCache.removeLocationSiteKey(state, oldLocation, oldKey)
-
- if (skipSync) {
- site = site.set('skipSync', true)
- }
-
- state = state.set('sites', sites)
- const key = module.exports.getSiteKey(site)
- if (key === null) {
- return state
- }
- state = state.setIn(['sites', key], site)
- state = siteCache.addLocationSiteKey(state, location, key)
- return state
-}
-
/**
* Removes the appropriate tag from a site given the site's sync objectId.
* @param {Immutable.Map} state - Application state
@@ -347,12 +109,16 @@ module.exports.removeSiteByObjectId = function (state, objectId, objectData) {
if (!site) {
return state
}
+
+ // TODO fix so that correct remove is called
+ /*
let tag = ''
if (objectData === 'bookmark') {
// determine whether this is a folder
tag = site.get('folderId') ? siteTags.BOOKMARK_FOLDER : siteTags.BOOKMARK
}
state = module.exports.removeSite(state, site, tag)
+ */
// If the object has been removed completely, purge it from the sync site
// cache
if (!state.getIn(objectKey)) {
@@ -361,67 +127,6 @@ module.exports.removeSiteByObjectId = function (state, objectId, objectData) {
return state
}
-/**
- * Removes the specified tag from a siteDetail
- *
- * @param {Immutable.Map} state The application state Immutable map
- * @param {Immutable.Map} siteDetail The siteDetail to remove a tag from
- * @param {string} tag
- * @param {boolean} reorder whether to reorder sites (default with reorder)
- * @param {Function=} syncCallback
- * @return {Immutable.Map} The new state Immutable object
- */
-module.exports.removeSite = function (state, siteDetail, tag, reorder = true, syncCallback) {
- let sites = state.get('sites')
- const key = module.exports.getSiteKey(siteDetail)
- if (!key) {
- return state
- }
- if (getSetting(settings.SYNC_ENABLED) === true && syncCallback) {
- syncCallback(sites.getIn([key]))
- }
-
- const tags = sites.getIn([key, 'tags'])
- if (isBookmarkFolder(tags)) {
- const folderId = sites.getIn([key, 'folderId'])
- const childSites = sites.filter((site) => site.get('parentFolderId') === folderId)
- childSites.forEach((site) => {
- const tags = site.get('tags')
- tags.forEach((tag) => {
- state = module.exports.removeSite(state, site, tag, false, syncCallback)
- })
- })
- }
-
- const location = siteDetail.get('location')
- state = siteCache.removeLocationSiteKey(state, location, key)
-
- const stateKey = ['sites', key]
- let site = state.getIn(stateKey)
- if (!site) {
- return state
- }
- if (isBookmark(tag)) {
- if (isPinnedTab(tags)) {
- const tags = site.get('tags').filterNot((tag) => tag === siteTags.BOOKMARK)
- site = site.set('tags', tags)
- return state.setIn(stateKey, site)
- }
- if (state.get('sites').size && reorder) {
- const order = state.getIn(stateKey.concat(['order']))
- state = state.set('sites', reorderSite(state.get('sites'), order))
- }
- return state.deleteIn(['sites', key])
- } else if (isPinnedTab(tag)) {
- const tags = site.get('tags').filterNot((tag) => tag === siteTags.PINNED)
- site = site.set('tags', tags)
- return state.setIn(stateKey, site)
- } else {
- site = site.set('lastAccessedTime', undefined)
- return state.setIn(stateKey, site)
- }
-}
-
/**
* Called by isMoveAllowed
* Trace a folder's ancestory, collecting all parent folderIds until reaching Bookmarks Toolbar (folderId=0)
@@ -459,223 +164,12 @@ module.exports.isMoveAllowed = (sites, sourceDetail, destinationDetail) => {
return true
}
-/**
- * Moves the specified site from one location to another
- *
- * @param state The application state Immutable map
- * @param sourceKey The site key to move
- * @param destinationKey The site key to move to
- * @param prepend Whether the destination detail should be prepended or not, not used if destinationIsParent is true
- * @param destinationIsParent Whether the item should be moved inside of the destinationDetail.
- * @param disallowReparent If set to true, parent folder will not be set
- * @return The new state Immutable object
- */
-module.exports.moveSite = function (state, sourceKey, destinationKey, prepend,
- destinationIsParent, disallowReparent) {
- let sites = state.get('sites')
- let sourceSite = sites.get(sourceKey, Immutable.Map())
- const destinationSite = sites.get(destinationKey, Immutable.Map())
-
- if (sourceSite.isEmpty() || !module.exports.isMoveAllowed(sites, sourceSite, destinationSite)) {
- return state
- }
-
- const sourceSiteIndex = sourceSite.get('order')
- let destinationSiteIndex
- if (destinationIsParent) {
- // When the destination is the parent we want to put it at the end
- destinationSiteIndex = sites.size - 1
- prepend = true
- } else {
- destinationSiteIndex = destinationSite.get('order')
- }
-
- let newIndex = destinationSiteIndex + (prepend ? 0 : 1)
- if (destinationSiteIndex > sourceSiteIndex) {
- --newIndex
- }
-
- const location = sourceSite.get('location')
- state = siteCache.removeLocationSiteKey(state, location, sourceKey)
- state = state.deleteIn(['sites', sourceKey])
- state = state.set('sites', state.get('sites').map((site) => {
- const siteOrder = site.get('order')
- if (siteOrder >= newIndex && siteOrder < sourceSiteIndex) {
- return site.set('order', siteOrder + 1)
- } else if (siteOrder <= newIndex && siteOrder > sourceSiteIndex) {
- return site.set('order', siteOrder - 1)
- }
- return site
- }))
- sourceSite = sourceSite.set('order', newIndex)
-
- if (!disallowReparent) {
- if (destinationIsParent && destinationSite.get('folderId') !== sourceSite.get('folderId')) {
- sourceSite = sourceSite.set('parentFolderId', destinationSite.get('folderId'))
- } else if (destinationSite.get('parentFolderId') == null) {
- sourceSite = sourceSite.set('parentFolderId', 0)
- } else if (destinationSite.get('parentFolderId') !== sourceSite.get('parentFolderId')) {
- sourceSite = sourceSite.set('parentFolderId', destinationSite.get('parentFolderId'))
- }
- }
- const destinationSiteKey = module.exports.getSiteKey(sourceSite)
- state = siteCache.addLocationSiteKey(state, location, destinationSiteKey)
- return state.setIn(['sites', destinationSiteKey], sourceSite)
-}
-
-module.exports.getDetailFromFrame = function (frame, tag) {
- const pinnedLocation = frame.get('pinnedLocation')
- let location = frame.get('location')
- if (pinnedLocation && pinnedLocation !== 'about:blank' && tag === siteTags.PINNED) {
- location = frame.get('pinnedLocation')
- }
-
- return makeImmutable({
- location,
- title: frame.get('title'),
- partitionNumber: frame.get('partitionNumber'),
- tags: tag ? [tag] : [],
- favicon: frame.get('icon'),
- themeColor: frame.get('themeColor') || frame.get('computedThemeColor')
- })
-}
-
-const getSitesBySubkey = (sites, siteKey, tag) => {
- if (!sites || !siteKey) {
- return makeImmutable([])
- }
- const splitKey = siteKey.split('|', 2)
- const partialKey = splitKey.join('|')
- const matches = sites.filter((site, key) => {
- if (key.indexOf(partialKey) > -1 && (!tag || (tag && site.get('tags').includes(tag)))) {
- return true
- }
- return false
- })
- return matches.toList()
-}
-
-module.exports.getDetailFromTab = function (tab, tag, sites) {
- let location = tab.get('url')
- const partitionNumber = tab.get('partitionNumber')
- let parentFolderId
-
- // if site map is available, look up extra information:
- // - original url (if redirected)
- // - parent folder id
- if (sites) {
- let results = makeImmutable([])
-
- // get all sites matching URL and partition (disregarding parentFolderId)
- let siteKey = module.exports.getSiteKey(makeImmutable({location, partitionNumber}))
- results = results.merge(getSitesBySubkey(sites, siteKey, tag))
-
- // only check for provisional location if entry is not found
- if (results.size === 0) {
- // if provisional location is different, grab any results which have that URL
- // this may be different if the site was redirected
- const provisionalLocation = tab.getIn(['frame', 'provisionalLocation'])
- if (provisionalLocation && provisionalLocation !== location) {
- siteKey = module.exports.getSiteKey(makeImmutable({
- location: provisionalLocation,
- partitionNumber
- }))
- results = results.merge(getSitesBySubkey(sites, siteKey, tag))
- }
- }
-
- // update details which get returned below
- if (results.size > 0) {
- location = results.getIn([0, 'location'])
- parentFolderId = results.getIn([0, 'parentFolderId'])
- }
- }
-
- const siteDetail = {
- location: location,
- title: tab.get('title'),
- tags: tag ? [tag] : []
- }
- if (partitionNumber) {
- siteDetail.partitionNumber = partitionNumber
- }
- if (parentFolderId) {
- siteDetail.parentFolderId = parentFolderId
- }
- return Immutable.fromJS(siteDetail)
-}
-
-module.exports.getDetailFromCreateProperties = function (createProperties, tag) {
- const siteDetail = {
- location: createProperties.get('url'),
- tags: tag ? [tag] : []
- }
- if (createProperties.get('partitionNumber') !== undefined) {
- siteDetail.partitionNumber = createProperties.get('partitionNumber')
- }
- return Immutable.fromJS(siteDetail)
-}
-
-/**
- * Update the favicon URL for all entries in the state sites
- * which match a given location. Currently, there should only be
- * one match, but this will handle multiple.
- *
- * @param state The application state
- * @param location URL for the entry needing an update
- * @param favicon favicon URL
- */
-module.exports.updateSiteFavicon = function (state, location, favicon) {
- if (UrlUtil.isNotURL(location)) {
- return state
- }
- const siteKeys = siteCache.getLocationSiteKeys(state, location)
- if (!siteKeys || siteKeys.length === 0) {
- return state
- }
- siteKeys.forEach((siteKey) => {
- state = state.setIn(['sites', siteKey, 'favicon'], favicon)
- })
- return state
-}
-
-/**
- * Converts a siteDetail to createProperties format
- * @param {Object} siteDetail - A site detail as per app state
- * @return {Object} A createProperties plain JS object, not ImmutableJS
- */
-module.exports.toCreateProperties = function (siteDetail) {
- return {
- url: siteDetail.get('location'),
- partitionNumber: siteDetail.get('partitionNumber')
- }
-}
-
-/**
- * Compares 2 site details
- * @param siteDetail1 The first site detail to compare.
- * @param siteDetail2 The second site detail to compare.
- * @return true if the site details should be considered the same.
- */
-module.exports.isEquivalent = function (siteDetail1, siteDetail2) {
- const isFolder1 = module.exports.isFolder(siteDetail1)
- const isFolder2 = module.exports.isFolder(siteDetail2)
- if (isFolder1 !== isFolder2) {
- return false
- }
-
- // If they are both folders
- if (isFolder1) {
- return siteDetail1.get('folderId') === siteDetail2.get('folderId')
- }
- return siteDetail1.get('location') === siteDetail2.get('location') && siteDetail1.get('partitionNumber') === siteDetail2.get('partitionNumber')
-}
-
/**
* Determines if the site detail is a bookmark.
* @param siteDetail The site detail to check.
* @return true if the site detail has a bookmark tag.
*/
+// TODO remove when sync is refactored
module.exports.isBookmark = function (siteDetail) {
if (siteDetail) {
return isBookmark(siteDetail.get('tags'))
@@ -688,6 +182,7 @@ module.exports.isBookmark = function (siteDetail) {
* @param siteDetail The site detail to check.
* @return true if the site detail is a folder.
*/
+// TODO remove when sync is refactored
module.exports.isFolder = function (siteDetail) {
if (siteDetail) {
return isBookmarkFolder(siteDetail.get('tags')) && siteDetail.get('folderId') !== undefined
@@ -695,25 +190,16 @@ module.exports.isFolder = function (siteDetail) {
return false
}
-/**
- * Determines if the site detail is an imported bookmark.
- * @param siteDetail The site detail to check.
- * @return true if the site detail is a folder.
- */
-module.exports.isImportedBookmark = function (siteDetail) {
- return siteDetail.get('lastAccessedTime') === 0
-}
-
/**
* Determines if the site detail is a history entry.
* @param siteDetail The site detail to check.
* @return true if the site detail is a history entry.
*/
+// TODO remove when sync is refactored
module.exports.isHistoryEntry = function (siteDetail) {
if (siteDetail && typeof siteDetail.get('location') === 'string') {
const tags = siteDetail.get('tags')
if (siteDetail.get('location').startsWith('about:') ||
- module.exports.isDefaultEntry(siteDetail) ||
isBookmarkFolder(tags)) {
return false
}
@@ -722,122 +208,11 @@ module.exports.isHistoryEntry = function (siteDetail) {
return false
}
-/**
- * Determines if the site detail is one of default sites in about:newtab.
- * @param {Immutable.Map} siteDetail The site detail to check.
- * @returns {boolean} if the site detail is a default newtab entry.
- */
-module.exports.isDefaultEntry = function (siteDetail) {
- return Immutable.is(siteDetail.get('tags'), defaultTags) &&
- siteDetail.get('lastAccessedTime') === 1
-}
-
-/**
- * Get a folder by folderId
- * @returns {Immutable.List.} sites
- * @param {number} folderId
- * @returns {Array[, ]|undefined}
- */
-module.exports.getFolder = function (sites, folderId) {
- const entry = sites.findEntry((site, _path) => {
- return module.exports.isFolder(site) && site.get('folderId') === folderId
- })
- if (!entry) { return undefined }
- return entry
-}
-
-/**
- * Obtains an array of folders
- */
-module.exports.getFolders = function (sites, folderId, parentId, labelPrefix) {
- parentId = parentId || 0
- let folders = []
- const results = sites
- .filter(site => {
- return (site.get('parentFolderId', 0) === parentId && module.exports.isFolder(site))
- })
- .toList()
- .sort(module.exports.siteSort)
-
- const resultSize = results.size
- for (let i = 0; i < resultSize; i++) {
- const site = results.get(i)
- if (site.get('folderId') === folderId) {
- continue
- }
-
- const label = (labelPrefix || '') + (site.get('customTitle') || site.get('title'))
- folders.push({
- folderId: site.get('folderId'),
- parentFolderId: site.get('parentFolderId'),
- label
- })
- const subsites = module.exports.getFolders(sites, folderId, site.get('folderId'), (label || '') + ' / ')
- folders = folders.concat(subsites)
- }
-
- return folders
-}
-
-/**
- * Filters out non recent sites based on the app setting for history size.
- * @param sites The application state's Immutable sites list.
- */
-module.exports.filterOutNonRecents = function (sites) {
- const sitesWithTags = sites
- .filter((site) => site.get('tags').size)
- const topHistorySites = sites
- .filter((site) => site.get('tags').size === 0)
- .sort((site1, site2) => (site2.get('lastAccessedTime') || 0) - (site1.get('lastAccessedTime') || 0))
- .take(getSetting(settings.AUTOCOMPLETE_HISTORY_SIZE))
- return sitesWithTags.concat(topHistorySites)
-}
-
-/**
- * Filters sites relative to a parent site (folder).
- * @param sites The application state's Immutable sites list.
- * @param relSite The folder to filter to.
- */
-module.exports.filterSitesRelativeTo = function (sites, relSite) {
- if (!relSite.get('folderId')) {
- return sites
- }
- return sites.filter((site) => site.get('parentFolderId') === relSite.get('folderId'))
-}
-
-/**
- * Clears history by
- * - filtering out entries which have no tags
- * - setting lastAccessedTime to null for remaining entries (bookmarks)
- * @param sites The application state's Immutable sites list.
- */
-module.exports.clearHistory = function (sites) {
- let bookmarks = sites.filter((site) => site.get('tags') && site.get('tags').size > 0)
- bookmarks.forEach((site, index) => {
- if (site.get('lastAccessedTime')) {
- bookmarks = bookmarks.setIn([index, 'lastAccessedTime'], null)
- }
- })
- return bookmarks
-}
-
-/**
- * Returns all sites that have a bookmark tag.
- * @param sites The application state's Immutable sites list.
- */
-
-module.exports.getBookmarks = function (sites) {
- if (sites) {
- return sites.filter((site) => isBookmarkFolder(site.get('tags')) || isBookmark(site.get('tags')))
- }
- return makeImmutable({})
-}
-
/**
* Gets a site origin (scheme + hostname + port) from a URL or null if not
* available.
* @param {string} location
- * @return {string?}
+ * @return {string|null}
*/
module.exports.getOrigin = function (location) {
// Returns scheme + hostname + port
diff --git a/js/state/syncUtil.js b/js/state/syncUtil.js
index 2439eef3d19..c56f50910e1 100644
--- a/js/state/syncUtil.js
+++ b/js/state/syncUtil.js
@@ -9,7 +9,9 @@ const crypto = require('crypto')
const writeActions = require('../constants/sync/proto').actions
const siteTags = require('../constants/siteTags')
const siteUtil = require('./siteUtil')
+const {getSetting} = require('../settings')
const {isDataUrl} = require('../lib/urlutil')
+const settings = require('../constants/settings')
const CATEGORY_MAP = {
bookmark: {
@@ -47,7 +49,19 @@ module.exports.siteSettingDefaults = {
// Whitelist of valid browser-laptop site fields. In browser-laptop, site
// is used for both bookmarks and history sites.
-const SITE_FIELDS = ['objectId', 'location', 'title', 'customTitle', 'tags', 'favicon', 'themeColor', 'lastAccessedTime', 'creationTime', 'partitionNumber', 'folderId', 'parentFolderId']
+const SITE_FIELDS = [
+ 'objectId',
+ 'location',
+ 'title',
+ 'tags',
+ 'favicon',
+ 'themeColor',
+ 'lastAccessedTime',
+ 'creationTime',
+ 'partitionNumber',
+ 'folderId',
+ 'parentFolderId'
+]
const pickFields = (object, fields) => {
return fields.reduce((a, x) => {
@@ -101,10 +115,7 @@ module.exports.getSiteDataFromRecord = (record, appState, records) => {
record.bookmark && record.bookmark.site,
{objectId}
)
- if (siteProps.customTitle === '') {
- // browser-laptop UI expects the customTitle field to not exist if it is empty
- delete siteProps.customTitle
- }
+ delete siteProps.customTitle
if (record.objectData === 'bookmark') {
const existingFolderId = existingObjectData && existingObjectData.get('folderId')
if (existingFolderId) {
@@ -151,7 +162,6 @@ const applySiteSettingRecord = (record) => {
return value
}
}
- const appActions = require('../actions/appActions')
const hostPattern = record.siteSetting.hostPattern
if (!hostPattern) {
throw new Error('siteSetting.hostPattern is required.')
@@ -210,7 +220,7 @@ const applySyncRecord = (record) => {
break
case 'device':
const device = Object.assign({}, record.device, {lastRecordTimestamp: record.syncTimestamp})
- require('../actions/appActions').saveSyncDevices({
+ appActions.saveSyncDevices({
[deviceIdString(record.deviceId)]: device
})
break
@@ -225,19 +235,39 @@ const applySyncRecord = (record) => {
*/
module.exports.applySyncRecords = (records) => {
if (!records || records.length === 0) { return }
- const siteRecords = []
+ const bookmarkRecords = []
+ const bookmarkFoldersRecords = []
+ const historyRecords = []
const otherRecords = []
records.forEach((record) => {
- if (record && ['bookmark', 'historySite'].includes(record.objectData)) {
- siteRecords.push(record)
+ if (record && ['bookmark'].includes(record.objectData)) {
+ bookmarkRecords.push(record)
+ } else if (record && ['historySite'].includes(record.objectData)) {
+ historyRecords.push(record)
+ } else if (record && ['bookmark-folder'].includes(record.objectData)) {
+ bookmarkFoldersRecords.push(record)
} else {
otherRecords.push(record)
}
})
applyNonBatchedRecords(otherRecords)
- if (siteRecords.length) {
+
+ // TODO we now always add (need to check record.action for what to do)
+ if (bookmarkRecords.length) {
+ setImmediate(() => {
+ appActions.addBookmarks(new Immutable.List(bookmarkRecords))
+ })
+ }
+
+ if (bookmarkFoldersRecords.length) {
setImmediate(() => {
- require('../actions/appActions').applySiteRecords(new Immutable.List(siteRecords))
+ appActions.addBookmarkFolder(new Immutable.List(bookmarkFoldersRecords))
+ })
+ }
+
+ if (historyRecords.length) {
+ setImmediate(() => {
+ appActions.addHistorySites(new Immutable.List(historyRecords))
})
}
}
@@ -293,6 +323,7 @@ module.exports.getExistingObject = (categoryName, syncRecord) => {
*/
module.exports.createSiteCache = (appState) => {
const objectsById = new Immutable.Map().withMutations(objectsById => {
+ // TODO what to do here?
appState.get('sites').forEach((site, siteKey) => {
const objectId = site.get('objectId')
if (!objectId) { return true }
@@ -461,7 +492,6 @@ module.exports.createSiteData = (site, appState) => {
const siteData = {
location: '',
title: '',
- customTitle: '',
favicon: '',
lastAccessedTime: 0,
creationTime: 0
@@ -582,3 +612,7 @@ module.exports.deepArrayify = deepArrayify
module.exports.ipcSafeObject = (object) => {
return deepArrayify(object)
}
+
+module.exports.syncEnabled = () => {
+ return getSetting(settings.SYNC_ENABLED) === true
+}
diff --git a/js/stores/appStore.js b/js/stores/appStore.js
index 04a72501ba5..dda7fc815a7 100644
--- a/js/stores/appStore.js
+++ b/js/stores/appStore.js
@@ -45,6 +45,8 @@ const extensionState = require('../../app/common/state/extensionState')
const aboutNewTabState = require('../../app/common/state/aboutNewTabState')
const aboutHistoryState = require('../../app/common/state/aboutHistoryState')
const tabState = require('../../app/common/state/tabState')
+const bookmarksState = require('../../app/common/state/bookmarksState')
+const bookmarkFoldersState = require('../../app/common/state/bookmarkFoldersState')
const isDarwin = process.platform === 'darwin'
const isWindows = process.platform === 'win32'
@@ -343,16 +345,6 @@ function setDefaultWindowSize () {
const appStore = new AppStore()
const emitChanges = debounce(appStore.emitChanges.bind(appStore), 5)
-/**
- * Clears out the top X non tagged sites.
- * This is debounced to every 1 minute, the cleanup is not particularly intensive
- * but there's no point to cleanup frequently.
- */
-const filterOutNonRecents = debounce(() => {
- appState = appState.set('sites', siteUtil.filterOutNonRecents(appState.get('sites')))
- emitChanges()
-}, 60 * 1000)
-
/**
* Useful for updating non-react preferences (electron properties, etc).
* Called when any settings are modified (ex: via preferences).
@@ -398,6 +390,10 @@ const handleAppAction = (action) => {
// until we have a better way to manage dependencies.
// tabsReducer must be above dragDropReducer.
require('../../app/browser/reducers/tabsReducer'),
+ require('../../app/browser/reducers/bookmarksReducer'),
+ require('../../app/browser/reducers/bookmarkFoldersReducer'),
+ require('../../app/browser/reducers/historyReducer'),
+ require('../../app/browser/reducers/pinnedSitesReducer'),
require('../../app/browser/reducers/sitesReducer'),
require('../../app/browser/reducers/windowsReducer'),
require('../../app/browser/reducers/syncReducer'),
@@ -457,19 +453,11 @@ const handleAppAction = (action) => {
case appConstants.APP_DATA_URL_COPIED:
nativeImage.copyDataURL(action.dataURL, action.html, action.text)
break
- case appConstants.APP_ADD_SITE:
- case appConstants.APP_ADD_BOOKMARK:
- case appConstants.APP_EDIT_BOOKMARK:
- const oldSiteSize = appState.get('sites').size
- calculateTopSites(false)
+ case appConstants.APP_ADD_HISTORY_SITE:
+ calculateTopSites(true)
appState = aboutHistoryState.setHistory(appState, action)
- // If there was an item added then clear out the old history entries
- if (oldSiteSize !== appState.get('sites').size) {
- filterOutNonRecents()
- }
break
- case appConstants.APP_APPLY_SITE_RECORDS:
- case appConstants.APP_REMOVE_SITE:
+ case appConstants.APP_REMOVE_HISTORY_SITE:
calculateTopSites(true)
appState = aboutHistoryState.setHistory(appState, action)
break
@@ -665,8 +653,8 @@ const handleAppAction = (action) => {
const clearData = defaults ? defaults.merge(temp) : temp
if (clearData.get('browserHistory')) {
- calculateTopSites(true)
- appState = aboutHistoryState.setHistory(appState)
+ appState = aboutNewTabState.clearTopSites(appState)
+ appState = aboutHistoryState.clearHistory(appState)
syncActions.clearHistory()
BrowserWindow.getAllWindows().forEach((wnd) => wnd.webContents.send(messages.CLEAR_CLOSED_FRAMES))
}
@@ -800,7 +788,7 @@ const handleAppAction = (action) => {
appState = appState.set('defaultBrowserCheckComplete', {})
break
case windowConstants.WINDOW_SET_FAVICON:
- appState = siteUtil.updateSiteFavicon(appState, action.frameProps.get('location'), action.favicon)
+ appState = bookmarksState.updateSiteFavicon(appState, action.frameProps.get('location'), action.favicon)
if (action.frameProps.get('favicon') !== action.favicon) {
calculateTopSites(false)
}
@@ -856,13 +844,22 @@ const handleAppAction = (action) => {
const syncDefault = Immutable.fromJS(sessionStore.defaultAppState().sync)
const originalSeed = appState.getIn(['sync', 'seed'])
appState = appState.set('sync', syncDefault)
- appState.get('sites').forEach((site, key) => {
- if (site.has('objectId') && syncUtil.isSyncable('bookmark', site)) {
+ bookmarksState.getBookmarks(appState).forEach((site, key) => {
+ if (site.has('objectId')) {
+ // Remember which profile this bookmark was originally synced to.
+ // Since old bookmarks should be synced when a new profile is created,
+ // we have to keep track of which profile already has these bookmarks
+ // or else the old profile may have these bookmarks duplicated. #7405
+ appState = appState.setIn(['bookmarks', key, 'originalSeed'], originalSeed)
+ }
+ })
+ bookmarkFoldersState.getFolders(appState).forEach((site, key) => {
+ if (site.has('objectId')) {
// Remember which profile this bookmark was originally synced to.
// Since old bookmarks should be synced when a new profile is created,
// we have to keep track of which profile already has these bookmarks
// or else the old profile may have these bookmarks duplicated. #7405
- appState = appState.setIn(['sites', key, 'originalSeed'], originalSeed)
+ appState = appState.setIn(['bookmarks', key, 'originalSeed'], originalSeed)
}
})
appState.setIn(['sync', 'devices'], {})
diff --git a/js/stores/windowStore.js b/js/stores/windowStore.js
index 4e09138b53f..2741c6cc2fc 100644
--- a/js/stores/windowStore.js
+++ b/js/stores/windowStore.js
@@ -23,6 +23,9 @@ const assert = require('assert')
const contextMenuState = require('../../app/common/state/contextMenuState')
const appStoreRenderer = require('./appStoreRenderer')
const windowActions = require('../actions/windowActions')
+const siteUtil = require('../state/siteUtil')
+const bookmarkFoldersState = require('../../app/common/state/bookmarkFoldersState')
+const bookmarksState = require('../../app/common/state/bookmarksState')
let windowState = Immutable.fromJS({
activeFrameKey: null,
@@ -64,10 +67,6 @@ class WindowStore extends EventEmitter {
windowState = newWindowState
}
- getFrames () {
- return frameStateUtil.getFrames(this.state)
- }
-
getFrame (key) {
return frameStateUtil.getFrameByKey(windowState, key)
}
@@ -471,38 +470,55 @@ const doAction = (action) => {
windowState = windowState.delete('bookmarkDetail')
break
case windowConstants.WINDOW_ON_EDIT_BOOKMARK:
- const siteDetail = appStoreRenderer.state.getIn(['sites', action.editKey])
+ {
+ const siteDetail = bookmarksState.getBookmark(appStoreRenderer.state, action.editKey)
- windowState = windowState.setIn(['bookmarkDetail'], Immutable.fromJS({
- siteDetail: siteDetail,
- editKey: action.editKey,
- isBookmarkHanger: action.isHanger
- }))
- break
+ windowState = windowState.setIn(['bookmarkDetail'], Immutable.fromJS({
+ siteDetail: siteDetail,
+ editKey: action.editKey,
+ isBookmarkHanger: action.isHanger
+ }))
+ break
+ }
case windowConstants.WINDOW_ON_BOOKMARK_ADDED:
{
- let editKey = action.editKey
- const site = appStoreRenderer.state.getIn(['sites', editKey])
- let siteDetail = action.siteDetail
+ let bookmarkDetail = action.bookmarkDetail
- if (site) {
- siteDetail = site
+ if (bookmarkDetail == null) {
+ bookmarkDetail = frameStateUtil.getActiveFrame(windowState)
}
- if (siteDetail == null) {
- siteDetail = frameStateUtil.getActiveFrame(windowState)
- }
+ bookmarkDetail = bookmarkDetail.set('location', UrlUtil.getLocationIfPDF(bookmarkDetail.get('location')))
- siteDetail = siteDetail.set('location', UrlUtil.getLocationIfPDF(siteDetail.get('location')))
+ const editKey = siteUtil.getSiteKey(bookmarkDetail)
windowState = windowState.setIn(['bookmarkDetail'], Immutable.fromJS({
- siteDetail: siteDetail,
+ siteDetail: bookmarkDetail,
editKey: editKey,
isBookmarkHanger: action.isHanger,
isAdded: true
}))
}
break
+ case windowConstants.WINDOW_ON_ADD_BOOKMARK_FOLDER:
+ windowState = windowState.setIn(['bookmarkFolderDetail'], Immutable.fromJS({
+ folderDetails: action.folderDetails,
+ closestKey: action.closestKey
+ }))
+ break
+ case windowConstants.WINDOW_ON_EDIT_BOOKMARK_FOLDER:
+ {
+ const folderDetails = bookmarkFoldersState.getFolder(appStoreRenderer.state, action.editKey)
+
+ windowState = windowState.setIn(['bookmarkFolderDetail'], Immutable.fromJS({
+ folderDetails: folderDetails,
+ editKey: action.editKey
+ }))
+ break
+ }
+ case windowConstants.WINDOW_ON_BOOKMARK_FOLDER_CLOSE:
+ windowState = windowState.delete('bookmarkFolderDetail')
+ break
case windowConstants.WINDOW_AUTOFILL_SELECTION_CLICKED:
ipc.send('autofill-selection-clicked', action.tabId, action.value, action.frontEndId, action.index)
windowState = windowState.delete('contextMenuDetail')
diff --git a/test/about/bookmarksManagerTest.js b/test/about/bookmarksManagerTest.js
index 3cecb0dd755..5b4a91ab5d4 100644
--- a/test/about/bookmarksManagerTest.js
+++ b/test/about/bookmarksManagerTest.js
@@ -10,7 +10,6 @@ const Immutable = require('immutable')
describe('about:bookmarks', function () {
const folderId = Math.random()
const lastVisit = 1476140184441
- const bookmarkTag = [siteTags.BOOKMARK]
const browseableSiteUrl = 'page1.html'
const browseableSiteTitle = 'Page 1'
@@ -30,36 +29,30 @@ describe('about:bookmarks', function () {
location: siteWithFavicon,
title: 'Page with Favicon',
favicon: favicon,
- tags: bookmarkTag,
+ type: siteTags.BOOKMARK,
parentFolderId: 0,
lastAccessedTime: lastVisit
},
{
location: siteWithoutFavicon,
title: 'Page without Favicon',
- tags: bookmarkTag,
+ type: siteTags.BOOKMARK,
parentFolderId: 0,
lastAccessedTime: lastVisit
}
])
yield client
- .addSiteList(sites)
+ .addBookmarks(sites)
.tabByIndex(0)
.loadUrl(aboutBookmarksUrl)
}
function * addDemoSites (client) {
const sites = Immutable.fromJS([
- {
- customTitle: 'demo1',
- folderId: folderId,
- parentFolderId: 0,
- tags: [siteTags.BOOKMARK_FOLDER]
- },
{
location: 'https://brave.com',
title: 'Brave',
- tags: bookmarkTag,
+ type: siteTags.BOOKMARK,
parentFolderId: 0,
lastAccessedTime: lastVisit
},
@@ -67,7 +60,7 @@ describe('about:bookmarks', function () {
location: 'https://brave.com/test',
title: 'Test',
customTitle: 'customTest',
- tags: bookmarkTag,
+ type: siteTags.BOOKMARK,
parentFolderId: 0,
lastAccessedTime: lastVisit
},
@@ -75,41 +68,41 @@ describe('about:bookmarks', function () {
location: 'https://brave.com/test',
title: 'Test',
customTitle: 'customTest',
- tags: bookmarkTag,
+ type: siteTags.BOOKMARK,
parentFolderId: 0,
lastAccessedTime: lastVisit
},
{
location: 'https://www.youtube.com',
- tags: bookmarkTag,
+ type: siteTags.BOOKMARK,
parentFolderId: 0,
lastAccessedTime: lastVisit
},
{
location: 'https://www.facebook.com',
title: 'facebook',
- tags: bookmarkTag,
+ type: siteTags.BOOKMARK,
parentFolderId: 0,
lastAccessedTime: lastVisit
},
{
location: 'https://duckduckgo.com',
title: 'duckduckgo',
- tags: bookmarkTag,
+ type: siteTags.BOOKMARK,
parentFolderId: folderId,
lastAccessedTime: lastVisit
},
{
location: 'https://google.com',
title: 'Google',
- tags: bookmarkTag,
+ type: siteTags.BOOKMARK,
parentFolderId: folderId,
lastAccessedTime: lastVisit
},
{
location: 'https://bing.com',
title: 'Bing',
- tags: bookmarkTag,
+ type: siteTags.BOOKMARK,
parentFolderId: folderId,
lastAccessedTime: lastVisit
}
@@ -117,7 +110,13 @@ describe('about:bookmarks', function () {
yield client
.waitForBrowserWindow()
- .addSiteList(sites)
+ .addBookmarkFolder({
+ customTitle: 'demo1',
+ folderId: folderId,
+ parentFolderId: 0,
+ type: siteTags.BOOKMARK_FOLDER
+ })
+ .addBookmarks(sites)
.tabByIndex(0)
.loadUrl(aboutBookmarksUrl)
}
@@ -126,13 +125,13 @@ describe('about:bookmarks', function () {
const site = Brave.server.url(browseableSiteUrl)
yield client
.waitForBrowserWindow()
- .addSite({
+ .addBookmark({
location: site,
title: browseableSiteTitle,
- tags: bookmarkTag,
+ type: siteTags.BOOKMARK,
parentFolderId: 0,
lastAccessedTime: lastVisit
- }, siteTags.BOOKMARK)
+ })
.tabByIndex(0)
.loadUrl(aboutBookmarksUrl)
}
diff --git a/test/about/historyTest.js b/test/about/historyTest.js
index 8045311ec9e..56ca569e254 100644
--- a/test/about/historyTest.js
+++ b/test/about/historyTest.js
@@ -19,10 +19,10 @@ describe('about:history', function () {
function * addDemoSites (client) {
yield client
- .addSite({ location: 'https://brave.com', title: 'Brave' })
- .addSite({ location: 'https://brave.com/test', customTitle: 'customTest' })
- .addSite({ location: 'https://www.youtube.com' })
- .addSite({ location: 'https://www.facebook.com' })
+ .addHistorySite({ location: 'https://brave.com', title: 'Brave' })
+ .addHistorySite({ location: 'https://brave.com/test', customTitle: 'customTest' })
+ .addHistorySite({ location: 'https://www.youtube.com' })
+ .addHistorySite({ location: 'https://www.facebook.com' })
.waitForExist('[data-test-id="tab"][data-frame-key="1"]')
.tabByIndex(0)
.url(aboutHistoryUrl)
@@ -31,7 +31,7 @@ describe('about:history', function () {
function * addBrowseableSite (client) {
const site = Brave.server.url(browseableSiteUrl)
yield client
- .addSite({
+ .addHistorySite({
location: site,
title: 'Page 1'
})
diff --git a/test/about/ledgerPanelTest.js b/test/about/ledgerPanelTest.js
index 9788d68db38..0a85f86a712 100644
--- a/test/about/ledgerPanelTest.js
+++ b/test/about/ledgerPanelTest.js
@@ -154,11 +154,11 @@ describe('Regular payment panel tests', function () {
.tabByIndex(0)
.loadUrl(site1)
.windowByUrl(Brave.browserWindowUrl)
- .waitForSiteEntry(site1)
+ .waitForHistoryEntry(site1)
.tabByUrl(site1)
.loadUrl(site2)
.windowByUrl(Brave.browserWindowUrl)
- .waitForSiteEntry(site2)
+ .waitForHistoryEntry(site2)
.tabByUrl(site2)
.loadUrl(prefsUrl)
.waitForVisible(paymentsTab)
@@ -197,11 +197,11 @@ describe('Regular payment panel tests', function () {
.tabByIndex(0)
.loadUrl(site1)
.windowByUrl(Brave.browserWindowUrl)
- .waitForSiteEntry(site1)
+ .waitForHistoryEntry(site1)
.tabByUrl(site1)
.loadUrl(site2)
.windowByUrl(Brave.browserWindowUrl)
- .waitForSiteEntry(site2)
+ .waitForHistoryEntry(site2)
.tabByUrl(site2)
.loadUrl(prefsUrl)
.waitForVisible(paymentsTab)
@@ -240,11 +240,11 @@ describe('Regular payment panel tests', function () {
.tabByIndex(0)
.loadUrl(site1)
.windowByUrl(Brave.browserWindowUrl)
- .waitForSiteEntry(site1)
+ .waitForHistoryEntry(site1)
.tabByUrl(site1)
.loadUrl(site2)
.windowByUrl(Brave.browserWindowUrl)
- .waitForSiteEntry(site2)
+ .waitForHistoryEntry(site2)
.tabByUrl(site2)
.loadUrl(prefsUrl)
.waitForVisible(paymentsTab)
@@ -296,11 +296,11 @@ describe('Regular payment panel tests', function () {
yield this.app.client
.loadUrl(site1)
.windowByUrl(Brave.browserWindowUrl)
- .waitForSiteEntry(site1)
+ .waitForHistoryEntry(site1)
.tabByUrl(site1)
.loadUrl(site2)
.windowByUrl(Brave.browserWindowUrl)
- .waitForSiteEntry(site2)
+ .waitForHistoryEntry(site2)
.tabByUrl(site2)
.loadUrl(prefsUrl)
.waitForVisible(paymentsTab)
@@ -326,11 +326,11 @@ describe('Regular payment panel tests', function () {
.tabByIndex(0)
.loadUrl(site1)
.windowByUrl(Brave.browserWindowUrl)
- .waitForSiteEntry(site1)
+ .waitForHistoryEntry(site1)
.tabByUrl(site1)
.loadUrl(site2)
.windowByUrl(Brave.browserWindowUrl)
- .waitForSiteEntry(site2)
+ .waitForHistoryEntry(site2)
.tabByUrl(site2)
.loadUrl(prefsUrl)
.waitForVisible(paymentsTab)
@@ -354,14 +354,14 @@ describe('Regular payment panel tests', function () {
.tabByIndex(0)
.loadUrl(site1)
.windowByUrl(Brave.browserWindowUrl)
- .waitForSiteEntry(site1)
+ .waitForHistoryEntry(site1)
.tabByUrl(site1)
.windowByUrl(Brave.browserWindowUrl)
.changeSetting(settings.AUTO_SUGGEST_SITES, false)
.tabByIndex(0)
.loadUrl(site2)
.windowByUrl(Brave.browserWindowUrl)
- .waitForSiteEntry(site2)
+ .waitForHistoryEntry(site2)
.tabByUrl(site2)
.loadUrl(prefsUrl)
.waitForVisible(paymentsTab)
@@ -419,15 +419,15 @@ describe('synopsis', function () {
yield this.app.client
.loadUrl(site3)
.windowByUrl(Brave.browserWindowUrl)
- .waitForSiteEntry(site3, false)
+ .waitForHistoryEntry(site3, false)
.tabByUrl(site3)
.loadUrl(site1)
.windowByUrl(Brave.browserWindowUrl)
- .waitForSiteEntry(site1)
+ .waitForHistoryEntry(site1)
.tabByUrl(site1)
.loadUrl(site2)
.windowByUrl(Brave.browserWindowUrl)
- .waitForSiteEntry(site2)
+ .waitForHistoryEntry(site2)
.tabByUrl(site2)
.loadUrl(prefsUrl)
.waitForVisible(paymentsTab)
diff --git a/test/about/ledgerTableTest.js b/test/about/ledgerTableTest.js
index 8278563f569..5a507f5ba95 100644
--- a/test/about/ledgerTableTest.js
+++ b/test/about/ledgerTableTest.js
@@ -56,7 +56,7 @@ function * before (client, siteList) {
.tabByIndex(0)
.loadUrl(site)
.windowByUrl(Brave.browserWindowUrl)
- .waitForSiteEntry(site, false)
+ .waitForHistoryEntry(site, false)
.tabByUrl(site)
}
diff --git a/test/about/newTabTest.js b/test/about/newTabTest.js
index 4ec019c0bba..bc7283ed421 100644
--- a/test/about/newTabTest.js
+++ b/test/about/newTabTest.js
@@ -42,23 +42,23 @@ describe('about:newtab tests', function () {
function * addDemoAboutPages (client) {
yield client
- .addSite({ location: 'about:about' })
- .addSite({ location: 'about:adblock' })
- .addSite({ location: 'about:autofill' })
- .addSite({ location: 'about:blank' })
- .addSite({ location: 'about:bookmarks' })
- .addSite({ location: 'about:brave' })
- .addSite({ location: 'about:certerror' })
- .addSite({ location: 'about:config' })
- .addSite({ location: 'about:downloads' })
- .addSite({ location: 'about:error' })
- .addSite({ location: 'about:extensions' })
- .addSite({ location: 'about:history' })
- .addSite({ location: 'about:newtab' })
- .addSite({ location: 'about:passwords' })
- .addSite({ location: 'about:preferences' })
- .addSite({ location: 'about:safebrowsing' })
- .addSite({ location: 'about:styles' })
+ .addHistorySite({ location: 'about:about' })
+ .addHistorySite({ location: 'about:adblock' })
+ .addHistorySite({ location: 'about:autofill' })
+ .addHistorySite({ location: 'about:blank' })
+ .addHistorySite({ location: 'about:bookmarks' })
+ .addHistorySite({ location: 'about:brave' })
+ .addHistorySite({ location: 'about:certerror' })
+ .addHistorySite({ location: 'about:config' })
+ .addHistorySite({ location: 'about:downloads' })
+ .addHistorySite({ location: 'about:error' })
+ .addHistorySite({ location: 'about:extensions' })
+ .addHistorySite({ location: 'about:history' })
+ .addHistorySite({ location: 'about:newtab' })
+ .addHistorySite({ location: 'about:passwords' })
+ .addHistorySite({ location: 'about:preferences' })
+ .addHistorySite({ location: 'about:safebrowsing' })
+ .addHistorySite({ location: 'about:styles' })
.waitForExist('[data-test-id="tab"][data-frame-key="1"]')
.tabByIndex(0)
.url(aboutNewTabUrl)
diff --git a/test/app/sessionStoreTest.js b/test/app/sessionStoreTest.js
index e3a384529b4..7f5aa9aeee4 100644
--- a/test/app/sessionStoreTest.js
+++ b/test/app/sessionStoreTest.js
@@ -6,7 +6,7 @@ const siteTags = require('../../js/constants/siteTags')
const settings = require('../../js/constants/settings')
describe('sessionStore test', function () {
- function * setup (client) {
+ function * setup () {
Brave.addCommands()
}
@@ -16,7 +16,8 @@ describe('sessionStore test', function () {
const page1Url = Brave.server.url('page1.html')
const site = {
location: page1Url,
- title: 'some page'
+ title: 'some page',
+ type: siteTags.BOOKMARK
}
yield Brave.startApp()
yield setup(Brave.app.client)
@@ -28,7 +29,7 @@ describe('sessionStore test', function () {
.windowParentByUrl(page1Url)
.activateURLMode()
.waitForExist(navigatorNotBookmarked)
- .addBookmark(site, siteTags.BOOKMARK)
+ .addBookmark(site)
.waitForExist(navigatorBookmarked)
yield Brave.stopApp(false)
yield Brave.startApp()
@@ -62,7 +63,8 @@ describe('sessionStore test', function () {
const page1Url = Brave.server.url('page1.html')
const site = {
location: page1Url,
- title: 'some page'
+ title: 'some page',
+ type: siteTags.BOOKMARK
}
yield Brave.startApp()
yield setup(Brave.app.client)
@@ -74,7 +76,7 @@ describe('sessionStore test', function () {
.windowParentByUrl(page1Url)
.activateURLMode()
.waitForExist(navigatorNotBookmarked)
- .addBookmark(site, siteTags.BOOKMARK)
+ .addBookmark(site)
.waitForExist(navigatorBookmarked)
yield Brave.stopApp(false)
diff --git a/test/bookmark-components/bookmarksTest.js b/test/bookmark-components/bookmarksTest.js
index 60859a6aef8..fe75a7ebe48 100644
--- a/test/bookmark-components/bookmarksTest.js
+++ b/test/bookmark-components/bookmarksTest.js
@@ -1,7 +1,6 @@
/* global describe, it, before, beforeEach */
const Brave = require('../lib/brave')
-const Immutable = require('immutable')
const {homepageInput, urlInput, navigator, navigatorBookmarked, navigatorNotBookmarked, doneButton, removeButton, bookmarkNameInput, bookmarkLocationInput} = require('../lib/selectors')
const siteTags = require('../../js/constants/siteTags')
@@ -87,7 +86,7 @@ describe('bookmark tests', function () {
.windowByUrl(Brave.browserWindowUrl)
.waitUntil(function () {
return this.getAppState().then((val) => {
- return val.value.sites['https://www.brave.xn--com-8cd/|0|0'].customTitle === 'https://www.brave.xn--com-8cd/'
+ return val.value.sites['https://www.brave.xn--com-8cd/|0|0'].title === 'https://www.brave.xn--com-8cd/'
})
})
})
@@ -303,12 +302,12 @@ describe('bookmark tests', function () {
this.page2Url = Brave.server.url('page2.html')
yield setup(this.app.client)
yield this.app.client
- .addSite({
+ .addBookmark({
location: this.page1Url,
folderId: 1,
parentFolderId: 0,
- tags: [siteTags.BOOKMARK]
- }, siteTags.BOOKMARK)
+ type: siteTags.BOOKMARK
+ })
})
it('on new active tabs', function * () {
@@ -332,9 +331,18 @@ describe('bookmark tests', function () {
})
describe('menu behavior', function () {
+ // Skip this test if we are not on Windows,
+ // we only generate menu on windows
+ const isWindows = process.platform === 'win32'
+
Brave.beforeAll(this)
before(function * () {
+ if (!isWindows) {
+ this.skip()
+ return
+ }
+
yield setup(this.app.client)
})
@@ -342,12 +350,12 @@ describe('bookmark tests', function () {
const folderName = 'bookmark-folder-rebuild-menu-demo'
yield this.app.client
- .addSite({
+ .addBookmarkFolder({
customTitle: folderName,
folderId: 1,
parentFolderId: 0,
- tags: [siteTags.BOOKMARK_FOLDER]
- }, siteTags.BOOKMARK_FOLDER)
+ type: siteTags.BOOKMARK_FOLDER
+ })
.waitUntil(function () {
return this.getAppState().then((val) => {
const bookmarksMenu = val.value.menu.template.find((item) => {
@@ -368,12 +376,12 @@ describe('bookmark tests', function () {
const bookmarkTitle = 'bookmark-rebuild-menu-demo'
yield this.app.client
- .addSite({
+ .addBookmark({
lastAccessedTime: 456,
- tags: [siteTags.BOOKMARK],
+ type: siteTags.BOOKMARK,
location: 'https://brave.com',
title: bookmarkTitle
- }, siteTags.BOOKMARK)
+ })
.waitUntil(function () {
return this.getAppState().then((val) => {
const bookmarksMenu = val.value.menu.template.find((item) => {
@@ -393,22 +401,19 @@ describe('bookmark tests', function () {
it('rebuilds the menu when add a list of items', function * () {
const bookmarkTitle = 'bookmark-rebuild-menu-demo'
const folderName = 'bookmark-folder-rebuild-menu-demo'
- const sites = Immutable.fromJS([
- {
+ yield this.app.client
+ .addBookmarkFolder({
customTitle: folderName,
folderId: 1,
parentFolderId: 0,
- tags: [siteTags.BOOKMARK_FOLDER]
- },
- {
+ type: siteTags.BOOKMARK_FOLDER
+ })
+ .addBookmark({
lastAccessedTime: 123,
title: bookmarkTitle,
location: 'https://brave.com',
- tags: [siteTags.BOOKMARK]
- }
- ])
- yield this.app.client
- .addSiteList(sites)
+ type: siteTags.BOOKMARK
+ })
.waitForBrowserWindow()
.waitUntil(function () {
return this.getAppState().then((val) => {
diff --git a/test/bookmark-components/bookmarksToolbarTest.js b/test/bookmark-components/bookmarksToolbarTest.js
index f632a03d6bf..759f7a30e6f 100644
--- a/test/bookmark-components/bookmarksToolbarTest.js
+++ b/test/bookmark-components/bookmarksToolbarTest.js
@@ -57,12 +57,12 @@ describe('bookmarksToolbar', function () {
yield this.app.client
.changeSetting(settings.SHOW_BOOKMARKS_TOOLBAR, true)
.waitForVisible(bookmarksToolbar)
- .addSite({
+ .addBookmarkFolder({
customTitle: 'demo1',
folderId: Math.random(),
parentFolderId: 0,
- tags: [siteTags.BOOKMARK_FOLDER]
- }, siteTags.BOOKMARK_FOLDER)
+ type: siteTags.BOOKMARK_FOLDER
+ })
.waitForVisible('[data-test-id="bookmarkToolbarButton"][title=demo1]')
.click(bookmarksToolbar)
.click('[data-test-id="bookmarkToolbarButton"][title=demo1]')
@@ -78,23 +78,23 @@ describe('bookmarksToolbar', function () {
yield this.app.client
.changeSetting(settings.SHOW_BOOKMARKS_TOOLBAR, true)
.waitForVisible(bookmarksToolbar)
- .addSite({
+ .addBookmarkFolder({
customTitle: 'demo1',
folderId: folderId1,
parentFolderId: 0,
- tags: [siteTags.BOOKMARK_FOLDER]
- }, siteTags.BOOKMARK_FOLDER)
+ type: siteTags.BOOKMARK_FOLDER
+ })
.waitUntil(function () {
return this.getAppState().then((val) => {
return findBookmarkFolder('demo1', val)
})
})
- .addSite({
+ .addBookmarkFolder({
customTitle: 'demo2',
folderId: folderId2,
parentFolderId: 0,
- tags: [siteTags.BOOKMARK_FOLDER]
- }, siteTags.BOOKMARK_FOLDER)
+ type: siteTags.BOOKMARK_FOLDER
+ })
.waitUntil(function () {
return this.getAppState().then((val) => {
return findBookmarkFolder('demo2', val)
@@ -103,7 +103,7 @@ describe('bookmarksToolbar', function () {
.waitForUrl(Brave.newTabUrl)
.loadUrl(this.page1Url)
.windowParentByUrl(this.page1Url)
- .waitForSiteEntry(this.page1Url)
+ .waitForHistoryEntry(this.page1Url)
.waitForVisible(navigator)
.activateURLMode()
.waitForVisible(navigatorNotBookmarked)
@@ -123,12 +123,12 @@ describe('bookmarksToolbar', function () {
yield this.app.client
.changeSetting(settings.SHOW_BOOKMARKS_TOOLBAR, true)
.waitForVisible(bookmarksToolbar)
- .addSite({
+ .addBookmarkFolder({
customTitle: 'demo1',
folderId: Math.random(),
parentFolderId: 0,
- tags: [siteTags.BOOKMARK_FOLDER]
- }, siteTags.BOOKMARK_FOLDER)
+ type: siteTags.BOOKMARK_FOLDER
+ })
.waitUntil(function () {
return this.getAppState().then((val) => {
return findBookmarkFolder('demo1', val)
@@ -137,7 +137,7 @@ describe('bookmarksToolbar', function () {
.waitForUrl(Brave.newTabUrl)
.loadUrl(this.page1Url)
.windowParentByUrl(this.page1Url)
- .waitForSiteEntry(this.page1Url)
+ .waitForHistoryEntry(this.page1Url)
.waitForVisible(navigator)
.activateURLMode()
.waitForVisible(navigatorNotBookmarked)
@@ -172,7 +172,7 @@ describe('bookmarksToolbar', function () {
.waitForUrl(Brave.newTabUrl)
.loadUrl(pageWithFavicon)
.windowParentByUrl(pageWithFavicon)
- .waitForSiteEntry(pageWithFavicon, false)
+ .waitForHistoryEntry(pageWithFavicon, false)
.activateURLMode()
.waitForVisible(navigatorNotBookmarked)
.click(navigatorNotBookmarked)
@@ -197,7 +197,7 @@ describe('bookmarksToolbar', function () {
.waitForUrl(Brave.newTabUrl)
.loadUrl(pageWithoutFavicon)
.windowParentByUrl(pageWithoutFavicon)
- .waitForSiteEntry(pageWithoutFavicon, false)
+ .waitForHistoryEntry(pageWithoutFavicon, false)
.activateURLMode()
.waitForVisible(navigatorNotBookmarked)
.click(navigatorNotBookmarked)
diff --git a/test/lib/brave.js b/test/lib/brave.js
index f7f7eff2d64..15e981c205d 100644
--- a/test/lib/brave.js
+++ b/test/lib/brave.js
@@ -452,19 +452,6 @@ var exports = {
}, 5000, null, 100)
})
- this.app.client.addCommand('waitForSiteEntry', function (location, waitForTitle = true) {
- logVerbose('waitForSiteEntry("' + location + '", "' + waitForTitle + '")')
- return this.waitUntil(function () {
- return this.getAppState().then((val) => {
- const ret = val.value && val.value.sites && Array.from(Object.values(val.value.sites)).find(
- (site) => site.location === location &&
- (!waitForTitle || (waitForTitle && site.title)))
- logVerbose('waitForSiteEntry("' + location + ', ' + waitForTitle + '") => ' + ret)
- return ret
- })
- }, 5000, null, 100)
- })
-
this.app.client.addCommand('waitForAddressEntry', function (location, waitForTitle = true) {
logVerbose('waitForAddressEntry("' + location + '", "' + waitForTitle + '")')
return this.waitUntil(function () {
@@ -473,7 +460,7 @@ var exports = {
(site) => site.location === location &&
(!waitForTitle || (waitForTitle && site.title)))
logVerbose('sites:' + JSON.stringify(val.value.sites))
- logVerbose('waitForSiteEntry("' + location + '", ' + waitForTitle + ') => ' + ret)
+ logVerbose('waitForAddressEntry("' + location + '", ' + waitForTitle + ') => ' + ret)
return ret
})
}, 5000, null, 100)
@@ -672,51 +659,114 @@ var exports = {
})
/**
- * Adds a site to the sites list, such as a bookmarks.
+ * Adds a bookmark
*
* @param {object} siteDetail - Properties for the siteDetail to add
- * @param {string} tag - A site tag from js/constants/siteTags.js
*/
- this.app.client.addCommand('addSite', function (siteDetail, tag) {
- logVerbose('addSite("' + siteDetail + '", "' + tag + '")')
+ this.app.client.addCommand('addBookmark', function (siteDetail) {
+ logVerbose('addBookmark("' + siteDetail + '")')
let waitUrl = siteDetail.location
if (isSourceAboutUrl(waitUrl)) {
waitUrl = getTargetAboutUrl(waitUrl)
}
- return this.execute(function (siteDetail, tag) {
- return devTools('appActions').addSite(siteDetail, tag)
- }, siteDetail, tag).then((response) => response.value)
- .waitForSiteEntry(waitUrl, false)
+ return this.execute(function (siteDetail) {
+ return devTools('appActions').addBookmark(siteDetail)
+ }, siteDetail).then((response) => response.value)
+ .waitForBookmarkEntry(waitUrl, false)
+ })
+
+ this.app.client.addCommand('waitForBookmarkEntry', function (location, waitForTitle = true) {
+ logVerbose('waitForBookmarkEntry("' + location + '", "' + waitForTitle + '")')
+ return this.waitUntil(function () {
+ return this.getAppState().then((val) => {
+ const ret = val.value && val.value.bookmarks && Array.from(Object.values(val.value.bookmarks)).find(
+ (bookmark) => bookmark.location === location &&
+ (!waitForTitle || (waitForTitle && bookmark.title)))
+ logVerbose('waitForBookmarkEntry("' + location + ', ' + waitForTitle + '") => ' + ret)
+ return ret
+ })
+ }, 5000, null, 100)
})
/**
- * Adds a bookmark to the bookmarks list.
+ * Adds a history site
*
* @param {object} siteDetail - Properties for the siteDetail to add
- * @param {string} tag - A site tag from js/constants/siteTags.js
*/
- this.app.client.addCommand('addBookmark', function (siteDetail, tag) {
- logVerbose('addBookmark("' + siteDetail + '", "' + tag + '")')
+ this.app.client.addCommand('addHistorySite', function (siteDetail) {
+ logVerbose('addHistorySite("' + siteDetail + '")')
let waitUrl = siteDetail.location
if (isSourceAboutUrl(waitUrl)) {
waitUrl = getTargetAboutUrl(waitUrl)
}
- return this.execute(function (siteDetail, tag) {
- return devTools('appActions').addBookmark(siteDetail, tag)
- }, siteDetail, tag).then((response) => response.value)
- .waitForSiteEntry(waitUrl, false)
+ return this.execute(function (siteDetail) {
+ return devTools('appActions').addHistorySite(siteDetail)
+ }, siteDetail).then((response) => response.value)
+ .waitForHistoryEntry(waitUrl, false)
+ })
+
+ this.app.client.addCommand('waitForHistoryEntry', function (location, waitForTitle = true) {
+ logVerbose('waitForHistoryEntry("' + location + '", "' + waitForTitle + '")')
+ return this.waitUntil(function () {
+ return this.getAppState().then((val) => {
+ const ret = val.value && val.value.historySites && Array.from(Object.values(val.value.historySites)).find(
+ (site) => site.location === location &&
+ (!waitForTitle || (waitForTitle && site.title)))
+ logVerbose('waitForHistoryEntry("' + location + ', ' + waitForTitle + '") => ' + ret)
+ return ret
+ })
+ }, 5000, null, 100)
})
/**
- * Adds a list sites to the sites list, including bookmark and foler.
+ * Adds a bookmark folder
*
* @param {object} siteDetail - Properties for the siteDetail to add
*/
- this.app.client.addCommand('addSiteList', function (siteDetail) {
- logVerbose('addSiteList("' + siteDetail + '")')
+ this.app.client.addCommand('addBookmarkFolder', function (siteDetail) {
+ logVerbose('addBookmarkFolder("' + siteDetail + '")')
return this.execute(function (siteDetail) {
- return devTools('appActions').addSite(siteDetail)
+ return devTools('appActions').addBookmarkFolder(siteDetail)
}, siteDetail).then((response) => response.value)
+ .waitForBookmarkFolderEntry(siteDetail.folderId, false)
+ })
+
+ this.app.client.addCommand('waitForBookmarkFolderEntry', function (folderId, waitForTitle = true) {
+ logVerbose('waitForBookmarkFolderEntry("' + folderId + '", "' + waitForTitle + '")')
+ return this.waitUntil(function () {
+ return this.getAppState().then((val) => {
+ const ret = val.value && val.value.bookmarkFolders && Array.from(Object.values(val.value.bookmarkFolders)).find(
+ (folder) => folder.folderId === folderId &&
+ (!waitForTitle || (waitForTitle && folder.title)))
+ logVerbose('waitForBookmarkFolderEntry("' + folderId + ', ' + waitForTitle + '") => ' + ret)
+ return ret
+ })
+ }, 5000, null, 100)
+ })
+
+ /**
+ * Adds a list of bookmarks
+ *
+ * @param {object} bookmarkList - List of bookmarks to add
+ */
+ // TODO fix
+ this.app.client.addCommand('addBookmarks', function (bookmarkList) {
+ logVerbose('addBookmarks("' + bookmarkList + '")')
+ return this.execute(function (bookmarkList) {
+ return devTools('appActions').addBookmark(bookmarkList)
+ }, bookmarkList).then((response) => response.value)
+ })
+
+ /**
+ * Adds a list of history sites
+ *
+ * @param {object} historyList - List of history sites to add
+ */
+ this.app.client.addCommand('addHistorySites', function (historyList) {
+ logVerbose('addHistorySites("' + historyList + '")')
+ return this.execute(function (historyList) {
+ return devTools('appActions').addHistorySites(historyList)
+ }, historyList).then((response) => response.value)
})
/**
diff --git a/test/misc-components/syncTest.js b/test/misc-components/syncTest.js
index 7f81c8e710b..af375e6e711 100644
--- a/test/misc-components/syncTest.js
+++ b/test/misc-components/syncTest.js
@@ -673,7 +673,7 @@ describe('Syncing history', function () {
.tabByIndex(0)
.loadUrl(this.page1Url)
.windowParentByUrl(this.page1Url)
- .waitForSiteEntry(this.page1Url)
+ .waitForHistoryEntry(this.page1Url)
// For order: Visit page 2
yield Brave.app.client
diff --git a/test/navbar-components/navigationBarTest.js b/test/navbar-components/navigationBarTest.js
index 48e63e356bc..d54749830f8 100644
--- a/test/navbar-components/navigationBarTest.js
+++ b/test/navbar-components/navigationBarTest.js
@@ -1181,8 +1181,8 @@ describe('navigationBar tests', function () {
.waitForExist(urlInput)
.waitForElementFocus(urlInput)
.waitForInputText(urlInput, '')
- .addSite({ location: 'https://brave.com', title: 'Brave' })
- .waitForSiteEntry('https://brave.com')
+ .addHistorySite({ location: 'https://brave.com', title: 'Brave' })
+ .waitForHistoryEntry('https://brave.com')
.keys('br')
yield selectsText(this.app.client, 'ave.com')
yield blur(this.app.client)
@@ -1261,7 +1261,7 @@ describe('navigationBar tests', function () {
.url(page1Url)
.waitForUrl(page1Url)
.windowParentByUrl(page1Url)
- .waitForSiteEntry(page1Url)
+ .waitForHistoryEntry(page1Url)
.activateURLMode()
.waitForExist(navigatorNotBookmarked)
.click(navigatorNotBookmarked)
diff --git a/test/navbar-components/urlBarSuggestionsTest.js b/test/navbar-components/urlBarSuggestionsTest.js
index 52fa5cee56d..b8cfc3c9e27 100644
--- a/test/navbar-components/urlBarSuggestionsTest.js
+++ b/test/navbar-components/urlBarSuggestionsTest.js
@@ -24,11 +24,11 @@ describe('urlBarSuggestions', function () {
.tabByIndex(0)
.loadUrl(this.page1Url)
.windowByUrl(Brave.browserWindowUrl)
- .waitForSiteEntry(this.page1Url)
+ .waitForHistoryEntry(this.page1Url)
.tabByIndex(0)
.loadUrl(this.page2Url)
.windowByUrl(Brave.browserWindowUrl)
- .waitForSiteEntry(this.page2Url)
+ .waitForHistoryEntry(this.page2Url)
.newTab()
.waitForUrl(Brave.newTabUrl)
.windowByUrl(Brave.browserWindowUrl)
diff --git a/test/navbar-components/urlBarTest.js b/test/navbar-components/urlBarTest.js
index 6206086dff7..fb840bfe1ec 100644
--- a/test/navbar-components/urlBarTest.js
+++ b/test/navbar-components/urlBarTest.js
@@ -29,7 +29,7 @@ describe('urlBar tests', function () {
yield this.app.client.waitForElementFocus(urlInput)
yield this.app.client
.onClearBrowsingData('browserHistory', true)
- .addSite({ location: 'https://brave.com', title: 'Brave' })
+ .addHistorySite({ location: 'https://brave.com', title: 'Brave' })
})
// OMG, Brad would hate this test!
@@ -65,10 +65,10 @@ describe('urlBar tests', function () {
yield this.app.client
.onClearBrowsingData('browserHistory', true)
- .addSite({ location: 'https://brave.com', title: 'Brave' })
- .addSite({ location: 'https://brave.com/test' })
- .addSite({ location: 'https://www.youtube.com' })
- .addSite({ location: 'http://uncrate.com' })
+ .addHistorySite({ location: 'https://brave.com', title: 'Brave' })
+ .addHistorySite({ location: 'https://brave.com/test' })
+ .addHistorySite({ location: 'https://www.youtube.com' })
+ .addHistorySite({ location: 'http://uncrate.com' })
})
describe('press backspace key', function () {
@@ -150,7 +150,7 @@ describe('urlBar tests', function () {
describe('typing prefix with characters from "https" prefix', function () {
beforeEach(function * () {
yield this.app.client
- .addSite({ location: 'https://slo-tech.com', title: 'title' })
+ .addHistorySite({ location: 'https://slo-tech.com', title: 'title' })
.setInputText(urlInput, '')
.keys('s')
})
@@ -163,7 +163,7 @@ describe('urlBar tests', function () {
describe('typing with characters that do not match prefix should not select first item', function () {
beforeEach(function * () {
yield this.app.client
- .addSite({ location: 'https://slo-tech.com', title: 'title' })
+ .addHistorySite({ location: 'https://slo-tech.com', title: 'title' })
.setInputText(urlInput, '')
.keys('o')
})
@@ -176,7 +176,7 @@ describe('urlBar tests', function () {
describe('typing with characters that do not match prefix should not select first item', function () {
beforeEach(function * () {
yield this.app.client
- .addSite({ location: 'https://slo-tech.com', title: 'title' })
+ .addHistorySite({ location: 'https://slo-tech.com', title: 'title' })
.setInputText(urlInput, '')
.keys('o')
})
@@ -378,12 +378,12 @@ describe('urlBar tests', function () {
it('typing in the urlbar should override mouse hover for suggestions', function * () {
yield this.app.client
- .addSite({ location: 'https://brave.com', title: 'Brave' })
- .addSite({ location: 'https://brave.com/test' })
- .addSite({ location: 'https://brave.com/test2' })
- .addSite({ location: 'https://brave.com/test3' })
- .addSite({ location: 'https://brave.com/test4' })
- .addSite({ location: 'https://brianbondy.com/test4' })
+ .addHistorySite({ location: 'https://brave.com', title: 'Brave' })
+ .addHistorySite({ location: 'https://brave.com/test' })
+ .addHistorySite({ location: 'https://brave.com/test2' })
+ .addHistorySite({ location: 'https://brave.com/test3' })
+ .addHistorySite({ location: 'https://brave.com/test4' })
+ .addHistorySite({ location: 'https://brianbondy.com/test4' })
.resizeWindow(500, 300)
.setValue(urlInput, 'b')
.waitForVisible(urlBarSuggestions)
@@ -688,7 +688,7 @@ describe('urlBar tests', function () {
yield this.app.client.waitForExist(urlInput)
yield this.app.client.waitForElementFocus(urlInput)
yield this.app.client
- .addSiteList(sites)
+ .addHistorySites(sites)
.waitForInputText(urlInput, '')
.windowByUrl(Brave.browserWindowUrl)
.newTab()
@@ -763,8 +763,8 @@ describe('urlBar tests', function () {
yield this.app.client.waitForElementFocus(urlInput)
yield this.app.client
.onClearBrowsingData('browserHistory', true)
- .addSite({ location: 'https://github.com/brave/browser-laptop', title: 'browser-laptop' })
- .addSite({ location: 'https://github.com/brave/ad-block', title: 'Muon' })
+ .addHistorySite({ location: 'https://github.com/brave/browser-laptop', title: 'browser-laptop' })
+ .addHistorySite({ location: 'https://github.com/brave/ad-block', title: 'Muon' })
})
it('changes only the selection', function * () {
diff --git a/test/unit/app/common/lib/pinnedSitesUtilTest.js b/test/unit/app/common/lib/pinnedSitesUtilTest.js
new file mode 100644
index 00000000000..e2ef0ffeedf
--- /dev/null
+++ b/test/unit/app/common/lib/pinnedSitesUtilTest.js
@@ -0,0 +1,39 @@
+/* global describe, it */
+const pinnedSitesUtil = require('../../../../../app/common/lib/pinnedSitesUtil')
+const assert = require('assert')
+const Immutable = require('immutable')
+
+require('../../../braveUnit')
+
+describe('pinnedSitesUtil', () => {
+ const location = 'https://css-tricks.com/'
+ const order = 9
+ const partitionNumber = 5
+ const expectedSiteProps = Immutable.fromJS({
+ location,
+ order,
+ partitionNumber
+ })
+
+ let site = Immutable.fromJS({
+ favicon: 'https://css-tricks.com/favicon.ico',
+ lastAccessedTime: 1493560182224,
+ location: location,
+ order: order,
+ partitionNumber: partitionNumber,
+ title: 'CSS-Tricks'
+ })
+
+ describe('getPinnedSiteProps', () => {
+ it('returns object with necessary fields', () => {
+ const result = pinnedSitesUtil.getPinnedSiteProps(site)
+ assert.deepEqual(expectedSiteProps, result)
+ })
+
+ it('set partitionNumber field to 0 in case of missing this field', () => {
+ const newSite = site.delete('partitionNumber')
+ const result = pinnedSitesUtil.getPinnedSiteProps(newSite)
+ assert.equal(0, result.get('partitionNumber'))
+ })
+ })
+})
diff --git a/test/unit/app/common/lib/windowsUtilTest.js b/test/unit/app/common/lib/windowsUtilTest.js
deleted file mode 100644
index 60ece75b82b..00000000000
--- a/test/unit/app/common/lib/windowsUtilTest.js
+++ /dev/null
@@ -1,40 +0,0 @@
-/* global describe, beforeEach, it */
-const windowsUtil = require('../../../../../app/common/lib/windowsUtil')
-const assert = require('assert')
-const Immutable = require('immutable')
-
-require('../../../braveUnit')
-
-describe('windowsUtil', () => {
- const location = 'https://css-tricks.com/'
- const order = 9
- const partitionNumber = 5
- const expectedSiteProps = Immutable.fromJS({
- location,
- order,
- partitionNumber
- })
- let site
-
- describe('getPinnedSiteProps', () => {
- beforeEach(() => {
- site = Immutable.fromJS({
- favicon: 'https://css-tricks.com/favicon.ico',
- lastAccessedTime: 1493560182224,
- location: location,
- order: order,
- partitionNumber: partitionNumber,
- title: 'CSS-Tricks'
- })
- })
- it('returns object with necessary fields', () => {
- const result = windowsUtil.getPinnedSiteProps(site)
- assert.deepEqual(expectedSiteProps, result)
- })
- it('set partitionNumber field to 0 in case of missing this field', () => {
- site = site.delete('partitionNumber')
- const result = windowsUtil.getPinnedSiteProps(site)
- assert.equal(0, result.get('partitionNumber'))
- })
- })
-})
diff --git a/test/unit/state/siteUtilTest.js b/test/unit/state/siteUtilTest.js
index f45653f3ca0..0114b9feaf8 100644
--- a/test/unit/state/siteUtilTest.js
+++ b/test/unit/state/siteUtilTest.js
@@ -1335,67 +1335,6 @@ describe('siteUtil', function () {
})
})
- describe('isEquivalent', function () {
- it('returns true if both siteDetail objects are identical', function () {
- const siteDetail1 = Immutable.fromJS({
- location: testUrl1,
- partitionNumber: 0,
- tags: [siteTags.BOOKMARK]
- })
- const siteDetail2 = Immutable.fromJS({
- location: testUrl1,
- partitionNumber: 0,
- tags: [siteTags.BOOKMARK]
- })
- assert.equal(siteUtil.isEquivalent(siteDetail1, siteDetail2), true)
- })
- it('returns false if one object is a folder and the other is not', function () {
- const siteDetail1 = Immutable.fromJS({
- tags: [siteTags.BOOKMARK]
- })
- const siteDetail2 = Immutable.fromJS({
- tags: [siteTags.BOOKMARK_FOLDER],
- folderId: 1
- })
- assert.equal(siteUtil.isEquivalent(siteDetail1, siteDetail2), false)
- })
- it('returns false if both are folders and have a different folderId', function () {
- const siteDetail1 = Immutable.fromJS({
- tags: [siteTags.BOOKMARK_FOLDER],
- folderId: 0
- })
- const siteDetail2 = Immutable.fromJS({
- tags: [siteTags.BOOKMARK_FOLDER],
- folderId: 1
- })
- assert.equal(siteUtil.isEquivalent(siteDetail1, siteDetail2), false)
- })
- it('returns false if both are bookmarks and have a different location', function () {
- const siteDetail1 = Immutable.fromJS({
- tags: [siteTags.BOOKMARK],
- location: testUrl1
- })
- const siteDetail2 = Immutable.fromJS({
- tags: [siteTags.BOOKMARK],
- location: 'http://example.com/'
- })
- assert.equal(siteUtil.isEquivalent(siteDetail1, siteDetail2), false)
- })
- it('returns false if both are bookmarks and have a different partitionNumber', function () {
- const siteDetail1 = Immutable.fromJS({
- tags: [siteTags.BOOKMARK],
- location: testUrl1,
- partitionNumber: 0
- })
- const siteDetail2 = Immutable.fromJS({
- tags: [siteTags.BOOKMARK],
- location: testUrl2,
- partitionNumber: 1
- })
- assert.equal(siteUtil.isEquivalent(siteDetail1, siteDetail2), false)
- })
- })
-
describe('isFolder', function () {
it('returns true if the input is a siteDetail and has a `BOOKMARK_FOLDER` tag and a folder ID', function () {
const siteDetail = Immutable.fromJS({
@@ -1683,20 +1622,4 @@ describe('siteUtil', function () {
assert.strictEqual(siteUtil.getOrigin('http://http/test'), 'http://http')
})
})
- describe('isPinnedTab', function () {
- it('detects pinned tab site', function () {
- assert.strictEqual(siteUtil.isPinnedTab(siteTags.PINNED), true)
- assert.strictEqual(siteUtil.isPinnedTab([siteTags.PINNED]), true)
- })
- it('detects not pinned for no site tags', function () {
- assert.strictEqual(siteUtil.isPinnedTab([]), false)
- })
- it('detects not pinned for site tags which are not PINNED', function () {
- assert.strictEqual(siteUtil.isPinnedTab(siteTags.BOOKMARK), false)
- assert.strictEqual(siteUtil.isPinnedTab([siteTags.BOOKMARK]), false)
- })
- it('detects pinned when bookmarked and pinned', function () {
- assert.strictEqual(siteUtil.isPinnedTab([siteTags.PINNED, siteTags.BOOKMARK]), true)
- })
- })
})