Created
January 17, 2018 14:27
-
-
Save median-man/5b5ff8de285531511cca6c39b791b4de to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Usage: | |
Create an instance of the class passing a selector string, callback for handling shift + click | |
on element completing a range, and a callback for handling a click on a single element. | |
The selector is a string passed to document.querySelector to set the container for the shiftGroup. | |
The onGroupClick callback is passed the original event object and an array containing the range | |
of selected elements. | |
The onItemClick callback is passed the original event object and the item containing the target | |
element of the event. | |
Example: | |
function handleSelection() {} | |
function handleItemClick() {} | |
const shiftGroup = new ShiftGroup('#group', handleSelection, handleItemClick); | |
*/ | |
/** | |
* Class representing an element which contains a group of elements with shift + click handling | |
* on a range of elements from the group. | |
*/ | |
class ShiftGroup { | |
/** | |
* Create a shiftGroup. | |
* @param {string} selector - Query selector for shift group container. | |
* @param {function} onGroupClick - Callback to handle group selection shift + click. | |
* @param {function} onItemClick - Callback to handle click on a single item in the group. | |
*/ | |
constructor(selector, onGroupClick, onItemClick) { | |
this.lastItem = false; | |
this.container = document.querySelector(selector); | |
this.container.addEventListener('click', this.handleContainerClick.bind(this)); | |
this.onGroupClick = onGroupClick; | |
this.onItemClick = onItemClick; | |
} | |
/** | |
* Gets array of item elements from the previously selected item to the target item (inclusive) | |
* and calls this.onGroupItem(event, selectedItems) where selectedItems is the array. | |
* @param {MouseEvent} event - MouseEvent triggered from descendant of this.container. | |
* @param {HTMLElement} targetItem - Group item from which the event was triggered. | |
*/ | |
handleGroupClick(event, targetItem) { | |
const siblings = [...this.container.children]; | |
const fromIndex = siblings.indexOf(targetItem); | |
const toIndex = siblings.indexOf(this.lastItem); | |
let selectedItems; | |
// get array of all items from the last selected item to the target item inclusive | |
if (fromIndex > toIndex) { | |
selectedItems = siblings.slice(toIndex, fromIndex + 1); | |
} else { | |
selectedItems = siblings.slice(fromIndex, toIndex + 1); | |
} | |
this.onGroupClick(event, selectedItems); | |
this.lastItem = false; | |
} | |
/** | |
* Assigns targetItem to lastItem property and passes the event and targetItem to callback. | |
* @param {MouseEvent} event - MouseEvent triggered from descendant of this.container. | |
* @param {HTMLElement} targetItem - Group item from which the event was triggered. | |
*/ | |
handleItemClick(event, targetItem) { | |
this.lastItem = targetItem; | |
this.onItemClick(event, targetItem); | |
} | |
/** | |
* Determines if event is a range selection or single item and calls the corresponding handler. | |
* @param {MouseEvent} event | |
*/ | |
handleContainerClick(event) { | |
// get the item of the group containing the event.target element | |
let targetItem = event.target; | |
while (targetItem.parentNode !== this.container) { | |
targetItem = targetItem.parentNode; | |
} | |
// if shift key was pressed and lastItem was set then proceed to group event handler | |
if (this.handleGroupClick && event.shiftKey && this.lastItem) { | |
return this.handleGroupClick(event, targetItem); | |
} | |
return this.handleItemClick ? this.handleItemClick(event, targetItem) : null; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment