1 /* Copyright 2014+, Federico Zivolo, LICENSE at https://github.com/FezVrasta/bootstrap-material-design/blob/master/LICENSE.md */
2 /* globals jQuery, navigator */
4 (function($, window, document, undefined) {
9 * Define the name of the plugin
11 var ripples = "ripples";
15 * Get an instance of the plugin
21 * Define the defaults of the plugin
27 * Create the main plugin function
29 function Ripples(element, options) {
32 this.element = $(element);
34 this.options = $.extend({}, defaults, options);
36 this._defaults = defaults;
44 * Initialize the plugin
46 Ripples.prototype.init = function() {
47 var $element = this.element;
49 $element.on("mousedown touchstart", function(event) {
51 * Verify if the user is just touching on a device and return if so
53 if(self.isTouch() && event.type === "mousedown") {
59 * Verify if the current element already has a ripple wrapper element and
60 * creates if it doesn't
62 if(!($element.find(".ripple-wrapper").length)) {
63 $element.append("<div class=\"ripple-wrapper\"></div>");
68 * Find the ripple wrapper
70 var $wrapper = $element.children(".ripple-wrapper");
74 * Get relY and relX positions
76 var relY = self.getRelY($wrapper, event);
77 var relX = self.getRelX($wrapper, event);
81 * If relY and/or relX are false, return the event
89 * Get the ripple color
91 var rippleColor = self.getRipplesColor($element);
95 * Create the ripple element
97 var $ripple = $("<div></div>");
104 "background-color": rippleColor
109 * Append the ripple to the wrapper
111 $wrapper.append($ripple);
115 * Make sure the ripple has the styles applied (ugly hack but it works)
117 (function() { return window.getComputedStyle($ripple[0]).opacity; })();
121 * Turn on the ripple animation
123 self.rippleOn($element, $ripple);
127 * Call the rippleEnd function when the transition "on" ends
129 setTimeout(function() {
130 self.rippleEnd($ripple);
135 * Detect when the user leaves the element
137 $element.on("mouseup mouseleave touchend", function() {
138 $ripple.data("mousedown", "off");
140 if($ripple.data("animating") === "off") {
141 self.rippleOut($ripple);
150 * Get the new size based on the element height/width and the ripple width
152 Ripples.prototype.getNewSize = function($element, $ripple) {
154 return (Math.max($element.outerWidth(), $element.outerHeight()) / $ripple.outerWidth()) * 2.5;
161 Ripples.prototype.getRelX = function($wrapper, event) {
162 var wrapperOffset = $wrapper.offset();
164 if(!self.isTouch()) {
166 * Get the mouse position relative to the ripple wrapper
168 return event.pageX - wrapperOffset.left;
171 * Make sure the user is using only one finger and then get the touch
172 * position relative to the ripple wrapper
174 event = event.originalEvent;
176 if(event.touches.length === 1) {
177 return event.touches[0].pageX - wrapperOffset.left;
188 Ripples.prototype.getRelY = function($wrapper, event) {
189 var wrapperOffset = $wrapper.offset();
191 if(!self.isTouch()) {
193 * Get the mouse position relative to the ripple wrapper
195 return event.pageY - wrapperOffset.top;
198 * Make sure the user is using only one finger and then get the touch
199 * position relative to the ripple wrapper
201 event = event.originalEvent;
203 if(event.touches.length === 1) {
204 return event.touches[0].pageY - wrapperOffset.top;
213 * Get the ripple color
215 Ripples.prototype.getRipplesColor = function($element) {
217 var color = $element.data("ripple-color") ? $element.data("ripple-color") : window.getComputedStyle($element[0]).color;
224 * Verify if the client browser has transistion support
226 Ripples.prototype.hasTransitionSupport = function() {
227 var thisBody = document.body || document.documentElement;
228 var thisStyle = thisBody.style;
231 thisStyle.transition !== undefined ||
232 thisStyle.WebkitTransition !== undefined ||
233 thisStyle.MozTransition !== undefined ||
234 thisStyle.MsTransition !== undefined ||
235 thisStyle.OTransition !== undefined
243 * Verify if the client is using a mobile device
245 Ripples.prototype.isTouch = function() {
246 return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
251 * End the animation of the ripple
253 Ripples.prototype.rippleEnd = function($ripple) {
254 $ripple.data("animating", "off");
256 if($ripple.data("mousedown") === "off") {
257 self.rippleOut($ripple);
263 * Turn off the ripple effect
265 Ripples.prototype.rippleOut = function($ripple) {
268 if(self.hasTransitionSupport()) {
269 $ripple.addClass("ripple-out");
271 $ripple.animate({"opacity": 0}, 100, function() {
272 $ripple.trigger("transitionend");
276 $ripple.on("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", function() {
283 * Turn on the ripple effect
285 Ripples.prototype.rippleOn = function($element, $ripple) {
286 var size = self.getNewSize($element, $ripple);
288 if(self.hasTransitionSupport()) {
291 "-ms-transform": "scale(" + size + ")",
292 "-moz-transform": "scale(" + size + ")",
293 "-webkit-transform": "scale(" + size + ")",
294 "transform": "scale(" + size + ")"
296 .addClass("ripple-on")
297 .data("animating", "on")
298 .data("mousedown", "on");
301 "width": Math.max($element.outerWidth(), $element.outerHeight()) * 2,
302 "height": Math.max($element.outerWidth(), $element.outerHeight()) * 2,
303 "margin-left": Math.max($element.outerWidth(), $element.outerHeight()) * (-1),
304 "margin-top": Math.max($element.outerWidth(), $element.outerHeight()) * (-1),
307 $ripple.trigger("transitionend");
314 * Create the jquery plugin function
316 $.fn.ripples = function(options) {
317 return this.each(function() {
318 if(!$.data(this, "plugin_" + ripples)) {
319 $.data(this, "plugin_" + ripples, new Ripples(this, options));
324 })(jQuery, window, document);