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