diff --git a/lib/moodlelib.php b/lib/moodlelib.php
index 1e6cc12f116..60dbcc95559 100644
--- a/lib/moodlelib.php
+++ b/lib/moodlelib.php
@@ -9242,7 +9242,7 @@ function array_is_nested($array) {
* @return array
*/
function get_performance_info() {
- global $CFG, $PERF, $DB;
+ global $CFG, $PERF, $DB, $PAGE;
$info = array();
$info['html'] = ''; // holds userfriendly HTML representation
@@ -9292,6 +9292,33 @@ function get_performance_info() {
}
}
+ $jsmodules = $PAGE->requires->get_loaded_modules();
+ if ($jsmodules) {
+ $yuicount = 0;
+ $othercount = 0;
+ $details = '';
+ foreach ($jsmodules as $module => $backtraces) {
+ if (strpos($module, 'yui') === 0) {
+ $yuicount += 1;
+ } else {
+ $othercount += 1;
+ }
+ $details .= "
$module
";
+ foreach ($backtraces as $backtrace) {
+ $details .= "
$backtrace
";
+ }
+ $details .= '
';
+ }
+ $info['html'] .= "Included YUI modules: $yuicount ";
+ $info['txt'] .= "includedyuimodules: $yuicount ";
+ $info['html'] .= "Other JavaScript modules: $othercount ";
+ $info['txt'] .= "includedjsmodules: $othercount ";
+ // Slightly odd to output the details in a display: none div. The point
+ // Is that it takes a lot of space, and if you care you can reveal it
+ // using firebug.
+ $info['html'] .= ''.$details.'
';
+ }
+
if (!empty($PERF->logwrites)) {
$info['logwrites'] = $PERF->logwrites;
$info['html'] .= 'Log DB writes '.$info['logwrites'].' ';
diff --git a/lib/outputrequirementslib.php b/lib/outputrequirementslib.php
index 39857aa8bd8..54cb95927d5 100644
--- a/lib/outputrequirementslib.php
+++ b/lib/outputrequirementslib.php
@@ -109,6 +109,8 @@ class page_requirements_manager {
protected $M_yui_loader;
/** some config vars exposed in JS, please no secret stuff there */
protected $M_cfg;
+ /** stores debug backtraces from when JS modules were included in the page */
+ protected $debug_moduleloadstacktraces = array();
/**
* Page requirements constructor.
@@ -257,6 +259,12 @@ class page_requirements_manager {
}
}
$this->M_yui_loader->modules[$name] = $module;
+ if (debugging('', DEBUG_DEVELOPER)) {
+ if (!array_key_exists($name, $this->debug_moduleloadstacktraces)) {
+ $this->debug_moduleloadstacktraces[$name] = array();
+ }
+ $this->debug_moduleloadstacktraces[$name][] = format_backtrace(debug_backtrace());
+ }
}
}
@@ -497,6 +505,14 @@ class page_requirements_manager {
throw new coding_exception('Missing YUI3 module details.');
}
+ // 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;
+ }
+
$module['fullpath'] = $this->js_fix_url($module['fullpath'])->out(false);
// add all needed strings
if (!empty($module['strings'])) {
@@ -509,11 +525,52 @@ class page_requirements_manager {
}
unset($module['strings']);
+ // 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);
+ }
+ }
+ }
+
if ($this->headdone) {
$this->extramodules[$module['name']] = $module;
} else {
$this->M_yui_loader->modules[$module['name']] = $module;
}
+ if (debugging('', DEBUG_DEVELOPER)) {
+ if (!array_key_exists($module['name'], $this->debug_moduleloadstacktraces)) {
+ $this->debug_moduleloadstacktraces[$module['name']] = array();
+ }
+ $this->debug_moduleloadstacktraces[$module['name']][] = format_backtrace(debug_backtrace());
+ }
+ }
+
+ /**
+ * Returns true if the module has already been loaded.
+ *
+ * @param string|array $modulename
+ * @return bool True if the module has already been loaded
+ */
+ protected function js_module_loaded($module) {
+ if (is_string($module)) {
+ $modulename = $module;
+ } else {
+ $modulename = $module['name'];
+ }
+ return array_key_exists($modulename, $this->M_yui_loader->modules) ||
+ array_key_exists($modulename, $this->extramodules);
+ }
+
+ /**
+ * Returns the stacktraces from loading js modules.
+ * @return array
+ */
+ public function get_loaded_modules() {
+ return $this->debug_moduleloadstacktraces;
}
/**
diff --git a/mod/quiz/locallib.php b/mod/quiz/locallib.php
index f83a364625f..27ee96e60d1 100644
--- a/mod/quiz/locallib.php
+++ b/mod/quiz/locallib.php
@@ -1247,7 +1247,6 @@ function quiz_check_safe_browser() {
function quiz_get_js_module() {
global $PAGE;
- $PAGE->requires->js_module('core_question_engine');
return array(
'name' => 'mod_quiz',
'fullpath' => '/mod/quiz/module.js',
diff --git a/theme/base/style/core.css b/theme/base/style/core.css
index bdd3a19ee06..3ec94986a2d 100644
--- a/theme/base/style/core.css
+++ b/theme/base/style/core.css
@@ -128,6 +128,8 @@ a.skip:active {position: static;display: block;}
.arrow,
.arrow_button input {font-family: Arial,Helvetica,Courier,sans-serif;}
+#yui-module-debug {display:none;}
+
/**
* Header
*/