mirror of
https://github.com/moodle/moodle.git
synced 2025-08-08 10:26:40 +02:00
MDL-81597 theme_boost: Fix header bar alignment
- Refactot context_header class to implement named templatable so render_context_header in core and theme_boost can be removed - Refactor context_header to use templates - Fix context header layout and styles
This commit is contained in:
parent
e1d2a046d3
commit
78db6bbce8
8 changed files with 149 additions and 167 deletions
5
.upgradenotes/MDL-81597-2024052802370704.yml
Normal file
5
.upgradenotes/MDL-81597-2024052802370704.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
issueNumber: MDL-81597
|
||||
notes:
|
||||
theme:
|
||||
- message: New `core/contextheader` mustache template has been added. This template can be overridden by themes to modify the context header
|
||||
type: improved
|
|
@ -27,6 +27,7 @@
|
|||
*/
|
||||
|
||||
use core\output\local\action_menu\subpanel;
|
||||
use core\output\named_templatable;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
@ -4109,7 +4110,7 @@ class tabobject implements renderable, templatable {
|
|||
* @copyright 2015 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class context_header implements renderable {
|
||||
class context_header implements renderable, named_templatable {
|
||||
|
||||
/**
|
||||
* @var string $heading Main heading.
|
||||
|
@ -4190,6 +4191,57 @@ class context_header implements renderable {
|
|||
array('class' => $class));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Export for template.
|
||||
*
|
||||
* @param renderer_base $output Renderer.
|
||||
* @return array
|
||||
*/
|
||||
public function export_for_template(renderer_base $output): array {
|
||||
// Heading.
|
||||
$headingtext = isset($this->heading) ? $this->heading : $output->get_page()->heading;
|
||||
$heading = $output->heading($headingtext, $this->headinglevel, "h2 mb-0");
|
||||
|
||||
// Buttons.
|
||||
if (isset($this->additionalbuttons)) {
|
||||
$additionalbuttons = [];
|
||||
foreach ($this->additionalbuttons as $button) {
|
||||
if (!isset($button->page)) {
|
||||
// Include js for messaging.
|
||||
if ($button['buttontype'] === 'togglecontact') {
|
||||
\core_message\helper::togglecontact_requirejs();
|
||||
}
|
||||
if ($button['buttontype'] === 'message') {
|
||||
\core_message\helper::messageuser_requirejs();
|
||||
}
|
||||
}
|
||||
foreach ($button['linkattributes'] as $key => $value) {
|
||||
$button['attributes'][] = ['name' => $key, 'value' => $value];
|
||||
}
|
||||
$additionalbuttons[] = $button;
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'heading' => $heading,
|
||||
'headinglevel' => $this->headinglevel,
|
||||
'imagedata' => $this->imagedata,
|
||||
'prefix' => $this->prefix,
|
||||
'hasadditionalbuttons' => !empty($additionalbuttons),
|
||||
'additionalbuttons' => $additionalbuttons ?? [],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the template name.
|
||||
*
|
||||
* @param renderer_base $renderer Renderer.
|
||||
* @return string
|
||||
*/
|
||||
public function get_template_name(renderer_base $renderer): string {
|
||||
return 'core/contextheader';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -4589,9 +4589,13 @@ EOD;
|
|||
}
|
||||
}
|
||||
|
||||
// Return the heading wrapped in an sr-only element so it is only visible to screen-readers for nocontextheader layouts.
|
||||
if (!empty($this->page->layout_options['nocontextheader'])) {
|
||||
return html_writer::div($heading, 'sr-only');
|
||||
}
|
||||
|
||||
$contextheader = new context_header($heading, $headinglevel, $imagedata, $userbuttons);
|
||||
return $this->render_context_header($contextheader);
|
||||
return $this->render($contextheader);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4610,74 +4614,6 @@ EOD;
|
|||
return $this->render_from_template('core/skip_links', $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the header bar.
|
||||
*
|
||||
* @param context_header $contextheader Header bar object.
|
||||
* @return string HTML for the header bar.
|
||||
*/
|
||||
protected function render_context_header(context_header $contextheader) {
|
||||
|
||||
// Generate the heading first and before everything else as we might have to do an early return.
|
||||
if (!isset($contextheader->heading)) {
|
||||
$heading = $this->heading($this->page->heading, $contextheader->headinglevel);
|
||||
} else {
|
||||
$heading = $this->heading($contextheader->heading, $contextheader->headinglevel);
|
||||
}
|
||||
|
||||
$showheader = empty($this->page->layout_options['nocontextheader']);
|
||||
if (!$showheader) {
|
||||
// Return the heading wrapped in an sr-only element so it is only visible to screen-readers.
|
||||
return html_writer::div($heading, 'sr-only');
|
||||
}
|
||||
|
||||
// All the html stuff goes here.
|
||||
$html = html_writer::start_div('page-context-header');
|
||||
|
||||
// Image data.
|
||||
if (isset($contextheader->imagedata)) {
|
||||
// Header specific image.
|
||||
$html .= html_writer::div($contextheader->imagedata, 'page-header-image icon-size-7');
|
||||
}
|
||||
|
||||
// Headings.
|
||||
if (isset($contextheader->prefix)) {
|
||||
$prefix = html_writer::div($contextheader->prefix, 'text-muted');
|
||||
$heading = $prefix . $heading;
|
||||
}
|
||||
$html .= html_writer::tag('div', $heading, array('class' => 'page-header-headings'));
|
||||
|
||||
// Buttons.
|
||||
if (isset($contextheader->additionalbuttons)) {
|
||||
$html .= html_writer::start_div('btn-group header-button-group');
|
||||
foreach ($contextheader->additionalbuttons as $button) {
|
||||
if (!isset($button->page)) {
|
||||
// Include js for messaging.
|
||||
if ($button['buttontype'] === 'togglecontact') {
|
||||
\core_message\helper::togglecontact_requirejs();
|
||||
}
|
||||
if ($button['buttontype'] === 'message') {
|
||||
\core_message\helper::messageuser_requirejs();
|
||||
}
|
||||
$image = $this->pix_icon($button['formattedimage'], '', 'moodle', array(
|
||||
'class' => 'iconsmall',
|
||||
));
|
||||
$image .= html_writer::span($button['title'], 'header-button-title');
|
||||
} else {
|
||||
$image = html_writer::empty_tag('img', array(
|
||||
'src' => $button['formattedimage'],
|
||||
'alt' => $button['title'],
|
||||
));
|
||||
}
|
||||
$html .= html_writer::link($button['url'], html_writer::tag('span', $image), $button['linkattributes']);
|
||||
}
|
||||
$html .= html_writer::end_div();
|
||||
}
|
||||
$html .= html_writer::end_div();
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for header elements.
|
||||
*
|
||||
|
|
75
lib/templates/contextheader.mustache
Normal file
75
lib/templates/contextheader.mustache
Normal file
|
@ -0,0 +1,75 @@
|
|||
{{!
|
||||
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/contextheader
|
||||
|
||||
Context header template.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"heading": "<h2>Page title</h2>",
|
||||
"prefix": "Page prefix",
|
||||
"hasadditionalbuttons": true,
|
||||
"additionalbuttons": [
|
||||
{
|
||||
"url": "http://example.com",
|
||||
"title": "Button title",
|
||||
"formattedimage": "http://example.com/image.jpg",
|
||||
"attributes": [
|
||||
{
|
||||
"name": "data-attribute",
|
||||
"value": "attribute value"
|
||||
},
|
||||
{
|
||||
"name": "class",
|
||||
"value": "btn btn-primary"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}}
|
||||
<div class="page-context-header d-flex align-items-center mb-2">
|
||||
{{#imagedata}}
|
||||
<div class="page-header-image">
|
||||
{{{imagedata}}}
|
||||
</div>
|
||||
{{/imagedata}}
|
||||
<div class="page-header-headings">
|
||||
{{#prefix}}
|
||||
<div class="text-muted text-uppercase small line-height-3">
|
||||
{{{prefix}}}
|
||||
</div>
|
||||
{{/prefix}}
|
||||
{{{heading}}}
|
||||
</div>
|
||||
{{#hasadditionalbuttons}}
|
||||
<div class="btn-group header-button-group mx-3">
|
||||
{{#additionalbuttons}}
|
||||
<a href="{{url}}" {{#attributes}} {{name}}="{{value}}" {{/attributes}}>
|
||||
{{#page}}
|
||||
{{#pix}}{{formattedimage}}{{/pix}}
|
||||
<span class="header-button-title">{{title}}</span>
|
||||
{{/page}}
|
||||
{{^page}}
|
||||
<img src="{{formattedimage}}" alt="{{title}}">
|
||||
{{/page}}
|
||||
</a>
|
||||
{{/additionalbuttons}}
|
||||
</div>
|
||||
{{/hasadditionalbuttons}}
|
||||
</div>
|
|
@ -179,69 +179,7 @@ class core_renderer extends \core_renderer {
|
|||
}
|
||||
|
||||
$contextheader = new \context_header($heading, $headinglevel, $imagedata, $userbuttons, $prefix);
|
||||
return $this->render_context_header($contextheader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the header bar.
|
||||
*
|
||||
* @param context_header $contextheader Header bar object.
|
||||
* @return string HTML for the header bar.
|
||||
*/
|
||||
protected function render_context_header(\context_header $contextheader) {
|
||||
|
||||
// Generate the heading first and before everything else as we might have to do an early return.
|
||||
if (!isset($contextheader->heading)) {
|
||||
$heading = $this->heading($this->page->heading, $contextheader->headinglevel, 'h2');
|
||||
} else {
|
||||
$heading = $this->heading($contextheader->heading, $contextheader->headinglevel, 'h2');
|
||||
}
|
||||
|
||||
// All the html stuff goes here.
|
||||
$html = html_writer::start_div('page-context-header');
|
||||
|
||||
// Image data.
|
||||
if (isset($contextheader->imagedata)) {
|
||||
// Header specific image.
|
||||
$html .= html_writer::div($contextheader->imagedata, 'page-header-image mr-2');
|
||||
}
|
||||
|
||||
// Headings.
|
||||
if (isset($contextheader->prefix)) {
|
||||
$prefix = html_writer::div($contextheader->prefix, 'text-muted text-uppercase small line-height-3');
|
||||
$heading = $prefix . $heading;
|
||||
}
|
||||
$html .= html_writer::tag('div', $heading, array('class' => 'page-header-headings'));
|
||||
|
||||
// Buttons.
|
||||
if (isset($contextheader->additionalbuttons)) {
|
||||
$html .= html_writer::start_div('btn-group header-button-group');
|
||||
foreach ($contextheader->additionalbuttons as $button) {
|
||||
if (!isset($button->page)) {
|
||||
// Include js for messaging.
|
||||
if ($button['buttontype'] === 'togglecontact') {
|
||||
\core_message\helper::togglecontact_requirejs();
|
||||
}
|
||||
if ($button['buttontype'] === 'message') {
|
||||
\core_message\helper::messageuser_requirejs();
|
||||
}
|
||||
$image = $this->pix_icon($button['formattedimage'], '', 'moodle', array(
|
||||
'class' => 'iconsmall',
|
||||
));
|
||||
$image .= html_writer::span($button['title'], 'header-button-title');
|
||||
} else {
|
||||
$image = html_writer::empty_tag('img', array(
|
||||
'src' => $button['formattedimage'],
|
||||
'alt' => $button['title'],
|
||||
));
|
||||
}
|
||||
$html .= html_writer::link($button['url'], html_writer::tag('span', $image), $button['linkattributes']);
|
||||
}
|
||||
$html .= html_writer::end_div();
|
||||
}
|
||||
$html .= html_writer::end_div();
|
||||
|
||||
return $html;
|
||||
return $this->render($contextheader);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1955,24 +1955,14 @@ nav.navbar .logo img {
|
|||
overflow: hidden;
|
||||
padding: 0.25rem 0;
|
||||
|
||||
display: flex;
|
||||
|
||||
.page-header-image {
|
||||
& > a {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.page-header-headings,
|
||||
.header-button-group {
|
||||
position: relative;
|
||||
line-height: 24px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.header-button-group {
|
||||
display: block;
|
||||
float: left;
|
||||
.userinitials,
|
||||
.userpicture {
|
||||
margin-right: map-get($spacers, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24954,20 +24954,13 @@ nav.navbar .logo img {
|
|||
.page-context-header {
|
||||
overflow: hidden;
|
||||
padding: 0.25rem 0;
|
||||
display: flex;
|
||||
}
|
||||
.page-context-header .page-header-image > a {
|
||||
display: inline-block;
|
||||
}
|
||||
.page-context-header .page-header-headings,
|
||||
.page-context-header .header-button-group {
|
||||
position: relative;
|
||||
line-height: 24px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.page-context-header .header-button-group {
|
||||
display: block;
|
||||
float: left;
|
||||
.page-context-header .page-header-image .userinitials,
|
||||
.page-context-header .page-header-image .userpicture {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
ul.dragdrop-keyboard-drag li {
|
||||
|
|
|
@ -24954,20 +24954,13 @@ nav.navbar .logo img {
|
|||
.page-context-header {
|
||||
overflow: hidden;
|
||||
padding: 0.25rem 0;
|
||||
display: flex;
|
||||
}
|
||||
.page-context-header .page-header-image > a {
|
||||
display: inline-block;
|
||||
}
|
||||
.page-context-header .page-header-headings,
|
||||
.page-context-header .header-button-group {
|
||||
position: relative;
|
||||
line-height: 24px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.page-context-header .header-button-group {
|
||||
display: block;
|
||||
float: left;
|
||||
.page-context-header .page-header-image .userinitials,
|
||||
.page-context-header .page-header-image .userpicture {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
ul.dragdrop-keyboard-drag li {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue