chemistrykit 3.8.1 → 3.9.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/.gitignore +1 -0
  2. data/CHANGELOG.md +15 -5
  3. data/Gemfile +4 -0
  4. data/README.md +13 -1
  5. data/Rakefile +3 -3
  6. data/chemistrykit.gemspec +7 -3
  7. data/features/brew.feature +1 -1
  8. data/features/chemists.feature +56 -1
  9. data/features/concurrency.feature +2 -2
  10. data/features/exit_status.feature +1 -0
  11. data/features/logging.feature +88 -85
  12. data/features/reporting.feature +105 -0
  13. data/features/step_definitions/steps.rb +4 -4
  14. data/features/support/env.rb +1 -1
  15. data/features/tags.feature +1 -0
  16. data/lib/chemistrykit/chemist.rb +6 -1
  17. data/lib/chemistrykit/chemist/repository/csv_chemist_repository.rb +1 -1
  18. data/lib/chemistrykit/cli/cli.rb +33 -12
  19. data/lib/chemistrykit/configuration.rb +2 -2
  20. data/lib/chemistrykit/formula/formula_lab.rb +13 -0
  21. data/lib/chemistrykit/{parallel_tests_mods.rb → parallel_tests/rspec/runner.rb} +5 -5
  22. data/lib/chemistrykit/reporting/html_report_assembler.rb +170 -0
  23. data/lib/chemistrykit/rspec/html_formatter.rb +241 -0
  24. data/lib/chemistrykit/rspec/j_unit_formatter.rb +124 -0
  25. data/report/config.rb +28 -0
  26. data/report/index.html +213 -0
  27. data/report/javascripts/foundation/foundation.abide.js +194 -0
  28. data/report/javascripts/foundation/foundation.alerts.js +52 -0
  29. data/report/javascripts/foundation/foundation.clearing.js +516 -0
  30. data/report/javascripts/foundation/foundation.cookie.js +74 -0
  31. data/report/javascripts/foundation/foundation.dropdown.js +177 -0
  32. data/report/javascripts/foundation/foundation.forms.js +533 -0
  33. data/report/javascripts/foundation/foundation.interchange.js +280 -0
  34. data/report/javascripts/foundation/foundation.joyride.js +850 -0
  35. data/report/javascripts/foundation/foundation.js +440 -0
  36. data/report/javascripts/foundation/foundation.magellan.js +135 -0
  37. data/report/javascripts/foundation/foundation.orbit.js +412 -0
  38. data/report/javascripts/foundation/foundation.placeholder.js +179 -0
  39. data/report/javascripts/foundation/foundation.reveal.js +330 -0
  40. data/report/javascripts/foundation/foundation.section.js +400 -0
  41. data/report/javascripts/foundation/foundation.tooltips.js +208 -0
  42. data/report/javascripts/foundation/foundation.topbar.js +300 -0
  43. data/report/javascripts/vendor/custom.modernizr.js +4 -0
  44. data/report/javascripts/vendor/jquery.js +9789 -0
  45. data/report/sass/_normalize.scss +402 -0
  46. data/report/sass/_settings.scss +1301 -0
  47. data/report/sass/app.scss +571 -0
  48. data/report/stylesheets/app.css +3636 -0
  49. data/spec/integration/lib/chemistrykit/formula/formula_lab_spec.rb +26 -2
  50. data/spec/integration/lib/chemistrykit/reporting/html_reporting_assembler_spec.rb +18 -0
  51. data/spec/support/evidence/results_0.html +30 -0
  52. data/spec/support/evidence/results_1.html +27 -0
  53. data/spec/unit/lib/chemistrykit/chemist/repository/csv_chemist_repository_spec.rb +15 -2
  54. data/spec/unit/lib/chemistrykit/chemist_spec.rb +17 -1
  55. data/spec/unit/lib/chemistrykit/configuration_spec.rb +2 -2
  56. data/spec/unit/lib/chemistrykit/formula/formula_lab_spec.rb +7 -0
  57. data/spec/unit/lib/chemistrykit/reporting/html_reporting_assembler_spec.rb +22 -0
  58. metadata +94 -13
  59. data/lib/chemistrykit/j_unit.rb +0 -121
@@ -0,0 +1,74 @@
1
+ /*!
2
+ * jQuery Cookie Plugin v1.3
3
+ * https://github.com/carhartl/jquery-cookie
4
+ *
5
+ * Copyright 2011, Klaus Hartl
6
+ * Dual licensed under the MIT or GPL Version 2 licenses.
7
+ * http://www.opensource.org/licenses/mit-license.php
8
+ * http://www.opensource.org/licenses/GPL-2.0
9
+ *
10
+ * Modified to work with Zepto.js by ZURB
11
+ */
12
+ (function ($, document, undefined) {
13
+
14
+ var pluses = /\+/g;
15
+
16
+ function raw(s) {
17
+ return s;
18
+ }
19
+
20
+ function decoded(s) {
21
+ return decodeURIComponent(s.replace(pluses, ' '));
22
+ }
23
+
24
+ var config = $.cookie = function (key, value, options) {
25
+
26
+ // write
27
+ if (value !== undefined) {
28
+ options = $.extend({}, config.defaults, options);
29
+
30
+ if (value === null) {
31
+ options.expires = -1;
32
+ }
33
+
34
+ if (typeof options.expires === 'number') {
35
+ var days = options.expires, t = options.expires = new Date();
36
+ t.setDate(t.getDate() + days);
37
+ }
38
+
39
+ value = config.json ? JSON.stringify(value) : String(value);
40
+
41
+ return (document.cookie = [
42
+ encodeURIComponent(key), '=', config.raw ? value : encodeURIComponent(value),
43
+ options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
44
+ options.path ? '; path=' + options.path : '',
45
+ options.domain ? '; domain=' + options.domain : '',
46
+ options.secure ? '; secure' : ''
47
+ ].join(''));
48
+ }
49
+
50
+ // read
51
+ var decode = config.raw ? raw : decoded;
52
+ var cookies = document.cookie.split('; ');
53
+ for (var i = 0, l = cookies.length; i < l; i++) {
54
+ var parts = cookies[i].split('=');
55
+ if (decode(parts.shift()) === key) {
56
+ var cookie = decode(parts.join('='));
57
+ return config.json ? JSON.parse(cookie) : cookie;
58
+ }
59
+ }
60
+
61
+ return null;
62
+ };
63
+
64
+ config.defaults = {};
65
+
66
+ $.removeCookie = function (key, options) {
67
+ if ($.cookie(key) !== null) {
68
+ $.cookie(key, null, options);
69
+ return true;
70
+ }
71
+ return false;
72
+ };
73
+
74
+ })(Foundation.zj, document);
@@ -0,0 +1,177 @@
1
+ /*jslint unparam: true, browser: true, indent: 2 */
2
+
3
+ ;(function ($, window, document, undefined) {
4
+ 'use strict';
5
+
6
+ Foundation.libs.dropdown = {
7
+ name : 'dropdown',
8
+
9
+ version : '4.3.0',
10
+
11
+ settings : {
12
+ activeClass: 'open',
13
+ is_hover: false,
14
+ opened: function(){},
15
+ closed: function(){}
16
+ },
17
+
18
+ init : function (scope, method, options) {
19
+ this.scope = scope || this.scope;
20
+ Foundation.inherit(this, 'throttle scrollLeft data_options');
21
+
22
+ if (typeof method === 'object') {
23
+ $.extend(true, this.settings, method);
24
+ }
25
+
26
+ if (typeof method !== 'string') {
27
+
28
+ if (!this.settings.init) {
29
+ this.events();
30
+ }
31
+
32
+ return this.settings.init;
33
+ } else {
34
+ return this[method].call(this, options);
35
+ }
36
+ },
37
+
38
+ events : function () {
39
+ var self = this;
40
+
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
+ $(document).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;
69
+ }
70
+
71
+ self.close.call(self, $('[data-dropdown-content]'));
72
+ });
73
+
74
+ $(window).on('resize.fndtn.dropdown', self.throttle(function () {
75
+ self.resize.call(self);
76
+ }, 50)).trigger('resize');
77
+
78
+ this.settings.init = true;
79
+ },
80
+
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) {
101
+ var dropdown = $('#' + target.data('dropdown'));
102
+
103
+ this.close.call(this, $('[data-dropdown-content]').not(dropdown));
104
+
105
+ if (dropdown.hasClass(this.settings.activeClass)) {
106
+ this.close.call(this, dropdown);
107
+ } else {
108
+ this.close.call(this, $('[data-dropdown-content]'))
109
+ this.open.call(this, dropdown, target);
110
+ }
111
+ },
112
+
113
+ resize : function () {
114
+ var dropdown = $('[data-dropdown-content].open'),
115
+ target = $("[data-dropdown='" + dropdown.attr('id') + "']");
116
+
117
+ if (dropdown.length && target.length) {
118
+ this.css(dropdown, target);
119
+ }
120
+ },
121
+
122
+ css : function (dropdown, target) {
123
+ var offset_parent = dropdown.offsetParent();
124
+ // if (offset_parent.length > 0 && /body/i.test(dropdown.offsetParent()[0].nodeName)) {
125
+ var position = target.offset();
126
+ position.top -= offset_parent.offset().top;
127
+ position.left -= offset_parent.offset().left;
128
+ // } else {
129
+ // var position = target.position();
130
+ // }
131
+
132
+ if (this.small()) {
133
+ dropdown.css({
134
+ position : 'absolute',
135
+ width: '95%',
136
+ left: '2.5%',
137
+ 'max-width': 'none',
138
+ top: position.top + this.outerHeight(target)
139
+ });
140
+ } else {
141
+ if (!Foundation.rtl && $(window).width() > this.outerWidth(dropdown) + target.offset().left) {
142
+ var left = position.left;
143
+ if (dropdown.hasClass('right')) {
144
+ dropdown.removeClass('right');
145
+ }
146
+ } else {
147
+ if (!dropdown.hasClass('right')) {
148
+ dropdown.addClass('right');
149
+ }
150
+ var left = position.left - (this.outerWidth(dropdown) - this.outerWidth(target));
151
+ }
152
+
153
+ dropdown.attr('style', '').css({
154
+ position : 'absolute',
155
+ top: position.top + this.outerHeight(target),
156
+ left: left
157
+ });
158
+ }
159
+
160
+ return dropdown;
161
+ },
162
+
163
+ small : function () {
164
+ return $(window).width() < 768 || $('html').hasClass('lt-ie9');
165
+ },
166
+
167
+ off: function () {
168
+ $(this.scope).off('.fndtn.dropdown');
169
+ $('html, body').off('.fndtn.dropdown');
170
+ $(window).off('.fndtn.dropdown');
171
+ $('[data-dropdown-content]').off('.fndtn.dropdown');
172
+ this.settings.init = false;
173
+ },
174
+
175
+ reflow : function () {}
176
+ };
177
+ }(Foundation.zj, this, this.document));
@@ -0,0 +1,533 @@
1
+ (function ($, window, document, undefined) {
2
+ 'use strict';
3
+
4
+ Foundation.libs.forms = {
5
+ name : 'forms',
6
+
7
+ version: '4.3.1',
8
+
9
+ cache: {},
10
+
11
+ settings: {
12
+ disable_class: 'no-custom',
13
+ last_combo : null
14
+ },
15
+
16
+ init: function (scope, method, options) {
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))
37
+ .not('[data-customforms="disabled"]')
38
+ .not('.' + this.settings.disable_class)
39
+ .each(this.append_custom_markup);
40
+ $('form.custom input[type="checkbox"]', $(this.scope))
41
+ .not('[data-customforms="disabled"]')
42
+ .not('.' + this.settings.disable_class)
43
+ .each(this.append_custom_markup);
44
+ $('form.custom select', $(this.scope))
45
+ .not('[data-customforms="disabled"]')
46
+ .not('.' + this.settings.disable_class)
47
+ .not('[multiple=multiple]')
48
+ .each(this.append_custom_select);
49
+ },
50
+
51
+ events: function () {
52
+ var self = this;
53
+
54
+ $(this.scope)
55
+ .on('click.fndtn.forms', 'form.custom span.custom.checkbox', function (e) {
56
+ e.preventDefault();
57
+ e.stopPropagation();
58
+ self.toggle_checkbox($(this));
59
+ })
60
+ .on('click.fndtn.forms', 'form.custom span.custom.radio', function (e) {
61
+ e.preventDefault();
62
+ e.stopPropagation();
63
+ self.toggle_radio($(this));
64
+ })
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);
68
+ })
69
+ .on('click.fndtn.forms', 'form.custom label', function (e) {
70
+ if ($(e.target).is('label')) {
71
+ var $associatedElement = $('#' + self.escape($(this).attr('for'))).not('[data-customforms="disabled"]'),
72
+ $customCheckbox,
73
+ $customRadio;
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);
92
+ }
93
+ }
94
+ }
95
+ })
96
+ .on('mousedown.fndtn.forms', 'form.custom div.custom.dropdown', function () {
97
+ return false;
98
+ })
99
+ .on('click.fndtn.forms', 'form.custom div.custom.dropdown a.current, form.custom div.custom.dropdown a.selector', function (e) {
100
+ var $this = $(this),
101
+ $dropdown = $this.closest('div.custom.dropdown'),
102
+ $select = getFirstPrevSibling($dropdown, 'select');
103
+
104
+ // make sure other dropdowns close
105
+ if (!$dropdown.hasClass('open')) $(self.scope).trigger('click');
106
+
107
+ e.preventDefault();
108
+ if (false === $select.is(':disabled')) {
109
+ $dropdown.toggleClass('open');
110
+
111
+ if ($dropdown.hasClass('open')) {
112
+ $(self.scope).on('click.fndtn.forms.customdropdown', function () {
113
+ $dropdown.removeClass('open');
114
+ $(self.scope).off('.fndtn.forms.customdropdown');
115
+ });
116
+ } else {
117
+ $(self.scope).on('.fndtn.forms.customdropdown');
118
+ }
119
+ return false;
120
+ }
121
+ })
122
+ .on('click.fndtn.forms touchend.fndtn.forms', 'form.custom div.custom.dropdown li', function (e) {
123
+ var $this = $(this),
124
+ $customDropdown = $this.closest('div.custom.dropdown'),
125
+ $select = getFirstPrevSibling($customDropdown, 'select'),
126
+ selectedIndex = 0;
127
+
128
+ e.preventDefault();
129
+ e.stopPropagation();
130
+
131
+ if (!$(this).hasClass('disabled')) {
132
+ $('div.dropdown').not($customDropdown).removeClass('open');
133
+
134
+ var $oldThis = $this.closest('ul')
135
+ .find('li.selected');
136
+ $oldThis.removeClass('selected');
137
+
138
+ $this.addClass('selected');
139
+
140
+ $customDropdown.removeClass('open')
141
+ .find('a.current')
142
+ .text($this.text());
143
+
144
+ $this.closest('ul').find('li').each(function (index) {
145
+ if ($this[0] === this) {
146
+ selectedIndex = index;
147
+ }
148
+ });
149
+ $select[0].selectedIndex = selectedIndex;
150
+
151
+ //store the old value in data
152
+ $select.data('prevalue', $oldThis.html());
153
+
154
+ // Kick off full DOM change event
155
+ if (typeof (document.createEvent) != 'undefined') {
156
+ var event = document.createEvent('HTMLEvents');
157
+ event.initEvent('change', true, true);
158
+ $select[0].dispatchEvent(event);
159
+ } else {
160
+ $select[0].fireEvent('onchange'); // for IE
161
+ }
162
+ }
163
+ });
164
+
165
+ $(window).on('keydown', function (e) {
166
+ var focus = document.activeElement,
167
+ self = Foundation.libs.forms,
168
+ dropdown = $('.custom.dropdown.open');
169
+
170
+ if (dropdown.length > 0) {
171
+ e.preventDefault();
172
+
173
+ if (e.which === 13) {
174
+ dropdown.find('li.selected').trigger('click');
175
+ }
176
+
177
+ if (e.which === 27) {
178
+ dropdown.removeClass('open');
179
+ }
180
+
181
+ if (e.which >= 65 && e.which <= 90) {
182
+ var next = self.go_to(dropdown, e.which),
183
+ current = dropdown.find('li.selected');
184
+
185
+ if (next) {
186
+ current.removeClass('selected');
187
+ self.scrollTo(next.addClass('selected'), 300);
188
+ }
189
+ }
190
+
191
+ if (e.which === 38) {
192
+ var current = dropdown.find('li.selected'),
193
+ prev = current.prev(':not(.disabled)');
194
+
195
+ if (prev.length > 0) {
196
+ prev.parent()[0].scrollTop = prev.parent().scrollTop() - self.outerHeight(prev);
197
+ current.removeClass('selected');
198
+ prev.addClass('selected');
199
+ }
200
+ } else if (e.which === 40) {
201
+ var current = dropdown.find('li.selected'),
202
+ next = current.next(':not(.disabled)');
203
+
204
+ if (next.length > 0) {
205
+ next.parent()[0].scrollTop = next.parent().scrollTop() + self.outerHeight(next);
206
+ current.removeClass('selected');
207
+ next.addClass('selected');
208
+ }
209
+ }
210
+ }
211
+ });
212
+
213
+ this.settings.init = true;
214
+ },
215
+
216
+ go_to: function (dropdown, character) {
217
+ var lis = dropdown.find('li'),
218
+ count = lis.length;
219
+
220
+ if (count > 0) {
221
+ for (var i = 0; i < count; i++) {
222
+ var first_letter = lis.eq(i).text().charAt(0).toLowerCase();
223
+ if (first_letter === String.fromCharCode(character).toLowerCase()) return lis.eq(i);
224
+ }
225
+ }
226
+ },
227
+
228
+ scrollTo: function (el, duration) {
229
+ if (duration < 0) return;
230
+ var parent = el.parent();
231
+ var li_height = this.outerHeight(el);
232
+ var difference = (li_height * (el.index())) - parent.scrollTop();
233
+ var perTick = difference / duration * 10;
234
+
235
+ this.scrollToTimerCache = setTimeout(function () {
236
+ if (!isNaN(parseInt(perTick, 10))) {
237
+ parent[0].scrollTop = parent.scrollTop() + perTick;
238
+ this.scrollTo(el, duration - 10);
239
+ }
240
+ }.bind(this), 10);
241
+ },
242
+
243
+ append_custom_markup: function (idx, sel) {
244
+ var $this = $(sel),
245
+ type = $this.attr('type'),
246
+ $span = $this.next('span.custom.' + type);
247
+
248
+ if (!$this.parent().hasClass('switch')) {
249
+ $this.addClass('hidden-field');
250
+ }
251
+
252
+ if ($span.length === 0) {
253
+ $span = $('<span class="custom ' + type + '"></span>').insertAfter($this);
254
+ }
255
+
256
+ $span.toggleClass('checked', $this.is(':checked'));
257
+ $span.toggleClass('disabled', $this.is(':disabled'));
258
+ },
259
+
260
+ append_custom_select: function (idx, sel) {
261
+ var self = Foundation.libs.forms,
262
+ $this = $(sel),
263
+ $customSelect = $this.next('div.custom.dropdown'),
264
+ $customList = $customSelect.find('ul'),
265
+ $selectCurrent = $customSelect.find(".current"),
266
+ $selector = $customSelect.find(".selector"),
267
+ $options = $this.find('option'),
268
+ $selectedOption = $options.filter(':selected'),
269
+ copyClasses = $this.attr('class') ? $this.attr('class').split(' ') : [],
270
+ maxWidth = 0,
271
+ liHtml = '',
272
+ $listItems,
273
+ $currentSelect = false;
274
+
275
+ if ($customSelect.length === 0) {
276
+ var customSelectSize = $this.hasClass('small') ? 'small' : $this.hasClass('medium') ? 'medium' : $this.hasClass('large') ? 'large' : $this.hasClass('expand') ? 'expand' : '';
277
+
278
+ $customSelect = $('<div class="' + ['custom', 'dropdown', customSelectSize].concat(copyClasses).filter(function (item, idx, arr) {
279
+ if (item === '') return false;
280
+ return arr.indexOf(item) === idx;
281
+ }).join(' ') + '"><a href="#" class="selector"></a><ul /></div>');
282
+
283
+ $selector = $customSelect.find(".selector");
284
+ $customList = $customSelect.find("ul");
285
+
286
+ liHtml = $options.map(function () {
287
+ var copyClasses = $(this).attr('class') ? $(this).attr('class') : '';
288
+ return "<li class='" + copyClasses + "'>" + $(this).html() + "</li>";
289
+ }).get().join('');
290
+
291
+ $customList.append(liHtml);
292
+
293
+ $currentSelect = $customSelect
294
+ .prepend('<a href="#" class="current">' + $selectedOption.html() + '</a>')
295
+ .find(".current");
296
+
297
+ $this.after($customSelect)
298
+ .addClass('hidden-field');
299
+ } else {
300
+ liHtml = $options.map(function () {
301
+ return "<li>" + $(this).html() + "</li>";
302
+ })
303
+ .get().join('');
304
+
305
+ $customList.html('')
306
+ .append(liHtml);
307
+
308
+ } // endif $customSelect.length === 0
309
+
310
+ self.assign_id($this, $customSelect);
311
+ $customSelect.toggleClass('disabled', $this.is(':disabled'));
312
+ $listItems = $customList.find('li');
313
+
314
+ // cache list length
315
+ self.cache[$customSelect.data('id')] = $listItems.length;
316
+
317
+ $options.each(function (index) {
318
+ if (this.selected) {
319
+ $listItems.eq(index).addClass('selected');
320
+
321
+ if ($currentSelect) {
322
+ $currentSelect.html($(this).html());
323
+ }
324
+ }
325
+ if ($(this).is(':disabled')) {
326
+ $listItems.eq(index).addClass('disabled');
327
+ }
328
+ });
329
+
330
+ //
331
+ // If we're not specifying a predetermined form size.
332
+ //
333
+ if (!$customSelect.is('.small, .medium, .large, .expand')) {
334
+
335
+ // ------------------------------------------------------------------------------------
336
+ // This is a work-around for when elements are contained within hidden parents.
337
+ // For example, when custom-form elements are inside of a hidden reveal modal.
338
+ //
339
+ // We need to display the current custom list element as well as hidden parent elements
340
+ // in order to properly calculate the list item element's width property.
341
+ // -------------------------------------------------------------------------------------
342
+
343
+ $customSelect.addClass('open');
344
+ //
345
+ // Quickly, display all parent elements.
346
+ // This should help us calcualate the width of the list item's within the drop down.
347
+ //
348
+ var self = Foundation.libs.forms;
349
+ self.hidden_fix.adjust($customList);
350
+
351
+ maxWidth = (self.outerWidth($listItems) > maxWidth) ? self.outerWidth($listItems) : maxWidth;
352
+
353
+ Foundation.libs.forms.hidden_fix.reset();
354
+
355
+ $customSelect.removeClass('open');
356
+
357
+ } // endif
358
+
359
+ },
360
+
361
+ assign_id: function ($select, $customSelect) {
362
+ var id = [+new Date(), Foundation.random_str(5)].join('-');
363
+ $select.attr('data-id', id);
364
+ $customSelect.attr('data-id', id);
365
+ },
366
+
367
+ refresh_custom_select: function ($select, force_refresh) {
368
+ var self = this;
369
+ var maxWidth = 0,
370
+ $customSelect = $select.next(),
371
+ $options = $select.find('option'),
372
+ $listItems = $customSelect.find('li');
373
+
374
+ if ($listItems.length !== this.cache[$customSelect.data('id')] || force_refresh) {
375
+ $customSelect.find('ul').html('');
376
+
377
+ $options.each(function () {
378
+ var $li = $('<li>' + $(this).html() + '</li>');
379
+ $customSelect.find('ul').append($li);
380
+ });
381
+
382
+ // re-populate
383
+ $options.each(function (index) {
384
+ if (this.selected) {
385
+ $customSelect.find('li').eq(index).addClass('selected');
386
+ $customSelect.find('.current').html($(this).html());
387
+ }
388
+ if ($(this).is(':disabled')) {
389
+ $customSelect.find('li').eq(index).addClass('disabled');
390
+ }
391
+ });
392
+
393
+ // fix width
394
+ $customSelect.removeAttr('style')
395
+ .find('ul').removeAttr('style');
396
+ $customSelect.find('li').each(function () {
397
+ $customSelect.addClass('open');
398
+ if (self.outerWidth($(this)) > maxWidth) {
399
+ maxWidth = self.outerWidth($(this));
400
+ }
401
+ $customSelect.removeClass('open');
402
+ });
403
+
404
+ $listItems = $customSelect.find('li');
405
+ // cache list length
406
+ this.cache[$customSelect.data('id')] = $listItems.length;
407
+ }
408
+ },
409
+
410
+ toggle_checkbox: function ($element) {
411
+ var $input = $element.prev(),
412
+ input = $input[0];
413
+
414
+ if (false === $input.is(':disabled')) {
415
+ input.checked = ((input.checked) ? false : true);
416
+ $element.toggleClass('checked');
417
+
418
+ $input.trigger('change');
419
+ }
420
+ },
421
+
422
+ toggle_radio: function ($element) {
423
+ var $input = $element.prev(),
424
+ $form = $input.closest('form.custom'),
425
+ input = $input[0];
426
+
427
+ if (false === $input.is(':disabled')) {
428
+ $form.find('input[type="radio"][name="' + this.escape($input.attr('name')) + '"]')
429
+ .next().not($element).removeClass('checked');
430
+
431
+ if (!$element.hasClass('checked')) {
432
+ $element.toggleClass('checked');
433
+ }
434
+
435
+ input.checked = $element.hasClass('checked');
436
+
437
+ $input.trigger('change');
438
+ }
439
+ },
440
+
441
+ escape: function (text) {
442
+ if (!text) return '';
443
+ return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
444
+ },
445
+
446
+ hidden_fix: {
447
+ /**
448
+ * Sets all hidden parent elements and self to visibile.
449
+ *
450
+ * @method adjust
451
+ * @param {jQuery Object} $child
452
+ */
453
+
454
+ // We'll use this to temporarily store style properties.
455
+ tmp: [],
456
+
457
+ // We'll use this to set hidden parent elements.
458
+ hidden: null,
459
+
460
+ adjust: function ($child) {
461
+ // Internal reference.
462
+ var _self = this;
463
+
464
+ // Set all hidden parent elements, including this element.
465
+ _self.hidden = $child.parents();
466
+ _self.hidden = _self.hidden.add($child).filter(":hidden");
467
+
468
+ // Loop through all hidden elements.
469
+ _self.hidden.each(function () {
470
+
471
+ // Cache the element.
472
+ var $elem = $(this);
473
+
474
+ // Store the style attribute.
475
+ // Undefined if element doesn't have a style attribute.
476
+ _self.tmp.push($elem.attr('style'));
477
+
478
+ // Set the element's display property to block,
479
+ // but ensure it's visibility is hidden.
480
+ $elem.css({
481
+ 'visibility': 'hidden',
482
+ 'display': 'block'
483
+ });
484
+ });
485
+
486
+ }, // end adjust
487
+
488
+ /**
489
+ * Resets the elements previous state.
490
+ *
491
+ * @method reset
492
+ */
493
+ reset: function () {
494
+ // Internal reference.
495
+ var _self = this;
496
+ // Loop through our hidden element collection.
497
+ _self.hidden.each(function (i) {
498
+ // Cache this element.
499
+ var $elem = $(this),
500
+ _tmp = _self.tmp[i]; // Get the stored 'style' value for this element.
501
+
502
+ // If the stored value is undefined.
503
+ if (_tmp === undefined)
504
+ // Remove the style attribute.
505
+ $elem.removeAttr('style');
506
+ else
507
+ // Otherwise, reset the element style attribute.
508
+ $elem.attr('style', _tmp);
509
+ });
510
+ // Reset the tmp array.
511
+ _self.tmp = [];
512
+ // Reset the hidden elements variable.
513
+ _self.hidden = null;
514
+
515
+ } // end reset
516
+ },
517
+
518
+ off: function () {
519
+ $(this.scope).off('.fndtn.forms');
520
+ },
521
+
522
+ reflow : function () {}
523
+ };
524
+
525
+ var getFirstPrevSibling = function($el, selector) {
526
+ var $el = $el.prev();
527
+ while ($el.length) {
528
+ if ($el.is(selector)) return $el;
529
+ $el = $el.prev();
530
+ }
531
+ return $();
532
+ };
533
+ }(Foundation.zj, this, this.document));