1/** 2 * @file 3 * JavaScript behaviors for Ajax. 4 */ 5 6(function ($, Drupal, drupalSettings, once) { 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 $(once('webform-ajax-link', '.webform-ajax-link', context)).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 $(once('webform-ajax-hash', '[data-hash]', context)).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 $(once('webform-confirmation-back-ajax', '.js-webform-confirmation-back-link-ajax', context)) 96 .on('click', function (event) { 97 var $form = $(this).parents('form'); 98 99 // Trigger the Ajax call back for the hidden submit button. 100 // @see \Drupal\webform\WebformSubmissionForm::getCustomForm 101 $form.find('.js-webform-confirmation-back-submit-ajax').trigger('click'); 102 103 // Move the progress indicator from the submit button to after this link. 104 // @todo Figure out a better way to set a progress indicator. 105 var $progress_indicator = $form.find('.ajax-progress'); 106 if ($progress_indicator) { 107 $(this).after($progress_indicator); 108 } 109 110 // Cancel the click event. 111 event.preventDefault(); 112 event.stopPropagation(); 113 }); 114 } 115 }; 116 117 /** ********************************************************************** **/ 118 // Ajax commands. 119 /** ********************************************************************** **/ 120 121 /** 122 * Track the updated table row key. 123 */ 124 var updateKey; 125 126 /** 127 * Track the add element key. 128 */ 129 var addElement; 130 131 /** 132 * Command to insert new content into the DOM. 133 * 134 * @param {Drupal.Ajax} ajax 135 * {@link Drupal.Ajax} object created by {@link Drupal.ajax}. 136 * @param {object} response 137 * The response from the Ajax request. 138 * @param {string} response.data 139 * The data to use with the jQuery method. 140 * @param {string} [response.method] 141 * The jQuery DOM manipulation method to be used. 142 * @param {string} [response.selector] 143 * A optional jQuery selector string. 144 * @param {object} [response.settings] 145 * An optional array of settings that will be used. 146 * @param {number} [status] 147 * The XMLHttpRequest status. 148 */ 149 Drupal.AjaxCommands.prototype.webformInsert = function (ajax, response, status) { 150 // Insert the HTML. 151 this.insert(ajax, response, status); 152 153 // Add element. 154 if (addElement) { 155 var addSelector = (addElement === '_root_') 156 ? '#webform-ui-add-element' 157 : '[data-drupal-selector="edit-webform-ui-elements-' + addElement + '-add"]'; 158 $(addSelector).trigger('click'); 159 } 160 161 // If not add element, then scroll to and highlight the updated table row. 162 if (!addElement && updateKey) { 163 var $element = $('tr[data-webform-key="' + updateKey + '"]'); 164 165 // Highlight the updated element's row. 166 $element.addClass('color-success'); 167 setTimeout(function () {$element.removeClass('color-success');}, 3000); 168 169 // Focus first tabbable item for the updated elements and handlers. 170 $element.find(':tabbable:not(.tabledrag-handle)').eq(0).trigger('focus'); 171 172 // Scroll element into view. 173 Drupal.webformScrolledIntoView($element); 174 } 175 else { 176 // Focus main content. 177 $('#main-content').trigger('focus'); 178 } 179 180 // Display main page's status message in a floating container. 181 var $wrapper = $(response.selector); 182 if ($wrapper.parents('.ui-dialog').length === 0) { 183 var $messages = $wrapper.find('.messages'); 184 // If 'add element' don't show any messages. 185 if (addElement) { 186 $messages.remove(); 187 } 188 else if ($messages.length) { 189 var $floatingMessage = $('#webform-ajax-messages'); 190 if ($floatingMessage.length === 0) { 191 $floatingMessage = $('<div id="webform-ajax-messages" class="webform-ajax-messages"></div>'); 192 $('body').append($floatingMessage); 193 } 194 if ($floatingMessage.is(':animated')) { 195 $floatingMessage.stop(true, true); 196 } 197 $floatingMessage.html($messages).show().delay(3000).fadeOut(1000); 198 } 199 } 200 201 updateKey = null; // Reset element update. 202 addElement = null; // Reset add element. 203 }; 204 205 /** 206 * Scroll to top ajax command. 207 * 208 * @param {Drupal.Ajax} [ajax] 209 * A {@link Drupal.ajax} object. 210 * @param {object} response 211 * Ajax response. 212 * @param {string} response.selector 213 * Selector to use. 214 * 215 * @see Drupal.AjaxCommands.prototype.viewScrollTop 216 */ 217 Drupal.AjaxCommands.prototype.webformScrollTop = function (ajax, response) { 218 // Scroll top. 219 Drupal.webformScrollTop(response.selector, response.target); 220 221 // Focus on the form wrapper content bookmark if 222 // .js-webform-autofocus is not enabled. 223 // @see \Drupal\webform\Form\WebformAjaxFormTrait::buildAjaxForm 224 var $form = $(response.selector + '-content').find('form'); 225 if (!$form.hasClass('js-webform-autofocus')) { 226 $(response.selector + '-content').trigger('focus'); 227 } 228 }; 229 230 /** 231 * Command to refresh the current webform page. 232 * 233 * @param {Drupal.Ajax} [ajax] 234 * {@link Drupal.Ajax} object created by {@link Drupal.ajax}. 235 * @param {object} response 236 * The response from the Ajax request. 237 * @param {string} response.url 238 * The URL to redirect to. 239 * @param {number} [status] 240 * The XMLHttpRequest status. 241 */ 242 Drupal.AjaxCommands.prototype.webformRefresh = function (ajax, response, status) { 243 // Get URL path name. 244 // @see https://stackoverflow.com/questions/6944744/javascript-get-portion-of-url-path 245 var a = document.createElement('a'); 246 a.href = response.url; 247 var forceReload = (response.url.match(/\?reload=([^&]+)($|&)/)) ? RegExp.$1 : null; 248 if (forceReload) { 249 response.url = response.url.replace(/\?reload=([^&]+)($|&)/, ''); 250 this.redirect(ajax, response, status); 251 return; 252 } 253 254 if (a.pathname === window.location.pathname && $('.webform-ajax-refresh').length) { 255 updateKey = (response.url.match(/[?|&]update=([^&]+)($|&)/)) ? RegExp.$1 : null; 256 addElement = (response.url.match(/[?|&]add_element=([^&]+)($|&)/)) ? RegExp.$1 : null; 257 $('.webform-ajax-refresh').trigger('click'); 258 } 259 else { 260 // Clear unsaved information flag so that the current webform page 261 // can be redirected. 262 // @see Drupal.behaviors.webformUnsaved.clear 263 if (Drupal.behaviors.webformUnsaved) { 264 Drupal.behaviors.webformUnsaved.clear(); 265 } 266 267 // For webform embedded in an iframe, open all redirects in the top 268 // of the browser window. 269 // @see \Drupal\webform_share\Controller\WebformShareController::page 270 if (drupalSettings.webform_share && 271 drupalSettings.webform_share.page) { 272 window.top.location = response.url; 273 } 274 else { 275 this.redirect(ajax, response, status); 276 } 277 } 278 }; 279 280 /** 281 * Command to close a off-canvas and modal dialog. 282 * 283 * If no selector is given, it defaults to trying to close the modal. 284 * 285 * @param {Drupal.Ajax} [ajax] 286 * {@link Drupal.Ajax} object created by {@link Drupal.ajax}. 287 * @param {object} response 288 * The response from the Ajax request. 289 * @param {string} response.selector 290 * Selector to use. 291 * @param {bool} response.persist 292 * Whether to persist the dialog element or not. 293 * @param {number} [status] 294 * The HTTP status code. 295 */ 296 Drupal.AjaxCommands.prototype.webformCloseDialog = function (ajax, response, status) { 297 if ($('#drupal-off-canvas').length) { 298 // Close off-canvas system tray which is not triggered by close dialog 299 // command. 300 // @see Drupal.behaviors.offCanvasEvents 301 $('#drupal-off-canvas').remove(); 302 $('body').removeClass('js-tray-open'); 303 // Remove all *.off-canvas events 304 $(document).off('.off-canvas'); 305 $(window).off('.off-canvas'); 306 var edge = document.documentElement.dir === 'rtl' ? 'left' : 'right'; 307 var $mainCanvasWrapper = $('[data-off-canvas-main-canvas]'); 308 $mainCanvasWrapper.css('padding-' + edge, 0); 309 310 // Resize tabs when closing off-canvas system tray. 311 $(window).trigger('resize.tabs'); 312 } 313 314 // https://stackoverflow.com/questions/15763909/jquery-ui-dialog-check-if-exists-by-instance-method 315 if ($(response.selector).hasClass('ui-dialog-content')) { 316 this.closeDialog(ajax, response, status); 317 } 318 }; 319 320 /** 321 * Triggers confirm page reload. 322 * 323 * @param {Drupal.Ajax} [ajax] 324 * A {@link Drupal.ajax} object. 325 * @param {object} response 326 * Ajax response. 327 * @param {string} response.message 328 * A message to be displayed in the confirm dialog. 329 */ 330 Drupal.AjaxCommands.prototype.webformConfirmReload = function (ajax, response) { 331 if (window.confirm(response.message)) { 332 window.location.reload(true); 333 } 334 }; 335 336})(jQuery, Drupal, drupalSettings, once);
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.