MDL-75146 mod_data: migrate templates editor to mustache

This commit is contained in:
Ferran Recio
2022-07-22 07:27:40 +02:00
committed by Sara Arjona
parent c6db008496
commit e2da14bbb8
13 changed files with 953 additions and 290 deletions
+137 -1
View File
@@ -16,11 +16,13 @@
namespace mod_data;
use context_module;
use cm_info;
use context_module;
use completion_info;
use data_field_base;
use mod_data\event\course_module_viewed;
use mod_data\event\template_viewed;
use mod_data\event\template_updated;
use stdClass;
/**
@@ -38,6 +40,23 @@ class manager {
/** Pluginname name. */
const PLUGIN = 'mod_data';
/** Template list with their files required to save the information of a preset. */
const TEMPLATES_LIST = [
'listtemplate' => 'listtemplate.html',
'singletemplate' => 'singletemplate.html',
'asearchtemplate' => 'asearchtemplate.html',
'addtemplate' => 'addtemplate.html',
'rsstemplate' => 'rsstemplate.html',
'csstemplate' => 'csstemplate.css',
'jstemplate' => 'jstemplate.js',
'listtemplateheader' => 'listtemplateheader.html',
'listtemplatefooter' => 'listtemplatefooter.html',
'rsstitletemplate' => 'rsstitletemplate.html',
];
/** @var string plugin path. */
private $path;
/** @var stdClass course_module record. */
private $instance;
@@ -47,6 +66,11 @@ class manager {
/** @var cm_info course_modules record. */
private $cm;
/** @var array the current data_fields records.
* Do not acces this attribute directly, use $this->get_field_records instead
*/
private $_fieldrecords = null;
/**
* Class contructor.
*
@@ -54,10 +78,12 @@ class manager {
* @param stdClass $instance activity instance object.
*/
public function __construct(cm_info $cm, stdClass $instance) {
global $CFG;
$this->cm = $cm;
$this->instance = $instance;
$this->context = context_module::instance($cm->id);
$this->instance->cmidnumber = $cm->idnumber;
$this->path = $CFG->dirroot . '/mod/' . self::MODULE;
}
/**
@@ -167,4 +193,114 @@ class manager {
$event->add_record_snapshot(self::MODULE, $this->instance);
$event->trigger();
}
/**
* Return the database fields.
*
* @return data_field_base[] the field instances.
*/
public function get_fields(): array {
$result = [];
$fieldrecords = $this->get_field_records();
foreach ($fieldrecords as $fieldrecord) {
$result[$fieldrecord->id] = $this->get_field($fieldrecord);
}
return $result;
}
/**
* Return the field records (the current data_fields records).
*
* @return stdClass[] an array of records
*/
public function get_field_records() {
global $DB;
if ($this->_fieldrecords === null) {
$this->_fieldrecords = $DB->get_records('data_fields', ['dataid' => $this->instance->id]);
}
return $this->_fieldrecords;
}
/**
* Return a specific field instance from a field record.
*
* @param stdClass $fieldrecord the fieldrecord to convert
* @return data_field_base the data field class instance
*/
public function get_field(stdClass $fieldrecord): data_field_base {
$filepath = "{$this->path}/field/{$fieldrecord->type}/field.class.php";
$classname = "data_field_{$fieldrecord->type}";
if (!file_exists($filepath) || !class_exists($classname)) {
return new data_field_base($fieldrecord, $this->instance, $this->cm);
}
require_once($filepath);
$newfield = new $classname($fieldrecord, $this->instance, $this->cm);
return $newfield;
}
/**
* Return a specific template.
*
* NOTE: this method returns a default template if the module template is empty.
* However, it won't update the template database field.
*
* @param string $templatename
* @param array $options extra display options array
* @return template the template instance
*/
public function get_template(string $templatename, array $options = []): template {
if ($templatename == 'single') {
$templatename == 'singletemplate';
}
$instance = $this->instance;
$templatestr = $instance->{$templatename} ?? '';
if (empty($templatestr)) {
$templatestr = data_generate_default_template($instance, $templatename, 0, false, false);
}
// Some templates have extra options.
if ($templatename == 'singletemplate') {
$options['comments'] = true;
$options['ratings'] = true;
}
return new template($this, $templatestr, $options);
}
/**
* Update the database templates.
*
* @param stdClass $newtemplates an object with all the new templates
* @return bool if updated successfully.
*/
public function update_templates(stdClass $newtemplates) {
global $DB;
$record = (object)[
'id' => $this->instance->id,
];
foreach (self::TEMPLATES_LIST as $templatename => $templatefile) {
if (!isset($newtemplates->{$templatename})) {
continue;
}
$record->{$templatename} = $newtemplates->{$templatename};
}
// The add entry form cannot repeat tags.
if (isset($record->addtemplate) && !data_tags_check($this->instance->id, $record->addtemplate)) {
return false;
}
$DB->update_record(self::MODULE, $record);
$this->instance = $DB->get_record(self::MODULE, ['id' => $this->cm->instance], '*', MUST_EXIST);
// Trigger an event for saving the templates.
$event = template_updated::create(array(
'context' => $this->context,
'courseid' => $this->cm->course,
'other' => array(
'dataid' => $this->instance->id,
)
));
$event->trigger();
return true;
}
}
+191
View File
@@ -0,0 +1,191 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_data\output;
use templatable;
use renderable;
use mod_data\manager;
use moodle_url;
use texteditor;
/**
* Renderable class for template editor.
*
* @package mod_data
* @copyright 2022 Ferran Recio <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class template_editor implements templatable, renderable {
/** @var manager manager instance. */
private $manager;
/** @var string the template name. */
private $templatename;
/**
* The class constructor.
*
* @param manager $manager the activity instance manager
* @param string $templatename the template to edit
*/
public function __construct(manager $manager, string $templatename) {
$this->manager = $manager;
$this->templatename = $templatename;
}
/**
* Export the data for the mustache template.
*
* @param \renderer_base $output renderer to be used to render the action bar elements.
* @return array
*/
public function export_for_template(\renderer_base $output): array {
$instance = $this->manager->get_instance();
$cm = $this->manager->get_coursemodule();
$data = [
'title' => get_string('header' . $this->templatename, 'data'),
'sesskey' => sesskey(),
'disableeditor' => true,
'url' => new moodle_url('/mod/data/templates.php', ['id' => $cm->id, 'mode' => $this->templatename]),
];
// Determine whether to use HTML editors.
if (($this->templatename === 'csstemplate') || ($this->templatename === 'jstemplate')) {
$usehtmleditor = false;
} else {
$usehtmleditor = data_get_config($instance, "editor_{$this->templatename}", true);
}
$data['usehtmleditor'] = $usehtmleditor;
$tools = new template_editor_tools($this->manager, $this->templatename);
$data['toolbar'] = $tools->export_for_template($output);
$data['editors'] = $this->get_editors_data($usehtmleditor);
// Some templates cannot enable the wysiwyg editor.
if ($this->templatename == 'csstemplate' || $this->templatename == 'jstemplate') {
$data['disableeditor'] = false;
}
return $data;
}
/**
* Get the editors data.
*
* @param bool $usehtmleditor if the user wants wysiwyg editor or not
* @return array editors data
*/
private function get_editors_data(bool $usehtmleditor): array {
global $PAGE;
$result = [];
$instance = $this->manager->get_instance();
// Setup editor.
editors_head_setup();
$PAGE->requires->js_call_amd(
'mod_data/templateseditor',
'init',
['d' => $instance->id, 'mode' => $this->templatename]
);
if ($usehtmleditor) {
$format = FORMAT_HTML;
} else {
$format = FORMAT_PLAIN;
}
$editor = editors_get_preferred_editor($format);
// Add editors.
if ($this->templatename == 'listtemplate') {
$result[] = $this->generate_editor_data(
$editor,
'header',
'listtemplateheader',
$instance->listtemplateheader
);
$maineditorname = 'multientry';
} else {
$maineditorname = $this->templatename;
}
$value = $instance->{$this->templatename} ?? '';
$result[] = $this->generate_editor_data(
$editor,
$maineditorname,
$this->templatename,
$value
);
if ($this->templatename == 'listtemplate') {
$result[] = $this->generate_editor_data(
$editor,
'footer',
'listtemplatefooter',
$instance->listtemplatefooter
);
}
if ($this->templatename == 'rsstemplate') {
$result[] = $this->generate_editor_data(
$editor,
'rsstitletemplate',
'rsstitletemplate',
$instance->rsstitletemplate
);
}
return $result;
}
/**
* Generate a single editor data.
*
* @param texteditor $editor the edtitor object
* @param string $name the editor name
* @param string $fieldname the field name
* @param string|null $value the current value
* @return array the editor data
*/
private function generate_editor_data(
texteditor $editor,
string $name,
string $fieldname,
?string $value
): array {
$options = [
'trusttext' => false,
'forcehttps' => false,
'subdirs' => false,
'maxfiles' => 0,
'maxbytes' => 0,
'changeformat' => 0,
'noclean' => false,
];
$result = [
'name' => get_string($name, 'data'),
'fieldname' => $fieldname,
'value' => $value,
];
$editor->set_text($value);
$editor->use_editor($fieldname, $options);
return $result;
}
}
@@ -0,0 +1,199 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_data\output;
use templatable;
use renderable;
use core_tag_tag;
use mod_data\manager;
use moodle_url;
/**
* Renderable class for template editor tools.
*
* @package mod_data
* @copyright 2022 Ferran Recio <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class template_editor_tools implements templatable, renderable {
/** @var manager manager instance. */
private $manager;
/** @var string the template name. */
private $templatename;
/**
* The class constructor.
*
* @param manager $manager the activity instance manager
* @param string $templatename the template to edit
*/
public function __construct(manager $manager, string $templatename) {
$this->manager = $manager;
$this->templatename = $templatename;
}
/**
* Export the data for the mustache template.
*
* @param \renderer_base $output renderer to be used to render the action bar elements.
* @return array
*/
public function export_for_template(\renderer_base $output): array {
$tools = [
$this->get_field_tags($this->templatename),
$this->get_field_id_tags($this->templatename),
$this->get_action_tags($this->templatename),
$this->get_other_tags($this->templatename),
];
$tools = array_filter($tools, static function ($value) {
return !empty($value['tags']);
});
return [
'toolshelp' => $output->help_icon('availabletags', 'data'),
'hastools' => !empty($tools),
'tools' => array_values($tools),
];
}
/**
* Return the field template tags.
*
* @param string $templatename the template name
* @return array|null array of tags.
*/
protected function get_field_tags(string $templatename): array {
$name = get_string('fields', 'data');
if ($templatename == 'csstemplate' || $templatename == 'jstemplate') {
return $this->get_optgroup_data($name, []);
}
$taglist = [];
$fields = $this->manager->get_fields();
foreach ($fields as $field) {
$fieldname = $field->get_name();
$taglist["[[$fieldname]]"] = $fieldname;
}
return $this->get_optgroup_data($name, $taglist);
}
/**
* Return the field IDs template tags.
*
* @param string $templatename the template name
* @return array|null array of tags.
*/
protected function get_field_id_tags(string $templatename): array {
$name = get_string('fieldids', 'data');
if ($templatename != 'addtemplate') {
return $this->get_optgroup_data($name, []);
}
$taglist = [];
// Field IDs.
$fields = $this->manager->get_fields();
foreach ($fields as $field) {
$fieldname = $field->get_name();
$taglist["[[$fieldname#id]]"] = "$fieldname id";
}
return $this->get_optgroup_data($name, $taglist);
}
/**
* Return the field action tags.
*
* @param string $templatename the template name
* @return array|null array of tags.
*/
protected function get_action_tags(string $templatename = null): array {
$name = get_string('actions');
if ($templatename == 'addtemplate' || $templatename == 'asearchtemplate') {
return $this->get_optgroup_data($name, []);
}
$taglist = [
'##edit##' => get_string('edit', 'data'),
'##delete##' => get_string('delete', 'data'),
'##approve##' => get_string('approve', 'data'),
'##disapprove##' => get_string('disapprove', 'data'),
];
if ($templatename != 'rsstemplate') {
$taglist['##export##'] = get_string('export', 'data');
}
if ($templatename != 'singletemplate') {
$taglist['##more##'] = get_string('more', 'data');
$taglist['##moreurl##'] = get_string('moreurl', 'data');
$taglist['##delcheck##'] = get_string('delcheck', 'data');
}
return $this->get_optgroup_data($name, $taglist);
}
/**
* Return the available other tags
*
* @param string $templatename the template name
* @return array associative array of tags => tag name
*/
protected function get_other_tags(string $templatename = null): array {
$name = get_string('other', 'data');
$taglist = [];
if ($templatename == 'asearchtemplate') {
$taglist['##firstname##'] = get_string('firstname');
$taglist['##lastname##'] = get_string('lastname');
return $this->get_optgroup_data($name, $taglist);
}
if (core_tag_tag::is_enabled('mod_data', 'data_records')) {
$taglist['##tags##'] = get_string('tags');
}
if ($templatename == 'addtemplate') {
return $this->get_optgroup_data($name, $taglist);
}
$taglist['##timeadded##'] = get_string('timeadded', 'data');
$taglist['##timemodified##'] = get_string('timemodified', 'data');
$taglist['##user##'] = get_string('user');
$taglist['##userpicture##'] = get_string('userpic');
$taglist['##approvalstatus##'] = get_string('approvalstatus', 'data');
$taglist['##id##'] = get_string('id', 'data');
if ($templatename == 'singletemplate') {
return $this->get_optgroup_data($name, $taglist);
}
$taglist['##comments##'] = get_string('comments', 'data');
return $this->get_optgroup_data($name, $taglist);
}
/**
* Generate a valid optgroup data.
*
* @param string $name the optgroup name
* @param array $taglist the indexed array of taglists ($tag => $tagname)
* @return array of optgroup data
*/
protected function get_optgroup_data (string $name, array $taglist): array {
$tags = [];
foreach ($taglist as $tag => $tagname) {
$tags[] = [
'tag' => "$tag",
'tagname' => $tagname . ' - ' . $tag,
];
}
return [
'name' => $name,
'tags' => $tags,
];
}
}