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 event is triggered also when pressing enter when the focus is on 88 // previous webform components, but we only want to do something when 89 // we are on the calendar component. By checking the event client x/y 90 // position we known if it was the user clicking. For keyboard navigators 91 // simply the focus handles the date picker so we don't have to do 92 // anything special for them. 93 if (event.clientX !== 0 && event.clientY !== 0) { 94 // Focus is only necessary for Safari. But it has no impact on other 95 // browsers. 96 $(this).focus(); 97 event.preventDefault(); 98 } 99 }); 100 101 // Clear date on backspace or delete. 102 $calendar.keyup(function (e) { 103 if (e.keyCode == 8 || e.keyCode == 46) { 104 $.datepicker._clearDate(this); 105 } 106 }); 107 }); 108 }; 109 110 Drupal.webform.conditional = function (context) { 111 // Add the bindings to each webform on the page. 112 $.each(Drupal.settings.webform.conditionals, function (formKey, settings) { 113 var $form = $('.' + formKey + ':not(.webform-conditional-processed)'); 114 $form.each(function (index, currentForm) { 115 var $currentForm = $(currentForm); 116 $currentForm.addClass('webform-conditional-processed'); 117 $currentForm.bind('change', {'settings': settings}, Drupal.webform.conditionalCheck); 118 119 // Trigger all the elements that cause conditionals on this form. 120 Drupal.webform.doConditions($currentForm, settings); 121 }); 122 }); 123 }; 124 125 /** 126 * Event handler to respond to field changes in a form. 127 * 128 * This event is bound to the entire form, not individual fields. 129 */ 130 Drupal.webform.conditionalCheck = function (e) { 131 var $triggerElement = $(e.target).closest('.webform-component'); 132 if (!$triggerElement.length) { 133 return; 134 } 135 var $form = $triggerElement.closest('form'); 136 var triggerElementKey = $triggerElement.attr('class').match(/webform-component--[^ ]+/)[0]; 137 var settings = e.data.settings; 138 if (settings.sourceMap[triggerElementKey]) { 139 Drupal.webform.doConditions($form, settings); 140 } 141 }; 142 143 /** 144 * Processes all conditional. 145 */ 146 Drupal.webform.doConditions = function ($form, settings) { 147 148 var stackPointer; 149 var resultStack; 150 151 /** 152 * Initializes an execution stack for a conditional group's rules. 153 * 154 * Also initializes sub-conditional rules. 155 */ 156 function executionStackInitialize(andor) { 157 stackPointer = -1; 158 resultStack = []; 159 executionStackPush(andor); 160 } 161 162 /** 163 * Starts a new subconditional for the given and/or operator. 164 */ 165 function executionStackPush(andor) { 166 resultStack[++stackPointer] = { 167 results: [], 168 andor: andor, 169 }; 170 } 171 172 /** 173 * Adds a rule's result to the current sub-conditional. 174 */ 175 function executionStackAccumulate(result) { 176 resultStack[stackPointer]['results'].push(result); 177 } 178 179 /** 180 * Finishes a sub-conditional and adds the result to the parent stack frame. 181 */ 182 function executionStackPop() { 183 // Calculate the and/or result. 184 var stackFrame = resultStack[stackPointer]; 185 // Pop stack and protect against stack underflow. 186 stackPointer = Math.max(0, stackPointer - 1); 187 var $conditionalResults = stackFrame['results']; 188 var filteredResults = $.map($conditionalResults, function (val) { 189 return val ? val : null; 190 }); 191 return stackFrame['andor'] === 'or' 192 ? filteredResults.length > 0 193 : filteredResults.length === $conditionalResults.length; 194 } 195 196 // Track what has been set/hidden for each target component's elements. 197 // Hidden elements must be disabled because if they are required and don't 198 // have a value, they will prevent submission due to html5 validation. 199 // Each execution of the conditionals adds a temporary class 200 // webform-disabled-flag so that elements hidden or set can be disabled and 201 // also be prevented from being re-enabled by another conditional (such as a 202 // parent fieldset). After processing conditionals, this temporary class 203 // must be removed in preparation for the next execution of the 204 // conditionals. 205 $.each(settings.ruleGroups, function (rgid_key, rule_group) { 206 var ruleGroup = settings.ruleGroups[rgid_key]; 207 208 // Perform the comparison callback and build the results for this group. 209 executionStackInitialize(ruleGroup['andor']); 210 $.each(ruleGroup['rules'], function (m, rule) { 211 switch (rule['source_type']) { 212 case 'component':
213 var elementKey = rule['source']; 214 var element = $form.find('.' + elementKey)[0]; 215 var existingValue = settings.values[elementKey] ? settings.values[elementKey] : null; 216 executionStackAccumulate(window['Drupal']['webform'][rule.callback](element, existingValue, rule['value'])); 217 break; 218 219 case 'conditional_start': 220 executionStackPush(rule['andor']); 221 break; 222 223 case 'conditional_end': 224 executionStackAccumulate(executionStackPop()); 225 break; 226 } 227 }); 228 var conditionalResult = executionStackPop(); 229 230 $.each(ruleGroup['actions'], function (aid, action) { 231 var $target = $form.find('.' + action['target']); 232 var actionResult = action['invert'] ? !conditionalResult : conditionalResult; 233 switch (action['action']) { 234 case 'show': 235 var changed = actionResult != Drupal.webform.isVisible($target); 236 if (actionResult) { 237 $target.find('.webform-conditional-disabled:not(.webform-disabled-flag)') 238 .removeClass('webform-conditional-disabled') 239 .webformProp('disabled', false); 240 $target 241 .removeClass('webform-conditional-hidden') 242 .show(); 243 $form.find('.chosen-disabled').prev().trigger('chosen:updated.chosen'); 244 } 245 else { 246 $target 247 .hide() 248 .addClass('webform-conditional-hidden') 249 .find(':input') 250 .addClass('webform-conditional-disabled webform-disabled-flag') 251 .webformProp('disabled', true); 252 } 253 if (changed && $target.is('tr')) { 254 Drupal.webform.restripeTable($target.closest('table').first()); 255 } 256 break; 257 258 case 'require': 259 var $requiredSpan = $target.find('.form-required, .form-optional').first(); 260 if (actionResult != $requiredSpan.hasClass('form-required')) { 261 var $targetInputElements = $target.find("input:text,textarea,input[type='email'],select,input:radio,input:checkbox,input:file"); 262 // Rather than hide the required tag, remove it so that other 263 // jQuery can respond via Drupal behaviors. 264 Drupal.detachBehaviors($requiredSpan); 265 $targetInputElements 266 .webformProp('required', actionResult) 267 .toggleClass('required', actionResult); 268 if (actionResult) { 269 $requiredSpan.replaceWith('<span class="form-required" title="' + Drupal.t('This field is required.') + '">*</span>'); 270 } 271 else { 272 $requiredSpan.replaceWith('<span class="form-optional"></span>'); 273 } 274 Drupal.attachBehaviors($requiredSpan); 275 } 276 break; 277 278 case 'set': 279 var $texts = $target.find("input:text,textarea,input[type='email']"); 280 var $selects = $target.find('select,select option,input:radio,input:checkbox'); 281 var $markups = $target.filter('.webform-component-markup'); 282 if (actionResult) { 283 var multiple = $.map(action['argument'].split(','), $.trim); 284 $selects 285 .webformVal(multiple) 286 .webformProp('disabled', true) 287 .addClass('webform-disabled-flag'); 288 $texts 289 .val([action['argument']]) 290 .webformProp('readonly', true) 291 .addClass('webform-disabled-flag'); 292 // A special case is made for markup. It is sanitized with 293 // filter_xss_admin on the server. otherwise text() should be used 294 // to avoid an XSS vulnerability. text() however would preclude 295 // the use of tags like <strong> or <a>. 296 $markups.html(action['argument']); 297 } 298 else { 299 $selects.not('.webform-disabled-flag') 300 .webformProp('disabled', false); 301 $texts.not('.webform-disabled-flag') 302 .webformProp('readonly', false); 303 // Markup not set? Then restore original markup as provided in 304 // the attribute data-webform-markup. 305 $markups.each(function () { 306 var $this = $(this); 307 var original = $this.data('webform-markup'); 308 if (original !== undefined) { 309 $this.html(original); 310 } 311 }); 312 } 313 break; 314 } 315 }); // End look on each action for one conditional. 316 }); // End loop on each conditional. 317 318 $form.find('.webform-disabled-flag').removeClass('webform-disabled-flag'); 319 }; 320 321 /** 322 * Event handler to prevent propagation of events. 323 * 324 * Typically click for disabling radio and checkboxes. 325 */ 326 Drupal.webform.stopEvent = function () { 327 return false;
328 }; 329 330 Drupal.webform.conditionalOperatorStringEqual = function (element, existingValue, ruleValue) { 331 var returnValue = false; 332 var currentValue = Drupal.webform.stringValue(element, existingValue); 333 $.each(currentValue, function (n, value) { 334 if (value.toLowerCase() === ruleValue.toLowerCase()) { 335 returnValue = true; 336 return false; // break. 337 } 338 }); 339 return returnValue; 340 }; 341 342 Drupal.webform.conditionalOperatorStringNotEqual = function (element, existingValue, ruleValue) { 343 var found = false; 344 var currentValue = Drupal.webform.stringValue(element, existingValue); 345 $.each(currentValue, function (n, value) { 346 if (value.toLowerCase() === ruleValue.toLowerCase()) { 347 found = true; 348 } 349 }); 350 return !found; 351 }; 352 353 Drupal.webform.conditionalOperatorStringContains = function (element, existingValue, ruleValue) { 354 var returnValue = false; 355 var currentValue = Drupal.webform.stringValue(element, existingValue); 356 $.each(currentValue, function (n, value) { 357 if (value.toLowerCase().indexOf(ruleValue.toLowerCase()) > -1) { 358 returnValue = true; 359 return false; // break. 360 } 361 }); 362 return returnValue; 363 }; 364 365 Drupal.webform.conditionalOperatorStringDoesNotContain = function (element, existingValue, ruleValue) { 366 var found = false; 367 var currentValue = Drupal.webform.stringValue(element, existingValue); 368 $.each(currentValue, function (n, value) { 369 if (value.toLowerCase().indexOf(ruleValue.toLowerCase()) > -1) { 370 found = true; 371 } 372 }); 373 return !found; 374 }; 375 376 Drupal.webform.conditionalOperatorStringBeginsWith = function (element, existingValue, ruleValue) { 377 var returnValue = false; 378 var currentValue = Drupal.webform.stringValue(element, existingValue); 379 $.each(currentValue, function (n, value) { 380 if (value.toLowerCase().indexOf(ruleValue.toLowerCase()) === 0) { 381 returnValue = true; 382 return false; // break. 383 } 384 }); 385 return returnValue; 386 }; 387 388 Drupal.webform.conditionalOperatorStringEndsWith = function (element, existingValue, ruleValue) { 389 var returnValue = false; 390 var currentValue = Drupal.webform.stringValue(element, existingValue); 391 $.each(currentValue, function (n, value) { 392 if (value.toLowerCase().lastIndexOf(ruleValue.toLowerCase()) === value.length - ruleValue.length) { 393 returnValue = true; 394 return false; // break. 395 } 396 }); 397 return returnValue; 398 }; 399 400 Drupal.webform.conditionalOperatorStringEmpty = function (element, existingValue, ruleValue) { 401 var currentValue = Drupal.webform.stringValue(element, existingValue); 402 var returnValue = true; 403 $.each(currentValue, function (n, value) { 404 if (value !== '') { 405 returnValue = false; 406 return false; // break. 407 } 408 }); 409 return returnValue; 410 }; 411 412 Drupal.webform.conditionalOperatorStringNotEmpty = function (element, existingValue, ruleValue) { 413 return !Drupal.webform.conditionalOperatorStringEmpty(element, existingValue, ruleValue); 414 }; 415 416 Drupal.webform.conditionalOperatorSelectGreaterThan = function (element, existingValue, ruleValue) { 417 var currentValue = Drupal.webform.stringValue(element, existingValue); 418 return Drupal.webform.compare_select(currentValue[0], ruleValue, element) > 0; 419 }; 420 421 Drupal.webform.conditionalOperatorSelectGreaterThanEqual = function (element, existingValue, ruleValue) { 422 var currentValue = Drupal.webform.stringValue(element, existingValue); 423 var comparison = Drupal.webform.compare_select(currentValue[0], ruleValue, element); 424 return comparison > 0 || comparison === 0; 425 }; 426 427 Drupal.webform.conditionalOperatorSelectLessThan = function (element, existingValue, ruleValue) { 428 var currentValue = Drupal.webform.stringValue(element, existingValue); 429 return Drupal.webform.compare_select(currentValue[0], ruleValue, element) < 0; 430 }; 431 432 Drupal.webform.conditionalOperatorSelectLessThanEqual = function (element, existingValue, ruleValue) { 433 var currentValue = Drupal.webform.stringValue(element, existingV
433alue); 434 var comparison = Drupal.webform.compare_select(currentValue[0], ruleValue, element); 435 return comparison < 0 || comparison === 0; 436 }; 437 438 Drupal.webform.conditionalOperatorNumericEqual = function (element, existingValue, ruleValue) { 439 // See float comparison: http://php.net/manual/en/language.types.float.php 440 var currentValue = Drupal.webform.stringValue(element, existingValue); 441 var epsilon = 0.000001; 442 // An empty string does not match any number. 443 return currentValue[0] === '' ? false : (Math.abs(parseFloat(currentValue[0]) - parseFloat(ruleValue)) < epsilon); 444 }; 445 446 Drupal.webform.conditionalOperatorNumericNotEqual = function (element, existingValue, ruleValue) { 447 // See float comparison: http://php.net/manual/en/language.types.float.php 448 var currentValue = Drupal.webform.stringValue(element, existingValue); 449 var epsilon = 0.000001; 450 // An empty string does not match any number. 451 return currentValue[0] === '' ? true : (Math.abs(parseFloat(currentValue[0]) - parseFloat(ruleValue)) >= epsilon); 452 }; 453 454 Drupal.webform.conditionalOperatorNumericGreaterThan = function (element, existingValue, ruleValue) { 455 var currentValue = Drupal.webform.stringValue(element, existingValue); 456 return parseFloat(currentValue[0]) > parseFloat(ruleValue); 457 }; 458 459 Drupal.webform.conditionalOperatorNumericGreaterThanEqual = function (element, existingValue, ruleValue) { 460 return Drupal.webform.conditionalOperatorNumericGreaterThan(element, existingValue, ruleValue) || 461 Drupal.webform.conditionalOperatorNumericEqual(element, existingValue, ruleValue); 462 }; 463 464 Drupal.webform.conditionalOperatorNumericLessThan = function (element, existingValue, ruleValue) { 465 var currentValue = Drupal.webform.stringValue(element, existingValue); 466 return parseFloat(currentValue[0]) < parseFloat(ruleValue); 467 }; 468 469 Drupal.webform.conditionalOperatorNumericLessThanEqual = function (element, existingValue, ruleValue) { 470 return Drupal.webform.conditionalOperatorNumericLessThan(element, existingValue, ruleValue) || 471 Drupal.webform.conditionalOperatorNumericEqual(element, existingValue, ruleValue); 472 }; 473 474 Drupal.webform.conditionalOperatorDateEqual = function (element, existingValue, ruleValue) { 475 var currentValue = Drupal.webform.dateValue(element, existingValue); 476 return currentValue === ruleValue; 477 }; 478 479 Drupal.webform.conditionalOperatorDateNotEqual = function (element, existingValue, ruleValue) { 480 return !Drupal.webform.conditionalOperatorDateEqual(element, existingValue, ruleValue); 481 }; 482 483 Drupal.webform.conditionalOperatorDateBefore = function (element, existingValue, ruleValue) { 484 var currentValue = Drupal.webform.dateValue(element, existingValue); 485 return (currentValue !== false) && currentValue < ruleValue; 486 }; 487 488 Drupal.webform.conditionalOperatorDateBeforeEqual = function (element, existingValue, ruleValue) { 489 var currentValue = Drupal.webform.dateValue(element, existingValue); 490 return (currentValue !== false) && (currentValue < ruleValue || currentValue === ruleValue); 491 }; 492 493 Drupal.webform.conditionalOperatorDateAfter = function (element, existingValue, ruleValue) { 494 var currentValue = Drupal.webform.dateValue(element, existingValue); 495 return (currentValue !== false) && currentValue > ruleValue; 496 }; 497 498 Drupal.webform.conditionalOperatorDateAfterEqual = function (element, existingValue, ruleValue) { 499 var currentValue = Drupal.webform.dateValue(element, existingValue); 500 return (currentValue !== false) && (currentValue > ruleValue || currentValue === ruleValue); 501 }; 502 503 Drupal.webform.conditionalOperatorTimeEqual = function (element, existingValue, ruleValue) { 504 var currentValue = Drupal.webform.timeValue(element, existingValue); 505 return currentValue === ruleValue; 506 }; 507 508 Drupal.webform.conditionalOperatorTimeNotEqual = function (element, existingValue, ruleValue) { 509 return !Drupal.webform.conditionalOperatorTimeEqual(element, existingValue, ruleValue); 510 }; 511 512 Drupal.webform.conditionalOperatorTimeBefore = function (element, existingV
512alue, ruleValue) { 513 // Date and time operators intentionally exclusive for "before". 514 var currentValue = Drupal.webform.timeValue(element, existingValue); 515 return (currentValue !== false) && (currentValue < ruleValue); 516 }; 517 518 Drupal.webform.conditionalOperatorTimeBeforeEqual = function (element, existingValue, ruleValue) { 519 // Date and time operators intentionally exclusive for "before". 520 var currentValue = Drupal.webform.timeValue(element, existingValue); 521 return (currentValue !== false) && (currentValue < ruleValue || currentValue === ruleValue); 522 }; 523 524 Drupal.webform.conditionalOperatorTimeAfter = function (element, existingValue, ruleValue) { 525 // Date and time operators intentionally inclusive for "after". 526 var currentValue = Drupal.webform.timeValue(element, existingValue); 527 return (currentValue !== false) && (currentValue > ruleValue); 528 }; 529 530 Drupal.webform.conditionalOperatorTimeAfterEqual = function (element, existingValue, ruleValue) { 531 // Date and time operators intentionally inclusive for "after". 532 var currentValue = Drupal.webform.timeValue(element, existingValue); 533 return (currentValue !== false) && (currentValue > ruleValue || currentValue === ruleValue); 534 }; 535 536 /** 537 * Utility function to compare values of a select component. 538 * 539 * @param string a 540 * First select option key to compare 541 * @param string b 542 * Second select option key to compare 543 * @param array options 544 * Associative array where the a and b are within the keys 545 * 546 * @return integer based upon position of $a and $b in $options 547 * -N if $a above (<) $b 548 * 0 if $a = $b 549 * +N if $a is below (>) $b 550 */ 551 Drupal.webform.compare_select = function (a, b, element) { 552 var optionList = []; 553 $('option,input:radio,input:checkbox', element).each(function () { 554 optionList.push($(this).val()); 555 }); 556 var a_position = optionList.indexOf(a); 557 var b_position = optionList.indexOf(b); 558 return (a_position < 0 || b_position < 0) ? null : a_position - b_position; 559 }; 560 561 /** 562 * Utility to return current visibility. 563 * 564 * Uses actual visibility, except for hidden components which use the applied 565 * disabled class. 566 */ 567 Drupal.webform.isVisible = function ($element) { 568 return $element.hasClass('webform-component-hidden') 569 ? !$element.find('input').first().hasClass('webform-conditional-disabled') 570 : $element.closest('.webform-conditional-hidden').length == 0; 571 }; 572 573 /** 574 * Function to get a string value from a select/radios/text/etc. field. 575 */ 576 Drupal.webform.stringValue = function (element, existingValue) { 577 var value = []; 578 if (element) { 579 var $element = $(element); 580 if (Drupal.webform.isVisible($element)) { 581 // Checkboxes and radios. 582 $element.find('input[type=checkbox]:checked,input[type=radio]:checked').each(function () { 583 value.push(this.value); 584 }); 585 // Select lists. 586 if (!value.length) { 587 var selectValue = $element.find('select').val(); 588 if (selectValue) { 589 if ($.isArray(selectValue)) { 590 value = selectValue; 591 } 592 else { 593 value.push(selectValue); 594 } 595 } 596 } 597 // Simple text fields. This check is done last so that the select list 598 // in select-or-other fields comes before the "other" text field. 599 if (!value.length) { 600 $element.find('input:not([type=checkbox],[type=radio]),textarea').each(function () { 601 value.push(this.value); 602 }); 603 } 604 } 605 } 606 else { 607 switch ($.type(existingValue)) { 608 case 'array':
609 value = existingValue; 610 break; 611 612 case 'string': 613 value.push(existingValue); 614 break; 615 } 616 } 617 return value; 618 }; 619 620 /** 621 * Utility function to calculate a second-based timestamp from a time field. 622 */ 623 Drupal.webform.dateValue = function (element, existingValue) { 624 var value = false; 625 if (element) { 626 var $element = $(element); 627 if (Drupal.webform.isVisible($element)) { 628 var day = $element.find('[name*=day]').val(); 629 var month = $element.find('[name*=month]').val(); 630 var year = $element.find('[name*=year]').val(); 631 // Months are 0 indexed in JavaScript. 632 if (month) { 633 month--; 634 } 635 if (year !== '' && month !== '' && day !== '') { 636 value = Date.UTC(year, month, day) / 1000; 637 } 638 } 639 } 640 else { 641 if ($.type(existingValue) === 'array' && existingValue.length) { 642 existingValue = existingValue[0]; 643 } 644 if ($.type(existingValue) === 'string') { 645 existingValue = existingV
645alue.split('-'); 646 } 647 if (existingValue.length === 3) { 648 value = Date.UTC(existingValue[0], existingValue[1], existingValue[2]) / 1000; 649 } 650 } 651 return value; 652 }; 653 654 /** 655 * Utility function to calculate a millisecond timestamp from a time field. 656 */ 657 Drupal.webform.timeValue = function (element, existingValue) { 658 var value = false; 659 if (element) { 660 var $element = $(element); 661 if (Drupal.webform.isVisible($element)) { 662 var hour = $element.find('[name*=hour]').val(); 663 var minute = $element.find('[name*=minute]').val(); 664 var ampm = $element.find('[name*=ampm]:checked').val(); 665 666 // Convert to integers if set. 667 hour = (hour === '') ? hour : parseInt(hour); 668 minute = (minute === '') ? minute : parseInt(minute); 669 670 if (hour !== '') { 671 hour = (hour < 12 && ampm == 'pm') ? hour + 12 : hour; 672 hour = (hour === 12 && ampm == 'am') ? 0 : hour; 673 } 674 if (hour !== '' && minute !== '') { 675 value = Date.UTC(1970, 0, 1, hour, minute) / 1000; 676 } 677 } 678 } 679 else { 680 if ($.type(existingValue) === 'array' && existingValue.length) {
681 existingValue = existingValue[0]; 682 } 683 if ($.type(existingValue) === 'string') { 684 existingValue = existingValue.split(':'); 685 } 686 if (existingValue.length >= 2) { 687 value = Date.UTC(1970, 0, 1, existingValue[0], existingValue[1]) / 1000; 688 } 689 } 690 return value; 691 }; 692 693 /** 694 * Make a prop shim for jQuery < 1.9. 695 */ 696 $.fn.webformProp = $.fn.webformProp || function (name, value) { 697 if (value) { 698 return $.fn.prop ? this.prop(name, true) : this.attr(name, true); 699 } 700 else { 701 return $.fn.prop ? this.prop(name, false) : this.removeAttr(name); 702 } 703 }; 704 705 /** 706 * Make a multi-valued val() function. 707 * 708 * This is for setting checkboxes, radios, and select elements. 709 */ 710 $.fn.webformVal = function (values) { 711 this.each(function () { 712 var $this = $(this); 713 var value = $this.val(); 714 var on = $.inArray($this.val(), values) != -1; 715 if (this.nodeName == 'OPTION') { 716 $this.webformProp('selected', on ? value : false); 717 } 718 else { 719 $this.val(on ? [value] : false); 720 } 721 }); 722 return this; 723 }; 724 725 /** 726 * Given a table's DOM element, restripe the odd/even classes. 727 */ 728 Drupal.webform.restripeTable = function (table) { 729 // :even and :odd are reversed because jQuery counts from 0 and 730 // we count from 1, so we're out of sync. 731 // Match immediate children of the parent element to allow nesting. 732 $('> tbody > tr, > tr', table) 733 .filter(':visible:odd').filter('.odd') 734 .removeClass('odd').addClass('even') 735 .end().end() 736 .filter(':visible:even').filter('.even') 737 .removeClass('even').addClass('odd'); 738 }; 739 740})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.