// 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) { YAHOO.util.Dom.addClass(document.body, 'yui-skin-sam'); 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); } /** elementToggleHide (element, elementFinder) If elementFinder is not provided, toggles the "hidden" class for the specified element. If elementFinder is provided, then the "hidden" class will be toggled for the object returned by the function call elementFinder(element). If persistent == true, also sets a cookie for this. */ function elementToggleHide(el, persistent, elementFinder, strShow, strHide) { if(!elementFinder) { var obj = el; //el:container el = document.getElementById('togglehide_'+obj.id); } else { var obj = elementFinder(el); //el:button. } if(obj.className.indexOf('hidden') == -1) { obj.className += ' hidden'; if (el.src) { el.src = el.src.replace('switch_minus', 'switch_plus'); el.alt = strShow; el.title = strShow; } var shown = 0; } else { obj.className = obj.className.replace(new RegExp(' ?hidden'), ''); if (el.src) { el.src = el.src.replace('switch_plus', 'switch_minus'); el.alt = strHide; el.title = strHide; } var shown = 1; } if(persistent == true) { new cookie('hide:' + obj.id, 1, (shown ? -1 : 356), '/').set(); } } function elementCookieHide(id, strShow, strHide) { var obj = document.getElementById(id); var cook = new cookie('hide:' + id).read(); if(cook != null) { elementToggleHide(obj, false, null, strShow, strHide); } } function filterByParent(elCollection, parentFinder) { var filteredCollection = []; for(var i = 0; i < elCollection.length; ++i) { var findParent = parentFinder(elCollection[i]); if(findParent.nodeName != '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 = moodle_cfg.pixpath + '/t/collapsed.png'; } else { this.icon.src = moodle_cfg.pixpath + '/t/expanded.png'; } a.appendChild(this.icon); // Hook up the event handler. var self = this; YAHOO.util.Event.addListener(a, 'click', function(e) {self.handle_click(e);}); // 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 = moodle_cfg.pixpath + '/t/collapsed.png'; } else { this.icon.src = moodle_cfg.pixpath + '/t/expanded.png'; } // 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'; } } /** 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. } }