Move all files to 2017/
This commit is contained in:
parent
ac7370f67f
commit
2875863330
15717 changed files with 0 additions and 0 deletions
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
* @file
|
||||
* Dropbutton feature.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// Make sure that dropButton behavior exists.
|
||||
if (!Drupal.behaviors.dropButton) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap Drupal's dropbutton behavior so that the dropbutton widget is only visible after it is initialized.
|
||||
*/
|
||||
var dropButton = Drupal.behaviors.dropButton;
|
||||
Drupal.behaviors.dropButton = {
|
||||
attach: function (context, settings) {
|
||||
dropButton.attach(context, settings);
|
||||
$(context).find('.webform-dropbutton .dropbutton-wrapper').once('webform-dropbutton').css('visibility', 'visible');
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
189
2017/web/modules/contrib/webform/js/webform.admin.js
Normal file
189
2017/web/modules/contrib/webform/js/webform.admin.js
Normal file
|
@ -0,0 +1,189 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for admin pages.
|
||||
*/
|
||||
|
||||
(function ($, Drupal, debounce) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Filters the webform element list by a text input search string.
|
||||
*
|
||||
* The text input will have the selector `input.webform-form-filter-text`.
|
||||
*
|
||||
* The target element to do searching in will be in the selector
|
||||
* `input.webform-form-filter-text[data-element]`
|
||||
*
|
||||
* The text source where the text should be found will have the selector
|
||||
* `.webform-form-filter-text-source`
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the behavior for the webform element filtering.
|
||||
*/
|
||||
Drupal.behaviors.webformFilterByText = {
|
||||
attach: function (context, settings) {
|
||||
$('input.webform-form-filter-text', context).once('webform-form-filter-text').each(function () {
|
||||
var $input = $(this);
|
||||
var $table = $($input.data('element'));
|
||||
var $summary = $($input.data('summary'));
|
||||
var $noResults = $($input.data('no-results'));
|
||||
var $details = $table.closest('details');
|
||||
var sourceSelector = $input.data('source') || '.webform-form-filter-text-source';
|
||||
var parentSelector = $input.data('parent') || 'tr';
|
||||
var $filterRows;
|
||||
|
||||
var hasDetails = $details.length;
|
||||
var totalItems;
|
||||
var args = {
|
||||
'@item': $input.data('item-single') || Drupal.t('item'),
|
||||
'@items': $input.data('item-plural') || Drupal.t('items'),
|
||||
'@total': null
|
||||
};
|
||||
|
||||
if ($table.length) {
|
||||
$filterRows = $table.find(sourceSelector);
|
||||
$input
|
||||
.attr('autocomplete', 'off')
|
||||
.on('keyup', debounce(filterElementList, 200))
|
||||
.keyup();
|
||||
// Make sure the filter input is always focused.
|
||||
setTimeout(function () {$input.focus();});
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the webform element list.
|
||||
*
|
||||
* @param {jQuery.Event} e
|
||||
* The jQuery event for the keyup event that triggered the filter.
|
||||
*/
|
||||
function filterElementList(e) {
|
||||
var query = $(e.target).val().toLowerCase();
|
||||
|
||||
// Filter if the length of the query is at least 2 characters.
|
||||
if (query.length >= 2) {
|
||||
// Reset count.
|
||||
totalItems = 0;
|
||||
if ($details.length) {
|
||||
$details.hide();
|
||||
}
|
||||
$filterRows.each(toggleEntry);
|
||||
|
||||
// Announce filter changes.
|
||||
// @see Drupal.behaviors.blockFilterByText
|
||||
Drupal.announce(Drupal.formatPlural(
|
||||
totalItems,
|
||||
'1 @item is available in the modified list.',
|
||||
'@total @items are available in the modified list.',
|
||||
args
|
||||
));
|
||||
}
|
||||
else {
|
||||
totalItems = $filterRows.length;
|
||||
$filterRows.each(function (index) {
|
||||
$(this).closest(parentSelector).show();
|
||||
if ($details.length) {
|
||||
$details.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Set total.
|
||||
args['@total'] = totalItems;
|
||||
|
||||
// Hide/show no results.
|
||||
$noResults[totalItems ? 'hide' : 'show']();
|
||||
|
||||
// Update summary.
|
||||
if ($summary.length) {
|
||||
$summary.html(Drupal.formatPlural(
|
||||
totalItems,
|
||||
'1 @item',
|
||||
'@total @items',
|
||||
args
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows or hides the webform element entry based on the query.
|
||||
*
|
||||
* @param {number} index
|
||||
* The index in the loop, as provided by `jQuery.each`
|
||||
* @param {HTMLElement} label
|
||||
* The label of the webform.
|
||||
*/
|
||||
function toggleEntry(index, label) {
|
||||
var $label = $(label);
|
||||
var $row = $label.closest(parentSelector);
|
||||
var textMatch = $label.text().toLowerCase().indexOf(query) !== -1;
|
||||
$row.toggle(textMatch);
|
||||
if (textMatch) {
|
||||
totalItems++;
|
||||
if (hasDetails) {
|
||||
$row.closest('details').show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Filter webform autocomplete handler.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformFilterAutocomplete = {
|
||||
attach: function (context) {
|
||||
$('.webform-filter-form input.form-autocomplete', context).once('webform-autocomplete')
|
||||
.each(function () {
|
||||
// If input value is an autocomplete match, reset the input to its
|
||||
// default value.
|
||||
if (/\(([^)]+)\)$/.test(this.value)) {
|
||||
this.value = this.defaultValue;
|
||||
}
|
||||
|
||||
// From: http://stackoverflow.com/questions/5366068/jquery-ui-autocomplete-submit-onclick-result
|
||||
$(this).bind('autocompleteselect', function (event, ui) {
|
||||
if (ui.item) {
|
||||
$(this).val(ui.item.value);
|
||||
this.form.submit();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Allow table rows to be hyperlinked.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformTableRowHref = {
|
||||
attach: function (context) {
|
||||
// Only attach the click event handler to the entire table and determine
|
||||
// which row triggers the event.
|
||||
$('.webform-results-table', context).once('webform-results-table').click(function (event) {
|
||||
if (event.target.tagName === 'A' || event.target.tagName === 'BUTTON') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($(event.target).parents('a[href]').length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var $tr = $(event.target).parents('tr[data-webform-href]');
|
||||
if (!$tr.length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
window.location = $tr.attr('data-webform-href');
|
||||
return false;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal, Drupal.debounce);
|
|
@ -0,0 +1,19 @@
|
|||
/**
|
||||
* @file
|
||||
* Dropbutton feature.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// Make sure that dropButton behavior exists.
|
||||
if (!Drupal.behaviors.tableDrag) {
|
||||
return;
|
||||
}
|
||||
|
||||
$(function () {
|
||||
$('head').append('<style type="text/css">.webform-tabledrag-hide {display: table-cell;}</style>');
|
||||
});
|
||||
|
||||
})(jQuery, Drupal);
|
366
2017/web/modules/contrib/webform/js/webform.ajax.js
Normal file
366
2017/web/modules/contrib/webform/js/webform.ajax.js
Normal file
|
@ -0,0 +1,366 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for Ajax.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
Drupal.webform = Drupal.webform || {};
|
||||
Drupal.webform.ajax = Drupal.webform.ajax || {};
|
||||
// Allow scrollTopOffset to be custom defined or based on whether there is a
|
||||
// floating toolbar.
|
||||
Drupal.webform.ajax.scrollTopOffset = Drupal.webform.ajax.scrollTopOffset || ($('#toolbar-administration').length ? 140 : 10);
|
||||
|
||||
/**
|
||||
* Provide Webform Ajax link behavior.
|
||||
*
|
||||
* Display fullscreen progress indicator instead of throbber.
|
||||
* Copied from: Drupal.behaviors.AJAX
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the behavior to a.webform-ajax-link.
|
||||
*/
|
||||
Drupal.behaviors.webformAjaxLink = {
|
||||
attach: function (context) {
|
||||
$('.webform-ajax-link', context).once('webform-ajax-link').each(function () {
|
||||
var element_settings = {};
|
||||
element_settings.progress = {type: 'fullscreen'};
|
||||
|
||||
// For anchor tags, these will go to the target of the anchor rather
|
||||
// than the usual location.
|
||||
var href = $(this).attr('href');
|
||||
if (href) {
|
||||
element_settings.url = href;
|
||||
element_settings.event = 'click';
|
||||
}
|
||||
element_settings.dialogType = $(this).data('dialog-type');
|
||||
element_settings.dialogRenderer = $(this).data('dialog-renderer');
|
||||
element_settings.dialog = $(this).data('dialog-options');
|
||||
element_settings.base = $(this).attr('id');
|
||||
element_settings.element = this;
|
||||
Drupal.ajax(element_settings);
|
||||
|
||||
// Close all open modal dialogs when opening off-canvas dialog.
|
||||
if (element_settings.dialogRenderer === 'off_canvas') {
|
||||
$(this).on('click', function () {
|
||||
$('.ui-dialog.webform-ui-dialog:visible').find('.ui-dialog-content').dialog('close');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a hash (#) to current pages location for links and buttons
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the behavior to a[data-hash] or :button[data-hash].
|
||||
*
|
||||
* @see \Drupal\webform_ui\WebformUiEntityElementsForm::getElementRow
|
||||
* @see Drupal.behaviors.webformFormTabs
|
||||
*/
|
||||
Drupal.behaviors.webformAjaxHash = {
|
||||
attach: function (context) {
|
||||
$('[data-hash]', context).once('webform-ajax-hash').each(function () {
|
||||
var hash = $(this).data('hash');
|
||||
if (hash) {
|
||||
$(this).on('click', function () {
|
||||
location.hash = $(this).data('hash');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Provide Ajax callback for confirmation back to link.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the behavior to confirmation back to link.
|
||||
*/
|
||||
Drupal.behaviors.webformConfirmationBackAjax = {
|
||||
attach: function (context) {
|
||||
$('.js-webform-confirmation-back-link-ajax', context)
|
||||
.once('webform-confirmation-back-ajax')
|
||||
.click(function (event) {
|
||||
var $form = $(this).parents('form');
|
||||
|
||||
// Trigger the Ajax call back for the hidden submit button.
|
||||
// @see \Drupal\webform\WebformSubmissionForm::getCustomForm
|
||||
$form.find('.js-webform-confirmation-back-submit-ajax').click();
|
||||
|
||||
// Move the progress indicator from the submit button to after this link.
|
||||
// @todo Figure out a better way to set a progress indicator.
|
||||
var $progress_indicator = $form.find('.ajax-progress');
|
||||
if ($progress_indicator) {
|
||||
$(this).after($progress_indicator);
|
||||
}
|
||||
|
||||
// Cancel the click event.
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/** ********************************************************************** **/
|
||||
// Ajax commands.
|
||||
/** ********************************************************************** **/
|
||||
|
||||
/**
|
||||
* Track the updated table row key.
|
||||
*/
|
||||
var updateKey;
|
||||
|
||||
/**
|
||||
* Track the add element key.
|
||||
*/
|
||||
var addElement;
|
||||
|
||||
/**
|
||||
* Command to insert new content into the DOM.
|
||||
*
|
||||
* @param {Drupal.Ajax} ajax
|
||||
* {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
|
||||
* @param {object} response
|
||||
* The response from the Ajax request.
|
||||
* @param {string} response.data
|
||||
* The data to use with the jQuery method.
|
||||
* @param {string} [response.method]
|
||||
* The jQuery DOM manipulation method to be used.
|
||||
* @param {string} [response.selector]
|
||||
* A optional jQuery selector string.
|
||||
* @param {object} [response.settings]
|
||||
* An optional array of settings that will be used.
|
||||
* @param {number} [status]
|
||||
* The XMLHttpRequest status.
|
||||
*/
|
||||
Drupal.AjaxCommands.prototype.webformInsert = function (ajax, response, status) {
|
||||
// Insert the HTML.
|
||||
this.insert(ajax, response, status);
|
||||
|
||||
// Add element.
|
||||
if (addElement) {
|
||||
var addSelector = (addElement === '_root_')
|
||||
? '#webform-ui-add-element'
|
||||
: '[data-drupal-selector="edit-webform-ui-elements-' + addElement + '-add"]';
|
||||
$(addSelector).click();
|
||||
}
|
||||
|
||||
// If not add element, then scroll to and highlight the updated table row.
|
||||
if (!addElement && updateKey) {
|
||||
var $element = $('tr[data-webform-key="' + updateKey + '"]');
|
||||
|
||||
// Highlight the updated element's row.
|
||||
$element.addClass('color-success');
|
||||
setTimeout(function () {$element.removeClass('color-success');}, 3000);
|
||||
|
||||
// Focus first tabbable item for the updated elements and handlers.
|
||||
$element.find(':tabbable:not(.tabledrag-handle)').eq(0).focus();
|
||||
|
||||
// Scroll to elements that are not visible.
|
||||
if (!isScrolledIntoView($element)) {
|
||||
$('html, body').animate({scrollTop: $element.offset().top - Drupal.webform.ajax.scrollTopOffset}, 500);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Focus main content.
|
||||
$('#main-content').focus();
|
||||
}
|
||||
|
||||
// Display main page's status message in a floating container.
|
||||
var $wrapper = $(response.selector);
|
||||
if ($wrapper.parents('.ui-dialog').length === 0) {
|
||||
var $messages = $wrapper.find('.messages');
|
||||
// If 'add element' don't show any messages.
|
||||
if (addElement) {
|
||||
$messages.remove();
|
||||
}
|
||||
else if ($messages.length) {
|
||||
var $floatingMessage = $('#webform-ajax-messages');
|
||||
if ($floatingMessage.length === 0) {
|
||||
$floatingMessage = $('<div id="webform-ajax-messages" class="webform-ajax-messages"></div>');
|
||||
$('body').append($floatingMessage);
|
||||
}
|
||||
if ($floatingMessage.is(':animated')) {
|
||||
$floatingMessage.stop(true, true);
|
||||
}
|
||||
$floatingMessage.html($messages).show().delay(3000).fadeOut(1000);
|
||||
}
|
||||
}
|
||||
|
||||
updateKey = null; // Reset element update.
|
||||
addElement = null; // Reset add element.
|
||||
};
|
||||
|
||||
/**
|
||||
* Scroll to top ajax command.
|
||||
*
|
||||
* @param {Drupal.Ajax} [ajax]
|
||||
* A {@link Drupal.ajax} object.
|
||||
* @param {object} response
|
||||
* Ajax response.
|
||||
* @param {string} response.selector
|
||||
* Selector to use.
|
||||
*
|
||||
* @see Drupal.AjaxCommands.prototype.viewScrollTop
|
||||
*/
|
||||
Drupal.AjaxCommands.prototype.webformScrollTop = function (ajax, response) {
|
||||
// Scroll to the top of the view. This will allow users
|
||||
// to browse newly loaded content after e.g. clicking a pager
|
||||
// link.
|
||||
var offset = $(response.selector).offset();
|
||||
// We can't guarantee that the scrollable object should be
|
||||
// the body, as the view could be embedded in something
|
||||
// more complex such as a modal popup. Recurse up the DOM
|
||||
// and scroll the first element that has a non-zero top.
|
||||
var scrollTarget = response.selector;
|
||||
while ($(scrollTarget).scrollTop() === 0 && $(scrollTarget).parent()) {
|
||||
scrollTarget = $(scrollTarget).parent();
|
||||
}
|
||||
|
||||
if (response.target === 'page' && $(scrollTarget).length && $(scrollTarget)[0].tagName === 'HTML') {
|
||||
// Scroll to top when scroll target is the entire page.
|
||||
// @see https://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport
|
||||
var rect = $(scrollTarget)[0].getBoundingClientRect();
|
||||
if (!(rect.top >= 0 && rect.left >= 0 && rect.bottom <= $(window).height() && rect.right <= $(window).width())) {
|
||||
$(scrollTarget).animate({scrollTop: 0}, 500);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Only scroll upward.
|
||||
if (offset.top - Drupal.webform.ajax.scrollTopOffset < $(scrollTarget).scrollTop()) {
|
||||
$(scrollTarget).animate({scrollTop: (offset.top - Drupal.webform.ajax.scrollTopOffset)}, 500);
|
||||
}
|
||||
}
|
||||
|
||||
// Focus on the form wrapper content bookmark if
|
||||
// .js-webform-autofocus is not enabled.
|
||||
// @see \Drupal\webform\Form\WebformAjaxFormTrait::buildAjaxForm
|
||||
var $form = $(response.selector + '-content').find('form');
|
||||
if (!$form.hasClass('js-webform-autofocus')) {
|
||||
$(response.selector + '-content').focus();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Command to refresh the current webform page.
|
||||
*
|
||||
* @param {Drupal.Ajax} [ajax]
|
||||
* {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
|
||||
* @param {object} response
|
||||
* The response from the Ajax request.
|
||||
* @param {string} response.url
|
||||
* The URL to redirect to.
|
||||
* @param {number} [status]
|
||||
* The XMLHttpRequest status.
|
||||
*/
|
||||
Drupal.AjaxCommands.prototype.webformRefresh = function (ajax, response, status) {
|
||||
// Get URL path name.
|
||||
// @see https://stackoverflow.com/questions/6944744/javascript-get-portion-of-url-path
|
||||
var a = document.createElement('a');
|
||||
a.href = response.url;
|
||||
if (a.pathname === window.location.pathname && $('.webform-ajax-refresh').length) {
|
||||
updateKey = (response.url.match(/[?|&]update=([^&]+)($|&)/)) ? RegExp.$1 : null;
|
||||
addElement = (response.url.match(/[?|&]add_element=([^&]+)($|&)/)) ? RegExp.$1 : null;
|
||||
$('.webform-ajax-refresh').click();
|
||||
}
|
||||
else {
|
||||
this.redirect(ajax, response, status);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Command to close a off-canvas and modal dialog.
|
||||
*
|
||||
* If no selector is given, it defaults to trying to close the modal.
|
||||
*
|
||||
* @param {Drupal.Ajax} [ajax]
|
||||
* {@link Drupal.Ajax} object created by {@link Drupal.ajax}.
|
||||
* @param {object} response
|
||||
* The response from the Ajax request.
|
||||
* @param {string} response.selector
|
||||
* Selector to use.
|
||||
* @param {bool} response.persist
|
||||
* Whether to persist the dialog element or not.
|
||||
* @param {number} [status]
|
||||
* The HTTP status code.
|
||||
*/
|
||||
Drupal.AjaxCommands.prototype.webformCloseDialog = function (ajax, response, status) {
|
||||
if ($('#drupal-off-canvas').length) {
|
||||
// Close off-canvas system tray which is not triggered by close dialog
|
||||
// command.
|
||||
// @see Drupal.behaviors.offCanvasEvents
|
||||
$('#drupal-off-canvas').remove();
|
||||
$('body').removeClass('js-tray-open');
|
||||
// Remove all *.off-canvas events
|
||||
$(document).off('.off-canvas');
|
||||
$(window).off('.off-canvas');
|
||||
var edge = document.documentElement.dir === 'rtl' ? 'left' : 'right';
|
||||
var $mainCanvasWrapper = $('[data-off-canvas-main-canvas]');
|
||||
$mainCanvasWrapper.css('padding-' + edge, 0);
|
||||
|
||||
// Resize tabs when closing off-canvas system tray.
|
||||
$(window).trigger('resize.tabs');
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/15763909/jquery-ui-dialog-check-if-exists-by-instance-method
|
||||
if ($(response.selector).hasClass('ui-dialog-content')) {
|
||||
this.closeDialog(ajax, response, status);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Triggers audio UAs to read the supplied text.
|
||||
*
|
||||
* @param {Drupal.Ajax} [ajax]
|
||||
* A {@link Drupal.ajax} object.
|
||||
* @param {object} response
|
||||
* Ajax response.
|
||||
* @param {string} response.text
|
||||
* A string to be read by the UA.
|
||||
* @param {string} [response.priority='polite']
|
||||
* A string to indicate the priority of the message. Can be either
|
||||
* 'polite' or 'assertive'.
|
||||
*
|
||||
* @see Drupal.announce
|
||||
*/
|
||||
Drupal.AjaxCommands.prototype.webformAnnounce = function (ajax, response) {
|
||||
// Delay the announcement.
|
||||
setTimeout(function () {Drupal.announce(response.text, response.priority);}, 200);
|
||||
};
|
||||
|
||||
/** ********************************************************************** **/
|
||||
// Helper functions.
|
||||
/** ********************************************************************** **/
|
||||
|
||||
/**
|
||||
* Determine if element is visible in the viewport.
|
||||
*
|
||||
* @param {Element} element
|
||||
* An element.
|
||||
*
|
||||
* @return {boolean}
|
||||
* TRUE if element is visible in the viewport.
|
||||
*
|
||||
* @see https://stackoverflow.com/questions/487073/check-if-element-is-visible-after-scrolling
|
||||
*/
|
||||
function isScrolledIntoView(element) {
|
||||
var docViewTop = $(window).scrollTop();
|
||||
var docViewBottom = docViewTop + $(window).height();
|
||||
|
||||
var elemTop = $(element).offset().top;
|
||||
var elemBottom = elemTop + $(element).height();
|
||||
|
||||
return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
|
||||
}
|
||||
|
||||
})(jQuery, Drupal);
|
33
2017/web/modules/contrib/webform/js/webform.announce.js
Normal file
33
2017/web/modules/contrib/webform/js/webform.announce.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for announcing changes.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Provide Webform announce attribute behavior.
|
||||
*
|
||||
* Announces changes using [data-webform-announce] attribute.
|
||||
*
|
||||
* The announce attributes allows FAPI Ajax callbacks to easily
|
||||
* trigger announcements.
|
||||
*
|
||||
* @see \Drupal\webform\Element\WebformComputedBase::ajaxWebformComputedCallback
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the behavior to [data-webform-announce] attribute.
|
||||
*/
|
||||
Drupal.behaviors.webformAnnounce = {
|
||||
attach: function (context) {
|
||||
$('[data-webform-announce]', context).once('data-webform-announce').each(function () {
|
||||
Drupal.announce($(this).data('webform-announce'));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
8
2017/web/modules/contrib/webform/js/webform.assets.js
Normal file
8
2017/web/modules/contrib/webform/js/webform.assets.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
/**
|
||||
* @file
|
||||
* This an empty placeholder file that is replaced with custom JavaScript.
|
||||
*
|
||||
* @see webform_js_alter()
|
||||
* @see _webform_asset_alter()
|
||||
* @see \Drupal\webform\WebformSubmissionForm::form
|
||||
*/
|
44
2017/web/modules/contrib/webform/js/webform.block.js
Normal file
44
2017/web/modules/contrib/webform/js/webform.block.js
Normal file
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* @file
|
||||
* Webform block behaviors.
|
||||
*/
|
||||
|
||||
(function ($, window, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Provide the summary information for the block settings vertical tabs.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the behavior for the block settings summaries.
|
||||
*/
|
||||
Drupal.behaviors.webformBlockSettingsSummary = {
|
||||
attach: function () {
|
||||
// The drupalSetSummary method required for this behavior is not available
|
||||
// on the Blocks administration page, so we need to make sure this
|
||||
// behavior is processed only if drupalSetSummary is defined.
|
||||
if (typeof $.fn.drupalSetSummary === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a summary for selected in the provided context.
|
||||
*
|
||||
* @param {HTMLDocument|HTMLElement} context
|
||||
* A context where one would find selected to summarize.
|
||||
*
|
||||
* @return {string}
|
||||
* A string with the summary.
|
||||
*/
|
||||
function selectSummary(context) {
|
||||
return $(context).find('#edit-visibility-webform-webforms option:selected').map(function () { return this.text; }).get().join(', ') || Drupal.t('Not restricted');
|
||||
}
|
||||
|
||||
$('[data-drupal-selector="edit-visibility-webform"]').drupalSetSummary(selectSummary);
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, window, Drupal);
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for confirmation modal.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// @see http://api.jqueryui.com/dialog/
|
||||
Drupal.webform = Drupal.webform || {};
|
||||
Drupal.webform.confirmationModal = Drupal.webform.confirmationModal || {};
|
||||
Drupal.webform.confirmationModal.options = Drupal.webform.confirmationModal.options || {};
|
||||
|
||||
/**
|
||||
* Display confirmation message in a modal.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformConfirmationModal = {
|
||||
attach: function (context) {
|
||||
$('.js-webform-confirmation-modal', context).once('webform-confirmation-modal').each(function () {
|
||||
var $element = $(this);
|
||||
|
||||
var $dialog = $element.find('.webform-confirmation-modal--content');
|
||||
|
||||
var options = {
|
||||
dialogClass: 'webform-confirmation-modal',
|
||||
minWidth: 600,
|
||||
resizable: false,
|
||||
title: $element.find('.webform-confirmation-modal--title').text(),
|
||||
close: function (event) {
|
||||
Drupal.dialog(event.target).close();
|
||||
Drupal.detachBehaviors(event.target, null, 'unload');
|
||||
$(event.target).remove();
|
||||
}
|
||||
};
|
||||
|
||||
options = $.extend(options, Drupal.webform.confirmationModal.options);
|
||||
|
||||
var dialog = Drupal.dialog($dialog, options);
|
||||
|
||||
// Use setTimeout to prevent dialog.position.js
|
||||
// Uncaught TypeError: Cannot read property 'settings' of undefined
|
||||
setTimeout(function () {dialog.showModal();}, 1);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
25
2017/web/modules/contrib/webform/js/webform.contextual.js
Normal file
25
2017/web/modules/contrib/webform/js/webform.contextual.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behavior to remove destination from contextual links.
|
||||
*/
|
||||
|
||||
(function ($) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// Bind click event to all .contextual links which are
|
||||
// dynamically inserted via Ajax.
|
||||
// @see webform_contextual_links_view_alter()
|
||||
// @see Drupal.behaviors.contextual
|
||||
$(document).on('click', '.contextual', function () {
|
||||
$(this).find('a.webform-contextual').once('webform-contextual').each(function () {
|
||||
this.href = this.href.split('?')[0];
|
||||
|
||||
// Add ?_webform_test={webform} to the current page's URL.
|
||||
if (/webform\/([^/]+)\/test/.test(this.href)) {
|
||||
this.href = window.location.pathname + '?_webform_test=' + RegExp.$1;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
})(jQuery);
|
75
2017/web/modules/contrib/webform/js/webform.dialog.js
Normal file
75
2017/web/modules/contrib/webform/js/webform.dialog.js
Normal file
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for webform dialogs.
|
||||
*/
|
||||
|
||||
(function ($, Drupal, drupalSettings) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// @see http://api.jqueryui.com/dialog/
|
||||
Drupal.webform = Drupal.webform || {};
|
||||
Drupal.webform.dialog = Drupal.webform.dialog || {};
|
||||
Drupal.webform.dialog.options = Drupal.webform.dialog.options || {};
|
||||
|
||||
/**
|
||||
* Open webform dialog using preset options.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformDialog = {
|
||||
attach: function (context) {
|
||||
$('a.webform-dialog', context).once('webform-dialog').each(function () {
|
||||
var $a = $(this);
|
||||
|
||||
// Get default options.
|
||||
var options = $.extend({}, Drupal.webform.dialog.options);
|
||||
|
||||
// Get preset dialog options.
|
||||
if ($a.attr('class').match(/webform-dialog-([a-z0-9_]+)/)) {
|
||||
var dialogOptionsName = RegExp.$1;
|
||||
if (drupalSettings.webform.dialog.options[dialogOptionsName]) {
|
||||
options = drupalSettings.webform.dialog.options[dialogOptionsName];
|
||||
|
||||
// Unset title.
|
||||
delete options.title;
|
||||
}
|
||||
}
|
||||
|
||||
// Get custom dialog options.
|
||||
if ($(this).data('dialog-options')) {
|
||||
$.extend(options, $(this).data('dialog-options'));
|
||||
}
|
||||
|
||||
var href = $a.attr('href');
|
||||
|
||||
// Replace ENTITY_TYPE and ENTITY_ID placeholders and update the href.
|
||||
// @see webform_page_attachments()
|
||||
if (href.indexOf('?source_entity_type=ENTITY_TYPE&source_entity_id=ENTITY_ID') !== -1) {
|
||||
if (drupalSettings.webform.dialog.entity_type && drupalSettings.webform.dialog.entity_id) {
|
||||
href = href.replace('ENTITY_TYPE', encodeURIComponent(drupalSettings.webform.dialog.entity_type));
|
||||
href = href.replace('ENTITY_ID', encodeURIComponent(drupalSettings.webform.dialog.entity_id));
|
||||
}
|
||||
else {
|
||||
href = href.replace('?source_entity_type=ENTITY_TYPE&source_entity_id=ENTITY_ID', '');
|
||||
}
|
||||
$a.attr('href', href);
|
||||
}
|
||||
|
||||
// Append _webform_dialog=1 to href to trigger Ajax support.
|
||||
// @see \Drupal\webform\WebformSubmissionForm::setEntity
|
||||
href += (href.indexOf('?') === -1 ? '?' : '&') + '_webform_dialog=1';
|
||||
|
||||
var element_settings = {};
|
||||
element_settings.progress = {type: 'fullscreen'};
|
||||
element_settings.url = href;
|
||||
element_settings.event = 'click';
|
||||
element_settings.dialogType = $a.data('dialog-type') || 'modal';
|
||||
element_settings.dialog = options;
|
||||
element_settings.element = this;
|
||||
Drupal.ajax(element_settings);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal, drupalSettings);
|
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for jQuery UI buttons (checkboxradio) element integration.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
Drupal.webform = Drupal.webform || {};
|
||||
Drupal.webform.buttons = Drupal.webform.buttons || {};
|
||||
Drupal.webform.buttons.selector = Drupal.webform.buttons.selector || [
|
||||
// Applies to Classy, Bartik, and Seven themes.
|
||||
'.js-webform-buttons .form-radios',
|
||||
// Applies to Stable and Bootstrap themes.
|
||||
'.js-webform-buttons .js-form-type-radio'
|
||||
].join(',');
|
||||
|
||||
/**
|
||||
* Create jQuery UI buttons element.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformButtons = {
|
||||
attach: function (context) {
|
||||
$(context).find(Drupal.webform.buttons.selector).once('webform-buttons').each(function () {
|
||||
var $buttons = $(this);
|
||||
|
||||
// Remove classes around radios and labels and move to main element.
|
||||
$buttons.find('input[type="radio"], label').each(function () {
|
||||
$buttons.append($(this).removeAttr('class'));
|
||||
});
|
||||
|
||||
// Remove all empty div wrappers.
|
||||
$buttons.find('div').remove();
|
||||
|
||||
// Must reset $buttons since the contents have changed.
|
||||
$buttons = $(this);
|
||||
|
||||
// Get radios.
|
||||
var $input = $buttons.find('input[type="radio"]');
|
||||
|
||||
// Create checkboxradio.
|
||||
$input.checkboxradio({icon: false});
|
||||
|
||||
// Disable checkboxradio.
|
||||
$input.checkboxradio('option', 'disabled', $input.is(':disabled'));
|
||||
|
||||
// Turn checkboxradio off/on when the input is disabled/enabled.
|
||||
// @see webform.states.js
|
||||
$input.on('webform:disabled', function () {
|
||||
$input.checkboxradio('option', 'disabled', $input.is(':disabled'));
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
|
@ -0,0 +1,76 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for Chosen integration.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// @see https://harvesthq.github.io/chosen/options.html
|
||||
Drupal.webform = Drupal.webform || {};
|
||||
Drupal.webform.chosen = Drupal.webform.chosen || {};
|
||||
Drupal.webform.chosen.options = Drupal.webform.chosen.options || {};
|
||||
|
||||
/**
|
||||
* Initialize Chosen support.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformChosen = {
|
||||
attach: function (context) {
|
||||
if (!$.fn.chosen) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add HTML5 required attribute support.
|
||||
// Checking for $oldChosen to prevent duplicate workarounds from
|
||||
// being applied.
|
||||
// @see https://github.com/harvesthq/chosen/issues/515
|
||||
if (!$.fn.oldChosen) {
|
||||
$.fn.oldChosen = $.fn.chosen;
|
||||
$.fn.chosen = function (options) {
|
||||
var select = $(this);
|
||||
var is_creating_chosen = !!options;
|
||||
if (is_creating_chosen && select.css('position') === 'absolute') {
|
||||
select.removeAttr('style');
|
||||
}
|
||||
var ret = select.oldChosen(options);
|
||||
if (is_creating_chosen && select.css('display') === 'none') {
|
||||
select.attr('style', 'display:visible; position:absolute; width:0px; height: 0px; clip:rect(0,0,0,0)');
|
||||
select.attr('tabindex', -1);
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
}
|
||||
|
||||
$(context)
|
||||
.find('select.js-webform-chosen, .js-webform-chosen select')
|
||||
.once('webform-chosen')
|
||||
.each(function () {
|
||||
var $select = $(this);
|
||||
// Check for .chosen-enable to prevent the chosen.module and
|
||||
// webform.module from both initializing the chosen select element.
|
||||
if ($select.hasClass('chosen-enable')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var options = $.extend({width: '100%'}, Drupal.webform.chosen.options);
|
||||
if ($select.data('placeholder')) {
|
||||
if ($select.prop('multiple')) {
|
||||
options.placeholder_text_multiple = $select.data('placeholder');
|
||||
}
|
||||
else {
|
||||
// Clear option value so that placeholder is displayed.
|
||||
$select.find('option[value=""]').html('');
|
||||
// Allow single option to be deselected.
|
||||
options.allow_single_deselect = true;
|
||||
}
|
||||
}
|
||||
|
||||
$select.chosen(options);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
|
@ -0,0 +1,122 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for CodeMirror integration.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// @see http://codemirror.net/doc/manual.html#config
|
||||
Drupal.webform = Drupal.webform || {};
|
||||
Drupal.webform.codeMirror = Drupal.webform.codeMirror || {};
|
||||
Drupal.webform.codeMirror.options = Drupal.webform.codeMirror.options || {};
|
||||
|
||||
/**
|
||||
* Initialize CodeMirror editor.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformCodeMirror = {
|
||||
attach: function (context) {
|
||||
if (!window.CodeMirror) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Webform CodeMirror editor.
|
||||
$(context).find('textarea.js-webform-codemirror').once('webform-codemirror').each(function () {
|
||||
var $input = $(this);
|
||||
|
||||
// Open all closed details, so that editor height is correctly calculated.
|
||||
var $details = $(this).parents('details:not([open])');
|
||||
$details.attr('open', 'open');
|
||||
|
||||
// #59 HTML5 required attribute breaks hack for webform submission.
|
||||
// https://github.com/marijnh/CodeMirror-old/issues/59
|
||||
$(this).removeAttr('required');
|
||||
|
||||
var options = $.extend({
|
||||
mode: $(this).attr('data-webform-codemirror-mode'),
|
||||
lineNumbers: true,
|
||||
c: ($(this).attr('wrap') === 'off') ? false : true,
|
||||
viewportMargin: Infinity,
|
||||
readOnly: ($(this).prop('readonly') || $(this).prop('disabled')) ? true : false,
|
||||
extraKeys: {
|
||||
// Setting for using spaces instead of tabs - https://github.com/codemirror/CodeMirror/issues/988
|
||||
Tab: function (cm) {
|
||||
var spaces = Array(cm.getOption('indentUnit') + 1).join(' ');
|
||||
cm.replaceSelection(spaces, 'end', '+element');
|
||||
},
|
||||
// On 'Escape' move to the next tabbable input.
|
||||
// @see http://bgrins.github.io/codemirror-accessible/
|
||||
Esc: function (cm) {
|
||||
// Must show and then textarea so that we can determine
|
||||
// its tabindex.
|
||||
var textarea = $(cm.getTextArea());
|
||||
$(textarea).show().addClass('visually-hidden');
|
||||
var $tabbable = $(':tabbable');
|
||||
var tabindex = $tabbable.index(textarea);
|
||||
$(textarea).hide().removeClass('visually-hidden');
|
||||
|
||||
// Tabindex + 2 accounts for the CodeMirror's iframe.
|
||||
$tabbable.eq(tabindex + 2).focus();
|
||||
}
|
||||
|
||||
}
|
||||
}, Drupal.webform.codeMirror.options);
|
||||
|
||||
var editor = CodeMirror.fromTextArea(this, options);
|
||||
|
||||
// Now, close details.
|
||||
$details.removeAttr('open');
|
||||
|
||||
// Issue #2764443: CodeMirror is not setting submitted value when
|
||||
// rendered within a webform UI dialog.
|
||||
editor.on('blur', function (event) {
|
||||
editor.save();
|
||||
});
|
||||
|
||||
// Update CodeMirror when the textarea's value has changed.
|
||||
// @see webform.states.js
|
||||
$input.on('change', function () {
|
||||
editor.getDoc().setValue($input.val());
|
||||
});
|
||||
|
||||
// Set CodeMirror to be readonly when the textarea is disabled.
|
||||
// @see webform.states.js
|
||||
$input.on('webform:disabled', function () {
|
||||
editor.setOption('readOnly', $input.is(':disabled'));
|
||||
});
|
||||
|
||||
// Delay refreshing CodeMirror for 10 millisecond while the dialog is
|
||||
// still being rendered.
|
||||
// @see http://stackoverflow.com/questions/8349571/codemirror-editor-is-not-loading-content-until-clicked
|
||||
setTimeout(function () {
|
||||
// Show tab panel and open details.
|
||||
var $tabPanel = $input.parents('.ui-tabs-panel:hidden');
|
||||
var $details = $input.parents('details:not([open])');
|
||||
|
||||
if (!$tabPanel.length && $details.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
$tabPanel.show();
|
||||
$details.attr('open', 'open');
|
||||
|
||||
editor.refresh();
|
||||
|
||||
// Hide tab panel and close details.
|
||||
$tabPanel.hide();
|
||||
$details.removeAttr('open');
|
||||
}, 10);
|
||||
});
|
||||
|
||||
// Webform CodeMirror syntax coloring.
|
||||
$(context).find('.js-webform-codemirror-runmode').once('webform-codemirror-runmode').each(function () {
|
||||
// Mode Runner - http://codemirror.net/demo/runmode.html
|
||||
CodeMirror.runMode($(this).addClass('cm-s-default').text(), $(this).attr('data-webform-codemirror-mode'), this);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
56
2017/web/modules/contrib/webform/js/webform.element.color.js
Normal file
56
2017/web/modules/contrib/webform/js/webform.element.color.js
Normal file
|
@ -0,0 +1,56 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for color element integration.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Enhance HTML5 color element.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformColor = {
|
||||
attach: function (context) {
|
||||
$(context).find('.form-color:not(.form-color-output)').once('webform-color').each(function () {
|
||||
var $element = $(this);
|
||||
// Handle browser that don't support the HTML5 color input.
|
||||
if (Modernizr.inputtypes.color === false) {
|
||||
// Remove swatch sizes.
|
||||
$element.removeClass('form-color-small')
|
||||
.removeClass('form-color-medium')
|
||||
.removeClass('form-color-large');
|
||||
}
|
||||
else {
|
||||
// Display color input's output w/ visually-hidden label to
|
||||
// the end user.
|
||||
var $output = $('<input class="form-color-output ' + $element.attr('class') + ' js-webform-input-mask" data-inputmask-mask="\\#######" />').uniqueId();
|
||||
var $label = $element.parent('.js-form-type-color').find('label').clone();
|
||||
$label.attr({
|
||||
for: $output.attr('id'),
|
||||
class: 'visually-hidden'
|
||||
});
|
||||
if ($.fn.inputmask) {
|
||||
$output.inputmask();
|
||||
}
|
||||
$output[0].value = $element[0].value;
|
||||
$element
|
||||
.after($output)
|
||||
.after($label)
|
||||
.css({float: 'left'});
|
||||
|
||||
// Sync $element and $output.
|
||||
$element.on('input', function () {
|
||||
$output[0].value = $element[0].value;
|
||||
});
|
||||
$output.on('input', function () {
|
||||
$element[0].value = $output[0].value;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for composite element builder.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Initialize composite element builder.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformElementComposite = {
|
||||
attach: function (context) {
|
||||
$('[data-composite-types]').once('webform-composite-types').each(function () {
|
||||
var $element = $(this);
|
||||
var $type = $element.closest('tr').find('.js-webform-composite-type');
|
||||
|
||||
var types = $element.attr('data-composite-types').split(',');
|
||||
var required = $element.attr('data-composite-required');
|
||||
|
||||
$type.on('change', function () {
|
||||
if ($.inArray($(this).val(), types) === -1) {
|
||||
$element.hide();
|
||||
if (required) {
|
||||
$element.removeAttr('required aria-required');
|
||||
}
|
||||
}
|
||||
else {
|
||||
$element.show();
|
||||
if (required) {
|
||||
$element.attr({'required': 'required', 'aria-required': 'true'});
|
||||
}
|
||||
}
|
||||
}).change();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
|
@ -0,0 +1,74 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for computed elements.
|
||||
*/
|
||||
|
||||
(function ($, Drupal, debounce) {
|
||||
|
||||
'use strict';
|
||||
|
||||
Drupal.webform = Drupal.webform || {};
|
||||
Drupal.webform.computed = Drupal.webform.computed || {};
|
||||
Drupal.webform.computed.delay = Drupal.webform.computed.delay || 500;
|
||||
|
||||
/**
|
||||
* Initialize computed elements.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformComputed = {
|
||||
attach: function (context) {
|
||||
$(context).find('.js-webform-computed').once('webform-computed').each(function () {
|
||||
// Get computed element and parent form.
|
||||
var $element = $(this);
|
||||
var $form = $element.closest('form');
|
||||
|
||||
// Get elements that are used by the computed element.
|
||||
var elementKeys = $(this).data('webform-element-keys').split(',');
|
||||
if (!elementKeys) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get computed element triggers.
|
||||
var inputs = [];
|
||||
$.each(elementKeys, function (i, key) {
|
||||
// Exact input match.
|
||||
inputs.push(':input[name="' + key + '"]');
|
||||
// Sub inputs. (aka #tree)
|
||||
inputs.push(':input[name^="' + key + '["]');
|
||||
});
|
||||
var $triggers = $form.find(inputs.join(','));
|
||||
|
||||
// Add event handler to computed element triggers.
|
||||
$triggers.on('keyup change',
|
||||
debounce(triggerUpdate, Drupal.webform.computed.delay));
|
||||
|
||||
// Initialize computed element update which refreshes the displayed
|
||||
// value and accounts for any changes to the #default_value for a
|
||||
// computed element.
|
||||
triggerUpdate(true);
|
||||
|
||||
function triggerUpdate(initialize) {
|
||||
// Prevent duplicate computations.
|
||||
// @see Drupal.behaviors.formSingleSubmit
|
||||
if (initialize !== true) {
|
||||
var formValues = $triggers.serialize();
|
||||
var previousValues = $element.attr('data-webform-computed-last');
|
||||
if (previousValues === formValues) {
|
||||
return;
|
||||
}
|
||||
$element.attr('data-webform-computed-last', formValues);
|
||||
}
|
||||
|
||||
// Add loading class to computed wrapper.
|
||||
$element.find('.js-webform-computed-wrapper')
|
||||
.addClass('webform-computed-loading');
|
||||
|
||||
// Trigger computation.
|
||||
$element.find('.js-form-submit').mousedown();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal, Drupal.debounce);
|
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for jQuery Text Counter integration.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// @see https://github.com/ractoon/jQuery-Text-Counter#options
|
||||
Drupal.webform = Drupal.webform || {};
|
||||
Drupal.webform.counter = Drupal.webform.counter || {};
|
||||
Drupal.webform.counter.options = Drupal.webform.counter.options || {};
|
||||
|
||||
/**
|
||||
* Initialize text field and textarea word and character counter.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformCounter = {
|
||||
attach: function (context) {
|
||||
if (!$.fn.textcounter) {
|
||||
return;
|
||||
}
|
||||
|
||||
$(context).find('.js-webform-counter').once('webform-counter').each(function () {
|
||||
var options = {
|
||||
type: $(this).data('counter-type'),
|
||||
max: $(this).data('counter-maximum'),
|
||||
min: $(this).data('counter-minimum') || 0,
|
||||
counterText: $(this).data('counter-minimum-message'),
|
||||
countDownText: $(this).data('counter-maximum-message'),
|
||||
inputErrorClass: 'webform-counter-warning',
|
||||
counterErrorClass: 'webform-counter-warning',
|
||||
countSpaces: true,
|
||||
stopInputAtMaximum: false,
|
||||
// Don't display min/max message since server-side validation will
|
||||
// display these messages.
|
||||
minimumErrorText: '',
|
||||
maximumErrorText: ''
|
||||
};
|
||||
|
||||
options.countDown = (options.max) ? true : false;
|
||||
if (!options.counterText) {
|
||||
options.counterText = (options.type === 'word') ? Drupal.t('%d word(s) entered') : Drupal.t('%d characters(s) entered');
|
||||
}
|
||||
if (!options.countDownText) {
|
||||
options.countDownText = (options.type === 'word') ? Drupal.t('%d word(s) remaining') : Drupal.t('%d characters(s) remaining');
|
||||
}
|
||||
|
||||
options = $.extend(options, Drupal.webform.counter.options);
|
||||
|
||||
$(this).textcounter(options);
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
111
2017/web/modules/contrib/webform/js/webform.element.date.js
Normal file
111
2017/web/modules/contrib/webform/js/webform.element.date.js
Normal file
|
@ -0,0 +1,111 @@
|
|||
/**
|
||||
* @file
|
||||
* Override polyfill for HTML5 date input and provide support for custom date formats.
|
||||
*/
|
||||
|
||||
(function ($, Modernizr, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// @see http://api.jqueryui.com/datepicker/
|
||||
Drupal.webform = Drupal.webform || {};
|
||||
Drupal.webform.datePicker = Drupal.webform.datePicker || {};
|
||||
Drupal.webform.datePicker.options = Drupal.webform.datePicker.options || {};
|
||||
|
||||
/**
|
||||
* Attach datepicker fallback on date elements.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the behavior. Accepts in `settings.date` an object listing
|
||||
* elements to process, keyed by the HTML ID of the form element containing
|
||||
* the human-readable value. Each element is an datepicker settings object.
|
||||
* @prop {Drupal~behaviorDetach} detach
|
||||
* Detach the behavior destroying datepickers on effected elements.
|
||||
*/
|
||||
Drupal.behaviors.date = {
|
||||
attach: function (context, settings) {
|
||||
var $context = $(context);
|
||||
$context.find('input[data-drupal-date-format]').once('datePicker').each(function () {
|
||||
var $input = $(this);
|
||||
|
||||
// Skip if date inputs are supported by the browser and input is not a text field.
|
||||
// @see \Drupal\webform\Element\WebformDatetime
|
||||
if (window.Modernizr && Modernizr.inputtypes.date === true && $input.attr('type') !== 'text') {
|
||||
return;
|
||||
}
|
||||
|
||||
var options = $.extend({
|
||||
changeMonth: true,
|
||||
changeYear: true
|
||||
}, Drupal.webform.datePicker.options);
|
||||
|
||||
// Add datepicker button.
|
||||
if ($input.hasData('datepicker-button')) {
|
||||
options = $.extend({
|
||||
showOn: 'both',
|
||||
buttonImage: settings.webform.datePicker.buttonImage,
|
||||
buttonImageOnly: true,
|
||||
buttonText: Drupal.t('Select date')
|
||||
}, Drupal.webform.datePicker.options);
|
||||
}
|
||||
|
||||
var dateFormat = $input.data('drupalDateFormat');
|
||||
|
||||
// The date format is saved in PHP style, we need to convert to jQuery
|
||||
// datepicker.
|
||||
// @see http://stackoverflow.com/questions/16702398/convert-a-php-date-format-to-a-jqueryui-datepicker-date-format
|
||||
// @see http://php.net/manual/en/function.date.php
|
||||
options.dateFormat = dateFormat
|
||||
// Year.
|
||||
.replace('Y', 'yy') // A full numeric representation of a year, 4 digits (1999 or 2003)
|
||||
.replace('y', 'y') // A two digit representation of a year (99 or 03)
|
||||
// Month.
|
||||
.replace('F', 'MM') // A full textual representation of a month, such as January or March (January through December)
|
||||
.replace('m', 'mm') // Numeric representation of a month, with leading zeros (01 through 12)
|
||||
.replace('M', 'M') // A short textual representation of a month, three letters (Jan through Dec)
|
||||
.replace('n', 'm') // Numeric representation of a month, without leading zeros (1 through 12)
|
||||
// Day.
|
||||
.replace('d', 'dd') // Day of the month, 2 digits with leading zeros (01 to 31)
|
||||
.replace('D', 'D') // A textual representation of a day, three letters (Mon through Sun)
|
||||
.replace('j', 'd') // Day of the month without leading zeros (1 to 31)
|
||||
.replace('l', 'DD'); // A full textual representation of the day of the week (Sunday through Saturday)
|
||||
|
||||
// Add min and max date if set on the input.
|
||||
if ($input.attr('min')) {
|
||||
options.minDate = $input.attr('min');
|
||||
}
|
||||
if ($input.attr('max')) {
|
||||
options.maxDate = $input.attr('max');
|
||||
}
|
||||
|
||||
// Add min/max year to data range.
|
||||
if (!options.yearRange && $input.data('min-year') && $input.data('max-year')) {
|
||||
options.yearRange = $input.data('min-year') + ':' + $input.attr('data-max-year');
|
||||
}
|
||||
|
||||
// First day of the week.
|
||||
options.firstDay = settings.webform.dateFirstDay;
|
||||
|
||||
// Disable autocomplete.
|
||||
// @see https://gist.github.com/niksumeiko/360164708c3b326bd1c8
|
||||
var isChrome = /Chrome/.test(window.navigator.userAgent) && /Google Inc/.test(window.navigator.vendor);
|
||||
$input.attr('autocomplete', (isChrome) ? 'off' : 'false');
|
||||
|
||||
$input.datepicker(options);
|
||||
});
|
||||
}
|
||||
// Issue #2983363: Datepicker is being detached when multiple files are
|
||||
// uploaded.
|
||||
/*
|
||||
},
|
||||
detach: function (context, settings, trigger) {
|
||||
if (trigger === 'unload') {
|
||||
$(context).find('input[data-drupal-date-format]').findOnce('datePicker').datepicker('destroy');
|
||||
}
|
||||
}
|
||||
*/
|
||||
};
|
||||
|
||||
})(jQuery, Modernizr, Drupal);
|
|
@ -0,0 +1,108 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for details element.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Attach handler to save details open/close state.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformDetailsSave = {
|
||||
attach: function (context) {
|
||||
if (!window.localStorage) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Summary click event handler.
|
||||
$('details > summary', context).once('webform-details-summary-save').click(function () {
|
||||
var $details = $(this).parent();
|
||||
|
||||
|
||||
// @see https://css-tricks.com/snippets/jquery/make-an-jquery-hasattr/
|
||||
if ($details[0].hasAttribute('data-webform-details-nosave')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var name = Drupal.webformDetailsSaveGetName($details);
|
||||
if (!name) {
|
||||
return;
|
||||
}
|
||||
|
||||
var open = ($details.attr('open') !== 'open') ? '1' : '0';
|
||||
localStorage.setItem(name, open);
|
||||
});
|
||||
|
||||
// Initialize details open state via local storage.
|
||||
$('details', context).once('webform-details-save').each(function () {
|
||||
var $details = $(this);
|
||||
|
||||
var name = Drupal.webformDetailsSaveGetName($details);
|
||||
if (!name) {
|
||||
return;
|
||||
}
|
||||
|
||||
var open = localStorage.getItem(name);
|
||||
if (open === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (open === '1') {
|
||||
$details.attr('open', 'open');
|
||||
}
|
||||
else {
|
||||
$details.removeAttr('open');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the name used to store the state of details element.
|
||||
*
|
||||
* @param {jQuery} $details
|
||||
* A details element.
|
||||
*
|
||||
* @return {string}
|
||||
* The name used to store the state of details element.
|
||||
*/
|
||||
Drupal.webformDetailsSaveGetName = function ($details) {
|
||||
if (!window.localStorage) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Any details element not included a webform must have define its own id.
|
||||
var webformId = $details.attr('data-webform-element-id');
|
||||
if (webformId) {
|
||||
return 'Drupal.webform.' + webformId.replace('--', '.');
|
||||
}
|
||||
|
||||
var detailsId = $details.attr('id');
|
||||
if (!detailsId) {
|
||||
return '';
|
||||
}
|
||||
|
||||
var $form = $details.parents('form');
|
||||
if (!$form.length || !$form.attr('id')) {
|
||||
return '';
|
||||
}
|
||||
|
||||
var formId = $form.attr('id');
|
||||
if (!formId) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// ISSUE: When Drupal renders a webform in a modal dialog it appends a unique
|
||||
// identifier to webform ids and details ids. (i.e. my-form--FeSFISegTUI)
|
||||
// WORKAROUND: Remove the unique id that delimited using double dashes.
|
||||
formId = formId.replace(/--.+?$/, '').replace(/-/g, '_');
|
||||
detailsId = detailsId.replace(/--.+?$/, '').replace(/-/g, '_');
|
||||
return 'Drupal.webform.' + formId + '.' + detailsId;
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
|
@ -0,0 +1,114 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for details element.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
Drupal.webform = Drupal.webform || {};
|
||||
Drupal.webform.detailsToggle = Drupal.webform.detailsToggle || {};
|
||||
Drupal.webform.detailsToggle.options = Drupal.webform.detailsToggle.options || {};
|
||||
|
||||
/**
|
||||
* Attach handler to toggle details open/close state.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformDetailsToggle = {
|
||||
attach: function (context) {
|
||||
$('.js-webform-details-toggle', context).once('webform-details-toggle').each(function () {
|
||||
var $form = $(this);
|
||||
var $tabs = $form.find('.webform-tabs');
|
||||
|
||||
// Get only the main details elements and ignore all nested details.
|
||||
var selector = ($tabs.length) ? '.webform-tab' : '.js-webform-details-toggle';
|
||||
var $details = $form.find('details').filter(function () {
|
||||
// @todo Figure out how to optimize the below code.
|
||||
var $parents = $(this).parentsUntil(selector);
|
||||
return ($parents.find('details').length === 0);
|
||||
});
|
||||
|
||||
// Toggle is only useful when there are two or more details elements.
|
||||
if ($details.length < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
var options = $.extend({
|
||||
button: '<button type="button" class="webform-details-toggle-state"></button>'
|
||||
}, Drupal.webform.detailsToggle.options);
|
||||
|
||||
// Create toggle buttons.
|
||||
var $toggle = $(options.button)
|
||||
.attr('title', Drupal.t('Toggle details widget state.'))
|
||||
.on('click', function (e) {
|
||||
var open;
|
||||
if (isFormDetailsOpen($form)) {
|
||||
$form.find('details').removeAttr('open');
|
||||
open = 0;
|
||||
}
|
||||
else {
|
||||
$form.find('details').attr('open', 'open');
|
||||
open = 1;
|
||||
}
|
||||
setDetailsToggleLabel($form);
|
||||
|
||||
// Set the saved states for all the details elements.
|
||||
// @see webform.element.details.save.js
|
||||
if (Drupal.webformDetailsSaveGetName) {
|
||||
$form.find('details').each(function () {
|
||||
var name = Drupal.webformDetailsSaveGetName($(this));
|
||||
if (name) {
|
||||
localStorage.setItem(name, open);
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
.wrap('<div class="webform-details-toggle-state-wrapper"></div>')
|
||||
.parent();
|
||||
|
||||
if ($tabs.length) {
|
||||
// Add toggle state before the tabs.
|
||||
$tabs.find('.item-list:first-child').eq(0).before($toggle);
|
||||
}
|
||||
else {
|
||||
// Add toggle state link to first details element.
|
||||
$details.eq(0).before($toggle);
|
||||
}
|
||||
|
||||
setDetailsToggleLabel($form);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine if a webform's details are all opened.
|
||||
*
|
||||
* @param {jQuery} $form
|
||||
* A webform.
|
||||
*
|
||||
* @return {boolean}
|
||||
* TRUE if a webform's details are all opened.
|
||||
*/
|
||||
function isFormDetailsOpen($form) {
|
||||
return ($form.find('details[open]').length === $form.find('details').length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a webform's details toggle state widget label.
|
||||
*
|
||||
* @param {jQuery} $form
|
||||
* A webform.
|
||||
*/
|
||||
function setDetailsToggleLabel($form) {
|
||||
var isOpen = isFormDetailsOpen($form);
|
||||
|
||||
var label = (isOpen) ? Drupal.t('Collapse all') : Drupal.t('Expand all');
|
||||
$form.find('.webform-details-toggle-state').html(label);
|
||||
|
||||
var text = (isOpen) ? Drupal.t('All details have been expanded.') : Drupal.t('All details have been collapsed.');
|
||||
Drupal.announce(text);
|
||||
}
|
||||
|
||||
})(jQuery, Drupal);
|
73
2017/web/modules/contrib/webform/js/webform.element.help.js
Normal file
73
2017/web/modules/contrib/webform/js/webform.element.help.js
Normal file
|
@ -0,0 +1,73 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for element help text (tooltip).
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// @see http://api.jqueryui.com/tooltip/
|
||||
Drupal.webform = Drupal.webform || {};
|
||||
Drupal.webform.elementHelpIcon = Drupal.webform.elementHelpIcon || {};
|
||||
Drupal.webform.elementHelpIcon.options = Drupal.webform.elementHelpIcon.options || {
|
||||
position: {my: 'left+5 top+5', at: 'left bottom', collision: 'flipfit'},
|
||||
tooltipClass: 'webform-element-help--tooltip',
|
||||
// @see https://stackoverflow.com/questions/18231315/jquery-ui-tooltip-html-with-links
|
||||
show: {delay: 100},
|
||||
close: function (event, ui) {
|
||||
ui.tooltip.hover(
|
||||
function () {
|
||||
$(this).stop(true).fadeTo(400, 1);
|
||||
},
|
||||
function () {
|
||||
$(this).fadeOut('400', function () {
|
||||
$(this).remove();
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Element help icon.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformElementHelpIcon = {
|
||||
attach: function (context) {
|
||||
$(context).find('.webform-element-help').once('webform-element-help').each(function () {
|
||||
var $link = $(this);
|
||||
|
||||
var options = $.extend({
|
||||
// Use 'data-webform-help' attribute which can include HTML markup.
|
||||
content: $link.attr('data-webform-help'),
|
||||
items: '[data-webform-help]'
|
||||
}, Drupal.webform.elementHelpIcon.options);
|
||||
|
||||
$link.tooltip(options)
|
||||
.on('click', function (event) {
|
||||
// Prevent click from toggling <label>s wrapped around help.
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
// Help tooltips are generally placed with <label> tags.
|
||||
// Screen readers are also reading the <label> and the
|
||||
// 'aria-describedby' attribute.
|
||||
// To prevent this issue we are removing the <label>'s 'for' attribute
|
||||
// when the tooltip is focused.
|
||||
var $label = $(this).parent('label');
|
||||
var labelFor = $label.attr('for') || '';
|
||||
if ($label.length && labelFor) {
|
||||
$link
|
||||
.on('focus', function () {
|
||||
$label.removeAttr('for');
|
||||
})
|
||||
.on('blur', function () {
|
||||
$label.attr('for', labelFor);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
|
@ -0,0 +1,137 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for HTML editor integration.
|
||||
*/
|
||||
|
||||
(function ($, Drupal, drupalSettings) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// @see http://docs.ckeditor.com/#!/api/CKEDITOR.config
|
||||
Drupal.webform = Drupal.webform || {};
|
||||
Drupal.webform.htmlEditor = Drupal.webform.htmlEditor || {};
|
||||
Drupal.webform.htmlEditor.options = Drupal.webform.htmlEditor.options || {};
|
||||
|
||||
/**
|
||||
* Initialize HTML Editor.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformHtmlEditor = {
|
||||
attach: function (context) {
|
||||
if (!window.CKEDITOR) {
|
||||
return;
|
||||
}
|
||||
|
||||
$(context).find('textarea.js-html-editor').once('webform-html-editor').each(function () {
|
||||
var $textarea = $(this);
|
||||
|
||||
var allowedContent = drupalSettings['webform']['html_editor']['allowedContent'];
|
||||
|
||||
// Load additional CKEditor plugins used by the Webform HTML editor.
|
||||
// @see \Drupal\webform\Element\WebformHtmlEditor::preRenderWebformHtmlEditor
|
||||
// @see \Drupal\webform\WebformLibrariesManager::initLibraries
|
||||
var plugins = drupalSettings['webform']['html_editor']['plugins'];
|
||||
|
||||
// If requirejs is present don't use the codemirror plugin.
|
||||
// @see Issue #2936147: ckeditor.codemirror plugin breaks admin textarea.
|
||||
// @todo Remove the below code once this issue is resolved.
|
||||
if (plugins.codemirror
|
||||
&& drupalSettings.yamlEditor
|
||||
&& drupalSettings.yamlEditor.source
|
||||
&& drupalSettings.yamlEditor.source.indexOf('noconflict') !== -1) {
|
||||
delete plugins.codemirror;
|
||||
if ('console' in window) {
|
||||
window.console.log('YAML Editor module is not compatible with the ckeditor.codemirror plugin. @see Issue #2936147: ckeditor.codemirror plugin breaks admin textarea.');
|
||||
}
|
||||
}
|
||||
|
||||
for (var plugin_name in plugins) {
|
||||
if (plugins.hasOwnProperty(plugin_name)) {
|
||||
CKEDITOR.plugins.addExternal(plugin_name, plugins[plugin_name]);
|
||||
}
|
||||
}
|
||||
|
||||
var options = {
|
||||
// Turn off external config and styles.
|
||||
customConfig: '',
|
||||
stylesSet: false,
|
||||
contentsCss: [],
|
||||
allowedContent: allowedContent,
|
||||
// Use <br> tags instead of <p> tags.
|
||||
enterMode: CKEDITOR.ENTER_BR,
|
||||
shiftEnterMode: CKEDITOR.ENTER_BR,
|
||||
// Set height.
|
||||
height: '100px',
|
||||
// Remove status bar.
|
||||
resize_enabled: false,
|
||||
removePlugins: 'elementspath,magicline',
|
||||
// Toolbar settings.
|
||||
format_tags: 'p;h2;h3;h4;h5;h6',
|
||||
// extraPlugins
|
||||
extraPlugins: ''
|
||||
};
|
||||
|
||||
// Add toolbar.
|
||||
if (!options.toolbar) {
|
||||
options.toolbar = [];
|
||||
options.toolbar.push({name: 'styles', items: ['Format', 'Font', 'FontSize']});
|
||||
options.toolbar.push({name: 'basicstyles', items: ['Bold', 'Italic', 'Subscript', 'Superscript']});
|
||||
// Add IMCE image button.
|
||||
if (CKEDITOR.plugins.get('imce')) {
|
||||
CKEDITOR.config.ImceImageIcon = drupalSettings['webform']['html_editor']['ImceImageIcon'];
|
||||
options.extraPlugins += (options.extraPlugins ? ',' : '') + 'imce';
|
||||
options.toolbar.push({name: 'insert', items: ['ImceImage', 'SpecialChar']});
|
||||
}
|
||||
else {
|
||||
options.toolbar.push({name: 'insert', items: ['SpecialChar']});
|
||||
}
|
||||
|
||||
// Add link plugin.
|
||||
if (plugins['link']) {
|
||||
options.extraPlugins += (options.extraPlugins ? ',' : '') + 'link';
|
||||
options.toolbar.push({name: 'links', items: ['Link', 'Unlink']});
|
||||
}
|
||||
options.toolbar.push({name: 'colors', items: ['TextColor', 'BGColor']});
|
||||
options.toolbar.push({name: 'paragraph', items: ['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'Blockquote']});
|
||||
options.toolbar.push({name: 'tools', items: ['Source', '-', 'Maximize']});
|
||||
}
|
||||
|
||||
// Add autogrow plugin.
|
||||
if (plugins['autogrow']) {
|
||||
options.extraPlugins += (options.extraPlugins ? ',' : '') + 'autogrow';
|
||||
options.autoGrow_minHeight = 60;
|
||||
options.autoGrow_maxHeight = 300;
|
||||
}
|
||||
|
||||
// Add CodeMirror integration plugin.
|
||||
if (plugins['codemirror']) {
|
||||
options.extraPlugins += (options.extraPlugins ? ',' : '') + 'codemirror';
|
||||
options.codemirror = {
|
||||
mode: 'text/html'
|
||||
};
|
||||
}
|
||||
|
||||
options = $.extend(options, Drupal.webform.htmlEditor.options);
|
||||
|
||||
// Catch and suppress
|
||||
// "Uncaught TypeError: Cannot read property 'getEditor' of undefined".
|
||||
//
|
||||
// Steps to reproduce this error.
|
||||
// - Goto any form elements.
|
||||
// - Edit an element.
|
||||
// - Save the element.
|
||||
try {
|
||||
CKEDITOR.replace(this.id, options).on('change', function (evt) {
|
||||
// Save data onchange since Ajax dialogs don't execute form.onsubmit.
|
||||
$textarea.val(evt.editor.getData().trim());
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
// Do nothing.
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal, drupalSettings);
|
110
2017/web/modules/contrib/webform/js/webform.element.icheck.js
Normal file
110
2017/web/modules/contrib/webform/js/webform.element.icheck.js
Normal file
|
@ -0,0 +1,110 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for iCheck integration.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// @see http://icheck.fronteed.com/#options
|
||||
Drupal.webform = Drupal.webform || {};
|
||||
Drupal.webform.iCheck = Drupal.webform.iCheck || {};
|
||||
Drupal.webform.iCheck.options = Drupal.webform.iCheck.options || {};
|
||||
|
||||
/**
|
||||
* Enhance checkboxes and radios using iCheck.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformICheck = {
|
||||
attach: function (context) {
|
||||
if (!$.fn.iCheck) {
|
||||
return;
|
||||
}
|
||||
$('input[data-webform-icheck]', context).each(function () {
|
||||
var $input = $(this);
|
||||
var icheck = $input.attr('data-webform-icheck');
|
||||
|
||||
var options = $.extend({
|
||||
checkboxClass: 'icheckbox_' + icheck,
|
||||
radioClass: 'iradio_' + icheck
|
||||
}, Drupal.webform.iCheck.options);
|
||||
|
||||
// The line skin requires that the label be added to the options.
|
||||
// @see http://icheck.fronteed.com/#skin-line
|
||||
if (icheck.indexOf('line') === 0) {
|
||||
var $label = $input.parent().find('label[for="' + $input.attr('id') + '"]');
|
||||
|
||||
// Set insert with label text.
|
||||
options.insert = '<div class="icheck_line-icon"></div>' + $label.text();
|
||||
|
||||
// Make sure checkbox is outside the label and then remove the label.
|
||||
$label.insertAfter($input).remove();
|
||||
}
|
||||
|
||||
$input.addClass('js-webform-icheck')
|
||||
.iCheck(options)
|
||||
// @see https://github.com/fronteed/iCheck/issues/244
|
||||
.on('ifChecked', function (e) {
|
||||
$(e.target).attr('checked', 'checked').change();
|
||||
})
|
||||
.on('ifUnchecked', function (e) {
|
||||
$(e.target).removeAttr('checked').change();
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Enhance table select checkall.
|
||||
*
|
||||
* ISSUE: Select all is not sync'd with checkboxes because iCheck overrides all existing event handlers.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformICheckTableSelectAll = {
|
||||
attach: function (context) {
|
||||
if (!$.fn.iCheck) {
|
||||
return;
|
||||
}
|
||||
|
||||
$('table[data-webform-icheck] th.select-all').bind('DOMNodeInserted', function () {
|
||||
$(this).unbind('DOMNodeInserted');
|
||||
$(this).find('input[type="checkbox"]').each(function () {
|
||||
var icheck = $(this).closest('table[data-webform-icheck]').attr('data-webform-icheck');
|
||||
|
||||
var options = $.extend({
|
||||
checkboxClass: 'icheckbox_' + icheck,
|
||||
radioClass: 'iradio_' + icheck
|
||||
}, Drupal.webform.iCheck.options);
|
||||
|
||||
$(this).iCheck(options);
|
||||
})
|
||||
.on('ifChanged', function () {
|
||||
var _index = $(this).parents('th').index() + 1;
|
||||
$(this).parents('thead').next('tbody').find('tr td:nth-child(' + _index + ') input')
|
||||
.iCheck(!$(this).is(':checked') ? 'check' : 'uncheck')
|
||||
.iCheck($(this).is(':checked') ? 'check' : 'uncheck');
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sync iCheck element when checkbox/radio is enabled/disabled via the #states.
|
||||
*
|
||||
* @see core/misc/states.js
|
||||
*/
|
||||
if ($.fn.iCheck) {
|
||||
$(document).on('state:disabled', function (e) {
|
||||
if ($(e.target).hasClass('.js-webform-icheck')) {
|
||||
$(e.target).iCheck(e.value ? 'disable' : 'enable');
|
||||
}
|
||||
|
||||
$(e.target).iCheck(e.value ? 'disable' : 'enable');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
})(jQuery, Drupal);
|
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for webform_image_file modal.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Display webform image file in a modal.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformImageFileModal = {
|
||||
attach: function (context) {
|
||||
$('.js-webform-image-file-modal', context).once('js-webform-image-file-modal').on('click', function () {
|
||||
// http://stackoverflow.com/questions/11442712/get-width-height-of-remote-image-from-url
|
||||
var img = new Image();
|
||||
img.src = $(this).attr('href');
|
||||
img.onload = function () {
|
||||
$('<div><img src="' + this.src + '" style="display: block; margin: 0 auto" /></div>').dialog({
|
||||
dialogClass: 'webform-image-file-modal-dialog',
|
||||
width: this.width + 60,
|
||||
height: this.height + 100,
|
||||
resizable: false,
|
||||
modal: true
|
||||
}).dialog('open');
|
||||
};
|
||||
return false;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for input hiding.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
var isChrome = /Chrome/.test(window.navigator.userAgent) && /Google Inc/.test(window.navigator.vendor);
|
||||
|
||||
/**
|
||||
* Initialize input hiding.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformInputHide = {
|
||||
attach: function (context) {
|
||||
// Apply chrome fix to prevent password input from being autofilled.
|
||||
// @see https://stackoverflow.com/questions/15738259/disabling-chrome-autofill
|
||||
if (isChrome) {
|
||||
$(context).find('form:has(input.js-webform-input-hide)')
|
||||
.once('webform-input-hide-chrome-workaround')
|
||||
.each(function () {
|
||||
$(this).prepend('<input style="display:none" type="text" name="chrome_autocomplete_username"/><input style="display:none" type="password" name="chrome_autocomplete_password"/>');
|
||||
});
|
||||
}
|
||||
|
||||
// Convert text based inputs to password input on blur.
|
||||
$(context).find('input.js-webform-input-hide')
|
||||
.once('webform-input-hide')
|
||||
.each(function () {
|
||||
var type = this.type;
|
||||
// Initialize input hiding.
|
||||
this.type = 'password';
|
||||
|
||||
// Attach blur and focus event handlers.
|
||||
$(this)
|
||||
.on('blur', function () {
|
||||
this.type = 'password';
|
||||
$(this).attr('autocomplete', 'off');
|
||||
})
|
||||
.on('focus', function () {
|
||||
this.type = type;
|
||||
$(this).removeAttr('autocomplete');
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for jquery.inputmask integration.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Initialize input masks.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformInputMask = {
|
||||
attach: function (context) {
|
||||
if (!$.fn.inputmask) {
|
||||
return;
|
||||
}
|
||||
|
||||
$(context).find('input.js-webform-input-mask').once('webform-input-mask').inputmask();
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for Geocomplete location integration.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// @see https://ubilabs.github.io/geocomplete/
|
||||
// @see https://developers.google.com/maps/documentation/javascript/reference?csw=1#MapOptions
|
||||
Drupal.webform = Drupal.webform || {};
|
||||
Drupal.webform.locationGeocomplete = Drupal.webform.locationGeocomplete || {};
|
||||
Drupal.webform.locationGeocomplete.options = Drupal.webform.locationGeocomplete.options || {};
|
||||
|
||||
/**
|
||||
* Initialize location geocomplete.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformLocationGeocomplete = {
|
||||
attach: function (context) {
|
||||
if (!$.fn.geocomplete) {
|
||||
return;
|
||||
}
|
||||
|
||||
$(context).find('.js-webform-type-webform-location-geocomplete').once('webform-location-geocomplete').each(function () {
|
||||
var $element = $(this);
|
||||
var $input = $element.find('.webform-location-geocomplete');
|
||||
|
||||
// Display a map.
|
||||
var $map = null;
|
||||
if ($input.attr('data-webform-location-geocomplete-map')) {
|
||||
$map = $('<div class="webform-location-geocomplete-map"><div class="webform-location-geocomplete-map--container"></div></div>').insertAfter($input).find('.webform-location-geocomplete-map--container');
|
||||
}
|
||||
|
||||
var options = $.extend({
|
||||
details: $element,
|
||||
detailsAttribute: 'data-webform-location-geocomplete-attribute',
|
||||
types: ['geocode'],
|
||||
map: $map,
|
||||
geocodeAfterResult: false,
|
||||
restoreValueAfterBlur: true,
|
||||
mapOptions: {
|
||||
disableDefaultUI: true,
|
||||
zoomControl: true
|
||||
}
|
||||
}, Drupal.webform.locationGeocomplete.options);
|
||||
|
||||
var $geocomplete = $input.geocomplete(options);
|
||||
|
||||
// If there is default value look up location's attributes, else see if
|
||||
// the default value should be set to the browser's current geolocation.
|
||||
var value = $geocomplete.val();
|
||||
if (value) {
|
||||
$geocomplete.geocomplete('find', value);
|
||||
}
|
||||
else if (navigator.geolocation && $geocomplete.attr('data-webform-location-geocomplete-geolocation')) {
|
||||
navigator.geolocation.getCurrentPosition(function (position) {
|
||||
$geocomplete.geocomplete('find', position.coords.latitude + ', ' + position.coords.longitude);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
|
@ -0,0 +1,101 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for Algolia places location integration.
|
||||
*/
|
||||
|
||||
(function ($, Drupal, drupalSettings) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// @see https://github.com/algolia/places
|
||||
// @see https://community.algolia.com/places/documentation.html#options
|
||||
Drupal.webform = Drupal.webform || {};
|
||||
Drupal.webform.locationPlaces = Drupal.webform.locationPlaces || {};
|
||||
Drupal.webform.locationPlaces.options = Drupal.webform.locationPlaces.options || {};
|
||||
|
||||
var mapping = {
|
||||
lat: 'lat',
|
||||
lng: 'lng',
|
||||
name: 'name',
|
||||
postcode: 'postcode',
|
||||
locality: 'locality',
|
||||
city: 'city',
|
||||
administrative: 'administrative',
|
||||
country: 'country',
|
||||
countryCode: 'country_code',
|
||||
county: 'county',
|
||||
suburb: 'suburb'
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize location places.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformLocationPlaces = {
|
||||
attach: function (context) {
|
||||
if (!window.places) {
|
||||
return;
|
||||
}
|
||||
|
||||
$(context).find('.js-webform-type-webform-location-places').once('webform-location-places').each(function () {
|
||||
var $element = $(this);
|
||||
var $input = $element.find('.webform-location-places');
|
||||
|
||||
// Prevent the 'Enter' key from submitting the form.
|
||||
$input.keydown(function (event) {
|
||||
if (event.keyCode === 13) {
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
var options = $.extend({
|
||||
type: 'address',
|
||||
useDeviceLocation: true,
|
||||
container: $input.get(0)
|
||||
}, Drupal.webform.locationPlaces.options);
|
||||
|
||||
// Add application id and API key.
|
||||
if (drupalSettings.webform.location.places.app_id && drupalSettings.webform.location.places.api_key) {
|
||||
options.appId = drupalSettings.webform.location.places.app_id;
|
||||
options.apiKey = drupalSettings.webform.location.places.api_key;
|
||||
}
|
||||
|
||||
var placesAutocomplete = window.places(options);
|
||||
|
||||
// Disable autocomplete.
|
||||
// @see https://gist.github.com/niksumeiko/360164708c3b326bd1c8
|
||||
var isChrome = /Chrome/.test(window.navigator.userAgent) && /Google Inc/.test(window.navigator.vendor);
|
||||
$input.attr('autocomplete', (isChrome) ? 'off' : 'false');
|
||||
|
||||
// Sync values on change and clear events.
|
||||
placesAutocomplete.on('change', function (e) {
|
||||
$.each(mapping, function (source, destination) {
|
||||
var value = (source === 'lat' || source === 'lng' ? e.suggestion.latlng[source] : e.suggestion[source]) || '';
|
||||
setValue(destination, value);
|
||||
});
|
||||
});
|
||||
placesAutocomplete.on('clear', function (e) {
|
||||
$.each(mapping, function (source, destination) {
|
||||
setValue(destination, '');
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Set attribute value.
|
||||
*
|
||||
* @param {string} name
|
||||
* The attribute name
|
||||
* @param {string} value
|
||||
* The attribute value
|
||||
*/
|
||||
function setValue(name, value) {
|
||||
var inputSelector = ':input[data-webform-location-places-attribute="' + name + '"]';
|
||||
$element.find(inputSelector).val(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal, drupalSettings);
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for managed file uploads.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Track file uploads and display confirm dialog when an file upload is inprogress.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformManagedFileAutoUpload = {
|
||||
attach: function attach(context) {
|
||||
// Add submit handler to file upload form.
|
||||
$(context).find('form')
|
||||
.once('webform-auto-file-upload')
|
||||
.on('submit', function (event) {
|
||||
var $form = $(this);
|
||||
if ($form.data('webform-auto-file-uploads') > 0 && blockSubmit($form)) {
|
||||
event.preventDefault();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
// Add submit handler to form.beforeSend.
|
||||
// Update Drupal.Ajax.prototype.beforeSend only once.
|
||||
if (typeof Drupal.Ajax !== 'undefined' && typeof Drupal.Ajax.prototype.beforeSubmitWebformManagedFileAutoUploadOriginal === 'undefined') {
|
||||
Drupal.Ajax.prototype.beforeSubmitWebformManagedFileAutoUploadOriginal = Drupal.Ajax.prototype.beforeSubmit;
|
||||
Drupal.Ajax.prototype.beforeSubmit = function (form_values, element_settings, options) {
|
||||
var $form = this.$form;
|
||||
var $element = $(this.element);
|
||||
|
||||
// Determine if the triggering element is within .form-actions.
|
||||
var isFormActions = $element
|
||||
.closest('.form-actions').length;
|
||||
|
||||
// Determine if the triggering element is within a multiple element.
|
||||
var isMultipleUpload = $element
|
||||
.parents('.js-form-type-webform-multiple, .js-form-type-webform-custom-composite')
|
||||
.find('.js-form-managed-file').length;
|
||||
|
||||
// Determine if the triggering element is not within a
|
||||
// managed file element.
|
||||
var isManagedUploadButton = $element.parents('.js-form-managed-file').length;
|
||||
|
||||
// Only trigger block submit for .form-actions and multiple element
|
||||
// with file upload.
|
||||
if ($form.data('webform-auto-file-uploads') > 0 &&
|
||||
(isFormActions || (isMultipleUpload && !isManagedUploadButton)) &&
|
||||
blockSubmit($form)) {
|
||||
this.ajaxing = false;
|
||||
return false;
|
||||
}
|
||||
return this.beforeSubmitWebformManagedFileAutoUploadOriginal();
|
||||
};
|
||||
}
|
||||
|
||||
$(context).find('input[type="file"]').once('webform-auto-file-upload').on('change', function () {
|
||||
// Track file upload.
|
||||
$(this).data('msk-auto-file-upload', true);
|
||||
|
||||
// Increment form file uploads.
|
||||
var $form = $(this.form);
|
||||
var fileUploads = ($form.data('webform-auto-file-uploads') || 0);
|
||||
$form.data('webform-auto-file-uploads', fileUploads + 1);
|
||||
});
|
||||
},
|
||||
detach: function detach(context, settings, trigger) {
|
||||
if (trigger === 'unload') {
|
||||
$(context).find('input[type="file"]').removeOnce('webform-auto-file-upload').each(function () {
|
||||
if ($(this).data('msk-auto-file-upload')) {
|
||||
// Remove file upload tracking.
|
||||
$(this).removeData('msk-auto-file-upload');
|
||||
|
||||
// Decrease form file uploads.
|
||||
var $form = $(this.form);
|
||||
var fileUploads = ($form.data('webform-auto-file-uploads') || 0);
|
||||
$form.data('webform-auto-file-uploads', fileUploads - 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Block form submit.
|
||||
*
|
||||
* @param {jQuery} form
|
||||
* A form.
|
||||
*
|
||||
* @return {boolean}
|
||||
* TRUE if form submit should be blocked.
|
||||
*/
|
||||
function blockSubmit(form) {
|
||||
if ($(form).data('webform-auto-file-uploads') < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var message = Drupal.t('File upload inprogress. Uploaded file may be lost.') +
|
||||
'\n' +
|
||||
Drupal.t('Do you want to continue?');
|
||||
return !window.confirm(message);
|
||||
}
|
||||
|
||||
})(jQuery, Drupal);
|
|
@ -0,0 +1,98 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for message element integration.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Behavior for handler message close.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformMessageClose = {
|
||||
attach: function (context) {
|
||||
$(context).find('.js-webform-message--close').once('webform-message--close').each(function () {
|
||||
var $element = $(this);
|
||||
|
||||
var id = $element.attr('data-message-id');
|
||||
var storage = $element.attr('data-message-storage');
|
||||
var effect = $element.attr('data-message-close-effect') || 'hide';
|
||||
switch (effect) {
|
||||
case 'slide': effect = 'slideUp'; break;
|
||||
|
||||
case 'fade': effect = 'fadeOut'; break;
|
||||
}
|
||||
|
||||
// Check storage status.
|
||||
if (isClosed($element, storage, id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only show element if it's style is not set to 'display: none'.
|
||||
if ($element.attr('style') !== 'display: none;') {
|
||||
$element.show();
|
||||
}
|
||||
|
||||
$element.find('.js-webform-message__link').on('click', function (event) {
|
||||
$element[effect]();
|
||||
setClosed($element, storage, id);
|
||||
$element.trigger('close');
|
||||
event.preventDefault();
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function isClosed($element, storage, id) {
|
||||
if (!id || !storage) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (storage) {
|
||||
case 'local':
|
||||
if (window.localStorage) {
|
||||
return localStorage.getItem('Drupal.webform.message.' + id) || false;
|
||||
}
|
||||
return false;
|
||||
|
||||
case 'session':
|
||||
if (window.sessionStorage) {
|
||||
return sessionStorage.getItem('Drupal.webform.message.' + id) || false;
|
||||
}
|
||||
return false;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function setClosed($element, storage, id) {
|
||||
if (!id || !storage) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (storage) {
|
||||
case 'local':
|
||||
if (window.localStorage) {
|
||||
localStorage.setItem('Drupal.webform.message.' + id, true);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'session':
|
||||
if (window.sessionStorage) {
|
||||
sessionStorage.setItem('Drupal.webform.message.' + id, true);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'user':
|
||||
case 'state':
|
||||
case 'custom':
|
||||
$.get($element.find('.js-webform-message__link').attr('href'));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
})(jQuery, Drupal);
|
59
2017/web/modules/contrib/webform/js/webform.element.more.js
Normal file
59
2017/web/modules/contrib/webform/js/webform.element.more.js
Normal file
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for element (read) more.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Element (read) more.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformElementMore = {
|
||||
attach: function (context) {
|
||||
$(context).find('.js-webform-element-more').once('webform-element-more').each(function (event) {
|
||||
var $more = $(this);
|
||||
var $a = $more.find('a');
|
||||
var $content = $more.find('.webform-element-more--content');
|
||||
|
||||
// Add aria-* attributes.
|
||||
$a.attr({
|
||||
'aria-expanded': false,
|
||||
'aria-controls': $content.attr('id')
|
||||
});
|
||||
|
||||
// Add event handlers.
|
||||
$a.on('click', toggle)
|
||||
.on('keydown', function (event) {
|
||||
// Space or Return.
|
||||
if (event.which === 32 || event.which === 13) {
|
||||
toggle(event);
|
||||
}
|
||||
});
|
||||
|
||||
function toggle(event) {
|
||||
var expanded = ($a.attr('aria-expanded') === 'true');
|
||||
|
||||
// Toggle `aria-expanded` attributes on link.
|
||||
$a.attr('aria-expanded', !expanded);
|
||||
|
||||
// Toggle content and more .is-open state.
|
||||
if (expanded) {
|
||||
$more.removeClass('is-open');
|
||||
$content.slideUp();
|
||||
}
|
||||
else {
|
||||
$more.addClass('is-open');
|
||||
$content.slideDown();
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for multiple element.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Move show weight to after the table.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformMultipleTableDrag = {
|
||||
attach: function (context, settings) {
|
||||
for (var base in settings.tableDrag) {
|
||||
if (settings.tableDrag.hasOwnProperty(base)) {
|
||||
$(context).find('.js-form-type-webform-multiple #' + base).once('webform-multiple-table-drag').each(function () {
|
||||
var $tableDrag = $(this);
|
||||
var $toggleWeight = $tableDrag.prev().prev('.tabledrag-toggle-weight-wrapper');
|
||||
if ($toggleWeight.length) {
|
||||
$toggleWeight.addClass('webform-multiple-tabledrag-toggle-weight');
|
||||
$tableDrag.after($toggleWeight);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Submit multiple add number input value when enter is pressed.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformMultipleAdd = {
|
||||
attach: function (context, settings) {
|
||||
$(context).find('.js-webform-multiple-add').once('webform-multiple-add').each(function () {
|
||||
var $submit = $(this).find('input[type="submit"], button');
|
||||
var $number = $(this).find('input[type="number"]');
|
||||
$number.keyup(function (event) {
|
||||
if (event.which === 13) {
|
||||
// Note: Mousedown is the default trigger for Ajax events.
|
||||
// @see Drupal.Ajax.
|
||||
$submit.mousedown();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for options (admin) elements.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
|
||||
/**
|
||||
* Attach handlers to options (admin) element.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformOptionsAdmin = {
|
||||
attach: function (context) {
|
||||
$(context).find('.js-webform-options-sync').once('js-webform-options-sync').each(function () {
|
||||
// Target input name and not id because the id will be changing via
|
||||
// Ajax callbacks.
|
||||
var name = this.name;
|
||||
|
||||
var $value = $(this);
|
||||
var $text = $('input[name="' + name.replace(/\[value\]$/, '[text]') + '"]');
|
||||
|
||||
// On focus, determine if option value and option text are in-sync.
|
||||
$value.on('focus', function () {
|
||||
var sync = $value.val() === $text.val();
|
||||
$value.data('webform_options_sync', sync);
|
||||
if (sync) {
|
||||
$text.prop('readonly', true).closest('.js-form-item, .js-form-wrapper').addClass('webform-readonly');
|
||||
}
|
||||
});
|
||||
|
||||
// On blur, if option value and option text are in-sync remove readonly.
|
||||
$value.on('blur', function () {
|
||||
if ($value.data('webform_options_sync')) {
|
||||
$text.prop('readonly', false).closest('.js-form-item, .js-form-wrapper').removeClass('webform-readonly');
|
||||
}
|
||||
});
|
||||
|
||||
// On keyup, if option value and option text are in-sync then set
|
||||
// option text to option value.
|
||||
$value.on('keyup', function () {
|
||||
if ($value.data('webform_options_sync')) {
|
||||
$text.val($value.val());
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
})(jQuery, Drupal);
|
158
2017/web/modules/contrib/webform/js/webform.element.other.js
Normal file
158
2017/web/modules/contrib/webform/js/webform.element.other.js
Normal file
|
@ -0,0 +1,158 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for other elements.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Toggle other input (text) field.
|
||||
*
|
||||
* @param {boolean} show
|
||||
* TRUE will display the text field. FALSE with hide and clear the text field.
|
||||
* @param {object} $element
|
||||
* The input (text) field to be toggled.
|
||||
* @param {string} effect
|
||||
* Effect.
|
||||
*/
|
||||
function toggleOther(show, $element, effect) {
|
||||
var $input = $element.find('input');
|
||||
var hideEffect = (effect === false) ? 'hide' : 'slideUp';
|
||||
var showEffect = (effect === false) ? 'show' : 'slideDown';
|
||||
|
||||
if (show) {
|
||||
// Limit the other inputs width to the parent's container.
|
||||
// If the parent container is not visible it's width will be 0
|
||||
// and ignored.
|
||||
var width = $element.parent().width();
|
||||
if (width) {
|
||||
$element.width(width);
|
||||
}
|
||||
|
||||
// Display the element.
|
||||
$element[showEffect]();
|
||||
// If not initializing, then focus the other element.
|
||||
if (effect !== false) {
|
||||
$input.focus();
|
||||
}
|
||||
// Require the input.
|
||||
$input.prop('required', true).attr('aria-required', 'true');
|
||||
// Restore the input's value.
|
||||
var value = $input.data('webform-value');
|
||||
if (typeof value !== 'undefined') {
|
||||
$input.val(value);
|
||||
var input = $input.get(0);
|
||||
// Move cursor to the beginning of the other text input.
|
||||
// @see https://stackoverflow.com/questions/21177489/selectionstart-selectionend-on-input-type-number-no-longer-allowed-in-chrome
|
||||
if ($.inArray(input.type, ['text', 'search', 'url', 'tel', 'password']) !== -1) {
|
||||
input.setSelectionRange(0, 0);
|
||||
}
|
||||
}
|
||||
// Refresh CodeMirror used as other element.
|
||||
$element.parent().find('.CodeMirror').each(function (index, $element) {
|
||||
$element.CodeMirror.refresh();
|
||||
});
|
||||
}
|
||||
else {
|
||||
// Hide the element.
|
||||
$element[hideEffect]();
|
||||
// Save the input's value.
|
||||
$input.data('webform-value', $input.val());
|
||||
// Empty and un-required the input.
|
||||
$input.val('').prop('required', false).removeAttr('aria-required');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach handlers to select other elements.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformSelectOther = {
|
||||
attach: function (context) {
|
||||
$(context).find('.js-webform-select-other').once('webform-select-other').each(function () {
|
||||
var $element = $(this);
|
||||
|
||||
var $select = $element.find('select');
|
||||
var $otherOption = $element.find('option[value="_other_"]');
|
||||
var $input = $element.find('.js-webform-select-other-input');
|
||||
|
||||
$select.on('change', function () {
|
||||
toggleOther($otherOption.is(':selected'), $input);
|
||||
});
|
||||
|
||||
toggleOther($otherOption.is(':selected'), $input, false);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Attach handlers to checkboxes other elements.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformCheckboxesOther = {
|
||||
attach: function (context) {
|
||||
$(context).find('.js-webform-checkboxes-other').once('webform-checkboxes-other').each(function () {
|
||||
var $element = $(this);
|
||||
var $checkbox = $element.find('input[value="_other_"]');
|
||||
var $input = $element.find('.js-webform-checkboxes-other-input');
|
||||
|
||||
$checkbox.on('change', function () {
|
||||
toggleOther(this.checked, $input);
|
||||
});
|
||||
|
||||
toggleOther($checkbox.is(':checked'), $input, false);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Attach handlers to radios other elements.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformRadiosOther = {
|
||||
attach: function (context) {
|
||||
$(context).find('.js-webform-radios-other').once('webform-radios-other').each(function () {
|
||||
var $element = $(this);
|
||||
|
||||
var $radios = $element.find('input[type="radio"]');
|
||||
var $input = $element.find('.js-webform-radios-other-input');
|
||||
|
||||
$radios.on('change', function () {
|
||||
toggleOther(($radios.filter(':checked').val() === '_other_'), $input);
|
||||
});
|
||||
|
||||
toggleOther(($radios.filter(':checked').val() === '_other_'), $input, false);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Attach handlers to buttons other elements.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformButtonsOther = {
|
||||
attach: function (context) {
|
||||
$(context).find('.js-webform-buttons-other').once('webform-buttons-other').each(function () {
|
||||
var $element = $(this);
|
||||
|
||||
var $buttons = $element.find('input[type="radio"]');
|
||||
var $input = $element.find('.js-webform-buttons-other-input');
|
||||
var $container = $(this).find('.js-webform-webform-buttons');
|
||||
|
||||
// Create set onchange handler.
|
||||
$container.change(function () {
|
||||
toggleOther(($(this).find(':radio:checked').val() === '_other_'), $input);
|
||||
});
|
||||
|
||||
toggleOther(($buttons.filter(':checked').val() === '_other_'), $input, false);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for radio buttons.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Adds HTML5 validation to required radios buttons.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @see Issue #2856795: If radio buttons are required but not filled form is nevertheless submitted.
|
||||
*/
|
||||
Drupal.behaviors.webformRadiosRequired = {
|
||||
attach: function (context) {
|
||||
$('.js-webform-type-radios.required, .js-webform-type-webform-radios-other.required', context).each(function () {
|
||||
$(this).find('input[type="radio"]').attr({'required': 'required', 'aria-required': 'true'});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
148
2017/web/modules/contrib/webform/js/webform.element.range.js
Normal file
148
2017/web/modules/contrib/webform/js/webform.element.range.js
Normal file
|
@ -0,0 +1,148 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for range element integration.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Display HTML5 range output in a left/right aligned number input.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformRangeOutputNumber = {
|
||||
attach: function (context) {
|
||||
$(context).find('.js-form-type-range').once('webform-range-output-number').each(function () {
|
||||
// Handle browser that don't support the HTML5 range input.
|
||||
if (Modernizr.inputtypes.range === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
var $element = $(this);
|
||||
var $input = $element.find('input[type="range"]');
|
||||
var $output = $element.find('input[type="number"]');
|
||||
if (!$output.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set output value.
|
||||
$output.val($input.val());
|
||||
|
||||
// Sync input and output values.
|
||||
$input.on('input', function () {
|
||||
$output.val($input.val());
|
||||
});
|
||||
$output.on('input', function () {
|
||||
$input.val($output.val());
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Display HTML5 range output in a floating bubble.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @see https://css-tricks.com/value-bubbles-for-range-inputs/
|
||||
* @see https://stackoverflow.com/questions/33794123/absolute-positioning-in-relation-to-a-inputtype-range
|
||||
*/
|
||||
Drupal.behaviors.webformRangeOutputBubble = {
|
||||
attach: function (context) {
|
||||
$(context).find('.js-form-type-range').once('webform-range-output-bubble').each(function () {
|
||||
// Handle browser that don't support the HTML5 range input.
|
||||
if (Modernizr.inputtypes.range === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
var $element = $(this);
|
||||
var $input = $element.find('input[type="range"]');
|
||||
var $output = $element.find('output');
|
||||
var display = $output.attr('data-display');
|
||||
|
||||
if (!$output.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
$element.css('position', 'relative');
|
||||
|
||||
$input.on('input', function () {
|
||||
var inputValue = $input.val();
|
||||
|
||||
// Set output text with prefix and suffix.
|
||||
var text = ($output.attr('data-field-prefix') || '') +
|
||||
inputValue +
|
||||
($output.attr('data-field-suffix') || '');
|
||||
$output.text(text);
|
||||
|
||||
// Set output top position.
|
||||
var top;
|
||||
if (display === 'above') {
|
||||
top = $input.position().top - $output.outerHeight() + 2;
|
||||
}
|
||||
else {
|
||||
top = $input.position().top + $input.outerHeight() + 2;
|
||||
}
|
||||
|
||||
// It is impossible to accurately calculate the exact position of the
|
||||
// range's buttons so we only incrementally move the output bubble.
|
||||
var inputWidth = $input.outerWidth();
|
||||
var buttonPosition = Math.floor(inputWidth * (inputValue - $input.attr('min')) / ($input.attr('max') - $input.attr('min')));
|
||||
var increment = Math.floor(inputWidth / 5);
|
||||
var outputWidth = $output.outerWidth();
|
||||
|
||||
// Set output left position.
|
||||
var left;
|
||||
if (buttonPosition <= increment) {
|
||||
left = 0;
|
||||
}
|
||||
else if (buttonPosition <= increment * 2) {
|
||||
left = (increment * 1.5) - outputWidth;
|
||||
if (left < 0) {
|
||||
left = 0;
|
||||
}
|
||||
}
|
||||
else if (buttonPosition <= increment * 3) {
|
||||
left = (increment * 2.5) - (outputWidth / 2);
|
||||
|
||||
}
|
||||
else if (buttonPosition <= increment * 4) {
|
||||
left = (increment * 4) - outputWidth;
|
||||
if (left > (increment * 5) - outputWidth) {
|
||||
left = (increment * 5) - outputWidth;
|
||||
}
|
||||
}
|
||||
else if (buttonPosition <= inputWidth) {
|
||||
left = (increment * 5) - outputWidth;
|
||||
}
|
||||
// Also make sure to include the input's left position.
|
||||
left = Math.floor($input.position().left + left);
|
||||
|
||||
// Finally, position the output.
|
||||
$output.css({top: top, left: left});
|
||||
})
|
||||
// Fake a change to position output at page load.
|
||||
.trigger('input');
|
||||
|
||||
// Add fade in/out event handlers if opacity is defined.
|
||||
var defaultOpacity = $output.css('opacity');
|
||||
if (defaultOpacity < 1) {
|
||||
// Fade in/out on focus/blur of the input.
|
||||
$input.on('focus mouseover', function () {
|
||||
$output.stop().fadeTo('slow', 1);
|
||||
});
|
||||
$input.on('blur mouseout', function () {
|
||||
$output.stop().fadeTo('slow', defaultOpacity);
|
||||
});
|
||||
// Also fade in when focusing the output.
|
||||
$output.on('touchstart mouseover', function () {
|
||||
$output.stop().fadeTo('slow', 1);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for RateIt integration.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// All options can be override using custom data-* attributes.
|
||||
// @see https://github.com/gjunge/rateit.js/wiki#options.
|
||||
|
||||
/**
|
||||
* Initialize rating element using RateIt.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformRating = {
|
||||
attach: function (context) {
|
||||
if (!$.fn.rateit) {
|
||||
return;
|
||||
}
|
||||
|
||||
$(context)
|
||||
.find('[data-rateit-backingfld]')
|
||||
.once('webform-rating')
|
||||
.each(function () {
|
||||
var $rateit = $(this);
|
||||
var $input = $($rateit.attr('data-rateit-backingfld'));
|
||||
|
||||
// Rateit only initialize inputs on load.
|
||||
if (document.readyState === 'complete') {
|
||||
$rateit.rateit();
|
||||
}
|
||||
|
||||
// Update the RateIt widget when the input's value has changed.
|
||||
// @see webform.states.js
|
||||
$input.on('change', function () {
|
||||
$rateit.rateit('value', $input.val());
|
||||
});
|
||||
|
||||
// Set RateIt widget to be readonly when the input is disabled.
|
||||
// @see webform.states.js
|
||||
$input.on('webform:disabled', function () {
|
||||
$rateit.rateit('readonly', $input.is(':disabled'));
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
39
2017/web/modules/contrib/webform/js/webform.element.roles.js
Normal file
39
2017/web/modules/contrib/webform/js/webform.element.roles.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for roles element integration.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Enhance roles element.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformRoles = {
|
||||
attach: function (context) {
|
||||
$(context).find('.js-webform-roles-role[value="authenticated"]').once('webform-roles').each(function () {
|
||||
var $authenticated = $(this);
|
||||
var $checkboxes = $authenticated.parents('.form-checkboxes').find('.js-webform-roles-role').filter(function () {
|
||||
return ($(this).val() !== 'anonymous' && $(this).val() !== 'authenticated');
|
||||
});
|
||||
|
||||
$authenticated.on('click', function () {
|
||||
if ($authenticated.is(':checked')) {
|
||||
$checkboxes.prop('checked', true).attr('disabled', true);
|
||||
}
|
||||
else {
|
||||
$checkboxes.prop('checked', false).removeAttr('disabled');
|
||||
}
|
||||
});
|
||||
|
||||
if ($authenticated.is(':checked')) {
|
||||
$checkboxes.prop('checked', true).attr('disabled', true);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
|
@ -0,0 +1,73 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for Select2 integration.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// @see https://select2.github.io/options.html
|
||||
Drupal.webform = Drupal.webform || {};
|
||||
Drupal.webform.select2 = Drupal.webform.select2 || {};
|
||||
Drupal.webform.select2.options = Drupal.webform.select2.options || {};
|
||||
|
||||
/**
|
||||
* Initialize Select2 support.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformSelect2 = {
|
||||
attach: function (context) {
|
||||
if (!$.fn.select2) {
|
||||
return;
|
||||
}
|
||||
|
||||
$(context)
|
||||
.find('select.js-webform-select2, .js-webform-select2 select')
|
||||
.once('webform-select2')
|
||||
// http://stackoverflow.com/questions/14313001/select2-not-calculating-resolved-width-correctly-if-select-is-hidden
|
||||
.css('width', '100%')
|
||||
.each(function () {
|
||||
var $select = $(this);
|
||||
|
||||
var options = $.extend({}, Drupal.webform.select2.options);
|
||||
if ($select.data('placeholder')) {
|
||||
options.placeholder = $select.data('placeholder');
|
||||
if (!$select.prop('multiple')) {
|
||||
// Allow single option to be deselected.
|
||||
options.allowClear = true;
|
||||
}
|
||||
}
|
||||
|
||||
$select.select2(options);
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* ISSUE:
|
||||
* Hiding/showing element via #states API cause select2 dropdown to appear in the wrong position.
|
||||
*
|
||||
* WORKAROUND:
|
||||
* Close (aka hide) select2 dropdown when #states API hides or shows an element.
|
||||
*
|
||||
* Steps to reproduce:
|
||||
* - Add custom 'Submit button(s)'
|
||||
* - Hide submit button
|
||||
* - Save
|
||||
* - Open 'Submit button(s)' dialog
|
||||
*
|
||||
* Dropdown body is positioned incorrectly when dropdownParent isn't statically positioned.
|
||||
* @see https://github.com/select2/select2/issues/3303
|
||||
*/
|
||||
$(function () {
|
||||
if ($.fn.select2) {
|
||||
$(document).on('state:visible state:visible-slide', function (e) {
|
||||
$('select.select2-hidden-accessible').select2('close');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery, Drupal);
|
104
2017/web/modules/contrib/webform/js/webform.element.signature.js
Normal file
104
2017/web/modules/contrib/webform/js/webform.element.signature.js
Normal file
|
@ -0,0 +1,104 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for signature pad integration.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// @see https://github.com/szimek/signature_pad#options
|
||||
Drupal.webform = Drupal.webform || {};
|
||||
Drupal.webform.signaturePad = Drupal.webform.signaturePad || {};
|
||||
Drupal.webform.signaturePad.options = Drupal.webform.signaturePad.options || {};
|
||||
|
||||
/**
|
||||
* Initialize signature element.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformSignature = {
|
||||
attach: function (context) {
|
||||
if (!window.SignaturePad) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$(context).find('input.js-webform-signature').once('webform-signature').each(function () {
|
||||
var $input = $(this);
|
||||
var value = $input.val();
|
||||
var $wrapper = $input.parent();
|
||||
var $canvas = $wrapper.find('canvas');
|
||||
var $button = $wrapper.find(':button, :submit');
|
||||
var canvas = $canvas[0];
|
||||
|
||||
var calculateDimensions = function () {
|
||||
$canvas.attr('width', $wrapper.width());
|
||||
$canvas.attr('height', $wrapper.width() / 3);
|
||||
};
|
||||
|
||||
// Set height.
|
||||
$canvas.attr('width', $wrapper.width());
|
||||
$canvas.attr('height', $wrapper.width() / 3);
|
||||
$(window).resize(function () {
|
||||
calculateDimensions();
|
||||
|
||||
// Resizing clears the canvas so we need to reset the signature pad.
|
||||
signaturePad.clear();
|
||||
var value = $input.val();
|
||||
if (value) {
|
||||
signaturePad.fromDataURL(value);
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize signature canvas.
|
||||
var options = $.extend({
|
||||
onEnd: function () {
|
||||
$input.val(signaturePad.toDataURL());
|
||||
}
|
||||
}, Drupal.webform.signaturePad.options);
|
||||
var signaturePad = new SignaturePad(canvas, options);
|
||||
|
||||
// Set value.
|
||||
if (value) {
|
||||
signaturePad.fromDataURL(value);
|
||||
}
|
||||
|
||||
// Set reset handler.
|
||||
$button.on('click', function () {
|
||||
signaturePad.clear();
|
||||
$input.val('');
|
||||
this.blur();
|
||||
return false;
|
||||
});
|
||||
|
||||
// Input onchange clears signature pad if value is empty.
|
||||
// Onchange events handlers are triggered when a webform is
|
||||
// hidden or shown.
|
||||
// @see webform.states.js
|
||||
// @see triggerEventHandlers()
|
||||
$input.on('change', function () {
|
||||
if (!$input.val()) {
|
||||
signaturePad.clear();
|
||||
}
|
||||
setTimeout(function () {
|
||||
calculateDimensions();
|
||||
}, 1);
|
||||
});
|
||||
|
||||
// Turn signature pad off/on when the input is disabled/enabled.
|
||||
// @see webform.states.js
|
||||
$input.on('webform:disabled', function () {
|
||||
if ($input.is(':disabled')) {
|
||||
signaturePad.off();
|
||||
}
|
||||
else {
|
||||
signaturePad.on();
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for element #states.
|
||||
*/
|
||||
|
||||
(function ($, Drupal, drupalSettings) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Element #states builder.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformElementStates = {
|
||||
attach: function (context) {
|
||||
$(context).find('.webform-states-table--condition').once('webform-element-states').each(function () {
|
||||
var $condition = $(this);
|
||||
var $selector = $condition.find('.webform-states-table--selector select');
|
||||
var $value = $condition.find('.webform-states-table--value input');
|
||||
var $trigger = $condition.find('.webform-states-table--trigger select');
|
||||
|
||||
// Initialize autocompletion.
|
||||
$value.autocomplete({minLength: 0}).on('focus', function () {
|
||||
$value.autocomplete('search', '');
|
||||
});
|
||||
|
||||
// Initialize trigger and selector.
|
||||
$trigger.on('change', function () {$selector.change();});
|
||||
|
||||
$selector.on('change', function () {
|
||||
var selector = $selector.val();
|
||||
var sourceKey = drupalSettings.webformElementStates.selectors[selector];
|
||||
var source = drupalSettings.webformElementStates.sources[sourceKey];
|
||||
var notPattern = ($trigger.val().indexOf('pattern') === -1);
|
||||
if (source && notPattern) {
|
||||
// Enable autocompletion.
|
||||
$value
|
||||
.autocomplete('option', 'source', source)
|
||||
.addClass('form-autocomplete');
|
||||
}
|
||||
else {
|
||||
// Disable autocompletion.
|
||||
$value
|
||||
.autocomplete('option', 'source', [])
|
||||
.removeClass('form-autocomplete');
|
||||
}
|
||||
}).change();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal, drupalSettings);
|
|
@ -0,0 +1,66 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for tableselect enhancements.
|
||||
*
|
||||
* @see core/misc/tableselect.es6.js
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Initialize and tweak webform tableselect behavior.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformTableSelect = {
|
||||
attach: function (context) {
|
||||
$(context)
|
||||
.find('table.js-webform-tableselect')
|
||||
.once('webform-tableselect')
|
||||
.each(Drupal.webformTableSelect);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback used in {@link Drupal.behaviors.tableSelect}.
|
||||
*/
|
||||
Drupal.webformTableSelect = function () {
|
||||
var $table = $(this);
|
||||
|
||||
// Set default table rows to .selected class.
|
||||
$table.find('tr').each(function () {
|
||||
// Set table row selected for checkboxes.
|
||||
var $tr = $(this);
|
||||
if ($tr.find('input[type="checkbox"]:checked').length && !$tr.hasClass('selected')) {
|
||||
$tr.addClass('selected');
|
||||
}
|
||||
});
|
||||
|
||||
// Add .selected class event handler to all tableselect elements.
|
||||
// Currently .selected is only added to tables with .select-all.
|
||||
if ($table.find('th.select-all').length === 0) {
|
||||
$table.find('td input[type="checkbox"]:enabled').on('click', function () {
|
||||
$(this).closest('tr').toggleClass('selected', this.checked);
|
||||
});
|
||||
}
|
||||
|
||||
// Add click event handler to the table row that toggles the
|
||||
// checkbox or radio.
|
||||
$table.find('tr').on('click', function (event) {
|
||||
if ($.inArray(event.target.tagName, ['A', 'BUTTON', 'INPUT', 'SELECT']) !== -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var $tr = $(this);
|
||||
var $checkbox = $tr.find('td input[type="checkbox"]:enabled, td input[type="radio"]:enabled');
|
||||
if ($checkbox.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$checkbox.click();
|
||||
});
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for Telephone element.
|
||||
*/
|
||||
|
||||
(function ($, Drupal, drupalSettings) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// @see https://github.com/jackocnr/intl-tel-input#options
|
||||
Drupal.webform = Drupal.webform || {};
|
||||
Drupal.webform.intlTelInput = Drupal.webform.intlTelInput || {};
|
||||
Drupal.webform.intlTelInput.options = Drupal.webform.intlTelInput.options || {};
|
||||
|
||||
/**
|
||||
* Initialize Telephone international element.
|
||||
* @see http://intl-tel-input.com/node_modules/intl-tel-input/examples/gen/is-valid-number.html
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformTelephoneInternational = {
|
||||
attach: function (context) {
|
||||
if (!$.fn.intlTelInput) {
|
||||
return;
|
||||
}
|
||||
|
||||
$(context).find('input.js-webform-telephone-international').once('webform-telephone-international').each(function () {
|
||||
var $telephone = $(this);
|
||||
|
||||
// Add error message container.
|
||||
var $error = $('<div class="form-item--error-message">' + Drupal.t('Invalid phone number') + '</div>').hide();
|
||||
$telephone.closest('.js-form-item').append($error);
|
||||
|
||||
// @todo: Figure out how to lazy load utilsScript (build/js/utils.js).
|
||||
// @see https://github.com/jackocnr/intl-tel-input#utilities-script
|
||||
var options = $.extend({
|
||||
nationalMode: false,
|
||||
initialCountry: $telephone.attr('data-webform-telephone-international-initial-country') || ''
|
||||
}, Drupal.webform.intlTelInput.options);
|
||||
$telephone.intlTelInput(options);
|
||||
|
||||
var reset = function () {
|
||||
$telephone.removeClass('error');
|
||||
$error.hide();
|
||||
};
|
||||
|
||||
$telephone.blur(function () {
|
||||
reset();
|
||||
if ($.trim($telephone.val())) {
|
||||
if (!$telephone.intlTelInput('isValidNumber')) {
|
||||
$telephone.addClass('error');
|
||||
$error.show();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$telephone.on('keyup change', reset);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal, drupalSettings);
|
|
@ -0,0 +1,83 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for terms of service.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// @see http://api.jqueryui.com/dialog/
|
||||
Drupal.webform = Drupal.webform || {};
|
||||
Drupal.webform.termsOfServiceModal = Drupal.webform.termsOfServiceModal || {};
|
||||
Drupal.webform.termsOfServiceModal.options = Drupal.webform.termsOfServiceModal.options || {};
|
||||
|
||||
/**
|
||||
* Initialize terms of service element.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformTermsOfService = {
|
||||
attach: function (context) {
|
||||
$(context).find('.js-form-type-webform-terms-of-service').once('webform-terms-of-service').each(function () {
|
||||
var $element = $(this);
|
||||
var $a = $element.find('label a');
|
||||
var $details = $element.find('.webform-terms-of-service-details');
|
||||
|
||||
var type = $element.attr('data-webform-terms-of-service-type');
|
||||
|
||||
// Initialize the modal.
|
||||
if (type === 'modal') {
|
||||
// Move details title to attribute.
|
||||
var $title = $element.find('.webform-terms-of-service-details--title');
|
||||
if ($title.length) {
|
||||
$details.attr('title', $title.text());
|
||||
$title.remove();
|
||||
}
|
||||
|
||||
var options = $.extend({
|
||||
modal: true,
|
||||
autoOpen: false,
|
||||
minWidth: 600,
|
||||
maxWidth: 800
|
||||
}, Drupal.webform.termsOfServiceModal.options);
|
||||
$details.dialog(options);
|
||||
}
|
||||
|
||||
// Add aria-* attributes.
|
||||
if (type !== 'modal') {
|
||||
$a.attr({
|
||||
'aria-expanded': false,
|
||||
'aria-controls': $details.attr('id')
|
||||
});
|
||||
}
|
||||
|
||||
// Set event handlers.
|
||||
$a.click(openDetails)
|
||||
.on('keydown', function (event) {
|
||||
// Space or Return.
|
||||
if (event.which === 32 || event.which === 13) {
|
||||
openDetails(event);
|
||||
}
|
||||
});
|
||||
|
||||
function openDetails(event) {
|
||||
if (type === 'modal') {
|
||||
$details.dialog('open');
|
||||
}
|
||||
else {
|
||||
var expanded = ($a.attr('aria-expanded') === 'true');
|
||||
|
||||
// Toggle `aria-expanded` attributes on link.
|
||||
$a.attr('aria-expanded', !expanded);
|
||||
|
||||
// Toggle details.
|
||||
$details[expanded ? 'slideUp' : 'slideDown']();
|
||||
}
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for Text format integration.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Enhance text format element.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformTextFormat = {
|
||||
attach: function (context) {
|
||||
$(context).find('.js-text-format-wrapper textarea').once('webform-text-format').each(function () {
|
||||
if (!window.CKEDITOR) {
|
||||
return;
|
||||
}
|
||||
|
||||
var $textarea = $(this);
|
||||
// Update the CKEDITOR when the textarea's value has changed.
|
||||
// @see webform.states.js
|
||||
$textarea.on('change', function () {
|
||||
if (CKEDITOR.instances[$textarea.attr('id')]) {
|
||||
var editor = CKEDITOR.instances[$textarea.attr('id')];
|
||||
editor.setData($textarea.val());
|
||||
}
|
||||
});
|
||||
|
||||
// Set CKEDITOR to be readonly when the textarea is disabled.
|
||||
// @see webform.states.js
|
||||
$textarea.on('webform:disabled', function () {
|
||||
if (CKEDITOR.instances[$textarea.attr('id')]) {
|
||||
var editor = CKEDITOR.instances[$textarea.attr('id')];
|
||||
editor.setReadOnly($textarea.is(':disabled'));
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
67
2017/web/modules/contrib/webform/js/webform.element.time.js
Normal file
67
2017/web/modules/contrib/webform/js/webform.element.time.js
Normal file
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for time integration.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// @see https://github.com/jonthornton/jquery-timepicker#options
|
||||
Drupal.webform = Drupal.webform || {};
|
||||
Drupal.webform.timePicker = Drupal.webform.timePicker || {};
|
||||
Drupal.webform.timePicker.options = Drupal.webform.timePicker.options || {};
|
||||
|
||||
/**
|
||||
* Attach timepicker fallback on time elements.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the behavior to time elements.
|
||||
*/
|
||||
Drupal.behaviors.webformTime = {
|
||||
attach: function (context, settings) {
|
||||
if (!$.fn.timepicker) {
|
||||
return;
|
||||
}
|
||||
|
||||
$(context).find('input[data-webform-time-format]').once('webformTimePicker').each(function () {
|
||||
var $input = $(this);
|
||||
|
||||
// Skip if time inputs are supported by the browser and input is not a text field.
|
||||
// @see \Drupal\webform\Element\WebformDatetime
|
||||
if (window.Modernizr && Modernizr.inputtypes.time === true && $input.attr('type') !== 'text') {
|
||||
return;
|
||||
}
|
||||
|
||||
var options = {};
|
||||
options.timeFormat = $input.data('webformTimeFormat');
|
||||
if ($input.attr('min')) {
|
||||
options.minTime = $input.attr('min');
|
||||
}
|
||||
if ($input.attr('max')) {
|
||||
options.maxTime = $input.attr('max');
|
||||
}
|
||||
|
||||
// HTML5 time element steps is in seconds but for the timepicker
|
||||
// fallback it needs to be in minutes.
|
||||
// Note: The 'datetime' element uses the #date_increment which defaults
|
||||
// to 1 (second).
|
||||
// @see \Drupal\Core\Datetime\Element\Datetime::processDatetime
|
||||
// Only use step if it is greater than 60 seconds.
|
||||
if ($input.attr('step') && ($input.attr('step') > 60)) {
|
||||
options.step = Math.round($input.attr('step') / 60);
|
||||
}
|
||||
else {
|
||||
options.step = 1;
|
||||
}
|
||||
|
||||
options = $.extend(options, Drupal.webform.timePicker.options);
|
||||
|
||||
$input.timepicker(options);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
|
@ -0,0 +1,74 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for toggle integration.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// @see https://github.com/simontabor/jquery-toggles
|
||||
Drupal.webform = Drupal.webform || {};
|
||||
Drupal.webform.toggles = Drupal.webform.toggles || {};
|
||||
Drupal.webform.toggles.options = Drupal.webform.toggles.options || {};
|
||||
|
||||
/**
|
||||
* Initialize toggle element using Toggles.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformToggle = {
|
||||
attach: function (context) {
|
||||
if (!$.fn.toggles) {
|
||||
return;
|
||||
}
|
||||
|
||||
$(context).find('.js-webform-toggle').once('webform-toggle').each(function () {
|
||||
var $toggle = $(this);
|
||||
var $wrapper = $toggle.parent();
|
||||
var $checkbox = $wrapper.find('input[type="checkbox"]');
|
||||
var $label = $wrapper.find('label');
|
||||
|
||||
var options = $.extend({
|
||||
checkbox: $checkbox,
|
||||
on: $checkbox.is(':checked'),
|
||||
clicker: $label,
|
||||
text: {
|
||||
on: $toggle.attr('data-toggle-text-on') || '',
|
||||
off: $toggle.attr('data-toggle-text-off') || ''
|
||||
}
|
||||
}, Drupal.webform.toggles.options);
|
||||
|
||||
$toggle.toggles(options);
|
||||
|
||||
// Trigger change event for #states API.
|
||||
// @see Drupal.states.Trigger.states.checked.change
|
||||
$toggle.on('toggle', function () {
|
||||
$checkbox.trigger('change');
|
||||
});
|
||||
|
||||
// If checkbox is disabled then add the .disabled class to the toggle.
|
||||
if ($checkbox.attr('disabled') || $checkbox.attr('readonly')) {
|
||||
$toggle.addClass('disabled');
|
||||
}
|
||||
|
||||
// Add .clearfix to the wrapper.
|
||||
$wrapper.addClass('clearfix');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Track the disabling of a toggle's checkbox using states.
|
||||
if ($.fn.toggles) {
|
||||
$(document).on('state:disabled', function (event) {
|
||||
$('.js-webform-toggle').each(function () {
|
||||
var $toggle = $(this);
|
||||
var $wrapper = $toggle.parent();
|
||||
var $checkbox = $wrapper.find('input[type="checkbox"]');
|
||||
var isDisabled = ($checkbox.attr('disabled') || $checkbox.attr('readonly'));
|
||||
$toggle[isDisabled ? 'disabled' : 'disabled']();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
})(jQuery, Drupal);
|
|
@ -0,0 +1,16 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript to disable back button.
|
||||
*/
|
||||
|
||||
(function () {
|
||||
|
||||
'use strict';
|
||||
|
||||
// From: http://stackoverflow.com/questions/17962130/restrict-user-to-refresh-and-back-forward-in-any-browser
|
||||
history.pushState({page: 1}, 'Title 1', '#no-back');
|
||||
window.onhashchange = function (event) {
|
||||
window.location.hash = 'no-back';
|
||||
};
|
||||
|
||||
})();
|
148
2017/web/modules/contrib/webform/js/webform.form.js
Normal file
148
2017/web/modules/contrib/webform/js/webform.form.js
Normal file
|
@ -0,0 +1,148 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for webforms.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Remove single submit event listener.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the behavior for removing single submit event listener.
|
||||
*
|
||||
* @see Drupal.behaviors.formSingleSubmit
|
||||
*/
|
||||
Drupal.behaviors.weformRemoveFormSingleSubmit = {
|
||||
attach: function attach() {
|
||||
function onFormSubmit(e) {
|
||||
var $form = $(e.currentTarget);
|
||||
$form.removeAttr('data-drupal-form-submit-last');
|
||||
}
|
||||
$('body')
|
||||
.once('webform-single-submit')
|
||||
.on('submit.singleSubmit', 'form.webform-remove-single-submit:not([method~="GET"])', onFormSubmit);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Autofocus first input.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the behavior for the webform autofocusing.
|
||||
*/
|
||||
Drupal.behaviors.webformAutofocus = {
|
||||
attach: function (context) {
|
||||
$(context).find('.webform-submission-form.js-webform-autofocus :input:visible:enabled:first').focus();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Prevent webform autosubmit on wizard pages.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the behavior for disabling webform autosubmit.
|
||||
* Wizard pages need to be progressed with the Previous or Next buttons, not by pressing Enter.
|
||||
*/
|
||||
Drupal.behaviors.webformDisableAutoSubmit = {
|
||||
attach: function (context) {
|
||||
// @see http://stackoverflow.com/questions/11235622/jquery-disable-form-submit-on-enter
|
||||
$(context).find('.webform-submission-form.js-webform-disable-autosubmit input')
|
||||
.not(':button, :submit, :reset, :image, :file')
|
||||
.once('webform-disable-autosubmit')
|
||||
.on('keyup keypress', function (e) {
|
||||
var keyCode = e.keyCode || e.which;
|
||||
if (keyCode === 13) {
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Skip client-side validation when submit button is pressed.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the behavior for the skipping client-side validation.
|
||||
*/
|
||||
Drupal.behaviors.webformSubmitNoValidate = {
|
||||
attach: function (context) {
|
||||
$(context).find(':submit.js-webform-novalidate').once('webform-novalidate').on('click', function () {
|
||||
$(this.form).attr('novalidate', 'novalidate');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Attach behaviors to trigger submit button from input onchange.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches form trigger submit events.
|
||||
*/
|
||||
Drupal.behaviors.webformSubmitTrigger = {
|
||||
attach: function (context) {
|
||||
$('[data-webform-trigger-submit]').once('webform-trigger-submit').on('change', function () {
|
||||
var submit = $(this).attr('data-webform-trigger-submit');
|
||||
$(submit).mousedown();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Custom required error message.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the behavior for the webform custom required error message.
|
||||
*
|
||||
* @see http://stackoverflow.com/questions/5272433/html5-form-required-attribute-set-custom-validation-message
|
||||
*/
|
||||
Drupal.behaviors.webformRequiredError = {
|
||||
attach: function (context) {
|
||||
$(context).find(':input[data-webform-required-error]').once('webform-required-error')
|
||||
.on('invalid', function () {
|
||||
this.setCustomValidity('');
|
||||
if (!this.valid) {
|
||||
this.setCustomValidity($(this).attr('data-webform-required-error'));
|
||||
}
|
||||
})
|
||||
.on('input, change', function () {
|
||||
// Find all related elements by name and reset custom validity.
|
||||
// This specifically applies to required radios and checkboxes.
|
||||
var name = $(this).attr('name');
|
||||
$(this.form).find(':input[name="' + name + '"]').each(function () {
|
||||
this.setCustomValidity('');
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// When #state:required is triggered we need to reset the target elements
|
||||
// custom validity.
|
||||
$(document).on('state:required', function (e) {
|
||||
$(e.target).filter('[data-webform-required-error]')
|
||||
.each(function () {this.setCustomValidity('');});
|
||||
});
|
||||
|
||||
if (window.imceInput) {
|
||||
window.imceInput.processUrlInput = function (i, el) {
|
||||
var button = imceInput.createUrlButton(el.id, el.getAttribute('data-imce-type'));
|
||||
el.parentNode.insertAfter(button, el);
|
||||
};
|
||||
}
|
||||
|
||||
})(jQuery, Drupal);
|
|
@ -0,0 +1,18 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript to allow back button submit wizard page.
|
||||
*/
|
||||
|
||||
(function ($) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// From: https://stackoverflow.com/a/39019647
|
||||
if (window.history && window.history.pushState) {
|
||||
window.history.pushState('', null, '');
|
||||
window.onpopstate = function (event) {
|
||||
$('#edit-wizard-prev, #edit-preview-prev').click();
|
||||
};
|
||||
}
|
||||
|
||||
})(jQuery);
|
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for preventing duplicate webform submissions.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Submit once.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the behavior for preventing duplicate webform submissions.
|
||||
*/
|
||||
Drupal.behaviors.webformSubmitOnce = {
|
||||
attach: function (context) {
|
||||
$('.js-webform-submit-once', context).each(function () {
|
||||
var $form = $(this);
|
||||
// Remove data-webform-submitted.
|
||||
$form.removeData('webform-submitted');
|
||||
// Remove .js-webform-submit-clicked.
|
||||
$form.find('.form-actions :submit').removeClass('js-webform-submit-clicked');
|
||||
|
||||
// Track which submit button was clicked.
|
||||
// @see http://stackoverflow.com/questions/5721724/jquery-how-to-get-which-button-was-clicked-upon-form-submission
|
||||
$form.find('.form-actions :submit').click(function () {
|
||||
$form.find('.form-actions :submit')
|
||||
.removeClass('js-webform-submit-clicked');
|
||||
$(this)
|
||||
.addClass('js-webform-submit-clicked');
|
||||
});
|
||||
|
||||
$(this).submit(function () {
|
||||
// Don't submit if client-side validation has failed.
|
||||
if ($.isFunction(jQuery.fn.valid) && !($form.valid())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Track webform submitted.
|
||||
if ($form.data('webform-submitted')) {
|
||||
return false;
|
||||
}
|
||||
$form.data('webform-submitted', 'true');
|
||||
|
||||
// Visually disable all submit buttons.
|
||||
// Submit buttons can't disabled because their op(eration) must to be posted back to the server.
|
||||
$form.find('.form-actions :submit').addClass('is-disabled');
|
||||
|
||||
// Set the throbber progress indicator.
|
||||
// @see Drupal.Ajax.prototype.setProgressIndicatorThrobber
|
||||
var $clickedButton = $form.find('.form-actions :submit.js-webform-submit-clicked');
|
||||
var $progress = $('<div class="ajax-progress ajax-progress-throbber"><div class="throbber"> </div></div>');
|
||||
$clickedButton.after($progress);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
48
2017/web/modules/contrib/webform/js/webform.form.tabs.js
Normal file
48
2017/web/modules/contrib/webform/js/webform.form.tabs.js
Normal file
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for form tabs using jQuery UI.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// @see http://api.jqueryui.com/tabs/
|
||||
Drupal.webform = Drupal.webform || {};
|
||||
Drupal.webform.formTabs = Drupal.webform.formTabs || {};
|
||||
Drupal.webform.formTabs.options = Drupal.webform.formTabs.options || {
|
||||
hide: true,
|
||||
show: true
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize webform tabs.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the behavior for form tabs using jQuery UI.
|
||||
*
|
||||
* @see \Drupal\webform\Utility\WebformFormHelper::buildTabs
|
||||
*/
|
||||
Drupal.behaviors.webformFormTabs = {
|
||||
attach: function (context) {
|
||||
$(context).find('div.webform-tabs').once('webform-tabs').each(function () {
|
||||
var $tabs = $(this);
|
||||
var options = jQuery.extend({}, Drupal.webform.formTabs.options);
|
||||
|
||||
// Set active tab and clear the location hash once it is set.
|
||||
if (location.hash) {
|
||||
var active = $('a[href="' + location.hash + '"]').data('tab-index');
|
||||
if (typeof active !== 'undefined') {
|
||||
options.active = active;
|
||||
location.hash = '';
|
||||
}
|
||||
}
|
||||
|
||||
$tabs.tabs(options);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
99
2017/web/modules/contrib/webform/js/webform.form.unsaved.js
Normal file
99
2017/web/modules/contrib/webform/js/webform.form.unsaved.js
Normal file
|
@ -0,0 +1,99 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for unsaved webforms.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
var unsaved = false;
|
||||
|
||||
/**
|
||||
* Unsaved changes.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the behavior for unsaved changes.
|
||||
*/
|
||||
Drupal.behaviors.webformUnsaved = {
|
||||
attach: function (context) {
|
||||
// Look for the 'data-webform-unsaved' attribute which indicates that the
|
||||
// multi-step webform has unsaved data.
|
||||
// @see \Drupal\webform\WebformSubmissionForm::buildForm
|
||||
if ($('.js-webform-unsaved[data-webform-unsaved]').length) {
|
||||
unsaved = true;
|
||||
}
|
||||
else {
|
||||
$('.js-webform-unsaved :input:not(:button, :submit, :reset)', context).once('webform-unsaved').on('change keypress', function (event, param1) {
|
||||
// Ignore events triggered when #states API is changed,
|
||||
// which passes 'webform.states' as param1.
|
||||
// @see webform.states.js ::triggerEventHandlers().
|
||||
if (param1 !== 'webform.states') {
|
||||
unsaved = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$('.js-webform-unsaved button, .js-webform-unsaved input[type="submit"]', context).once('webform-unsaved').on('click', function (event) {
|
||||
// For reset button we must confirm unsaved changes before the
|
||||
// before unload event handler.
|
||||
if ($(this).hasClass('webform-button--reset') && unsaved) {
|
||||
if (!window.confirm(Drupal.t('Changes you made may not be saved.') + '\n\n' + Drupal.t('Press OK to leave this page or Cancel to stay.'))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
unsaved = false;
|
||||
});
|
||||
|
||||
// Track all CKEditor change events.
|
||||
// @see https://ckeditor.com/old/forums/Support/CKEditor-jQuery-change-event
|
||||
if (window.CKEDITOR && !CKEDITOR.webformUnsaved) {
|
||||
CKEDITOR.webformUnsaved = true;
|
||||
CKEDITOR.on('instanceCreated', function (event) {
|
||||
event.editor.on('change', function (evt) {
|
||||
unsaved = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$(window).on('beforeunload', function () {
|
||||
if (unsaved) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* An experimental shim to partially emulate onBeforeUnload on iOS.
|
||||
* Part of https://github.com/codedance/jquery.AreYouSure/
|
||||
*
|
||||
* Copyright (c) 2012-2014, Chris Dance and PaperCut Software http://www.papercut.com/
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* Author: chris.dance@papercut.com
|
||||
* Date: 19th May 2014
|
||||
*/
|
||||
$(function () {
|
||||
if (!navigator.userAgent.toLowerCase().match(/iphone|ipad|ipod|opera/)) {
|
||||
return;
|
||||
}
|
||||
$('a').bind('click', function (evt) {
|
||||
var href = $(evt.target).closest('a').attr('href');
|
||||
if (typeof href !== 'undefined' && !(href.match(/^#/) || href.trim() === '')) {
|
||||
if ($(window).triggerHandler('beforeunload')) {
|
||||
if (!window.confirm(Drupal.t('Changes you made may not be saved.') + '\n\n' + Drupal.t('Press OK to leave this page or Cancel to stay.'))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
window.location.href = href;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
})(jQuery, Drupal);
|
36
2017/web/modules/contrib/webform/js/webform.help.js
Normal file
36
2017/web/modules/contrib/webform/js/webform.help.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for help.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Handles disabling help dialog for mobile devices.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the behavior for disabling help dialog for mobile devices.
|
||||
*/
|
||||
Drupal.behaviors.webformHelpDialog = {
|
||||
attach: function (context) {
|
||||
$(context).find('.button-webform-play').once('webform-help-dialog').on('click', function (event) {
|
||||
if ($(window).width() < 768) {
|
||||
event.stopImmediatePropagation();
|
||||
}
|
||||
}).each(function () {
|
||||
// Must make sure that this click event handler is execute first and
|
||||
// before the Ajax dialog handler.
|
||||
// @see http://stackoverflow.com/questions/2360655/jquery-event-handlers-always-execute-in-order-they-were-bound-any-way-around-t
|
||||
var handlers = $._data(this, 'events')['click'];
|
||||
var handler = handlers.pop();
|
||||
// Move it at the beginning.
|
||||
handlers.splice(0, 0, handler);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
23
2017/web/modules/contrib/webform/js/webform.imce.js
Normal file
23
2017/web/modules/contrib/webform/js/webform.imce.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for IMCE.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Override processUrlInput to place the 'Open File Browser' links after the target element.
|
||||
*
|
||||
* @param {int} i
|
||||
* Element's index.
|
||||
* @param {element} el
|
||||
* A element.
|
||||
*/
|
||||
window.imceInput.processUrlInput = function (i, el) {
|
||||
var button = imceInput.createUrlButton(el.id, el.getAttribute('data-imce-type'));
|
||||
$(button).insertAfter($(el));
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors to fix jQuery UI dialogs.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Ensure that ckeditor has focus when displayed inside of jquery-ui dialog widget
|
||||
*
|
||||
* @see http://stackoverflow.com/questions/20533487/how-to-ensure-that-ckeditor-has-focus-when-displayed-inside-of-jquery-ui-dialog
|
||||
*/
|
||||
var _allowInteraction = $.ui.dialog.prototype._allowInteraction;
|
||||
$.ui.dialog.prototype._allowInteraction = function (event) {
|
||||
if ($(event.target).closest('.cke_dialog').length) {
|
||||
return true;
|
||||
}
|
||||
return _allowInteraction.apply(this, arguments);
|
||||
};
|
||||
|
||||
/**
|
||||
* Attaches webform dialog behaviors.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches event listeners for webform dialogs.
|
||||
*/
|
||||
Drupal.behaviors.webformDialogEvents = {
|
||||
attach: function () {
|
||||
$(window).once('webform-dialog').on({
|
||||
'dialog:aftercreate': function (event, dialog, $element, settings) {
|
||||
setTimeout(function () {
|
||||
var hasFocus = $element.find('[autofocus]:tabbable');
|
||||
if (!hasFocus.length) {
|
||||
// Move focus to first input which is not a button.
|
||||
hasFocus = $element.find(':input:tabbable:not(:button)');
|
||||
}
|
||||
if (!hasFocus.length) {
|
||||
// Move focus to close dialog button.
|
||||
hasFocus = $element.parent().find('.ui-dialog-titlebar-close');
|
||||
}
|
||||
hasFocus.eq(0).focus();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
39
2017/web/modules/contrib/webform/js/webform.off-canvas.js
Normal file
39
2017/web/modules/contrib/webform/js/webform.off-canvas.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for webform off-canvas dialogs.
|
||||
*
|
||||
* @see misc/dialog/off-canvas.js
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Attaches webform off-canvas behaviors.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches event listeners to window for off-canvas dialogs.
|
||||
*/
|
||||
Drupal.behaviors.webformOffCanvasEvents = {
|
||||
attach: function () {
|
||||
// Resize seven.theme tabs when off-canvas dialog opened and closed.
|
||||
// @see core/themes/seven/js/nav-tabs.js
|
||||
$(window).once('webform-off-canvas').on({
|
||||
'dialog:aftercreate': function (event, dialog, $element, settings) {
|
||||
if (Drupal.offCanvas.isOffCanvas($element)) {
|
||||
$(window).trigger('resize.tabs');
|
||||
}
|
||||
},
|
||||
'dialog:afterclose': function (event, dialog, $element, settings) {
|
||||
if (Drupal.offCanvas.isOffCanvas($element)) {
|
||||
$(window).trigger('resize.tabs');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
381
2017/web/modules/contrib/webform/js/webform.states.js
Normal file
381
2017/web/modules/contrib/webform/js/webform.states.js
Normal file
|
@ -0,0 +1,381 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for custom webform #states.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
Drupal.webform = Drupal.webform || {};
|
||||
Drupal.webform.states = Drupal.webform.states || {};
|
||||
Drupal.webform.states.slideDown = Drupal.webform.states.slideDown || {};
|
||||
Drupal.webform.states.slideDown.duration = 'slow';
|
||||
Drupal.webform.states.slideUp = Drupal.webform.states.slideUp || {};
|
||||
Drupal.webform.states.slideUp.duration = 'fast';
|
||||
|
||||
/**
|
||||
* Check if an element has a specified data attribute.
|
||||
*
|
||||
* @param {string} data
|
||||
* The data attribute name.
|
||||
*
|
||||
* @return {boolean}
|
||||
* TRUE if an element has a specified data attribute.
|
||||
*/
|
||||
$.fn.hasData = function (data) {
|
||||
return (typeof this.data(data) !== 'undefined');
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if element is within the webform or not.
|
||||
*
|
||||
* @return {boolean}
|
||||
* TRUE if element is within the webform.
|
||||
*/
|
||||
$.fn.isWebform = function () {
|
||||
return $(this).closest('form[id^="webform"]').length ? true : false;
|
||||
};
|
||||
|
||||
// The change event is triggered by cut-n-paste and select menus.
|
||||
// Issue #2445271: #states element empty check not triggered on mouse
|
||||
// based paste.
|
||||
// @see https://www.drupal.org/node/2445271
|
||||
Drupal.states.Trigger.states.empty.change = function change() {
|
||||
return this.val() === '';
|
||||
};
|
||||
|
||||
// Apply solution included in #1962800 patch.
|
||||
// Issue #1962800: Form #states not working with literal integers as
|
||||
// values in IE11.
|
||||
// @see https://www.drupal.org/project/drupal/issues/1962800
|
||||
// @see https://www.drupal.org/files/issues/core-states-not-working-with-integers-ie11_1962800_46.patch
|
||||
//
|
||||
// This issue causes pattern, less than, and greater than support to break.
|
||||
// @see https://www.drupal.org/project/webform/issues/2981724
|
||||
var states = Drupal.states;
|
||||
Drupal.states.Dependent.prototype.compare = function compare(reference, selector, state) {
|
||||
var value = this.values[selector][state.name];
|
||||
|
||||
var name = reference.constructor.name;
|
||||
if (!name) {
|
||||
name = $.type(reference);
|
||||
|
||||
name = name.charAt(0).toUpperCase() + name.slice(1);
|
||||
}
|
||||
if (name in states.Dependent.comparisons) {
|
||||
return states.Dependent.comparisons[name](reference, value);
|
||||
}
|
||||
|
||||
if (reference.constructor.name in states.Dependent.comparisons) {
|
||||
return states.Dependent.comparisons[reference.constructor.name](reference, value);
|
||||
}
|
||||
|
||||
return _compare2(reference, value);
|
||||
};
|
||||
function _compare2(a, b) {
|
||||
if (a === b) {
|
||||
return typeof a === 'undefined' ? a : true;
|
||||
}
|
||||
|
||||
return typeof a === 'undefined' || typeof b === 'undefined';
|
||||
}
|
||||
|
||||
// Adds pattern, less than, and greater than support to #state API.
|
||||
// @see http://drupalsun.com/julia-evans/2012/03/09/extending-form-api-states-regular-expressions
|
||||
Drupal.states.Dependent.comparisons.Object = function (reference, value) {
|
||||
if ('pattern' in reference) {
|
||||
return (new RegExp(reference['pattern'])).test(value);
|
||||
}
|
||||
else if ('!pattern' in reference) {
|
||||
return !((new RegExp(reference['!pattern'])).test(value));
|
||||
}
|
||||
else if ('less' in reference) {
|
||||
return (value !== '' && parseFloat(reference['less']) > parseFloat(value));
|
||||
}
|
||||
else if ('greater' in reference) {
|
||||
return (value !== '' && parseFloat(reference['greater']) < parseFloat(value));
|
||||
}
|
||||
else {
|
||||
return reference.indexOf(value) !== false;
|
||||
}
|
||||
};
|
||||
|
||||
var $document = $(document);
|
||||
|
||||
$document.on('state:required', function (e) {
|
||||
if (e.trigger && $(e.target).isWebform()) {
|
||||
var $target = $(e.target);
|
||||
// Fix #required file upload.
|
||||
// @see Issue #2860529: Conditional required File upload field don't work.
|
||||
if (e.value) {
|
||||
$target.find('input[type="file"]').attr({'required': 'required', 'aria-required': 'true'});
|
||||
}
|
||||
else {
|
||||
$target.find('input[type="file"]').removeAttr('required aria-required');
|
||||
}
|
||||
|
||||
// Fix required label for checkboxes and radios.
|
||||
// @see Issue #2938414: Checkboxes don't support #states required
|
||||
// @see Issue #2731991: Setting required on radios marks all options required.
|
||||
// @see Issue #2856315: Conditional Logic - Requiring Radios in a Fieldset.
|
||||
// Fix #required for fieldsets.
|
||||
// @see Issue #2977569: Hidden fieldsets that become visible with conditional logic cannot be made required.
|
||||
if ($target.is('.js-webform-type-radios, .js-webform-type-checkboxes, fieldset')) {
|
||||
if (e.value) {
|
||||
$target.find('legend span.fieldset-legend:not(.visually-hidden)').addClass('js-form-required form-required');
|
||||
}
|
||||
else {
|
||||
$target.find('legend span.fieldset-legend:not(.visually-hidden)').removeClass('js-form-required form-required');
|
||||
}
|
||||
}
|
||||
|
||||
// Fix #required for radios.
|
||||
// @see Issue #2856795: If radio buttons are required but not filled form is nevertheless submitted.
|
||||
if ($target.is('.js-webform-type-radios, .js-form-type-webform-radios-other')) {
|
||||
if (e.value) {
|
||||
$target.find('input[type="radio"]').attr({'required': 'required', 'aria-required': 'true'});
|
||||
}
|
||||
else {
|
||||
$target.find('input[type="radio"]').removeAttr('required aria-required');
|
||||
}
|
||||
}
|
||||
|
||||
// Fix #required for checkboxes.
|
||||
// @see Issue #2938414: Checkboxes don't support #states required.
|
||||
// @see checkboxRequiredhandler
|
||||
if ($target.is('.js-webform-type-checkboxes, .js-form-type-webform-checkboxes-other')) {
|
||||
var $checkboxes = $target.find('input[type="checkbox"]');
|
||||
if (e.value) {
|
||||
// Bind the event handler and add custom HTML5 required validation
|
||||
// to all checkboxes.
|
||||
$checkboxes.bind('click', checkboxRequiredhandler);
|
||||
if (!$checkboxes.is(':checked')) {
|
||||
$checkboxes.attr({'required': 'required', 'aria-required': 'true'});
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Remove custom HTML5 required validation from all checkboxes
|
||||
// and unbind the event handler.
|
||||
$checkboxes
|
||||
.removeAttr('required aria-required')
|
||||
.unbind('click', checkboxRequiredhandler);
|
||||
}
|
||||
}
|
||||
|
||||
// Issue #2986017: Fieldsets shouldn't have required attribute.
|
||||
if ($target.is('fieldset')) {
|
||||
$target.removeAttr('required aria-required');
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
$document.on('state:readonly', function (e) {
|
||||
if (e.trigger && $(e.target).isWebform()) {
|
||||
$(e.target).prop('readonly', e.value).closest('.js-form-item, .js-form-wrapper').toggleClass('webform-readonly', e.value).find('input, textarea').prop('readonly', e.value);
|
||||
}
|
||||
});
|
||||
|
||||
$document.on('state:visible state:visible-slide', function (e) {
|
||||
if (e.trigger && $(e.target).isWebform()) {
|
||||
if (e.value) {
|
||||
$(':input', e.target).addBack().each(function () {
|
||||
restoreValueAndRequired(this);
|
||||
triggerEventHandlers(this);
|
||||
});
|
||||
}
|
||||
else {
|
||||
// @see https://www.sitepoint.com/jquery-function-clear-form-data/
|
||||
$(':input', e.target).addBack().each(function () {
|
||||
backupValueAndRequired(this);
|
||||
clearValueAndRequired(this);
|
||||
triggerEventHandlers(this);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$document.bind('state:visible-slide', function (e) {
|
||||
if (e.trigger && $(e.target).isWebform()) {
|
||||
var effect = e.value ? 'slideDown' : 'slideUp';
|
||||
var duration = Drupal.webform.states[effect].duration;
|
||||
$(e.target).closest('.js-form-item, .js-form-submit, .js-form-wrapper')[effect](duration);
|
||||
}
|
||||
});
|
||||
Drupal.states.State.aliases['invisible-slide'] = '!visible-slide';
|
||||
|
||||
$document.on('state:disabled', function (e) {
|
||||
if (e.trigger && $(e.target).isWebform()) {
|
||||
// Make sure disabled property is set before triggering webform:disabled.
|
||||
// Copied from: core/misc/states.js
|
||||
$(e.target)
|
||||
.prop('disabled', e.value)
|
||||
.closest('.js-form-item, .js-form-submit, .js-form-wrapper').toggleClass('form-disabled', e.value)
|
||||
.find('select, input, textarea, button').prop('disabled', e.value);
|
||||
|
||||
// Trigger webform:disabled.
|
||||
$(e.target).trigger('webform:disabled')
|
||||
.find('select, input, textarea, button').trigger('webform:disabled');
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Trigger custom HTML5 multiple checkboxes validation.
|
||||
*
|
||||
* @see https://stackoverflow.com/a/37825072/145846
|
||||
*/
|
||||
function checkboxRequiredhandler() {
|
||||
var $checkboxes = $(this).closest('.js-webform-type-checkboxes, .js-form-type-webform-checkboxes-other').find('input[type="checkbox"]');
|
||||
if ($checkboxes.is(':checked')) {
|
||||
$checkboxes.removeAttr('required aria-required');
|
||||
}
|
||||
else {
|
||||
$checkboxes.attr({'required': 'required', 'aria-required': 'true'});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger an input's event handlers.
|
||||
*
|
||||
* @param {element} input
|
||||
* An input.
|
||||
*/
|
||||
function triggerEventHandlers(input) {
|
||||
var $input = $(input);
|
||||
var type = input.type;
|
||||
var tag = input.tagName.toLowerCase();
|
||||
// Add 'webform.states' as extra parameter to event handlers.
|
||||
// @see Drupal.behaviors.webformUnsaved
|
||||
var extraParameters = ['webform.states'];
|
||||
if (type === 'checkbox' || type === 'radio') {
|
||||
$input
|
||||
.trigger('change', extraParameters)
|
||||
.trigger('blur', extraParameters);
|
||||
}
|
||||
else if (tag === 'select') {
|
||||
$input
|
||||
.trigger('change', extraParameters)
|
||||
.trigger('blur', extraParameters);
|
||||
}
|
||||
else if (type !== 'submit' && type !== 'button' && type !== 'file') {
|
||||
$input
|
||||
.trigger('input', extraParameters)
|
||||
.trigger('change', extraParameters)
|
||||
.trigger('keydown', extraParameters)
|
||||
.trigger('keyup', extraParameters)
|
||||
.trigger('blur', extraParameters);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Backup an input's current value and required attribute
|
||||
*
|
||||
* @param {element} input
|
||||
* An input.
|
||||
*/
|
||||
function backupValueAndRequired(input) {
|
||||
var $input = $(input);
|
||||
var type = input.type;
|
||||
var tag = input.tagName.toLowerCase(); // Normalize case.
|
||||
|
||||
// Backup required.
|
||||
if ($input.prop('required') && !$input.hasData('webform-required')) {
|
||||
$input.data('webform-required', true);
|
||||
}
|
||||
|
||||
// Backup value.
|
||||
if (!$input.hasData('webform-value')) {
|
||||
if (type === 'checkbox' || type === 'radio') {
|
||||
$input.data('webform-value', $input.prop('checked'));
|
||||
}
|
||||
else if (tag === 'select') {
|
||||
var values = [];
|
||||
$input.find('option:selected').each(function (i, option) {
|
||||
values[i] = option.value;
|
||||
});
|
||||
$input.data('webform-value', values);
|
||||
}
|
||||
else if (type !== 'submit' && type !== 'button') {
|
||||
$input.data('webform-value', input.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore an input's value and required attribute.
|
||||
*
|
||||
* @param {element} input
|
||||
* An input.
|
||||
*/
|
||||
function restoreValueAndRequired(input) {
|
||||
var $input = $(input);
|
||||
|
||||
// Restore value.
|
||||
var value = $input.data('webform-value');
|
||||
if (typeof value !== 'undefined') {
|
||||
var type = input.type;
|
||||
var tag = input.tagName.toLowerCase(); // Normalize case.
|
||||
|
||||
if (type === 'checkbox' || type === 'radio') {
|
||||
$input.prop('checked', value);
|
||||
}
|
||||
else if (tag === 'select') {
|
||||
$.each(value, function (i, option_value) {
|
||||
$input.find("option[value='" + option_value + "']").prop('selected', true);
|
||||
});
|
||||
}
|
||||
else if (type !== 'submit' && type !== 'button') {
|
||||
input.value = value;
|
||||
}
|
||||
$input.removeData('webform-value');
|
||||
}
|
||||
|
||||
// Restore required.
|
||||
var required = $input.data('webform-required');
|
||||
if (typeof required !== 'undefined') {
|
||||
if (required) {
|
||||
$input.prop('required', true);
|
||||
}
|
||||
$input.removeData('webform-required');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear an input's value and required attributes.
|
||||
*
|
||||
* @param {element} input
|
||||
* An input.
|
||||
*/
|
||||
function clearValueAndRequired(input) {
|
||||
var $input = $(input);
|
||||
|
||||
// Check for #states no clear attribute.
|
||||
// @see https://css-tricks.com/snippets/jquery/make-an-jquery-hasattr/
|
||||
if ($input.closest('[data-webform-states-no-clear]').length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear value.
|
||||
var type = input.type;
|
||||
var tag = input.tagName.toLowerCase(); // Normalize case.
|
||||
if (type === 'checkbox' || type === 'radio') {
|
||||
$input.prop('checked', false);
|
||||
}
|
||||
else if (tag === 'select') {
|
||||
if ($input.find('option[value=""]').length) {
|
||||
$input.val('');
|
||||
}
|
||||
else {
|
||||
input.selectedIndex = -1;
|
||||
}
|
||||
}
|
||||
else if (type !== 'submit' && type !== 'button') {
|
||||
input.value = (type === 'color') ? '#000000' : '';
|
||||
}
|
||||
|
||||
// Clear required.
|
||||
$input.prop('required', false);
|
||||
}
|
||||
|
||||
})(jQuery, Drupal);
|
100
2017/web/modules/contrib/webform/js/webform.tooltip.js
Normal file
100
2017/web/modules/contrib/webform/js/webform.tooltip.js
Normal file
|
@ -0,0 +1,100 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for jQuery UI tooltip integration.
|
||||
*
|
||||
* Please Note:
|
||||
* jQuery UI's tooltip implementation is not very responsive or adaptive.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2207383
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
var tooltipDefaultOptions = {
|
||||
// @see https://stackoverflow.com/questions/18231315/jquery-ui-tooltip-html-with-links
|
||||
show: {delay: 100},
|
||||
close: function (event, ui) {
|
||||
ui.tooltip.hover(
|
||||
function () {
|
||||
$(this).stop(true).fadeTo(400, 1);
|
||||
},
|
||||
function () {
|
||||
$(this).fadeOut('400', function () {
|
||||
$(this).remove();
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// @see http://api.jqueryui.com/tooltip/
|
||||
Drupal.webform = Drupal.webform || {};
|
||||
|
||||
Drupal.webform.tooltipElement = Drupal.webform.tooltipElement || {};
|
||||
Drupal.webform.tooltipElement.options = Drupal.webform.tooltipElement.options || tooltipDefaultOptions;
|
||||
|
||||
Drupal.webform.tooltipLink = Drupal.webform.tooltipLink || {};
|
||||
Drupal.webform.tooltipLink.options = Drupal.webform.tooltipLink.options || tooltipDefaultOptions;
|
||||
|
||||
/**
|
||||
* Initialize jQuery UI tooltip element support.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformTooltipElement = {
|
||||
attach: function (context) {
|
||||
$(context).find('.js-webform-tooltip-element').once('webform-tooltip-element').each(function () {
|
||||
var $element = $(this);
|
||||
|
||||
// Checkboxes, radios, buttons, toggles, etc… use fieldsets.
|
||||
// @see \Drupal\webform\Plugin\WebformElement\OptionsBase::prepare
|
||||
var $description;
|
||||
if ($element.is('fieldset')) {
|
||||
$description = $element.find('> .fieldset-wrapper > .description > .webform-element-description.visually-hidden');
|
||||
}
|
||||
else {
|
||||
$description = $element.find('> .description > .webform-element-description.visually-hidden');
|
||||
}
|
||||
|
||||
var has_visible_input = $element.find(':input:not([type=hidden])').length;
|
||||
var has_checkboxes_or_radios = $element.find(':checkbox, :radio').length;
|
||||
var is_composite = $element.hasClass('form-composite');
|
||||
var is_custom = $element.is('.js-form-type-webform-signature, .js-form-type-webform-image-select, .js-form-type-webform-mapping, .js-form-type-webform-rating, .js-form-type-datelist, .js-form-type-datetime');
|
||||
|
||||
var items;
|
||||
if (has_visible_input && !has_checkboxes_or_radios && !is_composite && !is_custom) {
|
||||
items = ':input';
|
||||
}
|
||||
else {
|
||||
items = $element;
|
||||
}
|
||||
|
||||
var options = $.extend({
|
||||
items: items,
|
||||
content: $description.html()
|
||||
}, Drupal.webform.tooltipElement.options);
|
||||
|
||||
$element.tooltip(options);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize jQuery UI tooltip link support.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformTooltipLink = {
|
||||
attach: function (context) {
|
||||
$(context).find('.js-webform-tooltip-link').once('webform-tooltip-link').each(function () {
|
||||
var $link = $(this);
|
||||
|
||||
var options = $.extend({}, Drupal.webform.tooltipLink.options);
|
||||
|
||||
$link.tooltip(options);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
61
2017/web/modules/contrib/webform/js/webform.wizard.pages.js
Normal file
61
2017/web/modules/contrib/webform/js/webform.wizard.pages.js
Normal file
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for webform wizard.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Link the wizard's previous pages.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Links the wizard's previous pages.
|
||||
*/
|
||||
Drupal.behaviors.webformWizardPagesLink = {
|
||||
attach: function (context) {
|
||||
$('.js-webform-wizard-pages-links', context).once('webform-wizard-pages-links').each(function () {
|
||||
var $pages = $(this);
|
||||
var $form = $pages.closest('form');
|
||||
|
||||
var hasProgressLink = $pages.data('wizard-progress-link');
|
||||
var hasPreviewLink = $pages.data('wizard-preview-link');
|
||||
|
||||
$pages.find('.js-webform-wizard-pages-link').each(function () {
|
||||
var $button = $(this);
|
||||
var title = $button.attr('title');
|
||||
var page = $button.data('webform-page');
|
||||
|
||||
// Link progress marker and title.
|
||||
if (hasProgressLink) {
|
||||
var $progress = $form.find('.webform-progress [data-webform-page="' + page + '"]');
|
||||
$progress.find('.progress-marker, .progress-title')
|
||||
.attr({
|
||||
'role': 'link',
|
||||
'title': title,
|
||||
'aria-label': title
|
||||
})
|
||||
.click(function () {
|
||||
$button.click();
|
||||
});
|
||||
// Only allow the marker to be tabbable.
|
||||
$progress.find('.progress-marker').attr('tabindex', 0);
|
||||
}
|
||||
|
||||
// Move button to preview page div container with [data-webform-page].
|
||||
// @see \Drupal\webform\Plugin\WebformElement\WebformWizardPage::formatHtmlItem
|
||||
if (hasPreviewLink) {
|
||||
$form
|
||||
.find('.webform-preview [data-webform-page="' + page + '"]')
|
||||
.append($button)
|
||||
.show();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
67
2017/web/modules/contrib/webform/js/webform.wizard.track.js
Normal file
67
2017/web/modules/contrib/webform/js/webform.wizard.track.js
Normal file
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for webform wizard.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Tracks the wizard's current page in the URL.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Tracks the wizard's current page in the URL.
|
||||
*/
|
||||
Drupal.behaviors.webformWizardTrackPage = {
|
||||
attach: function (context) {
|
||||
// Make sure on page load or Ajax refresh the location ?page is correct
|
||||
// since conditional logic can skip pages.
|
||||
// Note: window.history is only supported by IE 10+.
|
||||
if (window.history && window.history.replaceState) {
|
||||
// Track the form's current page for 8.5.x and below.
|
||||
// @todo Remove the below code once only 8.6.x is supported.
|
||||
// @see https://www.drupal.org/project/drupal/issues/2508796
|
||||
$('form[data-webform-wizard-current-page]', context)
|
||||
.once('webform-wizard-current-page')
|
||||
.each(function () {
|
||||
trackPage(this);
|
||||
});
|
||||
|
||||
// Track the form's current page for 8.6.x and above.
|
||||
if ($(context).hasData('webform-wizard-current-page')) {
|
||||
trackPage(context);
|
||||
}
|
||||
}
|
||||
|
||||
// When paging next and back update the URL so that Drupal knows what
|
||||
// the expected page name or index is going to be.
|
||||
// NOTE: If conditional wizard page logic is configured the
|
||||
// expected page name or index may not be accurate.
|
||||
$(':button[data-webform-wizard-page], :submit[data-webform-wizard-page]', context).once('webform-wizard-page').on('click', function () {
|
||||
var page = $(this).attr('data-webform-wizard-page');
|
||||
this.form.action = this.form.action.replace(/\?.+$/, '') + '?page=' + page;
|
||||
});
|
||||
|
||||
/**
|
||||
* Append the form's current page data attribute to the browser's URL.
|
||||
*
|
||||
* @param {HTMLElement} form
|
||||
* The form element.
|
||||
*/
|
||||
function trackPage(form) {
|
||||
var $form = $(form);
|
||||
// Make sure the form is visible before updating the URL.
|
||||
if ($form.is(':visible')) {
|
||||
var page = $form.attr('data-webform-wizard-current-page');
|
||||
var url = window.location.toString().replace(/\?.+$/, '') +
|
||||
'?page=' + page;
|
||||
window.history.replaceState(null, null, url);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
Reference in a new issue