Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/lib/outputrequirementslib.php
Go to the documentation of this file.
00001 <?php
00002 
00003 // This file is part of Moodle - http://moodle.org/
00004 //
00005 // Moodle is free software: you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License as published by
00007 // the Free Software Foundation, either version 3 of the License, or
00008 // (at your option) any later version.
00009 //
00010 // Moodle is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License
00016 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
00017 
00018 
00028 defined('MOODLE_INTERNAL') || die();
00029 
00030 // note: you can find history of this file in lib/ajax/ajaxlib.php
00031 
00059 class page_requirements_manager {
00061     protected $stringsforjs = array();
00063     protected $jsinitvariables = array('head'=>array(), 'footer'=>array());
00065     protected $jsincludes = array('head'=>array(), 'footer'=>array());
00067     protected $jscalls = array('normal'=>array(), 'ondomready'=>array());
00072     protected $skiplinks = array();
00077     protected $jsinitcode = array();
00082     protected $cssthemeurls = array();
00088     protected $cssurls = array();
00093     protected $eventhandlers = array();
00098     protected $extramodules = array();
00100     protected $headdone = false;
00102     protected $topofbodydone = false;
00103 
00105     protected $yui2loader;
00107     protected $yui3loader;
00109     protected $M_yui_loader;
00111     protected $M_cfg;
00113     protected $debug_moduleloadstacktraces = array();
00114 
00118     public function __construct() {
00119         global $CFG;
00120 
00121         require_once("$CFG->libdir/yui/phploader/phploader/loader.php");
00122 
00123         $this->yui3loader = new stdClass();
00124         $this->yui2loader = new YAHOO_util_Loader($CFG->yui2version);
00125 
00126         // set up some loader options
00127         if (debugging('', DEBUG_DEVELOPER)) {
00128             $this->yui3loader->filter = YUI_RAW; // for more detailed logging info use YUI_DEBUG here
00129             $this->yui2loader->filter = YUI_RAW; // for more detailed logging info use YUI_DEBUG here
00130             $this->yui2loader->allowRollups = false;
00131         } else {
00132             $this->yui3loader->filter = null;
00133             $this->yui2loader->filter = null;
00134         }
00135         if (!empty($CFG->useexternalyui) and strpos($CFG->httpswwwroot, 'https:') !== 0) {
00136             $this->yui3loader->base = 'http://yui.yahooapis.com/' . $CFG->yui3version . '/build/';
00137             $this->yui2loader->base = 'http://yui.yahooapis.com/' . $CFG->yui2version . '/build/';
00138             $this->yui3loader->comboBase = 'http://yui.yahooapis.com/combo?';
00139             $this->yui2loader->comboBase = 'http://yui.yahooapis.com/combo?';
00140         } else {
00141             $this->yui3loader->base = $CFG->httpswwwroot . '/lib/yui/'. $CFG->yui3version . '/build/';
00142             $this->yui2loader->base = $CFG->httpswwwroot . '/lib/yui/'. $CFG->yui2version . '/build/';
00143             $this->yui3loader->comboBase = $CFG->httpswwwroot . '/theme/yui_combo.php?';
00144             $this->yui2loader->comboBase = $CFG->httpswwwroot . '/theme/yui_combo.php?';
00145         }
00146 
00147         // enable combo loader? this significantly helps with caching and performance!
00148         $this->yui3loader->combine = !empty($CFG->yuicomboloading);
00149         $this->yui2loader->combine = !empty($CFG->yuicomboloading);
00150 
00151         if (empty($CFG->cachejs)) {
00152             $jsrev = -1;
00153         } else if (empty($CFG->jsrev)) {
00154             $jsrev = 1;
00155         } else {
00156             $jsrev = $CFG->jsrev;
00157         }
00158 
00159         // set up JS YUI loader helper object
00160         $this->M_yui_loader = new stdClass();
00161         $this->M_yui_loader->base         = $this->yui3loader->base;
00162         $this->M_yui_loader->comboBase    = $this->yui3loader->comboBase;
00163         $this->M_yui_loader->combine      = $this->yui3loader->combine;
00164         $this->M_yui_loader->filter       = (string)$this->yui3loader->filter;
00165         $this->M_yui_loader->insertBefore = 'firstthemesheet';
00166         $this->M_yui_loader->modules      = array();
00167         $this->M_yui_loader->groups       = array(
00168             'moodle' => array(
00169                 'name' => 'moodle',
00170                 'base' => $CFG->httpswwwroot . '/theme/yui_combo.php?moodle/'.$jsrev.'/',
00171                 'comboBase' => $CFG->httpswwwroot . '/theme/yui_combo.php?',
00172                 'combine' => $this->yui3loader->combine,
00173                 'filter' => '',
00174                 'ext' => false,
00175                 'root' => 'moodle/'.$jsrev.'/', // Add the rev to the root path so that we can control caching
00176                 'patterns' => array(
00177                     'moodle-' => array(
00178                         'group' => 'moodle',
00179                         'configFn' => '@MOODLECONFIGFN@'
00180                     ),
00181                     'root' => 'moodle'
00182                 )
00183             ),
00184             'local' => array(
00185                 'name' => 'gallery',
00186                 'base' => $CFG->wwwroot.'/lib/yui/gallery/',
00187                 'comboBase' => $CFG->httpswwwroot . '/theme/yui_combo.php?',
00188                 'combine' => $this->yui3loader->combine,
00189                 'filter' => $this->M_yui_loader->filter,
00190                 'ext' => false,
00191                 'root' => 'gallery/',
00192                 'patterns' => array(
00193                     'gallery-' => array(
00194                         'group' => 'gallery',
00195                         'configFn' => '@GALLERYCONFIGFN@',
00196                     ),
00197                     'root' => 'gallery'
00198                 )
00199             )
00200         );
00201         $this->add_yui2_modules(); // adds loading info for all YUI2 modules
00202         $this->js_module($this->find_module('core_filepicker'));
00203         $this->js_module($this->find_module('core_dock'));
00204 
00205     }
00206 
00211     protected function add_yui2_modules() {
00212         //note: this function is definitely not perfect, because
00213         //      it adds tons of markup into each page, but it can be
00214         //      abstracted into separate JS file with proper headers
00215         global $CFG;
00216 
00217         $GLOBALS['yui_current'] = array();
00218         require($CFG->libdir.'/yui/phploader/lib/meta/config_'.$CFG->yui2version.'.php');
00219         $info = $GLOBALS['yui_current'];
00220         unset($GLOBALS['yui_current']);
00221 
00222         if (empty($CFG->yuicomboloading)) {
00223             $urlbase = $this->yui2loader->base;
00224         } else {
00225             $urlbase = $this->yui2loader->comboBase.$CFG->yui2version.'/build/';
00226         }
00227 
00228         $modules = array();
00229         $ignored = array(); // list of CSS modules that are not needed
00230         foreach ($info['moduleInfo'] as $name => $module) {
00231             if ($module['type'] === 'css') {
00232                 $ignored[$name] = true;
00233             } else {
00234                 $modules['yui2-'.$name] = $module;
00235             }
00236         }
00237         foreach ($modules as $name=>$module) {
00238             $module['fullpath'] = $urlbase.$module['path']; // fix path to point to correct location
00239             unset($module['path']);
00240             unset($module['skinnable']); // we load all YUI2 css automatically, this prevents weird missing css loader problems
00241             foreach(array('requires', 'optional', 'supersedes') as $fixme) {
00242                 if (!empty($module[$fixme])) {
00243                     $fixed = false;
00244                     foreach ($module[$fixme] as $key=>$dep) {
00245                         if (isset($ignored[$dep])) {
00246                             unset($module[$fixme][$key]);
00247                             $fixed = true;
00248                         } else {
00249                             $module[$fixme][$key] = 'yui2-'.$dep;
00250                         }
00251                     }
00252                     if ($fixed) {
00253                         $module[$fixme] = array_merge($module[$fixme]); // fix keys
00254                     }
00255                 }
00256             }
00257             $this->M_yui_loader->modules[$name] = $module;
00258             if (debugging('', DEBUG_DEVELOPER)) {
00259                 if (!array_key_exists($name, $this->debug_moduleloadstacktraces)) {
00260                     $this->debug_moduleloadstacktraces[$name] = array();
00261                 }
00262                 $this->debug_moduleloadstacktraces[$name][] = format_backtrace(debug_backtrace());
00263             }
00264         }
00265     }
00266 
00273     protected function init_requirements_data(moodle_page $page, core_renderer $renderer) {
00274         global $CFG;
00275 
00276         // JavaScript should always work with $CFG->httpswwwroot rather than $CFG->wwwroot.
00277         // Otherwise, in some situations, users will get warnings about insecure content
00278         // on secure pages from their web browser.
00279 
00280         $this->M_cfg = array(
00281             'wwwroot'             => $CFG->httpswwwroot, // Yes, really. See above.
00282             'sesskey'             => sesskey(),
00283             'loadingicon'         => $renderer->pix_url('i/loading_small', 'moodle')->out(false),
00284             'themerev'            => theme_get_revision(),
00285             'theme'               => $page->theme->name,
00286             'jsrev'               => ((empty($CFG->cachejs) or empty($CFG->jsrev)) ? -1 : $CFG->jsrev),
00287         );
00288         if (debugging('', DEBUG_DEVELOPER)) {
00289             $this->M_cfg['developerdebug'] = true;
00290             $this->yui2_lib('logger');
00291         }
00292 
00293         // accessibility stuff
00294         $this->skip_link_to('maincontent', get_string('tocontent', 'access'));
00295 
00296         // to be removed soon
00297         $this->yui2_lib('dom');        // at least javascript-static.js needs to be migrated to YUI3
00298 
00299         $this->string_for_js('confirmation', 'admin');
00300         $this->string_for_js('cancel', 'moodle');
00301         $this->string_for_js('yes', 'moodle');
00302 
00303         if ($page->pagelayout === 'frametop') {
00304             $this->js_init_call('M.util.init_frametop');
00305         }
00306     }
00307 
00324     public function js($url, $inhead=false) {
00325         $url = $this->js_fix_url($url);
00326         $where = $inhead ? 'head' : 'footer';
00327         $this->jsincludes[$where][$url->out()] = $url;
00328     }
00329 
00347     public function yui2_lib($libname) {
00348         $libnames = (array)$libname;
00349         foreach ($libnames as $lib) {
00350             $this->yui2loader->load($lib);
00351         }
00352     }
00353 
00359     protected function js_fix_url($url) {
00360         global $CFG;
00361 
00362         if ($url instanceof moodle_url) {
00363             return $url;
00364         } else if (strpos($url, '/') === 0) {
00365             if (debugging()) {
00366                 // check file existence only when in debug mode
00367                 if (!file_exists($CFG->dirroot . strtok($url, '?'))) {
00368                     throw new coding_exception('Attempt to require a JavaScript file that does not exist.', $url);
00369                 }
00370             }
00371             if (!empty($CFG->cachejs) and !empty($CFG->jsrev) and strpos($url, '/lib/editor/') !== 0 and substr($url, -3) === '.js') {
00372                 return new moodle_url($CFG->httpswwwroot.'/lib/javascript.php', array('file'=>$url, 'rev'=>$CFG->jsrev));
00373             } else {
00374                 return new moodle_url($CFG->httpswwwroot.$url);
00375             }
00376         } else {
00377             throw new coding_exception('Invalid JS url, it has to be shortened url starting with / or moodle_url instance.', $url);
00378         }
00379     }
00380 
00386     protected function find_module($component) {
00387         global $CFG;
00388 
00389         $module = null;
00390 
00391 
00392         if (strpos($component, 'core_') === 0) {
00393             // must be some core stuff - list here is not complete, this is just the stuff used from multiple places
00394             // so that we do nto have to repeat the definition of these modules over and over again
00395             switch($component) {
00396                 case 'core_filepicker':
00397                     $module = array('name'     => 'core_filepicker',
00398                                     'fullpath' => '/repository/filepicker.js',
00399                                     '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'),
00400                                     'strings'  => array(array('add', 'repository'), array('back', 'repository'), array('cancel', 'moodle'), array('close', 'repository'),
00401                                                         array('cleancache', 'repository'), array('copying', 'repository'), array('date', 'repository'), array('downloadsucc', 'repository'),
00402                                                         array('emptylist', 'repository'), array('error', 'repository'), array('federatedsearch', 'repository'),
00403                                                         array('filenotnull', 'repository'), array('getfile', 'repository'), array('help', 'moodle'), array('iconview', 'repository'),
00404                                                         array('invalidjson', 'repository'), array('linkexternal', 'repository'), array('listview', 'repository'),
00405                                                         array('loading', 'repository'), array('login', 'repository'), array('logout', 'repository'), array('noenter', 'repository'),
00406                                                         array('noresult', 'repository'), array('manageurl', 'repository'), array('popup', 'repository'), array('preview', 'repository'),
00407                                                         array('refresh', 'repository'), array('save', 'repository'), array('saveas', 'repository'), array('saved', 'repository'),
00408                                                         array('saving', 'repository'), array('search', 'repository'), array('searching', 'repository'), array('size', 'repository'),
00409                                                         array('submit', 'repository'), array('sync', 'repository'), array('title', 'repository'), array('upload', 'repository'),
00410                                                         array('uploading', 'repository'), array('xhtmlerror', 'repository'),
00411                                                         array('cancel'), array('chooselicense', 'repository'), array('author', 'repository'),
00412                                                         array('ok', 'moodle'), array('error', 'moodle'), array('info', 'moodle'), array('norepositoriesavailable', 'repository'), array('norepositoriesexternalavailable', 'repository'),
00413                                                         array('nofilesattached', 'repository'), array('filepicker', 'repository'),
00414                                                         array('nofilesavailable', 'repository'), array('overwrite', 'repository'),
00415                                                         array('renameto', 'repository'), array('fileexists', 'repository'),
00416                                                         array('fileexistsdialogheader', 'repository'), array('fileexistsdialog_editor', 'repository'),
00417                                                         array('fileexistsdialog_filemanager', 'repository')
00418                                                     ));
00419                     break;
00420                 case 'core_comment':
00421                     $module = array('name'     => 'core_comment',
00422                                     'fullpath' => '/comment/comment.js',
00423                                     'requires' => array('base', 'io-base', 'node', 'json', 'yui2-animation', 'overlay'),
00424                                     'strings' => array(array('confirmdeletecomments', 'admin'), array('yes', 'moodle'), array('no', 'moodle'))
00425                                 );
00426                     break;
00427                 case 'core_role':
00428                     $module = array('name'     => 'core_role',
00429                                     'fullpath' => '/admin/roles/module.js',
00430                                     'requires' => array('node', 'cookie'));
00431                     break;
00432                 case 'core_completion':
00433                     $module = array('name'     => 'core_completion',
00434                                     'fullpath' => '/course/completion.js');
00435                     break;
00436                 case 'core_dock':
00437                     $module = array('name'     => 'core_dock',
00438                                     'fullpath' => '/blocks/dock.js',
00439                                     'requires' => array('base', 'node', 'event-custom', 'event-mouseenter', 'event-resize'),
00440                                     'strings' => array(array('addtodock', 'block'),array('undockitem', 'block'),array('undockall', 'block'),array('thisdirectionvertical', 'langconfig')));
00441                     break;
00442                 case 'core_message':
00443                     $module = array('name'     => 'core_message',
00444                                     'requires' => array('base', 'node', 'event', 'node-event-simulate'),
00445                                     'fullpath' => '/message/module.js');
00446                     break;
00447                 case 'core_group':
00448                     $module = array('name'     => 'core_group',
00449                                     'fullpath' => '/group/module.js',
00450                                     'requires' => array('node', 'overlay', 'event-mouseenter'));
00451                     break;
00452                 case 'core_question_engine':
00453                     $module = array('name'     => 'core_question_engine',
00454                                     'fullpath' => '/question/qengine.js',
00455                                     'requires' => array('node', 'event'));
00456                     break;
00457                 case 'core_rating':
00458                     $module = array('name'     => 'core_rating',
00459                                     'fullpath' => '/rating/module.js',
00460                                     'requires' => array('node', 'event', 'overlay', 'io-base', 'json'));
00461                     break;
00462                 case 'core_filetree':
00463                     $module = array('name'     => 'core_filetree',
00464                                     'fullpath' => '/files/module.js',
00465                                     'requires' => array('node', 'event', 'overlay', 'io-base', 'json', 'yui2-treeview'));
00466                     break;
00467             }
00468 
00469         } else {
00470             if ($dir = get_component_directory($component)) {
00471                 if (file_exists("$dir/module.js")) {
00472                     if (strpos($dir, $CFG->dirroot.'/') === 0) {
00473                         $dir = substr($dir, strlen($CFG->dirroot));
00474                         $module = array('name'=>$component, 'fullpath'=>"$dir/module.js", 'requires' => array());
00475                     }
00476                 }
00477             }
00478         }
00479 
00480         return $module;
00481     }
00482 
00489     public function js_module($module) {
00490         global $CFG;
00491 
00492         if (empty($module)) {
00493             throw new coding_exception('Missing YUI3 module name or full description.');
00494         }
00495 
00496         if (is_string($module)) {
00497             $module = $this->find_module($module);
00498         }
00499 
00500         if (empty($module) or empty($module['name']) or empty($module['fullpath'])) {
00501             throw new coding_exception('Missing YUI3 module details.');
00502         }
00503 
00504         // Don't load this module if we already have, no need to!
00505         if ($this->js_module_loaded($module['name'])) {
00506             if (debugging('', DEBUG_DEVELOPER)) {
00507                 $this->debug_moduleloadstacktraces[$module['name']][] = format_backtrace(debug_backtrace());
00508             }
00509             return;
00510         }
00511 
00512         $module['fullpath'] = $this->js_fix_url($module['fullpath'])->out(false);
00513         // add all needed strings
00514         if (!empty($module['strings'])) {
00515             foreach ($module['strings'] as $string) {
00516                 $identifier = $string[0];
00517                 $component = isset($string[1]) ? $string[1] : 'moodle';
00518                 $a = isset($string[2]) ? $string[2] : null;
00519                 $this->string_for_js($identifier, $component, $a);
00520             }
00521         }
00522         unset($module['strings']);
00523 
00524         // Process module requirements and attempt to load each. This allows
00525         // moodle modules to require each other.
00526         if (!empty($module['requires'])){
00527             foreach ($module['requires'] as $requirement) {
00528                 $rmodule = $this->find_module($requirement);
00529                 if (is_array($rmodule)) {
00530                     $this->js_module($rmodule);
00531                 }
00532             }
00533         }
00534 
00535         if ($this->headdone) {
00536             $this->extramodules[$module['name']] = $module;
00537         } else {
00538             $this->M_yui_loader->modules[$module['name']] = $module;
00539         }
00540         if (debugging('', DEBUG_DEVELOPER)) {
00541             if (!array_key_exists($module['name'], $this->debug_moduleloadstacktraces)) {
00542                 $this->debug_moduleloadstacktraces[$module['name']] = array();
00543             }
00544             $this->debug_moduleloadstacktraces[$module['name']][] = format_backtrace(debug_backtrace());
00545         }
00546     }
00547 
00554     protected function js_module_loaded($module) {
00555         if (is_string($module)) {
00556             $modulename = $module;
00557         } else {
00558             $modulename = $module['name'];
00559         }
00560         return array_key_exists($modulename, $this->M_yui_loader->modules) ||
00561                array_key_exists($modulename, $this->extramodules);
00562     }
00563 
00568     public function get_loaded_modules() {
00569         return $this->debug_moduleloadstacktraces;
00570     }
00571 
00592     public function css($stylesheet) {
00593         global $CFG;
00594 
00595         if ($this->headdone) {
00596             throw new coding_exception('Cannot require a CSS file after &lt;head> has been printed.', $stylesheet);
00597         }
00598 
00599         if ($stylesheet instanceof moodle_url) {
00600             // ok
00601         } else if (strpos($stylesheet, '/') === 0) {
00602             $stylesheet = new moodle_url($CFG->httpswwwroot.$stylesheet);
00603         } else {
00604             throw new coding_exception('Invalid stylesheet parameter.', $stylesheet);
00605         }
00606 
00607         $this->cssurls[$stylesheet->out()] = $stylesheet; // overrides
00608     }
00609 
00616     public function css_theme(moodle_url $stylesheet) {
00617         $this->cssthemeurls[] = $stylesheet;
00618     }
00619 
00635     public function skip_link_to($target, $linktext) {
00636         if ($this->topofbodydone) {
00637             debugging('Page header already printed, can not add skip links any more, code needs to be fixed.');
00638             return;
00639         }
00640         $this->skiplinks[$target] = $linktext;
00641     }
00642 
00668     public function js_function_call($function, array $arguments = null, $ondomready = false, $delay = 0) {
00669         $where = $ondomready ? 'ondomready' : 'normal';
00670         $this->jscalls[$where][] = array($function, $arguments, $delay);
00671     }
00672 
00684     public function js_gallery_module($modules, $version, $function, array $arguments = null, $ondomready = false) {
00685         global $CFG;
00686         debugging('This function will be removed before 2.0 is released please change it from js_gallery_module to yui_module', DEBUG_DEVELOPER);
00687         $this->yui_module($modules, $function, $arguments, $version, $ondomready);
00688     }
00689 
00705     public function yui_module($modules, $function, array $arguments = null, $galleryversion = '2010.04.08-12-35', $ondomready = false) {
00706         global $CFG;
00707 
00708         if (!is_array($modules)) {
00709             $modules = array($modules);
00710         }
00711         if (empty($CFG->useexternalyui) || true) {
00712             // We need to set the M.yui.galleryversion to the correct version
00713             $jscode = 'M.yui.galleryversion='.json_encode($galleryversion).';';
00714         } else {
00715             // Set Y's config.gallery to the version
00716             $jscode = 'Y.config.gallery='.json_encode($galleryversion).';';
00717         }
00718         $jscode .= 'Y.use('.join(',', array_map('json_encode', $modules)).',function() {'.js_writer::function_call($function, $arguments).'});';
00719         if ($ondomready) {
00720             $jscode = "Y.on('domready', function() { $jscode });";
00721         }
00722         $this->jsinitcode[] = $jscode;
00723     }
00724 
00738     public function js_init_call($function, array $extraarguments = null, $ondomready = false, array $module = null) {
00739         $jscode = js_writer::function_call_with_Y($function, $extraarguments);
00740         if (!$module) {
00741             // detect module automatically
00742             if (preg_match('/M\.([a-z0-9]+_[^\.]+)/', $function, $matches)) {
00743                 $module = $this->find_module($matches[1]);
00744             }
00745         }
00746 
00747         $this->js_init_code($jscode, $ondomready, $module);
00748     }
00749 
00760     public function js_init_code($jscode, $ondomready = false, array $module = null) {
00761         $jscode = trim($jscode, " ;\n"). ';';
00762 
00763         if ($module) {
00764             $this->js_module($module);
00765             $modulename = $module['name'];
00766             $jscode = "Y.use('$modulename', function(Y) { $jscode });";
00767         }
00768 
00769         if ($ondomready) {
00770             $jscode = "Y.on('domready', function() { $jscode });";
00771         }
00772 
00773         $this->jsinitcode[] = $jscode;
00774     }
00775 
00825     public function string_for_js($identifier, $component, $a = NULL) {
00826         $string = get_string($identifier, $component, $a);
00827         if (!$component) {
00828             throw new coding_exception('The $module parameter is required for page_requirements_manager::string_for_js.');
00829         }
00830         if (isset($this->stringsforjs[$component][$identifier]) && $this->stringsforjs[$component][$identifier] !== $string) {
00831             throw new coding_exception("Attempt to re-define already required string '$identifier' " .
00832                     "from lang file '$component'. Did you already ask for it with a different \$a? {$this->stringsforjs[$component][$identifier]} !== $string");
00833         }
00834         $this->stringsforjs[$component][$identifier] = $string;
00835     }
00836 
00861     public function strings_for_js($identifiers, $component, $a=NULL) {
00862         foreach ($identifiers as $key => $identifier) {
00863             if (is_array($a) && array_key_exists($key, $a)) {
00864                 $extra = $a[$key];
00865             } else {
00866                 $extra = $a;
00867             }
00868             $this->string_for_js($identifier, $component, $extra);
00869         }
00870     }
00871 
00890     public function data_for_js($variable, $data, $inhead=false) {
00891         $where = $inhead ? 'head' : 'footer';
00892         $this->jsinitvariables[$where][] = array($variable, $data);
00893     }
00894 
00904     public function event_handler($selector, $event, $function, array $arguments = null) {
00905         $this->eventhandlers[] = array('selector'=>$selector, 'event'=>$event, 'function'=>$function, 'arguments'=>$arguments);
00906     }
00907 
00912     protected function get_event_handler_code() {
00913         $output = '';
00914         foreach ($this->eventhandlers as $h) {
00915             $output .= js_writer::event_handler($h['selector'], $h['event'], $h['function'], $h['arguments']);
00916         }
00917         return $output;
00918     }
00919 
00925     protected function get_javascript_code($ondomready) {
00926         $where = $ondomready ? 'ondomready' : 'normal';
00927         $output = '';
00928         if ($this->jscalls[$where]) {
00929             foreach ($this->jscalls[$where] as $data) {
00930                 $output .= js_writer::function_call($data[0], $data[1], $data[2]);
00931             }
00932             if (!empty($ondomready)) {
00933                 $output = "    Y.on('domready', function() {\n$output\n    });";
00934             }
00935         }
00936         return $output;
00937     }
00938 
00943     protected function get_javascript_init_code() {
00944         if (count($this->jsinitcode)) {
00945             return implode("\n", $this->jsinitcode) . "\n";
00946         }
00947         return '';
00948     }
00949 
00959     protected function get_yui3lib_headcode() {
00960         global $CFG;
00961 
00962         $code = '';
00963 
00964         if ($this->yui3loader->combine) {
00965             $code .= '<link rel="stylesheet" type="text/css" href="'.$this->yui3loader->comboBase
00966                      .$CFG->yui3version.'/build/cssreset/reset-min.css&amp;'
00967                      .$CFG->yui3version.'/build/cssfonts/fonts-min.css&amp;'
00968                      .$CFG->yui3version.'/build/cssgrids/grids-min.css&amp;'
00969                      .$CFG->yui3version.'/build/cssbase/base-min.css" />';
00970         } else {
00971             $code .= '<link rel="stylesheet" type="text/css" href="'.$this->yui3loader->base.'cssreset/reset-min.css" />';
00972             $code .= '<link rel="stylesheet" type="text/css" href="'.$this->yui3loader->base.'cssfonts/fonts-min.css" />';
00973             $code .= '<link rel="stylesheet" type="text/css" href="'.$this->yui3loader->base.'cssgrids/grids-min.css" />';
00974             $code .= '<link rel="stylesheet" type="text/css" href="'.$this->yui3loader->base.'cssbase/base-min.css" />';
00975         }
00976 
00977         $code .= '<script type="text/javascript" src="'.$this->yui3loader->base.'yui/yui-min.js"></script>';
00978 
00979         if ($this->yui3loader->filter === YUI_RAW) {
00980             $code = str_replace('-min.css', '.css', $code);
00981             $code = str_replace('-min.js', '.js', $code);
00982         } else if ($this->yui3loader->filter === YUI_DEBUG) {
00983             $code = str_replace('-min.css', '.css', $code);
00984             $code = str_replace('-min.js', '-debug.js', $code);
00985         }
00986 
00987         return $code;
00988     }
00989 
01002     public function get_yui2lib_code() {
01003         global $CFG;
01004 
01005         if ($this->headdone) {
01006             $code = $this->yui2loader->script();
01007         } else {
01008             $code = $this->yui2loader->script();
01009             if ($this->yui2loader->combine) {
01010                 $skinurl = $this->yui2loader->comboBase . $CFG->yui2version . '/build/assets/skins/sam/skin.css';
01011             } else {
01012                 $skinurl = $this->yui2loader->base . 'assets/skins/sam/skin.css';
01013             }
01014             // please note this is a temporary hack until we fully migrate to later YUI3 that has all the widgets
01015             $attributes = array('rel'=>'stylesheet', 'type'=>'text/css', 'href'=>$skinurl);
01016             $code .= "\n" . html_writer::empty_tag('link', $attributes) . "\n";
01017         }
01018         $code = str_replace('&amp;', '&', $code);
01019         $code = str_replace('&', '&amp;', $code);
01020         return $code;
01021     }
01022 
01027     protected function get_css_code() {
01028         // First of all the theme CSS, then any custom CSS
01029         // Please note custom CSS is strongly discouraged,
01030         // because it can not be overridden by themes!
01031         // It is suitable only for things like mod/data which accepts CSS from teachers.
01032         $attributes = array('rel'=>'stylesheet', 'type'=>'text/css');
01033 
01034         // This line of code may look funny but it is currently required in order
01035         // to avoid MASSIVE display issues in Internet Explorer.
01036         // As of IE8 + YUI3.1.1 the reference stylesheet (firstthemesheet) gets
01037         // ignored whenever another resource is added until such time as a redraw
01038         // is forced, usually by moving the mouse over the affected element.
01039         $code = html_writer::tag('script', '/** Required in order to fix style inclusion problems in IE with YUI **/', array('id'=>'firstthemesheet', 'type'=>'text/css'));
01040 
01041         $urls = $this->cssthemeurls + $this->cssurls;
01042         foreach ($urls as $url) {
01043             $attributes['href'] = $url;
01044             $code .= html_writer::empty_tag('link', $attributes) . "\n";
01045             // this id is needed in first sheet only so that theme may override YUI sheets laoded on the fly
01046             unset($attributes['id']);
01047         }
01048 
01049         return $code;
01050     }
01051 
01056     protected function get_extra_modules_code() {
01057         if (empty($this->extramodules)) {
01058             return '';
01059         }
01060         return html_writer::script(js_writer::function_call('M.yui.add_module', array($this->extramodules)));
01061     }
01062 
01073     public function get_head_code(moodle_page $page, core_renderer $renderer) {
01074         global $CFG;
01075 
01076         // note: the $page and $output are not stored here because it would
01077         // create circular references in memory which prevents garbage collection
01078         $this->init_requirements_data($page, $renderer);
01079 
01080         // yui3 JS and CSS is always loaded first - it is cached in browser
01081         $output = $this->get_yui3lib_headcode();
01082 
01083         // BC: load basic YUI2 for now, all yui2 things should be loaded via Y.use('yui2-oldmodulename')
01084         $output .= $this->get_yui2lib_code();
01085 
01086         // now theme CSS + custom CSS in this specific order
01087         $output .= $this->get_css_code();
01088 
01089         // set up global YUI3 loader object - this should contain all code needed by plugins
01090         // note: in JavaScript just use "YUI(M.yui.loader).use('overlay', function(Y) { .... });"
01091         // this needs to be done before including any other script
01092         $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";
01093         $js .= js_writer::set_variable('M.yui.loader', $this->M_yui_loader, false) . "\n";
01094         $js .= js_writer::set_variable('M.cfg', $this->M_cfg, false);
01095         $js = str_replace('"@GALLERYCONFIGFN@"', 'galleryConfigFn', $js);
01096         $js = str_replace('"@MOODLECONFIGFN@"', 'moodleConfigFn', $js);
01097 
01098         $output .= html_writer::script($js);
01099 
01100         // link our main JS file, all core stuff should be there
01101         $output .= html_writer::script('', $this->js_fix_url('/lib/javascript-static.js'));
01102 
01103         // add variables
01104         if ($this->jsinitvariables['head']) {
01105             $js = '';
01106             foreach ($this->jsinitvariables['head'] as $data) {
01107                 list($var, $value) = $data;
01108                 $js .= js_writer::set_variable($var, $value, true);
01109             }
01110             $output .= html_writer::script($js);
01111         }
01112 
01113         // all the other linked things from HEAD - there should be as few as possible
01114         if ($this->jsincludes['head']) {
01115             foreach ($this->jsincludes['head'] as $url) {
01116                 $output .= html_writer::script('', $url);
01117             }
01118         }
01119 
01120         // mark head sending done, it is not possible to anything there
01121         $this->headdone = true;
01122 
01123         return $output;
01124     }
01125 
01134     public function get_top_of_body_code() {
01135         // first the skip links
01136         $links = '';
01137         $attributes = array('class'=>'skip');
01138         foreach ($this->skiplinks as $url => $text) {
01139             $attributes['href'] = '#' . $url;
01140             $links .= html_writer::tag('a', $text, $attributes);
01141         }
01142         $output = html_writer::tag('div', $links, array('class'=>'skiplinks')) . "\n";
01143 
01144         // then the clever trick for hiding of things not needed when JS works
01145         $output .= html_writer::script("document.body.className += ' jsenabled';") . "\n";
01146         $this->topofbodydone = true;
01147         return $output;
01148     }
01149 
01158     public function get_end_code() {
01159         global $CFG;
01160         // add other requested modules
01161         $output = $this->get_extra_modules_code();
01162 
01163         // add missing YUI2 YUI - to be removed once we convert everything to YUI3!
01164         $output .= $this->get_yui2lib_code();
01165 
01166         // all the other linked scripts - there should be as few as possible
01167         if ($this->jsincludes['footer']) {
01168             foreach ($this->jsincludes['footer'] as $url) {
01169                 $output .= html_writer::script('', $url);
01170             }
01171         }
01172 
01173         // add all needed strings
01174         if (!empty($this->stringsforjs)) {
01175             $output .= html_writer::script(js_writer::set_variable('M.str', $this->stringsforjs));
01176         }
01177 
01178         // add variables
01179         if ($this->jsinitvariables['footer']) {
01180             $js = '';
01181             foreach ($this->jsinitvariables['footer'] as $data) {
01182                 list($var, $value) = $data;
01183                 $js .= js_writer::set_variable($var, $value, true);
01184             }
01185             $output .= html_writer::script($js);
01186         }
01187 
01188         $inyuijs = $this->get_javascript_code(false);
01189         $ondomreadyjs = $this->get_javascript_code(true);
01190         $jsinit = $this->get_javascript_init_code();
01191         $handlersjs = $this->get_event_handler_code();
01192 
01193         // there is no global Y, make sure it is available in your scope
01194         $js = "YUI(M.yui.loader).use('node', function(Y) {\n{$inyuijs}{$ondomreadyjs}{$jsinit}{$handlersjs}\n});";
01195 
01196         $output .= html_writer::script($js);
01197 
01198         return $output;
01199     }
01200 
01204     public function is_head_done() {
01205         return $this->headdone;
01206     }
01207 
01211     public function is_top_of_body_done() {
01212         return $this->topofbodydone;
01213     }
01214 }
01215 
01220 function js_reset_all_caches() {
01221     global $CFG;
01222     require_once("$CFG->libdir/filelib.php");
01223 
01224     set_config('jsrev', empty($CFG->jsrev) ? 1 : $CFG->jsrev+1);
01225     fulldelete("$CFG->cachedir/js");
01226 }
01227 
 All Data Structures Namespaces Files Functions Variables Enumerations