From bc06f3558adbcedc5d165c0cbe7962beabdb3539 Mon Sep 17 00:00:00 2001 From: NejcZdovc Date: Thu, 20 Jul 2017 13:39:06 +0200 Subject: [PATCH] Moves bookarks manager from js to app Resolves #10075 Auditors: @bsclifton Test Plan: - check if bookmarks manager is displayed correctly --- .../about/bookmarks/bookmarkFolderItem.js | 134 +++++ .../about/bookmarks/bookmarkFolderList.js | 75 +++ .../about/bookmarks/bookmarkTitleCell.js | 56 ++ .../about/bookmarks/bookmarkTitleHeader.js | 37 ++ app/renderer/about/bookmarks/bookmarks.js | 173 ++++++ app/renderer/about/bookmarks/bookmarksList.js | 148 +++++ js/about/bookmarks.js | 508 ------------------ js/about/entry.js | 2 +- 8 files changed, 624 insertions(+), 509 deletions(-) create mode 100644 app/renderer/about/bookmarks/bookmarkFolderItem.js create mode 100644 app/renderer/about/bookmarks/bookmarkFolderList.js create mode 100644 app/renderer/about/bookmarks/bookmarkTitleCell.js create mode 100644 app/renderer/about/bookmarks/bookmarkTitleHeader.js create mode 100644 app/renderer/about/bookmarks/bookmarks.js create mode 100644 app/renderer/about/bookmarks/bookmarksList.js delete mode 100644 js/about/bookmarks.js 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')