/**
* JavaScript behaviors for the front-end display of webforms.
*/
(function ($) {
Drupal.behaviors.webform = Drupal.behaviors.webform || {};
Drupal.behaviors.webform.attach = function(context) {
// Calendar datepicker behavior.
Drupal.webform.datepicker(context);
// Conditional logic.
if (Drupal.settings.webform && Drupal.settings.webform.conditionals) {
Drupal.webform.conditional(context);
}
};
Drupal.webform = Drupal.webform || {};
Drupal.webform.datepicker = function(context) {
$('div.webform-datepicker').each(function() {
var $webformDatepicker = $(this);
var $calendar = $webformDatepicker.find('input.webform-calendar');
// Ensure the page we're on actually contains a datepicker.
if ($calendar.length == 0) {
return;
}
var startDate = $calendar[0].className.replace(/.*webform-calendar-start-(\d{4}-\d{2}-\d{2}).*/, '$1').split('-');
var endDate = $calendar[0].className.replace(/.*webform-calendar-end-(\d{4}-\d{2}-\d{2}).*/, '$1').split('-');
var firstDay = $calendar[0].className.replace(/.*webform-calendar-day-(\d).*/, '$1');
// Convert date strings into actual Date objects.
startDate = new Date(startDate[0], startDate[1] - 1, startDate[2]);
endDate = new Date(endDate[0], endDate[1] - 1, endDate[2]);
// Ensure that start comes before end for datepicker.
if (startDate > endDate) {
var laterDate = startDate;
startDate = endDate;
endDate = laterDate;
}
var startYear = startDate.getFullYear();
var endYear = endDate.getFullYear();
// Set up the jQuery datepicker element.
$calendar.datepicker({
dateFormat: 'yy-mm-dd',
yearRange: startYear + ':' + endYear,
firstDay: parseInt(firstDay),
minDate: startDate,
maxDate: endDate,
onSelect: function(dateText, inst) {
var date = dateText.split('-');
$webformDatepicker.find('select.year, input.year').val(+date[0]).trigger('change');
$webformDatepicker.find('select.month').val(+date[1]).trigger('change');
$webformDatepicker.find('select.day').val(+date[2]).trigger('change');
},
beforeShow: function(input, inst) {
// Get the select list values.
var year = $webformDatepicker.find('select.year, input.year').val();
var month = $webformDatepicker.find('select.month').val();
var day = $webformDatepicker.find('select.day').val();
// If empty, default to the current year/month/day in the popup.
var today = new Date();
year = year ? year : today.getFullYear();
month = month ? month : today.getMonth() + 1;
day = day ? day : today.getDate();
// Make sure that the default year fits in the available options.
year = (year < startYear || year > endYear) ? startYear : year;
// jQuery UI Datepicker will read the input field and base its date off
// of that, even though in our case the input field is a button.
$(input).val(year + '-' + month + '-' + day);
}
});
// Prevent the calendar button from submitting the form.
$calendar.click(function(event) {
$(this).focus();
event.preventDefault();
});
});
};
Drupal.webform.conditional = function(context) {
// Add the bindings to each webform on the page.
$.each(Drupal.settings.webform.conditionals, function(formKey, settings) {
var $form = $('.' + formKey + ':not(.webform-conditional-processed)');
$form.each(function(index, currentForm) {
var $currentForm = $(currentForm);
$currentForm.addClass('webform-conditional-processed');
$currentForm.bind('change', { 'settings': settings }, Drupal.webform.conditionalCheck);
// Trigger all the elements that cause conditionals on this form.
$.each(Drupal.settings.webform.conditionals[formKey]['sourceMap'], function(elementKey) {
$currentForm.find('.' + elementKey).find('input,select,textarea').filter(':first').trigger('change');
});
})
});
};
/**
* Event handler to respond to field changes in a form.
*
* This event is bound to the entire form, not individual fields.
*/
Drupal.webform.conditionalCheck = function(e) {
var $triggerElement = $(e.target).closest('.webform-component');
var $form = $triggerElement.closest('form');
var triggerElementKey = $triggerElement.attr('class').match(/webform-component--[^ ]+/)[0];
var settings = e.data.settings;
if (settings.sourceMap[triggerElementKey]) {
$.each(settings.sourceMap[triggerElementKey], function(n, rgid_key) {
var ruleGroup = settings.ruleGroups[rgid_key];
// Perform the comparison callback and build the results for this group.
var conditionalResult = true;
var conditionalResults = [];
$.each(ruleGroup['rules'], function(m, rule) {
var elementKey = rule['source'];
var element = $form.find('.' + elementKey)[0];
var existingValue = settings.values[elementKey] ? settings.values[elementKey] : null;
conditionalResults.push(window['Drupal']['webform'][rule.callback](element, existingValue, rule['value'] ));
});
// Filter out false values.
var filteredResults = [];
for (var i = 0; i < conditionalResults.length; i++) {
if (conditionalResults[i]) {
filteredResults.push(conditionalResults[i]);
}
}
// Calculate the and/or result.
if (ruleGroup['andor'] === 'or') {
conditionalResult = filteredResults.length > 0;
}
else {
conditionalResult = filteredResults.length === conditionalResults.length;
}
// Flip the result of the action is to hide.
var showComponent;
if (ruleGroup['action'] == 'hide') {
showComponent = !conditionalResult;
}
else {
showComponent = conditionalResult;
}
var $target = $form.find('.' + ruleGroup['target']);
var $targetElements;
if (showComponent != $target.is(':visible')) {
if (showComponent) {
$targetElements = $target.find('.webform-conditional-disabled').removeClass('webform-conditional-disabled');
$.fn.prop ? $targetElements.prop('disabled', false) : $targetElements.removeAttr('disabled');
$target.show();
}
else {
$targetElements = $target.find(':input').addClass('webform-conditional-disabled');
$.fn.prop ? $targetElements.prop('disabled', true) : $targetElements.attr('disabled', true);
$target.hide();
}
// Trigger change if not already in recurive infinite loop
var target = $target.get(0);
target.changeDepth = target.changeDepth || 0;
if (target.changeDepth < 10) {
target.changeDepth++;
$target.trigger('change');
target.changeDepth--;
} else {
alert(Drupal.t("An infinite loop was detected in this webform's conditionals. Contact the administrator."));
}
}
});
}
};
Drupal.webform.conditionalOperatorStringEqual = function(element, existingValue, ruleValue) {
var returnValue = false;
var currentValue = Drupal.webform.stringValue(element, existingValue);
$.each(currentValue, function(n, value) {
if (value.toLowerCase() === ruleValue.toLowerCase()) {
returnValue = true;
return false; // break.
}
});
return returnValue;
};
Drupal.webform.conditionalOperatorStringNotEqual = function(element, existingValue, ruleValue) {
var found = false;
var currentValue = Drupal.webform.stringValue(element, existingValue);
$.each(currentValue, function(n, value) {
if (value.toLowerCase() === ruleValue.toLowerCase()) {
found = true;
}
});
return !found;
};
Drupal.webform.conditionalOperatorStringContains = function(element, existingValue, ruleValue) {
var returnValue = false;
var currentValue = Drupal.webform.stringValue(element, existingValue);
$.each(currentValue, function(n, value) {
if (value.toLowerCase().indexOf(ruleValue.toLowerCase()) > -1) {
returnValue = true;
return false; // break.
}
});
return returnValue;
};
Drupal.webform.conditionalOperatorStringDoesNotContain = function(element, existingValue, ruleValue) {
var found = false;
var currentValue = Drupal.webform.stringValue(element, existingValue);
$.each(currentValue, function(n, value) {
if (value.toLowerCase().indexOf(ruleValue.toLowerCase()) > -1) {
found = true;
}
});
return !found;
};
Drupal.webform.conditionalOperatorStringBeginsWith = function(element, existingValue, ruleValue) {
var returnValue = false;
var currentValue = Drupal.webform.stringValue(element, existingValue);
$.each(currentValue, function(n, value) {
if (value.toLowerCase().indexOf(ruleValue.toLowerCase()) === 0) {
returnValue = true;
return false; // break.
}
});
return returnValue;
};
Drupal.webform.conditionalOperatorStringEndsWith = function(element, existingValue, ruleValue) {
var returnValue = false;
var currentValue = Drupal.webform.stringValue(element, existingValue);
$.each(currentValue, function(n, value) {
if (value.toLowerCase().lastIndexOf(ruleValue.toLowerCase()) === value.length - ruleValue.length) {
returnValue = true;
return false; // break.
}
});
return returnValue;
};
Drupal.webform.conditionalOperatorStringEmpty = function(element, existingValue, ruleValue) {
var currentValue = Drupal.webform.stringValue(element, existingValue);
var returnValue = true;
$.each(currentValue, function(n, value) {
if (value !== '') {
returnValue = false;
return false; // break.
}
});
return returnValue;
};
Drupal.webform.conditionalOperatorStringNotEmpty = function(element, existingValue, ruleValue) {
return !Drupal.webform.conditionalOperatorStringEmpty(element, existingValue, ruleValue);
};
Drupal.webform.conditionalOperatorNumericEqual = function(element, existingValue, ruleValue) {
// See float comparison: http://php.net/manual/en/language.types.float.php
var currentValue = Drupal.webform.stringValue(element, existingValue);
var epsilon = 0.000001;
// An empty string does not match any number.
return currentValue[0] === '' ? false : (Math.abs(parseFloat(currentValue[0]) - parseFloat(ruleValue)) < epsilon);
};
Drupal.webform.conditionalOperatorNumericNotEqual = function(element, existingValue, ruleValue) {
// See float comparison: http://php.net/manual/en/language.types.float.php
var currentValue = Drupal.webform.stringValue(element, existingValue);
var epsilon = 0.000001;
// An empty string does not match any number.
return currentValue[0] === '' ? true : (Math.abs(parseFloat(currentValue[0]) - parseFloat(ruleValue)) >= epsilon);
};
Drupal.webform.conditionalOperatorNumericGreaterThan = function(element, existingValue, ruleValue) {
var currentValue = Drupal.webform.stringValue(element, existingValue);
return parseFloat(currentValue[0]) > parseFloat(ruleValue);
};
Drupal.webform.conditionalOperatorNumericLessThan = function(element, existingValue, ruleValue) {
var currentValue = Drupal.webform.stringValue(element, existingValue);
return parseFloat(currentValue[0]) < parseFloat(ruleValue);
};
Drupal.webform.conditionalOperatorDateEqual = function(element, existingValue, ruleValue) {
var currentValue = Drupal.webform.dateValue(element, existingValue);
return currentValue === ruleValue;
};
Drupal.webform.conditionalOperatorDateBefore = function(element, existingValue, ruleValue) {
var currentValue = Drupal.webform.dateValue(element, existingValue);
return (currentValue !== false) && currentValue < ruleValue;
};
Drupal.webform.conditionalOperatorDateAfter = function(element, existingValue, ruleValue) {
var currentValue = Drupal.webform.dateValue(element, existingValue);
return (currentValue !== false) && currentValue > ruleValue;
};
Drupal.webform.conditionalOperatorTimeEqual = function(element, existingValue, ruleValue) {
var currentValue = Drupal.webform.timeValue(element, existingValue);
return currentValue === ruleValue;
};
Drupal.webform.conditionalOperatorTimeBefore = function(element, existingValue, ruleValue) {
// Date and time operators intentionally exclusive for "before".
var currentValue = Drupal.webform.timeValue(element, existingValue);
return (currentValue !== false) && (currentValue < ruleValue);
};
Drupal.webform.conditionalOperatorTimeAfter = function(element, existingValue, ruleValue) {
// Date and time operators intentionally inclusive for "after".
var currentValue = Drupal.webform.timeValue(element, existingValue);
return (currentValue !== false) && (currentValue >= ruleValue);
};
/**
* Utility function to get a string value from a select/radios/text/etc. field.
*/
Drupal.webform.stringValue = function(element, existingValue) {
var value = [];
if (element) {
var $element = $(element);
if ($element.is(':visible')) {
// Checkboxes and radios.
$element.find('input[type=checkbox]:checked,input[type=radio]:checked').each(function() {
value.push(this.value);
});
// Select lists.
if (!value.length) {
var selectValue = $element.find('select').val();
if (selectValue) {
value.push(selectValue);
}
}
// Simple text fields. This check is done last so that the select list in
// select-or-other fields comes before the "other" text field.
if (!value.length) {
$element.find('input:not([type=checkbox],[type=radio]),textarea').each(function() {
value.push(this.value);
});
}
}
}
else {
switch ($.type(existingValue)) {
case 'array':
value = existingValue;
break;
case 'string':
value.push(existingValue);
break;
}
}
return value;
};
/**
* Utility function to calculate a millisecond timestamp from a time field.
*/
Drupal.webform.dateValue = function(element, existingValue) {
var value = false;
if (element) {
var $element = $(element);
if ($element.is(':visible')) {
var day = $element.find('[name*=day]').val();
var month = $element.find('[name*=month]').val();
var year = $element.find('[name*=year]').val();
// Months are 0 indexed in JavaScript.
if (month) {
month--;
}
if (year !== '' && month !== '' && day !== '') {
value = Date.UTC(year, month, day) / 1000;
}
}
}
else {
if ($.type(existingValue) === 'array' && existingValue.length) {
existingValue = existingValue[0];
}
if ($.type(existingValue) === 'string') {
existingValue = existingValue.split('-');
}
if (existingValue.length === 3) {
value = Date.UTC(existingValue[0], existingValue[1], existingValue[2]) / 1000;
}
}
return value;
};
/**
* Utility function to calculate a millisecond timestamp from a time field.
*/
Drupal.webform.timeValue = function(element, existingValue) {
var value = false;
if (element) {
var $element = $(element);
if ($element.is(':visible')) {
var hour = $element.find('[name*=hour]').val();
var minute = $element.find('[name*=minute]').val();
var ampm = $element.find('[name*=ampm]:checked').val();
// Convert to integers if set.
hour = (hour === '') ? hour : parseInt(hour);
minute = (minute === '') ? minute : parseInt(minute);
if (hour !== '') {
hour = (hour < 12 && ampm == 'pm') ? hour + 12 : hour;
hour = (hour === 12 && ampm == 'am') ? 0 : hour;
}
if (hour !== '' && minute !== '') {
value = Date.UTC(1970, 0, 1, hour, minute) / 1000;
}
}
}
else {
if ($.type(existingValue) === 'array' && existingValue.length) {
existingValue = existingValue[0];
}
if ($.type(existingValue) === 'string') {
existingValue = existingValue.split(':');
}
if (existingValue.length >= 2) {
value = Date.UTC(1970, 0, 1, existingValue[0], existingValue[1]) / 1000;
}
}
return value;
};
})(jQuery);