diff --git a/app/renderer/about/bookmarks/bookmarkFolderItem.js b/app/renderer/about/bookmarks/bookmarkFolderItem.js
new file mode 100644
index 00000000000..f2a31c5d9a4
--- /dev/null
+++ b/app/renderer/about/bookmarks/bookmarkFolderItem.js
@@ -0,0 +1,134 @@
+/* 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')
+
+// Components
+const ImmutableComponent = require('../../components/immutableComponent')
+
+// Actions
+const aboutActions = require('../../../../js/about/aboutActions')
+
+// Constants
+const dragTypes = require('../../../../js/constants/dragTypes')
+
+// Utils
+const dndData = require('../../../../js/dndData')
+const siteUtil = require('../../../../js/state/siteUtil')
+const cx = require('../../../../js/lib/classSet')
+
+class BookmarkFolderItem extends ImmutableComponent {
+ constructor (props) {
+ super(props)
+ this.state = {
+ isDragOver: false
+ }
+ }
+ onDragStart (e) {
+ if (this.props.draggable !== false) {
+ e.dataTransfer.effectAllowed = 'all'
+ dndData.setupDataTransferURL(e.dataTransfer,
+ this.props.bookmarkFolder.get('location'),
+ this.props.bookmarkFolder.get('customTitle') || this.props.bookmarkFolder.get('title'))
+ dndData.setupDataTransferBraveData(e.dataTransfer, dragTypes.BOOKMARK, this.props.bookmarkFolder)
+ }
+ }
+ onDragOver (e) {
+ e.preventDefault()
+ e.dataTransfer.dropEffect = 'move'
+ this.setState({
+ isDragOver: true
+ })
+ }
+ onDragLeave (e) {
+ this.setState({
+ isDragOver: false
+ })
+ }
+ /**
+ * Move a folder, a bookmark, or multiple bookmarks IF move is allowed.
+ * ex: won't allow child folder to become parent of an ancestor, etc.
+ */
+ 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)
+ }
+ }
+ clearSelection () {
+ if (this.props.onClearSelection) {
+ this.props.onClearSelection()
+ }
+ }
+ // NOTE: both folders AND bookmarks can be dropped here
+ onDrop (e) {
+ this.setState({
+ isDragOver: false
+ })
+
+ const bookmarkData = dndData.getDragData(e.dataTransfer, dragTypes.BOOKMARK)
+ if (bookmarkData) {
+ if (Immutable.List.isList(bookmarkData)) {
+ bookmarkData.forEach((bookmark) => {
+ this.moveBookmark(e, bookmark)
+ })
+ this.clearSelection()
+ return
+ }
+
+ this.moveBookmark(e, bookmarkData)
+ this.clearSelection()
+ }
+ }
+ 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')}
+
+
+ {
+ childBookmarkFolders.size > 0
+ ?
+ : null
+ }
+
+ }
+}
+
+module.exports = BookmarkFolderItem
diff --git a/app/renderer/about/bookmarks/bookmarkFolderList.js b/app/renderer/about/bookmarks/bookmarkFolderList.js
new file mode 100644
index 00000000000..ee918f34731
--- /dev/null
+++ b/app/renderer/about/bookmarks/bookmarkFolderList.js
@@ -0,0 +1,75 @@
+/* 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')
+
+// Components
+const ImmutableComponent = require('../../components/immutableComponent')
+const BookmarkFolderItem = require('./bookmarkFolderItem')
+
+// Constants
+const siteTags = require('../../../../js/constants/siteTags')
+
+class BookmarkFolderList extends ImmutableComponent {
+ render () {
+ return
+ {
+ this.props.isRoot && this.props.search
+ ?
+
+
+
+ : null
+ }
+ {
+ this.props.isRoot
+ ?
+ : null
+ }
+ {
+ this.props.bookmarkFolders.map((bookmarkFolder) =>
+ this.props.isRoot && bookmarkFolder.get('parentFolderId') === -1
+ ? null
+ :
+ )
+ }
+ {
+ this.props.isRoot
+ ?
+ : null
+ }
+
+ }
+}
+
+module.exports = BookmarkFolderList
diff --git a/app/renderer/about/bookmarks/bookmarkTitleCell.js b/app/renderer/about/bookmarks/bookmarkTitleCell.js
new file mode 100644
index 00000000000..f2c99d121e6
--- /dev/null
+++ b/app/renderer/about/bookmarks/bookmarkTitleCell.js
@@ -0,0 +1,56 @@
+/* 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')
+
+// Components
+const ImmutableComponent = require('../../components/immutableComponent')
+
+// Constants
+const {iconSize} = require('../../../../js/constants/config')
+
+// Utils
+const siteUtil = require('../../../../js/state/siteUtil')
+const cx = require('../../../../js/lib/classSet')
+
+class BookmarkTitleCell extends ImmutableComponent {
+ render () {
+ let iconStyle
+ const icon = this.props.siteDetail.get('favicon')
+ if (!siteUtil.isFolder(this.props.siteDetail)) {
+ if (icon) {
+ iconStyle = {
+ minWidth: iconSize,
+ width: iconSize,
+ backgroundImage: `url(${icon})`,
+ backgroundSize: iconSize,
+ height: iconSize
+ }
+ }
+ }
+
+ const bookmarkTitle = this.props.siteDetail.get('customTitle') || this.props.siteDetail.get('title')
+ const bookmarkLocation = this.props.siteDetail.get('location')
+ const defaultIcon = 'fa fa-file-o'
+
+ return
+ {
+
+ }
+ {bookmarkTitle || bookmarkLocation}
+ {
+ bookmarkTitle ? {bookmarkLocation} : null
+ }
+
+ }
+}
+
+module.exports = BookmarkTitleCell
diff --git a/app/renderer/about/bookmarks/bookmarkTitleHeader.js b/app/renderer/about/bookmarks/bookmarkTitleHeader.js
new file mode 100644
index 00000000000..953ca91de7f
--- /dev/null
+++ b/app/renderer/about/bookmarks/bookmarkTitleHeader.js
@@ -0,0 +1,37 @@
+/* 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')
+
+// Components
+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()
+ this.addBookmark = this.addBookmark.bind(this)
+ }
+ addBookmark () {
+ const newBookmark = Immutable.fromJS({
+ parentFolderId: this.props.selectedFolderId,
+ tags: [siteTags.BOOKMARK]
+ })
+ windowActions.addBookmark(newBookmark)
+ }
+ render () {
+ return
+
+
+
+ }
+}
+
+module.exports = BookmarkTitleHeader
diff --git a/app/renderer/about/bookmarks/bookmarks.js b/app/renderer/about/bookmarks/bookmarks.js
new file mode 100644
index 00000000000..936af4a748a
--- /dev/null
+++ b/app/renderer/about/bookmarks/bookmarks.js
@@ -0,0 +1,173 @@
+/* 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/. */
+
+// Note that these are webpack requires, not CommonJS node requiring requires
+const React = require('react')
+const Immutable = require('immutable')
+const ipc = window.chrome.ipcRenderer
+
+// Components
+const {AboutPageSectionTitle} = require('../../components/common/sectionTitle')
+const BookmarkFolderList = require('./bookmarkFolderList')
+const BookmarksList = require('./bookmarksList')
+
+// Constants
+const messages = require('../../../../js/constants/messages')
+const siteTags = require('../../../../js/constants/siteTags')
+
+// Actions
+const aboutActions = require('../../../../js/about/aboutActions')
+const windowActions = require('../../../../js/actions/windowActions')
+
+// Stylesheets
+require('../../../../less/about/bookmarks.less')
+require('../../../../node_modules/font-awesome/css/font-awesome.css')
+
+class Bookmarks extends React.Component {
+ constructor (props) {
+ super(props)
+ this.onChangeSelectedFolder = this.onChangeSelectedFolder.bind(this)
+ this.onChangeSearch = this.onChangeSearch.bind(this)
+ this.onClearSearchText = this.onClearSearchText.bind(this)
+ this.importBrowserData = this.importBrowserData.bind(this)
+ this.exportBookmarks = this.exportBookmarks.bind(this)
+ this.addBookmarkFolder = this.addBookmarkFolder.bind(this)
+ this.onClick = this.onClick.bind(this)
+ this.clearSelection = this.clearSelection.bind(this)
+ this.state = {
+ bookmarks: Immutable.Map(),
+ bookmarkFolders: Immutable.Map(),
+ selectedFolderId: 0,
+ search: ''
+ }
+
+ ipc.on(messages.BOOKMARKS_UPDATED, (e, handle) => {
+ const detail = handle.memory()
+ this.setState({
+ bookmarks: Immutable.fromJS((detail && detail.bookmarks) || {}),
+ bookmarkFolders: Immutable.fromJS((detail && detail.bookmarkFolders) || {})
+ })
+ })
+ }
+
+ onChangeSelectedFolder (id) {
+ this.setState({
+ selectedFolderId: id,
+ search: ''
+ })
+ }
+
+ onChangeSearch (evt) {
+ this.setState({
+ search: evt.target.value
+ })
+ }
+
+ onClearSearchText () {
+ this.setState({
+ search: ''
+ })
+ }
+
+ onClick (e) {
+ // Determine if click was on sortableTable
+ let targetElement = e.target
+ while (targetElement) {
+ if (targetElement.tagName === 'TBODY') {
+ return
+ }
+ targetElement = targetElement.parentNode
+ }
+
+ // Click was not a child element of sortableTable; clear selection
+ this.clearSelection()
+ }
+
+ searchedBookmarks (searchTerm, bookmarks) {
+ return bookmarks.filter((bookmark) => {
+ const title = bookmark.get('customTitle') + 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)
+ }
+
+ importBrowserData () {
+ aboutActions.importBrowserDataNow()
+ }
+
+ exportBookmarks () {
+ aboutActions.exportBookmarks()
+ }
+
+ addBookmarkFolder () {
+ const newFolder = Immutable.fromJS({
+ parentFolderId: this.state.selectedFolderId,
+ tags: [siteTags.BOOKMARK_FOLDER]
+ })
+ windowActions.addBookmark(newFolder)
+ }
+
+ clearSelection () {
+ this.refs.bookmarkList.clearSelection()
+ }
+
+ componentDidMount () {
+ this.refs.bookmarkSearch.focus()
+ }
+
+ render () {
+ return
+
+
+
+
+
+
+
+ {
+ this.state.search
+ ?
+ :
+ }
+
+
+
+
+
+
+
+
+
+
+
bookmark.get('parentFolderId') === -1)}
+ allBookmarkFolders={this.state.bookmarkFolders}
+ isRoot
+ selectedFolderId={this.state.selectedFolderId}
+ search={this.state.search} />
+
+
+
+
+
+
+ }
+}
+
+module.exports =
diff --git a/app/renderer/about/bookmarks/bookmarksList.js b/app/renderer/about/bookmarks/bookmarksList.js
new file mode 100644
index 00000000000..ae5bf5af536
--- /dev/null
+++ b/app/renderer/about/bookmarks/bookmarksList.js
@@ -0,0 +1,148 @@
+/* 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')
+
+// Components
+const ImmutableComponent = require('../../components/immutableComponent')
+const SortableTable = require('../../components/common/sortableTable')
+const BookmarkTitleCell = require('./bookmarkTitleCell')
+const BookmarkTitleHeader = require('./bookmarkTitleHeader')
+
+// Constants
+const dragTypes = require('../../../../js/constants/dragTypes')
+const siteTags = require('../../../../js/constants/siteTags')
+
+// Actions
+const aboutActions = require('../../../../js/about/aboutActions')
+
+// Utils
+const dndData = require('../../../../js/dndData')
+const siteUtil = require('../../../../js/state/siteUtil')
+const formatUtil = require('../../../common/lib/formatUtil')
+
+class BookmarksList extends ImmutableComponent {
+ onDoubleClick (entry, e) {
+ if (e && e.preventDefault) {
+ e.preventDefault()
+ }
+ aboutActions.createTabRequested({
+ url: entry.location,
+ partitionNumber: entry.partitionNumber
+ })
+ }
+ /**
+ * Called when a bookmark (or bookmarks) begin dragging.
+ * If multiple items are selected, please note this method is
+ * called by the onDragStart handler in sortableTable instead
+ * of being directly bound to the table row being dragged.
+ */
+ onDragStart (siteDetail, e) {
+ const isList = Immutable.List.isList(siteDetail)
+ e.dataTransfer.effectAllowed = 'all'
+ dndData.setupDataTransferBraveData(e.dataTransfer, dragTypes.BOOKMARK, siteDetail)
+ // TODO: Pass the location here when content scripts are fixed
+ dndData.setupDataTransferURL(e.dataTransfer, '', isList
+ ? 'Multi-selection (' + siteDetail.size + ' bookmarks)'
+ : siteDetail.get('customTitle') || siteDetail.get('title'))
+ }
+ /**
+ * Bookmark entry is being dragged.
+ */
+ onDragOver (siteDetail, e) {
+ e.preventDefault()
+ e.dataTransfer.dropEffect = 'move'
+ }
+ /**
+ * Move a folder, a bookmark, or multiple bookmarks IF move is allowed.
+ * ex: won't allow child folder to become parent of an ancestor, etc.
+ */
+ moveBookmark (e, bookmark, siteDetail) {
+ let destinationIsParent = false
+
+ // If source is folder, destination needs to be a folder too
+ if (siteUtil.isFolder(bookmark)) {
+ siteDetail = siteDetail.get('parentFolderId')
+ ? this.props.allBookmarkFolders.find((folder) => 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())
+
+ aboutActions.moveSite(bookmarkSiteKey,
+ siteKey,
+ dndData.shouldPrependVerticalItem(e.target, e.clientY),
+ destinationIsParent)
+ }
+ }
+ /**
+ * Bookmark (one or multiple) or BookmarkFolderItem object was dropped
+ * onto `siteDetail` (which is a bookmark inside of sortableTable).
+ */
+ onDrop (siteDetail, e) {
+ const bookmarkData = dndData.getDragData(e.dataTransfer, dragTypes.BOOKMARK)
+ if (bookmarkData) {
+ if (Immutable.List.isList(bookmarkData)) {
+ bookmarkData.forEach((bookmark) => {
+ this.moveBookmark(e, bookmark, siteDetail)
+ })
+ this.clearSelection()
+ return
+ }
+
+ this.moveBookmark(e, bookmarkData, siteDetail)
+ this.clearSelection()
+ }
+ }
+ clearSelection () {
+ this.refs.bookmarkTable.clearSelection()
+ }
+ render () {
+ const props = !this.props.draggable ? {
+ onDragStart: this.onDragStart,
+ sortingDisabled: !this.props.sortable
+ } : {
+ onDoubleClick: this.onDoubleClick,
+ onDragStart: this.onDragStart,
+ onDragOver: this.onDragOver,
+ onDrop: this.onDrop,
+ sortingDisabled: !this.props.sortable
+ }
+ return
+ ,
+
+ ]}
+ defaultHeading='Title'
+ rows={this.props.bookmarks.map((entry) => [
+ {
+ cell: ,
+ value: entry.get('customTitle') || entry.get('title') || entry.get('location')
+ },
+ {
+ html: formatUtil.toLocaleString(entry.get('lastAccessedTime'), ''),
+ value: entry.get('lastAccessedTime') || 0
+ }
+ ])}
+ rowObjects={this.props.bookmarks}
+ columnClassNames={['title', 'date']}
+ addHoverClass
+ multiSelect
+ onDoubleClick={this.onDoubleClick}
+ {...props}
+ contextMenuName='bookmark'
+ thisArg={this}
+ onContextMenu={aboutActions.contextMenu}
+ />
+
+ }
+}
+
+module.exports = BookmarksList
diff --git a/js/about/bookmarks.js b/js/about/bookmarks.js
deleted file mode 100644
index 32ea4046491..00000000000
--- a/js/about/bookmarks.js
+++ /dev/null
@@ -1,508 +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/. */
-
-// Note that these are webpack requires, not CommonJS node requiring requires
-const React = require('react')
-const Immutable = require('immutable')
-const ImmutableComponent = require('../../app/renderer/components/immutableComponent')
-const messages = require('../constants/messages')
-const siteTags = require('../constants/siteTags')
-const dragTypes = require('../constants/dragTypes')
-const aboutActions = require('./aboutActions')
-const dndData = require('../dndData')
-const cx = require('../lib/classSet')
-const SortableTable = require('../../app/renderer/components/common/sortableTable')
-const siteUtil = require('../state/siteUtil')
-const formatUtil = require('../../app/common/lib/formatUtil')
-const {iconSize} = require('../constants/config')
-const windowActions = require('../actions/windowActions')
-
-const ipc = window.chrome.ipcRenderer
-
-const {AboutPageSectionTitle} = require('../../app/renderer/components/common/sectionTitle')
-
-// Stylesheets
-require('../../less/about/bookmarks.less')
-require('../../node_modules/font-awesome/css/font-awesome.css')
-
-class BookmarkFolderItem extends React.Component {
- constructor (props) {
- super(props)
- this.state = {
- isDragOver: false
- }
- }
- onDragStart (e) {
- if (this.props.draggable !== false) {
- e.dataTransfer.effectAllowed = 'all'
- dndData.setupDataTransferURL(e.dataTransfer,
- this.props.bookmarkFolder.get('location'),
- this.props.bookmarkFolder.get('customTitle') || this.props.bookmarkFolder.get('title'))
- dndData.setupDataTransferBraveData(e.dataTransfer, dragTypes.BOOKMARK, this.props.bookmarkFolder)
- }
- }
- onDragOver (e) {
- e.preventDefault()
- e.dataTransfer.dropEffect = 'move'
- this.setState({
- isDragOver: true
- })
- }
- onDragLeave (e) {
- this.setState({
- isDragOver: false
- })
- }
- /**
- * Move a folder, a bookmark, or multiple bookmarks IF move is allowed.
- * ex: won't allow child folder to become parent of an ancestor, etc.
- */
- 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)
- }
- }
- clearSelection () {
- if (this.props.onClearSelection) {
- this.props.onClearSelection()
- }
- }
- // NOTE: both folders AND bookmarks can be dropped here
- onDrop (e) {
- this.setState({
- isDragOver: false
- })
-
- const bookmarkData = dndData.getDragData(e.dataTransfer, dragTypes.BOOKMARK)
- if (bookmarkData) {
- if (Immutable.List.isList(bookmarkData)) {
- bookmarkData.forEach((bookmark) => {
- this.moveBookmark(e, bookmark)
- })
- this.clearSelection()
- return
- }
-
- this.moveBookmark(e, bookmarkData)
- this.clearSelection()
- }
- }
- render () {
- 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')}
-
-
- {
- childBookmarkFolders.size > 0
- ?
- : null
- }
-
- }
-}
-
-class BookmarkFolderList extends ImmutableComponent {
- render () {
- return
- {
- this.props.isRoot && this.props.search
- ?
-
-
-
- : null
- }
- {
- this.props.isRoot
- ?
- : null
- }
- {
- this.props.bookmarkFolders.map((bookmarkFolder) =>
- this.props.isRoot && bookmarkFolder.get('parentFolderId') === -1
- ? null
- : )
- }
- {
- this.props.isRoot
- ?
- : null
- }
-
- }
-}
-
-class BookmarkTitleHeader extends ImmutableComponent {
- constructor () {
- super()
- this.addBookmark = this.addBookmark.bind(this)
- }
- addBookmark () {
- const newBookmark = Immutable.fromJS({
- parentFolderId: this.props.selectedFolderId,
- tags: [siteTags.BOOKMARK]
- })
- windowActions.addBookmark(newBookmark)
- }
- render () {
- return
-
-
-
- }
-}
-
-class BookmarkTitleCell extends ImmutableComponent {
- render () {
- let iconStyle
- const icon = this.props.siteDetail.get('favicon')
- if (!siteUtil.isFolder(this.props.siteDetail)) {
- if (icon) {
- iconStyle = {
- minWidth: iconSize,
- width: iconSize,
- backgroundImage: `url(${icon})`,
- backgroundSize: iconSize,
- height: iconSize
- }
- }
- }
-
- const bookmarkTitle = this.props.siteDetail.get('customTitle') || this.props.siteDetail.get('title')
- const bookmarkLocation = this.props.siteDetail.get('location')
- const defaultIcon = 'fa fa-file-o'
-
- return
- {
-
- }
- {bookmarkTitle || bookmarkLocation}
- {
- bookmarkTitle ? {bookmarkLocation} : null
- }
-
- }
-}
-
-class BookmarksList extends ImmutableComponent {
- onDoubleClick (entry, e) {
- if (e && e.preventDefault) {
- e.preventDefault()
- }
- aboutActions.createTabRequested({
- url: entry.location,
- partitionNumber: entry.partitionNumber
- })
- }
- /**
- * Called when a bookmark (or bookmarks) begin dragging.
- * If multiple items are selected, please note this method is
- * called by the onDragStart handler in sortableTable instead
- * of being directly bound to the table row being dragged.
- */
- onDragStart (siteDetail, e) {
- const isList = Immutable.List.isList(siteDetail)
- e.dataTransfer.effectAllowed = 'all'
- dndData.setupDataTransferBraveData(e.dataTransfer, dragTypes.BOOKMARK, siteDetail)
- // TODO: Pass the location here when content scripts are fixed
- dndData.setupDataTransferURL(e.dataTransfer, '', isList
- ? 'Multi-selection (' + siteDetail.size + ' bookmarks)'
- : siteDetail.get('customTitle') || siteDetail.get('title'))
- }
- /**
- * Bookmark entry is being dragged.
- */
- onDragOver (siteDetail, e) {
- e.preventDefault()
- e.dataTransfer.dropEffect = 'move'
- }
- /**
- * Move a folder, a bookmark, or multiple bookmarks IF move is allowed.
- * ex: won't allow child folder to become parent of an ancestor, etc.
- */
- moveBookmark (e, bookmark, siteDetail) {
- let destinationIsParent = false
-
- // If source is folder, destination needs to be a folder too
- if (siteUtil.isFolder(bookmark)) {
- siteDetail = siteDetail.get('parentFolderId')
- ? this.props.allBookmarkFolders.find((folder) => 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())
-
- aboutActions.moveSite(bookmarkSiteKey,
- siteKey,
- dndData.shouldPrependVerticalItem(e.target, e.clientY),
- destinationIsParent)
- }
- }
- /**
- * Bookmark (one or multiple) or BookmarkFolderItem object was dropped
- * onto `siteDetail` (which is a bookmark inside of sortableTable).
- */
- onDrop (siteDetail, e) {
- const bookmarkData = dndData.getDragData(e.dataTransfer, dragTypes.BOOKMARK)
- if (bookmarkData) {
- if (Immutable.List.isList(bookmarkData)) {
- bookmarkData.forEach((bookmark) => {
- this.moveBookmark(e, bookmark, siteDetail)
- })
- this.clearSelection()
- return
- }
-
- this.moveBookmark(e, bookmarkData, siteDetail)
- this.clearSelection()
- }
- }
- clearSelection () {
- this.refs.bookmarkTable.clearSelection()
- }
- render () {
- const props = !this.props.draggable ? {
- onDragStart: this.onDragStart,
- sortingDisabled: !this.props.sortable
- } : {
- onDoubleClick: this.onDoubleClick,
- onDragStart: this.onDragStart,
- onDragOver: this.onDragOver,
- onDrop: this.onDrop,
- sortingDisabled: !this.props.sortable
- }
- return
- ,
-
- ]}
- defaultHeading='Title'
- rows={this.props.bookmarks.map((entry) => [
- {
- cell: ,
- value: entry.get('customTitle') || entry.get('title') || entry.get('location')
- },
- {
- html: formatUtil.toLocaleString(entry.get('lastAccessedTime'), ''),
- value: entry.get('lastAccessedTime') || 0
- }
- ])}
- rowObjects={this.props.bookmarks}
- columnClassNames={['title', 'date']}
- addHoverClass
- multiSelect
- onDoubleClick={this.onDoubleClick}
- {...props}
- contextMenuName='bookmark'
- thisArg={this}
- onContextMenu={aboutActions.contextMenu} />
-
- }
-}
-
-class AboutBookmarks extends React.Component {
- constructor (props) {
- super(props)
- this.onChangeSelectedFolder = this.onChangeSelectedFolder.bind(this)
- this.onChangeSearch = this.onChangeSearch.bind(this)
- this.onClearSearchText = this.onClearSearchText.bind(this)
- this.importBrowserData = this.importBrowserData.bind(this)
- this.exportBookmarks = this.exportBookmarks.bind(this)
- this.addBookmarkFolder = this.addBookmarkFolder.bind(this)
- this.onClick = this.onClick.bind(this)
- this.clearSelection = this.clearSelection.bind(this)
- this.state = {
- bookmarks: Immutable.List(),
- bookmarkFolders: Immutable.Map(),
- selectedFolderId: 0,
- search: ''
- }
- ipc.on(messages.BOOKMARKS_UPDATED, (e, handle) => {
- const detail = handle.memory()
- this.setState({
- bookmarks: Immutable.fromJS((detail && detail.bookmarks) || {}),
- bookmarkFolders: Immutable.fromJS((detail && detail.bookmarkFolders) || {})
- })
- })
- }
- onChangeSelectedFolder (id) {
- this.setState({
- selectedFolderId: id,
- search: ''
- })
- }
- onChangeSearch (evt) {
- this.setState({
- search: evt.target.value
- })
- }
- onClearSearchText (evt) {
- this.setState({
- search: ''
- })
- }
- onClick (e) {
- // Determine if click was on sortableTable
- let targetElement = e.target
- while (targetElement) {
- if (targetElement.tagName === 'TBODY') {
- return
- }
- targetElement = targetElement.parentNode
- }
-
- // Click was not a child element of sortableTable; clear selection
- this.clearSelection()
- }
- searchedBookmarks (searchTerm, bookmarks) {
- return bookmarks.filter((bookmark) => {
- const title = bookmark.get('customTitle') + 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)
- }
- importBrowserData () {
- aboutActions.importBrowserDataNow()
- }
- exportBookmarks () {
- aboutActions.exportBookmarks()
- }
- addBookmarkFolder () {
- const newFolder = Immutable.fromJS({
- parentFolderId: this.state.selectedFolderId,
- tags: [siteTags.BOOKMARK_FOLDER]
- })
- windowActions.addBookmark(newFolder)
- }
- clearSelection () {
- this.refs.bookmarkList.clearSelection()
- }
- componentDidMount () {
- this.refs.bookmarkSearch.focus()
- }
- render () {
- return
-
-
-
-
-
-
-
- {
- this.state.search
- ?
- :
- }
-
-
-
-
-
-
-
-
-
-
-
bookmark.get('parentFolderId') === -1)}
- allBookmarkFolders={this.state.bookmarkFolders}
- isRoot
- selectedFolderId={this.state.selectedFolderId}
- search={this.state.search} />
-
-
-
-
-
-
- }
-}
-
-module.exports =
diff --git a/js/about/entry.js b/js/about/entry.js
index 70e53eaca68..02092fa7d2b 100644
--- a/js/about/entry.js
+++ b/js/about/entry.js
@@ -60,7 +60,7 @@ switch (getBaseUrl(getSourceAboutUrl(window.location.href))) {
element = require('./brave')
break
case 'about:bookmarks':
- element = require('./bookmarks')
+ element = require('../../app/renderer/about/bookmarks/bookmarks')
break
case 'about:certerror':
element = require('./certerror')