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