From f6b38fafb72992b73312f55e1827ad468c5ac70d Mon Sep 17 00:00:00 2001 From: mbeard Date: Wed, 25 Mar 2015 15:32:06 -0400 Subject: [PATCH 1/4] refactoring of radio button --- index.html | 12 +- index.js | 23 +-- js/radio.js | 211 ++++++++++++------------- test/markup/radio-markup.html | 55 +++---- test/radio-test.js | 284 +++++++++++++++++++++++++++------- 5 files changed, 371 insertions(+), 214 deletions(-) diff --git a/index.html b/index.html index 1b4a6a68e..6afd4d4f2 100644 --- a/index.html +++ b/index.html @@ -688,13 +688,13 @@

Radio Buttons

@@ -767,6 +767,14 @@

Radio Buttons

Custom inline highlight radio +
+ + + + + + +
diff --git a/index.js b/index.js index ee19725aa..342e7d701 100644 --- a/index.js +++ b/index.js @@ -426,22 +426,27 @@ define(function (require) { // sample method buttons $('#btnRadioDisable').on('click', function () { - $('[name=radio1]').radio('disable'); + console.log('in disable'); + $('#myCustomRadio1').radio('disable'); }); $('#btnRadioEnable').on('click', function () { - $('[name=radio1]').radio('enable'); + $('#myCustomRadio1').radio('enable'); }); $('#btnRadioDestroy').on('click', function () { - var $container = $('#myCustomRadio1').parents('.thin-box:first'); + var $container = $('#myCustomRadio1').parent(); var markup = $('#myCustomRadio1').radio('destroy'); + log(markup); $container.append(markup); - $('#myRadio1').radio(); }); - $('#btnRadioInlineDestroy').on('click', function () { - var $container = $('#myCustomInlineRadio1').parents('.thin-box:first'); - var markup = $('#myCustomInlineRadio1').radio('destroy'); - $container.append(markup); - $('#myCustomInlineRadio1').radio(); + $('#btnRadioIsChecked').on('click', function () { + var checked = $('#myCustomRadio1').radio('isChecked'); + log(checked); + }); + $('#btnRadioCheck').on('click', function () { + $('#myCustomRadio1').radio('check'); + }); + $('#btnRadioUncheck').on('click', function () { + $('#myCustomRadio1').radio('uncheck'); }); diff --git a/js/radio.js b/js/radio.js index ceecbd8e8..e04eb0885 100644 --- a/js/radio.js +++ b/js/radio.js @@ -31,152 +31,132 @@ var Radio = function (element, options) { this.options = $.extend({}, $.fn.radio.defaults, options); - // cache elements - this.$radio = $(element).is('input[type="radio"]') ? $(element) : $(element).find('input[type="radio"]:first'); - this.$label = this.$radio.parent(); - this.groupName = this.$radio.attr('name'); - this.$blockWrapper = this.$label.parent('.radio'); // only used if block radio control, otherwise radio is inline - this.isBlockWrapped = true; // initialized as a block radio control - this.$toggleContainer = null; - - if (this.$blockWrapper.length === 0) { - this.isBlockWrapped = false; + if(element.tagName.toLowerCase() !== 'label') { + //console.log('initialize radio on the label that wraps the radio'); + return; } - var toggleSelector = this.$radio.attr('data-toggle'); - if (toggleSelector) { - this.$toggleContainer = $(toggleSelector); - } + // cache elements + this.$label = $(element); + this.$radio = this.$label.find('input[type="radio"]'); + this.groupName = this.$radio.attr('name'); // don't cache group itself since items can be added programmatically - // set default state - this.setState(this.$radio); + // determine if a toggle container is specified + var containerSelector = this.$radio.attr('data-toggle'); + this.$toggleContainer = $(containerSelector); + + // handle internal events + this.$radio.on('change', $.proxy(this.itemchecked, this)); - // handle events - this.$radio.on('change.fu.radio', $.proxy(this.itemchecked, this)); + // set default state + this.setInitialState(); }; Radio.prototype = { constructor: Radio, - destroy: function () { - // remove any external bindings - // [none] - // empty elements to return to original markup - // [none] - // return string of markup - if (this.isBlockWrapped) { - this.$blockWrapper.remove(); - return this.$blockWrapper[0].outerHTML; - } else { - this.$label.remove(); - return this.$label[0].outerHTML; - } + setInitialState: function() { + var $radio = this.$radio; + var $lbl = this.$label; - }, + // get current state of input + var checked = $radio.prop('checked'); + var disabled = $radio.prop('disabled'); - setState: function ($radio) { - $radio = $radio || this.$radio; + // sync label class with input state + this.setCheckedState($radio, checked); + this.setDisabledState($radio, disabled); + }, - var checked = $radio.is(':checked'); - var disabled = !!$radio.prop('disabled'); + resetGroup: function() { + var $radios = $('input[name="' + this.groupName + '"]'); + $radios.each(function(index, item) { + var $radio = $(item); + var $lbl = $radio.parent(); + var containerSelector = $radio.attr('data-toggle'); + var $containerToggle = $(containerSelector); - this.$label.removeClass('checked'); - if (this.isBlockWrapped) { - this.$blockWrapper.removeClass('checked disabled'); - } - // set state of radio - if (checked === true) { - this.$label.addClass('checked'); - if (this.isBlockWrapped) { - this.$blockWrapper.addClass('checked'); - } + $lbl.removeClass('checked'); + $containerToggle.addClass('hidden'); + }); + }, - } + setCheckedState: function(element, checked) { + // reset all items in group + this.resetGroup(); - if (disabled === true) { - this.$label.addClass('disabled'); - if (this.isBlockWrapped) { - this.$blockWrapper.addClass('disabled'); - } + var $radio = element; + var $lbl = $radio.parent(); + var containerSelector = $radio.attr('data-toggle'); + var $containerToggle = $(containerSelector); + if(checked) { + $radio.prop('checked', true); + $lbl.addClass('checked'); + $containerToggle.removeClass('hide hidden'); + $lbl.trigger('checked.fu.radio'); + } + else { + $radio.prop('checked', false); + $lbl.removeClass('checked'); + $containerToggle.addClass('hidden'); + $lbl.trigger('unchecked.fu.radio'); } - //toggle container - this.toggleContainer(); + $lbl.trigger('changed.fu.radio', checked); }, - resetGroup: function () { - var group = $('input[name="' + this.groupName + '"]'); - - group.each(function () { - var lbl = $(this).parent('label'); - lbl.removeClass('checked'); - lbl.parent('.radio').removeClass('checked'); - }); - }, + setDisabledState: function(element, disabled) { + var $radio = element; + var $lbl = this.$label; - enable: function () { - this.$radio.attr('disabled', false); - this.$label.removeClass('disabled'); - if (this.isBlockWrapped) { - this.$blockWrapper.removeClass('disabled'); + if(disabled) { + this.$radio.prop('disabled', true); + $lbl.addClass('disabled'); + $lbl.trigger('disabled.fu.radio'); } - }, - - disable: function () { - this.$radio.attr('disabled', true); - this.$label.addClass('disabled'); - if (this.isBlockWrapped) { - this.$blockWrapper.addClass('disabled'); + else { + this.$radio.prop('disabled', false); + $lbl.removeClass('disabled'); + $lbl.trigger('enabled.fu.radio'); } }, - itemchecked: function (e) { - var radio = $(e.target); - - this.resetGroup(); - this.setState(radio); + itemchecked: function (evt) { + var $radio = $(evt.target); + this.setCheckedState($radio, true); }, check: function () { - this.resetGroup(); - this.$radio.prop('checked', true); - this.$radio.attr('checked', 'checked'); - this.setState(this.$radio); + this.setCheckedState(this.$radio, true); }, - toggleContainer: function () { - var group; - if (this.$toggleContainer) { - // show corresponding container for currently selected radio - if (this.isChecked()) { - // hide containers for each item in group - group = $('input[name="' + this.groupName + '"]'); - group.each(function () { - var selector = $(this).attr('data-toggle'); - $(selector).addClass('hidden'); - $(selector).attr('aria-hidden', 'true'); - }); - this.$toggleContainer.removeClass('hide hidden'); - this.$toggleContainer.attr('aria-hidden', 'false'); - } else { - this.$toggleContainer.addClass('hidden'); - this.$toggleContainer.attr('aria-hidden', 'true'); - } + uncheck: function () { + this.setCheckedState(this.$radio, false); + }, - } + isChecked: function () { + var checked = this.$radio.prop('checked'); + return checked; }, - uncheck: function () { - this.$radio.prop('checked', false); - this.$radio.removeAttr('checked'); - this.setState(this.$radio); + enable: function () { + this.setDisabledState(this.$radio, false); }, - isChecked: function () { - return this.$radio.is(':checked'); + disable: function () { + this.setDisabledState(this.$radio, true); + }, + + destroy: function () { + this.$label.remove(); + // remove any external bindings + // [none] + // empty elements to return to original markup + // [none] + return this.$label[0].outerHTML; } }; @@ -216,8 +196,8 @@ // DATA-API - $(document).on('mouseover.fu.checkbox.data-api', '[data-initialize=radio]', function (e) { - var $control = $(e.target).closest('.radio').find('[type=radio]'); + $(document).on('mouseover.fu.radio.data-api', '[data-initialize=radio]', function (e) { + var $control = $(e.target); if (!$control.data('fu.radio')) { $control.radio($control.data()); } @@ -225,13 +205,14 @@ // Must be domReady for AMD compatibility $(function () { - $('[data-initialize=radio] [type=radio]').each(function () { + $('[data-initialize=radio]').each(function () { var $this = $(this); - if ($this.data('fu.radio')) return; - $this.radio($this.data()); + if (!$this.data('fu.radio')) { + $this.radio($this.data()); + } }); }); // -- BEGIN UMD WRAPPER AFTERWORD -- })); -// -- END UMD WRAPPER AFTERWORD -- +// -- END UMD WRAPPER AFTERWORD -- \ No newline at end of file diff --git a/test/markup/radio-markup.html b/test/markup/radio-markup.html index 7ef3ce3b1..e752822dd 100644 --- a/test/markup/radio-markup.html +++ b/test/markup/radio-markup.html @@ -1,47 +1,42 @@
-
-
diff --git a/index.js b/index.js index ee19725aa..342e7d701 100644 --- a/index.js +++ b/index.js @@ -426,22 +426,27 @@ define(function (require) { // sample method buttons $('#btnRadioDisable').on('click', function () { - $('[name=radio1]').radio('disable'); + console.log('in disable'); + $('#myCustomRadio1').radio('disable'); }); $('#btnRadioEnable').on('click', function () { - $('[name=radio1]').radio('enable'); + $('#myCustomRadio1').radio('enable'); }); $('#btnRadioDestroy').on('click', function () { - var $container = $('#myCustomRadio1').parents('.thin-box:first'); + var $container = $('#myCustomRadio1').parent(); var markup = $('#myCustomRadio1').radio('destroy'); + log(markup); $container.append(markup); - $('#myRadio1').radio(); }); - $('#btnRadioInlineDestroy').on('click', function () { - var $container = $('#myCustomInlineRadio1').parents('.thin-box:first'); - var markup = $('#myCustomInlineRadio1').radio('destroy'); - $container.append(markup); - $('#myCustomInlineRadio1').radio(); + $('#btnRadioIsChecked').on('click', function () { + var checked = $('#myCustomRadio1').radio('isChecked'); + log(checked); + }); + $('#btnRadioCheck').on('click', function () { + $('#myCustomRadio1').radio('check'); + }); + $('#btnRadioUncheck').on('click', function () { + $('#myCustomRadio1').radio('uncheck'); }); diff --git a/js/radio.js b/js/radio.js index 404ae32a9..e04eb0885 100644 --- a/js/radio.js +++ b/js/radio.js @@ -31,152 +31,132 @@ var Radio = function (element, options) { this.options = $.extend({}, $.fn.radio.defaults, options); - // cache elements - this.$radio = $(element).is('input[type="radio"]') ? $(element) : $(element).find('input[type="radio"]:first'); - this.$label = this.$radio.parent(); - this.groupName = this.$radio.attr('name'); - this.$blockWrapper = this.$label.parent('.radio'); // only used if block radio control, otherwise radio is inline - this.isBlockWrapped = true; // initialized as a block radio control - this.$toggleContainer = null; - - if (this.$blockWrapper.length === 0) { - this.isBlockWrapped = false; + if(element.tagName.toLowerCase() !== 'label') { + //console.log('initialize radio on the label that wraps the radio'); + return; } - var toggleSelector = this.$radio.attr('data-toggle'); - if (toggleSelector) { - this.$toggleContainer = $(toggleSelector); - } + // cache elements + this.$label = $(element); + this.$radio = this.$label.find('input[type="radio"]'); + this.groupName = this.$radio.attr('name'); // don't cache group itself since items can be added programmatically - // set default state - this.setState(this.$radio); + // determine if a toggle container is specified + var containerSelector = this.$radio.attr('data-toggle'); + this.$toggleContainer = $(containerSelector); + + // handle internal events + this.$radio.on('change', $.proxy(this.itemchecked, this)); - // handle events - this.$radio.on('change.fu.radio', $.proxy(this.itemchecked, this)); + // set default state + this.setInitialState(); }; Radio.prototype = { constructor: Radio, - destroy: function () { - // remove any external bindings - // [none] - // empty elements to return to original markup - // [none] - // return string of markup - if (this.isBlockWrapped) { - this.$blockWrapper.remove(); - return this.$blockWrapper[0].outerHTML; - } else { - this.$label.remove(); - return this.$label[0].outerHTML; - } + setInitialState: function() { + var $radio = this.$radio; + var $lbl = this.$label; - }, + // get current state of input + var checked = $radio.prop('checked'); + var disabled = $radio.prop('disabled'); - setState: function ($radio) { - $radio = $radio || this.$radio; + // sync label class with input state + this.setCheckedState($radio, checked); + this.setDisabledState($radio, disabled); + }, - var checked = $radio.is(':checked'); - var disabled = !!$radio.prop('disabled'); + resetGroup: function() { + var $radios = $('input[name="' + this.groupName + '"]'); + $radios.each(function(index, item) { + var $radio = $(item); + var $lbl = $radio.parent(); + var containerSelector = $radio.attr('data-toggle'); + var $containerToggle = $(containerSelector); - this.$label.removeClass('checked'); - if (this.isBlockWrapped) { - this.$blockWrapper.removeClass('checked disabled'); - } - // set state of radio - if (checked === true) { - this.$label.addClass('checked'); - if (this.isBlockWrapped) { - this.$blockWrapper.addClass('checked'); - } + $lbl.removeClass('checked'); + $containerToggle.addClass('hidden'); + }); + }, - } + setCheckedState: function(element, checked) { + // reset all items in group + this.resetGroup(); - if (disabled === true) { - this.$label.addClass('disabled'); - if (this.isBlockWrapped) { - this.$blockWrapper.addClass('disabled'); - } + var $radio = element; + var $lbl = $radio.parent(); + var containerSelector = $radio.attr('data-toggle'); + var $containerToggle = $(containerSelector); + if(checked) { + $radio.prop('checked', true); + $lbl.addClass('checked'); + $containerToggle.removeClass('hide hidden'); + $lbl.trigger('checked.fu.radio'); + } + else { + $radio.prop('checked', false); + $lbl.removeClass('checked'); + $containerToggle.addClass('hidden'); + $lbl.trigger('unchecked.fu.radio'); } - //toggle container - this.toggleContainer(); + $lbl.trigger('changed.fu.radio', checked); }, - resetGroup: function () { - var group = $('input[name="' + this.groupName + '"]'); - - group.each(function () { - var lbl = $(this).parent('label'); - lbl.removeClass('checked'); - lbl.parent('.radio').removeClass('checked'); - }); - }, + setDisabledState: function(element, disabled) { + var $radio = element; + var $lbl = this.$label; - enable: function () { - this.$radio.attr('disabled', false); - this.$label.removeClass('disabled'); - if (this.isBlockWrapped) { - this.$blockWrapper.removeClass('disabled'); + if(disabled) { + this.$radio.prop('disabled', true); + $lbl.addClass('disabled'); + $lbl.trigger('disabled.fu.radio'); } - }, - - disable: function () { - this.$radio.attr('disabled', true); - this.$label.addClass('disabled'); - if (this.isBlockWrapped) { - this.$blockWrapper.addClass('disabled'); + else { + this.$radio.prop('disabled', false); + $lbl.removeClass('disabled'); + $lbl.trigger('enabled.fu.radio'); } }, - itemchecked: function (e) { - var radio = $(e.target); - - this.resetGroup(); - this.setState(radio); + itemchecked: function (evt) { + var $radio = $(evt.target); + this.setCheckedState($radio, true); }, check: function () { - this.resetGroup(); - this.$radio.prop('checked', true); - this.$radio.attr('checked', 'checked'); - this.setState(this.$radio); + this.setCheckedState(this.$radio, true); }, - toggleContainer: function () { - var group; - if (this.$toggleContainer) { - // show corresponding container for currently selected radio - if (this.isChecked()) { - // hide containers for each item in group - group = $('input[name="' + this.groupName + '"]'); - group.each(function () { - var selector = $(this).attr('data-toggle'); - $(selector).addClass('hidden'); - $(selector).attr('aria-hidden', 'true'); - }); - this.$toggleContainer.removeClass('hide hidden'); // hide is deprecated - this.$toggleContainer.attr('aria-hidden', 'false'); - } else { - this.$toggleContainer.addClass('hidden'); - this.$toggleContainer.attr('aria-hidden', 'true'); - } + uncheck: function () { + this.setCheckedState(this.$radio, false); + }, - } + isChecked: function () { + var checked = this.$radio.prop('checked'); + return checked; }, - uncheck: function () { - this.$radio.prop('checked', false); - this.$radio.removeAttr('checked'); - this.setState(this.$radio); + enable: function () { + this.setDisabledState(this.$radio, false); }, - isChecked: function () { - return this.$radio.is(':checked'); + disable: function () { + this.setDisabledState(this.$radio, true); + }, + + destroy: function () { + this.$label.remove(); + // remove any external bindings + // [none] + // empty elements to return to original markup + // [none] + return this.$label[0].outerHTML; } }; @@ -216,8 +196,8 @@ // DATA-API - $(document).on('mouseover.fu.checkbox.data-api', '[data-initialize=radio]', function (e) { - var $control = $(e.target).closest('.radio').find('[type=radio]'); + $(document).on('mouseover.fu.radio.data-api', '[data-initialize=radio]', function (e) { + var $control = $(e.target); if (!$control.data('fu.radio')) { $control.radio($control.data()); } @@ -225,13 +205,14 @@ // Must be domReady for AMD compatibility $(function () { - $('[data-initialize=radio] [type=radio]').each(function () { + $('[data-initialize=radio]').each(function () { var $this = $(this); - if ($this.data('fu.radio')) return; - $this.radio($this.data()); + if (!$this.data('fu.radio')) { + $this.radio($this.data()); + } }); }); // -- BEGIN UMD WRAPPER AFTERWORD -- })); -// -- END UMD WRAPPER AFTERWORD -- +// -- END UMD WRAPPER AFTERWORD -- \ No newline at end of file diff --git a/test/markup/radio-markup.html b/test/markup/radio-markup.html index 7ef3ce3b1..e752822dd 100644 --- a/test/markup/radio-markup.html +++ b/test/markup/radio-markup.html @@ -1,47 +1,42 @@
-
-