Fix some fallout from the pagelib changes.
[moodle.git] / lib / ajax / ajaxlib.php
CommitLineData
f72f94a2 1<?php
b2330db6 2
3// This file is part of Moodle - http://moodle.org/
4//
5// Moodle is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// Moodle is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17
18
19/**
20 * Library functions to facilitate the use of JavaScript in Moodle.
21 *
22 * @package moodlecore
23 * @copyright 2009 Tim Hunt
24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 */
26
27
28/**
29 * Initialise a page_requirements_manager with the bits of JavaScript that every
30 * Moodle page needs.
31 *
32 * @param page_requirements_manager $requires The page_requirements_manager to initialise.
33 */
34function setup_core_javascript(page_requirements_manager $requires) {
35 global $CFG;
36
37 // JavaScript should always work with $CFG->httpswwwroot rather than $CFG->wwwroot.
38 // Otherwise, in some situations, users will get warnings about insecure content
39 // on sercure pages from their web browser.
40
41 $config = array(
42 'wwwroot' => $CFG->httpswwwroot, // Yes, really. See above.
43 'pixpath' => $CFG->pixpath,
44 'modpixpath' => $CFG->modpixpath,
45 'sesskey' => sesskey(),
46 );
47 if (debugging('', DEBUG_DEVELOPER)) {
48 $config['developerdebug'] = true;
49 }
50 $requires->data_for_js('moodle_cfg', $config)->in_head();
51
52 // Note that, as a short-cut, the code
53 // $js = "document.body.className += ' jsenabled';\n";
54 // is hard-coded in @see{page_requirements_manager::get_top_of_body_code}.
55}
56
57
58/**
59 * This class tracks all the things that are needed by the current page.
60 *
61 * Normally, the only instance of this class you will need to work with is the
62 * one accessible via $PAGE->requires.
63 *
64 * Typical useage would be
65 * $PAGE->requires->css('mod/mymod/styles.css');
66 * $PAGE->requires->js('mod/mymod/script.js');
67 * $PAGE->requires->js('mod/mymod/small_but_urgent.js')->in_head();
68 * $PAGE->requires->js_function_call('init_mymod', array($data))->on_dom_ready();
69 *
70 * @copyright 2009 Tim Hunt
71 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
72 */
73class page_requirements_manager {
74 const WHEN_IN_HEAD = 0;
75 const WHEN_TOP_OF_BODY = 10;
76 const WHEN_AT_END = 20;
77 const WHEN_ON_DOM_READY = 30;
78
79 protected $linkedrequiremets = array();
80 protected $stringsforjs = array();
81 protected $requiredjscode = array();
82
83 protected $variablesinitialised = array('mstr' => 1); // 'mstr' is special. See string_for_js.
84
85 protected $headdone = false;
86 protected $topofbodydone = false;
87
88 /**
89 * Ensure that the specified script file is linked to from this page. By default
90 * the link is put at the end of the page, since this gives best load performance.
91 *
92 * Even if a particular script is requested more than once, it will only be linked
93 * to once.
94 *
95 * @param $jsfile The path to the .js file, relative to $CFG->dirroot / $CFG->wwwroot.
96 * No leading slash. For example 'mod/mymod/customscripts.js';
97 * @param boolean $fullurl This parameter is intended for internal use only.
98 * (If true, $jsfile is treaded as a full URL, not relative $CFG->wwwroot.)
99 * @return required_js A required_js object. This allows you to control when the
100 * link to the script is output by calling methods like ->asap() or
101 * ->in_head().
102 */
103 public function js($jsfile, $fullurl = false) {
104 global $CFG;
105 if (!$fullurl) {
106 if (!file_exists($CFG->dirroot . '/' . $jsfile)) {
107 throw new coding_exception('Attept to require a JavaScript file that does not exist.', $jsfile);
108 }
109 $url = $CFG->httpswwwroot . '/' . $jsfile;
110 } else {
111 $url = $jsfile;
112 }
113 if (!isset($this->linkedrequiremets[$url])) {
114 $this->linkedrequiremets[$url] = new required_js($this, $url);
115 }
116 return $this->linkedrequiremets[$url];
117 }
118
119 /**
120 * Ensure that the specified YUI library file, and all its required dependancies,
121 * are linked to from this page. By default the link is put at the end of the
122 * page, since this gives best load performance. Optional dependencies are not
123 * loaded automatically - if you want them you will need to load them first with
124 * other calls to this method.
125 *
126 * If the YUI library you ask for requires one or more CSS files, and if
127 * &lt;head> has already been printed, then an exception will be thrown.
128 *
129 * Even if a particular library is requested more than once (perhaps as a dependancy
130 * of other libraries) it will only be linked to once.
131 *
132 * @param $libname the name of the YUI library you require. For example 'autocomplete'.
133 * @return required_yui_lib A requried_yui_lib object. This allows you to control when the
134 * link to the script is output by calling methods like ->asap() or
135 * ->in_head().
136 */
137 public function yui_lib($libname) {
138 $key = 'yui:' . $libname;
139 if (!isset($this->linkedrequiremets[$key])) {
140 $this->linkedrequiremets[$key] = new required_yui_lib($this, $libname);
141 }
142 return $this->linkedrequiremets[$key];
143 }
144
145 /**
146 * Ensure that the specified CSS file is linked to from this page. Because
147 * stylesheet links must go in the &lt;head> part of the HTML, you must call
148 * this function before get_head_code is called. That normally means before
149 * the call to print_header. If you call it when it is too late, an exception
150 * will be thrown.
151 *
152 * Even if a particular style sheet is requested more than once, it will only
153 * be linked to once.
154 *
155 * @param string $stylesheet The path to the .js file, relative to
156 * $CFG->dirroot / $CFG->wwwroot. No leading slash. For example
157 * 'mod/mymod/styles.css';
158 * @param boolean $fullurl This parameter is intended for internal use only.
159 * (If true, $stylesheet is treaded as a full URL, not relative $CFG->wwwroot.)
160 */
161 public function css($stylesheet, $fullurl = false) {
162 global $CFG;
163
164 if ($this->headdone) {
165 throw new coding_exception('Cannot require a CSS file after <head> has been printed.', $stylesheet);
166 }
167 if (!$fullurl) {
168 if (!file_exists($CFG->dirroot . '/' . $stylesheet)) {
169 throw new coding_exception('Attept to require a CSS file that does not exist.', $stylesheet);
170 }
171 $url = $CFG->httpswwwroot . '/' . $stylesheet;
172 } else {
173 $url = $stylesheet;
174 }
175 if (!isset($this->linkedrequiremets[$url])) {
176 $this->linkedrequiremets[$url] = new required_css($this, $url);
177 }
178 }
179
180 /**
181 * Ensure that a skip link to a given target is printed at the top of the &lt;body>.
182 * You must call this function before get_top_of_body_code, (if not, an exception
183 * will be thrown). That normally means you must call this before the call to print_header.
184 *
185 * If you ask for a particular skip link to be printed, it is then your responsibility
186 * to ensure that the appropraite &lt;a name="..."> tag is printed in the body of the
187 * page, so that the skip link goes somewhere.
188 *
189 * Even if a particular skip link is requested more than once, only one copy of it will be output.
190 *
191 * @param $target the name of anchor this link should go to. For example 'maincontent'.
192 * @param $linktext The text to use for the skip link. Normally get_string('skipto', 'access', ...);
193 */
194 public function skip_link_to($target, $linktext) {
195 if (!isset($this->linkedrequiremets[$target])) {
196 $this->linkedrequiremets[$target] = new required_skip_link($this, $target, $linktext);
197 }
198 }
199
200 /**
201 * Ensure that the specified JavaScript function is called from an inline script
202 * somewhere on this page. By default the call will be put in a script tag at the
203 * end of the page, since this gives best page-load performance.
204 *
205 * If you request that a particular function is called several times, then
206 * that is what will happen (unlike linking to a CSS or JS file, where only
207 * one link will be output).
208 *
209 * @param string $function the name of the JavaScritp function to call. Can
210 * be a compound name like 'YAHOO.util.Event.addListener'.
211 * @param array $arguments and array of arguments to be passed to the function.
212 * When generating the function call, this will be escaped using json_encode,
213 * so passing objects and arrays should work.
214 * @return required_js_function_call A required_js_function_call object.
215 * This allows you to control when the link to the script is output by
216 * calling methods like ->asap(), ->in_head(), ->at_top_of_body() or
217 * ->on_dom_ready() methods.
218 */
219 public function js_function_call($function, $arguments = array()) {
220 $requirement = new required_js_function_call($this, $function, $arguments);
221 $this->requiredjscode[] = $requirement;
222 return $requirement;
223 }
224
225 /**
226 * Make a language string available to JavaScript. All the strings will be
227 * available in a mstr object in the global namespace. So, for example,
228 * after a call to $PAGE->requires->string_for_js('course', 'moodle');
229 * then the JavaScript variable mstr.moodle.course will be 'Course', or the
230 * equivalent in the current language.
231 *
232 * The arguments to this function are just like the arguments to get_string
233 * except that $module is not optional, and there are limitations on how you
234 * use $a. Because each string is only stored once in the JavaScript (based
235 * on $identifier and $module) you cannot get the same string with two different
236 * values of $a. If you try, an exception will be thrown.
237 *
238 * If you do need the same string expanded with different $a values, then
239 * the solution is to put them in your own data structure (e.g. and array)
240 * that you pass to JavaScript with @see{data_for_js}.
241 *
242 * @param string $identifier the desired string.
243 * @param string $module the language file to look in.
244 * @param mixed $a any extra data to add into the string (optional).
245 */
246 public function string_for_js($identifier, $module, $a = NULL) {
247 $string = get_string($identifier, $module, $a);
248 if (!$module) {
249 $module = 'moodle';
250 }
251 if (isset($this->stringsforjs[$module][$identifier]) && $this->stringsforjs[$module][$identifier] != $string) {
252 throw new coding_exception("Attempt to re-define already required string '$identifier' " .
253 "from lang file '$module'. Did you already ask for it with a different \$a?");
254 }
255 $this->stringsforjs[$module][$identifier] = $string;
256 }
257
258 /**
259 * Make some data from PHP available to JavaScript code. For example, if you call
260 * $PAGE->requires->data_for_js('mydata', array('name' => 'Moodle'));
261 * then in JavsScript mydata.name will be 'Moodle'.
262 *
263 * You cannot call this function more than once with the same variable name
264 * (if you try, it will throw an exception). Your code should prepare all the
265 * date you want, and then pass it to this method. There is no way to change
266 * the value associated with a particular variable later.
267 *
268 * @param string $variable the the name of the JavaScript variable to assign the data to.
269 * Will probably work if you use a compound name like 'mybuttons.button[1]', but this
270 * should be considered an experimental feature.
271 * @param mixed $data The data to pass to JavaScript. This will be escaped using json_encode,
272 * so passing objects and arrays should work.
273 * @return required_data_for_js A required_data_for_js object.
274 * This allows you to control when the link to the script is output by
275 * calling methods like ->asap(), ->in_head(), ->at_top_of_body() or
276 * ->on_dom_ready() methods.
277 */
278 public function data_for_js($variable, $data) {
279 if (isset($this->variablesinitialised[$variable])) {
280 throw new coding_exception("A variable called '" . $variable .
281 "' has already been passed ot JavaScript. You cannot overwrite it.");
282 }
283 $requirement = new required_data_for_js($this, $variable, $data);
284 $this->requiredjscode[] = $requirement;
285 $this->variablesinitialised[$variable] = 1;
286 return $requirement;
287 }
288
289 /**
290 * Get the code for the linked resources that need to appear in a particular place.
291 * @param $when one of the WHEN_... constants.
292 * @return string the HTML that should be output in that place.
293 */
294 protected function get_linked_resources_code($when) {
295 $output = '';
296 foreach ($this->linkedrequiremets as $requirement) {
297 if (!$requirement->is_done() && $requirement->get_when() == $when) {
298 $output .= $requirement->get_html();
299 $requirement->mark_done();
300 }
301 }
302 return $output;
303 }
304
305 /**
306 * Get the code for the linked resources that need to appear in a particular place.
307 * @param $when one of the WHEN_... constants.
308 * @return string the javascript that should be output in that place.
309 */
310 protected function get_javascript_code($when, $indent = '') {
311 $output = '';
312 foreach ($this->requiredjscode as $requirement) {
313 if (!$requirement->is_done() && $requirement->get_when() == $when) {
314 $output .= $indent . $requirement->get_js_code();
315 $requirement->mark_done();
316 }
317 }
318 return $output;
319 }
320
321 /**
322 * Generate any HTML that needs to go inside the &lt;head> tag.
323 *
324 * @return string the HTML code to to inside the &lt;head> tag.
325 */
326 public function get_head_code() {
327 $output = $this->get_linked_resources_code(self::WHEN_IN_HEAD);
328 $js = $this->get_javascript_code(self::WHEN_IN_HEAD);
329 $output .= ajax_generate_script_tag($js);
330 $this->headdone = true;
331 return $output;
332 }
333
334 /**
335 * Generate any HTML that needs to go at the start of the &lt;body> tag.
336 *
337 * @return string the HTML code to go at the start of the &lt;body> tag.
338 */
339 public function get_top_of_body_code() {
340 $output = $this->get_linked_resources_code(self::WHEN_TOP_OF_BODY);
341 $js = "document.body.className += ' jsenabled';\n";
342 $js .= $this->get_javascript_code(self::WHEN_TOP_OF_BODY);
343 $output .= ajax_generate_script_tag($js);
344 $this->topofbodydone = true;
345 return $output;
346 }
347
348 /**
349 * Generate any HTML that needs to go at the end of the page.
350 *
351 * @return string the HTML code to to at the end of the page.
352 */
353 public function get_end_code() {
354 $output = $this->get_linked_resources_code(self::WHEN_AT_END);
355
356 array_unshift($this->requiredjscode, new required_data_for_js($this, 'mstr', $this->stringsforjs));
357 $js = $this->get_javascript_code(self::WHEN_AT_END);
358
359 $ondomreadyjs = $this->get_javascript_code(self::WHEN_ON_DOM_READY, ' ');
360 if ($ondomreadyjs) {
361 $js .= "YAHOO.util.Event.onDOMReady(function() {\n" . $ondomreadyjs . "});\n";
362 }
363
364 $output .= ajax_generate_script_tag($js);
365
366 return $output;
367 }
368
369 /**
370 * Have we already output the code in the <lt;head> tag?
371 *
372 * @return boolean
373 */
374 public function is_head_done() {
375 return $this->headdone;
376 }
377
378 /**
379 * Have we already output the code at the start of the <lt;body> tag?
380 *
381 * @return boolean
382 */
383 public function is_top_of_body_done() {
384 return $this->topofbodydone;
385 }
386}
387
388
389/**
390 * This is the base class for all sorts of requirements. just to factor out some
391 * common code.
392 *
393 * @copyright 2009 Tim Hunt
394 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
395 */
396abstract class requirement_base {
397 protected $manager;
398 protected $when;
399 protected $done = false;
400
401 /**
402 * Constructor. Normally the class and its subclasses should not be created
403 * directly. Client code should create them via a page_requirements_manager
404 * method like ->js(...).
405 *
406 * @param page_requirements_manager $manager the page_requirements_manager we are associated with.
407 */
408 protected function __construct(page_requirements_manager $manager) {
409 $this->manager = $manager;
410 }
411
412 /**
413 * Mark that this requirement has been satisfied (that is, that the HTML
414 * returned by @see{get_html} has been output.
415 * @return boolean has this requirement been satisfied yet? That is, has
416 * that the HTML returned by @see{get_html} has been output already.
417 */
418 public function is_done() {
419 return $this->done;
420 }
421
422 /**
423 * Mark that this requirement has been satisfied (that is, that the HTML
424 * returned by @see{get_html} has been output.
425 */
426 public function mark_done() {
427 $this->done = true;
428 }
429
430 /**
431 * Where on the page the HTML this requirement is meant to go.
432 * @return integer One of the page_requirements_manager::WHEN_... constants.
433 */
434 public function get_when() {
435 return $this->when;
436 }
437}
438
439/**
440 * This class represents something that must be output somewhere in the HTML.
441 *
442 * Examples include links to JavaScript or CSS files. However, it should not
443 * necessarily be output immediately, we may have to wait for an appropriate time.
444 *
445 * @copyright 2009 Tim Hunt
446 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
447 */
448abstract class linked_requirement extends requirement_base {
449 protected $url;
450
451 /**
452 * Constructor. Normally the class and its subclasses should not be created
453 * directly. Client code should create them via a page_requirements_manager
454 * method like ->js(...).
455 *
456 * @param page_requirements_manager $manager the page_requirements_manager we are associated with.
457 * @param string $url The URL of the thing we are linking to.
458 */
459 protected function __construct(page_requirements_manager $manager, $url) {
460 parent::__construct($manager);
461 $this->url = $url;
462 }
463
464 /**
465 * @return string the HTML needed to satisfy this requirement.
466 */
467 abstract public function get_html();
468}
469
470
471/**
472 * A subclass of @see{linked_requirement} to represent a requried JavaScript file.
473 *
474 * You should not create instances of this class directly. Instead you should
475 * work with a @see{page_requirements_manager} - and probably the only
476 * page_requirements_manager you will ever need is the one at $PAGE->requires.
477 *
478 * The methods ->asap, ->in_head and at_top_of_body() are indented to be used
479 * as a fluid API, so you can say things like
480 * $PAGE->requires->js('mod/mymod/script.js')->in_head();
481 *
482 * However, by default JavaScript files are included at the end of the HTML.
483 * This is recommended practice because it means that the web browser will only
484 * start loading the javascript files after the rest of the page is loaded, and
485 * that gives the best performance for users.
486 *
487 * @copyright 2009 Tim Hunt
488 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
489 */
490class required_js extends linked_requirement {
491 /**
492 * Constructor. Normally instances of this class should not be created
493 * directly. Client code should create them via the page_requirements_manager
494 * method ->js(...).
495 *
496 * @param page_requirements_manager $manager the page_requirements_manager we are associated with.
497 * @param string $url The URL of the JavaScript file we are linking to.
498 */
499 public function __construct(page_requirements_manager $manager, $url) {
500 parent::__construct($manager, $url);
501 $this->when = page_requirements_manager::WHEN_AT_END;
502 }
503
504 public function get_html() {
505 return '<script type="text/javascript" src="' . $this->url . '"></script>' . "\n";
506 }
507
508 /**
509 * Indicate that the link to this JavaScript file should be output as soon as
510 * possible. That is, if this requirement has already been output, this method
511 * does nothing. Otherwise, if the &lt;head> tag has not yet been printed, the link
512 * to this script will be put in &lt;head>. Otherwise, this method returns a
513 * fragment of HTML that the caller is responsible for outputting as soon as
514 * possible. In fact, it is recommended that you only call this function from
515 * an echo statement, like:
516 * echo $PAGE->requires->js(...)->asap();
517 *
518 * @return string The HTML required to include this JavaScript file. The caller
519 * is responsible for outputting this HTML promptly.
520 */
521 public function asap() {
522 if ($this->is_done()) {
523 return;
524 }
525 if (!$this->manager->is_head_done()) {
526 $this->in_head();
527 return '';
528 }
529 $ouput = $this->get_html();
530 $this->mark_done();
531 return $ouput;
532 }
533
534 /**
535 * Indicate that the link to this JavaScript file should be output in the
536 * &lt;head> section of the HTML. If it too late for this request to be
537 * satisfied, an exception is thrown.
538 */
539 public function in_head() {
540 if ($this->is_done() || $this->when <= page_requirements_manager::WHEN_IN_HEAD) {
541 return;
542 }
543 if ($this->manager->is_head_done()) {
544 throw new coding_exception('Too late to ask for a JavaScript file to be linked to from &lt;head>.');
545 }
546 $this->when = page_requirements_manager::WHEN_IN_HEAD;
547 }
548
549 /**
550 * Indicate that the link to this JavaScript file should be output at the top
551 * of the &lt;body> section of the HTML. If it too late for this request to be
552 * satisfied, an exception is thrown.
553 */
554 public function at_top_of_body() {
555 if ($this->is_done() || $this->when <= page_requirements_manager::WHEN_TOP_OF_BODY) {
556 return;
557 }
558 if ($this->manager->is_top_of_body_done()) {
559 throw new coding_exception('Too late to ask for a JavaScript file to be linked to from the top of &lt;body>.');
560 }
561 $this->when = page_requirements_manager::WHEN_TOP_OF_BODY;
562 }
563}
564
565
f72f94a2 566/**
b2330db6 567 * A subclass of @see{linked_requirement} to represent a requried YUI library.
568 *
569 * You should not create instances of this class directly. Instead you should
570 * work with a @see{page_requirements_manager} - and probably the only
571 * page_requirements_manager you will ever need is the one at $PAGE->requires.
572 *
573 * The methods ->asap, ->in_head and at_top_of_body() are indented to be used
574 * as a fluid API, so you can say things like
575 * $PAGE->requires->yui_lib('autocomplete')->in_head();
576 *
577 * This class (with the help of @see{ajax_resolve_yui_lib}) knows about the
578 * dependancies between the different YUI libraries, and will include all the
579 * other libraries required by the one you ask for. It also knows which YUI
580 * libraries require css files. If the library you ask for requires CSS files,
581 * then you should ask for it before &lt;head> is output, or an exception will
582 * be thrown.
583 *
584 * By default JavaScript files are included at the end of the HTML.
585 * This is recommended practice because it means that the web browser will only
586 * start loading the javascript files after the rest of the page is loaded, and
587 * that gives the best performance for users.
588 *
589 * @copyright 2009 Tim Hunt
590 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
f72f94a2 591 */
b2330db6 592class required_yui_lib extends linked_requirement {
593 protected $jss = array();
594 protected $cssurls;
595
596 /**
597 * Constructor. Normally instances of this class should not be created
598 * directly. Client code should create them via the page_requirements_manager
599 * method ->yui_lib(...).
600 *
601 * @param page_requirements_manager $manager the page_requirements_manager we are associated with.
602 * @param string $libname The name of the YUI library you want. See the array
603 * defined in @see{ajax_resolve_yui_lib} for a list of known libraries.
604 */
605 public function __construct(page_requirements_manager $manager, $libname) {
606 parent::__construct($manager, '');
607 $this->when = page_requirements_manager::WHEN_AT_END;
608
609 list($jsurls, $this->cssurls) = ajax_resolve_yui_lib($libname);
610 foreach ($jsurls as $jsurl) {
611 $this->jss[] = $manager->js($jsurl, true);
612 }
613 foreach ($this->cssurls as $cssurl) {
614 $manager->css($cssurl, true);
615 }
616 if (!empty($this->cssurls)) {
617 global $PAGE;
618 $page->add_body_class('yui-skin-sam');
619 }
620 }
621
622 public function get_html() {
623 // Since we create a required_js for each of our files, that will generate the HTML.
624 return '';
625 }
626
627 /**
628 * Indicate that the link to this YUI library file should be output as soon as
629 * possible. The comment above @see{required_js::asap} applies to this method too.
630 *
631 * @return string The HTML required to include this JavaScript file. The caller
632 * is responsible for outputting this HTML promptly. For example, a good way to
633 * call this method is like
634 * echo $PAGE->requires->yui_lib(...)->asap();
635 */
636 public function asap() {
637 if ($this->is_done()) {
638 return;
639 }
640
641 if (!$this->manager->is_head_done()) {
642 $this->in_head();
643 return '';
644 }
645
646 $ouput = '';
647 foreach ($this->jss as $requiredjs) {
648 $ouput .= $requiredjs->immediately();
649 }
650 $this->mark_done();
651 return $ouput;
652 }
653
654 /**
655 * Indicate that the links to this YUI library should be output in the
656 * &lt;head> section of the HTML. If it too late for this request to be
657 * satisfied, an exception is thrown.
658 */
659 public function in_head() {
660 if ($this->is_done() || $this->when <= page_requirements_manager::WHEN_IN_HEAD) {
661 return;
662 }
663
664 if ($this->manager->is_head_done()) {
665 throw new coding_exception('Too late to ask for a YUI library to be linked to from &lt;head>.');
666 }
667
668 $this->when = page_requirements_manager::WHEN_IN_HEAD;
669 foreach ($this->jss as $requiredjs) {
670 $ouput .= $requiredjs->in_head();
671 }
672 }
673
674 /**
675 * Indicate that the links to this YUI library should be output in the
676 * &lt;head> section of the HTML. If it too late for this request to be
677 * satisfied, an exception is thrown.
678 */
679 public function at_top_of_body() {
680 if ($this->is_done() || $this->when <= page_requirements_manager::WHEN_TOP_OF_BODY) {
681 return;
682 }
683
684 if ($this->manager->is_top_of_body_done()) {
685 throw new coding_exception('Too late to ask for a YUI library to be linked to from the top of &lt;body>.');
686 }
687
688 $this->when = page_requirements_manager::WHEN_TOP_OF_BODY;
689 foreach ($this->jss as $requiredjs) {
690 $ouput .= $requiredjs->at_top_of_body();
691 }
692 }
693}
694
695
696/**
697 * A subclass of @see{linked_requirement} to represent a required CSS file.
698 * Of course, all links to CSS files must go in the &lt;head section of the HTML.
699 *
700 * @copyright 2009 Tim Hunt
701 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
702 */
703class required_css extends linked_requirement {
704 /**
705 * Constructor. Normally instances of this class should not be created
706 * directly. Client code should create them via the page_requirements_manager
707 * method ->css(...).
708 *
709 * @param page_requirements_manager $manager the page_requirements_manager we are associated with.
710 * @param string $url The URL of the CSS file we are linking to.
711 */
712 public function __construct(page_requirements_manager $manager, $url) {
713 parent::__construct($manager, $url);
714 $this->when = page_requirements_manager::WHEN_IN_HEAD;
715 }
716
717 public function get_html() {
718 return '<link rel="stylesheet" type="text/css" href="' . $this->url . '" />' . "\n";;
719 }
720}
721
722
723/**
724 * A subclass of @see{linked_requirement} to represent a skip link.
725 * A skip link is a concept from accessibility. You have some links like
726 * 'Skip to main content' linking to an #maincontent anchor, at the start of the
727 * &lt;body> tag, so that users using assistive technologies like screen readers
728 * can easily get to the main content without having to work their way through
729 * any navigation, blocks, etc. that comes before it in the HTML.
730 *
731 * @copyright 2009 Tim Hunt
732 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
733 */
734class required_skip_link extends linked_requirement {
735 protected $linktext;
736
737 /**
738 * Constructor. Normally instances of this class should not be created
739 * directly. Client code should create them via the page_requirements_manager
740 * method ->yui_lib(...).
741 *
742 * @param page_requirements_manager $manager the page_requirements_manager we are associated with.
743 * @param string $target the name of the anchor in the page we are linking to.
744 * @param string $linktext the test to use for the link.
745 */
746 public function __construct(page_requirements_manager $manager, $target, $linktext) {
747 parent::__construct($manager, $target);
748 $this->when = page_requirements_manager::WHEN_TOP_OF_BODY;
749 $this->linktext = $linktext;
750 }
751
752 public function get_html() {
753 return '<a class="skip" href="#' . $this->url . '">' . $this->linktext . "</a>\n";
754 }
755}
756
757
758/**
759 * This is the base class for requirements that are JavaScript code.
760 *
761 * @copyright 2009 Tim Hunt
762 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
763 */
764abstract class required_js_code extends requirement_base {
765
766 /**
767 * Constructor. Normally the class and its subclasses should not be created
768 * directly. Client code should create them via a page_requirements_manager
769 * method like ->js(...).
770 *
771 * @param page_requirements_manager $manager the page_requirements_manager we are associated with.
772 */
773 protected function __construct(page_requirements_manager $manager) {
774 parent::__construct($manager);
775 $this->when = page_requirements_manager::WHEN_AT_END;
776 }
777
778 /**
779 * @return string the JavaScript code needed to satisfy this requirement.
780 */
781 abstract public function get_js_code();
782
783 /**
784 * Indicate that the link to this JavaScript file should be output as soon as
785 * possible. That is, if this requirement has already been output, this method
786 * does nothing. Otherwise, if the &lt;head> tag has not yet been printed, the link
787 * to this script will be put in &lt;head>. Otherwise, this method returns a
788 * fragment of HTML that the caller is responsible for outputting as soon as
789 * possible. In fact, it is recommended that you only call this function from
790 * an echo statement, like:
791 * echo $PAGE->requires->js(...)->asap();
792 *
793 * @return string The HTML required to include this JavaScript file. The caller
794 * is responsible for outputting this HTML promptly.
795 */
796 public function asap() {
797 if ($this->is_done()) {
798 return;
799 }
800 if (!$this->manager->is_head_done()) {
801 $this->in_head();
802 return '';
803 }
804 $js = $this->get_js_code();
805 $output = ajax_generate_script_tag($js);
806 $this->mark_done();
807 return $output;
808 }
809
810 /**
811 * Indicate that the link to this JavaScript file should be output in the
812 * &lt;head> section of the HTML. If it too late for this request to be
813 * satisfied, an exception is thrown.
814 */
815 public function in_head() {
816 if ($this->is_done() || $this->when <= page_requirements_manager::WHEN_IN_HEAD) {
817 return;
818 }
819 if ($this->manager->is_head_done()) {
820 throw new coding_exception('Too late to ask for some JavaScript code to be output in &lt;head>.');
821 }
822 $this->when = page_requirements_manager::WHEN_IN_HEAD;
823 }
824
825 /**
826 * Indicate that the link to this JavaScript file should be output at the top
827 * of the &lt;body> section of the HTML. If it too late for this request to be
828 * satisfied, an exception is thrown.
829 */
830 public function at_top_of_body() {
831 if ($this->is_done() || $this->when <= page_requirements_manager::WHEN_TOP_OF_BODY) {
832 return;
833 }
834 if ($this->manager->is_top_of_body_done()) {
835 throw new coding_exception('Too late to ask for some JavaScript code to be output at the top of &lt;body>.');
836 }
837 $this->when = page_requirements_manager::WHEN_TOP_OF_BODY;
838 }
839}
840
841
842/**
843 * This class represents a JavaScript function that must be called from the HTML
844 * page. By default the call will be made at the end of the page, but you can
845 * chage that using the ->asap, ->in_head, etc. methods.
846 *
847 * @copyright 2009 Tim Hunt
848 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
849 */
850class required_js_function_call extends required_js_code {
851 protected $function;
852 protected $arguments;
853
854 /**
855 * Constructor. Normally the class and its subclasses should not be created
856 * directly. Client code should create them via the page_requirements_manager
857 * method ->js_function_call(...).
858 *
859 * @param page_requirements_manager $manager the page_requirements_manager we are associated with.
860 * @param string $function the name of the JavaScritp function to call.
861 * Can be a compound name like 'YAHOO.util.Event.addListener'.
862 * @param array $arguments and array of arguments to be passed to the function.
863 * When generating the function call, this will be escaped using json_encode,
864 * so passing objects and arrays should work.
865 */
866 public function __construct(page_requirements_manager $manager, $function, $arguments) {
867 parent::__construct($manager);
868 $this->function = $function;
869 $this->arguments = $arguments;
870 }
871
872 public function get_js_code() {
873 $quotedargs = array();
874 foreach ($this->arguments as $arg) {
875 $quotedargs[] = json_encode($arg);
876 }
877 return $this->function . '(' . implode(', ', $quotedargs) . ");\n";
878 }
879
880 /**
881 * Indicate that this function should be called in YUI's onDomReady event.
882 *
883 * Not that this is probably not necessary most of the time. Just having the
884 * function call at the end of the HTML should normally be sufficient.
885 */
886 public function on_dom_ready() {
887 if ($this->is_done() || $this->when < page_requirements_manager::WHEN_AT_END) {
888 return;
889 }
890 $this->manager->yui_lib('event');
891 $this->when = page_requirements_manager::WHEN_ON_DOM_READY;
892 }
893}
894
895
896/**
897 * This class represents some data from PHP that needs to be made available in a
898 * global JavaScript variable. By default the data will be output at the end of
899 * the page, but you can chage that using the ->asap, ->in_head, etc. methods.
900 *
901 * @copyright 2009 Tim Hunt
902 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
903 */
904class required_data_for_js extends required_js_code {
905 protected $variable;
906 protected $data;
907
908 /**
909 * Constructor. Normally the class and its subclasses should not be created
910 * directly. Client code should create them via the page_requirements_manager
911 * method ->data_for_js(...).
912 *
913 * @param page_requirements_manager $manager the page_requirements_manager we are associated with.
914 * @param string $variable the the name of the JavaScript variable to assign the data to.
915 * Will probably work if you use a compound name like 'mybuttons.button[1]', but this
916 * should be considered an experimental feature.
917 * @param mixed $data The data to pass to JavaScript. This will be escaped using json_encode,
918 * so passing objects and arrays should work.
919 */
920 public function __construct(page_requirements_manager $manager, $variable, $data) {
921 parent::__construct($manager);
922 $this->variable = $variable;
923 $this->data = json_encode($data);
924 // json_encode immediately, so that if $data is an object (and therefore was
925 // passed in by reference) we get the data at the time the call was made, and
926 // not whatever the data happened to be when this is output.
927 }
928
929 public function get_js_code() {
930 $prefix = 'var ';
931 if (strpos($this->variable, '.') || strpos($this->variable, '[')) {
932 $prefix = '';
933 }
934 return $prefix . $this->variable . ' = ' . $this->data . ";\n";
935 }
936}
937
938
939/**
940 * Generate a script tag containing the the specified code.
941 *
942 * @param string $js the JavaScript code
943 * @return string HTML, the code wrapped in <script> tags.
944 */
945function ajax_generate_script_tag($js) {
946 return '<script type="text/javascript">' . "\n//<![CDATA[\n" .
947 $js . "//]]>\n</script>\n";
948}
949
950
951/**
952 * Given the name of a YUI library, return a list of the .js and .css files that
953 * it requries.
954 *
955 * This method takes note of the $CFG->useexternalyui setting.
956 *
957 * If $CFG->debug is set to DEBUG_DEVELOPER then this method will return links to
958 * the -debug version of the YUI files, otherwise it will return links to the -min versions.
959 *
960 * @param string $libname the name of a YUI library, for example 'autocomplete'.
961 * @return array with two elementes. The first is an array of the JavaScript URLs
962 * that must be loaded to make this library work, in the order they should be
963 * loaded. The second element is a (possibly empty) list of CSS files that
964 * need to be loaded.
965 */
966function ajax_resolve_yui_lib($libname) {
967 global $CFG;
968
969 // Note, we always use yahoo-dom-event, even if we are only asked for part of it.
970 // because another part of the code may later ask for other bits. It is easier, and
971 // not very inefficient, just to always use (and get browsers to cache) the combined file.
972 static $translatelist = array(
973 'yahoo' => 'yahoo-dom-event',
974 'animation' => array('yahoo-dom-event', 'animation'),
975 'autocomplete' => array(
976 'js' => array('yahoo-dom-event', 'datasource', 'autocomplete'),
977 'css' => array('autocomplete/assets/skins/sam/autocomplete.css')),
978 'button' => array(
979 'js' => array('yahoo-dom-event', 'element', 'button'),
980 'css' => array('button/assets/skins/sam/button.css')),
981 'calendar' => array(
982 'js' => array('yahoo-dom-event', 'calendar'),
983 'css' => array('calendar/assets/skins/sam/calendar.css')),
984 'carousel' => array(
985 'js' => array('yahoo-dom-event', 'element', 'carousel'),
986 'css' => array('carousel/assets/skins/sam/carousel.css')),
987 'charts' => array('yahoo-dom-event', 'element', 'datasource', 'json', 'charts'),
988 'colorpicker' => array(
989 'js' => array('utilities', 'slider', 'colorpicker'),
990 'css' => array('colorpicker/assets/skins/sam/colorpicker.css')),
991 'connection' => array('yahoo-dom-event', 'connection'),
992 'container' => array(
993 'js' => array('yahoo-dom-event', 'container'),
994 'css' => array('container/assets/skins/sam/container.css')),
995 'cookie' => array('yahoo-dom-event', 'cookie'),
996 'datasource' => array('yahoo-dom-event', 'datasource'),
997 'datatable' => array(
998 'js' => array('yahoo-dom-event', 'element', 'datasource', 'datatable'),
999 'css' => array('datatable/assets/skins/sam/datatable.css')),
1000 'dom' => 'yahoo-dom-event',
1001 'dom-event' => 'yahoo-dom-event',
1002 'dragdrop' => array('yahoo-dom-event', 'dragdrop'),
1003 'editor' => array(
1004 'js' => array('yahoo-dom-event', 'element', 'container', 'menu', 'button', 'editor'),
1005 'css' => array('assets/skins/sam/skin.css')),
1006 'element' => array('yahoo-dom-event', 'element'),
1007 'event' => 'yahoo-dom-event',
1008 'get' => array('yahoo-dom-event', 'get'),
1009 'history' => array('yahoo-dom-event', 'history'),
1010 'imagecropper' => array(
1011 'js' => array('yahoo-dom-event', 'dragdrop', 'element', 'resize', 'imagecropper'),
1012 'css' => array('assets/skins/sam/resize.css', 'assets/skins/sam/imagecropper.css')),
1013 'imageloader' => array('yahoo-dom-event', 'imageloader'),
1014 'json' => array('yahoo-dom-event', 'json/json'),
1015 'layout' => array(
1016 'js' => array('yahoo-dom-event', 'dragdrop', 'element', 'layout'),
1017 'css' => array('reset-fonts-grids/reset-fonts-grids.css', 'assets/skins/sam/layout.css')),
1018 'logger' => array(
1019 'js' => array('yahoo-dom-event', 'logger'),
1020 'css' => array('logger/assets/skins/sam/logger.css')),
1021 'menu' => array(
1022 'js' => array('yahoo-dom-event', 'container', 'menu'),
1023 'css' => array('menu/assets/skins/sam/menu.css')),
1024 'paginator' => array(
1025 'js' => array('yahoo-dom-event', 'element', 'paginator'),
1026 'css' => array('paginator/assets/skins/sam/paginator.css')),
1027 'profiler' => array('yahoo-dom-event', 'profiler'),
1028 'profilerviewer' => array('yuiloader-dom-event', 'element', 'profiler', 'profilerviewer'),
1029 'resize' => array(
1030 'js' => array('yahoo-dom-event', 'dragdrop', 'element', 'resize'),
1031 'css' => array('assets/skins/sam/resize.css')),
1032 'selector' => array('yahoo-dom-event', 'selector'),
1033 'simpleeditor' => array(
1034 'js' => array('yahoo-dom-event', 'element', 'container', 'simpleeditor'),
1035 'css' => array('assets/skins/sam/skin.css')),
1036 'slider' => array('yahoo-dom-event', 'gragdrop', 'slider'),
1037 'stylesheet' => array('yahoo-dom-event', 'stylesheet'),
1038 'tabview' => array(
1039 'js' => array('yahoo-dom-event', 'element', 'tabview'),
1040 'css' => array('assets/skins/sam/skin.css')),
1041 'treeview' => array(
1042 'js' => array('yahoo-dom-event', 'treeviewed'),
1043 'css' => array('treeview/assets/skins/sam/treeview.css')),
1044 'uploader' => array('yahoo-dom-event', 'element', 'uploader'),
1045 'utilities' => array('yahoo-dom-event', 'connection', 'animation', 'dragdrop', 'element', 'get'),
1046 'yuiloader' => 'yuiloader',
1047 'yuitest' => array(
1048 'js' => array('yahoo-dom-event', 'logger', 'yuitest'),
1049 'css' => array('logger/assets/logger.css', 'yuitest/assets/testlogger.css')),
1050 );
1051 if (!isset($translatelist[$libname])) {
1052 throw new coding_exception('Unknown YUI library ' . $libname);
1053 }
1054
1055 $data = $translatelist[$libname];
1056 if (!is_array($data)) {
1057 $jsnames = array($data);
1058 $cssfiles = array();
1059 } else if (isset($data['js']) && isset($data['css'])) {
1060 $jsnames = $data['js'];
1061 $cssfiles = $data['css'];
1062 } else {
1063 $jsnames = $data;
1064 $cssfiles = array();
1065 }
1066
1067 $debugging = debugging('', DEBUG_DEVELOPER);
1068 if ($debugging) {
1069 $suffix = '-debug.js';
1070 } else {
1071 $suffix = '-min.js';
1072 }
1073 $libpath = $CFG->httpswwwroot . '/lib/yui/';
1074
1075 $externalyui = !empty($CFG->useexternalyui);
1076 if ($externalyui) {
1077 include($CFG->libdir.'/yui/version.php'); // Sets $yuiversion.
1078 $libpath = 'http://yui.yahooapis.com/' . $yuiversion . '/build/';
1079 }
1080
1081 $jsurls = array();
1082 foreach ($jsnames as $js) {
1083 if ($js == 'yahoo-dom-event') {
1084 if ($debugging) {
1085 $jsurls[] = $libpath . 'yahoo/yahoo' . $suffix;
1086 $jsurls[] = $libpath . 'dom/dom' . $suffix;
1087 $jsurls[] = $libpath . 'event/event' . $suffix;
1088 } else {
1089 $jsurls[] = $jsurls[] = $libpath . $js . '/' . $js . '.js';
1090 }
1091 } else {
1092 $jsurls[] = $libpath . $js . '/' . $js . $suffix;
1093 }
1094 }
1095
1096 $cssurls = array();
1097 foreach ($cssfiles as $css) {
1098 $cssurls[] = $libpath . $css;
1099 }
1100
1101 return array($jsurls, $cssurls);
1102}
f72f94a2 1103
f72f94a2 1104/**
1105 * Get the path to a JavaScript library.
1106 * @param $libname - the name of the library whose path we need.
1107 * @return string
1108 */
1109function ajax_get_lib($libname) {
1f3ffe33 1110 global $CFG, $HTTPSPAGEREQUIRED;
b7658fa0 1111
f72f94a2 1112 $libpath = '';
b958e941 1113 $external_yui = false;
c081fdca 1114
9bb74178 1115 $translatelist = array(
3972629d 1116 'yui_yahoo' => '/lib/yui/yahoo/yahoo-min.js',
72d28452 1117 'yui_animation' => '/lib/yui/animation/animation-min.js',
1118 'yui_autocomplete' => '/lib/yui/autocomplete/autocomplete-min.js',
483f3067 1119 'yui_button' => '/lib/yui/button/button-min.js',
72d28452 1120 'yui_calendar' => '/lib/yui/calendar/calendar-min.js',
fbaa7b88 1121 'yui_charts' => '/lib/yui/charts/charts-min.js',
483f3067 1122 'yui_colorpicker' => '/lib/yui/colorpicker/colorpicker-min.js',
72d28452 1123 'yui_connection' => '/lib/yui/connection/connection-min.js',
1124 'yui_container' => '/lib/yui/container/container-min.js',
25e3d9f2 1125 'yui_cookie' => '/lib/yui/cookie/cookie-min.js',
1126 'yui_datasource' => '/lib/yui/datasource/datasource-min.js',
1127 'yui_datatable' => '/lib/yui/datatable/datatable-min.js',
3972629d 1128 'yui_dom' => '/lib/yui/dom/dom-min.js',
72d28452 1129 'yui_dom-event' => '/lib/yui/yahoo-dom-event/yahoo-dom-event.js',
1130 'yui_dragdrop' => '/lib/yui/dragdrop/dragdrop-min.js',
25e3d9f2 1131 'yui_editor' => '/lib/yui/editor/editor-min.js',
fbaa7b88 1132 'yui_element' => '/lib/yui/element/element-min.js',
3972629d 1133 'yui_event' => '/lib/yui/event/event-min.js',
483f3067 1134 'yui_get' => '/lib/yui/get/get-min.js',
1135 'yui_history' => '/lib/yui/history/history-min.js',
fbaa7b88 1136 'yui_imagecropper' => '/lib/yui/imagecropper/imagecropper-min.js',
483f3067 1137 'yui_imageloader' => '/lib/yui/imageloader/imageloader-min.js',
b244b9b7 1138 'yui_json' => '/lib/yui/json/json-min.js',
25e3d9f2 1139 'yui_layout' => '/lib/yui/layout/layout-min.js',
3972629d 1140 'yui_logger' => '/lib/yui/logger/logger-min.js',
72d28452 1141 'yui_menu' => '/lib/yui/menu/menu-min.js',
25e3d9f2 1142 'yui_profiler' => '/lib/yui/profiler/profiler-min.js',
fbaa7b88 1143 'yui_profilerviewer' => '/lib/yui/profilerviewer/profilerviewer-min.js',
25e3d9f2 1144 'yui_resize' => '/lib/yui/resize/resize-min.js',
fbaa7b88 1145 'yui_selector' => '/lib/yui/selector/selector-min.js',
25e3d9f2 1146 'yui_simpleeditor' => '/lib/yui/editor/simpleeditor-min.js',
483f3067 1147 'yui_slider' => '/lib/yui/slider/slider-min.js',
72d28452 1148 'yui_tabview' => '/lib/yui/tabview/tabview-min.js',
1149 'yui_treeview' => '/lib/yui/treeview/treeview-min.js',
fbaa7b88 1150 'yui_uploader' => '/lib/yui/uploader/uploader-min.js',
72d28452 1151 'yui_utilities' => '/lib/yui/utilities/utilities.js',
25e3d9f2 1152 'yui_yuiloader' => '/lib/yui/yuiloader/yuiloader-min.js',
1153 'yui_yuitest' => '/lib/yui/yuitest/yuitest-min.js',
3e1e2b69 1154 'ajaxcourse_blocks' => '/lib/ajax/block_classes.js',
1155 'ajaxcourse_sections' => '/lib/ajax/section_classes.js',
9bb74178 1156 'ajaxcourse' => '/lib/ajax/ajaxcourse.js'
1157 );
1158
b7658fa0 1159 if (!empty($HTTPSPAGEREQUIRED)) {
1160 $wwwroot = $CFG->httpswwwroot;
1161 } else {
1162 $wwwroot = $CFG->wwwroot;
1163 }
1164
f72f94a2 1165 if (array_key_exists($libname, $translatelist)) {
b958e941 1166 // If this is a YUI file and we are using external libraries
b7658fa0 1167 if (substr($libname, 0, 3) == 'yui' && !empty($CFG->useexternalyui)) {
b958e941 1168 $external_yui = true;
1169 // Get current version
1170 include($CFG->libdir.'/yui/version.php');
1171 $libpath = 'http://yui.yahooapis.com/'.$yuiversion.'/build/'.substr($translatelist[$libname], 9);
1172 } else {
b7658fa0 1173 $libpath = $wwwroot . $translatelist[$libname];
b958e941 1174 }
1175
f2eb5002 1176 // If we are in developer debug mode, use the non-compressed version of YUI for easier debugging.
1177 if (debugging('', DEBUG_DEVELOPER)) {
1178 $libpath = str_replace('-min.js', '.js', $libpath);
1179 }
1180
e874af28 1181 } else if (preg_match('/^https?:/', $libname)) {
f72f94a2 1182 $libpath = $libname;
e874af28 1183
1184 } else {
b7658fa0 1185 $libpath = $wwwroot . '/' . $libname;
9bb74178 1186 }
f72f94a2 1187
b958e941 1188 // Make sure the file exists if it is local.
1189 if ($external_yui === false) {
b7658fa0 1190 $testpath = str_replace($wwwroot, $CFG->dirroot, $libpath);
b958e941 1191 if (!file_exists($testpath)) {
e874af28 1192 throw new moodle_exception('unknownjsinrequirejs', '', '', $libpath);
b958e941 1193 }
f72f94a2 1194 }
1195
1196 return $libpath;
9bb74178 1197}
88c5092a 1198
1199
1200/**
1201 * Returns whether ajax is enabled/allowed or not.
1202 */
c2a9fc91 1203function ajaxenabled($browsers = array()) {
88c5092a 1204
1205 global $CFG, $USER;
483f3067 1206
c2a9fc91 1207 if (!empty($browsers)) {
1208 $valid = false;
1209 foreach ($browsers as $brand => $version) {
1210 if (check_browser_version($brand, $version)) {
1211 $valid = true;
483f3067 1212 }
c2a9fc91 1213 }
483f3067 1214
c2a9fc91 1215 if (!$valid) {
1216 return false;
1217 }
1218 }
483f3067 1219
d499142e 1220 $ie = check_browser_version('MSIE', 6.0);
1221 $ff = check_browser_version('Gecko', 20051106);
1222 $op = check_browser_version('Opera', 9.0);
1223 $sa = check_browser_version('Safari', 412);
1224
1225 if (!$ie && !$ff && !$op && !$sa) {
1226 /** @see http://en.wikipedia.org/wiki/User_agent */
483f3067 1227 // Gecko build 20051107 is what is in Firefox 1.5.
88c5092a 1228 // We still have issues with AJAX in other browsers.
1229 return false;
1230 }
1231
2f11bfc0 1232 if (!empty($CFG->enableajax) && (!empty($USER->ajax) || !isloggedin())) {
88c5092a 1233 return true;
1234 } else {
1235 return false;
1236 }
1237}
9bb74178 1238
35b974da 1239
1240/**
2469f7ea 1241 * Used to create view of document to be passed to JavaScript on pageload.
1242 * We use this class to pass data from PHP to JavaScript.
35b974da 1243 */
4fc45e1d 1244class jsportal {
9bb74178 1245
0a0bb380 1246 var $currentblocksection = null;
9bb74178 1247 var $blocks = array();
0a0bb380 1248
9bb74178 1249
35b974da 1250 /**
1251 * Takes id of block and adds it
1252 */
2469f7ea 1253 function block_add($id, $hidden=false){
0a0bb380 1254 $hidden_binary = 0;
9bb74178 1255
1256 if ($hidden) {
1257 $hidden_binary = 1;
1258 }
35b974da 1259 $this->blocks[count($this->blocks)] = array($this->currentblocksection, $id, $hidden_binary);
0a0bb380 1260 }
9bb74178 1261
1262
2469f7ea 1263 /**
1264 * Prints the JavaScript code needed to set up AJAX for the course.
1265 */
1266 function print_javascript($courseid, $return=false) {
c4ca9cb3 1267 global $CFG, $USER;
9bb74178 1268
d4df8fdc 1269 $blocksoutput = $output = '';
35b974da 1270 for ($i=0; $i<count($this->blocks); $i++) {
2469f7ea 1271 $blocksoutput .= "['".$this->blocks[$i][0]."',
1272 '".$this->blocks[$i][1]."',
1273 '".$this->blocks[$i][2]."']";
1274
1275 if ($i != (count($this->blocks) - 1)) {
35b974da 1276 $blocksoutput .= ',';
9bb74178 1277 }
1278 }
32f0b38a 1279 $output .= "<script type=\"text/javascript\">\n";
72d28452 1280 $output .= " main.portal.id = ".$courseid.";\n";
2469f7ea 1281 $output .= " main.portal.blocks = new Array(".$blocksoutput.");\n";
1282 $output .= " main.portal.strings['wwwroot']='".$CFG->wwwroot."';\n";
d8158863 1283 $output .= " main.portal.strings['pixpath']='".$CFG->pixpath."';\n";
f8eaeffa 1284 $output .= " main.portal.strings['marker']='".get_string('markthistopic', '', '_var_')."';\n";
1285 $output .= " main.portal.strings['marked']='".get_string('markedthistopic', '', '_var_')."';\n";
1286 $output .= " main.portal.strings['hide']='".get_string('hide')."';\n";
1287 $output .= " main.portal.strings['hidesection']='".get_string('hidesection', '', '_var_')."';\n";
1288 $output .= " main.portal.strings['show']='".get_string('show')."';\n";
1289 $output .= " main.portal.strings['delete']='".get_string('delete')."';\n";
d2a11d46 1290 $output .= " main.portal.strings['move']='".get_string('move')."';\n";
f8eaeffa 1291 $output .= " main.portal.strings['movesection']='".get_string('movesection', '', '_var_')."';\n";
d2a11d46 1292 $output .= " main.portal.strings['moveleft']='".get_string('moveleft')."';\n";
1293 $output .= " main.portal.strings['moveright']='".get_string('moveright')."';\n";
4fc45e1d 1294 $output .= " main.portal.strings['update']='".get_string('update')."';\n";
d2a11d46 1295 $output .= " main.portal.strings['groupsnone']='".get_string('groupsnone')."';\n";
1296 $output .= " main.portal.strings['groupsseparate']='".get_string('groupsseparate')."';\n";
1297 $output .= " main.portal.strings['groupsvisible']='".get_string('groupsvisible')."';\n";
1298 $output .= " main.portal.strings['clicktochange']='".get_string('clicktochange')."';\n";
2469f7ea 1299 $output .= " main.portal.strings['deletecheck']='".get_string('deletecheck','','_var_')."';\n";
1300 $output .= " main.portal.strings['resource']='".get_string('resource')."';\n";
1301 $output .= " main.portal.strings['activity']='".get_string('activity')."';\n";
d4a1fcaf 1302 $output .= " main.portal.strings['sesskey']='".sesskey()."';\n";
2469f7ea 1303 $output .= " onloadobj.load();\n";
4fc45e1d 1304 $output .= " main.process_blocks();\n";
35b974da 1305 $output .= "</script>";
2469f7ea 1306 if ($return) {
1307 return $output;
1308 } else {
1309 echo $output;
1310 }
0a0bb380 1311 }
9bb74178 1312
2469f7ea 1313}
f68a7947 1314
c6307019 1315?>