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