Skip to content

Commit

Permalink
Merge 2333966 into 52ea5cf
Browse files Browse the repository at this point in the history
  • Loading branch information
frosetti committed Mar 2, 2017
2 parents 52ea5cf + 2333966 commit 85b793f
Show file tree
Hide file tree
Showing 5 changed files with 669 additions and 177 deletions.
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ addons:
- g++-4.8
env:
matrix:
- EMBER_TRY_SCENARIO=ember-2-3
- EMBER_TRY_SCENARIO=ember-2-8
- EMBER_TRY_SCENARIO=default
- EMBER_TRY_SCENARIO=ember-release
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ Detailed API and example usage can be found in the sample application in tests/d
| `Sub Attribute` | `activeSorting` | `array` | | Array that specifies the sort order. eg. [{"direction: "asc/desc", "value": <attr-name>}], This is an attribute on frost-list-expansion component.|
| `Sub Attribute` | `properties` | `array` | | Array of sortable attributes. eg. [{"label: "foo", "value": "bar"}], This is an attribute on frost-sort component.|
| `Sub Attribute` | `onSort` | `action closure` | | callback functions user provided to handle sorting. This is an attribute on frost-sort component.|
| `Attribute` | `itemComparator` | `action closure` | | callback functions user provided to handle custom item comparisons.|
| `Attribute` | `itemKey` | `string` | | Optional: With itemKey set, item.get(itemKey) will be used for comparision, Else the default item === item comparison used. |


### Infinite scroll
Expand Down Expand Up @@ -261,7 +261,7 @@ execute the test suite and output code coverage.
[cov-img]: https://coveralls.io/repos/github/ciena-frost/ember-frost-list/badge.svg?branch=master "Code Coverage"
[cov-url]: https://coveralls.io/github/ciena-frost/ember-frost-list

[ember-img]: https://img.shields.io/badge/ember-2.0.0+-orange.svg "Ember 2.0.0+"
[ember-img]: https://img.shields.io/badge/ember-2.8.0+-orange.svg "Ember 2.8.0+"

[npm-img]: https://img.shields.io/npm/v/ember-frost-list.svg "NPM Version"
[npm-url]: https://www.npmjs.com/package/ember-frost-list
35 changes: 24 additions & 11 deletions addon/components/frost-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export default Component.extend({
PropTypes.object
])),
onSelectionChange: PropTypes.func,
itemComparator: PropTypes.func,
itemKey: PropTypes.string,

// Options - sub-components
pagination: PropTypes.EmberComponent,
Expand All @@ -56,6 +56,9 @@ export default Component.extend({
bufferSize: PropTypes.number,
defaultHeight: PropTypes.number,

// Private
_itemComparator: PropTypes.func,

// State
_isShiftDown: PropTypes.bool,

Expand All @@ -75,7 +78,6 @@ export default Component.extend({
return {
// Options - general
scrollTop: 0,
itemComparator: (rhs, lhs) => { return rhs === lhs },

// Smoke and mirrors options
alwaysUseDefaultHeight: false,
Expand All @@ -84,16 +86,16 @@ export default Component.extend({

// State
_rangeState: {
anchor: null,
endpoint: null
anchor: Ember.Object.create(),
endpoint: Ember.Object.create()
}
}
},

// == Computed Properties ===================================================

@readOnly
@computed('expandedItems.[]', 'items.[]', 'selectedItems.[]', 'itemComparator')
@computed('expandedItems.[]', 'items.[]', 'selectedItems.[]', '_itemComparator')
_items (expandedItems, items, selectedItems, itemComparator) {
if (isEmpty(items)) {
return []
Expand Down Expand Up @@ -136,6 +138,16 @@ export default Component.extend({

init () {
this._super(...arguments)
const itemKey = this.get('itemKey')
if (itemKey) {
this.set('_itemComparator', function (lhs, rhs) {
return lhs.get(itemKey) === rhs.get(itemKey)
})
} else {
this.set('_itemComparator', function (lhs, rhs) {
return lhs === rhs
})
}

$(document).on(`keyup.${this.elementId} keydown.${this.elementId}`, this.setShift.bind(this))
},
Expand All @@ -153,8 +165,8 @@ export default Component.extend({

_expand (item) {
const clonedExpandedItems = A(this.get('expandedItems').slice())
const itemComparator = this.get('itemComparator')
const index = clonedExpandedItems.findIndex(expandedItem => itemComparator(expandedItem, item))
const _itemComparator = this.get('_itemComparator')
const index = clonedExpandedItems.findIndex(expandedItem => _itemComparator(expandedItem, item))
if (index >= 0) {
clonedExpandedItems.removeAt(index)
} else {
Expand All @@ -169,17 +181,18 @@ export default Component.extend({

_select ({isRangeSelect, isSpecificSelect, item}) {
const items = this.get('items')
const itemComparator = this.get('itemComparator')
const itemKey = this.get('itemKey')
const _itemComparator = this.get('_itemComparator')
const clonedSelectedItems = A(this.get('selectedItems').slice())
const _rangeState = this.get('_rangeState')

// Selects are proccessed in order of precedence: specific, range, basic
if (isSpecificSelect) {
selection.specific(clonedSelectedItems, item, _rangeState, itemComparator)
selection.specific(clonedSelectedItems, item, _rangeState, _itemComparator)
} else if (isRangeSelect) {
selection.range(items, clonedSelectedItems, item, _rangeState, itemComparator)
selection.range(items, clonedSelectedItems, item, _rangeState, _itemComparator, itemKey)
} else {
selection.basic(clonedSelectedItems, item, _rangeState, itemComparator)
selection.basic(clonedSelectedItems, item, _rangeState, _itemComparator)
}
this.onSelectionChange(clonedSelectedItems)
}
Expand Down
26 changes: 18 additions & 8 deletions addon/utils/selection.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
*/

import Ember from 'ember'
const {isNone} = Ember

export default {
/**
Expand Down Expand Up @@ -63,24 +62,27 @@ export default {
* @param {Function} itemComparator - comparator for items
*/
/* eslint-disable complexity */
range (items, selectedItems, item, rangeState, itemComparator) {
range (items, selectedItems, item, rangeState, itemComparator, itemKey) {
// If an anchor isn't set, then set the anchor and exit
const rangeAnchor = rangeState['anchor']
if (isNone(rangeAnchor)) {

const anchor = items.findIndex(currentItem => itemComparator(currentItem, rangeState['anchor']))
// If anchor is -1 then it was a anchor from a previous page that we can not find, so reset
if (Ember.isEmpty(rangeAnchor) || anchor === -1) {
// Range select is always a positive selection (no deselect)
rangeState['anchor'] = item

// New anchor, clear any previous endpoint
rangeState['endpoint'] = Ember.Object.create()

// Add the anchor to the selected items
selectedItems.pushObject(item)
// Add the anchor to the selected items if not already in it from a previous page
if (!selectedItems.some(selectedItem => itemComparator(selectedItem, item))) {
selectedItems.pushObject(item)
}

return
}

// Find the indicies of the anchor and endpoint
const anchor = items.findIndex(currentItem => itemComparator(currentItem, rangeState['anchor']))
// Find the indices of the endpoint
const endpoint = items.findIndex(currentItem => itemComparator(currentItem, item))

// Select all of the items between the anchor and the item (inclusive)
Expand Down Expand Up @@ -114,6 +116,14 @@ export default {
}
}

// Wipe out duplicates if range selection covered already selected items
// e.g item2-3 already selected but shift click item0 through item5 happens
if (itemKey) {
selectedItems.setObjects(selectedItems.uniqBy(itemKey))
} else {
selectedItems.setObjects(selectedItems.uniq())
}

// Store the new endpoint
rangeState['endpoint'] = item
},
Expand Down
Loading

0 comments on commit 85b793f

Please sign in to comment.