123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516 |
- (function ($, window, document, undefined) {
- 'use strict';
- Foundation.libs.forms = {
- name: 'forms',
- version: '4.2.1',
- cache: {},
- settings: {
- disable_class: 'no-custom',
- last_combo : null
- },
- init: function (scope, method, options) {
- if (typeof method === 'object') {
- $.extend(true, this.settings, method);
- }
- if (typeof method != 'string') {
- if (!this.settings.init) {
- this.events();
- }
- this.assemble();
- return this.settings.init;
- } else {
- return this[method].call(this, options);
- }
- },
- assemble: function () {
- $('form.custom input[type="radio"]', $(this.scope)).not('[data-customforms="disabled"]')
- .each(this.append_custom_markup);
- $('form.custom input[type="checkbox"]', $(this.scope)).not('[data-customforms="disabled"]')
- .each(this.append_custom_markup);
- $('form.custom select', $(this.scope))
- .not('[data-customforms="disabled"]')
- .not('[multiple=multiple]')
- .each(this.append_custom_select);
- },
- events: function () {
- var self = this;
- $(this.scope)
- .on('click.fndtn.forms', 'form.custom span.custom.checkbox', function (e) {
- e.preventDefault();
- e.stopPropagation();
- self.toggle_checkbox($(this));
- })
- .on('click.fndtn.forms', 'form.custom span.custom.radio', function (e) {
- e.preventDefault();
- e.stopPropagation();
- self.toggle_radio($(this));
- })
- .on('change.fndtn.forms', 'form.custom select:not([data-customforms="disabled"])', function (e, force_refresh) {
- self.refresh_custom_select($(this), force_refresh);
- })
- .on('click.fndtn.forms', 'form.custom label', function (e) {
- if ($(e.target).is('label')) {
- var $associatedElement = $('#' + self.escape($(this).attr('for')) + ':not([data-customforms="disabled"])'),
- $customCheckbox,
- $customRadio;
- if ($associatedElement.length !== 0) {
- if ($associatedElement.attr('type') === 'checkbox') {
- e.preventDefault();
- $customCheckbox = $(this).find('span.custom.checkbox');
- //the checkbox might be outside after the label or inside of another element
- if ($customCheckbox.length == 0) {
- $customCheckbox = $associatedElement.add(this).siblings('span.custom.checkbox').first();
- }
- self.toggle_checkbox($customCheckbox);
- } else if ($associatedElement.attr('type') === 'radio') {
- e.preventDefault();
- $customRadio = $(this).find('span.custom.radio');
- //the radio might be outside after the label or inside of another element
- if ($customRadio.length == 0) {
- $customRadio = $associatedElement.add(this).siblings('span.custom.radio').first();
- }
- self.toggle_radio($customRadio);
- }
- }
- }
- })
- .on('mousedown.fndtn.forms', 'form.custom div.custom.dropdown', function () {
- return false;
- })
- .on('click.fndtn.forms', 'form.custom div.custom.dropdown a.current, form.custom div.custom.dropdown a.selector', function (e) {
- var $this = $(this),
- $dropdown = $this.closest('div.custom.dropdown'),
- $select = getFirstPrevSibling($dropdown, 'select');
- // make sure other dropdowns close
- if (!$dropdown.hasClass('open')) $(self.scope).trigger('click');
- e.preventDefault();
- if (false === $select.is(':disabled')) {
- $dropdown.toggleClass('open');
- if ($dropdown.hasClass('open')) {
- $(self.scope).on('click.fndtn.forms.customdropdown', function () {
- $dropdown.removeClass('open');
- $(self.scope).off('.fndtn.forms.customdropdown');
- });
- } else {
- $(self.scope).on('.fndtn.forms.customdropdown');
- }
- return false;
- }
- })
- .on('click.fndtn.forms touchend.fndtn.forms', 'form.custom div.custom.dropdown li', function (e) {
- var $this = $(this),
- $customDropdown = $this.closest('div.custom.dropdown'),
- $select = getFirstPrevSibling($customDropdown, 'select'),
- selectedIndex = 0;
- e.preventDefault();
- e.stopPropagation();
- if (!$(this).hasClass('disabled')) {
- $('div.dropdown').not($customDropdown).removeClass('open');
- var $oldThis = $this.closest('ul')
- .find('li.selected');
- $oldThis.removeClass('selected');
- $this.addClass('selected');
- $customDropdown.removeClass('open')
- .find('a.current')
- .text($this.text());
- $this.closest('ul').find('li').each(function (index) {
- if ($this[0] == this) {
- selectedIndex = index;
- }
- });
- $select[0].selectedIndex = selectedIndex;
- //store the old value in data
- $select.data('prevalue', $oldThis.html());
- $select.trigger('change');
- }
- });
- $(window).on('keydown', function (e) {
- var focus = document.activeElement,
- self = Foundation.libs.forms,
- dropdown = $('.custom.dropdown.open');
- if (dropdown.length > 0) {
- e.preventDefault();
- if (e.which === 13) {
- dropdown.find('li.selected').trigger('click');
- }
- if (e.which === 27) {
- dropdown.removeClass('open');
- }
- if (e.which >= 65 && e.which <= 90) {
- var next = self.go_to(dropdown, e.which),
- current = dropdown.find('li.selected');
- if (next) {
- current.removeClass('selected');
- self.scrollTo(next.addClass('selected'), 300);
- }
- }
- if (e.which === 38) {
- var current = dropdown.find('li.selected'),
- prev = current.prev(':not(.disabled)');
- if (prev.length > 0) {
- prev.parent()[0].scrollTop = prev.parent().scrollTop() - self.outerHeight(prev);
- current.removeClass('selected');
- prev.addClass('selected');
- }
- } else if (e.which === 40) {
- var current = dropdown.find('li.selected'),
- next = current.next(':not(.disabled)');
- if (next.length > 0) {
- next.parent()[0].scrollTop = next.parent().scrollTop() + self.outerHeight(next);
- current.removeClass('selected');
- next.addClass('selected');
- }
- }
- }
- });
- this.settings.init = true;
- },
- go_to: function (dropdown, character) {
- var lis = dropdown.find('li'),
- count = lis.length;
- if (count > 0) {
- for (var i = 0; i < count; i++) {
- var first_letter = lis.eq(i).text().charAt(0).toLowerCase();
- if (first_letter === String.fromCharCode(character).toLowerCase()) return lis.eq(i);
- }
- }
- },
- scrollTo: function (el, duration) {
- if (duration < 0) return;
- var parent = el.parent();
- var li_height = this.outerHeight(el);
- var difference = (li_height * (el.index())) - parent.scrollTop();
- var perTick = difference / duration * 10;
- this.scrollToTimerCache = setTimeout(function () {
- if (!isNaN(parseInt(perTick, 10))) {
- parent[0].scrollTop = parent.scrollTop() + perTick;
- this.scrollTo(el, duration - 10);
- }
- }.bind(this), 10);
- },
- append_custom_markup: function (idx, sel) {
- var $this = $(sel),
- type = $this.attr('type'),
- $span = $this.next('span.custom.' + type);
- if ($span.length === 0) {
- $span = $('<span class="custom ' + type + '"></span>').insertAfter($this);
- }
- $span.toggleClass('checked', $this.is(':checked'));
- $span.toggleClass('disabled', $this.is(':disabled'));
- },
- append_custom_select: function (idx, sel) {
- var self = Foundation.libs.forms,
- $this = $(sel),
- $customSelect = $this.next('div.custom.dropdown'),
- $customList = $customSelect.find('ul'),
- $selectCurrent = $customSelect.find(".current"),
- $selector = $customSelect.find(".selector"),
- $options = $this.find('option'),
- $selectedOption = $options.filter(':selected'),
- copyClasses = $this.attr('class') ? $this.attr('class').split(' ') : [],
- maxWidth = 0,
- liHtml = '',
- $listItems,
- $currentSelect = false;
- if ($this.hasClass(self.settings.disable_class)) return;
- if ($customSelect.length === 0) {
- var customSelectSize = $this.hasClass('small') ? 'small' : $this.hasClass('medium') ? 'medium' : $this.hasClass('large') ? 'large' : $this.hasClass('expand') ? 'expand' : '';
- $customSelect = $('<div class="' + ['custom', 'dropdown', customSelectSize].concat(copyClasses).filter(function (item, idx, arr) {
- if (item == '') return false;
- return arr.indexOf(item) == idx;
- }).join(' ') + '"><a href="#" class="selector"></a><ul /></div>');
- $selector = $customSelect.find(".selector");
- $customList = $customSelect.find("ul");
- liHtml = $options.map(function () {
- var copyClasses = $(this).attr('class') ? $(this).attr('class') : '';
- return "<li class='" + copyClasses + "'>" + $(this).html() + "</li>";
- }).get().join('');
- $customList.append(liHtml);
- $currentSelect = $customSelect
- .prepend('<a href="#" class="current">' + $selectedOption.html() + '</a>')
- .find(".current");
- $this.after($customSelect)
- .addClass('hidden-field');
- } else {
- liHtml = $options.map(function () {
- return "<li>" + $(this).html() + "</li>";
- })
- .get().join('');
- $customList.html('')
- .append(liHtml);
- } // endif $customSelect.length === 0
- self.assign_id($this, $customSelect);
- $customSelect.toggleClass('disabled', $this.is(':disabled'));
- $listItems = $customList.find('li');
- // cache list length
- self.cache[$customSelect.data('id')] = $listItems.length;
- $options.each(function (index) {
- if (this.selected) {
- $listItems.eq(index).addClass('selected');
- if ($currentSelect) {
- $currentSelect.html($(this).html());
- }
- }
- if ($(this).is(':disabled')) {
- $listItems.eq(index).addClass('disabled');
- }
- });
- //
- // If we're not specifying a predetermined form size.
- //
- if (!$customSelect.is('.small, .medium, .large, .expand')) {
- // ------------------------------------------------------------------------------------
- // This is a work-around for when elements are contained within hidden parents.
- // For example, when custom-form elements are inside of a hidden reveal modal.
- //
- // We need to display the current custom list element as well as hidden parent elements
- // in order to properly calculate the list item element's width property.
- // -------------------------------------------------------------------------------------
- $customSelect.addClass('open');
- //
- // Quickly, display all parent elements.
- // This should help us calcualate the width of the list item's within the drop down.
- //
- var self = Foundation.libs.forms;
- self.hidden_fix.adjust($customList);
- maxWidth = (self.outerWidth($listItems) > maxWidth) ? self.outerWidth($listItems) : maxWidth;
- Foundation.libs.forms.hidden_fix.reset();
- $customSelect.removeClass('open');
- } // endif
- },
- assign_id: function ($select, $customSelect) {
- var id = [+new Date(), Foundation.random_str(5)].join('-');
- $select.attr('data-id', id);
- $customSelect.attr('data-id', id);
- },
- refresh_custom_select: function ($select, force_refresh) {
- var self = this;
- var maxWidth = 0,
- $customSelect = $select.next(),
- $options = $select.find('option'),
- $listItems = $customSelect.find('li');
- if ($listItems.length != this.cache[$customSelect.data('id')] || force_refresh) {
- $customSelect.find('ul').html('');
- $options.each(function () {
- var $li = $('<li>' + $(this).html() + '</li>');
- $customSelect.find('ul').append($li);
- });
- // re-populate
- $options.each(function (index) {
- if (this.selected) {
- $customSelect.find('li').eq(index).addClass('selected');
- $customSelect.find('.current').html($(this).html());
- }
- if ($(this).is(':disabled')) {
- $customSelect.find('li').eq(index).addClass('disabled');
- }
- });
- // fix width
- $customSelect.removeAttr('style')
- .find('ul').removeAttr('style');
- $customSelect.find('li').each(function () {
- $customSelect.addClass('open');
- if (self.outerWidth($(this)) > maxWidth) {
- maxWidth = self.outerWidth($(this));
- }
- $customSelect.removeClass('open');
- });
- $listItems = $customSelect.find('li');
- // cache list length
- this.cache[$customSelect.data('id')] = $listItems.length;
- }
- },
- toggle_checkbox: function ($element) {
- var $input = $element.prev(),
- input = $input[0];
- if (false === $input.is(':disabled')) {
- input.checked = ((input.checked) ? false : true);
- $element.toggleClass('checked');
- $input.trigger('change');
- }
- },
- toggle_radio: function ($element) {
- var $input = $element.prev(),
- $form = $input.closest('form.custom'),
- input = $input[0];
- if (false === $input.is(':disabled')) {
- $form.find('input[type="radio"][name="' + this.escape($input.attr('name')) + '"]')
- .next().not($element).removeClass('checked');
- if (!$element.hasClass('checked')) {
- $element.toggleClass('checked');
- }
- input.checked = $element.hasClass('checked');
- $input.trigger('change');
- }
- },
- escape: function (text) {
- return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
- },
- hidden_fix: {
- /**
- * Sets all hidden parent elements and self to visibile.
- *
- * @method adjust
- * @param {jQuery Object} $child
- */
- // We'll use this to temporarily store style properties.
- tmp: [],
- // We'll use this to set hidden parent elements.
- hidden: null,
- adjust: function ($child) {
- // Internal reference.
- var _self = this;
- // Set all hidden parent elements, including this element.
- _self.hidden = $child.parents();
- _self.hidden = _self.hidden.add($child).filter(":hidden");
- // Loop through all hidden elements.
- _self.hidden.each(function () {
- // Cache the element.
- var $elem = $(this);
- // Store the style attribute.
- // Undefined if element doesn't have a style attribute.
- _self.tmp.push($elem.attr('style'));
- // Set the element's display property to block,
- // but ensure it's visibility is hidden.
- $elem.css({
- 'visibility': 'hidden',
- 'display': 'block'
- });
- });
- }, // end adjust
- /**
- * Resets the elements previous state.
- *
- * @method reset
- */
- reset: function () {
- // Internal reference.
- var _self = this;
- // Loop through our hidden element collection.
- _self.hidden.each(function (i) {
- // Cache this element.
- var $elem = $(this),
- _tmp = _self.tmp[i]; // Get the stored 'style' value for this element.
- // If the stored value is undefined.
- if (_tmp === undefined)
- // Remove the style attribute.
- $elem.removeAttr('style');
- else
- // Otherwise, reset the element style attribute.
- $elem.attr('style', _tmp);
- });
- // Reset the tmp array.
- _self.tmp = [];
- // Reset the hidden elements variable.
- _self.hidden = null;
- } // end reset
- },
- off: function () {
- $(this.scope).off('.fndtn.forms');
- },
- reflow : function () {}
- };
- var getFirstPrevSibling = function($el, selector) {
- var $el = $el.prev();
- while ($el.length) {
- if ($el.is(selector)) return $el;
- $el = $el.prev();
- }
- return $();
- };
- }(Foundation.zj, this, this.document));
|