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