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