Ripples.js rewritten with jQuery + added JS maps

This commit is contained in:
FezVrasta 2014-11-26 12:42:41 +01:00
parent c776bc231b
commit 30d53dab95
12 changed files with 532 additions and 688 deletions

View File

@ -52,10 +52,13 @@ module.exports = function(grunt) {
},
uglify: {
options: {
sourceMap: true
},
minifyjs: {
files: {
"dist/js/material.min.js": "scripts/material.js",
"dist/js/ripples.min.js": "scripts/ripples.js"
"dist/js/material.min.js": "dist/js/material.js",
"dist/js/ripples.min.js": "dist/js/ripples.js"
}
}
},
@ -164,9 +167,9 @@ module.exports = function(grunt) {
});
grunt.registerTask("default", ["less", "autoprefixer", "cssmin", "uglify", "copy"]);
grunt.registerTask("default", ["less", "autoprefixer", "cssmin", "copy", "uglify"]);
grunt.registerTask("scss", ["sass", "autoprefixer", "cssmin", "uglify", "copy"]);
grunt.registerTask("scss", ["sass", "autoprefixer", "cssmin", "copy", "uglify"]);
grunt.registerTask("build", function(target) {
var buildType = "default";

16
dist/css/ripples.css vendored
View File

@ -19,22 +19,16 @@
margin-top: -10px;
border-radius: 100%;
background-color: rgba(0, 0, 0, 0.05);
-webkit-transform: scale(1);
-ms-transform: scale(1);
transform: scale(1);
-webkit-transform-origin: 50%;
-ms-transform-origin: 50%;
transform-origin: 50%;
transform: scale(1);
transform-origin: 50%;
opacity: 0;
pointer-events: none;
}
.ripple.ripple-on {
-webkit-transition: opacity 0.15s ease-in 0s, -webkit-transform 0.5s cubic-bezier(0.4, 0, 0.2, 1) 0.1s;
transition: opacity 0.15s ease-in 0s, transform 0.5s cubic-bezier(0.4, 0, 0.2, 1) 0.1s;
opacity: 1;
transition: opacity 0.15s ease-in 0s, transform 0.5s cubic-bezier(0.4, 0, 0.2, 1) 0.1s;
opacity: 0.2;
}
.ripple.ripple-out {
-webkit-transition: opacity 0.1s linear 0s !important;
transition: opacity 0.1s linear 0s !important;
transition: opacity 0.1s linear 0s !important;
opacity: 0;
}

View File

@ -1 +1 @@
.withripple{position:relative}.ripple-wrapper{position:absolute;top:0;left:0;z-index:1;width:100%;height:100%;overflow:hidden;border-radius:inherit}.ripple{position:absolute;width:20px;height:20px;margin-left:-10px;margin-top:-10px;border-radius:100%;background-color:rgba(0,0,0,.05);-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1);-webkit-transform-origin:50%;-ms-transform-origin:50%;transform-origin:50%;opacity:0;pointer-events:none}.ripple.ripple-on{-webkit-transition:opacity .15s ease-in 0s,-webkit-transform .5s cubic-bezier(0.4,0,.2,1) .1s;transition:opacity .15s ease-in 0s,transform .5s cubic-bezier(0.4,0,.2,1) .1s;opacity:1}.ripple.ripple-out{-webkit-transition:opacity .1s linear 0s!important;transition:opacity .1s linear 0s!important;opacity:0}
.withripple{position:relative}.ripple-wrapper{position:absolute;top:0;left:0;z-index:1;width:100%;height:100%;overflow:hidden;border-radius:inherit}.ripple{position:absolute;width:20px;height:20px;margin-left:-10px;margin-top:-10px;border-radius:100%;background-color:rgba(0,0,0,.05);-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1);-webkit-transform-origin:50%;-ms-transform-origin:50%;transform-origin:50%;opacity:0;pointer-events:none}.ripple.ripple-on{-webkit-transition:opacity .15s ease-in 0s,-webkit-transform .5s cubic-bezier(0.4,0,.2,1) .1s;transition:opacity .15s ease-in 0s,transform .5s cubic-bezier(0.4,0,.2,1) .1s;opacity:.2}.ripple.ripple-out{-webkit-transition:opacity .1s linear 0s!important;transition:opacity .1s linear 0s!important;opacity:0}

311
dist/js/material.js vendored
View File

@ -1,159 +1,170 @@
/* globals jQuery, ripples */
/* globals jQuery */
(function($) {
// Selector to select only not already processed elements
$.expr[":"].notmdproc = function(obj){
if ($(obj).data("mdproc")) {
return false;
} else {
return true;
}
};
function _isChar(evt) {
if (typeof evt.which == "undefined") {
return true;
} else if (typeof evt.which == "number" && evt.which > 0) {
return !evt.ctrlKey && !evt.metaKey && !evt.altKey && evt.which != 8;
}
return false;
// Selector to select only not already processed elements
$.expr[":"].notmdproc = function(obj){
if ($(obj).data("mdproc")) {
return false;
} else {
return true;
}
};
$.material = {
"options": {
"withRipples": [
".btn:not(.btn-link)",
".card-image",
".navbar a:not(.withoutripple)",
".dropdown-menu a",
".nav-tabs a:not(.withoutripple)",
".withripple"
].join(","),
"inputElements": "input.form-control, textarea.form-control, select.form-control",
"checkboxElements": ".checkbox > label > input[type=checkbox]",
"radioElements": ".radio > label > input[type=radio]"
},
"checkbox": function(selector) {
// Add fake-checkbox to material checkboxes
$((selector) ? selector : this.options.checkboxElements)
.filter(":notmdproc")
.data("mdproc", true)
.after("<span class=ripple></span><span class=check></span>");
},
"radio": function(selector) {
// Add fake-radio to material radios
$((selector) ? selector : this.options.radioElements)
.filter(":notmdproc")
.data("mdproc", true)
.after("<span class=circle></span><span class=check></span>");
},
"input": function(selector) {
$((selector) ? selector : this.options.inputElements)
.filter(":notmdproc")
.data("mdproc", true)
.each( function() {
var $this = $(this);
$this.wrap("<div class=form-control-wrapper></div>");
$this.after("<span class=material-input></span>");
if ($this.hasClass("floating-label")) {
var placeholder = $this.attr("placeholder");
$this.attr("placeholder", null).removeClass("floating-label");
$this.after("<div class=floating-label>" + placeholder + "</div>");
}
if ($this.val() === null || $this.val() == "undefined" || $this.val() === "") {
$this.addClass("empty");
}
if ($this.parent().next().is("[type=file]")) {
$this.parent().addClass("fileinput");
var $input = $this.parent().next().detach();
$this.after($input);
}
});
function _isChar(evt) {
if (typeof evt.which == "undefined") {
return true;
} else if (typeof evt.which == "number" && evt.which > 0) {
return !evt.ctrlKey && !evt.metaKey && !evt.altKey && evt.which != 8;
}
return false;
}
$(document)
.on("change", ".checkbox input", function() { $(this).blur(); })
.on("keydown paste", ".form-control", function(e) {
if(_isChar(e)) {
$(this).removeClass("empty");
}
})
.on("keyup change", ".form-control", function() {
var $this = $(this);
if($this.val() === "") {
$this.addClass("empty");
} else {
$this.removeClass("empty");
}
})
.on("focus", ".form-control-wrapper.fileinput", function() {
$(this).find("input").addClass("focus");
})
.on("blur", ".form-control-wrapper.fileinput", function() {
$(this).find("input").removeClass("focus");
})
.on("change", ".form-control-wrapper.fileinput [type=file]", function() {
var value = "";
$.each($(this)[0].files, function(i, file) {
console.log(file);
value += file.name + ", ";
});
value = value.substring(0, value.length - 2);
if (value) {
$(this).prev().removeClass("empty");
} else {
$(this).prev().addClass("empty");
}
$(this).prev().val(value);
});
},
"ripples": function(selector) {
ripples.init((selector) ? selector : this.options.withRipples);
},
"init": function() {
this.ripples();
this.input();
this.checkbox();
this.radio();
$.material = {
"options": {
"withRipples": [
".btn:not(.btn-link)",
".card-image",
".navbar a:not(.withoutripple)",
".dropdown-menu a",
".nav-tabs a:not(.withoutripple)",
".withripple"
].join(","),
"inputElements": "input.form-control, textarea.form-control, select.form-control",
"checkboxElements": ".checkbox > label > input[type=checkbox]",
"radioElements": ".radio > label > input[type=radio]"
},
"checkbox": function(selector) {
// Add fake-checkbox to material checkboxes
$((selector) ? selector : this.options.checkboxElements)
.filter(":notmdproc")
.data("mdproc", true)
.after("<span class=ripple></span><span class=check></span>");
},
"radio": function(selector) {
// Add fake-radio to material radios
$((selector) ? selector : this.options.radioElements)
.filter(":notmdproc")
.data("mdproc", true)
.after("<span class=circle></span><span class=check></span>");
},
"input": function(selector) {
$((selector) ? selector : this.options.inputElements)
.filter(":notmdproc")
.data("mdproc", true)
.each( function() {
var $this = $(this);
$this.wrap("<div class=form-control-wrapper></div>");
$this.after("<span class=material-input></span>");
if (document.arrive) {
document.arrive("input, textarea, select", function() {
$.material.init();
});
}
// Detect autofill
(function() {
// This part of code will detect autofill when the page is loading (username and password inputs for example)
var loading = setInterval(function() {
$("input").each(function() {
if ($(this).val() !== $(this).attr("value")) {
$(this).trigger("change");
}
});
}, 100);
// After 10 seconds we are quite sure all the needed inputs are autofilled then we can stop checking them
setTimeout(function() {
clearInterval(loading);
}, 10000);
// Now we just listen on inputs of the focused form (because user can select from the autofill dropdown only when the input has focus)
var focused;
$(document)
.on("focus", "input", function() {
var $inputs = $(this).parents("form").find("input");
focused = setInterval(function() {
$inputs.each(function() {
if ($(this).val() !== $(this).attr("value")) {
$(this).trigger("change");
}
});
}, 100);
})
.on("blur", "input", function() {
clearInterval(focused);
});
})();
// Add floating label if required
if ($this.hasClass("floating-label")) {
var placeholder = $this.attr("placeholder");
$this.attr("placeholder", null).removeClass("floating-label");
$this.after("<div class=floating-label>" + placeholder + "</div>");
}
};
// Add hint label if required
if ($this.attr("data-hint")) {
$this.after("<div class=hint>" + $this.attr("data-hint") + "</div>");
}
// Set as empty if is empty (damn I must improve this...)
if ($this.val() === null || $this.val() == "undefined" || $this.val() === "") {
$this.addClass("empty");
}
// Support for file input
if ($this.parent().next().is("[type=file]")) {
$this.parent().addClass("fileinput");
var $input = $this.parent().next().detach();
$this.after($input);
}
});
$(document)
.on("change", ".checkbox input[type=checkbox]", function() { $(this).blur(); })
.on("keydown paste", ".form-control", function(e) {
if(_isChar(e)) {
$(this).removeClass("empty");
}
})
.on("keyup change", ".form-control", function() {
var $this = $(this);
if($this.val() === "") {
$this.addClass("empty");
} else {
$this.removeClass("empty");
}
})
.on("focus", ".form-control-wrapper.fileinput", function() {
$(this).find("input").addClass("focus");
})
.on("blur", ".form-control-wrapper.fileinput", function() {
$(this).find("input").removeClass("focus");
})
.on("change", ".form-control-wrapper.fileinput [type=file]", function() {
var value = "";
$.each($(this)[0].files, function(i, file) {
console.log(file);
value += file.name + ", ";
});
value = value.substring(0, value.length - 2);
if (value) {
$(this).prev().removeClass("empty");
} else {
$(this).prev().addClass("empty");
}
$(this).prev().val(value);
});
},
"ripples": function(selector) {
$.ripples({"target": (selector) ? selector : this.options.withRipples});
},
"init": function() {
this.ripples();
this.input();
this.checkbox();
this.radio();
if (document.arrive) {
document.arrive("input, textarea, select", function() {
$.material.init();
});
}
// Detect autofill
(function() {
// This part of code will detect autofill when the page is loading (username and password inputs for example)
var loading = setInterval(function() {
$("input[type!=checkbox]").each(function() {
if ($(this).val() && $(this).val() !== $(this).attr("value")) {
$(this).trigger("change");
}
});
}, 100);
// After 10 seconds we are quite sure all the needed inputs are autofilled then we can stop checking them
setTimeout(function() {
clearInterval(loading);
}, 10000);
// Now we just listen on inputs of the focused form (because user can select from the autofill dropdown only when the input has focus)
var focused;
$(document)
.on("focus", "input", function() {
var $inputs = $(this).parents("form").find("input");
focused = setInterval(function() {
$inputs.each(function() {
if ($(this).val() !== $(this).attr("value")) {
$(this).trigger("change");
}
});
}, 100);
})
.on("blur", "input", function() {
clearInterval(focused);
});
})();
}
};
})(jQuery);

View File

@ -1 +1,2 @@
!function(a){function b(a){return"undefined"==typeof a.which?!0:"number"==typeof a.which&&a.which>0?!a.ctrlKey&&!a.metaKey&&!a.altKey&&8!=a.which:!1}a.expr[":"].notmdproc=function(b){return a(b).data("mdproc")?!1:!0},a.material={options:{withRipples:[".btn:not(.btn-link)",".card-image",".navbar a:not(.withoutripple)",".dropdown-menu a",".nav-tabs a:not(.withoutripple)",".withripple"].join(","),inputElements:"input.form-control, textarea.form-control, select.form-control",checkboxElements:".checkbox > label > input[type=checkbox]",radioElements:".radio > label > input[type=radio]"},checkbox:function(b){a(b?b:this.options.checkboxElements).filter(":notmdproc").data("mdproc",!0).after("<span class=ripple></span><span class=check></span>")},radio:function(b){a(b?b:this.options.radioElements).filter(":notmdproc").data("mdproc",!0).after("<span class=circle></span><span class=check></span>")},input:function(c){a(c?c:this.options.inputElements).filter(":notmdproc").data("mdproc",!0).each(function(){var b=a(this);if(b.wrap("<div class=form-control-wrapper></div>"),b.after("<span class=material-input></span>"),b.hasClass("floating-label")){var c=b.attr("placeholder");b.attr("placeholder",null).removeClass("floating-label"),b.after("<div class=floating-label>"+c+"</div>")}if(b.attr("data-hint")&&b.after("<div class=hint>"+b.attr("data-hint")+"</div>"),(null===b.val()||"undefined"==b.val()||""===b.val())&&b.addClass("empty"),b.parent().next().is("[type=file]")){b.parent().addClass("fileinput");var d=b.parent().next().detach();b.after(d)}}),a(document).on("change",".checkbox input[type=checkbox]",function(){a(this).blur()}).on("keydown paste",".form-control",function(c){b(c)&&a(this).removeClass("empty")}).on("keyup change",".form-control",function(){var b=a(this);""===b.val()?b.addClass("empty"):b.removeClass("empty")}).on("focus",".form-control-wrapper.fileinput",function(){a(this).find("input").addClass("focus")}).on("blur",".form-control-wrapper.fileinput",function(){a(this).find("input").removeClass("focus")}).on("change",".form-control-wrapper.fileinput [type=file]",function(){var b="";a.each(a(this)[0].files,function(a,c){console.log(c),b+=c.name+", "}),b=b.substring(0,b.length-2),b?a(this).prev().removeClass("empty"):a(this).prev().addClass("empty"),a(this).prev().val(b)})},ripples:function(a){ripples.init(a?a:this.options.withRipples)},init:function(){this.ripples(),this.input(),this.checkbox(),this.radio(),document.arrive&&document.arrive("input, textarea, select",function(){a.material.init()}),function(){var b=setInterval(function(){a("input[type!=checkbox]").each(function(){a(this).val()&&a(this).val()!==a(this).attr("value")&&a(this).trigger("change")})},100);setTimeout(function(){clearInterval(b)},1e4);var c;a(document).on("focus","input",function(){var b=a(this).parents("form").find("input");c=setInterval(function(){b.each(function(){a(this).val()!==a(this).attr("value")&&a(this).trigger("change")})},100)}).on("blur","input",function(){clearInterval(c)})}()}}}(jQuery);
!function(a){function b(a){return"undefined"==typeof a.which?!0:"number"==typeof a.which&&a.which>0?!a.ctrlKey&&!a.metaKey&&!a.altKey&&8!=a.which:!1}a.expr[":"].notmdproc=function(b){return a(b).data("mdproc")?!1:!0},a.material={options:{withRipples:[".btn:not(.btn-link)",".card-image",".navbar a:not(.withoutripple)",".dropdown-menu a",".nav-tabs a:not(.withoutripple)",".withripple"].join(","),inputElements:"input.form-control, textarea.form-control, select.form-control",checkboxElements:".checkbox > label > input[type=checkbox]",radioElements:".radio > label > input[type=radio]"},checkbox:function(b){a(b?b:this.options.checkboxElements).filter(":notmdproc").data("mdproc",!0).after("<span class=ripple></span><span class=check></span>")},radio:function(b){a(b?b:this.options.radioElements).filter(":notmdproc").data("mdproc",!0).after("<span class=circle></span><span class=check></span>")},input:function(c){a(c?c:this.options.inputElements).filter(":notmdproc").data("mdproc",!0).each(function(){var b=a(this);if(b.wrap("<div class=form-control-wrapper></div>"),b.after("<span class=material-input></span>"),b.hasClass("floating-label")){var c=b.attr("placeholder");b.attr("placeholder",null).removeClass("floating-label"),b.after("<div class=floating-label>"+c+"</div>")}if(b.attr("data-hint")&&b.after("<div class=hint>"+b.attr("data-hint")+"</div>"),(null===b.val()||"undefined"==b.val()||""===b.val())&&b.addClass("empty"),b.parent().next().is("[type=file]")){b.parent().addClass("fileinput");var d=b.parent().next().detach();b.after(d)}}),a(document).on("change",".checkbox input[type=checkbox]",function(){a(this).blur()}).on("keydown paste",".form-control",function(c){b(c)&&a(this).removeClass("empty")}).on("keyup change",".form-control",function(){var b=a(this);""===b.val()?b.addClass("empty"):b.removeClass("empty")}).on("focus",".form-control-wrapper.fileinput",function(){a(this).find("input").addClass("focus")}).on("blur",".form-control-wrapper.fileinput",function(){a(this).find("input").removeClass("focus")}).on("change",".form-control-wrapper.fileinput [type=file]",function(){var b="";a.each(a(this)[0].files,function(a,c){console.log(c),b+=c.name+", "}),b=b.substring(0,b.length-2),b?a(this).prev().removeClass("empty"):a(this).prev().addClass("empty"),a(this).prev().val(b)})},ripples:function(b){a.ripples({target:b?b:this.options.withRipples})},init:function(){this.ripples(),this.input(),this.checkbox(),this.radio(),document.arrive&&document.arrive("input, textarea, select",function(){a.material.init()}),function(){var b=setInterval(function(){a("input[type!=checkbox]").each(function(){a(this).val()&&a(this).val()!==a(this).attr("value")&&a(this).trigger("change")})},100);setTimeout(function(){clearInterval(b)},1e4);var c;a(document).on("focus","input",function(){var b=a(this).parents("form").find("input");c=setInterval(function(){b.each(function(){a(this).val()!==a(this).attr("value")&&a(this).trigger("change")})},100)}).on("blur","input",function(){clearInterval(c)})}()}}}(jQuery);
//# sourceMappingURL=material.min.js.map

1
dist/js/material.min.js.map vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"material.min.js","sources":["material.js"],"names":["$","_isChar","evt","which","ctrlKey","metaKey","altKey","expr","notmdproc","obj","data","material","options","withRipples","join","inputElements","checkboxElements","radioElements","checkbox","selector","this","filter","after","radio","input","each","$this","wrap","hasClass","placeholder","attr","removeClass","val","addClass","parent","next","is","$input","detach","document","on","blur","e","find","value","files","i","file","console","log","name","substring","length","prev","ripples","target","init","arrive","loading","setInterval","trigger","setTimeout","clearInterval","focused","$inputs","parents","jQuery"],"mappings":"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"}

274
dist/js/ripples.js vendored
View File

@ -1,189 +1,105 @@
/* Copyright 2014+, Federico Zivolo, LICENSE at https://github.com/FezVrasta/bootstrap-material-design/blob/master/LICENSE.md */
/* globals CustomEvent */
window.ripples = {
done: false,
init : function(withRipple) {
"use strict";
/* globals jQuery */
if (this.done) {
return console.log("Ripples.js was already initialzied.");
}
(function($) {
$.ripples = function(options) {
this.done = true;
// Default options
var defaultOptions = {
"target": ".btn:not(.btn-link), .card-image, .navbar a:not(.withoutripple), .nav-tabs a:not(.withoutripple), .withripple"
};
// Cross browser matches function
function matchesSelector(domElement, selector) {
var matches = domElement.matches ||
domElement.matchesSelector ||
domElement.webkitMatchesSelector ||
domElement.mozMatchesSelector ||
domElement.msMatchesSelector ||
domElement.oMatchesSelector;
return matches.call(domElement, selector);
}
// Fade out the ripple and then destroy it
function rippleOut(ripple) {
// animations time
var rippleOutTime = 100,
rippleStartTime = 500;
// Unbind events from ripple
ripple.off();
// Helper to bind events on dynamically created elements
var bind = function(events, selector, callback) {
if (typeof events === "string") {
events = [events];
}
events.forEach(function(event) {
document.addEventListener(event, function(e) {
var target = (typeof e.detail !== "number") ? e.detail : e.target;
// Start the out animation
ripple.addClass("ripple-out");
if (matchesSelector(target, selector)) {
callback(e, target);
}
});
});
};
var rippleStart = function(e, target, callback) {
// Init variables
var $rippleWrapper = target,
$el = $rippleWrapper.parentNode,
$ripple = document.createElement("div"),
elPos = $el.getBoundingClientRect(),
// Mouse pos in most cases
mousePos = {x: e.clientX - elPos.left, y: ((window.ontouchstart) ? e.clientY - window.scrollY: e.clientY) - elPos.top},
scale = "scale(" + Math.round($rippleWrapper.offsetWidth / 5) + ")",
rippleEnd = new CustomEvent("rippleEnd", {detail: $ripple}),
_rippleOpacity = 0.3,
refreshElementStyle;
// If multitouch is detected or some other black magic suff is happening...
if (e.touches) {
mousePos = {x: e.touches[0].clientX - elPos.left, y: e.touches[0].clientY - elPos.top};
}
$ripplecache = $ripple;
// Set ripple class
$ripple.className = "ripple";
// Move ripple to the mouse position
$ripple.setAttribute("style", "left:" + mousePos.x + "px; top:" + mousePos.y + "px;");
// Get the clicked target's text color, this will be applied to the ripple as background-color.
var targetColor = window.getComputedStyle($el).color;
// Convert the rgb color to an rgba color with opacity set to __rippleOpacity__
if ( targetColor.indexOf("rgba") >= 0 ) {
var alphaPosition = targetColor.lastIndexOf(",") + 1;
targetColor = targetColor.substring(0, alphaPosition) + _rippleOpacity + ")";
} else {
targetColor = targetColor.replace("rgb", "rgba").replace(")", ", " + _rippleOpacity + ")");
}
// Insert new ripple into ripple wrapper
$rippleWrapper.appendChild($ripple);
// Make sure the ripple has the class applied (ugly hack but it works)
refreshElementStyle = window.getComputedStyle($ripple).opacity;
// Let other funtions know that this element is animating
$ripple.dataset.animating = 1;
// Set scale value, background-color and opacity to ripple and animate it
$ripple.className = "ripple ripple-on";
// Prepare the style of the ripple
var rippleStyle = [
$ripple.getAttribute("style"),
"background-color: " + targetColor,
"-ms-transform: " + scale,
"-moz-transform:" + scale,
"-webkit-transform:" + scale,
"transform: " + scale
];
// Apply the style
$ripple.setAttribute("style", rippleStyle.join(";"));
// This function is called when the animation is finished
setTimeout(function() {
// Let know to other functions that this element has finished the animation
$ripple.dataset.animating = 0;
document.dispatchEvent(rippleEnd);
if (callback) {
callback();
}
}, rippleStartTime);
};
var rippleOut = function($ripple) {
// Clear previous animation
$ripple.className = "ripple ripple-on ripple-out";
// Let ripple fade out (with CSS)
setTimeout(function() {
$ripple.remove();
}, rippleOutTime);
};
// Helper, need to know if mouse is up or down
var mouseDown = false;
bind(["mousedown", "touchstart"], "*", function() {
mouseDown = true;
});
bind(["mouseup", "touchend", "mouseout"], "*", function() {
mouseDown = false;
});
// Append ripple wrapper if not exists already
var rippleInit = function(e, target) {
if (target.getElementsByClassName("ripple-wrapper").length === 0) {
target.className += " withripple";
var $rippleWrapper = document.createElement("div");
$rippleWrapper.className = "ripple-wrapper";
target.appendChild($rippleWrapper);
}
};
var $ripplecache;
// Events handler
// init RippleJS and start ripple effect on mousedown
bind(["mouseover"], withRipple, rippleInit);
// Init if the device is touch screen
bind(["touchstart"], withRipple, rippleInit);
// start ripple effect on mousedown
bind(["mousedown", "touchstart"], ".ripple-wrapper", function(e, $ripple) {
// Start ripple only on left or middle mouse click and touch click
if (e.which === 0 || e.which === 1 || e.which === 2) {
rippleStart(e, $ripple);
}
});
// if animation ends and user is not holding mouse then destroy the ripple
bind("rippleEnd", ".ripple-wrapper .ripple", function(e, $ripple) {
var $ripples = $ripple.parentNode.getElementsByClassName("ripple");
if (!mouseDown || ( $ripples[0] == $ripple && $ripples.length > 1)) {
rippleOut($ripple);
}
});
// Destroy ripple when mouse is not holded anymore if the ripple still exists
bind(["mouseup", "touchend", "mouseout"], ".ripple-wrapper", function() {
var $ripple = $ripplecache;
if ($ripple && $ripple.dataset.animating != 1) {
rippleOut($ripple);
}
});
// This function is called when the transition "out" ends
ripple.on("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", function(){
ripple.remove();
});
}
};
// Apply custom options
options = $.extend(defaultOptions, options);
$(document)
.on("mousedown", options.target, function(e) {
// If the ripple wrapper does not exists, create it
if (!$(this).find(".ripple-wrapper").length) {
$(this).append("<div class=ripple-wrapper></div>");
}
var wrapper = $(this).find(".ripple-wrapper");
// Get the mouse position relative to the ripple wrapper
var wrapperOffset = wrapper.offset();
var relX = e.pageX - wrapperOffset.left;
var relY = e.pageY - wrapperOffset.top;
// Meet the new ripple
var ripple = $("<div></div>");
// Add to it the ripple class
ripple.addClass("ripple");
// Position it in the right place
ripple.css({"left": relX, "top": relY});
// Set the background color of the ripple
ripple.css({"background-color": window.getComputedStyle($(this)[0]).color});
// Spawn it
wrapper.append(ripple);
// Make sure the ripple has the styles applied (ugly hack but it works)
(function() { return window.getComputedStyle(ripple[0]).opacity; })();
// Set the new size
var size = (Math.max($(this).outerWidth(), $(this).outerHeight()) / ripple.outerWidth()) * 2.5;
ripple.css({
"-ms-transform": "scale(" + size + ")",
"-moz-transform": "scale(" + size + ")",
"-webkit-transform": "scale(" + size + ")",
"transform": "scale(" + size + ")"
});
// Start the transition
ripple.addClass("ripple-on");
ripple.data("animating", "on");
ripple.data("mousedown", "on");
// This function is called when the transition "on" ends
setTimeout(function() {
ripple.data("animating", "off");
if (ripple.data("mousedown") == "off") {
rippleOut(ripple);
}
}, 500);
// On mouseup or on mouseleave, set the mousedown flag to "off" and try to destroy the ripple
wrapper.on("mouseup mouseleave", function() {
ripple.data("mousedown", "off");
// If the transition "on" is finished then we can destroy the ripple with transition "out"
if (ripple.data("animating") == "off") {
rippleOut(ripple);
}
});
});
};
$.fn.ripples = function() {
$.ripples({"target": $(this)});
};
})(jQuery);

View File

@ -1 +1,2 @@
window.ripples={done:!1,init:function(a){"use strict";function b(a,b){var c=a.matches||a.matchesSelector||a.webkitMatchesSelector||a.mozMatchesSelector||a.msMatchesSelector||a.oMatchesSelector;return c.call(a,b)}if(this.done)return console.log("Ripples.js was already initialzied.");this.done=!0;var c=100,d=500,e=function(a,c,d){"string"==typeof a&&(a=[a]),a.forEach(function(a){document.addEventListener(a,function(a){var e="number"!=typeof a.detail?a.detail:a.target;b(e,c)&&d(a,e)})})},f=function(a,b,c){var e,f=b,g=f.parentNode,h=document.createElement("div"),j=g.getBoundingClientRect(),k={x:a.clientX-j.left,y:(window.ontouchstart?a.clientY-window.scrollY:a.clientY)-j.top},l="scale("+Math.round(f.offsetWidth/5)+")",m=new CustomEvent("rippleEnd",{detail:h}),n=.3;a.touches&&(k={x:a.touches[0].clientX-j.left,y:a.touches[0].clientY-j.top}),i=h,h.className="ripple",h.setAttribute("style","left:"+k.x+"px; top:"+k.y+"px;");var o=window.getComputedStyle(g).color;if(o.indexOf("rgba")>=0){var p=o.lastIndexOf(",")+1;o=o.substring(0,p)+n+")"}else o=o.replace("rgb","rgba").replace(")",", "+n+")");f.appendChild(h),e=window.getComputedStyle(h).opacity,h.dataset.animating=1,h.className="ripple ripple-on";var q=[h.getAttribute("style"),"background-color: "+o,"-ms-transform: "+l,"-moz-transform:"+l,"-webkit-transform:"+l,"transform: "+l];h.setAttribute("style",q.join(";")),setTimeout(function(){h.dataset.animating=0,document.dispatchEvent(m),c&&c()},d)},g=function(a){a.className="ripple ripple-on ripple-out",setTimeout(function(){a.remove()},c)},h=!1;e(["mousedown","touchstart"],"*",function(){h=!0}),e(["mouseup","touchend","mouseout"],"*",function(){h=!1});var i,j=function(a,b){if(0===b.getElementsByClassName("ripple-wrapper").length){b.className+=" withripple";var c=document.createElement("div");c.className="ripple-wrapper",b.appendChild(c)}};e(["mouseover"],a,j),e(["touchstart"],a,j),e(["mousedown","touchstart"],".ripple-wrapper",function(a,b){(0===a.which||1===a.which||2===a.which)&&f(a,b)}),e("rippleEnd",".ripple-wrapper .ripple",function(a,b){var c=b.parentNode.getElementsByClassName("ripple");(!h||c[0]==b&&c.length>1)&&g(b)}),e(["mouseup","touchend","mouseout"],".ripple-wrapper",function(){var a=i;a&&1!=a.dataset.animating&&g(a)})}};
!function(a){a.ripples=function(b){function c(a){a.off(),a.addClass("ripple-out"),a.on("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd",function(){a.remove()})}var d={target:".btn:not(.btn-link), .card-image, .navbar a:not(.withoutripple), .nav-tabs a:not(.withoutripple), .withripple"};b=a.extend(d,b),a(document).on("mousedown",b.target,function(b){a(this).find(".ripple-wrapper").length||a(this).append("<div class=ripple-wrapper></div>");var d=a(this).find(".ripple-wrapper"),e=d.offset(),f=b.pageX-e.left,g=b.pageY-e.top,h=a("<div></div>");h.addClass("ripple"),h.css({left:f,top:g}),h.css({"background-color":window.getComputedStyle(a(this)[0]).color}),d.append(h),function(){return window.getComputedStyle(h[0]).opacity}();var i=Math.max(a(this).outerWidth(),a(this).outerHeight())/h.outerWidth()*2.5;h.css({"-ms-transform":"scale("+i+")","-moz-transform":"scale("+i+")","-webkit-transform":"scale("+i+")",transform:"scale("+i+")"}),h.addClass("ripple-on"),h.data("animating","on"),h.data("mousedown","on"),setTimeout(function(){h.data("animating","off"),"off"==h.data("mousedown")&&c(h)},500),d.on("mouseup mouseleave",function(){h.data("mousedown","off"),"off"==h.data("animating")&&c(h)})})},a.fn.ripples=function(){a.ripples({target:a(this)})}}(jQuery);
//# sourceMappingURL=ripples.min.js.map

1
dist/js/ripples.min.js.map vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"ripples.min.js","sources":["ripples.js"],"names":["$","ripples","options","rippleOut","ripple","off","addClass","on","remove","defaultOptions","target","extend","document","e","this","find","length","append","wrapper","wrapperOffset","offset","relX","pageX","left","relY","pageY","top","css","background-color","window","getComputedStyle","color","opacity","size","Math","max","outerWidth","outerHeight","-ms-transform","-moz-transform","-webkit-transform","transform","data","setTimeout","fn","jQuery"],"mappings":"CAGA,SAAUA,GACRA,EAAEC,QAAU,SAASC,GASnB,QAASC,GAAUC,GAGjBA,EAAOC,MAGPD,EAAOE,SAAS,cAGhBF,EAAOG,GAAG,mEAAoE,WAC5EH,EAAOI,WAhBX,GAAIC,IACFC,OAAU,gHAqBZR,GAAUF,EAAEW,OAAOF,EAAgBP,GAGnCF,EAAEY,UACDL,GAAG,YAAaL,EAAQQ,OAAQ,SAASG,GAEnCb,EAAEc,MAAMC,KAAK,mBAAmBC,QACnChB,EAAEc,MAAMG,OAAO,mCAGjB,IAAIC,GAAUlB,EAAEc,MAAMC,KAAK,mBAGvBI,EAAgBD,EAAQE,SACxBC,EAAOR,EAAES,MAAQH,EAAcI,KAC/BC,EAAOX,EAAEY,MAAQN,EAAcO,IAG/BtB,EAASJ,EAAE,cAGfI,GAAOE,SAAS,UAGhBF,EAAOuB,KAAKJ,KAAQF,EAAMK,IAAOF,IAGjCpB,EAAOuB,KAAKC,mBAAoBC,OAAOC,iBAAiB9B,EAAEc,MAAM,IAAIiB,QAGpEb,EAAQD,OAAOb,GAGf,WAAc,MAAOyB,QAAOC,iBAAiB1B,EAAO,IAAI4B,UAGxD,IAAIC,GAAQC,KAAKC,IAAInC,EAAEc,MAAMsB,aAAcpC,EAAEc,MAAMuB,eAAiBjC,EAAOgC,aAAgB,GAE3FhC,GAAOuB,KACLW,gBAAiB,SAAWL,EAAO,IACnCM,iBAAkB,SAAWN,EAAO,IACpCO,oBAAqB,SAAWP,EAAO,IACvCQ,UAAa,SAAWR,EAAO,MAIjC7B,EAAOE,SAAS,aAChBF,EAAOsC,KAAK,YAAa,MACzBtC,EAAOsC,KAAK,YAAa,MAGzBC,WAAW,WACTvC,EAAOsC,KAAK,YAAa,OACO,OAA5BtC,EAAOsC,KAAK,cACdvC,EAAUC,IAEX,KAGHc,EAAQX,GAAG,qBAAsB,WAC/BH,EAAOsC,KAAK,YAAa,OAEO,OAA5BtC,EAAOsC,KAAK,cACdvC,EAAUC,QAQlBJ,EAAE4C,GAAG3C,QAAU,WACbD,EAAEC,SAASS,OAAUV,EAAEc,UAGxB+B"}

View File

@ -26,7 +26,7 @@
}
.ripple.ripple-on {
transition: opacity 0.15s ease-in 0s, transform 0.5s cubic-bezier(0.4, 0, 0.2, 1) 0.1s;
opacity: 1;
opacity: 0.2;
}
.ripple.ripple-out {
transition: opacity 0.1s linear 0s !important;

View File

@ -1,170 +1,170 @@
/* globals jQuery, ripples */
/* globals jQuery */
(function($) {
// Selector to select only not already processed elements
$.expr[":"].notmdproc = function(obj){
if ($(obj).data("mdproc")) {
return false;
} else {
return true;
}
};
function _isChar(evt) {
if (typeof evt.which == "undefined") {
return true;
} else if (typeof evt.which == "number" && evt.which > 0) {
return !evt.ctrlKey && !evt.metaKey && !evt.altKey && evt.which != 8;
}
return false;
// Selector to select only not already processed elements
$.expr[":"].notmdproc = function(obj){
if ($(obj).data("mdproc")) {
return false;
} else {
return true;
}
};
$.material = {
"options": {
"withRipples": [
".btn:not(.btn-link)",
".card-image",
".navbar a:not(.withoutripple)",
".dropdown-menu a",
".nav-tabs a:not(.withoutripple)",
".withripple"
].join(","),
"inputElements": "input.form-control, textarea.form-control, select.form-control",
"checkboxElements": ".checkbox > label > input[type=checkbox]",
"radioElements": ".radio > label > input[type=radio]"
},
"checkbox": function(selector) {
// Add fake-checkbox to material checkboxes
$((selector) ? selector : this.options.checkboxElements)
.filter(":notmdproc")
.data("mdproc", true)
.after("<span class=ripple></span><span class=check></span>");
},
"radio": function(selector) {
// Add fake-radio to material radios
$((selector) ? selector : this.options.radioElements)
.filter(":notmdproc")
.data("mdproc", true)
.after("<span class=circle></span><span class=check></span>");
},
"input": function(selector) {
$((selector) ? selector : this.options.inputElements)
.filter(":notmdproc")
.data("mdproc", true)
.each( function() {
var $this = $(this);
$this.wrap("<div class=form-control-wrapper></div>");
$this.after("<span class=material-input></span>");
function _isChar(evt) {
if (typeof evt.which == "undefined") {
return true;
} else if (typeof evt.which == "number" && evt.which > 0) {
return !evt.ctrlKey && !evt.metaKey && !evt.altKey && evt.which != 8;
}
return false;
}
// Add floating label if required
if ($this.hasClass("floating-label")) {
var placeholder = $this.attr("placeholder");
$this.attr("placeholder", null).removeClass("floating-label");
$this.after("<div class=floating-label>" + placeholder + "</div>");
}
$.material = {
"options": {
"withRipples": [
".btn:not(.btn-link)",
".card-image",
".navbar a:not(.withoutripple)",
".dropdown-menu a",
".nav-tabs a:not(.withoutripple)",
".withripple"
].join(","),
"inputElements": "input.form-control, textarea.form-control, select.form-control",
"checkboxElements": ".checkbox > label > input[type=checkbox]",
"radioElements": ".radio > label > input[type=radio]"
},
"checkbox": function(selector) {
// Add fake-checkbox to material checkboxes
$((selector) ? selector : this.options.checkboxElements)
.filter(":notmdproc")
.data("mdproc", true)
.after("<span class=ripple></span><span class=check></span>");
},
"radio": function(selector) {
// Add fake-radio to material radios
$((selector) ? selector : this.options.radioElements)
.filter(":notmdproc")
.data("mdproc", true)
.after("<span class=circle></span><span class=check></span>");
},
"input": function(selector) {
$((selector) ? selector : this.options.inputElements)
.filter(":notmdproc")
.data("mdproc", true)
.each( function() {
var $this = $(this);
$this.wrap("<div class=form-control-wrapper></div>");
$this.after("<span class=material-input></span>");
// Add hint label if required
if ($this.attr("data-hint")) {
$this.after("<div class=hint>" + $this.attr("data-hint") + "</div>");
}
// Set as empty if is empty (damn I must improve this...)
if ($this.val() === null || $this.val() == "undefined" || $this.val() === "") {
$this.addClass("empty");
}
// Support for file input
if ($this.parent().next().is("[type=file]")) {
$this.parent().addClass("fileinput");
var $input = $this.parent().next().detach();
$this.after($input);
}
});
$(document)
.on("change", ".checkbox input[type=checkbox]", function() { $(this).blur(); })
.on("keydown paste", ".form-control", function(e) {
if(_isChar(e)) {
$(this).removeClass("empty");
}
})
.on("keyup change", ".form-control", function() {
var $this = $(this);
if($this.val() === "") {
$this.addClass("empty");
} else {
$this.removeClass("empty");
}
})
.on("focus", ".form-control-wrapper.fileinput", function() {
$(this).find("input").addClass("focus");
})
.on("blur", ".form-control-wrapper.fileinput", function() {
$(this).find("input").removeClass("focus");
})
.on("change", ".form-control-wrapper.fileinput [type=file]", function() {
var value = "";
$.each($(this)[0].files, function(i, file) {
console.log(file);
value += file.name + ", ";
});
value = value.substring(0, value.length - 2);
if (value) {
$(this).prev().removeClass("empty");
} else {
$(this).prev().addClass("empty");
}
$(this).prev().val(value);
});
},
"ripples": function(selector) {
ripples.init((selector) ? selector : this.options.withRipples);
},
"init": function() {
this.ripples();
this.input();
this.checkbox();
this.radio();
if (document.arrive) {
document.arrive("input, textarea, select", function() {
$.material.init();
});
}
// Detect autofill
(function() {
// This part of code will detect autofill when the page is loading (username and password inputs for example)
var loading = setInterval(function() {
$("input[type!=checkbox]").each(function() {
if ($(this).val() && $(this).val() !== $(this).attr("value")) {
$(this).trigger("change");
}
});
}, 100);
// After 10 seconds we are quite sure all the needed inputs are autofilled then we can stop checking them
setTimeout(function() {
clearInterval(loading);
}, 10000);
// Now we just listen on inputs of the focused form (because user can select from the autofill dropdown only when the input has focus)
var focused;
$(document)
.on("focus", "input", function() {
var $inputs = $(this).parents("form").find("input");
focused = setInterval(function() {
$inputs.each(function() {
if ($(this).val() !== $(this).attr("value")) {
$(this).trigger("change");
}
});
}, 100);
})
.on("blur", "input", function() {
clearInterval(focused);
});
})();
// Add floating label if required
if ($this.hasClass("floating-label")) {
var placeholder = $this.attr("placeholder");
$this.attr("placeholder", null).removeClass("floating-label");
$this.after("<div class=floating-label>" + placeholder + "</div>");
}
};
// Add hint label if required
if ($this.attr("data-hint")) {
$this.after("<div class=hint>" + $this.attr("data-hint") + "</div>");
}
// Set as empty if is empty (damn I must improve this...)
if ($this.val() === null || $this.val() == "undefined" || $this.val() === "") {
$this.addClass("empty");
}
// Support for file input
if ($this.parent().next().is("[type=file]")) {
$this.parent().addClass("fileinput");
var $input = $this.parent().next().detach();
$this.after($input);
}
});
$(document)
.on("change", ".checkbox input[type=checkbox]", function() { $(this).blur(); })
.on("keydown paste", ".form-control", function(e) {
if(_isChar(e)) {
$(this).removeClass("empty");
}
})
.on("keyup change", ".form-control", function() {
var $this = $(this);
if($this.val() === "") {
$this.addClass("empty");
} else {
$this.removeClass("empty");
}
})
.on("focus", ".form-control-wrapper.fileinput", function() {
$(this).find("input").addClass("focus");
})
.on("blur", ".form-control-wrapper.fileinput", function() {
$(this).find("input").removeClass("focus");
})
.on("change", ".form-control-wrapper.fileinput [type=file]", function() {
var value = "";
$.each($(this)[0].files, function(i, file) {
console.log(file);
value += file.name + ", ";
});
value = value.substring(0, value.length - 2);
if (value) {
$(this).prev().removeClass("empty");
} else {
$(this).prev().addClass("empty");
}
$(this).prev().val(value);
});
},
"ripples": function(selector) {
$.ripples({"target": (selector) ? selector : this.options.withRipples});
},
"init": function() {
this.ripples();
this.input();
this.checkbox();
this.radio();
if (document.arrive) {
document.arrive("input, textarea, select", function() {
$.material.init();
});
}
// Detect autofill
(function() {
// This part of code will detect autofill when the page is loading (username and password inputs for example)
var loading = setInterval(function() {
$("input[type!=checkbox]").each(function() {
if ($(this).val() && $(this).val() !== $(this).attr("value")) {
$(this).trigger("change");
}
});
}, 100);
// After 10 seconds we are quite sure all the needed inputs are autofilled then we can stop checking them
setTimeout(function() {
clearInterval(loading);
}, 10000);
// Now we just listen on inputs of the focused form (because user can select from the autofill dropdown only when the input has focus)
var focused;
$(document)
.on("focus", "input", function() {
var $inputs = $(this).parents("form").find("input");
focused = setInterval(function() {
$inputs.each(function() {
if ($(this).val() !== $(this).attr("value")) {
$(this).trigger("change");
}
});
}, 100);
})
.on("blur", "input", function() {
clearInterval(focused);
});
})();
}
};
})(jQuery);

View File

@ -1,189 +1,105 @@
/* Copyright 2014+, Federico Zivolo, LICENSE at https://github.com/FezVrasta/bootstrap-material-design/blob/master/LICENSE.md */
/* globals CustomEvent */
window.ripples = {
done: false,
init : function(withRipple) {
"use strict";
/* globals jQuery */
if (this.done) {
return console.log("Ripples.js was already initialzied.");
}
(function($) {
$.ripples = function(options) {
this.done = true;
// Default options
var defaultOptions = {
"target": ".btn:not(.btn-link), .card-image, .navbar a:not(.withoutripple), .nav-tabs a:not(.withoutripple), .withripple"
};
// Cross browser matches function
function matchesSelector(domElement, selector) {
var matches = domElement.matches ||
domElement.matchesSelector ||
domElement.webkitMatchesSelector ||
domElement.mozMatchesSelector ||
domElement.msMatchesSelector ||
domElement.oMatchesSelector;
return matches.call(domElement, selector);
}
// Fade out the ripple and then destroy it
function rippleOut(ripple) {
// animations time
var rippleOutTime = 100,
rippleStartTime = 500;
// Unbind events from ripple
ripple.off();
// Helper to bind events on dynamically created elements
var bind = function(events, selector, callback) {
if (typeof events === "string") {
events = [events];
}
events.forEach(function(event) {
document.addEventListener(event, function(e) {
var target = (typeof e.detail !== "number") ? e.detail : e.target;
// Start the out animation
ripple.addClass("ripple-out");
if (matchesSelector(target, selector)) {
callback(e, target);
}
});
});
};
var rippleStart = function(e, target, callback) {
// Init variables
var $rippleWrapper = target,
$el = $rippleWrapper.parentNode,
$ripple = document.createElement("div"),
elPos = $el.getBoundingClientRect(),
// Mouse pos in most cases
mousePos = {x: e.clientX - elPos.left, y: ((window.ontouchstart) ? e.clientY - window.scrollY: e.clientY) - elPos.top},
scale = "scale(" + Math.round($rippleWrapper.offsetWidth / 5) + ")",
rippleEnd = new CustomEvent("rippleEnd", {detail: $ripple}),
_rippleOpacity = 0.3,
refreshElementStyle;
// If multitouch is detected or some other black magic suff is happening...
if (e.touches) {
mousePos = {x: e.touches[0].clientX - elPos.left, y: e.touches[0].clientY - elPos.top};
}
$ripplecache = $ripple;
// Set ripple class
$ripple.className = "ripple";
// Move ripple to the mouse position
$ripple.setAttribute("style", "left:" + mousePos.x + "px; top:" + mousePos.y + "px;");
// Get the clicked target's text color, this will be applied to the ripple as background-color.
var targetColor = window.getComputedStyle($el).color;
// Convert the rgb color to an rgba color with opacity set to __rippleOpacity__
if ( targetColor.indexOf("rgba") >= 0 ) {
var alphaPosition = targetColor.lastIndexOf(",") + 1;
targetColor = targetColor.substring(0, alphaPosition) + _rippleOpacity + ")";
} else {
targetColor = targetColor.replace("rgb", "rgba").replace(")", ", " + _rippleOpacity + ")");
}
// Insert new ripple into ripple wrapper
$rippleWrapper.appendChild($ripple);
// Make sure the ripple has the class applied (ugly hack but it works)
refreshElementStyle = window.getComputedStyle($ripple).opacity;
// Let other funtions know that this element is animating
$ripple.dataset.animating = 1;
// Set scale value, background-color and opacity to ripple and animate it
$ripple.className = "ripple ripple-on";
// Prepare the style of the ripple
var rippleStyle = [
$ripple.getAttribute("style"),
"background-color: " + targetColor,
"-ms-transform: " + scale,
"-moz-transform:" + scale,
"-webkit-transform:" + scale,
"transform: " + scale
];
// Apply the style
$ripple.setAttribute("style", rippleStyle.join(";"));
// This function is called when the animation is finished
setTimeout(function() {
// Let know to other functions that this element has finished the animation
$ripple.dataset.animating = 0;
document.dispatchEvent(rippleEnd);
if (callback) {
callback();
}
}, rippleStartTime);
};
var rippleOut = function($ripple) {
// Clear previous animation
$ripple.className = "ripple ripple-on ripple-out";
// Let ripple fade out (with CSS)
setTimeout(function() {
$ripple.remove();
}, rippleOutTime);
};
// Helper, need to know if mouse is up or down
var mouseDown = false;
bind(["mousedown", "touchstart"], "*", function() {
mouseDown = true;
});
bind(["mouseup", "touchend", "mouseout"], "*", function() {
mouseDown = false;
});
// Append ripple wrapper if not exists already
var rippleInit = function(e, target) {
if (target.getElementsByClassName("ripple-wrapper").length === 0) {
target.className += " withripple";
var $rippleWrapper = document.createElement("div");
$rippleWrapper.className = "ripple-wrapper";
target.appendChild($rippleWrapper);
}
};
var $ripplecache;
// Events handler
// init RippleJS and start ripple effect on mousedown
bind(["mouseover"], withRipple, rippleInit);
// Init if the device is touch screen
bind(["touchstart"], withRipple, rippleInit);
// start ripple effect on mousedown
bind(["mousedown", "touchstart"], ".ripple-wrapper", function(e, $ripple) {
// Start ripple only on left or middle mouse click and touch click
if (e.which === 0 || e.which === 1 || e.which === 2) {
rippleStart(e, $ripple);
}
});
// if animation ends and user is not holding mouse then destroy the ripple
bind("rippleEnd", ".ripple-wrapper .ripple", function(e, $ripple) {
var $ripples = $ripple.parentNode.getElementsByClassName("ripple");
if (!mouseDown || ( $ripples[0] == $ripple && $ripples.length > 1)) {
rippleOut($ripple);
}
});
// Destroy ripple when mouse is not holded anymore if the ripple still exists
bind(["mouseup", "touchend", "mouseout"], ".ripple-wrapper", function() {
var $ripple = $ripplecache;
if ($ripple && $ripple.dataset.animating != 1) {
rippleOut($ripple);
}
});
// This function is called when the transition "out" ends
ripple.on("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", function(){
ripple.remove();
});
}
};
// Apply custom options
options = $.extend(defaultOptions, options);
$(document)
.on("mousedown", options.target, function(e) {
// If the ripple wrapper does not exists, create it
if (!$(this).find(".ripple-wrapper").length) {
$(this).append("<div class=ripple-wrapper></div>");
}
var wrapper = $(this).find(".ripple-wrapper");
// Get the mouse position relative to the ripple wrapper
var wrapperOffset = wrapper.offset();
var relX = e.pageX - wrapperOffset.left;
var relY = e.pageY - wrapperOffset.top;
// Meet the new ripple
var ripple = $("<div></div>");
// Add to it the ripple class
ripple.addClass("ripple");
// Position it in the right place
ripple.css({"left": relX, "top": relY});
// Set the background color of the ripple
ripple.css({"background-color": window.getComputedStyle($(this)[0]).color});
// Spawn it
wrapper.append(ripple);
// Make sure the ripple has the styles applied (ugly hack but it works)
(function() { return window.getComputedStyle(ripple[0]).opacity; })();
// Set the new size
var size = (Math.max($(this).outerWidth(), $(this).outerHeight()) / ripple.outerWidth()) * 2.5;
ripple.css({
"-ms-transform": "scale(" + size + ")",
"-moz-transform": "scale(" + size + ")",
"-webkit-transform": "scale(" + size + ")",
"transform": "scale(" + size + ")"
});
// Start the transition
ripple.addClass("ripple-on");
ripple.data("animating", "on");
ripple.data("mousedown", "on");
// This function is called when the transition "on" ends
setTimeout(function() {
ripple.data("animating", "off");
if (ripple.data("mousedown") == "off") {
rippleOut(ripple);
}
}, 500);
// On mouseup or on mouseleave, set the mousedown flag to "off" and try to destroy the ripple
wrapper.on("mouseup mouseleave", function() {
ripple.data("mousedown", "off");
// If the transition "on" is finished then we can destroy the ripple with transition "out"
if (ripple.data("animating") == "off") {
rippleOut(ripple);
}
});
});
};
$.fn.ripples = function() {
$.ripples({"target": $(this)});
};
})(jQuery);