MDL-49152 output: Templates for renderers (JS and PHP)
Mustache support for rendering templates from either php or js.
This commit is contained in:
+161
-1
@@ -66,6 +66,129 @@ class renderer_base {
|
||||
*/
|
||||
protected $target;
|
||||
|
||||
/**
|
||||
* @var Mustache_Engine $mustache The mustache template compiler
|
||||
*/
|
||||
private $mustache;
|
||||
|
||||
/**
|
||||
* @var string $component The component used when requesting this renderer.
|
||||
*/
|
||||
private $component;
|
||||
|
||||
/**
|
||||
* @var string $subtype The subtype used when requesting this renderer.
|
||||
*/
|
||||
private $subtype;
|
||||
|
||||
/**
|
||||
* This is not done in the constructor because that would be a
|
||||
* compatibility breaking change, and we can just pass this always in the
|
||||
* renderer factory, immediately after creating the renderer.
|
||||
* @since 2.9
|
||||
* @param string $subtype
|
||||
*/
|
||||
public function set_subtype($subtype) {
|
||||
$this->subtype = $subtype;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is not done in the constructor because that would be a
|
||||
* compatibility breaking change, and we can just pass this always in the
|
||||
* renderer factory, immediately after creating the renderer.
|
||||
* @since 2.9
|
||||
* @param string $component
|
||||
*/
|
||||
public function set_component($component) {
|
||||
$this->component = $component;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an instance of the mustache class.
|
||||
*
|
||||
* @since 2.9
|
||||
* @return Mustache_Engine
|
||||
*/
|
||||
protected function get_mustache() {
|
||||
global $CFG;
|
||||
|
||||
if ($this->mustache === null) {
|
||||
require_once($CFG->dirroot . '/lib/mustache/src/Mustache/Autoloader.php');
|
||||
Mustache_Autoloader::register();
|
||||
|
||||
$themename = $this->page->theme->name;
|
||||
$themerev = theme_get_revision();
|
||||
$target = $this->target;
|
||||
|
||||
$cachedir = make_localcache_directory("mustache/$themerev/$themename/$target");
|
||||
$loaderoptions = array();
|
||||
|
||||
// Where are all the places we should look for templates?
|
||||
|
||||
$suffix = $this->component;
|
||||
if ($this->subtype !== null) {
|
||||
$suffix .= '_' . $this->subtype;
|
||||
}
|
||||
|
||||
// Start with an empty list.
|
||||
$loader = new Mustache_Loader_CascadingLoader(array());
|
||||
$loaderdir = $CFG->dirroot . '/theme/' . $themename . '/templates/' . $suffix;
|
||||
if (is_dir($loaderdir)) {
|
||||
$loader->addLoader(new \core\output\mustache_filesystem_loader($loaderdir, $loaderoptions));
|
||||
}
|
||||
|
||||
// Search each of the parent themes second.
|
||||
foreach ($this->page->theme->parents as $parent) {
|
||||
$loaderdir = $CFG->dirroot . '/theme/' . $parent . '/templates/' . $suffix;
|
||||
if (is_dir($loaderdir)) {
|
||||
$loader->addLoader(new \core\output\mustache_filesystem_loader($loaderdir, $loaderoptions));
|
||||
}
|
||||
}
|
||||
|
||||
// Look in a components templates dir for a base implementation.
|
||||
|
||||
$compdirectory = core_component::get_component_directory($suffix);
|
||||
if ($compdirectory) {
|
||||
$loaderdir = $compdirectory . '/templates';
|
||||
if (is_dir($loaderdir)) {
|
||||
$loader->addLoader(new \core\output\mustache_filesystem_loader($loaderdir, $loaderoptions));
|
||||
}
|
||||
}
|
||||
|
||||
// Look in the core templates dir as a final fallback.
|
||||
|
||||
$compdirectory = $CFG->libdir;
|
||||
if ($compdirectory) {
|
||||
$loaderdir = $compdirectory . '/templates';
|
||||
if (is_dir($loaderdir)) {
|
||||
$loader->addLoader(new \core\output\mustache_filesystem_loader($loaderdir, $loaderoptions));
|
||||
}
|
||||
}
|
||||
|
||||
$stringhelper = new \core\output\mustache_string_helper();
|
||||
$jshelper = new \core\output\mustache_javascript_helper($this->page->requires);
|
||||
$pixhelper = new \core\output\mustache_pix_helper($this);
|
||||
|
||||
// We only expose the variables that are exposed to JS templates.
|
||||
$safeconfig = $this->page->requires->get_config_for_javascript($this->page, $this);
|
||||
|
||||
$helpers = array('config' => $safeconfig,
|
||||
'str' => array($stringhelper, 'str'),
|
||||
'js' => array($jshelper, 'help'),
|
||||
'pix' => array($pixhelper, 'pix'));
|
||||
|
||||
$this->mustache = new Mustache_Engine(array(
|
||||
'cache' => $cachedir,
|
||||
'escape' => 's',
|
||||
'loader' => $loader,
|
||||
'helpers' => $helpers));
|
||||
|
||||
}
|
||||
|
||||
return $this->mustache;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
@@ -83,6 +206,39 @@ class renderer_base {
|
||||
$this->target = $target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a template by name with the given context.
|
||||
*
|
||||
* The provided data needs to be array/stdClass made up of only simple types.
|
||||
* Simple types are array,stdClass,bool,int,float,string
|
||||
*
|
||||
* @since 2.9
|
||||
* @param array|stdClass $context Context containing data for the template.
|
||||
* @return string|boolean
|
||||
*/
|
||||
public function render_from_template($templatename, $context) {
|
||||
static $templatecache = array();
|
||||
$mustache = $this->get_mustache();
|
||||
|
||||
// Provide 1 random value that will not change within a template
|
||||
// but will be different from template to template. This is useful for
|
||||
// e.g. aria attributes that only work with id attributes and must be
|
||||
// unique in a page.
|
||||
$mustache->addHelper('uniqid', new \core\output\mustache_uniqid_helper());
|
||||
if (isset($templatecache[$templatename])) {
|
||||
$template = $templatecache[$templatename];
|
||||
} else {
|
||||
try {
|
||||
$template = $mustache->loadTemplate($templatename);
|
||||
$templatecache[$templatename] = $template;
|
||||
} catch (Mustache_Exception_UnknownTemplateException $e) {
|
||||
throw new moodle_exception('Unknown template: ' . $templatename);
|
||||
}
|
||||
}
|
||||
return trim($template->render($context));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns rendered widget.
|
||||
*
|
||||
@@ -2016,7 +2172,11 @@ class core_renderer extends renderer_base {
|
||||
protected function render_pix_icon(pix_icon $icon) {
|
||||
$attributes = $icon->attributes;
|
||||
$attributes['src'] = $this->pix_url($icon->pix, $icon->component);
|
||||
return html_writer::empty_tag('img', $attributes);
|
||||
$templatecontext = array();
|
||||
foreach ($attributes as $name => $value) {
|
||||
$templatecontext[] = array('name' => $name, 'value' => $value);
|
||||
}
|
||||
return $this->render_from_template('core/pix_icon', array('attributes' => $templatecontext));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user