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