mdb-ui-kit/js/src/ripples.js

351 lines
9.2 KiB
JavaScript
Raw Normal View History

2015-11-30 23:57:40 +03:00
// FIXME: convert to member variable use instead of passing around/finding?
const Ripples = (($) => {
2015-11-21 02:50:50 +03:00
/**
2015-11-30 23:57:40 +03:00
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
2015-11-21 02:50:50 +03:00
*/
2015-11-30 23:57:40 +03:00
const NAME = 'ripples'
const DATA_KEY = `bmd.${NAME}`
// const EVENT_KEY = `.${DATA_KEY}`
// const DATA_API_KEY = '.data-api'
const JQUERY_NO_CONFLICT = $.fn[NAME]
const DEFAULT_OPTIONS = {}
// const Selector = {
// DATA_DISMISS: '[data-dismiss="ripples"]'
// }
//
// const Event = {
// CLOSE: `close${EVENT_KEY}`,
// CLOSED: `closed${EVENT_KEY}`,
// CLICK_DATA_API: `click${EVENT_KEY}${DATA_API_KEY}`
// }
2015-11-21 02:50:50 +03:00
/**
2015-11-30 23:57:40 +03:00
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
2015-11-21 02:50:50 +03:00
*/
2015-11-30 23:57:40 +03:00
class Ripples {
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
constructor(element, options) {
this._element = $(element)
this._options = $.extend({}, DEFAULT_OPTIONS, options)
this._element.on("mousedown touchstart", this._createRipple)
}
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
// getters
static get NAME() {
return NAME
}
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
// public
close(element) {
element = element || this._element
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
let rootElement = this._getRootElement(element)
let customEvent = this._triggerCloseEvent(rootElement)
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
if (customEvent.isDefaultPrevented()) {
return
}
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
this._removeElement(rootElement)
}
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
dispose() {
$.removeData(this._element, DATA_KEY)
this._element = null
}
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
// ------------------------------------------------------------------------
// private
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
_createRipple(event) {
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
// Verify if the user is just touching on a device and return if so
if (this.isTouch() && event.type === "mousedown") {
return
2015-11-21 02:50:50 +03:00
}
2015-11-30 23:57:40 +03:00
// Verify if the current element already has a ripple wrapper element and creates if it doesn't
if (!(this._element.find(".ripple-container").length)) {
this._element.append("<div class='ripple-container'></div>")
2015-11-21 02:50:50 +03:00
}
2015-11-30 23:57:40 +03:00
// Find the ripple wrapper
let containerElement = this._element.children(".ripple-container")
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
// Get relY and relX positions
let relY = this._getRelY(containerElement, event)
let relX = this._getRelX(containerElement, event)
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
// If relY and/or relX are false, return the event
if (!relY && !relX) {
return
2015-11-21 02:50:50 +03:00
}
2015-11-30 23:57:40 +03:00
// Get the ripple color
let rippleColor = this._getRipplesColor(this._element)
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
// Create the ripple element
let rippleElement = $("<div></div>")
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
rippleElement.addClass("ripple").css(`left: ${relX}; top: ${relY}; background-color: ${rippleColor}`)
/* https://github.com/eslint/eslint/issues/4579
rippleElement.addClass("ripple").css({
"left": relX,
"top": relY,
"background-color": rippleColor
})
2015-11-21 02:50:50 +03:00
*/
2015-11-30 23:57:40 +03:00
// Append the ripple to the wrapper
containerElement.append(rippleElement)
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
// Make sure the ripple has the styles applied (ugly hack but it works)
(() => { return window.getComputedStyle(rippleElement[0]).opacity })()
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
// Turn on the ripple animation
this.rippleOn(this._element, rippleElement)
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
// Call the rippleEnd function when the transition "on" ends
setTimeout(() => {
this.rippleEnd(rippleElement)
}, 500)
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
// Detect when the user leaves the element
this._element.on("mouseup mouseleave touchend", () => {
rippleElement.data("mousedown", "off")
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
if (rippleElement.data("animating") === "off") {
this.rippleOut(rippleElement)
}
})
}
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
/**
* Get the relX
*/
_getRelX(containerElement, event) {
let wrapperOffset = containerElement.offset()
let result = null
if (!this.isTouch()) {
// Get the mouse position relative to the ripple wrapper
result = event.pageX - wrapperOffset.left
} else {
// Make sure the user is using only one finger and then get the touch
// position relative to the ripple wrapper
event = event.originalEvent
if (event.touches.length === 1) {
result = event.touches[0].pageX - wrapperOffset.left
} else {
result = false
}
}
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
return result
}
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
/**
* Get the relY
*/
_getRelY(containerElement, event) {
let wrapperOffset = containerElement.offset()
let result = null
if (!this.isTouch()) {
/**
* Get the mouse position relative to the ripple wrapper
*/
result = event.pageY - wrapperOffset.top
} else {
/**
* Make sure the user is using only one finger and then get the touch
* position relative to the ripple wrapper
*/
event = event.originalEvent
if (event.touches.length === 1) {
result = event.touches[0].pageY - wrapperOffset.top
} else {
result = false
2015-11-21 02:50:50 +03:00
}
2015-11-30 23:57:40 +03:00
}
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
return result
}
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
/**
* Get the ripple color
*/
_getRipplesColor(element) {
let color = element.data("ripple-color") ? element.data("ripple-color") : window.getComputedStyle(element[0]).color
return color
}
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
/**
* Verify if the client browser has transistion support
*/
_hasTransitionSupport() {
let thisBody = document.body || document.documentElement
let thisStyle = thisBody.style
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
let support = (
thisStyle.transition !== undefined ||
thisStyle.WebkitTransition !== undefined ||
thisStyle.MozTransition !== undefined ||
thisStyle.MsTransition !== undefined ||
thisStyle.OTransition !== undefined
)
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
return support
}
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
/**
* Verify if the client is using a mobile device
*/
isTouch() {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
2015-11-21 02:50:50 +03:00
}
2015-11-30 23:57:40 +03:00
/**
* End the animation of the ripple
*/
rippleEnd(rippleElement) {
rippleElement.data("animating", "off")
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
if (rippleElement.data("mousedown") === "off") {
this.rippleOut(rippleElement)
2015-11-21 02:50:50 +03:00
}
}
2015-11-30 23:57:40 +03:00
/**
* Turn off the ripple effect
*/
rippleOut(rippleElement) {
rippleElement.off()
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
if (this._hasTransitionSupport()) {
rippleElement.addClass("ripple-out")
} else {
rippleElement.animate({ "opacity": 0 }, 100, () => {
rippleElement.trigger("transitionend")
})
}
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
rippleElement.on("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", () => {
rippleElement.remove()
})
}
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
/**
* Turn on the ripple effect
*/
rippleOn(element, rippleElement) {
let size = this._getNewSize(element, rippleElement)
if (this._hasTransitionSupport()) {
rippleElement
.css({
"-ms-transform": `scale(${size})`,
"-moz-transform": `scale(${size})`,
"-webkit-transform": `scale(${size})`,
"transform": `scale(${size})`
})
.addClass("ripple-on")
.data("animating", "on")
.data("mousedown", "on")
} else {
rippleElement.animate({
"width": Math.max(element.outerWidth(), element.outerHeight()) * 2,
"height": Math.max(element.outerWidth(), element.outerHeight()) * 2,
"margin-left": Math.max(element.outerWidth(), element.outerHeight()) * (-1),
"margin-top": Math.max(element.outerWidth(), element.outerHeight()) * (-1),
"opacity": 0.2
}, 500, () => {
rippleElement.trigger("transitionend")
})
}
}
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
// ------------------------------------------------------------------------
// static
/**
* Get the new size based on the element height/width and the ripple width
*/
static _getNewSize(element, rippleElement) {
return (Math.max(element.outerWidth(), element.outerHeight()) / rippleElement.outerWidth()) * 2.5
}
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
static _jQueryInterface(options) {
return this.each(() => {
let element = $(this)
let data = element.data(DATA_KEY)
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
if (!data) {
data = new Ripples(this, options)
element.data(DATA_KEY, data)
}
})
2015-11-21 02:50:50 +03:00
}
2015-11-30 23:57:40 +03:00
// static _handleClose(fooInstance) {
// return function(event) {
// if (event) {
// event.preventDefault()
// }
//
// fooInstance.close(this)
// }
// }
}
2015-11-21 02:50:50 +03:00
/**
2015-11-30 23:57:40 +03:00
* ------------------------------------------------------------------------
* Data Api implementation
* ------------------------------------------------------------------------
2015-11-21 02:50:50 +03:00
*/
2015-11-30 23:57:40 +03:00
// $(document).on(
// Event.CLICK_DATA_API,
// Selector.DATA_DISMISS,
// Ripples._handleClose(new Ripples())
// )
2015-11-21 02:50:50 +03:00
/**
2015-11-30 23:57:40 +03:00
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
2015-11-21 02:50:50 +03:00
*/
2015-11-30 23:57:40 +03:00
$.fn[NAME] = Ripples._jQueryInterface
$.fn[NAME].Constructor = Ripples
$.fn[NAME].noConflict = () => {
$.fn[NAME] = JQUERY_NO_CONFLICT
return Ripples._jQueryInterface
}
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
return Ripples
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
})(jQuery)
2015-11-21 02:50:50 +03:00
2015-11-30 23:57:40 +03:00
export default Ripples