1/** 2 * @file 3 * JavaScript behaviors for unsaved webforms. 4 */ 5 6(function ($, Drupal, once) { 7 var unsaved = false; 8 9 /** 10 * Unsaved changes. 11 * 12 * @type {Drupal~behavior} 13 * 14 * @prop {Drupal~behaviorAttach} attach 15 * Attaches the behavior for unsaved changes. 16 */ 17 Drupal.behaviors.webformUnsaved = { 18 clear: function () { 19 // Allow Ajax refresh/redirect to clear unsaved flag. 20 // @see Drupal.AjaxCommands.prototype.webformRefresh 21 unsaved = false; 22 }, 23 get: function () { 24 // Get the current unsaved flag state. 25 return unsaved; 26 }, 27 set: function (value) { 28 // Set the current unsaved flag state. 29 unsaved = value; 30 }, 31 attach(context) { 32 // Look for the 'data-webform-unsaved' attribute which indicates that 33 // a multi-step webform has unsaved data. 34 // @see \Drupal\webform\WebformSubmissionForm::buildForm 35 if ($(once('data-webform-unsaved', '.js-webform-unsaved[data-webform-unsaved]')).length) { 36 unsaved = true; 37 } 38 else { 39 $(once('webform-unsaved', $('.js-webform-unsaved :input:not(:button, :submit, :reset, [type="hidden"])'))).on('change keypress', function (event, param1) { 40 // Ignore events triggered when #states API is changed, 41 // which passes 'webform.states' as param1. 42 // @see webform.states.js ::triggerEventHandlers(). 43 if (param1 !== 'webform.states') { 44 unsaved = true; 45 } 46 }); 47 } 48 49 $(once('webform-unsaved', $('.js-webform-unsaved button, .js-webform-unsaved input[type="submit"]', context))).not('[data-webform-unsaved-ignore]') 50 .on('click', function (event) { 51 // For reset button we must confirm unsaved changes before the 52 // before unload event handler. 53 if ($(this).hasClass('webform-button--reset') && unsaved) { 54 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.'))) { 55 return false; 56 } 57 } 58 59 unsaved = false; 60 }); 61 62 // Add submit handler to form.beforeSend. 63 // Update Drupal.Ajax.prototype.beforeSend only once. 64 if (typeof Drupal.Ajax !== 'undefined' && typeof Drupal.Ajax.prototype.beforeSubmitWebformUnsavedOriginal === 'undefined') { 65 Drupal.Ajax.prototype.beforeSubmitWebformUnsavedOriginal = Drupal.Ajax.prototype.beforeSubmit; 66 Drupal.Ajax.prototype.beforeSubmit = function (form_values, element_settings, options) { 67 unsaved = false; 68 return this.beforeSubmitWebformUnsavedOriginal.apply(this, arguments); 69 }; 70 } 71 72 // Track all CKEditor change events. 73 // @see https://ckeditor.com/old/forums/Support/CKEditor-jQuery-change-event 74 if (window.CKEDITOR && !CKEDITOR.webformUnsaved) { 75 CKEDITOR.webformUnsaved = true; 76 CKEDITOR.on('instanceCreated', function (event) { 77 event.editor.on('change', function (evt) { 78 unsaved = true; 79 }); 80 }); 81 } 82 } 83 }; 84 85 $(window).on('beforeunload', function () { 86 if (unsaved) { 87 return true; 88 } 89 }); 90 91 /** 92 * An experimental shim to partially emulate onBeforeUnload on iOS. 93 * Part of https://github.com/codedance/jquery.AreYouSure/ 94 * 95 * Copyright (c) 2012-2014, Chris Dance and PaperCut Software http://www.papercut.com/ 96 * Dual licensed under the MIT or GPL Version 2 licenses. 97 * http://jquery.org/license 98 * 99 * Author: [email protected] 100 * Date: 19th May 2014 101 */ 102 $(function () { 103 // @see https://stackoverflow.com/questions/58019463/how-to-detect-device-name-in-safari-on-ios-13-while-it-doesnt-show-the-correct 104 var isIOSorOpera = navigator.userAgent.toLowerCase().match(/iphone|ipad|ipod|opera/) 105 || navigator.platform.toLowerCase().match(/iphone|ipad|ipod/) 106 || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1); 107 if (!isIOSorOpera) { 108 return; 109 } 110 111 $('a:not(.use-ajax)').bind('click', function (evt) { 112 var a = $(evt.target).closest('a'); 113 var href = a.attr('href'); 114 if (typeof href !== 'undefined' && !(href.match(/^#/) || href.trim() === '')) { 115 if ($(window).triggerHandler('beforeunload')) {
116 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.'))) { 117 return false; 118 } 119 } 120 var target = a.attr('target'); 121 if (target) { 122 window.open(href, target); 123 } 124 else { 125 window.location.href = href; 126 } 127 return false; 128 } 129 }); 130 }); 131 132})(jQuery, Drupal, 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.