Merge and dist

This commit is contained in:
Kevin Ross 2015-12-13 19:38:09 -06:00
commit 8bec58172c
13 changed files with 389 additions and 359 deletions

View File

@ -811,6 +811,9 @@ fieldset[disabled][disabled] .btn-group-vertical.btn-group-raised:focus:not(:act
.form-group.is-focused .checkbox label:focus { .form-group.is-focused .checkbox label:focus {
color: rgba(0,0,0, .54); color: rgba(0,0,0, .54);
} }
fieldset[disabled] .form-group.is-focused .checkbox label {
color: rgba(0,0,0, 0.26);
}
.checkbox input[type=checkbox] { .checkbox input[type=checkbox] {
opacity: 0; opacity: 0;
position: absolute; position: absolute;
@ -1236,6 +1239,9 @@ fieldset[disabled] .checkbox input[type=checkbox],
.form-group.is-focused .togglebutton label:focus { .form-group.is-focused .togglebutton label:focus {
color: rgba(0,0,0, .54); color: rgba(0,0,0, .54);
} }
fieldset[disabled] .form-group.is-focused .togglebutton label {
color: rgba(0,0,0, 0.26);
}
.togglebutton label input[type=checkbox] { .togglebutton label input[type=checkbox] {
opacity: 0; opacity: 0;
width: 0; width: 0;
@ -1309,6 +1315,9 @@ fieldset[disabled] .checkbox input[type=checkbox],
.form-group.is-focused .radio label:focus { .form-group.is-focused .radio label:focus {
color: rgba(0,0,0, .54); color: rgba(0,0,0, .54);
} }
fieldset[disabled] .form-group.is-focused .radio label {
color: rgba(0,0,0, 0.26);
}
.radio label span { .radio label span {
display: block; display: block;
position: absolute; position: absolute;
@ -2962,9 +2971,9 @@ hr.on-light {
-webkit-box-shadow: 0 1px 6px 0 rgba(0, 0, 0, 0.12), 0 1px 6px 0 rgba(0, 0, 0, 0.12); -webkit-box-shadow: 0 1px 6px 0 rgba(0, 0, 0, 0.12), 0 1px 6px 0 rgba(0, 0, 0, 0.12);
box-shadow: 0 1px 6px 0 rgba(0, 0, 0, 0.12), 0 1px 6px 0 rgba(0, 0, 0, 0.12); box-shadow: 0 1px 6px 0 rgba(0, 0, 0, 0.12), 0 1px 6px 0 rgba(0, 0, 0, 0.12);
height: 0; height: 0;
-webkit-transition: -webkit-transform 0.2s ease-in-out, opacity 0.2s ease-in, height 0 linear 0.2s, padding 0 linear 0.2s, height 0 linear 0.2s; -webkit-transition: -webkit-transform 0.2s ease-in-out, opacity 0.2s ease-in, height 0s linear 0.2s, padding 0s linear 0.2s, height 0s linear 0.2s;
-o-transition: -o-transform 0.2s ease-in-out, opacity 0.2s ease-in, height 0 linear 0.2s, padding 0 linear 0.2s, height 0 linear 0.2s; -o-transition: -o-transform 0.2s ease-in-out, opacity 0.2s ease-in, height 0s linear 0.2s, padding 0s linear 0.2s, height 0s linear 0.2s;
transition: transform 0.2s ease-in-out, opacity 0.2s ease-in, height 0 linear 0.2s, padding 0 linear 0.2s, height 0 linear 0.2s; transition: transform 0.2s ease-in-out, opacity 0.2s ease-in, height 0s linear 0.2s, padding 0s linear 0.2s, height 0s linear 0.2s;
-webkit-transform: translateY(200%); -webkit-transform: translateY(200%);
-ms-transform: translateY(200%); -ms-transform: translateY(200%);
-o-transform: translateY(200%); -o-transform: translateY(200%);
@ -2974,9 +2983,9 @@ hr.on-light {
padding: 14px 15px; padding: 14px 15px;
margin-bottom: 20px; margin-bottom: 20px;
height: auto; height: auto;
-webkit-transition: -webkit-transform 0.2s ease-in-out, opacity 0.2s ease-in, height 0 linear 0.2s, height 0 linear 0.2s; -webkit-transition: -webkit-transform 0.2s ease-in-out, opacity 0.2s ease-in, height 0s linear 0.2s, height 0s linear 0.2s;
-o-transition: -o-transform 0.2s ease-in-out, opacity 0.2s ease-in, height 0 linear 0.2s, height 0 linear 0.2s; -o-transition: -o-transform 0.2s ease-in-out, opacity 0.2s ease-in, height 0s linear 0.2s, height 0s linear 0.2s;
transition: transform 0.2s ease-in-out, opacity 0.2s ease-in, height 0 linear 0.2s, height 0 linear 0.2s; transition: transform 0.2s ease-in-out, opacity 0.2s ease-in, height 0s linear 0.2s, height 0s linear 0.2s;
-webkit-transform: none; -webkit-transform: none;
-ms-transform: none; -ms-transform: none;
-o-transform: none; -o-transform: none;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

373
dist/js/material.js vendored
View File

@ -1,8 +1,8 @@
/* globals jQuery */ /* globals jQuery */
(function($) { (function ($) {
// Selector to select only not already processed elements // Selector to select only not already processed elements
$.expr[":"].notmdproc = function(obj){ $.expr[":"].notmdproc = function (obj) {
if ($(obj).data("mdproc")) { if ($(obj).data("mdproc")) {
return false; return false;
} else { } else {
@ -14,20 +14,45 @@
if (typeof evt.which == "undefined") { if (typeof evt.which == "undefined") {
return true; return true;
} else if (typeof evt.which == "number" && evt.which > 0) { } else if (typeof evt.which == "number" && evt.which > 0) {
return !evt.ctrlKey && !evt.metaKey && !evt.altKey && evt.which != 8 && evt.which != 9; return (
!evt.ctrlKey
&& !evt.metaKey
&& !evt.altKey
&& evt.which != 8 // backspace
&& evt.which != 9 // tab
&& evt.which != 13 // enter
&& evt.which != 16 // shift
&& evt.which != 17 // ctrl
&& evt.which != 20 // caps lock
&& evt.which != 27 // escape
);
} }
return false; return false;
} }
function _addFormGroupFocus(element){ function _addFormGroupFocus(element) {
$(element).closest(".form-group").addClass("is-focused"); var $element = $(element);
if (!$element.prop('disabled')) { // this is showing as undefined on chrome but works fine on firefox??
$element.closest(".form-group").addClass("is-focused");
}
} }
function _removeFormGroupFocus(element){ function _toggleTypeFocus($input) {
$input.closest('label').hover(function () {
var $i = $(this).find('input');
if (!$i.prop('disabled')) { // hack because the _addFormGroupFocus() wasn't identifying the property on chrome
_addFormGroupFocus($i); // need to find the input so we can check disablement
}
}, function () {
_removeFormGroupFocus($(this).find('input'));
});
}
function _removeFormGroupFocus(element) {
$(element).closest(".form-group").removeClass("is-focused"); // remove class from form-group $(element).closest(".form-group").removeClass("is-focused"); // remove class from form-group
} }
$.material = { $.material = {
"options": { "options": {
// These options set what will be started by $.material.init() // These options set what will be started by $.material.init()
"validate": true, "validate": true,
@ -53,191 +78,177 @@
"togglebuttonElements": ".togglebutton > label > input[type=checkbox]", "togglebuttonElements": ".togglebutton > label > input[type=checkbox]",
"radioElements": ".radio > label > input[type=radio]" "radioElements": ".radio > label > input[type=radio]"
}, },
"checkbox": function(selector) { "checkbox": function (selector) {
// Add fake-checkbox to material checkboxes // Add fake-checkbox to material checkboxes
$((selector) ? selector : this.options.checkboxElements) var $input = $((selector) ? selector : this.options.checkboxElements)
.filter(":notmdproc") .filter(":notmdproc")
.data("mdproc", true) .data("mdproc", true)
.after("<span class='checkbox-material'><span class='check'></span></span>"); .after("<span class='checkbox-material'><span class='check'></span></span>");
_toggleTypeFocus($input);
}, },
"togglebutton": function(selector) { "togglebutton": function (selector) {
// Add fake-checkbox to material checkboxes // Add fake-checkbox to material checkboxes
var $input = $((selector) ? selector : this.options.togglebuttonElements) var $input = $((selector) ? selector : this.options.togglebuttonElements)
.filter(":notmdproc") .filter(":notmdproc")
.data("mdproc", true) .data("mdproc", true)
.after("<span class='toggle'></span>"); .after("<span class='toggle'></span>");
var $formGroup = $input.closest(".form-group"); // note that form-group may be grandparent in the case of an input-group _toggleTypeFocus($input);
$formGroup.find('label').hover(function() {
_addFormGroupFocus(this);
}, function() {
_removeFormGroupFocus(this);
});
}, },
"radio": function(selector) { "radio": function (selector) {
// Add fake-radio to material radios // Add fake-radio to material radios
var $input = $((selector) ? selector : this.options.radioElements) var $input = $((selector) ? selector : this.options.radioElements)
.filter(":notmdproc") .filter(":notmdproc")
.data("mdproc", true) .data("mdproc", true)
.after("<span class='circle'></span><span class='check'></span>"); .after("<span class='circle'></span><span class='check'></span>");
_toggleTypeFocus($input);
var $formGroup = $input.closest(".form-group"); // note that form-group may be grandparent in the case of an input-group
$formGroup.find('label').hover(function() {
_addFormGroupFocus(this);
}, function() {
_removeFormGroupFocus(this);
});
}, },
"input": function(selector) { "input": function (selector) {
$((selector) ? selector : this.options.inputElements) $((selector) ? selector : this.options.inputElements)
.filter(":notmdproc") .filter(":notmdproc")
.data("mdproc", true) .data("mdproc", true)
.each( function() { .each(function () {
var $input = $(this); var $input = $(this);
// Requires form-group standard markup (will add it if necessary) // Requires form-group standard markup (will add it if necessary)
var $formGroup = $input.closest(".form-group"); // note that form-group may be grandparent in the case of an input-group var $formGroup = $input.closest(".form-group"); // note that form-group may be grandparent in the case of an input-group
if($formGroup.length === 0){ if ($formGroup.length === 0) {
$input.wrap("<div class='form-group'></div>"); $input.wrap("<div class='form-group'></div>");
$formGroup = $input.closest(".form-group"); // find node after attached (otherwise additional attachments don't work) $formGroup = $input.closest(".form-group"); // find node after attached (otherwise additional attachments don't work)
}
// Legacy - Add hint label if using the old shorthand data-hint attribute on the input
if ($input.attr("data-hint")) {
$input.after("<p class='help-block'>" + $input.attr("data-hint") + "</p>");
$input.removeAttr("data-hint");
}
// Legacy - Change input-sm/lg to form-group-sm/lg instead (preferred standard and simpler css/less variants)
var legacySizes = {
"input-lg": "form-group-lg",
"input-sm": "form-group-sm"
};
$.each( legacySizes, function( legacySize, standardSize ) {
if ($input.hasClass(legacySize)) {
$input.removeClass(legacySize);
$formGroup.addClass(standardSize);
} }
});
// Legacy - Add label-floating if using old shorthand <input class="floating-label" placeholder="foo"> // Legacy - Add hint label if using the old shorthand data-hint attribute on the input
if ($input.hasClass("floating-label")) { if ($input.attr("data-hint")) {
var placeholder = $input.attr("placeholder"); $input.after("<p class='help-block'>" + $input.attr("data-hint") + "</p>");
$input.attr("placeholder", null).removeClass("floating-label"); $input.removeAttr("data-hint");
var id = $input.attr("id");
var forAttribute = "";
if(id) {
forAttribute = "for='" + id + "'";
} }
$formGroup.addClass("label-floating");
$input.after("<label " + forAttribute + "class='control-label'>" + placeholder + "</label>");
}
// Set as empty if is empty (damn I must improve this...) // Legacy - Change input-sm/lg to form-group-sm/lg instead (preferred standard and simpler css/less variants)
if ($input.val() === null || $input.val() == "undefined" || $input.val() === "") { var legacySizes = {
$formGroup.addClass("is-empty"); "input-lg": "form-group-lg",
} "input-sm": "form-group-sm"
};
$.each(legacySizes, function (legacySize, standardSize) {
if ($input.hasClass(legacySize)) {
$input.removeClass(legacySize);
$formGroup.addClass(standardSize);
}
});
// Legacy - Add label-floating if using old shorthand <input class="floating-label" placeholder="foo">
if ($input.hasClass("floating-label")) {
var placeholder = $input.attr("placeholder");
$input.attr("placeholder", null).removeClass("floating-label");
var id = $input.attr("id");
var forAttribute = "";
if (id) {
forAttribute = "for='" + id + "'";
}
$formGroup.addClass("label-floating");
$input.after("<label " + forAttribute + "class='control-label'>" + placeholder + "</label>");
}
// Set as empty if is empty (damn I must improve this...)
if ($input.val() === null || $input.val() == "undefined" || $input.val() === "") {
$formGroup.addClass("is-empty");
}
// Add at the end of the form-group // Add at the end of the form-group
$formGroup.append("<span class='material-input'></span>"); $formGroup.append("<span class='material-input'></span>");
// Support for file input // Support for file input
if ($formGroup.find("input[type=file]").length > 0) { if ($formGroup.find("input[type=file]").length > 0) {
$formGroup.addClass("is-fileinput"); $formGroup.addClass("is-fileinput");
} }
}); });
}, },
"attachInputEventHandlers": function() { "attachInputEventHandlers": function () {
var validate = this.options.validate; var validate = this.options.validate;
// checkboxes didn't appear to bubble to the document, so we'll bind these directly
$(".form-group .checkbox label").hover(function() {
_addFormGroupFocus(this);
}, function() {
_removeFormGroupFocus(this);
});
$(document) $(document)
.on("change", ".checkbox input[type=checkbox]", function() { $(this).blur(); }) .on("change", ".checkbox input[type=checkbox]", function () {
.on("keydown paste", ".form-control", function(e) { $(this).blur();
if(_isChar(e)) { })
$(this).closest(".form-group").removeClass("is-empty"); .on("keydown paste", ".form-control", function (e) {
} if (_isChar(e)) {
}) $(this).closest(".form-group").removeClass("is-empty");
.on("keyup change", ".form-control", function() { }
var $input = $(this); })
var $formGroup = $input.closest(".form-group"); .on("keyup change", ".form-control", function () {
var isValid = (typeof $input[0].checkValidity === "undefined" || $input[0].checkValidity()); var $input = $(this);
var $formGroup = $input.closest(".form-group");
var isValid = (typeof $input[0].checkValidity === "undefined" || $input[0].checkValidity());
if ($input.val() === "" && isValid) { if ($input.val() === "" && isValid) {
$formGroup.addClass("is-empty"); $formGroup.addClass("is-empty");
}
else {
$formGroup.removeClass("is-empty");
}
// Validation events do not bubble, so they must be attached directly to the input: http://jsfiddle.net/PEpRM/1/
// Further, even the bind method is being caught, but since we are already calling #checkValidity here, just alter
// the form-group on change.
//
// NOTE: I'm not sure we should be intervening regarding validation, this seems better as a README and snippet of code.
// BUT, I've left it here for backwards compatibility.
if(validate) {
if (isValid) {
$formGroup.removeClass("has-error");
} }
else { else {
$formGroup.addClass("has-error"); $formGroup.removeClass("is-empty");
} }
}
})
.on("focus", ".form-control, .form-group.is-fileinput", function() {
_addFormGroupFocus(this);
})
.on("blur", ".form-control, .form-group.is-fileinput", function() {
_removeFormGroupFocus(this);
})
// make sure empty is added back when there is a programmatic value change.
// NOTE: programmatic changing of value using $.val() must trigger the change event i.e. $.val('x').trigger('change')
.on("change", ".form-group input", function() {
var $input = $(this);
if($input.attr("type") == "file") {
return;
}
var $formGroup = $input.closest(".form-group"); // Validation events do not bubble, so they must be attached directly to the input: http://jsfiddle.net/PEpRM/1/
var value = $input.val(); // Further, even the bind method is being caught, but since we are already calling #checkValidity here, just alter
if (value) { // the form-group on change.
$formGroup.removeClass("is-empty"); //
} else { // NOTE: I'm not sure we should be intervening regarding validation, this seems better as a README and snippet of code.
$formGroup.addClass("is-empty"); // BUT, I've left it here for backwards compatibility.
} if (validate) {
}) if (isValid) {
// set the fileinput readonly field with the name of the file $formGroup.removeClass("has-error");
.on("change", ".form-group.is-fileinput input[type='file']", function() { }
var $input = $(this); else {
var $formGroup = $input.closest(".form-group"); $formGroup.addClass("has-error");
var value = ""; }
$.each(this.files, function(i, file) { }
value += file.name + ", "; })
.on("focus", ".form-control, .form-group.is-fileinput", function () {
_addFormGroupFocus(this);
})
.on("blur", ".form-control, .form-group.is-fileinput", function () {
_removeFormGroupFocus(this);
})
// make sure empty is added back when there is a programmatic value change.
// NOTE: programmatic changing of value using $.val() must trigger the change event i.e. $.val('x').trigger('change')
.on("change", ".form-group input", function () {
var $input = $(this);
if ($input.attr("type") == "file") {
return;
}
var $formGroup = $input.closest(".form-group");
var value = $input.val();
if (value) {
$formGroup.removeClass("is-empty");
} else {
$formGroup.addClass("is-empty");
}
})
// set the fileinput readonly field with the name of the file
.on("change", ".form-group.is-fileinput input[type='file']", function () {
var $input = $(this);
var $formGroup = $input.closest(".form-group");
var value = "";
$.each(this.files, function (i, file) {
value += file.name + ", ";
});
value = value.substring(0, value.length - 2);
if (value) {
$formGroup.removeClass("is-empty");
} else {
$formGroup.addClass("is-empty");
}
$formGroup.find("input.form-control[readonly]").val(value);
}); });
value = value.substring(0, value.length - 2);
if (value) {
$formGroup.removeClass("is-empty");
} else {
$formGroup.addClass("is-empty");
}
$formGroup.find("input.form-control[readonly]").val(value);
});
}, },
"ripples": function(selector) { "ripples": function (selector) {
$((selector) ? selector : this.options.withRipples).ripples(); $((selector) ? selector : this.options.withRipples).ripples();
}, },
"autofill": function() { "autofill": function () {
// This part of code will detect autofill when the page is loading (username and password inputs for example) // This part of code will detect autofill when the page is loading (username and password inputs for example)
var loading = setInterval(function() { var loading = setInterval(function () {
$("input[type!=checkbox]").each(function() { $("input[type!=checkbox]").each(function () {
var $this = $(this); var $this = $(this);
if ($this.val() && $this.val() !== $this.attr("value")) { if ($this.val() && $this.val() !== $this.attr("value")) {
$this.trigger("change"); $this.trigger("change");
@ -246,30 +257,30 @@
}, 100); }, 100);
// After 10 seconds we are quite sure all the needed inputs are autofilled then we can stop checking them // After 10 seconds we are quite sure all the needed inputs are autofilled then we can stop checking them
setTimeout(function() { setTimeout(function () {
clearInterval(loading); clearInterval(loading);
}, 10000); }, 10000);
}, },
"attachAutofillEventHandlers": function() { "attachAutofillEventHandlers": function () {
// Listen on inputs of the focused form (because user can select from the autofill dropdown only when the input has focus) // Listen on inputs of the focused form (because user can select from the autofill dropdown only when the input has focus)
var focused; var focused;
$(document) $(document)
.on("focus", "input", function() { .on("focus", "input", function () {
var $inputs = $(this).parents("form").find("input").not("[type=file]"); var $inputs = $(this).parents("form").find("input").not("[type=file]");
focused = setInterval(function() { focused = setInterval(function () {
$inputs.each(function() { $inputs.each(function () {
var $this = $(this); var $this = $(this);
if ($this.val() !== $this.attr("value")) { if ($this.val() !== $this.attr("value")) {
$this.trigger("change"); $this.trigger("change");
} }
}); });
}, 100); }, 100);
}) })
.on("blur", ".form-group input", function() { .on("blur", ".form-group input", function () {
clearInterval(focused); clearInterval(focused);
}); });
}, },
"init": function(options) { "init": function (options) {
this.options = $.extend({}, this.options, options); this.options = $.extend({}, this.options, options);
var $document = $(document); var $document = $(document);
@ -296,27 +307,27 @@
if (document.arrive && this.options.arrive) { if (document.arrive && this.options.arrive) {
if ($.fn.ripples && this.options.ripples) { if ($.fn.ripples && this.options.ripples) {
$document.arrive(this.options.withRipples, function() { $document.arrive(this.options.withRipples, function () {
$.material.ripples($(this)); $.material.ripples($(this));
}); });
} }
if (this.options.input) { if (this.options.input) {
$document.arrive(this.options.inputElements, function() { $document.arrive(this.options.inputElements, function () {
$.material.input($(this)); $.material.input($(this));
}); });
} }
if (this.options.checkbox) { if (this.options.checkbox) {
$document.arrive(this.options.checkboxElements, function() { $document.arrive(this.options.checkboxElements, function () {
$.material.checkbox($(this)); $.material.checkbox($(this));
}); });
} }
if (this.options.radio) { if (this.options.radio) {
$document.arrive(this.options.radioElements, function() { $document.arrive(this.options.radioElements, function () {
$.material.radio($(this)); $.material.radio($(this));
}); });
} }
if (this.options.togglebutton) { if (this.options.togglebutton) {
$document.arrive(this.options.togglebuttonElements, function() { $document.arrive(this.options.togglebuttonElements, function () {
$.material.togglebutton($(this)); $.material.togglebutton($(this));
}); });
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -29,7 +29,7 @@ h5, h6{
} }
a, a:hover, a:focus { a, a:hover, a:focus {
color: @brand-primary; color: @link-color;
& .material-icons { & .material-icons {
vertical-align: middle; vertical-align: middle;

View File

@ -31,7 +31,7 @@ h5, h6{
} }
a, a:hover, a:focus { a, a:hover, a:focus {
color: $brand-primary; color: $link-color;
& .material-icons { & .material-icons {
vertical-align: middle; vertical-align: middle;

View File

@ -10,6 +10,11 @@
&:focus { &:focus {
color: $mdb-label-color-toggle-focus; color: $mdb-label-color-toggle-focus;
} }
// correct the above focus color for disabled items
fieldset[disabled] & {
color: $mdb-label-color;
}
} }
} }

View File

@ -13,7 +13,7 @@
// Animation // Animation
height: 0; height: 0;
transition: transform 0.2s ease-in-out, opacity 0.2s ease-in, height 0 linear 0.2s, padding 0 linear 0.2s, height 0 linear 0.2s; transition: transform 0.2s ease-in-out, opacity 0.2s ease-in, height 0s linear 0.2s, padding 0s linear 0.2s, height 0s linear 0.2s;
transform: translateY(200%); transform: translateY(200%);
} }
@ -24,7 +24,7 @@
// Animation // Animation
height: auto; height: auto;
transition: transform 0.2s ease-in-out, opacity 0.2s ease-in, height 0 linear 0.2s, height 0 linear 0.2s; transition: transform 0.2s ease-in-out, opacity 0.2s ease-in, height 0s linear 0.2s, height 0s linear 0.2s;
transform: none; transform: none;
} }

View File

@ -1,4 +1,5 @@
{ {
"laxbreak": true,
"bitwise": true, "bitwise": true,
"camelcase": true, "camelcase": true,
"curly": true, "curly": true,

View File

@ -1,8 +1,8 @@
/* globals jQuery */ /* globals jQuery */
(function($) { (function ($) {
// Selector to select only not already processed elements // Selector to select only not already processed elements
$.expr[":"].notmdproc = function(obj){ $.expr[":"].notmdproc = function (obj) {
if ($(obj).data("mdproc")) { if ($(obj).data("mdproc")) {
return false; return false;
} else { } else {
@ -14,7 +14,8 @@
if (typeof evt.which == "undefined") { if (typeof evt.which == "undefined") {
return true; return true;
} else if (typeof evt.which == "number" && evt.which > 0) { } else if (typeof evt.which == "number" && evt.which > 0) {
return !evt.ctrlKey return (
!evt.ctrlKey
&& !evt.metaKey && !evt.metaKey
&& !evt.altKey && !evt.altKey
&& evt.which != 8 // backspace && evt.which != 8 // backspace
@ -23,34 +24,35 @@
&& evt.which != 16 // shift && evt.which != 16 // shift
&& evt.which != 17 // ctrl && evt.which != 17 // ctrl
&& evt.which != 20 // caps lock && evt.which != 20 // caps lock
&& evt.which != 27; // escape && evt.which != 27 // escape
);
} }
return false; return false;
} }
function _addFormGroupFocus(element){ function _addFormGroupFocus(element) {
var $element = $(element); var $element = $(element);
if (!$element.prop('disabled')) { // this is showing as undefined on chrome but works fine on firefox?? if (!$element.prop('disabled')) { // this is showing as undefined on chrome but works fine on firefox??
$element.closest(".form-group").addClass("is-focused"); $element.closest(".form-group").addClass("is-focused");
} }
} }
function _toggleTypeFocus($input){ function _toggleTypeFocus($input) {
$input.closest('label').hover(function() { $input.closest('label').hover(function () {
var $i = $(this).find('input'); var $i = $(this).find('input');
if (!$i.prop('disabled')) { // hack because the _addFormGroupFocus() wasn't identifying the property on chrome if (!$i.prop('disabled')) { // hack because the _addFormGroupFocus() wasn't identifying the property on chrome
_addFormGroupFocus($i); // need to find the input so we can check disablement _addFormGroupFocus($i); // need to find the input so we can check disablement
} }
}, function() { }, function () {
_removeFormGroupFocus($(this).find('input')); _removeFormGroupFocus($(this).find('input'));
}); });
} }
function _removeFormGroupFocus(element){ function _removeFormGroupFocus(element) {
$(element).closest(".form-group").removeClass("is-focused"); // remove class from form-group $(element).closest(".form-group").removeClass("is-focused"); // remove class from form-group
} }
$.material = { $.material = {
"options": { "options": {
// These options set what will be started by $.material.init() // These options set what will be started by $.material.init()
"validate": true, "validate": true,
@ -76,175 +78,177 @@
"togglebuttonElements": ".togglebutton > label > input[type=checkbox]", "togglebuttonElements": ".togglebutton > label > input[type=checkbox]",
"radioElements": ".radio > label > input[type=radio]" "radioElements": ".radio > label > input[type=radio]"
}, },
"checkbox": function(selector) { "checkbox": function (selector) {
// Add fake-checkbox to material checkboxes // Add fake-checkbox to material checkboxes
var $input = $((selector) ? selector : this.options.checkboxElements) var $input = $((selector) ? selector : this.options.checkboxElements)
.filter(":notmdproc") .filter(":notmdproc")
.data("mdproc", true) .data("mdproc", true)
.after("<span class='checkbox-material'><span class='check'></span></span>"); .after("<span class='checkbox-material'><span class='check'></span></span>");
_toggleTypeFocus($input); _toggleTypeFocus($input);
}, },
"togglebutton": function(selector) { "togglebutton": function (selector) {
// Add fake-checkbox to material checkboxes // Add fake-checkbox to material checkboxes
var $input = $((selector) ? selector : this.options.togglebuttonElements) var $input = $((selector) ? selector : this.options.togglebuttonElements)
.filter(":notmdproc") .filter(":notmdproc")
.data("mdproc", true) .data("mdproc", true)
.after("<span class='toggle'></span>"); .after("<span class='toggle'></span>");
_toggleTypeFocus($input); _toggleTypeFocus($input);
}, },
"radio": function(selector) { "radio": function (selector) {
// Add fake-radio to material radios // Add fake-radio to material radios
var $input = $((selector) ? selector : this.options.radioElements) var $input = $((selector) ? selector : this.options.radioElements)
.filter(":notmdproc") .filter(":notmdproc")
.data("mdproc", true) .data("mdproc", true)
.after("<span class='circle'></span><span class='check'></span>"); .after("<span class='circle'></span><span class='check'></span>");
_toggleTypeFocus($input); _toggleTypeFocus($input);
}, },
"input": function(selector) { "input": function (selector) {
$((selector) ? selector : this.options.inputElements) $((selector) ? selector : this.options.inputElements)
.filter(":notmdproc") .filter(":notmdproc")
.data("mdproc", true) .data("mdproc", true)
.each( function() { .each(function () {
var $input = $(this); var $input = $(this);
// Requires form-group standard markup (will add it if necessary) // Requires form-group standard markup (will add it if necessary)
var $formGroup = $input.closest(".form-group"); // note that form-group may be grandparent in the case of an input-group var $formGroup = $input.closest(".form-group"); // note that form-group may be grandparent in the case of an input-group
if($formGroup.length === 0){ if ($formGroup.length === 0) {
$input.wrap("<div class='form-group'></div>"); $input.wrap("<div class='form-group'></div>");
$formGroup = $input.closest(".form-group"); // find node after attached (otherwise additional attachments don't work) $formGroup = $input.closest(".form-group"); // find node after attached (otherwise additional attachments don't work)
}
// Legacy - Add hint label if using the old shorthand data-hint attribute on the input
if ($input.attr("data-hint")) {
$input.after("<p class='help-block'>" + $input.attr("data-hint") + "</p>");
$input.removeAttr("data-hint");
}
// Legacy - Change input-sm/lg to form-group-sm/lg instead (preferred standard and simpler css/less variants)
var legacySizes = {
"input-lg": "form-group-lg",
"input-sm": "form-group-sm"
};
$.each( legacySizes, function( legacySize, standardSize ) {
if ($input.hasClass(legacySize)) {
$input.removeClass(legacySize);
$formGroup.addClass(standardSize);
} }
});
// Legacy - Add label-floating if using old shorthand <input class="floating-label" placeholder="foo"> // Legacy - Add hint label if using the old shorthand data-hint attribute on the input
if ($input.hasClass("floating-label")) { if ($input.attr("data-hint")) {
var placeholder = $input.attr("placeholder"); $input.after("<p class='help-block'>" + $input.attr("data-hint") + "</p>");
$input.attr("placeholder", null).removeClass("floating-label"); $input.removeAttr("data-hint");
var id = $input.attr("id");
var forAttribute = "";
if(id) {
forAttribute = "for='" + id + "'";
} }
$formGroup.addClass("label-floating");
$input.after("<label " + forAttribute + "class='control-label'>" + placeholder + "</label>");
}
// Set as empty if is empty (damn I must improve this...) // Legacy - Change input-sm/lg to form-group-sm/lg instead (preferred standard and simpler css/less variants)
if ($input.val() === null || $input.val() == "undefined" || $input.val() === "") { var legacySizes = {
$formGroup.addClass("is-empty"); "input-lg": "form-group-lg",
} "input-sm": "form-group-sm"
};
$.each(legacySizes, function (legacySize, standardSize) {
if ($input.hasClass(legacySize)) {
$input.removeClass(legacySize);
$formGroup.addClass(standardSize);
}
});
// Legacy - Add label-floating if using old shorthand <input class="floating-label" placeholder="foo">
if ($input.hasClass("floating-label")) {
var placeholder = $input.attr("placeholder");
$input.attr("placeholder", null).removeClass("floating-label");
var id = $input.attr("id");
var forAttribute = "";
if (id) {
forAttribute = "for='" + id + "'";
}
$formGroup.addClass("label-floating");
$input.after("<label " + forAttribute + "class='control-label'>" + placeholder + "</label>");
}
// Set as empty if is empty (damn I must improve this...)
if ($input.val() === null || $input.val() == "undefined" || $input.val() === "") {
$formGroup.addClass("is-empty");
}
// Add at the end of the form-group // Add at the end of the form-group
$formGroup.append("<span class='material-input'></span>"); $formGroup.append("<span class='material-input'></span>");
// Support for file input // Support for file input
if ($formGroup.find("input[type=file]").length > 0) { if ($formGroup.find("input[type=file]").length > 0) {
$formGroup.addClass("is-fileinput"); $formGroup.addClass("is-fileinput");
} }
}); });
}, },
"attachInputEventHandlers": function() { "attachInputEventHandlers": function () {
var validate = this.options.validate; var validate = this.options.validate;
$(document) $(document)
.on("change", ".checkbox input[type=checkbox]", function() { $(this).blur(); }) .on("change", ".checkbox input[type=checkbox]", function () {
.on("keydown paste", ".form-control", function(e) { $(this).blur();
if(_isChar(e)) { })
$(this).closest(".form-group").removeClass("is-empty"); .on("keydown paste", ".form-control", function (e) {
} if (_isChar(e)) {
}) $(this).closest(".form-group").removeClass("is-empty");
.on("keyup change", ".form-control", function() { }
var $input = $(this); })
var $formGroup = $input.closest(".form-group"); .on("keyup change", ".form-control", function () {
var isValid = (typeof $input[0].checkValidity === "undefined" || $input[0].checkValidity()); var $input = $(this);
var $formGroup = $input.closest(".form-group");
var isValid = (typeof $input[0].checkValidity === "undefined" || $input[0].checkValidity());
if ($input.val() === "" && isValid) { if ($input.val() === "" && isValid) {
$formGroup.addClass("is-empty"); $formGroup.addClass("is-empty");
}
else {
$formGroup.removeClass("is-empty");
}
// Validation events do not bubble, so they must be attached directly to the input: http://jsfiddle.net/PEpRM/1/
// Further, even the bind method is being caught, but since we are already calling #checkValidity here, just alter
// the form-group on change.
//
// NOTE: I'm not sure we should be intervening regarding validation, this seems better as a README and snippet of code.
// BUT, I've left it here for backwards compatibility.
if(validate) {
if (isValid) {
$formGroup.removeClass("has-error");
} }
else { else {
$formGroup.addClass("has-error"); $formGroup.removeClass("is-empty");
} }
}
})
.on("focus", ".form-control, .form-group.is-fileinput", function() {
_addFormGroupFocus(this);
})
.on("blur", ".form-control, .form-group.is-fileinput", function() {
_removeFormGroupFocus(this);
})
// make sure empty is added back when there is a programmatic value change.
// NOTE: programmatic changing of value using $.val() must trigger the change event i.e. $.val('x').trigger('change')
.on("change", ".form-group input", function() {
var $input = $(this);
if($input.attr("type") == "file") {
return;
}
var $formGroup = $input.closest(".form-group"); // Validation events do not bubble, so they must be attached directly to the input: http://jsfiddle.net/PEpRM/1/
var value = $input.val(); // Further, even the bind method is being caught, but since we are already calling #checkValidity here, just alter
if (value) { // the form-group on change.
$formGroup.removeClass("is-empty"); //
} else { // NOTE: I'm not sure we should be intervening regarding validation, this seems better as a README and snippet of code.
$formGroup.addClass("is-empty"); // BUT, I've left it here for backwards compatibility.
} if (validate) {
}) if (isValid) {
// set the fileinput readonly field with the name of the file $formGroup.removeClass("has-error");
.on("change", ".form-group.is-fileinput input[type='file']", function() { }
var $input = $(this); else {
var $formGroup = $input.closest(".form-group"); $formGroup.addClass("has-error");
var value = ""; }
$.each(this.files, function(i, file) { }
value += file.name + ", "; })
.on("focus", ".form-control, .form-group.is-fileinput", function () {
_addFormGroupFocus(this);
})
.on("blur", ".form-control, .form-group.is-fileinput", function () {
_removeFormGroupFocus(this);
})
// make sure empty is added back when there is a programmatic value change.
// NOTE: programmatic changing of value using $.val() must trigger the change event i.e. $.val('x').trigger('change')
.on("change", ".form-group input", function () {
var $input = $(this);
if ($input.attr("type") == "file") {
return;
}
var $formGroup = $input.closest(".form-group");
var value = $input.val();
if (value) {
$formGroup.removeClass("is-empty");
} else {
$formGroup.addClass("is-empty");
}
})
// set the fileinput readonly field with the name of the file
.on("change", ".form-group.is-fileinput input[type='file']", function () {
var $input = $(this);
var $formGroup = $input.closest(".form-group");
var value = "";
$.each(this.files, function (i, file) {
value += file.name + ", ";
});
value = value.substring(0, value.length - 2);
if (value) {
$formGroup.removeClass("is-empty");
} else {
$formGroup.addClass("is-empty");
}
$formGroup.find("input.form-control[readonly]").val(value);
}); });
value = value.substring(0, value.length - 2);
if (value) {
$formGroup.removeClass("is-empty");
} else {
$formGroup.addClass("is-empty");
}
$formGroup.find("input.form-control[readonly]").val(value);
});
}, },
"ripples": function(selector) { "ripples": function (selector) {
$((selector) ? selector : this.options.withRipples).ripples(); $((selector) ? selector : this.options.withRipples).ripples();
}, },
"autofill": function() { "autofill": function () {
// This part of code will detect autofill when the page is loading (username and password inputs for example) // This part of code will detect autofill when the page is loading (username and password inputs for example)
var loading = setInterval(function() { var loading = setInterval(function () {
$("input[type!=checkbox]").each(function() { $("input[type!=checkbox]").each(function () {
var $this = $(this); var $this = $(this);
if ($this.val() && $this.val() !== $this.attr("value")) { if ($this.val() && $this.val() !== $this.attr("value")) {
$this.trigger("change"); $this.trigger("change");
@ -253,30 +257,30 @@
}, 100); }, 100);
// After 10 seconds we are quite sure all the needed inputs are autofilled then we can stop checking them // After 10 seconds we are quite sure all the needed inputs are autofilled then we can stop checking them
setTimeout(function() { setTimeout(function () {
clearInterval(loading); clearInterval(loading);
}, 10000); }, 10000);
}, },
"attachAutofillEventHandlers": function() { "attachAutofillEventHandlers": function () {
// Listen on inputs of the focused form (because user can select from the autofill dropdown only when the input has focus) // Listen on inputs of the focused form (because user can select from the autofill dropdown only when the input has focus)
var focused; var focused;
$(document) $(document)
.on("focus", "input", function() { .on("focus", "input", function () {
var $inputs = $(this).parents("form").find("input").not("[type=file]"); var $inputs = $(this).parents("form").find("input").not("[type=file]");
focused = setInterval(function() { focused = setInterval(function () {
$inputs.each(function() { $inputs.each(function () {
var $this = $(this); var $this = $(this);
if ($this.val() !== $this.attr("value")) { if ($this.val() !== $this.attr("value")) {
$this.trigger("change"); $this.trigger("change");
} }
}); });
}, 100); }, 100);
}) })
.on("blur", ".form-group input", function() { .on("blur", ".form-group input", function () {
clearInterval(focused); clearInterval(focused);
}); });
}, },
"init": function(options) { "init": function (options) {
this.options = $.extend({}, this.options, options); this.options = $.extend({}, this.options, options);
var $document = $(document); var $document = $(document);
@ -303,27 +307,27 @@
if (document.arrive && this.options.arrive) { if (document.arrive && this.options.arrive) {
if ($.fn.ripples && this.options.ripples) { if ($.fn.ripples && this.options.ripples) {
$document.arrive(this.options.withRipples, function() { $document.arrive(this.options.withRipples, function () {
$.material.ripples($(this)); $.material.ripples($(this));
}); });
} }
if (this.options.input) { if (this.options.input) {
$document.arrive(this.options.inputElements, function() { $document.arrive(this.options.inputElements, function () {
$.material.input($(this)); $.material.input($(this));
}); });
} }
if (this.options.checkbox) { if (this.options.checkbox) {
$document.arrive(this.options.checkboxElements, function() { $document.arrive(this.options.checkboxElements, function () {
$.material.checkbox($(this)); $.material.checkbox($(this));
}); });
} }
if (this.options.radio) { if (this.options.radio) {
$document.arrive(this.options.radioElements, function() { $document.arrive(this.options.radioElements, function () {
$.material.radio($(this)); $.material.radio($(this));
}); });
} }
if (this.options.togglebutton) { if (this.options.togglebutton) {
$document.arrive(this.options.togglebuttonElements, function() { $document.arrive(this.options.togglebuttonElements, function () {
$.material.togglebutton($(this)); $.material.togglebutton($(this));
}); });
} }