This commit is contained in:
Jesús Pérez 2015-01-24 01:08:11 +00:00
commit 36b130d4bf
11 changed files with 628 additions and 9 deletions

View File

@ -1,10 +1,23 @@
var COMMONJS_BANNER = "// This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.\n";
var COMMONJS_HEAD = "\nmodule.exports = function(jQuery) {\n";
var COMMONJS_FOOT = "\n};\n";
module.exports = function(grunt) {
"use strict";
require("load-grunt-tasks")(grunt);
grunt.initConfig({
function createCommonjsCode (srcPath, destPath) {
var finalCode = COMMONJS_BANNER;
finalCode += COMMONJS_HEAD;
finalCode += grunt.file.read(srcPath);
finalCode += COMMONJS_FOOT;
grunt.file.write(destPath, finalCode);
}
grunt.initConfig({
// Compile less to .css
// Compile less to .min.css
@ -235,7 +248,7 @@ module.exports = function(grunt) {
});
grunt.registerTask("default", ["material", "ripples"]);
grunt.registerTask("default", ["material", "ripples", "commonjs"]);
grunt.registerTask("material", [
"material:less",
@ -267,7 +280,15 @@ module.exports = function(grunt) {
"copy:ripples",
"uglify:ripples"
]);
grunt.registerTask("commonjs", "Generate CommonJS entrypoint module in dist dir.", function () {
var distPath = "dist/js/";
var npmPath = distPath + "npm/";
createCommonjsCode(distPath + "material.js", npmPath + "material.js");
createCommonjsCode(distPath + "ripples.js", npmPath + "bootstrap-material-ripples/ripples.js");
});
grunt.registerTask("build", function(target) {
var buildType = "default";
if (target && target === "scss") {

View File

@ -17,7 +17,10 @@ You may install this theme using Bower or Meteor:
- Bower : `bower install bootstrap-material-design`
- Meteor: `meteor add fezvrasta:bootstrap-material-design`
- NPM:
- Material.js: `npm i bootstrap-material`
- Ripples.js: `npm i bootstrap-material-ripples`
If you prefer, you can include this framework in your project using our official CDN:
- [Bootstrap Material Design on CDNJS.com](https://cdnjs.com/libraries/bootstrap-material-design)
@ -189,3 +192,19 @@ Read more about [selectize.js](http://brianreavis.github.io/selectize.js/).
## Compatibility
Currently, Material Design for Bootstrap supports Google Chrome (tested v37+), Mozilla Firefox (tested 30+), and Internet Explorer (tested 11+). Mobile browsers are not currently tested but they may work.
###Browserify
This library is [CommonJS](http://www.commonjs.org/) compatible, so you can use it this way:
```javascript
var jquery = require('jquery');
require('bootstrap')(jquery);
require('bootstrap-material')(jquery);
require('bootstrap-material-ripples')(jquery);
console.log('Is Bootstrap loaded?');
console.log(typeof jquery().modal === 'function');
console.log('Is Bootstrap Material loaded?');
console.log(typeof jquery.material === 'object');
```
NOTE: Until this [PR](https://github.com/twbs/bootstrap/pull/15640) be accepted into the main Bootstrap project this fork must be used: [https://github.com/eface2face/bootstrap](https://github.com/eface2face/bootstrap)

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

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
Ripples.js library of the Bootstrap theme "Material Design". Please, visit the [repository](https://github.com/FezVrasta/bootstrap-material-design#ripplesjs) to know more about it.

View File

@ -0,0 +1,22 @@
{
"name": "bootstrap-material-ripples",
"version": "0.2.0",
"description": "Material Design for Bootstrap 3 (Ripples.js component)",
"main": "./ripples",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://github.com/FezVrasta/bootstrap-material-design.git"
},
"author": {
"name": "Federico Zivolo"
},
"license": "https://github.com/FezVrasta/bootstrap-material-design/blob/master/LICENSE.md",
"bugs": {
"url": "https://github.com/FezVrasta/bootstrap-material-design/issues"
},
"homepage": "https://github.com/FezVrasta/bootstrap-material-design",
"devDependencies": {}
}

View File

@ -0,0 +1,329 @@
// This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.
module.exports = function(jQuery) {
/* Copyright 2014+, Federico Zivolo, LICENSE at https://github.com/FezVrasta/bootstrap-material-design/blob/master/LICENSE.md */
/* globals jQuery, navigator */
(function($, window, document, undefined) {
"use strict";
/**
* Define the name of the plugin
*/
var ripples = "ripples";
/**
* Get an instance of the plugin
*/
var self = null;
/**
* Define the defaults of the plugin
*/
var defaults = {};
/**
* Create the main plugin function
*/
function Ripples(element, options) {
self = this;
this.element = $(element);
this.options = $.extend({}, defaults, options);
this._defaults = defaults;
this._name = ripples;
this.init();
}
/**
* Initialize the plugin
*/
Ripples.prototype.init = function() {
var $element = this.element;
$element.on("mousedown touchstart", function(event) {
/**
* Verify if the user is just touching on a device and return if so
*/
if(self.isTouch() && event.type === "mousedown") {
return false;
}
/**
* Verify if the current element already has a ripple wrapper element and
* creates if it doesn't
*/
if(!($element.find(".ripple-wrapper").length)) {
$element.append("<div class=\"ripple-wrapper\"></div>");
}
/**
* Find the ripple wrapper
*/
var $wrapper = $element.children(".ripple-wrapper");
/**
* Get relY and relX positions
*/
var relY = self.getRelY($wrapper, event);
var relX = self.getRelX($wrapper, event);
/**
* If relY and/or relX are false, return the event
*/
if(!relY && !relX) {
return;
}
/**
* Get the ripple color
*/
var rippleColor = self.getRipplesColor($element);
/**
* Create the ripple element
*/
var $ripple = $("<div></div>");
$ripple
.addClass("ripple")
.css({
"left": relX,
"top": relY,
"background-color": rippleColor
});
/**
* Append the ripple to the wrapper
*/
$wrapper.append($ripple);
/**
* Make sure the ripple has the styles applied (ugly hack but it works)
*/
(function() { return window.getComputedStyle($ripple[0]).opacity; })();
/**
* Turn on the ripple animation
*/
self.rippleOn($element, $ripple);
/**
* Call the rippleEnd function when the transition "on" ends
*/
setTimeout(function() {
self.rippleEnd($ripple);
}, 500);
/**
* Detect when the user leaves the element
*/
$element.on("mouseup mouseleave touchend", function() {
$ripple.data("mousedown", "off");
if($ripple.data("animating") === "off") {
self.rippleOut($ripple);
}
});
});
};
/**
* Get the new size based on the element height/width and the ripple width
*/
Ripples.prototype.getNewSize = function($element, $ripple) {
return (Math.max($element.outerWidth(), $element.outerHeight()) / $ripple.outerWidth()) * 2.5;
};
/**
* Get the relX
*/
Ripples.prototype.getRelX = function($wrapper, event) {
var wrapperOffset = $wrapper.offset();
if(!self.isTouch()) {
/**
* Get the mouse position relative to the ripple wrapper
*/
return event.pageX - wrapperOffset.left;
} else {
/**
* Make sure the user is using only one finger and then get the touch
* position relative to the ripple wrapper
*/
event = event.originalEvent;
if(event.touches.length !== 1) {
return event.touches[0].pageX - wrapperOffset.left;
}
return false;
}
};
/**
* Get the relY
*/
Ripples.prototype.getRelY = function($wrapper, event) {
var wrapperOffset = $wrapper.offset();
if(!self.isTouch()) {
/**
* Get the mouse position relative to the ripple wrapper
*/
return event.pageY - wrapperOffset.top;
} else {
/**
* Make sure the user is using only one finger and then get the touch
* position relative to the ripple wrapper
*/
event = event.originalEvent;
if(event.touches.length !== 1) {
return event.touches[0].pageY - wrapperOffset.top;
}
return false;
}
};
/**
* Get the ripple color
*/
Ripples.prototype.getRipplesColor = function($element) {
var color = $element.data("ripple-color") ? $element.data("ripple-color") : window.getComputedStyle($element[0]).color;
return color;
};
/**
* Verify if the client browser has transistion support
*/
Ripples.prototype.hasTransitionSupport = function() {
var thisBody = document.body || document.documentElement;
var thisStyle = thisBody.style;
var support = (
thisStyle.transition !== undefined ||
thisStyle.WebkitTransition !== undefined ||
thisStyle.MozTransition !== undefined ||
thisStyle.MsTransition !== undefined ||
thisStyle.OTransition !== undefined
);
return support;
};
/**
* Verify if the client is using a mobile device
*/
Ripples.prototype.isTouch = function() {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
};
/**
* End the animation of the ripple
*/
Ripples.prototype.rippleEnd = function($ripple) {
$ripple.data("animating", "off");
if($ripple.data("mousedown") === "off") {
self.rippleOut($ripple);
}
};
/**
* Turn off the ripple effect
*/
Ripples.prototype.rippleOut = function($ripple) {
$ripple.off();
if(self.hasTransitionSupport()) {
$ripple.addClass("ripple-out");
} else {
$ripple.animate({"opacity": 0}, 100, function() {
$ripple.trigger("transitionend");
});
}
$ripple.on("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", function() {
$ripple.remove();
});
};
/**
* Turn on the ripple effect
*/
Ripples.prototype.rippleOn = function($element, $ripple) {
var size = self.getNewSize($element, $ripple);
if(self.hasTransitionSupport()) {
$ripple
.css({
"-ms-transform": "scale(" + size + ")",
"-moz-transform": "scale(" + size + ")",
"-webkit-transform": "scale(" + size + ")",
"transform": "scale(" + size + ")"
})
.addClass("ripple-on")
.data("animating", "on")
.data("mousedown", "on");
} else {
$ripple.animate({
"width": Math.max($element.outerWidth(), $element.outerHeight()) * 2,
"height": Math.max($element.outerWidth(), $element.outerHeight()) * 2,
"margin-left": Math.max($element.outerWidth(), $element.outerHeight()) * (-1),
"margin-top": Math.max($element.outerWidth(), $element.outerHeight()) * (-1),
"opacity": 0.2
}, 500, function() {
$ripple.trigger("transitionend");
});
}
};
/**
* Create the jquery plugin function
*/
$.fn.ripples = function(options) {
return this.each(function() {
if(!$.data(this, "plugin_" + ripples)) {
$.data(this, "plugin_" + ripples, new Ripples(this, options));
}
});
};
})(jQuery, window, document);
};

227
dist/js/npm/material.js vendored Normal file
View File

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

View File

@ -2,7 +2,7 @@
"name": "bootstrap-material",
"version": "0.2.0",
"description": "Material Design for Bootstrap 3",
"main": "index.js",
"main": "./dist/js/npm/material",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},