1/** 2 * @file 3 * JavaScript behaviors for Ajax. 4 */ 5 6(function ($, Drupal, drupalSettings) { 7 8 'use strict'; 9 10 Drupal.webform = Drupal.webform || {}; 11 Drupal.webform.ajax = Drupal.webform.ajax || {}; 12 // Allow scrollTopOffset to be custom defined or based on whether there is a 13 // floating toolbar. 14 Drupal.webform.ajax.scrollTopOffset = Drupal.webform.ajax.scrollTopOffset || ($('#toolbar-administration').length ? 140 : 10); 15 16 // Set global scroll top offset. 17 // @todo Remove in Webform 6.x. 18 Drupal.webform.scrollTopOffset = Drupal.webform.ajax.scrollTopOffset; 19 20 /** 21 * Provide Webform Ajax link behavior. 22 * 23 * Display fullscreen progress indicator instead of throbber. 24 * Copied from: Drupal.behaviors.AJAX 25 * 26 * @type {Drupal~behavior} 27 * 28 * @prop {Drupal~behaviorAttach} attach 29 * Attaches the behavior to a.webform-ajax-link. 30 */ 31 Drupal.behaviors.webformAjaxLink = { 32 attach: function (context) { 33 $('.webform-ajax-link', context).once('webform-ajax-link').each(function () { 34 var element_settings = {}; 35 element_settings.progress = {type: 'fullscreen'}; 36 37 // For anchor tags, these will go to the target of the anchor rather 38 // than the usual location. 39 var href = $(this).attr('href'); 40 if (href) { 41 element_settings.url = href; 42 element_settings.event = 'click'; 43 } 44 element_settings.dialogType = $(this).data('dialog-type'); 45 element_settings.dialogRenderer = $(this).data('dialog-renderer'); 46 element_settings.dialog = $(this).data('dialog-options'); 47 element_settings.base = $(this).attr('id'); 48 element_settings.element = this; 49 Drupal.ajax(element_settings); 50 51 // Close all open modal dialogs when opening off-canvas dialog. 52 if (element_settings.dialogRenderer === 'off_canvas') { 53 $(this).on('click', function () { 54 $('.ui-dialog.webform-ui-dialog:visible').find('.ui-dialog-content').dialog('close'); 55 }); 56 } 57 }); 58 } 59 }; 60 61 /** 62 * Adds a hash (#) to current pages location for links and buttons 63 * 64 * @type {Drupal~behavior} 65 * 66 * @prop {Drupal~behaviorAttach} attach 67 * Attaches the behavior to a[data-hash] or :button[data-hash]. 68 * 69 * @see \Drupal\webform_ui\WebformUiEntityElementsForm::getElementRow 70 * @see Drupal.behaviors.webformFormTabs 71 */ 72 Drupal.behaviors.webformAjaxHash = { 73 attach: function (context) { 74 $('[data-hash]', context).once('webform-ajax-hash').each(function () { 75 var hash = $(this).data('hash'); 76 if (hash) { 77 $(this).on('click', function () { 78 location.hash = $(this).data('hash'); 79 }); 80 } 81 }); 82 } 83 }; 84 85 /** 86 * Provide Ajax callback for confirmation back to link. 87 * 88 * @type {Drupal~behavior} 89 * 90 * @prop {Drupal~behaviorAttach} attach 91 * Attaches the behavior to confirmation back to link. 92 */ 93 Drupal.behaviors.webformConfirmationBackAjax = { 94 attach: function (context) { 95 $('.js-webform-confirmation-back-link-ajax', context) 96 .once('webform-confirmation-back-ajax') 97 .on('click', function (event) { 98 var $form = $(this).parents('form'); 99 100 // Trigger the Ajax call back for the hidden submit button. 101 // @see \Drupal\webform\WebformSubmissionForm::getCustomForm 102 $form.find('.js-webform-confirmation-back-submit-ajax').trigger('click'); 103 104 // Move the progress indicator from the submit button to after this link. 105 // @todo Figure out a better way to set a progress indicator. 106 var $progress_indicator = $form.find('.ajax-progress'); 107 if ($progress_indicator) { 108 $(this).after($progress_indicator); 109 } 110 111 // Cancel the click event. 112 event.preventDefault(); 113 event.stopPropagation(); 114 }); 115 } 116 }; 117 118 /** ********************************************************************** **/ 119 // Ajax commands. 120 /** ********************************************************************** **/ 121 122 /** 123 * Track the updated table row key. 124 */ 125 var updateKey; 126 127 /** 128 * Track the add element key. 129 */ 130 var addElement; 131 132 /** 133 * Command to insert new content into the DOM. 134 * 135 * @param {Drupal.Ajax} ajax 136 * {@link Drupal.Ajax} object created by {@link Drupal.ajax}. 137 * @param {object} response 138 * The response from the Ajax request. 139 * @param {string} response.data 140 * The data to use with the jQuery method. 141 * @param {string} [response.method] 142 * The jQuery DOM manipulation method to be used. 143 * @param {string} [response.selector] 144 * A optional jQuery selector string. 145 * @param {object} [response.settings] 146 * An optional array of settings that will be used. 147 * @param {number} [status] 148 * The XMLHttpRequest status. 149 */ 150 Drupal.AjaxCommands.prototype.webformInsert = function (ajax, response, status) { 151 // Insert the HTML. 152 this.insert(ajax, response, status); 153 154 // Add element. 155 if (addElement) { 156 var addSelector = (addElement === '_root_') 157 ? '#webform-ui-add-element' 158 : '[data-drupal-selector="edit-webform-ui-elements-' + addElement + '-add"]'; 159 $(addSelector).trigger('click'); 160 } 161 162 // If not add element, then scroll to and highlight the updated table row. 163 if (!addElement && updateKey) { 164 var $element = $('tr[data-webform-key="' + updateKey + '"]'); 165 166 // Highlight the updated element's row. 167 $element.addClass('color-success'); 168 setTimeout(function () {$element.removeClass('color-success');}, 3000); 169 170 // Focus first tabbable item for the updated elements and handlers. 171 $element.find(':tabbable:not(.tabledrag-handle)').eq(0).trigger('focus'); 172 173 // Scroll element into view. 174 Drupal.webformScrolledIntoView($element); 175 } 176 else { 177 // Focus main content. 178 $('#main-content').trigger('focus'); 179 } 180 181 // Display main page's status message in a floating container. 182 var $wrapper = $(response.selector); 183 if ($wrapper.parents('.ui-dialog').length === 0) { 184 var $messages = $wrapper.find('.messages'); 185 // If 'add element' don't show any messages. 186 if (addElement) { 187 $messages.remove(); 188 } 189 else if ($messages.length) { 190 var $floatingMessage = $('#webform-ajax-messages'); 191 if ($floatingMessage.length === 0) { 192 $floatingMessage = $('<div id="webform-ajax-messages" class="webform-ajax-messages"></div>'); 193 $('body').append($floatingMessage); 194 } 195 if ($floatingMessage.is(':animated')) { 196 $floatingMessage.stop(true, true); 197 } 198 $floatingMessage.html($messages).show().delay(3000).fadeOut(1000); 199 } 200 } 201 202 updateKey = null; // Reset element update. 203 addElement = null; // Reset add element. 204 }; 205 206 /** 207 * Scroll to top ajax command. 208 * 209 * @param {Drupal.Ajax} [ajax] 210 * A {@link Drupal.ajax} object. 211 * @param {object} response 212 * Ajax response. 213 * @param {string} response.selector 214 * Selector to use. 215 * 216 * @see Drupal.AjaxCommands.prototype.viewScrollTop 217 */ 218 Drupal.AjaxCommands.prototype.webformScrollTop = function (ajax, response) { 219 // Scroll top. 220 Drupal.webformScrollTop(response.selector, response.target); 221 222 // Focus on the form wrapper content bookmark if 223 // .js-webform-autofocus is not enabled. 224 // @see \Drupal\webform\Form\WebformAjaxFormTrait::buildAjaxForm 225 var $form = $(response.selector + '-content').find('form'); 226 if (!$form.hasClass('js-webform-autofocus')) { 227 $(response.selector + '-content').trigger('focus'); 228 } 229 }; 230 231 /** 232 * Command to refresh the current webform page. 233 * 234 * @param {Drupal.Ajax} [ajax] 235 * {@link Drupal.Ajax} object created by {@link Drupal.ajax}. 236 * @param {object} response 237 * The response from the Ajax request. 238 * @param {string} response.url 239 * The URL to redirect to. 240 * @param {number} [status] 241 * The XMLHttpRequest status. 242 */ 243 Drupal.AjaxCommands.prototype.webformRefresh = function (ajax, response, status) { 244 // Get URL path name. 245 // @see https://stackoverflow.com/questions/6944744/javascript-get-portion-of-url-path 246 var a = document.createElement('a'); 247 a.href = response.url; 248 var forceReload = (response.url.match(/\?reload=([^&]+)($|&)/)) ? RegExp.$1 : null; 249 if (forceReload) { 250 response.url = response.url.replace(/\?reload=([^&]+)($|&)/, ''); 251 this.redirect(ajax, response, status); 252 return; 253 } 254 255 if (a.pathname === window.location.pathname && $('.webform-ajax-refresh').length) { 256 updateKey = (response.url.match(/[?|&]update=([^&]+)($|&)/)) ? RegExp.$1 : null; 257 addElement = (response.url.match(/[?|&]add_element=([^&]+)($|&)/)) ? RegExp.$1 : null; 258 $('.webform-ajax-refresh').trigger('click'); 259 } 260 else { 261 // Clear unsaved information flag so that the current webform page 262 // can be redirected. 263 // @see Drupal.behaviors.webformUnsaved.clear 264 if (Drupal.behaviors.webformUnsaved) { 265 Drupal.behaviors.webformUnsaved.clear(); 266 } 267 268 // For webform embedded in an iframe, open all redirects in the top 269 // of the browser window. 270 // @see \Drupal\webform_share\Controller\WebformShareController::page 271 if (drupalSettings.webform_share && 272 drupalSettings.webform_share.page) { 273 window.top.location = response.url; 274 } 275 else { 276 this.redirect(ajax, response, status); 277 } 278 } 279 }; 280 281 /** 282 * Command to close a off-canvas and modal dialog. 283 * 284 * If no selector is given, it defaults to trying to close the modal. 285 * 286 * @param {Drupal.Ajax} [ajax] 287 * {@link Drupal.Ajax} object created by {@link Drupal.ajax}. 288 * @param {object} response 289 * The response from the Ajax request. 290 * @param {string} response.selector 291 * Selector to use. 292 * @param {bool} response.persist 293 * Whether to persist the dialog element or not. 294 * @param {number} [status] 295 * The HTTP status code. 296 */ 297 Drupal.AjaxCommands.prototype.webformCloseDialog = function (ajax, response, status) { 298 if ($('#drupal-off-canvas').length) { 299 // Close off-canvas system tray which is not triggered by close dialog 300 // command. 301 // @see Drupal.behaviors.offCanvasEvents 302 $('#drupal-off-canvas').remove(); 303 $('body').removeClass('js-tray-open'); 304 // Remove all *.off-canvas events 305 $(document).off('.off-canvas'); 306 $(window).off('.off-canvas'); 307 var edge = document.documentElement.dir === 'rtl' ? 'left' : 'right'; 308 var $mainCanvasWrapper = $('[data-off-canvas-main-canvas]'); 309 $mainCanvasWrapper.css('padding-' + edge, 0); 310 311 // Resize tabs when closing off-canvas system tray. 312 $(window).trigger('resize.tabs'); 313 } 314 315 // https://stackoverflow.com/questions/15763909/jquery-ui-dialog-check-if-exists-by-instance-method 316 if ($(response.selector).hasClass('ui-dialog-content')) { 317 this.closeDialog(ajax, response, status); 318 } 319 }; 320 321 /** 322 * Triggers confirm page reload. 323 * 324 * @param {Drupal.Ajax} [ajax] 325 * A {@link Drupal.ajax} object. 326 * @param {object} response 327 * Ajax response. 328 * @param {string} response.message 329 * A message to be displayed in the confirm dialog. 330 */ 331 Drupal.AjaxCommands.prototype.webformConfirmReload = function (ajax, response) { 332 if (window.confirm(response.message)) { 333 window.location.reload(true); 334 } 335 }; 336 337})(jQuery, Drupal, drupalSettings);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.