mirror of
https://github.com/moodle/moodle.git
synced 2025-04-21 16:32:18 +02:00
MDL-83869 output: new collapsable section component
This commit is contained in:
parent
a2653cc924
commit
46318e53d0
9
.upgradenotes/MDL-83869-2025011609294854.yml
Normal file
9
.upgradenotes/MDL-83869-2025011609294854.yml
Normal file
@ -0,0 +1,9 @@
|
||||
issueNumber: MDL-83869
|
||||
notes:
|
||||
core:
|
||||
- message: >
|
||||
New generic collapsable section output added. Use
|
||||
core\output\local\collapsable_section or include the
|
||||
core/local/collapsable_section template to use it. See the full
|
||||
documentation in the component library.
|
||||
type: improved
|
19
lib/amd/build/local/collapsable_section/controls.min.js
vendored
Normal file
19
lib/amd/build/local/collapsable_section/controls.min.js
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
define("core/local/collapsable_section/controls",["exports","core/local/collapsable_section/events","jquery"],(function(_exports,_events,_jquery){var obj;
|
||||
/**
|
||||
* The collapsable sections controls.
|
||||
*
|
||||
* @module core/local/collapsable_section/controls
|
||||
* @copyright 2024 Ferran Recio <ferran@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*
|
||||
* @example <caption>Example of controlling a collapsable section.</caption>
|
||||
*
|
||||
* import CollapsableSection from 'core/local/collapsable_section/controls';
|
||||
*
|
||||
* const section = CollapsableSection.instanceFromSelector('#MyCollapsableSection');
|
||||
*
|
||||
* // Use hide, show and toggle methods to control the section.
|
||||
* section.hide();
|
||||
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_jquery=(obj=_jquery)&&obj.__esModule?obj:{default:obj};let initialized=!1;return _exports.default=class{static instanceFromSelector(selector){const elements=document.querySelector(selector);if(!elements)throw new Error("No elements found with the selector: "+selector);return new this(elements)}static init(){initialized||(initialized=!0,(0,_jquery.default)(document).on(_events.eventTypes.hiddenBsCollapse,(event=>{this.isCollapsableComponent(event.target)&&(0,_events.notifyCollapsableSectionHidden)(event.target)})),(0,_jquery.default)(document).on(_events.eventTypes.shownBsCollapse,(event=>{this.isCollapsableComponent(event.target)&&(0,_events.notifyCollapsableSectionShown)(event.target)})))}static isCollapsableComponent(element){return element.hasAttribute("data-mdl-component")&&"core/local/collapsable_section"===element.getAttribute("data-mdl-component")}constructor(element){this.element=element}hide(){(0,_jquery.default)(this.element).collapse("hide")}show(){(0,_jquery.default)(this.element).collapse("show")}toggle(){(0,_jquery.default)(this.element).collapse("toggle")}isVisible(){return this.element.classList.contains("show")}},_exports.default}));
|
||||
|
||||
//# sourceMappingURL=controls.min.js.map
|
File diff suppressed because one or more lines are too long
20
lib/amd/build/local/collapsable_section/events.min.js
vendored
Normal file
20
lib/amd/build/local/collapsable_section/events.min.js
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
define("core/local/collapsable_section/events",["exports","core/event_dispatcher"],(function(_exports,_event_dispatcher){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.notifyCollapsableSectionShown=_exports.notifyCollapsableSectionHidden=_exports.eventTypes=void 0;
|
||||
/**
|
||||
* The collapsable section events.
|
||||
*
|
||||
* This module wraps the standard bootstrap collapsable events, but for collapsable sections.
|
||||
*
|
||||
* @module core/local/collapsable_section/events
|
||||
* @copyright 2024 Ferran Recio <ferran@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*
|
||||
* @example <caption>Example of listening to a collapsable section events.</caption>
|
||||
* import {eventTypes as collapsableSectionEventTypes} from 'core/local/collapsable_section/events';
|
||||
*
|
||||
* document.addEventListener(collapsableSectionEventTypes.shown, event => {
|
||||
* window.console.log(event.target); // The HTMLElement relating to the block whose content was updated.
|
||||
* });
|
||||
*/
|
||||
const eventTypes={shown:"core_collapsable_section_shown",hidden:"core_collapsable_section_hidden",hideBsCollapse:"hide.bs.collapse",hiddenBsCollapse:"hidden.bs.collapse",showBsCollapse:"show.bs.collapse",shownBsCollapse:"shown.bs.collapse"};_exports.eventTypes=eventTypes;_exports.notifyCollapsableSectionShown=element=>(0,_event_dispatcher.dispatchEvent)(eventTypes.shown,{},element);_exports.notifyCollapsableSectionHidden=element=>(0,_event_dispatcher.dispatchEvent)(eventTypes.hidden,{},element)}));
|
||||
|
||||
//# sourceMappingURL=events.min.js.map
|
@ -0,0 +1 @@
|
||||
{"version":3,"file":"events.min.js","sources":["../../../src/local/collapsable_section/events.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * The collapsable section events.\n *\n * This module wraps the standard bootstrap collapsable events, but for collapsable sections.\n *\n * @module core/local/collapsable_section/events\n * @copyright 2024 Ferran Recio <ferran@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n *\n * @example <caption>Example of listening to a collapsable section events.</caption>\n * import {eventTypes as collapsableSectionEventTypes} from 'core/local/collapsable_section/events';\n *\n * document.addEventListener(collapsableSectionEventTypes.shown, event => {\n * window.console.log(event.target); // The HTMLElement relating to the block whose content was updated.\n * });\n */\n\nimport {dispatchEvent} from 'core/event_dispatcher';\n\n/**\n * Events for `core_block`.\n *\n * @constant\n * @property {String} blockContentUpdated See {@link event:blockContentUpdated}\n */\nexport const eventTypes = {\n /**\n * An event triggered when the content of a block has changed.\n *\n * @event blockContentUpdated\n * @type {CustomEvent}\n * @property {HTMLElement} target The block element that was updated\n * @property {object} detail\n * @property {number} detail.instanceId The block instance id\n */\n shown: 'core_collapsable_section_shown',\n hidden: 'core_collapsable_section_hidden',\n // All Bootstrap 4 jQuery events are wrapped while MDL-71979 is not integrated.\n hideBsCollapse: 'hide.bs.collapse',\n hiddenBsCollapse: 'hidden.bs.collapse',\n showBsCollapse: 'show.bs.collapse',\n shownBsCollapse: 'shown.bs.collapse',\n};\n\n/**\n * Trigger an event to indicate that the content of a block was updated.\n *\n * @method notifyBlockContentUpdated\n * @param {HTMLElement} element The HTMLElement containing the updated block.\n * @returns {CustomEvent}\n * @fires blockContentUpdated\n */\nexport const notifyCollapsableSectionShown = element => dispatchEvent(\n eventTypes.shown,\n {},\n element\n);\n\n/**\n * Trigger an event to indicate that the content of a block was updated.\n *\n * @method notifyBlockContentUpdated\n * @param {HTMLElement} element The HTMLElement containing the updated block.\n * @returns {CustomEvent}\n * @fires blockContentUpdated\n */\nexport const notifyCollapsableSectionHidden = element => dispatchEvent(\n eventTypes.hidden,\n {},\n element\n);\n"],"names":["eventTypes","shown","hidden","hideBsCollapse","hiddenBsCollapse","showBsCollapse","shownBsCollapse","element"],"mappings":";;;;;;;;;;;;;;;;;MAwCaA,WAAa,CAUtBC,MAAO,iCACPC,OAAQ,kCAERC,eAAgB,mBAChBC,iBAAkB,qBAClBC,eAAgB,mBAChBC,gBAAiB,2FAWwBC,UAAW,mCACpDP,WAAWC,MACX,GACAM,iDAW0CA,UAAW,mCACrDP,WAAWE,OACX,GACAK"}
|
138
lib/amd/src/local/collapsable_section/controls.js
vendored
Normal file
138
lib/amd/src/local/collapsable_section/controls.js
vendored
Normal file
@ -0,0 +1,138 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The collapsable sections controls.
|
||||
*
|
||||
* @module core/local/collapsable_section/controls
|
||||
* @copyright 2024 Ferran Recio <ferran@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*
|
||||
* @example <caption>Example of controlling a collapsable section.</caption>
|
||||
*
|
||||
* import CollapsableSection from 'core/local/collapsable_section/controls';
|
||||
*
|
||||
* const section = CollapsableSection.instanceFromSelector('#MyCollapsableSection');
|
||||
*
|
||||
* // Use hide, show and toggle methods to control the section.
|
||||
* section.hide();
|
||||
*/
|
||||
|
||||
import {
|
||||
eventTypes,
|
||||
notifyCollapsableSectionHidden,
|
||||
notifyCollapsableSectionShown
|
||||
} from 'core/local/collapsable_section/events';
|
||||
|
||||
// The jQuery module is only used for interacting with Boostrap 4. It can we removed when MDL-71979 is integrated.
|
||||
import jQuery from 'jquery';
|
||||
|
||||
let initialized = false;
|
||||
|
||||
export default class {
|
||||
/**
|
||||
* Create a new instance from a query selector.
|
||||
*
|
||||
* @param {String} selector The selector of the collapsable section.
|
||||
* @return {CollapsableSection} The collapsable section controls.
|
||||
* @throws {Error} If no elements are found with the selector.
|
||||
*/
|
||||
static instanceFromSelector(selector) {
|
||||
const elements = document.querySelector(selector);
|
||||
if (!elements) {
|
||||
throw new Error('No elements found with the selector: ' + selector);
|
||||
}
|
||||
return new this(elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the collapsable section controls.
|
||||
*/
|
||||
static init() {
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
initialized = true;
|
||||
|
||||
// We want to add extra events to the standard bootstrap collapsable events.
|
||||
// TODO: change all jquery events to custom events once MDL-71979 is integrated.
|
||||
jQuery(document).on(eventTypes.hiddenBsCollapse, event => {
|
||||
if (!this.isCollapsableComponent(event.target)) {
|
||||
return;
|
||||
}
|
||||
notifyCollapsableSectionHidden(event.target);
|
||||
});
|
||||
jQuery(document).on(eventTypes.shownBsCollapse, event => {
|
||||
if (!this.isCollapsableComponent(event.target)) {
|
||||
return;
|
||||
}
|
||||
notifyCollapsableSectionShown(event.target);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the element is a collapsable section.
|
||||
*
|
||||
* @private
|
||||
* @param {HTMLElement} element The element to check.
|
||||
* @return {boolean} True if the element is a collapsable section.
|
||||
*/
|
||||
static isCollapsableComponent(element) {
|
||||
return element.hasAttribute('data-mdl-component')
|
||||
&& element.getAttribute('data-mdl-component') === 'core/local/collapsable_section';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of the controls for a collapsable section.
|
||||
*
|
||||
* @param {HTMLElement} element - The DOM element that this control will manage.
|
||||
*/
|
||||
constructor(element) {
|
||||
this.element = element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides the collapsible section element.
|
||||
*/
|
||||
hide() {
|
||||
// TODO: change all jquery once MDL-71979 is integrated.
|
||||
jQuery(this.element).collapse('hide');
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the collapsible section element.
|
||||
*/
|
||||
show() {
|
||||
// TODO: change all jquery once MDL-71979 is integrated.
|
||||
jQuery(this.element).collapse('show');
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the collapsible section element.
|
||||
*/
|
||||
toggle() {
|
||||
// TODO: change all jquery once MDL-71979 is integrated.
|
||||
jQuery(this.element).collapse('toggle');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the collapsable section is visible.
|
||||
*
|
||||
* @return {boolean} True if the collapsable section is visible.
|
||||
*/
|
||||
isVisible() {
|
||||
return this.element.classList.contains('show');
|
||||
}
|
||||
}
|
86
lib/amd/src/local/collapsable_section/events.js
Normal file
86
lib/amd/src/local/collapsable_section/events.js
Normal file
@ -0,0 +1,86 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The collapsable section events.
|
||||
*
|
||||
* This module wraps the standard bootstrap collapsable events, but for collapsable sections.
|
||||
*
|
||||
* @module core/local/collapsable_section/events
|
||||
* @copyright 2024 Ferran Recio <ferran@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*
|
||||
* @example <caption>Example of listening to a collapsable section events.</caption>
|
||||
* import {eventTypes as collapsableSectionEventTypes} from 'core/local/collapsable_section/events';
|
||||
*
|
||||
* document.addEventListener(collapsableSectionEventTypes.shown, event => {
|
||||
* window.console.log(event.target); // The HTMLElement relating to the block whose content was updated.
|
||||
* });
|
||||
*/
|
||||
|
||||
import {dispatchEvent} from 'core/event_dispatcher';
|
||||
|
||||
/**
|
||||
* Events for `core_block`.
|
||||
*
|
||||
* @constant
|
||||
* @property {String} blockContentUpdated See {@link event:blockContentUpdated}
|
||||
*/
|
||||
export const eventTypes = {
|
||||
/**
|
||||
* An event triggered when the content of a block has changed.
|
||||
*
|
||||
* @event blockContentUpdated
|
||||
* @type {CustomEvent}
|
||||
* @property {HTMLElement} target The block element that was updated
|
||||
* @property {object} detail
|
||||
* @property {number} detail.instanceId The block instance id
|
||||
*/
|
||||
shown: 'core_collapsable_section_shown',
|
||||
hidden: 'core_collapsable_section_hidden',
|
||||
// All Bootstrap 4 jQuery events are wrapped while MDL-71979 is not integrated.
|
||||
hideBsCollapse: 'hide.bs.collapse',
|
||||
hiddenBsCollapse: 'hidden.bs.collapse',
|
||||
showBsCollapse: 'show.bs.collapse',
|
||||
shownBsCollapse: 'shown.bs.collapse',
|
||||
};
|
||||
|
||||
/**
|
||||
* Trigger an event to indicate that the content of a block was updated.
|
||||
*
|
||||
* @method notifyBlockContentUpdated
|
||||
* @param {HTMLElement} element The HTMLElement containing the updated block.
|
||||
* @returns {CustomEvent}
|
||||
* @fires blockContentUpdated
|
||||
*/
|
||||
export const notifyCollapsableSectionShown = element => dispatchEvent(
|
||||
eventTypes.shown,
|
||||
{},
|
||||
element
|
||||
);
|
||||
|
||||
/**
|
||||
* Trigger an event to indicate that the content of a block was updated.
|
||||
*
|
||||
* @method notifyBlockContentUpdated
|
||||
* @param {HTMLElement} element The HTMLElement containing the updated block.
|
||||
* @returns {CustomEvent}
|
||||
* @fires blockContentUpdated
|
||||
*/
|
||||
export const notifyCollapsableSectionHidden = element => dispatchEvent(
|
||||
eventTypes.hidden,
|
||||
{},
|
||||
element
|
||||
);
|
147
lib/classes/output/local/collapsable_section.php
Normal file
147
lib/classes/output/local/collapsable_section.php
Normal file
@ -0,0 +1,147 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace core\output\local;
|
||||
|
||||
use core\output\named_templatable;
|
||||
use core\output\renderable;
|
||||
|
||||
/**
|
||||
* Collapsable section output.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2024 Ferran Recio <ferran@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class collapsable_section implements named_templatable, renderable {
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $titlecontent The content to be displayed inside the button.
|
||||
* @param string $sectioncontent The content to be displayed inside the dialog.
|
||||
* @param string $classes Additional CSS classes to be applied to the section.
|
||||
* @param array $extras An attribute => value array to be added to the element.
|
||||
* @param bool $open If the section is opened by default.
|
||||
* @param string|null $expandlabel The label for the expand button.
|
||||
* @param string|null $collapselabel The label for the collapse button.
|
||||
*/
|
||||
public function __construct(
|
||||
/** @var string $titlecontent The content to be displayed inside the button. */
|
||||
protected string $titlecontent,
|
||||
/** @var string $sectioncontent The content to be displayed inside the dialog. */
|
||||
protected string $sectioncontent,
|
||||
/** @var string $classes Additional CSS classes to be applied to the section. */
|
||||
protected string $classes = '',
|
||||
/** @var array $extras A attribute => value array to be added to the element. */
|
||||
protected array $extras = [],
|
||||
/** @var bool $open if the section is opened by default. */
|
||||
protected bool $open = false,
|
||||
/** @var string|null $expandlabel The label for the expand button. */
|
||||
protected string|null $expandlabel = null,
|
||||
/** @var string|null $collapselabel The label for the collapse button. */
|
||||
protected string|null $collapselabel = null,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the title content.
|
||||
*
|
||||
* @param string $titlecontent
|
||||
*/
|
||||
public function set_title_content(string $titlecontent) {
|
||||
$this->titlecontent = $titlecontent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the content for the collapsable section.
|
||||
*
|
||||
* @param string $sectioncontent The content to be set for the section.
|
||||
*/
|
||||
public function set_section_content(string $sectioncontent) {
|
||||
$this->sectioncontent = $sectioncontent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the CSS classes for the collapsable section.
|
||||
*
|
||||
* @param string $classes The CSS classes to be applied to the collapsable section.
|
||||
*/
|
||||
public function set_classes(string $classes) {
|
||||
$this->classes = $classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the provided extras array with the existing extras array.
|
||||
*
|
||||
* @param array $extras The array of extra attributes => extra value.
|
||||
*/
|
||||
public function add_extra_attributes(array $extras) {
|
||||
$this->extras = array_merge($this->extras, $extras);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default open state of the collapsible section.
|
||||
*
|
||||
* @param bool $open
|
||||
*/
|
||||
public function set_open(bool $open) {
|
||||
$this->open = $open;
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function export_for_template(\renderer_base $output): array {
|
||||
$elementid = $this->extras['id'] ?? \html_writer::random_id('collapsableSection_');
|
||||
|
||||
$data = [
|
||||
'titlecontent' => $this->titlecontent,
|
||||
'sectioncontent' => $this->sectioncontent,
|
||||
'classes' => $this->classes,
|
||||
'extras' => $this->export_extras(),
|
||||
'elementid' => $elementid,
|
||||
];
|
||||
if ($this->open) {
|
||||
$data['open'] = 'true';
|
||||
}
|
||||
if ($this->expandlabel) {
|
||||
$data['expandlabel'] = $this->expandlabel;
|
||||
}
|
||||
if ($this->collapselabel) {
|
||||
$data['collapselabel'] = $this->collapselabel;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports the extras as an array of attribute-value pairs.
|
||||
*
|
||||
* @return array An array of associative arrays, each containing 'attribute' and 'value' keys.
|
||||
*/
|
||||
private function export_extras(): array {
|
||||
$extras = [];
|
||||
foreach ($this->extras as $attribute => $value) {
|
||||
$extras[] = [
|
||||
'attribute' => $attribute,
|
||||
'value' => $value,
|
||||
];
|
||||
}
|
||||
return $extras;
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function get_template_name(\renderer_base $renderer): string {
|
||||
return 'core/local/collapsable_section';
|
||||
}
|
||||
}
|
147
lib/templates/local/collapsable_section.mustache
Normal file
147
lib/templates/local/collapsable_section.mustache
Normal file
@ -0,0 +1,147 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template core/local/collapsable_section
|
||||
|
||||
Standard collapsible section.
|
||||
|
||||
Optional blocks:
|
||||
* extraclasses - additional classes.
|
||||
* elementid - optional element id.
|
||||
* titlecontent - the collpasible title content.
|
||||
* sectioncontent - the collapsible content.
|
||||
* extras - custom HTML attributes for the component.
|
||||
* expandlabel - the label for the expand icon.
|
||||
* collapselabel - the label for the collapse icon.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"titlecontent": "New content",
|
||||
"sectioncontent": "New content",
|
||||
"classes": "someclass",
|
||||
"extras": [
|
||||
{
|
||||
"attribute": "data-example",
|
||||
"value": "something"
|
||||
}
|
||||
],
|
||||
"open": true,
|
||||
"expandlabel": "Expand",
|
||||
"collapselabel": "Collapse",
|
||||
"elementid": "someuniqueid"
|
||||
}
|
||||
}}
|
||||
<div
|
||||
class="collapsable-section mb-3 {{!
|
||||
}} {{$ extraclasses }} {{!
|
||||
}} {{#classes}} {{classes}} {{/classes}} {{!
|
||||
}} {{/ extraclasses }}"
|
||||
id="{{$ elementid }}{{!
|
||||
}}{{#elementid}}collapsable_section_{{elementid}}{{/elementid}}{{!
|
||||
}}{{^elementid}}collapsable_section_{{uniqid}}{{/elementid}}{{!
|
||||
}}{{/ elementid }}_collapsible"
|
||||
>
|
||||
<div class="d-flex">
|
||||
<div class="d-flex align-items-center position-relative">
|
||||
<a
|
||||
role="button"
|
||||
data-toggle="collapse"
|
||||
href="#{{$ elementid }}{{!
|
||||
}}{{#elementid}}{{elementid}}{{/elementid}}{{!
|
||||
}}{{^elementid}}collapsable_{{uniqid}}{{/elementid}}{{!
|
||||
}}{{/ elementid }}"
|
||||
{{#open}} aria-expanded="true" {{/open}}
|
||||
{{^open}} aria-expanded="false" {{/open}}
|
||||
aria-controls="{{$ elementid }}{{!
|
||||
}}{{#elementid}}{{elementid}}{{/elementid}}{{!
|
||||
}}{{^elementid}}collapsable_{{uniqid}}{{/elementid}}{{!
|
||||
}}{{/ elementid }}"
|
||||
class="btn btn-icon me-3 icons-collapse-expand justify-content-center {{!
|
||||
}} {{^open}} collapsed {{/open}}"
|
||||
>
|
||||
<span
|
||||
class="collapsed-icon icon-no-margin me-1"
|
||||
title="{{!
|
||||
}}{{$ expandlabel }}{{!
|
||||
}}{{#expandlabel}}{{expandlabel}}{{/expandlabel}}{{!
|
||||
}}{{^expandlabel}}{{#str}} expand, core {{/str}}{{/expandlabel}}{{!
|
||||
}}{{/ expandlabel }}{{!
|
||||
}}"
|
||||
>
|
||||
<span class="dir-rtl-hide">{{#pix}} t/collapsedchevron, core {{/pix}}</span>
|
||||
<span class="dir-ltr-hide">{{#pix}} t/collapsedchevron_rtl, core {{/pix}}</span>
|
||||
<span class="sr-only">{{!
|
||||
}}{{$ expandlabel }}{{!
|
||||
}}{{#expandlabel}}{{expandlabel}}{{/expandlabel}}{{!
|
||||
}}{{^expandlabel}}{{#str}} expand, core {{/str}}{{/expandlabel}}{{!
|
||||
}}{{/ expandlabel }}{{!
|
||||
}}</span>
|
||||
</span>
|
||||
<span
|
||||
class="expanded-icon icon-no-margin me-1"
|
||||
title="{{!
|
||||
}}{{$ collapselabel }}{{!
|
||||
}}{{#collapselabel}}{{collapselabel}}{{/collapselabel}}{{!
|
||||
}}{{^collapselabel}}{{#str}} collapse, core {{/str}}{{/collapselabel}}{{!
|
||||
}}{{/ collapselabel }}{{!
|
||||
}}"
|
||||
>
|
||||
{{#pix}} t/expandedchevron, core {{/pix}}
|
||||
<span class="sr-only">{{!
|
||||
}}{{$ collapselabel }}{{!
|
||||
}}{{#collapselabel}}{{collapselabel}}{{/collapselabel}}{{!
|
||||
}}{{^collapselabel}}{{#str}} collapse, core {{/str}}{{/collapselabel}}{{!
|
||||
}}{{/ collapselabel }}{{!
|
||||
}}</span>
|
||||
</span>
|
||||
</a>
|
||||
<h3
|
||||
class="d-flex align-self-stretch align-items-center mb-0"
|
||||
id="{{$ elementid }}{{!
|
||||
}}{{#elementid}}collapsable_section_{{elementid}}{{/elementid}}{{!
|
||||
}}{{^elementid}}collapsable_section_{{uniqid}}{{/elementid}}{{!
|
||||
}}{{/ elementid }}_title"
|
||||
>
|
||||
{{$ titlecontent }}
|
||||
{{{titlecontent}}}
|
||||
{{/ titlecontent }}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
id="{{$ elementid }}{{!
|
||||
}}{{#elementid}}{{elementid}}{{/elementid}}{{!
|
||||
}}{{^elementid}}collapsable_{{uniqid}}{{/elementid}}{{!
|
||||
}}{{/ elementid }}"
|
||||
class="content collapse {{#open}}show{{/open}} pt-3"
|
||||
data-mdl-component="core/local/collapsable_section"
|
||||
{{$ extras }}
|
||||
{{#extras}}
|
||||
{{attribute}}="{{value}}"
|
||||
{{/extras}}
|
||||
{{/ extras }}
|
||||
>
|
||||
{{$ sectioncontent }}
|
||||
{{{sectioncontent}}}
|
||||
{{/ sectioncontent }}
|
||||
</div>
|
||||
</div>
|
||||
{{#js}}
|
||||
require(['core/local/collapsable_section/controls'], function(Controls) {
|
||||
Controls.init();
|
||||
});
|
||||
{{/js}}
|
66
lib/tests/behat/collapsable_section_output.feature
Normal file
66
lib/tests/behat/collapsable_section_output.feature
Normal file
@ -0,0 +1,66 @@
|
||||
@core @javascript
|
||||
Feature: Test collapsable section output module
|
||||
In order to show extra information to the user
|
||||
As a user
|
||||
I need to interact with the collapsable section output
|
||||
|
||||
Background:
|
||||
# Get to the fixture page.
|
||||
Given I log in as "admin"
|
||||
And I am on fixture page "/lib/tests/behat/fixtures/collapsable_section_output_testpage.php"
|
||||
|
||||
Scenario: Collapsable sections can be opened and closed
|
||||
Given I should not see "Dialog content"
|
||||
And I should not see "This is the closed section content." in the "closedsection" "region"
|
||||
And I should see "This is the open section content." in the "opensection" "region"
|
||||
When I click on "Expand" "button" in the "closedsection" "region"
|
||||
And I click on "Collapse" "button" in the "opensection" "region"
|
||||
Then I should see "This is the closed section content." in the "closedsection" "region"
|
||||
And I should not see "This is the open section content." in the "opensection" "region"
|
||||
|
||||
Scenario: Collapsable sections content can have rich content inside
|
||||
When I click on "Expand" "button" in the "closedsection" "region"
|
||||
Then I should see "This is the closed section content." in the "closedsection" "region"
|
||||
And "Link" "link" should exist in the "closedsection" "region"
|
||||
And "Eye icon" "icon" should exist in the "closedsection" "region"
|
||||
|
||||
Scenario: Collapsable sections HTML attributtes can be overriden
|
||||
When I click on "Expand" "button" in the "extraclasses" "region"
|
||||
And I click on "Expand" "button" in the "extraattributes" "region"
|
||||
Then ".extraclass" "css_element" should exist in the "extraclasses" "region"
|
||||
And "[data-foo='bar']" "css_element" should exist in the "extraattributes" "region"
|
||||
And "#myid" "css_element" should exist in the "extraattributes" "region"
|
||||
|
||||
Scenario: Collapsable sections can have custom labels for expand and collapse
|
||||
When I click on "Custom expand" "button" in the "customlabels" "region"
|
||||
Then I should see "This is the custom labels content." in the "customlabels" "region"
|
||||
And I click on "Custom collapse" "button" in the "customlabels" "region"
|
||||
And I should not see "This is the custom labels content." in the "customlabels" "region"
|
||||
|
||||
Scenario: Collapsable sections can be controlled via javascript
|
||||
# Toggle.
|
||||
Given I should not see "This is the javascript controls content." in the "jscontrols" "region"
|
||||
When I click on "Toggle" "button" in the "jscontrols" "region"
|
||||
Then I should see "This is the javascript controls content." in the "jscontrols" "region"
|
||||
And I click on "Toggle" "button" in the "jscontrols" "region"
|
||||
And I should not see "This is the javascript controls content." in the "jscontrols" "region"
|
||||
# Show and Hide.
|
||||
And I click on "Show" "button" in the "jscontrols" "region"
|
||||
And I should see "This is the javascript controls content." in the "jscontrols" "region"
|
||||
And I click on "Show" "button" in the "jscontrols" "region"
|
||||
And I should see "This is the javascript controls content." in the "jscontrols" "region"
|
||||
And I click on "Hide" "button" in the "jscontrols" "region"
|
||||
And I should not see "This is the javascript controls content." in the "jscontrols" "region"
|
||||
And I click on "Hide" "button" in the "jscontrols" "region"
|
||||
And I should not see "This is the javascript controls content." in the "jscontrols" "region"
|
||||
# Test state.
|
||||
And I click on "Test state" "button" in the "jscontrols" "region"
|
||||
And I should see "hidden" in the "state" "region"
|
||||
And I click on "Show" "button" in the "jscontrols" "region"
|
||||
And I click on "Test state" "button" in the "jscontrols" "region"
|
||||
And I should see "visible" in the "state" "region"
|
||||
# Events.
|
||||
And I click on "Show" "button" in the "jscontrols" "region"
|
||||
And I should see "Last event: Section shown" in the "jscontrols" "region"
|
||||
And I click on "Hide" "button" in the "jscontrols" "region"
|
||||
And I should see "Last event: Section hidden" in the "jscontrols" "region"
|
204
lib/tests/behat/fixtures/collapsable_section_output_testpage.php
Normal file
204
lib/tests/behat/fixtures/collapsable_section_output_testpage.php
Normal file
@ -0,0 +1,204 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Test page for the collapsable section output component.
|
||||
*
|
||||
* @copyright 2024 Ferran Recio <ferran@moodle.com>
|
||||
* @package core
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once(__DIR__ . '/../../../../config.php');
|
||||
|
||||
use core\output\local\collapsable_section;
|
||||
|
||||
defined('BEHAT_SITE_RUNNING') || die();
|
||||
|
||||
/**
|
||||
* Generate the title content.
|
||||
*
|
||||
* @param string $content The content to be displayed inside the button.
|
||||
* @return string
|
||||
*/
|
||||
function title_content(string $content): string {
|
||||
return ucfirst($content) . ' title';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the section content.
|
||||
*
|
||||
* @param string $content The content to be displayed inside the dialog.
|
||||
* @return string
|
||||
*/
|
||||
function section_content(string $content): string {
|
||||
global $OUTPUT;
|
||||
$icon = $OUTPUT->pix_icon('t/hide', 'Eye icon');
|
||||
return '
|
||||
<p>This is the ' . $content . ' content.</p>
|
||||
<p>Some rich content <a href="">Link</a> ' . $icon . '.</p>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
||||
tempor <b>incididunt ut labore et dolore magna aliqua</b>. Ut enim ad minim veniam,
|
||||
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||
consequat.</p>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||
consequat.</p>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||
consequat.</p>
|
||||
';
|
||||
}
|
||||
|
||||
global $CFG, $PAGE, $OUTPUT;
|
||||
$PAGE->set_url('/lib/tests/behat/fixtures/collapsable_section_output_testpage.php');
|
||||
$PAGE->add_body_class('limitedwidth');
|
||||
require_login();
|
||||
$PAGE->set_context(core\context\system::instance());
|
||||
$PAGE->set_title('Collapsable section test page');
|
||||
|
||||
echo $OUTPUT->header();
|
||||
|
||||
echo "<h2>Collapsable section test page</h2>";
|
||||
echo $OUTPUT->paragraph('This page is used to test the collapsable section output component.');
|
||||
|
||||
$sample = 'closed section';
|
||||
echo '<div id="closedsection" class="mb-4 border border-1 rounded-3 p-3">';
|
||||
echo $OUTPUT->paragraph($sample . ' example');
|
||||
$collapsable = new collapsable_section(
|
||||
titlecontent: title_content($sample),
|
||||
sectioncontent: section_content($sample),
|
||||
);
|
||||
echo $OUTPUT->render($collapsable);
|
||||
echo '</div>';
|
||||
|
||||
$sample = 'open section';
|
||||
echo '<div id="opensection" class="mb-4 border border-1 rounded-3 p-3">';
|
||||
echo $OUTPUT->paragraph($sample . ' example');
|
||||
$collapsable = new collapsable_section(
|
||||
titlecontent: title_content($sample),
|
||||
sectioncontent: section_content($sample),
|
||||
open: true,
|
||||
);
|
||||
echo $OUTPUT->render($collapsable);
|
||||
echo '</div>';
|
||||
|
||||
$sample = 'extra classes';
|
||||
echo '<div id="extraclasses" class="mb-4 border border-1 rounded-3 p-3">';
|
||||
echo $OUTPUT->paragraph($sample . ' example');
|
||||
$collapsable = new collapsable_section(
|
||||
titlecontent: title_content($sample),
|
||||
sectioncontent: section_content($sample),
|
||||
classes: 'bg-dark text-white p-3 rounded-3 extraclass',
|
||||
);
|
||||
echo $OUTPUT->render($collapsable);
|
||||
echo '</div>';
|
||||
|
||||
$sample = 'extra attributes';
|
||||
echo '<div id="extraattributes" class="mb-4 border border-1 rounded-3 p-3">';
|
||||
echo $OUTPUT->paragraph($sample . ' example');
|
||||
$collapsable = new collapsable_section(
|
||||
titlecontent: title_content($sample),
|
||||
sectioncontent: section_content($sample),
|
||||
extras: ['data-foo' => 'bar', 'id' => 'myid'],
|
||||
);
|
||||
echo $OUTPUT->render($collapsable);
|
||||
echo '</div>';
|
||||
|
||||
$sample = 'custom labels';
|
||||
echo '<div id="customlabels" class="mb-4 border border-1 rounded-3 p-3">';
|
||||
echo $OUTPUT->paragraph($sample . ' example');
|
||||
$collapsable = new collapsable_section(
|
||||
titlecontent: title_content($sample),
|
||||
sectioncontent: section_content($sample),
|
||||
expandlabel: 'Custom expand',
|
||||
collapselabel: 'Custom collapse',
|
||||
);
|
||||
echo $OUTPUT->render($collapsable);
|
||||
echo '</div>';
|
||||
|
||||
$sample = 'javascript controls';
|
||||
echo '<div id="jscontrols" class="mb-4 border border-1 rounded-3 p-3">';
|
||||
echo $OUTPUT->paragraph($sample . ' example');
|
||||
echo '
|
||||
<div class="d-flex justify-content-center">
|
||||
<button class="btn btn-secondary mx-2" id="toggleBtn">Toggle</button>
|
||||
<button class="btn btn-secondary mx-2" id="showBtn">Show</button>
|
||||
<button class="btn btn-secondary mx-2" id="hideBtn">Hide</button>
|
||||
<button class="btn btn-secondary mx-2" id="testBtn">Test state</button>
|
||||
<div class="d-flex align-content-center mx-2 rounded p-2 border">
|
||||
Current state: <div class="d-inline-block" id="state">?</div>
|
||||
</div>
|
||||
</div>';
|
||||
echo '<div class="rounded my-2 p-2 border">
|
||||
Last event: <div class="d-inline-block" id="lastevent">?</div>
|
||||
</div>';
|
||||
$collapsable = new collapsable_section(
|
||||
titlecontent: title_content($sample),
|
||||
sectioncontent: section_content($sample),
|
||||
extras: ['id' => 'jsCollapsable'],
|
||||
);
|
||||
echo $OUTPUT->render($collapsable);
|
||||
echo '</div>';
|
||||
|
||||
$inlinejs = <<<EOF
|
||||
require(
|
||||
[
|
||||
'core/local/collapsable_section/controls',
|
||||
'core/local/collapsable_section/events'
|
||||
],
|
||||
function(
|
||||
CollapsableSection,
|
||||
events
|
||||
) {
|
||||
|
||||
const section = CollapsableSection.instanceFromSelector('#jsCollapsable');
|
||||
|
||||
document.getElementById('toggleBtn').addEventListener('click', function() {
|
||||
section.toggle();
|
||||
});
|
||||
|
||||
document.getElementById('showBtn').addEventListener('click', function() {
|
||||
section.show();
|
||||
});
|
||||
|
||||
document.getElementById('hideBtn').addEventListener('click', function() {
|
||||
section.hide();
|
||||
});
|
||||
|
||||
document.getElementById('testBtn').addEventListener('click', function() {
|
||||
document.getElementById('state').textContent = section.isVisible() ? 'visible' : 'hidden';
|
||||
});
|
||||
|
||||
const jscontrolregion = document.getElementById('jscontrols');
|
||||
|
||||
jscontrolregion.addEventListener(events.eventTypes.shown, function() {
|
||||
document.getElementById('lastevent').textContent = 'Section shown';
|
||||
});
|
||||
|
||||
jscontrolregion.addEventListener(events.eventTypes.hidden, function() {
|
||||
document.getElementById('lastevent').textContent = 'Section hidden';
|
||||
});
|
||||
}
|
||||
);
|
||||
EOF;
|
||||
|
||||
$PAGE->requires->js_amd_inline($inlinejs);
|
||||
|
||||
echo '</div>';
|
||||
echo $OUTPUT->footer();
|
Loading…
x
Reference in New Issue
Block a user