Skip to content

Instantly share code, notes, and snippets.

@sglanzer-deprecated
Created January 5, 2017 14:23
Show Gist options
  • Save sglanzer-deprecated/557d96e5ef4bc43f66472e65e4478df5 to your computer and use it in GitHub Desktop.
Save sglanzer-deprecated/557d96e5ef4bc43f66472e65e4478df5 to your computer and use it in GitHub Desktop.
this.set('selectedItems', []) // TODO prefix
this.set('previousRangeEndItemIndex', null) // TODO prefix
this.set('rangeAnchorIndex', null) // TODO prefix
this.set('actions.select', function ({isCheckboxSelect, isRangeSelect, isCurrentlySelected, isSpecificSelect, item}) {
const selectedItems = this.get('selectedItems')
// Selects are proccessed in order of precedence: checkbox, specific, range, default
if (isCheckboxSelect) {
// Checkbox select works like a specific select, the target item
// is selected/deselected without modifying other existing selections
const isSelected = !isCurrentlySelected
this.setProperties({
rangeAnchorItem: isSelected ? item : null,
previousRangeEndItemIndex: null
})
if (isSelected) {
selectedItems.pushObject(item)
} else {
selectedItems.removeObject(item)
}
} else if (isSpecificSelect) {
// Select/deselect the item without modifying other existing selections
const isSelected = !isCurrentlySelected
this.setProperties({
rangeAnchorItem: isSelected ? item : null,
previousRangeEndItemIndex: null
})
if (isSelected) {
selectedItems.pushObject(item)
} else {
selectedItems.removeObject(item)
}
} else if (isRangeSelect) {
// The range anchor is the previous selection if:
// - the selection was positive
// - the selection wasn't the end of a range select
const rangeAnchorItem = this.get('rangeAnchorItem')
if (isNone(rangeAnchorItem)) {
// A range select without an established anchor is a specific select;
// however, a range select will always issue a positive select
this.setProperties({
rangeAnchorItem: item,
previousRangeEndItemIndex: null
})
selectedItems.pushObject(item)
} else {
// Select all of the items between the anchor and the item (inclusive)
// The range anchor doesn't update when selecting the end of a range
const items = this.get('items')
const rangeAnchorIndex = items.indexOf(rangeAnchorItem)
const itemIndex = items.indexOf(item)
const isSelectionAscending = rangeAnchorIndex < itemIndex
const rangeStartIndex = isSelectionAscending ? rangeAnchorIndex : itemIndex
const rangeEndIndex = isSelectionAscending ? itemIndex : rangeAnchorIndex
// If a previous range end was selected, deselect all selections no longer in the range
const previousRangeEndItemIndex = this.get('previousRangeEndItemIndex')
let deselectedItems = []
if (!isNone(previousRangeEndItemIndex)) {
const isPreviousSelectionAscending = rangeAnchorIndex < previousRangeEndItemIndex
if (isSelectionAscending === isPreviousSelectionAscending) {
if (isSelectionAscending && itemIndex < previousRangeEndItemIndex) {
deselectedItems = items.slice(itemIndex + 1, previousRangeEndItemIndex + 1)
} else if (!isSelectionAscending && itemIndex > previousRangeEndItemIndex) {
deselectedItems = items.slice(previousRangeEndItemIndex, itemIndex)
}
} else if (isPreviousSelectionAscending) {
deselectedItems = items.slice(rangeAnchorIndex + 1, previousRangeEndItemIndex + 1)
} else {
deselectedItems = items.slice(previousRangeEndItemIndex, rangeAnchorIndex)
}
}
// Set the (now) previous range end item index
this.set('previousRangeEndItemIndex', itemIndex)
selectedItems.pushObjects(items.slice(rangeStartIndex, rangeEndIndex + 1))
selectedItems.removeObjects(deselectedItems)
}
} else {
// If the item is part of a previous set of selections
// the item remains selected while the rest are deselected
const isInPreviousSelections =
selectedItems.get('length') > 1 &&
selectedItems.findBy('id', item.get('id'))
const isSelected = isInPreviousSelections ? true : !isCurrentlySelected
this.setProperties({
rangeAnchorItem: isSelected ? item : null,
previousRangeEndItemIndex: null
})
// Default select clears out any prior selections
if (isSelected) {
selectedItems.setObjects([item])
} else {
selectedItems.clear()
}
}
})
click (event) {
// Acceptable event modifiers for range selection
const simpleClick = Ember.ViewUtils.isSimpleClick(event)
const specificSelectModifier = (new window.UAParser()).getOS() === 'Mac OS' ? event.ctrlKey : event.metaKey // TODO Move instance to a service
const rangeSelectModifier = event.shiftKey
// Only process simple clicks or clicks with the acceptable modifiers
if (simpleClick || specificSelectModifier || rangeSelectModifier) {
event.preventDefault()
event.stopPropagation()
this.onSelect({
isCheckboxSelect: $(event.target).hasClass('frost-list-selection-indicator'),
isRangeSelect: rangeSelectModifier,
isCurrentlySelected: this.get('model.isSelected'),
isSpecificSelect: specificSelectModifier,
item: this.get('model')
})
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment