4a145b12b9c7b1c68adaae8cafcc0d377afab93c
[moodle.git] / theme / noname / classes / output / core_renderer.php
1 <?php
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 <http://www.gnu.org/licenses/>.
17 namespace theme_noname\output;
19 use html_writer;
20 use tabobject;
21 use tabtree;
22 use custom_menu_item;
23 use custom_menu;
24 use block_contents;
25 use stdClass;
27 defined('MOODLE_INTERNAL') || die;
29 /**
30  * Renderers to align Moodle's HTML with that expected by Bootstrap
31  *
32  * @package    theme_noname
33  * @copyright  2012 Bas Brands, www.basbrands.nl
34  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35  */
37 class core_renderer extends \core_renderer {
39     /** @var custom_menu_item language The language menu if created */
40     protected $language = null;
42     /**
43      * The standard tags that should be included in the <head> tag
44      * including a meta description for the front page
45      *
46      * @return string HTML fragment.
47      */
48     public function standard_head_html() {
49         global $SITE, $PAGE;
51         $output = parent::standard_head_html();
52         if ($PAGE->pagelayout == 'frontpage') {
53             $summary = s(strip_tags(format_text($SITE->summary, FORMAT_HTML)));
54             if (!empty($summary)) {
55                 $output .= "<meta name=\"description\" content=\"$summary\" />\n";
56             }
57         }
59         return $output;
60     }
62     /*
63      * This renders the navbar.
64      * Uses bootstrap compatible html.
65      */
66     public function navbar() {
67         $items = $this->page->navbar->get_items();
68         if (empty($items)) {
69             return '';
70         }
72         $breadcrumbs = array();
73         foreach ($items as $item) {
74             $item->hideicon = true;
75             $breadcrumbs[] = $this->render($item);
76         }
77         $list_items = '<li>'.join(" </li><li>", $breadcrumbs).'</li>';
78         $title = '<span class="accesshide" id="navbar-label">'.get_string('pagepath').'</span>';
79         return $title . '<nav aria-labelledby="navbar-label"><ul class="breadcrumb">' .
80                 $list_items . '</ul></nav>';
81     }
83     /*
84      * Overriding the custom_menu function ensures the custom menu is
85      * always shown, even if no menu items are configured in the global
86      * theme settings page.
87      */
88     public function custom_menu($custommenuitems = '') {
89         global $CFG;
91         if (empty($custommenuitems) && !empty($CFG->custommenuitems)) {
92             $custommenuitems = $CFG->custommenuitems;
93         }
94         $custommenu = new custom_menu($custommenuitems, current_language());
95         return $this->render_custom_menu($custommenu);
96     }
98     /*
99      * This renders the bootstrap top menu.
100      *
101      * This renderer is needed to enable the Bootstrap style navigation.
102      */
103     protected function render_custom_menu(custom_menu $menu) {
104         global $CFG;
106         $langs = get_string_manager()->get_list_of_translations();
107         $haslangmenu = $this->lang_menu() != '';
109         if (!$menu->has_children() && !$haslangmenu) {
110             return '';
111         }
113         if ($haslangmenu) {
114             $strlang =  get_string('language');
115             $currentlang = current_language();
116             if (isset($langs[$currentlang])) {
117                 $currentlang = $langs[$currentlang];
118             } else {
119                 $currentlang = $strlang;
120             }
121             $this->language = $menu->add($currentlang, new moodle_url('#'), $strlang, 10000);
122             foreach ($langs as $langtype => $langname) {
123                 $this->language->add($langname, new moodle_url($this->page->url, array('lang' => $langtype)), $langname);
124             }
125         }
127         $content = '<ul class="nav">';
128         foreach ($menu->get_children() as $item) {
129             $content .= $this->render_custom_menu_item($item, 1);
130         }
132         return $content.'</ul>';
133     }
135     /*
136      * This code renders the custom menu items for the
137      * bootstrap dropdown menu.
138      */
139     protected function render_custom_menu_item(custom_menu_item $menunode, $level = 0 ) {
140         static $submenucount = 0;
142         $content = '';
143         if ($menunode->has_children()) {
145             if ($level == 1) {
146                 $class = 'dropdown';
147             } else {
148                 $class = 'dropdown-submenu';
149             }
151             if ($menunode === $this->language) {
152                 $class .= ' langmenu';
153             }
154             $content = html_writer::start_tag('li', array('class' => $class));
155             // If the child has menus render it as a sub menu.
156             $submenucount++;
157             if ($menunode->get_url() !== null) {
158                 $url = $menunode->get_url();
159             } else {
160                 $url = '#cm_submenu_'.$submenucount;
161             }
162             $content .= html_writer::start_tag('a', array('href'=>$url, 'class'=>'dropdown-toggle', 'data-toggle'=>'dropdown', 'title'=>$menunode->get_title()));
163             $content .= $menunode->get_text();
164             if ($level == 1) {
165                 $content .= '<b class="caret"></b>';
166             }
167             $content .= '</a>';
168             $content .= '<ul class="dropdown-menu">';
169             foreach ($menunode->get_children() as $menunode) {
170                 $content .= $this->render_custom_menu_item($menunode, 0);
171             }
172             $content .= '</ul>';
173         } else {
174             // The node doesn't have children so produce a final menuitem.
175             // Also, if the node's text matches '####', add a class so we can treat it as a divider.
176             if (preg_match("/^#+$/", $menunode->get_text())) {
177                 // This is a divider.
178                 $content = '<li class="divider">&nbsp;</li>';
179             } else {
180                 $content = '<li>';
181                 if ($menunode->get_url() !== null) {
182                     $url = $menunode->get_url();
183                 } else {
184                     $url = '#';
185                 }
186                 $content .= html_writer::link($url, $menunode->get_text(), array('title' => $menunode->get_title()));
187                 $content .= '</li>';
188             }
189         }
190         return $content;
191     }
193     /**
194      * This code renders the navbar button to control the display of the custom menu
195      * on smaller screens.
196      *
197      * Do not display the button if the menu is empty.
198      *
199      * @return string HTML fragment
200      */
201     public function navbar_button() {
202         global $CFG;
204         if (empty($CFG->custommenuitems) && $this->lang_menu() == '') {
205             return '';
206         }
208         $iconbar = html_writer::tag('span', '', array('class' => 'icon-bar'));
209         $button = html_writer::tag('a', $iconbar . "\n" . $iconbar. "\n" . $iconbar, array(
210             'class'       => 'btn btn-navbar',
211             'data-toggle' => 'collapse',
212             'data-target' => '.nav-collapse'
213         ));
214         return $button;
215     }
217     /**
218      * Renders tabtree
219      *
220      * @param tabtree $tabtree
221      * @return string
222      */
223     protected function render_tabtree(tabtree $tabtree) {
224         if (empty($tabtree->subtree)) {
225             return '';
226         }
227         $firstrow = $secondrow = '';
228         foreach ($tabtree->subtree as $tab) {
229             $firstrow .= $this->render($tab);
230             if (($tab->selected || $tab->activated) && !empty($tab->subtree) && $tab->subtree !== array()) {
231                 $secondrow = $this->tabtree($tab->subtree);
232             }
233         }
234         return html_writer::tag('ul', $firstrow, array('class' => 'nav nav-tabs')) . $secondrow;
235     }
237     /**
238      * Renders tabobject (part of tabtree)
239      *
240      * This function is called from {@link core_renderer::render_tabtree()}
241      * and also it calls itself when printing the $tabobject subtree recursively.
242      *
243      * @param tabobject $tabobject
244      * @return string HTML fragment
245      */
246     protected function render_tabobject(tabobject $tab) {
247         if (($tab->selected and (!$tab->linkedwhenselected)) or $tab->activated) {
248             return html_writer::tag('li', html_writer::tag('a', $tab->text), array('class' => 'active'));
249         } else if ($tab->inactive) {
250             return html_writer::tag('li', html_writer::tag('a', $tab->text), array('class' => 'disabled'));
251         } else {
252             if (!($tab->link instanceof moodle_url)) {
253                 // backward compartibility when link was passed as quoted string
254                 $link = "<a href=\"$tab->link\" title=\"$tab->title\">$tab->text</a>";
255             } else {
256                 $link = html_writer::link($tab->link, $tab->text, array('title' => $tab->title));
257             }
258             $params = $tab->selected ? array('class' => 'active') : null;
259             return html_writer::tag('li', $link, $params);
260         }
261     }
263     /**
264      * Prints a nice side block with an optional header.
265      *
266      * @param block_contents $bc HTML for the content
267      * @param string $region the region the block is appearing in.
268      * @return string the HTML to be output.
269      */
270     public function block(block_contents $bc, $region) {
271         $bc = clone($bc); // Avoid messing up the object passed in.
272         if (empty($bc->blockinstanceid) || !strip_tags($bc->title)) {
273             $bc->collapsible = block_contents::NOT_HIDEABLE;
274         }
275         if (!empty($bc->blockinstanceid)) {
276             $bc->attributes['data-instanceid'] = $bc->blockinstanceid;
277         }
278         $skiptitle = strip_tags($bc->title);
279         if ($bc->blockinstanceid && !empty($skiptitle)) {
280             $bc->attributes['aria-labelledby'] = 'instance-'.$bc->blockinstanceid.'-header';
281         } else if (!empty($bc->arialabel)) {
282             $bc->attributes['aria-label'] = $bc->arialabel;
283         }
284         if ($bc->dockable) {
285             $bc->attributes['data-dockable'] = 1;
286         }
287         if ($bc->collapsible == block_contents::HIDDEN) {
288             $bc->add_class('hidden');
289         }
290         if (!empty($bc->controls)) {
291             $bc->add_class('block_with_controls');
292         }
294         $id = !empty($bc->attributes['id']) ? $bc->attributes['id'] : uniqid('block-');
295         $context = new stdClass();
296         $context->skipid = $bc->skipid;
297         $context->blockinstanceid = $bc->blockinstanceid;
298         $context->dockable = $bc->dockable;
299         $context->id = $id;
300         $context->hidden = $bc->collapsible == block_contents::HIDDEN;
301         $context->skiptitle = strip_tags($bc->title);
302         $context->showskiplink = !empty($context->skiptitle);
303         $context->arialabel = $bc->arialabel;
304         $context->ariarole = !empty($bc->attributes['role']) ? $bc->attributes['role'] : 'complementary';
305         $context->type = $bc->attributes['data-block'];
306         $context->title = $bc->title;
307         $context->content = $bc->content;
308         $context->annotation = $bc->annotation;
309         $context->footer = $bc->footer;
310         $context->hascontrols = !empty($bc->controls);
311         if ($context->hascontrols) {
312             $context->controls = $this->block_controls($bc->controls, $id);
313         }
315         return $this->render_from_template('core/block', $context);
316     }
318     /**
319      * Returns the CSS classes to apply to the body tag.
320      *
321      * @since Moodle 2.5.1 2.6
322      * @param array $additionalclasses Any additional classes to apply.
323      * @return string
324      */
325     public function body_css_classes(array $additionalclasses = array()) {
326         return $this->page->bodyclasses;
327     }