Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ;(function () {
- // SWIPE DETECT HELPER
- // ----------------------------------------------
- // http://www.javascriptkit.com/javatutors/touchevents2.shtml
- var swipeDetect = function (el, callback) {
- var touchsurface = el,
- swipedir,
- startX,
- startY,
- distX,
- distY,
- threshold = 100, // required min distance traveled to be considered swipe
- restraint = 100, // maximum distance allowed at the same time in perpendicular direction
- allowedTime = 300, // maximum time allowed to travel that distance
- elapsedTime,
- startTime,
- eventObj,
- handleswipe = callback || function (swipedir, eventObj) {}
- touchsurface.addEventListener('touchstart', function (e) {
- var touchobj = e.changedTouches[0]
- swipedir = 'none'
- startX = touchobj.pageX
- startY = touchobj.pageY
- startTime = Date.now() // record time when finger first makes contact with surface
- eventObj = e
- }, false)
- touchsurface.addEventListener('touchend', function (e) {
- var touchobj = e.changedTouches[0]
- distX = touchobj.pageX - startX // get horizontal dist traveled by finger while in contact with surface
- distY = touchobj.pageY - startY // get vertical dist traveled by finger while in contact with surface
- elapsedTime = Date.now() - startTime // get time elapsed
- if (elapsedTime <= allowedTime) {
- // first condition for awipe met
- if (Math.abs(distX) >= threshold && Math.abs(distY) <= restraint) {
- // 2nd condition for horizontal swipe met
- swipedir = distX < 0 ? 'left' : 'right' // if dist traveled is negative, it indicates left swipe
- } else if (Math.abs(distY) >= threshold && Math.abs(distX) <= restraint) {
- // 2nd condition for vertical swipe met
- swipedir = distY < 0 ? 'up' : 'down' // if dist traveled is negative, it indicates up swipe
- }
- }
- handleswipe(swipedir, eventObj)
- }, false)
- }
- // CLOSEST PARENT HELPER FUNCTION
- // ----------------------------------------------
- var closestParent = function (child, match) {
- if (!child || child === document) return null
- if (child.classList.contains(match) || child.nodeName.toLowerCase() === match) return child
- return closestParent(child.parentNode, match)
- }
- // REUSABLE FUNCTION
- // ----------------------------------------------
- // Change function
- var processChange = function (elem) {
- // Grab data-state list and convert to array
- var dataState = elem.getAttribute('data-state')
- dataState = dataState.split(', ')
- // Grab data-state-behaviour list if present and convert to array
- if (elem.getAttribute('data-state-behaviour')) {
- var dataStateBehaviour = elem.getAttribute('data-state-behaviour')
- dataStateBehaviour = dataStateBehaviour.split(', ')
- }
- // Grab data-scope list if present and convert to array
- if (elem.getAttribute('data-state-scope')) {
- var dataStateScope = elem.getAttribute('data-state-scope')
- dataStateScope = dataStateScope.split(', ')
- }
- // Grab data-state-element list and convert to array
- // If data-state-element isn't found, pass self, set scope to self if none is present, essentially replicating "this"
- var dataStateElement
- if (elem.getAttribute('data-state-element')) {
- dataStateElement = elem.getAttribute('data-state-element')
- dataStateElement = dataStateElement.split(', ')
- } else {
- dataStateElement = []
- dataStateElement.push(elem.classList[0])
- if (!dataStateScope) dataStateScope = dataStateElement
- }
- // Find out which has the biggest length between states and elements and use that length as loop number
- // This is to make sure situations where we have one data-state-element value and many data-state values are correctly setup
- var dataLength = Math.max(dataStateElement.length, dataState.length)
- // Loop
- for (var b = 0; b < dataLength; b++) {
- // If a data-state-element value isn't found, use last valid one
- if (dataStateElement[b] !== undefined) var dataStateElementValue = dataStateElement[b]
- // If scope isn't found, use last valid one
- if (dataStateScope && dataStateScope[b] !== undefined) var cachedScope = dataStateScope[b]
- else if (cachedScope) dataStateScope[b] = cachedScope
- // Grab elem references, apply scope if found
- var elemRef
- if (dataStateScope && dataStateScope[b] !== 'false') {
- // Grab parent
- var elemParent = closestParent(elem, dataStateScope[b])
- // Grab all matching child elements of parent
- elemRef = elemParent.querySelectorAll('.' + dataStateElementValue)
- // Convert to array
- elemRef = Array.prototype.slice.call(elemRef)
- // Add parent if it matches the data-state-element and fits within scope
- if (elemParent.classList.contains(dataStateElementValue)) elemRef.unshift(elemParent)
- }
- else elemRef = document.querySelectorAll('.' + dataStateElementValue)
- // Grab state we will add
- // If one isn't found, keep last valid one
- if (dataState[b] !== undefined) var elemState = dataState[b]
- // Grab behaviour if any exists
- // If one isn't found, keep last valid one
- if (dataStateBehaviour && dataStateBehaviour[b] !== undefined) var elemBehaviour = dataStateBehaviour[b]
- // Do
- for (var c = 0; c < elemRef.length; c++) {
- // Find out if we're manipulating aria-attributes or classes
- var toggleAttr
- if (elemRef[c].getAttribute(elemState)) toggleAttr = true
- else toggleAttr = false
- if (elemBehaviour === 'add') {
- if (toggleAttr) elemRef[c].setAttribute(elemState, true)
- else elemRef[c].classList.add(elemState)
- }
- else if (elemBehaviour === 'remove') {
- if (toggleAttr) elemRef[c].setAttribute(elemState, false)
- else elemRef[c].classList.remove(elemState)
- }
- else if (toggleAttr) {
- if (elemRef[c].getAttribute(elemState) === 'true') elemRef[c].setAttribute(elemState, false)
- else elemRef[c].setAttribute(elemState, true)
- }
- else elemRef[c].classList.toggle(elemState)
- }
- }
- }
- // Init function
- var initDataState = function (elem) {
- // Detect data-swipe attribute before we do anything, as it's optional
- if (elem.getAttribute('data-state-swipe')) {
- // Grab swipe specific data from data-state-swipe
- var elemSwipe = elem.getAttribute('data-state-swipe').split(', '),
- direction = elemSwipe[0],
- elemSwipeBool = elemSwipe[1],
- currentElem = elem
- // If the behaviour flag is set to "false", or not set at all, then assign our click event
- if (elemSwipeBool === 'false' || !elemSwipeBool) {
- // Assign click event
- elem.addEventListener('click', function (e) {
- // Prevent default action of element
- e.preventDefault()
- // Run state function
- processChange(this)
- })
- }
- // Use our swipeDetect helper function to determine if the swipe direction matches our desired direction
- swipeDetect(elem, function (swipedir) {
- // Run state function
- if (swipedir === direction) processChange(currentElem)
- })
- } else {
- // Assign click event
- elem.addEventListener('click', function (e) {
- // Prevent default action of element
- e.preventDefault()
- // Run state function
- processChange(this)
- })
- }
- // Add keyboard event for enter key or space to mimic anchor functionality
- elem.addEventListener('keypress', function (e) {
- if (e.which !== 13 && e.which !== 32) return
- // Prevent default action of element
- e.preventDefault()
- // Run state function
- processChange(this)
- })
- }
- // Run when DOM has finished loading
- document.addEventListener('DOMContentLoaded', function () {
- // Grab all elements with required attributes
- var elems = document.querySelectorAll('[data-state]')
- // Loop through our matches and add click events
- for (var a = 0; a < elems.length; a++) initDataState(elems[a])
- // Setup mutation observer to track changes for matching elements added after initial DOM render
- var observer = new MutationObserver(function (mutations) {
- mutations.forEach(function (mutation) {
- for (var d = 0; d < mutation.addedNodes.length; d++) {
- // Check if we're dealing with an element node
- if (typeof mutation.addedNodes[d].getAttribute === 'function' && mutation.addedNodes[d].getAttribute('data-state')) {
- initDataState(mutation.addedNodes[d])
- }
- }
- })
- })
- // Define type of change our observer will watch out for
- observer.observe(document.body, {
- childList: true,
- subtree: true
- })
- })
- })()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement