Projet

Général

Profil

Paste
Télécharger (27,3 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / webform / js / webform.js @ 01f36513

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
80
          // off 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($currentForm, 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.
133
     *
134
     * Also initializes sub-conditional rules.
135
     */
136
    function executionStackInitialize(andor) {
137
      stackPointer = -1;
138
      resultStack = [];
139
      executionStackPush(andor);
140
    }
141

    
142
    /**
143
     * Starts a new subconditional for the given and/or operator.
144
     */
145
    function executionStackPush(andor) {
146
      resultStack[++stackPointer] = {
147
        results: [],
148
        andor: andor,
149
      };
150
    }
151

    
152
    /**
153
     * Adds a rule's result to the current sub-conditional.
154
     */
155
    function executionStackAccumulate(result) {
156
      resultStack[stackPointer]['results'].push(result);
157
    }
158

    
159
    /**
160
     * Finishes a sub-conditional and adds the result to the parent stack frame.
161
     */
162
    function executionStackPop() {
163
      // Calculate the and/or result.
164
      var stackFrame = resultStack[stackPointer];
165
      // Pop stack and protect against stack underflow.
166
      stackPointer = Math.max(0, stackPointer - 1);
167
      var $conditionalResults = stackFrame['results'];
168
      var filteredResults = $.map($conditionalResults, function (val) {
169
        return val ? val : null;
170
      });
171
      return stackFrame['andor'] === 'or'
172
                ? filteredResults.length > 0
173
                : filteredResults.length === $conditionalResults.length;
174
    }
175

    
176
    // Track what has been set/hidden for each target component's elements.
177
    // Hidden elements must be disabled because if they are required and don't
178
    // have a value, they will prevent submission due to html5 validation.
179
    // Each execution of the conditionals adds a temporary class
180
    // webform-disabled-flag so that elements hidden or set can be disabled and
181
    // also be prevented from being re-enabled by another conditional (such as a
182
    // parent fieldset). After processing conditionals, this temporary class
183
    // must be removed in preparation for the next execution of the
184
    // conditionals.
185
    $.each(settings.ruleGroups, function (rgid_key, rule_group) {
186
      var ruleGroup = settings.ruleGroups[rgid_key];
187

    
188
      // Perform the comparison callback and build the results for this group.
189
      executionStackInitialize(ruleGroup['andor']);
190
      $.each(ruleGroup['rules'], function (m, rule) {
191
        switch (rule['source_type']) {
192
          case 'component':
193
            var elementKey = rule['source'];
194
            var element = $form.find('.' + elementKey)[0];
195
            var existingValue = settings.values[elementKey] ? settings.values[elementKey] : null;
196
            executionStackAccumulate(window['Drupal']['webform'][rule.callback](element, existingValue, rule['value']));
197
            break;
198

    
199
          case 'conditional_start':
200
            executionStackPush(rule['andor']);
201
            break;
202

    
203
          case 'conditional_end':
204
            executionStackAccumulate(executionStackPop());
205
            break;
206
        }
207
      });
208
      var conditionalResult = executionStackPop();
209

    
210
      $.each(ruleGroup['actions'], function (aid, action) {
211
        var $target = $form.find('.' + action['target']);
212
        var actionResult = action['invert'] ? !conditionalResult : conditionalResult;
213
        switch (action['action']) {
214
          case 'show':
215
            var changed = actionResult != Drupal.webform.isVisible($target);
216
            if (actionResult) {
217
              $target.find('.webform-conditional-disabled:not(.webform-disabled-flag)')
218
                .removeClass('webform-conditional-disabled')
219
                .webformProp('disabled', false);
220
              $target
221
                .removeClass('webform-conditional-hidden')
222
                .show();
223
              $form.find('.chosen-disabled').prev().trigger('chosen:updated.chosen');
224
            }
225
            else {
226
              $target
227
                .hide()
228
                .addClass('webform-conditional-hidden')
229
                .find(':input')
230
                  .addClass('webform-conditional-disabled webform-disabled-flag')
231
                  .webformProp('disabled', true);
232
            }
233
            if (changed && $target.is('tr')) {
234
              Drupal.webform.restripeTable($target.closest('table').first());
235
            }
236
            break;
237

    
238
          case 'require':
239
            var $requiredSpan = $target.find('.form-required, .form-optional').first();
240
            if (actionResult != $requiredSpan.hasClass('form-required')) {
241
              var $targetInputElements = $target.find("input:text,textarea,input[type='email'],select,input:radio,input:file");
242
              // Rather than hide the required tag, remove it so that other
243
              // jQuery can respond via Drupal behaviors.
244
              Drupal.detachBehaviors($requiredSpan);
245
              $targetInputElements
246
                .webformProp('required', actionResult)
247
                .toggleClass('required', actionResult);
248
              if (actionResult) {
249
                $requiredSpan.replaceWith('<span class="form-required" title="' + Drupal.t('This field is required.') + '">*</span>');
250
              }
251
              else {
252
                $requiredSpan.replaceWith('<span class="form-optional"></span>');
253
              }
254
              Drupal.attachBehaviors($requiredSpan);
255
            }
256
            break;
257

    
258
          case 'set':
259
            var $texts = $target.find("input:text,textarea,input[type='email']");
260
            var $selects = $target.find('select,select option,input:radio,input:checkbox');
261
            var $markups = $target.filter('.webform-component-markup');
262
            if (actionResult) {
263
              var multiple = $.map(action['argument'].split(','), $.trim);
264
              $selects
265
                .webformVal(multiple)
266
                .webformProp('disabled', true)
267
                  .addClass('webform-disabled-flag');
268
              $texts
269
                .val([action['argument']])
270
                .webformProp('readonly', true)
271
                .addClass('webform-disabled-flag');
272
              // A special case is made for markup. It is sanitized with
273
              // filter_xss_admin on the server. otherwise text() should be used
274
              // to avoid an XSS vulnerability. text() however would preclude
275
              // the use of tags like <strong> or <a>.
276
              $markups.html(action['argument']);
277
            }
278
            else {
279
              $selects.not('.webform-disabled-flag')
280
                .webformProp('disabled', false);
281
              $texts.not('.webform-disabled-flag')
282
                .webformProp('readonly', false);
283
              // Markup not set? Then restore original markup as provided in
284
              // the attribute data-webform-markup.
285
              $markups.each(function () {
286
                var $this = $(this);
287
                var original = $this.data('webform-markup');
288
                if (original !== undefined) {
289
                  $this.html(original);
290
                }
291
              });
292
            }
293
            break;
294
        }
295
      }); // End look on each action for one conditional.
296
    }); // End loop on each conditional.
297

    
298
    $form.find('.webform-disabled-flag').removeClass('webform-disabled-flag');
299
  };
300

    
301
  /**
302
   * Event handler to prevent propagation of events.
303
   *
304
   * Typically click for disabling radio and checkboxes.
305
   */
306
  Drupal.webform.stopEvent = function () {
307
    return false;
308
  };
309

    
310
  Drupal.webform.conditionalOperatorStringEqual = function (element, existingValue, ruleValue) {
311
    var returnValue = false;
312
    var currentValue = Drupal.webform.stringValue(element, existingValue);
313
    $.each(currentValue, function (n, value) {
314
      if (value.toLowerCase() === ruleValue.toLowerCase()) {
315
        returnValue = true;
316
        return false; // break.
317
      }
318
    });
319
    return returnValue;
320
  };
321

    
322
  Drupal.webform.conditionalOperatorStringNotEqual = function (element, existingValue, ruleValue) {
323
    var found = false;
324
    var currentValue = Drupal.webform.stringValue(element, existingValue);
325
    $.each(currentValue, function (n, value) {
326
      if (value.toLowerCase() === ruleValue.toLowerCase()) {
327
        found = true;
328
      }
329
    });
330
    return !found;
331
  };
332

    
333
  Drupal.webform.conditionalOperatorStringContains = function (element, existingValue, ruleValue) {
334
    var returnValue = false;
335
    var currentValue = Drupal.webform.stringValue(element, existingValue);
336
    $.each(currentValue, function (n, value) {
337
      if (value.toLowerCase().indexOf(ruleValue.toLowerCase()) > -1) {
338
        returnValue = true;
339
        return false; // break.
340
      }
341
    });
342
    return returnValue;
343
  };
344

    
345
  Drupal.webform.conditionalOperatorStringDoesNotContain = function (element, existingValue, ruleValue) {
346
    var found = false;
347
    var currentValue = Drupal.webform.stringValue(element, existingValue);
348
    $.each(currentValue, function (n, value) {
349
      if (value.toLowerCase().indexOf(ruleValue.toLowerCase()) > -1) {
350
        found = true;
351
      }
352
    });
353
    return !found;
354
  };
355

    
356
  Drupal.webform.conditionalOperatorStringBeginsWith = function (element, existingValue, ruleValue) {
357
    var returnValue = false;
358
    var currentValue = Drupal.webform.stringValue(element, existingValue);
359
    $.each(currentValue, function (n, value) {
360
      if (value.toLowerCase().indexOf(ruleValue.toLowerCase()) === 0) {
361
        returnValue = true;
362
        return false; // break.
363
      }
364
    });
365
    return returnValue;
366
  };
367

    
368
  Drupal.webform.conditionalOperatorStringEndsWith = function (element, existingValue, ruleValue) {
369
    var returnValue = false;
370
    var currentValue = Drupal.webform.stringValue(element, existingValue);
371
    $.each(currentValue, function (n, value) {
372
      if (value.toLowerCase().lastIndexOf(ruleValue.toLowerCase()) === value.length - ruleValue.length) {
373
        returnValue = true;
374
        return false; // break.
375
      }
376
    });
377
    return returnValue;
378
  };
379

    
380
  Drupal.webform.conditionalOperatorStringEmpty = function (element, existingValue, ruleValue) {
381
    var currentValue = Drupal.webform.stringValue(element, existingValue);
382
    var returnValue = true;
383
    $.each(currentValue, function (n, value) {
384
      if (value !== '') {
385
        returnValue = false;
386
        return false; // break.
387
      }
388
    });
389
    return returnValue;
390
  };
391

    
392
  Drupal.webform.conditionalOperatorStringNotEmpty = function (element, existingValue, ruleValue) {
393
    return !Drupal.webform.conditionalOperatorStringEmpty(element, existingValue, ruleValue);
394
  };
395

    
396
  Drupal.webform.conditionalOperatorSelectGreaterThan = function (element, existingValue, ruleValue) {
397
    var currentValue = Drupal.webform.stringValue(element, existingValue);
398
    return Drupal.webform.compare_select(currentValue[0], ruleValue, element) > 0;
399
  };
400

    
401
  Drupal.webform.conditionalOperatorSelectGreaterThanEqual = function (element, existingValue, ruleValue) {
402
    var currentValue = Drupal.webform.stringValue(element, existingValue);
403
    var comparison = Drupal.webform.compare_select(currentValue[0], ruleValue, element);
404
    return comparison > 0 || comparison === 0;
405
  };
406

    
407
  Drupal.webform.conditionalOperatorSelectLessThan = function (element, existingValue, ruleValue) {
408
    var currentValue = Drupal.webform.stringValue(element, existingValue);
409
    return Drupal.webform.compare_select(currentValue[0], ruleValue, element) < 0;
410
  };
411

    
412
  Drupal.webform.conditionalOperatorSelectLessThanEqual = function (element, existingValue, ruleValue) {
413
    var currentValue = Drupal.webform.stringValue(element, existingValue);
414
    var comparison = Drupal.webform.compare_select(currentValue[0], ruleValue, element);
415
    return comparison < 0 || comparison === 0;
416
  };
417

    
418
  Drupal.webform.conditionalOperatorNumericEqual = function (element, existingValue, ruleValue) {
419
    // See float comparison: http://php.net/manual/en/language.types.float.php
420
    var currentValue = Drupal.webform.stringValue(element, existingValue);
421
    var epsilon = 0.000001;
422
    // An empty string does not match any number.
423
    return currentValue[0] === '' ? false : (Math.abs(parseFloat(currentValue[0]) - parseFloat(ruleValue)) < epsilon);
424
  };
425

    
426
  Drupal.webform.conditionalOperatorNumericNotEqual = function (element, existingValue, ruleValue) {
427
    // See float comparison: http://php.net/manual/en/language.types.float.php
428
    var currentValue = Drupal.webform.stringValue(element, existingValue);
429
    var epsilon = 0.000001;
430
    // An empty string does not match any number.
431
    return currentValue[0] === '' ? true : (Math.abs(parseFloat(currentValue[0]) - parseFloat(ruleValue)) >= epsilon);
432
  };
433

    
434
  Drupal.webform.conditionalOperatorNumericGreaterThan = function (element, existingValue, ruleValue) {
435
    var currentValue = Drupal.webform.stringValue(element, existingValue);
436
    return parseFloat(currentValue[0]) > parseFloat(ruleValue);
437
  };
438

    
439
  Drupal.webform.conditionalOperatorNumericGreaterThanEqual = function (element, existingValue, ruleValue) {
440
    return Drupal.webform.conditionalOperatorNumericGreaterThan(element, existingValue, ruleValue) ||
441
           Drupal.webform.conditionalOperatorNumericEqual(element, existingValue, ruleValue);
442
  };
443

    
444
  Drupal.webform.conditionalOperatorNumericLessThan = function (element, existingValue, ruleValue) {
445
    var currentValue = Drupal.webform.stringValue(element, existingValue);
446
    return parseFloat(currentValue[0]) < parseFloat(ruleValue);
447
  };
448

    
449
  Drupal.webform.conditionalOperatorNumericLessThanEqual = function (element, existingValue, ruleValue) {
450
    return Drupal.webform.conditionalOperatorNumericLessThan(element, existingValue, ruleValue) ||
451
           Drupal.webform.conditionalOperatorNumericEqual(element, existingValue, ruleValue);
452
  };
453

    
454
  Drupal.webform.conditionalOperatorDateEqual = function (element, existingValue, ruleValue) {
455
    var currentValue = Drupal.webform.dateValue(element, existingValue);
456
    return currentValue === ruleValue;
457
  };
458

    
459
  Drupal.webform.conditionalOperatorDateNotEqual = function (element, existingValue, ruleValue) {
460
    return !Drupal.webform.conditionalOperatorDateEqual(element, existingValue, ruleValue);
461
  };
462

    
463
  Drupal.webform.conditionalOperatorDateBefore = function (element, existingValue, ruleValue) {
464
    var currentValue = Drupal.webform.dateValue(element, existingValue);
465
    return (currentValue !== false) && currentValue < ruleValue;
466
  };
467

    
468
  Drupal.webform.conditionalOperatorDateBeforeEqual = function (element, existingValue, ruleValue) {
469
    var currentValue = Drupal.webform.dateValue(element, existingValue);
470
    return (currentValue !== false) && (currentValue < ruleValue || currentValue === ruleValue);
471
  };
472

    
473
  Drupal.webform.conditionalOperatorDateAfter = function (element, existingValue, ruleValue) {
474
    var currentValue = Drupal.webform.dateValue(element, existingValue);
475
    return (currentValue !== false) && currentValue > ruleValue;
476
  };
477

    
478
  Drupal.webform.conditionalOperatorDateAfterEqual = function (element, existingValue, ruleValue) {
479
    var currentValue = Drupal.webform.dateValue(element, existingValue);
480
    return (currentValue !== false) && (currentValue > ruleValue || currentValue === ruleValue);
481
  };
482

    
483
  Drupal.webform.conditionalOperatorTimeEqual = function (element, existingValue, ruleValue) {
484
    var currentValue = Drupal.webform.timeValue(element, existingValue);
485
    return currentValue === ruleValue;
486
  };
487

    
488
  Drupal.webform.conditionalOperatorTimeNotEqual = function (element, existingValue, ruleValue) {
489
    return !Drupal.webform.conditionalOperatorTimeEqual(element, existingValue, ruleValue);
490
  };
491

    
492
  Drupal.webform.conditionalOperatorTimeBefore = function (element, existingValue, ruleValue) {
493
    // Date and time operators intentionally exclusive for "before".
494
    var currentValue = Drupal.webform.timeValue(element, existingValue);
495
    return (currentValue !== false) && (currentValue < ruleValue);
496
  };
497

    
498
  Drupal.webform.conditionalOperatorTimeBeforeEqual = function (element, existingValue, ruleValue) {
499
    // Date and time operators intentionally exclusive for "before".
500
    var currentValue = Drupal.webform.timeValue(element, existingValue);
501
    return (currentValue !== false) && (currentValue < ruleValue || currentValue === ruleValue);
502
  };
503

    
504
  Drupal.webform.conditionalOperatorTimeAfter = function (element, existingValue, ruleValue) {
505
    // Date and time operators intentionally inclusive for "after".
506
    var currentValue = Drupal.webform.timeValue(element, existingValue);
507
    return (currentValue !== false) && (currentValue > ruleValue);
508
  };
509

    
510
  Drupal.webform.conditionalOperatorTimeAfterEqual = function (element, existingValue, ruleValue) {
511
    // Date and time operators intentionally inclusive for "after".
512
    var currentValue = Drupal.webform.timeValue(element, existingValue);
513
    return (currentValue !== false) && (currentValue > ruleValue || currentValue === ruleValue);
514
  };
515

    
516
  /**
517
   * Utility function to compare values of a select component.
518
   *
519
   * @param string a
520
   *   First select option key to compare
521
   * @param string b
522
   *   Second select option key to compare
523
   * @param array options
524
   *   Associative array where the a and b are within the keys
525
   *
526
   * @return integer based upon position of $a and $b in $options
527
   *   -N if $a above (<) $b
528
   *   0 if $a = $b
529
   *   +N if $a is below (>) $b
530
   */
531
  Drupal.webform.compare_select = function (a, b, element) {
532
    var optionList = [];
533
    $('option,input:radio,input:checkbox', element).each(function () {
534
      optionList.push($(this).val());
535
    });
536
    var a_position = optionList.indexOf(a);
537
    var b_position = optionList.indexOf(b);
538
    return (a_position < 0 || b_position < 0) ? null : a_position - b_position;
539
  };
540

    
541
  /**
542
   * Utility to return current visibility.
543
   *
544
   * Uses actual visibility, except for hidden components which use the applied
545
   * disabled class.
546
   */
547
  Drupal.webform.isVisible = function ($element) {
548
    return $element.hasClass('webform-component-hidden')
549
              ? !$element.find('input').first().hasClass('webform-conditional-disabled')
550
              : $element.closest('.webform-conditional-hidden').length == 0;
551
  };
552

    
553
  /**
554
   * Function to get a string value from a select/radios/text/etc. field.
555
   */
556
  Drupal.webform.stringValue = function (element, existingValue) {
557
    var value = [];
558
    if (element) {
559
      var $element = $(element);
560
      if (Drupal.webform.isVisible($element)) {
561
        // Checkboxes and radios.
562
        $element.find('input[type=checkbox]:checked,input[type=radio]:checked').each(function () {
563
          value.push(this.value);
564
        });
565
        // Select lists.
566
        if (!value.length) {
567
          var selectValue = $element.find('select').val();
568
          if (selectValue) {
569
            if ($.isArray(selectValue)) {
570
              value = selectValue;
571
            }
572
            else {
573
              value.push(selectValue);
574
            }
575
          }
576
        }
577
        // Simple text fields. This check is done last so that the select list
578
        // in select-or-other fields comes before the "other" text field.
579
        if (!value.length) {
580
          $element.find('input:not([type=checkbox],[type=radio]),textarea').each(function () {
581
            value.push(this.value);
582
          });
583
        }
584
      }
585
    }
586
    else {
587
      switch ($.type(existingValue)) {
588
        case 'array':
589
          value = existingValue;
590
          break;
591

    
592
        case 'string':
593
          value.push(existingValue);
594
          break;
595
      }
596
    }
597
    return value;
598
  };
599

    
600
  /**
601
   * Utility function to calculate a second-based timestamp from a time field.
602
   */
603
  Drupal.webform.dateValue = function (element, existingValue) {
604
    var value = false;
605
    if (element) {
606
      var $element = $(element);
607
      if (Drupal.webform.isVisible($element)) {
608
        var day = $element.find('[name*=day]').val();
609
        var month = $element.find('[name*=month]').val();
610
        var year = $element.find('[name*=year]').val();
611
        // Months are 0 indexed in JavaScript.
612
        if (month) {
613
          month--;
614
        }
615
        if (year !== '' && month !== '' && day !== '') {
616
          value = Date.UTC(year, month, day) / 1000;
617
        }
618
      }
619
    }
620
    else {
621
      if ($.type(existingValue) === 'array' && existingValue.length) {
622
        existingValue = existingValue[0];
623
      }
624
      if ($.type(existingValue) === 'string') {
625
        existingValue = existingValue.split('-');
626
      }
627
      if (existingValue.length === 3) {
628
        value = Date.UTC(existingValue[0], existingValue[1], existingValue[2]) / 1000;
629
      }
630
    }
631
    return value;
632
  };
633

    
634
  /**
635
   * Utility function to calculate a millisecond timestamp from a time field.
636
   */
637
  Drupal.webform.timeValue = function (element, existingValue) {
638
    var value = false;
639
    if (element) {
640
      var $element = $(element);
641
      if (Drupal.webform.isVisible($element)) {
642
        var hour = $element.find('[name*=hour]').val();
643
        var minute = $element.find('[name*=minute]').val();
644
        var ampm = $element.find('[name*=ampm]:checked').val();
645

    
646
        // Convert to integers if set.
647
        hour = (hour === '') ? hour : parseInt(hour);
648
        minute = (minute === '') ? minute : parseInt(minute);
649

    
650
        if (hour !== '') {
651
          hour = (hour < 12 && ampm == 'pm') ? hour + 12 : hour;
652
          hour = (hour === 12 && ampm == 'am') ? 0 : hour;
653
        }
654
        if (hour !== '' && minute !== '') {
655
          value = Date.UTC(1970, 0, 1, hour, minute) / 1000;
656
        }
657
      }
658
    }
659
    else {
660
      if ($.type(existingValue) === 'array' && existingValue.length) {
661
        existingValue = existingValue[0];
662
      }
663
      if ($.type(existingValue) === 'string') {
664
        existingValue = existingValue.split(':');
665
      }
666
      if (existingValue.length >= 2) {
667
        value = Date.UTC(1970, 0, 1, existingValue[0], existingValue[1]) / 1000;
668
      }
669
    }
670
    return value;
671
  };
672

    
673
  /**
674
   * Make a prop shim for jQuery < 1.9.
675
   */
676
  $.fn.webformProp = $.fn.webformProp || function (name, value) {
677
    if (value) {
678
      return $.fn.prop ? this.prop(name, true) : this.attr(name, true);
679
    }
680
    else {
681
      return $.fn.prop ? this.prop(name, false) : this.removeAttr(name);
682
    }
683
  };
684

    
685
  /**
686
   * Make a multi-valued val() function.
687
   *
688
   * This is for setting checkboxes, radios, and select elements.
689
   */
690
  $.fn.webformVal = function (values) {
691
    this.each(function () {
692
      var $this = $(this);
693
      var value = $this.val();
694
      var on = $.inArray($this.val(), values) != -1;
695
      if (this.nodeName == 'OPTION') {
696
        $this.webformProp('selected', on ? value : false);
697
      }
698
      else {
699
        $this.val(on ? [value] : false);
700
      }
701
    });
702
    return this;
703
  };
704

    
705
  /**
706
   * Given a table's DOM element, restripe the odd/even classes.
707
   */
708
  Drupal.webform.restripeTable = function (table) {
709
    // :even and :odd are reversed because jQuery counts from 0 and
710
    // we count from 1, so we're out of sync.
711
    // Match immediate children of the parent element to allow nesting.
712
    $('> tbody > tr, > tr', table)
713
      .filter(':visible:odd').filter('.odd')
714
        .removeClass('odd').addClass('even')
715
      .end().end()
716
      .filter(':visible:even').filter('.even')
717
        .removeClass('even').addClass('odd');
718
  };
719

    
720
})(jQuery);