Skip to content

Commit

Permalink
MDL-69588 theme_boost: Use partial templates in boost.
Browse files Browse the repository at this point in the history
This moves away from using escaped html injected into the template
and uses partial templates instead.
  • Loading branch information
abgreeve authored and Chocolate-lightning committed Aug 23, 2021
1 parent 2d548e7 commit 56c34d7
Show file tree
Hide file tree
Showing 13 changed files with 297 additions and 62 deletions.
3 changes: 2 additions & 1 deletion admin/search.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@
if ($showsettingslinks) {
$node = $PAGE->settingsnav->find('root', navigation_node::TYPE_SITE_ADMIN);
if ($node) {
$secondarynavigation = $OUTPUT->more_menu($PAGE->secondarynav, 'nav-tabs', true);
$moremenu = new \core\navigation\output\more_menu($PAGE->secondarynav, 'nav-tabs', true);
$secondarynavigation = $moremenu->export_for_template($OUTPUT);
echo $OUTPUT->render_from_template('core/settings_link_page',
['node' => $node, 'secondarynavigation' => $secondarynavigation]);
}
Expand Down
74 changes: 74 additions & 0 deletions lib/classes/navigation/output/more_menu.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?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\navigation\output;

use renderable;
use renderer_base;
use templatable;
use custom_menu;

/**
* more menu navigation renderable
*
* @package core
* @category navigation
* @copyright 2021 onwards Adrian Greeve
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class more_menu implements renderable, templatable {

protected $content;
protected $navbarstyle;
protected $hastabs;
protected $haschildren;

/**
* Constructor for this class.
*
* @param object $content Navigation objects.
* @param string $navbarstyle class name.
* @param bool $hastabs If tabs are being used.
* @param bool $haschildren The content has children.
*/
public function __construct(object $content, string $navbarstyle, bool $hastabs = false, bool $haschildren = true) {
$this->content = $content;
$this->navbarstyle = $navbarstyle;
$this->hastabs = $hastabs;
$this->haschildren = $haschildren;
}

/**
* Return data for rendering a template.
*
* @param renderer_base $output The output
* @return array Data for rendering a template
*/
public function export_for_template(renderer_base $output): array {
$data = ['navbarstyle' => $this->navbarstyle, 'tabs' => $this->hastabs];
if ($this->haschildren) {
if (!isset($this->content->children) || count($this->content->children) == 0) {
$data = [];
}
$data['nodecollection'] = $this->content;
} else {
$data['nodearray'] = (array) $this->content;
}

return $data;
}

}
6 changes: 4 additions & 2 deletions lib/classes/navigation/output/primary.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,11 @@ public function export_for_template(?renderer_base $output = null): array {
$output = $this->page->get_renderer('core');
}

$menudata = (object) array_merge($this->get_primary_nav(), $this->get_custom_menu($output));
$moremenu = new \core\navigation\output\more_menu($menudata, 'navbar-nav', false, false);

return [
'primary' => $this->get_primary_nav(),
'custom' => $this->get_custom_menu($output),
'moremenu' => $moremenu->export_for_template($output),
'lang' => !isloggedin() || isguestuser() ? $this->get_lang_menu($output) : [],
'user' => $this->get_user_menu($output),
];
Expand Down
28 changes: 0 additions & 28 deletions lib/outputrenderers.php
Original file line number Diff line number Diff line change
Expand Up @@ -3808,34 +3808,6 @@ protected function render_custom_menu_item(custom_menu_item $menunode) {
return $content;
}

/**
* Renders a navigation bar into a "more menu" navigation bar
*
* @param array $content
* @param string $navbarstyle navbar-nav or nav-tabs
* @param boolean $hastabs
* @return string
*/
public function more_menu($content, $navbarstyle, $hastabs = false) {
$tabs = ($navbarstyle == 'nav-tabs');
if (is_object($content)) {
if (!isset($content->children) || count($content->children) == 0) {
return false;
}
return $this->render_from_template('core/moremenu', (object) [
'nodecollection' => $content,
'navbarstyle' => $navbarstyle,
'tabs' => $hastabs
]);
} else {
return $this->render_from_template('core/moremenu', (object) [
'nodearray' => $content,
'navbarstyle' => $navbarstyle,
'tabs' => $hastabs
]);
}
}

/**
* Renders theme links for switching between default and other themes.
*
Expand Down
5 changes: 2 additions & 3 deletions lib/templates/moremenu.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
}
}}
<nav class="moremenu">
<ul id="moremenu-{{ uniqid }}" role="menubar" class="nav more-nav {{navbarstyle}}">
<ul id="moremenu-{{ uniqid }}-{{navbarstyle}}" role="menubar" class="nav more-nav {{navbarstyle}}">
{{#nodecollection}}
{{#children}}
{{> core/moremenu_children}}
Expand All @@ -65,7 +65,6 @@
</nav>
{{#js}}
require(['core/moremenu'], function(moremenu) {
var moreMenu = document.querySelector('#moremenu-{{ uniqid }}');
moremenu(moreMenu);
moremenu(document.querySelector('#moremenu-{{ uniqid }}-{{navbarstyle}}'));
});
{{/js}}
2 changes: 1 addition & 1 deletion lib/templates/settings_link_page.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
}
}}
{{#secondarynavigation}}
{{{secondarynavigation}}}
{{> core/moremenu}}
{{/secondarynavigation}}
{{^secondarynavigation}}
<ul class="nav nav-tabs" role="tablist">
Expand Down
18 changes: 9 additions & 9 deletions lib/tests/navigation/output/primary_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -116,31 +116,31 @@ public function test_primary_export(bool $withcustom, bool $withlang, string $us
public function test_primary_export_provider(): array {
return [
"Export the menu data when: custom menu exists; multiple langs installed; user is not logged in." => [
true, true, '', ['primary', 'custom', 'lang', 'user']
true, true, '', ['moremenu', 'lang', 'user']
],
"Export the menu data when: custom menu exists; langs not installed; user is not logged in." => [
true, false, '', ['primary', 'custom', 'user']
true, false, '', ['moremenu', 'user']
],
"Export the menu data when: custom menu exists; multiple langs installed; logged in as admin." => [
true, true, 'admin', ['primary', 'custom', 'user']
true, true, 'admin', ['moremenu', 'user']
],
"Export the menu data when: custom menu exists; langs not installed; logged in as admin." => [
true, false, 'admin', ['primary', 'custom', 'user']
true, false, 'admin', ['moremenu', 'user']
],
"Export the menu data when: custom menu exists; multiple langs installed; logged in as guest." => [
true, true, 'guest', ['primary', 'custom', 'lang', 'user']
true, true, 'guest', ['moremenu', 'lang', 'user']
],
"Export the menu data when: custom menu exists; langs not installed; logged in as guest." => [
true, false, 'guest', ['primary', 'custom', 'user']
true, false, 'guest', ['moremenu', 'user']
],
"Export the menu data when: custom menu does not exist; multiple langs installed; logged in as guest." => [
false, true, 'guest', ['primary', 'lang', 'user']
false, true, 'guest', ['moremenu', 'lang', 'user']
],
"Export the menu data when: custom menu does not exist; multiple langs installed; logged in as admin." => [
false, true, 'admin', ['primary', 'user']
false, true, 'admin', ['moremenu', 'user']
],
"Export the menu data when: custom menu does not exist; langs not installed; user is not logged in." => [
false, false, '', ['primary', 'user']
false, false, '', ['moremenu', 'user']
],
];
}
Expand Down
186 changes: 182 additions & 4 deletions theme/boost/classes/output/core_renderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,187 @@ public function navbar(): string {
* @param int $headinglevel What 'h' level to make the heading.
* @return string A rendered context header.
*/
public function context_header($headerinfo = null, $headinglevel = 1) {
$contextheader = new \theme_boost\output\context_header($this->page, $headerinfo, $headinglevel);
$data = $contextheader->export_for_template($this);
return $this->render_from_template('theme_boost/context_header', $data);
public function context_header($headerinfo = null, $headinglevel = 1): string {
global $DB, $USER, $CFG, $SITE;
require_once($CFG->dirroot . '/user/lib.php');
$context = $this->page->context;
$heading = null;
$imagedata = null;
$subheader = null;
$userbuttons = null;

// Make sure to use the heading if it has been set.
if (isset($headerinfo['heading'])) {
$heading = $headerinfo['heading'];
} else {
$heading = $this->page->heading;
}

// The user context currently has images and buttons. Other contexts may follow.
if (isset($headerinfo['user']) || $context->contextlevel == CONTEXT_USER) {
if (isset($headerinfo['user'])) {
$user = $headerinfo['user'];
} else {
// Look up the user information if it is not supplied.
$user = $DB->get_record('user', array('id' => $context->instanceid));
}

// If the user context is set, then use that for capability checks.
if (isset($headerinfo['usercontext'])) {
$context = $headerinfo['usercontext'];
}

// Only provide user information if the user is the current user, or a user which the current user can view.
// When checking user_can_view_profile(), either:
// If the page context is course, check the course context (from the page object) or;
// If page context is NOT course, then check across all courses.
$course = ($this->page->context->contextlevel == CONTEXT_COURSE) ? $this->page->course : null;

if (user_can_view_profile($user, $course)) {
// Use the user's full name if the heading isn't set.
if (empty($heading)) {
$heading = fullname($user);
}

$imagedata = $this->user_picture($user, array('size' => 100));

// Check to see if we should be displaying a message button.
if (!empty($CFG->messaging) && has_capability('moodle/site:sendmessage', $context)) {
$userbuttons = array(
'messages' => array(
'buttontype' => 'message',
'title' => get_string('message', 'message'),
'url' => new moodle_url('/message/index.php', array('id' => $user->id)),
'image' => 'message',
'linkattributes' => \core_message\helper::messageuser_link_params($user->id),
'page' => $this->page
)
);

if ($USER->id != $user->id) {
$iscontact = \core_message\api::is_contact($USER->id, $user->id);
$contacttitle = $iscontact ? 'removefromyourcontacts' : 'addtoyourcontacts';
$contacturlaction = $iscontact ? 'removecontact' : 'addcontact';
$contactimage = $iscontact ? 'removecontact' : 'addcontact';
$userbuttons['togglecontact'] = array(
'buttontype' => 'togglecontact',
'title' => get_string($contacttitle, 'message'),
'url' => new moodle_url('/message/index.php', array(
'user1' => $USER->id,
'user2' => $user->id,
$contacturlaction => $user->id,
'sesskey' => sesskey())
),
'image' => $contactimage,
'linkattributes' => \core_message\helper::togglecontact_link_params($user, $iscontact),
'page' => $this->page
);
}

$this->page->requires->string_for_js('changesmadereallygoaway', 'moodle');
}
} else {
$heading = null;
}
}

$prefix = null;
if ($context->contextlevel == CONTEXT_MODULE) {
$heading = $this->page->cm->name;
$imagedata = $this->pix_icon('icon', '', $this->page->activityname);
$prefix = get_string('modulename', $this->page->activityname);
}

if ($this->should_display_main_logo($headinglevel)) {
$sitename = format_string($SITE->fullname, true, ['context' => \context_course::instance(SITEID)]);
// Logo.
$html = html_writer::div(
html_writer::empty_tag('img', [
'src' => $this->get_logo_url(null, 150),
'alt' => get_string('logoof', '', $sitename),
'class' => 'img-fluid'
]),
'logo'
);
// Heading.
if (!isset($heading)) {
$html .= $this->heading($this->page->heading, $headinglevel, 'sr-only');
} else {
$html .= $this->heading($heading, $headinglevel, 'sr-only');
}
return $html;
}

$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');
}

$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-6');
}

// Headings.
if (isset($contextheader->prefix)) {
$prefix = html_writer::div($contextheader->prefix, 'text-muted text-uppercase');
$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'], $button['title'], 'moodle', array(
'class' => 'iconsmall',
'role' => 'presentation'
));
$image .= html_writer::span($button['title'], 'header-button-title');
} else {
$image = html_writer::empty_tag('img', array(
'src' => $button['formattedimage'],
'role' => 'presentation'
));
}
$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;
}
}
Loading

0 comments on commit 56c34d7

Please sign in to comment.