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', files: 'js/src/*.js',
tasks: ['dist-js'] tasks: ['dist-js']
}, },
docsjs: { docsjs: { // watch both the source and docs js
files: ['docs/assets/js/src/*.js'], files: ['js/src/*.js', 'docs/assets/js/src/*.js'],
tasks: ['docs-js'] tasks: ['docs-js']
}, },
core: { core: {

View File

@ -17,6 +17,7 @@ group: material-design
{% endexample %} {% endexample %}
## With label-placeholder ## 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? 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 %} {% example html %}

View File

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

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' import Util from './util'
const BaseInput = (($) => { const BaseInput = (($) => {
@ -26,7 +27,7 @@ const BaseInput = (($) => {
required: false required: false
}, },
mdbFormGroup: { 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 create: true, // create a wrapper if form-group not found
required: true // not recommended to turn this off, only used for inline components required: true // not recommended to turn this off, only used for inline components
}, },
@ -60,7 +61,7 @@ const BaseInput = (($) => {
* Class Definition * 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` * @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 = {}) { constructor($element, config, properties = {}) {
this.$element = $element super($element, $.extend(true, {}, Default, config), properties)
this.config = $.extend(true, {}, Default, config)
// set properties for use in the constructor initialization
for (let key in properties) {
this[key] = properties[key]
}
// Enforce no overlap between components to prevent side effects // Enforce no overlap between components to prevent side effects
this._rejectInvalidComponentMatches() this._rejectInvalidComponentMatches()
@ -106,10 +101,9 @@ const BaseInput = (($) => {
} }
dispose(dataKey) { dispose(dataKey) {
$.removeData(this.$element, dataKey) super.dispose(dataKey)
this.$element = null
this.$mdbFormGroup = null 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() { addHasDanger() {
this.$mdbFormGroup.addClass(ClassName.HAS_DANGER) this.$mdbFormGroup.addClass(ClassName.HAS_DANGER)
} }
@ -181,14 +165,6 @@ const BaseInput = (($) => {
this.$mdbFormGroup.removeClass(ClassName.HAS_DANGER) this.$mdbFormGroup.removeClass(ClassName.HAS_DANGER)
} }
removeIsFilled() {
this.$mdbFormGroup.removeClass(ClassName.IS_FILLED)
}
addIsFilled() {
this.$mdbFormGroup.addClass(ClassName.IS_FILLED)
}
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() === '')
} }
@ -264,15 +240,6 @@ const BaseInput = (($) => {
return label 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 // Find mdb-form-group
findFormGroup(raiseError = true) { findFormGroup(raiseError = true) {
let fg = this.$element.closest(Selector.FORM_GROUP) 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 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: { ripples: {
//selector: ['.btn:not(.btn-link):not(.ripple-none)'] // testing only //selector: ['.btn:not(.btn-link):not(.ripple-none)'] // testing only
selector: [ selector: [
@ -49,43 +70,26 @@ const BootstrapMaterialDesign = (($) => {
'.ripple' // generic marker class to add ripple to elements '.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: { select: {
selector: ['select'] selector: ['select']
}, },
switch: { switch: {
selector: '.switch > label > input[type=checkbox]' selector: '.switch > label > input[type=checkbox]'
}, },
text: {
// omit inputs we have specialized components to handle
selector: [`input[type!='checkbox'][type!='radio'][type!='file']`]
},
textarea: { textarea: {
selector: ['textarea'] selector: ['textarea']
}, },
autofill: {
selector: 'body'
},
arrive: true, arrive: true,
// create an ordered component list for instantiation // create an ordered component list for instantiation
instantiation: [ instantiation: [
'ripples', 'ripples',
'checkbox', 'checkbox',
'checkboxInline', 'checkboxInline',
'collapseInline',
'file', 'file',
'radio', 'radio',
'radioInline', 'radioInline',

View File

@ -1,9 +1,9 @@
import BaseSelection from './baseSelection' import BaseSelection from './baseSelection'
import Text from './text' //import Text from './text'
import File from './file' //import File from './file'
import Radio from './radio' //import Radio from './radio'
import Textarea from './textarea' //import Textarea from './textarea'
import Select from './select' //import Select from './select'
import Util from './util' import Util from './util'
const Checkbox = (($) => { const Checkbox = (($) => {
@ -30,9 +30,9 @@ const Checkbox = (($) => {
class Checkbox extends BaseSelection { class Checkbox extends BaseSelection {
constructor($element, config, properties = {inputType: NAME, outerClass: NAME}) { constructor($element, config, properties = {inputType: NAME, outerClass: NAME}) {
super($element, $.extend(true, { super($element, $.extend(true,
invalidComponentMatches: [File, Radio, Text, Textarea, Select] //{invalidComponentMatches: [File, Radio, Text, Textarea, Select]},
}, Default, config), properties) Default, config), properties)
} }
dispose(dataKey = DATA_KEY) { 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 BaseInput from './baseInput'
import Checkbox from './checkbox' //import Checkbox from './checkbox'
import Radio from './radio' //import Radio from './radio'
import Switch from './switch' //import Switch from './switch'
import Text from './text' //import Text from './text'
import Textarea from './textarea' //import Textarea from './textarea'
import Select from './select' //import Select from './select'
import Util from './util' import Util from './util'
const File = (($) => { const File = (($) => {
@ -38,7 +38,9 @@ const File = (($) => {
class File extends BaseInput { class File extends BaseInput {
constructor($element, config) { 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) this.$mdbFormGroup.addClass(ClassName.IS_FILE)
} }

View File

@ -10,20 +10,19 @@
/* eslint-disable no-unused-vars */ /* eslint-disable no-unused-vars */
import '../../node_modules/babel-polyfill/dist/polyfill' import '../../node_modules/babel-polyfill/dist/polyfill'
import BaseInput from './baseInput' // invalidComponentMatches is currently disabled due to https://github.com/rollup/rollup/issues/428#issuecomment-170066452
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'
import Checkbox from './checkbox' import Checkbox from './checkbox'
import CheckboxInline from './checkboxInline' import CheckboxInline from './checkboxInline'
import Switch from './switch' import CollapseInline from './collapseInline'
import File from './file'
import Radio from './radio' import Radio from './radio'
import RadioInline from './radioInline' 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' import BootstrapMaterialDesign from './bootstrapMaterialDesign'
/* eslint-enable no-unused-vars */ /* eslint-enable no-unused-vars */

View File

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

View File

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

View File

@ -1,10 +1,10 @@
import BaseFormControl from './baseFormControl' import BaseFormControl from './baseFormControl'
import Checkbox from './checkbox' //import Checkbox from './checkbox'
import File from './file' //import File from './file'
import Radio from './radio' //import Radio from './radio'
import Switch from './switch' //import Switch from './switch'
import Textarea from './textarea' //import Textarea from './textarea'
import Select from './select' //import Select from './select'
import Util from './util' import Util from './util'
const Text = (($) => { const Text = (($) => {
@ -29,7 +29,9 @@ const Text = (($) => {
class Text extends BaseFormControl { class Text extends BaseFormControl {
constructor($element, config) { 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) { dispose(dataKey = DATA_KEY) {

View File

@ -1,10 +1,10 @@
import BaseFormControl from './baseFormControl' import BaseFormControl from './baseFormControl'
import Checkbox from './checkbox' //import Checkbox from './checkbox'
import File from './file' //import File from './file'
import Radio from './radio' //import Radio from './radio'
import Switch from './switch' //import Switch from './switch'
import Text from './text' //import Text from './text'
import Select from './select' //import Select from './select'
import Util from './util' import Util from './util'
const Textarea = (($) => { const Textarea = (($) => {
@ -29,7 +29,9 @@ const Textarea = (($) => {
class Textarea extends BaseFormControl { class Textarea extends BaseFormControl {
constructor($element, config) { 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() { dispose() {