| /* Copyright 2014+, Federico Zivolo, LICENSE at https://github.com/FezVrasta/bootstrap-material-design/blob/master/LICENSE.md */ |
| /* globals jQuery, navigator */ |
| |
| (function($, window, document, undefined) { |
| |
| "use strict"; |
| |
| /** |
| * Define the name of the plugin |
| */ |
| var ripples = "ripples"; |
| |
| |
| /** |
| * Get an instance of the plugin |
| */ |
| var self = null; |
| |
| |
| /** |
| * Define the defaults of the plugin |
| */ |
| var defaults = {}; |
| |
| |
| /** |
| * Create the main plugin function |
| */ |
| function Ripples(element, options) { |
| self = this; |
| |
| this.element = $(element); |
| |
| this.options = $.extend({}, defaults, options); |
| |
| this._defaults = defaults; |
| this._name = ripples; |
| |
| this.init(); |
| } |
| |
| |
| /** |
| * Initialize the plugin |
| */ |
| Ripples.prototype.init = function() { |
| var $element = this.element; |
| |
| $element.on("mousedown touchstart", function(event) { |
| /** |
| * Verify if the user is just touching on a device and return if so |
| */ |
| if(self.isTouch() && event.type === "mousedown") { |
| return; |
| } |
| |
| |
| /** |
| * Verify if the current element already has a ripple wrapper element and |
| * creates if it doesn't |
| */ |
| if(!($element.find(".ripple-container").length)) { |
| $element.append("<div class=\"ripple-container\"></div>"); |
| } |
| |
| |
| /** |
| * Find the ripple wrapper |
| */ |
| var $wrapper = $element.children(".ripple-container"); |
| |
| |
| /** |
| * Get relY and relX positions |
| */ |
| var relY = self.getRelY($wrapper, event); |
| var relX = self.getRelX($wrapper, event); |
| |
| |
| /** |
| * If relY and/or relX are false, return the event |
| */ |
| if(!relY && !relX) { |
| return; |
| } |
| |
| |
| /** |
| * Get the ripple color |
| */ |
| var rippleColor = self.getRipplesColor($element); |
| |
| |
| /** |
| * Create the ripple element |
| */ |
| var $ripple = $("<div></div>"); |
| |
| $ripple |
| .addClass("ripple") |
| .css({ |
| "left": relX, |
| "top": relY, |
| "background-color": rippleColor |
| }); |
| |
| |
| /** |
| * Append the ripple to the wrapper |
| */ |
| $wrapper.append($ripple); |
| |
| |
| /** |
| * Make sure the ripple has the styles applied (ugly hack but it works) |
| */ |
| (function() { return window.getComputedStyle($ripple[0]).opacity; })(); |
| |
| |
| /** |
| * Turn on the ripple animation |
| */ |
| self.rippleOn($element, $ripple); |
| |
| |
| /** |
| * Call the rippleEnd function when the transition "on" ends |
| */ |
| setTimeout(function() { |
| self.rippleEnd($ripple); |
| }, 500); |
| |
| |
| /** |
| * Detect when the user leaves the element |
| */ |
| $element.on("mouseup mouseleave touchend", function() { |
| $ripple.data("mousedown", "off"); |
| |
| if($ripple.data("animating") === "off") { |
| self.rippleOut($ripple); |
| } |
| }); |
| |
| }); |
| }; |
| |
| |
| /** |
| * Get the new size based on the element height/width and the ripple width |
| */ |
| Ripples.prototype.getNewSize = function($element, $ripple) { |
| |
| return (Math.max($element.outerWidth(), $element.outerHeight()) / $ripple.outerWidth()) * 2.5; |
| }; |
| |
| |
| /** |
| * Get the relX |
| */ |
| Ripples.prototype.getRelX = function($wrapper, event) { |
| var wrapperOffset = $wrapper.offset(); |
| |
| if(!self.isTouch()) { |
| /** |
| * Get the mouse position relative to the ripple wrapper |
| */ |
| return 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) { |
| return event.touches[0].pageX - wrapperOffset.left; |
| } |
| |
| return false; |
| } |
| }; |
| |
| |
| /** |
| * Get the relY |
| */ |
| Ripples.prototype.getRelY = function($wrapper, event) { |
| var wrapperOffset = $wrapper.offset(); |
| |
| if(!self.isTouch()) { |
| /** |
| * Get the mouse position relative to the ripple wrapper |
| */ |
| return 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) { |
| return event.touches[0].pageY - wrapperOffset.top; |
| } |
| |
| return false; |
| } |
| }; |
| |
| |
| /** |
| * Get the ripple color |
| */ |
| Ripples.prototype.getRipplesColor = function($element) { |
| |
| var color = $element.data("ripple-color") ? $element.data("ripple-color") : window.getComputedStyle($element[0]).color; |
| |
| return color; |
| }; |
| |
| |
| /** |
| * Verify if the client browser has transistion support |
| */ |
| Ripples.prototype.hasTransitionSupport = function() { |
| var thisBody = document.body || document.documentElement; |
| var thisStyle = thisBody.style; |
| |
| var support = ( |
| thisStyle.transition !== undefined || |
| thisStyle.WebkitTransition !== undefined || |
| thisStyle.MozTransition !== undefined || |
| thisStyle.MsTransition !== undefined || |
| thisStyle.OTransition !== undefined |
| ); |
| |
| return support; |
| }; |
| |
| |
| /** |
| * Verify if the client is using a mobile device |
| */ |
| Ripples.prototype.isTouch = function() { |
| return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); |
| }; |
| |
| |
| /** |
| * End the animation of the ripple |
| */ |
| Ripples.prototype.rippleEnd = function($ripple) { |
| $ripple.data("animating", "off"); |
| |
| if($ripple.data("mousedown") === "off") { |
| self.rippleOut($ripple); |
| } |
| }; |
| |
| |
| /** |
| * Turn off the ripple effect |
| */ |
| Ripples.prototype.rippleOut = function($ripple) { |
| $ripple.off(); |
| |
| if(self.hasTransitionSupport()) { |
| $ripple.addClass("ripple-out"); |
| } else { |
| $ripple.animate({"opacity": 0}, 100, function() { |
| $ripple.trigger("transitionend"); |
| }); |
| } |
| |
| $ripple.on("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", function() { |
| $ripple.remove(); |
| }); |
| }; |
| |
| |
| /** |
| * Turn on the ripple effect |
| */ |
| Ripples.prototype.rippleOn = function($element, $ripple) { |
| var size = self.getNewSize($element, $ripple); |
| |
| if(self.hasTransitionSupport()) { |
| $ripple |
| .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 { |
| $ripple.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, function() { |
| $ripple.trigger("transitionend"); |
| }); |
| } |
| }; |
| |
| |
| /** |
| * Create the jquery plugin function |
| */ |
| $.fn.ripples = function(options) { |
| return this.each(function() { |
| if(!$.data(this, "plugin_" + ripples)) { |
| $.data(this, "plugin_" + ripples, new Ripples(this, options)); |
| } |
| }); |
| }; |
| |
| })(jQuery, window, document); |