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/togglebutton.js' : 'js/src/togglebutton.js',
'js/dist/radio.js' : 'js/src/radio.js',
'js/dist/fileinput.js' : 'js/src/fileinput.js',
//'js/dist/scrollspy.js' : 'js/src/scrollspy.js',
'js/dist/fileinput.js' : 'js/src/fileInput.js',
'js/dist/bootstrapMaterialDesign.js' : 'js/src/bootstrapMaterialDesign.js',
//'js/dist/tab.js' : 'js/src/tab.js',
//'js/dist/tooltip.js' : 'js/src/tooltip.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/togglebutton.js' : 'js/src/togglebutton.js',
'dist/js/umd/radio.js' : 'js/src/radio.js',
'dist/js/umd/fileinput.js' : 'js/src/fileinput.js',
//'dist/js/umd/modal.js' : 'js/src/modal.js',
//'dist/js/umd/scrollspy.js' : 'js/src/scrollspy.js',
'dist/js/umd/fileinput.js' : 'js/src/fileInput.js',
'dist/js/umd/bootstrapMaterialDesign.js' : 'js/src/bootstrapMaterialDesign.js',
//'dist/js/umd/tab.js' : 'js/src/tab.js',
//'dist/js/umd/tooltip.js' : 'js/src/tooltip.js',
//'dist/js/umd/popover.js' : 'js/src/popover.js'
@ -197,8 +196,8 @@ module.exports = function (grunt) {
'js/src/checkbox.js',
'js/src/togglebutton.js',
'js/src/radio.js',
'js/src/fileinput.js',
//'js/src/scrollspy.js',
'js/src/fileInput.js',
'js/src/bootstrapMaterialDesign.js',
//'js/src/tab.js',
//'js/src/tooltip.js',
//'js/src/popover.js'

View File

@ -155,6 +155,7 @@
"space-in-parens": 2,
"space-return-throw-case": 2,
"space-unary-ops": 2,
"quotes": [2, "single", "avoid-escape"],
// es6
"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)
_onLoading() {
setInterval(() => {
$("input[type!=checkbox]").each((index, element) => {
$('input[type!=checkbox]').each((index, element) => {
let $element = $(element)
if ($element.val() && $element.val() !== $element.attr("value")) {
$element.triggerStart("change")
if ($element.val() && $element.val() !== $element.attr('value')) {
$element.triggerStart('change')
}
})
}, 100)
@ -59,18 +59,18 @@ const Autofill = (($) => {
// (because user can select from the autofill dropdown only when the input has focus)
let focused = null
$(document)
.on("focus", "input", (event) => {
let $inputs = $(event.currentTarget).closest("form").find("input").not("[type=file]")
.on('focus', 'input', (event) => {
let $inputs = $(event.currentTarget).closest('form').find('input').not('[type=file]')
focused = setInterval(() => {
$inputs.each((index, element) => {
let $element = $(element)
if ($element.val() !== $element.attr("value")) {
$element.triggerStart("change")
if ($element.val() !== $element.attr('value')) {
$element.triggerStart('change')
}
})
}, 100)
})
.on("blur", ".form-group input", () => {
.on('blur', '.form-group input', () => {
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,
template: `<span class='material-input'></span>`,
formGroup: {
template: `"<div class='form-group'></div>`
template: `<div class='form-group'></div>`
}
}
const InputSizeConversions = {
"input-lg": "form-group-lg",
"input-sm": "form-group-sm"
'input-lg': 'form-group-lg',
'input-sm': 'form-group-sm'
}
const ClassName = {
@ -80,9 +80,9 @@ const Input = (($) => {
}
})
.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()
} else {
this._removeIsEmpty()
@ -139,7 +139,7 @@ const Input = (($) => {
}
_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() {

View File

@ -30,28 +30,28 @@
$.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,
//"input": true,
//"ripples": true,
//"checkbox": true,
//"togglebutton": true,
//"radio": true,
//"arrive": true,
//"autofill": false,
"withRipples": [
".btn:not(.btn-link)",
".card-image",
".navbar a:not(.ripple-none)",
".dropdown-menu a",
".nav-tabs a:not(.ripple-none)",
".withripple",
".pagination li:not(.active):not(.disabled) a:not(.ripple-none)"
].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]" ,
"fileInputElements": 'input[type=file]'
//"withRipples": [
// ".btn:not(.btn-link)",
// ".card-image",
// ".navbar a:not(.ripple-none)",
// ".dropdown-menu a",
// ".nav-tabs a:not(.ripple-none)",
// ".withripple",
// ".pagination li:not(.active):not(.disabled) a:not(.ripple-none)"
//].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]" ,
//"fileInputElements": 'input[type=file]'
},
//"checkbox": function(selector) {
// // Add fake-checkbox to material checkboxes

View File

@ -11,14 +11,29 @@ const Ripples = (($) => {
const DATA_KEY = `mdb.${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 = {
containerSelector: '.ripple-container',
rippleSelector: 'div.ripple',
containerTemplate: `<div class='ripple-container'></div>`,
rippleTemplate: `<div class='ripple'></div>`,
container: {
template: `<div class='${ClassName.CONTAINER}'></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,
triggerStart: 'mousedown touchstart',
triggerEnd: 'mouseup mouseleave touchend',
duration: 500
}
@ -41,7 +56,7 @@ const Ripples = (($) => {
$.removeData(this.element, DATA_KEY)
this.element = null
this.containerElement = null
this.rippleElement = null
this.decoratorElement = null
this.config = null
}
@ -51,7 +66,7 @@ const Ripples = (($) => {
_onStartRipple(event) {
// 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
}
@ -68,10 +83,10 @@ const Ripples = (($) => {
}
// set the location and color each time (even if element is cached)
this.rippleElement.css({
"left": relX,
"top": relY,
"background-color": this._getRipplesColor()
this.decoratorElement.css({
'left': relX,
'top': relY,
'background-color': this._getRipplesColor()
})
// Make sure the ripple has the styles applied (ugly hack but it works)
@ -80,16 +95,16 @@ const Ripples = (($) => {
// Turn on the ripple animation
this.rippleOn()
// Call the rippleEnd function when the transition "on" ends
// Call the rippleEnd function when the transition 'on' ends
setTimeout(() => {
this.rippleEnd()
}, this.config.duration)
// Detect when the user leaves the element (attach only when necessary for performance)
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()
}
})
@ -97,18 +112,18 @@ const Ripples = (($) => {
_findOrCreateContainer() {
if (!this.containerElement || !this.containerElement.length > 0) {
this.element.append(this.config.containerTemplate)
this.containerElement = this.element.find(this.config.containerSelector)
this.element.append(this.config.container.template)
this.containerElement = this.element.find(Selector.CONTAINER)
}
// always add the rippleElement, it is always removed
this.containerElement.append(this.config.rippleTemplate)
this.rippleElement = this.containerElement.find(this.config.rippleSelector)
this.containerElement.append(this.config.element.template)
this.decoratorElement = this.containerElement.find(Selector.DECORATOR)
}
// Make sure the ripple has the styles applied (ugly hack but it works)
_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
*/
_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
}
@ -184,10 +199,10 @@ const Ripples = (($) => {
* End the animation of the ripple
*/
rippleEnd() {
this.rippleElement.data("animating", "off")
this.decoratorElement.data('animating', 'off')
if (this.rippleElement.data("mousedown") === "off") {
this.rippleOut(this.rippleElement)
if (this.decoratorElement.data('mousedown') === 'off') {
this.rippleOut(this.decoratorElement)
}
}
@ -195,19 +210,19 @@ const Ripples = (($) => {
* Turn off the ripple effect
*/
rippleOut() {
this.rippleElement.off()
this.decoratorElement.off()
if (Util.transitionEndSupported()) {
this.rippleElement.addClass("ripple-out")
this.decoratorElement.addClass('ripple-out')
} else {
this.rippleElement.animate({ "opacity": 0 }, 100, () => {
this.rippleElement.triggerStart("transitionend")
this.decoratorElement.animate({ 'opacity': 0 }, 100, () => {
this.decoratorElement.triggerStart('transitionend')
})
}
this.rippleElement.on(Util.transitionEndSelector(), () => {
this.rippleElement.remove()
this.rippleElement = null
this.decoratorElement.on(Util.transitionEndSelector(), () => {
this.decoratorElement.remove()
this.decoratorElement = null
})
}
@ -218,25 +233,25 @@ const Ripples = (($) => {
let size = this._getNewSize()
if (Util.transitionEndSupported()) {
this.rippleElement
this.decoratorElement
.css({
"-ms-transform": `scale(${size})`,
"-moz-transform": `scale(${size})`,
"-webkit-transform": `scale(${size})`,
"transform": `scale(${size})`
'-ms-transform': `scale(${size})`,
'-moz-transform': `scale(${size})`,
'-webkit-transform': `scale(${size})`,
'transform': `scale(${size})`
})
.addClass("ripple-on")
.data("animating", "on")
.data("mousedown", "on")
.addClass('ripple-on')
.data('animating', 'on')
.data('mousedown', 'on')
} else {
this.rippleElement.animate({
"width": 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-top": Math.max(this.element.outerWidth(), this.element.outerHeight()) * (-1),
"opacity": 0.2
this.decoratorElement.animate({
'width': 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-top': Math.max(this.element.outerWidth(), this.element.outerHeight()) * (-1),
'opacity': 0.2
}, 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
*/
_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 transitionEndSelector = ""
let transitionEndSelector = ''
const TransitionEndEvent = {
WebkitTransition: 'webkitTransitionEnd',
@ -67,9 +67,9 @@ const Util = (($) => {
},
isChar(event) {
if (typeof event.which === "undefined") {
if (typeof event.which === 'undefined') {
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 false

View File

@ -1,20 +1,21 @@
.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;
}
// marker class (used as a selector) to add ripple to something
.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;
width: 20px;
height: 20px;
@ -22,17 +23,20 @@
margin-top: -10px;
border-radius: 100%;
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-origin: 50%;
opacity: 0;
pointer-events: none;
}
.ripple.ripple-on {
transition: opacity 0.15s ease-in 0s, transform 0.5s cubic-bezier(0.4, 0, 0.2, 1) 0.1s;
opacity: 0.1;
}
.ripple.ripple-out {
transition: opacity 0.1s linear 0s !important;
opacity: 0;
&.ripple-on {
transition: opacity 0.15s ease-in 0s, transform 0.5s cubic-bezier(0.4, 0, 0.2, 1) 0.1s;
opacity: 0.1;
}
&.ripple-out {
transition: opacity 0.1s linear 0s !important;
opacity: 0;
}
}
}