47aa42e2 |
1 | // Miscellaneous core Javascript functions for Moodle |
2 | |
b48fd7b5 |
3 | function popupchecker(msg) { |
4 | var testwindow = window.open('itestwin.html', '', 'width=1,height=1,left=0,top=0,scrollbars=no'); |
f6b6861d |
5 | if (!testwindow) { |
6 | alert(msg); |
7 | } else { |
b48fd7b5 |
8 | testwindow.close(); |
9 | } |
10 | } |
11 | |
63d28811 |
12 | function checkall() { |
214f5850 |
13 | var inputs = document.getElementsByTagName('input'); |
14 | for (var i = 0; i < inputs.length; i++) { |
15 | if (inputs[i].type == 'checkbox') { |
16 | inputs[i].checked = true; |
17 | } |
d2ce367f |
18 | } |
63d28811 |
19 | } |
20 | |
03f9425f |
21 | function checknone() { |
214f5850 |
22 | var inputs = document.getElementsByTagName('input'); |
23 | for (var i = 0; i < inputs.length; i++) { |
24 | if (inputs[i].type == 'checkbox') { |
25 | inputs[i].checked = false; |
26 | } |
d2ce367f |
27 | } |
03f9425f |
28 | } |
29 | |
d2ce367f |
30 | function lockoptions(formid, master, subitems) { |
027d0485 |
31 | // Subitems is an array of names of sub items. |
32 | // Optionally, each item in subitems may have a |
63d28811 |
33 | // companion hidden item in the form with the |
027d0485 |
34 | // same name but prefixed by "h". |
d2ce367f |
35 | var form = document.forms[formid]; |
36 | |
37 | if (eval("form."+master+".checked")) { |
63d28811 |
38 | for (i=0; i<subitems.length; i++) { |
39 | unlockoption(form, subitems[i]); |
40 | } |
41 | } else { |
42 | for (i=0; i<subitems.length; i++) { |
43 | lockoption(form, subitems[i]); |
44 | } |
45 | } |
46 | return(true); |
47 | } |
48 | |
f07b9627 |
49 | function lockoption(form,item) { |
d2ce367f |
50 | eval("form."+item+".disabled=true");/* IE thing */ |
51 | if(form.elements['h'+item]) { |
52 | eval("form.h"+item+".value=1"); |
f07b9627 |
53 | } |
54 | } |
55 | |
56 | function unlockoption(form,item) { |
d2ce367f |
57 | eval("form."+item+".disabled=false");/* IE thing */ |
58 | if(form.elements['h'+item]) { |
59 | eval("form.h"+item+".value=0"); |
f07b9627 |
60 | } |
61 | } |
dd07bbac |
62 | |
b51709c1 |
63 | /** |
64 | * Get the value of the 'virtual form element' with a particular name. That is, |
65 | * abstracts away the difference between a normal form element, like a select |
66 | * which is a single HTML element with a .value property, and a set of radio |
67 | * buttons, which is several HTML elements. |
68 | * |
69 | * @param form a HTML form. |
70 | * @param master the name of an element in that form. |
71 | * @return the value of that element. |
72 | */ |
73 | function get_form_element_value(form, name) { |
74 | var element = form[name]; |
75 | if (!element) { |
76 | return null; |
77 | } |
78 | if (element.tagName) { |
79 | // Ordinarly thing like a select box. |
80 | return element.value; |
81 | } |
82 | // Array of things, like radio buttons. |
83 | for (var j = 0; j < element.length; j++) { |
84 | var el = element[j]; |
85 | if (el.checked) { |
86 | return el.value; |
87 | } |
88 | } |
89 | return null; |
90 | } |
91 | |
92 | |
93 | /** |
94 | * Set the disabled state of the 'virtual form element' with a particular name. |
95 | * This abstracts away the difference between a normal form element, like a select |
96 | * which is a single HTML element with a .value property, and a set of radio |
97 | * buttons, which is several HTML elements. |
98 | * |
99 | * @param form a HTML form. |
100 | * @param master the name of an element in that form. |
101 | * @param disabled the disabled state to set. |
102 | */ |
103 | function set_form_element_disabled(form, name, disabled) { |
104 | var element = form[name]; |
105 | if (!element) { |
106 | return; |
107 | } |
108 | if (element.tagName) { |
109 | // Ordinarly thing like a select box. |
110 | element.disabled = disabled; |
111 | } |
112 | // Array of things, like radio buttons. |
113 | for (var j = 0; j < element.length; j++) { |
114 | var el = element[j]; |
115 | el.disabled = disabled; |
116 | } |
117 | } |
dd07bbac |
118 | |
50ef8eb9 |
119 | function lockoptionsall(formid) { |
dd07bbac |
120 | var form = document.forms[formid]; |
b51709c1 |
121 | var dependons = eval(formid + 'items'); |
122 | var tolock = []; |
dd07bbac |
123 | for (var dependon in dependons) { |
d63ef3b8 |
124 | // change for MooTools compatibility |
125 | if (!dependons.propertyIsEnumerable(dependon)) { |
126 | continue; |
127 | } |
b51709c1 |
128 | if (!form[dependon]) { |
4bc24867 |
129 | continue; |
130 | } |
dd07bbac |
131 | for (var condition in dependons[dependon]) { |
132 | for (var value in dependons[dependon][condition]) { |
133 | var lock; |
134 | switch (condition) { |
135 | case 'notchecked': |
b51709c1 |
136 | lock = !form[dependon].checked; break; |
dd07bbac |
137 | case 'checked': |
b51709c1 |
138 | lock = form[dependon].checked; break; |
dd07bbac |
139 | case 'noitemselected': |
b51709c1 |
140 | lock = form[dependon].selectedIndex == -1; break; |
dd07bbac |
141 | case 'eq': |
b51709c1 |
142 | lock = get_form_element_value(form, dependon) == value; break; |
dd07bbac |
143 | default: |
b51709c1 |
144 | lock = get_form_element_value(form, dependon) != value; break; |
dd07bbac |
145 | } |
146 | for (var ei in dependons[dependon][condition][value]) { |
d63ef3b8 |
147 | // change for MooTools compatibility |
148 | if (!window.webkit && (!dependons[dependon][condition][value].propertyIsEnumerable(ei))) { |
149 | continue; |
150 | } |
632b88d5 |
151 | var eltolock = dependons[dependon][condition][value][ei]; |
b51709c1 |
152 | if (tolock[eltolock] != null) { |
153 | tolock[eltolock] = lock || tolock[eltolock]; |
632b88d5 |
154 | } else { |
155 | tolock[eltolock] = lock; |
156 | } |
dd07bbac |
157 | } |
158 | } |
50ef8eb9 |
159 | } |
dd07bbac |
160 | } |
b51709c1 |
161 | for (var el in tolock) { |
d63ef3b8 |
162 | // change for MooTools compatibility |
163 | if (!tolock.propertyIsEnumerable(el)) { |
164 | continue; |
165 | } |
b51709c1 |
166 | set_form_element_disabled(form, el, tolock[el]); |
632b88d5 |
167 | } |
dd07bbac |
168 | return true; |
50ef8eb9 |
169 | } |
170 | |
d01a38cb |
171 | function lockoptionsallsetup(formid) { |
dd07bbac |
172 | var form = document.forms[formid]; |
173 | var dependons = eval(formid+'items'); |
174 | for (var dependon in dependons) { |
d63ef3b8 |
175 | // change for MooTools compatibility |
176 | if (!dependons.propertyIsEnumerable(dependon)) { |
177 | continue; |
178 | } |
b51709c1 |
179 | var masters = form[dependon]; |
180 | if (!masters) { |
4bc24867 |
181 | continue; |
182 | } |
a4db2e7c |
183 | if (masters.tagName) { |
b51709c1 |
184 | // If master is radio buttons, we get an array, otherwise we don't. |
185 | // Convert both cases to an array for convinience. |
186 | masters = [masters]; |
187 | } |
188 | for (var j = 0; j < masters.length; j++) { |
189 | master = masters[j]; |
190 | master.formid = formid; |
191 | master.onclick = function() {return lockoptionsall(this.formid);}; |
192 | master.onblur = function() {return lockoptionsall(this.formid);}; |
193 | master.onchange = function() {return lockoptionsall(this.formid);}; |
194 | } |
dd07bbac |
195 | } |
b51709c1 |
196 | for (var i = 0; i < form.elements.length; i++) { |
dd07bbac |
197 | var formelement = form.elements[i]; |
198 | if (formelement.type=='reset') { |
c0056e22 |
199 | formelement.formid = formid; |
200 | formelement.onclick = function() {this.form.reset();return lockoptionsall(this.formid);}; |
201 | formelement.onblur = function() {this.form.reset();return lockoptionsall(this.formid);}; |
202 | formelement.onchange = function() {this.form.reset();return lockoptionsall(this.formid);}; |
dd07bbac |
203 | } |
204 | } |
205 | return lockoptionsall(formid); |
d01a38cb |
206 | } |
50ef8eb9 |
207 | |
7678e65c |
208 | |
209 | function submitFormById(id) { |
210 | var theform = document.getElementById(id); |
211 | if(!theform) { |
212 | return false; |
213 | } |
bb006c95 |
214 | if(theform.tagName.toLowerCase() != 'form') { |
7678e65c |
215 | return false; |
216 | } |
217 | if(!theform.onsubmit || theform.onsubmit()) { |
218 | return theform.submit(); |
219 | } |
220 | } |
363cb62c |
221 | |
8ceb09e0 |
222 | function select_all_in(elTagName, elClass, elId) { |
d2ce367f |
223 | var inputs = document.getElementsByTagName('input'); |
8ceb09e0 |
224 | inputs = filterByParent(inputs, function(el) {return findParentNode(el, elTagName, elClass, elId);}); |
363cb62c |
225 | for(var i = 0; i < inputs.length; ++i) { |
bee40515 |
226 | if(inputs[i].type == 'checkbox' || inputs[i].type == 'radio') { |
363cb62c |
227 | inputs[i].checked = 'checked'; |
228 | } |
229 | } |
230 | } |
231 | |
8ceb09e0 |
232 | function deselect_all_in(elTagName, elClass, elId) { |
363cb62c |
233 | var inputs = document.getElementsByTagName('INPUT'); |
8ceb09e0 |
234 | inputs = filterByParent(inputs, function(el) {return findParentNode(el, elTagName, elClass, elId);}); |
363cb62c |
235 | for(var i = 0; i < inputs.length; ++i) { |
bee40515 |
236 | if(inputs[i].type == 'checkbox' || inputs[i].type == 'radio') { |
363cb62c |
237 | inputs[i].checked = ''; |
238 | } |
239 | } |
240 | } |
241 | |
242 | function confirm_if(expr, message) { |
243 | if(!expr) { |
244 | return true; |
245 | } |
246 | return confirm(message); |
247 | } |
47aa42e2 |
248 | |
249 | |
250 | /* |
251 | findParentNode (start, elementName, elementClass, elementID) |
50ef8eb9 |
252 | |
47aa42e2 |
253 | Travels up the DOM hierarchy to find a parent element with the |
254 | specified tag name, class, and id. All conditions must be met, |
255 | but any can be ommitted. Returns the BODY element if no match |
256 | found. |
257 | */ |
258 | function findParentNode(el, elName, elClass, elId) { |
ef4d42fd |
259 | while(el.nodeName.toUpperCase() != 'BODY') { |
47aa42e2 |
260 | if( |
ef4d42fd |
261 | (!elName || el.nodeName.toUpperCase() == elName) && |
47aa42e2 |
262 | (!elClass || el.className.indexOf(elClass) != -1) && |
263 | (!elId || el.id == elId)) |
264 | { |
265 | break; |
266 | } |
267 | el = el.parentNode; |
268 | } |
269 | return el; |
270 | } |
19194f82 |
271 | /* |
272 | findChildNode (start, elementName, elementClass, elementID) |
273 | |
274 | Travels down the DOM hierarchy to find all child elements with the |
275 | specified tag name, class, and id. All conditions must be met, |
276 | but any can be ommitted. |
a23f0aaf |
277 | Doesn't examine children of matches. |
19194f82 |
278 | */ |
279 | function findChildNodes(start, tagName, elementClass, elementID, elementName) { |
280 | var children = new Array(); |
83c9a8a2 |
281 | for (var i = 0; i < start.childNodes.length; i++) { |
a23f0aaf |
282 | var classfound = false; |
83c9a8a2 |
283 | var child = start.childNodes[i]; |
a23f0aaf |
284 | if((child.nodeType == 1) &&//element node type |
b51709c1 |
285 | (elementClass && (typeof(child.className)=='string'))) { |
a23f0aaf |
286 | var childClasses = child.className.split(/\s+/); |
b51709c1 |
287 | for (var childClassIndex in childClasses) { |
288 | if (childClasses[childClassIndex]==elementClass) { |
a23f0aaf |
289 | classfound = true; |
290 | break; |
291 | } |
292 | } |
293 | } |
f07b9627 |
294 | if(child.nodeType == 1) { //element node type |
295 | if ( (!tagName || child.nodeName == tagName) && |
296 | (!elementClass || classfound)&& |
297 | (!elementID || child.id == elementID) && |
298 | (!elementName || child.name == elementName)) |
299 | { |
300 | children = children.concat(child); |
301 | } else { |
302 | children = children.concat(findChildNodes(child, tagName, elementClass, elementID, elementName)); |
303 | } |
19194f82 |
304 | } |
19194f82 |
305 | } |
306 | return children; |
307 | } |
308 | /* |
309 | elementSetHide (elements, hide) |
310 | |
311 | Adds or removes the "hide" class for the specified elements depending on boolean hide. |
312 | */ |
313 | function elementShowAdvanced(elements, show) { |
b51709c1 |
314 | for (var elementIndex in elements) { |
19194f82 |
315 | element = elements[elementIndex]; |
316 | element.className = element.className.replace(new RegExp(' ?hide'), '') |
317 | if(!show) { |
318 | element.className += ' hide'; |
319 | } |
320 | } |
321 | } |
322 | |
cd350b53 |
323 | function showAdvancedInit(addBefore, nameAttr, buttonLabel, hideText, showText) { |
324 | var showHideButton = document.createElement("input"); |
325 | showHideButton.type = 'button'; |
326 | showHideButton.value = buttonLabel; |
327 | showHideButton.name = nameAttr; |
328 | showHideButton.moodle = { |
329 | hideLabel: hideText, |
330 | showLabel: showText |
331 | }; |
332 | YAHOO.util.Event.addListener(showHideButton, 'click', showAdvancedOnClick); |
333 | el = document.getElementById(addBefore); |
334 | el.parentNode.insertBefore(showHideButton, el); |
335 | } |
336 | |
337 | function showAdvancedOnClick(e) { |
338 | var button = e.target ? e.target : e.srcElement; |
339 | |
19194f82 |
340 | var toSet=findChildNodes(button.form, null, 'advanced'); |
341 | var buttontext = ''; |
74d15d35 |
342 | if (button.form.elements['mform_showadvanced_last'].value == '0' || button.form.elements['mform_showadvanced_last'].value == '' ) { |
19194f82 |
343 | elementShowAdvanced(toSet, true); |
cd350b53 |
344 | buttontext = button.moodle.hideLabel; |
19194f82 |
345 | button.form.elements['mform_showadvanced_last'].value = '1'; |
346 | } else { |
347 | elementShowAdvanced(toSet, false); |
cd350b53 |
348 | buttontext = button.moodle.showLabel; |
19194f82 |
349 | button.form.elements['mform_showadvanced_last'].value = '0'; |
350 | } |
351 | var formelements = button.form.elements; |
4ea054ec |
352 | // Fixed MDL-10506 |
b51709c1 |
353 | for (var i = 0; i < formelements.length; i++) { |
354 | if (formelements[i] && formelements[i].name && (formelements[i].name=='mform_showadvanced')) { |
19194f82 |
355 | formelements[i].value = buttontext; |
356 | } |
357 | } |
358 | //never submit the form if js is enabled. |
359 | return false; |
360 | } |
47aa42e2 |
361 | |
54bb33eb |
362 | function unmaskPassword(id) { |
239ade45 |
363 | var pw = document.getElementById(id); |
54bb33eb |
364 | var chb = document.getElementById(id+'unmask'); |
239ade45 |
365 | |
366 | try { |
367 | // first try IE way - it can not set name attribute later |
368 | if (chb.checked) { |
369 | var newpw = document.createElement('<input type="text" name="'+pw.name+'">'); |
370 | } else { |
371 | var newpw = document.createElement('<input type="password" name="'+pw.name+'">'); |
372 | } |
eba8cd63 |
373 | newpw.attributes['class'].nodeValue = pw.attributes['class'].nodeValue; |
239ade45 |
374 | } catch (e) { |
375 | var newpw = document.createElement('input'); |
376 | newpw.setAttribute('name', pw.name); |
377 | if (chb.checked) { |
378 | newpw.setAttribute('type', 'text'); |
379 | } else { |
380 | newpw.setAttribute('type', 'password'); |
381 | } |
eba8cd63 |
382 | newpw.setAttribute('class', pw.getAttribute('class')); |
239ade45 |
383 | } |
384 | newpw.id = pw.id; |
385 | newpw.size = pw.size; |
386 | newpw.onblur = pw.onblur; |
387 | newpw.onchange = pw.onchange; |
388 | newpw.value = pw.value; |
389 | pw.parentNode.replaceChild(newpw, pw); |
390 | } |
391 | |
8e7cebb0 |
392 | /** |
393 | * Search a Moodle form to find all the fdate_time_selector and fdate_selector |
394 | * elements, and add date_selector_calendar instance to each. |
395 | */ |
396 | function init_date_selectors(firstdayofweek) { |
397 | YAHOO.util.Dom.addClass(document.body, 'yui-skin-sam'); |
398 | var els = YAHOO.util.Dom.getElementsByClassName('fdate_time_selector', 'fieldset'); |
399 | for (var i = 0; i < els.length; i++) { |
400 | new date_selector_calendar(els[i], firstdayofweek); |
401 | } |
402 | els = YAHOO.util.Dom.getElementsByClassName('fdate_selector', 'fieldset'); |
403 | for (i = 0; i < els.length; i++) { |
404 | new date_selector_calendar(els[i], firstdayofweek); |
405 | } |
406 | } |
407 | |
408 | /** |
9bad31f5 |
409 | * Constructor for a JavaScript object that connects to a fdate_time_selector |
8e7cebb0 |
410 | * or a fdate_selector in a Moodle form, and shows a popup calendar whenever |
411 | * that element has keyboard focus. |
412 | * @param el the fieldset class="fdate_time_selector" or "fdate_selector". |
413 | */ |
414 | function date_selector_calendar(el, firstdayofweek) { |
415 | // Ensure that the shared div and calendar exist. |
416 | if (!date_selector_calendar.panel) { |
417 | date_selector_calendar.panel = new YAHOO.widget.Panel('date_selector_calendar_panel', |
b3a49376 |
418 | {visible: false, draggable: false}); |
8e7cebb0 |
419 | var div = document.createElement('div'); |
420 | date_selector_calendar.panel.setBody(div); |
421 | date_selector_calendar.panel.render(document.body); |
422 | |
423 | YAHOO.util.Event.addListener(document, 'click', date_selector_calendar.document_click); |
424 | date_selector_calendar.panel.showEvent.subscribe(function() { |
425 | date_selector_calendar.panel.fireEvent('changeContent'); |
426 | }); |
b3a49376 |
427 | date_selector_calendar.panel.hideEvent.subscribe(date_selector_calendar.release_current); |
8e7cebb0 |
428 | |
429 | date_selector_calendar.calendar = new YAHOO.widget.Calendar(div, |
430 | {iframe: false, hide_blank_weeks: true, start_weekday: firstdayofweek}); |
431 | date_selector_calendar.calendar.renderEvent.subscribe(function() { |
432 | date_selector_calendar.panel.fireEvent('changeContent'); |
bd55319b |
433 | date_selector_calendar.delayed_reposition(); |
8e7cebb0 |
434 | }); |
8e7cebb0 |
435 | } |
436 | |
437 | this.fieldset = el; |
438 | var controls = el.getElementsByTagName('select'); |
439 | for (var i = 0; i < controls.length; i++) { |
8e7cebb0 |
440 | if (/\[year\]$/.test(controls[i].name)) { |
441 | this.yearselect = controls[i]; |
9bad31f5 |
442 | } else if (/\[month\]$/.test(controls[i].name)) { |
8e7cebb0 |
443 | this.monthselect = controls[i]; |
9bad31f5 |
444 | } else if (/\[day\]$/.test(controls[i].name)) { |
8e7cebb0 |
445 | this.dayselect = controls[i]; |
9bad31f5 |
446 | } else { |
bd55319b |
447 | YAHOO.util.Event.addFocusListener(controls[i], date_selector_calendar.cancel_any_timeout, this); |
9bad31f5 |
448 | YAHOO.util.Event.addBlurListener(controls[i], this.blur_event, this); |
8e7cebb0 |
449 | } |
450 | } |
451 | if (!(this.yearselect && this.monthselect && this.dayselect)) { |
452 | throw 'Failed to initialise calendar.'; |
453 | } |
9bad31f5 |
454 | YAHOO.util.Event.addFocusListener([this.yearselect, this.monthselect, this.dayselect], this.focus_event, this); |
455 | YAHOO.util.Event.addBlurListener([this.yearselect, this.monthselect, this.dayselect], this.blur_event, this); |
8e7cebb0 |
456 | |
457 | this.enablecheckbox = el.getElementsByTagName('input')[0]; |
458 | if (this.enablecheckbox) { |
459 | YAHOO.util.Event.addFocusListener(this.enablecheckbox, this.focus_event, this); |
460 | YAHOO.util.Event.addListener(this.enablecheckbox, 'change', this.focus_event, this); |
461 | YAHOO.util.Event.addBlurListener(this.enablecheckbox, this.blur_event, this); |
462 | } |
463 | } |
464 | |
465 | /** The pop-up calendar that contains the calendar. */ |
466 | date_selector_calendar.panel = null; |
467 | |
468 | /** The shared YAHOO.widget.Calendar used by all date_selector_calendars. */ |
469 | date_selector_calendar.calendar = null; |
470 | |
471 | /** The date_selector_calendar that currently owns the shared stuff. */ |
472 | date_selector_calendar.currentowner = null; |
473 | |
474 | /** Used as a timeout when hiding the calendar on blur - so we don't hide the calendar |
475 | * if we are just jumping from on of our controls to another. */ |
476 | date_selector_calendar.hidetimeout = null; |
477 | |
bd55319b |
478 | /** Timeout for repositioning after a delay after a change of months. */ |
479 | date_selector_calendar.repositiontimeout = null; |
8e7cebb0 |
480 | |
bd55319b |
481 | /** Member variables. Pointers to various bits of the DOM. */ |
8e7cebb0 |
482 | date_selector_calendar.prototype.fieldset = null; |
483 | date_selector_calendar.prototype.yearselect = null; |
484 | date_selector_calendar.prototype.monthselect = null; |
485 | date_selector_calendar.prototype.dayselect = null; |
486 | date_selector_calendar.prototype.enablecheckbox = null; |
487 | |
bd55319b |
488 | date_selector_calendar.cancel_any_timeout = function() { |
8e7cebb0 |
489 | if (date_selector_calendar.hidetimeout) { |
490 | clearTimeout(date_selector_calendar.hidetimeout); |
491 | date_selector_calendar.hidetimeout = null; |
492 | } |
bd55319b |
493 | if (date_selector_calendar.repositiontimeout) { |
494 | clearTimeout(date_selector_calendar.repositiontimeout); |
495 | date_selector_calendar.repositiontimeout = null; |
496 | } |
497 | } |
498 | |
499 | date_selector_calendar.delayed_reposition = function() { |
500 | if (date_selector_calendar.repositiontimeout) { |
501 | clearTimeout(date_selector_calendar.repositiontimeout); |
502 | date_selector_calendar.repositiontimeout = null; |
503 | } |
b3a49376 |
504 | date_selector_calendar.repositiontimeout = setTimeout(date_selector_calendar.fix_position, 500); |
bd55319b |
505 | } |
506 | |
507 | date_selector_calendar.fix_position = function() { |
508 | if (date_selector_calendar.currentowner) { |
509 | date_selector_calendar.panel.cfg.setProperty('context', [date_selector_calendar.currentowner.fieldset, 'bl', 'tl']); |
510 | } |
8e7cebb0 |
511 | } |
512 | |
b3a49376 |
513 | date_selector_calendar.release_current = function() { |
514 | if (date_selector_calendar.currentowner) { |
515 | date_selector_calendar.currentowner.release_calendar(); |
516 | } |
517 | } |
518 | |
8e7cebb0 |
519 | date_selector_calendar.prototype.focus_event = function(e, me) { |
bd55319b |
520 | date_selector_calendar.cancel_any_timeout(); |
8e7cebb0 |
521 | if (me.enablecheckbox == null || me.enablecheckbox.checked) { |
522 | me.claim_calendar(); |
523 | } else { |
524 | if (date_selector_calendar.currentowner) { |
525 | date_selector_calendar.currentowner.release_calendar(); |
526 | } |
527 | } |
528 | } |
529 | |
530 | date_selector_calendar.prototype.blur_event = function(e, me) { |
b3a49376 |
531 | date_selector_calendar.hidetimeout = setTimeout(date_selector_calendar.release_current, 300); |
8e7cebb0 |
532 | } |
533 | |
534 | date_selector_calendar.prototype.handle_select_change = function(e, me) { |
535 | me.set_date_from_selects(); |
536 | } |
537 | |
538 | date_selector_calendar.document_click = function(event) { |
539 | if (date_selector_calendar.currentowner) { |
540 | var currentcontainer = date_selector_calendar.currentowner.fieldset; |
541 | var eventarget = YAHOO.util.Event.getTarget(event); |
b3a49376 |
542 | if (YAHOO.util.Dom.isAncestor(currentcontainer, eventarget)) { |
543 | setTimeout(function() {date_selector_calendar.cancel_any_timeout()}, 100); |
544 | } else { |
8e7cebb0 |
545 | date_selector_calendar.currentowner.release_calendar(); |
546 | } |
547 | } |
548 | } |
549 | |
550 | date_selector_calendar.prototype.claim_calendar = function() { |
bd55319b |
551 | date_selector_calendar.cancel_any_timeout(); |
8e7cebb0 |
552 | if (date_selector_calendar.currentowner == this) { |
553 | return; |
554 | } |
555 | if (date_selector_calendar.currentowner) { |
556 | date_selector_calendar.currentowner.release_calendar(); |
557 | } |
558 | |
bd55319b |
559 | if (date_selector_calendar.currentowner != this) { |
560 | this.connect_handlers(); |
561 | } |
562 | date_selector_calendar.currentowner = this; |
563 | |
8e7cebb0 |
564 | date_selector_calendar.calendar.cfg.setProperty('mindate', new Date(this.yearselect.options[0].value, 0, 1)); |
565 | date_selector_calendar.calendar.cfg.setProperty('maxdate', new Date(this.yearselect.options[this.yearselect.options.length - 1].value, 11, 31)); |
bd55319b |
566 | this.fieldset.insertBefore(date_selector_calendar.panel.element, this.yearselect.nextSibling); |
8e7cebb0 |
567 | this.set_date_from_selects(); |
568 | date_selector_calendar.panel.show(); |
569 | var me = this; |
bd55319b |
570 | setTimeout(function() {date_selector_calendar.cancel_any_timeout()}, 100); |
8e7cebb0 |
571 | } |
572 | |
573 | date_selector_calendar.prototype.set_date_from_selects = function() { |
574 | var year = parseInt(this.yearselect.value); |
575 | var month = parseInt(this.monthselect.value) - 1; |
576 | var day = parseInt(this.dayselect.value); |
577 | date_selector_calendar.calendar.select(new Date(year, month, day)); |
578 | date_selector_calendar.calendar.setMonth(month); |
579 | date_selector_calendar.calendar.setYear(year); |
bd55319b |
580 | date_selector_calendar.calendar.render(); |
581 | date_selector_calendar.fix_position(); |
8e7cebb0 |
582 | } |
583 | |
584 | date_selector_calendar.prototype.set_selects_from_date = function(eventtype, args) { |
585 | var date = args[0][0]; |
586 | var newyear = date[0]; |
587 | var newindex = newyear - this.yearselect.options[0].value; |
588 | this.yearselect.selectedIndex = newindex; |
589 | this.monthselect.selectedIndex = date[1] - this.monthselect.options[0].value; |
590 | this.dayselect.selectedIndex = date[2] - this.dayselect.options[0].value; |
591 | } |
592 | |
593 | date_selector_calendar.prototype.connect_handlers = function() { |
594 | YAHOO.util.Event.addListener([this.yearselect, this.monthselect, this.dayselect], 'change', this.handle_select_change, this); |
595 | date_selector_calendar.calendar.selectEvent.subscribe(this.set_selects_from_date, this, true); |
596 | } |
597 | |
598 | date_selector_calendar.prototype.release_calendar = function() { |
599 | date_selector_calendar.panel.hide(); |
600 | date_selector_calendar.currentowner = null; |
601 | YAHOO.util.Event.removeListener([this.yearselect, this.monthselect, this.dayselect], this.handle_select_change); |
602 | date_selector_calendar.calendar.selectEvent.unsubscribe(this.set_selects_from_date, this); |
603 | } |
604 | |
605 | /** |
47aa42e2 |
606 | elementToggleHide (element, elementFinder) |
607 | |
608 | If elementFinder is not provided, toggles the "hidden" class for the specified element. |
609 | If elementFinder is provided, then the "hidden" class will be toggled for the object |
610 | returned by the function call elementFinder(element). |
611 | |
612 | If persistent == true, also sets a cookie for this. |
613 | */ |
c076f4be |
614 | function elementToggleHide(el, persistent, elementFinder, strShow, strHide) { |
47aa42e2 |
615 | if(!elementFinder) { |
c076f4be |
616 | var obj = el; //el:container |
617 | el = document.getElementById('togglehide_'+obj.id); |
47aa42e2 |
618 | } |
619 | else { |
c076f4be |
620 | var obj = elementFinder(el); //el:button. |
47aa42e2 |
621 | } |
622 | if(obj.className.indexOf('hidden') == -1) { |
623 | obj.className += ' hidden'; |
c076f4be |
624 | if (el.src) { |
625 | el.src = el.src.replace('switch_minus', 'switch_plus'); |
626 | el.alt = strShow; |
627 | el.title = strShow; |
628 | } |
19194f82 |
629 | var shown = 0; |
47aa42e2 |
630 | } |
631 | else { |
c076f4be |
632 | obj.className = obj.className.replace(new RegExp(' ?hidden'), ''); |
633 | if (el.src) { |
634 | el.src = el.src.replace('switch_plus', 'switch_minus'); |
635 | el.alt = strHide; |
636 | el.title = strHide; |
637 | } |
19194f82 |
638 | var shown = 1; |
47aa42e2 |
639 | } |
19194f82 |
640 | |
47aa42e2 |
641 | if(persistent == true) { |
642 | new cookie('hide:' + obj.id, 1, (shown ? -1 : 356), '/').set(); |
643 | } |
644 | } |
645 | |
c076f4be |
646 | function elementCookieHide(id, strShow, strHide) { |
47aa42e2 |
647 | var obj = document.getElementById(id); |
648 | var cook = new cookie('hide:' + id).read(); |
649 | if(cook != null) { |
c076f4be |
650 | elementToggleHide(obj, false, null, strShow, strHide); |
47aa42e2 |
651 | } |
652 | } |
653 | |
654 | function filterByParent(elCollection, parentFinder) { |
655 | var filteredCollection = []; |
656 | for(var i = 0; i < elCollection.length; ++i) { |
657 | var findParent = parentFinder(elCollection[i]); |
658 | if(findParent.nodeName != 'BODY') { |
659 | filteredCollection.push(elCollection[i]); |
660 | } |
661 | } |
662 | return filteredCollection; |
663 | } |
664 | |
7979105c |
665 | /* |
666 | All this is here just so that IE gets to handle oversized blocks |
667 | in a visually pleasing manner. It does a browser detect. So sue me. |
668 | */ |
669 | |
670 | function fix_column_widths() { |
671 | var agt = navigator.userAgent.toLowerCase(); |
672 | if ((agt.indexOf("msie") != -1) && (agt.indexOf("opera") == -1)) { |
673 | fix_column_width('left-column'); |
674 | fix_column_width('right-column'); |
675 | } |
676 | } |
677 | |
678 | function fix_column_width(colName) { |
679 | if(column = document.getElementById(colName)) { |
680 | if(!column.offsetWidth) { |
681 | setTimeout("fix_column_width('" + colName + "')", 20); |
682 | return; |
683 | } |
684 | |
685 | var width = 0; |
686 | var nodes = column.childNodes; |
687 | |
688 | for(i = 0; i < nodes.length; ++i) { |
689 | if(nodes[i].className.indexOf("sideblock") != -1 ) { |
690 | if(width < nodes[i].offsetWidth) { |
691 | width = nodes[i].offsetWidth; |
692 | } |
693 | } |
694 | } |
695 | |
696 | for(i = 0; i < nodes.length; ++i) { |
697 | if(nodes[i].className.indexOf("sideblock") != -1 ) { |
698 | nodes[i].style.width = width + 'px'; |
699 | } |
700 | } |
701 | } |
702 | } |
d13c5938 |
703 | |
704 | |
705 | /* |
9f439b17 |
706 | Insert myValue at current cursor position |
707 | */ |
d13c5938 |
708 | function insertAtCursor(myField, myValue) { |
9f439b17 |
709 | // IE support |
710 | if (document.selection) { |
711 | myField.focus(); |
712 | sel = document.selection.createRange(); |
713 | sel.text = myValue; |
714 | } |
715 | // Mozilla/Netscape support |
716 | else if (myField.selectionStart || myField.selectionStart == '0') { |
717 | var startPos = myField.selectionStart; |
718 | var endPos = myField.selectionEnd; |
719 | myField.value = myField.value.substring(0, startPos) |
720 | + myValue + myField.value.substring(endPos, myField.value.length); |
721 | } else { |
722 | myField.value += myValue; |
723 | } |
d13c5938 |
724 | } |
7470d6de |
725 | |
726 | |
727 | /* |
c0056e22 |
728 | Call instead of setting window.onload directly or setting body onload=. |
729 | Adds your function to a chain of functions rather than overwriting anything |
730 | that exists. |
731 | */ |
7470d6de |
732 | function addonload(fn) { |
733 | var oldhandler=window.onload; |
734 | window.onload=function() { |
735 | if(oldhandler) oldhandler(); |
c0056e22 |
736 | fn(); |
7470d6de |
737 | } |
738 | } |
c849ed1e |
739 | |
b51709c1 |
740 | function getElementsByClassName(oElm, strTagName, oClassNames) { |
c849ed1e |
741 | var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName); |
742 | var arrReturnElements = new Array(); |
743 | var arrRegExpClassNames = new Array(); |
b51709c1 |
744 | if(typeof oClassNames == "object") { |
745 | for(var i=0; i<oClassNames.length; i++) { |
c849ed1e |
746 | arrRegExpClassNames.push(new RegExp("(^|\\s)" + oClassNames[i].replace(/\-/g, "\\-") + "(\\s|$)")); |
747 | } |
748 | } |
749 | else{ |
750 | arrRegExpClassNames.push(new RegExp("(^|\\s)" + oClassNames.replace(/\-/g, "\\-") + "(\\s|$)")); |
751 | } |
752 | var oElement; |
753 | var bMatchesAll; |
b51709c1 |
754 | for(var j=0; j<arrElements.length; j++) { |
c849ed1e |
755 | oElement = arrElements[j]; |
756 | bMatchesAll = true; |
b51709c1 |
757 | for(var k=0; k<arrRegExpClassNames.length; k++) { |
758 | if(!arrRegExpClassNames[k].test(oElement.className)) { |
c849ed1e |
759 | bMatchesAll = false; |
760 | break; |
761 | } |
762 | } |
b51709c1 |
763 | if(bMatchesAll) { |
c849ed1e |
764 | arrReturnElements.push(oElement); |
765 | } |
766 | } |
767 | return (arrReturnElements) |
768 | } |
77241d9b |
769 | |
770 | function openpopup(url, name, options, fullscreen) { |
bed9cec8 |
771 | var fullurl = url; |
772 | if (!url.match(/https?:\/\//)) { |
214f5850 |
773 | fullurl = moodle_cfg.wwwroot + url; |
bed9cec8 |
774 | } |
77241d9b |
775 | var windowobj = window.open(fullurl,name,options); |
214f5850 |
776 | if (!windowobj) { |
777 | return true; |
778 | } |
77241d9b |
779 | if (fullscreen) { |
780 | windowobj.moveTo(0,0); |
781 | windowobj.resizeTo(screen.availWidth,screen.availHeight); |
782 | } |
783 | windowobj.focus(); |
784 | return false; |
785 | } |
740939ec |
786 | |
787 | /* This is only used on a few help pages. */ |
788 | emoticons_help = { |
789 | inputarea: null, |
790 | |
791 | init: function(formname, fieldname, listid) { |
792 | if (!opener || !opener.document.forms[formname]) { |
793 | return; |
794 | } |
795 | emoticons_help.inputarea = opener.document.forms[formname][fieldname]; |
796 | if (!emoticons_help.inputarea) { |
797 | return; |
798 | } |
799 | var emoticons = document.getElementById(listid).getElementsByTagName('li'); |
800 | for (var i = 0; i < emoticons.length; i++) { |
801 | var text = emoticons[i].getElementsByTagName('img')[0].alt; |
802 | YAHOO.util.Event.addListener(emoticons[i], 'click', emoticons_help.inserttext, text); |
803 | } |
804 | }, |
805 | |
806 | inserttext: function(e, text) { |
807 | text = ' ' + text + ' '; |
808 | if (emoticons_help.inputarea.createTextRange && emoticons_help.inputarea.caretPos) { |
809 | var caretPos = emoticons_help.inputarea.caretPos; |
810 | caretPos.text = caretPos.text.charAt(caretPos.text.length - 1) == ' ' ? text + ' ' : text; |
811 | } else { |
812 | emoticons_help.inputarea.value += text; |
813 | } |
814 | emoticons_help.inputarea.focus(); |
815 | } |
bd1884fe |
816 | } |
817 | |
818 | /** |
819 | * Makes a best effort to connect back to Moodle to update a user preference, |
820 | * however, there is no mechanism for finding out if the update succeeded. |
821 | * |
822 | * Before you can use this function in your JavsScript, you must have called |
823 | * user_preference_allow_ajax_update from moodlelib.php to tell Moodle that |
824 | * the udpate is allowed, and how to safely clean and submitted values. |
825 | * |
826 | * @param String name the name of the setting to udpate. |
827 | * @param String the value to set it to. |
828 | */ |
829 | function set_user_preference(name, value) { |
830 | // Don't generate a script error if the library has not been loaded, |
831 | // unless we are a Developer, in which case we want the error. |
832 | if (YAHOO && YAHOO.util && YAHOO.util.Connect || moodle_cfg.developerdebug) { |
833 | var url = moodle_cfg.wwwroot + '/lib/ajax/setuserpref.php?sesskey=' + |
834 | moodle_cfg.sesskey + '&pref=' + encodeURI(name) + '&value=' + encodeURI(value); |
835 | |
836 | // If we are a developer, ensure that failures are reported. |
837 | var callback = {}; |
838 | if (moodle_cfg.developerdebug) { |
839 | callback.failure = function() { |
840 | var a = document.createElement('a'); |
841 | a.href = url; |
842 | a.classname = 'error'; |
843 | 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.")); |
844 | document.body.insertBefore(a, document.body.firstChild); |
845 | } |
846 | } |
847 | |
848 | // Make the request. |
849 | YAHOO.util.Connect.asyncRequest('GET', url, callback); |
850 | } |
3b0bf2e4 |
851 | } |
852 | |
853 | function moodle_initialise_body() { |
854 | document.body.className += ' jsenabled'; |
f2eb5002 |
855 | } |
856 | |
857 | /** |
858 | * Oject to handle a collapsible region, see print_collapsible_region in weblib.php |
859 | * @constructor |
860 | * @param String id the HTML id for the div. |
861 | * @param String userpref the user preference that records the state of this box. false if none. |
862 | * @param Boolean startcollapsed whether the box should start collapsed. |
863 | */ |
864 | function collapsible_region(id, userpref, strtooltip) { |
865 | // Record the pref name |
866 | this.userpref = userpref; |
867 | |
868 | // Find the divs in the document. |
869 | this.div = document.getElementById(id); |
904998d8 |
870 | this.innerdiv = document.getElementById(id + '_sizer'); |
f2eb5002 |
871 | this.caption = document.getElementById(id + '_caption'); |
872 | this.caption.title = strtooltip; |
873 | |
874 | // Put the contents of caption in an <a> to make it focussable. |
875 | var a = document.createElement('a'); |
876 | while (e = this.caption.firstChild) { |
877 | a.appendChild(e); |
878 | } |
879 | a.href = '#'; |
880 | this.caption.appendChild(a); |
881 | |
882 | // Create the animation. |
883 | this.animation = new YAHOO.util.Anim(this.div, {}, 0.3, YAHOO.util.Easing.easeBoth); |
884 | |
885 | // Get to the right initial state. |
886 | if (this.div.className.match(/\bcollapsed\b/)) { |
887 | this.collapsed = true; |
e7b7583c |
888 | var self = this; |
889 | setTimeout(function() { |
890 | var region = YAHOO.util.Region.getRegion(self.caption); |
891 | self.div.style.height = (region.bottom - region.top + 3) + 'px'; |
892 | }, 10); |
f2eb5002 |
893 | } |
894 | |
895 | // Add the appropriate image. |
896 | this.icon = document.createElement('img'); |
897 | this.icon.id = id + '_icon'; |
898 | this.icon.alt = ''; |
899 | if (this.collapsed) { |
900 | this.icon.src = moodle_cfg.pixpath + '/t/collapsed.png'; |
901 | } else { |
902 | this.icon.src = moodle_cfg.pixpath + '/t/expanded.png'; |
903 | } |
c9f8e118 |
904 | a.appendChild(this.icon); |
f2eb5002 |
905 | |
906 | // Hook up the event handler. |
904998d8 |
907 | var self = this; |
f2eb5002 |
908 | YAHOO.util.Event.addListener(a, 'click', function(e) {self.handle_click(e);}); |
904998d8 |
909 | |
910 | // Handler for the animation finishing. |
911 | this.animation.onComplete.subscribe(function() {self.handle_animation_complete();}); |
f2eb5002 |
912 | } |
913 | |
914 | /** |
915 | * The user preference that stores the state of this box. |
6a208406 |
916 | * @property userpref |
f2eb5002 |
917 | * @type String |
918 | */ |
919 | collapsible_region.prototype.userpref = null; |
920 | |
921 | /** |
922 | * The key divs that make up this |
923 | * @property div, innerdiv, captiondiv |
924 | * @type HTMLDivElement |
925 | */ |
926 | collapsible_region.prototype.div = null; |
927 | collapsible_region.prototype.innerdiv = null; |
928 | collapsible_region.prototype.captiondiv = null; |
929 | |
930 | /** |
931 | * The key divs that make up this |
932 | * @property icon |
933 | * @type HTMLImageElement |
934 | */ |
935 | collapsible_region.prototype.icon = null; |
936 | |
937 | /** |
938 | * Whether the region is currently collapsed. |
939 | * @property collapsed |
940 | * @type Boolean |
941 | */ |
942 | collapsible_region.prototype.collapsed = false; |
943 | |
944 | /** |
945 | * @property animation |
946 | * @type YAHOO.util.Anim |
947 | */ |
948 | collapsible_region.prototype.animation = null; |
949 | |
904998d8 |
950 | /** When clicked, toggle the collapsed state, and trigger the animation. */ |
f2eb5002 |
951 | collapsible_region.prototype.handle_click = function(e) { |
952 | // Toggle the state. |
953 | this.collapsed = !this.collapsed; |
954 | |
955 | // Stop the click following the link. |
956 | YAHOO.util.Event.stopEvent(e); |
957 | |
958 | // Animate to the appropriate size. |
959 | if (this.animation.isAnimated()) { |
960 | this.animation.stop(); |
961 | } |
962 | if (this.collapsed) { |
c679952e |
963 | var region = YAHOO.util.Region.getRegion(this.caption); |
964 | var targetheight = region.bottom - region.top + 3; |
f2eb5002 |
965 | } else { |
c679952e |
966 | var region = YAHOO.util.Region.getRegion(this.innerdiv); |
967 | var targetheight = region.bottom - region.top + 2; |
f2eb5002 |
968 | this.div.className = this.div.className.replace(/\s*\bcollapsed\b\s*/, ' '); |
969 | } |
c679952e |
970 | this.animation.attributes.height = { to: targetheight, unit: 'px' }; |
f2eb5002 |
971 | this.animation.animate(); |
972 | |
973 | // Set the appropriate icon. |
974 | if (this.collapsed) { |
975 | this.icon.src = moodle_cfg.pixpath + '/t/collapsed.png'; |
976 | } else { |
977 | this.icon.src = moodle_cfg.pixpath + '/t/expanded.png'; |
978 | } |
979 | |
980 | // Update the user preference. |
981 | if (this.userpref) { |
982 | set_user_preference(this.userpref, this.collapsed); |
983 | } |
984 | } |
904998d8 |
985 | |
986 | /** When when the animation is finished, add the collapsed class name in relevant. */ |
987 | collapsible_region.prototype.handle_animation_complete = function() { |
988 | if (this.collapsed) { |
989 | this.div.className += ' collapsed'; |
990 | } |
b166403f |
991 | } |
992 | |
993 | /** Close the current browser window. */ |
994 | function close_window() { |
995 | window.close(); |
996 | } |
997 | |
998 | /** |
999 | * Close the current browser window, forcing the window/tab that opened this |
1000 | * popup to reload itself. */ |
1001 | function close_window_reloading_opener() { |
1002 | if (window.opener) { |
1003 | window.opener.location.reload(1); |
1004 | close_window(); |
1005 | // Intentionally, only try to close the window if there is some evidence we are in a popup. |
1006 | } |
8e7cebb0 |
1007 | } |