PageRenderTime 35ms CodeModel.GetById 17ms app.highlight 15ms RepoModel.GetById 0ms app.codeStats 0ms

/components/foundation/javascripts/jquery.foundation.forms.js

https://bitbucket.org/ceoaliongroo/torredelprior
JavaScript | 486 lines | 365 code | 28 blank | 93 comment | 6 complexity | 67a3f0d91d5fc4142fe71cda2de49271 MD5 | raw file
  1/*
  2 * jQuery Custom Forms Plugin 1.0
  3 * www.ZURB.com
  4 * Copyright 2010, ZURB
  5 * Free to use under the MIT license.
  6 * http://www.opensource.org/licenses/mit-license.php
  7*/
  8
  9(function( $ ){
 10
 11  /**
 12   * Helper object used to quickly adjust all hidden parent element's, display and visibility properties.
 13   * This is currently used for the custom drop downs. When the dropdowns are contained within a reveal modal
 14   * we cannot accurately determine the list-item elements width property, since the modal's display property is set
 15   * to 'none'.
 16   *
 17   * This object will help us work around that problem.
 18   *
 19   * NOTE: This could also be plugin.
 20   *
 21   * @function hiddenFix
 22   */
 23  var hiddenFix = function() {
 24
 25    return {
 26      /**
 27       * Sets all hidden parent elements and self to visibile.
 28       *
 29       * @method adjust
 30       * @param {jQuery Object} $child
 31       */
 32
 33      // We'll use this to temporarily store style properties.
 34      tmp : [],
 35
 36      // We'll use this to set hidden parent elements.
 37      hidden : null,
 38
 39      adjust : function( $child ) {
 40        // Internal reference.
 41        var _self = this;
 42
 43        // Set all hidden parent elements, including this element.
 44        _self.hidden = $child.parents().andSelf().filter( ":hidden" );
 45
 46        // Loop through all hidden elements.
 47        _self.hidden.each( function() {
 48
 49          // Cache the element.
 50          var $elem = $( this );
 51
 52          // Store the style attribute.
 53          // Undefined if element doesn't have a style attribute.
 54          _self.tmp.push( $elem.attr( 'style' ) );
 55
 56          // Set the element's display property to block,
 57          // but ensure it's visibility is hidden.
 58          $elem.css( { 'visibility' : 'hidden', 'display' : 'block' } );
 59        });
 60
 61      }, // end adjust
 62
 63      /**
 64       * Resets the elements previous state.
 65       *
 66       * @method reset
 67       */
 68      reset : function() {
 69        // Internal reference.
 70        var _self = this;
 71        // Loop through our hidden element collection.
 72        _self.hidden.each( function( i ) {
 73          // Cache this element.
 74          var $elem = $( this ),
 75              _tmp = _self.tmp[ i ]; // Get the stored 'style' value for this element.
 76
 77          // If the stored value is undefined.
 78          if( _tmp === undefined )
 79            // Remove the style attribute.
 80            $elem.removeAttr( 'style' );
 81          else
 82            // Otherwise, reset the element style attribute.
 83            $elem.attr( 'style', _tmp );
 84
 85        });
 86        // Reset the tmp array.
 87        _self.tmp = [];
 88        // Reset the hidden elements variable.
 89        _self.hidden = null;
 90
 91      } // end reset
 92
 93    }; // end return
 94
 95  };
 96
 97  jQuery.foundation = jQuery.foundation || {};
 98  jQuery.foundation.customForms = jQuery.foundation.customForms || {};
 99
100  $.foundation.customForms.appendCustomMarkup = function ( options ) {
101
102    var defaults = {
103      disable_class: "js-disable-custom"
104    };
105
106    options = $.extend( defaults, options );
107
108    function appendCustomMarkup(idx, sel) {
109      var $this = $(sel).hide(),
110          type  = $this.attr('type'),
111          $span = $this.next('span.custom.' + type);
112
113      if ($span.length === 0) {
114        $span = $('<span class="custom ' + type + '"></span>').insertAfter($this);
115      }
116
117      $span.toggleClass('checked', $this.is(':checked'));
118      $span.toggleClass('disabled', $this.is(':disabled'));
119    }
120
121    function appendCustomSelect(idx, sel) {
122      var hiddenFixObj = hiddenFix();
123          //
124          // jQueryify the <select> element and cache it.
125          //
126      var $this = $( sel ),
127          //
128          // Find the custom drop down element.
129          //
130          $customSelect = $this.next( 'div.custom.dropdown' ),
131          //
132          // Find the custom select element within the custom drop down.
133          //
134          $customList = $customSelect.find( 'ul' ),
135          //
136          // Find the custom a.current element.
137          //
138          $selectCurrent = $customSelect.find( ".current" ),
139          //
140          // Find the custom a.selector element (the drop-down icon).
141          //
142          $selector = $customSelect.find( ".selector" ),
143          //
144          // Get the <options> from the <select> element.
145          //
146          $options = $this.find( 'option' ),
147          //
148          // Filter down the selected options
149          //
150          $selectedOption = $options.filter( ':selected' ),
151          //
152          // Initial max width.
153          //
154          maxWidth = 0,
155          //
156          // We'll use this variable to create the <li> elements for our custom select.
157          //
158          liHtml = '',
159          //
160          // We'll use this to cache the created <li> elements within our custom select.
161          //
162          $listItems
163      ;
164      var $currentSelect = false;
165      //
166      // Should we not create a custom list?
167      //
168      if ( $this.hasClass( 'no-custom' ) ) return;
169
170      //
171      // Did we not create a custom select element yet?
172      //
173      if ( $customSelect.length === 0 ) {
174        //
175        // Let's create our custom select element!
176        //
177
178            //
179            // Determine what select size to use.
180            //
181        var customSelectSize = $this.hasClass( 'small' )   ? 'small'   :
182                               $this.hasClass( 'medium' )  ? 'medium'  :
183                               $this.hasClass( 'large' )   ? 'large'   :
184                               $this.hasClass( 'expand' )  ? 'expand'  : ''
185        ;
186        //
187        // Build our custom list.
188        //
189        $customSelect = $('<div class="' + ['custom', 'dropdown', customSelectSize ].join( ' ' ) + '"><a href="#" class="selector"></a><ul /></div>"');
190        //
191        // Grab the selector element
192        //
193        $selector = $customSelect.find( ".selector" );
194        //
195        // Grab the unordered list element from the custom list.
196        //
197        $customList = $customSelect.find( "ul" );
198        //
199        // Build our <li> elements.
200        //
201        liHtml = $options.map( function() { return "<li>" + $( this ).html() + "</li>"; } ).get().join( '' );
202        //
203        // Append our <li> elements to the custom list (<ul>).
204        //
205        $customList.append( liHtml );
206        //
207        // Insert the the currently selected list item before all other elements.
208        // Then, find the element and assign it to $currentSelect.
209        //
210
211        $currentSelect = $customSelect.prepend( '<a href="#" class="current">' + $selectedOption.html() + '</a>' ).find( ".current" );
212        //
213        // Add the custom select element after the <select> element.
214        //
215        $this.after( $customSelect )
216        //
217        //then hide the <select> element.
218        //
219        .hide();
220
221      } else {
222        //
223        // Create our list item <li> elements.
224        //
225        liHtml = $options.map( function() { return "<li>" + $( this ).html() + "</li>"; } ).get().join( '' );
226        //
227        // Refresh the ul with options from the select in case the supplied markup doesn't match.
228        // Clear what's currently in the <ul> element.
229        //
230        $customList.html( '' )
231        //
232        // Populate the list item <li> elements.
233        //
234        .append( liHtml );
235
236      } // endif $customSelect.length === 0
237
238      //
239      // Determine whether or not the custom select element should be disabled.
240      //
241      $customSelect.toggleClass( 'disabled', $this.is( ':disabled' ) );
242      //
243      // Cache our List item elements.
244      //
245      $listItems = $customList.find( 'li' );
246
247      //
248      // Determine which elements to select in our custom list.
249      //
250      $options.each( function ( index ) {
251
252        if ( this.selected ) {
253          //
254          // Add the selected class to the current li element
255          //
256          $listItems.eq( index ).addClass( 'selected' );
257          //
258          // Update the current element with the option value.
259          //
260          if ($currentSelect) {
261            $currentSelect.html( $( this ).html() );
262          }
263
264        }
265
266      });
267
268      //
269      // Update the custom <ul> list width property.
270      //
271      $customList.css( 'width', 'inherit' );
272      //
273      // Set the custom select width property.
274      //
275      $customSelect.css( 'width', 'inherit' );
276
277      //
278      // If we're not specifying a predetermined form size.
279      //
280      if ( !$customSelect.is( '.small, .medium, .large, .expand' ) ) {
281
282        // ------------------------------------------------------------------------------------
283        // This is a work-around for when elements are contained within hidden parents.
284        // For example, when custom-form elements are inside of a hidden reveal modal.
285        //
286        // We need to display the current custom list element as well as hidden parent elements
287        // in order to properly calculate the list item element's width property.
288        // -------------------------------------------------------------------------------------
289
290        //
291        // Show the drop down.
292        // This should ensure that the list item's width values are properly calculated.
293        //
294        $customSelect.addClass( 'open' );
295        //
296        // Quickly, display all parent elements.
297        // This should help us calcualate the width of the list item's within the drop down.
298        //
299        hiddenFixObj.adjust( $customList );
300        //
301        // Grab the largest list item width.
302        //
303        maxWidth = ( $listItems.outerWidth() > maxWidth ) ? $listItems.outerWidth() : maxWidth;
304        //
305        // Okay, now reset the parent elements.
306        // This will hide them again.
307        //
308        hiddenFixObj.reset();
309        //
310        // Finally, hide the drop down.
311        //
312        $customSelect.removeClass( 'open' );
313        //
314        // Set the custom list width.
315        //
316        $customSelect.width( maxWidth + 18);
317        //
318        // Set the custom list element (<ul />) width.
319        //
320        $customList.width(  maxWidth + 16 );
321
322      } // endif
323
324    }
325
326    $('form.custom input:radio[data-customforms!=disabled]').each(appendCustomMarkup);
327    $('form.custom input:checkbox[data-customforms!=disabled]').each(appendCustomMarkup);
328    $('form.custom select[data-customforms!=disabled]').each(appendCustomSelect);
329  };
330
331  var refreshCustomSelect = function($select) {
332    var maxWidth = 0,
333        $customSelect = $select.next();
334    $options = $select.find('option');
335    $customSelect.find('ul').html('');
336
337    $options.each(function () {
338      $li = $('<li>' + $(this).html() + '</li>');
339      $customSelect.find('ul').append($li);
340    });
341
342    // re-populate
343    $options.each(function (index) {
344      if (this.selected) {
345        $customSelect.find('li').eq(index).addClass('selected');
346        $customSelect.find('.current').html($(this).html());
347      }
348    });
349
350    // fix width
351    $customSelect.removeAttr('style')
352      .find('ul').removeAttr('style');
353    $customSelect.find('li').each(function () {
354      $customSelect.addClass('open');
355      if ($(this).outerWidth() > maxWidth) {
356        maxWidth = $(this).outerWidth();
357      }
358      $customSelect.removeClass('open');
359    });
360    $customSelect.css('width', maxWidth + 18 + 'px');
361    $customSelect.find('ul').css('width', maxWidth + 16 + 'px');
362
363  };
364
365  var toggleCheckbox = function($element) {
366    var $input = $element.prev(),
367        input = $input[0];
368
369    if (false === $input.is(':disabled')) {
370        input.checked = ((input.checked) ? false : true);
371        $element.toggleClass('checked');
372
373        $input.trigger('change');
374    }
375  };
376
377  var toggleRadio = function($element) {
378    var $input = $element.prev(),
379        input = $input[0];
380
381    if (false === $input.is(':disabled')) {
382
383      $('input:radio[name="' + $input.attr('name') + '"]').next().not($element).removeClass('checked');
384      if ( !$element.hasClass('checked') ) {
385        $element.toggleClass('checked');
386      }
387      input.checked = $element.hasClass('checked');
388
389      $input.trigger('change');
390    }
391  };
392
393  $(document).on('click', 'form.custom span.custom.checkbox', function (event) {
394    event.preventDefault();
395    event.stopPropagation();
396
397    toggleCheckbox($(this));
398  });
399
400  $(document).on('click', 'form.custom span.custom.radio', function (event) {
401    event.preventDefault();
402    event.stopPropagation();
403
404    toggleRadio($(this));
405  });
406
407  $(document).on('change', 'form.custom select[data-customforms!=disabled]', function (event) {
408    refreshCustomSelect($(this));
409  });
410
411  $(document).on('click', 'form.custom label', function (event) {
412    var $associatedElement = $('#' + $(this).attr('for') + '[data-customforms!=disabled]'),
413        $customCheckbox,
414        $customRadio;
415    if ($associatedElement.length !== 0) {
416      if ($associatedElement.attr('type') === 'checkbox') {
417        event.preventDefault();
418        $customCheckbox = $(this).find('span.custom.checkbox');
419        toggleCheckbox($customCheckbox);
420      } else if ($associatedElement.attr('type') === 'radio') {
421        event.preventDefault();
422        $customRadio = $(this).find('span.custom.radio');
423        toggleRadio($customRadio);
424      }
425    }
426  });
427
428  $(document).on('click', 'form.custom div.custom.dropdown a.current, form.custom div.custom.dropdown a.selector', function (event) {
429    var $this = $(this),
430        $dropdown = $this.closest('div.custom.dropdown'),
431        $select = $dropdown.prev();
432
433    event.preventDefault();
434    $('div.dropdown').removeClass('open');
435
436    if (false === $select.is(':disabled')) {
437        $dropdown.toggleClass('open');
438
439        if ($dropdown.hasClass('open')) {
440          $(document).bind('click.customdropdown', function (event) {
441            $dropdown.removeClass('open');
442            $(document).unbind('.customdropdown');
443          });
444        } else {
445          $(document).unbind('.customdropdown');
446        }
447        return false;
448    }
449  });
450
451  $(document).on('click', 'form.custom div.custom.dropdown li', function (event) {
452    var $this = $(this),
453        $customDropdown = $this.closest('div.custom.dropdown'),
454        $select = $customDropdown.prev(),
455        selectedIndex = 0;
456
457    event.preventDefault();
458    event.stopPropagation();
459    $('div.dropdown').removeClass('open');
460
461    $this
462      .closest('ul')
463      .find('li')
464      .removeClass('selected');
465    $this.addClass('selected');
466
467    $customDropdown
468      .removeClass('open')
469      .find('a.current')
470      .html($this.html());
471
472    $this.closest('ul').find('li').each(function (index) {
473      if ($this[0] == this) {
474        selectedIndex = index;
475      }
476
477    });
478    $select[0].selectedIndex = selectedIndex;
479
480    $select.trigger('change');
481  });
482
483
484  $.fn.foundationCustomForms = $.foundation.customForms.appendCustomMarkup;
485
486})( jQuery );