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