MDL-10386 Quickfeedback and quickgrading fixed! It wasn't setting $needsupdate to...
[moodle.git] / lib / javascript-static.js
CommitLineData
47aa42e2 1// Miscellaneous core Javascript functions for Moodle
2
b48fd7b5 3function popupchecker(msg) {
4 var testwindow = window.open('itestwin.html', '', 'width=1,height=1,left=0,top=0,scrollbars=no');
5 if (testwindow == null)
6 {alert(msg);}
7 else {
8 testwindow.close();
9 }
10}
11
d2ce367f 12/*
63d28811 13function popUpProperties(inobj) {
d2ce367f 14/// Legacy function
15 var op = window.open();
63d28811 16 op.document.open('text/plain');
17 for (objprop in inobj) {
18 op.document.write(objprop + ' => ' + inobj[objprop] + '\n');
19 }
20 op.document.close();
21}
22
23function fillmessagebox(text) {
d2ce367f 24/// Legacy function
63d28811 25 document.form.message.value = text;
26}
27
28function copyrichtext(textname) {
29/// Legacy stub for old editor - to be removed soon
30 return true;
31}
d2ce367f 32*/
63d28811 33
34function checkall() {
d2ce367f 35 var el = document.getElementsByTagName('input');
36 for(var i=0; i<el.length; i++) {
37 if(el[i].type == 'checkbox') {
38 el[i].checked = true;
39 }
40 }
63d28811 41}
42
03f9425f 43function checknone() {
d2ce367f 44 var el = document.getElementsByTagName('input');
45 for(var i=0; i<el.length; i++) {
46 if(el[i].type == 'checkbox') {
47 el[i].checked = false;
48 }
49 }
03f9425f 50}
51
d2ce367f 52function lockoptions(formid, master, subitems) {
027d0485 53 // Subitems is an array of names of sub items.
54 // Optionally, each item in subitems may have a
63d28811 55 // companion hidden item in the form with the
027d0485 56 // same name but prefixed by "h".
d2ce367f 57 var form = document.forms[formid];
58
59 if (eval("form."+master+".checked")) {
63d28811 60 for (i=0; i<subitems.length; i++) {
61 unlockoption(form, subitems[i]);
62 }
63 } else {
64 for (i=0; i<subitems.length; i++) {
65 lockoption(form, subitems[i]);
66 }
67 }
68 return(true);
69}
70
f07b9627 71function lockoption(form,item) {
d2ce367f 72 eval("form."+item+".disabled=true");/* IE thing */
73 if(form.elements['h'+item]) {
74 eval("form.h"+item+".value=1");
f07b9627 75 }
76}
77
78function unlockoption(form,item) {
d2ce367f 79 eval("form."+item+".disabled=false");/* IE thing */
80 if(form.elements['h'+item]) {
81 eval("form.h"+item+".value=0");
f07b9627 82 }
83}
dd07bbac 84
85
50ef8eb9 86function lockoptionsall(formid) {
dd07bbac 87 var form = document.forms[formid];
88 var dependons = eval(formid+'items');
632b88d5 89 var tolock = Array();
dd07bbac 90 for (var dependon in dependons) {
91 var master = form[dependon];
4bc24867 92 if (master == undefined) {
93 continue;
94 }
dd07bbac 95 for (var condition in dependons[dependon]) {
96 for (var value in dependons[dependon][condition]) {
97 var lock;
98 switch (condition) {
99 case 'notchecked':
100 lock = !master.checked; break;
101 case 'checked':
102 lock = master.checked; break;
103 case 'noitemselected':
104 lock = master.selectedIndex==-1; break;
105 case 'eq':
106 lock = master.value==value; break;
107 default:
108 lock = master.value!=value; break;
109 }
110 for (var ei in dependons[dependon][condition][value]) {
632b88d5 111 var eltolock = dependons[dependon][condition][value][ei];
112 if (tolock[eltolock] != null){
113 tolock[eltolock] =
114 lock || tolock[eltolock];
115 } else {
116 tolock[eltolock] = lock;
117 }
dd07bbac 118 }
119 }
50ef8eb9 120 }
dd07bbac 121 }
632b88d5 122 for (var el in tolock){
123 var formelement = form[el];
4bc24867 124 if (formelement == undefined) {
125 continue;
126 }
632b88d5 127 formelement.disabled = tolock[el];
128 }
dd07bbac 129 return true;
50ef8eb9 130}
131
d01a38cb 132function lockoptionsallsetup(formid) {
dd07bbac 133 var form = document.forms[formid];
134 var dependons = eval(formid+'items');
135 for (var dependon in dependons) {
136 var master = form[dependon];
4bc24867 137 if (master == undefined) {
138 continue;
139 }
dd07bbac 140 master.onclick = function() {return lockoptionsall(this.form.getAttribute('id'));};
141 master.onblur = function() {return lockoptionsall(this.form.getAttribute('id'));};
142 master.onchange = function() {return lockoptionsall(this.form.getAttribute('id'));};
143 }
144 for (var i = 0; i < form.elements.length; i++){
145 var formelement = form.elements[i];
146 if (formelement.type=='reset') {
147 formelement.onclick = function() {this.form.reset();return lockoptionsall(this.form.getAttribute('id'));};
148 formelement.onblur = function() {this.form.reset();return lockoptionsall(this.form.getAttribute('id'));};
149 formelement.onchange = function() {this.form.reset();return lockoptionsall(this.form.getAttribute('id'));};
150 }
151 }
152 return lockoptionsall(formid);
d01a38cb 153}
50ef8eb9 154
7678e65c 155
156function submitFormById(id) {
157 var theform = document.getElementById(id);
158 if(!theform) {
159 return false;
160 }
bb006c95 161 if(theform.tagName.toLowerCase() != 'form') {
7678e65c 162 return false;
163 }
164 if(!theform.onsubmit || theform.onsubmit()) {
165 return theform.submit();
166 }
167}
363cb62c 168
8ceb09e0 169function select_all_in(elTagName, elClass, elId) {
d2ce367f 170 var inputs = document.getElementsByTagName('input');
8ceb09e0 171 inputs = filterByParent(inputs, function(el) {return findParentNode(el, elTagName, elClass, elId);});
363cb62c 172 for(var i = 0; i < inputs.length; ++i) {
bee40515 173 if(inputs[i].type == 'checkbox' || inputs[i].type == 'radio') {
363cb62c 174 inputs[i].checked = 'checked';
175 }
176 }
177}
178
8ceb09e0 179function deselect_all_in(elTagName, elClass, elId) {
363cb62c 180 var inputs = document.getElementsByTagName('INPUT');
8ceb09e0 181 inputs = filterByParent(inputs, function(el) {return findParentNode(el, elTagName, elClass, elId);});
363cb62c 182 for(var i = 0; i < inputs.length; ++i) {
bee40515 183 if(inputs[i].type == 'checkbox' || inputs[i].type == 'radio') {
363cb62c 184 inputs[i].checked = '';
185 }
186 }
187}
188
189function confirm_if(expr, message) {
190 if(!expr) {
191 return true;
192 }
193 return confirm(message);
194}
47aa42e2 195
196
197/*
198 findParentNode (start, elementName, elementClass, elementID)
50ef8eb9 199
47aa42e2 200 Travels up the DOM hierarchy to find a parent element with the
201 specified tag name, class, and id. All conditions must be met,
202 but any can be ommitted. Returns the BODY element if no match
203 found.
204*/
205function findParentNode(el, elName, elClass, elId) {
ef4d42fd 206 while(el.nodeName.toUpperCase() != 'BODY') {
47aa42e2 207 if(
ef4d42fd 208 (!elName || el.nodeName.toUpperCase() == elName) &&
47aa42e2 209 (!elClass || el.className.indexOf(elClass) != -1) &&
210 (!elId || el.id == elId))
211 {
212 break;
213 }
214 el = el.parentNode;
215 }
216 return el;
217}
19194f82 218/*
219 findChildNode (start, elementName, elementClass, elementID)
220
221 Travels down the DOM hierarchy to find all child elements with the
222 specified tag name, class, and id. All conditions must be met,
223 but any can be ommitted.
a23f0aaf 224 Doesn't examine children of matches.
19194f82 225*/
226function findChildNodes(start, tagName, elementClass, elementID, elementName) {
227 var children = new Array();
83c9a8a2 228 for (var i = 0; i < start.childNodes.length; i++) {
a23f0aaf 229 var classfound = false;
83c9a8a2 230 var child = start.childNodes[i];
a23f0aaf 231 if((child.nodeType == 1) &&//element node type
232 (elementClass && (typeof(child.className)=='string'))){
233 var childClasses = child.className.split(/\s+/);
234 for (var childClassIndex in childClasses){
235 if (childClasses[childClassIndex]==elementClass){
236 classfound = true;
237 break;
238 }
239 }
240 }
f07b9627 241 if(child.nodeType == 1) { //element node type
242 if ( (!tagName || child.nodeName == tagName) &&
243 (!elementClass || classfound)&&
244 (!elementID || child.id == elementID) &&
245 (!elementName || child.name == elementName))
246 {
247 children = children.concat(child);
248 } else {
249 children = children.concat(findChildNodes(child, tagName, elementClass, elementID, elementName));
250 }
19194f82 251 }
19194f82 252 }
253 return children;
254}
255/*
256 elementSetHide (elements, hide)
257
258 Adds or removes the "hide" class for the specified elements depending on boolean hide.
259*/
260function elementShowAdvanced(elements, show) {
261 for (var elementIndex in elements){
262 element = elements[elementIndex];
263 element.className = element.className.replace(new RegExp(' ?hide'), '')
264 if(!show) {
265 element.className += ' hide';
266 }
267 }
268}
269
270function showAdvancedOnClick(button, hidetext, showtext){
271 var toSet=findChildNodes(button.form, null, 'advanced');
272 var buttontext = '';
74d15d35 273 if (button.form.elements['mform_showadvanced_last'].value == '0' || button.form.elements['mform_showadvanced_last'].value == '' ) {
19194f82 274 elementShowAdvanced(toSet, true);
275 buttontext = hidetext;
276 button.form.elements['mform_showadvanced_last'].value = '1';
277 } else {
278 elementShowAdvanced(toSet, false);
279 buttontext = showtext;
280 button.form.elements['mform_showadvanced_last'].value = '0';
281 }
282 var formelements = button.form.elements;
283 for (var i in formelements){
9bf930bd 284 if (formelements[i] && formelements[i].name && (formelements[i].name=='mform_showadvanced')){
19194f82 285 formelements[i].value = buttontext;
286 }
287 }
288 //never submit the form if js is enabled.
289 return false;
290}
47aa42e2 291
54bb33eb 292function unmaskPassword(id) {
239ade45 293 var pw = document.getElementById(id);
54bb33eb 294 var chb = document.getElementById(id+'unmask');
239ade45 295
296 try {
297 // first try IE way - it can not set name attribute later
298 if (chb.checked) {
299 var newpw = document.createElement('<input type="text" name="'+pw.name+'">');
300 } else {
301 var newpw = document.createElement('<input type="password" name="'+pw.name+'">');
302 }
eba8cd63 303 newpw.attributes['class'].nodeValue = pw.attributes['class'].nodeValue;
239ade45 304 } catch (e) {
305 var newpw = document.createElement('input');
306 newpw.setAttribute('name', pw.name);
307 if (chb.checked) {
308 newpw.setAttribute('type', 'text');
309 } else {
310 newpw.setAttribute('type', 'password');
311 }
eba8cd63 312 newpw.setAttribute('class', pw.getAttribute('class'));
239ade45 313 }
314 newpw.id = pw.id;
315 newpw.size = pw.size;
316 newpw.onblur = pw.onblur;
317 newpw.onchange = pw.onchange;
318 newpw.value = pw.value;
319 pw.parentNode.replaceChild(newpw, pw);
320}
321
47aa42e2 322/*
323 elementToggleHide (element, elementFinder)
324
325 If elementFinder is not provided, toggles the "hidden" class for the specified element.
326 If elementFinder is provided, then the "hidden" class will be toggled for the object
327 returned by the function call elementFinder(element).
328
329 If persistent == true, also sets a cookie for this.
330*/
19194f82 331function elementToggleHide(el, persistent, elementFinder) {
47aa42e2 332 if(!elementFinder) {
333 var obj = el;
334 }
335 else {
336 var obj = elementFinder(el);
337 }
338 if(obj.className.indexOf('hidden') == -1) {
339 obj.className += ' hidden';
19194f82 340 var shown = 0;
47aa42e2 341 }
342 else {
19194f82 343 obj.className = obj.className.replace(new RegExp(' ?hidden'), '')
344 var shown = 1;
47aa42e2 345 }
19194f82 346
47aa42e2 347 if(persistent == true) {
348 new cookie('hide:' + obj.id, 1, (shown ? -1 : 356), '/').set();
349 }
350}
351
352
353function elementCookieHide(id) {
354 var obj = document.getElementById(id);
355 var cook = new cookie('hide:' + id).read();
356 if(cook != null) {
357 elementToggleHide(obj, false);
358 }
359}
360
361function filterByParent(elCollection, parentFinder) {
362 var filteredCollection = [];
363 for(var i = 0; i < elCollection.length; ++i) {
364 var findParent = parentFinder(elCollection[i]);
365 if(findParent.nodeName != 'BODY') {
366 filteredCollection.push(elCollection[i]);
367 }
368 }
369 return filteredCollection;
370}
371
7979105c 372/*
373 All this is here just so that IE gets to handle oversized blocks
374 in a visually pleasing manner. It does a browser detect. So sue me.
375*/
376
377function fix_column_widths() {
378 var agt = navigator.userAgent.toLowerCase();
379 if ((agt.indexOf("msie") != -1) && (agt.indexOf("opera") == -1)) {
380 fix_column_width('left-column');
381 fix_column_width('right-column');
382 }
383}
384
385function fix_column_width(colName) {
386 if(column = document.getElementById(colName)) {
387 if(!column.offsetWidth) {
388 setTimeout("fix_column_width('" + colName + "')", 20);
389 return;
390 }
391
392 var width = 0;
393 var nodes = column.childNodes;
394
395 for(i = 0; i < nodes.length; ++i) {
396 if(nodes[i].className.indexOf("sideblock") != -1 ) {
397 if(width < nodes[i].offsetWidth) {
398 width = nodes[i].offsetWidth;
399 }
400 }
401 }
402
403 for(i = 0; i < nodes.length; ++i) {
404 if(nodes[i].className.indexOf("sideblock") != -1 ) {
405 nodes[i].style.width = width + 'px';
406 }
407 }
408 }
409}
d13c5938 410
411
412/*
9f439b17 413 Insert myValue at current cursor position
414 */
d13c5938 415function insertAtCursor(myField, myValue) {
9f439b17 416 // IE support
417 if (document.selection) {
418 myField.focus();
419 sel = document.selection.createRange();
420 sel.text = myValue;
421 }
422 // Mozilla/Netscape support
423 else if (myField.selectionStart || myField.selectionStart == '0') {
424 var startPos = myField.selectionStart;
425 var endPos = myField.selectionEnd;
426 myField.value = myField.value.substring(0, startPos)
427 + myValue + myField.value.substring(endPos, myField.value.length);
428 } else {
429 myField.value += myValue;
430 }
d13c5938 431}
7470d6de 432
433
434/*
435 Call instead of setting window.onload directly or setting body onload=.
436 Adds your function to a chain of functions rather than overwriting anything
437 that exists.
438*/
439function addonload(fn) {
440 var oldhandler=window.onload;
441 window.onload=function() {
442 if(oldhandler) oldhandler();
443 fn();
444 }
445}