commiting uncommited changes on live site
[weblabels.fsf.org.git] / crm.fsf.org / 20131203 / files / sites / all / modules-old / webform / js / webform.js
1 /**
2 * @file
3 * JavaScript behaviors for the front-end display of webforms.
4 */
5
6 (function ($) {
7
8 "use strict";
9
10 Drupal.behaviors.webform = Drupal.behaviors.webform || {};
11
12 Drupal.behaviors.webform.attach = function (context) {
13 // Calendar datepicker behavior.
14 Drupal.webform.datepicker(context);
15
16 // Conditional logic.
17 if (Drupal.settings.webform && Drupal.settings.webform.conditionals) {
18 Drupal.webform.conditional(context);
19 }
20 };
21
22 Drupal.webform = Drupal.webform || {};
23
24 Drupal.webform.datepicker = function (context) {
25 $('div.webform-datepicker').each(function () {
26 var $webformDatepicker = $(this);
27 var $calendar = $webformDatepicker.find('input.webform-calendar');
28
29 // Ensure the page we're on actually contains a datepicker.
30 if ($calendar.length == 0) {
31 return;
32 }
33
34 var startDate = $calendar[0].className.replace(/.*webform-calendar-start-(\d{4}-\d{2}-\d{2}).*/, '$1').split('-');
35 var endDate = $calendar[0].className.replace(/.*webform-calendar-end-(\d{4}-\d{2}-\d{2}).*/, '$1').split('-');
36 var firstDay = $calendar[0].className.replace(/.*webform-calendar-day-(\d).*/, '$1');
37 // Convert date strings into actual Date objects.
38 startDate = new Date(startDate[0], startDate[1] - 1, startDate[2]);
39 endDate = new Date(endDate[0], endDate[1] - 1, endDate[2]);
40
41 // Ensure that start comes before end for datepicker.
42 if (startDate > endDate) {
43 var laterDate = startDate;
44 startDate = endDate;
45 endDate = laterDate;
46 }
47
48 var startYear = startDate.getFullYear();
49 var endYear = endDate.getFullYear();
50
51 // Set up the jQuery datepicker element.
52 $calendar.datepicker({
53 dateFormat: 'yy-mm-dd',
54 yearRange: startYear + ':' + endYear,
55 firstDay: parseInt(firstDay),
56 minDate: startDate,
57 maxDate: endDate,
58 onSelect: function (dateText, inst) {
59 var date = dateText.split('-');
60 $webformDatepicker.find('select.year, input.year').val(+date[0]).trigger('change');
61 $webformDatepicker.find('select.month').val(+date[1]).trigger('change');
62 $webformDatepicker.find('select.day').val(+date[2]).trigger('change');
63 },
64 beforeShow: function (input, inst) {
65 // Get the select list values.
66 var year = $webformDatepicker.find('select.year, input.year').val();
67 var month = $webformDatepicker.find('select.month').val();
68 var day = $webformDatepicker.find('select.day').val();
69
70 // If empty, default to the current year/month/day in the popup.
71 var today = new Date();
72 year = year ? year : today.getFullYear();
73 month = month ? month : today.getMonth() + 1;
74 day = day ? day : today.getDate();
75
76 // Make sure that the default year fits in the available options.
77 year = (year < startYear || year > endYear) ? startYear : year;
78
79 // jQuery UI Datepicker will read the input field and base its date off
80 // of that, even though in our case the input field is a button.
81 $(input).val(year + '-' + month + '-' + day);
82 }
83 });
84
85 // Prevent the calendar button from submitting the form.
86 $calendar.click(function (event) {
87 $(this).focus();
88 event.preventDefault();
89 });
90 });
91 };
92
93 Drupal.webform.conditional = function (context) {
94 // Add the bindings to each webform on the page.
95 $.each(Drupal.settings.webform.conditionals, function (formKey, settings) {
96 var $form = $('.' + formKey + ':not(.webform-conditional-processed)');
97 $form.each(function (index, currentForm) {
98 var $currentForm = $(currentForm);
99 $currentForm.addClass('webform-conditional-processed');
100 $currentForm.bind('change', {'settings': settings}, Drupal.webform.conditionalCheck);
101
102 // Trigger all the elements that cause conditionals on this form.
103 Drupal.webform.doConditions($form, settings);
104 });
105 });
106 };
107
108 /**
109 * Event handler to respond to field changes in a form.
110 *
111 * This event is bound to the entire form, not individual fields.
112 */
113 Drupal.webform.conditionalCheck = function (e) {
114 var $triggerElement = $(e.target).closest('.webform-component');
115 var $form = $triggerElement.closest('form');
116 var triggerElementKey = $triggerElement.attr('class').match(/webform-component--[^ ]+/)[0];
117 var settings = e.data.settings;
118 if (settings.sourceMap[triggerElementKey]) {
119 Drupal.webform.doConditions($form, settings);
120 }
121 };
122
123 /**
124 * Processes all conditional.
125 */
126 Drupal.webform.doConditions = function ($form, settings) {
127
128 var stackPointer;
129 var resultStack;
130
131 /**
132 * Initializes an execution stack for a conditional group's rules and
133 * sub-conditional rules.
134 */
135 function executionStackInitialize(andor) {
136 stackPointer = -1;
137 resultStack = [];
138 executionStackPush(andor);
139 }
140
141 /**
142 * Starts a new subconditional for the given and/or operator.
143 */
144 function executionStackPush(andor) {
145 resultStack[++stackPointer] = {
146 results: [],
147 andor: andor,
148 };
149 }
150
151 /**
152 * Adds a rule's result to the current sub-condtional.
153 */
154 function executionStackAccumulate(result) {
155 resultStack[stackPointer]['results'].push(result);
156 }
157
158 /**
159 * Finishes a sub-conditional and adds the result to the parent stack frame.
160 */
161 function executionStackPop() {
162 // Calculate the and/or result.
163 var stackFrame = resultStack[stackPointer];
164 // Pop stack and protect against stack underflow.
165 stackPointer = Math.max(0, stackPointer - 1);
166 var $conditionalResults = stackFrame['results'];
167 var filteredResults = $.map($conditionalResults, function(val) {
168 return val ? val : null;
169 });
170 return stackFrame['andor'] === 'or'
171 ? filteredResults.length > 0
172 : filteredResults.length === $conditionalResults.length;
173 }
174
175 // Track what has be set/shown for each target component.
176 var targetLocked = [];
177
178 $.each(settings.ruleGroups, function (rgid_key, rule_group) {
179 var ruleGroup = settings.ruleGroups[rgid_key];
180
181 // Perform the comparison callback and build the results for this group.
182 executionStackInitialize(ruleGroup['andor']);
183 $.each(ruleGroup['rules'], function (m, rule) {
184 switch (rule['source_type']) {
185 case 'component':
186 var elementKey = rule['source'];
187 var element = $form.find('.' + elementKey)[0];
188 var existingValue = settings.values[elementKey] ? settings.values[elementKey] : null;
189 executionStackAccumulate(window['Drupal']['webform'][rule.callback](element, existingValue, rule['value']));
190 break;
191 case 'conditional_start':
192 executionStackPush(rule['andor']);
193 break;
194 case 'conditional_end':
195 executionStackAccumulate(executionStackPop());
196 break;
197 }
198 });
199 var conditionalResult = executionStackPop();
200
201 $.each(ruleGroup['actions'], function (aid, action) {
202 var $target = $form.find('.' + action['target']);
203 var actionResult = action['invert'] ? !conditionalResult : conditionalResult;
204 switch (action['action']) {
205 case 'show':
206 if (actionResult != Drupal.webform.isVisible($target)) {
207 var $targetElements = actionResult
208 ? $target.find('.webform-conditional-disabled').removeClass('webform-conditional-disabled')
209 : $target.find(':input').addClass('webform-conditional-disabled');
210 $targetElements.webformProp('disabled', !actionResult);
211 $target.toggleClass('webform-conditional-hidden', !actionResult);
212 if (actionResult) {
213 $target.show();
214 }
215 else {
216 $target.hide();
217 // Record that the target was hidden.
218 targetLocked[action['target']] = 'hide';
219 }
220 if ($target.is('tr')) {
221 Drupal.webform.restripeTable($target.closest('table').first());
222 }
223 }
224 break;
225 case 'require':
226 var $requiredSpan = $target.find('.form-required, .form-optional').first();
227 if (actionResult != $requiredSpan.hasClass('form-required')) {
228 var $targetInputElements = $target.find("input:text,textarea,input[type='email'],select,input:radio,input:file");
229 // Rather than hide the required tag, remove it so that other jQuery can respond via Drupal behaviors.
230 Drupal.detachBehaviors($requiredSpan);
231 $targetInputElements
232 .webformProp('required', actionResult)
233 .toggleClass('required', actionResult);
234 if (actionResult) {
235 $requiredSpan.replaceWith('<span class="form-required" title="' + Drupal.t('This field is required.') + '">*</span>');
236 }
237 else {
238 $requiredSpan.replaceWith('<span class="form-optional"></span>');
239 }
240 Drupal.attachBehaviors($requiredSpan);
241 }
242 break;
243 case 'set':
244 var isLocked = targetLocked[action['target']];
245 var $texts = $target.find("input:text,textarea,input[type='email']");
246 var $selects = $target.find('select,select option,input:radio,input:checkbox');
247 var $markups = $target.filter('.webform-component-markup');
248 if (actionResult) {
249 var multiple = $.map(action['argument'].split(','), $.trim);
250 $selects.webformVal(multiple);
251 $texts.val([action['argument']]);
252 // A special case is made for markup. It is sanitized with filter_xss_admin on the server.
253 // otherwise text() should be used to avoid an XSS vulnerability. text() however would
254 // preclude the use of tags like <strong> or <a>
255 $markups.html(action['argument']);
256 }
257 else {
258 // Markup not set? Then restore original markup as provided in
259 // the attribute data-webform-markup.
260 $markups.each(function() {
261 var $this = $(this);
262 var original = $this.data('webform-markup');
263 if (original !== undefined) {
264 $this.html(original);
265 }
266 });
267 }
268 if (!isLocked) {
269 // If not previously hidden or set, disable the element readonly or readonly-like behavior.
270 $selects.webformProp('disabled', actionResult);
271 $texts.webformProp('readonly', actionResult);
272 targetLocked[action['target']] = actionResult ? 'set' : false;
273 }
274 break;
275 }
276 }); // End look on each action for one conditional
277 }); // End loop on each conditional
278 };
279
280 /**
281 * Event handler to prevent propogation of events, typically click for disabling
282 * radio and checkboxes.
283 */
284 Drupal.webform.stopEvent = function () {
285 return false;
286 };
287
288 Drupal.webform.conditionalOperatorStringEqual = function (element, existingValue, ruleValue) {
289 var returnValue = false;
290 var currentValue = Drupal.webform.stringValue(element, existingValue);
291 $.each(currentValue, function (n, value) {
292 if (value.toLowerCase() === ruleValue.toLowerCase()) {
293 returnValue = true;
294 return false; // break.
295 }
296 });
297 return returnValue;
298 };
299
300 Drupal.webform.conditionalOperatorStringNotEqual = function (element, existingValue, ruleValue) {
301 var found = false;
302 var currentValue = Drupal.webform.stringValue(element, existingValue);
303 $.each(currentValue, function (n, value) {
304 if (value.toLowerCase() === ruleValue.toLowerCase()) {
305 found = true;
306 }
307 });
308 return !found;
309 };
310
311 Drupal.webform.conditionalOperatorStringContains = function (element, existingValue, ruleValue) {
312 var returnValue = false;
313 var currentValue = Drupal.webform.stringValue(element, existingValue);
314 $.each(currentValue, function (n, value) {
315 if (value.toLowerCase().indexOf(ruleValue.toLowerCase()) > -1) {
316 returnValue = true;
317 return false; // break.
318 }
319 });
320 return returnValue;
321 };
322
323 Drupal.webform.conditionalOperatorStringDoesNotContain = function (element, existingValue, ruleValue) {
324 var found = false;
325 var currentValue = Drupal.webform.stringValue(element, existingValue);
326 $.each(currentValue, function (n, value) {
327 if (value.toLowerCase().indexOf(ruleValue.toLowerCase()) > -1) {
328 found = true;
329 }
330 });
331 return !found;
332 };
333
334 Drupal.webform.conditionalOperatorStringBeginsWith = function (element, existingValue, ruleValue) {
335 var returnValue = false;
336 var currentValue = Drupal.webform.stringValue(element, existingValue);
337 $.each(currentValue, function (n, value) {
338 if (value.toLowerCase().indexOf(ruleValue.toLowerCase()) === 0) {
339 returnValue = true;
340 return false; // break.
341 }
342 });
343 return returnValue;
344 };
345
346 Drupal.webform.conditionalOperatorStringEndsWith = function (element, existingValue, ruleValue) {
347 var returnValue = false;
348 var currentValue = Drupal.webform.stringValue(element, existingValue);
349 $.each(currentValue, function (n, value) {
350 if (value.toLowerCase().lastIndexOf(ruleValue.toLowerCase()) === value.length - ruleValue.length) {
351 returnValue = true;
352 return false; // break.
353 }
354 });
355 return returnValue;
356 };
357
358 Drupal.webform.conditionalOperatorStringEmpty = function (element, existingValue, ruleValue) {
359 var currentValue = Drupal.webform.stringValue(element, existingValue);
360 var returnValue = true;
361 $.each(currentValue, function (n, value) {
362 if (value !== '') {
363 returnValue = false;
364 return false; // break.
365 }
366 });
367 return returnValue;
368 };
369
370 Drupal.webform.conditionalOperatorStringNotEmpty = function (element, existingValue, ruleValue) {
371 return !Drupal.webform.conditionalOperatorStringEmpty(element, existingValue, ruleValue);
372 };
373
374 Drupal.webform.conditionalOperatorSelectGreaterThan = function (element, existingValue, ruleValue) {
375 var currentValue = Drupal.webform.stringValue(element, existingValue);
376 return Drupal.webform.compare_select(currentValue[0], ruleValue, element) > 0;
377 };
378
379 Drupal.webform.conditionalOperatorSelectGreaterThanEqual = function (element, existingValue, ruleValue) {
380 var currentValue = Drupal.webform.stringValue(element, existingValue);
381 var comparison = Drupal.webform.compare_select(currentValue[0], ruleValue, element);
382 return comparison > 0 || comparison === 0;
383 };
384
385 Drupal.webform.conditionalOperatorSelectLessThan = function (element, existingValue, ruleValue) {
386 var currentValue = Drupal.webform.stringValue(element, existingValue);
387 return Drupal.webform.compare_select(currentValue[0], ruleValue, element) < 0;
388 };
389
390 Drupal.webform.conditionalOperatorSelectLessThanEqual = function (element, existingValue, ruleValue) {
391 var currentValue = Drupal.webform.stringValue(element, existingValue);
392 var comparison = Drupal.webform.compare_select(currentValue[0], ruleValue, element);
393 return comparison < 0 || comparison === 0;
394 };
395
396 Drupal.webform.conditionalOperatorNumericEqual = function (element, existingValue, ruleValue) {
397 // See float comparison: http://php.net/manual/en/language.types.float.php
398 var currentValue = Drupal.webform.stringValue(element, existingValue);
399 var epsilon = 0.000001;
400 // An empty string does not match any number.
401 return currentValue[0] === '' ? false : (Math.abs(parseFloat(currentValue[0]) - parseFloat(ruleValue)) < epsilon);
402 };
403
404 Drupal.webform.conditionalOperatorNumericNotEqual = function (element, existingValue, ruleValue) {
405 // See float comparison: http://php.net/manual/en/language.types.float.php
406 var currentValue = Drupal.webform.stringValue(element, existingValue);
407 var epsilon = 0.000001;
408 // An empty string does not match any number.
409 return currentValue[0] === '' ? true : (Math.abs(parseFloat(currentValue[0]) - parseFloat(ruleValue)) >= epsilon);
410 };
411
412 Drupal.webform.conditionalOperatorNumericGreaterThan = function (element, existingValue, ruleValue) {
413 var currentValue = Drupal.webform.stringValue(element, existingValue);
414 return parseFloat(currentValue[0]) > parseFloat(ruleValue);
415 };
416
417 Drupal.webform.conditionalOperatorNumericGreaterThanEqual = function (element, existingValue, ruleValue) {
418 return Drupal.webform.conditionalOperatorNumericGreaterThan(element, existingValue, ruleValue) ||
419 Drupal.webform.conditionalOperatorNumericEqual(element, existingValue, ruleValue);
420 };
421
422 Drupal.webform.conditionalOperatorNumericLessThan = function (element, existingValue, ruleValue) {
423 var currentValue = Drupal.webform.stringValue(element, existingValue);
424 return parseFloat(currentValue[0]) < parseFloat(ruleValue);
425 };
426
427 Drupal.webform.conditionalOperatorNumericLessThanEqual = function (element, existingValue, ruleValue) {
428 return Drupal.webform.conditionalOperatorNumericLessThan(element, existingValue, ruleValue) ||
429 Drupal.webform.conditionalOperatorNumericEqual(element, existingValue, ruleValue);
430 };
431
432 Drupal.webform.conditionalOperatorDateEqual = function (element, existingValue, ruleValue) {
433 var currentValue = Drupal.webform.dateValue(element, existingValue);
434 return currentValue === ruleValue;
435 };
436
437 Drupal.webform.conditionalOperatorDateNotEqual = function (element, existingValue, ruleValue) {
438 return !Drupal.webform.conditionalOperatorDateEqual(element, existingValue, ruleValue);
439 };
440
441 Drupal.webform.conditionalOperatorDateBefore = function (element, existingValue, ruleValue) {
442 var currentValue = Drupal.webform.dateValue(element, existingValue);
443 return (currentValue !== false) && currentValue < ruleValue;
444 };
445
446 Drupal.webform.conditionalOperatorDateBeforeEqual = function (element, existingValue, ruleValue) {
447 var currentValue = Drupal.webform.dateValue(element, existingValue);
448 return (currentValue !== false) && (currentValue < ruleValue || currentValue === ruleValue);
449 };
450
451 Drupal.webform.conditionalOperatorDateAfter = function (element, existingValue, ruleValue) {
452 var currentValue = Drupal.webform.dateValue(element, existingValue);
453 return (currentValue !== false) && currentValue > ruleValue;
454 };
455
456 Drupal.webform.conditionalOperatorDateAfterEqual = function (element, existingValue, ruleValue) {
457 var currentValue = Drupal.webform.dateValue(element, existingValue);
458 return (currentValue !== false) && (currentValue > ruleValue || currentValue === ruleValue);
459 };
460
461 Drupal.webform.conditionalOperatorTimeEqual = function (element, existingValue, ruleValue) {
462 var currentValue = Drupal.webform.timeValue(element, existingValue);
463 return currentValue === ruleValue;
464 };
465
466 Drupal.webform.conditionalOperatorTimeNotEqual = function (element, existingValue, ruleValue) {
467 return !Drupal.webform.conditionalOperatorTimeEqual(element, existingValue, ruleValue);
468 };
469
470 Drupal.webform.conditionalOperatorTimeBefore = function (element, existingValue, ruleValue) {
471 // Date and time operators intentionally exclusive for "before".
472 var currentValue = Drupal.webform.timeValue(element, existingValue);
473 return (currentValue !== false) && (currentValue < ruleValue);
474 };
475
476 Drupal.webform.conditionalOperatorTimeBeforeEqual = function (element, existingValue, ruleValue) {
477 // Date and time operators intentionally exclusive for "before".
478 var currentValue = Drupal.webform.timeValue(element, existingValue);
479 return (currentValue !== false) && (currentValue < ruleValue || currentValue === ruleValue);
480 };
481
482 Drupal.webform.conditionalOperatorTimeAfter = function (element, existingValue, ruleValue) {
483 // Date and time operators intentionally inclusive for "after".
484 var currentValue = Drupal.webform.timeValue(element, existingValue);
485 return (currentValue !== false) && (currentValue > ruleValue);
486 };
487
488 Drupal.webform.conditionalOperatorTimeAfterEqual = function (element, existingValue, ruleValue) {
489 // Date and time operators intentionally inclusive for "after".
490 var currentValue = Drupal.webform.timeValue(element, existingValue);
491 return (currentValue !== false) && (currentValue > ruleValue || currentValue === ruleValue);
492 };
493
494 /**
495 * Utility function to compare values of a select component.
496 * @param string a
497 * First select option key to compare
498 * @param string b
499 * Second select option key to compare
500 * @param array options
501 * Associative array where the a and b are within the keys
502 * @return integer based upon position of $a and $b in $options
503 * -N if $a above (<) $b
504 * 0 if $a = $b
505 * +N if $a is below (>) $b
506 */
507 Drupal.webform.compare_select = function (a, b, element) {
508 var optionList = [];
509 $('option,input:radio,input:checkbox', element).each(function () {
510 optionList.push($(this).val());
511 });
512 var a_position = optionList.indexOf(a);
513 var b_position = optionList.indexOf(b);
514 return (a_position < 0 || b_position < 0) ? null : a_position - b_position;
515 };
516
517 /**
518 * Utility to return current visibility. Uses actual visibility, except for
519 * hidden components which use the applied disabled class.
520 */
521 Drupal.webform.isVisible = function ($element) {
522 return $element.hasClass('webform-component-hidden')
523 ? !$element.find('input').first().hasClass('webform-conditional-disabled')
524 : $element.closest('.webform-conditional-hidden').length == 0;
525 };
526
527 /**
528 * Utility function to get a string value from a select/radios/text/etc. field.
529 */
530 Drupal.webform.stringValue = function (element, existingValue) {
531 var value = [];
532 if (element) {
533 var $element = $(element);
534 if (Drupal.webform.isVisible($element)) {
535 // Checkboxes and radios.
536 $element.find('input[type=checkbox]:checked,input[type=radio]:checked').each(function () {
537 value.push(this.value);
538 });
539 // Select lists.
540 if (!value.length) {
541 var selectValue = $element.find('select').val();
542 if (selectValue) {
543 if ($.isArray(selectValue)) {
544 value = selectValue;
545 }
546 else {
547 value.push(selectValue);
548 }
549 }
550 }
551 // Simple text fields. This check is done last so that the select list in
552 // select-or-other fields comes before the "other" text field.
553 if (!value.length) {
554 $element.find('input:not([type=checkbox],[type=radio]),textarea').each(function () {
555 value.push(this.value);
556 });
557 }
558 }
559 }
560 else {
561 switch ($.type(existingValue)) {
562 case 'array':
563 value = existingValue;
564 break;
565 case 'string':
566 value.push(existingValue);
567 break;
568 }
569 }
570 return value;
571 };
572
573 /**
574 * Utility function to calculate a second-based timestamp from a time field.
575 */
576 Drupal.webform.dateValue = function (element, existingValue) {
577 var value = false;
578 if (element) {
579 var $element = $(element);
580 if (Drupal.webform.isVisible($element)) {
581 var day = $element.find('[name*=day]').val();
582 var month = $element.find('[name*=month]').val();
583 var year = $element.find('[name*=year]').val();
584 // Months are 0 indexed in JavaScript.
585 if (month) {
586 month--;
587 }
588 if (year !== '' && month !== '' && day !== '') {
589 value = Date.UTC(year, month, day) / 1000;
590 }
591 }
592 }
593 else {
594 if ($.type(existingValue) === 'array' && existingValue.length) {
595 existingValue = existingValue[0];
596 }
597 if ($.type(existingValue) === 'string') {
598 existingValue = existingValue.split('-');
599 }
600 if (existingValue.length === 3) {
601 value = Date.UTC(existingValue[0], existingValue[1], existingValue[2]) / 1000;
602 }
603 }
604 return value;
605 };
606
607 /**
608 * Utility function to calculate a millisecond timestamp from a time field.
609 */
610 Drupal.webform.timeValue = function (element, existingValue) {
611 var value = false;
612 if (element) {
613 var $element = $(element);
614 if (Drupal.webform.isVisible($element)) {
615 var hour = $element.find('[name*=hour]').val();
616 var minute = $element.find('[name*=minute]').val();
617 var ampm = $element.find('[name*=ampm]:checked').val();
618
619 // Convert to integers if set.
620 hour = (hour === '') ? hour : parseInt(hour);
621 minute = (minute === '') ? minute : parseInt(minute);
622
623 if (hour !== '') {
624 hour = (hour < 12 && ampm == 'pm') ? hour + 12 : hour;
625 hour = (hour === 12 && ampm == 'am') ? 0 : hour;
626 }
627 if (hour !== '' && minute !== '') {
628 value = Date.UTC(1970, 0, 1, hour, minute) / 1000;
629 }
630 }
631 }
632 else {
633 if ($.type(existingValue) === 'array' && existingValue.length) {
634 existingValue = existingValue[0];
635 }
636 if ($.type(existingValue) === 'string') {
637 existingValue = existingValue.split(':');
638 }
639 if (existingValue.length >= 2) {
640 value = Date.UTC(1970, 0, 1, existingValue[0], existingValue[1]) / 1000;
641 }
642 }
643 return value;
644 };
645
646 /**
647 * Make a prop shim for jQuery < 1.9.
648 */
649 $.fn.webformProp = $.fn.webformProp || function (name, value) {
650 if (value) {
651 return $.fn.prop ? this.prop(name, true) : this.attr(name, true);
652 }
653 else {
654 return $.fn.prop ? this.prop(name, false) : this.removeAttr(name);
655 }
656 };
657
658 /**
659 * Make a multi-valued val() function for setting checkboxes, radios, and select
660 * elements.
661 */
662 $.fn.webformVal = function (values) {
663 this.each(function () {
664 var $this = $(this);
665 var value = $this.val();
666 var on = $.inArray($this.val(), values) != -1;
667 if (this.nodeName == 'OPTION') {
668 $this.webformProp('selected', on ? value : false);
669 }
670 else {
671 $this.val(on ? [value] : false);
672 }
673 });
674 return this;
675 };
676
677 /**
678 * Given a table's DOM element, restripe the odd/even classes.
679 */
680 Drupal.webform.restripeTable = function (table) {
681 // :even and :odd are reversed because jQuery counts from 0 and
682 // we count from 1, so we're out of sync.
683 // Match immediate children of the parent element to allow nesting.
684 $('> tbody > tr, > tr', table)
685 .filter(':visible:odd').filter('.odd')
686 .removeClass('odd').addClass('even')
687 .end().end()
688 .filter(':visible:even').filter('.even')
689 .removeClass('even').addClass('odd');
690 };
691
692 })(jQuery);