seeded bootstrapMaterialDesign es6 file with new config

This commit is contained in:
Kevin Ross 2015-12-02 10:38:00 -06:00
parent 68391413ab
commit 23a7a4d77a
9 changed files with 262 additions and 116 deletions

View File

@ -107,8 +107,8 @@ module.exports = function (grunt) {
'js/dist/checkbox.js' : 'js/src/checkbox.js', 'js/dist/checkbox.js' : 'js/src/checkbox.js',
'js/dist/togglebutton.js' : 'js/src/togglebutton.js', 'js/dist/togglebutton.js' : 'js/src/togglebutton.js',
'js/dist/radio.js' : 'js/src/radio.js', 'js/dist/radio.js' : 'js/src/radio.js',
'js/dist/fileinput.js' : 'js/src/fileinput.js', 'js/dist/fileinput.js' : 'js/src/fileInput.js',
//'js/dist/scrollspy.js' : 'js/src/scrollspy.js', 'js/dist/bootstrapMaterialDesign.js' : 'js/src/bootstrapMaterialDesign.js',
//'js/dist/tab.js' : 'js/src/tab.js', //'js/dist/tab.js' : 'js/src/tab.js',
//'js/dist/tooltip.js' : 'js/src/tooltip.js', //'js/dist/tooltip.js' : 'js/src/tooltip.js',
//'js/dist/popover.js' : 'js/src/popover.js' //'js/dist/popover.js' : 'js/src/popover.js'
@ -134,9 +134,8 @@ module.exports = function (grunt) {
'dist/js/umd/checkbox.js' : 'js/src/checkbox.js', 'dist/js/umd/checkbox.js' : 'js/src/checkbox.js',
'dist/js/umd/togglebutton.js' : 'js/src/togglebutton.js', 'dist/js/umd/togglebutton.js' : 'js/src/togglebutton.js',
'dist/js/umd/radio.js' : 'js/src/radio.js', 'dist/js/umd/radio.js' : 'js/src/radio.js',
'dist/js/umd/fileinput.js' : 'js/src/fileinput.js', 'dist/js/umd/fileinput.js' : 'js/src/fileInput.js',
//'dist/js/umd/modal.js' : 'js/src/modal.js', 'dist/js/umd/bootstrapMaterialDesign.js' : 'js/src/bootstrapMaterialDesign.js',
//'dist/js/umd/scrollspy.js' : 'js/src/scrollspy.js',
//'dist/js/umd/tab.js' : 'js/src/tab.js', //'dist/js/umd/tab.js' : 'js/src/tab.js',
//'dist/js/umd/tooltip.js' : 'js/src/tooltip.js', //'dist/js/umd/tooltip.js' : 'js/src/tooltip.js',
//'dist/js/umd/popover.js' : 'js/src/popover.js' //'dist/js/umd/popover.js' : 'js/src/popover.js'
@ -197,8 +196,8 @@ module.exports = function (grunt) {
'js/src/checkbox.js', 'js/src/checkbox.js',
'js/src/togglebutton.js', 'js/src/togglebutton.js',
'js/src/radio.js', 'js/src/radio.js',
'js/src/fileinput.js', 'js/src/fileInput.js',
//'js/src/scrollspy.js', 'js/src/bootstrapMaterialDesign.js',
//'js/src/tab.js', //'js/src/tab.js',
//'js/src/tooltip.js', //'js/src/tooltip.js',
//'js/src/popover.js' //'js/src/popover.js'

View File

@ -155,6 +155,7 @@
"space-in-parens": 2, "space-in-parens": 2,
"space-return-throw-case": 2, "space-return-throw-case": 2,
"space-unary-ops": 2, "space-unary-ops": 2,
"quotes": [2, "single", "avoid-escape"],
// es6 // es6
"arrow-parens": 2, "arrow-parens": 2,

View File

@ -45,10 +45,10 @@ const Autofill = (($) => {
// 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)
_onLoading() { _onLoading() {
setInterval(() => { setInterval(() => {
$("input[type!=checkbox]").each((index, element) => { $('input[type!=checkbox]').each((index, element) => {
let $element = $(element) let $element = $(element)
if ($element.val() && $element.val() !== $element.attr("value")) { if ($element.val() && $element.val() !== $element.attr('value')) {
$element.triggerStart("change") $element.triggerStart('change')
} }
}) })
}, 100) }, 100)
@ -59,18 +59,18 @@ const Autofill = (($) => {
// (because user can select from the autofill dropdown only when the input has focus) // (because user can select from the autofill dropdown only when the input has focus)
let focused = null let focused = null
$(document) $(document)
.on("focus", "input", (event) => { .on('focus', 'input', (event) => {
let $inputs = $(event.currentTarget).closest("form").find("input").not("[type=file]") let $inputs = $(event.currentTarget).closest('form').find('input').not('[type=file]')
focused = setInterval(() => { focused = setInterval(() => {
$inputs.each((index, element) => { $inputs.each((index, element) => {
let $element = $(element) let $element = $(element)
if ($element.val() !== $element.attr("value")) { if ($element.val() !== $element.attr('value')) {
$element.triggerStart("change") $element.triggerStart('change')
} }
}) })
}, 100) }, 100)
}) })
.on("blur", ".form-group input", () => { .on('blur', '.form-group input', () => {
clearInterval(focused) clearInterval(focused)
}) })
} }

127
js/src/bootstrapMaterialDesign.js vendored Normal file
View File

@ -0,0 +1,127 @@
//import Util from './util'
/**
* $.bootstrapMaterialDesign(config) is a macro class to configure the components generally
* used in Material Design for Bootstrap. You may pass overrides to the configurations
* which will be passed into each component, or you may omit use of this class and
* configure each component separately.
*
* NOTE: If omitting use of this class, please note that the Input component must be
* initialized prior to other decorating components such as radio, checkbox,
* togglebutton, fileInput.
*
*/
const BootstrapMaterialDesign = (($) => {
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
const NAME = 'bootstrapMaterialDesign'
const DATA_KEY = `mdb.${NAME}`
const JQUERY_NO_CONFLICT = $.fn[NAME]
/**
*
* Default configuration for each component.
* - selector: may be a string or an array. Any array will be joined with a comma to generate the selector
* - filter: selector to individually filter elements sent to components e.g. ripple defaults `:not(.ripple-none)`
* - disable any component by defining it as false with an override. e.g. $.bootstrapMaterialDesign({ input: false })
*/
const Default = {
ripples: {
selector: [
'.btn:not(.btn-link)',
'.card-image',
'.navbar a',
'.dropdown-menu a',
'.nav-tabs a',
'.pagination li:not(.active):not(.disabled) a',
'.ripple' // generic marker class to add ripple to elements
],
filter: ':not(.ripple-none)'
},
input: {
selector: [
'input.form-control',
'textarea.form-control',
'select.form-control'
]
},
checkbox: {
selector: '.checkbox > label > input[type=checkbox]'
},
togglebutton: {
selector: '.togglebutton > label > input[type=checkbox]'
},
radio: {
selector: '.radio > label > input[type=radio]'
},
fileInput: {
selector: 'input[type=file]'
},
autofill: true,
arrive: true
}
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
class BootstrapMaterialDesign {
constructor(element, config) {
this.element = element
this.config = $.extend({}, Default, config)
// create an ordered component list for instantiation
}
dispose() {
$.removeData(this.element, DATA_KEY)
this.element = null
this.config = null
}
// ------------------------------------------------------------------------
// private
_bar(element) {
let x = 1
return x
}
// ------------------------------------------------------------------------
// static
static _jQueryInterface(config) {
return this.each(function () {
let $element = $(this)
let data = $element.data(DATA_KEY)
if (!data) {
data = new BootstrapMaterialDesign(this, config)
$element.data(DATA_KEY, data)
}
})
}
}
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
*/
$.fn[NAME] = BootstrapMaterialDesign._jQueryInterface
$.fn[NAME].Constructor = BootstrapMaterialDesign
$.fn[NAME].noConflict = () => {
$.fn[NAME] = JQUERY_NO_CONFLICT
return BootstrapMaterialDesign._jQueryInterface
}
return BootstrapMaterialDesign
})(jQuery)
export default BootstrapMaterialDesign

View File

@ -15,13 +15,13 @@ const Input = (($) => {
convertInputSizeVariations: true, convertInputSizeVariations: true,
template: `<span class='material-input'></span>`, template: `<span class='material-input'></span>`,
formGroup: { formGroup: {
template: `"<div class='form-group'></div>` template: `<div class='form-group'></div>`
} }
} }
const InputSizeConversions = { const InputSizeConversions = {
"input-lg": "form-group-lg", 'input-lg': 'form-group-lg',
"input-sm": "form-group-sm" 'input-sm': 'form-group-sm'
} }
const ClassName = { const ClassName = {
@ -80,9 +80,9 @@ const Input = (($) => {
} }
}) })
.on('keyup change', (event) => { .on('keyup change', (event) => {
let isValid = (typeof this.element[0].checkValidity === "undefined" || this.element[0].checkValidity()) let isValid = (typeof this.element[0].checkValidity === 'undefined' || this.element[0].checkValidity())
if (this.element.val() === "" && isValid) { if (this.element.val() === '' && isValid) {
this._addIsEmpty() this._addIsEmpty()
} else { } else {
this._removeIsEmpty() this._removeIsEmpty()
@ -139,7 +139,7 @@ const Input = (($) => {
} }
_isEmpty() { _isEmpty() {
return (this.element.val() === null || this.element.val() === undefined || this.element.val() === "") return (this.element.val() === null || this.element.val() === undefined || this.element.val() === '')
} }
_convertInputSizeVariations() { _convertInputSizeVariations() {

View File

@ -30,28 +30,28 @@
$.material = { $.material = {
"options": { "options": {
// These options set what will be started by $.material.init() // These options set what will be started by $.material.init()
"input": true, //"input": true,
"ripples": true, //"ripples": true,
"checkbox": true, //"checkbox": true,
"togglebutton": true, //"togglebutton": true,
"radio": true, //"radio": true,
"arrive": true, //"arrive": true,
"autofill": false, //"autofill": false,
"withRipples": [ //"withRipples": [
".btn:not(.btn-link)", // ".btn:not(.btn-link)",
".card-image", // ".card-image",
".navbar a:not(.ripple-none)", // ".navbar a:not(.ripple-none)",
".dropdown-menu a", // ".dropdown-menu a",
".nav-tabs a:not(.ripple-none)", // ".nav-tabs a:not(.ripple-none)",
".withripple", // ".withripple",
".pagination li:not(.active):not(.disabled) a:not(.ripple-none)" // ".pagination li:not(.active):not(.disabled) a:not(.ripple-none)"
].join(","), //].join(","),
"inputElements": "input.form-control, textarea.form-control, select.form-control", //"inputElements": "input.form-control, textarea.form-control, select.form-control",
"checkboxElements": ".checkbox > label > input[type=checkbox]", //"checkboxElements": ".checkbox > label > input[type=checkbox]",
"togglebuttonElements": ".togglebutton > label > input[type=checkbox]", //"togglebuttonElements": ".togglebutton > label > input[type=checkbox]",
"radioElements": ".radio > label > input[type=radio]" , //"radioElements": ".radio > label > input[type=radio]" ,
"fileInputElements": 'input[type=file]' //"fileInputElements": 'input[type=file]'
}, },
//"checkbox": function(selector) { //"checkbox": function(selector) {
// // Add fake-checkbox to material checkboxes // // Add fake-checkbox to material checkboxes

View File

@ -11,14 +11,29 @@ const Ripples = (($) => {
const DATA_KEY = `mdb.${NAME}` const DATA_KEY = `mdb.${NAME}`
const JQUERY_NO_CONFLICT = $.fn[NAME] const JQUERY_NO_CONFLICT = $.fn[NAME]
const ClassName = {
CONTAINER: 'ripple-container',
DECORATOR: 'ripple-decorator'
}
const Selector = {
CONTAINER: `.${ClassName.CONTAINER}`,
DECORATOR: `.${ClassName.DECORATOR}` //,
}
const Default = { const Default = {
containerSelector: '.ripple-container', container: {
rippleSelector: 'div.ripple', template: `<div class='${ClassName.CONTAINER}'></div>`
containerTemplate: `<div class='ripple-container'></div>`, },
rippleTemplate: `<div class='ripple'></div>`, decorator: {
template: `${ClassName.DECORATOR}'></div>`
},
trigger: {
start: 'mousedown touchstart',
end: 'mouseup mouseleave touchend'
},
touchUserAgentRegex: /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i, touchUserAgentRegex: /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i,
triggerStart: 'mousedown touchstart',
triggerEnd: 'mouseup mouseleave touchend',
duration: 500 duration: 500
} }
@ -41,7 +56,7 @@ const Ripples = (($) => {
$.removeData(this.element, DATA_KEY) $.removeData(this.element, DATA_KEY)
this.element = null this.element = null
this.containerElement = null this.containerElement = null
this.rippleElement = null this.decoratorElement = null
this.config = null this.config = null
} }
@ -51,7 +66,7 @@ const Ripples = (($) => {
_onStartRipple(event) { _onStartRipple(event) {
// Verify if the user is just touching on a device and return if so // Verify if the user is just touching on a device and return if so
if (this.isTouch() && event.type === "mousedown") { if (this.isTouch() && event.type === 'mousedown') {
return return
} }
@ -68,10 +83,10 @@ const Ripples = (($) => {
} }
// set the location and color each time (even if element is cached) // set the location and color each time (even if element is cached)
this.rippleElement.css({ this.decoratorElement.css({
"left": relX, 'left': relX,
"top": relY, 'top': relY,
"background-color": this._getRipplesColor() 'background-color': this._getRipplesColor()
}) })
// Make sure the ripple has the styles applied (ugly hack but it works) // Make sure the ripple has the styles applied (ugly hack but it works)
@ -80,16 +95,16 @@ const Ripples = (($) => {
// Turn on the ripple animation // Turn on the ripple animation
this.rippleOn() this.rippleOn()
// Call the rippleEnd function when the transition "on" ends // Call the rippleEnd function when the transition 'on' ends
setTimeout(() => { setTimeout(() => {
this.rippleEnd() this.rippleEnd()
}, this.config.duration) }, this.config.duration)
// Detect when the user leaves the element (attach only when necessary for performance) // Detect when the user leaves the element (attach only when necessary for performance)
this.element.on(this.config.triggerEnd, () => { this.element.on(this.config.triggerEnd, () => {
this.rippleElement.data("mousedown", "off") this.decoratorElement.data('mousedown', 'off')
if (this.rippleElement.data("animating") === "off") { if (this.decoratorElement.data('animating') === 'off') {
this.rippleOut() this.rippleOut()
} }
}) })
@ -97,18 +112,18 @@ const Ripples = (($) => {
_findOrCreateContainer() { _findOrCreateContainer() {
if (!this.containerElement || !this.containerElement.length > 0) { if (!this.containerElement || !this.containerElement.length > 0) {
this.element.append(this.config.containerTemplate) this.element.append(this.config.container.template)
this.containerElement = this.element.find(this.config.containerSelector) this.containerElement = this.element.find(Selector.CONTAINER)
} }
// always add the rippleElement, it is always removed // always add the rippleElement, it is always removed
this.containerElement.append(this.config.rippleTemplate) this.containerElement.append(this.config.element.template)
this.rippleElement = this.containerElement.find(this.config.rippleSelector) this.decoratorElement = this.containerElement.find(Selector.DECORATOR)
} }
// Make sure the ripple has the styles applied (ugly hack but it works) // Make sure the ripple has the styles applied (ugly hack but it works)
_forceStyleApplication() { _forceStyleApplication() {
return window.getComputedStyle(this.rippleElement[0]).opacity return window.getComputedStyle(this.decoratorElement[0]).opacity
} }
/** /**
@ -169,7 +184,7 @@ const Ripples = (($) => {
* Get the ripple color * Get the ripple color
*/ */
_getRipplesColor() { _getRipplesColor() {
let color = this.element.data("ripple-color") ? this.element.data("ripple-color") : window.getComputedStyle(this.element[0]).color let color = this.element.data('ripple-color') ? this.element.data('ripple-color') : window.getComputedStyle(this.element[0]).color
return color return color
} }
@ -184,10 +199,10 @@ const Ripples = (($) => {
* End the animation of the ripple * End the animation of the ripple
*/ */
rippleEnd() { rippleEnd() {
this.rippleElement.data("animating", "off") this.decoratorElement.data('animating', 'off')
if (this.rippleElement.data("mousedown") === "off") { if (this.decoratorElement.data('mousedown') === 'off') {
this.rippleOut(this.rippleElement) this.rippleOut(this.decoratorElement)
} }
} }
@ -195,19 +210,19 @@ const Ripples = (($) => {
* Turn off the ripple effect * Turn off the ripple effect
*/ */
rippleOut() { rippleOut() {
this.rippleElement.off() this.decoratorElement.off()
if (Util.transitionEndSupported()) { if (Util.transitionEndSupported()) {
this.rippleElement.addClass("ripple-out") this.decoratorElement.addClass('ripple-out')
} else { } else {
this.rippleElement.animate({ "opacity": 0 }, 100, () => { this.decoratorElement.animate({ 'opacity': 0 }, 100, () => {
this.rippleElement.triggerStart("transitionend") this.decoratorElement.triggerStart('transitionend')
}) })
} }
this.rippleElement.on(Util.transitionEndSelector(), () => { this.decoratorElement.on(Util.transitionEndSelector(), () => {
this.rippleElement.remove() this.decoratorElement.remove()
this.rippleElement = null this.decoratorElement = null
}) })
} }
@ -218,25 +233,25 @@ const Ripples = (($) => {
let size = this._getNewSize() let size = this._getNewSize()
if (Util.transitionEndSupported()) { if (Util.transitionEndSupported()) {
this.rippleElement this.decoratorElement
.css({ .css({
"-ms-transform": `scale(${size})`, '-ms-transform': `scale(${size})`,
"-moz-transform": `scale(${size})`, '-moz-transform': `scale(${size})`,
"-webkit-transform": `scale(${size})`, '-webkit-transform': `scale(${size})`,
"transform": `scale(${size})` 'transform': `scale(${size})`
}) })
.addClass("ripple-on") .addClass('ripple-on')
.data("animating", "on") .data('animating', 'on')
.data("mousedown", "on") .data('mousedown', 'on')
} else { } else {
this.rippleElement.animate({ this.decoratorElement.animate({
"width": Math.max(this.element.outerWidth(), this.element.outerHeight()) * 2, 'width': Math.max(this.element.outerWidth(), this.element.outerHeight()) * 2,
"height": Math.max(this.element.outerWidth(), this.element.outerHeight()) * 2, 'height': Math.max(this.element.outerWidth(), this.element.outerHeight()) * 2,
"margin-left": Math.max(this.element.outerWidth(), this.element.outerHeight()) * (-1), 'margin-left': Math.max(this.element.outerWidth(), this.element.outerHeight()) * (-1),
"margin-top": Math.max(this.element.outerWidth(), this.element.outerHeight()) * (-1), 'margin-top': Math.max(this.element.outerWidth(), this.element.outerHeight()) * (-1),
"opacity": 0.2 'opacity': 0.2
}, this.config.duration, () => { }, this.config.duration, () => {
this.rippleElement.triggerStart("transitionend") this.decoratorElement.triggerStart('transitionend')
}) })
} }
} }
@ -245,7 +260,7 @@ const Ripples = (($) => {
* Get the new size based on the element height/width and the ripple width * Get the new size based on the element height/width and the ripple width
*/ */
_getNewSize() { _getNewSize() {
return (Math.max(this.element.outerWidth(), this.element.outerHeight()) / this.rippleElement.outerWidth()) * 2.5 return (Math.max(this.element.outerWidth(), this.element.outerHeight()) / this.decoratorElement.outerWidth()) * 2.5
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------

View File

@ -7,7 +7,7 @@ const Util = (($) => {
*/ */
let transitionEnd = false let transitionEnd = false
let transitionEndSelector = "" let transitionEndSelector = ''
const TransitionEndEvent = { const TransitionEndEvent = {
WebkitTransition: 'webkitTransitionEnd', WebkitTransition: 'webkitTransitionEnd',
@ -67,9 +67,9 @@ const Util = (($) => {
}, },
isChar(event) { isChar(event) {
if (typeof event.which === "undefined") { if (typeof event.which === 'undefined') {
return true return true
} else if (typeof event.which === "number" && event.which > 0) { } else if (typeof event.which === 'number' && event.which > 0) {
return !event.ctrlKey && !event.metaKey && !event.altKey && event.which !== 8 && event.which !== 9 return !event.ctrlKey && !event.metaKey && !event.altKey && event.which !== 8 && event.which !== 9
} }
return false return false

View File

@ -1,20 +1,21 @@
// marker class (used as a selector) to add ripple to something
.withripple {
position: relative;
}
.ripple-container {
position: absolute;
top: 0;
left: 0;
z-index: 1;
width: 100%;
height: 100%;
overflow: hidden;
border-radius: inherit;
pointer-events: none;
}
.ripple { .ripple {
position: relative;
}
.ripple-container {
position: absolute;
top: 0;
left: 0;
z-index: 1;
width: 100%;
height: 100%;
overflow: hidden;
border-radius: inherit;
pointer-events: none;
.ripple-decorator {
position: absolute; position: absolute;
width: 20px; width: 20px;
height: 20px; height: 20px;
@ -22,17 +23,20 @@
margin-top: -10px; margin-top: -10px;
border-radius: 100%; border-radius: 100%;
background-color: #000; // fallback color background-color: #000; // fallback color
background-color: rgba(0,0,0,0.05); background-color: rgba(0, 0, 0, 0.05);
transform: scale(1); transform: scale(1);
transform-origin: 50%; transform-origin: 50%;
opacity: 0; opacity: 0;
pointer-events: none; pointer-events: none;
}
.ripple.ripple-on { &.ripple-on {
transition: opacity 0.15s ease-in 0s, transform 0.5s cubic-bezier(0.4, 0, 0.2, 1) 0.1s; transition: opacity 0.15s ease-in 0s, transform 0.5s cubic-bezier(0.4, 0, 0.2, 1) 0.1s;
opacity: 0.1; opacity: 0.1;
} }
.ripple.ripple-out {
transition: opacity 0.1s linear 0s !important; &.ripple-out {
opacity: 0; transition: opacity 0.1s linear 0s !important;
opacity: 0;
}
}
} }