helios 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +93 -71
  3. data/README.md +150 -127
  4. data/helios.gemspec +5 -4
  5. data/lib/helios/backend/push-notification.rb +1 -0
  6. data/lib/helios/commands/link.rb +2 -0
  7. data/lib/helios/commands/new.rb +1 -0
  8. data/lib/helios/frontend/javascripts/vendor/foundation.js +163 -47
  9. data/lib/helios/frontend/javascripts/vendor/foundation/foundation.alerts.js +6 -4
  10. data/lib/helios/frontend/javascripts/vendor/foundation/foundation.clearing.js +70 -32
  11. data/lib/helios/frontend/javascripts/vendor/foundation/foundation.dropdown.js +87 -31
  12. data/lib/helios/frontend/javascripts/vendor/foundation/foundation.forms.js +360 -238
  13. data/lib/helios/frontend/javascripts/vendor/foundation/foundation.interchange.js +271 -0
  14. data/lib/helios/frontend/javascripts/vendor/foundation/foundation.joyride.js +279 -48
  15. data/lib/helios/frontend/javascripts/vendor/foundation/foundation.magellan.js +8 -4
  16. data/lib/helios/frontend/javascripts/vendor/foundation/foundation.orbit.js +59 -24
  17. data/lib/helios/frontend/javascripts/vendor/foundation/foundation.placeholder.js +21 -1
  18. data/lib/helios/frontend/javascripts/vendor/foundation/foundation.reveal.js +100 -42
  19. data/lib/helios/frontend/javascripts/vendor/foundation/foundation.section.js +299 -60
  20. data/lib/helios/frontend/javascripts/vendor/foundation/foundation.tooltips.js +26 -13
  21. data/lib/helios/frontend/javascripts/vendor/foundation/foundation.topbar.js +154 -59
  22. data/lib/helios/frontend/javascripts/vendor/foundation/index.js +17 -0
  23. data/lib/helios/frontend/stylesheets/screen.sass +0 -1
  24. data/lib/helios/frontend/templates/push-notification/devices.jst.tpl +0 -3
  25. data/lib/helios/templates/.gitignore.erb +32 -0
  26. data/lib/helios/version.rb +1 -1
  27. metadata +31 -14
@@ -6,21 +6,24 @@
6
6
  Foundation.libs.dropdown = {
7
7
  name : 'dropdown',
8
8
 
9
- version : '4.0.0',
9
+ version : '4.2.0',
10
10
 
11
11
  settings : {
12
- activeClass: 'open'
12
+ activeClass: 'open',
13
+ is_hover: false,
14
+ opened: function(){},
15
+ closed: function(){}
13
16
  },
14
17
 
15
18
  init : function (scope, method, options) {
16
19
  this.scope = scope || this.scope;
17
- Foundation.inherit(this, 'throttle');
20
+ Foundation.inherit(this, 'throttle scrollLeft data_options');
18
21
 
19
22
  if (typeof method === 'object') {
20
23
  $.extend(true, this.settings, method);
21
24
  }
22
25
 
23
- if (typeof method != 'string') {
26
+ if (typeof method !== 'string') {
24
27
 
25
28
  if (!this.settings.init) {
26
29
  this.events();
@@ -35,22 +38,37 @@
35
38
  events : function () {
36
39
  var self = this;
37
40
 
38
- $(this.scope).on('click.fndtn.dropdown', '[data-dropdown]', function (e) {
39
- e.preventDefault();
40
- e.stopPropagation();
41
- self.toggle($(this));
42
- });
43
-
44
- $('*, html, body').on('click.fndtn.dropdown', function (e) {
45
- if (!$(e.target).data('dropdown')) {
46
- $('[data-dropdown-content]')
47
- .css('left', '-99999px')
48
- .removeClass(self.settings.activeClass);
41
+ $(this.scope)
42
+ .on('click.fndtn.dropdown', '[data-dropdown]', function (e) {
43
+ var settings = $.extend({}, self.settings, self.data_options($(this)));
44
+ e.preventDefault();
45
+
46
+ if (!settings.is_hover) self.toggle($(this));
47
+ })
48
+ .on('mouseenter', '[data-dropdown]', function (e) {
49
+ var settings = $.extend({}, self.settings, self.data_options($(this)));
50
+ if (settings.is_hover) self.toggle($(this));
51
+ })
52
+ .on('mouseleave', '[data-dropdown-content]', function (e) {
53
+ var target = $('[data-dropdown="' + $(this).attr('id') + '"]'),
54
+ settings = $.extend({}, self.settings, self.data_options(target));
55
+ if (settings.is_hover) self.close.call(self, $(this));
56
+ })
57
+ .on('opened.fndtn.dropdown', '[data-dropdown-content]', this.settings.opened)
58
+ .on('closed.fndtn.dropdown', '[data-dropdown-content]', this.settings.closed);
59
+
60
+ $('body').on('click.fndtn.dropdown', function (e) {
61
+ var parent = $(e.target).closest('[data-dropdown-content]');
62
+
63
+ if ($(e.target).data('dropdown')) {
64
+ return;
65
+ }
66
+ if (parent.length > 0 && ($(e.target).is('[data-dropdown-content]') || $.contains(parent.first()[0], e.target))) {
67
+ e.stopPropagation();
68
+ return;
49
69
  }
50
- });
51
70
 
52
- $('[data-dropdown-content]').on('click.fndtn.dropdown', function (e) {
53
- e.stopPropagation();
71
+ self.close.call(self, $('[data-dropdown-content]'));
54
72
  });
55
73
 
56
74
  $(window).on('resize.fndtn.dropdown', self.throttle(function () {
@@ -60,19 +78,35 @@
60
78
  this.settings.init = true;
61
79
  },
62
80
 
63
- toggle : function (target, resize) {
81
+ close: function (dropdown) {
82
+ var self = this;
83
+ dropdown.each(function () {
84
+ if ($(this).hasClass(self.settings.activeClass)) {
85
+ $(this)
86
+ .css(Foundation.rtl ? 'right':'left', '-99999px')
87
+ .removeClass(self.settings.activeClass);
88
+ $(this).trigger('closed');
89
+ }
90
+ });
91
+ },
92
+
93
+ open: function (dropdown, target) {
94
+ this
95
+ .css(dropdown
96
+ .addClass(this.settings.activeClass), target);
97
+ dropdown.trigger('opened');
98
+ },
99
+
100
+ toggle : function (target) {
64
101
  var dropdown = $('#' + target.data('dropdown'));
65
102
 
66
- $('[data-dropdown-content]').not(dropdown).css('left', '-99999px');
103
+ this.close.call(this, $('[data-dropdown-content]').not(dropdown));
67
104
 
68
105
  if (dropdown.hasClass(this.settings.activeClass)) {
69
- dropdown
70
- .css('left', '-99999px')
71
- .removeClass(this.settings.activeClass);
106
+ this.close.call(this, dropdown);
72
107
  } else {
73
- this
74
- .css(dropdown
75
- .addClass(this.settings.activeClass), target);
108
+ this.close.call(this, $('[data-dropdown-content]'))
109
+ this.open.call(this, dropdown, target);
76
110
  }
77
111
  },
78
112
 
@@ -86,7 +120,15 @@
86
120
  },
87
121
 
88
122
  css : function (dropdown, target) {
89
- var offset = target.offset();
123
+ var offset_parent = dropdown.offsetParent();
124
+ // temporary workaround until 4.2
125
+ if (offset_parent.length > 0 && /body/i.test(dropdown.offsetParent()[0].nodeName)) {
126
+ var position = target.offset();
127
+ position.top -= dropdown.offsetParent().offset().top;
128
+ position.left -= dropdown.offsetParent().offset().left;
129
+ } else {
130
+ var position = target.position();
131
+ }
90
132
 
91
133
  if (this.small()) {
92
134
  dropdown.css({
@@ -94,13 +136,25 @@
94
136
  width: '95%',
95
137
  left: '2.5%',
96
138
  'max-width': 'none',
97
- top: offset.top + this.outerHeight(target)
139
+ top: position.top + this.outerHeight(target)
98
140
  });
99
141
  } else {
142
+ if (!Foundation.rtl && $(window).width() > this.outerWidth(dropdown) + target.offset().left) {
143
+ var left = position.left;
144
+ if (dropdown.hasClass('right')) {
145
+ dropdown.removeClass('right');
146
+ }
147
+ } else {
148
+ if (!dropdown.hasClass('right')) {
149
+ dropdown.addClass('right');
150
+ }
151
+ var left = position.left - (this.outerWidth(dropdown) - this.outerWidth(target));
152
+ }
153
+
100
154
  dropdown.attr('style', '').css({
101
155
  position : 'absolute',
102
- top: offset.top + this.outerHeight(target),
103
- left: offset.left
156
+ top: position.top + this.outerHeight(target),
157
+ left: left
104
158
  });
105
159
  }
106
160
 
@@ -117,6 +171,8 @@
117
171
  $(window).off('.fndtn.dropdown');
118
172
  $('[data-dropdown-content]').off('.fndtn.dropdown');
119
173
  this.settings.init = false;
120
- }
174
+ },
175
+
176
+ reflow : function () {}
121
177
  };
122
178
  }(Foundation.zj, this, this.document));
@@ -1,25 +1,25 @@
1
- /*jslint unparam: true, browser: true, indent: 2 */
2
-
3
- ;(function ($, window, document, undefined) {
1
+ (function ($, window, document, undefined) {
4
2
  'use strict';
5
3
 
6
4
  Foundation.libs.forms = {
7
- name : 'forms',
5
+ name: 'forms',
6
+
7
+ version: '4.2.3',
8
8
 
9
- version : '4.0.4',
9
+ cache: {},
10
10
 
11
- settings : {
12
- disable_class: 'no-custom'
11
+ settings: {
12
+ disable_class: 'no-custom',
13
+ last_combo : null
13
14
  },
14
15
 
15
- init : function (scope, method, options) {
16
- this.scope = scope || this.scope;
16
+ init: function (scope, method, options) {
17
17
 
18
18
  if (typeof method === 'object') {
19
19
  $.extend(true, this.settings, method);
20
20
  }
21
21
 
22
- if (typeof method != 'string') {
22
+ if (typeof method !== 'string') {
23
23
  if (!this.settings.init) {
24
24
  this.events();
25
25
  }
@@ -32,16 +32,23 @@
32
32
  }
33
33
  },
34
34
 
35
- assemble : function () {
36
- $('form.custom input[type="radio"]').not('[data-customforms="disabled"]')
35
+ assemble: function () {
36
+ $('form.custom input[type="radio"]', $(this.scope))
37
+ .not('[data-customforms="disabled"]')
38
+ .not('.' + this.settings.disable_class)
37
39
  .each(this.append_custom_markup);
38
- $('form.custom input[type="checkbox"]').not('[data-customforms="disabled"]')
40
+ $('form.custom input[type="checkbox"]', $(this.scope))
41
+ .not('[data-customforms="disabled"]')
42
+ .not('.' + this.settings.disable_class)
39
43
  .each(this.append_custom_markup);
40
- $('form.custom select').not('[data-customforms="disabled"]')
44
+ $('form.custom select', $(this.scope))
45
+ .not('[data-customforms="disabled"]')
46
+ .not('.' + this.settings.disable_class)
47
+ .not('[multiple=multiple]')
41
48
  .each(this.append_custom_select);
42
49
  },
43
50
 
44
- events : function () {
51
+ events: function () {
45
52
  var self = this;
46
53
 
47
54
  $(this.scope)
@@ -55,49 +62,47 @@
55
62
  e.stopPropagation();
56
63
  self.toggle_radio($(this));
57
64
  })
58
- .on('change.fndtn.forms', 'form.custom select:not([data-customforms="disabled"])', function (e) {
59
- self.refresh_custom_select($(this));
65
+ .on('change.fndtn.forms', 'form.custom select', function (e, force_refresh) {
66
+ if ($(this).is('[data-customforms="disabled"]')) return;
67
+ self.refresh_custom_select($(this), force_refresh);
60
68
  })
61
69
  .on('click.fndtn.forms', 'form.custom label', function (e) {
62
- var $associatedElement = $('#' + self.escape($(this).attr('for')) + ':not([data-customforms="disabled"])'),
70
+ if ($(e.target).is('label')) {
71
+ var $associatedElement = $('#' + self.escape($(this).attr('for'))).not('[data-customforms="disabled"]'),
63
72
  $customCheckbox,
64
73
  $customRadio;
65
- if ($associatedElement.length !== 0) {
66
- if ($associatedElement.attr('type') === 'checkbox') {
67
- e.preventDefault();
68
- $customCheckbox = $(this).find('span.custom.checkbox');
69
- //the checkbox might be outside after the label
70
- if ($customCheckbox.length == 0) {
71
- $customCheckbox = $(this).next('span.custom.checkbox');
72
- }
73
- //the checkbox might be outside before the label
74
- if ($customCheckbox.length == 0) {
75
- $customCheckbox = $(this).prev('span.custom.checkbox');
76
- }
77
- self.toggle_checkbox($customCheckbox);
78
- } else if ($associatedElement.attr('type') === 'radio') {
79
- e.preventDefault();
80
- $customRadio = $(this).find('span.custom.radio');
81
- //the radio might be outside after the label
82
- if ($customRadio.length == 0) {
83
- $customRadio = $(this).next('span.custom.radio');
84
- }
85
- //the radio might be outside before the label
86
- if ($customRadio.length == 0) {
87
- $customRadio = $(this).prev('span.custom.radio');
74
+
75
+ if ($associatedElement.length !== 0) {
76
+ if ($associatedElement.attr('type') === 'checkbox') {
77
+ e.preventDefault();
78
+ $customCheckbox = $(this).find('span.custom.checkbox');
79
+ //the checkbox might be outside after the label or inside of another element
80
+ if ($customCheckbox.length === 0) {
81
+ $customCheckbox = $associatedElement.add(this).siblings('span.custom.checkbox').first();
82
+ }
83
+ self.toggle_checkbox($customCheckbox);
84
+ } else if ($associatedElement.attr('type') === 'radio') {
85
+ e.preventDefault();
86
+ $customRadio = $(this).find('span.custom.radio');
87
+ //the radio might be outside after the label or inside of another element
88
+ if ($customRadio.length === 0) {
89
+ $customRadio = $associatedElement.add(this).siblings('span.custom.radio').first();
90
+ }
91
+ self.toggle_radio($customRadio);
88
92
  }
89
- self.toggle_radio($customRadio);
90
93
  }
91
94
  }
92
95
  })
96
+ .on('mousedown.fndtn.forms', 'form.custom div.custom.dropdown', function () {
97
+ return false;
98
+ })
93
99
  .on('click.fndtn.forms', 'form.custom div.custom.dropdown a.current, form.custom div.custom.dropdown a.selector', function (e) {
94
100
  var $this = $(this),
95
101
  $dropdown = $this.closest('div.custom.dropdown'),
96
- $select = $dropdown.prev();
102
+ $select = getFirstPrevSibling($dropdown, 'select');
97
103
 
98
104
  // make sure other dropdowns close
99
- if(!$dropdown.hasClass('open'))
100
- $(self.scope).trigger('click');
105
+ if (!$dropdown.hasClass('open')) $(self.scope).trigger('click');
101
106
 
102
107
  e.preventDefault();
103
108
  if (false === $select.is(':disabled')) {
@@ -117,32 +122,29 @@
117
122
  .on('click.fndtn.forms touchend.fndtn.forms', 'form.custom div.custom.dropdown li', function (e) {
118
123
  var $this = $(this),
119
124
  $customDropdown = $this.closest('div.custom.dropdown'),
120
- $select = $customDropdown.prev(),
125
+ $select = getFirstPrevSibling($customDropdown, 'select'),
121
126
  selectedIndex = 0;
122
127
 
123
128
  e.preventDefault();
124
129
  e.stopPropagation();
125
130
 
126
- if ( ! $(this).hasClass('disabled')) {
131
+ if (!$(this).hasClass('disabled')) {
127
132
  $('div.dropdown').not($customDropdown).removeClass('open');
128
133
 
129
- var $oldThis= $this
130
- .closest('ul')
134
+ var $oldThis = $this.closest('ul')
131
135
  .find('li.selected');
132
136
  $oldThis.removeClass('selected');
133
137
 
134
138
  $this.addClass('selected');
135
139
 
136
- $customDropdown
137
- .removeClass('open')
140
+ $customDropdown.removeClass('open')
138
141
  .find('a.current')
139
- .html($this.html());
142
+ .text($this.text());
140
143
 
141
144
  $this.closest('ul').find('li').each(function (index) {
142
- if ($this[0] == this) {
145
+ if ($this[0] === this) {
143
146
  selectedIndex = index;
144
147
  }
145
-
146
148
  });
147
149
  $select[0].selectedIndex = selectedIndex;
148
150
 
@@ -150,15 +152,94 @@
150
152
  $select.data('prevalue', $oldThis.html());
151
153
  $select.trigger('change');
152
154
  }
153
- });
155
+ });
156
+
157
+ $(window).on('keydown', function (e) {
158
+ var focus = document.activeElement,
159
+ self = Foundation.libs.forms,
160
+ dropdown = $('.custom.dropdown.open');
161
+
162
+ if (dropdown.length > 0) {
163
+ e.preventDefault();
164
+
165
+ if (e.which === 13) {
166
+ dropdown.find('li.selected').trigger('click');
167
+ }
168
+
169
+ if (e.which === 27) {
170
+ dropdown.removeClass('open');
171
+ }
172
+
173
+ if (e.which >= 65 && e.which <= 90) {
174
+ var next = self.go_to(dropdown, e.which),
175
+ current = dropdown.find('li.selected');
176
+
177
+ if (next) {
178
+ current.removeClass('selected');
179
+ self.scrollTo(next.addClass('selected'), 300);
180
+ }
181
+ }
182
+
183
+ if (e.which === 38) {
184
+ var current = dropdown.find('li.selected'),
185
+ prev = current.prev(':not(.disabled)');
186
+
187
+ if (prev.length > 0) {
188
+ prev.parent()[0].scrollTop = prev.parent().scrollTop() - self.outerHeight(prev);
189
+ current.removeClass('selected');
190
+ prev.addClass('selected');
191
+ }
192
+ } else if (e.which === 40) {
193
+ var current = dropdown.find('li.selected'),
194
+ next = current.next(':not(.disabled)');
195
+
196
+ if (next.length > 0) {
197
+ next.parent()[0].scrollTop = next.parent().scrollTop() + self.outerHeight(next);
198
+ current.removeClass('selected');
199
+ next.addClass('selected');
200
+ }
201
+ }
202
+ }
203
+ });
154
204
 
155
205
  this.settings.init = true;
156
206
  },
157
207
 
158
- append_custom_markup : function (idx, sel) {
159
- var $this = $(sel).hide(),
160
- type = $this.attr('type'),
208
+ go_to: function (dropdown, character) {
209
+ var lis = dropdown.find('li'),
210
+ count = lis.length;
211
+
212
+ if (count > 0) {
213
+ for (var i = 0; i < count; i++) {
214
+ var first_letter = lis.eq(i).text().charAt(0).toLowerCase();
215
+ if (first_letter === String.fromCharCode(character).toLowerCase()) return lis.eq(i);
216
+ }
217
+ }
218
+ },
219
+
220
+ scrollTo: function (el, duration) {
221
+ if (duration < 0) return;
222
+ var parent = el.parent();
223
+ var li_height = this.outerHeight(el);
224
+ var difference = (li_height * (el.index())) - parent.scrollTop();
225
+ var perTick = difference / duration * 10;
226
+
227
+ this.scrollToTimerCache = setTimeout(function () {
228
+ if (!isNaN(parseInt(perTick, 10))) {
229
+ parent[0].scrollTop = parent.scrollTop() + perTick;
230
+ this.scrollTo(el, duration - 10);
231
+ }
232
+ }.bind(this), 10);
233
+ },
234
+
235
+ append_custom_markup: function (idx, sel) {
236
+ var $this = $(sel),
237
+ type = $this.attr('type'),
161
238
  $span = $this.next('span.custom.' + type);
239
+
240
+ if (!$this.parent().hasClass('switch')) {
241
+ $this.addClass('hidden-field');
242
+ }
162
243
 
163
244
  if ($span.length === 0) {
164
245
  $span = $('<span class="custom ' + type + '"></span>').insertAfter($this);
@@ -168,133 +249,157 @@
168
249
  $span.toggleClass('disabled', $this.is(':disabled'));
169
250
  },
170
251
 
171
- append_custom_select : function (idx, sel) {
172
- var self = Foundation.libs.forms,
173
- $this = $( sel ),
174
- $customSelect = $this.next( 'div.custom.dropdown' ),
175
- $customList = $customSelect.find( 'ul' ),
176
- $selectCurrent = $customSelect.find( ".current" ),
177
- $selector = $customSelect.find( ".selector" ),
178
- $options = $this.find( 'option' ),
179
- $selectedOption = $options.filter( ':selected' ),
180
- maxWidth = 0,
181
- liHtml = '',
182
- $listItems,
183
- $currentSelect = false;
184
-
185
- if ($this.hasClass(self.settings.disable_class)) return;
186
-
187
- if ($customSelect.length === 0) {
188
- var customSelectSize = $this.hasClass( 'small' ) ? 'small' :
189
- $this.hasClass( 'medium' ) ? 'medium' :
190
- $this.hasClass( 'large' ) ? 'large' :
191
- $this.hasClass( 'expand' ) ? 'expand' : '';
192
-
193
- $customSelect = $('<div class="' + ['custom', 'dropdown', customSelectSize ].join( ' ' ) + '"><a href="#" class="selector"></a><ul /></div>');
194
- $selector = $customSelect.find(".selector");
195
- $customList = $customSelect.find("ul");
196
- liHtml = $options.map(function() { return "<li>" + $( this ).html() + "</li>"; } ).get().join( '' );
197
- $customList.append(liHtml);
198
- $currentSelect = $customSelect.prepend('<a href="#" class="current">' + $selectedOption.html() + '</a>' ).find( ".current" );
199
- $this
200
- .after( $customSelect )
201
- .hide();
202
-
203
- } else {
204
- liHtml = $options.map(function() {
205
- return "<li>" + $( this ).html() + "</li>";
206
- })
207
- .get().join('');
208
- $customList
209
- .html('')
210
- .append(liHtml);
211
-
212
- } // endif $customSelect.length === 0
213
- $customSelect.toggleClass('disabled', $this.is( ':disabled' ) );
214
- $listItems = $customList.find( 'li' );
215
-
216
- $options.each( function ( index ) {
217
- if ( this.selected ) {
218
- $listItems.eq( index ).addClass( 'selected' );
219
-
220
- if ($currentSelect) {
221
- $currentSelect.html( $( this ).html() );
252
+ append_custom_select: function (idx, sel) {
253
+ var self = Foundation.libs.forms,
254
+ $this = $(sel),
255
+ $customSelect = $this.next('div.custom.dropdown'),
256
+ $customList = $customSelect.find('ul'),
257
+ $selectCurrent = $customSelect.find(".current"),
258
+ $selector = $customSelect.find(".selector"),
259
+ $options = $this.find('option'),
260
+ $selectedOption = $options.filter(':selected'),
261
+ copyClasses = $this.attr('class') ? $this.attr('class').split(' ') : [],
262
+ maxWidth = 0,
263
+ liHtml = '',
264
+ $listItems,
265
+ $currentSelect = false;
266
+
267
+ if ($customSelect.length === 0) {
268
+ var customSelectSize = $this.hasClass('small') ? 'small' : $this.hasClass('medium') ? 'medium' : $this.hasClass('large') ? 'large' : $this.hasClass('expand') ? 'expand' : '';
269
+
270
+ $customSelect = $('<div class="' + ['custom', 'dropdown', customSelectSize].concat(copyClasses).filter(function (item, idx, arr) {
271
+ if (item === '') return false;
272
+ return arr.indexOf(item) === idx;
273
+ }).join(' ') + '"><a href="#" class="selector"></a><ul /></div>');
274
+
275
+ $selector = $customSelect.find(".selector");
276
+ $customList = $customSelect.find("ul");
277
+
278
+ liHtml = $options.map(function () {
279
+ var copyClasses = $(this).attr('class') ? $(this).attr('class') : '';
280
+ return "<li class='" + copyClasses + "'>" + $(this).html() + "</li>";
281
+ }).get().join('');
282
+
283
+ $customList.append(liHtml);
284
+
285
+ $currentSelect = $customSelect
286
+ .prepend('<a href="#" class="current">' + $selectedOption.html() + '</a>')
287
+ .find(".current");
288
+
289
+ $this.after($customSelect)
290
+ .addClass('hidden-field');
291
+ } else {
292
+ liHtml = $options.map(function () {
293
+ return "<li>" + $(this).html() + "</li>";
294
+ })
295
+ .get().join('');
296
+
297
+ $customList.html('')
298
+ .append(liHtml);
299
+
300
+ } // endif $customSelect.length === 0
301
+
302
+ self.assign_id($this, $customSelect);
303
+ $customSelect.toggleClass('disabled', $this.is(':disabled'));
304
+ $listItems = $customList.find('li');
305
+
306
+ // cache list length
307
+ self.cache[$customSelect.data('id')] = $listItems.length;
308
+
309
+ $options.each(function (index) {
310
+ if (this.selected) {
311
+ $listItems.eq(index).addClass('selected');
312
+
313
+ if ($currentSelect) {
314
+ $currentSelect.html($(this).html());
315
+ }
316
+ }
317
+ if ($(this).is(':disabled')) {
318
+ $listItems.eq(index).addClass('disabled');
222
319
  }
320
+ });
223
321
 
224
- }
225
- if ($(this).is(':disabled')) {
226
- $listItems.eq( index ).addClass( 'disabled' );
227
- }
228
- });
322
+ //
323
+ // If we're not specifying a predetermined form size.
324
+ //
325
+ if (!$customSelect.is('.small, .medium, .large, .expand')) {
229
326
 
230
- //
231
- // If we're not specifying a predetermined form size.
232
- //
233
- if (!$customSelect.is('.small, .medium, .large, .expand')) {
327
+ // ------------------------------------------------------------------------------------
328
+ // This is a work-around for when elements are contained within hidden parents.
329
+ // For example, when custom-form elements are inside of a hidden reveal modal.
330
+ //
331
+ // We need to display the current custom list element as well as hidden parent elements
332
+ // in order to properly calculate the list item element's width property.
333
+ // -------------------------------------------------------------------------------------
234
334
 
235
- // ------------------------------------------------------------------------------------
236
- // This is a work-around for when elements are contained within hidden parents.
237
- // For example, when custom-form elements are inside of a hidden reveal modal.
238
- //
239
- // We need to display the current custom list element as well as hidden parent elements
240
- // in order to properly calculate the list item element's width property.
241
- // -------------------------------------------------------------------------------------
335
+ $customSelect.addClass('open');
336
+ //
337
+ // Quickly, display all parent elements.
338
+ // This should help us calcualate the width of the list item's within the drop down.
339
+ //
340
+ var self = Foundation.libs.forms;
341
+ self.hidden_fix.adjust($customList);
242
342
 
243
- $customSelect.addClass( 'open' );
244
- //
245
- // Quickly, display all parent elements.
246
- // This should help us calcualate the width of the list item's within the drop down.
247
- //
248
- var self = Foundation.libs.forms;
249
- self.hidden_fix.adjust( $customList );
343
+ maxWidth = (self.outerWidth($listItems) > maxWidth) ? self.outerWidth($listItems) : maxWidth;
250
344
 
251
- maxWidth = ( self.outerWidth($listItems) > maxWidth ) ? self.outerWidth($listItems) : maxWidth;
345
+ Foundation.libs.forms.hidden_fix.reset();
252
346
 
253
- Foundation.libs.forms.hidden_fix.reset();
347
+ $customSelect.removeClass('open');
254
348
 
255
- $customSelect.removeClass( 'open' );
349
+ } // endif
256
350
 
257
- } // endif
351
+ },
258
352
 
353
+ assign_id: function ($select, $customSelect) {
354
+ var id = [+new Date(), Foundation.random_str(5)].join('-');
355
+ $select.attr('data-id', id);
356
+ $customSelect.attr('data-id', id);
259
357
  },
260
358
 
261
- refresh_custom_select : function ($select) {
359
+ refresh_custom_select: function ($select, force_refresh) {
262
360
  var self = this;
263
361
  var maxWidth = 0,
264
- $customSelect = $select.next(),
265
- $options = $select.find('option');
362
+ $customSelect = $select.next(),
363
+ $options = $select.find('option'),
364
+ $listItems = $customSelect.find('li');
266
365
 
267
- $customSelect.find('ul').html('');
366
+ if ($listItems.length !== this.cache[$customSelect.data('id')] || force_refresh) {
367
+ $customSelect.find('ul').html('');
268
368
 
269
- $options.each(function () {
270
- var $li = $('<li>' + $(this).html() + '</li>');
271
- $customSelect.find('ul').append($li);
272
- });
369
+ $options.each(function () {
370
+ var $li = $('<li>' + $(this).html() + '</li>');
371
+ $customSelect.find('ul').append($li);
372
+ });
273
373
 
274
- // re-populate
275
- $options.each(function (index) {
276
- if (this.selected) {
277
- $customSelect.find('li').eq(index).addClass('selected');
278
- $customSelect.find('.current').html($(this).html());
279
- }
280
- if ($(this).is(':disabled')) {
281
- $customSelect.find('li').eq(index).addClass('disabled');
282
- }
283
- });
374
+ // re-populate
375
+ $options.each(function (index) {
376
+ if (this.selected) {
377
+ $customSelect.find('li').eq(index).addClass('selected');
378
+ $customSelect.find('.current').html($(this).html());
379
+ }
380
+ if ($(this).is(':disabled')) {
381
+ $customSelect.find('li').eq(index).addClass('disabled');
382
+ }
383
+ });
284
384
 
285
- // fix width
286
- $customSelect.removeAttr('style')
287
- .find('ul').removeAttr('style');
288
- $customSelect.find('li').each(function () {
289
- $customSelect.addClass('open');
290
- if (self.outerWidth($(this)) > maxWidth) {
291
- maxWidth = self.outerWidth($(this));
292
- }
293
- $customSelect.removeClass('open');
294
- });
385
+ // fix width
386
+ $customSelect.removeAttr('style')
387
+ .find('ul').removeAttr('style');
388
+ $customSelect.find('li').each(function () {
389
+ $customSelect.addClass('open');
390
+ if (self.outerWidth($(this)) > maxWidth) {
391
+ maxWidth = self.outerWidth($(this));
392
+ }
393
+ $customSelect.removeClass('open');
394
+ });
395
+
396
+ $listItems = $customSelect.find('li');
397
+ // cache list length
398
+ this.cache[$customSelect.data('id')] = $listItems.length;
399
+ }
295
400
  },
296
401
 
297
- toggle_checkbox : function ($element) {
402
+ toggle_checkbox: function ($element) {
298
403
  var $input = $element.prev(),
299
404
  input = $input[0];
300
405
 
@@ -306,98 +411,115 @@
306
411
  }
307
412
  },
308
413
 
309
- toggle_radio : function ($element) {
310
- var $input = $element.prev(),
311
- $form = $input.closest('form.custom'),
312
- input = $input[0];
414
+ toggle_radio: function ($element) {
415
+ var $input = $element.prev(),
416
+ $form = $input.closest('form.custom'),
417
+ input = $input[0];
313
418
 
314
- if (false === $input.is(':disabled')) {
315
- $form.find('input[type="radio"][name="' + this.escape($input.attr('name')) + '"]').next().not($element).removeClass('checked');
316
- if ( !$element.hasClass('checked') ) {
317
- $element.toggleClass('checked');
318
- }
319
- input.checked = $element.hasClass('checked');
419
+ if (false === $input.is(':disabled')) {
420
+ $form.find('input[type="radio"][name="' + this.escape($input.attr('name')) + '"]')
421
+ .next().not($element).removeClass('checked');
320
422
 
321
- $input.trigger('change');
322
- }
423
+ if (!$element.hasClass('checked')) {
424
+ $element.toggleClass('checked');
425
+ }
426
+
427
+ input.checked = $element.hasClass('checked');
428
+
429
+ $input.trigger('change');
430
+ }
323
431
  },
324
432
 
325
- escape : function (text) {
433
+ escape: function (text) {
434
+ if (!text) return '';
326
435
  return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
327
436
  },
328
437
 
329
- hidden_fix : {
330
- /**
331
- * Sets all hidden parent elements and self to visibile.
332
- *
333
- * @method adjust
334
- * @param {jQuery Object} $child
335
- */
438
+ hidden_fix: {
439
+ /**
440
+ * Sets all hidden parent elements and self to visibile.
441
+ *
442
+ * @method adjust
443
+ * @param {jQuery Object} $child
444
+ */
336
445
 
337
- // We'll use this to temporarily store style properties.
338
- tmp : [],
446
+ // We'll use this to temporarily store style properties.
447
+ tmp: [],
339
448
 
340
- // We'll use this to set hidden parent elements.
341
- hidden : null,
449
+ // We'll use this to set hidden parent elements.
450
+ hidden: null,
342
451
 
343
- adjust : function( $child ) {
344
- // Internal reference.
345
- var _self = this;
452
+ adjust: function ($child) {
453
+ // Internal reference.
454
+ var _self = this;
346
455
 
347
- // Set all hidden parent elements, including this element.
348
- _self.hidden = $child.parents().andSelf().filter( ":hidden" );
456
+ // Set all hidden parent elements, including this element.
457
+ _self.hidden = $child.parents();
458
+ _self.hidden = _self.hidden.add($child).filter(":hidden");
349
459
 
350
- // Loop through all hidden elements.
351
- _self.hidden.each( function() {
460
+ // Loop through all hidden elements.
461
+ _self.hidden.each(function () {
352
462
 
353
- // Cache the element.
354
- var $elem = $( this );
463
+ // Cache the element.
464
+ var $elem = $(this);
355
465
 
356
- // Store the style attribute.
357
- // Undefined if element doesn't have a style attribute.
358
- _self.tmp.push( $elem.attr( 'style' ) );
466
+ // Store the style attribute.
467
+ // Undefined if element doesn't have a style attribute.
468
+ _self.tmp.push($elem.attr('style'));
359
469
 
360
- // Set the element's display property to block,
361
- // but ensure it's visibility is hidden.
362
- $elem.css( { 'visibility' : 'hidden', 'display' : 'block' } );
363
- });
364
-
365
- }, // end adjust
366
-
367
- /**
368
- * Resets the elements previous state.
369
- *
370
- * @method reset
371
- */
372
- reset : function() {
373
- // Internal reference.
374
- var _self = this;
375
- // Loop through our hidden element collection.
376
- _self.hidden.each( function( i ) {
377
- // Cache this element.
378
- var $elem = $( this ),
379
- _tmp = _self.tmp[ i ]; // Get the stored 'style' value for this element.
380
-
381
- // If the stored value is undefined.
382
- if( _tmp === undefined )
470
+ // Set the element's display property to block,
471
+ // but ensure it's visibility is hidden.
472
+ $elem.css({
473
+ 'visibility': 'hidden',
474
+ 'display': 'block'
475
+ });
476
+ });
477
+
478
+ }, // end adjust
479
+
480
+ /**
481
+ * Resets the elements previous state.
482
+ *
483
+ * @method reset
484
+ */
485
+ reset: function () {
486
+ // Internal reference.
487
+ var _self = this;
488
+ // Loop through our hidden element collection.
489
+ _self.hidden.each(function (i) {
490
+ // Cache this element.
491
+ var $elem = $(this),
492
+ _tmp = _self.tmp[i]; // Get the stored 'style' value for this element.
493
+
494
+ // If the stored value is undefined.
495
+ if (_tmp === undefined)
383
496
  // Remove the style attribute.
384
- $elem.removeAttr( 'style' );
385
- else
497
+ $elem.removeAttr('style');
498
+ else
386
499
  // Otherwise, reset the element style attribute.
387
- $elem.attr( 'style', _tmp );
388
-
389
- });
390
- // Reset the tmp array.
391
- _self.tmp = [];
392
- // Reset the hidden elements variable.
393
- _self.hidden = null;
394
-
395
- } // end reset
396
-
500
+ $elem.attr('style', _tmp);
501
+ });
502
+ // Reset the tmp array.
503
+ _self.tmp = [];
504
+ // Reset the hidden elements variable.
505
+ _self.hidden = null;
506
+
507
+ } // end reset
397
508
  },
398
509
 
399
- off : function () {
510
+ off: function () {
400
511
  $(this.scope).off('.fndtn.forms');
512
+ },
513
+
514
+ reflow : function () {}
515
+ };
516
+
517
+ var getFirstPrevSibling = function($el, selector) {
518
+ var $el = $el.prev();
519
+ while ($el.length) {
520
+ if ($el.is(selector)) return $el;
521
+ $el = $el.prev();
401
522
  }
523
+ return $();
402
524
  };
403
- }(Foundation.zj, this, this.document));
525
+ }(Foundation.zj, this, this.document));