mirror of
https://github.com/moodle/moodle.git
synced 2025-04-21 00:12:56 +02:00
MDL-75146 mod_data: migrate templates editor to mustache
This commit is contained in:
parent
c6db008496
commit
e2da14bbb8
2
mod/data/amd/build/templateseditor.min.js
vendored
2
mod/data/amd/build/templateseditor.min.js
vendored
@ -6,6 +6,6 @@ define("mod_data/templateseditor",["exports","core/str","core/notification","cor
|
||||
* @copyright 2021 Mihail Geshoski <mihail@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
const selectors_toggleTemplateEditor='input[name="useeditor"]';_exports.init=(d,mode)=>{((d,mode)=>{document.querySelector(selectors_toggleTemplateEditor).addEventListener("click",(async event=>{event.preventDefault(),event.target.checked?(0,_notification.confirm)((0,_str.get_string)("confirmation","admin"),(0,_str.get_string)("enabletemplateeditorcheck","mod_data"),(0,_str.get_string)("yes","core"),(0,_str.get_string)("no","core"),(()=>{window.location=(0,_url.relativeUrl)("/mod/data/templates.php",{d:d,mode:mode,useeditor:!0})})):window.location=(0,_url.relativeUrl)("/mod/data/templates.php",{d:d,mode:mode,useeditor:!1})}))})(d,mode)}}));
|
||||
const selectors_toggleTemplateEditor='input[name="useeditor"]';_exports.init=(d,mode)=>{((d,mode)=>{const toggleTemplateEditor=document.querySelector(selectors_toggleTemplateEditor);toggleTemplateEditor&&toggleTemplateEditor.addEventListener("click",(async event=>{event.preventDefault(),event.target.checked?(0,_notification.confirm)((0,_str.get_string)("confirmation","admin"),(0,_str.get_string)("enabletemplateeditorcheck","mod_data"),(0,_str.get_string)("yes","core"),(0,_str.get_string)("no","core"),(()=>{window.location=(0,_url.relativeUrl)("/mod/data/templates.php",{d:d,mode:mode,useeditor:!0})})):window.location=(0,_url.relativeUrl)("/mod/data/templates.php",{d:d,mode:mode,useeditor:!1})}))})(d,mode)}}));
|
||||
|
||||
//# sourceMappingURL=templateseditor.min.js.map
|
@ -1 +1 @@
|
||||
{"version":3,"file":"templateseditor.min.js","sources":["../src/templateseditor.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Javascript module to control the template editor.\n *\n * @module mod_data/templateseditor\n * @copyright 2021 Mihail Geshoski <mihail@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {get_string as getString} from 'core/str';\nimport {confirm as confirmDialogue} from 'core/notification';\nimport {relativeUrl} from 'core/url';\n\n/**\n * Template editor constants.\n */\nconst selectors = {\n toggleTemplateEditor: 'input[name=\"useeditor\"]',\n};\n\n/**\n * Register event listeners for the module.\n *\n * @param {int} d The database ID\n * @param {string} mode The template mode\n */\nconst registerEventListeners = (d, mode) => {\n const toggleTemplateEditor = document.querySelector(selectors.toggleTemplateEditor);\n\n toggleTemplateEditor.addEventListener('click', async(event) => {\n event.preventDefault();\n // Whether the event action attempts to enable or disable the template editor.\n const enableTemplateEditor = event.target.checked;\n\n if (enableTemplateEditor) {\n // Display a confirmation dialog before enabling the template editor.\n confirmDialogue(\n getString('confirmation', 'admin'),\n getString('enabletemplateeditorcheck', 'mod_data'),\n getString('yes', 'core'),\n getString('no', 'core'),\n () => {\n window.location = relativeUrl('/mod/data/templates.php', {d: d, mode: mode, useeditor: true});\n }\n );\n } else {\n window.location = relativeUrl('/mod/data/templates.php', {d: d, mode: mode, useeditor: false});\n }\n });\n};\n\n/**\n * Initialize the module.\n *\n * @param {int} d The database ID\n * @param {string} mode The template mode\n */\nexport const init = (d, mode) => {\n registerEventListeners(d, mode);\n};\n"],"names":["selectors","d","mode","document","querySelector","addEventListener","async","event","preventDefault","target","checked","window","location","useeditor","registerEventListeners"],"mappings":";;;;;;;;MA8BMA,+BACoB,wCAwCN,CAACC,EAAGC,QA/BO,EAACD,EAAGC,QACFC,SAASC,cAAcJ,gCAE/BK,iBAAiB,SAASC,MAAAA,QAC3CC,MAAMC,iBAEuBD,MAAME,OAAOC,mCAKlC,mBAAU,eAAgB,UAC1B,mBAAU,4BAA6B,aACvC,mBAAU,MAAO,SACjB,mBAAU,KAAM,SAChB,KACIC,OAAOC,UAAW,oBAAY,0BAA2B,CAACX,EAAGA,EAAGC,KAAMA,KAAMW,WAAW,OAI/FF,OAAOC,UAAW,oBAAY,0BAA2B,CAACX,EAAGA,EAAGC,KAAMA,KAAMW,WAAW,QAY/FC,CAAuBb,EAAGC"}
|
||||
{"version":3,"file":"templateseditor.min.js","sources":["../src/templateseditor.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Javascript module to control the template editor.\n *\n * @module mod_data/templateseditor\n * @copyright 2021 Mihail Geshoski <mihail@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport {get_string as getString} from 'core/str';\nimport {confirm as confirmDialogue} from 'core/notification';\nimport {relativeUrl} from 'core/url';\n\n/**\n * Template editor constants.\n */\nconst selectors = {\n toggleTemplateEditor: 'input[name=\"useeditor\"]',\n};\n\n/**\n * Register event listeners for the module.\n *\n * @param {int} d The database ID\n * @param {string} mode The template mode\n */\nconst registerEventListeners = (d, mode) => {\n const toggleTemplateEditor = document.querySelector(selectors.toggleTemplateEditor);\n\n if (!toggleTemplateEditor) {\n return;\n }\n\n toggleTemplateEditor.addEventListener('click', async(event) => {\n event.preventDefault();\n // Whether the event action attempts to enable or disable the template editor.\n const enableTemplateEditor = event.target.checked;\n\n if (enableTemplateEditor) {\n // Display a confirmation dialog before enabling the template editor.\n confirmDialogue(\n getString('confirmation', 'admin'),\n getString('enabletemplateeditorcheck', 'mod_data'),\n getString('yes', 'core'),\n getString('no', 'core'),\n () => {\n window.location = relativeUrl('/mod/data/templates.php', {d: d, mode: mode, useeditor: true});\n }\n );\n } else {\n window.location = relativeUrl('/mod/data/templates.php', {d: d, mode: mode, useeditor: false});\n }\n });\n};\n\n/**\n * Initialize the module.\n *\n * @param {int} d The database ID\n * @param {string} mode The template mode\n */\nexport const init = (d, mode) => {\n registerEventListeners(d, mode);\n};\n"],"names":["selectors","d","mode","toggleTemplateEditor","document","querySelector","addEventListener","async","event","preventDefault","target","checked","window","location","useeditor","registerEventListeners"],"mappings":";;;;;;;;MA8BMA,+BACoB,wCA4CN,CAACC,EAAGC,QAnCO,EAACD,EAAGC,cACzBC,qBAAuBC,SAASC,cAAcL,gCAE/CG,sBAILA,qBAAqBG,iBAAiB,SAASC,MAAAA,QAC3CC,MAAMC,iBAEuBD,MAAME,OAAOC,mCAKlC,mBAAU,eAAgB,UAC1B,mBAAU,4BAA6B,aACvC,mBAAU,MAAO,SACjB,mBAAU,KAAM,SAChB,KACIC,OAAOC,UAAW,oBAAY,0BAA2B,CAACZ,EAAGA,EAAGC,KAAMA,KAAMY,WAAW,OAI/FF,OAAOC,UAAW,oBAAY,0BAA2B,CAACZ,EAAGA,EAAGC,KAAMA,KAAMY,WAAW,QAY/FC,CAAuBd,EAAGC"}
|
@ -41,6 +41,10 @@ const selectors = {
|
||||
const registerEventListeners = (d, mode) => {
|
||||
const toggleTemplateEditor = document.querySelector(selectors.toggleTemplateEditor);
|
||||
|
||||
if (!toggleTemplateEditor) {
|
||||
return;
|
||||
}
|
||||
|
||||
toggleTemplateEditor.addEventListener('click', async(event) => {
|
||||
event.preventDefault();
|
||||
// Whether the event action attempts to enable or disable the template editor.
|
||||
|
@ -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
mod/data/classes/output/template_editor.php
Normal file
191
mod/data/classes/output/template_editor.php
Normal 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 <ferran@moodle.com>
|
||||
* @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;
|
||||
}
|
||||
}
|
199
mod/data/classes/output/template_editor_tools.php
Normal file
199
mod/data/classes/output/template_editor_tools.php
Normal file
@ -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 <ferran@moodle.com>
|
||||
* @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,
|
||||
];
|
||||
}
|
||||
}
|
@ -52,7 +52,6 @@ Only the tags that are in the "Available tags" list may be used for the current
|
||||
$string['availabletodate'] = 'Available to';
|
||||
$string['availabletodatevalidation'] = 'The available to date cannot be before the available from date.';
|
||||
$string['blank'] = 'Blank';
|
||||
$string['buttons'] = 'Actions';
|
||||
$string['bynameondate'] = 'by {$a->name} - {$a->date}';
|
||||
$string['calendarend'] = '{$a} closes';
|
||||
$string['calendarstart'] = '{$a} opens';
|
||||
@ -203,6 +202,7 @@ $string['headerlisttemplate'] = 'Defines browsing interface for multiple entries
|
||||
$string['headerrsstemplate'] = 'Defines appearance of entries in RSS feeds';
|
||||
$string['headersingletemplate'] = 'Defines browsing interface for a single entry';
|
||||
$string['checkbox'] = 'Checkbox';
|
||||
$string['id'] = 'Entry ID';
|
||||
$string['chooseexportfields'] = 'Choose the fields you wish to export';
|
||||
$string['chooseexportformat'] = 'Choose the format you wish to export to';
|
||||
$string['chooseorupload'] = 'Choose file';
|
||||
@ -432,3 +432,6 @@ $string['wrongdataid'] = 'Wrong data id provided';
|
||||
|
||||
// Deprecated since Moodle 3.11.
|
||||
$string['unsupportedexport'] = '({$a->fieldtype}) cannot be exported.';
|
||||
|
||||
// Deprecated since Moodle 4.1.
|
||||
$string['buttons'] = 'Actions';
|
||||
|
@ -1 +1,2 @@
|
||||
unsupportedexport,mod_data
|
||||
buttons,mod_data
|
||||
|
@ -21,6 +21,8 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use mod_data\manager;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
// Some constants
|
||||
@ -136,6 +138,15 @@ class data_field_base { // Base class for Database Field Types (see field/*/
|
||||
$this->context = context_module::instance($this->cm->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the field type name.
|
||||
*
|
||||
* @return string the filed type.
|
||||
*/
|
||||
public function get_name(): string {
|
||||
return $this->field->name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This field just sets up a default field object
|
||||
@ -898,7 +909,7 @@ function data_get_field_new($type, $data) {
|
||||
* @param object $field
|
||||
* @param object $data
|
||||
* @param object $cm
|
||||
* @return object
|
||||
* @return data_field_base
|
||||
*/
|
||||
function data_get_field($field, $data, $cm=null) {
|
||||
global $CFG;
|
||||
|
@ -36,16 +36,16 @@ $useeditor = optional_param('useeditor', null, PARAM_BOOL);
|
||||
$url = new moodle_url('/mod/data/templates.php');
|
||||
|
||||
if ($id) {
|
||||
$url->param('id', $id);
|
||||
list($course, $cm) = get_course_and_cm_from_cmid($id, manager::MODULE);
|
||||
$manager = manager::create_from_coursemodule($cm);
|
||||
$url->param('d', $cm->instance);
|
||||
} else { // We must have $d.
|
||||
$instance = $DB->get_record('data', ['id' => $d], '*', MUST_EXIST);
|
||||
$manager = manager::create_from_instance($instance);
|
||||
$url->param('d', $d);
|
||||
$data = $DB->get_record('data', ['id' => $d], '*', MUST_EXIST);
|
||||
$manager = manager::create_from_instance($data);
|
||||
}
|
||||
|
||||
$data = $manager->get_instance();
|
||||
$instance = $manager->get_instance();
|
||||
$cm = $manager->get_coursemodule();
|
||||
$context = $manager->get_context();
|
||||
$course = get_course($cm->course);
|
||||
@ -54,319 +54,65 @@ $url->param('mode', $mode);
|
||||
$PAGE->set_url($url);
|
||||
|
||||
require_login($course, false, $cm);
|
||||
|
||||
require_capability('mod/data:managetemplates', $context);
|
||||
|
||||
if ($useeditor !== null) {
|
||||
// The useeditor param was set. Update the value for this template.
|
||||
data_set_config($data, "editor_{$mode}", !!$useeditor);
|
||||
}
|
||||
|
||||
if (!$DB->count_records('data_fields', array('dataid'=>$data->id))) { // Brand new database!
|
||||
redirect($CFG->wwwroot.'/mod/data/field.php?d='.$data->id); // Redirect to field entry
|
||||
// Check if it is an empty database.
|
||||
if (count($manager->get_field_records()) == 0) {
|
||||
redirect($CFG->wwwroot.'/mod/data/field.php?d='.$instance->id);
|
||||
}
|
||||
|
||||
$manager->set_template_viewed();
|
||||
|
||||
/// Print the page header
|
||||
|
||||
$strdata = get_string('modulenameplural','data');
|
||||
|
||||
// For the javascript for inserting template tags: initialise the default textarea to
|
||||
// 'edit_template' - it is always present in all different possible views.
|
||||
|
||||
if ($mode == 'singletemplate') {
|
||||
$PAGE->navbar->add(get_string($mode,'data'));
|
||||
if ($useeditor !== null) {
|
||||
// The useeditor param was set. Update the value for this template.
|
||||
data_set_config($instance, "editor_{$mode}", !!$useeditor);
|
||||
}
|
||||
|
||||
$PAGE->requires->js('/mod/data/data.js');
|
||||
$PAGE->set_title($data->name);
|
||||
$PAGE->set_title($instance->name);
|
||||
$PAGE->set_heading($course->fullname);
|
||||
$PAGE->set_pagelayout('admin');
|
||||
$PAGE->force_settings_menu(true);
|
||||
$PAGE->activityheader->disable();
|
||||
$PAGE->add_body_class('limitedwidth');
|
||||
|
||||
echo $OUTPUT->header();
|
||||
|
||||
$actionbar = new \mod_data\output\action_bar($data->id, $url);
|
||||
$actionbar = new \mod_data\output\action_bar($instance->id, $url);
|
||||
echo $actionbar->get_templates_action_bar();
|
||||
|
||||
echo $OUTPUT->heading(get_string($mode, 'data'), 2, 'mb-4');
|
||||
|
||||
/// Processing submitted data, i.e updating form.
|
||||
$resettemplate = false;
|
||||
|
||||
if (($mytemplate = data_submitted()) && confirm_sesskey()) {
|
||||
$newtemplate = new stdClass();
|
||||
$newtemplate->id = $data->id;
|
||||
$newtemplate->{$mode} = $mytemplate->template;
|
||||
|
||||
if (!empty($mytemplate->defaultform)) {
|
||||
if (($formdata = data_submitted()) && confirm_sesskey()) {
|
||||
if (!empty($formdata->defaultform)) {
|
||||
// Reset the template to default, but don't save yet.
|
||||
$resettemplate = true;
|
||||
$data->{$mode} = data_generate_default_template($data, $mode, 0, false, false);
|
||||
$instance->{$mode} = data_generate_default_template($instance, $mode, 0, false, false);
|
||||
if ($mode == 'listtemplate') {
|
||||
$data->listtemplateheader = '';
|
||||
$data->listtemplatefooter = '';
|
||||
$instance->listtemplateheader = '';
|
||||
$instance->listtemplatefooter = '';
|
||||
}
|
||||
} else {
|
||||
if (isset($mytemplate->listtemplateheader)){
|
||||
$newtemplate->listtemplateheader = $mytemplate->listtemplateheader;
|
||||
}
|
||||
if (isset($mytemplate->listtemplatefooter)){
|
||||
$newtemplate->listtemplatefooter = $mytemplate->listtemplatefooter;
|
||||
}
|
||||
if (isset($mytemplate->rsstitletemplate)){
|
||||
$newtemplate->rsstitletemplate = $mytemplate->rsstitletemplate;
|
||||
}
|
||||
|
||||
// Check for multiple tags, only need to check for add template.
|
||||
if ($mode != 'addtemplate' or data_tags_check($data->id, $newtemplate->{$mode})) {
|
||||
$DB->update_record('data', $newtemplate);
|
||||
if ($manager->update_templates($formdata)) {
|
||||
// Reload instance.
|
||||
$instance = $manager->get_instance();
|
||||
echo $OUTPUT->notification(get_string('templatesaved', 'data'), 'notifysuccess');
|
||||
|
||||
// Trigger an event for saving the templates.
|
||||
$event = \mod_data\event\template_updated::create(array(
|
||||
'context' => $context,
|
||||
'courseid' => $course->id,
|
||||
'other' => array(
|
||||
'dataid' => $data->id,
|
||||
)
|
||||
));
|
||||
$event->trigger();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
echo '<div class="template_heading">'.get_string('header'.$mode,'data').'</div>';
|
||||
}
|
||||
|
||||
/// If everything is empty then generate some defaults
|
||||
if (empty($data->addtemplate) and empty($data->singletemplate) and
|
||||
empty($data->listtemplate) and empty($data->rsstemplate)) {
|
||||
data_generate_default_template($data, 'singletemplate');
|
||||
data_generate_default_template($data, 'listtemplate');
|
||||
data_generate_default_template($data, 'addtemplate');
|
||||
data_generate_default_template($data, 'asearchtemplate'); //Template for advanced searches.
|
||||
data_generate_default_template($data, 'rsstemplate');
|
||||
if (empty($instance->addtemplate) && empty($instance->singletemplate) &&
|
||||
empty($instance->listtemplate) && empty($instance->rsstemplate)) {
|
||||
data_generate_default_template($instance, 'singletemplate');
|
||||
data_generate_default_template($instance, 'listtemplate');
|
||||
data_generate_default_template($instance, 'addtemplate');
|
||||
data_generate_default_template($instance, 'asearchtemplate');
|
||||
data_generate_default_template($instance, 'rsstemplate');
|
||||
}
|
||||
|
||||
editors_head_setup();
|
||||
|
||||
// Determine whether to use HTML editors.
|
||||
if (($mode === 'csstemplate') || ($mode === 'jstemplate')) {
|
||||
// The CSS and JS templates aren't HTML.
|
||||
$usehtmleditor = false;
|
||||
} else {
|
||||
$usehtmleditor = data_get_config($data, "editor_{$mode}", true);
|
||||
}
|
||||
|
||||
if ($usehtmleditor) {
|
||||
$format = FORMAT_HTML;
|
||||
} else {
|
||||
$format = FORMAT_PLAIN;
|
||||
}
|
||||
|
||||
$editor = editors_get_preferred_editor($format);
|
||||
$strformats = format_text_menu();
|
||||
$formats = $editor->get_supported_formats();
|
||||
foreach ($formats as $fid) {
|
||||
$formats[$fid] = $strformats[$fid];
|
||||
}
|
||||
$options = array();
|
||||
$options['trusttext'] = false;
|
||||
$options['forcehttps'] = false;
|
||||
$options['subdirs'] = false;
|
||||
$options['maxfiles'] = 0;
|
||||
$options['maxbytes'] = 0;
|
||||
$options['changeformat'] = 0;
|
||||
$options['noclean'] = false;
|
||||
|
||||
echo '<form id="tempform" action="templates.php?d='.$data->id.'&mode='.$mode.'" method="post">';
|
||||
echo '<div>';
|
||||
echo '<input name="sesskey" value="'.sesskey().'" type="hidden" />';
|
||||
// Print button to autogen all forms, if all templates are empty
|
||||
|
||||
if (!$resettemplate) {
|
||||
// Only reload if we are not resetting the template to default.
|
||||
$data = $DB->get_record('data', array('id'=>$d));
|
||||
}
|
||||
echo $OUTPUT->box_start('generalbox boxaligncenter boxwidthwide');
|
||||
echo '<table cellpadding="4" cellspacing="0" border="0">';
|
||||
|
||||
if ($mode == 'listtemplate'){
|
||||
// Print the list template header.
|
||||
echo '<tr>';
|
||||
echo '<td> </td>';
|
||||
echo '<td>';
|
||||
echo '<div class="template_heading"><label for="edit-listtemplateheader">'.get_string('header','data').'</label></div>';
|
||||
|
||||
$field = 'listtemplateheader';
|
||||
$editor->set_text($data->listtemplateheader);
|
||||
$editor->use_editor($field, $options);
|
||||
echo '<div><textarea id="'.$field.'" name="'.$field.'" class="form-control" rows="15" cols="80">' .
|
||||
s($data->listtemplateheader) . '</textarea></div>';
|
||||
|
||||
echo '</td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
|
||||
// Print the main template.
|
||||
|
||||
echo '<tr><td valign="top">';
|
||||
if ($mode != 'csstemplate' and $mode != 'jstemplate') {
|
||||
// Add all the available fields for this data.
|
||||
echo '<label for="availabletags">'.get_string('availabletags','data').'</label>';
|
||||
echo $OUTPUT->help_icon('availabletags', 'data');
|
||||
echo '<br />';
|
||||
|
||||
echo '<div class="no-overflow" id="availabletags_wrapper">';
|
||||
echo '<select name="fields1[]" id="availabletags" size="12" onclick="insert_field_tags(this)" class="form-control">';
|
||||
|
||||
$fields = $DB->get_records('data_fields', array('dataid'=>$data->id));
|
||||
echo '<optgroup label="'.get_string('fields', 'data').'">';
|
||||
foreach ($fields as $field) {
|
||||
echo '<option value="[['.$field->name.']]" title="'.$field->description.'">'.$field->name.' - [['.$field->name.']]</option>';
|
||||
}
|
||||
echo '</optgroup>';
|
||||
|
||||
if ($mode == 'addtemplate') {
|
||||
echo '<optgroup label="'.get_string('fieldids', 'data').'">';
|
||||
foreach ($fields as $field) {
|
||||
if (in_array($field->type, array('picture', 'checkbox', 'date', 'latlong', 'radiobutton'))) {
|
||||
continue; //ids are not usable for these composed items
|
||||
}
|
||||
echo '<option value="[['.$field->name.'#id]]" title="'.$field->description.' id">'.$field->name.' id - [['.$field->name.'#id]]</option>';
|
||||
}
|
||||
echo '</optgroup>';
|
||||
if (core_tag_tag::is_enabled('mod_data', 'data_records')) {
|
||||
echo '<optgroup label="'.get_string('other', 'data').'">';
|
||||
echo '<option value="##tags##">' . get_string('tags') . ' - ##tags##</option>';
|
||||
echo '</optgroup>';
|
||||
}
|
||||
}
|
||||
|
||||
// Print special tags. fix for MDL-7031
|
||||
if ($mode != 'addtemplate' && $mode != 'asearchtemplate') { //Don't print special tags when viewing the advanced search template and add template.
|
||||
echo '<optgroup label="'.get_string('buttons', 'data').'">';
|
||||
echo '<option value="##edit##">' .get_string('edit', 'data'). ' - ##edit##</option>';
|
||||
echo '<option value="##delete##">' .get_string('delete', 'data'). ' - ##delete##</option>';
|
||||
echo '<option value="##approve##">' .get_string('approve', 'data'). ' - ##approve##</option>';
|
||||
echo '<option value="##disapprove##">' .get_string('disapprove', 'data'). ' - ##disapprove##</option>';
|
||||
if ($mode != 'rsstemplate') {
|
||||
echo '<option value="##export##">' .get_string('export', 'data'). ' - ##export##</option>';
|
||||
}
|
||||
if ($mode != 'singletemplate') {
|
||||
// more points to single template - not useable there
|
||||
echo '<option value="##more##">' .get_string('more', 'data'). ' - ##more##</option>';
|
||||
echo '<option value="##moreurl##">' .get_string('moreurl', 'data'). ' - ##moreurl##</option>';
|
||||
echo '<option value="##delcheck##">' .get_string('delcheck', 'data'). ' - ##delcheck##</option>';
|
||||
}
|
||||
echo '</optgroup>';
|
||||
echo '<optgroup label="'.get_string('other', 'data').'">';
|
||||
echo '<option value="##timeadded##">'.get_string('timeadded', 'data'). ' - ##timeadded##</option>';
|
||||
echo '<option value="##timemodified##">'.get_string('timemodified', 'data'). ' - ##timemodified##</option>';
|
||||
echo '<option value="##user##">' .get_string('user'). ' - ##user##</option>';
|
||||
echo '<option value="##userpicture##">' . get_string('userpic') . ' - ##userpicture##</option>';
|
||||
echo '<option value="##approvalstatus##">' .get_string('approvalstatus', 'data'). ' - ##approvalstatus##</option>';
|
||||
|
||||
if (core_tag_tag::is_enabled('mod_data', 'data_records')) {
|
||||
echo '<option value="##tags##">' . get_string('tags') . ' - ##tags##</option>';
|
||||
}
|
||||
|
||||
if ($mode != 'singletemplate') {
|
||||
// more points to single template - not useable there
|
||||
echo '<option value="##comments##">' .get_string('comments', 'data'). ' - ##comments##</option>';
|
||||
}
|
||||
echo '</optgroup>';
|
||||
}
|
||||
|
||||
if ($mode == 'asearchtemplate') {
|
||||
echo '<optgroup label="'.get_string('other', 'data').'">';
|
||||
echo '<option value="##firstname##">' .get_string('authorfirstname', 'data'). ' - ##firstname##</option>';
|
||||
echo '<option value="##lastname##">' .get_string('authorlastname', 'data'). ' - ##lastname##</option>';
|
||||
echo '</optgroup>';
|
||||
}
|
||||
|
||||
echo '</select>';
|
||||
echo '</div>';
|
||||
}
|
||||
echo '</td>';
|
||||
|
||||
echo '<td valign="top">';
|
||||
if ($mode == 'listtemplate'){
|
||||
echo '<div class="template_heading"><label for="edit-template">'.get_string('multientry','data').'</label></div>';
|
||||
} else {
|
||||
echo '<div class="template_heading"><label for="edit-template">'.get_string($mode,'data').'</label></div>';
|
||||
}
|
||||
|
||||
$field = 'template';
|
||||
$editor->set_text($data->{$mode});
|
||||
$editor->use_editor($field, $options);
|
||||
echo '<div>';
|
||||
echo '<textarea class="form-control" id="' . $field . '" ' .
|
||||
'name="' . $field . '" rows="15" cols="80">' . s($data->{$mode}) . '</textarea>';
|
||||
echo '</div>';
|
||||
echo '</td>';
|
||||
echo '</tr>';
|
||||
|
||||
if ($mode == 'listtemplate'){
|
||||
echo '<tr>';
|
||||
echo '<td> </td>';
|
||||
echo '<td>';
|
||||
echo '<div class="template_heading"><label for="edit-listtemplatefooter">'.get_string('footer','data').'</label></div>';
|
||||
|
||||
$field = 'listtemplatefooter';
|
||||
$editor->set_text($data->listtemplatefooter);
|
||||
$editor->use_editor($field, $options);
|
||||
echo '<div>';
|
||||
echo '<textarea id="' . $field . '" class="form-control" ' .
|
||||
'name="' . $field . '" rows="15" cols="80">' . s($data->listtemplatefooter) . '</textarea>';
|
||||
echo '</div>';
|
||||
echo '</td>';
|
||||
echo '</tr>';
|
||||
} else if ($mode == 'rsstemplate') {
|
||||
echo '<tr>';
|
||||
echo '<td> </td>';
|
||||
echo '<td>';
|
||||
echo '<div class="template_heading">';
|
||||
echo '<label for="edit-rsstitletemplate">' . get_string('rsstitletemplate', 'data') . '</label>';
|
||||
echo '</div>';
|
||||
|
||||
$field = 'rsstitletemplate';
|
||||
$editor->set_text($data->rsstitletemplate);
|
||||
$editor->use_editor($field, $options);
|
||||
echo '<div>';
|
||||
echo '<textarea id="' . $field . '" name="' . $field . '" ' .
|
||||
'class="form-control" rows="15" cols="80">' . s($data->rsstitletemplate) . '</textarea>';
|
||||
echo '</div>';
|
||||
echo '</td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
|
||||
echo '</table>';
|
||||
echo html_writer::start_div('container-fluid mt-4');
|
||||
echo html_writer::start_div('row');
|
||||
|
||||
$resettemplatebutton = html_writer::empty_tag('input', ['type' => 'submit', 'name' => 'defaultform',
|
||||
'class' => 'btn btn-secondary', 'value' => get_string('resettemplate', 'data')]);
|
||||
$savetemplatebutton = html_writer::empty_tag('input', ['type' => 'submit', 'class' => 'btn btn-primary ml-2',
|
||||
'value' => get_string('savetemplate', 'data')]);
|
||||
|
||||
echo html_writer::div($resettemplatebutton . $savetemplatebutton);
|
||||
|
||||
if ($mode != 'csstemplate' and $mode != 'jstemplate') {
|
||||
// Output the toggle template editor element.
|
||||
$toggletemplateeditor = html_writer::checkbox('useeditor', 1, $usehtmleditor,
|
||||
get_string('editorenable', 'data'), null, ['class' => 'pl-2']);
|
||||
echo html_writer::div($toggletemplateeditor, 'ml-auto');
|
||||
$PAGE->requires->js_call_amd('mod_data/templateseditor', 'init', ['d' => $d, 'mode' => $mode]);
|
||||
}
|
||||
echo html_writer::end_div();
|
||||
echo html_writer::end_div();
|
||||
|
||||
echo $OUTPUT->box_end();
|
||||
echo '</div>';
|
||||
echo '</form>';
|
||||
$renderer = $PAGE->get_renderer('mod_data');
|
||||
$templateeditor = new \mod_data\output\template_editor($manager, $mode);
|
||||
echo $renderer->render($templateeditor);
|
||||
|
||||
/// Finish the page
|
||||
echo $OUTPUT->footer();
|
||||
|
123
mod/data/templates/template_editor.mustache
Normal file
123
mod/data/templates/template_editor.mustache
Normal file
@ -0,0 +1,123 @@
|
||||
{{!
|
||||
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/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_data/template_editor
|
||||
|
||||
Template editor in the database activity.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"title": "Defines browsing interface for multiple entries",
|
||||
"sesskey": "XXXXX",
|
||||
"disableeditor": true,
|
||||
"url": {},
|
||||
"usehtmleditor": true,
|
||||
"toolbar": {
|
||||
"toolshelp": "Available tags help",
|
||||
"hastools": true,
|
||||
"tools": [
|
||||
{
|
||||
"name": "Fields",
|
||||
"tags": [
|
||||
{
|
||||
"tag": "[[Checkme]]",
|
||||
"tagname": "Checkme - [[Checkme]]"
|
||||
},
|
||||
{
|
||||
"tag": "[[Description]]",
|
||||
"tagname": "Description - [[Description]]"
|
||||
},
|
||||
{
|
||||
"tag": "[[Name]]",
|
||||
"tagname": "Name - [[Name]]"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"editors": [
|
||||
{
|
||||
"name": "Header",
|
||||
"fieldname": "listtemplateheader",
|
||||
"value": ""
|
||||
},
|
||||
{
|
||||
"name": "Repeated entry",
|
||||
"fieldname": "listtemplate",
|
||||
"value": "Template content"
|
||||
},
|
||||
{
|
||||
"name": "Footer",
|
||||
"fieldname": "listtemplatefooter",
|
||||
"value": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
}}
|
||||
<div>{{title}}</div>
|
||||
<form id="tempform" action="{{{url}}}" method="post">
|
||||
<input name="sesskey" value="{{sesskey}}" type="hidden" />
|
||||
<div class="d-flex flex-row align-items-center">
|
||||
{{#toolbar}}
|
||||
{{> mod_data/template_editor_tools }}
|
||||
{{/toolbar}}
|
||||
<div class="d-flex flex-column">
|
||||
{{#editors}}
|
||||
<div class="m-1">
|
||||
<div class="template_heading">
|
||||
<label for="{{fieldname}}">{{name}}</label>
|
||||
</div>
|
||||
<div>
|
||||
<textarea
|
||||
id="{{fieldname}}"
|
||||
name="{{fieldname}}"
|
||||
class="form-control"
|
||||
rows="15"
|
||||
cols="80"
|
||||
>{{value}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
{{/editors}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="container-fluid mt-4">
|
||||
<div class="row">
|
||||
<div>
|
||||
<input
|
||||
class="btn btn-secondary"
|
||||
type="submit"
|
||||
name="defaultform"
|
||||
value="{{#str}} resettemplate, data {{/str}}"
|
||||
/>
|
||||
<input
|
||||
class="btn btn-primary"
|
||||
type="submit"
|
||||
value="{{#str}} savetemplate, data {{/str}}"
|
||||
/>
|
||||
</div>
|
||||
{{#disableeditor}}
|
||||
<div class="ml-auto">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="useeditor"
|
||||
id="useeditor"
|
||||
value="1"
|
||||
{{#usehtmleditor}}checked{{/usehtmleditor}}
|
||||
/>
|
||||
<label for="useeditor">{{#str}} editorenable, data {{/str}}</label>
|
||||
</div>
|
||||
{{/disableeditor}}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
134
mod/data/templates/template_editor_tools.mustache
Normal file
134
mod/data/templates/template_editor_tools.mustache
Normal file
@ -0,0 +1,134 @@
|
||||
{{!
|
||||
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/>.
|
||||
}}
|
||||
{{!
|
||||
@template mod_data/template_editor_tools
|
||||
|
||||
Tag tool box for the template editor in the mod_data.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"toolshelp": "Available tags",
|
||||
"hastools": true,
|
||||
"tools": [
|
||||
{
|
||||
"name": "Fields",
|
||||
"tags": [
|
||||
{
|
||||
"tag": "[[Checkme]]",
|
||||
"tagname": "Checkme - [[Checkme]]"
|
||||
},
|
||||
{
|
||||
"tag": "[[Description]]",
|
||||
"tagname": "Description - [[Description]]"
|
||||
},
|
||||
{
|
||||
"tag": "[[Name]]",
|
||||
"tagname": "Name - [[Name]]"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Actions",
|
||||
"tags": [
|
||||
{
|
||||
"tag": "##edit##",
|
||||
"tagname": "Edit - ##edit##"
|
||||
},
|
||||
{
|
||||
"tag": "##delete##",
|
||||
"tagname": "Delete - ##delete##"
|
||||
},
|
||||
{
|
||||
"tag": "##approve##",
|
||||
"tagname": "Approve - ##approve##"
|
||||
},
|
||||
{
|
||||
"tag": "##disapprove##",
|
||||
"tagname": "Undo approval - ##disapprove##"
|
||||
},
|
||||
{
|
||||
"tag": "##export##",
|
||||
"tagname": "Export - ##export##"
|
||||
},
|
||||
{
|
||||
"tag": "##more##",
|
||||
"tagname": "More - ##more##"
|
||||
},
|
||||
{
|
||||
"tag": "##moreurl##",
|
||||
"tagname": "More URL - ##moreurl##"
|
||||
},
|
||||
{
|
||||
"tag": "##delcheck##",
|
||||
"tagname": "Bulk delete checkbox - ##delcheck##"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Other",
|
||||
"tags": [
|
||||
{
|
||||
"tag": "##tags##",
|
||||
"tagname": "Tags - ##tags##"
|
||||
},
|
||||
{
|
||||
"tag": "##timeadded##",
|
||||
"tagname": "Time added - ##timeadded##"
|
||||
},
|
||||
{
|
||||
"tag": "##timemodified##",
|
||||
"tagname": "Time modified - ##timemodified##"
|
||||
},
|
||||
{
|
||||
"tag": "##user##",
|
||||
"tagname": "User - ##user##"
|
||||
},
|
||||
{
|
||||
"tag": "##userpicture##",
|
||||
"tagname": "User picture - ##userpicture##"
|
||||
},
|
||||
{
|
||||
"tag": "##approvalstatus##",
|
||||
"tagname": "Approval status - ##approvalstatus##"
|
||||
},
|
||||
{
|
||||
"tag": "##id##",
|
||||
"tagname": "Entry ID - ##id##"
|
||||
},
|
||||
{
|
||||
"tag": "##comments##",
|
||||
"tagname": "Comments - ##comments##"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}}
|
||||
{{#hastools}}
|
||||
<div class="p-2">
|
||||
<label for="availabletags">{{#str}} availabletags, data {{/str}}</label>
|
||||
{{{toolshelp}}}
|
||||
<div class="no-overflow" id="availabletags_wrapper">
|
||||
<select name="fields1[]" id="availabletags" size="20" onclick="insert_field_tags(this)" class="form-control">
|
||||
{{#tools}}
|
||||
<optgroup label="{{name}}">
|
||||
{{#tags}}
|
||||
<option value="{{tag}}">{{tagname}}</option>
|
||||
{{/tags}}
|
||||
</optgroup>
|
||||
{{/tools}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{{/hastools}}
|
115
mod/data/tests/behat/edit_templates.feature
Normal file
115
mod/data/tests/behat/edit_templates.feature
Normal file
@ -0,0 +1,115 @@
|
||||
@mod @mod_data
|
||||
Feature: Users can edit the database templates
|
||||
In order to use custom templates for entries
|
||||
As a teacher
|
||||
I need to edit the templates html
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber |
|
||||
| data | Test database name | Database intro | C1 | data1 |
|
||||
And the following "mod_data > fields" exist:
|
||||
| database | type | name | description |
|
||||
| data1 | text | field1 | Test field description |
|
||||
| data1 | text | field2 | Test field 2 description |
|
||||
And the following "mod_data > templates" exist:
|
||||
| database | name |
|
||||
| data1 | singletemplate |
|
||||
| data1 | listtemplate |
|
||||
| data1 | addtemplate |
|
||||
| data1 | asearchtemplate |
|
||||
| data1 | rsstemplate |
|
||||
And the following "mod_data > entries" exist:
|
||||
| database | field1 | field2 |
|
||||
| data1 | Student entry 1 | Some content 1 |
|
||||
And I am on the "Test database name" "data activity" page logged in as teacher1
|
||||
And I navigate to "Templates" in current page administration
|
||||
|
||||
@javascript
|
||||
Scenario: Edit list template
|
||||
Given I set the following fields to these values:
|
||||
| Header | New header! |
|
||||
| Repeated entry | [[field1]] and [[field2]]! |
|
||||
| Footer | New footer! |
|
||||
And I click on "Save template" "button"
|
||||
When I navigate to "Database" in current page administration
|
||||
Then I should see "New header!"
|
||||
And I should see "Student entry 1 and Some content 1!"
|
||||
And I should see "New footer!"
|
||||
|
||||
@javascript
|
||||
Scenario: Edit single template
|
||||
Given I set the field "Templates tertiary navigation" to "Single template"
|
||||
And I set the following fields to these values:
|
||||
| Single template | [[field1]] and [[field2]] details! |
|
||||
And I click on "Save template" "button"
|
||||
When I navigate to "Database" in current page administration
|
||||
And I set the field "View mode tertiary navigation" to "Single view"
|
||||
Then I should see "Student entry 1 and Some content 1 details!"
|
||||
|
||||
@javascript
|
||||
Scenario: Edit add entry template
|
||||
Given I set the field "Templates tertiary navigation" to "Add entry template"
|
||||
And I set the following fields to these values:
|
||||
| Add entry template | [[field1]] [[field2]] Form extra! |
|
||||
And I click on "Save template" "button"
|
||||
When I navigate to "Database" in current page administration
|
||||
And I click on "Add entry" "button"
|
||||
Then I should see "Form extra!"
|
||||
|
||||
@javascript
|
||||
Scenario: Edit advanced search template
|
||||
Given I set the field "Templates tertiary navigation" to "Advanced search template"
|
||||
And I set the following fields to these values:
|
||||
| Advanced search template | New advanced search template! |
|
||||
And I click on "Save template" "button"
|
||||
When I navigate to "Database" in current page administration
|
||||
And I click on "Advanced search" "checkbox"
|
||||
Then I should see "New advanced search template!"
|
||||
|
||||
@javascript
|
||||
Scenario: Edit without the wysiwyg editor
|
||||
Given I click on "Enable editor" "checkbox"
|
||||
And I set the following fields to these values:
|
||||
| Repeated entry | <span class="d-none">Nope</span>Yep! |
|
||||
And I click on "Save template" "button"
|
||||
When I navigate to "Database" in current page administration
|
||||
Then I should not see "Nope"
|
||||
And I should see "Yep!"
|
||||
|
||||
@javascript
|
||||
Scenario: Edit CSS teamplate
|
||||
Given I click on "Enable editor" "checkbox"
|
||||
And I set the following fields to these values:
|
||||
| Repeated entry | <span class="hideme">Nope</span>Yep! |
|
||||
And I click on "Save template" "button"
|
||||
And I set the field "Templates tertiary navigation" to "CSS template"
|
||||
And I set the following fields to these values:
|
||||
| CSS template | .hideme {display: none;} |
|
||||
And I click on "Save template" "button"
|
||||
When I navigate to "Database" in current page administration
|
||||
Then I should not see "Nope"
|
||||
And I should see "Yep!"
|
||||
|
||||
@javascript
|
||||
Scenario: Edit Javascript template
|
||||
Given I click on "Enable editor" "checkbox"
|
||||
And I set the following fields to these values:
|
||||
| Repeated entry | <span id="hideme">Nope</span>Yep! |
|
||||
And I click on "Save template" "button"
|
||||
And I set the field "Templates tertiary navigation" to "Javascript template"
|
||||
And I set the following fields to these values:
|
||||
| Javascript template | window.onload = () => document.querySelector('#hideme').style.display = 'none'; |
|
||||
And I click on "Save template" "button"
|
||||
When I navigate to "Database" in current page administration
|
||||
Then I should not see "Nope"
|
||||
And I should see "Yep!"
|
Loading…
x
Reference in New Issue
Block a user