// Miscellaneous core Javascript functions for Moodle function popupchecker(msg) { var testwindow = window.open('itestwin.html', '', 'width=1,height=1,left=0,top=0,scrollbars=no'); if (!testwindow) { alert(msg); } else { testwindow.close(); } } function checkall() { var inputs = document.getElementsByTagName('input'); for (var i = 0; i < inputs.length; i++) { if (inputs[i].type == 'checkbox') { inputs[i].checked = true; } } } function checknone() { var inputs = document.getElementsByTagName('input'); for (var i = 0; i < inputs.length; i++) { if (inputs[i].type == 'checkbox') { inputs[i].checked = false; } } } function lockoptions(formid, master, subitems) { // Subitems is an array of names of sub items. // Optionally, each item in subitems may have a // companion hidden item in the form with the // same name but prefixed by "h". var form = document.forms[formid]; if (eval("form."+master+".checked")) { for (i=0; i'); } else { var newpw = document.createElement(''); } newpw.attributes['class'].nodeValue = pw.attributes['class'].nodeValue; } catch (e) { var newpw = document.createElement('input'); newpw.setAttribute('name', pw.name); if (chb.checked) { newpw.setAttribute('type', 'text'); } else { newpw.setAttribute('type', 'password'); } newpw.setAttribute('class', pw.getAttribute('class')); } newpw.id = pw.id; newpw.size = pw.size; newpw.onblur = pw.onblur; newpw.onchange = pw.onchange; newpw.value = pw.value; pw.parentNode.replaceChild(newpw, pw); } /** * Search a Moodle form to find all the fdate_time_selector and fdate_selector * elements, and add date_selector_calendar instance to each. */ function init_date_selectors(firstdayofweek) { var els = YAHOO.util.Dom.getElementsByClassName('fdate_time_selector', 'fieldset'); for (var i = 0; i < els.length; i++) { new date_selector_calendar(els[i], firstdayofweek); } els = YAHOO.util.Dom.getElementsByClassName('fdate_selector', 'fieldset'); for (i = 0; i < els.length; i++) { new date_selector_calendar(els[i], firstdayofweek); } } /** * Constructor for a JavaScript object that connects to a fdate_time_selector * or a fdate_selector in a Moodle form, and shows a popup calendar whenever * that element has keyboard focus. * @param el the fieldset class="fdate_time_selector" or "fdate_selector". */ function date_selector_calendar(el, firstdayofweek) { // Ensure that the shared div and calendar exist. if (!date_selector_calendar.panel) { date_selector_calendar.panel = new YAHOO.widget.Panel('date_selector_calendar_panel', {visible: false, draggable: false}); var div = document.createElement('div'); date_selector_calendar.panel.setBody(div); date_selector_calendar.panel.render(document.body); YAHOO.util.Event.addListener(document, 'click', date_selector_calendar.document_click); date_selector_calendar.panel.showEvent.subscribe(function() { date_selector_calendar.panel.fireEvent('changeContent'); }); date_selector_calendar.panel.hideEvent.subscribe(date_selector_calendar.release_current); date_selector_calendar.calendar = new YAHOO.widget.Calendar(div, {iframe: false, hide_blank_weeks: true, start_weekday: firstdayofweek}); date_selector_calendar.calendar.renderEvent.subscribe(function() { date_selector_calendar.panel.fireEvent('changeContent'); date_selector_calendar.delayed_reposition(); }); } this.fieldset = el; var controls = el.getElementsByTagName('select'); for (var i = 0; i < controls.length; i++) { if (/\[year\]$/.test(controls[i].name)) { this.yearselect = controls[i]; } else if (/\[month\]$/.test(controls[i].name)) { this.monthselect = controls[i]; } else if (/\[day\]$/.test(controls[i].name)) { this.dayselect = controls[i]; } else { YAHOO.util.Event.addFocusListener(controls[i], date_selector_calendar.cancel_any_timeout, this); YAHOO.util.Event.addBlurListener(controls[i], this.blur_event, this); } } if (!(this.yearselect && this.monthselect && this.dayselect)) { throw 'Failed to initialise calendar.'; } YAHOO.util.Event.addFocusListener([this.yearselect, this.monthselect, this.dayselect], this.focus_event, this); YAHOO.util.Event.addBlurListener([this.yearselect, this.monthselect, this.dayselect], this.blur_event, this); this.enablecheckbox = el.getElementsByTagName('input')[0]; if (this.enablecheckbox) { YAHOO.util.Event.addFocusListener(this.enablecheckbox, this.focus_event, this); YAHOO.util.Event.addListener(this.enablecheckbox, 'change', this.focus_event, this); YAHOO.util.Event.addBlurListener(this.enablecheckbox, this.blur_event, this); } } /** The pop-up calendar that contains the calendar. */ date_selector_calendar.panel = null; /** The shared YAHOO.widget.Calendar used by all date_selector_calendars. */ date_selector_calendar.calendar = null; /** The date_selector_calendar that currently owns the shared stuff. */ date_selector_calendar.currentowner = null; /** Used as a timeout when hiding the calendar on blur - so we don't hide the calendar * if we are just jumping from on of our controls to another. */ date_selector_calendar.hidetimeout = null; /** Timeout for repositioning after a delay after a change of months. */ date_selector_calendar.repositiontimeout = null; /** Member variables. Pointers to various bits of the DOM. */ date_selector_calendar.prototype.fieldset = null; date_selector_calendar.prototype.yearselect = null; date_selector_calendar.prototype.monthselect = null; date_selector_calendar.prototype.dayselect = null; date_selector_calendar.prototype.enablecheckbox = null; date_selector_calendar.cancel_any_timeout = function() { if (date_selector_calendar.hidetimeout) { clearTimeout(date_selector_calendar.hidetimeout); date_selector_calendar.hidetimeout = null; } if (date_selector_calendar.repositiontimeout) { clearTimeout(date_selector_calendar.repositiontimeout); date_selector_calendar.repositiontimeout = null; } } date_selector_calendar.delayed_reposition = function() { if (date_selector_calendar.repositiontimeout) { clearTimeout(date_selector_calendar.repositiontimeout); date_selector_calendar.repositiontimeout = null; } date_selector_calendar.repositiontimeout = setTimeout(date_selector_calendar.fix_position, 500); } date_selector_calendar.fix_position = function() { if (date_selector_calendar.currentowner) { date_selector_calendar.panel.cfg.setProperty('context', [date_selector_calendar.currentowner.fieldset, 'bl', 'tl']); } } date_selector_calendar.release_current = function() { if (date_selector_calendar.currentowner) { date_selector_calendar.currentowner.release_calendar(); } } date_selector_calendar.prototype.focus_event = function(e, me) { date_selector_calendar.cancel_any_timeout(); if (me.enablecheckbox == null || me.enablecheckbox.checked) { me.claim_calendar(); } else { if (date_selector_calendar.currentowner) { date_selector_calendar.currentowner.release_calendar(); } } } date_selector_calendar.prototype.blur_event = function(e, me) { date_selector_calendar.hidetimeout = setTimeout(date_selector_calendar.release_current, 300); } date_selector_calendar.prototype.handle_select_change = function(e, me) { me.set_date_from_selects(); } date_selector_calendar.document_click = function(event) { if (date_selector_calendar.currentowner) { var currentcontainer = date_selector_calendar.currentowner.fieldset; var eventarget = YAHOO.util.Event.getTarget(event); if (YAHOO.util.Dom.isAncestor(currentcontainer, eventarget)) { setTimeout(function() {date_selector_calendar.cancel_any_timeout()}, 100); } else { date_selector_calendar.currentowner.release_calendar(); } } } date_selector_calendar.prototype.claim_calendar = function() { date_selector_calendar.cancel_any_timeout(); if (date_selector_calendar.currentowner == this) { return; } if (date_selector_calendar.currentowner) { date_selector_calendar.currentowner.release_calendar(); } if (date_selector_calendar.currentowner != this) { this.connect_handlers(); } date_selector_calendar.currentowner = this; date_selector_calendar.calendar.cfg.setProperty('mindate', new Date(this.yearselect.options[0].value, 0, 1)); date_selector_calendar.calendar.cfg.setProperty('maxdate', new Date(this.yearselect.options[this.yearselect.options.length - 1].value, 11, 31)); this.fieldset.insertBefore(date_selector_calendar.panel.element, this.yearselect.nextSibling); this.set_date_from_selects(); date_selector_calendar.panel.show(); var me = this; setTimeout(function() {date_selector_calendar.cancel_any_timeout()}, 100); } date_selector_calendar.prototype.set_date_from_selects = function() { var year = parseInt(this.yearselect.value); var month = parseInt(this.monthselect.value) - 1; var day = parseInt(this.dayselect.value); date_selector_calendar.calendar.select(new Date(year, month, day)); date_selector_calendar.calendar.setMonth(month); date_selector_calendar.calendar.setYear(year); date_selector_calendar.calendar.render(); date_selector_calendar.fix_position(); } date_selector_calendar.prototype.set_selects_from_date = function(eventtype, args) { var date = args[0][0]; var newyear = date[0]; var newindex = newyear - this.yearselect.options[0].value; this.yearselect.selectedIndex = newindex; this.monthselect.selectedIndex = date[1] - this.monthselect.options[0].value; this.dayselect.selectedIndex = date[2] - this.dayselect.options[0].value; } date_selector_calendar.prototype.connect_handlers = function() { YAHOO.util.Event.addListener([this.yearselect, this.monthselect, this.dayselect], 'change', this.handle_select_change, this); date_selector_calendar.calendar.selectEvent.subscribe(this.set_selects_from_date, this, true); } date_selector_calendar.prototype.release_calendar = function() { date_selector_calendar.panel.hide(); date_selector_calendar.currentowner = null; YAHOO.util.Event.removeListener([this.yearselect, this.monthselect, this.dayselect], this.handle_select_change); date_selector_calendar.calendar.selectEvent.unsubscribe(this.set_selects_from_date, this); } function filterByParent(elCollection, parentFinder) { var filteredCollection = []; for (var i = 0; i < elCollection.length; ++i) { var findParent = parentFinder(elCollection[i]); if (findParent.nodeName.toUpperCase != 'BODY') { filteredCollection.push(elCollection[i]); } } return filteredCollection; } /* All this is here just so that IE gets to handle oversized blocks in a visually pleasing manner. It does a browser detect. So sue me. */ function fix_column_widths() { var agt = navigator.userAgent.toLowerCase(); if ((agt.indexOf("msie") != -1) && (agt.indexOf("opera") == -1)) { fix_column_width('left-column'); fix_column_width('right-column'); } } function fix_column_width(colName) { if(column = document.getElementById(colName)) { if(!column.offsetWidth) { setTimeout("fix_column_width('" + colName + "')", 20); return; } var width = 0; var nodes = column.childNodes; for(i = 0; i < nodes.length; ++i) { if(nodes[i].className.indexOf("sideblock") != -1 ) { if(width < nodes[i].offsetWidth) { width = nodes[i].offsetWidth; } } } for(i = 0; i < nodes.length; ++i) { if(nodes[i].className.indexOf("sideblock") != -1 ) { nodes[i].style.width = width + 'px'; } } } } /* Insert myValue at current cursor position */ function insertAtCursor(myField, myValue) { // IE support if (document.selection) { myField.focus(); sel = document.selection.createRange(); sel.text = myValue; } // Mozilla/Netscape support else if (myField.selectionStart || myField.selectionStart == '0') { var startPos = myField.selectionStart; var endPos = myField.selectionEnd; myField.value = myField.value.substring(0, startPos) + myValue + myField.value.substring(endPos, myField.value.length); } else { myField.value += myValue; } } /* Call instead of setting window.onload directly or setting body onload=. Adds your function to a chain of functions rather than overwriting anything that exists. */ function addonload(fn) { var oldhandler=window.onload; window.onload=function() { if(oldhandler) oldhandler(); fn(); } } function getElementsByClassName(oElm, strTagName, oClassNames) { var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName); var arrReturnElements = new Array(); var arrRegExpClassNames = new Array(); if(typeof oClassNames == "object") { for(var i=0; i to make it focussable. var a = document.createElement('a'); while (e = this.caption.firstChild) { a.appendChild(e); } a.href = '#'; this.caption.appendChild(a); // Create the animation. this.animation = new YAHOO.util.Anim(this.div, {}, 0.3, YAHOO.util.Easing.easeBoth); // Get to the right initial state. if (this.div.className.match(/\bcollapsed\b/)) { this.collapsed = true; var self = this; setTimeout(function() { var region = YAHOO.util.Region.getRegion(self.caption); self.div.style.height = (region.bottom - region.top + 3) + 'px'; }, 10); } // Add the appropriate image. this.icon = document.createElement('img'); this.icon.id = id + '_icon'; this.icon.alt = ''; if (this.collapsed) { this.icon.src = this.collapsedicon; } else { this.icon.src = this.expandedicon; } a.appendChild(this.icon); // Hook up the event handler. YAHOO.util.Event.addListener(a, 'click', this.handle_click, null, this); // Handler for the animation finishing. this.animation.onComplete.subscribe(function() {self.handle_animation_complete();}); } /** * The user preference that stores the state of this box. * @property userpref * @type String */ collapsible_region.prototype.userpref = null; /** * The key divs that make up this * @property div, innerdiv, captiondiv * @type HTMLDivElement */ collapsible_region.prototype.div = null; collapsible_region.prototype.innerdiv = null; collapsible_region.prototype.captiondiv = null; /** * The key divs that make up this * @property icon * @type HTMLImageElement */ collapsible_region.prototype.icon = null; /** * Whether the region is currently collapsed. * @property collapsed * @type Boolean */ collapsible_region.prototype.collapsed = false; /** * @property animation * @type YAHOO.util.Anim */ collapsible_region.prototype.animation = null; /** When clicked, toggle the collapsed state, and trigger the animation. */ collapsible_region.prototype.handle_click = function(e) { // Toggle the state. this.collapsed = !this.collapsed; // Stop the click following the link. YAHOO.util.Event.stopEvent(e); // Animate to the appropriate size. if (this.animation.isAnimated()) { this.animation.stop(); } if (this.collapsed) { var region = YAHOO.util.Region.getRegion(this.caption); var targetheight = region.bottom - region.top + 3; } else { var region = YAHOO.util.Region.getRegion(this.innerdiv); var targetheight = region.bottom - region.top + 2; this.div.className = this.div.className.replace(/\s*\bcollapsed\b\s*/, ' '); } this.animation.attributes.height = { to: targetheight, unit: 'px' }; this.animation.animate(); // Set the appropriate icon. if (this.collapsed) { this.icon.src =this.collapsedicon; } else { this.icon.src = this.expandedicon; } // Update the user preference. if (this.userpref) { set_user_preference(this.userpref, this.collapsed); } } /** When when the animation is finished, add the collapsed class name in relevant. */ collapsible_region.prototype.handle_animation_complete = function() { if (this.collapsed) { this.div.className += ' collapsed'; } } /** * Oject to handle expanding and collapsing blocks when an icon is clicked on. * @constructor * @param String id the HTML id for the div. * @param String userpref the user preference that records the state of this block. * @param String visibletooltip tool tip/alt to show when the block is visible. * @param String hiddentooltip tool tip/alt to show when the block is hidden. * @param String visibleicon URL of the icon to show when the block is visible. * @param String hiddenicon URL of the icon to show when the block is hidden. */ function block_hider(id, userpref, visibletooltip, hiddentooltip, visibleicon, hiddenicon) { // Find the elemen that is the block. this.block = document.getElementById(id); var title_div = YAHOO.util.Dom.getElementsByClassName('title', 'div', this.block); if (!title_div || !title_div[0]) { return this; } title_div = title_div[0]; this.ishidden = YAHOO.util.Dom.hasClass(this.block, 'hidden'); // Record the pref name this.userpref = userpref; this.visibletooltip = visibletooltip; this.hiddentooltip = hiddentooltip; this.visibleicon = visibleicon; this.hiddenicon = hiddenicon; // Add the icon. this.icon = document.createElement('input'); this.icon.type = 'image'; this.icon.className = 'hide-show-image'; this.update_state(); title_div.insertBefore(this.icon, title_div.firstChild); // Hook up the event handler. YAHOO.util.Event.addListener(this.icon, 'click', this.handle_click, null, this); } /** Handle click on a block show/hide icon. */ block_hider.prototype.handle_click = function(e) { YAHOO.util.Event.stopEvent(e); this.ishidden = !this.ishidden; this.update_state(); set_user_preference(this.userpref, this.ishidden); } /** Set the state of the block show/hide icon to this.ishidden. */ block_hider.prototype.update_state = function () { if (this.ishidden) { YAHOO.util.Dom.addClass(this.block, 'hidden'); this.icon.alt = this.hiddentooltip; this.icon.title = this.hiddentooltip; this.icon.src = this.hiddenicon; } else { YAHOO.util.Dom.removeClass(this.block, 'hidden'); this.icon.alt = this.visibletooltip; this.icon.title = this.visibletooltip; this.icon.src = this.visibleicon; } } /** Close the current browser window. */ function close_window() { window.close(); } /** * Close the current browser window, forcing the window/tab that opened this * popup to reload itself. */ function close_window_reloading_opener() { if (window.opener) { window.opener.location.reload(1); close_window(); // Intentionally, only try to close the window if there is some evidence we are in a popup. } } /** * Used in a couple of modules to hide navigation areas when using AJAX */ function hide_item(itemid) { var item = document.getElementById(itemid); if (item) { item.style.display = "none"; } } /** * Tranfer keyboard focus to the HTML element with the given id, if it exists. * @param controlid the control id. */ function focuscontrol(controlid) { var control = document.getElementById(controlid); if (control) { control.focus(); } } /** * Transfers keyboard focus to an HTML element based on the old style style of focus * This function should be removed as soon as it is no longer used */ function old_onload_focus(formid, controlname) { if (document.forms[formid]) { document.forms[formid].elements[controlname].focus(); } } function scroll_to_end() { window.scrollTo(0, 5000000); } var scrolltoendtimeout; function repeatedly_scroll_to_end() { scrolltoendtimeout = setInterval(scroll_to_end, 50); } function cancel_scroll_to_end() { if (scrolltoendtimeout) { clearTimeout(scrolltoendtimeout); scrolltoendtimeout = null; } } function create_UFO_object(eid) { UFO.create(FO, eid); } function build_querystring(obj) { if (typeof obj !== 'object') { return null; } var list = []; for(var k in obj) { k = encodeURIComponent(k); var value = obj[k]; if(obj[k] instanceof Array) { for(var i in value) { list.push(k+'[]='+encodeURIComponent(value[i])); } } else { list.push(k+'='+encodeURIComponent(value)); } } return list.join('&'); }