MDL-35876: Whitespace, indenting and more verbose upgrade.txt
[moodle.git] / theme / mymobile / renderers.php
CommitLineData
2fd7abbb 1<?php
3c0c2bf0 2// This file is part of Moodle - http://moodle.org/
2fd7abbb 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/>.
16
17/**
3c0c2bf0 18 * Renderers for the mymobile theme
2fd7abbb 19 *
20 * @package theme
21 * @subpackage mymobile
22 * @copyright John Stabinger
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 */
3c0c2bf0
SH
25
26/**
27 * A custom renderer for the mymobile theme to produce snippets of content.
28 *
29 * @package theme
30 * @subpackage mymobile
31 * @copyright John Stabinger
32 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
33 */
0c97dc1a 34
3c0c2bf0
SH
35class theme_mymobile_renderer extends plugin_renderer_base {
36
37 /**
38 * Produces the settings tree
39 *
40 * @param settings_navigation $navigation
41 * @return string
42 */
43 public function settings_tree(settings_navigation $navigation) {
44 $content = $this->navigation_node($navigation, array('class' => 'settings'));
01ac2cd8 45 if (has_capability('moodle/site:config', context_system::instance())) {
3c0c2bf0
SH
46 // TODO: Work out whether something is missing from here.
47 }
48 return $content;
2fd7abbb 49 }
3c0c2bf0
SH
50
51 /**
52 * Produces the navigation tree
53 *
54 * @param global_navigation $navigation
55 * @return string
56 */
57 public function navigation_tree(global_navigation $navigation) {
58 return $this->navigation_node($navigation, array());
2fd7abbb 59 }
60
3c0c2bf0
SH
61 /**
62 * Protected method to render a navigaiton node
63 *
64 * @param navigation_node $node
65 * @param array $attrs
66 * @return type
67 */
68 protected function navigation_node(navigation_node $node, $attrs = array()) {
69 $items = $node->children;
70
71 // exit if empty, we don't want an empty ul element
72 if ($items->count() == 0) {
73 return '';
74 }
75
76 // array of nested li elements
77 $lis = array();
78 foreach ($items as $item) {
79 if (!$item->display) {
80 continue;
81 }
82
83 $isbranch = ($item->children->count() > 0 || $item->nodetype == navigation_node::NODETYPE_BRANCH);
84 $item->hideicon = true;
85
86 $content = $this->output->render($item);
87 $content .= $this->navigation_node($item);
88
89 if ($isbranch && !(is_string($item->action) || empty($item->action))) {
90 $content = html_writer::tag('li', $content, array('data-role' => 'list-divider', 'class' => (string)$item->key));
91 } else if($isbranch) {
92 $content = html_writer::tag('li', $content, array('data-role' => 'list-divider'));
93 } else {
94 $content = html_writer::tag('li', $content, array('class' => (string)$item->text));
95 }
96 $lis[] = $content;
97 }
98 if (!count($lis)) {
99 return '';
100 }
101 return implode("\n", $lis);
2fd7abbb 102 }
2fd7abbb 103}
2fd7abbb 104
3c0c2bf0
SH
105/**
106 * Overridden core renderer for the mymobile theme
107 *
108 * @package theme
109 * @subpackage mymobile
110 * @copyright John Stabinger
111 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
112 */
113class theme_mymobile_core_renderer extends core_renderer {
114
115 /**
116 * Returns the dtheme to use for the selected swatch
cf2de1cf 117 *
3c0c2bf0
SH
118 * @return string
119 */
120 protected function theme_swatch() {
121 $showswatch = 'light';
122 if (!empty($this->page->theme->settings->colourswatch)) {
123 $showswatch = $this->page->theme->settings->colourswatch;
2fd7abbb 124 }
125 if ($showswatch == 'light') {
3c0c2bf0
SH
126 $dtheme = 'b';
127 } else {
128 $dtheme = 'd';
129 }
130 return $dtheme;
131 }
132
133 /**
134 * Produces a heading
135 *
136 * @param string $text
137 * @param int $level
138 * @param string $classes
139 * @param string $id
140 * @return string
141 */
142 public function heading($text, $level = 2, $classes = 'main', $id = null) {
143 if ($classes == 'helpheading') {
144 // Keeps wrap from help headings in dialog.
145 $content = parent::heading($text, $level, $classes, $id);
7e6c6743 146 } else {
3c0c2bf0
SH
147 $content = html_writer::start_tag('div', array('class' => 'headingwrap ui-bar-'.$this->theme_swatch() .' ui-footer'));
148 $content .= parent::heading($text, $level, $classes.' ui-title', $id);
149 $content .= html_writer::end_tag('div');
2fd7abbb 150 }
3c0c2bf0
SH
151 return $content;
152 }
2fd7abbb 153
3c0c2bf0
SH
154 /**
155 * Renders a block
156 *
157 * @param block_contents $bc
158 * @param string $region
159 * @return string
160 */
161 public function block(block_contents $bc, $region) {
162 // Avoid messing up the object passed in.
163 $bc = clone($bc);
164 // The mymobile theme does not support collapsible blocks.
165 $bc->collapsible = block_contents::NOT_HIDEABLE;
166 // There are no controls that are usable within the
167 $bc->controls = array();
168
169 // TODO: Do we still need to support accessibility here? Surely screen
170 // readers don't present themselves as mobile devices too often.
2fd7abbb 171 $skiptitle = strip_tags($bc->title);
172 if (empty($skiptitle)) {
173 $output = '';
174 $skipdest = '';
175 } else {
176 $output = html_writer::tag('a', get_string('skipa', 'access', $skiptitle), array('href' => '#sb-' . $bc->skipid, 'class' => 'skip-block'));
177 $skipdest = html_writer::tag('span', '', array('id' => 'sb-' . $bc->skipid, 'class' => 'skip-block-to'));
178 }
179 $testb = $bc->attributes['class'];
256c51fa
JS
180 $testc = $bc->attributes['id'];
181 // TODO: Find a better solution to this hardcoded block checks.
2fd7abbb 182 if ($testb == "block_calendar_month2 block") {
3c0c2bf0
SH
183 $output = html_writer::start_tag('span');
184 } else if ($testb == "block_course_overview block") {
185 $output = html_writer::start_tag('div');
186 } else {
187 if (!empty($this->page->theme->settings->colourswatch)) {
188 $showswatch = $this->page->theme->settings->colourswatch;
189 } else {
190 $showswatch = '';
191 }
192 if ($showswatch == 'light') {
193 $dtheme = 'd';
194 } else {
195 $dtheme = 'c';
196 }
256c51fa
JS
197 if ($testc == "mod_quiz_navblock") {
198 $collap = 'false';
199 } else {
200 $collap = 'true';
201 }
202 $output = html_writer::start_tag('div', array('data-role' => 'collapsible', 'data-collapsed' => $collap, 'data-content-theme' => $dtheme));
2fd7abbb 203 }
3c0c2bf0
SH
204
205 $output .= html_writer::tag('h1', $this->block_header($bc));
2fd7abbb 206 $output .= html_writer::start_tag('div', $bc->attributes);
207 $output .= $this->block_content($bc);
2fd7abbb 208 $output .= html_writer::end_tag('div');
209 $output .= html_writer::end_tag('div');
210
211 $output .= $this->block_annotation($bc);
212
213 $output .= $skipdest;
214
215 return $output;
216 }
217
3c0c2bf0
SH
218 /**
219 * Produces a blocks header
220 *
221 * @param block_contents $bc
222 * @return string
223 */
2fd7abbb 224 protected function block_header(block_contents $bc) {
2fd7abbb 225 $title = '';
3c0c2bf0
SH
226 if (!$bc->title) {
227 return '&nbsp;';
2fd7abbb 228 }
3c0c2bf0
SH
229 $output = html_writer::start_tag('div', array('class' => 'header'));
230 $output .= html_writer::tag('div', html_writer::tag('div', '', array('class'=>'block_action')). $bc->title, array('class' => 'title'));
231 $output .= html_writer::end_tag('div');
2fd7abbb 232 return $output;
233 }
234
3c0c2bf0
SH
235 /**
236 * An evil function we don't want to execute
237 *
238 * @param block_contents $bc
239 */
240 protected function init_block_hider_js(block_contents $bc) {
241 // The mymobile theme in no shape or form supports the hiding of blocks
242 // this function has been defined and left empty intentionally so that
243 // the block hider JS is not even included.
2fd7abbb 244 }
2fd7abbb 245
3c0c2bf0
SH
246 /**
247 * Produces the navigation bar for the mymobile theme
248 *
249 * @return string
250 */
251 public function navbar() {
252 $items = $this->page->navbar->get_items();
2fd7abbb 253
3c0c2bf0 254 $htmlblocks = array(html_writer::tag('option', get_string('navigation'), array('data-placeholder' => 'true', 'value' => '-1')));
2fd7abbb 255 // Iterate the navarray and display each node
256 $itemcount = count($items);
257 $separator = "";
3c0c2bf0
SH
258
259 for ($i = 0; $i < $itemcount; $i++) {
2fd7abbb 260 $item = $items[$i];
261 $item->hideicon = true;
3c0c2bf0
SH
262 if ($i === 0) {
263 $content = html_writer::tag('option', $this->render($item), array('value' => (string)$item->action));
264 } else if (!empty($item->action)) {
265 $content = html_writer::tag('option', $this->render($item), array('value' => (string)$item->action));
2fd7abbb 266 } else {
3c0c2bf0 267 $content = '';
2fd7abbb 268 }
269 $htmlblocks[] = $content;
270 }
271
3c0c2bf0
SH
272 $navbarcontent = html_writer::start_tag('form', array('id' => 'navselectform'));
273 $navbarcontent .= html_writer::start_tag('select', array('id' => 'navselect', 'data-theme' => 'c', 'data-inline' => 'false', 'data-icon' => 'false'));
274 $navbarcontent .= join('', $htmlblocks);
275 $navbarcontent .= html_writer::end_tag('select');
276 $navbarcontent .= html_writer::end_tag('form');
2fd7abbb 277 // XHTML
278 return $navbarcontent;
3c0c2bf0 279 }
2fd7abbb 280
3c0c2bf0
SH
281 /**
282 * Renders a navigation node
283 *
284 * This function has been overridden to remove tabindexs
285 *
286 * @param navigation_node $item
287 * @return string
288 */
289 protected function render_navigation_node(navigation_node $item) {
290 // Generate the content normally
291 $content = parent::render_navigation_node($item);
292 // Strip out any tabindex's
293 $content = str_replace(' tabindex="0"', '', $content);
294 $content = str_replace(' tabindex=\'0\'', '', $content);
295 // Return the cleaned content
2fd7abbb 296 return $content;
297 }
298
3c0c2bf0
SH
299 /**
300 * Displays login info
301 *
302 * @return string
303 */
7e6c6743 304 public function login_info($withlinks = null) {
2fd7abbb 305 global $USER, $CFG, $DB, $SESSION;
306
307 if (during_initial_install()) {
308 return '';
309 }
310
c443c95c 311 $course = $this->page->course;
01ac2cd8 312
2fd7abbb 313 if (session_is_loggedinas()) {
314 $realuser = session_get_realuser();
315 $fullname = fullname($realuser, true);
01ac2cd8 316 $realuserinfo = " [<a href=\"$CFG->wwwroot/course/loginas.php?id=$course->id&amp;sesskey=".sesskey()."\">$fullname</a>] ";
2fd7abbb 317 } else {
318 $realuserinfo = '';
319 }
320
321 $loginurl = get_login_url();
322
323 if (empty($course->id)) {
324 // $course->id is not defined during installation
325 return '';
326 } else if (isloggedin()) {
43731030 327 $context = context_course::instance($course->id);
c443c95c 328 $fullname = fullname($USER, true);
01ac2cd8 329
2fd7abbb 330 // Since Moodle 2.0 this link always goes to the public profile page (not the course profile page)
01ac2cd8
DW
331 // TODO: Test what happens when someone is using this via mnet [for this as well as login_info_footer]
332 // TODO: Test what happens when you use the loginas feature [for this as well as login_info_footer]
333 $username = "";
2fd7abbb 334 if (is_mnet_remote_user($USER) and $idprovider = $DB->get_record('mnet_host', array('id'=>$USER->mnethostid))) {
01ac2cd8 335 $username .= " from <a href=\"{$idprovider->wwwroot}\">{$idprovider->name}</a>";
2fd7abbb 336 }
337 if (isguestuser()) {
01ac2cd8 338 $loggedinas = $realuserinfo.get_string('loggedinasguest')." (<a href=\"$loginurl\">".get_string('login').'</a>)';
2fd7abbb 339 } else if (is_role_switched($course->id)) { // Has switched roles
340 $rolename = '';
341 if ($role = $DB->get_record('role', array('id'=>$USER->access['rsw'][$context->path]))) {
342 $rolename = ': '.format_string($role->name);
343 }
2fd7abbb 344 } else {
7e6c6743 345 $loggedinas = $realuserinfo.$username.' <a id="mypower" data-inline="true" data-role="button" data-icon="mypower" data-ajax="false" class="ui-btn-right mypower" href="'.$CFG->wwwroot.'/login/logout.php?sesskey='.sesskey().'\">'.get_string('logout').'</a>';
2fd7abbb 346 }
347 } else {
01ac2cd8 348 $loggedinas = '<a data-role="button" data-icon="alert" class="ui-btn-right nolog" href="'.$loginurl.'" data-ajax="false">'.get_string('login').'</a>';
2fd7abbb 349 }
350
01ac2cd8
DW
351 // TODO: Enable $CFG->displayloginfailures and test as admin what happens after you succesfully
352 // log in after a failed log in attempt. [for this as well as login_info_footer]
353 // This is probably totally unneeded
2fd7abbb 354 if (isset($SESSION->justloggedin)) {
355 unset($SESSION->justloggedin);
356 if (!empty($CFG->displayloginfailures)) {
357 if (!isguestuser()) {
358 if ($count = count_login_failures($CFG->displayloginfailures, $USER->username, $USER->lastlogin)) {
359 $loggedinas .= '&nbsp;<div class="loginfailures">';
360 if (empty($count->accounts)) {
361 $loggedinas .= get_string('failedloginattempts', '', $count);
362 } else {
363 $loggedinas .= get_string('failedloginattemptsall', '', $count);
364 }
43731030 365 if (file_exists("$CFG->dirroot/report/log/index.php") and has_capability('report/log:view', context_system::instance())) {
01ac2cd8 366 $loggedinas .= ' (<a href="'.$CFG->wwwroot.'/course/report/log/index.php?chooselog=1&amp;id=1&amp;modid=site_errors">'.get_string('logs').'</a>)';
2fd7abbb 367 }
368 $loggedinas .= '</div>';
369 }
370 }
371 }
372 }
373
374 return $loggedinas;
375 }
376
3c0c2bf0
SH
377 /**
378 * Displays login info in the footer
379 *
380 * @return string
381 */
382 public function login_info_footer() {
2fd7abbb 383 global $USER, $CFG, $DB, $SESSION;
384
385 if (during_initial_install()) {
386 return '';
387 }
388
4a645a68 389 $loginpage = ((string)$this->page->url === get_login_url());
2fd7abbb 390 $course = $this->page->course;
391
392 if (session_is_loggedinas()) {
393 $realuser = session_get_realuser();
394 $fullname = fullname($realuser, true);
395 $realuserinfo = ' [<a href="'.$CFG->wwwroot.'/course/loginas.php?id=$course->id&amp;sesskey='.sesskey().'">$fullname</a>] ';
396 } else {
397 $realuserinfo = '';
398 }
399
400 $loginurl = get_login_url();
401
402 if (empty($course->id)) {
403 // $course->id is not defined during installation
404 return '';
405 } else if (isloggedin()) {
01ac2cd8 406 $context = context_course::instance($course->id);
2fd7abbb 407
408 $fullname = fullname($USER, true);
409 // Since Moodle 2.0 this link always goes to the public profile page (not the course profile page)
410 $username = '<a href="'.$CFG->wwwroot.'/user/profile.php?id='.$USER->id.'">'.$fullname.'</a>';
411 if (is_mnet_remote_user($USER) and $idprovider = $DB->get_record('mnet_host', array('id'=>$USER->mnethostid))) {
412 $username .= " from <a href=\"{$idprovider->wwwroot}\">{$idprovider->name}</a>";
413 }
414 if (isguestuser()) {
415 $loggedinas = $realuserinfo.get_string('loggedinasguest');
4a645a68 416 if (!$loginpage) {
2fd7abbb 417 $loggedinas .= " (<a href=\"$loginurl\">".get_string('login').'</a>)';
418 }
419 } else if (is_role_switched($course->id)) { // Has switched roles
420 $rolename = '';
421 if ($role = $DB->get_record('role', array('id'=>$USER->access['rsw'][$context->path]))) {
f2cf0f84 422 $rolename = ': '.role_get_name($role, $context);
2fd7abbb 423 }
3c0c2bf0 424 $loggedinas = get_string('loggedinas', 'moodle', $username).$rolename." (<a href=\"$CFG->wwwroot/course/view.php?id=$course->id&amp;switchrole=0&amp;sesskey=".sesskey()."\">".get_string('switchrolereturn').'</a>)';
2fd7abbb 425 } else {
3c0c2bf0 426 $loggedinas = $realuserinfo.get_string('loggedinas', 'moodle', $username).' '." (<a href=\"$CFG->wwwroot/login/logout.php?sesskey=".sesskey()."\" data-ajax=\"false\">".get_string('logout').'</a>)';
2fd7abbb 427 }
428 } else {
429 $loggedinas = get_string('loggedinnot', 'moodle');
4a645a68 430 if (!$loginpage) {
b35bf958 431 $loggedinas .= " (<a href=\"$loginurl\" data-ajax=\"false\">".get_string('login').'</a>)';
2fd7abbb 432 }
433 }
434
435 $loggedinas = '<div class="logininfo">'.$loggedinas.'</div>';
436
437 if (isset($SESSION->justloggedin)) {
438 unset($SESSION->justloggedin);
439 if (!empty($CFG->displayloginfailures)) {
440 if (!isguestuser()) {
441 if ($count = count_login_failures($CFG->displayloginfailures, $USER->username, $USER->lastlogin)) {
442 $loggedinas .= '&nbsp;<div class="loginfailures">';
443 if (empty($count->accounts)) {
444 $loggedinas .= get_string('failedloginattempts', '', $count);
445 } else {
446 $loggedinas .= get_string('failedloginattemptsall', '', $count);
447 }
01ac2cd8 448 if (has_capability('report/log:view', context_system::instance())) {
3c0c2bf0 449 $loggedinas .= ' (<a href="'.$CFG->wwwroot.'/course/report/log/index.php?chooselog=1&amp;id=1&amp;modid=site_errors">'.get_string('logs').'</a>)';
2fd7abbb 450 }
451 $loggedinas .= '</div>';
452 }
453 }
454 }
455 }
456
457 return $loggedinas;
458 }
459
3c0c2bf0
SH
460 /**
461 * Prints a message and redirects
462 *
463 * @param string $encodedurl
464 * @param string $message
465 * @param int $delay
466 * @param true $debugdisableredirect
467 * @return type
468 */
469 public function redirect_message($encodedurl, $message, $delay, $debugdisableredirect) {
2fd7abbb 470 global $CFG;
471 $url = str_replace('&amp;', '&', $encodedurl);
3c0c2bf0
SH
472 // TODO: Find a much better solution for this... looks like it is just removing
473 // the anchor from the link.
474 // The below to fix redirect issues with ajax... John
2fd7abbb 475 $encodedurl = str_replace('#', '&', $encodedurl);
3c0c2bf0 476
2fd7abbb 477 switch ($this->page->state) {
478 case moodle_page::STATE_BEFORE_HEADER :
479 // No output yet it is safe to delivery the full arsenal of redirect methods
480 if (!$debugdisableredirect) {
481 // Don't use exactly the same time here, it can cause problems when both redirects fire at the same time.
482 $this->metarefreshtag = '<meta http-equiv="refresh" content="'. $delay .'; url='. $encodedurl .'" />'."\n";
2fd7abbb 483 }
484 $output = $this->header();
485 break;
486 case moodle_page::STATE_PRINTING_HEADER :
487 // We should hopefully never get here
488 throw new coding_exception('You cannot redirect while printing the page header');
489 break;
490 case moodle_page::STATE_IN_BODY :
491 // We really shouldn't be here but we can deal with this
492 debugging("You should really redirect before you start page output");
493 if (!$debugdisableredirect) {
494 $this->page->requires->js_function_call('document.location.replace', array($url), false, $delay);
495 }
496 $output = $this->opencontainers->pop_all_but_last();
497 break;
498 case moodle_page::STATE_DONE :
499 // Too late to be calling redirect now
500 throw new coding_exception('You cannot redirect after the entire page has been generated');
501 break;
502 }
3c0c2bf0 503
2fd7abbb 504 $output .= $this->notification($message, 'redirectmessage');
2fd7abbb 505 $output .= '<div class="continuebutton"><a data-ajax="false" data-role="button" href="'. $encodedurl .'">'. get_string('continue') .'</a></div>';
2fd7abbb 506 if ($debugdisableredirect) {
507 $output .= '<p><strong>Error output, so disabling automatic redirect.</strong></p>';
508 }
509 $output .= $this->footer();
510 return $output;
511 }
2fd7abbb 512
3c0c2bf0
SH
513 /**
514 * Renders a help icon
515 *
516 * @param help_icon $helpicon
517 * @return string
518 */
519 protected function render_help_icon(help_icon $helpicon) {
2fd7abbb 520 global $CFG;
521
522 // first get the help image icon
523 $src = $this->pix_url('help');
524
525 $title = get_string($helpicon->identifier, $helpicon->component);
526
527 if (empty($helpicon->linktext)) {
528 $alt = $title;
529 } else {
530 $alt = get_string('helpwiththis');
531 }
532
533 $attributes = array('src'=>$src, 'alt'=>$alt, 'class'=>'iconhelp', 'data-role'=>'button', 'data-inline'=>'true');
534 $output = html_writer::empty_tag('img', $attributes);
535
536 // add the link text if given
537 if (!empty($helpicon->linktext)) {
538 // the spacing has to be done through CSS
539 $output .= $helpicon->linktext;
540 }
541
542 // now create the link around it
3c0c2bf0 543 // TODO: Do we need to specify the theme in the help.php link?
2fd7abbb 544 $url = new moodle_url('/help.php', array('component' => $helpicon->component, 'identifier' => $helpicon->identifier, 'lang'=>current_language(), 'theme'=>'mymobile'));
545
546 // note: this title is displayed only if JS is disabled, otherwise the link will have the new ajax tooltip
547 $title = get_string('helpprefix2', '', trim($title, ". \t"));
548
549 $attributes = array('href'=>$url, 'title'=>$title);
550 $id = html_writer::random_id('helpicon');
551 $attributes['id'] = $id;
552 $attributes['rel'] = 'notexternal';
553 $attributes['data-rel'] = 'dialog';
256c51fa 554 $attributes['data-transition'] = 'flow';
2fd7abbb 555 $output = html_writer::tag('a', $output, $attributes);
556
557 // and finally span
558 return html_writer::tag('span', $output, array('class' => 'helplink2'));
559 }
2fd7abbb 560
3c0c2bf0
SH
561 /**
562 * Renders a single button
563 *
564 * @param single_button $button
565 * @return string
566 */
567 protected function render_single_button(single_button $button) {
568 $attributes = array(
569 'type' => 'submit',
570 'value' => $button->label,
571 'disabled' => $button->disabled ? 'disabled' : null,
572 'title' => $button->tooltip
573 );
2fd7abbb 574
575 if ($button->actions) {
576 $id = html_writer::random_id('single_button');
577 $attributes['id'] = $id;
578 foreach ($button->actions as $action) {
579 $this->add_action_handler($action, $id);
580 }
581 }
582
583 // first the input element
584 $output = html_writer::empty_tag('input', $attributes);
585
586 // then hidden fields
587 $params = $button->url->params();
588 if ($button->method === 'post') {
589 $params['sesskey'] = sesskey();
590 }
591 foreach ($params as $var => $val) {
592 $output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => $var, 'value' => $val));
593 }
594
595 // then div wrapper for xhtml strictness
3c0c2bf0
SH
596 $output = html_writer::tag('div', $output, array('rel' => $button->url->out_omit_querystring()));
597
598 // TODO: Test a single_button that has an anchor and is set to use post
2fd7abbb 599 // now the form itself around it
600 $url = $button->url->out_omit_querystring(); // url without params
3c0c2bf0
SH
601
602 if ($url === '') {
2fd7abbb 603 $url = '#'; // there has to be always some action
604 }
3c0c2bf0
SH
605
606 // TODO: This is surely a bug that needs fixing.. all of a sudden we've switched
607 // to the pages URL.
608 // Test an single button with an external URL as its url
609 // If the url has http, cool, if not we need to add it, JOHN
610 $urlcheck = substr($url, 0, 4);
611 if ($urlcheck != 'http') {
612 $url = $this->page->url->out_omit_querystring();
613 }
614
615 $attributes = array(
616 'method' => $button->method,
617 'action' => $url,
618 'id' => $button->formid
619 );
2fd7abbb 620 $output = html_writer::tag('form', $output, $attributes);
621
622 // and finally one more wrapper with class
623 return html_writer::tag('div', $output, array('class' => $button->class));
624 }
3c0c2bf0
SH
625
626 /**
627 * Renders the header for the page
628 *
629 * @return string
630 */
631 public function header() {
2fd7abbb 632 global $USER, $CFG;
633
634 if (session_is_loggedinas()) {
635 $this->page->add_body_class('userloggedinas');
636 }
3c0c2bf0 637
42d79f55
GB
638 // Give themes a chance to init/alter the page object.
639 $this->page->theme->init_page($this->page);
640
2fd7abbb 641 $this->page->set_state(moodle_page::STATE_PRINTING_HEADER);
642
643 // Find the appropriate page layout file, based on $this->page->pagelayout.
2fd7abbb 644 $layoutfile = $this->page->theme->layout_file($this->page->pagelayout);
645 // Render the layout using the layout file.
646 $rendered = $this->render_page_layout($layoutfile);
647
648 // Slice the rendered output into header and footer.
3c0c2bf0 649 $cutpos = strpos($rendered, $this->unique_main_content_token);
2fd7abbb 650 if ($cutpos === false) {
3c0c2bf0
SH
651 $cutpos = strpos($rendered, self::MAIN_CONTENT_TOKEN);
652 $token = self::MAIN_CONTENT_TOKEN;
653 } else {
654 $token = $this->unique_main_content_token;
655 }
656
657 if ($cutpos === false) {
658 // TODO: Search for a better solution to this... check this is even needed?
659 // The following code will lead to header containing nothing, and
660 // footer containing all of the content for the template.
661 // turned off error by john for ajax load of blocks without main content.
662 // throw new coding_exception('page layout file ' . $layoutfile .
2fd7abbb 663 // ' does not contain the string "' . self::MAIN_CONTENT_TOKEN . '".');
664 }
665 $header = substr($rendered, 0, $cutpos);
3c0c2bf0 666 $footer = substr($rendered, $cutpos + strlen($token));
2fd7abbb 667
668 if (empty($this->contenttype)) {
669 debugging('The page layout file did not call $OUTPUT->doctype()');
670 $header = $this->doctype() . $header;
671 }
672
673 send_headers($this->contenttype, $this->page->cacheable);
674
675 $this->opencontainers->push('header/footer', $footer);
676 $this->page->set_state(moodle_page::STATE_IN_BODY);
677
678 return $header . $this->skip_link_target('maincontent');
679 }
680
3c0c2bf0
SH
681 /**
682 * Renders a notification
683 *
684 * @param string $message
685 * @param string $classes
686 * @return string
687 */
688 public function notification($message, $classes = 'notifyproblem') {
2fd7abbb 689 return html_writer::tag('div', clean_text($message), array('data-role'=>'none', 'data-icon'=>'alert', 'data-theme'=>'d', 'class' => renderer_base::prepare_classes($classes)));
690 }
3c0c2bf0
SH
691
692 /**
693 * Renders the blocks for a block region in the page
694 *
695 * @param type $region
696 * @return string
697 */
698 public function blocks_for_region($region) {
2fd7abbb 699 $blockcontents = $this->page->blocks->get_content_for_region($region, $this);
6671fa73
JF
700 $blocks = $this->page->blocks->get_blocks_for_region($region);
701 $lastblock = null;
702 $zones = array();
703 foreach ($blocks as $block) {
704 $zones[] = $block->title;
705 }
0e2ca62e 706
2fd7abbb 707 $output = '';
708 foreach ($blockcontents as $bc) {
709 if ($bc instanceof block_contents) {
6671fa73 710 $lastblock = $bc->title;
3c0c2bf0
SH
711 // We don't want to print navigation and settings blocks here.
712 if ($bc->attributes['class'] != 'block_settings block' && $bc->attributes['class'] != 'block_navigation block') {
2fd7abbb 713 $output .= $this->block($bc, $region);
714 }
715 } else if ($bc instanceof block_move_target) {
6671fa73 716 $output .= $this->block_move_target($bc, $zones, $lastblock);
2fd7abbb 717 } else {
718 throw new coding_exception('Unexpected type of thing (' . get_class($bc) . ') found in list of block contents.');
719 }
720 }
3c0c2bf0 721
2fd7abbb 722 return $output;
723 }
724
3c0c2bf0
SH
725 /**
726 * Renders a single select instance
727 *
728 * @param single_select $select
729 * @return string
730 */
731 protected function render_single_select(single_select $select) {
2fd7abbb 732 $select = clone($select);
733 if (empty($select->formid)) {
734 $select->formid = html_writer::random_id('single_select_f');
735 }
736
737 $output = '';
738 $params = $select->url->params();
739 if ($select->method === 'post') {
740 $params['sesskey'] = sesskey();
741 }
742 foreach ($params as $name=>$value) {
743 $output .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>$name, 'value'=>$value));
744 }
745
746 if (empty($select->attributes['id'])) {
747 $select->attributes['id'] = html_writer::random_id('single_select');
3c0c2bf0
SH
748 //$select->attributes['data-native-menu'] = 'false';
749 //above by john for select elements to use native style and help performance?
2fd7abbb 750 }
751
752 if ($select->disabled) {
753 $select->attributes['disabled'] = 'disabled';
754 }
755
756 if ($select->tooltip) {
757 $select->attributes['title'] = $select->tooltip;
758 }
759
01ac2cd8
DW
760 $select->attributes['class'] = 'autosubmit';
761 if ($select->class) {
762 $select->attributes['class'] .= ' ' . $select->class;
763 }
764
2fd7abbb 765 if ($select->label) {
766 $output .= html_writer::label($select->label, $select->attributes['id']);
767 }
768
769 if ($select->helpicon instanceof help_icon) {
770 $output .= $this->render($select->helpicon);
2fd7abbb 771 }
772
773 $output .= html_writer::select($select->options, $select->name, $select->selected, $select->nothing, $select->attributes);
3c0c2bf0 774
2fd7abbb 775 //by john show go button to fix selects
776 $go = '';
256c51fa 777 $output .= html_writer::empty_tag('input data-inline="true"', array('type' => 'submit','value' => get_string('go')));
3c0c2bf0 778 $output .= html_writer::tag('noscript', html_writer::tag('div', $go), array('style' => 'inline'));
2fd7abbb 779
780 $nothing = empty($select->nothing) ? false : key($select->nothing);
01ac2cd8
DW
781 $this->page->requires->yui_module('moodle-core-formautosubmit',
782 'M.core.init_formautosubmit',
783 array(array('selectid' => $select->attributes['id'], 'nothing' => $nothing))
784 );
2fd7abbb 785
786 // then div wrapper for xhtml strictness
787 $output = html_writer::tag('div', $output);
788
789 // now the form itself around it
3c0c2bf0
SH
790 $formattributes = array(
791 'method' => $select->method,
792 'action' => $select->url->out_omit_querystring(),
793 'id' => $select->formid
794 );
2fd7abbb 795 $output = html_writer::tag('form', $output, $formattributes);
796
797 // and finally one more wrapper with class
798 return html_writer::tag('div', $output, array('class' => $select->class));
799 }
2fd7abbb 800}
801
3c0c2bf0 802/**
1d4bfa09 803 * Overridden choice module renderer for the mymobile theme
3c0c2bf0
SH
804 *
805 * @package theme
806 * @subpackage mymobile
807 * @copyright John Stabinger
808 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
809 */
2fd7abbb 810
1d4bfa09
ME
811$choice = get_plugin_directory('mod', 'choice');
812if (file_exists($choice . '/renderer.php')) {
813 require_once($CFG->dirroot . '/theme/mymobile/renderers/mod_choice_renderer.php');
cf2de1cf 814}