MDL-35876: Whitespace, indenting and more verbose upgrade.txt
[moodle.git] / theme / mymobile / renderers.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 /**
18  * Renderers for the mymobile theme
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  */
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  */
35 class theme_mymobile_renderer extends plugin_renderer_base {
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'));
45         if (has_capability('moodle/site:config', context_system::instance())) {
46             // TODO: Work out whether something is missing from here.
47         }
48         return $content;
49     }
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());
59     }
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;
71         // exit if empty, we don't want an empty ul element
72         if ($items->count() == 0) {
73             return '';
74         }
76         // array of nested li elements
77         $lis = array();
78         foreach ($items as $item) {
79             if (!$item->display) {
80                 continue;
81             }
83             $isbranch = ($item->children->count() > 0 || $item->nodetype == navigation_node::NODETYPE_BRANCH);
84             $item->hideicon = true;
86             $content = $this->output->render($item);
87             $content .= $this->navigation_node($item);
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);
102     }
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  */
113 class theme_mymobile_core_renderer extends core_renderer {
115     /**
116      * Returns the dtheme to use for the selected swatch
117      *
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;
124         }
125         if ($showswatch == 'light') {
126             $dtheme = 'b';
127         } else {
128             $dtheme = 'd';
129         }
130         return $dtheme;
131      }
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);
146         } else {
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');
150         }
151         return $content;
152     }
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();
169         // TODO: Do we still need to support accessibility here? Surely screen
170         // readers don't present themselves as mobile devices too often.
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'];
180         $testc = $bc->attributes['id'];
181         // TODO: Find a better solution to this hardcoded block checks.
182         if ($testb == "block_calendar_month2  block") {
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             }
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));
203         }
205         $output .= html_writer::tag('h1', $this->block_header($bc));
206         $output .= html_writer::start_tag('div', $bc->attributes);
207         $output .= $this->block_content($bc);
208         $output .= html_writer::end_tag('div');
209         $output .= html_writer::end_tag('div');
211         $output .= $this->block_annotation($bc);
213         $output .= $skipdest;
215         return $output;
216     }
218     /**
219      * Produces a blocks header
220      *
221      * @param block_contents $bc
222      * @return string
223      */
224     protected function block_header(block_contents $bc) {
225         $title = '';
226         if (!$bc->title) {
227             return '&nbsp;';
228         }
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');
232         return $output;
233     }
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.
244     }
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();
254         $htmlblocks = array(html_writer::tag('option', get_string('navigation'), array('data-placeholder' => 'true', 'value' => '-1')));
255         // Iterate the navarray and display each node
256         $itemcount = count($items);
257         $separator = "";
259         for ($i = 0; $i < $itemcount; $i++) {
260             $item = $items[$i];
261             $item->hideicon = true;
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));
266             } else {
267                 $content = '';
268             }
269             $htmlblocks[] = $content;
270         }
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');
277         // XHTML
278         return $navbarcontent;
279     }
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
296         return $content;
297     }
299     /**
300      * Displays login info
301      *
302      * @return string
303      */
304     public function login_info($withlinks = null) {
305         global $USER, $CFG, $DB, $SESSION;
307         if (during_initial_install()) {
308             return '';
309         }
311         $course = $this->page->course;
313         if (session_is_loggedinas()) {
314             $realuser = session_get_realuser();
315             $fullname = fullname($realuser, true);
316             $realuserinfo = " [<a href=\"$CFG->wwwroot/course/loginas.php?id=$course->id&amp;sesskey=".sesskey()."\">$fullname</a>] ";
317         } else {
318             $realuserinfo = '';
319         }
321         $loginurl = get_login_url();
323         if (empty($course->id)) {
324             // $course->id is not defined during installation
325             return '';
326         } else if (isloggedin()) {
327             $context = context_course::instance($course->id);
328             $fullname = fullname($USER, true);
330             // Since Moodle 2.0 this link always goes to the public profile page (not the course profile page)
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 = "";
334             if (is_mnet_remote_user($USER) and $idprovider = $DB->get_record('mnet_host', array('id'=>$USER->mnethostid))) {
335                 $username .= " from <a href=\"{$idprovider->wwwroot}\">{$idprovider->name}</a>";
336             }
337             if (isguestuser()) {
338                 $loggedinas = $realuserinfo.get_string('loggedinasguest')." (<a href=\"$loginurl\">".get_string('login').'</a>)';
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                 }
344             } else {
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>';
346             }
347         } else {
348             $loggedinas = '<a data-role="button" data-icon="alert" class="ui-btn-right nolog" href="'.$loginurl.'" data-ajax="false">'.get_string('login').'</a>';
349         }
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
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                         }
365                         if (file_exists("$CFG->dirroot/report/log/index.php") and has_capability('report/log:view', context_system::instance())) {
366                             $loggedinas .= ' (<a href="'.$CFG->wwwroot.'/course/report/log/index.php?chooselog=1&amp;id=1&amp;modid=site_errors">'.get_string('logs').'</a>)';
367                         }
368                         $loggedinas .= '</div>';
369                     }
370                 }
371             }
372         }
374         return $loggedinas;
375     }
377     /**
378      * Displays login info in the footer
379      *
380      * @return string
381      */
382     public function login_info_footer() {
383         global $USER, $CFG, $DB, $SESSION;
385         if (during_initial_install()) {
386             return '';
387         }
389         $loginpage = ((string)$this->page->url === get_login_url());
390         $course = $this->page->course;
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         }
400         $loginurl = get_login_url();
402         if (empty($course->id)) {
403             // $course->id is not defined during installation
404             return '';
405         } else if (isloggedin()) {
406             $context = context_course::instance($course->id);
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');
416                 if (!$loginpage) {
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]))) {
422                     $rolename = ': '.role_get_name($role, $context);
423                 }
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>)';
425             } else {
426                 $loggedinas = $realuserinfo.get_string('loggedinas', 'moodle', $username).' '." (<a href=\"$CFG->wwwroot/login/logout.php?sesskey=".sesskey()."\" data-ajax=\"false\">".get_string('logout').'</a>)';
427             }
428         } else {
429             $loggedinas = get_string('loggedinnot', 'moodle');
430             if (!$loginpage) {
431                 $loggedinas .= " (<a href=\"$loginurl\" data-ajax=\"false\">".get_string('login').'</a>)';
432             }
433         }
435         $loggedinas = '<div class="logininfo">'.$loggedinas.'</div>';
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                         }
448                         if (has_capability('report/log:view', context_system::instance())) {
449                             $loggedinas .= ' (<a href="'.$CFG->wwwroot.'/course/report/log/index.php?chooselog=1&amp;id=1&amp;modid=site_errors">'.get_string('logs').'</a>)';
450                         }
451                         $loggedinas .= '</div>';
452                     }
453                 }
454             }
455         }
457         return $loggedinas;
458     }
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) {
470         global $CFG;
471         $url = str_replace('&amp;', '&', $encodedurl);
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
475         $encodedurl = str_replace('#', '&', $encodedurl);
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";
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         }
504         $output .= $this->notification($message, 'redirectmessage');
505         $output .= '<div class="continuebutton"><a data-ajax="false" data-role="button" href="'. $encodedurl .'">'. get_string('continue') .'</a></div>';
506         if ($debugdisableredirect) {
507             $output .= '<p><strong>Error output, so disabling automatic redirect.</strong></p>';
508         }
509         $output .= $this->footer();
510         return $output;
511     }
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) {
520         global $CFG;
522         // first get the help image icon
523         $src = $this->pix_url('help');
525         $title = get_string($helpicon->identifier, $helpicon->component);
527         if (empty($helpicon->linktext)) {
528             $alt = $title;
529         } else {
530             $alt = get_string('helpwiththis');
531         }
533         $attributes = array('src'=>$src, 'alt'=>$alt, 'class'=>'iconhelp', 'data-role'=>'button', 'data-inline'=>'true');
534         $output = html_writer::empty_tag('img', $attributes);
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         }
542         // now create the link around it
543         // TODO: Do we need to specify the theme in the help.php link?
544         $url = new moodle_url('/help.php', array('component' => $helpicon->component, 'identifier' => $helpicon->identifier, 'lang'=>current_language(), 'theme'=>'mymobile'));
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"));
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';
554         $attributes['data-transition'] = 'flow';
555         $output = html_writer::tag('a', $output, $attributes);
557         // and finally span
558         return html_writer::tag('span', $output, array('class' => 'helplink2'));
559     }
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         );
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         }
583         // first the input element
584         $output = html_writer::empty_tag('input', $attributes);
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         }
595         // then div wrapper for xhtml strictness
596         $output = html_writer::tag('div', $output, array('rel' => $button->url->out_omit_querystring()));
598         // TODO: Test a single_button that has an anchor and is set to use post
599         // now the form itself around it
600         $url = $button->url->out_omit_querystring(); // url without params
602         if ($url === '') {
603             $url = '#'; // there has to be always some action
604         }
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         }
615         $attributes = array(
616             'method' => $button->method,
617             'action' => $url,
618             'id'     => $button->formid
619         );
620         $output = html_writer::tag('form', $output, $attributes);
622         // and finally one more wrapper with class
623         return html_writer::tag('div', $output, array('class' => $button->class));
624     }
626     /**
627      * Renders the header for the page
628      *
629      * @return string
630      */
631     public function header() {
632         global $USER, $CFG;
634         if (session_is_loggedinas()) {
635             $this->page->add_body_class('userloggedinas');
636         }
638         // Give themes a chance to init/alter the page object.
639         $this->page->theme->init_page($this->page);
641         $this->page->set_state(moodle_page::STATE_PRINTING_HEADER);
643         // Find the appropriate page layout file, based on $this->page->pagelayout.
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);
648         // Slice the rendered output into header and footer.
649         $cutpos = strpos($rendered, $this->unique_main_content_token);
650         if ($cutpos === false) {
651             $cutpos = strpos($rendered, self::MAIN_CONTENT_TOKEN);
652             $token = self::MAIN_CONTENT_TOKEN;
653         } else {
654             $token = $this->unique_main_content_token;
655         }
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 .
663             //        ' does not contain the string "' . self::MAIN_CONTENT_TOKEN . '".');
664         }
665         $header = substr($rendered, 0, $cutpos);
666         $footer = substr($rendered, $cutpos + strlen($token));
668         if (empty($this->contenttype)) {
669             debugging('The page layout file did not call $OUTPUT->doctype()');
670             $header = $this->doctype() . $header;
671         }
673         send_headers($this->contenttype, $this->page->cacheable);
675         $this->opencontainers->push('header/footer', $footer);
676         $this->page->set_state(moodle_page::STATE_IN_BODY);
678         return $header . $this->skip_link_target('maincontent');
679     }
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') {
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     }
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) {
699         $blockcontents = $this->page->blocks->get_content_for_region($region, $this);
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         }
707         $output = '';
708         foreach ($blockcontents as $bc) {
709             if ($bc instanceof block_contents) {
710                 $lastblock = $bc->title;
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') {
713                     $output .= $this->block($bc, $region);
714                 }
715             } else if ($bc instanceof block_move_target) {
716                 $output .= $this->block_move_target($bc, $zones, $lastblock);
717             } else {
718                 throw new coding_exception('Unexpected type of thing (' . get_class($bc) . ') found in list of block contents.');
719             }
720         }
722         return $output;
723     }
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) {
732         $select = clone($select);
733         if (empty($select->formid)) {
734             $select->formid = html_writer::random_id('single_select_f');
735         }
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         }
746         if (empty($select->attributes['id'])) {
747             $select->attributes['id'] = html_writer::random_id('single_select');
748             //$select->attributes['data-native-menu'] = 'false';
749             //above by john for select elements to use native style and help performance?
750         }
752         if ($select->disabled) {
753             $select->attributes['disabled'] = 'disabled';
754         }
756         if ($select->tooltip) {
757             $select->attributes['title'] = $select->tooltip;
758         }
760         $select->attributes['class'] = 'autosubmit';
761         if ($select->class) {
762             $select->attributes['class'] .= ' ' . $select->class;
763         }
765         if ($select->label) {
766             $output .= html_writer::label($select->label, $select->attributes['id']);
767         }
769         if ($select->helpicon instanceof help_icon) {
770             $output .= $this->render($select->helpicon);
771         }
773         $output .= html_writer::select($select->options, $select->name, $select->selected, $select->nothing, $select->attributes);
775         //by john show go button to fix selects
776         $go = '';
777         $output .= html_writer::empty_tag('input data-inline="true"', array('type' => 'submit','value' => get_string('go')));
778         $output .= html_writer::tag('noscript', html_writer::tag('div', $go), array('style' => 'inline'));
780         $nothing = empty($select->nothing) ? false : key($select->nothing);
781         $this->page->requires->yui_module('moodle-core-formautosubmit',
782             'M.core.init_formautosubmit',
783             array(array('selectid' => $select->attributes['id'], 'nothing' => $nothing))
784         );
786         // then div wrapper for xhtml strictness
787         $output = html_writer::tag('div', $output);
789         // now the form itself around it
790         $formattributes = array(
791             'method' => $select->method,
792             'action' => $select->url->out_omit_querystring(),
793             'id'     => $select->formid
794         );
795         $output = html_writer::tag('form', $output, $formattributes);
797         // and finally one more wrapper with class
798         return html_writer::tag('div', $output, array('class' => $select->class));
799     }
802 /**
803  * Overridden choice module renderer for the mymobile theme
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  */
811 $choice = get_plugin_directory('mod', 'choice');
812 if (file_exists($choice . '/renderer.php')) {
813     require_once($CFG->dirroot . '/theme/mymobile/renderers/mod_choice_renderer.php');