first commit
This commit is contained in:
commit
346d1cb29d
287 changed files with 43533 additions and 0 deletions
23
modules/contrib/antibot/css/antibote628.css
Normal file
23
modules/contrib/antibot/css/antibote628.css
Normal file
|
@ -0,0 +1,23 @@
|
|||
.antibot-message {
|
||||
border: 1px solid;
|
||||
border-width: 1px 1px 1px 0;
|
||||
border-radius: 2px;
|
||||
padding: 15px;
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
margin: 9px 0 10px 8px;
|
||||
}
|
||||
|
||||
.antibot-message-warning {
|
||||
background-color: #fdf8ed;
|
||||
border-color: #f4daa6 #f4daa6 #f4daa6 transparent;
|
||||
color: #734c00;
|
||||
box-shadow: -8px 0 0 #e09600;
|
||||
}
|
||||
|
||||
.antibot-message-error {
|
||||
background-color: #fcf4f2;
|
||||
color: #a51b00;
|
||||
border-color: #f9c9bf #f9c9bf #f9c9bf transparent;
|
||||
box-shadow: -8px 0 0 #e62600;
|
||||
}
|
70
modules/contrib/antibot/js/antibote628.js
Normal file
70
modules/contrib/antibot/js/antibote628.js
Normal file
|
@ -0,0 +1,70 @@
|
|||
/**
|
||||
* @file
|
||||
* Unlock protected forms.
|
||||
*
|
||||
* This works by resetting the form action to the path that It should be as well
|
||||
* as injecting the secret form key, only if the current user is verified to be
|
||||
* human which is done by waiting for a mousemove, swipe, or tab/enter key to be
|
||||
* pressed.
|
||||
*/
|
||||
|
||||
(function (Drupal, drupalSettings) {
|
||||
"use strict";
|
||||
|
||||
Drupal.antibot = {};
|
||||
|
||||
Drupal.behaviors.antibot = {
|
||||
attach: function (context) {
|
||||
// Assume the user is not human, despite JS being enabled.
|
||||
drupalSettings.antibot.human = false;
|
||||
|
||||
// Wait for a mouse to move, indicating they are human.
|
||||
document.body.addEventListener('mousemove', function () {
|
||||
// Unlock the forms.
|
||||
Drupal.antibot.unlockForms();
|
||||
});
|
||||
|
||||
// Wait for a touch move event, indicating that they are human.
|
||||
document.body.addEventListener('touchmove', function () {
|
||||
// Unlock the forms.
|
||||
Drupal.antibot.unlockForms();
|
||||
});
|
||||
|
||||
// A tab or enter key pressed can also indicate they are human.
|
||||
document.body.addEventListener('keydown', function (e) {
|
||||
if ((e.code == 'Tab') || (e.code == 'Enter')) {
|
||||
// Unlock the forms.
|
||||
Drupal.antibot.unlockForms();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Unlock all locked forms.
|
||||
*/
|
||||
Drupal.antibot.unlockForms = function () {
|
||||
// Act only if we haven't yet verified this user as being human.
|
||||
if (!drupalSettings.antibot.human) {
|
||||
// Check if there are forms to unlock.
|
||||
if (drupalSettings.antibot.forms != undefined) {
|
||||
// Iterate all antibot forms that we need to unlock.
|
||||
Object.values(drupalSettings.antibot.forms).forEach(function (config) {
|
||||
// Switch the action.
|
||||
const form = document.getElementById(config.id);
|
||||
if (form) {
|
||||
form.setAttribute('action', form.getAttribute('data-action'));
|
||||
|
||||
// Set the key.
|
||||
const input = form.querySelector('input[name="antibot_key"]');
|
||||
if (input) {
|
||||
input.value = config.key;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// Mark this user as being human.
|
||||
drupalSettings.antibot.human = true;
|
||||
}
|
||||
};
|
||||
})(Drupal, drupalSettings);
|
51
modules/contrib/matomo/js/matomodfb4.js
Normal file
51
modules/contrib/matomo/js/matomodfb4.js
Normal file
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* @file
|
||||
* Attaches several event listener to a web page.
|
||||
*/
|
||||
|
||||
(function ($, drupalSettings) {
|
||||
|
||||
'use strict';
|
||||
|
||||
$(document).ready(function () {
|
||||
defaultBind();
|
||||
|
||||
// Colorbox: This event triggers when the transition has completed and the
|
||||
// newly loaded content has been revealed.
|
||||
if (drupalSettings.matomo && drupalSettings.matomo.trackColorbox) {
|
||||
$(document).bind('cbox_complete', function () {
|
||||
var href = $.colorbox.element().attr('href');
|
||||
if (href) {
|
||||
_paq.push(['setCustomUrl', href]);
|
||||
if (drupalSettings.matomo.disableCookies) {
|
||||
_paq.push(['disableCookies']);
|
||||
}
|
||||
_paq.push(['trackPageView']);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
* Default event binding.
|
||||
*
|
||||
* Attach mousedown, keyup, touchstart events to document only and catch
|
||||
* clicks on all elements.
|
||||
*/
|
||||
function defaultBind() {
|
||||
$(document.body).bind('mousedown keyup touchstart', function (event) {
|
||||
|
||||
// Catch the closest surrounding link of a clicked element.
|
||||
$(event.target).closest('a,area').each(function () {
|
||||
|
||||
if (drupalSettings.matomo.trackMailto && $(this).is("a[href^='mailto:'],area[href^='mailto:']")) {
|
||||
// Mailto link clicked.
|
||||
_paq.push(['trackEvent', 'Mails', 'Click', this.href.substring(7)]);
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
})(jQuery, drupalSettings);
|
56
modules/contrib/webform/css/webform.ajaxe628.css
Normal file
56
modules/contrib/webform/css/webform.ajaxe628.css
Normal file
|
@ -0,0 +1,56 @@
|
|||
/**
|
||||
* @file
|
||||
* Ajax styles.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Make sure full screen progress indicator is in front of .ui-dialog.
|
||||
*
|
||||
* @see core/themes/seven/css/components/dialog.css
|
||||
*/
|
||||
.ajax-progress.ajax-progress-fullscreen {
|
||||
z-index: 1261;
|
||||
}
|
||||
|
||||
/**
|
||||
* Floating Ajax message container.
|
||||
*
|
||||
* Display status message in a floating container at the bottom of the page.
|
||||
* NOTE: It is display to display message floating at top because of the floating
|
||||
* admin toolbar.
|
||||
*
|
||||
* @see Drupal.AjaxCommands.prototype.webformInsert
|
||||
*/
|
||||
.webform-ajax-messages {
|
||||
position: fixed;
|
||||
z-index: 100;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.webform-ajax-messages .messages {
|
||||
margin: 0;
|
||||
border-width: 10px 0 0 0;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.webform-ajax-messages .messages + .messages {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always position webform modal dialog at the top of the page.
|
||||
*
|
||||
* This prevents the dialogs position from jumping as its content is refreshed
|
||||
* and when the window is resized.
|
||||
*
|
||||
* @see core/misc/dialog/dialog.position.js
|
||||
* @see \Drupal\webform\Utility\WebformDialogHelper::getModalDialogAttributes
|
||||
*/
|
||||
.webform-ui-dialog {
|
||||
top: 50px !important;
|
||||
}
|
||||
|
||||
.toolbar-tray-open.toolbar-horizontal .webform-ui-dialog {
|
||||
top: 90px !important;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
* @file
|
||||
* Details toggle element styles.
|
||||
*
|
||||
* @see /webform/test_form_details_toggle
|
||||
*/
|
||||
|
||||
.webform-details-toggle-state-wrapper {
|
||||
text-align: right; /* LTR */
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
[dir="rtl"] .webform-details-toggle-state-wrapper {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.webform-details-toggle-state-wrapper + details {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* Tweak details toggle state. */
|
||||
.webform-details-toggle-state {
|
||||
margin-top: 0;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
font-size: 1em;
|
||||
text-decoration: none;
|
||||
color: #337ab7;
|
||||
}
|
||||
|
||||
.webform-details-toggle-state:hover,
|
||||
.webform-details-toggle-statelink:focus {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Float toggle to the right of webform tabs */
|
||||
.webform-tabs .webform-details-toggle-state-wrapper {
|
||||
float: right;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
.webform-tabs .webform-details-toggle-state-wrapper {
|
||||
float: none;
|
||||
}
|
||||
}
|
63
modules/contrib/webform/css/webform.element.messagee628.css
Normal file
63
modules/contrib/webform/css/webform.element.messagee628.css
Normal file
|
@ -0,0 +1,63 @@
|
|||
/**
|
||||
* @file
|
||||
* Message element styles.
|
||||
*
|
||||
* @see /webform/test_element_message
|
||||
*/
|
||||
|
||||
/**
|
||||
* Webform message close container.
|
||||
*/
|
||||
.webform-message--close .messages {
|
||||
position: relative;
|
||||
padding-right: 35px;
|
||||
}
|
||||
|
||||
.webform-message--close .webform-message__link {
|
||||
display: none;
|
||||
}
|
||||
|
||||
html.js .webform-message--close .webform-message__link {
|
||||
position: absolute;
|
||||
top: 11px;
|
||||
right: 10px;
|
||||
display: block;
|
||||
font-size: 24px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
html[dir="rtl"].js .webform-message--close .webform-message__link {
|
||||
top: 11px;
|
||||
right: inherit;
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
.webform-message__link {
|
||||
opacity: 0.33;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.webform-message__link:link {
|
||||
text-decoration: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.webform-message__link:hover,
|
||||
.webform-message__link:focus,
|
||||
.webform-message__link:active {
|
||||
text-decoration: none;
|
||||
opacity: 1;
|
||||
color: inherit;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
html.js .js-webform-message--close-storage {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide Gin themes dismiss button even when it appears on the node edit form.
|
||||
*/
|
||||
.js-webform-message--close .button--dismiss {
|
||||
display: none;
|
||||
}
|
131
modules/contrib/webform/css/webform.forme628.css
Normal file
131
modules/contrib/webform/css/webform.forme628.css
Normal file
|
@ -0,0 +1,131 @@
|
|||
/**
|
||||
* @file
|
||||
* Webform form styles.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This allows components to be hidden when a JS plugin provides the UI.
|
||||
*/
|
||||
html.js .js-webform-visually-hidden,
|
||||
html.js .js-webform-visually-hidden[style*="display: none"] {
|
||||
position: absolute !important;
|
||||
display: inline !important;
|
||||
overflow: hidden;
|
||||
clip: rect(1px, 1px, 1px, 1px);
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
word-wrap: normal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Element states.
|
||||
* @see \Drupal\webform\WebformSubmissionConditionsValidator::buildForm
|
||||
* @see \Drupal\webform\Utility\WebformElementHelper::fixStatesWrapper
|
||||
* @see \Drupal\webform\Plugin\WebformElement\TextFormat::preRenderFixTextFormatStates
|
||||
* @see text-format-wrapper.html.twig
|
||||
*/
|
||||
.js-form-item.js-webform-states-hidden,
|
||||
.js-form-submit.js-webform-states-hidden,
|
||||
.js-form-wrapper.js-webform-states-hidden,
|
||||
.js-webform-text-format-hidden > .js-text-format-wrapper {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Form inline. (This is not included in all themes)
|
||||
*/
|
||||
.form--inline .form-item {
|
||||
float: left; /* LTR */
|
||||
margin-right: 0.5em; /* LTR */
|
||||
}
|
||||
[dir="rtl"] .form--inline .form-item {
|
||||
float: right;
|
||||
margin-right: 0;
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
/**
|
||||
* Container inline
|
||||
*/
|
||||
.form-item .container-inline {
|
||||
margin: 2px 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue #2731991: Setting required on radios marks all options required.
|
||||
*/
|
||||
.form-checkboxes .form-required:after,
|
||||
.form-radios .form-required:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Element title inline.z
|
||||
*/
|
||||
.webform-element--title-inline > label {
|
||||
display: inline;
|
||||
padding-right: 0.5em;
|
||||
}
|
||||
|
||||
.webform-element--title-inline > div.container-inline {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fieldset title inline.
|
||||
* Applies to radios, checkboxes, and buttons. (aka .form-composite)
|
||||
* @see \Drupal\webform\Plugin\WebformElement\OptionsBase::prepare
|
||||
* @see webform_preprocess_fieldset()
|
||||
*/
|
||||
.form-composite.webform-fieldset--title-inline legend {
|
||||
float: left; /* LTR */
|
||||
margin: 0.4em 0.5em 0.4em 0; /* LTR */
|
||||
}
|
||||
|
||||
[dir=rtl] .form-composite.webform-fieldset--title-inline legend {
|
||||
float: right; /* RTL */
|
||||
margin-right: 0; /* RTL */
|
||||
margin-left: 0.5em; /* RTL */
|
||||
}
|
||||
|
||||
.form-composite.webform-fieldset--title-inline .fieldset-wrapper,
|
||||
.form-composite.webform-fieldset--title-inline .fieldset-wrapper > div {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checkboxes and radios title inline.
|
||||
*/
|
||||
.webform-element--title-inline .form-radios,
|
||||
.webform-element--title-inline .form-checkboxes {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clientside validation errors.
|
||||
|
||||
* @see webform_clientside_validation.ife.css
|
||||
*/
|
||||
.webform-submission-form strong.error.form-item--error-message {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Readonly inputs. (@see .form-disabled)
|
||||
* @see https://www.wufoo.com/html5/attributes/21-readonly.html
|
||||
*/
|
||||
.webform-readonly input[type="date"],
|
||||
.webform-readonly input[type="datetime-local"],
|
||||
.webform-readonly input[type="email"],
|
||||
.webform-readonly input[type="number"],
|
||||
.webform-readonly input[type="password"],
|
||||
.webform-readonly input[type="search"],
|
||||
.webform-readonly input[type="tel"],
|
||||
.webform-readonly input[type="text"],
|
||||
.webform-readonly input[type="time"],
|
||||
.webform-readonly input[type="url"],
|
||||
.webform-readonly textarea {
|
||||
color: #717171;
|
||||
border-color: #bbb;
|
||||
background: #ededed;
|
||||
}
|
25
modules/contrib/webform/css/webform.theme.classye628.css
Normal file
25
modules/contrib/webform/css/webform.theme.classye628.css
Normal file
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* @file
|
||||
* Classy theme styles.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Make sure the date picker is in front of the dialog.
|
||||
*
|
||||
* @see core/themes/classy/css/components/dialog.css
|
||||
* @see core/themes/seven/css/components/dialog.css
|
||||
*/
|
||||
.ui-datepicker {
|
||||
z-index: 1261 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax form wrapper.
|
||||
*
|
||||
* Prevent actions bottom margin from causing the slide effect to
|
||||
* jump when completed.
|
||||
*/
|
||||
.webform-ajax-form-wrapper[data-effect="slide"] .form-actions {
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 1em;
|
||||
}
|
337
modules/contrib/webform/js/webform.ajaxdfb4.js
Normal file
337
modules/contrib/webform/js/webform.ajaxdfb4.js
Normal file
|
@ -0,0 +1,337 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for Ajax.
|
||||
*/
|
||||
|
||||
(function ($, Drupal, drupalSettings) {
|
||||
|
||||
'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);
|
||||
|
||||
// Set global scroll top offset.
|
||||
// @todo Remove in Webform 6.x.
|
||||
Drupal.webform.scrollTopOffset = Drupal.webform.ajax.scrollTopOffset;
|
||||
|
||||
/**
|
||||
* 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')
|
||||
.on('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').trigger('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).trigger('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).trigger('focus');
|
||||
|
||||
// Scroll element into view.
|
||||
Drupal.webformScrolledIntoView($element);
|
||||
}
|
||||
else {
|
||||
// Focus main content.
|
||||
$('#main-content').trigger('focus');
|
||||
}
|
||||
|
||||
// Display main page's status message in a floating container.
|
||||
var $wrapper = $(response.selector);
|
||||
if ($wrapper.parents('.ui-dialog').length === 0) {
|
||||
var $messages = $wrapper.find('.messages');
|
||||
// If 'add element' don't show any messages.
|
||||
if (addElement) {
|
||||
$messages.remove();
|
||||
}
|
||||
else if ($messages.length) {
|
||||
var $floatingMessage = $('#webform-ajax-messages');
|
||||
if ($floatingMessage.length === 0) {
|
||||
$floatingMessage = $('<div id="webform-ajax-messages" class="webform-ajax-messages"></div>');
|
||||
$('body').append($floatingMessage);
|
||||
}
|
||||
if ($floatingMessage.is(':animated')) {
|
||||
$floatingMessage.stop(true, true);
|
||||
}
|
||||
$floatingMessage.html($messages).show().delay(3000).fadeOut(1000);
|
||||
}
|
||||
}
|
||||
|
||||
updateKey = null; // Reset element update.
|
||||
addElement = null; // Reset add element.
|
||||
};
|
||||
|
||||
/**
|
||||
* Scroll to top ajax command.
|
||||
*
|
||||
* @param {Drupal.Ajax} [ajax]
|
||||
* A {@link Drupal.ajax} object.
|
||||
* @param {object} response
|
||||
* Ajax response.
|
||||
* @param {string} response.selector
|
||||
* Selector to use.
|
||||
*
|
||||
* @see Drupal.AjaxCommands.prototype.viewScrollTop
|
||||
*/
|
||||
Drupal.AjaxCommands.prototype.webformScrollTop = function (ajax, response) {
|
||||
// Scroll top.
|
||||
Drupal.webformScrollTop(response.selector, response.target);
|
||||
|
||||
// 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').trigger('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;
|
||||
var forceReload = (response.url.match(/\?reload=([^&]+)($|&)/)) ? RegExp.$1 : null;
|
||||
if (forceReload) {
|
||||
response.url = response.url.replace(/\?reload=([^&]+)($|&)/, '');
|
||||
this.redirect(ajax, response, status);
|
||||
return;
|
||||
}
|
||||
|
||||
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').trigger('click');
|
||||
}
|
||||
else {
|
||||
// Clear unsaved information flag so that the current webform page
|
||||
// can be redirected.
|
||||
// @see Drupal.behaviors.webformUnsaved.clear
|
||||
if (Drupal.behaviors.webformUnsaved) {
|
||||
Drupal.behaviors.webformUnsaved.clear();
|
||||
}
|
||||
|
||||
// For webform embedded in an iframe, open all redirects in the top
|
||||
// of the browser window.
|
||||
// @see \Drupal\webform_share\Controller\WebformShareController::page
|
||||
if (drupalSettings.webform_share &&
|
||||
drupalSettings.webform_share.page) {
|
||||
window.top.location = response.url;
|
||||
}
|
||||
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 confirm page reload.
|
||||
*
|
||||
* @param {Drupal.Ajax} [ajax]
|
||||
* A {@link Drupal.ajax} object.
|
||||
* @param {object} response
|
||||
* Ajax response.
|
||||
* @param {string} response.message
|
||||
* A message to be displayed in the confirm dialog.
|
||||
*/
|
||||
Drupal.AjaxCommands.prototype.webformConfirmReload = function (ajax, response) {
|
||||
if (window.confirm(response.message)) {
|
||||
window.location.reload(true);
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal, drupalSettings);
|
41
modules/contrib/webform/js/webform.behaviorsdfb4.js
Normal file
41
modules/contrib/webform/js/webform.behaviorsdfb4.js
Normal file
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* @file
|
||||
* Webform behaviors.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// Trigger Drupal's attaching of behaviors after the page is
|
||||
// completely loaded.
|
||||
// @see https://stackoverflow.com/questions/37838430/detect-if-page-is-load-from-back-button
|
||||
// @see https://stackoverflow.com/questions/20899274/how-to-refresh-page-on-back-button-click/20899422#20899422
|
||||
var isChrome = (/chrom(e|ium)/.test(window.navigator.userAgent.toLowerCase()));
|
||||
if (isChrome) {
|
||||
// Track back button in navigation.
|
||||
// @see https://stackoverflow.com/questions/37838430/detect-if-page-is-load-from-back-button
|
||||
var backButton = false;
|
||||
if (window.performance) {
|
||||
var navEntries = window.performance.getEntriesByType('navigation');
|
||||
if (navEntries.length > 0 && navEntries[0].type === 'back_forward') {
|
||||
backButton = true;
|
||||
}
|
||||
else if (window.performance.navigation
|
||||
&& window.performance.navigation.type === window.performance.navigation.TYPE_BACK_FORWARD) {
|
||||
backButton = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If the back button is pressed, delay Drupal's attaching of behaviors.
|
||||
if (backButton) {
|
||||
var attachBehaviors = Drupal.attachBehaviors;
|
||||
Drupal.attachBehaviors = function (context, settings) {
|
||||
setTimeout(function (context, settings) {
|
||||
attachBehaviors(context, settings);
|
||||
}, 300);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
})(jQuery, Drupal);
|
126
modules/contrib/webform/js/webform.element.details.savedfb4.js
Normal file
126
modules/contrib/webform/js/webform.element.details.savedfb4.js
Normal file
|
@ -0,0 +1,126 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for details element.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// Determine if local storage exists and is enabled.
|
||||
// This approach is copied from Modernizr.
|
||||
// @see https://github.com/Modernizr/Modernizr/blob/c56fb8b09515f629806ca44742932902ac145302/modernizr.js#L696-731
|
||||
var hasLocalStorage = (function () {
|
||||
try {
|
||||
localStorage.setItem('webform', 'webform');
|
||||
localStorage.removeItem('webform');
|
||||
return true;
|
||||
}
|
||||
catch (e) {
|
||||
return false;
|
||||
}
|
||||
}());
|
||||
|
||||
/**
|
||||
* Attach handler to save details open/close state.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformDetailsSave = {
|
||||
attach: function (context) {
|
||||
if (!hasLocalStorage) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Summary click event handler.
|
||||
$('details > summary', context).once('webform-details-summary-save').on('click', function () {
|
||||
var $details = $(this).parent();
|
||||
|
||||
// @see https://css-tricks.com/snippets/jquery/make-an-jquery-hasattr/
|
||||
if ($details[0].hasAttribute('data-webform-details-nosave')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var name = Drupal.webformDetailsSaveGetName($details);
|
||||
if (!name) {
|
||||
return;
|
||||
}
|
||||
|
||||
var open = ($details.attr('open') !== 'open') ? '1' : '0';
|
||||
localStorage.setItem(name, open);
|
||||
});
|
||||
|
||||
// Initialize details open state via local storage.
|
||||
$('details', context).once('webform-details-save').each(function () {
|
||||
var $details = $(this);
|
||||
|
||||
var name = Drupal.webformDetailsSaveGetName($details);
|
||||
if (!name) {
|
||||
return;
|
||||
}
|
||||
|
||||
var open = localStorage.getItem(name);
|
||||
if (open === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (open === '1') {
|
||||
$details.attr('open', 'open');
|
||||
}
|
||||
else {
|
||||
$details.removeAttr('open');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the name used to store the state of details element.
|
||||
*
|
||||
* @param {jQuery} $details
|
||||
* A details element.
|
||||
*
|
||||
* @return {string}
|
||||
* The name used to store the state of details element.
|
||||
*/
|
||||
Drupal.webformDetailsSaveGetName = function ($details) {
|
||||
if (!hasLocalStorage) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Ignore details that are vertical tabs pane.
|
||||
if ($details.hasClass('vertical-tabs__pane')) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Any details element not included a webform must have define its own id.
|
||||
var webformId = $details.attr('data-webform-element-id');
|
||||
if (webformId) {
|
||||
return 'Drupal.webform.' + webformId.replace('--', '.');
|
||||
}
|
||||
|
||||
var detailsId = $details.attr('id');
|
||||
if (!detailsId) {
|
||||
return '';
|
||||
}
|
||||
|
||||
var $form = $details.parents('form');
|
||||
if (!$form.length || !$form.attr('id')) {
|
||||
return '';
|
||||
}
|
||||
|
||||
var formId = $form.attr('id');
|
||||
if (!formId) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// ISSUE: When Drupal renders a webform in a modal dialog it appends a unique
|
||||
// identifier to webform ids and details ids. (i.e. my-form--FeSFISegTUI)
|
||||
// WORKAROUND: Remove the unique id that delimited using double dashes.
|
||||
formId = formId.replace(/--.+?$/, '').replace(/-/g, '_');
|
||||
detailsId = detailsId.replace(/--.+?$/, '').replace(/-/g, '_');
|
||||
return 'Drupal.webform.' + formId + '.' + detailsId;
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
118
modules/contrib/webform/js/webform.element.details.toggledfb4.js
Normal file
118
modules/contrib/webform/js/webform.element.details.toggledfb4.js
Normal file
|
@ -0,0 +1,118 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for details element.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
Drupal.webform = Drupal.webform || {};
|
||||
Drupal.webform.detailsToggle = Drupal.webform.detailsToggle || {};
|
||||
Drupal.webform.detailsToggle.options = Drupal.webform.detailsToggle.options || {};
|
||||
|
||||
/**
|
||||
* Attach handler to toggle details open/close state.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformDetailsToggle = {
|
||||
attach: function (context) {
|
||||
$('.js-webform-details-toggle', context).once('webform-details-toggle').each(function () {
|
||||
var $form = $(this);
|
||||
var $tabs = $form.find('.webform-tabs');
|
||||
|
||||
// Get only the main details elements and ignore all nested details.
|
||||
var selector = ($tabs.length) ? '.webform-tab' : '.js-webform-details-toggle, .webform-elements';
|
||||
var $details = $form.find('details').filter(function () {
|
||||
var $parents = $(this).parentsUntil(selector);
|
||||
return ($parents.find('details').length === 0);
|
||||
});
|
||||
|
||||
// Toggle is only useful when there are two or more details elements.
|
||||
if ($details.length < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
var options = $.extend({
|
||||
button: '<button type="button" class="webform-details-toggle-state"></button>'
|
||||
}, Drupal.webform.detailsToggle.options);
|
||||
|
||||
// Create toggle buttons.
|
||||
var $toggle = $(options.button)
|
||||
.attr('title', Drupal.t('Toggle details widget state.'))
|
||||
.on('click', function (e) {
|
||||
// Get details that are not vertical tabs pane.
|
||||
var $details = $form.find('details:not(.vertical-tabs__pane)');
|
||||
var open;
|
||||
if (Drupal.webform.detailsToggle.isFormDetailsOpen($form)) {
|
||||
$details.removeAttr('open');
|
||||
open = 0;
|
||||
}
|
||||
else {
|
||||
$details.attr('open', 'open');
|
||||
open = 1;
|
||||
}
|
||||
Drupal.webform.detailsToggle.setDetailsToggleLabel($form);
|
||||
|
||||
// Set the saved states for all the details elements.
|
||||
// @see webform.element.details.save.js
|
||||
if (Drupal.webformDetailsSaveGetName) {
|
||||
$details.each(function () {
|
||||
// Note: Drupal.webformDetailsSaveGetName checks if localStorage
|
||||
// exists and is enabled.
|
||||
// @see webform.element.details.save.js
|
||||
var name = Drupal.webformDetailsSaveGetName($(this));
|
||||
if (name) {
|
||||
localStorage.setItem(name, open);
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
.wrap('<div class="webform-details-toggle-state-wrapper"></div>')
|
||||
.parent();
|
||||
|
||||
if ($tabs.length) {
|
||||
// Add toggle state before the tabs.
|
||||
$tabs.find('.item-list:first-child').eq(0).before($toggle);
|
||||
}
|
||||
else {
|
||||
// Add toggle state link to first details element.
|
||||
$details.eq(0).before($toggle);
|
||||
}
|
||||
|
||||
Drupal.webform.detailsToggle.setDetailsToggleLabel($form);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine if a webform's details are all opened.
|
||||
*
|
||||
* @param {jQuery} $form
|
||||
* A webform.
|
||||
*
|
||||
* @return {boolean}
|
||||
* TRUE if a webform's details are all opened.
|
||||
*/
|
||||
Drupal.webform.detailsToggle.isFormDetailsOpen = function ($form) {
|
||||
return ($form.find('details[open]').length === $form.find('details').length);
|
||||
};
|
||||
|
||||
/**
|
||||
* Set a webform's details toggle state widget label.
|
||||
*
|
||||
* @param {jQuery} $form
|
||||
* A webform.
|
||||
*/
|
||||
Drupal.webform.detailsToggle.setDetailsToggleLabel = function ($form) {
|
||||
var isOpen = Drupal.webform.detailsToggle.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);
|
28
modules/contrib/webform/js/webform.element.detailsdfb4.js
Normal file
28
modules/contrib/webform/js/webform.element.detailsdfb4.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for details element.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Attach handler to details with invalid inputs.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformDetailsInvalid = {
|
||||
attach: function (context) {
|
||||
$('details :input', context).on('invalid', function () {
|
||||
$(this).parents('details:not([open])').children('summary').trigger('click');
|
||||
|
||||
// Synd details toggle label.
|
||||
if (Drupal.webform && Drupal.webform.detailsToggle) {
|
||||
Drupal.webform.detailsToggle.setDetailsToggleLabel($(this.form));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
127
modules/contrib/webform/js/webform.element.messagedfb4.js
Normal file
127
modules/contrib/webform/js/webform.element.messagedfb4.js
Normal file
|
@ -0,0 +1,127 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for message element integration.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// Determine if local storage exists and is enabled.
|
||||
// This approach is copied from Modernizr.
|
||||
// @see https://github.com/Modernizr/Modernizr/blob/c56fb8b09515f629806ca44742932902ac145302/modernizr.js#L696-731
|
||||
var hasLocalStorage = (function () {
|
||||
try {
|
||||
localStorage.setItem('webform', 'webform');
|
||||
localStorage.removeItem('webform');
|
||||
return true;
|
||||
}
|
||||
catch (e) {
|
||||
return false;
|
||||
}
|
||||
}());
|
||||
|
||||
// Determine if session storage exists and is enabled.
|
||||
// This approach is copied from Modernizr.
|
||||
// @see https://github.com/Modernizr/Modernizr/blob/c56fb8b09515f629806ca44742932902ac145302/modernizr.js#L696-731
|
||||
var hasSessionStorage = (function () {
|
||||
try {
|
||||
sessionStorage.setItem('webform', 'webform');
|
||||
sessionStorage.removeItem('webform');
|
||||
return true;
|
||||
}
|
||||
catch (e) {
|
||||
return false;
|
||||
}
|
||||
}());
|
||||
|
||||
/**
|
||||
* Behavior for handler message close.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.webformMessageClose = {
|
||||
attach: function (context) {
|
||||
$(context).find('.js-webform-message--close').once('webform-message--close').each(function () {
|
||||
var $element = $(this);
|
||||
|
||||
var id = $element.attr('data-message-id');
|
||||
var storage = $element.attr('data-message-storage');
|
||||
var effect = $element.attr('data-message-close-effect') || 'hide';
|
||||
switch (effect) {
|
||||
case 'slide': effect = 'slideUp'; break;
|
||||
|
||||
case 'fade': effect = 'fadeOut'; break;
|
||||
}
|
||||
|
||||
// Check storage status.
|
||||
if (isClosed($element, storage, id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only show element if it's style is not set to 'display: none'
|
||||
// and it is not hidden via .js-webform-states-hidden.
|
||||
if ($element.attr('style') !== 'display: none;' && !$element.hasClass('js-webform-states-hidden')) {
|
||||
$element.show();
|
||||
}
|
||||
|
||||
$element.find('.js-webform-message__link').on('click', function (event) {
|
||||
$element[effect]();
|
||||
setClosed($element, storage, id);
|
||||
$element.trigger('close');
|
||||
event.preventDefault();
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function isClosed($element, storage, id) {
|
||||
if (!id || !storage) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (storage) {
|
||||
case 'local':
|
||||
if (hasLocalStorage) {
|
||||
return localStorage.getItem('Drupal.webform.message.' + id) || false;
|
||||
}
|
||||
return false;
|
||||
|
||||
case 'session':
|
||||
if (hasSessionStorage) {
|
||||
return sessionStorage.getItem('Drupal.webform.message.' + id) || false;
|
||||
}
|
||||
return false;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function setClosed($element, storage, id) {
|
||||
if (!id || !storage) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (storage) {
|
||||
case 'local':
|
||||
if (hasLocalStorage) {
|
||||
localStorage.setItem('Drupal.webform.message.' + id, true);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'session':
|
||||
if (hasSessionStorage) {
|
||||
sessionStorage.setItem('Drupal.webform.message.' + id, true);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'user':
|
||||
case 'state':
|
||||
case 'custom':
|
||||
$.get($element.find('.js-webform-message__link').attr('href'));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
})(jQuery, Drupal);
|
16
modules/contrib/webform/js/webform.form.disable_backdfb4.js
Normal file
16
modules/contrib/webform/js/webform.form.disable_backdfb4.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript to disable back button.
|
||||
*/
|
||||
|
||||
(function () {
|
||||
|
||||
'use strict';
|
||||
|
||||
// From: http://stackoverflow.com/questions/17962130/restrict-user-to-refresh-and-back-forward-in-any-browser
|
||||
history.pushState({page: 1}, 'Title 1', '#no-back');
|
||||
window.onhashchange = function (event) {
|
||||
window.location.hash = 'no-back';
|
||||
};
|
||||
|
||||
})();
|
68
modules/contrib/webform/js/webform.form.submit_oncedfb4.js
Normal file
68
modules/contrib/webform/js/webform.form.submit_oncedfb4.js
Normal file
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for preventing duplicate webform submissions.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Submit once.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the behavior for preventing duplicate webform submissions.
|
||||
*/
|
||||
Drupal.behaviors.webformSubmitOnce = {
|
||||
clear: function () {
|
||||
var $form = $('.js-webform-submit-once');
|
||||
$form.removeData('webform-submitted');
|
||||
$form.find('.js-webform-wizard-pages-links :submit, .form-actions :submit').removeClass('is-disabled');
|
||||
$form.find('.form-actions .ajax-progress.ajax-progress-throbber').remove();
|
||||
},
|
||||
attach: function (context) {
|
||||
$('.js-webform-submit-once', context).once('webform-submit-once').each(function () {
|
||||
var $form = $(this);
|
||||
// Remove data-webform-submitted.
|
||||
$form.removeData('webform-submitted');
|
||||
// Remove .js-webform-submit-clicked.
|
||||
$form.find('.js-webform-wizard-pages-links :submit, .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('.js-webform-wizard-pages-links :submit, .form-actions :submit').on('click', function () {
|
||||
$form.find('.js-webform-wizard-pages-links :submit, .form-actions :submit')
|
||||
.removeClass('js-webform-submit-clicked');
|
||||
$(this)
|
||||
.addClass('js-webform-submit-clicked');
|
||||
});
|
||||
|
||||
$(this).on('submit', function () {
|
||||
// Find clicked button
|
||||
var $clickedButton = $form.find('.js-webform-wizard-pages-links :submit.js-webform-submit-clicked, .form-actions :submit.js-webform-submit-clicked');
|
||||
|
||||
// Don't submit if client-side validation has failed.
|
||||
if (!$clickedButton.attr('formnovalidate') && $.isFunction(jQuery.fn.valid) && !($form.valid())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Track webform submitted.
|
||||
if ($form.data('webform-submitted')) {
|
||||
return false;
|
||||
}
|
||||
$form.data('webform-submitted', 'true');
|
||||
|
||||
// Visually disable all submit buttons.
|
||||
// Submit buttons can't disabled because their op(eration) must to be posted back to the server.
|
||||
$form.find('.js-webform-wizard-pages-links :submit, .form-actions :submit').addClass('is-disabled');
|
||||
|
||||
// Set the throbber progress indicator.
|
||||
$clickedButton.after(Drupal.theme.ajaxProgressThrobber());
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal);
|
137
modules/contrib/webform/js/webform.form.unsaveddfb4.js
Normal file
137
modules/contrib/webform/js/webform.form.unsaveddfb4.js
Normal file
|
@ -0,0 +1,137 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for unsaved webforms.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
var unsaved = false;
|
||||
|
||||
/**
|
||||
* Unsaved changes.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the behavior for unsaved changes.
|
||||
*/
|
||||
Drupal.behaviors.webformUnsaved = {
|
||||
clear: function () {
|
||||
// Allow Ajax refresh/redirect to clear unsaved flag.
|
||||
// @see Drupal.AjaxCommands.prototype.webformRefresh
|
||||
unsaved = false;
|
||||
},
|
||||
get: function () {
|
||||
// Get the current unsaved flag state.
|
||||
return unsaved;
|
||||
},
|
||||
set: function (value) {
|
||||
// Set the current unsaved flag state.
|
||||
unsaved = value;
|
||||
},
|
||||
attach: function (context) {
|
||||
// Look for the 'data-webform-unsaved' attribute which indicates that
|
||||
// a multi-step webform has unsaved data.
|
||||
// @see \Drupal\webform\WebformSubmissionForm::buildForm
|
||||
if ($('.js-webform-unsaved[data-webform-unsaved]').once('data-webform-unsaved').length) {
|
||||
unsaved = true;
|
||||
}
|
||||
else {
|
||||
$('.js-webform-unsaved :input:not(:button, :submit, :reset, [type="hidden"])').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')
|
||||
.not('[data-webform-unsaved-ignore]')
|
||||
.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;
|
||||
});
|
||||
|
||||
// Add submit handler to form.beforeSend.
|
||||
// Update Drupal.Ajax.prototype.beforeSend only once.
|
||||
if (typeof Drupal.Ajax !== 'undefined' && typeof Drupal.Ajax.prototype.beforeSubmitWebformUnsavedOriginal === 'undefined') {
|
||||
Drupal.Ajax.prototype.beforeSubmitWebformUnsavedOriginal = Drupal.Ajax.prototype.beforeSubmit;
|
||||
Drupal.Ajax.prototype.beforeSubmit = function (form_values, element_settings, options) {
|
||||
unsaved = false;
|
||||
return this.beforeSubmitWebformUnsavedOriginal.apply(this, arguments);
|
||||
};
|
||||
}
|
||||
|
||||
// Track all CKEditor change events.
|
||||
// @see https://ckeditor.com/old/forums/Support/CKEditor-jQuery-change-event
|
||||
if (window.CKEDITOR && !CKEDITOR.webformUnsaved) {
|
||||
CKEDITOR.webformUnsaved = true;
|
||||
CKEDITOR.on('instanceCreated', function (event) {
|
||||
event.editor.on('change', function (evt) {
|
||||
unsaved = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$(window).on('beforeunload', function () {
|
||||
if (unsaved) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* An experimental shim to partially emulate onBeforeUnload on iOS.
|
||||
* Part of https://github.com/codedance/jquery.AreYouSure/
|
||||
*
|
||||
* Copyright (c) 2012-2014, Chris Dance and PaperCut Software http://www.papercut.com/
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* Author: chris.dance@papercut.com
|
||||
* Date: 19th May 2014
|
||||
*/
|
||||
$(function () {
|
||||
// @see https://stackoverflow.com/questions/58019463/how-to-detect-device-name-in-safari-on-ios-13-while-it-doesnt-show-the-correct
|
||||
var isIOSorOpera = navigator.userAgent.toLowerCase().match(/iphone|ipad|ipod|opera/)
|
||||
|| navigator.platform.toLowerCase().match(/iphone|ipad|ipod/)
|
||||
|| (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
|
||||
if (!isIOSorOpera) {
|
||||
return;
|
||||
}
|
||||
|
||||
$('a:not(.use-ajax)').bind('click', function (evt) {
|
||||
var a = $(evt.target).closest('a');
|
||||
var href = a.attr('href');
|
||||
if (typeof href !== 'undefined' && !(href.match(/^#/) || href.trim() === '')) {
|
||||
if ($(window).triggerHandler('beforeunload')) {
|
||||
if (!window.confirm(Drupal.t('Changes you made may not be saved.') + '\n\n' + Drupal.t('Press OK to leave this page or Cancel to stay.'))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
var target = a.attr('target');
|
||||
if (target) {
|
||||
window.open(href, target);
|
||||
}
|
||||
else {
|
||||
window.location.href = href;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
})(jQuery, Drupal);
|
104
modules/contrib/webform/js/webform.formdfb4.js
Normal file
104
modules/contrib/webform/js/webform.formdfb4.js
Normal file
|
@ -0,0 +1,104 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for webforms.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Remove single submit event listener.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the behavior for removing single submit event listener.
|
||||
*
|
||||
* @see Drupal.behaviors.formSingleSubmit
|
||||
*/
|
||||
Drupal.behaviors.webformRemoveFormSingleSubmit = {
|
||||
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', onFormSubmit);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Prevent webform autosubmit on wizard pages.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the behavior for disabling webform autosubmit.
|
||||
* Wizard pages need to be progressed with the Previous or Next buttons,
|
||||
* not by pressing Enter.
|
||||
*/
|
||||
Drupal.behaviors.webformDisableAutoSubmit = {
|
||||
attach: function (context) {
|
||||
// Not using context so that inputs loaded via Ajax will have autosubmit
|
||||
// disabled.
|
||||
// @see http://stackoverflow.com/questions/11235622/jquery-disable-form-submit-on-enter
|
||||
$('.js-webform-disable-autosubmit input')
|
||||
.not(':button, :submit, :reset, :image, :file')
|
||||
.once('webform-disable-autosubmit')
|
||||
.on('keyup keypress', function (e) {
|
||||
if (e.which === 13) {
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Custom required and pattern validation error messages.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the behavior for the webform custom required and pattern
|
||||
* validation error messages.
|
||||
*
|
||||
* @see http://stackoverflow.com/questions/5272433/html5-form-required-attribute-set-custom-validation-message
|
||||
**/
|
||||
Drupal.behaviors.webformRequiredError = {
|
||||
attach: function (context) {
|
||||
$(context).find(':input[data-webform-required-error], :input[data-webform-pattern-error]').once('webform-required-error')
|
||||
.on('invalid', function () {
|
||||
this.setCustomValidity('');
|
||||
if (this.valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.validity.patternMismatch && $(this).attr('data-webform-pattern-error')) {
|
||||
this.setCustomValidity($(this).attr('data-webform-pattern-error'));
|
||||
}
|
||||
else if (this.validity.valueMissing && $(this).attr('data-webform-required-error')) {
|
||||
this.setCustomValidity($(this).attr('data-webform-required-error'));
|
||||
}
|
||||
})
|
||||
.on('input change', function () {
|
||||
// Find all related elements by name and reset custom validity.
|
||||
// This specifically applies to required radios and checkboxes.
|
||||
var name = $(this).attr('name');
|
||||
$(this.form).find(':input[name="' + name + '"]').each(function () {
|
||||
this.setCustomValidity('');
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// When #state:required is triggered we need to reset the target elements
|
||||
// custom validity.
|
||||
$(document).on('state:required', function (e) {
|
||||
$(e.target).filter('[data-webform-required-error]')
|
||||
.each(function () {this.setCustomValidity('');});
|
||||
});
|
||||
|
||||
})(jQuery, Drupal);
|
92
modules/contrib/webform/js/webform.scrolldfb4.js
Normal file
92
modules/contrib/webform/js/webform.scrolldfb4.js
Normal file
|
@ -0,0 +1,92 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for webform scroll top.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
Drupal.webform = Drupal.webform || {};
|
||||
// Allow scrollTopOffset to be custom defined or based on whether there is a
|
||||
// floating toolbar.
|
||||
Drupal.webform.scrollTopOffset = Drupal.webform.scrollTopOffset || ($('#toolbar-administration').length ? 140 : 10);
|
||||
|
||||
/**
|
||||
* Scroll to top ajax command.
|
||||
*
|
||||
* @param {Element} element
|
||||
* The element to scroll to.
|
||||
* @param {string} target
|
||||
* Scroll to target. (form or page)
|
||||
*/
|
||||
Drupal.webformScrollTop = function (element, target) {
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
var $element = $(element);
|
||||
|
||||
// Scroll to the top of the view. This will allow users
|
||||
// to browse newly loaded content after e.g. clicking a pager
|
||||
// link.
|
||||
var offset = $element.offset();
|
||||
// We can't guarantee that the scrollable object should be
|
||||
// the body, as the view could be embedded in something
|
||||
// more complex such as a modal popup. Recurse up the DOM
|
||||
// and scroll the first element that has a non-zero top.
|
||||
var $scrollTarget = $element;
|
||||
while ($scrollTarget.scrollTop() === 0 && $($scrollTarget).parent()) {
|
||||
$scrollTarget = $scrollTarget.parent();
|
||||
}
|
||||
|
||||
if (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.scrollTopOffset < $scrollTarget.scrollTop()) {
|
||||
$scrollTarget.animate({scrollTop: (offset.top - Drupal.webform.scrollTopOffset)}, 500);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Scroll element into view.
|
||||
*
|
||||
* @param {jQuery} $element
|
||||
* An element.
|
||||
*/
|
||||
Drupal.webformScrolledIntoView = function ($element) {
|
||||
if (!Drupal.webformIsScrolledIntoView($element)) {
|
||||
$('html, body').animate({scrollTop: $element.offset().top - Drupal.webform.scrollTopOffset}, 500);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
Drupal.webformIsScrolledIntoView = function (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);
|
647
modules/contrib/webform/js/webform.statesdfb4.js
Normal file
647
modules/contrib/webform/js/webform.statesdfb4.js
Normal file
|
@ -0,0 +1,647 @@
|
|||
/**
|
||||
* @file
|
||||
* JavaScript behaviors for custom webform #states.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
'use strict';
|
||||
|
||||
Drupal.webform = Drupal.webform || {};
|
||||
Drupal.webform.states = Drupal.webform.states || {};
|
||||
Drupal.webform.states.slideDown = Drupal.webform.states.slideDown || {};
|
||||
Drupal.webform.states.slideDown.duration = 'slow';
|
||||
Drupal.webform.states.slideUp = Drupal.webform.states.slideUp || {};
|
||||
Drupal.webform.states.slideUp.duration = 'fast';
|
||||
|
||||
/* ************************************************************************ */
|
||||
// jQuery functions.
|
||||
/* ************************************************************************ */
|
||||
|
||||
/**
|
||||
* 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.webform-submission-form, form[id^="webform"], form[data-is-webform]').length ? true : false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if element is to be treated as a webform element.
|
||||
*
|
||||
* @return {boolean}
|
||||
* TRUE if element is to be treated as a webform element.
|
||||
*/
|
||||
$.fn.isWebformElement = function () {
|
||||
return ($(this).isWebform() || $(this).closest('[data-is-webform-element]').length) ? true : false;
|
||||
};
|
||||
|
||||
/* ************************************************************************ */
|
||||
// Trigger.
|
||||
/* ************************************************************************ */
|
||||
|
||||
// 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() === '';
|
||||
};
|
||||
|
||||
/* ************************************************************************ */
|
||||
// Dependents.
|
||||
/* ************************************************************************ */
|
||||
|
||||
// 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 ('less_equal' in reference) {
|
||||
return (value !== '' && parseFloat(reference['less_equal']) >= parseFloat(value));
|
||||
}
|
||||
else if ('greater' in reference) {
|
||||
return (value !== '' && parseFloat(reference['greater']) < parseFloat(value));
|
||||
}
|
||||
else if ('greater_equal' in reference) {
|
||||
return (value !== '' && parseFloat(reference['greater_equal']) <= parseFloat(value));
|
||||
}
|
||||
else if ('between' in reference || '!between' in reference) {
|
||||
if (value === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
var between = reference['between'] || reference['!between'];
|
||||
var betweenParts = between.split(':');
|
||||
var greater = betweenParts[0];
|
||||
var less = (typeof betweenParts[1] !== 'undefined') ? betweenParts[1] : null;
|
||||
var isGreaterThan = (greater === null || greater === '' || parseFloat(value) >= parseFloat(greater));
|
||||
var isLessThan = (less === null || less === '' || parseFloat(value) <= parseFloat(less));
|
||||
var result = (isGreaterThan && isLessThan);
|
||||
return (reference['!between']) ? !result : result;
|
||||
}
|
||||
else {
|
||||
return reference.indexOf(value) !== false;
|
||||
}
|
||||
};
|
||||
|
||||
/* ************************************************************************ */
|
||||
// States events.
|
||||
/* ************************************************************************ */
|
||||
|
||||
var $document = $(document);
|
||||
|
||||
$document.on('state:required', function (e) {
|
||||
if (e.trigger && $(e.target).isWebformElement()) {
|
||||
var $target = $(e.target);
|
||||
// Fix #required file upload.
|
||||
// @see Issue #2860529: Conditional required File upload field don't work.
|
||||
toggleRequired($target.find('input[type="file"]'), e.value);
|
||||
|
||||
// Fix #required for radios and likert.
|
||||
// @see Issue #2856795: If radio buttons are required but not filled form is nevertheless submitted.
|
||||
if ($target.is('.js-form-type-radios, .js-form-type-webform-radios-other, .js-webform-type-radios, .js-webform-type-webform-radios-other, .js-webform-type-webform-entity-radios, .webform-likert-table')) {
|
||||
$target.toggleClass('required', e.value);
|
||||
toggleRequired($target.find('input[type="radio"]'), e.value);
|
||||
}
|
||||
|
||||
// Fix #required for checkboxes.
|
||||
// @see Issue #2938414: Checkboxes don't support #states required.
|
||||
// @see checkboxRequiredhandler
|
||||
if ($target.is('.js-form-type-checkboxes, .js-form-type-webform-checkboxes-other, .js-webform-type-checkboxes, .js-webform-type-webform-checkboxes-other')) {
|
||||
$target.toggleClass('required', e.value);
|
||||
var $checkboxes = $target.find('input[type="checkbox"]');
|
||||
if (e.value) {
|
||||
// Add event handler.
|
||||
$checkboxes.on('click', statesCheckboxesRequiredEventHandler);
|
||||
// Initialize and add required attribute.
|
||||
checkboxesRequired($target);
|
||||
}
|
||||
else {
|
||||
// Remove event handler.
|
||||
$checkboxes.off('click', statesCheckboxesRequiredEventHandler);
|
||||
// Remove required attribute.
|
||||
toggleRequired($checkboxes, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Fix #required for tableselect.
|
||||
// @see Issue #3212581: Table select does not trigger client side validation
|
||||
if ($target.is('.js-webform-tableselect')) {
|
||||
$target.toggleClass('required', e.value);
|
||||
var isMultiple = $target.is('[multiple]');
|
||||
if (isMultiple) {
|
||||
// Checkboxes.
|
||||
var $tbody = $target.find('tbody');
|
||||
var $checkboxes = $tbody.find('input[type="checkbox"]');
|
||||
copyRequireMessage($target, $checkboxes);
|
||||
if (e.value) {
|
||||
$checkboxes.on('click change', statesCheckboxesRequiredEventHandler);
|
||||
checkboxesRequired($tbody);
|
||||
}
|
||||
else {
|
||||
$checkboxes.off('click change ', statesCheckboxesRequiredEventHandler);
|
||||
toggleRequired($tbody, false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Radios.
|
||||
var $radios = $target.find('input[type="radio"]');
|
||||
copyRequireMessage($target, $radios);
|
||||
toggleRequired($radios, e.value);
|
||||
}
|
||||
}
|
||||
|
||||
// Fix required label for elements without the for attribute.
|
||||
// @see Issue #3145300: Conditional Visible Select Other not working.
|
||||
if ($target.is('.js-form-type-webform-select-other, .js-webform-type-webform-select-other')) {
|
||||
var $select = $target.find('select');
|
||||
toggleRequired($select, e.value);
|
||||
copyRequireMessage($target, $select);
|
||||
}
|
||||
if ($target.find('> label:not([for])').length) {
|
||||
$target.find('> label').toggleClass('js-form-required form-required', 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')) {
|
||||
$target.find('legend span.fieldset-legend:not(.visually-hidden)').toggleClass('js-form-required form-required', e.value);
|
||||
}
|
||||
|
||||
// Issue #2986017: Fieldsets shouldn't have required attribute.
|
||||
if ($target.is('fieldset')) {
|
||||
$target.removeAttr('required aria-required');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$document.on('state:checked', function (e) {
|
||||
if (e.trigger) {
|
||||
$(e.target).trigger('change');
|
||||
}
|
||||
});
|
||||
|
||||
$document.on('state:readonly', function (e) {
|
||||
if (e.trigger && $(e.target).isWebformElement()) {
|
||||
$(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);
|
||||
|
||||
// Trigger webform:readonly.
|
||||
$(e.target).trigger('webform:readonly')
|
||||
.find('select, input, textarea, button').trigger('webform:readonly');
|
||||
}
|
||||
});
|
||||
|
||||
$document.on('state:visible state:visible-slide', function (e) {
|
||||
if (e.trigger && $(e.target).isWebformElement()) {
|
||||
if (e.value) {
|
||||
$(':input', e.target).addBack().each(function () {
|
||||
restoreValueAndRequired(this);
|
||||
triggerEventHandlers(this);
|
||||
});
|
||||
}
|
||||
else {
|
||||
// @see https://www.sitepoint.com/jquery-function-clear-form-data/
|
||||
$(':input', e.target).addBack().each(function () {
|
||||
backupValueAndRequired(this);
|
||||
clearValueAndRequired(this);
|
||||
triggerEventHandlers(this);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$document.on('state:visible-slide', function (e) {
|
||||
if (e.trigger && $(e.target).isWebformElement()) {
|
||||
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).isWebformElement()) {
|
||||
// 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);
|
||||
|
||||
// Never disable hidden file[fids] because the existing values will
|
||||
// be completely lost when the webform is submitted.
|
||||
var fileElements = $(e.target)
|
||||
.find(':input[type="hidden"][name$="[fids]"]');
|
||||
if (fileElements.length) {
|
||||
// Remove 'disabled' attribute from fieldset which will block
|
||||
// all disabled elements from being submitted.
|
||||
if ($(e.target).is('fieldset')) {
|
||||
$(e.target).prop('disabled', false);
|
||||
}
|
||||
fileElements.removeAttr('disabled');
|
||||
}
|
||||
|
||||
// Trigger webform:disabled.
|
||||
$(e.target).trigger('webform:disabled')
|
||||
.find('select, input, textarea, button').trigger('webform:disabled');
|
||||
}
|
||||
});
|
||||
|
||||
/* ************************************************************************ */
|
||||
// Behaviors.
|
||||
/* ************************************************************************ */
|
||||
|
||||
/**
|
||||
* Adds HTML5 validation to required checkboxes.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @see https://www.drupal.org/project/webform/issues/3068998
|
||||
*/
|
||||
Drupal.behaviors.webformCheckboxesRequired = {
|
||||
attach: function (context) {
|
||||
$('.js-form-type-checkboxes.required, .js-form-type-webform-checkboxes-other.required, .js-webform-type-checkboxes.required, .js-webform-type-webform-checkboxes-other.required, .js-webform-type-webform-radios-other.checkboxes', context)
|
||||
.once('webform-checkboxes-required')
|
||||
.each(function () {
|
||||
var $element = $(this);
|
||||
$element.find('input[type="checkbox"]').on('click', statesCheckboxesRequiredEventHandler);
|
||||
setTimeout(function () {checkboxesRequired($element);});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds HTML5 validation to required radios.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @see https://www.drupal.org/project/webform/issues/2856795
|
||||
*/
|
||||
Drupal.behaviors.webformRadiosRequired = {
|
||||
attach: function (context) {
|
||||
$('.js-form-type-radios, .js-form-type-webform-radios-other, .js-webform-type-radios, .js-webform-type-webform-radios-other, .js-webform-type-webform-entity-radios, .js-webform-type-webform-scale', context)
|
||||
.once('webform-radios-required')
|
||||
.each(function () {
|
||||
var $element = $(this);
|
||||
setTimeout(function () {radiosRequired($element);});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds HTML5 validation to required table select.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @see https://www.drupal.org/project/webform/issues/2856795
|
||||
*/
|
||||
Drupal.behaviors.webformTableSelectRequired = {
|
||||
attach: function (context) {
|
||||
$('.js-webform-tableselect.required', context)
|
||||
.once('webform-tableselect-required')
|
||||
.each(function () {
|
||||
var $element = $(this);
|
||||
var $tbody = $element.find('tbody');
|
||||
var isMultiple = $element.is('[multiple]');
|
||||
|
||||
if (isMultiple) {
|
||||
// Check all checkbox triggers checkbox 'change' event on
|
||||
// select and deselect all.
|
||||
// @see Drupal.tableSelect
|
||||
$tbody.find('input[type="checkbox"]').on('click change', function () {
|
||||
checkboxesRequired($tbody);
|
||||
});
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
isMultiple ? checkboxesRequired($tbody) : radiosRequired($element);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Add HTML5 multiple checkboxes required validation.
|
||||
*
|
||||
* @param {jQuery} $element
|
||||
* An jQuery object containing HTML5 radios.
|
||||
*
|
||||
* @see https://stackoverflow.com/a/37825072/145846
|
||||
*/
|
||||
function checkboxesRequired($element) {
|
||||
var $firstCheckbox = $element.find('input[type="checkbox"]').first();
|
||||
var isChecked = $element.find('input[type="checkbox"]').is(':checked');
|
||||
toggleRequired($firstCheckbox, !isChecked);
|
||||
copyRequireMessage($element, $firstCheckbox);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add HTML5 radios required validation.
|
||||
*
|
||||
* @param {jQuery} $element
|
||||
* An jQuery object containing HTML5 radios.
|
||||
*
|
||||
* @see https://www.drupal.org/project/webform/issues/2856795
|
||||
*/
|
||||
function radiosRequired($element) {
|
||||
var $radios = $element.find('input[type="radio"]');
|
||||
var isRequired = $element.hasClass('required');
|
||||
toggleRequired($radios, isRequired);
|
||||
copyRequireMessage($element, $radios);
|
||||
}
|
||||
|
||||
/* ************************************************************************ */
|
||||
// Event handlers.
|
||||
/* ************************************************************************ */
|
||||
|
||||
/**
|
||||
* Trigger #states API HTML5 multiple checkboxes required validation.
|
||||
*
|
||||
* @see https://stackoverflow.com/a/37825072/145846
|
||||
*/
|
||||
function statesCheckboxesRequiredEventHandler() {
|
||||
var $element = $(this).closest('.js-webform-type-checkboxes, .js-webform-type-webform-checkboxes-other');
|
||||
checkboxesRequired($element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger an input's event handlers.
|
||||
*
|
||||
* @param {element} input
|
||||
* An input.
|
||||
*/
|
||||
function triggerEventHandlers(input) {
|
||||
var $input = $(input);
|
||||
var type = input.type;
|
||||
var tag = input.tagName.toLowerCase();
|
||||
// Add 'webform.states' as extra parameter to event handlers.
|
||||
// @see Drupal.behaviors.webformUnsaved
|
||||
var extraParameters = ['webform.states'];
|
||||
if (type === 'checkbox' || type === 'radio') {
|
||||
$input
|
||||
.trigger('change', extraParameters)
|
||||
.trigger('blur', extraParameters);
|
||||
}
|
||||
else if (tag === 'select') {
|
||||
// Do not trigger the onchange event for Address element's country code
|
||||
// when it is initialized.
|
||||
// @see \Drupal\address\Element\Country
|
||||
if ($input.closest('.webform-type-address').length) {
|
||||
if (!$input.data('webform-states-address-initialized')
|
||||
&& $input.attr('autocomplete') === 'country'
|
||||
&& $input.val() === $input.find("option[selected]").attr('value')) {
|
||||
return;
|
||||
}
|
||||
$input.data('webform-states-address-initialized', true);
|
||||
}
|
||||
|
||||
$input
|
||||
.trigger('change', extraParameters)
|
||||
.trigger('blur', extraParameters);
|
||||
}
|
||||
else if (type !== 'submit' && type !== 'button' && type !== 'file') {
|
||||
// Make sure input mask is removed and then reset when value is restored.
|
||||
// @see https://www.drupal.org/project/webform/issues/3124155
|
||||
// @see https://www.drupal.org/project/webform/issues/3202795
|
||||
var hasInputMask = ($.fn.inputmask && $input.hasClass('js-webform-input-mask'));
|
||||
hasInputMask && $input.inputmask('remove');
|
||||
|
||||
$input
|
||||
.trigger('input', extraParameters)
|
||||
.trigger('change', extraParameters)
|
||||
.trigger('keydown', extraParameters)
|
||||
.trigger('keyup', extraParameters)
|
||||
.trigger('blur', extraParameters);
|
||||
|
||||
hasInputMask && $input.inputmask();
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************ */
|
||||
// Backup and restore value functions.
|
||||
/* ************************************************************************ */
|
||||
|
||||
/**
|
||||
* Backup an input's current value and required attribute
|
||||
*
|
||||
* @param {element} input
|
||||
* An input.
|
||||
*/
|
||||
function backupValueAndRequired(input) {
|
||||
var $input = $(input);
|
||||
var type = input.type;
|
||||
var tag = input.tagName.toLowerCase(); // Normalize case.
|
||||
|
||||
// Backup required.
|
||||
if ($input.prop('required') && !$input.hasData('webform-required')) {
|
||||
$input.data('webform-required', true);
|
||||
}
|
||||
|
||||
// Backup value.
|
||||
if (!$input.hasData('webform-value')) {
|
||||
if (type === 'checkbox' || type === 'radio') {
|
||||
$input.data('webform-value', $input.prop('checked'));
|
||||
}
|
||||
else if (tag === 'select') {
|
||||
var values = [];
|
||||
$input.find('option:selected').each(function (i, option) {
|
||||
values[i] = option.value;
|
||||
});
|
||||
$input.data('webform-value', values);
|
||||
}
|
||||
else if (type !== 'submit' && type !== 'button') {
|
||||
$input.data('webform-value', input.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore an input's value and required attribute.
|
||||
*
|
||||
* @param {element} input
|
||||
* An input.
|
||||
*/
|
||||
function restoreValueAndRequired(input) {
|
||||
var $input = $(input);
|
||||
|
||||
// Restore value.
|
||||
var value = $input.data('webform-value');
|
||||
if (typeof value !== 'undefined') {
|
||||
var type = input.type;
|
||||
var tag = input.tagName.toLowerCase(); // Normalize case.
|
||||
|
||||
if (type === 'checkbox' || type === 'radio') {
|
||||
$input.prop('checked', value);
|
||||
}
|
||||
else if (tag === 'select') {
|
||||
$.each(value, function (i, option_value) {
|
||||
// Prevent "Syntax error, unrecognized expression" error by
|
||||
// escaping single quotes.
|
||||
// @see https://forum.jquery.com/topic/escape-characters-prior-to-using-selector
|
||||
option_value = option_value.replace(/'/g, "\\\'");
|
||||
$input.find("option[value='" + option_value + "']").prop('selected', true);
|
||||
});
|
||||
}
|
||||
else if (type !== 'submit' && type !== 'button') {
|
||||
input.value = value;
|
||||
}
|
||||
$input.removeData('webform-value');
|
||||
}
|
||||
|
||||
// Restore required.
|
||||
var required = $input.data('webform-required');
|
||||
if (typeof required !== 'undefined') {
|
||||
if (required) {
|
||||
$input.prop('required', true);
|
||||
}
|
||||
$input.removeData('webform-required');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear an input's value and required attributes.
|
||||
*
|
||||
* @param {element} input
|
||||
* An input.
|
||||
*/
|
||||
function clearValueAndRequired(input) {
|
||||
var $input = $(input);
|
||||
|
||||
// Check for #states no clear attribute.
|
||||
// @see https://css-tricks.com/snippets/jquery/make-an-jquery-hasattr/
|
||||
if ($input.closest('[data-webform-states-no-clear]').length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear value.
|
||||
var type = input.type;
|
||||
var tag = input.tagName.toLowerCase(); // Normalize case.
|
||||
if (type === 'checkbox' || type === 'radio') {
|
||||
$input.prop('checked', false);
|
||||
}
|
||||
else if (tag === 'select') {
|
||||
if ($input.find('option[value=""]').length) {
|
||||
$input.val('');
|
||||
}
|
||||
else {
|
||||
input.selectedIndex = -1;
|
||||
}
|
||||
}
|
||||
else if (type !== 'submit' && type !== 'button') {
|
||||
input.value = (type === 'color') ? '#000000' : '';
|
||||
}
|
||||
|
||||
// Clear required.
|
||||
$input.prop('required', false);
|
||||
}
|
||||
|
||||
/* ************************************************************************ */
|
||||
// Helper functions.
|
||||
/* ************************************************************************ */
|
||||
|
||||
/**
|
||||
* Toggle an input's required attributes.
|
||||
*
|
||||
* @param {element} $input
|
||||
* An input.
|
||||
* @param {boolean} required
|
||||
* Is input required.
|
||||
*/
|
||||
function toggleRequired($input, required) {
|
||||
var isCheckboxOrRadio = ($input.attr('type') === 'radio' || $input.attr('type') === 'checkbox');
|
||||
if (required) {
|
||||
if (isCheckboxOrRadio) {
|
||||
$input.attr({'required': 'required'});
|
||||
}
|
||||
else {
|
||||
$input.attr({'required': 'required', 'aria-required': 'true'});
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (isCheckboxOrRadio) {
|
||||
$input.removeAttr('required');
|
||||
}
|
||||
else {
|
||||
$input.removeAttr('required aria-required');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the clientside_validation.module's message.
|
||||
*
|
||||
* @param {jQuery} $source
|
||||
* The source element.
|
||||
* @param {jQuery} $destination
|
||||
* The destination element.
|
||||
*/
|
||||
function copyRequireMessage($source, $destination) {
|
||||
if ($source.attr('data-msg-required')) {
|
||||
$destination.attr('data-msg-required', $source.attr('data-msg-required'));
|
||||
}
|
||||
}
|
||||
|
||||
})(jQuery, Drupal);
|
Loading…
Add table
Add a link
Reference in a new issue