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 .
*
2012-01-05 13:28:24 +13:00
* Note : you can find history of this file in lib / ajax / ajaxlib . php
*
* @ copyright 2009 Tim Hunt , 2010 Petr Skoda
* @ license http :// www . gnu . org / copyleft / gpl . html GNU GPL v3 or later
2012-02-14 18:24:09 +13:00
* @ package core
2012-01-11 10:40:55 +13:00
* @ category output
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
/**
* 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
2012-01-05 13:28:24 +13:00
* @ license http :// www . gnu . org / copyleft / gpl . html GNU GPL v3 or later
2010-02-07 08:45:21 +00:00
* @ since Moodle 2.0
2012-02-14 18:24:09 +13:00
* @ package core
2012-01-11 10:40:55 +13:00
* @ category output
2010-02-07 08:45:21 +00:00
*/
class page_requirements_manager {
2012-01-05 13:28:24 +13:00
/**
2012-01-11 10:40:55 +13:00
* @ var array List of string available from JS
2012-01-05 13:28:24 +13:00
*/
2010-02-07 08:45:21 +00:00
protected $stringsforjs = array ();
2012-01-05 13:28:24 +13:00
2012-06-21 09:58:45 +02:00
/**
* @ var array List of get_string $a parameters - used for validation only .
*/
protected $stringsforjs_as = array ();
2012-01-05 13:28:24 +13:00
/**
2012-01-11 10:40:55 +13:00
* @ var array List of JS variables to be initialised
2012-01-05 13:28:24 +13:00
*/
2010-02-07 08:45:21 +00:00
protected $jsinitvariables = array ( 'head' => array (), 'footer' => array ());
2012-01-05 13:28:24 +13:00
/**
2012-01-11 10:40:55 +13:00
* @ var array Included JS scripts
2012-01-05 13:28:24 +13:00
*/
2010-02-07 08:45:21 +00:00
protected $jsincludes = array ( 'head' => array (), 'footer' => array ());
2012-01-05 13:28:24 +13:00
/**
2012-01-11 10:40:55 +13:00
* @ var array List of needed function calls
2012-01-05 13:28:24 +13:00
*/
2010-02-07 08:45:21 +00:00
protected $jscalls = array ( 'normal' => array (), 'ondomready' => array ());
2012-01-05 13:28:24 +13:00
2010-02-07 08:45:21 +00:00
/**
2012-01-11 10:40:55 +13:00
* @ var array List of skip links , those are needed for accessibility reasons
2010-02-07 08:45:21 +00:00
*/
protected $skiplinks = array ();
2012-01-05 13:28:24 +13:00
2010-02-07 08:45:21 +00:00
/**
2012-01-11 10:40:55 +13:00
* @ var array Javascript code used for initialisation of page , it should
* be relatively small
2010-02-07 08:45:21 +00:00
*/
protected $jsinitcode = array ();
2012-01-05 13:28:24 +13:00
2010-02-07 08:45:21 +00:00
/**
2012-01-11 10:40:55 +13:00
* @ var array of moodle_url Theme sheets , initialised only from core_renderer
2010-02-07 08:45:21 +00:00
*/
protected $cssthemeurls = array ();
2012-01-11 10:40:55 +13:00
2010-02-07 08:45:21 +00:00
/**
2012-01-11 10:40:55 +13:00
* @ var array of moodle_url List of custom theme sheets , these are strongly discouraged !
2010-02-07 08:45:21 +00:00
* Useful mostly only for CSS submitted by teachers that is not part of the theme .
*/
protected $cssurls = array ();
2012-01-05 13:28:24 +13:00
2010-02-07 08:45:21 +00:00
/**
2012-01-11 10:40:55 +13:00
* @ var array List of requested event handlers
2010-02-07 08:45:21 +00:00
*/
protected $eventhandlers = array ();
2012-01-05 13:28:24 +13:00
2010-02-07 08:45:21 +00:00
/**
2012-01-11 10:40:55 +13:00
* @ var array Extra modules
2010-02-07 08:45:21 +00:00
*/
protected $extramodules = array ();
2012-01-05 13:28:24 +13:00
/**
2012-01-11 10:40:55 +13:00
* @ var bool Flag indicated head stuff already printed
2012-01-05 13:28:24 +13:00
*/
2010-02-07 08:45:21 +00:00
protected $headdone = false ;
2012-01-05 13:28:24 +13:00
/**
2012-01-11 10:40:55 +13:00
* @ var bool Flag indicating top of body already printed
2012-01-05 13:28:24 +13:00
*/
2010-02-07 08:45:21 +00:00
protected $topofbodydone = false ;
2012-01-05 13:28:24 +13:00
/**
2012-01-11 10:40:55 +13:00
* @ var stdClass YUI PHPLoader instance responsible for YUI3 loading from PHP only
2012-01-05 13:28:24 +13:00
*/
2010-02-07 08:45:21 +00:00
protected $yui3loader ;
2012-01-05 13:28:24 +13:00
/**
2013-04-19 19:05:33 +01:00
* @ var YUI_config default YUI loader configuration
2012-01-05 13:28:24 +13:00
*/
2012-08-06 10:21:37 +02:00
protected $YUI_config ;
2012-01-05 13:28:24 +13:00
/**
2012-01-11 10:40:55 +13:00
* @ var array Some config vars exposed in JS , please no secret stuff there
2012-01-05 13:28:24 +13:00
*/
2010-02-07 08:45:21 +00:00
protected $M_cfg ;
2012-01-05 13:28:24 +13:00
/**
2012-01-11 10:40:55 +13:00
* @ var array Stores debug backtraces from when JS modules were included in the page
2012-01-05 13:28:24 +13:00
*/
2010-11-12 05:26:47 +00:00
protected $debug_moduleloadstacktraces = array ();
2010-02-07 08:45:21 +00:00
2013-03-19 11:47:31 +01:00
/**
* @ var array list of requested jQuery plugins
*/
protected $jqueryplugins = array ();
/**
* @ var array list of jQuery plugin overrides
*/
protected $jquerypluginoverrides = array ();
2010-02-07 08:45:21 +00:00
/**
* Page requirements constructor .
*/
public function __construct () {
global $CFG ;
2012-06-12 10:13:17 +02:00
// You may need to set up URL rewrite rule because oversized URLs might not be allowed by web server.
$sep = empty ( $CFG -> yuislasharguments ) ? '?' : '/' ;
2012-05-05 15:59:43 +02:00
2011-08-19 10:21:30 +02:00
$this -> yui3loader = new stdClass ();
2013-03-15 15:31:04 +00:00
$this -> YUI_config = new YUI_config ();
2010-02-07 08:45:21 +00:00
2012-08-12 11:41:53 +02:00
// Set up some loader options.
2012-01-15 15:24:34 +01:00
if ( ! empty ( $CFG -> useexternalyui ) and strpos ( $CFG -> httpswwwroot , 'https:' ) !== 0 ) {
2010-02-07 08:45:21 +00:00
$this -> yui3loader -> base = 'http://yui.yahooapis.com/' . $CFG -> yui3version . '/build/' ;
$this -> yui3loader -> comboBase = 'http://yui.yahooapis.com/combo?' ;
} else {
2012-08-05 21:30:18 +02:00
$this -> yui3loader -> base = $CFG -> httpswwwroot . '/lib/yuilib/' . $CFG -> yui3version . '/build/' ;
2012-05-05 15:59:43 +02:00
$this -> yui3loader -> comboBase = $CFG -> httpswwwroot . '/theme/yui_combo.php' . $sep ;
2010-02-07 08:45:21 +00:00
}
2012-08-12 11:41:53 +02:00
// Enable combo loader? This significantly helps with caching and performance!
2010-02-07 08:45:21 +00:00
$this -> yui3loader -> 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
2012-08-12 11:41:53 +02:00
// Set up JS YUI loader helper object.
2012-08-06 10:21:37 +02:00
$this -> YUI_config -> base = $this -> yui3loader -> base ;
$this -> YUI_config -> comboBase = $this -> yui3loader -> comboBase ;
$this -> YUI_config -> combine = $this -> yui3loader -> combine ;
2013-03-16 00:14:56 +00:00
$configname = $this -> YUI_config -> set_config_function ( " if(/-skin|reset|fonts|grids|base/.test(me.name)) { me.type='css';me.path=me.path.replace(/ \ .js/,'.css');me.path=me.path.replace(/ \ /yui2-skin/,'/assets/skins/sam/yui2-skin');} " );
2013-03-15 15:31:04 +00:00
$this -> YUI_config -> add_group ( 'yui2' , array (
2012-08-12 11:41:53 +02:00
// Loader configuration for our 2in3, for now ignores $CFG->useexternalyui.
2013-03-15 15:31:04 +00:00
'base' => $CFG -> httpswwwroot . '/lib/yuilib/2in3/' . $CFG -> yui2version . '/build/' ,
'comboBase' => $CFG -> httpswwwroot . '/theme/yui_combo.php' . $sep ,
'combine' => $this -> yui3loader -> combine ,
'ext' => false ,
'root' => '2in3/' . $CFG -> yui2version . '/build/' ,
'patterns' => array (
'yui2-' => array (
'group' => 'yui2' ,
2013-03-16 00:14:56 +00:00
'configFn' => $configname ,
2012-08-05 21:30:18 +02:00
)
2010-07-01 02:26:21 +00:00
)
2013-03-15 15:31:04 +00:00
));
2013-04-04 10:07:40 +01:00
$configname = $this -> YUI_config -> set_config_function ( " 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;if(me.type !== 'css') { me.path=me.path+'-min';};me.path=me.path+'.'+me.type; " );
2013-03-15 15:31:04 +00:00
$this -> YUI_config -> add_group ( 'moodle' , array (
'name' => 'moodle' ,
'base' => $CFG -> httpswwwroot . '/theme/yui_combo.php' . $sep . 'moodle/' . $jsrev . '/' ,
'combine' => $this -> yui3loader -> combine ,
'comboBase' => $CFG -> httpswwwroot . '/theme/yui_combo.php' . $sep ,
'ext' => false ,
'root' => 'moodle/' . $jsrev . '/' , // Add the rev to the root path so that we can control caching.
'patterns' => array (
'moodle-' => array (
'group' => 'moodle' ,
2013-03-16 00:14:56 +00:00
'configFn' => $configname ,
2013-03-15 15:31:04 +00:00
)
)
));
2012-08-12 11:41:53 +02:00
2013-03-08 05:46:55 +00:00
// Set some more loader options applying to groups too.
if ( debugging ( '' , DEBUG_DEVELOPER )) {
// When debugging is enabled, we want to load the non-minified (RAW) versions of YUI library modules rather
// than the DEBUG versions as these generally generate too much logging for our purposes.
// However we do want the DEBUG versions of our Moodle-specific modules.
// To debug a YUI-specific issue, change the yui3loader->filter value to DEBUG.
$this -> YUI_config -> filter = 'RAW' ;
$this -> YUI_config -> groups [ 'moodle' ][ 'filter' ] = 'DEBUG' ;
// We use the yui3loader->filter setting when writing the YUI3 seed scripts into the header.
$this -> yui3loader -> filter = $this -> YUI_config -> filter ;
$this -> YUI_config -> debug = true ;
} else {
$this -> yui3loader -> filter = null ;
$this -> YUI_config -> debug = false ;
}
2013-03-15 15:33:59 +00:00
// Add the moodle group's module data.
2013-03-18 23:29:57 +00:00
$this -> YUI_config -> add_moodle_metadata ();
2013-03-15 15:33:59 +00:00
2012-08-12 11:41:53 +02:00
// Every page should include definition of following 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' ));
}
/**
* Initialise with the bits of JavaScript that every Moodle page should have .
*
* @ param moodle_page $page
2011-12-10 13:16:18 +01:00
* @ param core_renderer $renderer
2010-02-07 08:45:21 +00:00
*/
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 (),
2012-05-05 14:45:26 +02:00
'slasharguments' => ( int )( ! empty ( $CFG -> slasharguments )),
2010-02-07 08:45:21 +00:00
'theme' => $page -> theme -> name ,
2011-03-12 17:42:52 +01:00
'jsrev' => (( empty ( $CFG -> cachejs ) or empty ( $CFG -> jsrev )) ? - 1 : $CFG -> jsrev ),
2012-09-27 10:58:42 +12:00
'svgicons' => $page -> theme -> use_svg_icons ()
2010-02-07 08:45:21 +00:00
);
if ( debugging ( '' , DEBUG_DEVELOPER )) {
$this -> M_cfg [ 'developerdebug' ] = true ;
}
2012-08-12 11:41:53 +02:00
// 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
2012-08-12 11:41:53 +02:00
// Add strings used on many pages.
2010-02-07 08:45:21 +00:00
$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
2012-08-12 11:41:53 +02:00
// Alter links in top frame to break out of frames.
2010-02-11 13:27:02 +00:00
if ( $page -> pagelayout === 'frametop' ) {
$this -> js_init_call ( 'M.util.init_frametop' );
}
2013-01-15 13:08:25 +13:00
// Include block drag/drop if editing is on
if ( $page -> user_is_editing ()) {
$params = array (
'courseid' => $page -> course -> id ,
'pagetype' => $page -> pagetype ,
'pagelayout' => $page -> pagelayout ,
'subpage' => $page -> subpage ,
'regions' => $page -> blocks -> get_regions (),
'contextid' => $page -> context -> id ,
);
if ( ! empty ( $page -> cm -> id )) {
$params [ 'cmid' ] = $page -> cm -> id ;
}
$page -> requires -> yui_module ( 'moodle-core-blocks' , 'M.core_blocks.init_dragdrop' , array ( $params ), null , true );
}
2010-02-07 08:45:21 +00:00
}
/**
* Ensure that the specified JavaScript file is linked to from this page .
*
2012-08-12 11:41:53 +02:00
* 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 or use / yui / subdirectories for YUI modules .
2010-02-07 08:45:21 +00:00
*
* 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
*/
2012-01-05 13:28:24 +13:00
public function js ( $url , $inhead = false ) {
2010-02-07 08:45:21 +00:00
$url = $this -> js_fix_url ( $url );
$where = $inhead ? 'head' : 'footer' ;
$this -> jsincludes [ $where ][ $url -> out ()] = $url ;
}
2013-03-19 11:47:31 +01:00
/**
* Request inclusion of jQuery library in the page .
*
* NOTE : this should not be used in official Moodle distribution !
*
* We are going to bundle jQuery 1.9 . x until we drop support
* all support for IE 6 - 8. Use $PAGE -> requires -> jquery_plugin ( 'migrate' )
* for code written for earlier jQuery versions .
*
* { @ see http :// docs . moodle . org / dev / jQuery }
*/
public function jquery () {
$this -> jquery_plugin ( 'jquery' );
}
/**
* Request inclusion of jQuery plugin .
*
* NOTE : this should not be used in official Moodle distribution !
*
* jQuery plugins are located in plugin / jquery /* subdirectory ,
* plugin / jquery / plugins . php lists all available plugins .
*
* Included core plugins :
* - jQuery UI
* - jQuery Migrate ( useful for code written for previous UI version )
*
* Add - ons may include extra jQuery plugins in jquery / directory ,
* plugins . php file defines the mapping between plugin names and
* necessary page includes .
*
* Examples :
* < code >
* // file: mod/xxx/view.php
* $PAGE -> requires -> jquery ();
* $PAGE -> requires -> jquery_plugin ( 'ui' );
* $PAGE -> requires -> jquery_plugin ( 'ui-css' );
* </ code >
*
* < code >
* // file: theme/yyy/lib.php
* function theme_yyy_page_init ( moodle_page $page ) {
* $page -> requires -> jquery ();
* $page -> requires -> jquery_plugin ( 'ui' );
* $page -> requires -> jquery_plugin ( 'ui-css' );
* }
* </ code >
*
* < code >
* // file: blocks/zzz/block_zzz.php
* public function get_required_javascript () {
* parent :: get_required_javascript ();
* $this -> page -> requires -> jquery ();
* $page -> requires -> jquery_plugin ( 'ui' );
* $page -> requires -> jquery_plugin ( 'ui-css' );
* }
* </ code >
*
* { @ see http :// docs . moodle . org / dev / jQuery }
*
* @ param string $plugin name of the jQuery plugin as defined in jquery / plugins . php
* @ param string $component name of the component
* @ return bool success
*/
public function jquery_plugin ( $plugin , $component = 'core' ) {
global $CFG ;
if ( $this -> headdone ) {
debugging ( 'Can not add jQuery plugins after starting page output!' );
return false ;
}
if ( $component !== 'core' and in_array ( $plugin , array ( 'jquery' , 'ui' , 'ui-css' , 'migrate' ))) {
debugging ( " jQuery plugin ' $plugin ' is included in Moodle core, other components can not use the same name. " , DEBUG_DEVELOPER );
$component = 'core' ;
} else if ( $component !== 'core' and strpos ( $component , '_' ) === false ) {
// Let's normalise the legacy activity names, Frankenstyle rulez!
$component = 'mod_' . $component ;
}
if ( empty ( $this -> jqueryplugins ) and ( $component !== 'core' or $plugin !== 'jquery' )) {
// Make sure the jQuery itself is always loaded first,
// the order of all other plugins depends on order of $PAGE_>requires->.
$this -> jquery_plugin ( 'jquery' , 'core' );
}
if ( isset ( $this -> jqueryplugins [ $plugin ])) {
// No problem, we already have something, first Moodle plugin to register the jQuery plugin wins.
return true ;
}
$componentdir = get_component_directory ( $component );
if ( ! file_exists ( $componentdir ) or ! file_exists ( " $componentdir /jquery/plugins.php " )) {
debugging ( " Can not load jQuery plugin ' $plugin ', missing plugins.php in component ' $component '. " , DEBUG_DEVELOPER );
return false ;
}
$plugins = array ();
require ( " $componentdir /jquery/plugins.php " );
if ( ! isset ( $plugins [ $plugin ])) {
debugging ( " jQuery plugin ' $plugin ' can not be found in component ' $component '. " , DEBUG_DEVELOPER );
return false ;
}
$this -> jqueryplugins [ $plugin ] = new stdClass ();
$this -> jqueryplugins [ $plugin ] -> plugin = $plugin ;
$this -> jqueryplugins [ $plugin ] -> component = $component ;
$this -> jqueryplugins [ $plugin ] -> urls = array ();
foreach ( $plugins [ $plugin ][ 'files' ] as $file ) {
if ( debugging ( '' , DEBUG_DEVELOPER )) {
if ( ! file_exists ( " $componentdir /jquery/ $file " )) {
debugging ( " Invalid file ' $file ' specified in jQuery plugin ' $plugin ' in component ' $component ' " );
continue ;
}
$file = str_replace ( '.min.css' , '.css' , $file );
$file = str_replace ( '.min.js' , '.js' , $file );
}
if ( ! file_exists ( " $componentdir /jquery/ $file " )) {
debugging ( " Invalid file ' $file ' specified in jQuery plugin ' $plugin ' in component ' $component ' " );
continue ;
}
if ( ! empty ( $CFG -> slasharguments )) {
$url = new moodle_url ( " $CFG->httpswwwroot /theme/jquery.php " );
$url -> set_slashargument ( " / $component / $file " );
} else {
// This is not really good, we need slasharguments for relative links, this means no caching...
$path = realpath ( " $componentdir /jquery/ $file " );
if ( strpos ( $path , $CFG -> dirroot ) === 0 ) {
$url = $CFG -> httpswwwroot . preg_replace ( '/^' . preg_quote ( $CFG -> dirroot , '/' ) . '/' , '' , $path );
$url = new moodle_url ( $url );
} else {
// Bad luck, fix your server!
debugging ( " Moodle jQuery integration requires 'slasharguments' setting to be enabled. " );
continue ;
}
}
$this -> jqueryplugins [ $plugin ] -> urls [] = $url ;
}
return true ;
}
/**
* Request replacement of one jQuery plugin by another .
*
* This is useful when themes want to replace the jQuery UI theme ,
* the problem is that theme can not prevent others from including the core ui - css plugin .
*
* Example :
* 1 / generate new jQuery UI theme and place it into theme / yourtheme / jquery /
* 2 / write theme / yourtheme / jquery / plugins . php
* 3 / init jQuery from theme
*
* < code >
* // file theme/yourtheme/lib.php
* function theme_yourtheme_page_init ( $page ) {
* $page -> requires -> jquery_plugin ( 'yourtheme-ui-css' , 'theme_yourtheme' );
* $page -> requires -> jquery_override_plugin ( 'ui-css' , 'yourtheme-ui-css' );
* }
* </ code >
*
* This code prevents loading of standard 'ui-css' which my be requested by other plugins ,
* the 'yourtheme-ui-css' gets loaded only if some other code requires jquery .
*
* { @ see http :// docs . moodle . org / dev / jQuery }
*
* @ param string $oldplugin original plugin
* @ param string $newplugin the replacement
*/
public function jquery_override_plugin ( $oldplugin , $newplugin ) {
if ( $this -> headdone ) {
debugging ( 'Can not override jQuery plugins after starting page output!' );
return ;
}
$this -> jquerypluginoverrides [ $oldplugin ] = $newplugin ;
}
/**
* Return jQuery related markup for page start .
* @ return string
*/
protected function get_jquery_headcode () {
if ( empty ( $this -> jqueryplugins [ 'jquery' ])) {
// If nobody requested jQuery then do not bother to load anything.
// This may be useful for themes that want to override 'ui-css' only if requested by something else.
return '' ;
}
$included = array ();
$urls = array ();
foreach ( $this -> jqueryplugins as $name => $unused ) {
if ( isset ( $included [ $name ])) {
continue ;
}
if ( array_key_exists ( $name , $this -> jquerypluginoverrides )) {
// The following loop tries to resolve the replacements,
// use max 100 iterations to prevent infinite loop resulting
// in blank page.
$cyclic = true ;
$oldname = $name ;
for ( $i = 0 ; $i < 100 ; $i ++ ) {
$name = $this -> jquerypluginoverrides [ $name ];
if ( ! array_key_exists ( $name , $this -> jquerypluginoverrides )) {
$cyclic = false ;
break ;
}
}
if ( $cyclic ) {
// We can not do much with cyclic references here, let's use the old plugin.
$name = $oldname ;
debugging ( " Cyclic overrides detected for jQuery plugin ' $name ' " );
} else if ( empty ( $name )) {
// Developer requested removal of the plugin.
continue ;
} else if ( ! isset ( $this -> jqueryplugins [ $name ])) {
debugging ( " Unknown jQuery override plugin ' $name ' detected " );
$name = $oldname ;
} else if ( isset ( $included [ $name ])) {
// The plugin was already included, easy.
continue ;
}
}
$plugin = $this -> jqueryplugins [ $name ];
$urls = array_merge ( $urls , $plugin -> urls );
$included [ $name ] = true ;
}
$output = '' ;
$attributes = array ( 'rel' => 'stylesheet' , 'type' => 'text/css' );
foreach ( $urls as $url ) {
if ( preg_match ( '/\.js$/' , $url )) {
$output .= html_writer :: script ( '' , $url );
} else if ( preg_match ( '/\.css$/' , $url )) {
$attributes [ 'href' ] = $url ;
$output .= html_writer :: empty_tag ( 'link' , $attributes ) . " \n " ;
}
}
return $output ;
}
2010-02-07 08:45:21 +00:00
/**
2012-08-12 11:41:53 +02:00
* This method was used to load YUI2 libraries into global scope ,
* use YUI 2 in3 instead . Every YUI2 module is represented as a yui2 -*
* sandboxed module in YUI3 code via Y . YUI2 . property .
2010-02-07 08:45:21 +00:00
*
2012-08-12 11:41:53 +02:00
* { @ see http :// tracker . moodle . org / browse / MDL - 34741 }
2010-02-07 08:45:21 +00:00
*
2012-08-12 11:41:53 +02:00
* @ param string | array $libname
* @ deprecated since 2.4
2010-02-07 08:45:21 +00:00
*/
public function yui2_lib ( $libname ) {
2012-08-12 11:41:53 +02:00
throw new coding_exception ( 'PAGE->yui2_lib() is not available any more, use YUI 2in3 instead, see MDL-34741 for more information.' );
2010-02-07 08:45:21 +00:00
}
/**
* Returns the actual url through which a script is served .
2012-01-05 13:28:24 +13:00
*
2010-02-07 08:45:21 +00:00
* @ 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 ) {
2012-07-05 19:33:06 +02:00
// Fix the admin links if needed.
if ( $CFG -> admin !== 'admin' ) {
if ( strpos ( $url , " /admin/ " ) === 0 ) {
$url = preg_replace ( " |^/admin/| " , " / $CFG->admin / " , $url );
}
}
2010-02-07 08:45:21 +00:00
if ( debugging ()) {
2012-08-12 11:41:53 +02:00
// Check file existence only when in debug mode.
2010-02-07 08:45:21 +00:00
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
}
}
2012-09-07 13:56:16 +02:00
if ( ! empty ( $CFG -> cachejs ) and ! empty ( $CFG -> jsrev ) and $CFG -> jsrev > 0 and substr ( $url , - 3 ) === '.js' ) {
2012-05-05 18:16:50 +02:00
if ( empty ( $CFG -> slasharguments )) {
2012-05-08 19:13:53 +02:00
return new moodle_url ( $CFG -> httpswwwroot . '/lib/javascript.php' , array ( 'rev' => $CFG -> jsrev , 'jsfile' => $url ));
2012-05-05 18:16:50 +02:00
} else {
$returnurl = new moodle_url ( $CFG -> httpswwwroot . '/lib/javascript.php' );
$returnurl -> set_slashargument ( '/' . $CFG -> jsrev . $url );
return $returnurl ;
}
2010-02-07 12:50:53 +00:00
} 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 .
2012-01-05 13:28:24 +13:00
*
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 ) {
2012-03-30 10:11:43 +08:00
global $CFG , $PAGE ;
2010-02-07 08:45:21 +00:00
$module = null ;
2010-04-01 20:54:27 +00:00
if ( strpos ( $component , 'core_' ) === 0 ) {
2012-08-12 11:41:53 +02: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' ,
2013-03-20 00:55:32 +01:00
'requires' => array ( 'base' , 'node' , 'node-event-simulate' , 'json' , 'async-queue' , 'io-base' , 'io-upload-iframe' , 'io-form' , 'yui2-treeview' , 'panel' , 'cookie' , 'datatable' , 'datatable-sort' , 'resize-plugin' , 'dd-plugin' , 'escape' , 'moodle-core_filepicker' ),
2012-05-04 16:46:41 +08:00
'strings' => array ( array ( 'lastmodified' , 'moodle' ), array ( 'name' , 'moodle' ), array ( 'type' , 'repository' ), array ( 'size' , 'repository' ),
array ( 'invalidjson' , 'repository' ), array ( 'error' , 'moodle' ), array ( 'info' , 'moodle' ),
array ( 'nofilesattached' , 'repository' ), array ( 'filepicker' , 'repository' ), array ( 'logout' , 'repository' ),
array ( 'nofilesavailable' , 'repository' ), array ( 'norepositoriesavailable' , 'repository' ),
2011-05-02 10:11:19 +08:00
array ( 'fileexistsdialogheader' , 'repository' ), array ( 'fileexistsdialog_editor' , 'repository' ),
2012-05-15 10:51:00 +08:00
array ( 'fileexistsdialog_filemanager' , 'repository' ), array ( 'renameto' , 'repository' ),
array ( 'referencesexist' , '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' ,
2013-03-08 14:28:28 +08:00
'requires' => array ( 'base' , 'node' , 'event-custom' , 'event-mouseenter' , 'event-resize' , 'escape' ),
'strings' => array ( array ( 'addtodock' , 'block' ), array ( 'undockitem' , 'block' ), array ( 'dockblock' , 'block' ),
array ( 'undockblock' , 'block' ), array ( 'undockall' , 'block' ), array ( 'thisdirectionvertical' , 'langconfig' ),
array ( 'hidedockpanel' , 'block' ), array ( 'hidepanel' , 'block' )
));
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 ;
2011-11-08 20:05:19 +00:00
case 'core_dndupload' :
$module = array ( 'name' => 'core_dndupload' ,
'fullpath' => '/lib/form/dndupload.js' ,
2012-06-16 15:42:07 +01:00
'requires' => array ( 'node' , 'event' , 'json' , 'core_filepicker' ),
2013-01-21 09:51:52 +08:00
'strings' => array ( array ( 'uploadformlimit' , 'moodle' ), array ( 'droptoupload' , 'moodle' ), array ( 'maxfilesreached' , 'moodle' ),
array ( 'dndenabled_inbox' , 'moodle' ), array ( 'fileexists' , 'moodle' ), array ( 'maxbytesforfile' , 'moodle' ),
array ( 'maxareabytesreached' , 'moodle' )
));
2011-11-08 20:05:19 +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 .
2012-01-05 13:28:24 +13:00
* The structure of module array is described at { @ link http :// developer . yahoo . com / yui / 3 / yui / }
*
2010-02-07 08:45:21 +00:00
* @ 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 );
2012-08-12 11:41:53 +02:00
// Add all needed strings.
2010-02-07 09:34:19 +00:00
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 {
2013-03-15 15:31:04 +00:00
$this -> YUI_config -> add_module_config ( $module [ 'name' ], $module );
2010-02-07 08:45:21 +00:00
}
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 .
*
2011-12-10 13:16:18 +01:00
* @ param string | array $module
2010-11-12 05:26:47 +00:00
* @ 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' ];
}
2012-08-06 10:21:37 +02:00
return array_key_exists ( $modulename , $this -> YUI_config -> modules ) ||
2010-11-12 05:26:47 +00:00
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 );
}
2012-08-12 11:41:53 +02:00
$this -> cssurls [ $stylesheet -> out ()] = $stylesheet ;
2010-02-07 08:45:21 +00:00
}
/**
2012-08-12 11:41:53 +02:00
* Add theme stylesheet to page - do not use from plugin code ,
2010-02-07 08:45:21 +00:00
* this should be called only from the core renderer !
2012-01-05 13:28:24 +13:00
*
2010-02-07 08:45:21 +00:00
* @ 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 .
*
2012-08-12 11:41:53 +02:00
* @ param string $target the name of anchor this link should go to . For example 'maincontent' .
* @ param string $linktext The text to use for the skip link . Normally get_string ( 'skipto' , 'access' , ... );
2010-02-07 08:45:21 +00:00
*/
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
*
2012-08-12 11:41:53 +02:00
* @ deprecated
*
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 .
2012-01-05 13:28:24 +13:00
* @ param bool $ondomready If tru the function is only called when the dom is
* ready for manipulation .
* @ param int $delay The delay before the function is called .
2010-02-07 08:45:21 +00:00
*/
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 );
}
/**
2012-08-12 11:41:53 +02:00
* Creates a JavaScript function call that requires one or more modules to be loaded .
2010-07-01 02:26:21 +00:00
*
* 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
*/
2012-10-17 10:14:56 +01:00
public function yui_module ( $modules , $function , array $arguments = null , $galleryversion = null , $ondomready = false ) {
2010-09-17 08:04:01 +00:00
global $CFG ;
2012-10-17 10:14:56 +01:00
if ( ! $galleryversion ) {
$galleryversion = '2010.04.08-12-35' ;
}
2010-06-04 01:49:53 +00:00
if ( ! is_array ( $modules )) {
$modules = array ( $modules );
}
2012-06-19 11:26:23 +12:00
if ( empty ( $CFG -> useexternalyui )) {
2010-06-04 01:49:53 +00:00
// 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
}
2012-03-28 11:38:53 +08:00
$jscode .= 'Y.use(' . join ( ',' , array_map ( 'json_encode' , convert_to_array ( $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
*/
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 ) {
2012-08-12 11:41:53 +02:00
// Detect module automatically.
2010-02-07 08:45:21 +00:00
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 .
2012-08-12 11:41:53 +02:00
*
2010-02-07 08:45:21 +00:00
* @ 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
*/
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 :
*
2012-08-12 11:41:53 +02:00
* // Require the string in PHP and replace the placeholder.
2010-11-02 14:59:32 +00:00
* $PAGE -> requires -> string_for_js ( 'fullnamedisplay' , 'moodle' , $USER );
2012-08-12 11:41:53 +02:00
* // Use the result of the substitution in Javascript.
2010-11-02 14:59:32 +00:00
* alert ( M . str . moodle . fullnamedisplay );
*
* To substitute the placeholder at client side , use M . util . get_string ()
2012-02-14 18:24:09 +13:00
* function . It implements the same logic as { @ link get_string ()} :
2010-11-02 14:59:32 +00:00
*
2012-08-12 11:41:53 +02:00
* // Require the string in PHP but keep {$a} as it is.
2010-11-02 14:59:32 +00:00
* $PAGE -> requires -> string_for_js ( 'fullnamedisplay' , 'moodle' );
2012-08-12 11:41:53 +02:00
* // Provide the values on the fly in Javascript.
2010-11-02 14:59:32 +00:00
* 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 .
2011-12-10 13:16:18 +01:00
* @ param string $component the language file to look in .
2010-02-07 08:45:21 +00:00
* @ param mixed $a any extra data to add into the string ( optional ) .
*/
2012-08-12 11:41:53 +02:00
public function string_for_js ( $identifier , $component , $a = null ) {
2010-02-07 08:45:21 +00:00
if ( ! $component ) {
2012-06-21 09:58:45 +02:00
throw new coding_exception ( 'The $component parameter is required for page_requirements_manager::string_for_js().' );
2010-02-07 08:45:21 +00:00
}
2012-06-21 09:58:45 +02:00
if ( isset ( $this -> stringsforjs_as [ $component ][ $identifier ]) and $this -> stringsforjs_as [ $component ][ $identifier ] !== $a ) {
2010-02-07 08:45:21 +00:00
throw new coding_exception ( " Attempt to re-define already required string ' $identifier ' " .
2012-06-21 09:58:45 +02:00
" from lang file ' $component ' with different \$ a parameter? " );
}
if ( ! isset ( $this -> stringsforjs [ $component ][ $identifier ])) {
$this -> stringsforjs [ $component ][ $identifier ] = new lang_string ( $identifier , $component , $a );
$this -> stringsforjs_as [ $component ][ $identifier ] = $a ;
2010-02-07 08:45:21 +00:00
}
}
/**
2012-08-12 11:41:53 +02:00
* Make an array of language strings available for JS .
2010-02-07 08:45:21 +00:00
*
* 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
*
2012-08-12 11:41:53 +02:00
* // The above is identical 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 .
*
*/
2012-08-12 11:41:53 +02:00
public function strings_for_js ( $identifiers , $component , $a = null ) {
2010-02-07 08:45:21 +00:00
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' .
2012-08-12 11:41:53 +02:00
*
* @ deprecated
2010-02-07 08:45:21 +00:00
* @ 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 .
*
2012-08-12 11:41:53 +02:00
* @ param mixed $selector standard YUI selector for elements , may be array or string , element id is in the form " #idvalue "
2010-02-07 08:45:21 +00:00
* @ 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
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 .
2011-12-10 13:16:18 +01:00
* @ param bool $ondomready
* @ return string
2010-02-07 08:45:21 +00:00
*/
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 .
2012-01-05 13:28:24 +13:00
* @ return string
2010-02-07 08:45:21 +00:00
*/
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 .
*
2013-03-14 15:59:03 +01:00
* @ param moodle_page $page
2010-02-07 08:45:21 +00:00
* @ return string
*/
2013-03-14 15:59:03 +01:00
protected function get_yui3lib_headcode ( $page ) {
2011-08-19 10:21:30 +02:00
global $CFG ;
$code = '' ;
if ( $this -> yui3loader -> combine ) {
2013-03-14 15:59:03 +01:00
if ( ! empty ( $page -> theme -> yuicssmodules )) {
$modules = array ();
foreach ( $page -> theme -> yuicssmodules as $module ) {
$modules [] = " $CFG->yui3version /build/ $module / $module -min.css " ;
}
$code .= '<link rel="stylesheet" type="text/css" href="' . $this -> yui3loader -> comboBase . implode ( '&' , $modules ) . '" />' ;
}
2012-10-24 22:18:23 +08:00
$code .= '<script type="text/javascript" src="' . $this -> yui3loader -> comboBase
. $CFG -> yui3version . '/build/simpleyui/simpleyui-min.js&'
. $CFG -> yui3version . '/build/loader/loader-min.js"></script>' ;
2011-08-19 10:21:30 +02:00
} else {
2013-03-14 15:59:03 +01:00
if ( ! empty ( $page -> theme -> yuicssmodules )) {
foreach ( $page -> theme -> yuicssmodules as $module ) {
$code .= '<link rel="stylesheet" type="text/css" href="' . $this -> yui3loader -> base . $module . '/' . $module . '-min.css" />' ;
}
}
2012-10-24 22:18:23 +08:00
$code .= '<script type="text/javascript" src="' . $this -> yui3loader -> base . 'simpleyui/simpleyui-min.js"></script>' ;
$code .= '<script type="text/javascript" src="' . $this -> yui3loader -> base . 'loader/loader-min.js"></script>' ;
2011-08-19 10:21:30 +02:00
}
2011-12-10 13:46:15 +01:00
2012-08-05 21:30:18 +02:00
if ( $this -> yui3loader -> filter === 'RAW' ) {
2011-12-10 13:46:15 +01:00
$code = str_replace ( '-min.css' , '.css' , $code );
$code = str_replace ( '-min.js' , '.js' , $code );
2012-08-05 21:30:18 +02:00
} else if ( $this -> yui3loader -> filter === 'DEBUG' ) {
2011-12-10 13:46:15 +01:00
$code = str_replace ( '-min.css' , '.css' , $code );
$code = str_replace ( '-min.js' , '-debug.js' , $code );
2011-08-19 10:21:30 +02:00
}
2010-02-07 08:45:21 +00:00
return $code ;
}
/**
2012-08-12 11:41:53 +02:00
* Returns html tags needed for inclusion of theme CSS .
2012-01-05 13:28:24 +13:00
*
2010-02-07 08:45:21 +00:00
* @ 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 " ;
2012-08-12 11:41:53 +02:00
// This id is needed in first sheet only so that theme may override YUI sheets loaded on the fly.
2010-02-07 08:45:21 +00:00
unset ( $attributes [ 'id' ]);
}
return $code ;
}
/**
2012-08-12 11:41:53 +02:00
* Adds extra modules specified after printing of page header .
2012-01-05 13:28:24 +13:00
*
2011-12-10 13:16:18 +01:00
* @ return string
2010-02-07 08:45:21 +00:00
*/
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 .
*
2011-12-10 13:16:18 +01:00
* @ param moodle_page $page
* @ param core_renderer $renderer
2010-02-07 08:45:21 +00:00
* @ return string the HTML code to to inside the < head > tag .
*/
public function get_head_code ( moodle_page $page , core_renderer $renderer ) {
global $CFG ;
2012-08-12 11:41:53 +02:00
// Note: the $page and $output are not stored here because it would
// create circular references in memory which prevents garbage collection.
2010-02-07 08:45:21 +00:00
$this -> init_requirements_data ( $page , $renderer );
2013-03-16 12:57:15 +00:00
$output = '' ;
2010-02-07 08:45:21 +00:00
2013-04-19 19:05:33 +01:00
// Set up the M namespace.
$js = " var M = { }; M.yui = { }; \n " ;
// Capture the time now ASAP during page load. This minimises the lag when
// we try to relate times on the server to times in the browser.
// An example of where this is used is the quiz countdown timer.
$js .= " M.pageloadstarttime = new Date(); \n " ;
// Add a subset of Moodle configuration to the M namespace.
$js .= js_writer :: set_variable ( 'M.cfg' , $this -> M_cfg , false );
2012-08-12 11:41:53 +02:00
// Set up global YUI3 loader object - this should contain all code needed by plugins.
// Note: in JavaScript just use "YUI().use('overlay', function(Y) { .... });",
// this needs to be done before including any other script.
2013-03-16 00:14:56 +00:00
$js .= $this -> YUI_config -> get_config_functions ();
2012-08-06 10:21:37 +02:00
$js .= js_writer :: set_variable ( 'YUI_config' , $this -> YUI_config , false ) . " \n " ;
2012-08-12 11:41:53 +02:00
$js .= " M.yui.loader = { modules: { }}; \n " ; // Backwards compatibility only, not used any more.
2013-03-16 00:14:56 +00:00
$js = $this -> YUI_config -> update_header_js ( $js );
2013-04-19 19:05:33 +01:00
2010-02-07 08:45:21 +00:00
$output .= html_writer :: script ( $js );
2013-03-16 12:57:15 +00:00
// YUI3 JS and CSS need to be loaded in the header but after the YUI_config has been created.
// They should be cached well by the browser.
$output .= $this -> get_yui3lib_headcode ( $page );
2013-03-19 11:47:31 +01:00
// Add hacked jQuery support, it is not intended for standard Moodle distribution!
$output .= $this -> get_jquery_headcode ();
2013-03-16 12:57:15 +00:00
// Now theme CSS + custom CSS in this specific order.
$output .= $this -> get_css_code ();
2012-08-12 11:41:53 +02:00
// 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
2012-08-12 11:41:53 +02:00
// Add variables.
2010-02-07 08:45:21 +00:00
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 );
}
2012-08-12 11:41:53 +02:00
// All the other linked things from HEAD - there should be as few as possible.
2010-02-07 08:45:21 +00:00
if ( $this -> jsincludes [ 'head' ]) {
foreach ( $this -> jsincludes [ 'head' ] as $url ) {
$output .= html_writer :: script ( '' , $url );
}
}
2012-08-12 11:41:53 +02:00
// Mark head sending done, it is not possible to anything there.
2010-02-07 08:45:21 +00:00
$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 () {
2012-08-12 11:41:53 +02:00
// First the skip links.
2010-02-07 08:45:21 +00:00
$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
2012-08-12 11:41:53 +02:00
// Then the clever trick for hiding of things not needed when JS works.
2010-02-07 08:45:21 +00:00
$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 ;
2012-08-12 11:41:53 +02:00
// Add other requested modules.
2010-02-07 08:45:21 +00:00
$output = $this -> get_extra_modules_code ();
2012-08-12 11:41:53 +02:00
// All the other linked scripts - there should be as few as possible.
2010-02-07 08:45:21 +00:00
if ( $this -> jsincludes [ 'footer' ]) {
foreach ( $this -> jsincludes [ 'footer' ] as $url ) {
$output .= html_writer :: script ( '' , $url );
}
}
2012-08-12 11:41:53 +02:00
// Add all needed strings.
2010-02-07 08:45:21 +00:00
if ( ! empty ( $this -> stringsforjs )) {
2012-06-21 09:58:45 +02:00
$strings = array ();
foreach ( $this -> stringsforjs as $component => $v ) {
foreach ( $v as $indentifier => $langstring ) {
$strings [ $component ][ $indentifier ] = $langstring -> out ();
}
}
$output .= html_writer :: script ( js_writer :: set_variable ( 'M.str' , $strings ));
2010-02-07 08:45:21 +00:00
}
2012-08-12 11:41:53 +02:00
// Add variables.
2010-02-07 08:45:21 +00:00
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 ();
2012-08-12 11:41:53 +02:00
// There is no global Y, make sure it is available in your scope.
2012-08-06 10:21:37 +02:00
$js = " YUI().use('node', function(Y) { \n { $inyuijs } { $ondomreadyjs } { $jsinit } { $handlersjs } \n }); " ;
2010-02-07 08:45:21 +00:00
$output .= html_writer :: script ( $js );
return $output ;
}
/**
2012-01-05 13:28:24 +13:00
* Have we already output the code in the < head > tag ?
*
2012-01-12 12:55:50 +13:00
* @ return bool
2010-02-07 08:45:21 +00:00
*/
public function is_head_done () {
return $this -> headdone ;
}
/**
2012-01-05 13:28:24 +13:00
* Have we already output the code at the start of the < body > tag ?
*
2012-01-12 12:55:50 +13:00
* @ return bool
2010-02-07 08:45:21 +00:00
*/
public function is_top_of_body_done () {
return $this -> topofbodydone ;
}
}
2010-02-07 12:50:53 +00:00
2013-03-15 15:31:04 +00:00
/**
* This class represents the YUI configuration .
*
2013-03-18 23:52:39 +00:00
* @ copyright 2013 Andrew Nicols
2013-03-15 15:31:04 +00:00
* @ license http :// www . gnu . org / copyleft / gpl . html GNU GPL v3 or later
* @ since Moodle 2.5
* @ package core
* @ category output
*/
class YUI_config {
2013-03-16 00:14:56 +00:00
/**
* These settings must be public so that when the object is converted to json they are exposed .
2013-03-18 23:16:59 +00:00
* Note : Some of these are camelCase because YUI uses camelCase variable names .
*
* The settings are described and documented in the YUI API at :
2013-03-16 00:14:56 +00:00
* - http :// yuilibrary . com / yui / docs / api / classes / config . html
* - http :// yuilibrary . com / yui / docs / api / classes / Loader . html
*/
2013-03-15 15:31:04 +00:00
public $debug = false ;
public $base ;
public $comboBase ;
public $combine ;
public $filter = null ;
public $insertBefore = 'firstthemesheet' ;
public $groups = array ();
public $modules = array ();
2013-03-16 00:14:56 +00:00
/**
* @ var array List of functions used by the YUI Loader group pattern recognition .
*/
protected $jsconfigfunctions = array ();
2013-03-15 15:31:04 +00:00
/**
* Create a new group within the YUI_config system .
*
* @ param String $name The name of the group . This must be unique and
* not previously used .
* @ param Array $config The configuration for this group .
* @ return void
*/
public function add_group ( $name , $config ) {
if ( isset ( $this -> groups [ $name ])) {
2013-03-15 15:33:59 +00:00
throw new coding_exception ( " A YUI configuration group for ' { $name } ' already exists. To make changes to this group use YUI_config->update_group(). " );
2013-03-15 15:31:04 +00:00
}
$this -> groups [ $name ] = $config ;
}
/**
* Update an existing group configuration
*
* Note , any existing configuration for that group will be wiped out .
* This includes module configuration .
*
* @ param String $name The name of the group . This must be unique and
* not previously used .
* @ param Array $config The configuration for this group .
* @ return void
*/
public function update_group ( $name , $config ) {
if ( ! isset ( $this -> groups [ $name ])) {
2013-03-15 15:33:59 +00:00
throw new coding_exception ( 'The Moodle YUI module does not exist. You must define the moodle module config using YUI_config->add_module_config first.' );
2013-03-15 15:31:04 +00:00
}
$this -> groups [ $name ] = $config ;
}
2013-03-16 00:14:56 +00:00
/**
* Set the value of a configuration function used by the YUI Loader ' s pattern testing .
*
* Only the body of the function should be passed , and not the whole function wrapper .
*
* The JS function your write will be passed a single argument 'name' containing the
* name of the module being loaded .
*
* @ param $function String the body of the JavaScript function . This should be used i
* @ return String the name of the function to use in the group pattern configuration .
*/
public function set_config_function ( $function ) {
$configname = 'yui' . ( count ( $this -> jsconfigfunctions ) + 1 ) . 'ConfigFn' ;
if ( isset ( $this -> jsconfigfunctions [ $configname ])) {
throw new coding_exception ( " A YUI config function with this name already exists. Config function names must be unique. " );
}
$this -> jsconfigfunctions [ $configname ] = $function ;
return '@' . $configname . '@' ;
}
/**
* Retrieve the list of JavaScript functions for YUI_config groups .
*
* @ return String The complete set of config functions
*/
public function get_config_functions () {
$configfunctions = '' ;
foreach ( $this -> jsconfigfunctions as $functionname => $function ) {
$configfunctions .= " var { $functionname } = function(me) { " ;
$configfunctions .= $function ;
$configfunctions .= " }; \n " ;
}
return $configfunctions ;
}
/**
* Update the header JavaScript with any required modification for the YUI Loader .
*
* @ param $js String The JavaScript to manipulate .
* @ return String the modified JS string .
*/
public function update_header_js ( $js ) {
// Update the names of the the configFn variables.
// The PHP json_encode function cannot handle literal names so we have to wrap
// them in @ and then replace them with literals of the same function name.
foreach ( $this -> jsconfigfunctions as $functionname => $function ) {
$js = str_replace ( '"@' . $functionname . '@"' , $functionname , $js );
}
return $js ;
}
2013-03-15 15:31:04 +00:00
/**
* Add configuration for a specific module .
*
* @ param String $name The name of the module to add configuration for .
* @ param Array $config The configuration for the specified module .
* @ param String $group The name of the group to add configuration for .
* If not specified , then this module is added to the global
* configuration .
* @ return void
*/
public function add_module_config ( $name , $config , $group = null ) {
if ( $group ) {
if ( ! isset ( $this -> groups [ $name ])) {
2013-03-15 15:33:59 +00:00
throw new coding_exception ( 'The Moodle YUI module does not exist. You must define the moodle module config using YUI_config->add_module_config first.' );
2013-03-15 15:31:04 +00:00
}
if ( ! isset ( $this -> groups [ $group ][ 'modules' ])) {
$this -> groups [ $group ][ 'modules' ] = array ();
}
$modules = & $this -> groups [ $group ][ 'modules' ];
} else {
$modules = & $this -> modules ;
}
$modules [ $name ] = $config ;
}
2013-03-15 15:33:59 +00:00
/**
2013-03-18 23:29:57 +00:00
* Add the moodle YUI module metadata for the moodle group to the YUI_config instance .
2013-03-15 15:33:59 +00:00
*
* If js caching is disabled , metadata will not be served causing YUI to calculate
* module dependencies as each module is loaded .
*
* If metadata does not exist it will be created and stored in a MUC entry .
*
2013-03-18 23:29:57 +00:00
* @ return void
2013-03-15 15:33:59 +00:00
*/
2013-03-18 23:29:57 +00:00
public function add_moodle_metadata () {
2013-03-15 15:33:59 +00:00
global $CFG ;
if ( ! isset ( $this -> groups [ 'moodle' ])) {
throw new coding_exception ( 'The Moodle YUI module does not exist. You must define the moodle module config using YUI_config->add_module_config first.' );
}
if ( ! isset ( $this -> groups [ 'moodle' ][ 'modules' ])) {
$this -> groups [ 'moodle' ][ 'modules' ] = array ();
}
$cache = cache :: make ( 'core' , 'yuimodules' );
2013-03-27 13:12:58 +00:00
if ( ! isset ( $CFG -> jsrev ) || $CFG -> jsrev == - 1 ) {
2013-03-15 15:33:59 +00:00
$metadata = array ();
$cache -> delete ( 'metadata' );
} else {
// Attempt to get the metadata from the cache.
if ( ! $metadata = $cache -> get ( 'metadata' )) {
$metadata = $this -> get_moodle_metadata ();
$cache -> set ( 'metadata' , $metadata );
}
}
// Merge with any metadata added specific to this page which was added manually.
$this -> groups [ 'moodle' ][ 'modules' ] = array_merge ( $this -> groups [ 'moodle' ][ 'modules' ],
$metadata );
}
/**
* Determine the module metadata for all moodle YUI modules .
*
* This works through all modules capable of serving YUI modules , and attempts to get
* metadata for each of those modules .
*
* @ return Array of module metadata
*/
private function get_moodle_metadata () {
$moodlemodules = array ();
2013-03-18 23:52:39 +00:00
// Core isn't a plugin type or subsystem - handle it seperately.
2013-03-15 15:33:59 +00:00
if ( $module = $this -> get_moodle_path_metadata ( get_component_directory ( 'core' ))) {
$moodlemodules = array_merge ( $moodlemodules , $module );
}
2013-03-18 23:52:39 +00:00
// Handle other core subsystems.
2013-06-07 18:15:28 +02:00
$subsystems = core_component :: get_core_subsystems ();
2013-03-18 23:52:39 +00:00
foreach ( $subsystems as $subsystem => $path ) {
if ( is_null ( $path )) {
continue ;
}
if ( $module = $this -> get_moodle_path_metadata ( $path )) {
$moodlemodules = array_merge ( $moodlemodules , $module );
}
}
// And finally the plugins.
2013-06-07 18:15:28 +02:00
$plugintypes = core_component :: get_plugin_types ();
2013-03-18 23:52:39 +00:00
foreach ( $plugintypes as $plugintype => $pathroot ) {
2013-03-15 15:33:59 +00:00
$pluginlist = get_plugin_list ( $plugintype );
foreach ( $pluginlist as $plugin => $path ) {
if ( $module = $this -> get_moodle_path_metadata ( $path )) {
$moodlemodules = array_merge ( $moodlemodules , $module );
}
}
}
return $moodlemodules ;
}
/**
* Helper function process and return the YUI metadata for all of the modules under the specified path .
*
* @ param String $path the UNC path to the YUI src directory .
* @ return Array the complete array for frankenstyle directory .
*/
private function get_moodle_path_metadata ( $path ) {
// Add module metadata is stored in frankenstyle_modname/yui/src/yui_modname/meta/yui_modname.json.
$baseyui = $path . '/yui/src' ;
$modules = array ();
if ( is_dir ( $baseyui )) {
$items = new DirectoryIterator ( $baseyui );
foreach ( $items as $item ) {
if ( $item -> isDot () or ! $item -> isDir ()) {
continue ;
}
$metafile = realpath ( $baseyui . '/' . $item . '/meta/' . $item . '.json' );
2013-03-18 23:52:39 +00:00
if ( ! is_readable ( $metafile )) {
continue ;
}
2013-03-15 15:33:59 +00:00
$metadata = file_get_contents ( $metafile );
$modules = array_merge ( $modules , ( array ) json_decode ( $metadata ));
}
}
return $modules ;
}
2013-03-15 15:31:04 +00:00
}
2010-02-07 12:50:53 +00:00
/**
* Invalidate all server and client side JS caches .
*/
function js_reset_all_caches () {
global $CFG ;
require_once ( " $CFG->libdir /filelib.php " );
2012-05-23 11:11:13 +02:00
$next = time ();
if ( isset ( $CFG -> jsrev ) and $next <= $CFG -> jsrev and $CFG -> jsrev - $next < 60 * 60 ) {
// This resolves problems when reset is requested repeatedly within 1s,
// the < 1h condition prevents accidental switching to future dates
// because we might not recover from it.
$next = $CFG -> jsrev + 1 ;
}
set_config ( 'jsrev' , $next );
2011-08-11 03:25:38 +09:30
fulldelete ( " $CFG->cachedir /js " );
2012-05-12 04:14:53 +08:00
}