MDL-21400 removing some YUI2 extras
[moodle.git] / lib / javascript-static.js
CommitLineData
47aa42e2 1// Miscellaneous core Javascript functions for Moodle
e50b4c89 2// Global M object is initilised in inline javascript
34f76e9a 3
e50b4c89
PS
4/**
5 * Add module to list of available modules that can be laoded from YUI.
126590b7 6 * @param {Array} modules
e50b4c89
PS
7 */
8M.yui.add_module = function(modules) {
126590b7 9 for (var modname in modules) {
fc367afb
PS
10 M.yui.loader.modules[modname] = modules[modname];
11 }
e50b4c89
PS
12};
13
38224dcb 14
bca09754
PS
15/**
16 * Various utility functions
17 */
38224dcb
PS
18M.util = {};
19
20/**
21 * Returns url for images.
126590b7
SH
22 * @param {String} imagename
23 * @param {String} component
24 * @return {String}
38224dcb
PS
25 */
26M.util.image_url = function(imagename, component) {
27 var url = M.cfg.wwwroot + '/theme/image.php?theme=' + M.cfg.theme + '&image=' + imagename;
28
29 if (M.cfg.themerev > 0) {
30 url = url + '&rev=' + M.cfg.themerev;
31 }
32
33 if (component != '' && component != 'moodle' && component != 'core') {
34 url = url + '&component=' + component;
35 }
36
37 return url;
38};
39
10eaeca8
PS
40M.util.create_UFO_object = function (eid, FO) {
41 UFO.create(FO, eid);
42}
43
38224dcb
PS
44/**
45 * Init a collapsible region, see print_collapsible_region in weblib.php
126590b7
SH
46 * @param {YUI} Y YUI3 instance with all libraries loaded
47 * @param {String} id the HTML id for the div.
48 * @param {String} userpref the user preference that records the state of this box. false if none.
49 * @param {String} strtooltip
38224dcb
PS
50 */
51M.util.init_collapsible_region = function(Y, id, userpref, strtooltip) {
52 Y.use('anim', function(Y) {
3b044ba3 53 new M.util.CollapsibleRegion(Y, id, userpref, strtooltip);
38224dcb
PS
54 });
55};
56
57/**
126590b7 58 * Object to handle a collapsible region : instantiate and forget styled object
3b044ba3 59 *
126590b7 60 * @class
38224dcb 61 * @constructor
126590b7
SH
62 * @param {YUI} Y YUI3 instance with all libraries loaded
63 * @param {String} id The HTML id for the div.
64 * @param {String} userpref The user preference that records the state of this box. false if none.
65 * @param {String} strtooltip
38224dcb
PS
66 */
67M.util.CollapsibleRegion = function(Y, id, userpref, strtooltip) {
38224dcb
PS
68 // Record the pref name
69 this.userpref = userpref;
38224dcb
PS
70
71 // Find the divs in the document.
126590b7
SH
72 this.div = Y.one('#'+id);
73
74 // Get the caption for the collapsible region
75 var caption = this.div.one('#'+id + '_caption');
76 caption.setAttribute('title', strtooltip);
77
78 // Create a link
79 var a = Y.Node.create('<a href="#"></a>');
80 // Create a local scoped lamba function to move nodes to a new link
81 var movenode = function(node){
82 node.remove();
83 a.append(node);
84 };
85 // Apply the lamba function on each of the captions child nodes
86 caption.get('children').each(movenode, this);
87 caption.append(a);
88
89 // Get the height of the div at this point before we shrink it if required
90 var height = this.div.get('offsetHeight');
91 if (this.div.hasClass('collapsed')) {
92 // Add the correct image and record the YUI node created in the process
93 this.icon = Y.Node.create('<img src="'+M.util.image_url('t/collapsed', 'moodle')+'" alt="" />');
94 // Shrink the div as it is collapsed by default
95 this.div.setStyle('height', caption.get('offsetHeight')+'px');
96 } else {
97 // Add the correct image and record the YUI node created in the process
98 this.icon = Y.Node.create('<img src="'+M.util.image_url('t/expanded', 'moodle')+'" alt="" />');
38224dcb 99 }
126590b7 100 a.append(this.icon);
38224dcb
PS
101
102 // Create the animation.
126590b7 103 var animation = new Y.Anim({
38224dcb
PS
104 node: this.div,
105 duration: 0.3,
126590b7
SH
106 easing: Y.Easing.easeBoth,
107 to: {height:caption.get('offsetHeight')},
108 from: {height:height}
38224dcb 109 });
3b044ba3 110
38224dcb 111 // Handler for the animation finishing.
126590b7
SH
112 animation.on('end', function() {
113 this.div.toggleClass('collapsed');
114 if (this.div.hasClass('collapsed')) {
115 this.icon.set('src', M.util.image_url('t/collapsed', 'moodle'));
116 } else {
117 this.icon.set('src', M.util.image_url('t/expanded', 'moodle'));
fc367afb 118 }
38224dcb 119 }, this);
126590b7
SH
120
121 // Hook up the event handler.
122 a.on('click', function(e, animation) {
123 e.preventDefault();
124 // Animate to the appropriate size.
125 if (animation.get('running')) {
126 animation.stop();
127 }
128 animation.set('reverse', this.div.hasClass('collapsed'));
129 // Update the user preference.
130 if (this.userpref) {
41912a26 131 M.util.set_user_preference(this.userpref, !this.div.hasClass('collapsed'));
126590b7
SH
132 }
133 animation.run();
134 }, this, animation);
38224dcb
PS
135};
136
137/**
138 * The user preference that stores the state of this box.
139 * @property userpref
140 * @type String
141 */
142M.util.CollapsibleRegion.prototype.userpref = null;
143
144/**
145 * The key divs that make up this
126590b7
SH
146 * @property div
147 * @type Y.Node
38224dcb
PS
148 */
149M.util.CollapsibleRegion.prototype.div = null;
38224dcb
PS
150
151/**
152 * The key divs that make up this
153 * @property icon
126590b7 154 * @type Y.Node
38224dcb
PS
155 */
156M.util.CollapsibleRegion.prototype.icon = null;
157
3b044ba3
PS
158/**
159 * Finds all help icons on the page and initiates YUI tooltips for
160 * each of them, which load a truncated version of the help's content
161 * on-the-fly asynchronously
162 */
163M.util.init_help_icons = function(Y) {
26114d52 164 Y.use('io', 'yui2-dom', 'yui2-container', function(Y) {
3b044ba3
PS
165 // remove all titles, they would obscure the YUI tooltip
166 Y.all('span.helplink a').each(function(node) {
167 node.set('title', '');
168 });
169
170 var iconspans = YAHOO.util.Dom.getElementsByClassName('helplink', 'span');
171 var tooltip = new YAHOO.widget.Tooltip('help_icon_tooltip', {
172 context: iconspans,
173 showdelay: 1000,
174 hidedelay: 150,
175 autodismissdelay: 50000,
176 underlay: 'none',
177 zIndex: '1000'
178 });
179
180 tooltip.contextTriggerEvent.subscribe(
181 function(type, args) {
182 // Fetch help page contents asynchronously
183 // Load spinner icon while content is loading
184 var spinner = document.createElement('img');
185 spinner.src = M.cfg.loadingicon;
186
187 this.cfg.setProperty('text', spinner);
188
189 var context = args[0];
190
191 var link = context.getElementsByTagName('a')[0];
192 var thistooltip = this;
193 var ajaxurl = link.href + '&fortooltip=1';
194
195
196 var cfg = {
197 method: 'get',
198 on: {
199 success: function(id, o, args) {
200 thistooltip.cfg.setProperty('text', o.responseText);
201 },
202 failure: function(id, o, args) {
203 var debuginfo = o.statusText;
204 if (M.cfg.developerdebug) {
205 o.statusText += ' (' + ajaxurl + ')';
206 }
207 thistooltip.cfg.setProperty('text', debuginfo);
208 }
209 }
210 };
211
212 var conn = Y.io(ajaxurl, cfg);
213 }
214 );
215 });
216};
217
41912a26
PS
218
219/**
220 * Makes a best effort to connect back to Moodle to update a user preference,
221 * however, there is no mechanism for finding out if the update succeeded.
222 *
223 * Before you can use this function in your JavsScript, you must have called
224 * user_preference_allow_ajax_update from moodlelib.php to tell Moodle that
225 * the udpate is allowed, and how to safely clean and submitted values.
226 *
227 * @param String name the name of the setting to udpate.
228 * @param String the value to set it to.
229 */
230M.util.set_user_preference = function(name, value) {
231 YUI(M.yui.loader).use('io', function(Y) {
232 var url = M.cfg.wwwroot + '/lib/ajax/setuserpref.php?sesskey=' +
233 M.cfg.sesskey + '&pref=' + encodeURI(name) + '&value=' + encodeURI(value);
234
235 // If we are a developer, ensure that failures are reported.
236 var cfg = {
237 method: 'get',
238 on: {},
239 };
240 if (M.cfg.developerdebug) {
241 cfg.on.failure = function(id, o, args) {
242 alert("Error updating user preference '" + name + "' using ajax. Clicking this link will repeat the Ajax call that failed so you can see the error: ");
243 }
244 }
245
246 // Make the request.
247 Y.io(url, cfg);
248 });
249};
250
38224dcb
PS
251//=== old legacy JS code, hopefully to be replaced soon by M.xx.yy and YUI3 code ===
252
b48fd7b5 253function popupchecker(msg) {
496e3ccd 254 var testwindow = window.open('', '', 'width=1,height=1,left=0,top=0,scrollbars=no');
f6b6861d 255 if (!testwindow) {
256 alert(msg);
257 } else {
b48fd7b5 258 testwindow.close();
259 }
260}
261
63d28811 262function checkall() {
214f5850 263 var inputs = document.getElementsByTagName('input');
264 for (var i = 0; i < inputs.length; i++) {
265 if (inputs[i].type == 'checkbox') {
266 inputs[i].checked = true;
267 }
d2ce367f 268 }
63d28811 269}
270
03f9425f 271function checknone() {
214f5850 272 var inputs = document.getElementsByTagName('input');
273 for (var i = 0; i < inputs.length; i++) {
274 if (inputs[i].type == 'checkbox') {
275 inputs[i].checked = false;
276 }
d2ce367f 277 }
03f9425f 278}
279
d2ce367f 280function lockoptions(formid, master, subitems) {
027d0485 281 // Subitems is an array of names of sub items.
282 // Optionally, each item in subitems may have a
63d28811 283 // companion hidden item in the form with the
027d0485 284 // same name but prefixed by "h".
d2ce367f 285 var form = document.forms[formid];
286
287 if (eval("form."+master+".checked")) {
63d28811 288 for (i=0; i<subitems.length; i++) {
289 unlockoption(form, subitems[i]);
290 }
291 } else {
292 for (i=0; i<subitems.length; i++) {
293 lockoption(form, subitems[i]);
294 }
295 }
296 return(true);
297}
298
f07b9627 299function lockoption(form,item) {
d2ce367f 300 eval("form."+item+".disabled=true");/* IE thing */
301 if(form.elements['h'+item]) {
302 eval("form.h"+item+".value=1");
f07b9627 303 }
304}
305
306function unlockoption(form,item) {
d2ce367f 307 eval("form."+item+".disabled=false");/* IE thing */
308 if(form.elements['h'+item]) {
309 eval("form.h"+item+".value=0");
f07b9627 310 }
311}
dd07bbac 312
b51709c1 313/**
314 * Get the value of the 'virtual form element' with a particular name. That is,
315 * abstracts away the difference between a normal form element, like a select
316 * which is a single HTML element with a .value property, and a set of radio
317 * buttons, which is several HTML elements.
318 *
319 * @param form a HTML form.
320 * @param master the name of an element in that form.
321 * @return the value of that element.
322 */
323function get_form_element_value(form, name) {
324 var element = form[name];
325 if (!element) {
326 return null;
327 }
328 if (element.tagName) {
329 // Ordinarly thing like a select box.
330 return element.value;
331 }
332 // Array of things, like radio buttons.
333 for (var j = 0; j < element.length; j++) {
334 var el = element[j];
335 if (el.checked) {
336 return el.value;
337 }
338 }
339 return null;
340}
341
342
343/**
344 * Set the disabled state of the 'virtual form element' with a particular name.
345 * This abstracts away the difference between a normal form element, like a select
346 * which is a single HTML element with a .value property, and a set of radio
347 * buttons, which is several HTML elements.
348 *
349 * @param form a HTML form.
350 * @param master the name of an element in that form.
351 * @param disabled the disabled state to set.
352 */
353function set_form_element_disabled(form, name, disabled) {
354 var element = form[name];
355 if (!element) {
356 return;
357 }
358 if (element.tagName) {
359 // Ordinarly thing like a select box.
360 element.disabled = disabled;
361 }
362 // Array of things, like radio buttons.
363 for (var j = 0; j < element.length; j++) {
364 var el = element[j];
365 el.disabled = disabled;
366 }
367}
dd07bbac 368
41f23791 369/**
370 * Set the hidden state of the 'virtual form element' with a particular name.
371 * This abstracts away the difference between a normal form element, like a select
372 * which is a single HTML element with a .value property, and a set of radio
373 * buttons, which is several HTML elements.
374 *
375 * @param form a HTML form.
376 * @param master the name of an element in that form.
377 * @param hidden the hidden state to set.
378 */
379function set_form_element_hidden(form, name, hidden) {
380 var element = form[name];
381 if (!element) {
382 return;
383 }
384 if (element.tagName) {
385 var el = findParentNode(element, 'DIV', 'fitem', false);
386 if (el!=null) {
387 el.style.display = hidden ? 'none' : '';
388 el.style.visibility = hidden ? 'hidden' : '';
389 }
390 }
391 // Array of things, like radio buttons.
392 for (var j = 0; j < element.length; j++) {
393 var el = findParentNode(element[j], 'DIV', 'fitem', false);
394 if (el!=null) {
395 el.style.display = hidden ? 'none' : '';
396 el.style.visibility = hidden ? 'hidden' : '';
397 }
398 }
399}
400
50ef8eb9 401function lockoptionsall(formid) {
dd07bbac 402 var form = document.forms[formid];
b51709c1 403 var dependons = eval(formid + 'items');
404 var tolock = [];
41f23791 405 var tohide = [];
dd07bbac 406 for (var dependon in dependons) {
d63ef3b8 407 // change for MooTools compatibility
408 if (!dependons.propertyIsEnumerable(dependon)) {
409 continue;
410 }
b51709c1 411 if (!form[dependon]) {
4bc24867 412 continue;
413 }
dd07bbac 414 for (var condition in dependons[dependon]) {
415 for (var value in dependons[dependon][condition]) {
416 var lock;
41f23791 417 var hide = false;
dd07bbac 418 switch (condition) {
419 case 'notchecked':
b51709c1 420 lock = !form[dependon].checked; break;
dd07bbac 421 case 'checked':
b51709c1 422 lock = form[dependon].checked; break;
dd07bbac 423 case 'noitemselected':
b51709c1 424 lock = form[dependon].selectedIndex == -1; break;
dd07bbac 425 case 'eq':
b51709c1 426 lock = get_form_element_value(form, dependon) == value; break;
41f23791 427 case 'hide':
428 // hide as well as disable
429 hide = true; break;
dd07bbac 430 default:
b51709c1 431 lock = get_form_element_value(form, dependon) != value; break;
dd07bbac 432 }
433 for (var ei in dependons[dependon][condition][value]) {
632b88d5 434 var eltolock = dependons[dependon][condition][value][ei];
41f23791 435 if (hide) {
436 tohide[eltolock] = true;
437 }
b51709c1 438 if (tolock[eltolock] != null) {
439 tolock[eltolock] = lock || tolock[eltolock];
632b88d5 440 } else {
441 tolock[eltolock] = lock;
442 }
dd07bbac 443 }
444 }
50ef8eb9 445 }
dd07bbac 446 }
b51709c1 447 for (var el in tolock) {
d63ef3b8 448 // change for MooTools compatibility
449 if (!tolock.propertyIsEnumerable(el)) {
450 continue;
451 }
b51709c1 452 set_form_element_disabled(form, el, tolock[el]);
41f23791 453 if (tohide.propertyIsEnumerable(el)) {
454 set_form_element_hidden(form, el, tolock[el]);
455 }
632b88d5 456 }
dd07bbac 457 return true;
50ef8eb9 458}
459
d01a38cb 460function lockoptionsallsetup(formid) {
dd07bbac 461 var form = document.forms[formid];
462 var dependons = eval(formid+'items');
463 for (var dependon in dependons) {
d63ef3b8 464 // change for MooTools compatibility
465 if (!dependons.propertyIsEnumerable(dependon)) {
466 continue;
467 }
b51709c1 468 var masters = form[dependon];
469 if (!masters) {
4bc24867 470 continue;
471 }
a4db2e7c 472 if (masters.tagName) {
b51709c1 473 // If master is radio buttons, we get an array, otherwise we don't.
474 // Convert both cases to an array for convinience.
475 masters = [masters];
476 }
477 for (var j = 0; j < masters.length; j++) {
478 master = masters[j];
479 master.formid = formid;
480 master.onclick = function() {return lockoptionsall(this.formid);};
481 master.onblur = function() {return lockoptionsall(this.formid);};
482 master.onchange = function() {return lockoptionsall(this.formid);};
483 }
dd07bbac 484 }
b51709c1 485 for (var i = 0; i < form.elements.length; i++) {
dd07bbac 486 var formelement = form.elements[i];
487 if (formelement.type=='reset') {
c0056e22 488 formelement.formid = formid;
489 formelement.onclick = function() {this.form.reset();return lockoptionsall(this.formid);};
490 formelement.onblur = function() {this.form.reset();return lockoptionsall(this.formid);};
491 formelement.onchange = function() {this.form.reset();return lockoptionsall(this.formid);};
dd07bbac 492 }
493 }
494 return lockoptionsall(formid);
d01a38cb 495}
50ef8eb9 496
dc580207 497/**
498 * Helper function mainly for drop-down menus' onchange events,
13a3ebca 499 * submits the form designated by args.id.
7b1f2c82 500 * Example usage of the html_select component with this function:
dc580207 501 * <pre>
7b1f2c82 502 * $select = new html_select();
49c8c8d2 503 * $select->options = array('delete' => get_string('delete'));
504 * $select->name = 'action';
505 * $select->button->label = get_string('withselected', 'quiz');
506 * $select->id = 'menuaction';
507 * $select->add_action('change', 'submit_form_by_id', array('id' => 'attemptsform', 'selectid' => 'menuaction'));
508 * echo $OUTPUT->select($select);
dc580207 509 * </pre>
510 */
511function submit_form_by_id(e, args) {
8e127eb3 512 var theform = document.getElementById(args.id);
dc580207 513 if (!theform) {
7678e65c 514 return false;
515 }
dc580207 516 if (theform.tagName.toLowerCase() != 'form') {
7678e65c 517 return false;
518 }
13a3ebca
AD
519 //MDL-21513 the below makes the first option unselectable assuming it will be some sort
520 //of "Choose..." option. However if there is no placeholder first option the first item is unselectable :(
521 //if (args.selectid) {
522 // var select = document.getElementById(args.selectid);
523 //if (select.selectedIndex == 0) {
524 // return false;
525 //}
526 //}
dc580207 527 return theform.submit();
7678e65c 528}
363cb62c 529
45caa363 530/**
531 * Either check, or uncheck, all checkboxes inside the element with id is
532 * @param id the id of the container
533 * @param checked the new state, either '' or 'checked'.
534 */
535function select_all_in_element_with_id(id, checked) {
536 var container = document.getElementById(id);
537 if (!container) {
538 return;
539 }
540 var inputs = container.getElementsByTagName('input');
541 for (var i = 0; i < inputs.length; ++i) {
542 if (inputs[i].type == 'checkbox' || inputs[i].type == 'radio') {
543 inputs[i].checked = checked;
544 }
545 }
546}
547
8ceb09e0 548function select_all_in(elTagName, elClass, elId) {
d2ce367f 549 var inputs = document.getElementsByTagName('input');
8ceb09e0 550 inputs = filterByParent(inputs, function(el) {return findParentNode(el, elTagName, elClass, elId);});
363cb62c 551 for(var i = 0; i < inputs.length; ++i) {
bee40515 552 if(inputs[i].type == 'checkbox' || inputs[i].type == 'radio') {
363cb62c 553 inputs[i].checked = 'checked';
554 }
555 }
556}
557
8ceb09e0 558function deselect_all_in(elTagName, elClass, elId) {
363cb62c 559 var inputs = document.getElementsByTagName('INPUT');
8ceb09e0 560 inputs = filterByParent(inputs, function(el) {return findParentNode(el, elTagName, elClass, elId);});
363cb62c 561 for(var i = 0; i < inputs.length; ++i) {
bee40515 562 if(inputs[i].type == 'checkbox' || inputs[i].type == 'radio') {
363cb62c 563 inputs[i].checked = '';
564 }
565 }
566}
567
568function confirm_if(expr, message) {
569 if(!expr) {
570 return true;
571 }
572 return confirm(message);
573}
47aa42e2 574
575
576/*
577 findParentNode (start, elementName, elementClass, elementID)
50ef8eb9 578
47aa42e2 579 Travels up the DOM hierarchy to find a parent element with the
580 specified tag name, class, and id. All conditions must be met,
581 but any can be ommitted. Returns the BODY element if no match
582 found.
583*/
584function findParentNode(el, elName, elClass, elId) {
45caa363 585 while (el.nodeName.toUpperCase() != 'BODY') {
586 if ((!elName || el.nodeName.toUpperCase() == elName) &&
47aa42e2 587 (!elClass || el.className.indexOf(elClass) != -1) &&
45caa363 588 (!elId || el.id == elId)) {
47aa42e2 589 break;
590 }
591 el = el.parentNode;
592 }
593 return el;
594}
19194f82 595/*
596 findChildNode (start, elementName, elementClass, elementID)
597
598 Travels down the DOM hierarchy to find all child elements with the
599 specified tag name, class, and id. All conditions must be met,
600 but any can be ommitted.
a23f0aaf 601 Doesn't examine children of matches.
19194f82 602*/
603function findChildNodes(start, tagName, elementClass, elementID, elementName) {
604 var children = new Array();
83c9a8a2 605 for (var i = 0; i < start.childNodes.length; i++) {
a23f0aaf 606 var classfound = false;
83c9a8a2 607 var child = start.childNodes[i];
a23f0aaf 608 if((child.nodeType == 1) &&//element node type
b51709c1 609 (elementClass && (typeof(child.className)=='string'))) {
a23f0aaf 610 var childClasses = child.className.split(/\s+/);
b51709c1 611 for (var childClassIndex in childClasses) {
612 if (childClasses[childClassIndex]==elementClass) {
a23f0aaf 613 classfound = true;
614 break;
615 }
616 }
617 }
f07b9627 618 if(child.nodeType == 1) { //element node type
619 if ( (!tagName || child.nodeName == tagName) &&
620 (!elementClass || classfound)&&
621 (!elementID || child.id == elementID) &&
622 (!elementName || child.name == elementName))
623 {
624 children = children.concat(child);
625 } else {
626 children = children.concat(findChildNodes(child, tagName, elementClass, elementID, elementName));
627 }
19194f82 628 }
19194f82 629 }
630 return children;
631}
632/*
633 elementSetHide (elements, hide)
634
635 Adds or removes the "hide" class for the specified elements depending on boolean hide.
636*/
637function elementShowAdvanced(elements, show) {
b51709c1 638 for (var elementIndex in elements) {
19194f82 639 element = elements[elementIndex];
640 element.className = element.className.replace(new RegExp(' ?hide'), '')
641 if(!show) {
642 element.className += ' hide';
643 }
644 }
645}
646
cd350b53 647function showAdvancedInit(addBefore, nameAttr, buttonLabel, hideText, showText) {
648 var showHideButton = document.createElement("input");
649 showHideButton.type = 'button';
650 showHideButton.value = buttonLabel;
651 showHideButton.name = nameAttr;
652 showHideButton.moodle = {
fc4f5796 653 hideLabel: mstr.form.hideadvanced,
654 showLabel: mstr.form.showadvanced
cd350b53 655 };
656 YAHOO.util.Event.addListener(showHideButton, 'click', showAdvancedOnClick);
657 el = document.getElementById(addBefore);
658 el.parentNode.insertBefore(showHideButton, el);
659}
660
661function showAdvancedOnClick(e) {
662 var button = e.target ? e.target : e.srcElement;
663
19194f82 664 var toSet=findChildNodes(button.form, null, 'advanced');
665 var buttontext = '';
74d15d35 666 if (button.form.elements['mform_showadvanced_last'].value == '0' || button.form.elements['mform_showadvanced_last'].value == '' ) {
19194f82 667 elementShowAdvanced(toSet, true);
cd350b53 668 buttontext = button.moodle.hideLabel;
19194f82 669 button.form.elements['mform_showadvanced_last'].value = '1';
670 } else {
671 elementShowAdvanced(toSet, false);
cd350b53 672 buttontext = button.moodle.showLabel;
19194f82 673 button.form.elements['mform_showadvanced_last'].value = '0';
674 }
675 var formelements = button.form.elements;
4ea054ec 676 // Fixed MDL-10506
b51709c1 677 for (var i = 0; i < formelements.length; i++) {
678 if (formelements[i] && formelements[i].name && (formelements[i].name=='mform_showadvanced')) {
19194f82 679 formelements[i].value = buttontext;
680 }
681 }
682 //never submit the form if js is enabled.
683 return false;
684}
47aa42e2 685
54bb33eb 686function unmaskPassword(id) {
239ade45 687 var pw = document.getElementById(id);
54bb33eb 688 var chb = document.getElementById(id+'unmask');
239ade45 689
690 try {
691 // first try IE way - it can not set name attribute later
692 if (chb.checked) {
693 var newpw = document.createElement('<input type="text" name="'+pw.name+'">');
694 } else {
695 var newpw = document.createElement('<input type="password" name="'+pw.name+'">');
696 }
eba8cd63 697 newpw.attributes['class'].nodeValue = pw.attributes['class'].nodeValue;
239ade45 698 } catch (e) {
699 var newpw = document.createElement('input');
700 newpw.setAttribute('name', pw.name);
701 if (chb.checked) {
702 newpw.setAttribute('type', 'text');
703 } else {
704 newpw.setAttribute('type', 'password');
705 }
eba8cd63 706 newpw.setAttribute('class', pw.getAttribute('class'));
239ade45 707 }
708 newpw.id = pw.id;
709 newpw.size = pw.size;
710 newpw.onblur = pw.onblur;
711 newpw.onchange = pw.onchange;
712 newpw.value = pw.value;
713 pw.parentNode.replaceChild(newpw, pw);
714}
715
8e7cebb0 716/**
717 * Search a Moodle form to find all the fdate_time_selector and fdate_selector
718 * elements, and add date_selector_calendar instance to each.
719 */
720function init_date_selectors(firstdayofweek) {
8e7cebb0 721 var els = YAHOO.util.Dom.getElementsByClassName('fdate_time_selector', 'fieldset');
722 for (var i = 0; i < els.length; i++) {
723 new date_selector_calendar(els[i], firstdayofweek);
724 }
725 els = YAHOO.util.Dom.getElementsByClassName('fdate_selector', 'fieldset');
726 for (i = 0; i < els.length; i++) {
727 new date_selector_calendar(els[i], firstdayofweek);
728 }
729}
730
731/**
9bad31f5 732 * Constructor for a JavaScript object that connects to a fdate_time_selector
8e7cebb0 733 * or a fdate_selector in a Moodle form, and shows a popup calendar whenever
734 * that element has keyboard focus.
735 * @param el the fieldset class="fdate_time_selector" or "fdate_selector".
736 */
737function date_selector_calendar(el, firstdayofweek) {
738 // Ensure that the shared div and calendar exist.
739 if (!date_selector_calendar.panel) {
740 date_selector_calendar.panel = new YAHOO.widget.Panel('date_selector_calendar_panel',
b3a49376 741 {visible: false, draggable: false});
8e7cebb0 742 var div = document.createElement('div');
743 date_selector_calendar.panel.setBody(div);
744 date_selector_calendar.panel.render(document.body);
745
746 YAHOO.util.Event.addListener(document, 'click', date_selector_calendar.document_click);
747 date_selector_calendar.panel.showEvent.subscribe(function() {
748 date_selector_calendar.panel.fireEvent('changeContent');
749 });
b3a49376 750 date_selector_calendar.panel.hideEvent.subscribe(date_selector_calendar.release_current);
8e7cebb0 751
752 date_selector_calendar.calendar = new YAHOO.widget.Calendar(div,
753 {iframe: false, hide_blank_weeks: true, start_weekday: firstdayofweek});
754 date_selector_calendar.calendar.renderEvent.subscribe(function() {
755 date_selector_calendar.panel.fireEvent('changeContent');
bd55319b 756 date_selector_calendar.delayed_reposition();
8e7cebb0 757 });
8e7cebb0 758 }
759
760 this.fieldset = el;
761 var controls = el.getElementsByTagName('select');
762 for (var i = 0; i < controls.length; i++) {
8e7cebb0 763 if (/\[year\]$/.test(controls[i].name)) {
764 this.yearselect = controls[i];
9bad31f5 765 } else if (/\[month\]$/.test(controls[i].name)) {
8e7cebb0 766 this.monthselect = controls[i];
9bad31f5 767 } else if (/\[day\]$/.test(controls[i].name)) {
8e7cebb0 768 this.dayselect = controls[i];
9bad31f5 769 } else {
bd55319b 770 YAHOO.util.Event.addFocusListener(controls[i], date_selector_calendar.cancel_any_timeout, this);
9bad31f5 771 YAHOO.util.Event.addBlurListener(controls[i], this.blur_event, this);
8e7cebb0 772 }
773 }
774 if (!(this.yearselect && this.monthselect && this.dayselect)) {
775 throw 'Failed to initialise calendar.';
776 }
9bad31f5 777 YAHOO.util.Event.addFocusListener([this.yearselect, this.monthselect, this.dayselect], this.focus_event, this);
778 YAHOO.util.Event.addBlurListener([this.yearselect, this.monthselect, this.dayselect], this.blur_event, this);
8e7cebb0 779
780 this.enablecheckbox = el.getElementsByTagName('input')[0];
781 if (this.enablecheckbox) {
782 YAHOO.util.Event.addFocusListener(this.enablecheckbox, this.focus_event, this);
783 YAHOO.util.Event.addListener(this.enablecheckbox, 'change', this.focus_event, this);
784 YAHOO.util.Event.addBlurListener(this.enablecheckbox, this.blur_event, this);
785 }
786}
787
788/** The pop-up calendar that contains the calendar. */
789date_selector_calendar.panel = null;
790
791/** The shared YAHOO.widget.Calendar used by all date_selector_calendars. */
792date_selector_calendar.calendar = null;
793
794/** The date_selector_calendar that currently owns the shared stuff. */
795date_selector_calendar.currentowner = null;
796
797/** Used as a timeout when hiding the calendar on blur - so we don't hide the calendar
798 * if we are just jumping from on of our controls to another. */
799date_selector_calendar.hidetimeout = null;
800
bd55319b 801/** Timeout for repositioning after a delay after a change of months. */
802date_selector_calendar.repositiontimeout = null;
8e7cebb0 803
bd55319b 804/** Member variables. Pointers to various bits of the DOM. */
8e7cebb0 805date_selector_calendar.prototype.fieldset = null;
806date_selector_calendar.prototype.yearselect = null;
807date_selector_calendar.prototype.monthselect = null;
808date_selector_calendar.prototype.dayselect = null;
809date_selector_calendar.prototype.enablecheckbox = null;
810
bd55319b 811date_selector_calendar.cancel_any_timeout = function() {
8e7cebb0 812 if (date_selector_calendar.hidetimeout) {
813 clearTimeout(date_selector_calendar.hidetimeout);
814 date_selector_calendar.hidetimeout = null;
815 }
bd55319b 816 if (date_selector_calendar.repositiontimeout) {
817 clearTimeout(date_selector_calendar.repositiontimeout);
818 date_selector_calendar.repositiontimeout = null;
819 }
820}
821
822date_selector_calendar.delayed_reposition = function() {
823 if (date_selector_calendar.repositiontimeout) {
824 clearTimeout(date_selector_calendar.repositiontimeout);
825 date_selector_calendar.repositiontimeout = null;
826 }
b3a49376 827 date_selector_calendar.repositiontimeout = setTimeout(date_selector_calendar.fix_position, 500);
bd55319b 828}
829
830date_selector_calendar.fix_position = function() {
831 if (date_selector_calendar.currentowner) {
832 date_selector_calendar.panel.cfg.setProperty('context', [date_selector_calendar.currentowner.fieldset, 'bl', 'tl']);
833 }
8e7cebb0 834}
835
b3a49376 836date_selector_calendar.release_current = function() {
837 if (date_selector_calendar.currentowner) {
838 date_selector_calendar.currentowner.release_calendar();
839 }
840}
841
8e7cebb0 842date_selector_calendar.prototype.focus_event = function(e, me) {
bd55319b 843 date_selector_calendar.cancel_any_timeout();
8e7cebb0 844 if (me.enablecheckbox == null || me.enablecheckbox.checked) {
845 me.claim_calendar();
846 } else {
847 if (date_selector_calendar.currentowner) {
848 date_selector_calendar.currentowner.release_calendar();
849 }
850 }
851}
852
853date_selector_calendar.prototype.blur_event = function(e, me) {
b3a49376 854 date_selector_calendar.hidetimeout = setTimeout(date_selector_calendar.release_current, 300);
8e7cebb0 855}
856
857date_selector_calendar.prototype.handle_select_change = function(e, me) {
858 me.set_date_from_selects();
859}
860
861date_selector_calendar.document_click = function(event) {
862 if (date_selector_calendar.currentowner) {
863 var currentcontainer = date_selector_calendar.currentowner.fieldset;
864 var eventarget = YAHOO.util.Event.getTarget(event);
b3a49376 865 if (YAHOO.util.Dom.isAncestor(currentcontainer, eventarget)) {
866 setTimeout(function() {date_selector_calendar.cancel_any_timeout()}, 100);
867 } else {
8e7cebb0 868 date_selector_calendar.currentowner.release_calendar();
869 }
870 }
f8065dd2 871}
8e7cebb0 872
873date_selector_calendar.prototype.claim_calendar = function() {
bd55319b 874 date_selector_calendar.cancel_any_timeout();
8e7cebb0 875 if (date_selector_calendar.currentowner == this) {
876 return;
877 }
878 if (date_selector_calendar.currentowner) {
879 date_selector_calendar.currentowner.release_calendar();
880 }
881
bd55319b 882 if (date_selector_calendar.currentowner != this) {
883 this.connect_handlers();
884 }
885 date_selector_calendar.currentowner = this;
886
8e7cebb0 887 date_selector_calendar.calendar.cfg.setProperty('mindate', new Date(this.yearselect.options[0].value, 0, 1));
888 date_selector_calendar.calendar.cfg.setProperty('maxdate', new Date(this.yearselect.options[this.yearselect.options.length - 1].value, 11, 31));
bd55319b 889 this.fieldset.insertBefore(date_selector_calendar.panel.element, this.yearselect.nextSibling);
8e7cebb0 890 this.set_date_from_selects();
891 date_selector_calendar.panel.show();
892 var me = this;
bd55319b 893 setTimeout(function() {date_selector_calendar.cancel_any_timeout()}, 100);
8e7cebb0 894}
895
896date_selector_calendar.prototype.set_date_from_selects = function() {
897 var year = parseInt(this.yearselect.value);
898 var month = parseInt(this.monthselect.value) - 1;
899 var day = parseInt(this.dayselect.value);
900 date_selector_calendar.calendar.select(new Date(year, month, day));
901 date_selector_calendar.calendar.setMonth(month);
902 date_selector_calendar.calendar.setYear(year);
bd55319b 903 date_selector_calendar.calendar.render();
904 date_selector_calendar.fix_position();
8e7cebb0 905}
906
907date_selector_calendar.prototype.set_selects_from_date = function(eventtype, args) {
908 var date = args[0][0];
909 var newyear = date[0];
910 var newindex = newyear - this.yearselect.options[0].value;
911 this.yearselect.selectedIndex = newindex;
912 this.monthselect.selectedIndex = date[1] - this.monthselect.options[0].value;
913 this.dayselect.selectedIndex = date[2] - this.dayselect.options[0].value;
914}
915
916date_selector_calendar.prototype.connect_handlers = function() {
917 YAHOO.util.Event.addListener([this.yearselect, this.monthselect, this.dayselect], 'change', this.handle_select_change, this);
918 date_selector_calendar.calendar.selectEvent.subscribe(this.set_selects_from_date, this, true);
919}
920
921date_selector_calendar.prototype.release_calendar = function() {
922 date_selector_calendar.panel.hide();
923 date_selector_calendar.currentowner = null;
924 YAHOO.util.Event.removeListener([this.yearselect, this.monthselect, this.dayselect], this.handle_select_change);
925 date_selector_calendar.calendar.selectEvent.unsubscribe(this.set_selects_from_date, this);
926}
927
47aa42e2 928function filterByParent(elCollection, parentFinder) {
929 var filteredCollection = [];
45caa363 930 for (var i = 0; i < elCollection.length; ++i) {
47aa42e2 931 var findParent = parentFinder(elCollection[i]);
45caa363 932 if (findParent.nodeName.toUpperCase != 'BODY') {
47aa42e2 933 filteredCollection.push(elCollection[i]);
934 }
935 }
936 return filteredCollection;
937}
938
7979105c 939/*
940 All this is here just so that IE gets to handle oversized blocks
941 in a visually pleasing manner. It does a browser detect. So sue me.
942*/
943
944function fix_column_widths() {
945 var agt = navigator.userAgent.toLowerCase();
946 if ((agt.indexOf("msie") != -1) && (agt.indexOf("opera") == -1)) {
947 fix_column_width('left-column');
948 fix_column_width('right-column');
949 }
950}
951
952function fix_column_width(colName) {
953 if(column = document.getElementById(colName)) {
954 if(!column.offsetWidth) {
955 setTimeout("fix_column_width('" + colName + "')", 20);
956 return;
957 }
958
959 var width = 0;
960 var nodes = column.childNodes;
961
962 for(i = 0; i < nodes.length; ++i) {
963 if(nodes[i].className.indexOf("sideblock") != -1 ) {
964 if(width < nodes[i].offsetWidth) {
965 width = nodes[i].offsetWidth;
966 }
967 }
968 }
969
970 for(i = 0; i < nodes.length; ++i) {
971 if(nodes[i].className.indexOf("sideblock") != -1 ) {
972 nodes[i].style.width = width + 'px';
973 }
974 }
975 }
976}
d13c5938 977
978
979/*
9f439b17 980 Insert myValue at current cursor position
981 */
d13c5938 982function insertAtCursor(myField, myValue) {
9f439b17 983 // IE support
984 if (document.selection) {
985 myField.focus();
986 sel = document.selection.createRange();
987 sel.text = myValue;
988 }
989 // Mozilla/Netscape support
990 else if (myField.selectionStart || myField.selectionStart == '0') {
991 var startPos = myField.selectionStart;
992 var endPos = myField.selectionEnd;
993 myField.value = myField.value.substring(0, startPos)
994 + myValue + myField.value.substring(endPos, myField.value.length);
995 } else {
996 myField.value += myValue;
997 }
d13c5938 998}
7470d6de 999
1000
1001/*
c0056e22 1002 Call instead of setting window.onload directly or setting body onload=.
1003 Adds your function to a chain of functions rather than overwriting anything
1004 that exists.
1005*/
7470d6de 1006function addonload(fn) {
1007 var oldhandler=window.onload;
1008 window.onload=function() {
1009 if(oldhandler) oldhandler();
c0056e22 1010 fn();
7470d6de 1011 }
1012}
7d2a0492 1013/**
1014 * Replacement for getElementsByClassName in browsers that aren't cool enough
6f5e0852 1015 *
7d2a0492 1016 * Relying on the built-in getElementsByClassName is far, far faster than
1017 * using YUI.
6f5e0852 1018 *
7d2a0492 1019 * Note: the third argument used to be an object with odd behaviour. It now
1020 * acts like the 'name' in the HTML5 spec, though the old behaviour is still
1021 * mimicked if you pass an object.
1022 *
1023 * @param {Node} oElm The top-level node for searching. To search a whole
1024 * document, use `document`.
1025 * @param {String} strTagName filter by tag names
1026 * @param {String} name same as HTML5 spec
1027 */
1028function getElementsByClassName(oElm, strTagName, name) {
1029 // for backwards compatibility
1030 if(typeof name == "object") {
1031 var names = new Array();
1032 for(var i=0; i<name.length; i++) names.push(names[i]);
1033 name = names.join('');
1034 }
1035 // use native implementation if possible
1036 if (oElm.getElementsByClassName && Array.filter) {
1037 if (strTagName == '*') {
1038 return oElm.getElementsByClassName(name);
1039 } else {
1040 return Array.filter(oElm.getElementsByClassName(name), function(el) {
1041 return el.nodeName.toLowerCase() == strTagName.toLowerCase();
1042 });
1043 }
1044 }
1045 // native implementation unavailable, fall back to slow method
c849ed1e 1046 var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);
1047 var arrReturnElements = new Array();
1048 var arrRegExpClassNames = new Array();
7d2a0492 1049 var names = name.split(' ');
1050 for(var i=0; i<names.length; i++) {
1051 arrRegExpClassNames.push(new RegExp("(^|\\s)" + names[i].replace(/\-/g, "\\-") + "(\\s|$)"));
c849ed1e 1052 }
1053 var oElement;
1054 var bMatchesAll;
b51709c1 1055 for(var j=0; j<arrElements.length; j++) {
c849ed1e 1056 oElement = arrElements[j];
1057 bMatchesAll = true;
b51709c1 1058 for(var k=0; k<arrRegExpClassNames.length; k++) {
1059 if(!arrRegExpClassNames[k].test(oElement.className)) {
c849ed1e 1060 bMatchesAll = false;
1061 break;
1062 }
1063 }
b51709c1 1064 if(bMatchesAll) {
c849ed1e 1065 arrReturnElements.push(oElement);
1066 }
1067 }
1068 return (arrReturnElements)
1069}
77241d9b 1070
f8065dd2 1071function openpopup(event, args) {
1072
1073 YAHOO.util.Event.preventDefault(event);
1074
1075 var fullurl = args.url;
1076 if (!args.url.match(/https?:\/\//)) {
9598d578 1077 fullurl = M.cfg.wwwroot + args.url;
bed9cec8 1078 }
f8065dd2 1079 var windowobj = window.open(fullurl,args.name,args.options);
214f5850 1080 if (!windowobj) {
1081 return true;
1082 }
474f6bfe 1083 if (args.fullscreen) {
77241d9b 1084 windowobj.moveTo(0,0);
1085 windowobj.resizeTo(screen.availWidth,screen.availHeight);
1086 }
1087 windowobj.focus();
1088 return false;
1089}
740939ec 1090
1091/* This is only used on a few help pages. */
1092emoticons_help = {
1093 inputarea: null,
1094
1095 init: function(formname, fieldname, listid) {
1096 if (!opener || !opener.document.forms[formname]) {
1097 return;
1098 }
1099 emoticons_help.inputarea = opener.document.forms[formname][fieldname];
1100 if (!emoticons_help.inputarea) {
1101 return;
1102 }
1103 var emoticons = document.getElementById(listid).getElementsByTagName('li');
1104 for (var i = 0; i < emoticons.length; i++) {
1105 var text = emoticons[i].getElementsByTagName('img')[0].alt;
1106 YAHOO.util.Event.addListener(emoticons[i], 'click', emoticons_help.inserttext, text);
1107 }
1108 },
1109
1110 inserttext: function(e, text) {
1111 text = ' ' + text + ' ';
1112 if (emoticons_help.inputarea.createTextRange && emoticons_help.inputarea.caretPos) {
1113 var caretPos = emoticons_help.inputarea.caretPos;
1114 caretPos.text = caretPos.text.charAt(caretPos.text.length - 1) == ' ' ? text + ' ' : text;
1115 } else {
1116 emoticons_help.inputarea.value += text;
1117 }
1118 emoticons_help.inputarea.focus();
1119 }
bd1884fe 1120}
1121
d4a03c00 1122/**
1123 * Oject to handle expanding and collapsing blocks when an icon is clicked on.
1124 * @constructor
1125 * @param String id the HTML id for the div.
1126 * @param String userpref the user preference that records the state of this block.
1127 * @param String visibletooltip tool tip/alt to show when the block is visible.
1128 * @param String hiddentooltip tool tip/alt to show when the block is hidden.
1129 * @param String visibleicon URL of the icon to show when the block is visible.
1130 * @param String hiddenicon URL of the icon to show when the block is hidden.
1131 */
1132function block_hider(id, userpref, visibletooltip, hiddentooltip, visibleicon, hiddenicon) {
1133 // Find the elemen that is the block.
1134 this.block = document.getElementById(id);
1135 var title_div = YAHOO.util.Dom.getElementsByClassName('title', 'div', this.block);
1136 if (!title_div || !title_div[0]) {
1137 return this;
1138 }
1139 title_div = title_div[0];
1140 this.ishidden = YAHOO.util.Dom.hasClass(this.block, 'hidden');
1141
1142 // Record the pref name
1143 this.userpref = userpref;
1144 this.visibletooltip = visibletooltip;
1145 this.hiddentooltip = hiddentooltip;
1146 this.visibleicon = visibleicon;
1147 this.hiddenicon = hiddenicon;
1148
1149 // Add the icon.
1150 this.icon = document.createElement('input');
1151 this.icon.type = 'image';
1152 this.icon.className = 'hide-show-image';
1153 this.update_state();
1154 title_div.insertBefore(this.icon, title_div.firstChild);
1155
1156 // Hook up the event handler.
1157 YAHOO.util.Event.addListener(this.icon, 'click', this.handle_click, null, this);
1158}
1159
1160/** Handle click on a block show/hide icon. */
1161block_hider.prototype.handle_click = function(e) {
1162 YAHOO.util.Event.stopEvent(e);
1163 this.ishidden = !this.ishidden;
1164 this.update_state();
41912a26 1165 M.util.set_user_preference(this.userpref, this.ishidden);
d4a03c00 1166}
1167
1168/** Set the state of the block show/hide icon to this.ishidden. */
1169block_hider.prototype.update_state = function () {
1170 if (this.ishidden) {
1171 YAHOO.util.Dom.addClass(this.block, 'hidden');
1172 this.icon.alt = this.hiddentooltip;
1173 this.icon.title = this.hiddentooltip;
1174 this.icon.src = this.hiddenicon;
1175 } else {
1176 YAHOO.util.Dom.removeClass(this.block, 'hidden');
1177 this.icon.alt = this.visibletooltip;
1178 this.icon.title = this.visibletooltip;
1179 this.icon.src = this.visibleicon;
1180 }
1181}
1182
b166403f 1183/** Close the current browser window. */
7a5c78e0 1184function close_window(e) {
1185 YAHOO.util.Event.preventDefault(e);
1186 self.close();
b166403f 1187}
1188
1189/**
1190 * Close the current browser window, forcing the window/tab that opened this
1191 * popup to reload itself. */
1192function close_window_reloading_opener() {
1193 if (window.opener) {
1194 window.opener.location.reload(1);
1195 close_window();
1196 // Intentionally, only try to close the window if there is some evidence we are in a popup.
1197 }
8e7cebb0 1198}
9f319372 1199
1200/**
1201 * Used in a couple of modules to hide navigation areas when using AJAX
1202 */
34a2777c 1203
2538037f 1204function show_item(itemid) {
1205 var item = document.getElementById(itemid);
1206 if (item) {
1207 item.style.display = "";
1208 }
1209}
1210
1211function destroy_item(itemid) {
1212 var item = document.getElementById(itemid);
1213 if (item) {
1214 item.parentNode.removeChild(item);
1215 }
1216}
34a2777c 1217/**
1218 * Tranfer keyboard focus to the HTML element with the given id, if it exists.
1219 * @param controlid the control id.
1220 */
1221function focuscontrol(controlid) {
1222 var control = document.getElementById(controlid);
1223 if (control) {
1224 control.focus();
1225 }
e29380f3 1226}
1227
e11a8328 1228/**
1229 * Transfers keyboard focus to an HTML element based on the old style style of focus
1230 * This function should be removed as soon as it is no longer used
1231 */
428acddb 1232function old_onload_focus(formid, controlname) {
5f8bce50 1233 if (document.forms[formid] && document.forms[formid].elements && document.forms[formid].elements[controlname]) {
428acddb 1234 document.forms[formid].elements[controlname].focus();
e11a8328 1235 }
1236}
1237
1bcb7eb5 1238function build_querystring(obj) {
1239 if (typeof obj !== 'object') {
1240 return null;
1241 }
1242 var list = [];
1243 for(var k in obj) {
1244 k = encodeURIComponent(k);
1245 var value = obj[k];
1246 if(obj[k] instanceof Array) {
1247 for(var i in value) {
1248 list.push(k+'[]='+encodeURIComponent(value[i]));
1249 }
1250 } else {
1251 list.push(k+'='+encodeURIComponent(value));
1252 }
1253 }
1254 return list.join('&');
1255}
d25e2ca3 1256
1257function stripHTML(str) {
1258 var re = /<\S[^><]*>/g;
1259 var ret = str.replace(re, "");
1260 return ret;
1261}
1262
f8065dd2 1263/**
1264 * Prints a confirmation dialog in the style of DOM.confirm().
1265 * @param object event A DOM event
1266 * @param string message The message to show in the dialog
1267 * @param string url The URL to forward to if YES is clicked. Disabled if fn is given
1268 * @param function fn A JS function to run if YES is clicked.
1269 */
49690843 1270function confirm_dialog(event, args) {
1271 var message = args.message;
1272 var target = this;
5529f787 1273 target.args = args;
f8065dd2 1274 YAHOO.util.Event.preventDefault(event);
1275
1276 var simpledialog = new YAHOO.widget.SimpleDialog('confirmdialog',
1277 { width: '300px',
1278 fixedcenter: true,
1279 modal: true,
1280 visible: false,
1281 draggable: false
1282 }
1283 );
1284
5f56f0a8 1285 simpledialog.setHeader(mstr.admin.confirmation);
f8065dd2 1286 simpledialog.setBody(message);
1287 simpledialog.cfg.setProperty('icon', YAHOO.widget.SimpleDialog.ICON_WARN);
1288
5529f787 1289 this.handle_cancel = function() {
f8065dd2 1290 this.hide();
1291 };
1292
5529f787 1293 this.handle_yes = function() {
f8065dd2 1294 this.hide();
5529f787 1295
1296 if (target.args.callback) {
1297 // args comes from PHP, so callback will be a string, needs to be evaluated by JS
2539ce37
DC
1298 var callback = null;
1299 if (Y.Lang.isFunction(target.args.callback)) {
1300 callback = target.args.callback;
1301 } else {
1302 callback = eval('('+target.args.callback+')');
1303 }
1304 if (Y.Lang.isObject(target.args.scope)) {
1305 callback.apply(target.args.scope);
1306 } else {
1307 callback();
1308 }
5529f787 1309 }
1310
f8065dd2 1311 if (target.tagName.toLowerCase() == 'a') {
1312 window.location = target.href;
1313 } else if (target.tagName.toLowerCase() == 'input') {
1314 var parentelement = target.parentNode;
1315 while (parentelement.tagName.toLowerCase() != 'form' && parentelement.tagName.toLowerCase() != 'body') {
1316 parentelement = parentelement.parentNode;
1317 }
1318 if (parentelement.tagName.toLowerCase() == 'form') {
1319 parentelement.submit();
1320 }
9598d578 1321 } else if(M.cfg.developerdebug) {
f8065dd2 1322 alert("Element of type " + target.tagName + " is not supported by the confirm_dialog function. Use A or INPUT");
1323 }
1324 };
1325
5529f787 1326 var buttons = [ { text: mstr.moodle.cancel, handler: this.handle_cancel, isDefault: true },
1327 { text: mstr.moodle.yes, handler: this.handle_yes } ];
f8065dd2 1328
1329 simpledialog.cfg.queueProperty('buttons', buttons);
1330
1331 simpledialog.render(document.body);
1332 simpledialog.show();
5529f787 1333 return simpledialog;
1334}
1335
1336function dialog_callback() {
1337 console.debug(this);
1338 console.debug(this.args);
f8065dd2 1339}
fd4faf98 1340Number.prototype.fixed=function(n){
1341 with(Math)
1342 return round(Number(this)*pow(10,n))/pow(10,n);
1343}
1344function update_progress_bar (id, width, pt, msg, es){
1345 var percent = pt*100;
1346 var status = document.getElementById("status_"+id);
1347 var percent_indicator = document.getElementById("pt_"+id);
1348 var progress_bar = document.getElementById("progress_"+id);
1349 var time_es = document.getElementById("time_"+id);
1350 status.innerHTML = msg;
1351 percent_indicator.innerHTML = percent.fixed(2) + '%';
1352 if(percent == 100) {
1353 progress_bar.style.background = "green";
1354 time_es.style.display = "none";
1355 } else {
1356 progress_bar.style.background = "#FFCC66";
1357 if (es == Infinity){
1358 time_es.innerHTML = "Initializing...";
1359 }else {
1360 time_es.innerHTML = es.fixed(2)+" sec";
1361 time_es.style.display
1362 = "block";
1363 }
1364 }
1365 progress_bar.style.width = width + "px";
1366
1367}
bf6c37c7 1368
1369function frame_breakout(e, properties) {
1370 this.setAttribute('target', properties.framename);
41f23791 1371}
78946b9b 1372
73b62703
PS
1373
1374// ===== Deprecated core Javascript functions for Moodle ====
1375// DO NOT USE!!!!!!!
e50b4c89 1376// Do not put this stuff in separate file because it only adds extra load on servers!
73b62703
PS
1377
1378function submitFormById(id) {
1379 submit_form_by_id(null, {id: id});
adacb0fe 1380}
2d65597b
PS
1381
1382/**
1383 * Used in a couple of modules to hide navigation areas when using AJAX
1384 */
1385function hide_item(itemid) {
3b044ba3 1386 // use class='hiddenifjs' instead
2d65597b
PS
1387 var item = document.getElementById(itemid);
1388 if (item) {
1389 item.style.display = "none";
1390 }
1391}