1/** 2 * @file 3 * Colorbox module init js. 4 */ 5 6(function ($) { 7 8Drupal.behaviors.initColorbox = { 9 attach: function (context, settings) { 10 if (!$.isFunction($('a, area, input', context).colorbox) || typeof settings.colorbox === 'undefined') { 11 return; 12 } 13 14 if (settings.colorbox.mobiledetect && window.matchMedia) { 15 // Disable Colorbox for small screens. 16 var mq = window.matchMedia("(max-device-width: " + settings.colorbox.mobiledevicewidth + ")"); 17 if (mq.matches) { 18 return; 19 } 20 } 21 22 // Use "data-colorbox-gallery" if set otherwise use "rel". 23 settings.colorbox.rel = function () { 24 if ($(this).data('colorbox-gallery')) { 25 return $(this).data('colorbox-gallery'); 26 } 27 else { 28 return $(this).attr('rel'); 29 } 30 }; 31 32 $('.colorbox', context) 33 .once('init-colorbox').each(function(){ 34 // Only images are supported for the "colorbox" class. 35 // The "photo" setting forces the href attribute to be treated as an image. 36 var extendParams = { 37 photo: true 38 }; 39 // If a title attribute is supplied, sanitize it. 40 var title = $(this).attr('title'); 41 if (typeof title === 'undefined') { 42 title = this.dataset.cboxTitle; 43 } 44 if (title) { 45 extendParams.title = Drupal.colorbox.sanitizeMarkup(title); 46 } 47 $(this).colorbox($.extend({}, settings.colorbox, extendParams)); 48 49 // Only allow http or https protocol in hrefs. 50 var href = $(this).attr('href'); 51 var protocolRegex = /^(https?)/; 52 if (href && href.substring(0, 1) !== '/') { 53 var protocol = href.split(':')[0]; 54 // Use a regex to match http or https protocol. 55 if (!protocolRegex.test(protocol)) { 56 $(this).removeAttr('href'); 57 } 58 } 59 var dataHref = this.dataset.cboxHref; 60 if (dataHref && dataHref.substring(0, 1) !== '/') { 61 var dataProtocol = dataHref.split(':')[0]; 62 if (!protocolRegex.test(dataProtocol)) { 63 delete this.dataset.cboxHref; 64 } 65 } 66 67 // Since the sanitized title has been passed to colorbox settings, 68 // delete the unsanitized data-cbox-title attribute. 69 delete this.dataset.cboxTitle; 70 71 // Disallow dangerous data attributes. 72 delete this.dataset.cboxIframeAttrs; 73 74 // Sanitize other data attributes. 75 var sanitizeDataList = ['cboxNext', 'cboxPrevious', 'cboxCurrent', 76 'cboxClose', 'cboxSlideshowstop', 'cboxSlideshowstart', 77 'cboxXhrError', 'cboxImgerror', 'cboxHtml' 78 ]; 79 for (var a of sanitizeDataList) { 80 if (this.dataset.hasOwnProperty(a)) { 81 this.dataset[a] = Drupal.colorbox.sanitizeMarkup(this.dataset[a]); 82 } 83 } 84 }); 85 86 $(context).bind('cbox_complete', function () { 87 Drupal.attachBehaviors($('#cboxLoadedContent')); 88 }); 89 } 90}; 91 92// Create colorbox namespace if it doesn't exist. 93if (!Drupal.hasOwnProperty('colorbox')) { 94 Drupal.colorbox = {}; 95} 96 97/** 98 * Global function to allow sanitizing captions and control strings. 99 * 100 * @param markup 101 * String containing potential markup. 102 * @return @string 103 * Sanitized string with potentially dangerous markup removed. 104 */ 105Drupal.colorbox.sanitizeMarkup = function(markup) { 106 // If DOMPurify installed, allow some HTML. Otherwise, treat as plain text. 107 if (typeof DOMPurify !== 'undefined') { 108 var purifyConfig = { 109 ALLOWED_TAGS: [ 110 'a', 111 'b', 112 'strong', 113 'i', 114 'em', 115 'u', 116 'cite', 117 'code', 118 'br' 119 ], 120 ALLOWED_ATTR: [ 121 'href', 122 'hreflang', 123 'title', 124 'target' 125 ] 126 } 127 if (Drupal.settings.hasOwnProperty('dompurify_custom_config')) { 128 purifyConfig = Drupal.settings.dompurify_custom_config; 129 } 130 return DOMPurify.sanitize(markup, purifyConfig); 131 } 132 else { 133 return Drupal.checkPlain(markup); 134 } 135} 136 137})(jQuery); 138; 139/** 140 * @file 141 * Colorbox module style js. 142 */ 143 144(function ($) { 145 146Drupal.behaviors.initColorboxDefaultStyle = { 147 attach: function (context, settings) { 148 $(context).bind('cbox_complete', function () { 149 // Only run if there is a title. 150 if ($('#cboxTitle:empty', context).length == false) { 151 $('#cboxLoadedContent img', context).bind('mouseover', function () { 152 $('#cboxTitle', context).slideDown(); 153 }); 154 $('#cboxOverlay', context).bind('mouseover', function () {
155 $('#cboxTitle', context).slideUp(); 156 }); 157 } 158 else { 159 $('#cboxTitle', context).hide(); 160 } 161 }); 162 } 163}; 164 165})(jQuery); 166; 167(function ($) { 168 169 Drupal.behaviors.captcha = { 170 attach: function (context) { 171 172 // Turn off autocompletion for the CAPTCHA response field. 173 // We do it here with JavaScript (instead of directly in the markup) 174 // because this autocomplete attribute is not standard and 175 // it would break (X)HTML compliance. 176 $("#edit-captcha-response").attr("autocomplete", "off"); 177 178 } 179 }; 180 181 Drupal.behaviors.captchaAdmin = { 182 attach: function (context) { 183 // Add onclick handler to checkbox for adding a CAPTCHA description 184 // so that the textfields for the CAPTCHA description are hidden 185 // when no description should be added. 186 // @todo: div.form-item-captcha-description depends on theming, maybe 187 // it's better to add our own wrapper with id (instead of a class). 188 $("#edit-captcha-add-captcha-description").click(function() { 189 if ($("#edit-captcha-add-captcha-description").is(":checked")) { 190 // Show the CAPTCHA description textfield(s). 191 $("div.form-item-captcha-description").show('slow'); 192 } 193 else { 194 // Hide the CAPTCHA description textfield(s). 195 $("div.form-item-captcha-description").hide('slow'); 196 } 197 }); 198 // Hide the CAPTCHA description textfields if option is disabled on page load. 199 if (!$("#edit-captcha-add-captcha-description").is(":checked")) { 200 $("div.form-item-captcha-description").hide(); 201 } 202 } 203 204 }; 205 206})(jQuery); 207; 208(function ($) { 209 210Drupal.behaviors.textarea = { 211 attach: function (context, settings) { 212 $('.form-textarea-wrapper.resizable', context).once('textarea', function () { 213 var staticOffset = null; 214 var textarea = $(this).addClass('resizable-textarea').find('textarea'); 215 var grippie = $('<div class="grippie"></div>').mousedown(startDrag); 216 217 grippie.insertAfter(textarea); 218 219 function startDrag(e) { 220 staticOffset = textarea.height() - e.pageY; 221 textarea.css('opacity', 0.25); 222 $(document).mousemove(performDrag).mouseup(endDrag); 223 return false; 224 } 225 226 function performDrag(e) { 227 textarea.height(Math.max(32, staticOffset + e.pageY) + 'px'); 228 return false; 229 } 230 231 function endDrag(e) { 232 $(document).unbind('mousemove', performDrag).unbind('mouseup', endDrag); 233 textarea.css('opacity', 1); 234 } 235 }); 236 } 237}; 238 239})(jQuery); 240; 241/** 242 * @file 243 * JavaScript behaviors for the front-end display of webforms. 244 */ 245 246(function ($) { 247 248 "use strict"; 249 250 Drupal.behaviors.webform = Drupal.behaviors.webform || {}; 251 252 Drupal.behaviors.webform.attach = function (context) { 253 // Calendar datepicker behavior. 254 Drupal.webform.datepicker(context); 255 256 // Conditional logic. 257 if (Drupal.settings.webform && Drupal.settings.webform.conditionals) { 258 Drupal.webform.conditional(context); 259 } 260 }; 261 262 Drupal.webform = Drupal.webform || {}; 263 264 Drupal.webform.datepicker = function (context) { 265 $('div.webform-datepicker').each(function () { 266 var $webformDatepicker = $(this); 267 var $calendar = $webformDatepicker.find('input.webform-calendar'); 268 269 // Ensure the page we're on actually contains a datepicker. 270 if ($calendar.length == 0) { 271 return; 272 } 273 274 var startDate = $calendar[0].className.replace(/.*webform-calendar-start-(\d{4}-\d{2}-\d{2}).*/, '$1').split('-'); 275 var endDate = $calendar[0].className.replace(/.*webform-calendar-end-(\d{4}-\d{2}-\d{2}).*/, '$1').split('-'); 276 var firstDay = $calendar[0].className.replace(/.*webform-calendar-day-(\d).*/, '$1'); 277 // Convert date strings into actual Date objects. 278 startDate = new Date(startDate[0], startDate[1] - 1, startDate[2]); 279 endDate = new Date(endDate[0], endDate[1] - 1, endDate[2]); 280 281 // Ensure that start comes before end for datepicker. 282 if (startDate > endDate) { 283 var laterDate = startDate; 284 startDate = endDate; 285 endDate = laterDate; 286 } 287 288 var startYear = startDate.getFullYear(); 289 var endYear = endDate.getFullYear(); 290 291 // Set up the jQuery datepicker element. 292 $calendar.datepicker({ 293 dateFormat: 'yy-mm-dd', 294 yearRange: startYear + ':' + endYear, 295 firstDay: parseInt(firstDay), 296 minDate: startDate, 297 maxDate: endDate, 298 onSelect: function (dateText, inst) { 299 var date = dateText.split('-'); 300 $webformDatepicker.find('select.year, input.year').val(+date[0]).trigger('change'); 301 $webformDatepicker.find('select.month').val(+date[1]).trigger('change'); 302 $webformDatepicker.find('select.day').val(+date[2]).trigger('change'); 303 }, 304 beforeShow: function (input, inst) { 305 // Get the select list values. 306 var year = $webformDatepicker.find('select.year, input.year').val();
307 var month = $webformDatepicker.find('select.month').val(); 308 var day = $webformDatepicker.find('select.day').val(); 309 310 // If empty, default to the current year/month/day in the popup. 311 var today = new Date(); 312 year = year ? year : today.getFullYear(); 313 month = month ? month : today.getMonth() + 1; 314 day = day ? day : today.getDate(); 315 316 // Make sure that the default year fits in the available options. 317 year = (year < startYear || year > endYear) ? startYear : year; 318 319 // jQuery UI Datepicker will read the input field and base its date 320 // off of that, even though in our case the input field is a button. 321 $(input).val(year + '-' + month + '-' + day); 322 } 323 }); 324 325 // Prevent the calendar button from submitting the form. 326 $calendar.click(function (event) { 327 // This event is triggered also when pressing enter when the focus is on 328 // previous webform components, but we only want to do something when 329 // we are on the calendar component. By checking the event client x/y 330 // position we known if it was the user clicking. For keyboard navigators 331 // simply the focus handles the date picker so we don't have to do 332 // anything special for them. 333 if (event.clientX !== 0 && event.clientY !== 0) { 334 // Focus is only necessary for Safari. But it has no impact on other 335 // browsers. 336 $(this).focus(); 337 event.preventDefault(); 338 } 339 }); 340 341 // Clear date on backspace or delete. 342 $calendar.keyup(function (e) { 343 if (e.keyCode == 8 || e.keyCode == 46) { 344 $.datepicker._clearDate(this); 345 } 346 }); 347 }); 348 }; 349 350 Drupal.webform.conditional = function (context) { 351 // Add the bindings to each webform on the page. 352 $.each(Drupal.settings.webform.conditionals, function (formKey, settings) { 353 var $form = $('.' + formKey + ':not(.webform-conditional-processed)'); 354 $form.each(function (index, currentForm) { 355 var $currentForm = $(currentForm); 356 $currentForm.addClass('webform-conditional-processed'); 357 $currentForm.bind('change', {'settings': settings}, Drupal.webform.conditionalCheck); 358 359 // Trigger all the elements that cause conditionals on this form. 360 Drupal.webform.doConditions($currentForm, settings); 361 }); 362 }); 363 }; 364 365 /** 366 * Event handler to respond to field changes in a form. 367 * 368 * This event is bound to the entire form, not individual fields. 369 */ 370 Drupal.webform.conditionalCheck = function (e) { 371 var $triggerElement = $(e.target).closest('.webform-component'); 372 if (!$triggerElement.length) { 373 return; 374 } 375 var $form = $triggerElement.closest('form'); 376 var triggerElementKey = $triggerElement.attr('class').match(/webform-component--[^ ]+/)[0]; 377 var settings = e.data.settings; 378 if (settings.sourceMap[triggerElementKey]) { 379 Drupal.webform.doConditions($form, settings); 380 } 381 }; 382 383 /** 384 * Processes all conditional. 385 */ 386 Drupal.webform.doConditions = function ($form, settings) { 387 388 var stackPointer; 389 var resultStack; 390 391 /** 392 * Initializes an execution stack for a conditional group's rules. 393 * 394 * Also initializes sub-conditional rules. 395 */ 396 function executionStackInitialize(andor) { 397 stackPointer = -1; 398 resultStack = []; 399 executionStackPush(andor); 400 } 401 402 /** 403 * Starts a new subconditional for the given and/or operator. 404 */ 405 function executionStackPush(andor) { 406 resultStack[++stackPointer] = { 407 results: [], 408 andor: andor, 409 }; 410 } 411 412 /** 413 * Adds a rule's result to the current sub-conditional. 414 */ 415 function executionStackAccumulate(result) { 416 resultStack[stackPointer]['results'].push(result); 417 } 418 419 /** 420 * Finishes a sub-conditional and adds the result to the parent stack frame. 421 */ 422 function executionStackPop() { 423 // Calculate the and/or result. 424 var stackFrame = resultStack[stackPointer]; 425 // Pop stack and protect against stack underflow. 426 stackPointer = Math.max(0, stackPointer - 1); 427 var $conditionalResults = stackFrame['results']; 428 var filteredResults = $.map($conditionalResults, function (val) { 429 return val ? val : null; 430 }); 431 return stackFrame['andor'] === 'or' 432 ? filteredResults.length > 0 433 : filteredResults.length === $conditionalResults.length; 434 } 435 436 // Track what has been set/hidden for each target component's elements. 437 // Hidden elements must be disabled because if they are required and don't 438 // have a value, they will prevent submission due to html5 validation. 439 // Each execution of the conditionals adds a temporary class 440 // webform-disabled-flag so that elements hidden or set can be disabled and 441 // also be prevented from being re-enabled by another conditional (such as a 442 // parent fieldset). After processing conditionals, this temporary class 443 // must be removed in preparation for the next execution of the 444 // conditionals. 445 $.each(settings.ruleGroups, function (rgid_key, rule_group) { 446 var ruleGroup = settings.ruleGroups[rgid_key]; 447 448 // Perform the comparison callback and build the results for this group. 449 executionStackInitialize(ruleGroup['andor']); 450 $.each(ruleGroup['rules'], function (m, rule) { 451 switch (rule['source_type']) { 452 case 'component':
453 var elementKey = rule['source']; 454 var element = $form.find('.' + elementKey)[0]; 455 var existingValue = settings.values[elementKey] ? settings.values[elementKey] : null; 456 executionStackAccumulate(window['Drupal']['webform'][rule.callback](element, existingValue, rule['value'])); 457 break; 458 459 case 'conditional_start': 460 executionStackPush(rule['andor']); 461 break; 462 463 case 'conditional_end': 464 executionStackAccumulate(executionStackPop()); 465 break; 466 } 467 }); 468 var conditionalResult = executionStackPop(); 469 470 $.each(ruleGroup['actions'], function (aid, action) { 471 var $target = $form.find('.' + action['target']); 472 var actionResult = action['invert'] ? !conditionalResult : conditionalResult; 473 switch (action['action']) { 474 case 'show': 475 var changed = actionResult != Drupal.webform.isVisible($target); 476 if (actionResult) { 477 $target.find('.webform-conditional-disabled:not(.webform-disabled-flag)') 478 .removeClass('webform-conditional-disabled') 479 .webformProp('disabled', false); 480 $target 481 .removeClass('webform-conditional-hidden') 482 .show(); 483 $form.find('.chosen-disabled').prev().trigger('chosen:updated.chosen'); 484 } 485 else { 486 $target 487 .hide() 488 .addClass('webform-conditional-hidden') 489 .find(':input') 490 .addClass('webform-conditional-disabled webform-disabled-flag') 491 .webformProp('disabled', true); 492 } 493 if (changed && $target.is('tr')) { 494 Drupal.webform.restripeTable($target.closest('table').first()); 495 } 496 break; 497 498 case 'require': 499 var $requiredSpan = $target.find('.form-required, .form-optional').first(); 500 if (actionResult != $requiredSpan.hasClass('form-required')) { 501 var $targetInputElements = $target.find("input:text,textarea,input[type='email'],select,input:radio,input:checkbox,input:file"); 502 // Rather than hide the required tag, remove it so that other 503 // jQuery can respond via Drupal behaviors. 504 Drupal.detachBehaviors($requiredSpan); 505 $targetInputElements 506 .webformProp('required', actionResult) 507 .toggleClass('required', actionResult); 508 if (actionResult) { 509 $requiredSpan.replaceWith('<span class="form-required" title="' + Drupal.t('This field is required.') + '">*</span>'); 510 } 511 else { 512 $requiredSpan.replaceWith('<span class="form-optional"></span>'); 513 } 514 Drupal.attachBehaviors($requiredSpan); 515 } 516 break; 517 518 case 'set': 519 var $texts = $target.find("input:text,textarea,input[type='email']"); 520 var $selects = $target.find('select,select option,input:radio,input:checkbox'); 521 var $markups = $target.filter('.webform-component-markup'); 522 if (actionResult) { 523 var multiple = $.map(action['argument'].split(','), $.trim); 524 $selects 525 .webformVal(multiple) 526 .webformProp('disabled', true) 527 .addClass('webform-disabled-flag'); 528 $texts 529 .val([action['argument']]) 530 .webformProp('readonly', true) 531 .addClass('webform-disabled-flag'); 532 // A special case is made for markup. It is sanitized with 533 // filter_xss_admin on the server. otherwise text() should be used 534 // to avoid an XSS vulnerability. text() however would preclude 535 // the use of tags like <strong> or <a>. 536 $markups.html(action['argument']); 537 } 538 else { 539 $selects.not('.webform-disabled-flag') 540 .webformProp('disabled', false); 541 $texts.not('.webform-disabled-flag') 542 .webformProp('readonly', false); 543 // Markup not set? Then restore original markup as provided in 544 // the attribute data-webform-markup. 545 $markups.each(function () { 546 var $this = $(this); 547 var original = $this.data('webform-markup'); 548 if (original !== undefined) { 549 $this.html(original); 550 } 551 }); 552 } 553 break; 554 } 555 }); // End look on each action for one conditional. 556 }); // End loop on each conditional. 557 558 $form.find('.webform-disabled-flag').removeClass('webform-disabled-flag'); 559 }; 560 561 /** 562 * Event handler to prevent propagation of events. 563 * 564 * Typically click for disabling radio and checkboxes. 565 */ 566 Drupal.webform.stopEvent = function () { 567 return false;
568 }; 569 570 Drupal.webform.conditionalOperatorStringEqual = function (element, existingValue, ruleValue) { 571 var returnValue = false; 572 var currentValue = Drupal.webform.stringValue(element, existingValue); 573 $.each(currentValue, function (n, value) { 574 if (value.toLowerCase() === ruleValue.toLowerCase()) { 575 returnValue = true; 576 return false; // break. 577 } 578 }); 579 return returnValue; 580 }; 581 582 Drupal.webform.conditionalOperatorStringNotEqual = function (element, existingValue, ruleValue) { 583 var found = false; 584 var currentValue = Drupal.webform.stringValue(element, existingValue); 585 $.each(currentValue, function (n, value) { 586 if (value.toLowerCase() === ruleValue.toLowerCase()) { 587 found = true; 588 } 589 }); 590 return !found; 591 }; 592 593 Drupal.webform.conditionalOperatorStringContains = function (element, existingValue, ruleValue) { 594 var returnValue = false; 595 var currentValue = Drupal.webform.stringValue(element, existingValue); 596 $.each(currentValue, function (n, value) { 597 if (value.toLowerCase().indexOf(ruleValue.toLowerCase()) > -1) { 598 returnValue = true; 599 return false; // break. 600 } 601 }); 602 return returnValue; 603 }; 604 605 Drupal.webform.conditionalOperatorStringDoesNotContain = function (element, existingValue, ruleValue) { 606 var found = false; 607 var currentValue = Drupal.webform.stringValue(element, existingValue); 608 $.each(currentValue, function (n, value) { 609 if (value.toLowerCase().indexOf(ruleValue.toLowerCase()) > -1) { 610 found = true; 611 } 612 }); 613 return !found; 614 }; 615 616 Drupal.webform.conditionalOperatorStringBeginsWith = function (element, existingValue, ruleValue) { 617 var returnValue = false; 618 var currentValue = Drupal.webform.stringValue(element, existingValue); 619 $.each(currentValue, function (n, value) { 620 if (value.toLowerCase().indexOf(ruleValue.toLowerCase()) === 0) { 621 returnValue = true; 622 return false; // break. 623 } 624 }); 625 return returnValue; 626 }; 627 628 Drupal.webform.conditionalOperatorStringEndsWith = function (element, existingValue, ruleValue) { 629 var returnValue = false; 630 var currentValue = Drupal.webform.stringValue(element, existingValue); 631 $.each(currentValue, function (n, value) { 632 if (value.toLowerCase().lastIndexOf(ruleValue.toLowerCase()) === value.length - ruleValue.length) { 633 returnValue = true; 634 return false; // break. 635 } 636 }); 637 return returnValue; 638 }; 639 640 Drupal.webform.conditionalOperatorStringEmpty = function (element, existingValue, ruleValue) { 641 var currentValue = Drupal.webform.stringValue(element, existingValue); 642 var returnValue = true; 643 $.each(currentValue, function (n, value) { 644 if (value !== '') { 645 returnValue = false; 646 return false; // break. 647 } 648 }); 649 return returnValue; 650 }; 651 652 Drupal.webform.conditionalOperatorStringNotEmpty = function (element, existingValue, ruleValue) { 653 return !Drupal.webform.conditionalOperatorStringEmpty(element, existingValue, ruleValue); 654 }; 655 656 Drupal.webform.conditionalOperatorSelectGreaterThan = function (element, existingValue, ruleValue) { 657 var currentValue = Drupal.webform.stringValue(element, existingValue); 658 return Drupal.webform.compare_select(currentValue[0], ruleValue, element) > 0; 659 }; 660 661 Drupal.webform.conditionalOperatorSelectGreaterThanEqual = function (element, existingValue, ruleValue) { 662 var currentValue = Drupal.webform.stringValue(element, existingValue); 663 var comparison = Drupal.webform.compare_select(currentValue[0], ruleValue, element); 664 return comparison > 0 || comparison === 0; 665 }; 666 667 Drupal.webform.conditionalOperatorSelectLessThan = function (element, existingValue, ruleValue) { 668 var currentValue = Drupal.webform.stringValue(element, existingValue); 669 return Drupal.webform.compare_select(currentValue[0], ruleValue, element) < 0; 670 }; 671 672 Drupal.webform.conditionalOperatorSelectLessThanEqual = function (element, existingValue, ruleValue) { 673 var currentValue = Drupal.webform.stringValue(element, existingV
673alue); 674 var comparison = Drupal.webform.compare_select(currentValue[0], ruleValue, element); 675 return comparison < 0 || comparison === 0; 676 }; 677 678 Drupal.webform.conditionalOperatorNumericEqual = function (element, existingValue, ruleValue) { 679 // See float comparison: http://php.net/manual/en/language.types.float.php 680 var currentValue = Drupal.webform.stringValue(element, existingValue); 681 var epsilon = 0.000001; 682 // An empty string does not match any number. 683 return currentValue[0] === '' ? false : (Math.abs(parseFloat(currentValue[0]) - parseFloat(ruleValue)) < epsilon); 684 }; 685 686 Drupal.webform.conditionalOperatorNumericNotEqual = function (element, existingValue, ruleValue) { 687 // See float comparison: http://php.net/manual/en/language.types.float.php 688 var currentValue = Drupal.webform.stringValue(element, existingValue); 689 var epsilon = 0.000001; 690 // An empty string does not match any number. 691 return currentValue[0] === '' ? true : (Math.abs(parseFloat(currentValue[0]) - parseFloat(ruleValue)) >= epsilon); 692 }; 693 694 Drupal.webform.conditionalOperatorNumericGreaterThan = function (element, existingValue, ruleValue) { 695 var currentValue = Drupal.webform.stringValue(element, existingValue); 696 return parseFloat(currentValue[0]) > parseFloat(ruleValue); 697 }; 698 699 Drupal.webform.conditionalOperatorNumericGreaterThanEqual = function (element, existingValue, ruleValue) { 700 return Drupal.webform.conditionalOperatorNumericGreaterThan(element, existingValue, ruleValue) || 701 Drupal.webform.conditionalOperatorNumericEqual(element, existingValue, ruleValue); 702 }; 703 704 Drupal.webform.conditionalOperatorNumericLessThan = function (element, existingValue, ruleValue) { 705 var currentValue = Drupal.webform.stringValue(element, existingValue); 706 return parseFloat(currentValue[0]) < parseFloat(ruleValue); 707 }; 708 709 Drupal.webform.conditionalOperatorNumericLessThanEqual = function (element, existingValue, ruleValue) { 710 return Drupal.webform.conditionalOperatorNumericLessThan(element, existingValue, ruleValue) || 711 Drupal.webform.conditionalOperatorNumericEqual(element, existingValue, ruleValue); 712 }; 713 714 Drupal.webform.conditionalOperatorDateEqual = function (element, existingValue, ruleValue) { 715 var currentValue = Drupal.webform.dateValue(element, existingValue); 716 return currentValue === ruleValue; 717 }; 718 719 Drupal.webform.conditionalOperatorDateNotEqual = function (element, existingValue, ruleValue) { 720 return !Drupal.webform.conditionalOperatorDateEqual(element, existingValue, ruleValue); 721 }; 722 723 Drupal.webform.conditionalOperatorDateBefore = function (element, existingValue, ruleValue) { 724 var currentValue = Drupal.webform.dateValue(element, existingValue); 725 return (currentValue !== false) && currentValue < ruleValue; 726 }; 727 728 Drupal.webform.conditionalOperatorDateBeforeEqual = function (element, existingValue, ruleValue) { 729 var currentValue = Drupal.webform.dateValue(element, existingValue); 730 return (currentValue !== false) && (currentValue < ruleValue || currentValue === ruleValue); 731 }; 732 733 Drupal.webform.conditionalOperatorDateAfter = function (element, existingValue, ruleValue) { 734 var currentValue = Drupal.webform.dateValue(element, existingValue); 735 return (currentValue !== false) && currentValue > ruleValue; 736 }; 737 738 Drupal.webform.conditionalOperatorDateAfterEqual = function (element, existingValue, ruleValue) { 739 var currentValue = Drupal.webform.dateValue(element, existingValue); 740 return (currentValue !== false) && (currentValue > ruleValue || currentValue === ruleValue); 741 }; 742 743 Drupal.webform.conditionalOperatorTimeEqual = function (element, existingValue, ruleValue) { 744 var currentValue = Drupal.webform.timeValue(element, existingValue); 745 return currentValue === ruleValue; 746 }; 747 748 Drupal.webform.conditionalOperatorTimeNotEqual = function (element, existingValue, ruleValue) { 749 return !Drupal.webform.conditionalOperatorTimeEqual(element, existingValue, ruleValue); 750 }; 751 752 Drupal.webform.conditionalOperatorTimeBefore = function (element, existingV
752alue, ruleValue) { 753 // Date and time operators intentionally exclusive for "before". 754 var currentValue = Drupal.webform.timeValue(element, existingValue); 755 return (currentValue !== false) && (currentValue < ruleValue); 756 }; 757 758 Drupal.webform.conditionalOperatorTimeBeforeEqual = function (element, existingValue, ruleValue) { 759 // Date and time operators intentionally exclusive for "before". 760 var currentValue = Drupal.webform.timeValue(element, existingValue); 761 return (currentValue !== false) && (currentValue < ruleValue || currentValue === ruleValue); 762 }; 763 764 Drupal.webform.conditionalOperatorTimeAfter = function (element, existingValue, ruleValue) { 765 // Date and time operators intentionally inclusive for "after". 766 var currentValue = Drupal.webform.timeValue(element, existingValue); 767 return (currentValue !== false) && (currentValue > ruleValue); 768 }; 769 770 Drupal.webform.conditionalOperatorTimeAfterEqual = function (element, existingValue, ruleValue) { 771 // Date and time operators intentionally inclusive for "after". 772 var currentValue = Drupal.webform.timeValue(element, existingValue); 773 return (currentValue !== false) && (currentValue > ruleValue || currentValue === ruleValue); 774 }; 775 776 /** 777 * Utility function to compare values of a select component. 778 * 779 * @param string a 780 * First select option key to compare 781 * @param string b 782 * Second select option key to compare 783 * @param array options 784 * Associative array where the a and b are within the keys 785 * 786 * @return integer based upon position of $a and $b in $options 787 * -N if $a above (<) $b 788 * 0 if $a = $b 789 * +N if $a is below (>) $b 790 */ 791 Drupal.webform.compare_select = function (a, b, element) { 792 var optionList = []; 793 $('option,input:radio,input:checkbox', element).each(function () { 794 optionList.push($(this).val()); 795 }); 796 var a_position = optionList.indexOf(a); 797 var b_position = optionList.indexOf(b); 798 return (a_position < 0 || b_position < 0) ? null : a_position - b_position; 799 }; 800 801 /** 802 * Utility to return current visibility. 803 * 804 * Uses actual visibility, except for hidden components which use the applied 805 * disabled class. 806 */ 807 Drupal.webform.isVisible = function ($element) { 808 return $element.hasClass('webform-component-hidden') 809 ? !$element.find('input').first().hasClass('webform-conditional-disabled') 810 : $element.closest('.webform-conditional-hidden').length == 0; 811 }; 812 813 /** 814 * Function to get a string value from a select/radios/text/etc. field. 815 */ 816 Drupal.webform.stringValue = function (element, existingValue) { 817 var value = []; 818 if (element) { 819 var $element = $(element); 820 if (Drupal.webform.isVisible($element)) { 821 // Checkboxes and radios. 822 $element.find('input[type=checkbox]:checked,input[type=radio]:checked').each(function () { 823 value.push(this.value); 824 }); 825 // Select lists. 826 if (!value.length) { 827 var selectValue = $element.find('select').val(); 828 if (selectValue) { 829 if ($.isArray(selectValue)) { 830 value = selectValue; 831 } 832 else { 833 value.push(selectValue); 834 } 835 } 836 } 837 // Simple text fields. This check is done last so that the select list 838 // in select-or-other fields comes before the "other" text field. 839 if (!value.length) { 840 $element.find('input:not([type=checkbox],[type=radio]),textarea').each(function () { 841 value.push(this.value); 842 }); 843 } 844 } 845 } 846 else { 847 switch ($.type(existingValue)) { 848 case 'array':
849 value = existingValue; 850 break; 851 852 case 'string': 853 value.push(existingValue); 854 break; 855 } 856 } 857 return value; 858 }; 859 860 /** 861 * Utility function to calculate a second-based timestamp from a time field. 862 */ 863 Drupal.webform.dateValue = function (element, existingValue) { 864 var value = false; 865 if (element) { 866 var $element = $(element); 867 if (Drupal.webform.isVisible($element)) { 868 var day = $element.find('[name*=day]').val(); 869 var month = $element.find('[name*=month]').val(); 870 var year = $element.find('[name*=year]').val(); 871 // Months are 0 indexed in JavaScript. 872 if (month) { 873 month--; 874 } 875 if (year !== '' && month !== '' && day !== '') { 876 value = Date.UTC(year, month, day) / 1000; 877 } 878 } 879 } 880 else { 881 if ($.type(existingValue) === 'array' && existingValue.length) { 882 existingValue = existingValue[0]; 883 } 884 if ($.type(existingValue) === 'string') { 885 existingValue = existingV
885alue.split('-'); 886 } 887 if (existingValue.length === 3) { 888 value = Date.UTC(existingValue[0], existingValue[1], existingValue[2]) / 1000; 889 } 890 } 891 return value; 892 }; 893 894 /** 895 * Utility function to calculate a millisecond timestamp from a time field. 896 */ 897 Drupal.webform.timeValue = function (element, existingValue) { 898 var value = false; 899 if (element) { 900 var $element = $(element); 901 if (Drupal.webform.isVisible($element)) { 902 var hour = $element.find('[name*=hour]').val(); 903 var minute = $element.find('[name*=minute]').val(); 904 var ampm = $element.find('[name*=ampm]:checked').val(); 905 906 // Convert to integers if set. 907 hour = (hour === '') ? hour : parseInt(hour); 908 minute = (minute === '') ? minute : parseInt(minute); 909 910 if (hour !== '') { 911 hour = (hour < 12 && ampm == 'pm') ? hour + 12 : hour; 912 hour = (hour === 12 && ampm == 'am') ? 0 : hour; 913 } 914 if (hour !== '' && minute !== '') { 915 value = Date.UTC(1970, 0, 1, hour, minute) / 1000; 916 } 917 } 918 } 919 else { 920 if ($.type(existingValue) === 'array' && existingValue.length) {
921 existingValue = existingValue[0]; 922 } 923 if ($.type(existingValue) === 'string') { 924 existingValue = existingValue.split(':'); 925 } 926 if (existingValue.length >= 2) { 927 value = Date.UTC(1970, 0, 1, existingValue[0], existingValue[1]) / 1000; 928 } 929 } 930 return value; 931 }; 932 933 /** 934 * Make a prop shim for jQuery < 1.9. 935 */ 936 $.fn.webformProp = $.fn.webformProp || function (name, value) { 937 if (value) { 938 return $.fn.prop ? this.prop(name, true) : this.attr(name, true); 939 } 940 else { 941 return $.fn.prop ? this.prop(name, false) : this.removeAttr(name); 942 } 943 }; 944 945 /** 946 * Make a multi-valued val() function. 947 * 948 * This is for setting checkboxes, radios, and select elements. 949 */ 950 $.fn.webformVal = function (values) { 951 this.each(function () { 952 var $this = $(this); 953 var value = $this.val(); 954 var on = $.inArray($this.val(), values) != -1; 955 if (this.nodeName == 'OPTION') { 956 $this.webformProp('selected', on ? value : false); 957 } 958 else { 959 $this.val(on ? [value] : false); 960 } 961 }); 962 return this; 963 }; 964 965 /** 966 * Given a table's DOM element, restripe the odd/even classes. 967 */ 968 Drupal.webform.restripeTable = function (table) { 969 // :even and :odd are reversed because jQuery counts from 0 and 970 // we count from 1, so we're out of sync. 971 // Match immediate children of the parent element to allow nesting. 972 $('> tbody > tr, > tr', table) 973 .filter(':visible:odd').filter('.odd') 974 .removeClass('odd').addClass('even') 975 .end().end() 976 .filter(':visible:even').filter('.even') 977 .removeClass('even').addClass('odd'); 978 }; 979 980})(jQuery); 981;
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.