Initial implementation of collapseInline is complete and working on the test page. Need to integrate it into documentation.

This commit is contained in:
Kevin Ross 2016-01-08 13:04:21 -06:00
parent ee7d22070f
commit a08b5a2ee8
14 changed files with 309 additions and 123 deletions

View File

@ -399,8 +399,8 @@ module.exports = function (grunt) {
files: 'js/src/*.js',
tasks: ['dist-js']
},
docsjs: {
files: ['docs/assets/js/src/*.js'],
docsjs: { // watch both the source and docs js
files: ['js/src/*.js', 'docs/assets/js/src/*.js'],
tasks: ['docs-js']
},
core: {

View File

@ -17,6 +17,7 @@ group: material-design
{% endexample %}
## With label-placeholder
Perhaps this isn't worth doing, considering the context. we need to override the top calc to determine where this goes, or perhaps we should switch to a bottom calc for everything?
{% example html %}

View File

@ -1,3 +1,5 @@
import Base from './base'
const Autofill = (($) => {
/**
@ -17,20 +19,17 @@ const Autofill = (($) => {
* Class Definition
* ------------------------------------------------------------------------
*/
class Autofill {
class Autofill extends Base {
constructor($element, config) {
this.$element = $element
this.config = $.extend(true, {}, Default, config)
super($element, $.extend(true, {}, Default, config))
this._watchLoading()
this._attachEventHandlers()
}
dispose() {
$.removeData(this.$element, DATA_KEY)
this.$element = null
this.config = null
super.dispose(DATA_KEY)
}
// ------------------------------------------------------------------------

95
js/src/base.js Normal file
View File

@ -0,0 +1,95 @@
import Util from './util'
const Base = (($) => {
const ClassName = {
//FORM_GROUP: 'form-group',
MDB_FORM_GROUP: 'mdb-form-group',
//MDB_LABEL: 'mdb-label',
//MDB_LABEL_STATIC: 'mdb-label-static',
//MDB_LABEL_PLACEHOLDER: 'mdb-label-placeholder',
//MDB_LABEL_FLOATING: 'mdb-label-floating',
//HAS_DANGER: 'has-danger',
IS_FILLED: 'is-filled',
IS_FOCUSED: 'is-focused'
}
const Selector = {
//FORM_GROUP: `.${ClassName.FORM_GROUP}`,
MDB_FORM_GROUP: `.${ClassName.MDB_FORM_GROUP}`
}
const Default = {}
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
class Base {
/**
*
* @param element
* @param config
* @param properties - anything that needs to be set as this[key] = value. Works around the need to call `super` before using `this`
*/
constructor($element, config, properties = {}) {
this.$element = $element
this.config = $.extend(true, {}, Default, config)
// set properties for use in the constructor initialization
for (let key in properties) {
this[key] = properties[key]
}
}
dispose(dataKey) {
$.removeData(this.$element, dataKey)
this.$element = null
this.config = null
}
// ------------------------------------------------------------------------
// protected
addFormGroupFocus() {
if (!this.$element.prop('disabled')) {
this.$mdbFormGroup.addClass(ClassName.IS_FOCUSED)
}
}
removeFormGroupFocus() {
this.$mdbFormGroup.removeClass(ClassName.IS_FOCUSED)
}
removeIsFilled() {
this.$mdbFormGroup.removeClass(ClassName.IS_FILLED)
}
addIsFilled() {
this.$mdbFormGroup.addClass(ClassName.IS_FILLED)
}
// Find mdb-form-group
findMdbFormGroup(raiseError = true) {
let mfg = this.$element.closest(Selector.MDB_FORM_GROUP)
if (mfg.length === 0 && raiseError) {
$.error(`Failed to find ${Selector.MDB_FORM_GROUP} for ${Util.describe(this.$element)}`)
}
return mfg
}
// ------------------------------------------------------------------------
// private
// ------------------------------------------------------------------------
// static
}
return Base
})(jQuery)
export default Base

View File

@ -1,3 +1,4 @@
import Base from './base'
import Util from './util'
const BaseInput = (($) => {
@ -26,7 +27,7 @@ const BaseInput = (($) => {
required: false
},
mdbFormGroup: {
template: `<span class='mdb-form-group'></span>`,
template: `<span class='${ClassName.MDB_FORM_GROUP}'></span>`,
create: true, // create a wrapper if form-group not found
required: true // not recommended to turn this off, only used for inline components
},
@ -60,7 +61,7 @@ const BaseInput = (($) => {
* Class Definition
* ------------------------------------------------------------------------
*/
class BaseInput {
class BaseInput extends Base {
/**
*
@ -69,13 +70,7 @@ const BaseInput = (($) => {
* @param properties - anything that needs to be set as this[key] = value. Works around the need to call `super` before using `this`
*/
constructor($element, config, properties = {}) {
this.$element = $element
this.config = $.extend(true, {}, Default, config)
// set properties for use in the constructor initialization
for (let key in properties) {
this[key] = properties[key]
}
super($element, $.extend(true, {}, Default, config), properties)
// Enforce no overlap between components to prevent side effects
this._rejectInvalidComponentMatches()
@ -106,10 +101,9 @@ const BaseInput = (($) => {
}
dispose(dataKey) {
$.removeData(this.$element, dataKey)
this.$element = null
super.dispose(dataKey)
this.$mdbFormGroup = null
this.config = null
this.$formGroup = null
}
// ------------------------------------------------------------------------
@ -163,16 +157,6 @@ const BaseInput = (($) => {
})
}
addFormGroupFocus() {
if (!this.$element.prop('disabled')) {
this.$mdbFormGroup.addClass(ClassName.IS_FOCUSED)
}
}
removeFormGroupFocus() {
this.$mdbFormGroup.removeClass(ClassName.IS_FOCUSED)
}
addHasDanger() {
this.$mdbFormGroup.addClass(ClassName.HAS_DANGER)
}
@ -181,14 +165,6 @@ const BaseInput = (($) => {
this.$mdbFormGroup.removeClass(ClassName.HAS_DANGER)
}
removeIsFilled() {
this.$mdbFormGroup.removeClass(ClassName.IS_FILLED)
}
addIsFilled() {
this.$mdbFormGroup.addClass(ClassName.IS_FILLED)
}
isEmpty() {
return (this.$element.val() === null || this.$element.val() === undefined || this.$element.val() === '')
}
@ -264,15 +240,6 @@ const BaseInput = (($) => {
return label
}
// Find mdb-form-group
findMdbFormGroup(raiseError = true) {
let mfg = this.$element.closest(Selector.MDB_FORM_GROUP)
if (mfg.length === 0 && raiseError) {
$.error(`Failed to find ${Selector.MDB_FORM_GROUP} for ${Util.describe(this.$element)}`)
}
return mfg
}
// Find mdb-form-group
findFormGroup(raiseError = true) {
let fg = this.$element.closest(Selector.FORM_GROUP)

View File

@ -37,6 +37,27 @@ const BootstrapMaterialDesign = (($) => {
className: 'mdb-label-static' // default style of label to be used if not specified in the html markup
}
},
autofill: {
selector: 'body'
},
checkbox: {
selector: '.checkbox > label > input[type=checkbox]'
},
checkboxInline: {
selector: 'label.checkbox-inline > input[type=checkbox]'
},
collapseInline: {
selector: '.mdb-collapse-inline [data-toggle="collapse"]'
},
file: {
selector: 'input[type=file]'
},
radio: {
selector: '.radio > label > input[type=radio]'
},
radioInline: {
selector: 'label.radio-inline > input[type=radio]'
},
ripples: {
//selector: ['.btn:not(.btn-link):not(.ripple-none)'] // testing only
selector: [
@ -49,43 +70,26 @@ const BootstrapMaterialDesign = (($) => {
'.ripple' // generic marker class to add ripple to elements
]
},
text: {
// omit inputs we have specialized components to handle
selector: [`input[type!='checkbox'][type!='radio'][type!='file']`]
},
file: {
selector: 'input[type=file]'
},
checkbox: {
selector: '.checkbox > label > input[type=checkbox]'
},
checkboxInline: {
selector: 'label.checkbox-inline > input[type=checkbox]'
},
radio: {
selector: '.radio > label > input[type=radio]'
},
radioInline: {
selector: 'label.radio-inline > input[type=radio]'
},
select: {
selector: ['select']
},
switch: {
selector: '.switch > label > input[type=checkbox]'
},
text: {
// omit inputs we have specialized components to handle
selector: [`input[type!='checkbox'][type!='radio'][type!='file']`]
},
textarea: {
selector: ['textarea']
},
autofill: {
selector: 'body'
},
arrive: true,
// create an ordered component list for instantiation
instantiation: [
'ripples',
'checkbox',
'checkboxInline',
'collapseInline',
'file',
'radio',
'radioInline',

View File

@ -1,9 +1,9 @@
import BaseSelection from './baseSelection'
import Text from './text'
import File from './file'
import Radio from './radio'
import Textarea from './textarea'
import Select from './select'
//import Text from './text'
//import File from './file'
//import Radio from './radio'
//import Textarea from './textarea'
//import Select from './select'
import Util from './util'
const Checkbox = (($) => {
@ -30,9 +30,9 @@ const Checkbox = (($) => {
class Checkbox extends BaseSelection {
constructor($element, config, properties = {inputType: NAME, outerClass: NAME}) {
super($element, $.extend(true, {
invalidComponentMatches: [File, Radio, Text, Textarea, Select]
}, Default, config), properties)
super($element, $.extend(true,
//{invalidComponentMatches: [File, Radio, Text, Textarea, Select]},
Default, config), properties)
}
dispose(dataKey = DATA_KEY) {

113
js/src/collapseInline.js Normal file
View File

@ -0,0 +1,113 @@
import Base from './base'
import Util from './util'
const CollapseInline = (($) => {
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
const NAME = 'collapseInline'
const DATA_KEY = `mdb.${NAME}`
const JQUERY_NAME = `mdb${NAME.charAt(0).toUpperCase() + NAME.slice(1)}`
const JQUERY_NO_CONFLICT = $.fn[JQUERY_NAME]
const Selector = {
ANY_INPUT: 'input, select, textarea'
}
const ClassName = {
IN: 'in',
COLLAPSE: 'collapse',
COLLAPSING: 'collapsing',
COLLAPSED: 'collapsed',
WIDTH: 'width'
}
const Default = {}
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
class CollapseInline extends Base {
// $element is expected to be the trigger
// i.e. <button class="btn mdb-btn-icon" for="search" data-toggle="collapse" data-target="#search-field" aria-expanded="false" aria-controls="search-field">
constructor($element, config) {
super($element, $.extend(true, {}, Default, config))
this.$mdbFormGroup = this.findMdbFormGroup(true)
let collapseSelector = $element.data('target')
this.$collapse = $(collapseSelector)
Util.assert($element, this.$collapse.length === 0, `Cannot find collapse target for ${Util.describe($element)}`)
Util.assert(this.$collapse, !this.$collapse.hasClass(ClassName.COLLAPSE), `${Util.describe(this.$collapse)} is expected to have the '${ClassName.COLLAPSE}' class. It is being targeted by ${Util.describe($element)}`)
// find the first input for focusing
let $inputs = this.$mdbFormGroup.find(Selector.ANY_INPUT)
if ($inputs.length > 0) {
this.$input = $inputs.first()
}
// automatically add the marker class to collapse width instead of height - nice convenience because it is easily forgotten
if (!this.$collapse.hasClass(ClassName.WIDTH)) {
this.$collapse.addClass(ClassName.WIDTH)
}
if (this.$input) {
// add a listener to set focus
this.$collapse.on('shown.bs.collapse', () => {
this.$input.focus()
})
// add a listener to collapse field
this.$input.blur(() => {
this.$collapse.collapse('hide')
})
}
}
dispose() {
super.dispose(DATA_KEY)
this.$mdbFormGroup = null
this.$collapse = null
this.$input = null
}
// ------------------------------------------------------------------------
// private
// ------------------------------------------------------------------------
// static
static _jQueryInterface(config) {
return this.each(function () {
let $element = $(this)
let data = $element.data(DATA_KEY)
if (!data) {
data = new CollapseInline($element, config)
$element.data(DATA_KEY, data)
}
})
}
}
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
*/
$.fn[JQUERY_NAME] = CollapseInline._jQueryInterface
$.fn[JQUERY_NAME].Constructor = CollapseInline
$.fn[JQUERY_NAME].noConflict = () => {
$.fn[JQUERY_NAME] = JQUERY_NO_CONFLICT
return CollapseInline._jQueryInterface
}
return CollapseInline
})(jQuery)
export default CollapseInline

View File

@ -1,10 +1,10 @@
import BaseInput from './baseInput'
import Checkbox from './checkbox'
import Radio from './radio'
import Switch from './switch'
import Text from './text'
import Textarea from './textarea'
import Select from './select'
//import Checkbox from './checkbox'
//import Radio from './radio'
//import Switch from './switch'
//import Text from './text'
//import Textarea from './textarea'
//import Select from './select'
import Util from './util'
const File = (($) => {
@ -38,7 +38,9 @@ const File = (($) => {
class File extends BaseInput {
constructor($element, config) {
super($element, $.extend(true, {invalidComponentMatches: [Checkbox, Radio, Text, Textarea, Select, Switch]}, Default, config))
super($element, $.extend(true,
//{invalidComponentMatches: [Checkbox, Radio, Text, Textarea, Select, Switch]},
Default, config))
this.$mdbFormGroup.addClass(ClassName.IS_FILE)
}

View File

@ -10,20 +10,19 @@
/* eslint-disable no-unused-vars */
import '../../node_modules/babel-polyfill/dist/polyfill'
import BaseInput from './baseInput'
import BaseFormControl from './baseFormControl'
import BaseSelection from './baseSelection'
import Util from './util'
import Ripples from './ripples'
import Autofill from './autofill'
import Text from './text'
import Textarea from './textarea'
import Select from './select'
// invalidComponentMatches is currently disabled due to https://github.com/rollup/rollup/issues/428#issuecomment-170066452
import Checkbox from './checkbox'
import CheckboxInline from './checkboxInline'
import Switch from './switch'
import CollapseInline from './collapseInline'
import File from './file'
import Radio from './radio'
import RadioInline from './radioInline'
import File from './file'
import Select from './select'
import Switch from './switch'
import Text from './text'
import Textarea from './textarea'
import Ripples from './ripples'
import Autofill from './autofill'
import BootstrapMaterialDesign from './bootstrapMaterialDesign'
/* eslint-enable no-unused-vars */

View File

@ -1,8 +1,8 @@
import BaseSelection from './baseSelection'
import Text from './text'
import File from './file'
import Checkbox from './checkbox'
import Switch from './switch'
//import Text from './text'
//import File from './file'
//import Checkbox from './checkbox'
//import Switch from './switch'
import Util from './util'
const Radio = (($) => {
@ -29,9 +29,9 @@ const Radio = (($) => {
class Radio extends BaseSelection {
constructor($element, config, properties = {inputType: NAME, outerClass: NAME}) {
super($element, $.extend(true, {
invalidComponentMatches: [Checkbox, File, Switch, Text]
}, Default, config), properties)
super($element, $.extend(true,
//{invalidComponentMatches: [Checkbox, File, Switch, Text]},
Default, config), properties)
}
dispose(dataKey = DATA_KEY) {

View File

@ -1,10 +1,10 @@
import BaseFormControl from './baseFormControl'
import Checkbox from './checkbox'
import File from './file'
import Radio from './radio'
import Switch from './switch'
import Text from './text'
import Textarea from './textarea'
//import Checkbox from './checkbox'
//import File from './file'
//import Radio from './radio'
//import Switch from './switch'
//import Text from './text'
//import Textarea from './textarea'
import Util from './util'
const Select = (($) => {
@ -31,7 +31,9 @@ const Select = (($) => {
class Select extends BaseFormControl {
constructor($element, config) {
super($element, $.extend(true, {invalidComponentMatches: [Checkbox, File, Radio, Switch, Text, Textarea]}, Default, config))
super($element, $.extend(true,
//{invalidComponentMatches: [Checkbox, File, Radio, Switch, Text, Textarea]},
Default, config))
// floating labels will cover the options, so trigger them to be above (if used)
this.addIsFilled()

View File

@ -1,10 +1,10 @@
import BaseFormControl from './baseFormControl'
import Checkbox from './checkbox'
import File from './file'
import Radio from './radio'
import Switch from './switch'
import Textarea from './textarea'
import Select from './select'
//import Checkbox from './checkbox'
//import File from './file'
//import Radio from './radio'
//import Switch from './switch'
//import Textarea from './textarea'
//import Select from './select'
import Util from './util'
const Text = (($) => {
@ -29,7 +29,9 @@ const Text = (($) => {
class Text extends BaseFormControl {
constructor($element, config) {
super($element, $.extend(true, {invalidComponentMatches: [Checkbox, File, Radio, Switch, Select, Textarea]}, Default, config))
super($element, $.extend(true,
//{invalidComponentMatches: [Checkbox, File, Radio, Switch, Select, Textarea]},
Default, config))
}
dispose(dataKey = DATA_KEY) {

View File

@ -1,10 +1,10 @@
import BaseFormControl from './baseFormControl'
import Checkbox from './checkbox'
import File from './file'
import Radio from './radio'
import Switch from './switch'
import Text from './text'
import Select from './select'
//import Checkbox from './checkbox'
//import File from './file'
//import Radio from './radio'
//import Switch from './switch'
//import Text from './text'
//import Select from './select'
import Util from './util'
const Textarea = (($) => {
@ -29,7 +29,9 @@ const Textarea = (($) => {
class Textarea extends BaseFormControl {
constructor($element, config) {
super($element, $.extend(true, {invalidComponentMatches: [Checkbox, File, Radio, Text, Select, Switch]}, Default, config))
super($element, $.extend(true,
//{invalidComponentMatches: [Checkbox, File, Radio, Text, Select, Switch]},
Default, config))
}
dispose() {