2010-02-07 08:45:21 +00:00
< ? php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Library functions to facilitate the use of JavaScript in Moodle .
*
2010-07-25 13:35:05 +00:00
* @ package core
* @ subpackage lib
* @ copyright 2009 Tim Hunt , 2010 Petr Skoda
* @ license http :// www . gnu . org / copyleft / gpl . html GNU GPL v3 or later
2010-02-07 08:45:21 +00:00
*/
2010-07-25 13:35:05 +00:00
defined ( 'MOODLE_INTERNAL' ) || die ();
2010-02-07 08:45:21 +00:00
// note: you can find history of this file in lib/ajax/ajaxlib.php
/**
* This class tracks all the things that are needed by the current page .
*
* Normally , the only instance of this class you will need to work with is the
* one accessible via $PAGE -> requires .
*
2010-05-22 19:34:17 +00:00
* Typical usage would be
2010-02-07 08:45:21 +00:00
* < pre >
2011-02-13 17:44:01 +01:00
* $PAGE -> requires -> js_init_call ( 'M.mod_forum.init_view' );
2010-02-07 08:45:21 +00:00
* </ pre >
*
* It also supports obsoleted coding style withouth YUI3 modules .
* < pre >
2010-05-22 19:34:17 +00:00
* $PAGE -> requires -> css ( '/mod/mymod/userstyles.php?id=' . $id ); // not overridable via themes!
2010-02-07 08:45:21 +00:00
* $PAGE -> requires -> js ( '/mod/mymod/script.js' );
* $PAGE -> requires -> js ( '/mod/mymod/small_but_urgent.js' , true );
* $PAGE -> requires -> js_function_call ( 'init_mymod' , array ( $data ), true );
* </ pre >
*
* There are some natural restrictions on some methods . For example , { @ link css ()}
* can only be called before the < head > tag is output . See the comments on the
* individual methods for details .
*
* @ copyright 2009 Tim Hunt , 2010 Petr Skoda
* @ license http :// www . gnu . org / copyleft / gpl . html GNU GPL v3 or later
* @ since Moodle 2.0
*/
class page_requirements_manager {
/** List of string available from JS */
protected $stringsforjs = array ();
/** List of JS variables to be initialised */
protected $jsinitvariables = array ( 'head' => array (), 'footer' => array ());
/** Included JS scripts */
protected $jsincludes = array ( 'head' => array (), 'footer' => array ());
/** List of needed function calls */
protected $jscalls = array ( 'normal' => array (), 'ondomready' => array ());
/**
* List of skip links , those are needed for accessibility reasons
* @ var array
*/
protected $skiplinks = array ();
/**
2010-05-22 19:34:17 +00:00
* Javascript code used for initialisation of page , it should be relatively small
2010-02-07 08:45:21 +00:00
* @ var array
*/
protected $jsinitcode = array ();
/**
* Theme sheets , initialised only from core_renderer
* @ var array of moodle_url
*/
protected $cssthemeurls = array ();
/**
* List of custom theme sheets , these are strongly discouraged !
* Useful mostly only for CSS submitted by teachers that is not part of the theme .
* @ var array of moodle_url
*/
protected $cssurls = array ();
/**
* List of requested event handlers
* @ var array
*/
protected $eventhandlers = array ();
/**
* Extra modules
* @ var array
*/
protected $extramodules = array ();
/** Flag indicated head stuff already printed */
protected $headdone = false ;
/** Flag indicating top of body already printed */
protected $topofbodydone = false ;
/** YUI PHPLoader instance responsible for YUI2 loading from PHP only */
protected $yui2loader ;
/** YUI PHPLoader instance responsible for YUI3 loading from PHP only */
protected $yui3loader ;
2011-08-19 10:21:30 +02:00
/** YUI loader information for YUI3 loading from javascript */
2010-02-07 08:45:21 +00:00
protected $M_yui_loader ;
/** some config vars exposed in JS, please no secret stuff there */
protected $M_cfg ;
2010-11-12 05:26:47 +00:00
/** stores debug backtraces from when JS modules were included in the page */
protected $debug_moduleloadstacktraces = array ();
2010-02-07 08:45:21 +00:00
/**
* Page requirements constructor .
*/
public function __construct () {
global $CFG ;
require_once ( " $CFG->libdir /yui/phploader/phploader/loader.php " );
2011-08-19 10:21:30 +02:00
$this -> yui3loader = new stdClass ();
2010-02-07 08:45:21 +00:00
$this -> yui2loader = new YAHOO_util_Loader ( $CFG -> yui2version );
// set up some loader options
if ( debugging ( '' , DEBUG_DEVELOPER )) {
2011-08-17 10:04:00 +01:00
$this -> yui3loader -> filter = YUI_RAW ; // for more detailed logging info use YUI_DEBUG here
$this -> yui2loader -> filter = YUI_RAW ; // for more detailed logging info use YUI_DEBUG here
2010-02-07 08:45:21 +00:00
} else {
$this -> yui3loader -> filter = null ;
$this -> yui2loader -> filter = null ;
}
if ( ! empty ( $CFG -> useexternalyui )) {
$this -> yui3loader -> base = 'http://yui.yahooapis.com/' . $CFG -> yui3version . '/build/' ;
$this -> yui2loader -> base = 'http://yui.yahooapis.com/' . $CFG -> yui2version . '/build/' ;
$this -> yui3loader -> comboBase = 'http://yui.yahooapis.com/combo?' ;
$this -> yui2loader -> comboBase = 'http://yui.yahooapis.com/combo?' ;
} else {
$this -> yui3loader -> base = $CFG -> httpswwwroot . '/lib/yui/' . $CFG -> yui3version . '/build/' ;
$this -> yui2loader -> base = $CFG -> httpswwwroot . '/lib/yui/' . $CFG -> yui2version . '/build/' ;
$this -> yui3loader -> comboBase = $CFG -> httpswwwroot . '/theme/yui_combo.php?' ;
$this -> yui2loader -> comboBase = $CFG -> httpswwwroot . '/theme/yui_combo.php?' ;
}
// enable combo loader? this significantly helps with caching and performance!
$this -> yui3loader -> combine = ! empty ( $CFG -> yuicomboloading );
$this -> yui2loader -> combine = ! empty ( $CFG -> yuicomboloading );
2010-08-05 04:05:28 +00:00
if ( empty ( $CFG -> cachejs )) {
$jsrev = - 1 ;
} else if ( empty ( $CFG -> jsrev )) {
$jsrev = 1 ;
} else {
$jsrev = $CFG -> jsrev ;
}
2010-09-06 06:07:47 +00:00
2010-02-07 08:45:21 +00:00
// set up JS YUI loader helper object
$this -> M_yui_loader = new stdClass ();
$this -> M_yui_loader -> base = $this -> yui3loader -> base ;
$this -> M_yui_loader -> comboBase = $this -> yui3loader -> comboBase ;
$this -> M_yui_loader -> combine = $this -> yui3loader -> combine ;
$this -> M_yui_loader -> filter = ( $this -> yui3loader -> filter == YUI_DEBUG ) ? 'debug' : '' ;
$this -> M_yui_loader -> insertBefore = 'firstthemesheet' ;
$this -> M_yui_loader -> modules = array ();
2010-07-01 02:26:21 +00:00
$this -> M_yui_loader -> groups = array (
'moodle' => array (
'name' => 'moodle' ,
2010-08-05 04:05:28 +00:00
'base' => $CFG -> httpswwwroot . '/theme/yui_combo.php?moodle/' . $jsrev . '/' ,
2010-07-01 02:26:21 +00:00
'comboBase' => $CFG -> httpswwwroot . '/theme/yui_combo.php?' ,
'combine' => $this -> yui3loader -> combine ,
'filter' => '' ,
'ext' => false ,
2010-08-05 04:05:28 +00:00
'root' => 'moodle/' . $jsrev . '/' , // Add the rev to the root path so that we can control caching
2010-07-01 02:26:21 +00:00
'patterns' => array (
'moodle-' => array (
'group' => 'moodle' ,
'configFn' => '@MOODLECONFIGFN@'
2010-06-04 01:49:53 +00:00
),
2010-07-01 02:26:21 +00:00
'root' => 'moodle'
2010-06-04 01:49:53 +00:00
)
2010-07-01 02:26:21 +00:00
),
'local' => array (
'name' => 'gallery' ,
'base' => $CFG -> wwwroot . '/lib/yui/gallery/' ,
'comboBase' => $CFG -> httpswwwroot . '/theme/yui_combo.php?' ,
'combine' => $this -> yui3loader -> combine ,
'filter' => $this -> M_yui_loader -> filter ,
'ext' => false ,
'root' => 'gallery/' ,
'patterns' => array (
'gallery-' => array (
'group' => 'gallery' ,
'configFn' => '@GALLERYCONFIGFN@' ,
),
'root' => 'gallery'
)
)
);
2010-02-07 08:45:21 +00:00
$this -> add_yui2_modules (); // adds loading info for all YUI2 modules
2011-08-03 18:20:01 +08:00
$this -> js_module ( $this -> find_module ( 'core_filepicker' ));
2010-02-07 08:45:21 +00:00
$this -> js_module ( $this -> find_module ( 'core_dock' ));
}
/**
* This method adds yui2 modules into the yui3 JS loader -
* @ return void
*/
protected function add_yui2_modules () {
//note: this function is definitely not perfect, because
// it adds tons of markup into each page, but it can be
// abstracted into separate JS file with proper headers
global $CFG ;
$GLOBALS [ 'yui_current' ] = array ();
require ( $CFG -> libdir . '/yui/phploader/lib/meta/config_' . $CFG -> yui2version . '.php' );
$info = $GLOBALS [ 'yui_current' ];
unset ( $GLOBALS [ 'yui_current' ]);
if ( empty ( $CFG -> yuicomboloading )) {
$urlbase = $this -> yui2loader -> base ;
} else {
$urlbase = $this -> yui2loader -> comboBase . $CFG -> yui2version . '/build/' ;
}
$modules = array ();
$ignored = array (); // list of CSS modules that are not needed
foreach ( $info [ 'moduleInfo' ] as $name => $module ) {
if ( $module [ 'type' ] === 'css' ) {
$ignored [ $name ] = true ;
} else {
$modules [ 'yui2-' . $name ] = $module ;
}
}
foreach ( $modules as $name => $module ) {
$module [ 'fullpath' ] = $urlbase . $module [ 'path' ]; // fix path to point to correct location
unset ( $module [ 'path' ]);
2010-02-07 12:50:53 +00:00
unset ( $module [ 'skinnable' ]); // we load all YUI2 css automatically, this prevents weird missing css loader problems
2010-02-07 08:45:21 +00:00
foreach ( array ( 'requires' , 'optional' , 'supersedes' ) as $fixme ) {
if ( ! empty ( $module [ $fixme ])) {
$fixed = false ;
foreach ( $module [ $fixme ] as $key => $dep ) {
if ( isset ( $ignored [ $dep ])) {
unset ( $module [ $fixme ][ $key ]);
$fixed = true ;
} else {
$module [ $fixme ][ $key ] = 'yui2-' . $dep ;
}
}
if ( $fixed ) {
$module [ $fixme ] = array_merge ( $module [ $fixme ]); // fix keys
}
}
}
$this -> M_yui_loader -> modules [ $name ] = $module ;
2010-11-12 05:26:47 +00:00
if ( debugging ( '' , DEBUG_DEVELOPER )) {
if ( ! array_key_exists ( $name , $this -> debug_moduleloadstacktraces )) {
$this -> debug_moduleloadstacktraces [ $name ] = array ();
}
$this -> debug_moduleloadstacktraces [ $name ][] = format_backtrace ( debug_backtrace ());
}
2010-02-07 08:45:21 +00:00
}
}
/**
* Initialise with the bits of JavaScript that every Moodle page should have .
*
* @ param moodle_page $page
* @ param core_renderer $output
*/
protected function init_requirements_data ( moodle_page $page , core_renderer $renderer ) {
global $CFG ;
// JavaScript should always work with $CFG->httpswwwroot rather than $CFG->wwwroot.
// Otherwise, in some situations, users will get warnings about insecure content
2010-02-11 13:27:02 +00:00
// on secure pages from their web browser.
2010-02-07 08:45:21 +00:00
$this -> M_cfg = array (
'wwwroot' => $CFG -> httpswwwroot , // Yes, really. See above.
'sesskey' => sesskey (),
'loadingicon' => $renderer -> pix_url ( 'i/loading_small' , 'moodle' ) -> out ( false ),
'themerev' => theme_get_revision (),
'theme' => $page -> theme -> name ,
2011-03-12 17:42:52 +01:00
'jsrev' => (( empty ( $CFG -> cachejs ) or empty ( $CFG -> jsrev )) ? - 1 : $CFG -> jsrev ),
2010-02-07 08:45:21 +00:00
);
if ( debugging ( '' , DEBUG_DEVELOPER )) {
$this -> M_cfg [ 'developerdebug' ] = true ;
$this -> yui2_lib ( 'logger' );
}
// accessibility stuff
2010-05-04 08:29:05 +00:00
$this -> skip_link_to ( 'maincontent' , get_string ( 'tocontent' , 'access' ));
2010-02-07 08:45:21 +00:00
// to be removed soon
$this -> yui2_lib ( 'dom' ); // at least javascript-static.js needs to be migrated to YUI3
$this -> string_for_js ( 'confirmation' , 'admin' );
$this -> string_for_js ( 'cancel' , 'moodle' );
$this -> string_for_js ( 'yes' , 'moodle' );
2010-05-21 08:13:08 +00:00
2010-02-11 13:27:02 +00:00
if ( $page -> pagelayout === 'frametop' ) {
$this -> js_init_call ( 'M.util.init_frametop' );
}
2010-02-07 08:45:21 +00:00
}
/**
* Ensure that the specified JavaScript file is linked to from this page .
*
* NOTE : This function is to be used in rare cases only , please store your JS in module . js file
* and use $PAGE -> requires -> js_init_call () instead .
*
* By default the link is put at the end of the page , since this gives best page - load performance .
*
* Even if a particular script is requested more than once , it will only be linked
* to once .
*
* @ param string | moodle_url $url The path to the . js file , relative to $CFG -> dirroot / $CFG -> wwwroot .
* For example '/mod/mymod/customscripts.js' ; use moodle_url for external scripts
* @ param bool $inhead initialise in head
* @ return void
*/
public function js ( $url , $inhead = false ) {
$url = $this -> js_fix_url ( $url );
$where = $inhead ? 'head' : 'footer' ;
$this -> jsincludes [ $where ][ $url -> out ()] = $url ;
}
/**
2010-05-22 19:34:17 +00:00
* Ensure that the specified YUI2 library file , and all its required dependencies ,
2010-02-07 08:45:21 +00:00
* are linked to from this page .
*
* By default the link is put at the end of the page , since this gives best page - load
* performance . Optional dependencies are not loaded automatically - if you want
* them you will need to load them first with other calls to this method .
*
2010-05-22 19:34:17 +00:00
* Even if a particular library is requested more than once ( perhaps as a dependency
2010-02-07 08:45:21 +00:00
* of other libraries ) it will only be linked to once .
*
* The library is leaded as soon as possible , if $OUTPUT -> header () not used yet it
* is put into the page header , otherwise it is loaded in the page footer .
*
* @ param string | array $libname the name of the YUI2 library you require . For example 'autocomplete' .
* @ return void
*/
public function yui2_lib ( $libname ) {
$libnames = ( array ) $libname ;
foreach ( $libnames as $lib ) {
$this -> yui2loader -> load ( $lib );
}
}
/**
* Returns the actual url through which a script is served .
* @ param moodle_url | string $url full moodle url , or shortened path to script
* @ return moodle_url
*/
protected function js_fix_url ( $url ) {
global $CFG ;
if ( $url instanceof moodle_url ) {
return $url ;
} else if ( strpos ( $url , '/' ) === 0 ) {
if ( debugging ()) {
// check file existence only when in debug mode
if ( ! file_exists ( $CFG -> dirroot . strtok ( $url , '?' ))) {
2010-08-03 14:32:28 +00:00
throw new coding_exception ( 'Attempt to require a JavaScript file that does not exist.' , $url );
2010-02-07 08:45:21 +00:00
}
}
2010-12-02 05:46:09 +00:00
if ( ! empty ( $CFG -> cachejs ) and ! empty ( $CFG -> jsrev ) and strpos ( $url , '/lib/editor/' ) !== 0 and substr ( $url , - 3 ) === '.js' ) {
2010-02-07 12:50:53 +00:00
return new moodle_url ( $CFG -> httpswwwroot . '/lib/javascript.php' , array ( 'file' => $url , 'rev' => $CFG -> jsrev ));
} else {
return new moodle_url ( $CFG -> httpswwwroot . $url );
}
2010-02-07 08:45:21 +00:00
} else {
throw new coding_exception ( 'Invalid JS url, it has to be shortened url starting with / or moodle_url instance.' , $url );
}
}
/**
2010-05-22 19:34:17 +00:00
* Find out if JS module present and return details .
2010-04-01 20:54:27 +00:00
* @ param string $component name of component in frankenstyle , ex : core_group , mod_forum
2010-02-07 08:45:21 +00:00
* @ return array description of module or null if not found
*/
2010-04-01 20:54:27 +00:00
protected function find_module ( $component ) {
2010-02-07 08:45:21 +00:00
global $CFG ;
$module = null ;
2010-05-21 08:13:08 +00:00
2010-04-01 20:54:27 +00:00
if ( strpos ( $component , 'core_' ) === 0 ) {
2010-02-07 08:45:21 +00:00
// must be some core stuff - list here is not complete, this is just the stuff used from multiple places
// so that we do nto have to repeat the definition of these modules over and over again
2010-04-01 20:54:27 +00:00
switch ( $component ) {
2010-02-07 08:45:21 +00:00
case 'core_filepicker' :
$module = array ( 'name' => 'core_filepicker' ,
'fullpath' => '/repository/filepicker.js' ,
2011-08-25 11:38:34 +02:00
'requires' => array ( 'base' , 'node' , 'node-event-simulate' , 'json' , 'async-queue' , 'io-base' , 'io-upload-iframe' , 'io-form' , 'yui2-button' , 'yui2-container' , 'yui2-layout' , 'yui2-menu' , 'yui2-treeview' , 'yui2-dragdrop' , 'yui2-cookie' ),
2010-02-07 09:34:19 +00:00
'strings' => array ( array ( 'add' , 'repository' ), array ( 'back' , 'repository' ), array ( 'cancel' , 'moodle' ), array ( 'close' , 'repository' ),
array ( 'cleancache' , 'repository' ), array ( 'copying' , 'repository' ), array ( 'date' , 'repository' ), array ( 'downloadsucc' , 'repository' ),
array ( 'emptylist' , 'repository' ), array ( 'error' , 'repository' ), array ( 'federatedsearch' , 'repository' ),
array ( 'filenotnull' , 'repository' ), array ( 'getfile' , 'repository' ), array ( 'help' , 'moodle' ), array ( 'iconview' , 'repository' ),
array ( 'invalidjson' , 'repository' ), array ( 'linkexternal' , 'repository' ), array ( 'listview' , 'repository' ),
array ( 'loading' , 'repository' ), array ( 'login' , 'repository' ), array ( 'logout' , 'repository' ), array ( 'noenter' , 'repository' ),
array ( 'noresult' , 'repository' ), array ( 'manageurl' , 'repository' ), array ( 'popup' , 'repository' ), array ( 'preview' , 'repository' ),
array ( 'refresh' , 'repository' ), array ( 'save' , 'repository' ), array ( 'saveas' , 'repository' ), array ( 'saved' , 'repository' ),
array ( 'saving' , 'repository' ), array ( 'search' , 'repository' ), array ( 'searching' , 'repository' ), array ( 'size' , 'repository' ),
array ( 'submit' , 'repository' ), array ( 'sync' , 'repository' ), array ( 'title' , 'repository' ), array ( 'upload' , 'repository' ),
array ( 'uploading' , 'repository' ), array ( 'xhtmlerror' , 'repository' ),
2011-03-09 15:16:02 +08:00
array ( 'cancel' ), array ( 'chooselicense' , 'repository' ), array ( 'author' , 'repository' ),
2010-07-24 18:15:45 +00:00
array ( 'ok' , 'moodle' ), array ( 'error' , 'moodle' ), array ( 'info' , 'moodle' ), array ( 'norepositoriesavailable' , 'repository' ), array ( 'norepositoriesexternalavailable' , 'repository' ),
2010-09-06 06:07:47 +00:00
array ( 'nofilesattached' , 'repository' ), array ( 'filepicker' , 'repository' ),
2011-05-02 10:11:19 +08:00
array ( 'nofilesavailable' , 'repository' ), array ( 'overwrite' , 'repository' ),
array ( 'renameto' , 'repository' ), array ( 'fileexists' , 'repository' ),
array ( 'fileexistsdialogheader' , 'repository' ), array ( 'fileexistsdialog_editor' , 'repository' ),
array ( 'fileexistsdialog_filemanager' , 'repository' )
2010-05-21 08:13:08 +00:00
));
2010-02-07 08:45:21 +00:00
break ;
case 'core_comment' :
$module = array ( 'name' => 'core_comment' ,
'fullpath' => '/comment/comment.js' ,
2011-08-25 11:38:34 +02:00
'requires' => array ( 'base' , 'io-base' , 'node' , 'json' , 'yui2-animation' , 'overlay' ),
2010-04-08 01:53:48 +00:00
'strings' => array ( array ( 'confirmdeletecomments' , 'admin' ), array ( 'yes' , 'moodle' ), array ( 'no' , 'moodle' ))
2010-03-31 09:53:05 +00:00
);
2010-02-07 08:45:21 +00:00
break ;
case 'core_role' :
$module = array ( 'name' => 'core_role' ,
2010-09-21 06:09:14 +00:00
'fullpath' => '/admin/roles/module.js' ,
'requires' => array ( 'node' , 'cookie' ));
2010-02-07 08:45:21 +00:00
break ;
case 'core_completion' :
$module = array ( 'name' => 'core_completion' ,
'fullpath' => '/course/completion.js' );
break ;
case 'core_dock' :
$module = array ( 'name' => 'core_dock' ,
'fullpath' => '/blocks/dock.js' ,
2010-05-31 03:33:34 +00:00
'requires' => array ( 'base' , 'node' , 'event-custom' , 'event-mouseenter' , 'event-resize' ),
2010-05-24 04:03:31 +00:00
'strings' => array ( array ( 'addtodock' , 'block' ), array ( 'undockitem' , 'block' ), array ( 'undockall' , 'block' ), array ( 'thisdirectionvertical' , 'langconfig' )));
2010-02-07 08:45:21 +00:00
break ;
case 'core_message' :
$module = array ( 'name' => 'core_message' ,
2011-05-13 11:13:13 +01:00
'requires' => array ( 'base' , 'node' , 'event' , 'node-event-simulate' ),
2010-02-07 08:45:21 +00:00
'fullpath' => '/message/module.js' );
break ;
2010-02-24 03:57:36 +00:00
case 'core_group' :
$module = array ( 'name' => 'core_group' ,
'fullpath' => '/group/module.js' ,
'requires' => array ( 'node' , 'overlay' , 'event-mouseenter' ));
break ;
2010-11-01 17:44:59 +00:00
case 'core_question_engine' :
$module = array ( 'name' => 'core_question_engine' ,
'fullpath' => '/question/qengine.js' ,
'requires' => array ( 'node' , 'event' ));
break ;
2010-04-01 20:33:15 +00:00
case 'core_rating' :
$module = array ( 'name' => 'core_rating' ,
2010-03-16 05:57:51 +00:00
'fullpath' => '/rating/module.js' ,
2011-08-25 11:38:34 +02:00
'requires' => array ( 'node' , 'event' , 'overlay' , 'io-base' , 'json' ));
2010-03-16 05:57:51 +00:00
break ;
2010-06-16 08:07:42 +00:00
case 'core_filetree' :
$module = array ( 'name' => 'core_filetree' ,
'fullpath' => '/files/module.js' ,
2011-08-25 11:38:34 +02:00
'requires' => array ( 'node' , 'event' , 'overlay' , 'io-base' , 'json' , 'yui2-treeview' ));
2010-06-16 08:07:42 +00:00
break ;
2010-02-07 08:45:21 +00:00
}
} else {
2010-04-10 23:21:18 +00:00
if ( $dir = get_component_directory ( $component )) {
if ( file_exists ( " $dir /module.js " )) {
if ( strpos ( $dir , $CFG -> dirroot . '/' ) === 0 ) {
$dir = substr ( $dir , strlen ( $CFG -> dirroot ));
$module = array ( 'name' => $component , 'fullpath' => " $dir /module.js " , 'requires' => array ());
}
2010-02-07 08:45:21 +00:00
}
}
}
return $module ;
}
/**
* Append YUI3 module to default YUI3 JS loader .
* The structure of module array is described at http :// developer . yahoo . com / yui / 3 / yui /:
* @ param string | array $module name of module ( details are autodetected ), or full module specification as array
* @ return void
*/
public function js_module ( $module ) {
global $CFG ;
if ( empty ( $module )) {
throw new coding_exception ( 'Missing YUI3 module name or full description.' );
}
if ( is_string ( $module )) {
$module = $this -> find_module ( $module );
}
if ( empty ( $module ) or empty ( $module [ 'name' ]) or empty ( $module [ 'fullpath' ])) {
throw new coding_exception ( 'Missing YUI3 module details.' );
}
2010-11-12 05:26:47 +00:00
// Don't load this module if we already have, no need to!
if ( $this -> js_module_loaded ( $module [ 'name' ])) {
if ( debugging ( '' , DEBUG_DEVELOPER )) {
$this -> debug_moduleloadstacktraces [ $module [ 'name' ]][] = format_backtrace ( debug_backtrace ());
}
return ;
}
2010-02-07 08:45:21 +00:00
$module [ 'fullpath' ] = $this -> js_fix_url ( $module [ 'fullpath' ]) -> out ( false );
2010-02-07 09:34:19 +00:00
// add all needed strings
if ( ! empty ( $module [ 'strings' ])) {
foreach ( $module [ 'strings' ] as $string ) {
$identifier = $string [ 0 ];
$component = isset ( $string [ 1 ]) ? $string [ 1 ] : 'moodle' ;
$a = isset ( $string [ 2 ]) ? $string [ 2 ] : null ;
$this -> string_for_js ( $identifier , $component , $a );
}
}
unset ( $module [ 'strings' ]);
2010-11-12 05:26:47 +00:00
// Process module requirements and attempt to load each. This allows
// moodle modules to require each other.
if ( ! empty ( $module [ 'requires' ])){
foreach ( $module [ 'requires' ] as $requirement ) {
$rmodule = $this -> find_module ( $requirement );
if ( is_array ( $rmodule )) {
$this -> js_module ( $rmodule );
}
}
}
2010-12-02 05:46:09 +00:00
2010-02-07 08:45:21 +00:00
if ( $this -> headdone ) {
$this -> extramodules [ $module [ 'name' ]] = $module ;
} else {
$this -> M_yui_loader -> modules [ $module [ 'name' ]] = $module ;
}
2010-11-12 05:26:47 +00:00
if ( debugging ( '' , DEBUG_DEVELOPER )) {
if ( ! array_key_exists ( $module [ 'name' ], $this -> debug_moduleloadstacktraces )) {
$this -> debug_moduleloadstacktraces [ $module [ 'name' ]] = array ();
}
$this -> debug_moduleloadstacktraces [ $module [ 'name' ]][] = format_backtrace ( debug_backtrace ());
}
}
/**
* Returns true if the module has already been loaded .
*
* @ param string | array $modulename
* @ return bool True if the module has already been loaded
*/
protected function js_module_loaded ( $module ) {
if ( is_string ( $module )) {
$modulename = $module ;
} else {
$modulename = $module [ 'name' ];
}
return array_key_exists ( $modulename , $this -> M_yui_loader -> modules ) ||
array_key_exists ( $modulename , $this -> extramodules );
}
/**
* Returns the stacktraces from loading js modules .
* @ return array
*/
public function get_loaded_modules () {
return $this -> debug_moduleloadstacktraces ;
2010-02-07 08:45:21 +00:00
}
/**
* Ensure that the specified CSS file is linked to from this page .
*
* Because stylesheet links must go in the < head > part of the HTML , you must call
* this function before { @ link get_head_code ()} is called . That normally means before
* the call to print_header . If you call it when it is too late , an exception
* will be thrown .
*
* Even if a particular style sheet is requested more than once , it will only
* be linked to once .
*
2010-05-31 12:22:21 +00:00
* Please note use of this feature is strongly discouraged ,
2010-02-07 08:45:21 +00:00
* it is suitable only for places where CSS is submitted directly by teachers .
* ( Students must not be allowed to submit any external CSS because it may
* contain embedded javascript ! ) . Example of correct use is mod / data .
*
* @ param string $stylesheet The path to the . css file , relative to $CFG -> wwwroot .
* For example :
* $PAGE -> requires -> css ( 'mod/data/css.php?d=' . $data -> id );
*/
public function css ( $stylesheet ) {
global $CFG ;
if ( $this -> headdone ) {
throw new coding_exception ( 'Cannot require a CSS file after <head> has been printed.' , $stylesheet );
}
if ( $stylesheet instanceof moodle_url ) {
// ok
} else if ( strpos ( $stylesheet , '/' ) === 0 ) {
$stylesheet = new moodle_url ( $CFG -> httpswwwroot . $stylesheet );
} else {
throw new coding_exception ( 'Invalid stylesheet parameter.' , $stylesheet );
}
$this -> cssurls [ $stylesheet -> out ()] = $stylesheet ; // overrides
}
/**
* Add theme stylkesheet to page - do not use from plugin code ,
* this should be called only from the core renderer !
* @ param moodle_url $stylesheet
* @ return void
*/
public function css_theme ( moodle_url $stylesheet ) {
$this -> cssthemeurls [] = $stylesheet ;
}
/**
* Ensure that a skip link to a given target is printed at the top of the < body >.
*
* You must call this function before { @ link get_top_of_body_code ()}, ( if not , an exception
* will be thrown ) . That normally means you must call this before the call to print_header .
*
* If you ask for a particular skip link to be printed , it is then your responsibility
2010-05-22 19:34:17 +00:00
* to ensure that the appropriate < a name = " ... " > tag is printed in the body of the
2010-02-07 08:45:21 +00:00
* page , so that the skip link goes somewhere .
*
* Even if a particular skip link is requested more than once , only one copy of it will be output .
*
* @ param $target the name of anchor this link should go to . For example 'maincontent' .
* @ param $linktext The text to use for the skip link . Normally get_string ( 'skipto' , 'access' , ... );
*/
public function skip_link_to ( $target , $linktext ) {
if ( $this -> topofbodydone ) {
debugging ( 'Page header already printed, can not add skip links any more, code needs to be fixed.' );
return ;
}
$this -> skiplinks [ $target ] = $linktext ;
}
/**
* !!! DEPRECATED !!! please use js_init_call () if possible
* Ensure that the specified JavaScript function is called from an inline script
* somewhere on this page .
*
* By default the call will be put in a script tag at the
* end of the page after initialising Y instance , since this gives best page - load
* performance and allows you to use YUI3 library .
*
* If you request that a particular function is called several times , then
* that is what will happen ( unlike linking to a CSS or JS file , where only
* one link will be output ) .
*
2010-05-22 19:34:17 +00:00
* The main benefit of the method is the automatic encoding of all function parameters .
2010-02-07 08:45:21 +00:00
*
* @ param string $function the name of the JavaScritp function to call . Can
* be a compound name like 'Y.Event.purgeElement' . Can also be
* used to create and object by using a 'function name' like 'new user_selector' .
* @ param array $arguments and array of arguments to be passed to the function .
* When generating the function call , this will be escaped using json_encode ,
* so passing objects and arrays should work .
* @ param bool $ondomready
* @ param int $delay
* @ return void
*/
public function js_function_call ( $function , array $arguments = null , $ondomready = false , $delay = 0 ) {
$where = $ondomready ? 'ondomready' : 'normal' ;
$this -> jscalls [ $where ][] = array ( $function , $arguments , $delay );
}
2010-06-04 01:49:53 +00:00
/**
2010-07-01 02:26:21 +00:00
* Adds a call to make use of a YUI gallery module . DEPRECATED DO NOT USE !!!
2010-06-04 01:49:53 +00:00
*
2010-07-01 02:26:21 +00:00
* @ deprecated DO NOT USE
2010-06-04 01:49:53 +00:00
*
* @ param string | array $modules One or more gallery modules to require
* @ param string $version
* @ param string $function
* @ param array $arguments
* @ param bool $ondomready
*/
public function js_gallery_module ( $modules , $version , $function , array $arguments = null , $ondomready = false ) {
global $CFG ;
2010-07-01 02:26:21 +00:00
debugging ( 'This function will be removed before 2.0 is released please change it from js_gallery_module to yui_module' , DEBUG_DEVELOPER );
$this -> yui_module ( $modules , $function , $arguments , $version , $ondomready );
}
/**
* Creates a JavaScript function call that requires one or more modules to be loaded
*
* This function can be used to include all of the standard YUI module types within JavaScript :
* - YUI3 modules [ node , event , io ]
* - YUI2 modules [ yui2 -* ]
* - Moodle modules [ moodle -* ]
* - Gallery modules [ gallery -* ]
*
* @ param array | string $modules One or more modules
* @ param string $function The function to call once modules have been loaded
* @ param array $arguments An array of arguments to pass to the function
* @ param string $galleryversion The gallery version to use
* @ param bool $ondomready
*/
public function yui_module ( $modules , $function , array $arguments = null , $galleryversion = '2010.04.08-12-35' , $ondomready = false ) {
2010-09-17 08:04:01 +00:00
global $CFG ;
2010-06-04 01:49:53 +00:00
if ( ! is_array ( $modules )) {
$modules = array ( $modules );
}
if ( empty ( $CFG -> useexternalyui ) || true ) {
// We need to set the M.yui.galleryversion to the correct version
2010-07-01 02:26:21 +00:00
$jscode = 'M.yui.galleryversion=' . json_encode ( $galleryversion ) . ';' ;
2010-06-04 01:49:53 +00:00
} else {
// Set Y's config.gallery to the version
2010-07-01 02:26:21 +00:00
$jscode = 'Y.config.gallery=' . json_encode ( $galleryversion ) . ';' ;
2010-06-04 01:49:53 +00:00
}
2011-07-23 11:48:53 +02:00
$jscode .= 'Y.use(' . join ( ',' , array_map ( 'json_encode' , $modules )) . ',function() {' . js_writer :: function_call ( $function , $arguments ) . '});' ;
2010-06-04 01:49:53 +00:00
if ( $ondomready ) {
$jscode = " Y.on('domready', function() { $jscode }); " ;
}
$this -> jsinitcode [] = $jscode ;
}
2010-02-07 08:45:21 +00:00
/**
* Ensure that the specified JavaScript function is called from an inline script
* from page footer .
*
* @ param string $function the name of the JavaScritp function to with init code ,
* usually something like 'M.mod_mymodule.init'
* @ param array $extraarguments and array of arguments to be passed to the function .
* The first argument is always the YUI3 Y instance with all required dependencies
* already loaded .
* @ param bool $ondomready wait for dom ready ( helps with some IE problems when modifying DOM )
* @ param array $module JS module specification array
* @ return void
*/
public function js_init_call ( $function , array $extraarguments = null , $ondomready = false , array $module = null ) {
$jscode = js_writer :: function_call_with_Y ( $function , $extraarguments );
if ( ! $module ) {
// detect module automatically
if ( preg_match ( '/M\.([a-z0-9]+_[^\.]+)/' , $function , $matches )) {
$module = $this -> find_module ( $matches [ 1 ]);
}
}
$this -> js_init_code ( $jscode , $ondomready , $module );
}
/**
* Add short static javascript code fragment to page footer .
* This is intended primarily for loading of js modules and initialising page layout .
* Ideally the JS code fragment should be stored in plugin renderer so that themes
* may override it .
* @ param string $jscode
* @ param bool $ondomready wait for dom ready ( helps with some IE problems when modifying DOM )
* @ param array $module JS module specification array
* @ return void
*/
public function js_init_code ( $jscode , $ondomready = false , array $module = null ) {
$jscode = trim ( $jscode , " ; \n " ) . ';' ;
if ( $module ) {
$this -> js_module ( $module );
$modulename = $module [ 'name' ];
$jscode = " Y.use(' $modulename ', function(Y) { $jscode }); " ;
}
if ( $ondomready ) {
$jscode = " Y.on('domready', function() { $jscode }); " ;
}
$this -> jsinitcode [] = $jscode ;
}
/**
* Make a language string available to JavaScript .
*
2010-02-07 09:43:07 +00:00
* All the strings will be available in a M . str object in the global namespace .
2010-02-07 08:45:21 +00:00
* So , for example , after a call to $PAGE -> requires -> string_for_js ( 'course' , 'moodle' );
2010-02-07 09:43:07 +00:00
* then the JavaScript variable M . str . moodle . course will be 'Course' , or the
2010-02-07 08:45:21 +00:00
* equivalent in the current language .
*
* The arguments to this function are just like the arguments to get_string
2010-11-02 14:59:32 +00:00
* except that $component is not optional , and there are some aspects to consider
* when the string contains { $a } placeholder .
*
* If the string does not contain any { $a } placeholder , you can simply use
* M . str . component . identifier to obtain it . If you prefer , you can call
* M . util . get_string ( identifier , component ) to get the same result .
*
* If you need to use { $a } placeholders , there are two options . Either the
* placeholder should be substituted in PHP on server side or it should
* be substituted in Javascript at client side .
*
* To substitute the placeholder at server side , just provide the required
* value for the placeholder when you require the string . Because each string
* is only stored once in the JavaScript ( based on $identifier and $module )
* you cannot get the same string with two different values of $a . If you try ,
* an exception will be thrown . Once the placeholder is substituted , you can
* use M . str or M . util . get_string () as shown above :
*
* // require the string in PHP and replace the placeholder
* $PAGE -> requires -> string_for_js ( 'fullnamedisplay' , 'moodle' , $USER );
* // use the result of the substitution in Javascript
* alert ( M . str . moodle . fullnamedisplay );
*
* To substitute the placeholder at client side , use M . util . get_string ()
* function . It implements the same logic as { @ see get_string ()} :
*
* // require the string in PHP but keep {$a} as it is
* $PAGE -> requires -> string_for_js ( 'fullnamedisplay' , 'moodle' );
* // provide the values on the fly in Javascript
* user = { firstname : 'Harry' , lastname : 'Potter' }
* alert ( M . util . get_string ( 'fullnamedisplay' , 'moodle' , user );
*
* If you do need the same string expanded with different $a values in PHP
* on server side , then the solution is to put them in your own data structure
* ( e . g . and array ) that you pass to JavaScript with { @ link data_for_js ()} .
2010-02-07 08:45:21 +00:00
*
* @ param string $identifier the desired string .
* @ param string $module the language file to look in .
* @ param mixed $a any extra data to add into the string ( optional ) .
*/
public function string_for_js ( $identifier , $component , $a = NULL ) {
$string = get_string ( $identifier , $component , $a );
if ( ! $component ) {
throw new coding_exception ( 'The $module parameter is required for page_requirements_manager::string_for_js.' );
}
MDL-21782 reworked enrolment framework, the core infrastructure is in place, the basic plugins are all implemented; see the tracker issue for list of unfinished bits, expect more changes and improvements during the next week
AMOS START
MOV [sendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage,enrol_self]
MOV [configsendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage_desc,enrol_self]
MOV [enrolstartdate,core],[enrolstartdate,enrol_self]
MOV [enrolenddate,core],[enrolenddate,enrol_self]
CPY [welcometocourse,core],[welcometocourse,enrol_self]
CPY [welcometocoursetext,core],[welcometocoursetext,enrol_self]
MOV [notenrollable,core],[notenrollable,core_enrol]
MOV [enrolenddaterror,core],[enrolenddaterror,enrol_self]
MOV [enrolmentkeyhint,core],[passwordinvalidhint,enrol_self]
MOV [coursemanager,core_admin],[coursecontact,core_admin]
MOV [configcoursemanager,core_admin],[coursecontact_desc,core_admin]
MOV [enrolledincourserole,core],[enrolledincourserole,enrol_manual]
MOV [enrolme,core],[enrolme,core_enrol]
MOV [unenrol,core],[unenrol,core_enrol]
MOV [unenrolme,core],[unenrolme,core_enrol]
MOV [enrolmentnew,core],[enrolmentnew,core_enrol]
MOV [enrolmentnewuser,core],[enrolmentnewuser,core_enrol]
MOV [enrolments,core],[enrolments,core_enrol]
MOV [enrolperiod,core],[enrolperiod,core_enrol]
MOV [unenrolroleusers,core],[unenrolroleusers,core_enrol]
AMOS END
2010-06-21 15:30:49 +00:00
if ( isset ( $this -> stringsforjs [ $component ][ $identifier ]) && $this -> stringsforjs [ $component ][ $identifier ] !== $string ) {
2010-02-07 08:45:21 +00:00
throw new coding_exception ( " Attempt to re-define already required string ' $identifier ' " .
MDL-21782 reworked enrolment framework, the core infrastructure is in place, the basic plugins are all implemented; see the tracker issue for list of unfinished bits, expect more changes and improvements during the next week
AMOS START
MOV [sendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage,enrol_self]
MOV [configsendcoursewelcomemessage,core_admin],[sendcoursewelcomemessage_desc,enrol_self]
MOV [enrolstartdate,core],[enrolstartdate,enrol_self]
MOV [enrolenddate,core],[enrolenddate,enrol_self]
CPY [welcometocourse,core],[welcometocourse,enrol_self]
CPY [welcometocoursetext,core],[welcometocoursetext,enrol_self]
MOV [notenrollable,core],[notenrollable,core_enrol]
MOV [enrolenddaterror,core],[enrolenddaterror,enrol_self]
MOV [enrolmentkeyhint,core],[passwordinvalidhint,enrol_self]
MOV [coursemanager,core_admin],[coursecontact,core_admin]
MOV [configcoursemanager,core_admin],[coursecontact_desc,core_admin]
MOV [enrolledincourserole,core],[enrolledincourserole,enrol_manual]
MOV [enrolme,core],[enrolme,core_enrol]
MOV [unenrol,core],[unenrol,core_enrol]
MOV [unenrolme,core],[unenrolme,core_enrol]
MOV [enrolmentnew,core],[enrolmentnew,core_enrol]
MOV [enrolmentnewuser,core],[enrolmentnewuser,core_enrol]
MOV [enrolments,core],[enrolments,core_enrol]
MOV [enrolperiod,core],[enrolperiod,core_enrol]
MOV [unenrolroleusers,core],[unenrolroleusers,core_enrol]
AMOS END
2010-06-21 15:30:49 +00:00
" from lang file ' $component '. Did you already ask for it with a different \$ a? { $this -> stringsforjs [ $component ][ $identifier ] } !== $string " );
2010-02-07 08:45:21 +00:00
}
$this -> stringsforjs [ $component ][ $identifier ] = $string ;
}
/**
* Make an array of language strings available for JS
*
* This function calls the above function { @ link string_for_js ()} for each requested
* string in the $identifiers array that is passed to the argument for a single module
* passed in $module .
*
* < code >
2011-03-10 00:50:18 +01:00
* $PAGE -> requires -> strings_for_js ( array ( 'one' , 'two' , 'three' ), 'mymod' , array ( 'a' , null , 3 ));
2010-02-07 08:45:21 +00:00
*
2010-05-22 19:34:17 +00:00
* // The above is identitical to calling
2010-02-07 08:45:21 +00:00
*
2011-03-10 00:50:18 +01:00
* $PAGE -> requires -> string_for_js ( 'one' , 'mymod' , 'a' );
* $PAGE -> requires -> string_for_js ( 'two' , 'mymod' );
* $PAGE -> requires -> string_for_js ( 'three' , 'mymod' , 3 );
2010-02-07 08:45:21 +00:00
* </ code >
*
* @ param array $identifiers An array of desired strings
* @ param string $component The module to load for
* @ param mixed $a This can either be a single variable that gets passed as extra
* information for every string or it can be an array of mixed data where the
* key for the data matches that of the identifier it is meant for .
*
*/
public function strings_for_js ( $identifiers , $component , $a = NULL ) {
foreach ( $identifiers as $key => $identifier ) {
if ( is_array ( $a ) && array_key_exists ( $key , $a )) {
$extra = $a [ $key ];
} else {
$extra = $a ;
}
$this -> string_for_js ( $identifier , $component , $extra );
}
}
/**
* !!!!!! DEPRECATED !!!!!! please use js_init_call () for everything now .
*
* Make some data from PHP available to JavaScript code .
*
* For example , if you call
* < pre >
* $PAGE -> requires -> data_for_js ( 'mydata' , array ( 'name' => 'Moodle' ));
* </ pre >
* then in JavsScript mydata . name will be 'Moodle' .
* @ param string $variable the the name of the JavaScript variable to assign the data to .
* Will probably work if you use a compound name like 'mybuttons.button[1]' , but this
* should be considered an experimental feature .
* @ param mixed $data The data to pass to JavaScript . This will be escaped using json_encode ,
* so passing objects and arrays should work .
* @ param bool $inhead initialise in head
* @ return void
*/
public function data_for_js ( $variable , $data , $inhead = false ) {
$where = $inhead ? 'head' : 'footer' ;
$this -> jsinitvariables [ $where ][] = array ( $variable , $data );
}
/**
* Creates a YUI event handler .
*
* @ param mixed $selector standard YUI selector for elemnts , may be array or string , element id is in the form " #idvalue "
* @ param string $event A valid DOM event ( click , mousedown , change etc . )
* @ param string $function The name of the function to call
* @ param array $arguments An optional array of argument parameters to pass to the function
* @ return void
2010-05-21 08:13:08 +00:00
*/
public function event_handler ( $selector , $event , $function , array $arguments = null ) {
2010-02-07 08:45:21 +00:00
$this -> eventhandlers [] = array ( 'selector' => $selector , 'event' => $event , 'function' => $function , 'arguments' => $arguments );
}
/**
* Returns code needed for registering of event handlers .
* @ return string JS code
*/
protected function get_event_handler_code () {
$output = '' ;
foreach ( $this -> eventhandlers as $h ) {
$output .= js_writer :: event_handler ( $h [ 'selector' ], $h [ 'event' ], $h [ 'function' ], $h [ 'arguments' ]);
}
return $output ;
}
/**
* Get the inline JavaScript code that need to appear in a particular place .
* @ return bool $ondomready
*/
protected function get_javascript_code ( $ondomready ) {
$where = $ondomready ? 'ondomready' : 'normal' ;
$output = '' ;
if ( $this -> jscalls [ $where ]) {
foreach ( $this -> jscalls [ $where ] as $data ) {
2010-02-14 08:56:57 +00:00
$output .= js_writer :: function_call ( $data [ 0 ], $data [ 1 ], $data [ 2 ]);
2010-02-07 08:45:21 +00:00
}
if ( ! empty ( $ondomready )) {
$output = " Y.on('domready', function() { \n $output\n }); " ;
}
}
return $output ;
}
/**
* Returns js code to be executed when Y is available .
* @ return unknown_type
*/
protected function get_javascript_init_code () {
if ( count ( $this -> jsinitcode )) {
return implode ( " \n " , $this -> jsinitcode ) . " \n " ;
}
return '' ;
}
/**
* Returns basic YUI3 JS loading code .
* YUI3 is using autoloading of both CSS and JS code .
*
* Major benefit of this compared to standard js / csss loader is much improved
* caching , better browser cache utilisation , much fewer http requests .
*
* @ return string
*/
protected function get_yui3lib_headcode () {
2011-08-19 10:21:30 +02:00
global $CFG ;
$code = '' ;
if ( $this -> yui3loader -> combine ) {
$code .= '<link rel="stylesheet" type="text/css" href="' . $this -> yui3loader -> comboBase
. $CFG -> yui3version . '/build/cssreset/reset-min.css&'
. $CFG -> yui3version . '/build/cssfonts/fonts-min.css&'
. $CFG -> yui3version . '/build/cssgrids/grids-min.css&'
. $CFG -> yui3version . '/build/cssbase/base-min.css" />' ;
} else {
$code .= '<link rel="stylesheet" type="text/css" href="' . $this -> yui3loader -> base . 'cssreset/reset-min.css" />' ;
$code .= '<link rel="stylesheet" type="text/css" href="' . $this -> yui3loader -> base . 'cssfonts/fonts-min.css" />' ;
$code .= '<link rel="stylesheet" type="text/css" href="' . $this -> yui3loader -> base . 'cssgrids/grids-min.css" />' ;
$code .= '<link rel="stylesheet" type="text/css" href="' . $this -> yui3loader -> base . 'cssbase/base-min.css" />' ;
}
if ( debugging ( '' , DEBUG_DEVELOPER )) {
2011-11-19 18:43:55 +01:00
$code .= '<script type="text/javascript" src="' . $this -> yui3loader -> base . 'yui/yui-debug.js"></script>' ;
2011-08-19 10:21:30 +02:00
} else {
2011-11-19 18:43:55 +01:00
$code .= '<script type="text/javascript" src="' . $this -> yui3loader -> base . 'yui/yui-min.js"></script>' ;
2011-08-19 10:21:30 +02:00
}
2010-02-07 08:45:21 +00:00
return $code ;
}
/**
* Returns basic YUI2 JS loading code .
* It can be called manually at any time .
* If called manually the result needs to be output using echo () .
*
* Major benefit of this compared to standard js loader is much improved
* caching , better browser cache utilisation , much fewer http requests .
*
* All YUI2 CSS is loaded automatically .
*
* @ return string JS embedding code
*/
public function get_yui2lib_code () {
global $CFG ;
if ( $this -> headdone ) {
$code = $this -> yui2loader -> script ();
} else {
$code = $this -> yui2loader -> script ();
if ( $this -> yui2loader -> combine ) {
$skinurl = $this -> yui2loader -> comboBase . $CFG -> yui2version . '/build/assets/skins/sam/skin.css' ;
} else {
$skinurl = $this -> yui2loader -> base . 'assets/skins/sam/skin.css' ;
}
// please note this is a temporary hack until we fully migrate to later YUI3 that has all the widgets
$attributes = array ( 'rel' => 'stylesheet' , 'type' => 'text/css' , 'href' => $skinurl );
$code .= " \n " . html_writer :: empty_tag ( 'link' , $attributes ) . " \n " ;
}
$code = str_replace ( '&' , '&' , $code );
$code = str_replace ( '&' , '&' , $code );
return $code ;
}
/**
* Returns html tags needed for inclusion of theme CSS
* @ return string
*/
protected function get_css_code () {
// First of all the theme CSS, then any custom CSS
// Please note custom CSS is strongly discouraged,
// because it can not be overridden by themes!
// It is suitable only for things like mod/data which accepts CSS from teachers.
2010-07-08 02:12:49 +00:00
$attributes = array ( 'rel' => 'stylesheet' , 'type' => 'text/css' );
2010-02-07 08:45:21 +00:00
2010-07-08 02:12:49 +00:00
// This line of code may look funny but it is currently required in order
// to avoid MASSIVE display issues in Internet Explorer.
// As of IE8 + YUI3.1.1 the reference stylesheet (firstthemesheet) gets
// ignored whenever another resource is added until such time as a redraw
// is forced, usually by moving the mouse over the affected element.
2010-07-20 05:19:22 +00:00
$code = html_writer :: tag ( 'script' , '/** Required in order to fix style inclusion problems in IE with YUI **/' , array ( 'id' => 'firstthemesheet' , 'type' => 'text/css' ));
2010-02-07 08:45:21 +00:00
$urls = $this -> cssthemeurls + $this -> cssurls ;
foreach ( $urls as $url ) {
$attributes [ 'href' ] = $url ;
$code .= html_writer :: empty_tag ( 'link' , $attributes ) . " \n " ;
// this id is needed in first sheet only so that theme may override YUI sheets laoded on the fly
unset ( $attributes [ 'id' ]);
}
return $code ;
}
/**
* Adds extra modules specified after printing of page header
*/
protected function get_extra_modules_code () {
if ( empty ( $this -> extramodules )) {
return '' ;
}
return html_writer :: script ( js_writer :: function_call ( 'M.yui.add_module' , array ( $this -> extramodules )));
}
/**
* Generate any HTML that needs to go inside the < head > tag .
*
* Normally , this method is called automatically by the code that prints the
* < head > tag . You should not normally need to call it in your own code .
*
* @ return string the HTML code to to inside the < head > tag .
*/
public function get_head_code ( moodle_page $page , core_renderer $renderer ) {
global $CFG ;
// note: the $page and $output are not stored here because it would
// create circular references in memory which prevents garbage collection
$this -> init_requirements_data ( $page , $renderer );
// yui3 JS and CSS is always loaded first - it is cached in browser
$output = $this -> get_yui3lib_headcode ();
// BC: load basic YUI2 for now, all yui2 things should be loaded via Y.use('yui2-oldmodulename')
$output .= $this -> get_yui2lib_code ();
// now theme CSS + custom CSS in this specific order
$output .= $this -> get_css_code ();
// set up global YUI3 loader object - this should contain all code needed by plugins
// note: in JavaScript just use "YUI(M.yui.loader).use('overlay', function(Y) { .... });"
// this needs to be done before including any other script
2010-07-01 02:26:21 +00:00
$js = " var M = { }; M.yui = { }; var moodleConfigFn = function(me) { var p = me.path, b = me.name.replace(/^moodle-/,'').split('-', 3), n = b.pop();if (/(skin|core)/.test(n)) { n = b.pop();me.type = 'css';};me.path = b.join('-')+'/'+n+'/'+n+'.'+me.type;}; var galleryConfigFn = function(me) { var p = me.path,v=M.yui.galleryversion,f;if(/-(skin|core)/.test(me.name)) { me.type = 'css';p = p.replace(/-(skin|core)/, '').replace(/ \ .js/, '.css').split('/'), f = p.pop().replace(/( \ -(min|debug))/, '');if (/-skin/.test(me.name)) { p.splice(p.length,0,v,'assets','skins','sam', f);} else { p.splice(p.length,0,v,'assets', f);};} else { p = p.split('/'), f = p.pop();p.splice(p.length,0,v, f);};me.path = p.join('/');}; \n " ;
$js .= js_writer :: set_variable ( 'M.yui.loader' , $this -> M_yui_loader , false ) . " \n " ;
2010-02-07 08:45:21 +00:00
$js .= js_writer :: set_variable ( 'M.cfg' , $this -> M_cfg , false );
2010-07-01 02:26:21 +00:00
$js = str_replace ( '"@GALLERYCONFIGFN@"' , 'galleryConfigFn' , $js );
$js = str_replace ( '"@MOODLECONFIGFN@"' , 'moodleConfigFn' , $js );
2010-02-07 08:45:21 +00:00
$output .= html_writer :: script ( $js );
// link our main JS file, all core stuff should be there
2010-02-07 12:50:53 +00:00
$output .= html_writer :: script ( '' , $this -> js_fix_url ( '/lib/javascript-static.js' ));
2010-02-07 08:45:21 +00:00
// add variables
if ( $this -> jsinitvariables [ 'head' ]) {
$js = '' ;
foreach ( $this -> jsinitvariables [ 'head' ] as $data ) {
list ( $var , $value ) = $data ;
$js .= js_writer :: set_variable ( $var , $value , true );
}
$output .= html_writer :: script ( $js );
}
// all the other linked things from HEAD - there should be as few as possible
if ( $this -> jsincludes [ 'head' ]) {
foreach ( $this -> jsincludes [ 'head' ] as $url ) {
$output .= html_writer :: script ( '' , $url );
}
}
// mark head sending done, it is not possible to anything there
$this -> headdone = true ;
return $output ;
}
/**
* Generate any HTML that needs to go at the start of the < body > tag .
*
* Normally , this method is called automatically by the code that prints the
* < head > tag . You should not normally need to call it in your own code .
*
* @ return string the HTML code to go at the start of the < body > tag .
*/
public function get_top_of_body_code () {
// first the skip links
$links = '' ;
$attributes = array ( 'class' => 'skip' );
foreach ( $this -> skiplinks as $url => $text ) {
$attributes [ 'href' ] = '#' . $url ;
2010-02-18 18:15:56 +00:00
$links .= html_writer :: tag ( 'a' , $text , $attributes );
2010-02-07 08:45:21 +00:00
}
2010-02-18 18:15:56 +00:00
$output = html_writer :: tag ( 'div' , $links , array ( 'class' => 'skiplinks' )) . " \n " ;
2010-02-07 08:45:21 +00:00
// then the clever trick for hiding of things not needed when JS works
$output .= html_writer :: script ( " document.body.className += ' jsenabled'; " ) . " \n " ;
$this -> topofbodydone = true ;
return $output ;
}
/**
* Generate any HTML that needs to go at the end of the page .
*
* Normally , this method is called automatically by the code that prints the
* page footer . You should not normally need to call it in your own code .
*
* @ return string the HTML code to to at the end of the page .
*/
public function get_end_code () {
2010-05-04 08:29:05 +00:00
global $CFG ;
2010-02-07 08:45:21 +00:00
// add other requested modules
$output = $this -> get_extra_modules_code ();
// add missing YUI2 YUI - to be removed once we convert everything to YUI3!
$output .= $this -> get_yui2lib_code ();
2010-05-04 08:29:05 +00:00
2010-02-07 08:45:21 +00:00
// all the other linked scripts - there should be as few as possible
if ( $this -> jsincludes [ 'footer' ]) {
foreach ( $this -> jsincludes [ 'footer' ] as $url ) {
$output .= html_writer :: script ( '' , $url );
}
}
// add all needed strings
if ( ! empty ( $this -> stringsforjs )) {
2010-02-07 09:43:07 +00:00
$output .= html_writer :: script ( js_writer :: set_variable ( 'M.str' , $this -> stringsforjs ));
2010-02-07 08:45:21 +00:00
}
// add variables
if ( $this -> jsinitvariables [ 'footer' ]) {
$js = '' ;
foreach ( $this -> jsinitvariables [ 'footer' ] as $data ) {
list ( $var , $value ) = $data ;
$js .= js_writer :: set_variable ( $var , $value , true );
}
$output .= html_writer :: script ( $js );
}
$inyuijs = $this -> get_javascript_code ( false );
$ondomreadyjs = $this -> get_javascript_code ( true );
$jsinit = $this -> get_javascript_init_code ();
$handlersjs = $this -> get_event_handler_code ();
2010-02-07 12:50:53 +00:00
// there is no global Y, make sure it is available in your scope
2010-02-07 08:45:21 +00:00
$js = " YUI(M.yui.loader).use('node', function(Y) { \n { $inyuijs } { $ondomreadyjs } { $jsinit } { $handlersjs } \n }); " ;
$output .= html_writer :: script ( $js );
return $output ;
}
/**
* @ return boolean Have we already output the code in the < head > tag ?
*/
public function is_head_done () {
return $this -> headdone ;
}
/**
* @ return boolean Have we already output the code at the start of the < body > tag ?
*/
public function is_top_of_body_done () {
return $this -> topofbodydone ;
}
}
2010-02-07 12:50:53 +00:00
/**
* Invalidate all server and client side JS caches .
* @ return void
*/
function js_reset_all_caches () {
global $CFG ;
require_once ( " $CFG->libdir /filelib.php " );
set_config ( 'jsrev' , empty ( $CFG -> jsrev ) ? 1 : $CFG -> jsrev + 1 );
2011-08-11 03:25:38 +09:30
fulldelete ( " $CFG->cachedir /js " );
2010-02-07 12:50:53 +00:00
}