diff --git a/lib/outputrequirementslib.php b/lib/outputrequirementslib.php index 0e55357bcb1..18aea452179 100644 --- a/lib/outputrequirementslib.php +++ b/lib/outputrequirementslib.php @@ -195,6 +195,15 @@ class page_requirements_manager { $this->YUI_config->comboBase = $this->yui3loader->comboBase; $this->YUI_config->combine = $this->yui3loader->combine; + // If we've had to patch any YUI modules between releases, we must override the YUI configuration to include them. + // For important information on patching YUI modules, please see http://docs.moodle.org/dev/YUI/Patching. + if (!empty($CFG->yuipatchedmodules) && !empty($CFG->yuipatchlevel)) { + $this->YUI_config->define_patched_core_modules($this->yui3loader->local_comboBase, + $CFG->yui3version, + $CFG->yuipatchlevel, + $CFG->yuipatchedmodules); + } + $configname = $this->YUI_config->set_config_source('lib/yui/config/yui2.js'); $this->YUI_config->add_group('yui2', array( // Loader configuration for our 2in3, for now ignores $CFG->useexternalyui. @@ -1773,6 +1782,59 @@ class YUI_config { } return $modules; } + + /** + * Define YUI modules which we have been required to patch between releases. + * + * We must do this because we aggressively cache content on the browser, and we must also override use of the + * external CDN which will serve the true authoritative copy of the code without our patches. + * + * @param String combobase The local combobase + * @param String yuiversion The current YUI version + * @param Int patchlevel The patch level we're working to for YUI + * @param Array patchedmodules An array containing the names of the patched modules + * @return void + */ + public function define_patched_core_modules($combobase, $yuiversion, $patchlevel, $patchedmodules) { + // The version we use is suffixed with a patchlevel so that we can get additional revisions between YUI releases. + $subversion = $yuiversion . '_' . $patchlevel; + + if ($this->comboBase == $combobase) { + // If we are using the local combobase in the loader, we can add a group and still make use of the combo + // loader. We just need to specify a different root which includes a slightly different YUI version number + // to include our patchlevel. + $patterns = array(); + $modules = array(); + foreach ($patchedmodules as $modulename) { + // We must define the pattern and module here so that the loader uses our group configuration instead of + // the standard module definition. We may lose some metadata provided by upstream but this will be + // loaded when the module is loaded anyway. + $patterns[$modulename] = array( + 'group' => 'yui-patched', + ); + $modules[$modulename] = array(); + } + + // Actually add the patch group here. + $this->add_group('yui-patched', array( + 'combine' => true, + 'root' => $subversion . '/', + 'patterns' => $patterns, + 'modules' => $modules, + )); + + } else { + // The CDN is in use - we need to instead use the local combobase for this module and override the modules + // definition. We cannot use the local base - we must use the combobase because we cannot invalidate the + // local base in browser caches. + $fullpathbase = $combobase . $subversion . '/'; + foreach ($patchedmodules as $modulename) { + $this->modules[$modulename] = array( + 'fullpath' => $fullpathbase . $modulename . '/' . $modulename . '-min.js' + ); + } + } + } } /** diff --git a/lib/setup.php b/lib/setup.php index 94115d43b2e..1618676f441 100644 --- a/lib/setup.php +++ b/lib/setup.php @@ -349,6 +349,15 @@ if (!defined('AJAX_SCRIPT')) { $CFG->yui2version = '2.9.0'; $CFG->yui3version = '3.13.0'; +// Patching the upstream YUI release. +// For important information on patching YUI modules, please see http://docs.moodle.org/dev/YUI/Patching. +// If we need to patch a YUI modules between official YUI releases, the yuipatchlevel will need to be manually +// incremented here. The module will also need to be listed in the yuipatchedmodules. +// When upgrading to a subsequent version of YUI, these should be reset back to 0 and an empty array. +$CFG->yuipatchlevel = 0; +$CFG->yuipatchedmodules = array( +); + // Store settings from config.php in array in $CFG - we can use it later to detect problems and overrides. if (!isset($CFG->config_php_settings)) { $CFG->config_php_settings = (array)$CFG; diff --git a/lib/yuilib/readme_moodle.txt b/lib/yuilib/readme_moodle.txt index 7c7a058eae0..64da716e370 100644 --- a/lib/yuilib/readme_moodle.txt +++ b/lib/yuilib/readme_moodle.txt @@ -12,6 +12,9 @@ Description of import of various YUI libraries into Moodle: * update lib/thrirdpartylibs.xml * verify our simpleyui rollup contents in /theme/yui_combo.php +If you need to patch the YUI library between its official releases, you *must* read +http://docs.moodle.org/dev/YUI/Patching. + 3/ YUI3 Gallery version gallery-2013.10.02-20-26: * selective copy of the "build" directory for the checked out tag of yui3-gallery. Unit test code coverage files (*-coverage.js) are removed but no other changes are made. diff --git a/theme/yui_combo.php b/theme/yui_combo.php index c19a9f13be6..83221392363 100644 --- a/theme/yui_combo.php +++ b/theme/yui_combo.php @@ -102,6 +102,11 @@ while (count($parts)) { continue; } + // Allow support for revisions on YUI between official releases. + // We can just discard the subrevision since it is only used to invalidate the browser cache. + $yuipatchedversion = explode('_', $revision); + $yuiversion = $yuipatchedversion[0]; + $yuimodules = array( // Include everything from original SimpleYUI, // this list can be built using http://yuilibrary.com/yui/configurator/ by selecting all modules @@ -193,14 +198,14 @@ while (count($parts)) { if ($type === 'js') { $newparts = array(); foreach ($yuimodules as $module) { - $newparts[] = $revision . '/' . $module . '/' . $module . $filesuffix; + $newparts[] = $yuiversion . '/' . $module . '/' . $module . $filesuffix; } $newparts[] = 'yuiuseall/yuiuseall'; $parts = array_merge($newparts, $parts); } else { $newparts = array(); foreach ($yuimodules as $module) { - $candidate = $revision . '/' . $module . '/assets/skins/sam/' . $module . '.css'; + $candidate = $yuiversion . '/' . $module . '/assets/skins/sam/' . $module . '.css'; if (!file_exists("$CFG->libdir/yuilib/$candidate")) { continue; } @@ -306,10 +311,17 @@ while (count($parts)) { $filecontent = "var Y = YUI().use('*');"; } else { - if ($version != $CFG->yui3version) { + // Allow support for revisions on YUI between official releases. + // We can just discard the subrevision since it is only used to invalidate the browser cache. + $yuipatchedversion = explode('_', $version); + $yuiversion = $yuipatchedversion[0]; + if ($yuiversion != $CFG->yui3version) { $content .= "\n// Wrong yui version $part!\n"; continue; } + $newpart = explode('/', $part); + $newpart[0] = $yuiversion; + $part = implode('/', $newpart); $contentfile = "$CFG->libdir/yuilib/$part"; } if (!file_exists($contentfile) or !is_file($contentfile)) { diff --git a/theme/yui_image.php b/theme/yui_image.php index 5a8818eb48d..5865aa37f7a 100644 --- a/theme/yui_image.php +++ b/theme/yui_image.php @@ -63,15 +63,21 @@ if ($version == 'moodle' && count($parts) >= 3) { } else if ($version == 'gallery' && count($parts) >= 3) { list($revision, $module, , , , $image) = $parts; $imagepath = "$CFG->dirroot/lib/yuilib/gallery/$module/assets/skins/sam/$image"; -} else if (count($parts) == 1 && ($version == $CFG->yui3version || $version == $CFG->yui2version)) { - list($image) = $parts; - if ($version == $CFG->yui3version) { - $imagepath = "$CFG->dirroot/lib/yuilib/$CFG->yui3version/assets/skins/sam/$image"; - } else { - $imagepath = "$CFG->dirroot/lib/yuilib/2in3/$CFG->yui2version/build/assets/skins/sam/$image"; - } } else { - yui_image_not_found(); + // Allow support for revisions on YUI between official releases. + // We can just discard the subrevision since it is only used to invalidate the browser cache. + $yuipatchedversion = explode('_', $version); + $yuiversion = $yuipatchedversion[0]; + if (count($parts) == 1 && ($yuiversion == $CFG->yui3version || $yuiversion == $CFG->yui2version)) { + list($image) = $parts; + if ($yuiversion == $CFG->yui3version) { + $imagepath = "$CFG->dirroot/lib/yuilib/$CFG->yui3version/assets/skins/sam/$image"; + } else { + $imagepath = "$CFG->dirroot/lib/yuilib/2in3/$CFG->yui2version/build/assets/skins/sam/$image"; + } + } else { + yui_image_not_found(); + } } if (!file_exists($imagepath)) {