Update Composer, update everything
This commit is contained in:
parent
ea3e94409f
commit
dda5c284b6
19527 changed files with 1135420 additions and 351004 deletions
|
@ -1,41 +0,0 @@
|
|||
/**
|
||||
* @file
|
||||
* Jquery plugin to find common ancestor.
|
||||
*
|
||||
* @see http://stackoverflow.com/questions/3217147/jquery-first-parent-containing-all-children
|
||||
*/
|
||||
|
||||
(function ($) {
|
||||
|
||||
'use strict';
|
||||
|
||||
jQuery.fn.commonAncestor = function() {
|
||||
var parents = [];
|
||||
var minlen = Infinity;
|
||||
|
||||
$(this).each(function() {
|
||||
var curparents = $(this).parents();
|
||||
parents.push(curparents);
|
||||
minlen = Math.min(minlen, curparents.length);
|
||||
});
|
||||
|
||||
for (var i in parents) {
|
||||
parents[i] = parents[i].slice(parents[i].length - minlen);
|
||||
}
|
||||
|
||||
// Iterate until equality is found
|
||||
for (var i = 0; i < parents[0].length; i++) {
|
||||
var equal = true;
|
||||
for (var j in parents) {
|
||||
if (parents[j][i] != parents[0][i]) {
|
||||
equal = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (equal) return $(parents[0][i]);
|
||||
}
|
||||
return $([]);
|
||||
}
|
||||
|
||||
})(jQuery);
|
||||
|
26
web/modules/contrib/webform/js/webform.admin.dropbutton.js
Normal file
26
web/modules/contrib/webform/js/webform.admin.dropbutton.js
Normal file
|
@ -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);
|
|
@ -1,12 +1,136 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for admin pages.
|
||||
* JavaScript behaviors for admin pages.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
(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.
|
||||
*
|
||||
|
@ -42,8 +166,12 @@
|
|||
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') {
|
||||
$('.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;
|
||||
}
|
||||
|
||||
|
@ -58,4 +186,4 @@
|
|||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
||||
})(jQuery, Drupal, Drupal.debounce);
|
||||
|
|
19
web/modules/contrib/webform/js/webform.admin.tabledrag.js
Normal file
19
web/modules/contrib/webform/js/webform.admin.tabledrag.js
Normal file
|
@ -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);
|
|
@ -1,12 +1,206 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for AJAX.
|
||||
* 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.
|
||||
*
|
||||
|
@ -17,7 +211,7 @@
|
|||
* @param {string} response.selector
|
||||
* Selector to use.
|
||||
*
|
||||
* @see Drupal.AjaxCommands.prototype.webformScrollTop
|
||||
* @see Drupal.AjaxCommands.prototype.viewScrollTop
|
||||
*/
|
||||
Drupal.AjaxCommands.prototype.webformScrollTop = function (ajax, response) {
|
||||
// Scroll to the top of the view. This will allow users
|
||||
|
@ -32,10 +226,141 @@
|
|||
while ($(scrollTarget).scrollTop() === 0 && $(scrollTarget).parent()) {
|
||||
scrollTarget = $(scrollTarget).parent();
|
||||
}
|
||||
// Only scroll upward.
|
||||
if (offset.top - 10 < $(scrollTarget).scrollTop()) {
|
||||
$(scrollTarget).animate({scrollTop: (offset.top - 10)}, 500);
|
||||
|
||||
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);
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
* 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');
|
||||
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);
|
||||
|
|
50
web/modules/contrib/webform/js/webform.confirmation.modal.js
Normal file
50
web/modules/contrib/webform/js/webform.confirmation.modal.js
Normal file
|
@ -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
web/modules/contrib/webform/js/webform.contextual.js
Normal file
25
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);
|
|
@ -1,19 +1,75 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors to fix dialogs.
|
||||
* JavaScript behaviors for webform dialogs.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
(function ($, Drupal, drupalSettings) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// @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;
|
||||
// @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);
|
||||
});
|
||||
}
|
||||
return _allowInteraction.apply(this, arguments);
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
||||
})(jQuery, Drupal, drupalSettings);
|
||||
|
|
|
@ -1,12 +1,21 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for jQuery UI buttons element integration.
|
||||
* 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.
|
||||
*
|
||||
|
@ -14,19 +23,33 @@
|
|||
*/
|
||||
Drupal.behaviors.webformButtons = {
|
||||
attach: function (context) {
|
||||
$(context).find('.js-webform-buttons [type="radio"]').commonAncestor().once('webform-buttons').each(function () {
|
||||
var $input = $(this);
|
||||
// Remove all div and classes around radios and labels.
|
||||
$input.html($input.find('input[type="radio"], label').removeClass());
|
||||
// Create buttonset.
|
||||
$input.buttonset();
|
||||
// Disable buttonset.
|
||||
$input.buttonset('option', 'disabled', $input.find('input[type="radio"]:disabled').length);
|
||||
$(context).find(Drupal.webform.buttons.selector).once('webform-buttons').each(function () {
|
||||
var $buttons = $(this);
|
||||
|
||||
// Turn buttonset off/on when the input is disabled/enabled.
|
||||
// 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.buttonset('option', 'disabled', $input.find('input[type="radio"]:disabled').length);
|
||||
$input.checkboxradio('option', 'disabled', $input.is(':disabled'));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
76
web/modules/contrib/webform/js/webform.element.chosen.js
Normal file
76
web/modules/contrib/webform/js/webform.element.chosen.js
Normal file
|
@ -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);
|
|
@ -1,12 +1,17 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for CodeMirror integration.
|
||||
* 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.
|
||||
*
|
||||
|
@ -14,6 +19,9 @@
|
|||
*/
|
||||
Drupal.behaviors.webformCodeMirror = {
|
||||
attach: function (context) {
|
||||
if (!window.CodeMirror) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Webform CodeMirror editor.
|
||||
$(context).find('textarea.js-webform-codemirror').once('webform-codemirror').each(function () {
|
||||
|
@ -27,19 +35,37 @@
|
|||
// https://github.com/marijnh/CodeMirror-old/issues/59
|
||||
$(this).removeAttr('required');
|
||||
|
||||
var editor = CodeMirror.fromTextArea(this, {
|
||||
var options = $.extend({
|
||||
mode: $(this).attr('data-webform-codemirror-mode'),
|
||||
lineNumbers: true,
|
||||
lineWrapping: true,
|
||||
viewportMargin: Infinity,
|
||||
readOnly: $(this).prop('readonly') ? true : false,
|
||||
// Setting for using spaces instead of tabs - https://github.com/codemirror/CodeMirror/issues/988
|
||||
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');
|
||||
|
@ -59,45 +85,38 @@
|
|||
// 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'));
|
||||
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').html(), $(this).attr('data-webform-codemirror-mode'), this);
|
||||
CodeMirror.runMode($(this).addClass('cm-s-default').text(), $(this).attr('data-webform-codemirror-mode'), this);
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// Workaround: When a dialog opens we need to reference all CodeMirror
|
||||
// editors to make sure they are properly initialized and sized.
|
||||
$(window).on('dialog:aftercreate', function (dialog, $element, settings) {
|
||||
// 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 () {
|
||||
$('.CodeMirror').each(function (index, $element) {
|
||||
var $details = $(this).parents('details:not([open])');
|
||||
$details.attr('open', 'open');
|
||||
$element.CodeMirror.refresh();
|
||||
// Now, close details.
|
||||
$details.removeAttr('open');
|
||||
});
|
||||
}, 10);
|
||||
});
|
||||
|
||||
// On state:visible refresh CodeMirror elements.
|
||||
$(document).on('state:visible', function (event) {
|
||||
var $element = $(event.target);
|
||||
if ($element.hasClass('js-webform-codemirror')) {
|
||||
$element.parent().find('.CodeMirror').each(function (index, $element) {
|
||||
$element.CodeMirror.refresh();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery, Drupal);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for color element integration.
|
||||
* JavaScript behaviors for color element integration.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
@ -24,11 +24,21 @@
|
|||
.removeClass('form-color-large');
|
||||
}
|
||||
else {
|
||||
// Display color input's output to the end user.
|
||||
var $output = $('<input class="form-color-output ' + $element.attr('class') + ' js-webform-element-mask" data-inputmask-mask="\\#######" />').inputmask();
|
||||
// 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.
|
||||
|
@ -39,7 +49,7 @@
|
|||
$element[0].value = $output[0].value;
|
||||
});
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
42
web/modules/contrib/webform/js/webform.element.composite.js
Normal file
42
web/modules/contrib/webform/js/webform.element.composite.js
Normal file
|
@ -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);
|
64
web/modules/contrib/webform/js/webform.element.computed.js
Normal file
64
web/modules/contrib/webform/js/webform.element.computed.js
Normal file
|
@ -0,0 +1,64 @@
|
|||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
// Add event handler to elements that are used by the computed element.
|
||||
$.each(elementKeys, function (i, key) {
|
||||
$form.find(':input[name^="' + key + '"]')
|
||||
.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();
|
||||
|
||||
function triggerUpdate() {
|
||||
// Prevent duplicate computations.
|
||||
// @see Drupal.behaviors.formSingleSubmit
|
||||
var formValues = $form.find('input[name!=form_build_id]').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);
|
|
@ -1,12 +1,17 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for jQuery Word and Counter Counter integration.
|
||||
* 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.
|
||||
*
|
||||
|
@ -14,23 +19,39 @@
|
|||
*/
|
||||
Drupal.behaviors.webformCounter = {
|
||||
attach: function (context) {
|
||||
if (!$.fn.textcounter) {
|
||||
return;
|
||||
}
|
||||
|
||||
$(context).find('.js-webform-counter').once('webform-counter').each(function () {
|
||||
var options = {
|
||||
goal: $(this).attr('data-counter-limit'),
|
||||
msg: $(this).attr('data-counter-message')
|
||||
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: ''
|
||||
};
|
||||
// Only word type can be defined, otherwise the counter defaults to
|
||||
// character counting.
|
||||
if ($(this).attr('data-counter-type') == 'word') {
|
||||
options.type = 'word';
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
// Set the target to a div that is appended to end of the input's parent container.
|
||||
options.target = $('<div></div>');
|
||||
$(this).parent().append(options.target);
|
||||
options = $.extend(options, Drupal.webform.counter.options);
|
||||
|
||||
$(this).counter(options);
|
||||
})
|
||||
$(this).textcounter(options);
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
|
|
|
@ -7,6 +7,11 @@
|
|||
|
||||
'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.
|
||||
*
|
||||
|
@ -22,48 +27,70 @@
|
|||
Drupal.behaviors.date = {
|
||||
attach: function (context, settings) {
|
||||
var $context = $(context);
|
||||
// Skip if date are supported by the browser.
|
||||
if (Modernizr.inputtypes.date === true) {
|
||||
return;
|
||||
}
|
||||
$context.find('input[data-drupal-date-format]').once('datePicker').each(function () {
|
||||
var $input = $(this);
|
||||
var datepickerSettings = {};
|
||||
|
||||
// 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);
|
||||
|
||||
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
|
||||
datepickerSettings.dateFormat = dateFormat
|
||||
// Year.
|
||||
.replace('Y', 'yy')
|
||||
// @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')
|
||||
.replace('m', 'mm')
|
||||
.replace('n', 'm')
|
||||
// Date.
|
||||
.replace('d', 'dd');
|
||||
.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')) {
|
||||
datepickerSettings.minDate = $.datepicker.formatDate(datepickerSettings.dateFormat, $.datepicker.parseDate('yy-mm-dd', $input.attr('min')));
|
||||
options.minDate = $input.attr('min');
|
||||
}
|
||||
if ($input.attr('max')) {
|
||||
datepickerSettings.maxDate = $.datepicker.formatDate(datepickerSettings.dateFormat, $.datepicker.parseDate('yy-mm-dd', $input.attr('max')));
|
||||
options.maxDate = $input.attr('max');
|
||||
}
|
||||
|
||||
// Format default value.
|
||||
if ($input.val()) {
|
||||
$input.val($.datepicker.formatDate(datepickerSettings.dateFormat, $.datepicker.parseDate('yy-mm-dd', $input.val())));
|
||||
// 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');
|
||||
}
|
||||
|
||||
$input.datepicker(datepickerSettings);
|
||||
// First day of the week.
|
||||
options.firstDay = settings.webform.dateFirstDay;
|
||||
|
||||
$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);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for details element.
|
||||
* JavaScript behaviors for details element.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
@ -22,12 +22,18 @@
|
|||
$('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;
|
||||
var open = ($details.attr('open') !== 'open') ? '1' : '0';
|
||||
localStorage.setItem(name, open);
|
||||
});
|
||||
|
||||
|
@ -45,7 +51,7 @@
|
|||
return;
|
||||
}
|
||||
|
||||
if (open == 1) {
|
||||
if (open === '1') {
|
||||
$details.attr('open', 'open');
|
||||
}
|
||||
else {
|
||||
|
@ -59,10 +65,10 @@
|
|||
/**
|
||||
* Get the name used to store the state of details element.
|
||||
*
|
||||
* @param $details
|
||||
* @param {jQuery} $details
|
||||
* A details element.
|
||||
*
|
||||
* @returns string
|
||||
* @return {string}
|
||||
* The name used to store the state of details element.
|
||||
*/
|
||||
Drupal.webformDetailsSaveGetName = function ($details) {
|
||||
|
@ -91,12 +97,12 @@
|
|||
return '';
|
||||
}
|
||||
|
||||
// ISSUE: When Drupal renders a webform in a modal dialog it appends a unique
|
||||
// identifier to webform ids and details ids. (ie my-form--FeSFISegTUI)
|
||||
// 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);
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for details element.
|
||||
* 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.
|
||||
*
|
||||
|
@ -16,15 +20,27 @@
|
|||
attach: function (context) {
|
||||
$('.js-webform-details-toggle', context).once('webform-details-toggle').each(function () {
|
||||
var $form = $(this);
|
||||
var $details = $form.find('details');
|
||||
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;
|
||||
}
|
||||
|
||||
// Add toggle state link to first details element.
|
||||
$details.first().before($('<button type="button" class="link webform-details-toggle-state"></button>')
|
||||
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;
|
||||
|
@ -40,7 +56,7 @@
|
|||
|
||||
// Set the saved states for all the details elements.
|
||||
// @see webform.element.details.save.js
|
||||
if (Drupal.webformDetailsSaveGetName) {
|
||||
if (!Drupal.webformDetailsSaveGetName) {
|
||||
$form.find('details').each(function () {
|
||||
var name = Drupal.webformDetailsSaveGetName($(this));
|
||||
if (name) {
|
||||
|
@ -50,8 +66,16 @@
|
|||
}
|
||||
})
|
||||
.wrap('<div class="webform-details-toggle-state-wrapper"></div>')
|
||||
.parent()
|
||||
);
|
||||
.parent();
|
||||
|
||||
if ($tabs.length) {
|
||||
// Add toggle state before the tabs.
|
||||
$tabs.find('.item-list:first-child').before($toggle);
|
||||
}
|
||||
else {
|
||||
// Add toggle state link to first details element.
|
||||
$details.eq(0).before($toggle);
|
||||
}
|
||||
|
||||
setDetailsToggleLabel($form);
|
||||
});
|
||||
|
@ -61,25 +85,30 @@
|
|||
/**
|
||||
* Determine if a webform's details are all opened.
|
||||
*
|
||||
* @param $form
|
||||
* @param {jQuery} $form
|
||||
* A webform.
|
||||
*
|
||||
* @returns {boolean}
|
||||
* @return {boolean}
|
||||
* TRUE if a webform's details are all opened.
|
||||
*/
|
||||
function isFormDetailsOpen($form) {
|
||||
return ($form.find('details[open]').length == $form.find('details').length)
|
||||
return ($form.find('details[open]').length === $form.find('details').length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a webform's details toggle state widget label.
|
||||
*
|
||||
* @param $form
|
||||
* @param {jQuery} $form
|
||||
* A webform.
|
||||
*/
|
||||
function setDetailsToggleLabel($form) {
|
||||
var label = (isFormDetailsOpen($form)) ? Drupal.t('Collapse all') : Drupal.t('Expand all');
|
||||
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
web/modules/contrib/webform/js/webform.element.help.js
Normal file
73
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);
|
|
@ -1,12 +1,17 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for HTML editor integration.
|
||||
* 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.
|
||||
*
|
||||
|
@ -14,10 +19,40 @@
|
|||
*/
|
||||
Drupal.behaviors.webformHtmlEditor = {
|
||||
attach: function (context) {
|
||||
$(context).find('.js-form-type-webform-html-editor textarea').once('webform-html-editor').each(function () {
|
||||
var allowedContent = drupalSettings['webform']['html_editor']['allowedContent'];
|
||||
if (!window.CKEDITOR) {
|
||||
return;
|
||||
}
|
||||
|
||||
$(context).find('textarea.js-html-editor').once('webform-html-editor').each(function () {
|
||||
var $textarea = $(this);
|
||||
CKEDITOR.replace(this.id, {
|
||||
|
||||
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,
|
||||
|
@ -26,26 +61,76 @@
|
|||
// Use <br> tags instead of <p> tags.
|
||||
enterMode: CKEDITOR.ENTER_BR,
|
||||
shiftEnterMode: CKEDITOR.ENTER_BR,
|
||||
// Set height, hide the status bar, and remove plugins.
|
||||
// Set height.
|
||||
height: '100px',
|
||||
// Remove status bar.
|
||||
resize_enabled: false,
|
||||
removePlugins: 'elementspath,magicline',
|
||||
// Toolbar settings.
|
||||
format_tags: 'p;h2;h3;h4;h5;h6',
|
||||
toolbar: [
|
||||
{ name: 'styles', items: ['Format', 'Font', 'FontSize' ] },
|
||||
{ name: 'basicstyles', items: [ 'Bold', 'Italic', 'Subscript', 'Superscript' ] },
|
||||
{ name: 'insert', items: [ 'SpecialChar' ] },
|
||||
{ name: 'colors', items: [ 'TextColor', 'BGColor' ] },
|
||||
{ name: 'paragraph', items: [ 'NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'Blockquote'] },
|
||||
{ name: 'links', items: [ 'Link', 'Unlink'] },
|
||||
{ name: 'tools', items: [ 'Source', '-', 'Maximize' ] }
|
||||
]
|
||||
}).on('change', function (evt) {
|
||||
// Save data onchange since AJAX dialogs don't execute webform.onsubmit.
|
||||
$textarea.val(evt.editor.getData().trim());
|
||||
});
|
||||
})
|
||||
// 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.
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
110
web/modules/contrib/webform/js/webform.element.icheck.js
Normal file
110
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);
|
51
web/modules/contrib/webform/js/webform.element.inputhide.js
Normal file
51
web/modules/contrib/webform/js/webform.element.inputhide.js
Normal file
|
@ -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);
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for jquery.inputmask integration.
|
||||
* JavaScript behaviors for jquery.inputmask integration.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
@ -12,9 +12,13 @@
|
|||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformElementMask = {
|
||||
Drupal.behaviors.webformInputMask = {
|
||||
attach: function (context) {
|
||||
$(context).find('input.js-webform-element-mask').once('webform-element-mask').inputmask();
|
||||
if (!$.fn.inputmask) {
|
||||
return;
|
||||
}
|
||||
|
||||
$(context).find('input.js-webform-input-mask').once('webform-input-mask').inputmask();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
|
@ -1,53 +0,0 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for Geocomplete location integration.
|
||||
*/
|
||||
|
||||
(function ($, Drupal, drupalSettings) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Initialize location Geocompletion.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformLocation = {
|
||||
attach: function (context) {
|
||||
$(context).find('div.js-webform-location').once('webform-location').each(function () {
|
||||
var $element = $(this);
|
||||
var $geocomplete = $element.find('.webform-location-geocomplete').geocomplete({
|
||||
details: $element,
|
||||
detailsAttribute: 'data-webform-location-attribute',
|
||||
types: ['geocode']
|
||||
});
|
||||
|
||||
$geocomplete.on('input', function () {
|
||||
// Reset attributes on input.
|
||||
$element.find('[data-webform-location-attribute]').val('');
|
||||
}).on('blur', function () {
|
||||
// Make sure to get attributes on blur.
|
||||
if ($element.find('[data-webform-location-attribute="location"]').val() == '') {
|
||||
var value = $geocomplete.val();
|
||||
if (value) {
|
||||
$geocomplete.geocomplete('find', value);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 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-geolocation')) {
|
||||
navigator.geolocation.getCurrentPosition(function (position) {
|
||||
$geocomplete.geocomplete('find', position.coords.latitude + ', ' + position.coords.longitude);
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal, drupalSettings);
|
|
@ -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) ? 'disabled' : '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);
|
||||
|
109
web/modules/contrib/webform/js/webform.element.managed_file.js
Normal file
109
web/modules/contrib/webform/js/webform.element.managed_file.js
Normal file
|
@ -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);
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for message element integration.
|
||||
* JavaScript behaviors for message element integration.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
@ -31,13 +31,18 @@
|
|||
return;
|
||||
}
|
||||
|
||||
$element.show().find('.js-webform-message__link').on('click', function (event) {
|
||||
// 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();
|
||||
});
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -84,6 +89,7 @@
|
|||
|
||||
case 'user':
|
||||
case 'state':
|
||||
case 'custom':
|
||||
$.get($element.find('.js-webform-message__link').attr('href'));
|
||||
return true;
|
||||
}
|
||||
|
|
59
web/modules/contrib/webform/js/webform.element.more.js
Normal file
59
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);
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for message element integration.
|
||||
* JavaScript behaviors for multiple element.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
@ -12,15 +12,42 @@
|
|||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformMultiple = {
|
||||
Drupal.behaviors.webformMultipleTableDrag = {
|
||||
attach: function (context, settings) {
|
||||
for (var base in settings.tableDrag) {
|
||||
var $tableDrag = $(context).find('#' + base);
|
||||
var $toggleWeight = $tableDrag.parent().find('.tabledrag-toggle-weight');
|
||||
$toggleWeight.addClass('webform-multiple-tabledrag-toggle-weight');
|
||||
$tableDrag.after($toggleWeight);
|
||||
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);
|
|
@ -1,11 +1,11 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for other elements.
|
||||
* JavaScript behaviors for other elements.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Toggle other input (text) field.
|
||||
|
@ -14,21 +14,41 @@
|
|||
* 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) {
|
||||
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.
|
||||
$element.width($element.parent().width());
|
||||
// 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.slideDown();
|
||||
// Focus and require the input.
|
||||
$input.focus().prop('required', true);
|
||||
$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 (value !== undefined) {
|
||||
if (typeof value !== 'undefined') {
|
||||
$input.val(value);
|
||||
$input.get(0).setSelectionRange(0, 0);
|
||||
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) {
|
||||
|
@ -36,11 +56,12 @@
|
|||
});
|
||||
}
|
||||
else {
|
||||
$element.slideUp();
|
||||
// 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);
|
||||
$input.val('').prop('required', false).removeAttr('aria-required');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,13 +79,11 @@
|
|||
var $otherOption = $element.find('option[value="_other_"]');
|
||||
var $input = $element.find('.js-webform-select-other-input');
|
||||
|
||||
if ($otherOption.is(':selected')) {
|
||||
$input.show().find('input').prop('required', true);
|
||||
}
|
||||
|
||||
$select.on('change', function () {
|
||||
toggleOther($otherOption.is(':selected'), $input);
|
||||
});
|
||||
|
||||
toggleOther($otherOption.is(':selected'), $input, false);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -81,13 +100,11 @@
|
|||
var $checkbox = $element.find('input[value="_other_"]');
|
||||
var $input = $element.find('.js-webform-checkboxes-other-input');
|
||||
|
||||
if ($checkbox.is(':checked')) {
|
||||
$input.show().find('input').prop('required', true);
|
||||
}
|
||||
|
||||
$checkbox.on('change', function () {
|
||||
toggleOther(this.checked, $input);
|
||||
});
|
||||
|
||||
toggleOther($checkbox.is(':checked'), $input, false);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -105,13 +122,11 @@
|
|||
var $radios = $element.find('input[type="radio"]');
|
||||
var $input = $element.find('.js-webform-radios-other-input');
|
||||
|
||||
if ($radios.filter(':checked').val() === '_other_') {
|
||||
$input.show().find('input').prop('required', true);
|
||||
}
|
||||
|
||||
$radios.on('change', function () {
|
||||
toggleOther(($radios.filter(':checked').val() === '_other_'), $input);
|
||||
});
|
||||
|
||||
toggleOther(($radios.filter(':checked').val() === '_other_'), $input, false);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -128,28 +143,14 @@
|
|||
|
||||
var $buttons = $element.find('input[type="radio"]');
|
||||
var $input = $element.find('.js-webform-buttons-other-input');
|
||||
var $container = $(this).find('.js-webform-webform-buttons');
|
||||
|
||||
if ($buttons.filter(':checked').val() === '_other_') {
|
||||
$input.show().find('input').prop('required', true);
|
||||
}
|
||||
|
||||
// Note: Initializing buttonset here so that we can set the onchange
|
||||
// event handler.
|
||||
// @see Drupal.behaviors.webformButtons
|
||||
var $container = $(this).find('.form-radios');
|
||||
// Remove all div and classes around radios and labels.
|
||||
$container.html($container.find('input[type="radio"], label').removeClass());
|
||||
// Create buttonset and set onchange handler.
|
||||
$container.buttonset().change(function () {
|
||||
// Create set onchange handler.
|
||||
$container.change(function () {
|
||||
toggleOther(($(this).find(':radio:checked').val() === '_other_'), $input);
|
||||
});
|
||||
// Disable buttonset.
|
||||
$container.buttonset('option', 'disabled', $container.find('input[type="radio"]:disabled').length);
|
||||
// Turn buttonset off/on when the input is disabled/enabled.
|
||||
// @see webform.states.js
|
||||
$container.on('webform:disabled', function () {
|
||||
$container.buttonset('option', 'disabled', $container.find('input[type="radio"]:disabled').length);
|
||||
});
|
||||
|
||||
toggleOther(($buttons.filter(':checked').val() === '_other_'), $input, false);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,14 +1,6 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for radio buttons.
|
||||
*
|
||||
* Fix #states and #required for radios buttons.
|
||||
*
|
||||
* @see Issue #2856795: If radio buttons are required but not filled form is nevertheless submitted.
|
||||
* @see Issue #2856315: Conditional Logic - Requiring Radios in a Fieldset.
|
||||
* @see Issue #2731991: Setting required on radios marks all options required.
|
||||
* @see css/webform.form.css
|
||||
* @see /core/misc/states.js
|
||||
* JavaScript behaviors for radio buttons.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
@ -16,43 +8,18 @@
|
|||
'use strict';
|
||||
|
||||
/**
|
||||
* Attach handler to add .js-webform-radios-fieldset to radios wrapper fieldset.
|
||||
* 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.webformRadios = {
|
||||
Drupal.behaviors.webformRadiosRequired = {
|
||||
attach: function (context) {
|
||||
$('.js-webform-radios', context).closest('fieldset.form-composite').addClass('js-webform-radios-fieldset');
|
||||
$('.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'});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Make absolutely sure the below event handlers are triggered after
|
||||
// the /core/misc/states.js event handlers by attaching them after DOM load.
|
||||
$(function () {
|
||||
Drupal.behaviors.webformRadios.attach($(document));
|
||||
|
||||
function setRequired($target, required) {
|
||||
if (!$target.hasClass('js-webform-radios-fieldset')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (required) {
|
||||
$target.find('input[type="radio"]').attr({'required': 'required', 'aria-required': 'aria-required'})
|
||||
$target.find('legend span').addClass('js-form-required form-required');
|
||||
}
|
||||
else {
|
||||
$target.find('input[type="radio"]').removeAttr('required aria-required');
|
||||
$target.find('legend span').removeClass('js-form-required form-required');
|
||||
}
|
||||
}
|
||||
|
||||
setRequired($('.form-composite[required="required"]'), true);
|
||||
|
||||
$(document).on('state:required', function (e) {
|
||||
if (e.trigger) {
|
||||
setRequired($(e.target), e.value);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
})(jQuery, Drupal);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for range element integration.
|
||||
* JavaScript behaviors for range element integration.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
@ -8,54 +8,140 @@
|
|||
'use strict';
|
||||
|
||||
/**
|
||||
* Enhance HTML5 range element.
|
||||
* Display HTML5 range output in a left/right aligned number input.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformRange = {
|
||||
Drupal.behaviors.webformRangeOutputNumber = {
|
||||
attach: function (context) {
|
||||
$(context).find('.form-range[data-range-output]').once('webform-range').each(function () {
|
||||
var $element = $(this);
|
||||
$(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 prefix = $element.attr('data-range-output-prefix');
|
||||
var suffix = $element.attr('data-range-output-suffix');
|
||||
var $element = $(this);
|
||||
var $input = $element.find('input[type="range"]');
|
||||
var $output = $element.find('input[type="number"]');
|
||||
if (!$output.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Display range input's output to the end user.
|
||||
var html = '';
|
||||
html += '<div class="form-range-output-container">';
|
||||
html += (prefix ? '<span class="field-prefix">' + prefix + '</span>' : '');
|
||||
html += '<input type="number" min="' + $element.attr('min') + '" max="' + $element.attr('max') + '" step="' + $element.attr('step') + '" class="form-range-output form-number" />';
|
||||
html += (suffix ? '<span class="field-suffix">' + suffix + '</span>' : '');
|
||||
html += '</div>';
|
||||
// Set output value.
|
||||
$output.val($input.val());
|
||||
|
||||
var height = parseInt($element.outerHeight()) || 24;
|
||||
var $outputContainer = $(html);
|
||||
|
||||
// Set the container element's line height which will vertically
|
||||
// align the range widget and the output.
|
||||
$outputContainer.find('input, span').css({
|
||||
height: height + 'px',
|
||||
lineHeight: height + 'px'
|
||||
});
|
||||
|
||||
var $output = $outputContainer.find('input');
|
||||
$output[0].value = $element[0].value;
|
||||
$element
|
||||
.after($outputContainer)
|
||||
.css({float: 'left'});
|
||||
|
||||
// Sync $element and $output.
|
||||
$element.on('input', function () {
|
||||
$output[0].value = $element[0].value;
|
||||
// Sync input and output values.
|
||||
$input.on('input', function () {
|
||||
$output.val($input.val());
|
||||
});
|
||||
$output.on('input', function () {
|
||||
$element[0].value = $output[0].value;
|
||||
$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);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for RateIt integration.
|
||||
* 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.
|
||||
*
|
||||
|
@ -14,6 +17,10 @@
|
|||
*/
|
||||
Drupal.behaviors.webformRating = {
|
||||
attach: function (context) {
|
||||
if (!$.fn.rateit) {
|
||||
return;
|
||||
}
|
||||
|
||||
$(context)
|
||||
.find('[data-rateit-backingfld]')
|
||||
.once('webform-rating')
|
||||
|
@ -21,6 +28,11 @@
|
|||
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 () {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for roles element integration.
|
||||
* JavaScript behaviors for roles element integration.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
@ -17,7 +17,7 @@
|
|||
$(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');
|
||||
return ($(this).val() !== 'anonymous' && $(this).val() !== 'authenticated');
|
||||
});
|
||||
|
||||
$authenticated.on('click', function () {
|
||||
|
@ -32,7 +32,7 @@
|
|||
if ($authenticated.is(':checked')) {
|
||||
$checkboxes.prop('checked', true).attr('disabled', true);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for Select2 integration.
|
||||
* 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.
|
||||
*
|
||||
|
@ -14,13 +19,55 @@
|
|||
*/
|
||||
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%')
|
||||
.select2();
|
||||
.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);
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for signature pad integration.
|
||||
* 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.
|
||||
*
|
||||
|
@ -14,20 +19,29 @@
|
|||
*/
|
||||
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('input[type="submit"]');
|
||||
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 () {
|
||||
$canvas.attr('width', $wrapper.width());
|
||||
$canvas.attr('height', $wrapper.width() / 3);
|
||||
calculateDimensions();
|
||||
|
||||
// Resizing clears the canvas so we need to reset the signature pad.
|
||||
signaturePad.clear();
|
||||
|
@ -38,11 +52,12 @@
|
|||
});
|
||||
|
||||
// Initialize signature canvas.
|
||||
var signaturePad = new SignaturePad(canvas, {
|
||||
'onEnd': function () {
|
||||
var options = $.extend({
|
||||
onEnd: function () {
|
||||
$input.val(signaturePad.toDataURL());
|
||||
}
|
||||
});
|
||||
}, Drupal.webform.signaturePad.options);
|
||||
var signaturePad = new SignaturePad(canvas, options);
|
||||
|
||||
// Set value.
|
||||
if (value) {
|
||||
|
@ -52,17 +67,23 @@
|
|||
// Set reset handler.
|
||||
$button.on('click', function () {
|
||||
signaturePad.clear();
|
||||
$input.val();
|
||||
$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.
|
||||
|
|
|
@ -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);
|
|
@ -1,12 +1,17 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for Telephone element.
|
||||
* 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
|
||||
|
@ -14,25 +19,31 @@
|
|||
*/
|
||||
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('.form-item').append($error);
|
||||
$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
|
||||
$telephone.intlTelInput({
|
||||
'nationalMode': false
|
||||
});
|
||||
var options = $.extend({
|
||||
nationalMode: false,
|
||||
initialCountry: $telephone.attr('data-webform-telephone-international-initial-country') || ''
|
||||
}, Drupal.webform.intlTelInput.options);
|
||||
$telephone.intlTelInput(options);
|
||||
|
||||
var reset = function() {
|
||||
var reset = function () {
|
||||
$telephone.removeClass('error');
|
||||
$error.hide();
|
||||
};
|
||||
|
||||
$telephone.blur(function() {
|
||||
$telephone.blur(function () {
|
||||
reset();
|
||||
if ($.trim($telephone.val())) {
|
||||
if (!$telephone.intlTelInput('isValidNumber')) {
|
||||
|
@ -43,7 +54,7 @@
|
|||
});
|
||||
|
||||
$telephone.on('keyup change', reset);
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for Text format integration.
|
||||
* JavaScript behaviors for Text format integration.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
@ -15,11 +15,11 @@
|
|||
Drupal.behaviors.webformTextFormat = {
|
||||
attach: function (context) {
|
||||
$(context).find('.js-text-format-wrapper textarea').once('webform-text-format').each(function () {
|
||||
var $textarea = $(this);
|
||||
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 () {
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for time integration.
|
||||
* 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.
|
||||
*
|
||||
|
@ -17,18 +22,21 @@
|
|||
*/
|
||||
Drupal.behaviors.webformTime = {
|
||||
attach: function (context, settings) {
|
||||
var $context = $(context);
|
||||
// Skip if time inputs are supported by the browser.
|
||||
if (Modernizr.inputtypes.time === true) {
|
||||
if (!$.fn.timepicker) {
|
||||
return;
|
||||
}
|
||||
$context.find('input[type="time"]').once('timePicker').each(function () {
|
||||
|
||||
$(context).find('input[data-webform-time-format]').once('webformTimePicker').each(function () {
|
||||
var $input = $(this);
|
||||
|
||||
var options = {};
|
||||
if ($input.data('webformTimeFormat')) {
|
||||
options.timeFormat = $input.data('webformTimeFormat');
|
||||
// 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');
|
||||
}
|
||||
|
@ -49,9 +57,11 @@
|
|||
options.step = 1;
|
||||
}
|
||||
|
||||
options = $.extend(options, Drupal.webform.timePicker.options);
|
||||
|
||||
$input.timepicker(options);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for toggle integration.
|
||||
* 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.
|
||||
*
|
||||
|
@ -14,13 +19,17 @@
|
|||
*/
|
||||
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');
|
||||
|
||||
$toggle.toggles({
|
||||
var options = $.extend({
|
||||
checkbox: $checkbox,
|
||||
on: $checkbox.is(':checked'),
|
||||
clicker: $label,
|
||||
|
@ -28,6 +37,14 @@
|
|||
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.
|
||||
|
@ -36,21 +53,22 @@
|
|||
}
|
||||
|
||||
// Add .clearfix to the wrapper.
|
||||
$wrapper.addClass('clearfix')
|
||||
|
||||
$wrapper.addClass('clearfix');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Track the disabling of a toggle's checkbox using states.
|
||||
$(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'));
|
||||
(isDisabled) ? $toggle.addClass('disabled') : $toggle.removeClass('disabled');
|
||||
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);
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript to disable back button.
|
||||
* JavaScript to disable back button.
|
||||
*/
|
||||
|
||||
// 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";
|
||||
};
|
||||
(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';
|
||||
};
|
||||
|
||||
})();
|
||||
|
|
|
@ -1,12 +1,34 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for webforms.
|
||||
* 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.
|
||||
*
|
||||
|
@ -28,17 +50,21 @@
|
|||
*
|
||||
* @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').once('webform-disable-autosubmit').on('keyup keypress', function (e) {
|
||||
var keyCode = e.keyCode || e.which;
|
||||
if (keyCode === 13) {
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
$(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;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -52,90 +78,71 @@
|
|||
*/
|
||||
Drupal.behaviors.webformSubmitNoValidate = {
|
||||
attach: function (context) {
|
||||
$(context).find('input:submit.js-webform-novalidate').once('webform-novalidate').on('click', function () {
|
||||
$(context).find(':submit.js-webform-novalidate').once('webform-novalidate').on('click', function () {
|
||||
$(this.form).attr('novalidate', 'novalidate');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Disable validate when save draft submit button is clicked.
|
||||
* Attach behaviors to trigger submit button from input onchange.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the behavior for the webform draft submit button.
|
||||
* Attaches form trigger submit events.
|
||||
*/
|
||||
Drupal.behaviors.webformDraft = {
|
||||
Drupal.behaviors.webformSubmitTrigger = {
|
||||
attach: function (context) {
|
||||
$(context).find('#edit-draft').once('webform-draft').on('click', function () {
|
||||
$(this.form).attr('novalidate', 'novalidate');
|
||||
$('[data-webform-trigger-submit]').once('webform-trigger-submit').on('change', function () {
|
||||
var submit = $(this).attr('data-webform-trigger-submit');
|
||||
$(submit).mousedown();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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`
|
||||
* Custom required error message.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the behavior for the webform element filtering.
|
||||
* 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.webformFilterByText = {
|
||||
attach: function (context, settings) {
|
||||
var $input = $('input.webform-form-filter-text').once('webform-form-filter-text');
|
||||
var $table = $($input.attr('data-element'));
|
||||
var $filter_rows;
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
/**
|
||||
* 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.parent().parent();
|
||||
var textMatch = $label.text().toLowerCase().indexOf(query) !== -1;
|
||||
$row.toggle(textMatch);
|
||||
}
|
||||
|
||||
// Filter if the length of the query is at least 2 characters.
|
||||
if (query.length >= 2) {
|
||||
$filter_rows.each(toggleEntry);
|
||||
}
|
||||
else {
|
||||
$filter_rows.each(function (index) {
|
||||
$(this).parent().parent().show();
|
||||
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('');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if ($table.length) {
|
||||
$filter_rows = $table.find('div.webform-form-filter-text-source');
|
||||
$input.on('keyup', filterElementList);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 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);
|
||||
|
|
18
web/modules/contrib/webform/js/webform.form.submit_back.js
Normal file
18
web/modules/contrib/webform/js/webform.form.submit_back.js
Normal file
|
@ -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);
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for preventing duplicate webform submissions.
|
||||
* JavaScript behaviors for preventing duplicate webform submissions.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
@ -19,34 +19,43 @@
|
|||
attach: function (context) {
|
||||
$('.js-webform-submit-once', context).each(function () {
|
||||
var $form = $(this);
|
||||
$form.removeAttr('webform-submitted');
|
||||
$form.find('#edit-actions input[type="submit"]').removeAttr('webform-clicked');
|
||||
// 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('#edit-actions input[type="submit"]').click(function () {
|
||||
$form.find('#edit-actions input[type="submit"]').removeAttr('webform-clicked');
|
||||
$(this).attr('webform-clicked', 'true');
|
||||
$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 () {
|
||||
// Track webform submitted.
|
||||
if ($form.attr('webform-submitted')) {
|
||||
// Don't submit if client-side validation has failed.
|
||||
if ($.isFunction(jQuery.fn.valid) && !($form.valid())) {
|
||||
return false;
|
||||
}
|
||||
$form.attr('webform-submitted', 'true');
|
||||
|
||||
// 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('#edit-actions input[type="submit"]').addClass('is-disabled');
|
||||
$form.find('.form-actions :submit').addClass('is-disabled');
|
||||
|
||||
// Set the throbber progress indicator.
|
||||
// @see Drupal.Ajax.prototype.setProgressIndicatorThrobber
|
||||
var $clickedButton = $form.find('#edit-actions input[type=submit][webform-clicked=true]');
|
||||
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);
|
||||
});
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
48
web/modules/contrib/webform/js/webform.form.tabs.js
Normal file
48
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);
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for unsaved webforms.
|
||||
* JavaScript behaviors for unsaved webforms.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
@ -26,14 +26,38 @@
|
|||
unsaved = true;
|
||||
}
|
||||
else {
|
||||
$('.js-webform-unsaved :input:not(input[type=\'submit\'])', context).once('webform-unsaved').on('change keypress', function () {
|
||||
unsaved = true;
|
||||
$('.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 () {
|
||||
$('.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;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -43,7 +67,7 @@
|
|||
}
|
||||
});
|
||||
|
||||
/*!
|
||||
/**
|
||||
* An experimental shim to partially emulate onBeforeUnload on iOS.
|
||||
* Part of https://github.com/codedance/jquery.AreYouSure/
|
||||
*
|
||||
|
@ -60,9 +84,9 @@
|
|||
}
|
||||
$('a').bind('click', function (evt) {
|
||||
var href = $(evt.target).closest('a').attr('href');
|
||||
if (href !== undefined && !(href.match(/^#/) || href.trim() == '')) {
|
||||
if (typeof href !== 'undefined' && !(href.match(/^#/) || href.trim() === '')) {
|
||||
if ($(window).triggerHandler('beforeunload')) {
|
||||
if (!confirm(Drupal.t('Changes you made may not be saved.') + '\n\n' + Drupal.t('Press OK to leave this page or Cancel to stay.'))) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,36 +1,12 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for help.
|
||||
* JavaScript behaviors for help.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Handles help accordion.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the behavior for help accordion.
|
||||
*/
|
||||
Drupal.behaviors.webformHelpAccordion = {
|
||||
attach: function (context) {
|
||||
var $widget = $(context).find('.webform-help-accordion');
|
||||
$widget.once('webform-help-accordion').accordion({
|
||||
collapsible: true,
|
||||
heightStyle: "content"
|
||||
});
|
||||
|
||||
var $container = $('h3' + location.hash, $widget);
|
||||
if ($container.length) {
|
||||
var active = $widget.find($widget.accordion('option', 'header')).index($container);
|
||||
$widget.accordion('option', 'active', active);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles disabling help dialog for mobile devices.
|
||||
*
|
||||
|
@ -47,7 +23,7 @@
|
|||
}
|
||||
}).each(function () {
|
||||
// Must make sure that this click event handler is execute first and
|
||||
// before the AJAX dialog handler.
|
||||
// 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();
|
||||
|
|
23
web/modules/contrib/webform/js/webform.imce.js
Normal file
23
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);
|
52
web/modules/contrib/webform/js/webform.jquery.ui.dialog.js
Normal file
52
web/modules/contrib/webform/js/webform.jquery.ui.dialog.js
Normal file
|
@ -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
web/modules/contrib/webform/js/webform.off-canvas.js
Normal file
39
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);
|
|
@ -1,80 +1,277 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for custom webform #states.
|
||||
* JavaScript behaviors for custom webform #states.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// Make absolutely sure the below event handlers are triggered after
|
||||
// the /core/misc/states.js event handlers by attaching them after DOM load.
|
||||
$(function () {
|
||||
var $document = $(document);
|
||||
$document.on('state:visible', function (e) {
|
||||
if (!e.trigger) {
|
||||
return TRUE;
|
||||
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');
|
||||
}
|
||||
|
||||
if (!e.value) {
|
||||
// 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:not(.visually-hidden)').addClass('js-form-required form-required');
|
||||
}
|
||||
else {
|
||||
$target.find('legend span: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).andSelf().each(function () {
|
||||
var $input = $(this);
|
||||
$(':input', e.target).addBack().each(function () {
|
||||
backupValueAndRequired(this);
|
||||
clearValueAndRequired(this);
|
||||
triggerEventHandlers(this);
|
||||
});
|
||||
}
|
||||
else {
|
||||
$(':input', e.target).andSelf().each(function () {
|
||||
restoreValueAndRequired(this);
|
||||
triggerEventHandlers(this);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$document.on('state:disabled', function (e) {
|
||||
if (e.trigger) {
|
||||
$(e.target).trigger('webform:disabled')
|
||||
.find('select, input, textarea').trigger('webform:disabled');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$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 input
|
||||
* @param {element} input
|
||||
* An input.
|
||||
*/
|
||||
function triggerEventHandlers(input) {
|
||||
var $input = $(input);
|
||||
var type = input.type;
|
||||
var tag = input.tagName.toLowerCase(); // Normalize case.
|
||||
if (type == 'checkbox' || type == 'radio') {
|
||||
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')
|
||||
.trigger('blur');
|
||||
.trigger('change', extraParameters)
|
||||
.trigger('blur', extraParameters);
|
||||
}
|
||||
else if (tag == 'select') {
|
||||
else if (tag === 'select') {
|
||||
$input
|
||||
.trigger('change')
|
||||
.trigger('blur');
|
||||
.trigger('change', extraParameters)
|
||||
.trigger('blur', extraParameters);
|
||||
}
|
||||
else if (type != 'submit' && type != 'button') {
|
||||
else if (type !== 'submit' && type !== 'button' && type !== 'file') {
|
||||
$input
|
||||
.trigger('input')
|
||||
.trigger('change')
|
||||
.trigger('keydown')
|
||||
.trigger('keyup')
|
||||
.trigger('blur');
|
||||
.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 input
|
||||
* @param {element} input
|
||||
* An input.
|
||||
*/
|
||||
function backupValueAndRequired(input) {
|
||||
|
@ -83,31 +280,32 @@
|
|||
var tag = input.tagName.toLowerCase(); // Normalize case.
|
||||
|
||||
// Backup required.
|
||||
if ($input.prop('required')) {
|
||||
$input.data('webform-require', true);
|
||||
if ($input.prop('required') && !$input.hasData('webform-required')) {
|
||||
$input.data('webform-required', true);
|
||||
}
|
||||
|
||||
// Backup value.
|
||||
if (type == 'checkbox' || type == 'radio') {
|
||||
$input.data('webform-value', $input.prop('checked'));
|
||||
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);
|
||||
}
|
||||
}
|
||||
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 input
|
||||
* @param {element} input
|
||||
* An input.
|
||||
*/
|
||||
function restoreValueAndRequired(input) {
|
||||
|
@ -119,41 +317,52 @@
|
|||
var type = input.type;
|
||||
var tag = input.tagName.toLowerCase(); // Normalize case.
|
||||
|
||||
if (type == 'checkbox' || type == 'radio') {
|
||||
$input.prop('checked', value)
|
||||
if (type === 'checkbox' || type === 'radio') {
|
||||
$input.prop('checked', value);
|
||||
}
|
||||
else if (tag == 'select') {
|
||||
else if (tag === 'select') {
|
||||
$.each(value, function (i, option_value) {
|
||||
$input.find("option[value='" + option_value + "']").prop("selected", true);
|
||||
$input.find("option[value='" + option_value + "']").prop('selected', true);
|
||||
});
|
||||
}
|
||||
else if (type != 'submit' && type != 'button') {
|
||||
else if (type !== 'submit' && type !== 'button') {
|
||||
input.value = value;
|
||||
}
|
||||
$input.removeData('webform-value');
|
||||
}
|
||||
|
||||
// Restore required.
|
||||
if ($input.data('webform-required')) {
|
||||
$input.prop('required', TRUE);
|
||||
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 input
|
||||
* @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') {
|
||||
if (type === 'checkbox' || type === 'radio') {
|
||||
$input.prop('checked', false);
|
||||
}
|
||||
else if (tag == 'select') {
|
||||
else if (tag === 'select') {
|
||||
if ($input.find('option[value=""]').length) {
|
||||
$input.val('');
|
||||
}
|
||||
|
@ -161,8 +370,8 @@
|
|||
input.selectedIndex = -1;
|
||||
}
|
||||
}
|
||||
else if (type != 'submit' && type != 'button') {
|
||||
input.value = (type == 'color') ? '#000000' : '';
|
||||
else if (type !== 'submit' && type !== 'button') {
|
||||
input.value = (type === 'color') ? '#000000' : '';
|
||||
}
|
||||
|
||||
// Clear required.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* @file
|
||||
* Javascript behaviors for jQuery UI tooltip integration.
|
||||
* JavaScript behaviors for jQuery UI tooltip integration.
|
||||
*
|
||||
* Please Note:
|
||||
* jQuery UI's tooltip implementation is not very responsive or adaptive.
|
||||
|
@ -12,6 +12,31 @@
|
|||
|
||||
'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.
|
||||
*
|
||||
|
@ -21,11 +46,36 @@
|
|||
attach: function (context) {
|
||||
$(context).find('.js-webform-tooltip-element').once('webform-tooltip-element').each(function () {
|
||||
var $element = $(this);
|
||||
var $description = $element.children('.description.visually-hidden');
|
||||
$element.tooltip({
|
||||
items: ':input',
|
||||
|
||||
// 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);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -37,8 +87,12 @@
|
|||
*/
|
||||
Drupal.behaviors.webformTooltipLink = {
|
||||
attach: function (context) {
|
||||
$(context).find('a.js-webform-tooltip-link').once('webform-tooltip-link').each(function () {
|
||||
$(this).tooltip();
|
||||
$(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);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
61
web/modules/contrib/webform/js/webform.wizard.pages.js
Normal file
61
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);
|
41
web/modules/contrib/webform/js/webform.wizard.track.js
Normal file
41
web/modules/contrib/webform/js/webform.wizard.track.js
Normal file
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* @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+ and all other browsers.
|
||||
if (window.history && history.replaceState) {
|
||||
$('form[data-webform-wizard-current-page]', context).once('webform-wizard-current-page').each(function () {
|
||||
var page = $(this).attr('data-webform-wizard-current-page');
|
||||
history.replaceState(null, null, window.location.toString().replace(/\?.+$/, '') + '?page=' + page);
|
||||
});
|
||||
}
|
||||
|
||||
// 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;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
Reference in a new issue