From c0885dc2eed1cb424634e8787f093503441e9117 Mon Sep 17 00:00:00 2001 From: Kevin Ross Date: Fri, 11 Dec 2015 11:07:03 -0600 Subject: [PATCH] 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! --- docs/_data/nav.yml | 1 + docs/assets/js/src/application.js | 8 +++ docs/material-design/test.md | 15 +++++ js/src/autofill.js | 2 +- js/src/baseInput.js | 98 +++++++++++++++++++++++++------ js/src/baseToggle.js | 19 +++++- js/src/bootstrapMaterialDesign.js | 9 ++- js/src/checkbox.js | 2 +- js/src/checkboxInline.js | 2 +- js/src/file.js | 2 +- js/src/old/es6Template.js | 2 +- js/src/radio.js | 2 +- js/src/radioInline.js | 2 +- js/src/ripples.js | 2 +- js/src/select.js | 2 +- js/src/switch.js | 2 +- js/src/text.js | 2 +- js/src/textarea.js | 2 +- js/src/util.js | 2 +- 19 files changed, 141 insertions(+), 35 deletions(-) create mode 100644 docs/material-design/test.md diff --git a/docs/_data/nav.yml b/docs/_data/nav.yml index 7f101146..efc9e696 100644 --- a/docs/_data/nav.yml +++ b/docs/_data/nav.yml @@ -25,6 +25,7 @@ - title: Material Design pages: + - title: Test - title: Forms - title: Components diff --git a/docs/assets/js/src/application.js b/docs/assets/js/src/application.js index 2b88f802..b903c88c 100644 --- a/docs/assets/js/src/application.js +++ b/docs/assets/js/src/application.js @@ -107,12 +107,20 @@ class Application { .tooltip('_fixTitle') }) } + + manipulateSearchBox() { + let $search = $('#search-input') + $search.wrap(`
`) + $search.before(``) + $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() diff --git a/docs/material-design/test.md b/docs/material-design/test.md new file mode 100644 index 00000000..ebe66430 --- /dev/null +++ b/docs/material-design/test.md @@ -0,0 +1,15 @@ +--- +layout: docs +title: Test +group: material-design +--- + +{% example html %} +
+
+ + + We'll never share your email with anyone else. +
+
+{% endexample %} diff --git a/js/src/autofill.js b/js/src/autofill.js index 96ead153..6a5b6e09 100644 --- a/js/src/autofill.js +++ b/js/src/autofill.js @@ -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() diff --git a/js/src/baseInput.js b/js/src/baseInput.js index 0efda33b..f67f1179 100644 --- a/js/src/baseInput.js +++ b/js/src/baseInput.js @@ -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: `` }, + 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]) } } } diff --git a/js/src/baseToggle.js b/js/src/baseToggle.js index dbe91886..29a769e2 100644 --- a/js/src/baseToggle.js +++ b/js/src/baseToggle.js @@ -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) } diff --git a/js/src/bootstrapMaterialDesign.js b/js/src/bootstrapMaterialDesign.js index c5c9855d..cf3915b0 100644 --- a/js/src/bootstrapMaterialDesign.js +++ b/js/src/bootstrapMaterialDesign.js @@ -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)}` diff --git a/js/src/checkbox.js b/js/src/checkbox.js index c4692662..44c5d789 100644 --- a/js/src/checkbox.js +++ b/js/src/checkbox.js @@ -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) } diff --git a/js/src/checkboxInline.js b/js/src/checkboxInline.js index 1cc0eaa0..6d06ce42 100644 --- a/js/src/checkboxInline.js +++ b/js/src/checkboxInline.js @@ -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() { diff --git a/js/src/file.js b/js/src/file.js index 8a10fe8f..ea04046b 100644 --- a/js/src/file.js +++ b/js/src/file.js @@ -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) } diff --git a/js/src/old/es6Template.js b/js/src/old/es6Template.js index 3e7ec2c7..06ace1ca 100644 --- a/js/src/old/es6Template.js +++ b/js/src/old/es6Template.js @@ -24,7 +24,7 @@ const Foo = (($) => { constructor($element, config) { this.$element = $element - this.config = $.extend({}, Default, config) + this.config = $.extend(true, {}, Default, config) } dispose() { diff --git a/js/src/radio.js b/js/src/radio.js index 141fa4ec..1a49f2c7 100644 --- a/js/src/radio.js +++ b/js/src/radio.js @@ -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) } diff --git a/js/src/radioInline.js b/js/src/radioInline.js index 3272260d..76dc006e 100644 --- a/js/src/radioInline.js +++ b/js/src/radioInline.js @@ -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() { diff --git a/js/src/ripples.js b/js/src/ripples.js index 613febee..38875474 100644 --- a/js/src/ripples.js +++ b/js/src/ripples.js @@ -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) diff --git a/js/src/select.js b/js/src/select.js index e4fedfe4..40233e6c 100644 --- a/js/src/select.js +++ b/js/src/select.js @@ -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() { diff --git a/js/src/switch.js b/js/src/switch.js index bc2687ef..93656511 100644 --- a/js/src/switch.js +++ b/js/src/switch.js @@ -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]' } diff --git a/js/src/text.js b/js/src/text.js index 2fb023ab..6c3cff3d 100644 --- a/js/src/text.js +++ b/js/src/text.js @@ -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()) { diff --git a/js/src/textarea.js b/js/src/textarea.js index cba01c22..7e377747 100644 --- a/js/src/textarea.js +++ b/js/src/textarea.js @@ -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() { diff --git a/js/src/util.js b/js/src/util.js index 60c27f7a..cb37f320 100644 --- a/js/src/util.js +++ b/js/src/util.js @@ -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 } },