├── composer.json ├── lang └── en │ └── deprecated.txt ├── templates ├── local │ ├── subsectionmodes │ │ ├── summary.mustache │ │ ├── list.mustache │ │ └── collapsible.mustache │ ├── activity_dateinline.mustache │ ├── content │ │ ├── cm.mustache │ │ ├── section │ │ │ └── content.mustache │ │ └── section.mustache │ └── content.mustache ├── courseformat │ ├── content │ │ ├── cminlinecompletion.mustache │ │ ├── cm │ │ │ ├── badgesinline.mustache │ │ │ ├── cmiconinline.mustache │ │ │ ├── availabilityinline.mustache │ │ │ ├── cmnameinline.mustache │ │ │ ├── activityinline.mustache │ │ │ └── cmhelpinfo.mustache │ │ └── cminline.mustache │ └── tabtree.mustache ├── footer.mustache └── header.mustache ├── format.js ├── classes ├── courseformat │ └── stateactions.php ├── local │ ├── hooks │ │ └── output │ │ │ └── before_http_headers.php │ ├── formelement_background.php │ └── clilib.php ├── privacy │ └── provider.php ├── output │ ├── courseformat │ │ ├── content │ │ │ ├── delegatedsection.php │ │ │ ├── sectionselector.php │ │ │ ├── section.php │ │ │ ├── sectionnavigation.php │ │ │ └── section │ │ │ │ ├── cmlist.php │ │ │ │ └── controlmenu.php │ │ └── content.php │ └── renderer.php ├── footer.php ├── singletab.php └── tabstyles.php ├── db ├── upgrade.php └── hooks.php ├── version.php ├── amd ├── build │ ├── main.min.js │ ├── onetopicbackground.min.js │ ├── oneline.min.js │ ├── main.min.js.map │ ├── onetopicbackground.min.js.map │ └── oneline.min.js.map └── src │ ├── main.js │ ├── onetopicbackground.js │ └── oneline.js ├── format.php ├── cli.php ├── tests └── behat │ ├── highlight_sections.feature │ └── edit_delete_sections.feature ├── backup └── moodle2 │ └── restore_format_onetopic_plugin.class.php ├── README.md ├── .github └── workflows │ └── moodle-ci.yml ├── changenumsections.php ├── styles.php └── settings.php /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "davidherney/moodle-format_onetopic", 3 | "type": "moodle-format", 4 | "require": { 5 | "composer/installers": "~1.0" 6 | }, 7 | "extra": { 8 | "installer-name": "onetopic" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /lang/en/deprecated.txt: -------------------------------------------------------------------------------- 1 | disable,format_onetopic 2 | disableajax,format_onetopic 3 | disableajax_help,format_onetopic 4 | enable,format_onetopic 5 | utilities,format_onetopic 6 | duplicate,format_onetopic 7 | duplicate_confirm,format_onetopic 8 | duplicatesection,format_onetopic 9 | duplicatesection_help,format_onetopic 10 | duplicating,format_onetopic 11 | progress_counter,format_onetopic 12 | progress_full,format_onetopic 13 | rebuild_course_cache,format_onetopic 14 | -------------------------------------------------------------------------------- /templates/local/subsectionmodes/summary.mustache: -------------------------------------------------------------------------------- 1 | {{! 2 | This file is part of Moodle - http://moodle.org/ 3 | 4 | Moodle is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Moodle is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Moodle. If not, see . 16 | }} 17 | {{! 18 | @template format_onetopic/local/subsectionmodes/summary 19 | 20 | Default moodle summary template for subsection mode. 21 | 22 | Example context (json): 23 | { 24 | } 25 | }} 26 | {{> core_courseformat/local/content/delegatedsection }} 27 | -------------------------------------------------------------------------------- /format.js: -------------------------------------------------------------------------------- 1 | // Javascript functions for onetopic course format 2 | 3 | M.course = M.course || {}; 4 | 5 | M.course.format = M.course.format || {}; 6 | 7 | M.course.format.showInfo = function(id) { 8 | 9 | new M.core.dialogue({ 10 | draggable: true, 11 | headerContent: '' + M.util.get_string('info', 'moodle') + '', 12 | bodyContent: Y.Node.one('#' + id), 13 | centered: true, 14 | width: '480px', 15 | modal: true, 16 | visible: true 17 | }); 18 | 19 | Y.Node.one('#' + id).show(); 20 | 21 | }; 22 | 23 | M.course.format.dialogueinitloaded = false; 24 | 25 | M.course.format.dialogueinit = function() { 26 | 27 | if (M.course.format.dialogueinitloaded) { 28 | return; 29 | } 30 | 31 | M.course.format.dialogueinitloaded = true; 32 | Y.all('[data-infoid]').each(function(node) { 33 | node.on('click', function(e) { 34 | e.preventDefault(); 35 | M.course.format.showInfo(node.getAttribute('data-infoid')); 36 | }); 37 | }); 38 | }; 39 | -------------------------------------------------------------------------------- /templates/local/activity_dateinline.mustache: -------------------------------------------------------------------------------- 1 | {{! 2 | This file is part of Moodle - http://moodle.org/ 3 | 4 | Moodle is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Moodle is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Moodle. If not, see . 16 | }} 17 | {{! 18 | @template format_onetopic/local/activity_date 19 | 20 | Template for displaying the activity's dates. 21 | 22 | Example context (json): 23 | { 24 | "label": "Opens:", 25 | "datestring": "6 April 2021, 6:46 PM" 26 | } 27 | }} 28 | 29 | {{label}} {{datestring}} 30 | 31 | -------------------------------------------------------------------------------- /classes/courseformat/stateactions.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | namespace format_onetopic\courseformat; 18 | 19 | use format_topics\courseformat\stateactions as stateactions_format_topics; 20 | 21 | /** 22 | * Contains the core course state actions specific to topics format. 23 | * 24 | * @package format_onetopic 25 | * @copyright 2024 David Herney - cirano. https://bambuco.co 26 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 27 | */ 28 | class stateactions extends stateactions_format_topics { 29 | } 30 | -------------------------------------------------------------------------------- /db/upgrade.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Upgrade scripts for course format "onetopic" 19 | * 20 | * @package format_onetopic 21 | * @copyright 2018 David Herney Bernal - cirano 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | /** 26 | * Upgrade script for format_onetopic 27 | * 28 | * @param int $oldversion the version we are upgrading from 29 | * @return bool result 30 | */ 31 | function xmldb_format_onetopic_upgrade($oldversion) { 32 | global $CFG, $DB; 33 | 34 | return true; 35 | } 36 | -------------------------------------------------------------------------------- /db/hooks.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Hook callbacks for Onetopic format 19 | * 20 | * @package format_onetopic 21 | * @copyright 2024 2024 David Herney @ BambuCo 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | defined('MOODLE_INTERNAL') || die(); 26 | 27 | $callbacks = [ 28 | 29 | [ 30 | 'hook' => core\hook\output\before_http_headers::class, 31 | 'callback' => 'format_onetopic\local\hooks\output\before_http_headers::callback', 32 | 'priority' => 0, 33 | ], 34 | ]; 35 | -------------------------------------------------------------------------------- /templates/courseformat/content/cminlinecompletion.mustache: -------------------------------------------------------------------------------- 1 | {{! 2 | This file is part of Moodle - http://moodle.org/ 3 | 4 | Moodle is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Moodle is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Moodle. If not, see . 16 | }} 17 | {{! 18 | @template format_onetopic/courseformat/content/cminlinecompletion 19 | 20 | Displays a course module instance inside a course section. 21 | 22 | Example context (json): 23 | { 24 | "completedclass": "complete" 25 | } 26 | }} 27 | 28 | {{$ format_onetopic/courseformat/content/cminline }} 29 | {{> format_onetopic/courseformat/content/cminline }} 30 | {{/ format_onetopic/courseformat/content/cminline }} 31 | 32 | -------------------------------------------------------------------------------- /classes/local/hooks/output/before_http_headers.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | namespace format_onetopic\local\hooks\output; 18 | 19 | /** 20 | * Hook callbacks for format_onetopic 21 | * 22 | * @package format_onetopic 23 | * @copyright 2024 David Herney @ BambuCo 24 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 25 | */ 26 | class before_http_headers { 27 | /** 28 | * Moodle native lib/navigationlib.php calls this hook allowing us to override UI. 29 | * 30 | * @param \core\hook\output\before_http_headers $unused 31 | */ 32 | public static function callback(\core\hook\output\before_http_headers $unused): void { 33 | global $PAGE; 34 | $PAGE->requires->css('/course/format/onetopic/styles.php'); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /templates/courseformat/content/cm/badgesinline.mustache: -------------------------------------------------------------------------------- 1 | {{! 2 | This file is part of Moodle - http://moodle.org/ 3 | 4 | Moodle is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Moodle is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Moodle. If not, see . 16 | }} 17 | {{! 18 | @template format_onetopic/courseformat/content/cm/badges 19 | 20 | Convenience mustache to displays if an activity is in hidden or stealth mode. 21 | 22 | Format plugins are free to implement an alternative inplace editable for activities. 23 | 24 | Example context (json): 25 | { 26 | "modhiddenfromstudents" : "1", 27 | "modstealth" : "1" 28 | } 29 | }} 30 | {{#modhiddenfromstudents}} 31 | 32 | {{#str}}hiddenfromstudents{{/str}} 33 | 34 | {{/modhiddenfromstudents}} 35 | {{#modstealth}} 36 | 37 | {{#str}}hiddenoncoursepage{{/str}} 38 | 39 | {{/modstealth}} 40 | -------------------------------------------------------------------------------- /templates/courseformat/content/cm/cmiconinline.mustache: -------------------------------------------------------------------------------- 1 | {{! 2 | This file is part of Moodle - http://moodle.org/ 3 | 4 | Moodle is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Moodle is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Moodle. If not, see . 16 | }} 17 | {{! 18 | @template format_onetopic/courseformat/content/cm/cmiconinline 19 | 20 | Displays a course module icon. 21 | 22 | Example context (json): 23 | { 24 | "icon": "../../../pix/help.svg", 25 | "iconclass": "", 26 | "purpose": "content", 27 | "modname": "resource", 28 | "pluginname": "File", 29 | "showtooltip": 1 30 | } 31 | }} 32 | 33 | {{#showtooltip}}{{#cleanstr}} activityicon, moodle, {{{pluginname}}} {{/cleanstr}}{{/showtooltip}} 41 | 42 | -------------------------------------------------------------------------------- /classes/privacy/provider.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Privacy Subsystem implementation for format_onetopic. 19 | * 20 | * @package format_onetopic 21 | * @copyright 2019 David Herney Bernal - cirano 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace format_onetopic\privacy; 26 | 27 | /** 28 | * Privacy Subsystem for format_onetopic implementing null_provider. 29 | * 30 | * @copyright 2019 David Herney Bernal - cirano 31 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 32 | */ 33 | class provider implements \core_privacy\local\metadata\null_provider { 34 | /** 35 | * Get the language string identifier with the component's language 36 | * file to explain why this plugin stores no data. 37 | * 38 | * @return string 39 | */ 40 | public static function get_reason(): string { 41 | return 'privacy:metadata'; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /templates/footer.mustache: -------------------------------------------------------------------------------- 1 | {{! 2 | This file is part of Moodle - http://moodle.org/ 3 | 4 | Moodle is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Moodle is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Moodle. If not, see . 16 | }} 17 | {{! 18 | @template format_onetopic/footer 19 | 20 | Example context (json): 21 | { 22 | "uniqid": "course-1", 23 | "sectionreturn": 1, 24 | "hastopictabs": true, 25 | "testing": true 26 | } 27 | }} 28 | 29 | {{#testing}} 30 |
31 |
32 |
33 |
34 | {{#hassecondrow}} 35 |
36 | {{/hassecondrow}} 37 | {{/testing}} 38 | {{#hassecondrow}} 39 |
40 | {{/hassecondrow}} 41 | 42 |
{{! Used in order to break the div wraped in output.course_content_footer }} 43 | 44 | {{! End of onetopic-tab-body box. }} 45 |
46 |
47 | 48 |
49 | 50 | {{#js}} 51 | require(['core_courseformat/local/content'], function(component) { 52 | component.init('#{{uniqid}}-course-format', 53 | { 54 | SECTION: `ul.onetopic [data-for='section']`, 55 | SECTION_CMLIST: `ul.onetopic [data-for='cmlist']`, 56 | CM: `ul.onetopic [data-for='cmitem']`, 57 | }, 58 | {{sectionreturn}}); 59 | }); 60 | {{/js}} 61 | -------------------------------------------------------------------------------- /templates/courseformat/content/cm/availabilityinline.mustache: -------------------------------------------------------------------------------- 1 | {{! 2 | This file is part of Moodle - http://moodle.org/ 3 | 4 | Moodle is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Moodle is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Moodle. If not, see . 16 | }} 17 | {{! 18 | @template format_onetopic/courseformat/content/cm/availabilityinline 19 | 20 | Displays a activity availability with inline tags. 21 | 22 | Example context (json): 23 | { 24 | "info": [ 25 | { 26 | "classes": "", 27 | "text": "Not available unless:
  • It is on or after 8 June 2012
", 28 | "ishidden": 0, 29 | "isstealth": 0, 30 | "isrestricted": 1, 31 | "isfullinfo": 1 32 | } 33 | ], 34 | "hasmodavailability": true 35 | } 36 | }} 37 | {{#hasmodavailability}} 38 | {{#info}} 39 | 40 | {{^isrestricted}} 41 | {{{text}}} 42 | {{/isrestricted}} 43 | {{#isrestricted}} 44 | 45 | {{#pix}}t/unlock, core{{/pix}} 46 | 47 | {{/isrestricted}} 48 | 49 | {{/info}} 50 | {{/hasmodavailability}} 51 | -------------------------------------------------------------------------------- /version.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Version details. 19 | * 20 | * Component releases: 21 | * Un recorderis de las Veredas de mi pueblo, en homenaje a los campesinos de mi tierra. 22 | * 23 | * Old releases: Guarango, Pantalio, Chalarca, Mazorcal, Chuscalito, Las Teresas, La Madera, Las Brisas, Buenavista, 24 | * San Juan, La Almería, Piedras Teherán, El Cardal, La Divisa, Las Acacias. 25 | * 26 | * Next releases: Santa Cruz, Vallejuelito, Fátima, La Cabaña, La Palmera, Las Colmenas, Minitas, 27 | * Quebrada Negra, San Francisco, San Miguel Abajo, San Miguel, La Concha. 28 | * 29 | * @package format_onetopic 30 | * @copyright 2015 David Herney - cirano. https://bambuco.co 31 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 32 | */ 33 | 34 | defined('MOODLE_INTERNAL') || die(); 35 | 36 | $plugin->version = 2025021902.02; // The current plugin version (Date: YYYYMMDDXX). 37 | $plugin->requires = 2025021400; // Requires this Moodle version. 38 | $plugin->component = 'format_onetopic'; // Full name of the plugin (used for diagnostics). 39 | $plugin->maturity = MATURITY_STABLE; 40 | $plugin->release = '5.0.2(LaDivisa)'; 41 | $plugin->dependencies = ['format_topics' => 2025041400]; 42 | $plugin->supported = [500, 500]; 43 | -------------------------------------------------------------------------------- /classes/output/courseformat/content/delegatedsection.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Contains the delegated section course format output class. 19 | * 20 | * @package format_onetopic 21 | * @copyright 2025 David Herney - cirano. https://bambuco.co 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace format_onetopic\output\courseformat\content; 26 | 27 | use core_courseformat\output\local\content\delegatedsection as delegatedsection_base; 28 | 29 | /** 30 | * Class to render a delegated section. 31 | * 32 | * @package format_onetopic 33 | * @copyright 2025 David Herney - cirano. https://bambuco.co 34 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 35 | */ 36 | class delegatedsection extends delegatedsection_base { 37 | /** 38 | * @var section The onetopic section output instance. 39 | */ 40 | public $onesection; 41 | 42 | /** 43 | * Load the section according to the current format because the delegated class is not aware of the specific format. 44 | * 45 | */ 46 | public function load_onesection() { 47 | $this->onesection = new \format_onetopic\output\courseformat\content\section($this->format, $this->section); 48 | $this->onesection->insection = true; 49 | } 50 | 51 | /** 52 | * Get the display mode of the delegated section. 53 | * 54 | * @return string 55 | */ 56 | public function get_displaymode(): string { 57 | $options = $this->format->get_format_options($this->section); 58 | 59 | return $options['displaymode'] ?? 'list'; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /templates/courseformat/tabtree.mustache: -------------------------------------------------------------------------------- 1 | {{! 2 | This file is part of Moodle - http://moodle.org/ 3 | 4 | Moodle is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Moodle is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Moodle. If not, see . 16 | }} 17 | {{! 18 | @template format_onetopic/courseformat/tabtree 19 | 20 | Tab tree. 21 | 22 | Example context (json): 23 | { 24 | "tabs": [{ 25 | "active": "true", 26 | "inactive": "false", 27 | "link": [{ 28 | "link": "http://moodle.org" 29 | }], 30 | "title": "Moodle.org", 31 | "text": "Moodle community", 32 | "styles": "color: #ff00ff" 33 | }] 34 | } 35 | }} 36 | 58 | -------------------------------------------------------------------------------- /amd/build/main.min.js: -------------------------------------------------------------------------------- 1 | define("format_onetopic/main",["exports","format_onetopic/oneline","jquery","core/modal_factory","core/str"],(function(_exports,OneLine,_jquery,_modal_factory,_str){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,OneLine=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj} 2 | /** 3 | * General format features. 4 | * 5 | * @module format_onetopic/main 6 | * @copyright 2021 David Herney Bernal - cirano 7 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 8 | */(OneLine),_jquery=_interopRequireDefault(_jquery),_modal_factory=_interopRequireDefault(_modal_factory);_exports.init=(formattype,icons)=>{2==formattype&&OneLine.load(icons);var infotitle=(0,_str.get_string)("aboutresource","format_onetopic");(0,_jquery.default)(".format-onetopic .onetopic .iconwithhelp[data-helpwindow]").each((function(){var $node=(0,_jquery.default)(this);$node.on("click",(function(e){e.preventDefault();var $content=(0,_jquery.default)("#hw-"+$node.data("helpwindow"));if($content.data("modal"))$content.data("modal").show();else{var title=$content.data("title");title||(title=infotitle),_modal_factory.default.create({title:title,body:""}).done((function(modal){var contenthtml=$content.html();contenthtml=contenthtml.replace(//g,(function(match,p1){return p1}));var $modalBody=modal.getBody();$modalBody.css("min-height","150px"),$modalBody.append(contenthtml),modal.show(),$content.data("modal",modal)}))}}))}))}})); 9 | 10 | //# sourceMappingURL=main.min.js.map -------------------------------------------------------------------------------- /templates/courseformat/content/cm/cmnameinline.mustache: -------------------------------------------------------------------------------- 1 | {{! 2 | This file is part of Moodle - http://moodle.org/ 3 | 4 | Moodle is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Moodle is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Moodle. If not, see . 16 | }} 17 | {{! 18 | @template format_onetopic/courseformat/content/cm/cmnameinline 19 | 20 | Convenience mustache to displays a course module inplcae editable from the format renderer. 21 | 22 | Format plugins are free to implement an alternative inplace editable for activities. 23 | 24 | Example context (json): 25 | { 26 | "url": "#", 27 | "icon": "../../../pix/help.svg", 28 | "pluginname": "File", 29 | "textclasses": "", 30 | "purpose": "content", 31 | "modname": "resource", 32 | "activityname": { 33 | "displayvalue" : "Moodle", 34 | "value" : "Moodle", 35 | "itemid" : "1", 36 | "component" : "core_unknown", 37 | "itemtype" : "unknown", 38 | "edithint" : "Edit this", 39 | "editlabel" : "New name for this", 40 | "type" : "text", 41 | "options" : "", 42 | "linkeverything": 0 43 | } 44 | } 45 | }} 46 | {{#url}} 47 | 48 | {{^hideicons}} 49 | {{! Icon }} 50 | {{#activityicon}} 51 | {{$ format_onetopic/courseformat/content/cm/cmiconinline }} 52 | {{> format_onetopic/courseformat/content/cm/cmiconinline }} 53 | {{/ format_onetopic/courseformat/content/cm/cmiconinline }} 54 | {{/activityicon}} 55 | {{/hideicons}} 56 | 57 | {{#activityname}} 58 | {{{displayvalue}}} 59 | {{/activityname}} 60 | 61 | 62 | {{/url}} 63 | -------------------------------------------------------------------------------- /amd/build/onetopicbackground.min.js: -------------------------------------------------------------------------------- 1 | define("format_onetopic/onetopicbackground",["exports","jquery","core/modal_factory","core/modal_save_cancel","core/modal_events"],(function(_exports,_jquery,_modal_factory,_modal_save_cancel,_modal_events){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}} 2 | /** 3 | * Onetopic background selector. 4 | * 5 | * @module format_onetopic/onetopicbackground 6 | * @copyright 2021 David Herney Bernal - cirano 7 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 8 | */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_jquery=_interopRequireDefault(_jquery),_modal_factory=_interopRequireDefault(_modal_factory),_modal_save_cancel=_interopRequireDefault(_modal_save_cancel),_modal_events=_interopRequireDefault(_modal_events);_exports.init=controlid=>{var $controlinput=(0,_jquery.default)("#"+controlid),$control=$controlinput.parent(".backgroundpicker"),$controlwindow=$control.find(".backgroundpickerwindow"),$controlbutton=$control.find(".backgroundpickerselector"),$colorpickerinput=$controlwindow.find('input.form-control[type="text"]');$controlinput.on("change",(function(){var $color=$controlinput.val();$color?$controlinput.css("background",$color):$controlinput.css("background","")})),$controlinput.trigger("change");var title=$controlwindow.attr("title"),buttons=[];buttons.save=$controlwindow.data("savelabel");_modal_factory.default.create({title:title,body:$controlwindow,type:_modal_save_cancel.default.TYPE,large:!0,buttons:buttons}).done((function(modal){modal.getBody().append($controlwindow),$control.data("modal",modal),function(modal){modal.getRoot().on(_modal_events.default.cancel,(()=>{modal.hide()})),modal.getRoot().on(_modal_events.default.save,(()=>{var newcolor=$colorpickerinput.val(),val=$controlinput.val(),color=readColor(val);color?val=val.replace(color,newcolor):""===val.trim()?val=newcolor:val+=" "+newcolor,$controlinput.val(val),$controlinput.css("background",val),modal.hide()}))}(modal)})),$controlbutton.on("click",(function(e){e.preventDefault(),$controlwindow.removeClass("hidden");var currentval=$controlinput.val(),color=readColor(currentval);$colorpickerinput.val(color),$control.data("modal").show()}))};var readColor=function(text){var regexcolor=new RegExp(/#[0-9a-fA-F]{6}/.source+/|#[0-9a-fA-F]{3}/.source+/|rgba?\(\s*([0-9]{1,3}\s*,\s*){2}[0-9]{1,3}\s*(,\s*[0-9.]+\s*)?\)/.source+/|hsla?\(\s*([0-9]{1,3}\s*,\s*){2}[0-9]{1,3}\s*(,\s*[0-9.]+\s*)?\)/.source),color=text.match(regexcolor);return color&&(color=color[0]),color}})); 9 | 10 | //# sourceMappingURL=onetopicbackground.min.js.map -------------------------------------------------------------------------------- /classes/footer.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * This file contains class for render the footer in the course format onetopic. 19 | * 20 | * @package format_onetopic 21 | * @copyright 2023 David Herney - https://bambuco.co 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace format_onetopic; 26 | 27 | use core_courseformat\output\local\content as content_base; 28 | use course_modinfo; 29 | 30 | /** 31 | * Class used to render the footer content in each course page. 32 | * 33 | * 34 | * @package format_onetopic 35 | * @copyright 2016 David Herney - https://bambuco.co 36 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 | */ 38 | class footer implements \renderable, \templatable { 39 | /** 40 | * @var \format_onetopic 41 | */ 42 | private $format; 43 | 44 | /** 45 | * Constructor. 46 | * 47 | * @param \format_onetopic $format Course format instance. 48 | */ 49 | public function __construct(\format_onetopic $format) { 50 | global $COURSE; 51 | 52 | $this->format = $format; 53 | } 54 | 55 | /** 56 | * Export this data so it can be used as the context for a mustache template (core/inplace_editable). 57 | * 58 | * @param renderer_base $output typically, the renderer that's calling this function 59 | * @return stdClass data context for a mustache template 60 | */ 61 | public function export_for_template(\renderer_base $output) { 62 | 63 | $format = $this->format; 64 | $currentsection = $this->format->get_sectionnum(); 65 | 66 | $data = (object)[ 67 | 'uniqid' => $format->uniqid, 68 | 'sectionreturn' => $currentsection ?? 0, 69 | 'hastopictabs' => $format->hastopictabs, 70 | 'hassecondrow' => $format->hassecondrow, 71 | ]; 72 | 73 | return $data; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /format.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Display the whole course as "tabs". 19 | * 20 | * It is based of the "topics" format. 21 | * 22 | * @since 2.0 23 | * @package format_onetopic 24 | * @copyright 2012 David Herney Bernal - cirano 25 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 26 | */ 27 | 28 | defined('MOODLE_INTERNAL') || die(); 29 | 30 | require_once($CFG->libdir . '/filelib.php'); 31 | require_once($CFG->libdir . '/completionlib.php'); 32 | 33 | // Horrible backwards compatible parameter aliasing. 34 | if ($topic = optional_param('topic', 0, PARAM_INT)) { 35 | $url = $PAGE->url; 36 | $url->param('section', $topic); 37 | debugging('Outdated topic param passed to course/view.php', DEBUG_DEVELOPER); 38 | redirect($url); 39 | } 40 | // End backwards-compatible aliasing. 41 | 42 | $context = context_course::instance($course->id); 43 | // Retrieve course format option fields and add them to the $course object. 44 | $course = course_get_format($course)->get_course(); 45 | 46 | if (($marker >= 0) && has_capability('moodle/course:setcurrentsection', $context) && confirm_sesskey()) { 47 | $course->marker = $marker; 48 | course_set_marker($course->id, $marker); 49 | } 50 | 51 | // Onetopic format is always multipage. 52 | $course->coursedisplay = COURSE_DISPLAY_MULTIPAGE; 53 | 54 | $renderer = $PAGE->get_renderer('format_onetopic'); 55 | 56 | $disableajax = optional_param('onetopic_da', -1, PARAM_INT); 57 | 58 | if (!isset($USER->onetopic_da)) { 59 | $USER->onetopic_da = []; 60 | } 61 | 62 | if ($disableajax !== -1) { 63 | if ($disableajax === 0) { 64 | $USER->onetopic_da[$course->id] = false; 65 | } else { 66 | $USER->onetopic_da[$course->id] = true; 67 | } 68 | } 69 | 70 | if (!is_null($displaysection)) { 71 | $format->set_sectionnum($displaysection); 72 | } 73 | 74 | $outputclass = $format->get_output_classname('content'); 75 | $widget = new $outputclass($format); 76 | echo $renderer->render($widget); 77 | -------------------------------------------------------------------------------- /amd/build/oneline.min.js: -------------------------------------------------------------------------------- 1 | define("format_onetopic/oneline",["exports","jquery"],(function(_exports,_jquery){var obj; 2 | /** 3 | * Used to oneline tabs view. 4 | * 5 | * @module format_onetopic/oneline 6 | * @copyright 2021 David Herney Bernal - cirano 7 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 8 | */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.load=void 0,_jquery=(obj=_jquery)&&obj.__esModule?obj:{default:obj};_exports.load=icons=>{(0,_jquery.default)(".format-onetopic .onelinetabs .tabs-wrapper").each((function(){var $container=(0,_jquery.default)(this),$menu=$container.find("> ul.nav.nav-tabs"),itemsLength=$menu.find("> li.nav-item").length,itemSize=$menu.find("> li.nav-item").outerWidth(!0),$leftarrow=(0,_jquery.default)('"),$rightarrow=(0,_jquery.default)('");$container.append($leftarrow),$container.append($rightarrow);var getMenuSize=function(){return itemsLength*itemSize},getMenuPosition=function(){return $menu.scrollLeft()},getMenuWrapperSize=function(){return $container.width()},hasScroll=function(){return $menu.get(0).scrollWidth>$menu.get(0).clientWidth},getInvisibleSize=function(){return menuSize-getMenuPosition()-menuWrapperSize};hasScroll()&&$container.addClass("hasscroll");var menuWrapperSize=getMenuWrapperSize(),wrapPadding=$container.outerWidth()-$container.width(),menuSize=getMenuSize(),menuInvisibleSize=getInvisibleSize();(0,_jquery.default)(window).on("resize",(function(){menuWrapperSize=getMenuWrapperSize(),menuSize=getMenuSize(),calcArrowVisible()}));var calcArrowVisible=function(){var menuPosition=getMenuPosition();menuInvisibleSize=getInvisibleSize();var maxScrollLeft=$menu.get(0).scrollWidth-$menu.get(0).clientWidth,menuEndOffset=menuInvisibleSize-20;hasScroll()?($container.addClass("hasscroll"),menuPosition<=20?($leftarrow.addClass("hidden"),$rightarrow.removeClass("hidden")):menuPosition=menuEndOffset&&($leftarrow.removeClass("hidden"),$rightarrow.addClass("hidden"))):($leftarrow.addClass("hidden"),$rightarrow.addClass("hidden"),$container.removeClass("hasscroll"))};$menu.on("scroll",(function(){calcArrowVisible()})),$rightarrow.on("click",(function(event){event.preventDefault();var newX=getMenuPosition()+.8*menuWrapperSize;$menu.animate({scrollLeft:newX},300)})),$leftarrow.on("click",(function(event){event.preventDefault();var newX=getMenuPosition()-.8*menuWrapperSize;$menu.animate({scrollLeft:newX},300)}));var $active=$container.find(".nav-link.active");if($active.length>0){var newX=$active.position().left-wrapPadding/2;$menu.animate({scrollLeft:newX},300)}calcArrowVisible()}))}})); 9 | 10 | //# sourceMappingURL=oneline.min.js.map -------------------------------------------------------------------------------- /templates/local/content/cm.mustache: -------------------------------------------------------------------------------- 1 | {{! 2 | This file is part of Moodle - http://moodle.org/ 3 | 4 | Moodle is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Moodle is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Moodle. If not, see . 16 | }} 17 | {{! 18 | @template format_onetopic/local/content/cm 19 | 20 | Displays a course module instance inside a course section. 21 | 22 | Example context (json): 23 | { 24 | "cmname": { 25 | "displayvalue" : "Activity example" 26 | }, 27 | "hasname": "true", 28 | "afterlink": "30 unread messages", 29 | "hasextras": true, 30 | "extras": ["[extras]"], 31 | "activityinfo": { 32 | "hasmodavailability": true, 33 | "activityname": "Activity example", 34 | "hascompletion": true, 35 | "uservisible": true, 36 | "hasdates": true, 37 | "isautomatic": true, 38 | "istrackeduser": true, 39 | "activitydates": [ 40 | { 41 | "label": "Opens:", 42 | "datestring": "6 April 2021, 6:46 PM" 43 | } 44 | ], 45 | "completiondetails": [ 46 | { 47 | "statuscomplete": 1, 48 | "description": "Viewed" 49 | }, 50 | { 51 | "statusincomplete": 1, 52 | "description": "Receive a grade" 53 | } 54 | ] 55 | }, 56 | "modstealth": true 57 | } 58 | }} 59 |
62 | {{! 63 | Place the actual content of the activity-item in a separate template to make it easier for other formats to add 64 | additional content to the activity wrapper. 65 | }} 66 | {{$ core_courseformat/local/content/cm/activity }} 67 | {{> core_courseformat/local/content/cm/activity }} 68 | {{/ core_courseformat/local/content/cm/activity }} 69 |
70 | -------------------------------------------------------------------------------- /templates/courseformat/content/cminline.mustache: -------------------------------------------------------------------------------- 1 | {{! 2 | This file is part of Moodle - http://moodle.org/ 3 | 4 | Moodle is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Moodle is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Moodle. If not, see . 16 | }} 17 | {{! 18 | @template format_onetopic/courseformat/content/cminline 19 | 20 | Displays a course module instance inside a course section. 21 | 22 | Example context (json): 23 | { 24 | "cmname": { 25 | "displayvalue" : "Activity example" 26 | }, 27 | "hasname": "true", 28 | "afterlink": "30 unread messages", 29 | "hasextras": true, 30 | "extras": ["[extras]"], 31 | "activityinfo": { 32 | "hasmodavailability": true, 33 | "activityname": "Activity example", 34 | "hascompletion": true, 35 | "uservisible": true, 36 | "hasdates": true, 37 | "isautomatic": true, 38 | "istrackeduser": true, 39 | "activitydates": [ 40 | { 41 | "label": "Opens:", 42 | "datestring": "6 April 2021, 6:46 PM" 43 | } 44 | ], 45 | "completiondetails": [ 46 | { 47 | "statuscomplete": 1, 48 | "description": "Viewed" 49 | }, 50 | { 51 | "statusincomplete": 1, 52 | "description": "Receive a grade" 53 | } 54 | ] 55 | }, 56 | "modstealth": true 57 | } 58 | }} 59 | 62 | {{! 63 | Place the actual content of the activity-item in a separate template to make it easier for other formats to add 64 | additional content to the activity wrapper. 65 | }} 66 | {{$ format_onetopic/courseformat/content/cm/activityinline }} 67 | {{> format_onetopic/courseformat/content/cm/activityinline }} 68 | {{/ format_onetopic/courseformat/content/cm/activityinline }} 69 | 70 | -------------------------------------------------------------------------------- /amd/src/main.js: -------------------------------------------------------------------------------- 1 | // This file is part of Moodle - http://moodle.org/ 2 | // 3 | // Moodle is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Moodle is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Moodle. If not, see . 15 | 16 | /** 17 | * General format features. 18 | * 19 | * @module format_onetopic/main 20 | * @copyright 2021 David Herney Bernal - cirano 21 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 22 | */ 23 | 24 | import * as OneLine from 'format_onetopic/oneline'; 25 | import $ from 'jquery'; 26 | import ModalFactory from 'core/modal_factory'; 27 | import {get_string as getString} from 'core/str'; 28 | 29 | /** 30 | * Component initialization. 31 | * 32 | * @method init 33 | * @param {string} formattype The course format type: 0: default, 1: vertical, 2: oneline. 34 | * @param {object} icons A list of usable icons: left arrow, right arrow. 35 | */ 36 | export const init = (formattype, icons) => { 37 | 38 | if (formattype == 2) { 39 | OneLine.load(icons); 40 | } 41 | 42 | var infotitle = getString('aboutresource', 'format_onetopic'); 43 | 44 | $('.format-onetopic .onetopic .iconwithhelp[data-helpwindow]').each(function() { 45 | var $node = $(this); 46 | $node.on('click', function(e) { 47 | e.preventDefault(); 48 | var $content = $('#hw-' + $node.data('helpwindow')); 49 | 50 | if ($content.data('modal')) { 51 | $content.data('modal').show(); 52 | return; 53 | } 54 | 55 | var title = $content.data('title'); 56 | 57 | if (!title) { 58 | title = infotitle; 59 | } 60 | 61 | // Show the content in a modal window. 62 | ModalFactory.create({ 63 | 'title': title, 64 | 'body': '', 65 | }).done(function(modal) { 66 | 67 | var contenthtml = $content.html(); 68 | 69 | // Uncomment html in contenthtml. The comment is used in order to load content with tags not inline. 70 | contenthtml = contenthtml.replace(//g, function(match, p1) { 71 | return p1; 72 | }); 73 | 74 | var $modalBody = modal.getBody(); 75 | $modalBody.css('min-height', '150px'); 76 | $modalBody.append(contenthtml); 77 | modal.show(); 78 | $content.data('modal', modal); 79 | }); 80 | }); 81 | }); 82 | }; 83 | -------------------------------------------------------------------------------- /templates/courseformat/content/cm/activityinline.mustache: -------------------------------------------------------------------------------- 1 | {{! 2 | This file is part of Moodle - http://moodle.org/ 3 | 4 | Moodle is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Moodle is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Moodle. If not, see . 16 | }} 17 | {{! 18 | @template format_onetopic/courseformat/content/cm/activityinline 19 | 20 | Display the activity content of a cm. 21 | 22 | Example context (json): 23 | { 24 | "cmname": { 25 | "displayvalue" : "Activity example" 26 | }, 27 | "hasname": "true", 28 | "afterlink": "30 unread messages", 29 | "hasextras": true, 30 | "extras": ["[extras]"], 31 | "activityinfo": { 32 | "hasmodavailability": true, 33 | "activityname": "Activity example", 34 | "hascompletion": true, 35 | "uservisible": true, 36 | "hasdates": true, 37 | "isautomatic": true, 38 | "istrackeduser": true, 39 | "activitydates": [ 40 | { 41 | "label": "Opens:", 42 | "datestring": "6 April 2021, 6:46 PM" 43 | } 44 | ], 45 | "completiondetails": [ 46 | { 47 | "statuscomplete": 1, 48 | "description": "Viewed" 49 | }, 50 | { 51 | "statusincomplete": 1, 52 | "description": "Receive a grade" 53 | } 54 | ] 55 | }, 56 | "modstealth": true 57 | } 58 | }} 59 | 60 | {{#cmname}} 61 | {{$ format_onetopic/courseformat/content/cm/cmnameinline }} 62 | {{> format_onetopic/courseformat/content/cm/cmnameinline }} 63 | {{/ format_onetopic/courseformat/content/cm/cmnameinline }} 64 | {{/cmname}} 65 | {{#afterlink}} 66 | 67 | {{{afterlink}}} 68 | 69 | {{/afterlink}} 70 | 71 | {{#showinlinehelp}} 72 | {{! Only show the icon if there is a name to display. }} 73 | {{#hasname}} 74 | 75 | {{#pix}} e/help, core, {{#str}} info {{/str}} {{/pix}} 76 | 77 | {{/hasname}} 78 | {{/showinlinehelp}} 79 | 80 | -------------------------------------------------------------------------------- /cli.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * This file contains cli commands for the Onetopic course format. 19 | * 20 | * @package format_onetopic 21 | * @copyright 2025 David Herney @ BambuCo 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | define('CLI_SCRIPT', true); 26 | 27 | require(__DIR__ . '/../../../config.php'); 28 | require_once($CFG->libdir . '/clilib.php'); // Cli only functions. 29 | require_once(__DIR__ . '/classes/local/clilib.php'); // Local cli functions. 30 | 31 | // Global options. 32 | $hr = "----------------------------------------\n"; 33 | 34 | // Get cli options. 35 | [$options, $unrecognized] = cli_get_params( 36 | [ 37 | 'help' => false, 38 | 'mstyles' => false, 39 | 'mslimit' => false, 40 | 'verbose' => false, 41 | ], 42 | [ 43 | 'h' => 'help', 44 | 'ms' => 'mstyles', 45 | 'msl' => 'mslimit', 46 | 'v' => 'verbose', 47 | ] 48 | ); 49 | 50 | $any = false; 51 | foreach ($options as $option) { 52 | if ($option) { 53 | $any = true; 54 | break; 55 | } 56 | } 57 | 58 | if (!$any) { 59 | $options['help'] = true; 60 | } 61 | 62 | if ($unrecognized) { 63 | $unrecognized = implode("\n ", $unrecognized); 64 | cli_error(get_string('cliunknowoption', 'admin', $unrecognized)); 65 | } 66 | 67 | if ($options['help']) { 68 | echo get_string('cli_help', 'format_onetopic'); 69 | die; 70 | } 71 | 72 | $cliverbose = $options['verbose'] ?? false; 73 | define('CLI_VERBOSE', $cliverbose); 74 | 75 | if ($options['mstyles']) { 76 | $action = $options['mstyles']; 77 | 78 | if ($action === true || !in_array($action, ['migrate', 'list'])) { 79 | $action = 'list'; 80 | } 81 | 82 | $limit = isset($options['mslimit']) && is_number($options['mslimit']) ? (int)$options['mslimit'] : 100; 83 | 84 | echo get_string('cli_migratestylesstarttitle', 'format_onetopic') . "\n"; 85 | echo $hr; 86 | 87 | if ($action === 'migrate') { 88 | echo get_string('cli_migratestylesstart', 'format_onetopic') . "\n"; 89 | \format_onetopic\local\clilib::mstyles_migrate($limit); 90 | echo get_string('cli_migratestylesend', 'format_onetopic') . "\n"; 91 | } else { 92 | \format_onetopic\local\clilib::mstyles_list($limit); 93 | } 94 | echo $hr; 95 | 96 | die; 97 | } 98 | -------------------------------------------------------------------------------- /templates/local/subsectionmodes/list.mustache: -------------------------------------------------------------------------------- 1 | {{! 2 | This file is part of Moodle - http://moodle.org/ 3 | 4 | Moodle is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Moodle is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Moodle. If not, see . 16 | }} 17 | {{! 18 | @template format_onetopic/local/subsectionmodes/list 19 | 20 | List template for subsection mode. 21 | 22 | Example context (json): 23 | { 24 | } 25 | }} 26 | {{< core_courseformat/local/content/delegatedsection }} 27 | {{$ core_courseformat/local/content/section/content }} 28 |
33 | {{#header}} 34 |

35 | {{{title}}} 36 |

37 | {{/header}} 38 |
39 |
41 |
42 | {{#isstealth}} 43 |
44 | {{#str}} orphansectionwarning, core_courseformat {{/str}} 45 |
46 | {{/isstealth}} 47 | {{#summary}} 48 | {{$ core_courseformat/local/content/section/summary }} 49 | {{> core_courseformat/local/content/section/summary }} 50 | {{/ core_courseformat/local/content/section/summary }} 51 | {{/summary}} 52 | {{#availability}} 53 | {{$ core_courseformat/local/content/section/availability }} 54 | {{> core_courseformat/local/content/section/availability }} 55 | {{/ core_courseformat/local/content/section/availability }} 56 | {{/availability}} 57 |
58 | {{#cmsummary}} 59 | {{$ core_courseformat/local/content/section/cmsummary }} 60 | {{> core_courseformat/local/content/section/cmsummary }} 61 | {{/ core_courseformat/local/content/section/cmsummary }} 62 | {{/cmsummary}} 63 | {{#cmlist}} 64 | {{$ core_courseformat/local/content/section/cmlist }} 65 | {{> core_courseformat/local/content/section/cmlist }} 66 | {{/ core_courseformat/local/content/section/cmlist }} 67 | {{/cmlist}} 68 | {{{cmcontrols}}} 69 |
70 | {{/ core_courseformat/local/content/section/content }} 71 | {{/ core_courseformat/local/content/delegatedsection}} 72 | -------------------------------------------------------------------------------- /tests/behat/highlight_sections.feature: -------------------------------------------------------------------------------- 1 | @format @format_onetopic 2 | Feature: Sections can be highlighted in Onetopic format 3 | In order to mark sections 4 | As a teacher 5 | I need to highlight and unhighlight sections 6 | 7 | Background: 8 | Given the following "users" exist: 9 | | username | firstname | lastname | email | 10 | | teacher1 | Teacher | 1 | teacher1@example.com | 11 | And the following "courses" exist: 12 | | fullname | shortname | format | coursedisplay | numsections | 13 | | Course 1 | C1 | onetopic | 0 | 5 | 14 | And the following "activities" exist: 15 | | activity | name | intro | course | idnumber | section | 16 | | assign | Test assignment name | Test assignment description | C1 | assign1 | 0 | 17 | | book | Test book name | Test book description | C1 | book1 | 1 | 18 | | lesson | Test lesson name | Test lesson description | C1 | lesson1 | 4 | 19 | | choice | Test choice name | Test choice description | C1 | choice1 | 5 | 20 | And the following "course enrolments" exist: 21 | | user | course | role | 22 | | teacher1 | C1 | editingteacher | 23 | And I log in as "teacher1" 24 | 25 | @javascript 26 | Scenario: Highlight a section in Onetopic format 27 | Given I am on "Course 1" course homepage with editing mode on 28 | When I click on "Topic 2" "link" in the "#page-content ul.nav.nav-tabs" "css_element" 29 | And I open section "2" edit menu 30 | And I click on "Highlight" "link" 31 | Then I should see "Highlighted" in the "#page-content .course-section .course-section-header" "css_element" 32 | 33 | @javascript 34 | Scenario: Highlight a section when another section is already highlighted in Onetopic format 35 | Given I am on "Course 1" course homepage with editing mode on 36 | And I click on "Topic 3" "link" in the "#page-content ul.nav.nav-tabs" "css_element" 37 | And I open section "3" edit menu 38 | And I click on "Highlight" "link" 39 | And I should see "Highlighted" in the "#page-content .course-section .course-section-header" "css_element" 40 | When I click on "Topic 2" "link" in the "#page-content ul.nav.nav-tabs" "css_element" 41 | And I open section "2" edit menu 42 | And I click on "Highlight" "link" 43 | Then I should see "Highlighted" in the "#page-content .course-section .course-section-header" "css_element" 44 | When I click on "Topic 3" "link" in the "#page-content ul.nav.nav-tabs" "css_element" 45 | And I should not see "Highlighted" in the "#page-content .course-section .course-section-header" "css_element" 46 | 47 | @javascript 48 | Scenario: Unhighlight a section in Onetopic format 49 | Given I am on "Course 1" course homepage with editing mode on 50 | And I click on "Topic 3" "link" in the "#page-content ul.nav.nav-tabs" "css_element" 51 | And I open section "3" edit menu 52 | And I click on "Highlight" "link" 53 | And I should see "Highlighted" in the "#page-content .course-section .course-section-header" "css_element" 54 | When I open section "3" edit menu 55 | And I click on "Unhighlight" "link" 56 | Then I should not see "Highlighted" in the "#page-content .course-section .course-section-header" "css_element" 57 | -------------------------------------------------------------------------------- /templates/local/subsectionmodes/collapsible.mustache: -------------------------------------------------------------------------------- 1 | {{! 2 | This file is part of Moodle - http://moodle.org/ 3 | 4 | Moodle is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Moodle is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Moodle. If not, see . 16 | }} 17 | {{! 18 | @template format_onetopic/local/subsectionmodes/collapsible 19 | 20 | List template for subsection mode. 21 | 22 | Example context (json): 23 | { 24 | } 25 | }} 26 | {{< core_courseformat/local/content/delegatedsection }} 27 | {{$ core_courseformat/local/content/section/content }} 28 |
33 | {{#header}} 34 | {{$ core_courseformat/local/content/section/header }} 35 | {{> core_courseformat/local/content/section/header }} 36 | {{/ core_courseformat/local/content/section/header }} 37 | {{/header}} 38 |
39 |
41 |
42 | {{#isstealth}} 43 |
44 | {{#str}} orphansectionwarning, core_courseformat {{/str}} 45 |
46 | {{/isstealth}} 47 | {{#summary}} 48 | {{$ core_courseformat/local/content/section/summary }} 49 | {{> core_courseformat/local/content/section/summary }} 50 | {{/ core_courseformat/local/content/section/summary }} 51 | {{/summary}} 52 | {{#availability}} 53 | {{$ core_courseformat/local/content/section/availability }} 54 | {{> core_courseformat/local/content/section/availability }} 55 | {{/ core_courseformat/local/content/section/availability }} 56 | {{/availability}} 57 |
58 | {{#cmsummary}} 59 | {{$ core_courseformat/local/content/section/cmsummary }} 60 | {{> core_courseformat/local/content/section/cmsummary }} 61 | {{/ core_courseformat/local/content/section/cmsummary }} 62 | {{/cmsummary}} 63 | {{#cmlist}} 64 | {{$ core_courseformat/local/content/section/cmlist }} 65 | {{> core_courseformat/local/content/section/cmlist }} 66 | {{/ core_courseformat/local/content/section/cmlist }} 67 | {{/cmlist}} 68 | {{{cmcontrols}}} 69 |
70 | {{/ core_courseformat/local/content/section/content }} 71 | {{/ core_courseformat/local/content/delegatedsection}} 72 | -------------------------------------------------------------------------------- /amd/build/main.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"main.min.js","sources":["../src/main.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 .\n\n/**\n * General format features.\n *\n * @module format_onetopic/main\n * @copyright 2021 David Herney Bernal - cirano\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport * as OneLine from 'format_onetopic/oneline';\nimport $ from 'jquery';\nimport ModalFactory from 'core/modal_factory';\nimport {get_string as getString} from 'core/str';\n\n/**\n * Component initialization.\n *\n * @method init\n * @param {string} formattype The course format type: 0: default, 1: vertical, 2: oneline.\n * @param {object} icons A list of usable icons: left arrow, right arrow.\n */\nexport const init = (formattype, icons) => {\n\n if (formattype == 2) {\n OneLine.load(icons);\n }\n\n var infotitle = getString('aboutresource', 'format_onetopic');\n\n $('.format-onetopic .onetopic .iconwithhelp[data-helpwindow]').each(function() {\n var $node = $(this);\n $node.on('click', function(e) {\n e.preventDefault();\n var $content = $('#hw-' + $node.data('helpwindow'));\n\n if ($content.data('modal')) {\n $content.data('modal').show();\n return;\n }\n\n var title = $content.data('title');\n\n if (!title) {\n title = infotitle;\n }\n\n // Show the content in a modal window.\n ModalFactory.create({\n 'title': title,\n 'body': '',\n }).done(function(modal) {\n\n var contenthtml = $content.html();\n\n // Uncomment html in contenthtml. The comment is used in order to load content with tags not inline.\n contenthtml = contenthtml.replace(//g, function(match, p1) {\n return p1;\n });\n\n var $modalBody = modal.getBody();\n $modalBody.css('min-height', '150px');\n $modalBody.append(contenthtml);\n modal.show();\n $content.data('modal', modal);\n });\n });\n });\n};\n"],"names":["formattype","icons","OneLine","load","infotitle","each","$node","this","on","e","preventDefault","$content","data","show","title","create","done","modal","contenthtml","html","replace","match","p1","$modalBody","getBody","css","append"],"mappings":";;;;;;;2HAmCoB,CAACA,WAAYC,SAEX,GAAdD,YACAE,QAAQC,KAAKF,WAGbG,WAAY,mBAAU,gBAAiB,uCAEzC,6DAA6DC,MAAK,eAC5DC,OAAQ,mBAAEC,MACdD,MAAME,GAAG,SAAS,SAASC,GACvBA,EAAEC,qBACEC,UAAW,mBAAE,OAASL,MAAMM,KAAK,kBAEjCD,SAASC,KAAK,SACdD,SAASC,KAAK,SAASC,gBAIvBC,MAAQH,SAASC,KAAK,SAErBE,QACDA,MAAQV,kCAICW,OAAO,OACPD,WACD,KACTE,MAAK,SAASC,WAETC,YAAcP,SAASQ,OAG3BD,YAAcA,YAAYE,QAAQ,sBAAsB,SAASC,MAAOC,WAC7DA,UAGPC,WAAaN,MAAMO,UACvBD,WAAWE,IAAI,aAAc,SAC7BF,WAAWG,OAAOR,aAClBD,MAAMJ,OACNF,SAASC,KAAK,QAASK"} -------------------------------------------------------------------------------- /classes/output/courseformat/content/sectionselector.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Contains the default section selector. 19 | * 20 | * @package format_onetopic 21 | * @copyright 2022 David Herney Bernal - cirano. https://bambuco.co 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace format_onetopic\output\courseformat\content; 26 | 27 | use core\output\named_templatable; 28 | use core_courseformat\base as course_format; 29 | use core_courseformat\output\local\courseformat_named_templatable; 30 | use core_courseformat\output\local\content\sectionselector as sectionselector_base; 31 | use renderable; 32 | use stdClass; 33 | use url_select; 34 | 35 | /** 36 | * Represents the section selector. 37 | * 38 | * @package format_onetopic 39 | * @copyright 2022 David Herney Bernal - cirano. https://bambuco.co 40 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 41 | */ 42 | class sectionselector extends sectionselector_base { 43 | /** 44 | * Export this data so it can be used as the context for a mustache template. 45 | * 46 | * @param renderer_base $output typically, the renderer that's calling this function 47 | * @return stdClass data context for a mustache template 48 | */ 49 | public function export_for_template(\renderer_base $output): stdClass { 50 | 51 | $format = $this->format; 52 | $course = $format->get_course(); 53 | 54 | $modinfo = $this->format->get_modinfo(); 55 | 56 | $data = $this->navigation->export_for_template($output); 57 | 58 | $anchortotabstree = get_config('format_onetopic', 'anchortotabstree'); 59 | 60 | $anchor = $anchortotabstree ? '#tabs-tree-start' : ''; 61 | 62 | // Add the section selector. 63 | $sectionmenu = []; 64 | $section = ($course->realcoursedisplay == COURSE_DISPLAY_MULTIPAGE) ? 1 : 0; 65 | $numsections = $format->get_last_section_number(); 66 | while ($section <= $numsections) { 67 | $thissection = $modinfo->get_section_info($section); 68 | $formatoptions = course_get_format($course)->get_format_options($thissection); 69 | $prefix = is_array($formatoptions) && $formatoptions['level'] > 0 ? '    ' : ''; 70 | 71 | $url = course_get_url($course, $section); 72 | if ($thissection->uservisible && $url) { 73 | $sectionmenu[$url->out(false) . $anchor] = $prefix . get_section_name($course, $section); 74 | } 75 | $section++; 76 | } 77 | 78 | $select = new url_select($sectionmenu, '', ['' => get_string('jumpto')]); 79 | $select->class = 'jumpmenu'; 80 | $select->formid = 'sectionmenu'; 81 | 82 | $data->selector = $output->render($select); 83 | return $data; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /backup/moodle2/restore_format_onetopic_plugin.class.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Specialised restore for format_onetopic 19 | * 20 | * @package format_onetopic 21 | * @category backup 22 | * @copyright 2018 David Herney Bernal - cirano 23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 | */ 25 | 26 | defined('MOODLE_INTERNAL') || die(); 27 | 28 | require_once($CFG->dirroot . '/course/format/topics/backup/moodle2/restore_format_topics_plugin.class.php'); 29 | 30 | /** 31 | * Specialised restore for format_onetopic 32 | * 33 | * Processes 'numsections' from the old backup files and hides sections that used to be "orphaned" 34 | * 35 | * @package format_onetopic 36 | * @category backup 37 | * @copyright 2018 David Herney Bernal - cirano 38 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 39 | */ 40 | class restore_format_onetopic_plugin extends restore_format_topics_plugin { 41 | /** 42 | * Executed after course restore is complete 43 | * 44 | * This method is only executed if course configuration was overridden 45 | */ 46 | public function after_restore_course() { 47 | global $DB; 48 | 49 | if (!$this->need_restore_numsections()) { 50 | // Backup file was made in Moodle 3.3 or later, we don't need to process 'numsecitons'. 51 | return; 52 | } 53 | 54 | $data = $this->connectionpoint->get_data(); 55 | $backupinfo = $this->step->get_task()->get_info(); 56 | if ($backupinfo->original_course_format !== 'onetopic' || !isset($data['tags']['numsections'])) { 57 | // Backup from another course format or backup file does not even have 'numsections'. 58 | return; 59 | } 60 | 61 | $numsections = (int)$data['tags']['numsections']; 62 | foreach ($backupinfo->sections as $key => $section) { 63 | // For each section from the backup file check if it was restored and if was "orphaned" in the original 64 | // course and mark it as hidden. This will leave all activities in it visible and available just as it was 65 | // in the original course. 66 | // Exception is when we restore with merging and the course already had a section with this section number, 67 | // in this case we don't modify the visibility. 68 | if ($this->step->get_task()->get_setting_value($key . '_included')) { 69 | $sectionnum = (int)$section->title; 70 | if ($sectionnum > $numsections && $sectionnum > $this->originalnumsections) { 71 | $DB->execute( 72 | "UPDATE {course_sections} SET visible = 0 WHERE course = ? AND section = ?", 73 | [$this->step->get_task()->get_courseid(), $sectionnum] 74 | ); 75 | } 76 | } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /templates/local/content.mustache: -------------------------------------------------------------------------------- 1 | {{! 2 | This file is part of Moodle - http://moodle.org/ 3 | 4 | Moodle is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Moodle is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Moodle. If not, see . 16 | }} 17 | {{! 18 | @template format_onetopic/local/content 19 | 20 | Displays the complete course format. 21 | 22 | Example context (json): 23 | { 24 | "sectionselector": { 25 | "hasprevious": true, 26 | "previousurl": "#", 27 | "larrow": "◄", 28 | "previousname": "Section 3", 29 | "hasnext": true, 30 | "rarrow": "►", 31 | "nexturl": "#", 32 | "nextname": "Section 5", 33 | "selector": "" 34 | }, 35 | "singlesection": { 36 | "num": 1, 37 | "id": 35, 38 | "header": { 39 | "name": "Single Section Example", 40 | "url": "#" 41 | }, 42 | "cmlist": { 43 | "cms": [ 44 | { 45 | "cmitem": { 46 | "cmformat": { 47 | "cmname": "Assign example", 48 | "hasname": "true" 49 | }, 50 | "cmid": 4, 51 | "id": 4, 52 | "anchor": "module-4", 53 | "module": "assign", 54 | "extraclasses": "" 55 | } 56 | } 57 | ], 58 | "hascms": true 59 | }, 60 | "iscurrent": true, 61 | "summary": { 62 | "summarytext": "Summary text!" 63 | } 64 | } 65 | } 66 | }} 67 | 68 |
69 | {{availability}} 70 | {{#sectionnavigation}} 71 | {{$ core_courseformat/local/content/sectionnavigation }} 72 | {{> core_courseformat/local/content/sectionnavigation }} 73 | {{/ core_courseformat/local/content/sectionnavigation }} 74 | {{/sectionnavigation}} 75 |
    76 | {{#singlesection}} 77 | {{$ format_onetopic/local/content/section }} 78 | {{> format_onetopic/local/content/section }} 79 | {{/ format_onetopic/local/content/section }} 80 | {{/singlesection}} 81 |
82 | {{#sectionselector}} 83 | {{$ core_courseformat/local/content/sectionselector }} 84 | {{> core_courseformat/local/content/sectionselector }} 85 | {{/ core_courseformat/local/content/sectionselector }} 86 | {{/sectionselector}} 87 | {{#bulkedittools}} 88 | {{$ core_courseformat/local/content/bulkedittools}} 89 | {{> core_courseformat/local/content/bulkedittools}} 90 | {{/ core_courseformat/local/content/bulkedittools}} 91 | {{/bulkedittools}} 92 | 93 |
94 | -------------------------------------------------------------------------------- /classes/output/courseformat/content/section.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Contains the default section controls output class. 19 | * 20 | * @package format_onetopic 21 | * @copyright 2022 David Herney Bernal - cirano. https://bambuco.co 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace format_onetopic\output\courseformat\content; 26 | 27 | use core_courseformat\base as course_format; 28 | use core_courseformat\output\local\content\section as section_base; 29 | use stdClass; 30 | 31 | /** 32 | * Base class to render a course section. 33 | * 34 | * @package format_onetopic 35 | * @copyright 2022 David Herney Bernal - cirano. https://bambuco.co 36 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 | */ 38 | class section extends section_base { 39 | /** 40 | * @var bool Whether we are rendering a delegated section within other section or not. 41 | */ 42 | public $insection = false; 43 | 44 | /** @var course_format the course format */ 45 | protected $format; 46 | 47 | /** 48 | * Export this data so it can be used as the context for a mustache template. 49 | * 50 | * @param \renderer_base $output typically, the renderer that's calling this function 51 | * @return stdClass data context for a mustache template 52 | */ 53 | public function export_for_template(\renderer_base $output): stdClass { 54 | global $PAGE; 55 | 56 | $format = $this->format; 57 | $course = $format->get_course(); 58 | $section = $this->section; 59 | 60 | if ($section->is_delegated()) { 61 | $format->subsectionmode = true; 62 | } 63 | 64 | $summary = new $this->summaryclass($format, $section); 65 | 66 | $data = (object)[ 67 | 'num' => $section->section ?? '0', 68 | 'id' => $section->id, 69 | 'sectionreturnid' => $format->get_sectionnum(), 70 | 'insertafter' => false, 71 | 'summary' => $summary->export_for_template($output), 72 | 'highlightedlabel' => $format->get_section_highlighted_name(), 73 | 'sitehome' => $course->id == SITEID, 74 | 'editing' => $PAGE->user_is_editing(), 75 | 'displayonesection' => ($course->id != SITEID && !is_null($format->get_sectionid())), 76 | ]; 77 | 78 | $haspartials = []; 79 | $haspartials['availability'] = $this->add_availability_data($data, $output); 80 | $haspartials['visibility'] = $this->add_visibility_data($data, $output); 81 | $haspartials['editor'] = $this->add_editor_data($data, $output); 82 | $haspartials['header'] = $this->add_header_data($data, $output); 83 | $haspartials['cm'] = $this->add_cm_data($data, $output); 84 | $this->add_format_data($data, $haspartials, $output); 85 | 86 | if (!$this->insection) { 87 | $data->contentcollapsed = false; 88 | } 89 | 90 | $format->subsectionmode = false; 91 | 92 | return $data; 93 | } 94 | 95 | /** 96 | * Get the section number. 97 | * 98 | * @return int 99 | */ 100 | public function get_sectionnum() { 101 | return $this->section->section; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /templates/courseformat/content/cm/cmhelpinfo.mustache: -------------------------------------------------------------------------------- 1 | {{! 2 | This file is part of Moodle - http://moodle.org/ 3 | 4 | Moodle is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Moodle is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Moodle. If not, see . 16 | }} 17 | {{! 18 | @template format_onetopic/courseformat/content/cm/cmhelpinfo 19 | 20 | Mustache to displays the help information for a course module instance. 21 | 22 | Example context (json): 23 | { 24 | "url": "#", 25 | "icon": "../../../pix/help.svg", 26 | "pluginname": "File", 27 | "textclasses": "", 28 | "purpose": "content", 29 | "modname": "resource", 30 | "activityname": { 31 | "displayvalue" : "Moodle", 32 | "value" : "Moodle", 33 | "itemid" : "1", 34 | "component" : "core_unknown", 35 | "itemtype" : "unknown", 36 | "edithint" : "Edit this", 37 | "editlabel" : "New name for this", 38 | "type" : "text", 39 | "options" : "", 40 | "linkeverything": 0 41 | } 42 | } 43 | }} 44 | 45 | {{! Only show the icon if there is a name to display. }} 46 | {{#hasname}} 47 | 95 | {{/hasname}} 96 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # COURSE FORMAT Onetopic 2 | 3 | Package tested in: moodle 5.0+. 4 | 5 | ## QUICK INSTALL 6 | Download zip package, extract the onetopic folder and upload this folder into course/format/. 7 | 8 | ## ABOUT 9 | * **Developed by:** David Herney - davidherney at gmail dot com 10 | * **GIT:** https://github.com/davidherney/moodle-format_onetopic 11 | * **Powered by:** [BambuCo](https://bambuco.co/) 12 | * **Documentation:** [En](https://bambuco.co/onetopic-en/) - [Es](https://bambuco.co/onetopic/) 13 | 14 | ## COMING SOON 15 | * Fix: the topics bar is not refresh when change (move a section in boost sections bar) or delete a section. 16 | 17 | ## IN VERSION 18 | 19 | ### 2025021903: 20 | * New feature: Subsection display mode. 21 | 22 | ### 2025021902: 23 | * Compatibility with changes in 5.0 24 | 25 | ### 2025021901: 26 | * Tool for migrating styles from old controls. 27 | 28 | ### 2025021900: 29 | * Compatibility with moodle 5.0 30 | 31 | ### 2024050906: 32 | * Option to remove icon in tab style editor. 33 | 34 | ### 2024050905: 35 | * New tab styles editor when editing each section. 36 | * ![Tabs styles editor](https://boa.nuestroscursos.net/api/c/web/resources/NDU1MEVCNjAtODQ4Qy00RTk3LUI2NzUtOUJBN0E5ODk0QTkyQGJvYS51ZGVhLmVkdS5jbw==/!/onetopic/3.1.tab_settings.png) 37 | * Select icon by tab and tab state. 38 | * New background option by section. 39 | * ![Tabs background color](https://boa.nuestroscursos.net/api/c/web/resources/NDU1MEVCNjAtODQ4Qy00RTk3LUI2NzUtOUJBN0E5ODk0QTkyQGJvYS51ZGVhLmVkdS5jbw==/!/onetopic/1.ejemplo_simple.png) 40 | * Compatibility with moodle 4.5 41 | * Do not show new subsections in tabs (Moodle 4.5). In the future these subsections become second-level tabs. 42 | 43 | ### 2024050904: 44 | * New "sectionname" parameter to navigate to a tab directly using its name. 45 | * New default course settings in site level. 46 | * The courseindex option has been removed from the tab view option. Courses that had it set will continue to work until the option is overridden. It is being removed because there is no way to customize its behavior from the course format and some serious UX bugs are occurring. 47 | 48 | ### 2024050903: 49 | * Fixed Load previously browsed section when section is not specified in URL. 50 | 51 | ### 2024050901: 52 | * Compatibility with moodle 4.4 53 | 54 | ### 2024050303: 55 | * Update section control menu for Moodle 4.2 and stabilization improvements. 56 | 57 | ### 2024050301: 58 | * Support bulk edit tools. 59 | 60 | ### 2022081610: 61 | * New scope to show tabs: modules. Included admin setting to enable it. Funded by [Ecole hôtelière de Lausanne](https://www.ehl.edu/) 62 | * ![Scope modules](https://boa.nuestroscursos.net/api/c/web/resources/NDU1MEVCNjAtODQ4Qy00RTk3LUI2NzUtOUJBN0E5ODk0QTkyQGJvYS51ZGVhLmVkdS5jbw==/!/onetopic/tabs_scopemodules.png) 63 | 64 | ### 2022081609: 65 | * New tabs style editor in site settings. Funded by [Ecole hôtelière de Lausanne](https://www.ehl.edu/) 66 | * ![Editor preview](https://boa.nuestroscursos.net/api/c/web/resources/NDU1MEVCNjAtODQ4Qy00RTk3LUI2NzUtOUJBN0E5ODk0QTkyQGJvYS51ZGVhLmVkdS5jbw==/!/onetopic/tabs_styles_editor.png) 67 | * Show "Availability information" in tabs and in the template mode. 68 | 1. ![Availability_information](https://boa.nuestroscursos.net/api/c/web/resources/NDU1MEVCNjAtODQ4Qy00RTk3LUI2NzUtOUJBN0E5ODk0QTkyQGJvYS51ZGVhLmVkdS5jbw==/!/onetopic/tpl_availability_information.png) 69 | 2. ![Availability_information window](https://boa.nuestroscursos.net/api/c/web/resources/NDU1MEVCNjAtODQ4Qy00RTk3LUI2NzUtOUJBN0E5ODk0QTkyQGJvYS51ZGVhLmVkdS5jbw==/!/onetopic/tpl_availability_information_window.png) 70 | 71 | ### 2022081608: 72 | * Navigation options: Next/previous section, with different display options. 73 | * A site setting option to define if use an anchor to navigate to the top of tabs when click in a tab. 74 | * New course setting to hide the course index bar. 75 | 76 | ### 2022081607: 77 | * Duplicate section feature. 78 | 79 | ### 2022081606: 80 | * Enable/disable custom styles in site level 81 | * Chevron icon for tabs with child's 82 | * New CSS class for tabs with child's: haschilds 83 | 84 | ### 2022081605: 85 | * Check compatibility with moodle 4.1 86 | * Add section move controls 87 | * Notice in the tab bar when a course is being edited and the tabs are hidden from students 88 | 89 | ### 2022081604: 90 | * Stabilization 91 | 92 | ### 2022081602: 93 | * Compatibility with moodle 4.0 94 | -------------------------------------------------------------------------------- /classes/output/courseformat/content/sectionnavigation.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Contains the default section navigation output class. 19 | * 20 | * @package format_onetopic 21 | * @copyright 2022 David Herney - cirano. https://bambuco.co 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace format_onetopic\output\courseformat\content; 26 | 27 | use context_course; 28 | use core\output\named_templatable; 29 | use core_courseformat\base as course_format; 30 | use core_courseformat\output\local\courseformat_named_templatable; 31 | use core_courseformat\output\local\content\sectionnavigation as sectionnavigation_base; 32 | use renderable; 33 | use stdClass; 34 | 35 | /** 36 | * Base class to render a course add section navigation. 37 | * 38 | * @package format_onetopic 39 | * @copyright 2022 David Herney - cirano. https://bambuco.co 40 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 41 | */ 42 | class sectionnavigation extends sectionnavigation_base { 43 | /** @var stdClass the calculated data to prevent calculations when rendered several times */ 44 | protected $data = null; 45 | 46 | /** 47 | * Export this data so it can be used as the context for a mustache template. 48 | * 49 | * @param renderer_base $output typically, the renderer that's calling this function 50 | * @return stdClass data context for a mustache template 51 | */ 52 | public function export_for_template(\renderer_base $output): stdClass { 53 | global $USER; 54 | 55 | if ($this->data !== null) { 56 | return $this->data; 57 | } 58 | 59 | $format = $this->format; 60 | $course = $format->get_course(); 61 | $context = context_course::instance($course->id); 62 | 63 | $modinfo = $this->format->get_modinfo(); 64 | $sections = $modinfo->get_section_info_all(); 65 | 66 | $data = (object)[ 67 | 'previousurl' => '', 68 | 'nexturl' => '', 69 | 'larrow' => $output->larrow(), 70 | 'rarrow' => $output->rarrow(), 71 | 'currentsection' => $this->sectionno, 72 | ]; 73 | 74 | $firstsection = ($course->realcoursedisplay == COURSE_DISPLAY_MULTIPAGE) ? 1 : 0; 75 | $back = $this->sectionno - 1; 76 | while ($back > ($firstsection - 1) && empty($data->previousurl)) { 77 | if ($sections[$back]->uservisible) { 78 | if (!$sections[$back]->visible) { 79 | $data->previoushidden = true; 80 | } 81 | $data->previousname = get_section_name($course, $sections[$back]); 82 | $data->previousurl = course_get_url($course, $back); 83 | $data->hasprevious = true; 84 | } 85 | $back--; 86 | } 87 | 88 | $forward = $this->sectionno + 1; 89 | $numsections = course_get_format($course)->get_last_section_number(); 90 | while ($forward <= $numsections && empty($data->nexturl)) { 91 | if ($sections[$forward]->uservisible) { 92 | if (!$sections[$forward]->visible) { 93 | $data->nexthidden = true; 94 | } 95 | $data->nextname = get_section_name($course, $sections[$forward]); 96 | $data->nexturl = course_get_url($course, $forward); 97 | $data->hasnext = true; 98 | } 99 | $forward++; 100 | } 101 | 102 | $this->data = $data; 103 | return $data; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /amd/src/onetopicbackground.js: -------------------------------------------------------------------------------- 1 | // This file is part of Moodle - http://moodle.org/ 2 | // 3 | // Moodle is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Moodle is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Moodle. If not, see . 15 | 16 | /** 17 | * Onetopic background selector. 18 | * 19 | * @module format_onetopic/onetopicbackground 20 | * @copyright 2021 David Herney Bernal - cirano 21 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 22 | */ 23 | import $ from 'jquery'; 24 | import ModalFactory from 'core/modal_factory'; 25 | import ModalSaveCancel from 'core/modal_save_cancel'; 26 | import ModalEvents from 'core/modal_events'; 27 | 28 | /** 29 | * Component initialization. 30 | * 31 | * @method init 32 | * @param {String} controlid The control id. 33 | */ 34 | export const init = (controlid) => { 35 | 36 | var $controlinput = $('#' + controlid); 37 | var $control = $controlinput.parent('.backgroundpicker'); 38 | var $controlwindow = $control.find('.backgroundpickerwindow'); 39 | var $controlbutton = $control.find('.backgroundpickerselector'); 40 | var $colorpickerinput = $controlwindow.find('input.form-control[type="text"]'); 41 | 42 | $controlinput.on('change', function() { 43 | var $color = $controlinput.val(); 44 | if ($color) { 45 | $controlinput.css('background', $color); 46 | } else { 47 | $controlinput.css('background', ''); 48 | } 49 | }); 50 | $controlinput.trigger('change'); 51 | 52 | // Initialize the modal window. 53 | var title = $controlwindow.attr('title'); 54 | var buttons = []; 55 | buttons.save = $controlwindow.data('savelabel'); 56 | 57 | var setEvents = function(modal) { 58 | modal.getRoot().on(ModalEvents.cancel, () => { 59 | modal.hide(); 60 | }); 61 | 62 | modal.getRoot().on(ModalEvents.save, () => { 63 | var newcolor = $colorpickerinput.val(); 64 | var val = $controlinput.val(); 65 | var color = readColor(val); 66 | if (color) { 67 | val = val.replace(color, newcolor); 68 | } else if (val.trim() === '') { 69 | val = newcolor; 70 | } else { 71 | val += ' ' + newcolor; 72 | } 73 | $controlinput.val(val); 74 | $controlinput.css('background', val); 75 | modal.hide(); 76 | }); 77 | }; 78 | 79 | ModalFactory.create({ 80 | 'title': title, 81 | 'body': $controlwindow, 82 | 'type': ModalSaveCancel.TYPE, 83 | 'large': true, 84 | 'buttons': buttons 85 | }) 86 | .done(function(modal) { 87 | var $modalBody = modal.getBody(); 88 | $modalBody.append($controlwindow); 89 | $control.data('modal', modal); 90 | setEvents(modal); 91 | }); 92 | 93 | // Color picker control. 94 | $controlbutton.on('click', function(e) { 95 | e.preventDefault(); 96 | $controlwindow.removeClass('hidden'); 97 | var currentval = $controlinput.val(); 98 | 99 | var color = readColor(currentval); 100 | 101 | $colorpickerinput.val(color); 102 | $control.data('modal').show(); 103 | }); 104 | 105 | }; 106 | 107 | /** 108 | * Extracts the first color from a text string. Recognizes hexadecimal, rgba and hsla. 109 | * 110 | * @param {string} text 111 | * @returns 112 | */ 113 | var readColor = function(text) { 114 | var regexcolor = new RegExp( 115 | /#[0-9a-fA-F]{6}/.source 116 | + /|#[0-9a-fA-F]{3}/.source 117 | + /|rgba?\(\s*([0-9]{1,3}\s*,\s*){2}[0-9]{1,3}\s*(,\s*[0-9.]+\s*)?\)/.source 118 | + /|hsla?\(\s*([0-9]{1,3}\s*,\s*){2}[0-9]{1,3}\s*(,\s*[0-9.]+\s*)?\)/.source); 119 | 120 | var color = text.match(regexcolor); 121 | if (color) { 122 | color = color[0]; 123 | } 124 | 125 | return color; 126 | }; 127 | -------------------------------------------------------------------------------- /classes/output/courseformat/content/section/cmlist.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Contains the default activity list from a section. 19 | * 20 | * @package format_onetopic 21 | * @copyright 2022 David Herney Bernal - cirano. https://bambuco.co 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | namespace format_onetopic\output\courseformat\content\section; 26 | 27 | use core\output\named_templatable; 28 | use core_courseformat\base as course_format; 29 | use core_courseformat\output\local\courseformat_named_templatable; 30 | use core_courseformat\output\local\content\section\cmlist as cmlist_base; 31 | use moodle_url; 32 | use renderable; 33 | use section_info; 34 | use stdClass; 35 | 36 | /** 37 | * Base class to render a section activity list. 38 | * 39 | * @package format_onetopic 40 | * @copyright 2022 David Herney Bernal - cirano. https://bambuco.co 41 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 42 | */ 43 | class cmlist extends cmlist_base { 44 | /** 45 | * Export this data so it can be used as the context for a mustache template. 46 | * 47 | * @param renderer_base $output typically, the renderer that's calling this function 48 | * @return stdClass data context for a mustache template 49 | */ 50 | public function export_for_template(\renderer_base $output): stdClass { 51 | global $USER; 52 | 53 | $format = $this->format; 54 | $section = $this->section; 55 | $course = $format->get_course(); 56 | $modinfo = $format->get_modinfo(); 57 | $user = $USER; 58 | 59 | $data = new stdClass(); 60 | $data->cms = []; 61 | 62 | // By default, non-ajax controls are disabled but in some places like the frontpage 63 | // it is necessary to display them. This is a temporal solution while JS is still 64 | // optional for course editing. 65 | $showmovehere = ismoving($course->id); 66 | 67 | if ($showmovehere) { 68 | $data->hascms = true; 69 | $data->showmovehere = true; 70 | $data->strmovefull = strip_tags(get_string("movefull", "", "'$user->activitycopyname'")); 71 | $data->movetosectionurl = new moodle_url('/course/mod.php', ['movetosection' => $section->id, 'sesskey' => sesskey()]); 72 | $data->movingstr = strip_tags(get_string('activityclipboard', '', $user->activitycopyname)); 73 | $data->cancelcopyurl = new moodle_url('/course/mod.php', ['cancelcopy' => 'true', 'sesskey' => sesskey()]); 74 | } 75 | 76 | if (empty($modinfo->sections[$section->section])) { 77 | return $data; 78 | } 79 | 80 | if (!$format->show_editor() && $course->templatetopic == \format_onetopic::TEMPLATETOPIC_SINGLE) { 81 | return $data; 82 | } 83 | 84 | foreach ($modinfo->sections[$section->section] as $modnumber) { 85 | if ( 86 | !$format->show_editor() && 87 | $course->templatetopic == \format_onetopic::TEMPLATETOPIC_LIST && 88 | in_array($modnumber, $format->tplcmsused) 89 | ) { 90 | continue; 91 | } 92 | 93 | $mod = $modinfo->cms[$modnumber]; 94 | // If the old non-ajax move is necessary, we do not print the selected cm. 95 | if ($showmovehere && $USER->activitycopy == $mod->id) { 96 | continue; 97 | } 98 | if ($mod->is_visible_on_course_page() && $mod->is_of_type_that_can_display()) { 99 | $item = new $this->itemclass($format, $section, $mod, $this->displayoptions); 100 | $data->cms[] = (object)[ 101 | 'cmitem' => $item->export_for_template($output), 102 | 'moveurl' => new moodle_url('/course/mod.php', ['moveto' => $modnumber, 'sesskey' => sesskey()]), 103 | ]; 104 | } 105 | } 106 | 107 | if (!empty($data->cms)) { 108 | $data->hascms = true; 109 | } 110 | 111 | return $data; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /classes/singletab.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Class containing a single tab. 19 | * 20 | * @package format_onetopic 21 | * @copyright 2021 David Herney - https://bambuco.co 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | namespace format_onetopic; 25 | 26 | /** 27 | * Class containing the tab information. 28 | * 29 | * @copyright 2021 David Herney - https://bambuco.co 30 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 31 | */ 32 | class singletab { 33 | /** 34 | * @var int Tab id. 35 | */ 36 | public $id; 37 | 38 | /** 39 | * @var int Tab index. 40 | */ 41 | public $index; 42 | 43 | /** 44 | * @var int Section index. 45 | */ 46 | public $section; 47 | 48 | /** 49 | * @var string Tab HTML content. 50 | */ 51 | public $content; 52 | 53 | /** 54 | * @var string Tab link. 55 | */ 56 | public $link; 57 | 58 | /** 59 | * @var string Tab title. 60 | */ 61 | public $title; 62 | 63 | /** 64 | * @var string Available message, in html format, if exist. 65 | */ 66 | public $availablemessage; 67 | 68 | /** 69 | * @var string Custom CSS styles. 70 | */ 71 | public $customstyles; 72 | 73 | /** 74 | * @var string Custom extra CSS classes. 75 | */ 76 | public $specialclass; 77 | 78 | /** 79 | * @var bool If tab is selected. 80 | */ 81 | public $selected = false; 82 | 83 | /** 84 | * @var bool If tab is active. 85 | */ 86 | public $active = true; 87 | 88 | /** 89 | * @var string Custom CSS styles. 90 | */ 91 | public $cssstyles = ''; 92 | 93 | /** 94 | * @var array Icons list. 95 | */ 96 | public $icons = []; 97 | 98 | /** 99 | * @var \format_onetopic\singletab Parent tab. 100 | */ 101 | public $parenttab = null; 102 | 103 | /** 104 | * @var \format_onetopic\tabs Tabs childs list. 105 | */ 106 | private $childs; 107 | 108 | /** 109 | * Constructor. 110 | * 111 | * @param int $section Section index. 112 | * @param string $content HTML tab content. 113 | * @param string $link Tab link. 114 | * @param string $title Tab title. 115 | * @param string $availablemessage Available message, in html format, if exist. 116 | * @param string $customstyles Custom CSS styles. 117 | * @param string $specialclass Custom extra CSS classes. 118 | */ 119 | public function __construct( 120 | $section, 121 | $content, 122 | $link, 123 | $title, 124 | $availablemessage = null, 125 | $customstyles = '', 126 | $specialclass = '' 127 | ) { 128 | 129 | $this->index = 0; 130 | $this->section = $section; 131 | $this->content = $content; 132 | $this->link = $link; 133 | $this->title = $title; 134 | $this->availablemessage = $availablemessage; 135 | $this->customstyles = $customstyles; 136 | $this->specialclass = $specialclass; 137 | 138 | $this->childs = new \format_onetopic\tabs(); 139 | } 140 | 141 | /** 142 | * Add a child or sub tab. 143 | * 144 | * @param \format_onetopic\singletab $child A subtab of current tab. 145 | */ 146 | public function add_child(singletab $child) { 147 | $child->parenttab = $this; 148 | $this->childs->add($child); 149 | } 150 | 151 | /** 152 | * Check if current tab has sub tabs. 153 | * 154 | * @return boolean True: If has sub tabs. 155 | */ 156 | public function has_childs() { 157 | return $this->childs->has_tabs(); 158 | } 159 | 160 | /** 161 | * Count the sub tabs. 162 | * 163 | * @return int Amount of sub tabs. 164 | */ 165 | public function count_childs() { 166 | return $this->childs->count_tabs(); 167 | } 168 | 169 | /** 170 | * To get the sub tabs list. 171 | * 172 | * @return \format_onetopic\tabs The sub tabs list object. 173 | */ 174 | public function get_childs() { 175 | return $this->childs; 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /templates/header.mustache: -------------------------------------------------------------------------------- 1 | {{! 2 | This file is part of Moodle - http://moodle.org/ 3 | 4 | Moodle is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Moodle is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Moodle. If not, see . 16 | }} 17 | {{! 18 | @template format_onetopic/header 19 | 20 | Example context (json): 21 | { 22 | "uniqid": "course-1", 23 | "title": "Course 1", 24 | "initialsection": { 25 | "num": 0, 26 | "id": 34, 27 | "cmlist": { 28 | "cms": [ 29 | { 30 | "cmitem": { 31 | "cmformat": { 32 | "cmname": "Forum example", 33 | "hasname": "true" 34 | }, 35 | "cmid": 3, 36 | "id": 3, 37 | "anchor": "module-3", 38 | "module": "forum", 39 | "extraclasses": "newmessages" 40 | } 41 | } 42 | ], 43 | "hascms": true 44 | }, 45 | "iscurrent": true, 46 | "summary": { 47 | "summarytext": "Summary text!" 48 | } 49 | }, 50 | "hasformatmsgs": "true", 51 | "formatmsgs": [{ 52 | "message": "This course uses the onetopic format." 53 | }], 54 | "format": "onetopic", 55 | "templatetopic": "true", 56 | "withicons": "true", 57 | "testing": true 58 | } 59 | }} 60 | 61 |
62 |

{{{title}}}

63 | {{{completionhelp}}} 64 | 65 | {{#hasformatmsgs}} 66 | {{#formatmsgs}} 67 | {{>core/notification_info}} 68 | {{/formatmsgs}} 69 | {{/hasformatmsgs}} 70 | 71 | {{#initialsection}} 72 |
73 |
74 |
    75 | {{$ format_onetopic/local/content/section }} 76 | {{> format_onetopic/local/content/section }} 77 | {{/ format_onetopic/local/content/section }} 78 |
79 |
80 |
81 | {{/initialsection}} 82 | 83 | {{#hidetabsbar}} 84 |
85 | {{#str}} hiddentabsbar, format_onetopic {{/str}} 86 |
87 | {{/hidetabsbar}} 88 | 89 |
90 | {{#cssstyles}} 91 | 94 | {{/cssstyles}} 95 | 96 | {{#hastopictabs}} 97 |
98 | 99 | {{{courseindex}}} 100 | 101 | {{^courseindex}} 102 | {{>format_onetopic/courseformat/tabtree}} 103 | {{/courseindex}} 104 |
105 | {{/hastopictabs}} 106 | 107 |
110 | 111 | {{#hassecondrow}} 112 | {{#secondrow}} 113 | {{>format_onetopic/courseformat/tabtree}} 114 | {{/secondrow}} 115 |
117 | {{/hassecondrow}} 118 | 119 |
{{! Used in order to break the div wraped in output.course_content_header }} 120 | 121 | {{#testing}} 122 | {{#hassecondrow}} 123 |
124 | {{/hassecondrow}} 125 |
126 | {{! End of onetopic-tab-body box. }} 127 |
128 |
129 |
130 | {{/testing}} 131 | 132 | -------------------------------------------------------------------------------- /.github/workflows/moodle-ci.yml: -------------------------------------------------------------------------------- 1 | # Copied from https://github.com/moodlehq/moodle-plugin-ci/blob/master/gha.dist.yml 2 | 3 | name: Moodle Plugin CI 4 | 5 | on: [push, pull_request] 6 | 7 | jobs: 8 | test: 9 | runs-on: ubuntu-latest 10 | 11 | services: 12 | postgres: 13 | image: postgres:14 14 | env: 15 | POSTGRES_USER: 'postgres' 16 | POSTGRES_HOST_AUTH_METHOD: 'trust' 17 | ports: 18 | - 5432:5432 19 | options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 3 20 | mariadb: 21 | image: mariadb:10.11 # Moodle 5.0: >=10.11 22 | env: 23 | MYSQL_USER: 'root' 24 | MYSQL_ALLOW_EMPTY_PASSWORD: "true" 25 | MYSQL_CHARACTER_SET_SERVER: "utf8mb4" 26 | MYSQL_COLLATION_SERVER: "utf8mb4_unicode_ci" 27 | ports: 28 | - 3306:3306 29 | options: --health-cmd="mysqladmin ping" --health-interval 10s --health-timeout 5s --health-retries 3 30 | 31 | strategy: 32 | fail-fast: false 33 | matrix: 34 | include: 35 | # Moodle 5.0, PHP 8.2, MariaDB 36 | - php: '8.2' 37 | moodle-branch: 'MOODLE_500_STABLE' 38 | database: mariadb 39 | plugin-ci: ^4 40 | # Moodle 5.0, PHP 8.3, MariaDB 41 | - php: '8.3' 42 | moodle-branch: 'MOODLE_500_STABLE' 43 | database: mariadb 44 | plugin-ci: ^4 45 | # Moodle 5.0, PHP 8.2, PostgreSQL 46 | - php: '8.3' 47 | moodle-branch: 'MOODLE_500_STABLE' 48 | database: pgsql 49 | plugin-ci: ^4 50 | steps: 51 | - name: Check out repository code 52 | uses: actions/checkout@v4 53 | with: 54 | path: plugin 55 | 56 | - name: Setup PHP ${{ matrix.php }} 57 | uses: shivammathur/setup-php@v2 58 | with: 59 | php-version: ${{ matrix.php }} 60 | extensions: ${{ matrix.extensions }} 61 | ini-values: max_input_vars=5000 62 | # If you are not using code coverage, keep "none". Otherwise, use "pcov" (Moodle 3.10 and up) or "xdebug". 63 | # If you try to use code coverage with "none", it will fallback to phpdbg (which has known problems). 64 | coverage: none 65 | 66 | - name: Initialise moodle-plugin-ci 67 | run: | 68 | composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci ${{ matrix.plugin-ci }} 69 | echo $(cd ci/bin; pwd) >> $GITHUB_PATH 70 | echo $(cd ci/vendor/bin; pwd) >> $GITHUB_PATH 71 | sudo locale-gen en_AU.UTF-8 72 | echo "NVM_DIR=$HOME/.nvm" >> $GITHUB_ENV 73 | 74 | - name: Install moodle-plugin-ci 75 | run: | 76 | moodle-plugin-ci install --plugin ./plugin --db-host=127.0.0.1 77 | env: 78 | DB: ${{ matrix.database }} 79 | MOODLE_BRANCH: ${{ matrix.moodle-branch }} 80 | # Uncomment this to run Behat tests using the Moodle App. 81 | # MOODLE_APP: 'true' 82 | 83 | - name: PHP Lint 84 | if: ${{ !cancelled() }} 85 | run: moodle-plugin-ci phplint 86 | 87 | - name: PHP Mess Detector 88 | continue-on-error: true # This step will show errors but will not fail 89 | if: ${{ !cancelled() }} 90 | run: moodle-plugin-ci phpmd 91 | 92 | - name: Moodle Code Checker 93 | if: ${{ !cancelled() }} 94 | run: moodle-plugin-ci phpcs --max-warnings 0 95 | 96 | - name: Moodle PHPDoc Checker 97 | if: ${{ !cancelled() }} 98 | run: moodle-plugin-ci phpdoc --max-warnings 0 99 | 100 | - name: Validating 101 | if: ${{ !cancelled() }} 102 | run: moodle-plugin-ci validate 103 | 104 | - name: Check upgrade savepoints 105 | if: ${{ !cancelled() }} 106 | run: moodle-plugin-ci savepoints 107 | 108 | - name: Mustache Lint 109 | if: ${{ !cancelled() }} 110 | run: moodle-plugin-ci mustache 111 | 112 | - name: Grunt 113 | if: ${{ !cancelled() }} 114 | run: moodle-plugin-ci grunt --max-lint-warnings 0 115 | 116 | - name: PHPUnit tests 117 | if: ${{ !cancelled() }} 118 | run: moodle-plugin-ci phpunit --fail-on-warning 119 | 120 | - name: Behat features 121 | id: behat 122 | if: ${{ !cancelled() }} 123 | run: moodle-plugin-ci behat --profile chrome 124 | 125 | - name: Upload Behat Faildump 126 | if: ${{ failure() && steps.behat.outcome == 'failure' }} 127 | uses: actions/upload-artifact@v4 128 | with: 129 | name: Behat Faildump (${{ join(matrix.*, ', ') }}) 130 | path: ${{ github.workspace }}/moodledata/behat_dump 131 | retention-days: 7 132 | if-no-files-found: ignore 133 | 134 | - name: Mark cancelled jobs as failed. 135 | if: ${{ cancelled() }} 136 | run: exit 1 -------------------------------------------------------------------------------- /changenumsections.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * This script allows the number of sections in a course to be increased or decreased. 19 | * 20 | * This script is based in the original feature created by Dan Poltawski. 21 | * 22 | * @package format_onetopic 23 | * @copyright 2021 David Herney Bernal - cirano 24 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 25 | */ 26 | 27 | require_once(__DIR__ . '/../../../config.php'); 28 | require_once($CFG->dirroot . '/course/lib.php'); 29 | 30 | $courseid = required_param('courseid', PARAM_INT); 31 | $increase = optional_param('increase', null, PARAM_BOOL); 32 | $insertsection = optional_param('insertsection', null, PARAM_INT); // Insert section at position; 0 means at the end. 33 | $numsections = optional_param('numsections', 1, PARAM_INT); // Number of sections to insert. 34 | $returnurl = optional_param('returnurl', null, PARAM_LOCALURL); // Where to return to after the action. 35 | $sectionreturn = optional_param('sectionreturn', null, PARAM_INT); // Section to return to, ignored if $returnurl is specified. 36 | $aschild = optional_param('aschild', 0, PARAM_BOOL); // It is created as child. 37 | 38 | $course = $DB->get_record('course', ['id' => $courseid], '*', MUST_EXIST); 39 | $courseformatoptions = course_get_format($course)->get_format_options(); 40 | 41 | $PAGE->set_url('/course/format/onetopic/changenumsections.php', ['courseid' => $courseid]); 42 | // Authorisation checks. 43 | require_login($course); 44 | require_capability('moodle/course:update', context_course::instance($course->id)); 45 | require_sesskey(); 46 | 47 | $desirednumsections = 0; 48 | $courseformat = course_get_format($course); 49 | $lastsectionnumber = $courseformat->get_last_section_number(); 50 | $maxsections = $courseformat->get_max_sections(); 51 | 52 | if (isset($courseformatoptions['numsections']) && $increase !== null) { 53 | $desirednumsections = $courseformatoptions['numsections'] + 1; 54 | } else if (course_get_format($course)->uses_sections() && $insertsection !== null) { 55 | // Count the sections in the course. 56 | $desirednumsections = $lastsectionnumber + $numsections; 57 | } 58 | 59 | if ($desirednumsections > $maxsections) { 60 | // Increase in number of sections is not allowed. 61 | \core\notification::warning(get_string('maxsectionslimit', 'moodle', $maxsections)); 62 | $increase = null; 63 | $insertsection = null; 64 | $numsections = 0; 65 | 66 | if (!$returnurl) { 67 | $returnurl = course_get_url($course); 68 | } 69 | } 70 | 71 | if (isset($courseformatoptions['numsections']) && $increase !== null) { 72 | if ($increase) { 73 | // Add an additional section. 74 | $courseformatoptions['numsections']++; 75 | course_create_sections_if_missing($course, $courseformatoptions['numsections']); 76 | } else { 77 | // Remove a section. 78 | $courseformatoptions['numsections']--; 79 | } 80 | 81 | // Don't go less than 0, intentionally redirect silently (for the case of 82 | // double clicks). 83 | if ($courseformatoptions['numsections'] >= 0) { 84 | update_course((object)['id' => $course->id, 85 | 'numsections' => $courseformatoptions['numsections'], ]); 86 | } 87 | if (!$returnurl) { 88 | $returnurl = course_get_url($course); 89 | } 90 | } else if (course_get_format($course)->uses_sections() && $insertsection !== null) { 91 | if ($insertsection) { 92 | // Inserting sections at any position except in the very end requires capability to move sections. 93 | require_capability('moodle/course:movesections', context_course::instance($course->id)); 94 | } 95 | $sections = []; 96 | for ($i = 0; $i < max($numsections, 1); $i++) { 97 | $section = course_create_section($course, $insertsection); 98 | $sections[] = $section; 99 | 100 | if ($aschild) { 101 | // Set level to one because it is a child tab. 102 | $courseformat->update_section_format_options(['level' => 1, 'id' => $section->id]); 103 | } 104 | } 105 | if (!$returnurl) { 106 | $returnurl = course_get_url( 107 | $course, 108 | $sections[0]->section, 109 | ($sectionreturn !== null) ? ['sr' => $sectionreturn] : [] 110 | ); 111 | } 112 | } 113 | 114 | $anchortotabstree = get_config('format_onetopic', 'anchortotabstree'); 115 | 116 | if ($anchortotabstree) { 117 | $returnurl->set_anchor('tabs-tree-start'); 118 | } 119 | 120 | // Redirect to where we were.. 121 | redirect($returnurl); 122 | -------------------------------------------------------------------------------- /amd/build/onetopicbackground.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"onetopicbackground.min.js","sources":["../src/onetopicbackground.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 .\n\n/**\n * Onetopic background selector.\n *\n * @module format_onetopic/onetopicbackground\n * @copyright 2021 David Herney Bernal - cirano\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport $ from 'jquery';\nimport ModalFactory from 'core/modal_factory';\nimport ModalSaveCancel from 'core/modal_save_cancel';\nimport ModalEvents from 'core/modal_events';\n\n/**\n * Component initialization.\n *\n * @method init\n * @param {String} controlid The control id.\n */\nexport const init = (controlid) => {\n\n var $controlinput = $('#' + controlid);\n var $control = $controlinput.parent('.backgroundpicker');\n var $controlwindow = $control.find('.backgroundpickerwindow');\n var $controlbutton = $control.find('.backgroundpickerselector');\n var $colorpickerinput = $controlwindow.find('input.form-control[type=\"text\"]');\n\n $controlinput.on('change', function() {\n var $color = $controlinput.val();\n if ($color) {\n $controlinput.css('background', $color);\n } else {\n $controlinput.css('background', '');\n }\n });\n $controlinput.trigger('change');\n\n // Initialize the modal window.\n var title = $controlwindow.attr('title');\n var buttons = [];\n buttons.save = $controlwindow.data('savelabel');\n\n var setEvents = function(modal) {\n modal.getRoot().on(ModalEvents.cancel, () => {\n modal.hide();\n });\n\n modal.getRoot().on(ModalEvents.save, () => {\n var newcolor = $colorpickerinput.val();\n var val = $controlinput.val();\n var color = readColor(val);\n if (color) {\n val = val.replace(color, newcolor);\n } else if (val.trim() === '') {\n val = newcolor;\n } else {\n val += ' ' + newcolor;\n }\n $controlinput.val(val);\n $controlinput.css('background', val);\n modal.hide();\n });\n };\n\n ModalFactory.create({\n 'title': title,\n 'body': $controlwindow,\n 'type': ModalSaveCancel.TYPE,\n 'large': true,\n 'buttons': buttons\n })\n .done(function(modal) {\n var $modalBody = modal.getBody();\n $modalBody.append($controlwindow);\n $control.data('modal', modal);\n setEvents(modal);\n });\n\n // Color picker control.\n $controlbutton.on('click', function(e) {\n e.preventDefault();\n $controlwindow.removeClass('hidden');\n var currentval = $controlinput.val();\n\n var color = readColor(currentval);\n\n $colorpickerinput.val(color);\n $control.data('modal').show();\n });\n\n};\n\n/**\n * Extracts the first color from a text string. Recognizes hexadecimal, rgba and hsla.\n *\n * @param {string} text\n * @returns\n */\nvar readColor = function(text) {\n var regexcolor = new RegExp(\n /#[0-9a-fA-F]{6}/.source\n + /|#[0-9a-fA-F]{3}/.source\n + /|rgba?\\(\\s*([0-9]{1,3}\\s*,\\s*){2}[0-9]{1,3}\\s*(,\\s*[0-9.]+\\s*)?\\)/.source\n + /|hsla?\\(\\s*([0-9]{1,3}\\s*,\\s*){2}[0-9]{1,3}\\s*(,\\s*[0-9.]+\\s*)?\\)/.source);\n\n var color = text.match(regexcolor);\n if (color) {\n color = color[0];\n }\n\n return color;\n};\n"],"names":["controlid","$controlinput","$control","parent","$controlwindow","find","$controlbutton","$colorpickerinput","on","$color","val","css","trigger","title","attr","buttons","save","data","create","ModalSaveCancel","TYPE","done","modal","getBody","append","getRoot","ModalEvents","cancel","hide","newcolor","color","readColor","replace","trim","setEvents","e","preventDefault","removeClass","currentval","show","text","regexcolor","RegExp","source","match"],"mappings":";;;;;;;gTAiCqBA,gBAEbC,eAAgB,mBAAE,IAAMD,WACxBE,SAAWD,cAAcE,OAAO,qBAChCC,eAAiBF,SAASG,KAAK,2BAC/BC,eAAiBJ,SAASG,KAAK,6BAC/BE,kBAAoBH,eAAeC,KAAK,mCAE5CJ,cAAcO,GAAG,UAAU,eACnBC,OAASR,cAAcS,MACvBD,OACAR,cAAcU,IAAI,aAAcF,QAEhCR,cAAcU,IAAI,aAAc,OAGxCV,cAAcW,QAAQ,cAGlBC,MAAQT,eAAeU,KAAK,SAC5BC,QAAU,GACdA,QAAQC,KAAOZ,eAAea,KAAK,oCAwBtBC,OAAO,OACPL,WACDT,oBACAe,2BAAgBC,YACf,UACEL,UAEdM,MAAK,SAASC,OACMA,MAAMC,UACZC,OAAOpB,gBAClBF,SAASe,KAAK,QAASK,OAhCX,SAASA,OACrBA,MAAMG,UAAUjB,GAAGkB,sBAAYC,QAAQ,KACnCL,MAAMM,UAGVN,MAAMG,UAAUjB,GAAGkB,sBAAYV,MAAM,SAC7Ba,SAAWtB,kBAAkBG,MAC7BA,IAAMT,cAAcS,MACpBoB,MAAQC,UAAUrB,KAClBoB,MACApB,IAAMA,IAAIsB,QAAQF,MAAOD,UACH,KAAfnB,IAAIuB,OACXvB,IAAMmB,SAENnB,KAAO,IAAMmB,SAEjB5B,cAAcS,IAAIA,KAClBT,cAAcU,IAAI,aAAcD,KAChCY,MAAMM,UAeVM,CAAUZ,UAIdhB,eAAeE,GAAG,SAAS,SAAS2B,GAChCA,EAAEC,iBACFhC,eAAeiC,YAAY,cACvBC,WAAarC,cAAcS,MAE3BoB,MAAQC,UAAUO,YAEtB/B,kBAAkBG,IAAIoB,OACtB5B,SAASe,KAAK,SAASsB,eAW3BR,UAAY,SAASS,UACjBC,WAAa,IAAIC,OACjB,kBAAkBC,OAChB,mBAAmBA,OACnB,oEAAoEA,OACpE,oEAAoEA,QAEtEb,MAAQU,KAAKI,MAAMH,mBACnBX,QACAA,MAAQA,MAAM,IAGXA"} -------------------------------------------------------------------------------- /classes/local/formelement_background.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | /** 18 | * Form element to select a background. 19 | * 20 | * @package format_onetopic 21 | * @copyright 2024 David Herney - https://bambuco.co 22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 | */ 24 | 25 | defined('MOODLE_INTERNAL') || die(); 26 | 27 | global $CFG; 28 | require_once($CFG->libdir . '/form/text.php'); 29 | require_once($CFG->libdir . '/adminlib.php'); 30 | 31 | /** 32 | * Display a tab styles form field. 33 | * 34 | * @package format_onetopic 35 | * @copyright 2024 David Herney - https://bambuco.co 36 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 | */ 38 | class format_onetopic_background_form_element extends MoodleQuickForm_text { 39 | use templatable_form_element { 40 | export_for_template as export_for_template_base; 41 | } 42 | 43 | /** 44 | * Constructor 45 | * 46 | * @param string $name Element name 47 | * @param mixed $label Label(s) for an element 48 | * @param mixed $attributes Either a typical HTML attribute string or an associative array. 49 | */ 50 | public function __construct($name = null, $label = null, $attributes = null) { 51 | 52 | parent::__construct($name, $label, $attributes); 53 | 54 | // The type is used to determine the template to use. 55 | // I did not find any conflict when handling a type different from the parent class but further review is needed. 56 | $this->_type = 'static'; 57 | } 58 | 59 | /** 60 | * Returns HTML for this form element. 61 | * 62 | * The uppercase in the function name needs to be ignored because it is required in the core. 63 | * 64 | * @return string 65 | */ 66 | // @codingStandardsIgnoreLine moodle.NamingConventions.ValidFunctionName.LowercaseMethod 67 | public function toHtml() { 68 | return $this->to_html(); 69 | } 70 | 71 | /** 72 | * Returns HTML for this form element. 73 | * 74 | * @return string 75 | */ 76 | public function to_html() { 77 | global $PAGE; 78 | 79 | static $loadedcounter = 0; 80 | $loadedcounter++; 81 | 82 | $colorpickerid = 'colorpicker' . $loadedcounter; 83 | $cp = new \admin_setting_configcolourpicker( 84 | $colorpickerid, 85 | get_string('colorpicker', 'format_onetopic'), 86 | get_string('colorpicker_help', 'format_onetopic'), 87 | '', 88 | ); 89 | 90 | $html = parent::toHtml(); 91 | 92 | $attrs = ['class' => 'backgroundpickerselector btn btn-secondary']; 93 | $html .= html_writer::tag('a', get_string('selectcolor', 'format_onetopic'), $attrs); 94 | 95 | $attrs = [ 96 | 'class' => 'backgroundpickerwindow hidden', 97 | 'title' => get_string('colorpicker', 'format_onetopic'), 98 | 'data-savelabel' => get_string('setcolor', 'format_onetopic'), 99 | ]; 100 | $html .= html_writer::tag('div', $cp->output_html(''), $attrs); 101 | 102 | $attrs = ['class' => 'backgroundpicker d-flex']; 103 | $html = html_writer::tag('div', $html, $attrs); 104 | 105 | $PAGE->requires->js_call_amd('format_onetopic/onetopicbackground', 'init', [$this->getAttribute('id')]); 106 | 107 | return $html; 108 | } 109 | 110 | /** 111 | * Export this element for template renderer. 112 | * 113 | * @param renderer_base $output 114 | * @return array 115 | */ 116 | public function export_for_template(renderer_base $output) { 117 | $context = $this->export_for_template_base($output); 118 | 119 | $context['html'] = $this->to_html(); 120 | 121 | $original = 'name="' . $this->getName() . '"'; 122 | $new = $original . ' class="form-control "'; 123 | $context['html'] = str_replace($original, $new, $context['html']); 124 | 125 | return $context; 126 | } 127 | 128 | /** 129 | * Check that all files have the allowed type. 130 | * 131 | * The uppercase in the function name needs to be ignored because it is required in the core. 132 | * 133 | * @param int $value Draft item id with the uploaded files. 134 | * @return string|null Validation error message or null. 135 | */ 136 | // @codingStandardsIgnoreLine moodle.NamingConventions.ValidFunctionName.LowercaseMethod 137 | public function validateSubmitValue($value) { 138 | 139 | if (empty($value)) { 140 | return; 141 | } 142 | 143 | $cleaned = clean_param($value, PARAM_NOTAGS); 144 | 145 | if ($cleaned !== $value) { 146 | return get_string('backgroundpickerinvalid', 'format_onetopic'); 147 | } 148 | 149 | return; 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /templates/local/content/section/content.mustache: -------------------------------------------------------------------------------- 1 | {{! 2 | This file is part of Moodle - http://moodle.org/ 3 | 4 | Moodle is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Moodle is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Moodle. If not, see . 16 | }} 17 | {{! 18 | @template format_onetopic/local/content/section/content 19 | 20 | The internal content of a section. 21 | 22 | Example context (json): 23 | { 24 | "num": 3, 25 | "id": 35, 26 | "controlmenu": "[tools menu]", 27 | "header": { 28 | "name": "Section title", 29 | "title": "Section title", 30 | "url": "#", 31 | "ishidden": true 32 | }, 33 | "cmlist": { 34 | "cms": [ 35 | { 36 | "cmitem": { 37 | "cmformat": { 38 | "cmname": "Forum example", 39 | "hasname": "true" 40 | }, 41 | "cmid": 3, 42 | "id": 3, 43 | "module": "forum", 44 | "anchor": "activity-3", 45 | "extraclasses": "newmessages" 46 | } 47 | }, 48 | { 49 | "cmitem": { 50 | "cmformat": { 51 | "cmname": "Assign example", 52 | "hasname": "true" 53 | }, 54 | "cmid": 4, 55 | "id": 4, 56 | "anchor": "activity-4", 57 | "module": "assign", 58 | "extraclasses": "" 59 | } 60 | } 61 | ], 62 | "hascms": true 63 | }, 64 | "ishidden": false, 65 | "iscurrent": true, 66 | "currentlink": "This topic", 67 | "availability": { 68 | "info": "Hidden from students", 69 | "hasavailability": true 70 | }, 71 | "summary": { 72 | "summarytext": "Summary text!" 73 | }, 74 | "controlmenu": { 75 | "menu": "Edit", 76 | "hasmenu": true 77 | }, 78 | "cmcontrols": "[Add an activity or resource]", 79 | "iscoursedisplaymultipage": true, 80 | "sectionreturnid": 0, 81 | "contentcollapsed": false, 82 | "insertafter": true, 83 | "numsections": 42, 84 | "sitehome": false, 85 | "highlightedlabel" : "Highlighted" 86 | } 87 | }} 88 | {{#collapsemenu}} 89 | {{^displayonesection}} 90 | 103 | {{/displayonesection}} 104 | {{/collapsemenu}} 105 | 106 |
108 |
109 | {{#availability}} 110 | {{$ core_courseformat/local/content/section/availability }} 111 | {{> core_courseformat/local/content/section/availability }} 112 | {{/ core_courseformat/local/content/section/availability }} 113 | {{/availability}} 114 | {{#summary}} 115 | {{$ core_courseformat/local/content/section/summary }} 116 | {{> core_courseformat/local/content/section/summary }} 117 | {{/ core_courseformat/local/content/section/summary }} 118 | {{/summary}} 119 |
120 | {{#cmsummary}} 121 | {{$ core_courseformat/local/content/section/cmsummary }} 122 | {{> core_courseformat/local/content/section/cmsummary }} 123 | {{/ core_courseformat/local/content/section/cmsummary }} 124 | {{/cmsummary}} 125 | {{#cmlist}} 126 | {{$ core_courseformat/local/content/section/cmlist }} 127 | {{> core_courseformat/local/content/section/cmlist }} 128 | {{/ core_courseformat/local/content/section/cmlist }} 129 | {{/cmlist}} 130 | {{{cmcontrols}}} 131 |
-------------------------------------------------------------------------------- /templates/local/content/section.mustache: -------------------------------------------------------------------------------- 1 | {{! 2 | This file is part of Moodle - http://moodle.org/ 3 | 4 | Moodle is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Moodle is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Moodle. If not, see . 16 | }} 17 | {{! 18 | @template format_onetopic/local/content/section 19 | 20 | Displays a course section. 21 | 22 | Note: This template is a wrapper around the section/content template to allow course formats and theme designers to 23 | modify parts of the wrapper without having to copy/paste the entire template. 24 | 25 | Example context (json): 26 | { 27 | "num": 3, 28 | "id": 35, 29 | "controlmenu": "[tools menu]", 30 | "header": { 31 | "name": "Section title", 32 | "title": "Section title", 33 | "url": "#", 34 | "ishidden": true 35 | }, 36 | "cmlist": { 37 | "cms": [ 38 | { 39 | "cmitem": { 40 | "cmformat": { 41 | "cmname": "Forum example", 42 | "hasname": "true" 43 | }, 44 | "cmid": 3, 45 | "id": 3, 46 | "module": "forum", 47 | "anchor": "activity-3", 48 | "extraclasses": "newmessages" 49 | } 50 | }, 51 | { 52 | "cmitem": { 53 | "cmformat": { 54 | "cmname": "Assign example", 55 | "hasname": "true" 56 | }, 57 | "cmid": 4, 58 | "id": 4, 59 | "anchor": "activity-4", 60 | "module": "assign", 61 | "extraclasses": "" 62 | } 63 | } 64 | ], 65 | "hascms": true 66 | }, 67 | "ishidden": false, 68 | "iscurrent": true, 69 | "currentlink": "This topic", 70 | "availability": { 71 | "info": "Hidden from students", 72 | "hasavailability": true 73 | }, 74 | "summary": { 75 | "summarytext": "Summary text!" 76 | }, 77 | "controlmenu": { 78 | "menu": "Edit", 79 | "hasmenu": true 80 | }, 81 | "cmcontrols": "[Add an activity or resource]", 82 | "iscoursedisplaymultipage": true, 83 | "sectionreturnid": 0, 84 | "contentcollapsed": false, 85 | "insertafter": true, 86 | "numsections": 42, 87 | "sitehome": false, 88 | "highlightedlabel" : "Highlighted", 89 | "testingsection": true 90 | } 91 | }} 92 | {{#testingsection}}
    {{/testingsection}} 93 | 139 | {{#testingsection}}
{{/testingsection}} 140 | -------------------------------------------------------------------------------- /classes/output/renderer.php: -------------------------------------------------------------------------------- 1 | . 16 | 17 | namespace format_onetopic\output; 18 | 19 | use core_courseformat\output\section_renderer; 20 | use moodle_page; 21 | 22 | /** 23 | * Basic renderer for topics format. 24 | * 25 | * @package format_onetopic 26 | * @copyright 2022 David Herney Bernal - cirano 27 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 28 | */ 29 | class renderer extends section_renderer { 30 | /** 31 | * Constructor method, calls the parent constructor. 32 | * 33 | * @param moodle_page $page 34 | * @param string $target one of rendering target constants 35 | */ 36 | public function __construct(moodle_page $page, $target) { 37 | parent::__construct($page, $target); 38 | 39 | // Since format_topics_renderer::section_edit_control_items() only displays the 'Highlight' control 40 | // when editing mode is on we need to be sure that the link 'Turn editing mode on' is available for a user 41 | // who does not have any other managing capability. 42 | $page->set_other_editing_capability('moodle/course:setcurrentsection'); 43 | } 44 | 45 | /** 46 | * Renders the provided widget and returns the HTML to display it. 47 | * 48 | * Course format templates uses a similar subfolder structure to the renderable classes. 49 | * This method find out the specific template for a course widget. That's the reason why 50 | * this render method is different from the normal plugin renderer one. 51 | * 52 | * course format templatables can be rendered using the core_course/local/* templates. 53 | * Format plugins are free to override the default template location using render_xxx methods as usual. 54 | * 55 | * @param \renderable $widget instance with renderable interface 56 | * @return string the widget HTML 57 | */ 58 | public function render(\renderable $widget) { 59 | global $CFG; 60 | $fullpath = str_replace('\\', '/', get_class($widget)); 61 | 62 | // Check for special course format templatables. 63 | if ($widget instanceof \templatable) { 64 | // Templatables from both core_courseformat\output\local\* and format_onetopic\output\courseformat\* 65 | // use format_onetopic/local/* templates, if they exist. 66 | $corepath = 'core_courseformat\/output\/local'; 67 | $pluginpath = 'format_onetopic\/output\/courseformat'; 68 | $specialrenderers = '/^(?' . $corepath . '|' . $pluginpath . ')\/(?