Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / ui / new_ui / ui / vendor / foundation / foundation.forms.js @ faad3c72

History | View | Annotate | Download (13 kB)

1
/*jslint unparam: true, browser: true, indent: 2 */
2

    
3
;(function ($, window, document, undefined) {
4
  'use strict';
5

    
6
  Foundation.libs.forms = {
7
    name : 'forms',
8

    
9
    version : '4.0.4',
10

    
11
    settings : {
12
      disable_class: 'no-custom'
13
    },
14

    
15
    init : function (scope, method, options) {
16
      this.scope = scope || this.scope;
17

    
18
      if (typeof method === 'object') {
19
        $.extend(true, this.settings, method);
20
      }
21

    
22
      if (typeof method != 'string') {
23
        if (!this.settings.init) {
24
          this.events();
25
        }
26

    
27
        this.assemble();
28

    
29
        return this.settings.init;
30
      } else {
31
        return this[method].call(this, options);
32
      }
33
    },
34

    
35
    assemble : function () {
36
      $('form.custom input[type="radio"]', $(this.scope)).not('[data-customforms="disabled"]')
37
        .each(this.append_custom_markup);
38
      $('form.custom input[type="checkbox"]', $(this.scope)).not('[data-customforms="disabled"]')
39
        .each(this.append_custom_markup);
40
      $('form.custom select', $(this.scope)).not('[data-customforms="disabled"]')
41
        .each(this.append_custom_select);
42
    },
43

    
44
    events : function () {
45
      var self = this;
46

    
47
      $(this.scope)
48
        .on('change.fndtn.forms', 'form.custom select:not([data-customforms="disabled"])', function (e) {
49
          self.refresh_custom_select($(this));
50
        })
51
        .on('click.fndtn.forms', 'form.custom label', function (e) {
52
          var $associatedElement = $('#' + self.escape($(this).attr('for')) + ':not([data-customforms="disabled"])'),
53
              $customCheckbox,
54
              $customRadio;
55
          if ($associatedElement.length !== 0) {
56
            if ($associatedElement.attr('type') === 'checkbox') {
57
              e.preventDefault();
58
              $customCheckbox = $(this).find('span.custom.checkbox');
59

    
60
              //the checkbox might be outside after the label
61
              if ($customCheckbox.length == 0) {
62
                $customCheckbox = $(this).next('span.custom.checkbox');
63
              }
64
              //the checkbox might be outside before the label
65
              if ($customCheckbox.length == 0) {
66
                $customCheckbox = $(this).prev('span.custom.checkbox');
67
              }
68
              self.toggle_checkbox($customCheckbox);
69
            } else if ($associatedElement.attr('type') === 'radio') {
70
              e.preventDefault();
71
              $customRadio = $(this).find('span.custom.radio');
72
              //the radio might be outside after the label
73
              if ($customRadio.length == 0) {
74
                $customRadio = $(this).next('span.custom.radio');
75
              }
76
              //the radio might be outside before the label
77
              if ($customRadio.length == 0) {
78
                $customRadio = $(this).prev('span.custom.radio');
79
              }
80
              self.toggle_radio($customRadio);
81
            }
82
          }
83
        })
84
        .on('click.fndtn.forms', 'form.custom div.custom.dropdown a.current, form.custom div.custom.dropdown a.selector', function (e) {
85
          var $this = $(this),
86
              $dropdown = $this.closest('div.custom.dropdown'),
87
              $select = $dropdown.prev();
88

    
89
          // make sure other dropdowns close
90
          if(!$dropdown.hasClass('open'))
91
            $(self.scope).trigger('click');
92

    
93
          e.preventDefault();
94
          if (false === $select.is(':disabled')) {
95
            $dropdown.toggleClass('open');
96

    
97
            if ($dropdown.hasClass('open')) {
98
              $(self.scope).on('click.fndtn.forms.customdropdown', function () {
99
                $dropdown.removeClass('open');
100
                $(self.scope).off('.fndtn.forms.customdropdown');
101
              });
102
            } else {
103
              $(self.scope).on('.fndtn.forms.customdropdown');
104
            }
105
            return false;
106
          }
107
        })
108
        .on('click.fndtn.forms touchend.fndtn.forms', 'form.custom div.custom.dropdown li', function (e) {
109
          var $this = $(this),
110
              $customDropdown = $this.closest('div.custom.dropdown'),
111
              $select = $customDropdown.prev(),
112
              selectedIndex = 0;
113

    
114
          e.preventDefault();
115
          e.stopPropagation();
116

    
117
          if ( ! $(this).hasClass('disabled')) {
118
            $('div.dropdown').not($customDropdown).removeClass('open');
119

    
120
            var $oldThis= $this
121
              .closest('ul')
122
              .find('li.selected');
123
            $oldThis.removeClass('selected');
124

    
125
            $this.addClass('selected');
126

    
127
            $customDropdown
128
              .removeClass('open')
129
              .find('a.current')
130
              .html($this.html());
131

    
132
            $this.closest('ul').find('li').each(function (index) {
133
              if ($this[0] == this) {
134
                selectedIndex = index;
135
              }
136

    
137
            });
138
            $select[0].selectedIndex = selectedIndex;
139

    
140
            //store the old value in data
141
            $select.data('prevalue', $oldThis.html());
142
            $select.trigger('change');
143
          }
144
        });
145

    
146
      this.settings.init = true;
147
    },
148

    
149
    append_custom_markup : function (idx, sel) {
150
      var $this = $(sel).hide(),
151
          type  = $this.attr('type'),
152
          $span = $this.next('span.custom.' + type);
153

    
154
      if ($span.length === 0) {
155
        $span = $('<span class="custom ' + type + '"></span>').insertAfter($this);
156
      }
157

    
158
      $span.toggleClass('checked', $this.is(':checked'));
159
      $span.toggleClass('disabled', $this.is(':disabled'));
160
    },
161

    
162
    append_custom_select : function (idx, sel) {
163
      var self = Foundation.libs.forms,
164
          $this = $( sel ),
165
          $customSelect = $this.next( 'div.custom.dropdown' ),
166
          $customList = $customSelect.find( 'ul' ),
167
          $selectCurrent = $customSelect.find( ".current" ),
168
          $selector = $customSelect.find( ".selector" ),
169
          $options = $this.find( 'option' ),
170
          $selectedOption = $options.filter( ':selected' ),
171
          copyClasses = $this.attr('class') ? $this.attr('class').split(' ') : [],
172
          maxWidth = 0,
173
          liHtml = '',
174
          $listItems,
175
          $currentSelect = false;
176

    
177
      if ($this.hasClass(self.settings.disable_class)) return;
178

    
179
      if ($customSelect.length === 0) {
180
        var customSelectSize = $this.hasClass( 'small' )   ? 'small'   :
181
                               $this.hasClass( 'medium' )  ? 'medium'  :
182
                               $this.hasClass( 'large' )   ? 'large'   :
183
                               $this.hasClass( 'expand' )  ? 'expand'  : '';
184

    
185
        $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>');
186
        $selector = $customSelect.find(".selector");
187
        $customList = $customSelect.find("ul");
188
        liHtml = $options.map(function() { return "<li>" + $( this ).html() + "</li>"; } ).get().join( '' );
189
        $customList.append(liHtml);
190
        $currentSelect = $customSelect.prepend('<a href="#" class="current">' + $selectedOption.html() + '</a>' ).find( ".current" );
191
        $this
192
          .after( $customSelect )
193
          .hide();
194

    
195
      } else {
196
        liHtml = $options.map(function() {
197
            return "<li>" + $( this ).html() + "</li>";
198
          })
199
          .get().join('');
200
        $customList
201
          .html('')
202
          .append(liHtml);
203

    
204
      } // endif $customSelect.length === 0
205
      $customSelect.toggleClass('disabled', $this.is( ':disabled' ) );
206
      $listItems = $customList.find( 'li' );
207

    
208
      $options.each( function ( index ) {
209
        if ( this.selected ) {
210
          $listItems.eq( index ).addClass( 'selected' );
211

    
212
          if ($currentSelect) {
213
            $currentSelect.html( $( this ).html() );
214
          }
215

    
216
        }
217
        if ($(this).is(':disabled')) {
218
          $listItems.eq( index ).addClass( 'disabled' );
219
        }
220
      });
221

    
222
      //
223
      // If we're not specifying a predetermined form size.
224
      //
225
      if (!$customSelect.is('.small, .medium, .large, .expand')) {
226

    
227
        // ------------------------------------------------------------------------------------
228
        // This is a work-around for when elements are contained within hidden parents.
229
        // For example, when custom-form elements are inside of a hidden reveal modal.
230
        //
231
        // We need to display the current custom list element as well as hidden parent elements
232
        // in order to properly calculate the list item element's width property.
233
        // -------------------------------------------------------------------------------------
234

    
235
        $customSelect.addClass( 'open' );
236
        //
237
        // Quickly, display all parent elements.
238
        // This should help us calcualate the width of the list item's within the drop down.
239
        //
240
        var self = Foundation.libs.forms;
241
        self.hidden_fix.adjust( $customList );
242

    
243
        maxWidth = ( self.outerWidth($listItems) > maxWidth ) ? self.outerWidth($listItems) : maxWidth;
244

    
245
        Foundation.libs.forms.hidden_fix.reset();
246

    
247
        $customSelect.removeClass( 'open' );
248

    
249
      } // endif
250

    
251
    },
252

    
253
    refresh_custom_select : function ($select) {
254
      var self = this;
255
      var maxWidth = 0,
256
        $customSelect = $select.next(),
257
        $options = $select.find('option');
258

    
259
      $customSelect.find('ul').html('');
260

    
261
      $options.each(function () {
262
        var $li = $('<li>' + $(this).html() + '</li>');
263
        $customSelect.find('ul').append($li);
264
      });
265

    
266
      // re-populate
267
      $options.each(function (index) {
268
        if (this.selected) {
269
          $customSelect.find('li').eq(index).addClass('selected');
270
          $customSelect.find('.current').html($(this).html());
271
        }
272
        if ($(this).is(':disabled')) {
273
          $customSelect.find('li').eq(index).addClass('disabled');
274
        }
275
      });
276

    
277
      // fix width
278
      $customSelect.removeAttr('style')
279
        .find('ul').removeAttr('style');
280
      $customSelect.find('li').each(function () {
281
        $customSelect.addClass('open');
282
        if (self.outerWidth($(this)) > maxWidth) {
283
          maxWidth = self.outerWidth($(this));
284
        }
285
        $customSelect.removeClass('open');
286
      });
287
    },
288

    
289
    toggle_checkbox : function ($element) {
290
      var $input = $element.prev(),
291
          input = $input[0];
292

    
293
      if (false === $input.is(':disabled')) {
294
        input.checked = ((input.checked) ? false : true);
295
        $element.toggleClass('checked');
296

    
297
        $input.trigger('change');
298
      }
299
    },
300

    
301
    toggle_radio : function ($element) {
302
      var $input = $element.prev(),
303
          $form = $input.closest('form.custom'),
304
          input = $input[0];
305

    
306
      if (false === $input.is(':disabled')) {
307
        $form.find('input[type="radio"][name="' + this.escape($input.attr('name')) + '"]').next().not($element).removeClass('checked');
308
        if ( !$element.hasClass('checked') ) {
309
          $element.toggleClass('checked');
310
        }
311
        input.checked = $element.hasClass('checked');
312

    
313
        $input.trigger('change');
314
      }
315
    },
316

    
317
    escape : function (text) {
318
      return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
319
    },
320

    
321
    hidden_fix : {
322
      /**
323
       * Sets all hidden parent elements and self to visibile.
324
       *
325
       * @method adjust
326
       * @param {jQuery Object} $child
327
       */
328

    
329
      // We'll use this to temporarily store style properties.
330
      tmp : [],
331

    
332
      // We'll use this to set hidden parent elements.
333
      hidden : null,
334

    
335
      adjust : function( $child ) {
336
        // Internal reference.
337
        var _self = this;
338

    
339
        // Set all hidden parent elements, including this element.
340
        _self.hidden = $child.parents().andSelf().filter( ":hidden" );
341

    
342
        // Loop through all hidden elements.
343
        _self.hidden.each( function() {
344

    
345
          // Cache the element.
346
          var $elem = $( this );
347

    
348
          // Store the style attribute.
349
          // Undefined if element doesn't have a style attribute.
350
          _self.tmp.push( $elem.attr( 'style' ) );
351

    
352
          // Set the element's display property to block,
353
          // but ensure it's visibility is hidden.
354
          $elem.css( { 'visibility' : 'hidden', 'display' : 'block' } );
355
        });
356

    
357
      }, // end adjust
358

    
359
      /**
360
       * Resets the elements previous state.
361
       *
362
       * @method reset
363
       */
364
      reset : function() {
365
        // Internal reference.
366
        var _self = this;
367
        // Loop through our hidden element collection.
368
        _self.hidden.each( function( i ) {
369
          // Cache this element.
370
          var $elem = $( this ),
371
              _tmp = _self.tmp[ i ]; // Get the stored 'style' value for this element.
372

    
373
          // If the stored value is undefined.
374
          if( _tmp === undefined )
375
            // Remove the style attribute.
376
            $elem.removeAttr( 'style' );
377
          else
378
            // Otherwise, reset the element style attribute.
379
            $elem.attr( 'style', _tmp );
380

    
381
        });
382
        // Reset the tmp array.
383
        _self.tmp = [];
384
        // Reset the hidden elements variable.
385
        _self.hidden = null;
386

    
387
      } // end reset
388

    
389
    },
390

    
391
    off : function () {
392
      $(this.scope).off('.fndtn.forms');
393
    }
394
  };
395
}(Foundation.zj, this, this.document));