Skip to content
This repository has been archived by the owner on Dec 11, 2019. It is now read-only.

Bookmark manager style update #4658

Merged
merged 6 commits into from
Oct 11, 2016
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/extensions/brave/about-bookmarks.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<meta name="defaultLanguage" content="en-US">
<meta name='theme-color' content='#035500'>
<link rel="shortcut icon"type="image/x-icon" href="data:image/x-icon;,">
<title data-l10n-id="bookmarks"></title>
<title data-l10n-id="bookmarkManager"></title>
<script src='js/about.js'></script>
<script src="ext/l20n.min.js" async></script>
<link rel="localization" href="locales/{locale}/bookmarks.properties">
Expand Down
3 changes: 3 additions & 0 deletions app/extensions/brave/locales/en-US/bookmarks.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
bookmarks=Bookmarks
bookmarkManager=Bookmark Manager
folders=Folders
organize=Organize
partitionNumber=Session {{partitionNumber}}
bookmarksToolbar=Bookmarks Toolbar
otherBookmarks=Other Bookmarks
bookmarkSearch.placeholder=Search bookmarks
importBrowserData=Import browser data
2 changes: 1 addition & 1 deletion app/extensions/brave/locales/en-US/history.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ historyTitle=History
history=History
clearBrowsingDataNow=Clear browsing data
removeSelectedItems=Remove selected items
historySearch=Search history
time=Time
title=Title
domain=Domain
historySearch.placeholder=Search history
233 changes: 124 additions & 109 deletions js/about/bookmarks.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,90 +5,24 @@
// Note that these are webpack requires, not CommonJS node requiring requires
const React = require('react')
const Immutable = require('immutable')
const Sticky = require('react-stickynode')
const ImmutableComponent = require('../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('../components/sortableTable')
const Button = require('../components/button')
const siteUtil = require('../state/siteUtil')
const iconSize = 16

const ipc = window.chrome.ipc

// Stylesheets
require('../../less/about/itemList.less')
require('../../less/about/siteDetails.less')
require('../../less/about/bookmarks.less')
require('../../node_modules/font-awesome/css/font-awesome.css')

class BookmarkItem extends ImmutableComponent {
onDragStart (e) {
e.dataTransfer.effectAllowed = 'all'
dndData.setupDataTransferBraveData(e.dataTransfer, dragTypes.BOOKMARK, this.props.bookmark)
// TODO: Pass the location here when content scripts are fixed
dndData.setupDataTransferURL(e.dataTransfer, '', this.props.bookmark.get('customTitle') || this.props.bookmark.get('title'))
}
onDragOver (e) {
e.preventDefault()
e.dataTransfer.dropEffect = 'move'
}
onDrop (e) {
const bookmark = dndData.getDragData(e.dataTransfer, dragTypes.BOOKMARK)
if (bookmark) {
aboutActions.moveSite(bookmark.toJS(), this.props.bookmark.toJS(), dndData.shouldPrependVerticalItem(e.target, e.clientY), false)
}
}
navigate () {
aboutActions.newFrame({
location: this.props.bookmark.get('location'),
partitionNumber: this.props.bookmark.get('partitionNumber')
})
}
render () {
// Figure out the partition info display
let partitionNumberInfo
if (this.props.bookmark.get('partitionNumber')) {
let l10nArgs = {
partitionNumber: this.props.bookmark.get('partitionNumber')
}
partitionNumberInfo =
<span>&nbsp;(<span data-l10n-id='partitionNumber' data-l10n-args={JSON.stringify(l10nArgs)} />)</span>
}

var className = 'listItem'

// If the bookmark item is in the selected folder, show
// it as selected
if (this.props.inSelectedFolder) {
className += ' selected'
}

return <div role='listitem'
onDrop={this.onDrop.bind(this)}
onDragStart={this.onDragStart.bind(this)}
onDragOver={this.onDragOver.bind(this)}
className={className}
onContextMenu={aboutActions.contextMenu.bind(this, this.props.bookmark.toJS(), 'bookmark')}
data-context-menu-disable
draggable='true'
onDoubleClick={this.navigate.bind(this)}>
{
this.props.bookmark.get('customTitle') || this.props.bookmark.get('title')
? <span className='aboutListItem' title={this.props.bookmark.get('location')}>
<span className='aboutItemTitle'>{this.props.bookmark.get('customTitle') || this.props.bookmark.get('title')}</span>
{partitionNumberInfo}
<span className='aboutItemSeparator'>-</span><span className='aboutItemLocation'>{this.props.bookmark.get('location')}</span>
</span>
: <span className='aboutListItem' title={this.props.bookmark.get('location')}>
<span>{this.props.bookmark.get('location')}</span>
{partitionNumberInfo}
</span>
}
</div>
}
}

class BookmarkFolderItem extends ImmutableComponent {
onDragStart (e) {
if (this.props.draggable !== false) {
Expand Down Expand Up @@ -178,38 +112,96 @@ class BookmarkFolderList extends ImmutableComponent {
}
}

class BookmarksList extends ImmutableComponent {
class BookmarkTitleCell extends ImmutableComponent {
render () {
return <list className='siteDetailsList'>
let iconStyle
let showingFavicon = false
if (!siteUtil.isFolder(this.props.siteDetail)) {
const icon = this.props.siteDetail.get('favicon')
if (icon) {
iconStyle = {
minWidth: iconSize,
width: iconSize,
backgroundImage: `url(${icon})`,
backgroundSize: iconSize,
height: iconSize
}
showingFavicon = true
}
}

const bookmarkTitle = this.props.siteDetail.get('customTitle') || this.props.siteDetail.get('title')
const bookmarkLocation = this.props.siteDetail.get('location')

return <div>
{
this.props.bookmarks.map((bookmark) =>
<BookmarkItem bookmark={bookmark} />)
showingFavicon ? <span className='bookmarkFavicon' style={iconStyle} /> : null
}
</list>
<span>{bookmarkTitle || bookmarkLocation}</span>
{
bookmarkTitle ? <span className='bookmarkLocation'>{bookmarkLocation}</span> : null
}
</div>
}
}

class SearchResults extends React.Component {
render () {
// Sort bookmarks by title
var sortedBookmarks = this.props.bookmarks.sort((a, b) => {
if (a.get('title').toUpperCase() < b.get('title').toUpperCase()) return -1
if (a.get('title').toUpperCase() > b.get('title').toUpperCase()) return 1
return 0
})

// Flag each bookmark if it is in the selected folder
var selectedFolderIndex = sortedBookmarks.map((bookmark, idx) => {
return sortedBookmarks.get(idx).get('parentFolderId') === this.props.selectedFolderId
class BookmarksList extends ImmutableComponent {
onDoubleClick (entry) {
aboutActions.newFrame({
location: entry.location,
partitionNumber: entry.partitionNumber
})
}
onDragStart (siteDetail, e) {
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, '', siteDetail.get('customTitle') || siteDetail.get('title'))
}
onDragOver (siteDetail, e) {
e.preventDefault()
e.dataTransfer.dropEffect = 'move'
}
onDrop (siteDetail, e) {
const bookmark = dndData.getDragData(e.dataTransfer, dragTypes.BOOKMARK)
if (bookmark) {
aboutActions.moveSite(bookmark.toJS(), siteDetail.toJS(), dndData.shouldPrependVerticalItem(e.target, e.clientY), false)
}
}
render () {
const props = !this.props.draggable ? {
sortingDisabled: !this.props.sortable
} : {
onDoubleClick: this.onDoubleClick,
onDragStart: this.onDragStart,
onDragOver: this.onDragOver,
onDrop: this.onDrop,
sortingDisabled: !this.props.sortable
}

return (
<list className='siteDetailsList'>
{
sortedBookmarks.map((bookmark, idx) => <BookmarkItem bookmark={bookmark} inSelectedFolder={selectedFolderIndex.get(idx)} />)
}
</list>
)
return <div>
<SortableTable headings={['Title', 'Last Visited']}
defaultHeading='Title'
rows={this.props.bookmarks.map((entry) => [
{
cell: <BookmarkTitleCell siteDetail={entry} />,
value: entry.get('customTitle') || entry.get('title')
},
{
html: new Date(entry.get('lastAccessedTime')).toLocaleString(),
value: entry.get('lastAccessedTime')
}
])}
rowObjects={this.props.bookmarks}
columnClassNames={['title', 'date']}
tableID={this.props.tableID}
addHoverClass
multiSelect
onDoubleClick={this.onDoubleClick}
{...props}
contextMenuName='bookmark'
onContextMenu={aboutActions.contextMenu} />
</div>
}
}

Expand All @@ -219,8 +211,9 @@ class AboutBookmarks extends React.Component {
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.state = {
bookmarks: Immutable.Map(),
bookmarks: Immutable.List(),
bookmarkFolders: Immutable.Map(),
selectedFolderId: 0,
search: ''
Expand Down Expand Up @@ -254,31 +247,53 @@ class AboutBookmarks extends React.Component {
return title.match(new RegExp(searchTerm, 'gi'))
})
}
get bookmarksInFolder () {
return this.state.bookmarks.filter((bookmark) => (bookmark.get('parentFolderId') || 0) === this.state.selectedFolderId)
}
importBrowserData () {
aboutActions.importBrowerDataNow()
}
componentDidMount () {
this.refs.bookmarkSearch.focus()
}
render () {
return <div className='siteDetailsPage'>
<h2 data-l10n-id='folders' />
<input type='text' className='searchInput' ref='bookmarkSearch' id='bookmarkSearch' value={this.state.search} onChange={this.onChangeSearch} data-l10n-id='bookmarkSearch' />
{
this.state.search
? <span onClick={this.onClearSearchText} className='fa fa-close searchInputClear' />
: null
}
<div className='siteDetailsPageHeader'>
<div data-l10n-id='bookmarkManager' className='sectionTitle' />
<div className='headerActions'>
<div className='searchWrapper'>
<input type='text' className='searchInput' ref='bookmarkSearch' id='bookmarkSearch' value={this.state.search} onChange={this.onChangeSearch} data-l10n-id='bookmarkSearch' />
{
this.state.search
? <span onClick={this.onClearSearchText} className='fa fa-close searchInputClear' />
: <span className='fa fa-search searchInputPlaceholder' />
}
</div>
<Button l10nId='importBrowserData' className='primaryButton clearBrowsingDataButton' onClick={this.importBrowserData} />
</div>
</div>

<div className='siteDetailsPageContent'>
<Sticky enabled top={10}>
<div className='folderView'>
<div data-l10n-id='folders' className='sectionTitle' />
<BookmarkFolderList onChangeSelectedFolder={this.onChangeSelectedFolder}
bookmarkFolders={this.state.bookmarkFolders.filter((bookmark) => bookmark.get('parentFolderId') === -1)}
allBookmarkFolders={this.state.bookmarkFolders}
isRoot
selectedFolderId={this.state.selectedFolderId} />
</Sticky>
{
this.state.search
? <SearchResults bookmarks={this.searchedBookmarks(this.state.search, this.state.bookmarks)} selectedFolderId={this.state.selectedFolderId} />
: <BookmarksList bookmarks={this.state.bookmarks.filter((bookmark) => (bookmark.get('parentFolderId') || 0) === this.state.selectedFolderId)} />
}
</div>
<div className='organizeView'>
<div data-l10n-id='organize' className='sectionTitle' />
<BookmarksList
bookmarks={
this.state.search
? this.searchedBookmarks(this.state.search, this.state.bookmarks)
: this.bookmarksInFolder
}
sortable={false}
draggable={!this.state.search}
tableID={this.selectedFolderId} />
</div>
</div>
</div>
}
Expand Down
29 changes: 14 additions & 15 deletions js/about/history.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ const siteUtil = require('../state/siteUtil')
const ipc = window.chrome.ipc

// Stylesheets
require('../../less/about/itemList.less')
require('../../less/about/siteDetails.less')
require('../../less/about/history.less')
require('../../node_modules/font-awesome/css/font-awesome.css')

Expand Down Expand Up @@ -149,7 +147,7 @@ class AboutHistory extends React.Component {
this.onClearSearchText = this.onClearSearchText.bind(this)
this.clearBrowsingDataNow = this.clearBrowsingDataNow.bind(this)
this.state = {
history: Immutable.Map(),
history: Immutable.List(),
search: '',
settings: Immutable.Map(),
languageCodes: Immutable.Map()
Expand Down Expand Up @@ -180,7 +178,7 @@ class AboutHistory extends React.Component {
return title.match(new RegExp(searchTerm, 'gi'))
})
}
historyDescendingOrder () {
get historyDescendingOrder () {
return this.state.history.filter((site) => siteUtil.isHistoryEntry(site))
.sort((left, right) => {
if (left.get('lastAccessedTime') < right.get('lastAccessedTime')) return 1
Expand All @@ -191,13 +189,16 @@ class AboutHistory extends React.Component {
clearBrowsingDataNow () {
aboutActions.clearBrowsingDataNow({browserHistory: true})
}
componentDidMount () {
this.refs.historySearch.focus()
}
render () {
return <div className='siteDetailsPage'>
<div className='siteDetailsPageHeader'>
<div data-l10n-id='history' className='sectionTitle' />
<div className='headerActions'>
<div className='searchWrapper'>
<input type='text' className='searchInput' id='historySearch' placeholder='Search' value={this.state.search} onChange={this.onChangeSearch} data-l10n-id='historySearch' />
<input type='text' className='searchInput' ref='historySearch' id='historySearch' value={this.state.search} onChange={this.onChangeSearch} data-l10n-id='historySearch' />
{
this.state.search
? <span onClick={this.onClearSearchText} className='fa fa-close searchInputClear' />
Expand All @@ -209,16 +210,14 @@ class AboutHistory extends React.Component {
</div>

<div className='siteDetailsPageContent'>
{
<GroupedHistoryList
languageCodes={this.state.languageCodes}
settings={this.state.settings}
history={
this.state.search
? this.searchedSiteDetails(this.state.search, this.historyDescendingOrder())
: this.historyDescendingOrder()
} />
}
<GroupedHistoryList
languageCodes={this.state.languageCodes}
settings={this.state.settings}
history={
this.state.search
? this.searchedSiteDetails(this.state.search, this.historyDescendingOrder)
: this.historyDescendingOrder
} />
</div>
</div>
}
Expand Down
Loading