MDL-49870 tool_templatelibrary: Allow docs in parent template only.
authorDamyon Wiese <damyon@moodle.com>
Mon, 4 May 2015 05:16:52 +0000 (13:16 +0800)
committerDamyon Wiese <damyon@moodle.com>
Wed, 6 May 2015 06:54:56 +0000 (14:54 +0800)
If the mustache comment containing the docs for the template is
not found in the theme overridden template, search the original
core/plugin template for the docs.

admin/tool/templatelibrary/amd/build/display.min.js
admin/tool/templatelibrary/amd/src/display.js
admin/tool/templatelibrary/classes/api.php
admin/tool/templatelibrary/classes/external.php
admin/tool/templatelibrary/db/services.php
admin/tool/templatelibrary/tests/externallib_test.php
admin/tool/templatelibrary/version.php
theme/base/templates/core/notification_message.mustache
theme/base/templates/core/notification_problem.mustache
theme/base/templates/core/notification_redirect.mustache
theme/base/templates/core/notification_success.mustache

index 3bc7ab4..a5bf8ab 100644 (file)
Binary files a/admin/tool/templatelibrary/amd/build/display.min.js and b/admin/tool/templatelibrary/amd/build/display.min.js differ
index a6c4a70..1585a18 100644 (file)
@@ -25,21 +25,20 @@ define(['jquery', 'core/ajax', 'core/log', 'core/notification', 'core/templates'
        function($, ajax, log, notification, templates, config, str) {
 
     /**
-     * Handle a template loaded response.
+     * Search through a template for a template docs comment.
      *
-     * @param {String} templateName The template name
-     * @param {String} source The template source
+     * @param {String} templateSource The raw template
+     * @param {String} templateName The name of the template used to search for docs tag
+     * @return {String|boolean} the correct comment or false
      */
-    var templateLoaded = function(templateName, source) {
-        str.get_string('templateselected', 'tool_templatelibrary', templateName).done(function(s) {
-            $('[data-region="displaytemplateheader"]').text(s);
-        }).fail(notification.exception);
+    var findDocsSection = function(templateSource, templateName) {
 
         // Find the comment section marked with @template component/template.
-        var marker = "@template " + templateName;
+        var marker = "@template " + templateName,
+            i = 0,
+            sections = [];
 
-        var sections = source.match(/{{!([\s\S]*?)}}/g);
-        var i = 0;
+        sections = templateSource.match(/{{!([\s\S]*?)}}/g);
 
         // If no sections match - show the entire file.
         if (sections !== null) {
@@ -50,11 +49,38 @@ define(['jquery', 'core/ajax', 'core/log', 'core/notification', 'core/templates'
                     // Remove {{! and }} from start and end.
                     var offset = start + marker.length + 1;
                     section = section.substr(offset, section.length - 2 - offset);
-                    source = section;
-                    break;
+                    return section;
                 }
             }
         }
+        // No matching comment.
+        return false;
+    };
+
+    /**
+     * Handle a template loaded response.
+     *
+     * @param {String} templateName The template name
+     * @param {String} source The template source
+     * @param {String} originalSource The original template source (not theme overridden)
+     */
+    var templateLoaded = function(templateName, source, originalSource) {
+        str.get_string('templateselected', 'tool_templatelibrary', templateName).done(function(s) {
+            $('[data-region="displaytemplateheader"]').text(s);
+        }).fail(notification.exception);
+
+        // Find the comment section marked with @template component/template.
+        var docs = findDocsSection(source, templateName);
+
+        if (docs === false) {
+            // Docs was not in theme template, try original.
+            docs = findDocsSection(originalSource, templateName);
+        }
+
+        // If we found a docs section, limit the template library to showing this section.
+        if (docs) {
+            source = docs;
+        }
 
         $('[data-region="displaytemplatesource"]').text(source);
 
@@ -86,6 +112,7 @@ define(['jquery', 'core/ajax', 'core/log', 'core/notification', 'core/templates'
 
     /**
      * Load the a template source from Moodle.
+     *
      * @param {String} templateName
      */
     var loadTemplate = function(templateName) {
@@ -93,16 +120,26 @@ define(['jquery', 'core/ajax', 'core/log', 'core/notification', 'core/templates'
         var component = parts.shift();
         var name = parts.shift();
 
-        ajax.call([{
+        var promises = ajax.call([{
             methodname: 'core_output_load_template',
             args:{
                     component: component,
                     template: name,
                     themename: config.theme
-            },
-            done: function(source) { templateLoaded(templateName, source); },
-            fail: notification.exception
+            }
+        }, {
+            methodname: 'tool_templatelibrary_load_canonical_template',
+            args:{
+                    component: component,
+                    template: name
+            }
         }]);
+
+        // When returns a new promise that is resolved when all the passed in promises are resolved.
+        // The arguments to the done become the values of each resolved promise.
+        $.when.apply($, promises)
+            .done( function(source, originalSource) { templateLoaded(templateName, source, originalSource); })
+            .fail(notification.exception);
     };
 
     // Add the event listeners.
index a2cf302..2ef5d4c 100644 (file)
  */
 namespace tool_templatelibrary;
 
-use core\output\mustache_template_finder;
-use stdClass;
 use core_component;
+use core\output\mustache_template_finder;
 use coding_exception;
+use moodle_exception;
 use required_capability_exception;
+use stdClass;
 
 /**
  * API exposed by tool_templatelibrary
@@ -103,4 +104,37 @@ class api {
         return $results;
     }
 
+    /**
+     * Return a mustache template.
+     * Note - this function differs from the function core_output_load_template
+     * because it will never return a theme overridden version of a template.
+     *
+     * @param string $component The component that holds the template.
+     * @param string $template The name of the template.
+     * @return string the template
+     */
+    public static function load_canonical_template($component, $template) {
+        // Get the list of possible template directories.
+        $dirs = mustache_template_finder::get_template_directories_for_component($component);
+        $filename = false;
+
+        foreach ($dirs as $dir) {
+            // Skip theme dirs - we only want the original plugin/core template.
+            if (strpos($dir, "/theme/") === false) {
+                $candidate = $dir . $template . '.mustache';
+                if (file_exists($candidate)) {
+                    $filename = $candidate;
+                    break;
+                }
+            }
+        }
+        if ($filename === false) {
+            throw new moodle_exception('filenotfound', 'error');
+        }
+
+        $templatestr = file_get_contents($filename);
+        return $templatestr;
+    }
+
+
 }
index 630f040..100172b 100644 (file)
@@ -95,4 +95,55 @@ class external extends external_api {
     public static function list_templates_returns() {
         return new external_multiple_structure(new external_value(PARAM_RAW, 'The template name (format is component/templatename)'));
     }
+
+    /**
+     * Returns description of load_canonical_template() parameters.
+     *
+     * @return external_function_parameters
+     */
+    public static function load_canonical_template_parameters() {
+        return new external_function_parameters(
+                array('component' => new external_value(PARAM_COMPONENT, 'component containing the template'),
+                      'template' => new external_value(PARAM_ALPHANUMEXT, 'name of the template'))
+            );
+    }
+
+    /**
+     * Can this function be called directly from ajax?
+     *
+     * @return boolean
+     * @since Moodle 2.9
+     */
+    public static function load_canonical_template_is_allowed_from_ajax() {
+        return true;
+    }
+
+    /**
+     * Return a mustache template.
+     * Note - this function differs from the function core_output_load_template
+     * because it will never return a theme overridden version of a template.
+     *
+     * @param string $component The component that holds the template.
+     * @param string $template The name of the template.
+     * @return string the template
+     */
+    public static function load_canonical_template($component, $template) {
+        $params = self::validate_parameters(self::load_canonical_template_parameters(),
+                                            array('component' => $component,
+                                                  'template' => $template));
+
+        $component = $params['component'];
+        $template = $params['template'];
+
+        return api::load_canonical_template($component, $template);
+    }
+
+    /**
+     * Returns description of load_canonical_template() result value.
+     *
+     * @return external_description
+     */
+    public static function load_canonical_template_returns() {
+        return new external_value(PARAM_RAW, 'template');
+    }
 }
index fdecc01..c1a9479 100644 (file)
@@ -33,5 +33,12 @@ $functions = array(
         'type'        => 'read',
         'capabilities'=> '',
     ),
+    'tool_templatelibrary_load_canonical_template' => array(
+        'classname'   => 'tool_templatelibrary\external',
+        'methodname'  => 'load_canonical_template',
+        'description' => 'Load a canonical template by name (not the theme overidden one).',
+        'type'        => 'read'
+    ),
+
 );
 
index db9d4df..9b09541 100644 (file)
@@ -65,5 +65,19 @@ class tool_templatelibrary_external_testcase extends externallib_advanced_testca
         $this->assertEquals($result[0], "tool_templatelibrary/list_templates_page");
     }
 
+    public function test_load_canonical_template() {
+        global $CFG;
 
+        $originaltheme = $CFG->theme;
+        // Change the theme to 'base' because it overrides these templates.
+        $CFG->theme = 'base';
+
+        $template = external::load_canonical_template('core', 'notification_problem');
+
+        // Only the base template should contain the docs.
+        $this->assertContains('@template core/notification_problem', $template);
+
+        // Restore the original theme.
+        $CFG->theme = $originaltheme;
+    }
 }
index 085d347..398b4cf 100644 (file)
@@ -21,6 +21,6 @@
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 defined('MOODLE_INTERNAL') || die();
-$plugin->version   = 2015021623; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->version   = 2015050401; // The current plugin version (Date: YYYYMMDDXX).
 $plugin->requires  = 2014110400; // Requires this Moodle version.
 $plugin->component = 'tool_templatelibrary'; // Full name of the plugin (used for diagnostics).
index ac0e3fa..d388942 100644 (file)
     You should have received a copy of the GNU General Public License
     along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 }}
-{{!
-    Moodle notification template.
-
-    The purpose of this template is to render a message notification.
-
-    Classes required for JS:
-    * none
-
-    Data attributes required for JS:
-    * none
-
-    Context variables required for this template:
-    * message A cleaned string (use clean_text()) to display.
-}}
-<div class="notifymessage">{{{message}}}</div>
\ No newline at end of file
+<div class="notifymessage">{{{message}}}</div>
index f87ce35..6349e70 100644 (file)
     You should have received a copy of the GNU General Public License
     along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 }}
-{{!
-    Moodle notification template.
-
-    The purpose of this template is to render a problem notification.
-
-    Classes required for JS:
-    * none
-
-    Data attributes required for JS:
-    * none
-
-    Context variables required for this template:
-    * message A cleaned string (use clean_text()) to display.
-}}
-<div class="notifyproblem">{{{message}}}</div>
\ No newline at end of file
+<div class="notifyproblem">{{{message}}}</div>
index af5cb5b..2c07a48 100644 (file)
     You should have received a copy of the GNU General Public License
     along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 }}
-{{!
-    Moodle notification template.
-
-    The purpose of this template is to render a message notification.
-
-    Classes required for JS:
-    * none
-
-    Data attributes required for JS:
-    * none
-
-    Context variables required for this template:
-    * message A cleaned string (use clean_text()) to display.
-}}
-<div class="redirectmessage">{{{message}}}</div>
\ No newline at end of file
+<div class="redirectmessage">{{{message}}}</div>
index 3b84161..3040cda 100644 (file)
     You should have received a copy of the GNU General Public License
     along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 }}
-{{!
-    Moodle notification template.
-
-    The purpose of this template is to render a success notification.
-
-    Classes required for JS:
-    * none
-
-    Data attributes required for JS:
-    * none
-
-    Context variables required for this template:
-    * message A cleaned string (use clean_text()) to display.
-}}
-<div class="notifysuccess">{{{message}}}</div>
\ No newline at end of file
+<div class="notifysuccess">{{{message}}}</div>