f7c253c5275096295455bf6ead97889fd8973f91
[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  */
34 class theme_mymobile_renderer extends plugin_renderer_base {
36     /**
37      * Produces the settings tree
38      *
39      * @param settings_navigation $navigation
40      * @return string
41      */
42     public function settings_tree(settings_navigation $navigation) {
43         $content = $this->navigation_node($navigation, array('class' => 'settings'));
44         if (has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) {
45             // TODO: Work out whether something is missing from here.
46         }
47         return $content;
48     }
50     /**
51      * Produces the navigation tree
52      *
53      * @param global_navigation $navigation
54      * @return string
55      */
56     public function navigation_tree(global_navigation $navigation) {
57         return $this->navigation_node($navigation, array());
58     }
60     /**
61      * Protected method to render a navigaiton node
62      *
63      * @param navigation_node $node
64      * @param array $attrs
65      * @return type
66      */
67     protected function navigation_node(navigation_node $node, $attrs = array()) {
68         $items = $node->children;
70         // exit if empty, we don't want an empty ul element
71         if ($items->count() == 0) {
72             return '';
73         }
75         // array of nested li elements
76         $lis = array();
77         foreach ($items as $item) {
78             if (!$item->display) {
79                 continue;
80             }
82             $isbranch = ($item->children->count() > 0 || $item->nodetype == navigation_node::NODETYPE_BRANCH);
83             $item->hideicon = true;
85             $content = $this->output->render($item);
86             $content .= $this->navigation_node($item);
88             if ($isbranch && !(is_string($item->action) || empty($item->action))) {
89                 $content = html_writer::tag('li', $content, array('data-role' => 'list-divider', 'class' => (string)$item->key));
90             } else if($isbranch) {
91                 $content = html_writer::tag('li', $content, array('data-role' => 'list-divider'));
92             } else {
93                 $content = html_writer::tag('li', $content, array('class' => (string)$item->text));
94             }
95             $lis[] = $content;
96         }
97         if (!count($lis)) {
98             return '';
99         }
100         return implode("\n", $lis);
101     }
104 /**
105  * Overridden core renderer for the mymobile theme
106  *
107  * @package    theme
108  * @subpackage mymobile
109  * @copyright  John Stabinger
110  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
111  */
112 class theme_mymobile_core_renderer extends core_renderer {
114     /**
115      * Returns the dtheme to use for the selected swatch
116      *
117      * @return string
118      */
119     protected function theme_swatch() {
120         $showswatch = 'light';
121         if (!empty($this->page->theme->settings->colourswatch)) {
122             $showswatch = $this->page->theme->settings->colourswatch;
123         }
124         if ($showswatch == 'light') {
125             $dtheme = 'b';
126         } else {
127             $dtheme = 'd';
128         }
129         return $dtheme;
130      }
132      /**
133       * Produces a heading
134       *
135       * @param string $text
136       * @param int $level
137       * @param string $classes
138       * @param string $id
139       * @return string
140       */
141      public function heading($text, $level = 2, $classes = 'main', $id = null) {
142         if ($classes == 'helpheading') {
143             // Keeps wrap from help headings in dialog.
144             $content = parent::heading($text, $level, $classes, $id);
145         } else {
146             $content  = html_writer::start_tag('div', array('class' => 'headingwrap ui-bar-'.$this->theme_swatch() .' ui-footer'));
147             $content .= parent::heading($text, $level, $classes.' ui-title', $id);
148             $content .= html_writer::end_tag('div');
149         }
150         return $content;
151     }
153     /**
154      * Renders a block
155      *
156      * @param block_contents $bc
157      * @param string $region
158      * @return string
159      */
160     public function block(block_contents $bc, $region) {
161         // Avoid messing up the object passed in.
162         $bc = clone($bc);
163         // The mymobile theme does not support collapsible blocks.
164         $bc->collapsible = block_contents::NOT_HIDEABLE;
165         // There are no controls that are usable within the
166         $bc->controls = array();
168         // TODO: Do we still need to support accessibility here? Surely screen
169         // readers don't present themselves as mobile devices too often.
170         $skiptitle = strip_tags($bc->title);
171         if (empty($skiptitle)) {
172             $output = '';
173             $skipdest = '';
174         } else {
175             $output = html_writer::tag('a', get_string('skipa', 'access', $skiptitle), array('href' => '#sb-' . $bc->skipid, 'class' => 'skip-block'));
176             $skipdest = html_writer::tag('span', '', array('id' => 'sb-' . $bc->skipid, 'class' => 'skip-block-to'));
177         }
178         $testb = $bc->attributes['class'];
180         // TODO: Find a better solution to this hardcoded block checks
181         if ($testb == "block_calendar_month2  block") {
182             $output  = html_writer::start_tag('span');
183         } else if ($testb == "block_course_overview  block") {
184             $output  = html_writer::start_tag('div');
185         } else {
186             if (!empty($this->page->theme->settings->colourswatch)) {
187                 $showswatch = $this->page->theme->settings->colourswatch;
188             } else {
189                 $showswatch = '';
190             }
191             if ($showswatch == 'light') {
192                 $dtheme = 'd';
193             } else {
194                 $dtheme = 'c';
195             }
196             $output  = html_writer::start_tag('div', array('data-role' => 'collapsible', 'data-collapsed' => 'true', 'data-content-theme' => $dtheme));
197         }
199         $output .= html_writer::tag('h1', $this->block_header($bc));
200         $output .= html_writer::start_tag('div', $bc->attributes);
201         $output .= $this->block_content($bc);
202         $output .= html_writer::end_tag('div');
203         $output .= html_writer::end_tag('div');
205         $output .= $this->block_annotation($bc);
207         $output .= $skipdest;
209         return $output;
210     }
212     /**
213      * Produces a blocks header
214      *
215      * @param block_contents $bc
216      * @return string
217      */
218     protected function block_header(block_contents $bc) {
219         $title = '';
220         if (!$bc->title) {
221             return '&nbsp;';
222         }
223         $output  = html_writer::start_tag('div', array('class' => 'header'));
224         $output .= html_writer::tag('div', html_writer::tag('div', '', array('class'=>'block_action')). $bc->title, array('class' => 'title'));
225         $output .= html_writer::end_tag('div');
226         return $output;
227     }
229     /**
230      * An evil function we don't want to execute
231      *
232      * @param block_contents $bc
233      */
234     protected function init_block_hider_js(block_contents $bc) {
235         // The mymobile theme in no shape or form supports the hiding of blocks
236         // this function has been defined and left empty intentionally so that
237         // the block hider JS is not even included.
238     }
240     /**
241      * Produces the navigation bar for the mymobile theme
242      *
243      * @return string
244      */
245     public function navbar() {
246         $items = $this->page->navbar->get_items();
248         $htmlblocks = array(html_writer::tag('option', get_string('navigation'), array('data-placeholder' => 'true', 'value' => '-1')));
249         // Iterate the navarray and display each node
250         $itemcount = count($items);
251         $separator = "";
253         for ($i = 0; $i < $itemcount; $i++) {
254             $item = $items[$i];
255             $item->hideicon = true;
256             if ($i === 0) {
257                 $content = html_writer::tag('option', $this->render($item), array('value' => (string)$item->action));
258             } else if (!empty($item->action)) {
259                 $content = html_writer::tag('option', $this->render($item), array('value' => (string)$item->action));
260             } else {
261                 $content = '';
262             }
263             $htmlblocks[] = $content;
264         }
266         $navbarcontent  = html_writer::start_tag('form', array('id' => 'navselectform'));
267         $navbarcontent .= html_writer::start_tag('select', array('id' => 'navselect', 'data-theme' => 'c', 'data-inline' => 'false', 'data-icon' => 'false'));
268         $navbarcontent .= join('', $htmlblocks);
269         $navbarcontent .= html_writer::end_tag('select');
270         $navbarcontent .= html_writer::end_tag('form');
271         // XHTML
272         return $navbarcontent;
273     }
275     /**
276      * Renders a navigation node
277      *
278      * This function has been overridden to remove tabindexs
279      *
280      * @param navigation_node $item
281      * @return string
282      */
283     protected function render_navigation_node(navigation_node $item) {
284         // Generate the content normally
285         $content = parent::render_navigation_node($item);
286         // Strip out any tabindex's
287         $content = str_replace(' tabindex="0"', '', $content);
288         $content = str_replace(' tabindex=\'0\'', '', $content);
289         // Return the cleaned content
290         return $content;
291     }
293     /**
294      * Displays login info
295      *
296      * @return string
297      */
298     public function login_info() {
299         global $USER, $CFG, $DB, $SESSION;
301         if (during_initial_install()) {
302             return '';
303         }
305         $course = $this->page->course;
307         if (session_is_loggedinas()) {
308             $realuser = session_get_realuser();
309             $fullname = fullname($realuser, true);
310             $realuserinfo = " [<a href=\"$CFG->wwwroot/course/loginas.php?id=$course->id&amp;sesskey=".sesskey()."\">$fullname</a>] ";
311         } else {
312             $realuserinfo = '';
313         }
315         $loginurl = get_login_url();
317         if (empty($course->id)) {
318             // $course->id is not defined during installation
319             return '';
320         } else if (isloggedin()) {
321             $context = get_context_instance(CONTEXT_COURSE, $course->id);
322             $fullname = fullname($USER, true);
324             // Since Moodle 2.0 this link always goes to the public profile page (not the course profile page)
325             // TODO: Test what happens when someone is using this via mnet [for this as well as login_info_footer]
326             // TODO: Test what happens when you use the loginas feature [for this as well as login_info_footer]
327             $username = "";
328             if (is_mnet_remote_user($USER) and $idprovider = $DB->get_record('mnet_host', array('id'=>$USER->mnethostid))) {
329                 $username .= " from <a href=\"{$idprovider->wwwroot}\">{$idprovider->name}</a>";
330             }
331             if (isguestuser()) {
332                 $loggedinas = $realuserinfo.get_string('loggedinasguest')." (<a href=\"$loginurl\">".get_string('login').'</a>)';
333             } else if (is_role_switched($course->id)) { // Has switched roles
334                 $rolename = '';
335                 if ($role = $DB->get_record('role', array('id'=>$USER->access['rsw'][$context->path]))) {
336                     $rolename = ': '.format_string($role->name);
337                 }
338             } else {
339                 $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>';
340             }
341         } else {
342             $loggedinas = '<a data-role="button" data-icon="alert" class="ui-btn-right nolog" href="'.$loginurl.'" data-prefetch>'.get_string('login').'</a>';
343         }
345         // TODO: Enable $CFG->displayloginfailures and test as admin what happens after you succesfully
346         //       log in after a failed log in attempt.  [for this as well as login_info_footer]
347         //       This is probably totally unneeded
348         if (isset($SESSION->justloggedin)) {
349             unset($SESSION->justloggedin);
350             if (!empty($CFG->displayloginfailures)) {
351                 if (!isguestuser()) {
352                     if ($count = count_login_failures($CFG->displayloginfailures, $USER->username, $USER->lastlogin)) {
353                         $loggedinas .= '&nbsp;<div class="loginfailures">';
354                         if (empty($count->accounts)) {
355                             $loggedinas .= get_string('failedloginattempts', '', $count);
356                         } else {
357                             $loggedinas .= get_string('failedloginattemptsall', '', $count);
358                         }
359                         if (has_capability('coursereport/log:view', get_context_instance(CONTEXT_SYSTEM))) {
360                             $loggedinas .= ' (<a href="'.$CFG->wwwroot.'/course/report/log/index.php?chooselog=1&amp;id=1&amp;modid=site_errors">'.get_string('logs').'</a>)';
361                         }
362                         $loggedinas .= '</div>';
363                     }
364                 }
365             }
366         }
368         return $loggedinas;
369     }
371     /**
372      * Displays login info in the footer
373      *
374      * @return string
375      */
376     public function login_info_footer() {
377         global $USER, $CFG, $DB, $SESSION;
379         if (during_initial_install()) {
380             return '';
381         }
383         $loginapge = ((string)$this->page->url === get_login_url());
384         $course = $this->page->course;
386         if (session_is_loggedinas()) {
387             $realuser = session_get_realuser();
388             $fullname = fullname($realuser, true);
389             $realuserinfo = ' [<a href="'.$CFG->wwwroot.'/course/loginas.php?id=$course->id&amp;sesskey='.sesskey().'">$fullname</a>] ';
390         } else {
391             $realuserinfo = '';
392         }
394         $loginurl = get_login_url();
396         if (empty($course->id)) {
397             // $course->id is not defined during installation
398             return '';
399         } else if (isloggedin()) {
400             $context = get_context_instance(CONTEXT_COURSE, $course->id);
402             $fullname = fullname($USER, true);
403             // Since Moodle 2.0 this link always goes to the public profile page (not the course profile page)
404             $username = '<a href="'.$CFG->wwwroot.'/user/profile.php?id='.$USER->id.'">'.$fullname.'</a>';
405             if (is_mnet_remote_user($USER) and $idprovider = $DB->get_record('mnet_host', array('id'=>$USER->mnethostid))) {
406                 $username .= " from <a href=\"{$idprovider->wwwroot}\">{$idprovider->name}</a>";
407             }
408             if (isguestuser()) {
409                 $loggedinas = $realuserinfo.get_string('loggedinasguest');
410                 if (!$loginapge) {
411                     $loggedinas .= " (<a href=\"$loginurl\">".get_string('login').'</a>)';
412                 }
413             } else if (is_role_switched($course->id)) { // Has switched roles
414                 $rolename = '';
415                 if ($role = $DB->get_record('role', array('id'=>$USER->access['rsw'][$context->path]))) {
416                     $rolename = ': '.format_string($role->name);
417                 }
418                 $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>)';
419             } else {
420                 $loggedinas = $realuserinfo.get_string('loggedinas', 'moodle', $username).' '." (<a href=\"$CFG->wwwroot/login/logout.php?sesskey=".sesskey()."\" data-ajax=\"false\">".get_string('logout').'</a>)';
421             }
422         } else {
423             $loggedinas = get_string('loggedinnot', 'moodle');
424             if (!$loginapge) {
425                 $loggedinas .= " (<a href=\"$loginurl\">".get_string('login').'</a>)';
426             }
427         }
429         $loggedinas = '<div class="logininfo">'.$loggedinas.'</div>';
431         if (isset($SESSION->justloggedin)) {
432             unset($SESSION->justloggedin);
433             if (!empty($CFG->displayloginfailures)) {
434                 if (!isguestuser()) {
435                     if ($count = count_login_failures($CFG->displayloginfailures, $USER->username, $USER->lastlogin)) {
436                         $loggedinas .= '&nbsp;<div class="loginfailures">';
437                         if (empty($count->accounts)) {
438                             $loggedinas .= get_string('failedloginattempts', '', $count);
439                         } else {
440                             $loggedinas .= get_string('failedloginattemptsall', '', $count);
441                         }
442                         if (has_capability('coursereport/log:view', get_context_instance(CONTEXT_SYSTEM))) {
443                             $loggedinas .= ' (<a href="'.$CFG->wwwroot.'/course/report/log/index.php?chooselog=1&amp;id=1&amp;modid=site_errors">'.get_string('logs').'</a>)';
444                         }
445                         $loggedinas .= '</div>';
446                     }
447                 }
448             }
449         }
451         return $loggedinas;
452     }
454     /**
455      * Prints a message and redirects
456      *
457      * @param string $encodedurl
458      * @param string $message
459      * @param int $delay
460      * @param true $debugdisableredirect
461      * @return type
462      */
463     public function redirect_message($encodedurl, $message, $delay, $debugdisableredirect) {
464         global $CFG;
465         $url = str_replace('&amp;', '&', $encodedurl);
466         // TODO: Find a much better solution for this... looks like it is just removing
467         //       the anchor from the link.
468         // The below to fix redirect issues with ajax... John
469         $encodedurl = str_replace('#', '&', $encodedurl);
471         switch ($this->page->state) {
472             case moodle_page::STATE_BEFORE_HEADER :
473                 // No output yet it is safe to delivery the full arsenal of redirect methods
474                 if (!$debugdisableredirect) {
475                     // Don't use exactly the same time here, it can cause problems when both redirects fire at the same time.
476                     $this->metarefreshtag = '<meta http-equiv="refresh" content="'. $delay .'; url='. $encodedurl .'" />'."\n";
477                 }
478                 $output = $this->header();
479                 break;
480             case moodle_page::STATE_PRINTING_HEADER :
481                 // We should hopefully never get here
482                 throw new coding_exception('You cannot redirect while printing the page header');
483                 break;
484             case moodle_page::STATE_IN_BODY :
485                 // We really shouldn't be here but we can deal with this
486                 debugging("You should really redirect before you start page output");
487                 if (!$debugdisableredirect) {
488                     $this->page->requires->js_function_call('document.location.replace', array($url), false, $delay);
489                 }
490                 $output = $this->opencontainers->pop_all_but_last();
491                 break;
492             case moodle_page::STATE_DONE :
493                 // Too late to be calling redirect now
494                 throw new coding_exception('You cannot redirect after the entire page has been generated');
495                 break;
496         }
498         $output .= $this->notification($message, 'redirectmessage');
499         $output .= '<div class="continuebutton"><a data-ajax="false" data-role="button" href="'. $encodedurl .'">'. get_string('continue') .'</a></div>';
500         if ($debugdisableredirect) {
501             $output .= '<p><strong>Error output, so disabling automatic redirect.</strong></p>';
502         }
503         $output .= $this->footer();
504         return $output;
505     }
507     /**
508      * Renders a help icon
509      *
510      * @param help_icon $helpicon
511      * @return string
512      */
513     protected function render_help_icon(help_icon $helpicon) {
514         global $CFG;
516         // first get the help image icon
517         $src = $this->pix_url('help');
519         $title = get_string($helpicon->identifier, $helpicon->component);
521         if (empty($helpicon->linktext)) {
522             $alt = $title;
523         } else {
524             $alt = get_string('helpwiththis');
525         }
527         $attributes = array('src'=>$src, 'alt'=>$alt, 'class'=>'iconhelp', 'data-role'=>'button', 'data-inline'=>'true');
528         $output = html_writer::empty_tag('img', $attributes);
530         // add the link text if given
531         if (!empty($helpicon->linktext)) {
532             // the spacing has to be done through CSS
533             $output .= $helpicon->linktext;
534         }
536         // now create the link around it
537         // TODO: Do we need to specify the theme in the help.php link?
538         $url = new moodle_url('/help.php', array('component' => $helpicon->component, 'identifier' => $helpicon->identifier, 'lang'=>current_language(), 'theme'=>'mymobile'));
540         // note: this title is displayed only if JS is disabled, otherwise the link will have the new ajax tooltip
541         $title = get_string('helpprefix2', '', trim($title, ". \t"));
543         $attributes = array('href'=>$url, 'title'=>$title);
544         $id = html_writer::random_id('helpicon');
545         $attributes['id'] = $id;
546         $attributes['rel'] = 'notexternal';
547         $attributes['data-rel'] = 'dialog';
548         $attributes['data-transition'] = 'slideup';
549         $output = html_writer::tag('a', $output, $attributes);
551         // and finally span
552         return html_writer::tag('span', $output, array('class' => 'helplink2'));
553     }
555     /**
556      * Renders a single button
557      *
558      * @param single_button $button
559      * @return string
560      */
561     protected function render_single_button(single_button $button) {
562         $attributes = array(
563             'type'     => 'submit',
564             'value'    => $button->label,
565             'disabled' => $button->disabled ? 'disabled' : null,
566             'title'    => $button->tooltip
567         );
569         if ($button->actions) {
570             $id = html_writer::random_id('single_button');
571             $attributes['id'] = $id;
572             foreach ($button->actions as $action) {
573                 $this->add_action_handler($action, $id);
574             }
575         }
577         // first the input element
578         $output = html_writer::empty_tag('input', $attributes);
580         // then hidden fields
581         $params = $button->url->params();
582         if ($button->method === 'post') {
583             $params['sesskey'] = sesskey();
584         }
585         foreach ($params as $var => $val) {
586             $output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => $var, 'value' => $val));
587         }
589         // then div wrapper for xhtml strictness
590         $output = html_writer::tag('div', $output, array('rel' => $button->url->out_omit_querystring()));
592         // TODO: Test a single_button that has an anchor and is set to use post
593         // now the form itself around it
594         $url = $button->url->out_omit_querystring(); // url without params
596         if ($url === '') {
597             $url = '#'; // there has to be always some action
598         }
600         // TODO: This is surely a bug that needs fixing.. all of a sudden we've switched
601         //       to the pages URL.
602         //       Test an single button with an external URL as its url
603         // If the url has http, cool, if not we need to add it, JOHN
604         $urlcheck = substr($url, 0, 4);
605         if ($urlcheck != 'http') {
606             $url = $this->page->url->out_omit_querystring();
607         }
609         $attributes = array(
610             'method' => $button->method,
611             'action' => $url,
612             'id'     => $button->formid
613         );
614         $output = html_writer::tag('form', $output, $attributes);
616         // and finally one more wrapper with class
617         return html_writer::tag('div', $output, array('class' => $button->class));
618     }
620     /**
621      * Renders the header for the page
622      *
623      * @return string
624      */
625     public function header() {
626         global $USER, $CFG;
628         if (session_is_loggedinas()) {
629             $this->page->add_body_class('userloggedinas');
630         }
632         $this->page->set_state(moodle_page::STATE_PRINTING_HEADER);
634         // Find the appropriate page layout file, based on $this->page->pagelayout.
635         $layoutfile = $this->page->theme->layout_file($this->page->pagelayout);
636         // Render the layout using the layout file.
637         $rendered = $this->render_page_layout($layoutfile);
639         // Slice the rendered output into header and footer.
640         $cutpos = strpos($rendered, $this->unique_main_content_token);
641         if ($cutpos === false) {
642             $cutpos = strpos($rendered, self::MAIN_CONTENT_TOKEN);
643             $token = self::MAIN_CONTENT_TOKEN;
644         } else {
645             $token = $this->unique_main_content_token;
646         }
648         if ($cutpos === false) {
649             // TODO: Search for a better solution to this... check this is even needed?
650             //       The following code will lead to header containing nothing, and
651             //       footer containing all of the content for the template.
652             // turned off error by john for ajax load of blocks without main content.
653             // throw new coding_exception('page layout file ' . $layoutfile .
654             //        ' does not contain the string "' . self::MAIN_CONTENT_TOKEN . '".');
655         }
656         $header = substr($rendered, 0, $cutpos);
657         $footer = substr($rendered, $cutpos + strlen($token));
659         if (empty($this->contenttype)) {
660             debugging('The page layout file did not call $OUTPUT->doctype()');
661             $header = $this->doctype() . $header;
662         }
664         send_headers($this->contenttype, $this->page->cacheable);
666         $this->opencontainers->push('header/footer', $footer);
667         $this->page->set_state(moodle_page::STATE_IN_BODY);
669         return $header . $this->skip_link_target('maincontent');
670     }
672     /**
673      * Renders a notification
674      *
675      * @param string $message
676      * @param string $classes
677      * @return string
678      */
679     public function notification($message, $classes = 'notifyproblem') {
680         return html_writer::tag('div', clean_text($message), array('data-role'=>'none', 'data-icon'=>'alert', 'data-theme'=>'d', 'class' => renderer_base::prepare_classes($classes)));
681     }
683     /**
684      * Renders the blocks for a block region in the page
685      *
686      * @param type $region
687      * @return string
688      */
689     public function blocks_for_region($region) {
690         $blockcontents = $this->page->blocks->get_content_for_region($region, $this);
692         $output = '';
693         foreach ($blockcontents as $bc) {
694             if ($bc instanceof block_contents) {
695                 // We don't want to print navigation and settings blocks here.
696                 if ($bc->attributes['class'] != 'block_settings  block' && $bc->attributes['class'] != 'block_navigation  block') {
697                     $output .= $this->block($bc, $region);
698                 }
699             } else if ($bc instanceof block_move_target) {
700                 $output .= $this->block_move_target($bc);
701             } else {
702                 throw new coding_exception('Unexpected type of thing (' . get_class($bc) . ') found in list of block contents.');
703             }
704         }
706         return $output;
707     }
709     /**
710      * Renders a single select instance
711      *
712      * @param single_select $select
713      * @return string
714      */
715     protected function render_single_select(single_select $select) {
716         $select = clone($select);
717         if (empty($select->formid)) {
718             $select->formid = html_writer::random_id('single_select_f');
719         }
721         $output = '';
722         $params = $select->url->params();
723         if ($select->method === 'post') {
724             $params['sesskey'] = sesskey();
725         }
726         foreach ($params as $name=>$value) {
727             $output .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>$name, 'value'=>$value));
728         }
730         if (empty($select->attributes['id'])) {
731             $select->attributes['id'] = html_writer::random_id('single_select');
732             //$select->attributes['data-native-menu'] = 'false';
733             //above by john for select elements to use native style and help performance?
734         }
736         if ($select->disabled) {
737             $select->attributes['disabled'] = 'disabled';
738         }
740         if ($select->tooltip) {
741             $select->attributes['title'] = $select->tooltip;
742         }
744         if ($select->label) {
745             $output .= html_writer::label($select->label, $select->attributes['id']);
746         }
748         if ($select->helpicon instanceof help_icon) {
749             $output .= $this->render($select->helpicon);
750         } else if ($select->helpicon instanceof old_help_icon) {
751             $output .= $this->render($select->helpicon);
752         }
754         $output .= html_writer::select($select->options, $select->name, $select->selected, $select->nothing, $select->attributes);
756         //by john show go button to fix selects
757         $go = '';
758         $output .= html_writer::empty_tag('input data-inline="true"', array('type' => 'submit', 'value' => get_string('go')));
759         $output .= html_writer::tag('noscript', html_writer::tag('div', $go), array('style' => 'inline'));
761         $nothing = empty($select->nothing) ? false : key($select->nothing);
762         $this->page->requires->js_init_call('M.util.init_select_autosubmit', array($select->formid, $select->attributes['id'], $nothing));
764         // then div wrapper for xhtml strictness
765         $output = html_writer::tag('div', $output);
767         // now the form itself around it
768         $formattributes = array(
769             'method' => $select->method,
770             'action' => $select->url->out_omit_querystring(),
771             'id'     => $select->formid
772         );
773         $output = html_writer::tag('form', $output, $formattributes);
775         // and finally one more wrapper with class
776         return html_writer::tag('div', $output, array('class' => $select->class));
777     }
780 /**
781  * Overridden choie module renderer for the mymobile theme
782  *
783  * @package    theme
784  * @subpackage mymobile
785  * @copyright  John Stabinger
786  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
787  */
788 class theme_mymobile_mod_choice_renderer extends plugin_renderer_base {
790     /**
791      * Returns HTML to display choices of option
792      * @param object $options
793      * @param int  $coursemoduleid
794      * @param bool $vertical
795      * @return string
796      */
797     public function display_options($options, $coursemoduleid, $vertical = false) {
798         $layoutclass = 'horizontal';
799         if ($vertical) {
800             $layoutclass = 'vertical';
801         }
802         $target = new moodle_url('/mod/choice/view.php');
803         //changed below to post from target john
804         $attributes = array('method'=>'POST', 'action'=>$target, 'class'=> $layoutclass);
806         $html = html_writer::start_tag('form', $attributes);
807         $html .= html_writer::start_tag('ul', array('class'=>'choices', 'data-role'=>'controlgroup' ));
809         $availableoption = count($options['options']);
810         foreach ($options['options'] as $option) {
811             $html .= html_writer::start_tag('li', array('class'=>'option'));
812             $option->attributes->name = 'answer';
813             $option->attributes->type = 'radio';
814             $option->attributes->id = 'answer'.html_writer::random_id();
816             $labeltext = $option->text;
817             if (!empty($option->attributes->disabled)) {
818                 $labeltext .= ' ' . get_string('full', 'choice');
819                 $availableoption--;
820             }
822             $html .= html_writer::empty_tag('input', (array)$option->attributes);
823             $html .= html_writer::tag('label', $labeltext, array('for'=>$option->attributes->id));
824             $html .= html_writer::end_tag('li');
825         }
826         $html .= html_writer::tag('li','', array('class'=>'clearfloat'));
827         $html .= html_writer::end_tag('ul');
828         $html .= html_writer::tag('div', '', array('class'=>'clearfloat'));
829         $html .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'sesskey', 'value'=>sesskey()));
830         $html .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'id', 'value'=>$coursemoduleid));
832         if (!empty($options['hascapability']) && ($options['hascapability'])) {
833             if ($availableoption < 1) {
834                $html .= html_writer::tag('label', get_string('choicefull', 'choice'));
835             } else {
836                 $html .= html_writer::empty_tag('input', array('type'=>'submit', 'value'=>get_string('savemychoice','choice'), 'class'=>'button'));
837             }
839             if (!empty($options['allowupdate']) && ($options['allowupdate'])) {
840                 $url = new moodle_url('view.php', array('id'=>$coursemoduleid, 'action'=>'delchoice', 'sesskey'=>sesskey()));
841                 $html .= html_writer::link($url, get_string('removemychoice','choice'));
842             }
843         } else {
844             $html .= html_writer::tag('label', get_string('havetologin', 'choice'));
845         }
847         $html .= html_writer::end_tag('ul');
848         $html .= html_writer::end_tag('form');
850         return $html;
851     }
853     /**
854      * Returns HTML to display choices result
855      *
856      * TODO: There are differences between this method and the mod choice renderers function.
857      *       This needs to be checked VERY careful as the minor changes look like they
858      *       may lead to regressions.
859      *
860      * @param object $choices
861      * @param bool $forcepublish
862      * @return string
863      */
864     public function display_publish_name_vertical($choices) {
865         $html ='';
866         $html .= html_writer::tag('h2',format_string(get_string("responses", "choice")), array('class'=>'main'));
868         $attributes = array('method'=>'POST');
869         $attributes['action'] = new moodle_url('/mod/choice/view.php');
870         $attributes['id'] = 'attemptsform';
872         if ($choices->viewresponsecapability) {
873             $html .= html_writer::start_tag('form', $attributes);
874             $html .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'id', 'value'=> $choices->coursemoduleid));
875             $html .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'sesskey', 'value'=> sesskey()));
876             $html .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'mode', 'value'=>'overview'));
877         }
879         $table = new html_table();
880         $table->cellpadding = 0;
881         $table->cellspacing = 0;
882         $table->attributes['class'] = 'results names ';
883         $table->tablealign = 'center';
884         $table->data = array();
886         $count = 0;
887         ksort($choices->options);
889         $columns = array();
890         foreach ($choices->options as $optionid => $options) {
891             $coldata = '';
892             if ($choices->showunanswered && $optionid == 0) {
893                 $coldata .= html_writer::tag('div', format_string(get_string('notanswered', 'choice')), array('class'=>'option'));
894             } else if ($optionid > 0) {
895                 $coldata .= html_writer::tag('div', format_string($choices->options[$optionid]->text), array('class'=>'option'));
896             }
897             $numberofuser = 0;
898             if (!empty($options->user) && count($options->user) > 0) {
899                 $numberofuser = count($options->user);
900             }
902             $coldata .= html_writer::tag('div', ' ('.$numberofuser. ')', array('class'=>'numberofuser', 'title' => get_string('numberofuser', 'choice')));
903             $columns[] = $coldata;
904         }
906         $table->head = $columns;
908         $coldata = '';
909         $columns = array();
910         foreach ($choices->options as $optionid => $options) {
911             $coldata = '';
912             if ($choices->showunanswered || $optionid > 0) {
913                 if (!empty($options->user)) {
914                     foreach ($options->user as $user) {
915                         $data = '';
916                         if (empty($user->imagealt)){
917                             $user->imagealt = '';
918                         }
920                         if ($choices->viewresponsecapability && $choices->deleterepsonsecapability  && $optionid > 0) {
921                             $attemptaction = html_writer::checkbox('attemptid[]', $user->id,'');
922                             $data .= html_writer::tag('div', $attemptaction, array('class'=>'attemptaction'));
923                         }
924                         $userimage = $this->output->user_picture($user, array('courseid'=>$choices->courseid));
925                         $data .= html_writer::tag('div', $userimage, array('class'=>'image'));
927                         $userlink = new moodle_url('/user/view.php', array('id'=>$user->id,'course'=>$choices->courseid));
928                         $name = html_writer::tag('a', fullname($user, $choices->fullnamecapability), array('href'=>$userlink, 'class'=>'username'));
929                         $data .= html_writer::tag('div', $name, array('class'=>'fullname'));
930                         $data .= html_writer::tag('div','', array('class'=>'clearfloat'));
931                         $coldata .= html_writer::tag('div', $data, array('class'=>'user'));
932                     }
933                 }
934             }
936             $columns[] = $coldata;
937             $count++;
938         }
940         $table->data[] = $columns;
941         foreach ($columns as $d) {
942             $table->colclasses[] = 'data';
943         }
944         $html .= html_writer::tag('div', html_writer::table($table), array('class'=>'response'));
946         $actiondata = '';
947         if ($choices->viewresponsecapability && $choices->deleterepsonsecapability) {
948             $selecturl = new moodle_url('#');
950             $selectallactions = new component_action('click',"select_all_in", array('div',null,'tablecontainer'));
951             $selectall = new action_link($selecturl, get_string('selectall'), $selectallactions);
952             $actiondata .= $this->output->render($selectall) . ' / ';
954             $deselectallactions = new component_action('click',"deselect_all_in", array('div',null,'tablecontainer'));
955             $deselectall = new action_link($selecturl, get_string('deselectall'), $deselectallactions);
956             $actiondata .= $this->output->render($deselectall);
957             //below john fixed
958             $actiondata .= html_writer::tag('label', ' ' . get_string('withselected', 'choice') . ' ', array('for'=>'menuaction'));
960             $actionurl = new moodle_url('/mod/choice/view.php', array('sesskey'=>sesskey(), 'action'=>'delete_confirmation()'));
961             $select = new single_select($actionurl, 'action', array('delete'=>get_string('delete')), null, array(''=>get_string('moveselectedusersto', 'choice')), 'attemptsform');
963             $actiondata .= $this->output->render($select);
964         }
965         $html .= html_writer::tag('div', $actiondata, array('class'=>'responseaction'));
967         if ($choices->viewresponsecapability) {
968             $html .= html_writer::end_tag('form');
969         }
971         return $html;
972     }