Skip to content

Commit

Permalink
Make ledger table sortable
Browse files Browse the repository at this point in the history
  • Loading branch information
diracdeltas authored and MKuenzi committed Sep 18, 2016
1 parent 04fc3c0 commit 2c4e02b
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 82 deletions.
1 change: 1 addition & 0 deletions app/extensions/brave/locales/en-US/preferences.properties
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ rank=Rank
views=Views
timeSpent=Time Spent
include=Include
percentage=%
bravery=Bravery
hintsTitle=Helpful hints
hint0=The Bravery panel allows you turn HTTPS Everywhere on or off. HTTPS Everywhere automatically rewrites your HTTP traffic to HTTPS for supported sites to keep you more secure.
Expand Down
103 changes: 50 additions & 53 deletions js/about/preferences.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ const getSetting = require('../settings').getSetting
const SortableTable = require('../components/sortableTable')
const Button = require('../components/button')
const searchProviders = require('../data/searchProviders')
const pad = require('underscore.string/pad')

const adblock = appConfig.resourceNames.ADBLOCK
const cookieblock = appConfig.resourceNames.COOKIEBLOCK
Expand Down Expand Up @@ -163,16 +162,16 @@ class SiteSettingCheckbox extends ImmutableComponent {
}
}

class LedgerTableRow extends ImmutableComponent {
class LedgerTable extends ImmutableComponent {
get synopsis () {
return this.props.synopsis
return this.props.ledgerData.get('synopsis')
}

get formattedTime () {
var d = this.synopsis.get('daysSpent')
var h = this.synopsis.get('hoursSpent')
var m = this.synopsis.get('minutesSpent')
var s = this.synopsis.get('secondsSpent')
getFormattedTime (synopsis) {
var d = synopsis.get('daysSpent')
var h = synopsis.get('hoursSpent')
var m = synopsis.get('minutesSpent')
var s = synopsis.get('secondsSpent')
if (d << 0 > 364) {
return '>1y'
}
Expand All @@ -183,14 +182,12 @@ class LedgerTableRow extends ImmutableComponent {
return (d + h + m + s + '')
}

padLeft (v) { return pad(v, 12, '0') }

get hostPattern () {
return `https?://${this.synopsis.get('site')}`
getHostPattern (synopsis) {
return `https?://${synopsis.get('site')}`
}

get enabled () {
const hostSettings = this.props.siteSettings.get(this.hostPattern)
enabledForSite (synopsis) {
const hostSettings = this.props.siteSettings.get(this.getHostPattern(synopsis))
if (hostSettings) {
const result = hostSettings.get('ledgerPayments')
if (typeof result === 'boolean') {
Expand All @@ -200,54 +197,54 @@ class LedgerTableRow extends ImmutableComponent {
return true
}

render () {
const faviconURL = this.synopsis.get('faviconURL') || appConfig.defaultFavicon
const rank = this.synopsis.get('rank')
const views = this.synopsis.get('views')
const duration = this.synopsis.get('duration')
const publisherURL = this.synopsis.get('publisherURL')
// TODO: This should redistribute percentages accordingly when a site is
// enabled/disabled for payments.
const percentage = this.synopsis.get('percentage')
const site = this.synopsis.get('site')
getRow (synopsis) {
if (!synopsis || !synopsis.get) {
return []
}
const faviconURL = synopsis.get('faviconURL') || appConfig.defaultFavicon
const rank = synopsis.get('rank')
const views = synopsis.get('views')
const duration = synopsis.get('duration')
const publisherURL = synopsis.get('publisherURL')
const percentage = synopsis.get('percentage')
const site = synopsis.get('site')
const defaultSiteSetting = true

return <tr className={this.enabled ? '' : 'paymentsDisabled'}>
<td className='alignRight' data-sort={this.padLeft(rank)}>{rank}</td>
<td><a href={publisherURL} target='_blank'><img src={faviconURL} alt={site} /><span>{site}</span></a></td>
<td><SiteSettingCheckbox hostPattern={this.hostPattern} defaultValue={defaultSiteSetting} prefKey='ledgerPayments' siteSettings={this.props.siteSettings} checked={this.enabled} /></td>
<td className='alignRight' data-sort={this.padLeft(views)}>{views}</td>
<td className='alignRight' data-sort={this.padLeft(duration)}>{this.formattedTime}</td>
<td className='alignRight' data-sort={this.padLeft(percentage)}>{percentage}</td>
</tr>
return [
rank,
{
html: <a href={publisherURL} target='_blank'><img src={faviconURL} alt={site} /><span>{site}</span></a>,
value: site
},
{
html: <SiteSettingCheckbox hostPattern={this.getHostPattern(synopsis)} defaultValue={defaultSiteSetting} prefKey='ledgerPayments' siteSettings={this.props.siteSettings} checked={this.enabledForSite(synopsis)} />,
value: this.enabledForSite(synopsis) ? 1 : 0
},
views,
{
html: this.getFormattedTime(synopsis),
value: duration
},
percentage
]
}
}

class LedgerTable extends ImmutableComponent {
render () {
const synopsis = this.props.ledgerData.get('synopsis')
if (!synopsis || !synopsis.size) {
if (!this.synopsis || !this.synopsis.size) {
return null
}
return <div id='ledgerTable'>
<table className='sort'>
<thead>
<tr>
<th className='sort-header' data-l10n-id='rank' />
<th className='sort-header' data-l10n-id='publisher' />
<th className='sort-header' data-l10n-id='include' />
<th className='sort-header' data-l10n-id='views' />
<th className='sort-header' data-l10n-id='timeSpent' />
<th className='sort-header'>&#37;</th>
</tr>
</thead>
<tbody>
{
synopsis.map((row) => <LedgerTableRow synopsis={row}
siteSettings={this.props.siteSettings} />)
<SortableTable
headings={['rank', 'publisher', 'include', 'views', 'timeSpent', 'percentage']}
defaultHeading='rank'
overrideDefaultStyle
columnClassNames={['alignRight', '', '', 'alignRight', 'alignRight', 'alignRight']}
rowClassNames={
this.synopsis.map((item) =>
this.enabledForSite(item) ? '' : 'paymentsDisabled').toJS()
}
</tbody>
</table>
onContextMenu={aboutActions.contextMenu}
rows={this.synopsis.map((synopsis) => this.getRow(synopsis)).toJS()} />
</div>
}
}
Expand Down
53 changes: 32 additions & 21 deletions js/components/sortableTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,17 @@ const ImmutableComponent = require('./immutableComponent')
const tableSort = require('tablesort')
const cx = require('../lib/classSet')

/**
* Represents a sortable table with supp
*/
tableSort.extend('number', (item) => {
return typeof item === 'number'
}, (a, b) => {
a = isNaN(a) ? 0 : a
b = isNaN(b) ? 0 : b
return b - a
})

class SortableTable extends ImmutableComponent {
componentDidMount (event) {
return tableSort(document.getElementsByClassName('sortableTable')[0])
return tableSort(this.table)
}
get hasClickHandler () {
return typeof this.props.onClick === 'function'
Expand All @@ -22,6 +26,10 @@ class SortableTable extends ImmutableComponent {
return this.props.columnClassNames &&
this.props.columnClassNames.length === this.props.headings.length
}
get hasRowClassNames () {
return this.props.rowClassNames &&
this.props.rowClassNames.length === this.props.rows.length
}
get hasDoubleClickHandler () {
return typeof this.props.onDoubleClick === 'function'
}
Expand Down Expand Up @@ -56,15 +64,26 @@ class SortableTable extends ImmutableComponent {
return false
}

return <table className='sortableTable sort'>
return <table className={cx({
sort: true,
sortableTable: !this.props.overrideDefaultStyle
})}
ref={(node) => { this.table = node }}>
<thead>
<tr>
{this.props.headings.map((heading) => <th className={cx({
'sort-header': true,
'sort-default': heading === this.props.defaultHeading
{this.props.headings.map((heading, j) => {
const firstEntry = this.props.rows[0][j]
let dataType = typeof firstEntry
if (dataType === 'object' && firstEntry.value) {
dataType = typeof firstEntry.value
}
return <th className={cx({
'sort-header': true,
'sort-default': heading === this.props.defaultHeading})}
data-l10n-id={heading}
data-sort-method={dataType === 'number' ? 'number' : undefined}
data-sort-order={this.props.defaultHeadingSortOrder} />
})}
data-l10n-id={heading}
data-sort-order={this.props.defaultHeadingSortOrder} />)}
</tr>
</thead>
<tbody>
Expand All @@ -78,22 +97,14 @@ class SortableTable extends ImmutableComponent {
</td>
})
const rowAttributes = this.getRowAttributes(row, i)
return rowAttributes.onContextMenu
? <tr {...rowAttributes} data-context-menu-disable>{entry}</tr>
: <tr {...rowAttributes}>{entry}</tr>
return <tr {...rowAttributes}
data-context-menu-disable={rowAttributes.onContextMenu ? true : undefined}
className={this.hasRowClassNames ? this.props.rowClassNames[i] : undefined}>{entry}</tr>
})
}
</tbody>
</table>
}
}

SortableTable.defaultProps = {
headings: React.PropTypes.array.isRequired, // list of data-10n-id's
rows: React.PropTypes.array.isRequired, // value or {html: <displayed_html>, value: <value_to_sort_by>} for each table entry
columnClassNames: React.PropTypes.array,
addHoverClass: React.PropTypes.bool,
contextMenuName: React.PropTypes.string
}

module.exports = SortableTable
19 changes: 12 additions & 7 deletions less/sortableTable.less
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@

@import "variables.less";

table.sort {
th {
cursor: pointer;
text-decoration: underline;
color: @darkGray;

&:hover {
color: #000;
}
}
}

table.sortableTable {
width: 100%;
border: solid 1px @lightGray;
Expand All @@ -17,17 +29,10 @@ table.sortableTable {

th {
background: @lightGray;
cursor: pointer;
text-decoration: underline;
color: @darkGray;
text-align: left;
font-weight: 300;
padding: 8px;
box-sizing: border-box;

&:hover {
color: #000;
}
}

td {
Expand Down
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@
"tldjs": "1.6.2",
"tracking-protection": "1.1.x",
"underscore": "1.8.3",
"underscore.string": "^3.3.4",
"url-loader": "^0.5.7"
},
"devDependencies": {
Expand Down

0 comments on commit 2c4e02b

Please sign in to comment.