Skip to content

Commit

Permalink
Merge 3521109 into a728be2
Browse files Browse the repository at this point in the history
  • Loading branch information
twjohnston committed Apr 6, 2018
2 parents a728be2 + 3521109 commit 7cdfe0a
Show file tree
Hide file tree
Showing 14 changed files with 284 additions and 17 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Detailed API and example usage can be found in the sample application in tests/d
| `Attribute` | `expansion` | `hash` | | component which handles expansion and collapsing for entire list. This component should be wrapped inside component helper. |
| `Sub Attribute` | `onExpandAll` | `action closure` | | callback functions user provided to handle all list items collapsing. This is an attribute on frost-list-expansion component.|
| `Sub Attribute` | `onCollapseAll` | `action closure` | | callback functions user provided to handle all list items expansion. This is an attribute on frost-list-expansion component. |
| `Attribute` | `sorting` | `hash` | | component which handles expansion and collapsing for entire list. This component should be wrapped inside component helper. |
| `Attribute` | `sorting` | `hash` | | component which handles sorting for the list. This component should be wrapped inside component helper. |
| `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.|
Expand All @@ -67,6 +67,8 @@ Detailed API and example usage can be found in the sample application in tests/d
| `Attribute` | `itemDefinitions` | `hash` | | Optional: A set of components that are to be used in the list as the `item` component. Note that this had to be used in conjunction with `componentKeyNamesForTypes` |
| `Attribute` | `itemExpansionDefinitions` | `hash` | | Optional: A set of components that are to be used in the list as the `itemExpansion` component. Note that this had to be used in conjunction with `componentKeyNamesForTypes` |
| `Attribute` | `disableDeselectAll` | `boolean` | false | Optional: disables deselect all click turning frost list into a multi-select type list |
| `Attribute` | `alwaysExpanded` | `boolean` | false | Optional: all list items will always be expanded. frost-list-expansion and frost-list-item-expansion will not be displayed. |
| `Attribute` | `singleSelection` | `boolean` | false | Optional: disables multiple selection entirely and displays radio buttons instead of checkboxes in frost-list-item-selection to clarify the list's behavior. |


### Infinite scroll
Expand Down
12 changes: 10 additions & 2 deletions addon/components/frost-list-item-content.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import computed, {readOnly} from 'ember-computed-decorators'
import {Component} from 'ember-frost-core'
import {PropTypes} from 'ember-prop-types'

Expand Down Expand Up @@ -27,16 +28,23 @@ export default Component.extend({
itemExpansion: PropTypes.oneOfType([
PropTypes.null,
PropTypes.EmberComponent
])
]),
alwaysExpanded: PropTypes.bool,
singleSelection: PropTypes.bool
},

getDefaultProps () {
return {
isAnyItemExpansion: false
}
}
},

// == Computed Properties ===================================================
@readOnly
@computed('itemExpansion', 'alwaysExpanded')
isExpansionIconVisible (itemExpansion, alwaysExpanded) {
return itemExpansion && !alwaysExpanded
}

// == Functions =============================================================

Expand Down
2 changes: 2 additions & 0 deletions addon/components/frost-list-item-selection.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ export default Component.extend({
PropTypes.EmberObject,
PropTypes.object
]),
index: PropTypes.number,
isSelected: PropTypes.bool,
singleSelection: PropTypes.bool,

onSelect: PropTypes.func.isRequired
},
Expand Down
30 changes: 26 additions & 4 deletions addon/components/frost-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ export default Component.extend({
PropTypes.EmberObject,
PropTypes.object
]),
alwaysExpanded: PropTypes.bool,
singleSelection: PropTypes.bool,

// Options - sub-components
pagination: PropTypes.EmberComponent,
Expand Down Expand Up @@ -110,6 +112,8 @@ export default Component.extend({
item: 'itemName',
itemExpansion: 'itemExpansionName'
},
alwaysExpanded: false,
singleSelection: false,

// Smoke and mirrors options
alwaysUseDefaultHeight: false,
Expand All @@ -132,12 +136,20 @@ export default Component.extend({
return []
}

const alwaysExpanded = this.get('alwaysExpanded')
return items.map(item => {
let expanded
if (alwaysExpanded === true) {
expanded = true
} else {
expanded = isEmpty(expandedItems) ? false : expandedItems.some(
expandedItem => _itemComparator(expandedItem, item))
}

return ObjectProxy.create({
content: item,
states: {
isExpanded: isEmpty(expandedItems) ? false : expandedItems.some(
expandedItem => _itemComparator(expandedItem, item)),
isExpanded: expanded,
isSelected: isEmpty(selectedItems) ? false : selectedItems.some(
selectedItem => _itemComparator(selectedItem, item))
}
Expand Down Expand Up @@ -207,6 +219,12 @@ export default Component.extend({
return pagination && isAnyItemExpansion
},

@readOnly
@computed('isAnyItemExpansion', 'alwaysExpanded')
isCollapseExpandAllVisible (isAnyItemExpansion, alwaysExpanded) {
return isAnyItemExpansion && !alwaysExpanded
},

// == Functions =============================================================

setShift (event) {
Expand Down Expand Up @@ -331,14 +349,18 @@ export default Component.extend({
const _itemComparator = this.get('_itemComparator')
const clonedSelectedItems = A(this.get('selectedItems').slice())
const _rangeState = this.get('_rangeState')
const singleSelection = this.get('singleSelection')

if (isRangeSelect === false && this.get('disableDeselectAll') === true) {
// Ensure we are not interrupting a range select prior to forcing a isSpecificSelect
isSpecificSelect = true
}

// Selects are proccessed in order of precedence: specific, range, basic
if (isSpecificSelect) {
// If single selection is enabled, we can just use the basic selection
// Otherwise, selects are proccessed in order of precedence: specific, range, basic
if (singleSelection) {
selection.basic(clonedSelectedItems, item, _rangeState, _itemComparator)
} else if (isSpecificSelect) {
selection.specific(clonedSelectedItems, item, _rangeState, _itemComparator)
} else if (isRangeSelect) {
selection.range(items, clonedSelectedItems, item, _rangeState, _itemComparator, itemKey)
Expand Down
4 changes: 3 additions & 1 deletion addon/templates/components/frost-list-item-content.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
data-test={{hook (concat hook '-item-container') index=index }}
>
<div class='frost-list-item-container-base' style={{listRowHeightString}}>
{{#if itemExpansion}}
{{#if isExpansionIconVisible}}
{{frost-list-item-expansion
hook=(concat hookPrefix '-expansion')
hookQualifiers=(hash index=index)
Expand All @@ -23,9 +23,11 @@
hook=(concat hookPrefix '-selection')
hookQualifiers=(hash index=index)
model=model.content
index=index
isSelected=model.states.isSelected
onSelect=onSelect
size=size
singleSelection=singleSelection
}}
{{/if}}

Expand Down
21 changes: 14 additions & 7 deletions addon/templates/components/frost-list-item-selection.hbs
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
{{! Template for the frost-list-item-selection component }}

{{frost-checkbox
checked=isSelected
hook=(concat hookPrefix '-checkbox')
size=size
}}
{{#if singleSelection}}
{{frost-radio-button
checked=isSelected
hook=(concat hookPrefix '-radio-button')
size=size
value=(concat index '')
}}
{{else}}
{{frost-checkbox
checked=isSelected
hook=(concat hookPrefix '-checkbox')
size=size
}}
{{/if}}
4 changes: 3 additions & 1 deletion addon/templates/components/frost-list.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<div class='frost-list-header-divider'></div>
{{/if}}

{{#if isAnyItemExpansion}}
{{#if isCollapseExpandAllVisible}}
{{frost-list-expansion
hook=(concat hookPrefix '-expansion')
onCollapseAll=(action '_collapseAll')
Expand Down Expand Up @@ -63,6 +63,8 @@
onSelectionChange=onSelectionChange
onExpand=(action '_expand')
onSelect=(action '_select')
alwaysExpanded=alwaysExpanded
singleSelection=singleSelection
}}
{{else}}
{{yield to="inverse"}}
Expand Down
1 change: 1 addition & 0 deletions tests/dummy/app/pods/application/template.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
{{#link-to 'infinite'}}Infinite{{/link-to}}
{{#link-to 'paged'}}Paged{{/link-to}}
{{#link-to 'typed'}}Typed{{/link-to}}
{{#link-to 'single'}}Single select{{/link-to}}
</div>
{{/frost-scroll}}
</div>
Expand Down
50 changes: 50 additions & 0 deletions tests/dummy/app/pods/single/controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import Ember from 'ember'
const {A, Controller, isEmpty} = Ember
import computed, {readOnly} from 'ember-computed-decorators'
import {sort} from 'ember-frost-sort'

export default Controller.extend({

// == Dependencies ==========================================================

// == Properties ============================================================

expandedItems: A([]),
selectedItems: A([]),
sortOrder: A(['-id']),
sortingProperties: [
{label: 'Id', value: 'id'},
{label: 'Label', value: 'label'}
],

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

@readOnly
@computed('model.[]', 'sortOrder.[]')
items (model, sortOrder) {
if (isEmpty(model)) {
return []
}
return sort(model, sortOrder) // Client side sorting
},

// == Functions =============================================================

// == Lifecycle Hooks =======================================================

// == Actions ===============================================================

actions: {
onExpansionChange (expandedItems) {
this.get('expandedItems').setObjects(expandedItems)
},

onSelectionChange (selectedItems) {
this.get('selectedItems').setObjects(selectedItems)
},

onSortingChange (sortOrder) {
this.get('sortOrder').setObjects(sortOrder)
}
}
})
8 changes: 8 additions & 0 deletions tests/dummy/app/pods/single/route.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import Ember from 'ember'
const {Route} = Ember

export default Route.extend({
model () {
return this.store.findAll('list-item')
}
})
17 changes: 17 additions & 0 deletions tests/dummy/app/pods/single/template.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{{frost-list
class='demo'
hook='demo'
item=(component 'list-item')
itemExpansion=(component 'list-item-expansion')
items=items
expandedItems=expandedItems
selectedItems=selectedItems
onExpansionChange=(action 'onExpansionChange')
onSelectionChange=(action 'onSelectionChange')
sorting=(component 'frost-sort'
sortOrder=sortOrder
sortingProperties=sortingProperties
onChange=(action 'onSortingChange')
)
singleSelection=true
}}
1 change: 1 addition & 0 deletions tests/dummy/app/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Router.map(function () {
this.route('paged')
this.route('size')
this.route('typed')
this.route('single')
})

export default Router
22 changes: 21 additions & 1 deletion tests/integration/components/frost-list-item-selection-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ describe(test.label, function () {
this.on('selectAction', selectSpy)
this.setProperties({
hook: 'myListItemSelection',
model: model
model: model,
singleSelection: false
})
this.render(hbs`
{{frost-list-item-selection
Expand All @@ -36,6 +37,7 @@ describe(test.label, function () {
model=model
size='medium'
onSelect=(action 'selectAction')
singleSelection=singleSelection
}}
`)
})
Expand Down Expand Up @@ -87,4 +89,22 @@ describe(test.label, function () {
expect($hook('myListItemSelection')).to.have.class('is-selected')
})
})

describe('when singleSelection is true', function () {
beforeEach(function () {
this.set('singleSelection', true)
})

it('should set -radio-button hook correctly', function () {
expect($hook('myListItemSelection-radio-button')).to.be.length(1)
})

it('should use radio buttons instead of checkboxes', function () {
expect($hook('myListItemSelection-radio-button-input').attr('type')).to.equal('radio')
})

it('should add correct size to the radio buttons', function () {
expect($hook('myListItemSelection-radio-button')).to.have.class('medium')
})
})
})
Loading

0 comments on commit 7cdfe0a

Please sign in to comment.