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.
- checksums.yaml +7 -0
- data/Gemfile +4 -0
- data/README.md +18 -0
- data/Rakefile +1 -0
- data/app/.DS_Store +0 -0
- data/app/assets/.DS_Store +0 -0
- data/app/assets/images/.DS_Store +0 -0
- data/app/assets/images/bootstrap-material-design/material-design-color-palette.jpg +0 -0
- data/app/assets/javascripts/.DS_Store +0 -0
- data/app/assets/javascripts/bootstrap-material-design.js +2 -0
- data/app/assets/javascripts/bootstrap-material-design/material.js +350 -0
- data/app/assets/javascripts/bootstrap-material-design/ripples.js +325 -0
- data/app/assets/stylesheets/.DS_Store +0 -0
- data/app/assets/stylesheets/bootstrap-material-design.scss +4 -0
- data/app/assets/stylesheets/bootstrap-material-design/.DS_Store +0 -0
- data/app/assets/stylesheets/bootstrap-material-design/_alerts.scss +17 -0
- data/app/assets/stylesheets/bootstrap-material-design/_buttons.scss +244 -0
- data/app/assets/stylesheets/bootstrap-material-design/_cards.scss +66 -0
- data/app/assets/stylesheets/bootstrap-material-design/_checkboxes.scss +270 -0
- data/app/assets/stylesheets/bootstrap-material-design/_colors-map.scss +311 -0
- data/app/assets/stylesheets/bootstrap-material-design/_colors.scss +359 -0
- data/app/assets/stylesheets/bootstrap-material-design/_core.scss +93 -0
- data/app/assets/stylesheets/bootstrap-material-design/_dialogs.scss +52 -0
- data/app/assets/stylesheets/bootstrap-material-design/_dividers.scss +71 -0
- data/app/assets/stylesheets/bootstrap-material-design/_form.scss +40 -0
- data/app/assets/stylesheets/bootstrap-material-design/_import-bs-sass.scss +2 -0
- data/app/assets/stylesheets/bootstrap-material-design/_inputs-size.scss +221 -0
- data/app/assets/stylesheets/bootstrap-material-design/_inputs.scss +352 -0
- data/app/assets/stylesheets/bootstrap-material-design/_labels.scss +4 -0
- data/app/assets/stylesheets/bootstrap-material-design/_lists.scss +102 -0
- data/app/assets/stylesheets/bootstrap-material-design/_mixins-utilities.scss +31 -0
- data/app/assets/stylesheets/bootstrap-material-design/_mixins.scss +241 -0
- data/app/assets/stylesheets/bootstrap-material-design/_navbar.scss +232 -0
- data/app/assets/stylesheets/bootstrap-material-design/_panels.scss +21 -0
- data/app/assets/stylesheets/bootstrap-material-design/_plugins.scss +5 -0
- data/app/assets/stylesheets/bootstrap-material-design/_popups.scss +18 -0
- data/app/assets/stylesheets/bootstrap-material-design/_progress.scss +10 -0
- data/app/assets/stylesheets/bootstrap-material-design/_radios.scss +115 -0
- data/app/assets/stylesheets/bootstrap-material-design/_shadows.scss +82 -0
- data/app/assets/stylesheets/bootstrap-material-design/_table.scss +15 -0
- data/app/assets/stylesheets/bootstrap-material-design/_tabs.scss +24 -0
- data/app/assets/stylesheets/bootstrap-material-design/_themes.scss +6 -0
- data/app/assets/stylesheets/bootstrap-material-design/_togglebutton.scss +83 -0
- data/app/assets/stylesheets/bootstrap-material-design/_typography.scss +15 -0
- data/app/assets/stylesheets/bootstrap-material-design/_variables.scss +169 -0
- data/app/assets/stylesheets/bootstrap-material-design/_welljumbo.scss +26 -0
- data/app/assets/stylesheets/bootstrap-material-design/plugins/_plugin-dropdownjs.scss +15 -0
- data/app/assets/stylesheets/bootstrap-material-design/plugins/_plugin-nouislider.scss +110 -0
- data/app/assets/stylesheets/bootstrap-material-design/plugins/_plugin-selectize.scss +91 -0
- data/app/assets/stylesheets/bootstrap-material-design/plugins/_plugin-snackbarjs.scss +32 -0
- data/app/assets/stylesheets/bootstrap-material-design/ripples.scss +36 -0
- data/lib/rails-bootstrap-material-design.rb +25 -0
- data/lib/rails-bootstrap-material-design/version.rb +3 -0
- data/rails-bootstrap-material-design.gemspec +20 -0
- metadata +124 -0
checksums.yaml
ADDED
@@ -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
data/README.md
ADDED
@@ -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
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
data/app/.DS_Store
ADDED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -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);
|