mirror of
https://github.com/mdbootstrap/mdb-ui-kit.git
synced 2024-11-10 19:57:13 +03:00
discretely separated all form input types into discrete es6 classes to allow for easy configuration/enforcement of markup/classes/structure
This commit is contained in:
parent
6f0e41a486
commit
108da48a0b
24
Gruntfile.js
24
Gruntfile.js
|
@ -105,11 +105,13 @@ module.exports = function (grunt) {
|
|||
'dist/js/babel/util.js': 'js/src/util.js',
|
||||
'dist/js/babel/ripples.js': 'js/src/ripples.js',
|
||||
'dist/js/babel/autofill.js': 'js/src/autofill.js',
|
||||
'dist/js/babel/textInput.js': 'js/src/textInput.js',
|
||||
'dist/js/babel/text.js': 'js/src/text.js',
|
||||
'dist/js/babel/textarea.js': 'js/src/textarea.js',
|
||||
'dist/js/babel/select.js': 'js/src/select.js',
|
||||
'dist/js/babel/checkbox.js': 'js/src/checkbox.js',
|
||||
'dist/js/babel/switch.js': 'js/src/switch.js',
|
||||
'dist/js/babel/radio.js': 'js/src/radio.js',
|
||||
'dist/js/babel/fileInput.js': 'js/src/fileInput.js',
|
||||
'dist/js/babel/fileInput.js': 'js/src/file.js',
|
||||
'dist/js/babel/bootstrapMaterialDesign.js': 'js/src/bootstrapMaterialDesign.js',
|
||||
}
|
||||
},
|
||||
|
@ -128,11 +130,13 @@ module.exports = function (grunt) {
|
|||
'docs/dist/js/babel/util.js': 'js/src/util.js',
|
||||
'docs/dist/js/babel/ripples.js': 'js/src/ripples.js',
|
||||
'docs/dist/js/babel/autofill.js': 'js/src/autofill.js',
|
||||
'docs/dist/js/babel/textInput.js': 'js/src/textInput.js',
|
||||
'docs/dist/js/babel/text.js': 'js/src/text.js',
|
||||
'docs/dist/js/babel/textarea.js': 'js/src/textarea.js',
|
||||
'docs/dist/js/babel/select.js': 'js/src/select.js',
|
||||
'docs/dist/js/babel/checkbox.js': 'js/src/checkbox.js',
|
||||
'docs/dist/js/babel/switch.js': 'js/src/switch.js',
|
||||
'docs/dist/js/babel/radio.js': 'js/src/radio.js',
|
||||
'docs/dist/js/babel/fileInput.js': 'js/src/fileInput.js',
|
||||
'docs/dist/js/babel/fileInput.js': 'js/src/file.js',
|
||||
'docs/dist/js/babel/bootstrapMaterialDesign.js': 'js/src/bootstrapMaterialDesign.js',
|
||||
}
|
||||
},
|
||||
|
@ -154,11 +158,13 @@ module.exports = function (grunt) {
|
|||
'dist/js/umd/util.js': 'js/src/util.js',
|
||||
'dist/js/umd/ripples.js': 'js/src/ripples.js',
|
||||
'dist/js/umd/autofill.js': 'js/src/autofill.js',
|
||||
'dist/js/umd/textInput.js': 'js/src/textInput.js',
|
||||
'dist/js/umd/text.js': 'js/src/text.js',
|
||||
'dist/js/umd/textarea.js': 'js/src/textarea.js',
|
||||
'dist/js/umd/select.js': 'js/src/select.js',
|
||||
'dist/js/umd/checkbox.js': 'js/src/checkbox.js',
|
||||
'dist/js/umd/switch.js': 'js/src/switch.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/file.js',
|
||||
'dist/js/umd/bootstrapMaterialDesign.js': 'js/src/bootstrapMaterialDesign.js',
|
||||
}
|
||||
}
|
||||
|
@ -216,11 +222,13 @@ module.exports = function (grunt) {
|
|||
'dist/js/babel/util.js',
|
||||
'dist/js/babel/ripples.js',
|
||||
'dist/js/babel/autofill.js',
|
||||
'dist/js/babel/textInput.js',
|
||||
'dist/js/babel/text.js',
|
||||
'dist/js/babel/textarea.js',
|
||||
'dist/js/babel/select.js',
|
||||
'dist/js/babel/checkbox.js',
|
||||
'dist/js/babel/switch.js',
|
||||
'dist/js/babel/radio.js',
|
||||
'dist/js/babel/fileInput.js',
|
||||
'dist/js/babel/file.js',
|
||||
'dist/js/babel/bootstrapMaterialDesign.js',
|
||||
],
|
||||
dest: 'dist/js/<%= pkg.name %>.js'
|
||||
|
|
|
@ -15,7 +15,9 @@
|
|||
"../dist/js/babel/bootstrapMaterialDesign.js",
|
||||
"../dist/js/babel/checkbox.js",
|
||||
"../dist/js/babel/fileInput.js",
|
||||
"../dist/js/babel/textInput.js",
|
||||
"../dist/js/babel/text.js",
|
||||
"../dist/js/babel/textarea.js",
|
||||
"../dist/js/babel/select.js",
|
||||
"../dist/js/babel/radio.js",
|
||||
"../dist/js/babel/ripples.js",
|
||||
"../dist/js/babel/switch.js",
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
//import Util from './util'
|
||||
|
||||
const Autofill = (($) => {
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
import Util from './util'
|
||||
|
||||
const BaseInput = (($) => {
|
||||
|
||||
const Default = {
|
||||
formGroup: {
|
||||
template: `<div class='form-group'></div>`,
|
||||
required: true,
|
||||
autoCreate: false
|
||||
autoCreate: true
|
||||
},
|
||||
requiredClasses: ['form-control'],
|
||||
invalidComponentMatches: []
|
||||
requiredClasses: [],
|
||||
invalidComponentMatches: [],
|
||||
convertInputSizeVariations: true
|
||||
}
|
||||
|
||||
const ClassName = {
|
||||
|
@ -20,6 +23,11 @@ const BaseInput = (($) => {
|
|||
FORM_GROUP: `.${ClassName.FORM_GROUP}` //,
|
||||
}
|
||||
|
||||
const FormControlSizeConversions = {
|
||||
'form-control-lg': 'form-group-lg',
|
||||
'form-control-sm': 'form-group-sm'
|
||||
}
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
* Class Definition
|
||||
|
@ -27,9 +35,9 @@ const BaseInput = (($) => {
|
|||
*/
|
||||
class BaseInput {
|
||||
|
||||
constructor(element, defaultConfig, config) {
|
||||
constructor(element, config) {
|
||||
this.$element = $(element)
|
||||
this.config = $.extend({}, Default, defaultConfig, config)
|
||||
this.config = $.extend({}, Default, config)
|
||||
|
||||
// Enforce no overlap between components to prevent side effects
|
||||
this._rejectInvalidComponentMatches()
|
||||
|
@ -48,6 +56,8 @@ const BaseInput = (($) => {
|
|||
// different components have different rules, always run this separately
|
||||
this.$formGroup = this.findFormGroup(this.config.formGroup.required)
|
||||
|
||||
this._convertFormControlSizeVariations()
|
||||
|
||||
this.addFocusListener()
|
||||
this.addChangeListener()
|
||||
}
|
||||
|
@ -67,11 +77,45 @@ const BaseInput = (($) => {
|
|||
}
|
||||
|
||||
addFocusListener() {
|
||||
// implement
|
||||
this.$element
|
||||
.on('focus', () => {
|
||||
this.addFormGroupFocus()
|
||||
})
|
||||
.on('blur', () => {
|
||||
this.removeFormGroupFocus()
|
||||
})
|
||||
}
|
||||
|
||||
addChangeListener() {
|
||||
// implement
|
||||
this.$element
|
||||
.on('keydown paste', (event) => {
|
||||
if (Util.isChar(event)) {
|
||||
this.removeIsEmpty()
|
||||
}
|
||||
})
|
||||
.on('keyup change', (event) => {
|
||||
|
||||
// make sure empty is added back when there is a programmatic value change.
|
||||
// NOTE: programmatic changing of value using $.val() must trigger the change event i.e. $.val('x').trigger('change')
|
||||
if (this.$element.val()) {
|
||||
this.addIsEmpty()
|
||||
} else {
|
||||
this.removeIsEmpty()
|
||||
}
|
||||
|
||||
// Validation events do not bubble, so they must be attached directly to the text: http://jsfiddle.net/PEpRM/1/
|
||||
// Further, even the bind method is being caught, but since we are already calling #checkValidity here, just alter
|
||||
// the form-group on change.
|
||||
//
|
||||
// NOTE: I'm not sure we should be intervening regarding validation, this seems better as a README and snippet of code.
|
||||
// BUT, I've left it here for backwards compatibility.
|
||||
let isValid = (typeof this.$element[0].checkValidity === 'undefined' || this.$element[0].checkValidity())
|
||||
if (isValid) {
|
||||
this.removeHasError()
|
||||
} else {
|
||||
this.addHasError()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
addFormGroupFocus() {
|
||||
|
@ -120,16 +164,7 @@ const BaseInput = (($) => {
|
|||
findFormGroup(raiseError = true) {
|
||||
let fg = this.$element.closest(Selector.FORM_GROUP) // note that form-group may be grandparent in the case of an input-group
|
||||
if (fg.length === 0 && raiseError) {
|
||||
$.error(`Failed to find form-group for ${this.$element}`)
|
||||
}
|
||||
return fg
|
||||
}
|
||||
|
||||
findOrCreateFormGroup() {
|
||||
let fg = this.$element.closest(Selector.FORM_GROUP) // note that form-group may be grandparent in the case of an baseInput-group
|
||||
if (fg === null || fg.length === 0) {
|
||||
this.$element.wrap(this.config.formGroup.template)
|
||||
fg = this.$element.closest(Selector.FORM_GROUP) // find node after attached (otherwise additional attachments don't work)
|
||||
$.error(`Failed to find form-group for ${Util.describe(this.$element)}`)
|
||||
}
|
||||
return fg
|
||||
}
|
||||
|
@ -137,15 +172,45 @@ const BaseInput = (($) => {
|
|||
// ------------------------------------------------------------------------
|
||||
// private
|
||||
_rejectInvalidComponentMatches() {
|
||||
for (let otherComponent in this.config.invalidComponentMatches) {
|
||||
for (let otherComponent of this.config.invalidComponentMatches) {
|
||||
otherComponent.rejectMatch(this.constructor.name, this.$element)
|
||||
}
|
||||
}
|
||||
|
||||
_rejectWithoutRequiredClasses() {
|
||||
for (let requiredClass in this.config.requiredClasses) {
|
||||
if (!this.$element.hasClass(requiredClass)) {
|
||||
$.error(`${this.constructor.name} elements require class: ${requiredClass}`)
|
||||
for (let requiredClass of this.config.requiredClasses) {
|
||||
|
||||
let found = false
|
||||
// allow one of several classes to be passed in x||y
|
||||
if (requiredClass.indexOf('||') !== -1) {
|
||||
let oneOf = requiredClass.split('||')
|
||||
for (let requiredClass of oneOf) {
|
||||
if (this.$element.hasClass(requiredClass)) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
} else if (this.$element.hasClass(requiredClass)) {
|
||||
found = true
|
||||
}
|
||||
|
||||
// error if not found
|
||||
if (!found) {
|
||||
$.error(`${this.constructor.name} element: ${Util.describe(this.$element)} requires class: ${requiredClass}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_convertFormControlSizeVariations() {
|
||||
if (!this.config.convertInputSizeVariations) {
|
||||
return
|
||||
}
|
||||
|
||||
// Modification - Change text-sm/lg to form-group-sm/lg instead (preferred standard and simpler css/less variants)
|
||||
for (let inputSize in FormControlSizeConversions) {
|
||||
if (this.$element.hasClass(inputSize)) {
|
||||
this.$element.removeClass(inputSize)
|
||||
this.$formGroup.addClass(FormControlSizeConversions[inputSize])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
import BaseInput from './baseInput'
|
||||
//import TextInput from './textInput'
|
||||
//import FileInput from './fileInput'
|
||||
//import Radio from './radio'
|
||||
//import Switch from './switch'
|
||||
import Util from './util'
|
||||
|
||||
const BaseToggle = (($) => {
|
||||
|
@ -13,9 +9,6 @@ const BaseToggle = (($) => {
|
|||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
const Default = {
|
||||
formGroup: {
|
||||
autoCreate: true
|
||||
}
|
||||
}
|
||||
|
||||
const Selector = {
|
||||
|
@ -30,7 +23,7 @@ const BaseToggle = (($) => {
|
|||
class BaseToggle extends BaseInput {
|
||||
|
||||
constructor(element, config, inputType, outerClass) {
|
||||
super(element, Default, config)
|
||||
super(element, $.extend({}, Default, config))
|
||||
this.$element.after(this.config.template)
|
||||
// '.checkbox|switch|radio > label > input[type=checkbox|radio]'
|
||||
// '.${this.outerClass} > label > input[type=${this.inputType}]'
|
||||
|
|
31
js/src/bootstrapMaterialDesign.js
vendored
31
js/src/bootstrapMaterialDesign.js
vendored
|
@ -1,15 +1,8 @@
|
|||
//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,
|
||||
* switch, fileInput.
|
||||
*
|
||||
*/
|
||||
const BootstrapMaterialDesign = (($) => {
|
||||
|
||||
|
@ -42,12 +35,14 @@ const BootstrapMaterialDesign = (($) => {
|
|||
'.ripple' // generic marker class to add ripple to elements
|
||||
]
|
||||
},
|
||||
textInput: {
|
||||
selector: [
|
||||
'input[type=text]',
|
||||
'textarea',
|
||||
'select'
|
||||
]
|
||||
text: {
|
||||
selector: ['input[type=text]']
|
||||
},
|
||||
textarea: {
|
||||
selector: ['textarea']
|
||||
},
|
||||
select: {
|
||||
selector: ['select']
|
||||
},
|
||||
checkbox: {
|
||||
selector: '.checkbox > label > input[type=checkbox]'
|
||||
|
@ -58,7 +53,7 @@ const BootstrapMaterialDesign = (($) => {
|
|||
radio: {
|
||||
selector: '.radio > label > input[type=radio]'
|
||||
},
|
||||
fileInput: {
|
||||
file: {
|
||||
selector: 'input[type=file]'
|
||||
},
|
||||
autofill: {
|
||||
|
@ -68,11 +63,13 @@ const BootstrapMaterialDesign = (($) => {
|
|||
// create an ordered component list for instantiation
|
||||
instantiation: [
|
||||
'ripples',
|
||||
'textInput',
|
||||
'checkbox',
|
||||
'switch',
|
||||
'file',
|
||||
'radio',
|
||||
'fileInput',
|
||||
'switch',
|
||||
'text',
|
||||
'textarea',
|
||||
'select',
|
||||
'autofill'
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import BaseToggle from './baseToggle'
|
||||
import TextInput from './textInput'
|
||||
import FileInput from './fileInput'
|
||||
import Text from './text'
|
||||
import File from './file'
|
||||
import Radio from './radio'
|
||||
import Textarea from './textare'
|
||||
import Select from './select'
|
||||
import Util from './util'
|
||||
|
||||
const Checkbox = (($) => {
|
||||
|
@ -16,8 +18,7 @@ const Checkbox = (($) => {
|
|||
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
||||
|
||||
const Default = {
|
||||
template: `<span class='checkbox-decorator'><span class='check'></span></span>`,
|
||||
invalidComponentMatches: [FileInput, Radio, TextInput]
|
||||
template: `<span class='checkbox-decorator'><span class='check'></span></span>`
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -28,7 +29,9 @@ const Checkbox = (($) => {
|
|||
class Checkbox extends BaseToggle {
|
||||
|
||||
constructor(element, config, inputType = NAME, outerClass = NAME) {
|
||||
super(element, $.extend({}, Default, config), inputType, outerClass)
|
||||
super(element, $.extend({
|
||||
invalidComponentMatches: [File, Radio, Text, Textarea, Select]
|
||||
}, Default, config), inputType, outerClass)
|
||||
}
|
||||
|
||||
dispose() {
|
||||
|
|
|
@ -2,30 +2,24 @@ import BaseInput from './baseInput'
|
|||
import Checkbox from './checkbox'
|
||||
import Radio from './radio'
|
||||
import Switch from './switch'
|
||||
import TextInput from './textInput'
|
||||
import Text from './text'
|
||||
import Textarea from './textare'
|
||||
import Select from './select'
|
||||
import Util from './util'
|
||||
|
||||
// FileInput decorator, to be called after Input
|
||||
const FileInput = (($) => {
|
||||
const File = (($) => {
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
* Constants
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
const NAME = 'fileInput'
|
||||
const NAME = 'file'
|
||||
const DATA_KEY = `mdb.${NAME}`
|
||||
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
||||
|
||||
const Default = {
|
||||
formGroup: {
|
||||
autoCreate: true
|
||||
},
|
||||
invalidComponentMatches: [Checkbox, Radio, Switch, TextInput]
|
||||
}
|
||||
|
||||
const ClassName = {
|
||||
IS_FILEINPUT: 'is-fileinput'
|
||||
IS_FILE: 'is-file'
|
||||
}
|
||||
|
||||
const Selector = {
|
||||
|
@ -37,12 +31,12 @@ const FileInput = (($) => {
|
|||
* Class Definition
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
class FileInput extends BaseInput {
|
||||
class File extends BaseInput {
|
||||
|
||||
constructor(element, config) {
|
||||
super(element, Default, config)
|
||||
super(element, $.extend({invalidComponentMatches: [Checkbox, Radio, Text, Textarea, Select, Switch]}, config))
|
||||
|
||||
this.$formGroup.addClass(ClassName.IS_FILEINPUT)
|
||||
this.$formGroup.addClass(ClassName.IS_FILE)
|
||||
}
|
||||
|
||||
dispose() {
|
||||
|
@ -105,7 +99,7 @@ const FileInput = (($) => {
|
|||
let data = $element.data(DATA_KEY)
|
||||
|
||||
if (!data) {
|
||||
data = new FileInput(this, config)
|
||||
data = new File(this, config)
|
||||
$element.data(DATA_KEY, data)
|
||||
}
|
||||
})
|
||||
|
@ -117,15 +111,15 @@ const FileInput = (($) => {
|
|||
* jQuery
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
$.fn[NAME] = FileInput._jQueryInterface
|
||||
$.fn[NAME].Constructor = FileInput
|
||||
$.fn[NAME] = File._jQueryInterface
|
||||
$.fn[NAME].Constructor = File
|
||||
$.fn[NAME].noConflict = () => {
|
||||
$.fn[NAME] = JQUERY_NO_CONFLICT
|
||||
return FileInput._jQueryInterface
|
||||
return File._jQueryInterface
|
||||
}
|
||||
|
||||
return FileInput
|
||||
return File
|
||||
|
||||
})(jQuery)
|
||||
|
||||
export default FileInput
|
||||
export default File
|
|
@ -1,11 +1,10 @@
|
|||
import BaseToggle from './baseToggle'
|
||||
import TextInput from './textInput'
|
||||
import FileInput from './fileInput'
|
||||
import Text from './text'
|
||||
import File from './file'
|
||||
import Checkbox from './checkbox'
|
||||
import Switch from './switch'
|
||||
import Util from './util'
|
||||
|
||||
// Radio decorator, to be called after Input
|
||||
const Radio = (($) => {
|
||||
|
||||
/**
|
||||
|
@ -18,8 +17,7 @@ const Radio = (($) => {
|
|||
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
||||
|
||||
const Default = {
|
||||
template: `<span class='radio-decorator'></span><span class='check'></span>`,
|
||||
invalidComponentMatches: [Checkbox, FileInput, Switch, TextInput]
|
||||
template: `<span class='radio-decorator'></span><span class='check'></span>`
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -30,7 +28,9 @@ const Radio = (($) => {
|
|||
class Radio extends BaseToggle {
|
||||
|
||||
constructor(element, config) {
|
||||
super(element, $.extend({}, Default, config), NAME, NAME)
|
||||
super(element, $.extend({
|
||||
invalidComponentMatches: [Checkbox, File, Switch, Text]
|
||||
}, Default, config), NAME, NAME)
|
||||
}
|
||||
|
||||
dispose() {
|
||||
|
|
87
js/src/select.js
Normal file
87
js/src/select.js
Normal file
|
@ -0,0 +1,87 @@
|
|||
import Checkbox from './checkbox'
|
||||
import File from './file'
|
||||
import Radio from './radio'
|
||||
import Switch from './switch'
|
||||
import Text from './text'
|
||||
import Textarea from './textare'
|
||||
import Util from './util'
|
||||
|
||||
const Select = (($) => {
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
* Constants
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
const NAME = 'select'
|
||||
const DATA_KEY = `mdb.${NAME}`
|
||||
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
||||
|
||||
const Default = {
|
||||
requiredClasses: ['form-control||c-select']
|
||||
}
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
* Class Definition
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
class Select extends Text {
|
||||
|
||||
constructor(element, config) {
|
||||
super(element, $.extend({invalidComponentMatches: [Checkbox, File, Radio, Switch, Text, Textarea]}, Default, config))
|
||||
}
|
||||
|
||||
dispose() {
|
||||
super.dispose(DATA_KEY)
|
||||
}
|
||||
|
||||
static matches($element) {
|
||||
if ($element.prop('tagName') === 'select') {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
static rejectMatch(component, $element) {
|
||||
Util.assert(this.matches($element), `${component} component is invalid for <select>.`)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// protected
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// private
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// static
|
||||
static _jQueryInterface(config) {
|
||||
return this.each(function () {
|
||||
let $element = $(this)
|
||||
let data = $element.data(DATA_KEY)
|
||||
|
||||
if (!data) {
|
||||
data = new Select(this, config)
|
||||
$element.data(DATA_KEY, data)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
* jQuery
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
$.fn[NAME] = Select._jQueryInterface
|
||||
$.fn[NAME].Constructor = Select
|
||||
$.fn[NAME].noConflict = () => {
|
||||
$.fn[NAME] = JQUERY_NO_CONFLICT
|
||||
return Select._jQueryInterface
|
||||
}
|
||||
|
||||
return Select
|
||||
|
||||
})(jQuery)
|
||||
|
||||
export default Select
|
|
@ -1,6 +1,5 @@
|
|||
import Checkbox from './checkbox'
|
||||
|
||||
// Switch decorator, to be called after Input
|
||||
const Switch = (($) => {
|
||||
|
||||
/**
|
||||
|
|
97
js/src/text.js
Normal file
97
js/src/text.js
Normal file
|
@ -0,0 +1,97 @@
|
|||
import BaseInput from './baseInput'
|
||||
import Checkbox from './checkbox'
|
||||
import File from './file'
|
||||
import Radio from './radio'
|
||||
import Switch from './switch'
|
||||
import Textarea from './textare'
|
||||
import Select from './select'
|
||||
import Util from './util'
|
||||
|
||||
const Text = (($) => {
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
* Constants
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
const NAME = 'text'
|
||||
const DATA_KEY = `mdb.${NAME}`
|
||||
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
||||
|
||||
const Default = {
|
||||
template: `<span class='text-input-decorator'></span>`,
|
||||
requiredClasses: ['form-control']
|
||||
}
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
* Class Definition
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
class Text extends BaseInput {
|
||||
|
||||
constructor(element, config) {
|
||||
super(element, $.extend({invalidComponentMatches: [Checkbox, File, Radio, Select, Switch, Textarea]}, Default, config))
|
||||
|
||||
// Initially mark as empty
|
||||
if (this.isEmpty()) {
|
||||
this.addIsEmpty()
|
||||
}
|
||||
|
||||
// Add marker div the end of the form-group
|
||||
this.$formGroup.append(this.config.template)
|
||||
}
|
||||
|
||||
dispose(dataKey = DATA_KEY) {
|
||||
super.dispose(dataKey)
|
||||
}
|
||||
|
||||
static matches($element) {
|
||||
if ($element.attr('type') === 'text') {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
static rejectMatch(component, $element) {
|
||||
Util.assert(this.matches($element), `${component} component is invalid for type='text'.`)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// protected
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// private
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// static
|
||||
static _jQueryInterface(config) {
|
||||
return this.each(function () {
|
||||
let $element = $(this)
|
||||
let data = $element.data(DATA_KEY)
|
||||
|
||||
if (!data) {
|
||||
data = new Text(this, config)
|
||||
$element.data(DATA_KEY, data)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
* jQuery
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
$.fn[NAME] = Text._jQueryInterface
|
||||
$.fn[NAME].Constructor = Text
|
||||
$.fn[NAME].noConflict = () => {
|
||||
$.fn[NAME] = JQUERY_NO_CONFLICT
|
||||
return Text._jQueryInterface
|
||||
}
|
||||
|
||||
return Text
|
||||
|
||||
})(jQuery)
|
||||
|
||||
export default Text
|
|
@ -1,167 +0,0 @@
|
|||
import BaseInput from './baseInput'
|
||||
import Checkbox from './checkbox'
|
||||
import FileInput from './fileInput'
|
||||
import Radio from './radio'
|
||||
import Switch from './switch'
|
||||
import Util from './util'
|
||||
|
||||
const TextInput = (($) => {
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
* Constants
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
const NAME = 'textInput'
|
||||
const DATA_KEY = `mdb.${NAME}`
|
||||
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
||||
|
||||
const Default = {
|
||||
convertInputSizeVariations: true,
|
||||
template: `<span class='material-input'></span>`,
|
||||
formGroup: {
|
||||
autoCreate: true
|
||||
},
|
||||
requiredClasses: ['form-control'],
|
||||
invalidComponentMatches: [Checkbox, FileInput, Radio, Switch]
|
||||
}
|
||||
|
||||
const InputSizeConversions = {
|
||||
'textInput-lg': 'form-group-lg',
|
||||
'textInput-sm': 'form-group-sm'
|
||||
}
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
* Class Definition
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
class TextInput extends BaseInput {
|
||||
|
||||
constructor(element, config) {
|
||||
super(element, Default, config)
|
||||
|
||||
this._convertInputSizeVariations()
|
||||
|
||||
// Initially mark as empty
|
||||
if (this.isEmpty()) {
|
||||
this.addIsEmpty()
|
||||
}
|
||||
|
||||
// Add marker div the end of the form-group
|
||||
this.$formGroup.append(this.config.template)
|
||||
}
|
||||
|
||||
dispose() {
|
||||
super.dispose(DATA_KEY)
|
||||
}
|
||||
|
||||
static matches($element) {
|
||||
if (
|
||||
($element.attr('type') === 'text')
|
||||
|| ($element.prop('tagName') === 'textarea')
|
||||
|| ($element.prop('tagName') === 'select')
|
||||
) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
static rejectMatch(component, $element) {
|
||||
Util.assert(this.matches($element), `${component} component is invalid for type='text'.`)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// protected
|
||||
|
||||
addFocusListener() {
|
||||
this.$element
|
||||
.on('focus', () => {
|
||||
this.addFormGroupFocus()
|
||||
})
|
||||
.on('blur', () => {
|
||||
this.removeFormGroupFocus()
|
||||
})
|
||||
}
|
||||
|
||||
addChangeListener() {
|
||||
this.$element
|
||||
.on('keydown paste', (event) => {
|
||||
if (Util.isChar(event)) {
|
||||
this.removeIsEmpty()
|
||||
}
|
||||
})
|
||||
.on('keyup change', (event) => {
|
||||
|
||||
// make sure empty is added back when there is a programmatic value change.
|
||||
// NOTE: programmatic changing of value using $.val() must trigger the change event i.e. $.val('x').trigger('change')
|
||||
if (this.$element.val()) {
|
||||
this.addIsEmpty()
|
||||
} else {
|
||||
this.removeIsEmpty()
|
||||
}
|
||||
|
||||
// Validation events do not bubble, so they must be attached directly to the textInput: http://jsfiddle.net/PEpRM/1/
|
||||
// Further, even the bind method is being caught, but since we are already calling #checkValidity here, just alter
|
||||
// the form-group on change.
|
||||
//
|
||||
// NOTE: I'm not sure we should be intervening regarding validation, this seems better as a README and snippet of code.
|
||||
// BUT, I've left it here for backwards compatibility.
|
||||
let isValid = (typeof this.$element[0].checkValidity === 'undefined' || this.$element[0].checkValidity())
|
||||
if (isValid) {
|
||||
this.removeHasError()
|
||||
} else {
|
||||
this.addHasError()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// private
|
||||
|
||||
_convertInputSizeVariations() {
|
||||
if (!this.config.convertInputSizeVariations) {
|
||||
return
|
||||
}
|
||||
|
||||
// Modification - Change textInput-sm/lg to form-group-sm/lg instead (preferred standard and simpler css/less variants)
|
||||
for (let inputSize in InputSizeConversions) {
|
||||
if (this.$element.hasClass(inputSize)) {
|
||||
this.$element.removeClass(inputSize)
|
||||
this.$formGroup.addClass(InputSizeConversions[inputSize])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// static
|
||||
static _jQueryInterface(config) {
|
||||
return this.each(function () {
|
||||
let $element = $(this)
|
||||
let data = $element.data(DATA_KEY)
|
||||
|
||||
if (!data) {
|
||||
data = new TextInput(this, config)
|
||||
$element.data(DATA_KEY, data)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
* jQuery
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
$.fn[NAME] = TextInput._jQueryInterface
|
||||
$.fn[NAME].Constructor = TextInput
|
||||
$.fn[NAME].noConflict = () => {
|
||||
$.fn[NAME] = JQUERY_NO_CONFLICT
|
||||
return TextInput._jQueryInterface
|
||||
}
|
||||
|
||||
return TextInput
|
||||
|
||||
})(jQuery)
|
||||
|
||||
export default TextInput
|
85
js/src/textarea.js
Normal file
85
js/src/textarea.js
Normal file
|
@ -0,0 +1,85 @@
|
|||
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 = (($) => {
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
* Constants
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
const NAME = 'textarea'
|
||||
const DATA_KEY = `mdb.${NAME}`
|
||||
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
||||
|
||||
const Default = {}
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
* Class Definition
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
class Textarea extends Text {
|
||||
|
||||
constructor(element, config) {
|
||||
super(element, $.extend({invalidComponentMatches: [Checkbox, File, Radio, Text, Select, Switch]}, Default, config))
|
||||
}
|
||||
|
||||
dispose() {
|
||||
super.dispose(DATA_KEY)
|
||||
}
|
||||
|
||||
static matches($element) {
|
||||
if ($element.prop('tagName') === 'textarea') {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
static rejectMatch(component, $element) {
|
||||
Util.assert(this.matches($element), `${component} component is invalid for <textarea>.`)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// protected
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// private
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// static
|
||||
static _jQueryInterface(config) {
|
||||
return this.each(function () {
|
||||
let $element = $(this)
|
||||
let data = $element.data(DATA_KEY)
|
||||
|
||||
if (!data) {
|
||||
data = new Textarea(this, config)
|
||||
$element.data(DATA_KEY, data)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ------------------------------------------------------------------------
|
||||
* jQuery
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
$.fn[NAME] = Textarea._jQueryInterface
|
||||
$.fn[NAME].Constructor = Textarea
|
||||
$.fn[NAME].noConflict = () => {
|
||||
$.fn[NAME] = JQUERY_NO_CONFLICT
|
||||
return Textarea._jQueryInterface
|
||||
}
|
||||
|
||||
return Textarea
|
||||
|
||||
})(jQuery)
|
||||
|
||||
export default Textarea
|
|
@ -70,6 +70,10 @@ const Util = (($) => {
|
|||
if (test) {
|
||||
$.error(message)
|
||||
}
|
||||
},
|
||||
|
||||
describe($element) {
|
||||
return `${$element[0].outerHTML.split('>')[0]}>`
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -220,7 +220,7 @@
|
|||
box-shadow: none;
|
||||
transition-duration: 0.3s;
|
||||
|
||||
.material-input:after {
|
||||
.text-input-decorator:after {
|
||||
background-color: $brand-primary;
|
||||
}
|
||||
}
|
||||
|
@ -259,7 +259,7 @@
|
|||
select {
|
||||
appearance: none; // Fix for OS X
|
||||
|
||||
& ~ .material-input:after {
|
||||
& ~ .text-input-decorator:after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -159,8 +159,8 @@
|
|||
// margin: 0;
|
||||
// padding: 0;
|
||||
//
|
||||
// .material-input:before,
|
||||
// &.is-focused .material-input:after {
|
||||
// .text-input-decorator:before,
|
||||
// &.is-focused .text-input-decorator:after {
|
||||
// background-color: inherit;
|
||||
// }
|
||||
// }
|
||||
|
|
Loading…
Reference in New Issue
Block a user