[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 /** 2 * A utility to check for form changes before navigating away from a page. 3 * 4 * @module moodle-core-formchangechecker 5 */ 6 7 /** 8 * A utility to check for form changes before navigating away from a page. 9 * 10 * @class M.core.formchangechecker 11 * @constructor 12 */ 13 14 var FORMCHANGECHECKERNAME = 'core-formchangechecker', 15 16 FORMCHANGECHECKER = function() { 17 FORMCHANGECHECKER.superclass.constructor.apply(this, arguments); 18 }; 19 20 Y.extend(FORMCHANGECHECKER, Y.Base, { 21 22 // The delegated listeners we need to detach after the initial value has been stored once 23 initialvaluelisteners: [], 24 25 /** 26 * Initialize the module 27 * 28 * @method initializer 29 */ 30 initializer: function() { 31 var formid = 'form#' + this.get('formid'), 32 currentform = Y.one(formid); 33 34 if (!currentform) { 35 // If the form was not found, then we can't check for changes. 36 return; 37 } 38 39 // Add a listener here for an editor restore event. 40 Y.on(M.core.event.EDITOR_CONTENT_RESTORED, M.core_formchangechecker.reset_form_dirty_state, this); 41 42 // Add change events to the form elements 43 currentform.delegate('change', M.core_formchangechecker.set_form_changed, 'input', this); 44 currentform.delegate('change', M.core_formchangechecker.set_form_changed, 'textarea', this); 45 currentform.delegate('change', M.core_formchangechecker.set_form_changed, 'select', this); 46 47 // Add a focus event to check for changes which are made without triggering a change event 48 this.initialvaluelisteners.push(currentform.delegate('focus', this.store_initial_value, 'input', this)); 49 this.initialvaluelisteners.push(currentform.delegate('focus', this.store_initial_value, 'textarea', this)); 50 this.initialvaluelisteners.push(currentform.delegate('focus', this.store_initial_value, 'select', this)); 51 52 // We need any submit buttons on the form to set the submitted flag 53 Y.one(formid).on('submit', M.core_formchangechecker.set_form_submitted, this); 54 55 // YUI doesn't support onbeforeunload properly so we must use the DOM to set the onbeforeunload. As 56 // a result, the has_changed must stay in the DOM too 57 window.onbeforeunload = M.core_formchangechecker.report_form_dirty_state; 58 }, 59 60 /** 61 * Store the initial value of the currently focussed element 62 * 63 * If an element has been focussed and changed but not yet blurred, the on change 64 * event won't be fired. We need to store it's initial value to compare it in the 65 * get_form_dirty_state function later. 66 * 67 * @method store_initial_value 68 * @param {EventFacade} e 69 */ 70 store_initial_value: function(e) { 71 var thisevent; 72 if (e.target.hasClass('ignoredirty')) { 73 // Don't warn on elements with the ignoredirty class 74 return; 75 } 76 if (M.core_formchangechecker.get_form_dirty_state()) { 77 // Detach all listen events to prevent duplicate initial value setting 78 while (this.initialvaluelisteners.length) { 79 thisevent = this.initialvaluelisteners.shift(); 80 thisevent.detach(); 81 } 82 83 return; 84 } 85 86 // Make a note of the current element so that it can be interrogated and 87 // compared in the get_form_dirty_state function 88 M.core_formchangechecker.stateinformation.focused_element = { 89 element: e.target, 90 initial_value: e.target.get('value') 91 }; 92 } 93 }, 94 { 95 NAME: FORMCHANGECHECKERNAME, 96 ATTRS: { 97 formid: { 98 'value': '' 99 } 100 } 101 } 102 ); 103 104 M.core_formchangechecker = M.core_formchangechecker || {}; 105 106 // We might have multiple instances of the form change protector 107 M.core_formchangechecker.instances = M.core_formchangechecker.instances || []; 108 M.core_formchangechecker.init = function(config) { 109 var formchangechecker = new FORMCHANGECHECKER(config); 110 M.core_formchangechecker.instances.push(formchangechecker); 111 return formchangechecker; 112 }; 113 114 // Store state information 115 M.core_formchangechecker.stateinformation = []; 116 117 /* 118 * Set the form changed state to true 119 */ 120 M.core_formchangechecker.set_form_changed = function(e) { 121 if (e && e.target && e.target.hasClass('ignoredirty')) { 122 // Don't warn on elements with the ignoredirty class 123 return; 124 } 125 M.core_formchangechecker.stateinformation.formchanged = 1; 126 127 // Once the form has been marked as dirty, we no longer need to keep track of form elements 128 // which haven't yet blurred 129 delete M.core_formchangechecker.stateinformation.focused_element; 130 }; 131 132 /* 133 * Set the form submitted state to true 134 */ 135 M.core_formchangechecker.set_form_submitted = function() { 136 M.core_formchangechecker.stateinformation.formsubmitted = 1; 137 }; 138 139 /* 140 * Attempt to determine whether the form has been modified in any way and 141 * is thus 'dirty' 142 * 143 * @return Integer 1 is the form is dirty; 0 if not 144 */ 145 M.core_formchangechecker.get_form_dirty_state = function() { 146 var state = M.core_formchangechecker.stateinformation, 147 editor; 148 149 // If the form was submitted, then return a non-dirty state 150 if (state.formsubmitted) { 151 return 0; 152 } 153 154 // If any fields have been marked dirty, return a dirty state 155 if (state.formchanged) { 156 return 1; 157 } 158 159 // If a field has been focused and changed, but still has focus then the browser won't fire the 160 // onChange event. We check for this eventuality here 161 if (state.focused_element) { 162 if (state.focused_element.element.get('value') !== state.focused_element.initial_value) { 163 return 1; 164 } 165 } 166 167 // Handle TinyMCE editor instances 168 // We can't add a listener in the initializer as the editors may not have been created by that point 169 // so we do so here instead 170 if (typeof window.tinyMCE !== 'undefined') { 171 for (editor in window.tinyMCE.editors) { 172 if (window.tinyMCE.editors[editor].isDirty()) { 173 return 1; 174 } 175 } 176 } 177 178 // If we reached here, then the form hasn't met any of the dirty conditions 179 return 0; 180 }; 181 182 /* 183 * Reset the form state 184 */ 185 M.core_formchangechecker.reset_form_dirty_state = function() { 186 M.core_formchangechecker.stateinformation.formsubmitted = false; 187 M.core_formchangechecker.stateinformation.formchanged = false; 188 }; 189 190 /* 191 * Return a suitable message if changes have been made to a form 192 */ 193 M.core_formchangechecker.report_form_dirty_state = function(e) { 194 if (!M.core_formchangechecker.get_form_dirty_state()) { 195 // the form is not dirty, so don't display any message 196 return; 197 } 198 199 // This is the error message that we'll show to browsers which support it 200 var warningmessage = M.util.get_string('changesmadereallygoaway', 'moodle'); 201 202 if (M.cfg.behatsiterunning) { 203 // If the behat site is running we don't want browser alerts. 204 return; 205 } 206 207 // Most browsers are happy with the returnValue being set on the event 208 // But some browsers do not consistently pass the event 209 if (e) { 210 e.returnValue = warningmessage; 211 } 212 213 // But some require it to be returned instead 214 return warningmessage; 215 };
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |