bootstrap-material 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/Gemfile +3 -0
  4. data/LICENSE +32 -0
  5. data/README.md +79 -0
  6. data/Rakefile +1 -0
  7. data/app/assets/fonts/LICENSE.txt +428 -0
  8. data/app/assets/fonts/Material-Design-Icons.eot +0 -0
  9. data/app/assets/fonts/Material-Design-Icons.svg +769 -0
  10. data/app/assets/fonts/Material-Design-Icons.ttf +0 -0
  11. data/app/assets/fonts/Material-Design-Icons.woff +0 -0
  12. data/app/assets/javascripts/bootstrap-material/index.js +4 -0
  13. data/app/assets/javascripts/bootstrap-material/jquery.nouislider.js +668 -0
  14. data/app/assets/javascripts/bootstrap-material/material.js +226 -0
  15. data/app/assets/javascripts/bootstrap-material/ripples.js +324 -0
  16. data/app/assets/javascripts/bootstrap-material/snackbar.js +153 -0
  17. data/app/assets/stylesheets/_bootstrap-material-fullpalette.scss +3 -0
  18. data/app/assets/stylesheets/_bootstrap-material-roboto.scss +1 -0
  19. data/app/assets/stylesheets/_bootstrap-material.scss +3 -0
  20. data/app/assets/stylesheets/bootstrap-material-fullpalette/index.css +5 -0
  21. data/app/assets/stylesheets/bootstrap-material-fullpalette/material-fullpalette.css.erb +73442 -0
  22. data/app/assets/stylesheets/bootstrap-material-fullpalette/ripples.css +41 -0
  23. data/app/assets/stylesheets/bootstrap-material-fullpalette/snackbar.css +35 -0
  24. data/app/assets/stylesheets/bootstrap-material/index.css +5 -0
  25. data/app/assets/stylesheets/bootstrap-material/material.css.erb +8308 -0
  26. data/app/assets/stylesheets/bootstrap-material/ripples.css +41 -0
  27. data/app/assets/stylesheets/bootstrap-material/snackbar.css +35 -0
  28. data/bootstrap-material.gemspec +21 -0
  29. data/lib/bootstrap-material.rb +3 -0
  30. data/lib/bootstrap-material/engine.rb +4 -0
  31. metadata +86 -0
@@ -0,0 +1,226 @@
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 !evt.ctrlKey && !evt.metaKey && !evt.altKey && evt.which != 8 && evt.which != 9;
18
+ }
19
+ return false;
20
+ }
21
+
22
+ $.material = {
23
+ "options": {
24
+ // These options set what will be started by $.material.init()
25
+ "input": true,
26
+ "ripples": true,
27
+ "checkbox": true,
28
+ "togglebutton": true,
29
+ "radio": true,
30
+ "arrive": true,
31
+ "autofill": false,
32
+
33
+ "withRipples": [
34
+ ".btn:not(.btn-link)",
35
+ ".card-image",
36
+ ".navbar a:not(.withoutripple)",
37
+ ".dropdown-menu a",
38
+ ".nav-tabs a:not(.withoutripple)",
39
+ ".withripple"
40
+ ].join(","),
41
+ "inputElements": "input.form-control, textarea.form-control, select.form-control",
42
+ "checkboxElements": ".checkbox > label > input[type=checkbox]",
43
+ "togglebuttonElements": ".togglebutton > label > input[type=checkbox]",
44
+ "radioElements": ".radio > label > input[type=radio]"
45
+ },
46
+ "checkbox": function(selector) {
47
+ // Add fake-checkbox to material checkboxes
48
+ $((selector) ? selector : this.options.checkboxElements)
49
+ .filter(":notmdproc")
50
+ .data("mdproc", true)
51
+ .after("<span class=checkbox-material><span class=check></span></span>");
52
+ },
53
+ "togglebutton": function(selector) {
54
+ // Add fake-checkbox to material checkboxes
55
+ $((selector) ? selector : this.options.togglebuttonElements)
56
+ .filter(":notmdproc")
57
+ .data("mdproc", true)
58
+ .after("<span class=toggle></span>");
59
+ },
60
+ "radio": function(selector) {
61
+ // Add fake-radio to material radios
62
+ $((selector) ? selector : this.options.radioElements)
63
+ .filter(":notmdproc")
64
+ .data("mdproc", true)
65
+ .after("<span class=circle></span><span class=check></span>");
66
+ },
67
+ "input": function(selector) {
68
+ $((selector) ? selector : this.options.inputElements)
69
+ .filter(":notmdproc")
70
+ .data("mdproc", true)
71
+ .each( function() {
72
+ var $this = $(this);
73
+
74
+ if (!$(this).attr("data-hint") && !$this.hasClass("floating-label")) {
75
+ return;
76
+ }
77
+ $this.wrap("<div class=form-control-wrapper></div>");
78
+ $this.after("<span class=material-input></span>");
79
+
80
+ // Add floating label if required
81
+ if ($this.hasClass("floating-label")) {
82
+ var placeholder = $this.attr("placeholder");
83
+ $this.attr("placeholder", null).removeClass("floating-label");
84
+ $this.after("<div class=floating-label>" + placeholder + "</div>");
85
+ }
86
+
87
+ // Add hint label if required
88
+ if ($this.attr("data-hint")) {
89
+ $this.after("<div class=hint>" + $this.attr("data-hint") + "</div>");
90
+ }
91
+
92
+ // Set as empty if is empty (damn I must improve this...)
93
+ if ($this.val() === null || $this.val() == "undefined" || $this.val() === "") {
94
+ $this.addClass("empty");
95
+ }
96
+
97
+ // Support for file input
98
+ if ($this.parent().next().is("[type=file]")) {
99
+ $this.parent().addClass("fileinput");
100
+ var $input = $this.parent().next().detach();
101
+ $this.after($input);
102
+ }
103
+ });
104
+
105
+ $(document)
106
+ .on("change", ".checkbox input[type=checkbox]", function() { $(this).blur(); })
107
+ .on("keydown paste", ".form-control", function(e) {
108
+ if(_isChar(e)) {
109
+ $(this).removeClass("empty");
110
+ }
111
+ })
112
+ .on("keyup change", ".form-control", function() {
113
+ var $this = $(this);
114
+ if ($this.val() === "" && (typeof $this[0].checkValidity != "undefined" && $this[0].checkValidity())) {
115
+ $this.addClass("empty");
116
+ } else {
117
+ $this.removeClass("empty");
118
+ }
119
+ })
120
+ .on("focus", ".form-control-wrapper.fileinput", function() {
121
+ $(this).find("input").addClass("focus");
122
+ })
123
+ .on("blur", ".form-control-wrapper.fileinput", function() {
124
+ $(this).find("input").removeClass("focus");
125
+ })
126
+ .on("change", ".form-control-wrapper.fileinput [type=file]", function() {
127
+ var value = "";
128
+ $.each($(this)[0].files, function(i, file) {
129
+ value += file.name + ", ";
130
+ });
131
+ value = value.substring(0, value.length - 2);
132
+ if (value) {
133
+ $(this).prev().removeClass("empty");
134
+ } else {
135
+ $(this).prev().addClass("empty");
136
+ }
137
+ $(this).prev().val(value);
138
+ });
139
+ },
140
+ "ripples": function(selector) {
141
+ $((selector) ? selector : this.options.withRipples).ripples();
142
+ },
143
+ "autofill": function() {
144
+
145
+ // This part of code will detect autofill when the page is loading (username and password inputs for example)
146
+ var loading = setInterval(function() {
147
+ $("input[type!=checkbox]").each(function() {
148
+ if ($(this).val() && $(this).val() !== $(this).attr("value")) {
149
+ $(this).trigger("change");
150
+ }
151
+ });
152
+ }, 100);
153
+
154
+ // After 10 seconds we are quite sure all the needed inputs are autofilled then we can stop checking them
155
+ setTimeout(function() {
156
+ clearInterval(loading);
157
+ }, 10000);
158
+ // Now we just listen on inputs of the focused form (because user can select from the autofill dropdown only when the input has focus)
159
+ var focused;
160
+ $(document)
161
+ .on("focus", "input", function() {
162
+ var $inputs = $(this).parents("form").find("input").not("[type=file]");
163
+ focused = setInterval(function() {
164
+ $inputs.each(function() {
165
+ if ($(this).val() !== $(this).attr("value")) {
166
+ $(this).trigger("change");
167
+ }
168
+ });
169
+ }, 100);
170
+ })
171
+ .on("blur", "input", function() {
172
+ clearInterval(focused);
173
+ });
174
+ },
175
+ "init": function() {
176
+ if ($.fn.ripples && this.options.ripples) {
177
+ this.ripples();
178
+ }
179
+ if (this.options.input) {
180
+ this.input();
181
+ }
182
+ if (this.options.checkbox) {
183
+ this.checkbox();
184
+ }
185
+ if (this.options.togglebutton) {
186
+ this.togglebutton();
187
+ }
188
+ if (this.options.radio) {
189
+ this.radio();
190
+ }
191
+ if (this.options.autofill) {
192
+ this.autofill();
193
+ }
194
+
195
+ if (document.arrive && this.options.arrive) {
196
+ if ($.fn.ripples && this.options.ripples) {
197
+ $(document).arrive(this.options.withRipples, function() {
198
+ $.material.ripples($(this));
199
+ });
200
+ }
201
+ if (this.options.input) {
202
+ $(document).arrive(this.options.inputElements, function() {
203
+ $.material.input($(this));
204
+ });
205
+ }
206
+ if (this.options.checkbox) {
207
+ $(document).arrive(this.options.checkboxElements, function() {
208
+ $.material.checkbox($(this));
209
+ });
210
+ }
211
+ if (this.options.radio) {
212
+ $(document).arrive(this.options.radioElements, function() {
213
+ $.material.radio($(this));
214
+ });
215
+ }
216
+ if (this.options.togglebutton) {
217
+ $(document).arrive(this.options.togglebuttonElements, function() {
218
+ $.material.togglebutton($(this));
219
+ });
220
+ }
221
+
222
+ }
223
+ }
224
+ };
225
+
226
+ })(jQuery);
@@ -0,0 +1,324 @@
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-wrapper").length)) {
63
+ $element.append("<div class=\"ripple-wrapper\"></div>");
64
+ }
65
+
66
+
67
+ /**
68
+ * Find the ripple wrapper
69
+ */
70
+ var $wrapper = $element.children(".ripple-wrapper");
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() { return window.getComputedStyle($ripple[0]).opacity; })();
118
+
119
+
120
+ /**
121
+ * Turn on the ripple animation
122
+ */
123
+ self.rippleOn($element, $ripple);
124
+
125
+
126
+ /**
127
+ * Call the rippleEnd function when the transition "on" ends
128
+ */
129
+ setTimeout(function() {
130
+ self.rippleEnd($ripple);
131
+ }, 500);
132
+
133
+
134
+ /**
135
+ * Detect when the user leaves the element
136
+ */
137
+ $element.on("mouseup mouseleave touchend", function() {
138
+ $ripple.data("mousedown", "off");
139
+
140
+ if($ripple.data("animating") === "off") {
141
+ self.rippleOut($ripple);
142
+ }
143
+ });
144
+
145
+ });
146
+ };
147
+
148
+
149
+ /**
150
+ * Get the new size based on the element height/width and the ripple width
151
+ */
152
+ Ripples.prototype.getNewSize = function($element, $ripple) {
153
+
154
+ return (Math.max($element.outerWidth(), $element.outerHeight()) / $ripple.outerWidth()) * 2.5;
155
+ };
156
+
157
+
158
+ /**
159
+ * Get the relX
160
+ */
161
+ Ripples.prototype.getRelX = function($wrapper, event) {
162
+ var wrapperOffset = $wrapper.offset();
163
+
164
+ if(!self.isTouch()) {
165
+ /**
166
+ * Get the mouse position relative to the ripple wrapper
167
+ */
168
+ return event.pageX - wrapperOffset.left;
169
+ } else {
170
+ /**
171
+ * Make sure the user is using only one finger and then get the touch
172
+ * position relative to the ripple wrapper
173
+ */
174
+ event = event.originalEvent;
175
+
176
+ if(event.touches.length !== 1) {
177
+ return event.touches[0].pageX - wrapperOffset.left;
178
+ }
179
+
180
+ return false;
181
+ }
182
+ };
183
+
184
+
185
+ /**
186
+ * Get the relY
187
+ */
188
+ Ripples.prototype.getRelY = function($wrapper, event) {
189
+ var wrapperOffset = $wrapper.offset();
190
+
191
+ if(!self.isTouch()) {
192
+ /**
193
+ * Get the mouse position relative to the ripple wrapper
194
+ */
195
+ return event.pageY - wrapperOffset.top;
196
+ } else {
197
+ /**
198
+ * Make sure the user is using only one finger and then get the touch
199
+ * position relative to the ripple wrapper
200
+ */
201
+ event = event.originalEvent;
202
+
203
+ if(event.touches.length !== 1) {
204
+ return event.touches[0].pageY - wrapperOffset.top;
205
+ }
206
+
207
+ return false;
208
+ }
209
+ };
210
+
211
+
212
+ /**
213
+ * Get the ripple color
214
+ */
215
+ Ripples.prototype.getRipplesColor = function($element) {
216
+
217
+ var color = $element.data("ripple-color") ? $element.data("ripple-color") : window.getComputedStyle($element[0]).color;
218
+
219
+ return color;
220
+ };
221
+
222
+
223
+ /**
224
+ * Verify if the client browser has transistion support
225
+ */
226
+ Ripples.prototype.hasTransitionSupport = function() {
227
+ var thisBody = document.body || document.documentElement;
228
+ var thisStyle = thisBody.style;
229
+
230
+ var support = (
231
+ thisStyle.transition !== undefined ||
232
+ thisStyle.WebkitTransition !== undefined ||
233
+ thisStyle.MozTransition !== undefined ||
234
+ thisStyle.MsTransition !== undefined ||
235
+ thisStyle.OTransition !== undefined
236
+ );
237
+
238
+ return support;
239
+ };
240
+
241
+
242
+ /**
243
+ * Verify if the client is using a mobile device
244
+ */
245
+ Ripples.prototype.isTouch = function() {
246
+ return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
247
+ };
248
+
249
+
250
+ /**
251
+ * End the animation of the ripple
252
+ */
253
+ Ripples.prototype.rippleEnd = function($ripple) {
254
+ $ripple.data("animating", "off");
255
+
256
+ if($ripple.data("mousedown") === "off") {
257
+ self.rippleOut($ripple);
258
+ }
259
+ };
260
+
261
+
262
+ /**
263
+ * Turn off the ripple effect
264
+ */
265
+ Ripples.prototype.rippleOut = function($ripple) {
266
+ $ripple.off();
267
+
268
+ if(self.hasTransitionSupport()) {
269
+ $ripple.addClass("ripple-out");
270
+ } else {
271
+ $ripple.animate({"opacity": 0}, 100, function() {
272
+ $ripple.trigger("transitionend");
273
+ });
274
+ }
275
+
276
+ $ripple.on("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", function() {
277
+ $ripple.remove();
278
+ });
279
+ };
280
+
281
+
282
+ /**
283
+ * Turn on the ripple effect
284
+ */
285
+ Ripples.prototype.rippleOn = function($element, $ripple) {
286
+ var size = self.getNewSize($element, $ripple);
287
+
288
+ if(self.hasTransitionSupport()) {
289
+ $ripple
290
+ .css({
291
+ "-ms-transform": "scale(" + size + ")",
292
+ "-moz-transform": "scale(" + size + ")",
293
+ "-webkit-transform": "scale(" + size + ")",
294
+ "transform": "scale(" + size + ")"
295
+ })
296
+ .addClass("ripple-on")
297
+ .data("animating", "on")
298
+ .data("mousedown", "on");
299
+ } else {
300
+ $ripple.animate({
301
+ "width": Math.max($element.outerWidth(), $element.outerHeight()) * 2,
302
+ "height": Math.max($element.outerWidth(), $element.outerHeight()) * 2,
303
+ "margin-left": Math.max($element.outerWidth(), $element.outerHeight()) * (-1),
304
+ "margin-top": Math.max($element.outerWidth(), $element.outerHeight()) * (-1),
305
+ "opacity": 0.2
306
+ }, 500, function() {
307
+ $ripple.trigger("transitionend");
308
+ });
309
+ }
310
+ };
311
+
312
+
313
+ /**
314
+ * Create the jquery plugin function
315
+ */
316
+ $.fn.ripples = function(options) {
317
+ return this.each(function() {
318
+ if(!$.data(this, "plugin_" + ripples)) {
319
+ $.data(this, "plugin_" + ripples, new Ripples(this, options));
320
+ }
321
+ });
322
+ };
323
+
324
+ })(jQuery, window, document);