summaryrefslogtreecommitdiff
path: root/templates/assets/bootstrap-material-design/js/ripples.js
diff options
context:
space:
mode:
authorschneefux <schneefux+commit@schneefux.xyz>2017-03-22 19:19:26 +0100
committerschneefux <schneefux+commit@schneefux.xyz>2017-03-22 19:19:26 +0100
commitd42c8b528eb595101954f478e0024e3f079f6fbf (patch)
tree61a528cf94f1f6941f4683ae8736a4a0135c035e /templates/assets/bootstrap-material-design/js/ripples.js
downloadminionlivesmatter-d42c8b528eb595101954f478e0024e3f079f6fbf.tar.gz
minionlivesmatter-d42c8b528eb595101954f478e0024e3f079f6fbf.zip
first implementation of fun stats site
Diffstat (limited to 'templates/assets/bootstrap-material-design/js/ripples.js')
-rw-r--r--templates/assets/bootstrap-material-design/js/ripples.js311
1 files changed, 311 insertions, 0 deletions
diff --git a/templates/assets/bootstrap-material-design/js/ripples.js b/templates/assets/bootstrap-material-design/js/ripples.js
new file mode 100644
index 0000000..c28d287
--- /dev/null
+++ b/templates/assets/bootstrap-material-design/js/ripples.js
@@ -0,0 +1,311 @@
+import Util from './util'
+
+const Ripples = (($) => {
+
+ /**
+ * ------------------------------------------------------------------------
+ * Constants
+ * ------------------------------------------------------------------------
+ */
+ const NAME = 'ripples'
+ const DATA_KEY = `bmd.${NAME}`
+ const JQUERY_NAME = `bmd${NAME.charAt(0).toUpperCase() + NAME.slice(1)}`
+ const JQUERY_NO_CONFLICT = $.fn[JQUERY_NAME]
+
+ const ClassName = {
+ CONTAINER: 'ripple-container',
+ DECORATOR: 'ripple-decorator'
+ }
+
+ const Selector = {
+ CONTAINER: `.${ClassName.CONTAINER}`,
+ DECORATOR: `.${ClassName.DECORATOR}` //,
+ }
+
+
+ const Default = {
+ container: {
+ template: `<div class='${ClassName.CONTAINER}'></div>`
+ },
+ decorator: {
+ template: `<div class='${ClassName.DECORATOR}'></div>`
+ },
+ trigger: {
+ start: 'mousedown touchstart',
+ end: 'mouseup mouseleave touchend'
+ },
+ touchUserAgentRegex: /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i,
+ duration: 500
+ }
+
+ /**
+ * ------------------------------------------------------------------------
+ * Class Definition
+ * ------------------------------------------------------------------------
+ */
+ class Ripples {
+
+ constructor($element, config) {
+ this.$element = $element
+
+ //console.log(`Adding ripples to ${Util.describe(this.$element)}`) // eslint-disable-line no-console
+ this.config = $.extend(true, {}, Default, config)
+
+ // attach initial listener
+ this.$element.on(this.config.trigger.start, (event) => {
+ this._onStartRipple(event)
+ })
+ }
+
+
+ dispose() {
+ this.$element.data(DATA_KEY, null)
+ this.$element = null
+ this.$container = null
+ this.$decorator = null
+ this.config = null
+ }
+
+ // ------------------------------------------------------------------------
+ // private
+
+ _onStartRipple(event) {
+
+ // Verify if the user is just touching on a device and return if so
+ if (this._isTouch() && event.type === 'mousedown') {
+ return
+ }
+
+ // Find or create the ripple container element
+ this._findOrCreateContainer()
+
+ // Get relY and relX positions of the container element
+ let relY = this._getRelY(event)
+ let relX = this._getRelX(event)
+
+ // If relY and/or relX are false, return the event
+ if (!relY && !relX) {
+ return
+ }
+
+ // set the location and color each time (even if element is cached)
+ this.$decorator.css({
+ left: relX,
+ top: relY,
+ 'background-color': this._getRipplesColor()
+ })
+
+ // Make sure the ripple has the styles applied (ugly hack but it works)
+ this._forceStyleApplication()
+
+ // Turn on the ripple animation
+ this.rippleOn()
+
+ // Call the rippleEnd function when the transition 'on' ends
+ setTimeout(() => {
+ this.rippleEnd()
+ }, this.config.duration)
+
+ // Detect when the user leaves the element to cleanup if not already done?
+ this.$element.on(this.config.trigger.end, () => {
+ if (this.$decorator) { // guard against race condition/mouse attack
+ this.$decorator.data('mousedown', 'off')
+
+ if (this.$decorator.data('animating') === 'off') {
+ this.rippleOut()
+ }
+ }
+ })
+ }
+
+ _findOrCreateContainer() {
+ if (!this.$container || !this.$container.length > 0) {
+ this.$element.append(this.config.container.template)
+ this.$container = this.$element.find(Selector.CONTAINER)
+ }
+
+ // always add the rippleElement, it is always removed
+ this.$container.append(this.config.decorator.template)
+ this.$decorator = this.$container.find(Selector.DECORATOR)
+ }
+
+ // Make sure the ripple has the styles applied (ugly hack but it works)
+ _forceStyleApplication() {
+ return window.getComputedStyle(this.$decorator[0]).opacity
+ }
+
+
+ /**
+ * Get the relX
+ */
+ _getRelX(event) {
+ let wrapperOffset = this.$container.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
+ }
+ }
+
+ return result
+ }
+
+ /**
+ * Get the relY
+ */
+ _getRelY(event) {
+ let containerOffset = this.$container.offset()
+ let result = null
+
+ if (!this._isTouch()) {
+ /**
+ * Get the mouse position relative to the ripple wrapper
+ */
+ result = event.pageY - containerOffset.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 - containerOffset.top
+ } else {
+ result = false
+ }
+ }
+
+ return result
+ }
+
+ /**
+ * Get the ripple color
+ */
+ _getRipplesColor() {
+ let color = this.$element.data('ripple-color') ? this.$element.data('ripple-color') : window.getComputedStyle(this.$element[0]).color
+ return color
+ }
+
+ /**
+ * Verify if the client is using a mobile device
+ */
+ _isTouch() {
+ return this.config.touchUserAgentRegex.test(navigator.userAgent)
+ }
+
+ /**
+ * End the animation of the ripple
+ */
+ rippleEnd() {
+ if (this.$decorator) { // guard against race condition/mouse attack
+ this.$decorator.data('animating', 'off')
+
+ if (this.$decorator.data('mousedown') === 'off') {
+ this.rippleOut(this.$decorator)
+ }
+ }
+ }
+
+ /**
+ * Turn off the ripple effect
+ */
+ rippleOut() {
+ this.$decorator.off()
+
+ if (Util.transitionEndSupported()) {
+ this.$decorator.addClass('ripple-out')
+ } else {
+ this.$decorator.animate({opacity: 0}, 100, () => {
+ this.$decorator.trigger('transitionend')
+ })
+ }
+
+ this.$decorator.on(Util.transitionEndSelector(), () => {
+ if (this.$decorator) {
+ this.$decorator.remove()
+ this.$decorator = null
+ }
+ })
+ }
+
+ /**
+ * Turn on the ripple effect
+ */
+ rippleOn() {
+ let size = this._getNewSize()
+
+ if (Util.transitionEndSupported()) {
+ this.$decorator
+ .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 {
+ this.$decorator.animate({
+ width: Math.max(this.$element.outerWidth(), this.$element.outerHeight()) * 2,
+ height: Math.max(this.$element.outerWidth(), this.$element.outerHeight()) * 2,
+ 'margin-left': Math.max(this.$element.outerWidth(), this.$element.outerHeight()) * (-1),
+ 'margin-top': Math.max(this.$element.outerWidth(), this.$element.outerHeight()) * (-1),
+ opacity: 0.2
+ }, this.config.duration, () => {
+ this.$decorator.trigger('transitionend')
+ })
+ }
+ }
+
+ /**
+ * Get the new size based on the element height/width and the ripple width
+ */
+ _getNewSize() {
+ return (Math.max(this.$element.outerWidth(), this.$element.outerHeight()) / this.$decorator.outerWidth()) * 2.5
+ }
+
+ // ------------------------------------------------------------------------
+ // static
+
+ static _jQueryInterface(config) {
+ return this.each(function () {
+ let $element = $(this)
+ let data = $element.data(DATA_KEY)
+
+ if (!data) {
+ data = new Ripples($element, config)
+ $element.data(DATA_KEY, data)
+ }
+ })
+ }
+ }
+
+ /**
+ * ------------------------------------------------------------------------
+ * jQuery
+ * ------------------------------------------------------------------------
+ */
+ $.fn[JQUERY_NAME] = Ripples._jQueryInterface
+ $.fn[JQUERY_NAME].Constructor = Ripples
+ $.fn[JQUERY_NAME].noConflict = () => {
+ $.fn[JQUERY_NAME] = JQUERY_NO_CONFLICT
+ return Ripples._jQueryInterface
+ }
+
+ return Ripples
+
+})(jQuery)
+
+export default Ripples