rails-bootstrap-material-design 0.5.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +4 -0
  3. data/README.md +18 -0
  4. data/Rakefile +1 -0
  5. data/app/.DS_Store +0 -0
  6. data/app/assets/.DS_Store +0 -0
  7. data/app/assets/images/.DS_Store +0 -0
  8. data/app/assets/images/bootstrap-material-design/material-design-color-palette.jpg +0 -0
  9. data/app/assets/javascripts/.DS_Store +0 -0
  10. data/app/assets/javascripts/bootstrap-material-design.js +2 -0
  11. data/app/assets/javascripts/bootstrap-material-design/material.js +350 -0
  12. data/app/assets/javascripts/bootstrap-material-design/ripples.js +325 -0
  13. data/app/assets/stylesheets/.DS_Store +0 -0
  14. data/app/assets/stylesheets/bootstrap-material-design.scss +4 -0
  15. data/app/assets/stylesheets/bootstrap-material-design/.DS_Store +0 -0
  16. data/app/assets/stylesheets/bootstrap-material-design/_alerts.scss +17 -0
  17. data/app/assets/stylesheets/bootstrap-material-design/_buttons.scss +244 -0
  18. data/app/assets/stylesheets/bootstrap-material-design/_cards.scss +66 -0
  19. data/app/assets/stylesheets/bootstrap-material-design/_checkboxes.scss +270 -0
  20. data/app/assets/stylesheets/bootstrap-material-design/_colors-map.scss +311 -0
  21. data/app/assets/stylesheets/bootstrap-material-design/_colors.scss +359 -0
  22. data/app/assets/stylesheets/bootstrap-material-design/_core.scss +93 -0
  23. data/app/assets/stylesheets/bootstrap-material-design/_dialogs.scss +52 -0
  24. data/app/assets/stylesheets/bootstrap-material-design/_dividers.scss +71 -0
  25. data/app/assets/stylesheets/bootstrap-material-design/_form.scss +40 -0
  26. data/app/assets/stylesheets/bootstrap-material-design/_import-bs-sass.scss +2 -0
  27. data/app/assets/stylesheets/bootstrap-material-design/_inputs-size.scss +221 -0
  28. data/app/assets/stylesheets/bootstrap-material-design/_inputs.scss +352 -0
  29. data/app/assets/stylesheets/bootstrap-material-design/_labels.scss +4 -0
  30. data/app/assets/stylesheets/bootstrap-material-design/_lists.scss +102 -0
  31. data/app/assets/stylesheets/bootstrap-material-design/_mixins-utilities.scss +31 -0
  32. data/app/assets/stylesheets/bootstrap-material-design/_mixins.scss +241 -0
  33. data/app/assets/stylesheets/bootstrap-material-design/_navbar.scss +232 -0
  34. data/app/assets/stylesheets/bootstrap-material-design/_panels.scss +21 -0
  35. data/app/assets/stylesheets/bootstrap-material-design/_plugins.scss +5 -0
  36. data/app/assets/stylesheets/bootstrap-material-design/_popups.scss +18 -0
  37. data/app/assets/stylesheets/bootstrap-material-design/_progress.scss +10 -0
  38. data/app/assets/stylesheets/bootstrap-material-design/_radios.scss +115 -0
  39. data/app/assets/stylesheets/bootstrap-material-design/_shadows.scss +82 -0
  40. data/app/assets/stylesheets/bootstrap-material-design/_table.scss +15 -0
  41. data/app/assets/stylesheets/bootstrap-material-design/_tabs.scss +24 -0
  42. data/app/assets/stylesheets/bootstrap-material-design/_themes.scss +6 -0
  43. data/app/assets/stylesheets/bootstrap-material-design/_togglebutton.scss +83 -0
  44. data/app/assets/stylesheets/bootstrap-material-design/_typography.scss +15 -0
  45. data/app/assets/stylesheets/bootstrap-material-design/_variables.scss +169 -0
  46. data/app/assets/stylesheets/bootstrap-material-design/_welljumbo.scss +26 -0
  47. data/app/assets/stylesheets/bootstrap-material-design/plugins/_plugin-dropdownjs.scss +15 -0
  48. data/app/assets/stylesheets/bootstrap-material-design/plugins/_plugin-nouislider.scss +110 -0
  49. data/app/assets/stylesheets/bootstrap-material-design/plugins/_plugin-selectize.scss +91 -0
  50. data/app/assets/stylesheets/bootstrap-material-design/plugins/_plugin-snackbarjs.scss +32 -0
  51. data/app/assets/stylesheets/bootstrap-material-design/ripples.scss +36 -0
  52. data/lib/rails-bootstrap-material-design.rb +25 -0
  53. data/lib/rails-bootstrap-material-design/version.rb +3 -0
  54. data/rails-bootstrap-material-design.gemspec +20 -0
  55. metadata +124 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 39fe8854485ed92b3141763acafcefd3316f7f50
4
+ data.tar.gz: 3e86639bf27c03bcc79719aac300cfdc8bbe271c
5
+ SHA512:
6
+ metadata.gz: e7d18f4c71837c68b30fb9c5800b2970f7a632fbfe1bec64c1898b47daaa63d58a48e89ca20ce1662bde0bbcfac0d3961f0725bb22b7b6713c8a7e97fb11bf48
7
+ data.tar.gz: 7a943308fa14ac1f76994caa2c28ca17733013379a6775354e6e5dfcbf08bf5efe8f2879e7681e097f6888ae8382db6fa32a13666f5312c6c55125bf46c89ffd
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+ source 'https://rails-assets.org'
3
+
4
+ gemspec
@@ -0,0 +1,18 @@
1
+ # rails-bootstrap-material-design
2
+
3
+ ## Usage
4
+
5
+ Add rails-assets source block to your `Gemfile`:
6
+
7
+ ```ruby
8
+ source "https://rails-assets.org" do
9
+ gem "rails-assets-bootstrap-material-design"
10
+ end
11
+
12
+ ```
13
+
14
+ Then, import the asset using Sprockets’ `require` directive:
15
+
16
+ ```js
17
+ //= require "bootstrap-material-design"
18
+ ```
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
Binary file
Binary file
@@ -0,0 +1,2 @@
1
+ //= require bootstrap-material-design/material.js
2
+ //= require bootstrap-material-design/ripples.js
@@ -0,0 +1,350 @@
1
+ /* globals jQuery */
2
+
3
+ (function($) {
4
+ // Selector to select only not already processed elements
5
+ $.expr[":"].notmdproc = function(obj) {
6
+ if ($(obj).data("mdproc")) {
7
+ return false;
8
+ } else {
9
+ return true;
10
+ }
11
+ };
12
+
13
+ function _isChar(evt) {
14
+ if (typeof evt.which == "undefined") {
15
+ return true;
16
+ } else if (typeof evt.which == "number" && evt.which > 0) {
17
+ return (
18
+ !evt.ctrlKey
19
+ && !evt.metaKey
20
+ && !evt.altKey
21
+ && evt.which != 8 // backspace
22
+ && evt.which != 9 // tab
23
+ && evt.which != 13 // enter
24
+ && evt.which != 16 // shift
25
+ && evt.which != 17 // ctrl
26
+ && evt.which != 20 // caps lock
27
+ && evt.which != 27 // escape
28
+ );
29
+ }
30
+ return false;
31
+ }
32
+
33
+ function _addFormGroupFocus(element) {
34
+ var $element = $(element);
35
+ if (!$element.prop('disabled')) { // this is showing as undefined on chrome but works fine on firefox??
36
+ $element.closest(".form-group").addClass("is-focused");
37
+ }
38
+ }
39
+
40
+ function _toggleDisabledState($element, state) {
41
+ var $target;
42
+ if ($element.hasClass('checkbox-inline') || $element.hasClass('radio-inline')) {
43
+ $target = $element;
44
+ } else {
45
+ $target = $element.closest('.checkbox').length ? $element.closest('.checkbox') : $element.closest('.radio');
46
+ }
47
+ return $target.toggleClass('disabled', state);
48
+ }
49
+
50
+ function _toggleTypeFocus($input) {
51
+ var disabledToggleType = false;
52
+ if ($input.is($.material.options.checkboxElements) || $input.is($.material.options.radioElements)) {
53
+ disabledToggleType = true;
54
+ }
55
+ $input.closest('label').hover(function() {
56
+ var $i = $(this).find('input');
57
+ var isDisabled = $i.prop('disabled'); // hack because the _addFormGroupFocus() wasn't identifying the property on chrome
58
+ if (disabledToggleType) {
59
+ _toggleDisabledState($(this), isDisabled);
60
+ }
61
+ if (!isDisabled) {
62
+ _addFormGroupFocus($i); // need to find the input so we can check disablement
63
+ }
64
+ },
65
+ function() {
66
+ _removeFormGroupFocus($(this).find('input'));
67
+ });
68
+ }
69
+
70
+ function _removeFormGroupFocus(element) {
71
+ $(element).closest(".form-group").removeClass("is-focused"); // remove class from form-group
72
+ }
73
+
74
+ $.material = {
75
+ "options": {
76
+ // These options set what will be started by $.material.init()
77
+ "validate": true,
78
+ "input": true,
79
+ "ripples": true,
80
+ "checkbox": true,
81
+ "togglebutton": true,
82
+ "radio": true,
83
+ "arrive": true,
84
+ "autofill": false,
85
+
86
+ "withRipples": [
87
+ ".btn:not(.btn-link)",
88
+ ".card-image",
89
+ ".navbar a:not(.withoutripple)",
90
+ ".dropdown-menu a",
91
+ ".nav-tabs a:not(.withoutripple)",
92
+ ".withripple",
93
+ ".pagination li:not(.active):not(.disabled) a:not(.withoutripple)"
94
+ ].join(","),
95
+ "inputElements": "input.form-control, textarea.form-control, select.form-control",
96
+ "checkboxElements": ".checkbox > label > input[type=checkbox], label.checkbox-inline > input[type=checkbox]",
97
+ "togglebuttonElements": ".togglebutton > label > input[type=checkbox]",
98
+ "radioElements": ".radio > label > input[type=radio], label.radio-inline > input[type=radio]"
99
+ },
100
+ "checkbox": function(selector) {
101
+ // Add fake-checkbox to material checkboxes
102
+ var $input = $((selector) ? selector : this.options.checkboxElements)
103
+ .filter(":notmdproc")
104
+ .data("mdproc", true)
105
+ .after("<span class='checkbox-material'><span class='check'></span></span>");
106
+
107
+ _toggleTypeFocus($input);
108
+ },
109
+ "togglebutton": function(selector) {
110
+ // Add fake-checkbox to material checkboxes
111
+ var $input = $((selector) ? selector : this.options.togglebuttonElements)
112
+ .filter(":notmdproc")
113
+ .data("mdproc", true)
114
+ .after("<span class='toggle'></span>");
115
+
116
+ _toggleTypeFocus($input);
117
+ },
118
+ "radio": function(selector) {
119
+ // Add fake-radio to material radios
120
+ var $input = $((selector) ? selector : this.options.radioElements)
121
+ .filter(":notmdproc")
122
+ .data("mdproc", true)
123
+ .after("<span class='circle'></span><span class='check'></span>");
124
+
125
+ _toggleTypeFocus($input);
126
+ },
127
+ "input": function(selector) {
128
+ $((selector) ? selector : this.options.inputElements)
129
+ .filter(":notmdproc")
130
+ .data("mdproc", true)
131
+ .each(function() {
132
+ var $input = $(this);
133
+
134
+ // Requires form-group standard markup (will add it if necessary)
135
+ var $formGroup = $input.closest(".form-group"); // note that form-group may be grandparent in the case of an input-group
136
+ if ($formGroup.length === 0 && $input.attr('type') !== "hidden" && !$input.attr('hidden')) {
137
+ $input.wrap("<div class='form-group'></div>");
138
+ $formGroup = $input.closest(".form-group"); // find node after attached (otherwise additional attachments don't work)
139
+ }
140
+
141
+ // Legacy - Add hint label if using the old shorthand data-hint attribute on the input
142
+ if ($input.attr("data-hint")) {
143
+ $input.after("<p class='help-block'>" + $input.attr("data-hint") + "</p>");
144
+ $input.removeAttr("data-hint");
145
+ }
146
+
147
+ // Legacy - Change input-sm/lg to form-group-sm/lg instead (preferred standard and simpler css/less variants)
148
+ var legacySizes = {
149
+ "input-lg": "form-group-lg",
150
+ "input-sm": "form-group-sm"
151
+ };
152
+ $.each(legacySizes, function(legacySize, standardSize) {
153
+ if ($input.hasClass(legacySize)) {
154
+ $input.removeClass(legacySize);
155
+ $formGroup.addClass(standardSize);
156
+ }
157
+ });
158
+
159
+ // Legacy - Add label-floating if using old shorthand <input class="floating-label" placeholder="foo">
160
+ if ($input.hasClass("floating-label")) {
161
+ var placeholder = $input.attr("placeholder");
162
+ $input.attr("placeholder", null).removeClass("floating-label");
163
+ var id = $input.attr("id");
164
+ var forAttribute = "";
165
+ if (id) {
166
+ forAttribute = "for='" + id + "'";
167
+ }
168
+ $formGroup.addClass("label-floating");
169
+ $input.after("<label " + forAttribute + "class='control-label'>" + placeholder + "</label>");
170
+ }
171
+
172
+ // Set as empty if is empty (damn I must improve this...)
173
+ if ($input.val() === null || $input.val() == "undefined" || $input.val() === "") {
174
+ $formGroup.addClass("is-empty");
175
+ }
176
+
177
+ // Support for file input
178
+ if ($formGroup.find("input[type=file]").length > 0) {
179
+ $formGroup.addClass("is-fileinput");
180
+ }
181
+ });
182
+ },
183
+ "attachInputEventHandlers": function() {
184
+ var validate = this.options.validate;
185
+
186
+ $(document)
187
+ .on("keydown paste", ".form-control", function(e) {
188
+ if (_isChar(e)) {
189
+ $(this).closest(".form-group").removeClass("is-empty");
190
+ }
191
+ })
192
+ .on("keyup change", ".form-control", function() {
193
+ var $input = $(this);
194
+ var $formGroup = $input.closest(".form-group");
195
+ var isValid = (typeof $input[0].checkValidity === "undefined" || $input[0].checkValidity());
196
+
197
+ if ($input.val() === "") {
198
+ $formGroup.addClass("is-empty");
199
+ } else {
200
+ $formGroup.removeClass("is-empty");
201
+ }
202
+
203
+ // Validation events do not bubble, so they must be attached directly to the input: http://jsfiddle.net/PEpRM/1/
204
+ // Further, even the bind method is being caught, but since we are already calling #checkValidity here, just alter
205
+ // the form-group on change.
206
+ //
207
+ // NOTE: I'm not sure we should be intervening regarding validation, this seems better as a README and snippet of code.
208
+ // BUT, I've left it here for backwards compatibility.
209
+ if (validate) {
210
+ if (isValid) {
211
+ $formGroup.removeClass("has-error");
212
+ } else {
213
+ $formGroup.addClass("has-error");
214
+ }
215
+ }
216
+ })
217
+ .on("focus", ".form-control, .form-group.is-fileinput", function() {
218
+ _addFormGroupFocus(this);
219
+ })
220
+ .on("blur", ".form-control, .form-group.is-fileinput", function() {
221
+ _removeFormGroupFocus(this);
222
+ })
223
+ // make sure empty is added back when there is a programmatic value change.
224
+ // NOTE: programmatic changing of value using $.val() must trigger the change event i.e. $.val('x').trigger('change')
225
+ .on("change", ".form-group input", function() {
226
+ var $input = $(this);
227
+ if ($input.attr("type") == "file") {
228
+ return;
229
+ }
230
+
231
+ var $formGroup = $input.closest(".form-group");
232
+ var value = $input.val();
233
+ if (value) {
234
+ $formGroup.removeClass("is-empty");
235
+ } else {
236
+ $formGroup.addClass("is-empty");
237
+ }
238
+ })
239
+ // set the fileinput readonly field with the name of the file
240
+ .on("change", ".form-group.is-fileinput input[type='file']", function() {
241
+ var $input = $(this);
242
+ var $formGroup = $input.closest(".form-group");
243
+ var value = "";
244
+ $.each(this.files, function(i, file) {
245
+ value += file.name + ", ";
246
+ });
247
+ value = value.substring(0, value.length - 2);
248
+ if (value) {
249
+ $formGroup.removeClass("is-empty");
250
+ } else {
251
+ $formGroup.addClass("is-empty");
252
+ }
253
+ $formGroup.find("input.form-control[readonly]").val(value);
254
+ });
255
+ },
256
+ "ripples": function(selector) {
257
+ $((selector) ? selector : this.options.withRipples).ripples();
258
+ },
259
+ "autofill": function() {
260
+ // This part of code will detect autofill when the page is loading (username and password inputs for example)
261
+ var loading = setInterval(function() {
262
+ $("input[type!=checkbox]").each(function() {
263
+ var $this = $(this);
264
+ if ($this.val() && $this.val() !== $this.attr("value")) {
265
+ $this.trigger("change");
266
+ }
267
+ });
268
+ }, 100);
269
+
270
+ // After 10 seconds we are quite sure all the needed inputs are autofilled then we can stop checking them
271
+ setTimeout(function() {
272
+ clearInterval(loading);
273
+ }, 10000);
274
+ },
275
+ "attachAutofillEventHandlers": function() {
276
+ // Listen on inputs of the focused form (because user can select from the autofill dropdown only when the input has focus)
277
+ var focused;
278
+ $(document)
279
+ .on("focus", "input", function() {
280
+ var $inputs = $(this).parents("form").find("input").not("[type=file]");
281
+ focused = setInterval(function() {
282
+ $inputs.each(function() {
283
+ var $this = $(this);
284
+ if ($this.val() !== $this.attr("value")) {
285
+ $this.trigger("change");
286
+ }
287
+ });
288
+ }, 100);
289
+ })
290
+ .on("blur", ".form-group input", function() {
291
+ clearInterval(focused);
292
+ });
293
+ },
294
+ "init": function(options) {
295
+ this.options = $.extend({}, this.options, options);
296
+ var $document = $(document);
297
+
298
+ if ($.fn.ripples && this.options.ripples) {
299
+ this.ripples();
300
+ }
301
+ if (this.options.input) {
302
+ this.input();
303
+ this.attachInputEventHandlers();
304
+ }
305
+ if (this.options.checkbox) {
306
+ this.checkbox();
307
+ }
308
+ if (this.options.togglebutton) {
309
+ this.togglebutton();
310
+ }
311
+ if (this.options.radio) {
312
+ this.radio();
313
+ }
314
+ if (this.options.autofill) {
315
+ this.autofill();
316
+ this.attachAutofillEventHandlers();
317
+ }
318
+
319
+ if (document.arrive && this.options.arrive) {
320
+ if ($.fn.ripples && this.options.ripples) {
321
+ $document.arrive(this.options.withRipples, function() {
322
+ $.material.ripples($(this));
323
+ });
324
+ }
325
+ if (this.options.input) {
326
+ $document.arrive(this.options.inputElements, function() {
327
+ $.material.input($(this));
328
+ });
329
+ }
330
+ if (this.options.checkbox) {
331
+ $document.arrive(this.options.checkboxElements, function() {
332
+ $.material.checkbox($(this));
333
+ });
334
+ }
335
+ if (this.options.radio) {
336
+ $document.arrive(this.options.radioElements, function() {
337
+ $.material.radio($(this));
338
+ });
339
+ }
340
+ if (this.options.togglebutton) {
341
+ $document.arrive(this.options.togglebuttonElements, function() {
342
+ $.material.togglebutton($(this));
343
+ });
344
+ }
345
+
346
+ }
347
+ }
348
+ };
349
+
350
+ })(jQuery);
@@ -0,0 +1,325 @@
1
+ /* Copyright 2014+, Federico Zivolo, LICENSE at https://github.com/FezVrasta/bootstrap-material-design/blob/master/LICENSE.md */
2
+ /* globals jQuery, navigator */
3
+
4
+ (function($, window, document, undefined) {
5
+
6
+ "use strict";
7
+
8
+ /**
9
+ * Define the name of the plugin
10
+ */
11
+ var ripples = "ripples";
12
+
13
+
14
+ /**
15
+ * Get an instance of the plugin
16
+ */
17
+ var self = null;
18
+
19
+
20
+ /**
21
+ * Define the defaults of the plugin
22
+ */
23
+ var defaults = {};
24
+
25
+
26
+ /**
27
+ * Create the main plugin function
28
+ */
29
+ function Ripples(element, options) {
30
+ self = this;
31
+
32
+ this.element = $(element);
33
+
34
+ this.options = $.extend({}, defaults, options);
35
+
36
+ this._defaults = defaults;
37
+ this._name = ripples;
38
+
39
+ this.init();
40
+ }
41
+
42
+
43
+ /**
44
+ * Initialize the plugin
45
+ */
46
+ Ripples.prototype.init = function() {
47
+ var $element = this.element;
48
+
49
+ $element.on("mousedown touchstart", function(event) {
50
+ /**
51
+ * Verify if the user is just touching on a device and return if so
52
+ */
53
+ if (self.isTouch() && event.type === "mousedown") {
54
+ return;
55
+ }
56
+
57
+
58
+ /**
59
+ * Verify if the current element already has a ripple wrapper element and
60
+ * creates if it doesn't
61
+ */
62
+ if (!($element.find(".ripple-container").length)) {
63
+ $element.append("<div class=\"ripple-container\"></div>");
64
+ }
65
+
66
+
67
+ /**
68
+ * Find the ripple wrapper
69
+ */
70
+ var $wrapper = $element.children(".ripple-container");
71
+
72
+
73
+ /**
74
+ * Get relY and relX positions
75
+ */
76
+ var relY = self.getRelY($wrapper, event);
77
+ var relX = self.getRelX($wrapper, event);
78
+
79
+
80
+ /**
81
+ * If relY and/or relX are false, return the event
82
+ */
83
+ if (!relY && !relX) {
84
+ return;
85
+ }
86
+
87
+
88
+ /**
89
+ * Get the ripple color
90
+ */
91
+ var rippleColor = self.getRipplesColor($element);
92
+
93
+
94
+ /**
95
+ * Create the ripple element
96
+ */
97
+ var $ripple = $("<div></div>");
98
+
99
+ $ripple
100
+ .addClass("ripple")
101
+ .css({
102
+ "left": relX,
103
+ "top": relY,
104
+ "background-color": rippleColor
105
+ });
106
+
107
+
108
+ /**
109
+ * Append the ripple to the wrapper
110
+ */
111
+ $wrapper.append($ripple);
112
+
113
+
114
+ /**
115
+ * Make sure the ripple has the styles applied (ugly hack but it works)
116
+ */
117
+ (function() {
118
+ return window.getComputedStyle($ripple[0]).opacity; })();
119
+
120
+
121
+ /**
122
+ * Turn on the ripple animation
123
+ */
124
+ self.rippleOn($element, $ripple);
125
+
126
+
127
+ /**
128
+ * Call the rippleEnd function when the transition "on" ends
129
+ */
130
+ setTimeout(function() {
131
+ self.rippleEnd($ripple);
132
+ }, 500);
133
+
134
+
135
+ /**
136
+ * Detect when the user leaves the element
137
+ */
138
+ $element.on("mouseup mouseleave touchend", function() {
139
+ $ripple.data("mousedown", "off");
140
+
141
+ if ($ripple.data("animating") === "off") {
142
+ self.rippleOut($ripple);
143
+ }
144
+ });
145
+
146
+ });
147
+ };
148
+
149
+
150
+ /**
151
+ * Get the new size based on the element height/width and the ripple width
152
+ */
153
+ Ripples.prototype.getNewSize = function($element, $ripple) {
154
+
155
+ return (Math.max($element.outerWidth(), $element.outerHeight()) / $ripple.outerWidth()) * 2.5;
156
+ };
157
+
158
+
159
+ /**
160
+ * Get the relX
161
+ */
162
+ Ripples.prototype.getRelX = function($wrapper, event) {
163
+ var wrapperOffset = $wrapper.offset();
164
+
165
+ if (!self.isTouch()) {
166
+ /**
167
+ * Get the mouse position relative to the ripple wrapper
168
+ */
169
+ return event.pageX - wrapperOffset.left;
170
+ } else {
171
+ /**
172
+ * Make sure the user is using only one finger and then get the touch
173
+ * position relative to the ripple wrapper
174
+ */
175
+ event = event.originalEvent;
176
+
177
+ if (event.touches.length === 1) {
178
+ return event.touches[0].pageX - wrapperOffset.left;
179
+ }
180
+
181
+ return false;
182
+ }
183
+ };
184
+
185
+
186
+ /**
187
+ * Get the relY
188
+ */
189
+ Ripples.prototype.getRelY = function($wrapper, event) {
190
+ var wrapperOffset = $wrapper.offset();
191
+
192
+ if (!self.isTouch()) {
193
+ /**
194
+ * Get the mouse position relative to the ripple wrapper
195
+ */
196
+ return event.pageY - wrapperOffset.top;
197
+ } else {
198
+ /**
199
+ * Make sure the user is using only one finger and then get the touch
200
+ * position relative to the ripple wrapper
201
+ */
202
+ event = event.originalEvent;
203
+
204
+ if (event.touches.length === 1) {
205
+ return event.touches[0].pageY - wrapperOffset.top;
206
+ }
207
+
208
+ return false;
209
+ }
210
+ };
211
+
212
+
213
+ /**
214
+ * Get the ripple color
215
+ */
216
+ Ripples.prototype.getRipplesColor = function($element) {
217
+
218
+ var color = $element.data("ripple-color") ? $element.data("ripple-color") : window.getComputedStyle($element[0]).color;
219
+
220
+ return color;
221
+ };
222
+
223
+
224
+ /**
225
+ * Verify if the client browser has transistion support
226
+ */
227
+ Ripples.prototype.hasTransitionSupport = function() {
228
+ var thisBody = document.body || document.documentElement;
229
+ var thisStyle = thisBody.style;
230
+
231
+ var support = (
232
+ thisStyle.transition !== undefined ||
233
+ thisStyle.WebkitTransition !== undefined ||
234
+ thisStyle.MozTransition !== undefined ||
235
+ thisStyle.MsTransition !== undefined ||
236
+ thisStyle.OTransition !== undefined
237
+ );
238
+
239
+ return support;
240
+ };
241
+
242
+
243
+ /**
244
+ * Verify if the client is using a mobile device
245
+ */
246
+ Ripples.prototype.isTouch = function() {
247
+ return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
248
+ };
249
+
250
+
251
+ /**
252
+ * End the animation of the ripple
253
+ */
254
+ Ripples.prototype.rippleEnd = function($ripple) {
255
+ $ripple.data("animating", "off");
256
+
257
+ if ($ripple.data("mousedown") === "off") {
258
+ self.rippleOut($ripple);
259
+ }
260
+ };
261
+
262
+
263
+ /**
264
+ * Turn off the ripple effect
265
+ */
266
+ Ripples.prototype.rippleOut = function($ripple) {
267
+ $ripple.off();
268
+
269
+ if (self.hasTransitionSupport()) {
270
+ $ripple.addClass("ripple-out");
271
+ } else {
272
+ $ripple.animate({ "opacity": 0 }, 100, function() {
273
+ $ripple.trigger("transitionend");
274
+ });
275
+ }
276
+
277
+ $ripple.on("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", function() {
278
+ $ripple.remove();
279
+ });
280
+ };
281
+
282
+
283
+ /**
284
+ * Turn on the ripple effect
285
+ */
286
+ Ripples.prototype.rippleOn = function($element, $ripple) {
287
+ var size = self.getNewSize($element, $ripple);
288
+
289
+ if (self.hasTransitionSupport()) {
290
+ $ripple
291
+ .css({
292
+ "-ms-transform": "scale(" + size + ")",
293
+ "-moz-transform": "scale(" + size + ")",
294
+ "-webkit-transform": "scale(" + size + ")",
295
+ "transform": "scale(" + size + ")"
296
+ })
297
+ .addClass("ripple-on")
298
+ .data("animating", "on")
299
+ .data("mousedown", "on");
300
+ } else {
301
+ $ripple.animate({
302
+ "width": Math.max($element.outerWidth(), $element.outerHeight()) * 2,
303
+ "height": Math.max($element.outerWidth(), $element.outerHeight()) * 2,
304
+ "margin-left": Math.max($element.outerWidth(), $element.outerHeight()) * (-1),
305
+ "margin-top": Math.max($element.outerWidth(), $element.outerHeight()) * (-1),
306
+ "opacity": 0.2
307
+ }, 500, function() {
308
+ $ripple.trigger("transitionend");
309
+ });
310
+ }
311
+ };
312
+
313
+
314
+ /**
315
+ * Create the jquery plugin function
316
+ */
317
+ $.fn.ripples = function(options) {
318
+ return this.each(function() {
319
+ if (!$.data(this, "plugin_" + ripples)) {
320
+ $.data(this, "plugin_" + ripples, new Ripples(this, options));
321
+ }
322
+ });
323
+ };
324
+
325
+ })(jQuery, window, document);