Changing strategy on labels. Using js to resolve unmarked labels, otherwise going to specify the label variant as a class on the label itself. The js is just a fall back for default markup and specialized markup will win. i.e. mark any label.mdb-label and regardless of it's location, it will be used for styling. Configurable selectors in the config. On the plus side, if you are good with js resolution, this allows for globally specified label styles!

This commit is contained in:
Kevin Ross 2015-12-11 11:07:03 -06:00
parent 2b64baf94c
commit c0885dc2ee
19 changed files with 141 additions and 35 deletions

View File

@ -25,6 +25,7 @@
- title: Material Design
pages:
- title: Test
- title: Forms
- title: Components

View File

@ -107,12 +107,20 @@ class Application {
.tooltip('_fixTitle')
})
}
manipulateSearchBox() {
let $search = $('#search-input')
$search.wrap(`<div class='mdb-form-group'></div>`)
$search.before(`<label class='mdb-label-placeholder'>${$search.prop('placeholder')}</label>`)
$search.removeAttr('placeholder')
}
}
$(() => {
let app = new Application()
app.displayTypographyProperties()
app.initializeClipboard()
app.manipulateSearchBox()
// FIXME: file inputs seems to be in flux, delete the offending one for now.
$('#exampleInputFile').closest('.form-group').detach()

View File

@ -0,0 +1,15 @@
---
layout: docs
title: Test
group: material-design
---
{% example html %}
<form>
<fieldset class="form-group label-floating">
<label for="exampleInputEmail1">Email address</label>
<input type="email" class="form-control" id="exampleInputEmail1" placeholder="Enter email">
<span class="mdb-help">We'll never share your email with anyone else.</span>
</fieldset>
</form>
{% endexample %}

View File

@ -21,7 +21,7 @@ const Autofill = (($) => {
constructor($element, config) {
this.$element = $element
this.config = $.extend({}, Default, config)
this.config = $.extend(true, {}, Default, config)
this._watchLoading()
this._attachEventHandlers()

View File

@ -2,6 +2,23 @@ import Util from './util'
const BaseInput = (($) => {
const ClassName = {
FORM_GROUP: 'form-group',
MDB_FORM_GROUP: 'mdb-form-group',
MDB_LABEL: 'mdb-label',
MDB_LABEL_PLACEHOLDER: 'mdb-label-placeholder',
MDB_LABEL_FLOATING: 'mdb-label-floating',
HAS_DANGER: 'has-danger',
IS_EMPTY: 'is-empty',
IS_FOCUSED: 'is-focused'
}
const Selector = {
FORM_GROUP: `.${ClassName.FORM_GROUP}`,
MDB_FORM_GROUP: `.${ClassName.MDB_FORM_GROUP}`,
MDB_LABEL_WILDCARD: `label[class^='${ClassName.MDB_LABEL}'], label[class*=' ${ClassName.MDB_LABEL}']` // match any label variant if specified
}
const Default = {
validate: false,
formGroup: {
@ -10,25 +27,27 @@ const BaseInput = (($) => {
mdbFormGroup: {
template: `<span class='mdb-form-group'></span>`
},
mdbLabel: {
required: false,
// Prioritized find order for resolving the label to be used as an mdb-label if not specified in the markup
// - a function(thisComponent); or
// - a string selector used like $mdbFormGroup.find(selector)
//
// Note this only runs if $mdbFormGroup.find(Selector.MDB_LABEL_WILDCARD) fails to find a label (as authored in the markup)
//
selectors: [
`.form-control-label`, // in the case of horizontal or inline forms, this will be marked
`> label` // usual case for text inputs
],
className: `mdb-label`
},
requiredClasses: [],
invalidComponentMatches: [],
convertInputSizeVariations: true
}
const ClassName = {
FORM_GROUP: 'form-group',
MDB_FORM_GROUP: 'mdb-form-group',
HAS_DANGER: 'has-danger',
IS_EMPTY: 'is-empty',
IS_FOCUSED: 'is-focused'
}
const Selector = {
FORM_GROUP: `.${ClassName.FORM_GROUP}`,
MDB_FORM_GROUP: `.${ClassName.MDB_FORM_GROUP}`
}
const FormControlSizeConversions = {
const FormControlSizeMarkers = {
'form-control-lg': 'mdb-form-group-lg',
'form-control-sm': 'mdb-form-group-sm'
}
@ -48,7 +67,7 @@ const BaseInput = (($) => {
*/
constructor($element, config, properties = {}) {
this.$element = $element
this.config = $.extend({}, Default, config)
this.config = $.extend(true, {}, Default, config)
// set properties for use in the constructor initialization
for (let key in properties) {
@ -73,6 +92,9 @@ const BaseInput = (($) => {
// rendering changes once added.
this.$mdbFormGroup = this.resolveMdbFormGroup()
// Resolve and mark the mdbLabel if necessary as defined by the config
this.$mdbLabel = this.resolveMdbLabel()
// Signal to the mdb-form-group that a form-control-* variation is being used
this.resolveMdbFormGroupSizing()
@ -197,6 +219,48 @@ const BaseInput = (($) => {
return this.$element
}
// Will add mdb-label to mdb-form-group if not already specified
resolveMdbLabel() {
let label = this.$mdbFormGroup.find(Selector.MDB_LABEL_WILDCARD)
if (label === undefined || label.length === 0) {
// we need to find it based on the configured selectors
label = this.findMdbLabel(this.config.mdbLabel.required)
if (label === undefined || label.length === 0) {
// no label found, and finder did not require one
} else {
// a candidate label was found, add the configured default class name
label.addClass(this.config.mdbLabel.className)
}
}
return label
}
// Find mdb-label variant based on the config selectors
findMdbLabel(raiseError = true) {
let label = null
// use the specified selector order
for (let selector of this.config.mdbLabel.selectors) {
if ($.isFunction(selector)) {
label = selector(this)
} else {
label = this.$mdbFormGroup.find(selector)
}
if(label !== undefined && label.length > 0){
break;
}
}
if (label.length === 0 && raiseError) {
$.error(`Failed to find ${Selector.MDB_LABEL_WILDCARD} within form-group for ${Util.describe(this.$element)}`)
}
return label
}
// Find mdb-form-group
findMdbFormGroup(raiseError = true) {
let mfg = this.$element.closest(Selector.MDB_FORM_GROUP)
@ -223,10 +287,10 @@ const BaseInput = (($) => {
}
// Modification - Change text-sm/lg to form-group-sm/lg instead (preferred standard and simpler css/less variants)
for (let inputSize in FormControlSizeConversions) {
for (let inputSize in FormControlSizeMarkers) {
if (this.$element.hasClass(inputSize)) {
//this.$element.removeClass(inputSize)
this.$mdbFormGroup.addClass(FormControlSizeConversions[inputSize])
this.$mdbFormGroup.addClass(FormControlSizeMarkers[inputSize])
}
}
}

View File

@ -8,7 +8,22 @@ const BaseToggle = (($) => {
* Constants
* ------------------------------------------------------------------------
*/
const Default = {}
const Default = {
mdbLabel: {
required: false
// Prioritized find order for resolving the label to be used as an mdb-label if not specified in the markup
// - a function(thisComponent); or
// - a string selector used like $mdbFormGroup.find(selector)
//
// Note this only runs if $mdbFormGroup.find(Selector.MDB_LABEL_WILDCARD) fails to find a label (as authored in the markup)
//
//selectors: [
// `.form-control-label`, // in the case of horizontal or inline forms, this will be marked
// `> label` // usual case for text inputs
//]
}
}
const Selector = {
LABEL: 'label'
@ -26,7 +41,7 @@ const BaseToggle = (($) => {
// '.checkbox|switch|radio > label > input[type=checkbox|radio]'
// '.${this.outerClass} > label > input[type=${this.inputType}]'
super($element, $.extend({}, Default, config), properties)
super($element, $.extend(true, {}, Default, config), properties)
this.$element.after(this.config.template)
}

View File

@ -30,7 +30,10 @@ const BootstrapMaterialDesign = (($) => {
*/
const Default = {
global: {
validate: false
validate: false,
mdbLabel: {
className: `mdb-label`
}
},
ripples: {
selector: [
@ -100,7 +103,7 @@ const BootstrapMaterialDesign = (($) => {
constructor($element, config) {
this.$element = $element
this.config = $.extend({}, Default, config)
this.config = $.extend(true, {}, Default, config)
let $document = $(document)
for (let component of this.config.instantiation) {
@ -115,7 +118,7 @@ const BootstrapMaterialDesign = (($) => {
let selector = this._resolveSelector(componentConfig)
// mix in global options
componentConfig = $.extend({}, this.config.global, componentConfig)
componentConfig = $.extend(true, {}, this.config.global, componentConfig)
// create the jquery fn name e.g. 'mdbText' for 'text'
let jqueryFn = `mdb${component.charAt(0).toUpperCase() + component.slice(1)}`

View File

@ -30,7 +30,7 @@ const Checkbox = (($) => {
class Checkbox extends BaseToggle {
constructor($element, config, properties = {inputType: NAME, outerClass: NAME}) {
super($element, $.extend({
super($element, $.extend(true, {
invalidComponentMatches: [File, Radio, Text, Textarea, Select]
}, Default, config), properties)
}

View File

@ -22,7 +22,7 @@ const CheckboxInline = (($) => {
class CheckboxInline extends Checkbox {
constructor($element, config, properties = {inputType: 'checkbox', outerClass: 'checkbox-inline'}) {
super($element, $.extend({}, Default, config), properties)
super($element, $.extend(true, {}, Default, config), properties)
}
dispose() {

View File

@ -38,7 +38,7 @@ const File = (($) => {
class File extends BaseInput {
constructor($element, config) {
super($element, $.extend({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

@ -24,7 +24,7 @@ const Foo = (($) => {
constructor($element, config) {
this.$element = $element
this.config = $.extend({}, Default, config)
this.config = $.extend(true, {}, Default, config)
}
dispose() {

View File

@ -29,7 +29,7 @@ const Radio = (($) => {
class Radio extends BaseToggle {
constructor($element, config, properties = {inputType: NAME, outerClass: NAME}) {
super($element, $.extend({
super($element, $.extend(true, {
invalidComponentMatches: [Checkbox, File, Switch, Text]
}, Default, config), properties)
}

View File

@ -22,7 +22,7 @@ const RadioInline = (($) => {
class RadioInline extends Radio {
constructor($element, config, properties = {inputType: 'radio', outerClass: 'radio-inline'}) {
super($element, $.extend({}, Default, config), properties)
super($element, $.extend(true, {}, Default, config), properties)
}
dispose() {

View File

@ -49,7 +49,7 @@ const Ripples = (($) => {
this.$element = $element
//console.log(`Adding ripples to ${Util.describe(this.$element)}`) // eslint-disable-line no-console
this.config = $.extend({}, Default, config)
this.config = $.extend(true, {}, Default, config)
// attach initial listener
this.$element.on(this.config.triggerStart, this._onStartRipple)

View File

@ -30,7 +30,7 @@ const Select = (($) => {
class Select extends Text {
constructor($element, config) {
super($element, $.extend({invalidComponentMatches: [Checkbox, File, Radio, Switch, Text, Textarea]}, Default, config))
super($element, $.extend(true, {invalidComponentMatches: [Checkbox, File, Radio, Switch, Text, Textarea]}, Default, config))
}
dispose() {

View File

@ -24,7 +24,7 @@ const Switch = (($) => {
class Switch extends Checkbox {
constructor($element, config) {
super($element, $.extend({}, Default, config), 'checkbox', NAME)
super($element, $.extend(true, {}, Default, config), 'checkbox', NAME)
// selector: '.switch > label > input[type=checkbox]'
}

View File

@ -34,7 +34,7 @@ const Text = (($) => {
class Text extends BaseInput {
constructor($element, config) {
super($element, $.extend({invalidComponentMatches: [Checkbox, File, Radio, Select, Switch, Textarea]}, Default, config))
super($element, $.extend(true, {invalidComponentMatches: [Checkbox, File, Radio, Select, Switch, Textarea]}, Default, config))
// Initially mark as empty
if (this.isEmpty()) {

View File

@ -28,7 +28,7 @@ const Textarea = (($) => {
class Textarea extends Text {
constructor($element, config) {
super($element, $.extend({invalidComponentMatches: [Checkbox, File, Radio, Text, Select, Switch]}, Default, config))
super($element, $.extend(true, {invalidComponentMatches: [Checkbox, File, Radio, Text, Select, Switch]}, Default, config))
}
dispose() {

View File

@ -72,7 +72,7 @@ const Util = (($) => {
$element.css('border', '1px solid red')
}
console.error(message, $element) // eslint-disable-line no-console
$.error(message)
throw message
}
},