Commit | Line | Data |
---|---|---|
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 | */ | |
34 | class theme_mymobile_renderer extends plugin_renderer_base { | |
35 | ||
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; | |
2fd7abbb | 48 | } |
3c0c2bf0 SH |
49 | |
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()); | |
2fd7abbb | 58 | } |
59 | ||
3c0c2bf0 SH |
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; | |
69 | ||
70 | // exit if empty, we don't want an empty ul element | |
71 | if ($items->count() == 0) { | |
72 | return ''; | |
73 | } | |
74 | ||
75 | // array of nested li elements | |
76 | $lis = array(); | |
77 | foreach ($items as $item) { | |
78 | if (!$item->display) { | |
79 | continue; | |
80 | } | |
81 | ||
82 | $isbranch = ($item->children->count() > 0 || $item->nodetype == navigation_node::NODETYPE_BRANCH); | |
83 | $item->hideicon = true; | |
84 | ||
85 | $content = $this->output->render($item); | |
86 | $content .= $this->navigation_node($item); | |
87 | ||
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); | |
2fd7abbb | 101 | } |
2fd7abbb | 102 | } |
2fd7abbb | 103 | |
3c0c2bf0 SH |
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 { | |
113 | ||
114 | /** | |
115 | * Returns the dtheme to use for the selected swatch | |
cf2de1cf | 116 | * |
3c0c2bf0 SH |
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; | |
2fd7abbb | 123 | } |
124 | if ($showswatch == 'light') { | |
3c0c2bf0 SH |
125 | $dtheme = 'b'; |
126 | } else { | |
127 | $dtheme = 'd'; | |
128 | } | |
129 | return $dtheme; | |
130 | } | |
131 | ||
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'); | |
2fd7abbb | 149 | } |
3c0c2bf0 SH |
150 | return $content; |
151 | } | |
2fd7abbb | 152 | |
3c0c2bf0 SH |
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(); | |
167 | ||
168 | // TODO: Do we still need to support accessibility here? Surely screen | |
169 | // readers don't present themselves as mobile devices too often. | |
2fd7abbb | 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']; | |
3c0c2bf0 SH |
179 | |
180 | // TODO: Find a better solution to this hardcoded block checks | |
2fd7abbb | 181 | if ($testb == "block_calendar_month2 block") { |
3c0c2bf0 SH |
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)); | |
2fd7abbb | 197 | } |
3c0c2bf0 SH |
198 | |
199 | $output .= html_writer::tag('h1', $this->block_header($bc)); | |
2fd7abbb | 200 | $output .= html_writer::start_tag('div', $bc->attributes); |
201 | $output .= $this->block_content($bc); | |
2fd7abbb | 202 | $output .= html_writer::end_tag('div'); |
203 | $output .= html_writer::end_tag('div'); | |
204 | ||
205 | $output .= $this->block_annotation($bc); | |
206 | ||
207 | $output .= $skipdest; | |
208 | ||
209 | return $output; | |
210 | } | |
211 | ||
3c0c2bf0 SH |
212 | /** |
213 | * Produces a blocks header | |
214 | * | |
215 | * @param block_contents $bc | |
216 | * @return string | |
217 | */ | |
2fd7abbb | 218 | protected function block_header(block_contents $bc) { |
2fd7abbb | 219 | $title = ''; |
3c0c2bf0 SH |
220 | if (!$bc->title) { |
221 | return ' '; | |
2fd7abbb | 222 | } |
3c0c2bf0 SH |
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'); | |
2fd7abbb | 226 | return $output; |
227 | } | |
228 | ||
3c0c2bf0 SH |
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. | |
2fd7abbb | 238 | } |
2fd7abbb | 239 | |
3c0c2bf0 SH |
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(); | |
2fd7abbb | 247 | |
3c0c2bf0 | 248 | $htmlblocks = array(html_writer::tag('option', get_string('navigation'), array('data-placeholder' => 'true', 'value' => '-1'))); |
2fd7abbb | 249 | // Iterate the navarray and display each node |
250 | $itemcount = count($items); | |
251 | $separator = ""; | |
3c0c2bf0 SH |
252 | |
253 | for ($i = 0; $i < $itemcount; $i++) { | |
2fd7abbb | 254 | $item = $items[$i]; |
255 | $item->hideicon = true; | |
3c0c2bf0 SH |
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)); | |
2fd7abbb | 260 | } else { |
3c0c2bf0 | 261 | $content = ''; |
2fd7abbb | 262 | } |
263 | $htmlblocks[] = $content; | |
264 | } | |
265 | ||
3c0c2bf0 SH |
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'); | |
2fd7abbb | 271 | // XHTML |
272 | return $navbarcontent; | |
3c0c2bf0 | 273 | } |
2fd7abbb | 274 | |
3c0c2bf0 SH |
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 | |
2fd7abbb | 290 | return $content; |
291 | } | |
292 | ||
3c0c2bf0 SH |
293 | /** |
294 | * Displays login info | |
295 | * | |
296 | * @return string | |
297 | */ | |
298 | public function login_info() { | |
2fd7abbb | 299 | global $USER, $CFG, $DB, $SESSION; |
300 | ||
301 | if (during_initial_install()) { | |
302 | return ''; | |
303 | } | |
304 | ||
305 | $course = $this->page->course; | |
306 | ||
307 | if (session_is_loggedinas()) { | |
308 | $realuser = session_get_realuser(); | |
309 | $fullname = fullname($realuser, true); | |
2fd7abbb | 310 | $realuserinfo = " [<a href=\"$CFG->wwwroot/course/loginas.php?id=$course->id&sesskey=".sesskey()."\">$fullname</a>] "; |
311 | } else { | |
312 | $realuserinfo = ''; | |
313 | } | |
314 | ||
315 | $loginurl = get_login_url(); | |
316 | ||
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); | |
2fd7abbb | 322 | $fullname = fullname($USER, true); |
3c0c2bf0 | 323 | |
2fd7abbb | 324 | // Since Moodle 2.0 this link always goes to the public profile page (not the course profile page) |
3c0c2bf0 SH |
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 = ""; | |
2fd7abbb | 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()) { | |
3c0c2bf0 | 332 | $loggedinas = $realuserinfo.get_string('loggedinasguest')." (<a href=\"$loginurl\">".get_string('login').'</a>)'; |
2fd7abbb | 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 | } | |
2fd7abbb | 338 | } else { |
3c0c2bf0 | 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>'; |
2fd7abbb | 340 | } |
341 | } else { | |
3c0c2bf0 | 342 | $loggedinas = '<a data-role="button" data-icon="alert" class="ui-btn-right nolog" href="'.$loginurl.'" data-prefetch>'.get_string('login').'</a>'; |
2fd7abbb | 343 | } |
344 | ||
3c0c2bf0 SH |
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 | |
2fd7abbb | 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 .= ' <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))) { | |
3c0c2bf0 | 360 | $loggedinas .= ' (<a href="'.$CFG->wwwroot.'/course/report/log/index.php?chooselog=1&id=1&modid=site_errors">'.get_string('logs').'</a>)'; |
2fd7abbb | 361 | } |
362 | $loggedinas .= '</div>'; | |
363 | } | |
364 | } | |
365 | } | |
366 | } | |
367 | ||
368 | return $loggedinas; | |
369 | } | |
370 | ||
3c0c2bf0 SH |
371 | /** |
372 | * Displays login info in the footer | |
373 | * | |
374 | * @return string | |
375 | */ | |
376 | public function login_info_footer() { | |
2fd7abbb | 377 | global $USER, $CFG, $DB, $SESSION; |
378 | ||
379 | if (during_initial_install()) { | |
380 | return ''; | |
381 | } | |
382 | ||
4a645a68 | 383 | $loginpage = ((string)$this->page->url === get_login_url()); |
2fd7abbb | 384 | $course = $this->page->course; |
385 | ||
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&sesskey='.sesskey().'">$fullname</a>] '; | |
390 | } else { | |
391 | $realuserinfo = ''; | |
392 | } | |
393 | ||
394 | $loginurl = get_login_url(); | |
395 | ||
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); | |
401 | ||
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'); | |
4a645a68 | 410 | if (!$loginpage) { |
2fd7abbb | 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 | } | |
3c0c2bf0 | 418 | $loggedinas = get_string('loggedinas', 'moodle', $username).$rolename." (<a href=\"$CFG->wwwroot/course/view.php?id=$course->id&switchrole=0&sesskey=".sesskey()."\">".get_string('switchrolereturn').'</a>)'; |
2fd7abbb | 419 | } else { |
3c0c2bf0 | 420 | $loggedinas = $realuserinfo.get_string('loggedinas', 'moodle', $username).' '." (<a href=\"$CFG->wwwroot/login/logout.php?sesskey=".sesskey()."\" data-ajax=\"false\">".get_string('logout').'</a>)'; |
2fd7abbb | 421 | } |
422 | } else { | |
423 | $loggedinas = get_string('loggedinnot', 'moodle'); | |
4a645a68 | 424 | if (!$loginpage) { |
2fd7abbb | 425 | $loggedinas .= " (<a href=\"$loginurl\">".get_string('login').'</a>)'; |
426 | } | |
427 | } | |
428 | ||
429 | $loggedinas = '<div class="logininfo">'.$loggedinas.'</div>'; | |
430 | ||
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 .= ' <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))) { | |
3c0c2bf0 | 443 | $loggedinas .= ' (<a href="'.$CFG->wwwroot.'/course/report/log/index.php?chooselog=1&id=1&modid=site_errors">'.get_string('logs').'</a>)'; |
2fd7abbb | 444 | } |
445 | $loggedinas .= '</div>'; | |
446 | } | |
447 | } | |
448 | } | |
449 | } | |
450 | ||
451 | return $loggedinas; | |
452 | } | |
453 | ||
3c0c2bf0 SH |
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) { | |
2fd7abbb | 464 | global $CFG; |
465 | $url = str_replace('&', '&', $encodedurl); | |
3c0c2bf0 SH |
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 | |
2fd7abbb | 469 | $encodedurl = str_replace('#', '&', $encodedurl); |
3c0c2bf0 | 470 | |
2fd7abbb | 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"; | |
2fd7abbb | 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 | } | |
3c0c2bf0 | 497 | |
2fd7abbb | 498 | $output .= $this->notification($message, 'redirectmessage'); |
2fd7abbb | 499 | $output .= '<div class="continuebutton"><a data-ajax="false" data-role="button" href="'. $encodedurl .'">'. get_string('continue') .'</a></div>'; |
2fd7abbb | 500 | if ($debugdisableredirect) { |
501 | $output .= '<p><strong>Error output, so disabling automatic redirect.</strong></p>'; | |
502 | } | |
503 | $output .= $this->footer(); | |
504 | return $output; | |
505 | } | |
2fd7abbb | 506 | |
3c0c2bf0 SH |
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) { | |
2fd7abbb | 514 | global $CFG; |
515 | ||
516 | // first get the help image icon | |
517 | $src = $this->pix_url('help'); | |
518 | ||
519 | $title = get_string($helpicon->identifier, $helpicon->component); | |
520 | ||
521 | if (empty($helpicon->linktext)) { | |
522 | $alt = $title; | |
523 | } else { | |
524 | $alt = get_string('helpwiththis'); | |
525 | } | |
526 | ||
527 | $attributes = array('src'=>$src, 'alt'=>$alt, 'class'=>'iconhelp', 'data-role'=>'button', 'data-inline'=>'true'); | |
528 | $output = html_writer::empty_tag('img', $attributes); | |
529 | ||
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 | } | |
535 | ||
536 | // now create the link around it | |
3c0c2bf0 | 537 | // TODO: Do we need to specify the theme in the help.php link? |
2fd7abbb | 538 | $url = new moodle_url('/help.php', array('component' => $helpicon->component, 'identifier' => $helpicon->identifier, 'lang'=>current_language(), 'theme'=>'mymobile')); |
539 | ||
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")); | |
542 | ||
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); | |
550 | ||
551 | // and finally span | |
552 | return html_writer::tag('span', $output, array('class' => 'helplink2')); | |
553 | } | |
2fd7abbb | 554 | |
3c0c2bf0 SH |
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 | ); | |
2fd7abbb | 568 | |
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 | } | |
576 | ||
577 | // first the input element | |
578 | $output = html_writer::empty_tag('input', $attributes); | |
579 | ||
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 | } | |
588 | ||
589 | // then div wrapper for xhtml strictness | |
3c0c2bf0 SH |
590 | $output = html_writer::tag('div', $output, array('rel' => $button->url->out_omit_querystring())); |
591 | ||
592 | // TODO: Test a single_button that has an anchor and is set to use post | |
2fd7abbb | 593 | // now the form itself around it |
594 | $url = $button->url->out_omit_querystring(); // url without params | |
3c0c2bf0 SH |
595 | |
596 | if ($url === '') { | |
2fd7abbb | 597 | $url = '#'; // there has to be always some action |
598 | } | |
3c0c2bf0 SH |
599 | |
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 | } | |
608 | ||
609 | $attributes = array( | |
610 | 'method' => $button->method, | |
611 | 'action' => $url, | |
612 | 'id' => $button->formid | |
613 | ); | |
2fd7abbb | 614 | $output = html_writer::tag('form', $output, $attributes); |
615 | ||
616 | // and finally one more wrapper with class | |
617 | return html_writer::tag('div', $output, array('class' => $button->class)); | |
618 | } | |
3c0c2bf0 SH |
619 | |
620 | /** | |
621 | * Renders the header for the page | |
622 | * | |
623 | * @return string | |
624 | */ | |
625 | public function header() { | |
2fd7abbb | 626 | global $USER, $CFG; |
627 | ||
628 | if (session_is_loggedinas()) { | |
629 | $this->page->add_body_class('userloggedinas'); | |
630 | } | |
3c0c2bf0 | 631 | |
2fd7abbb | 632 | $this->page->set_state(moodle_page::STATE_PRINTING_HEADER); |
633 | ||
634 | // Find the appropriate page layout file, based on $this->page->pagelayout. | |
2fd7abbb | 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); | |
638 | ||
639 | // Slice the rendered output into header and footer. | |
3c0c2bf0 | 640 | $cutpos = strpos($rendered, $this->unique_main_content_token); |
2fd7abbb | 641 | if ($cutpos === false) { |
3c0c2bf0 SH |
642 | $cutpos = strpos($rendered, self::MAIN_CONTENT_TOKEN); |
643 | $token = self::MAIN_CONTENT_TOKEN; | |
644 | } else { | |
645 | $token = $this->unique_main_content_token; | |
646 | } | |
647 | ||
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 . | |
2fd7abbb | 654 | // ' does not contain the string "' . self::MAIN_CONTENT_TOKEN . '".'); |
655 | } | |
656 | $header = substr($rendered, 0, $cutpos); | |
3c0c2bf0 | 657 | $footer = substr($rendered, $cutpos + strlen($token)); |
2fd7abbb | 658 | |
659 | if (empty($this->contenttype)) { | |
660 | debugging('The page layout file did not call $OUTPUT->doctype()'); | |
661 | $header = $this->doctype() . $header; | |
662 | } | |
663 | ||
664 | send_headers($this->contenttype, $this->page->cacheable); | |
665 | ||
666 | $this->opencontainers->push('header/footer', $footer); | |
667 | $this->page->set_state(moodle_page::STATE_IN_BODY); | |
668 | ||
669 | return $header . $this->skip_link_target('maincontent'); | |
670 | } | |
671 | ||
3c0c2bf0 SH |
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') { | |
2fd7abbb | 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 | } | |
3c0c2bf0 SH |
682 | |
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) { | |
2fd7abbb | 690 | $blockcontents = $this->page->blocks->get_content_for_region($region, $this); |
cf2de1cf | 691 | |
2fd7abbb | 692 | $output = ''; |
693 | foreach ($blockcontents as $bc) { | |
694 | if ($bc instanceof block_contents) { | |
3c0c2bf0 SH |
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') { | |
2fd7abbb | 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 | } | |
3c0c2bf0 | 705 | |
2fd7abbb | 706 | return $output; |
707 | } | |
708 | ||
3c0c2bf0 SH |
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) { | |
2fd7abbb | 716 | $select = clone($select); |
717 | if (empty($select->formid)) { | |
718 | $select->formid = html_writer::random_id('single_select_f'); | |
719 | } | |
720 | ||
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 | } | |
729 | ||
730 | if (empty($select->attributes['id'])) { | |
731 | $select->attributes['id'] = html_writer::random_id('single_select'); | |
3c0c2bf0 SH |
732 | //$select->attributes['data-native-menu'] = 'false'; |
733 | //above by john for select elements to use native style and help performance? | |
2fd7abbb | 734 | } |
735 | ||
736 | if ($select->disabled) { | |
737 | $select->attributes['disabled'] = 'disabled'; | |
738 | } | |
739 | ||
740 | if ($select->tooltip) { | |
741 | $select->attributes['title'] = $select->tooltip; | |
742 | } | |
743 | ||
744 | if ($select->label) { | |
745 | $output .= html_writer::label($select->label, $select->attributes['id']); | |
746 | } | |
747 | ||
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 | } | |
753 | ||
754 | $output .= html_writer::select($select->options, $select->name, $select->selected, $select->nothing, $select->attributes); | |
3c0c2bf0 | 755 | |
2fd7abbb | 756 | //by john show go button to fix selects |
757 | $go = ''; | |
3c0c2bf0 SH |
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')); | |
2fd7abbb | 760 | |
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)); | |
763 | ||
764 | // then div wrapper for xhtml strictness | |
765 | $output = html_writer::tag('div', $output); | |
766 | ||
767 | // now the form itself around it | |
3c0c2bf0 SH |
768 | $formattributes = array( |
769 | 'method' => $select->method, | |
770 | 'action' => $select->url->out_omit_querystring(), | |
771 | 'id' => $select->formid | |
772 | ); | |
2fd7abbb | 773 | $output = html_writer::tag('form', $output, $formattributes); |
774 | ||
775 | // and finally one more wrapper with class | |
776 | return html_writer::tag('div', $output, array('class' => $select->class)); | |
777 | } | |
2fd7abbb | 778 | } |
779 | ||
3c0c2bf0 SH |
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 | */ | |
2fd7abbb | 788 | class theme_mymobile_mod_choice_renderer extends plugin_renderer_base { |
789 | ||
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); | |
805 | ||
806 | $html = html_writer::start_tag('form', $attributes); | |
807 | $html .= html_writer::start_tag('ul', array('class'=>'choices', 'data-role'=>'controlgroup' )); | |
3c0c2bf0 | 808 | |
2fd7abbb | 809 | $availableoption = count($options['options']); |
810 | foreach ($options['options'] as $option) { | |
3c0c2bf0 | 811 | $html .= html_writer::start_tag('li', array('class'=>'option')); |
2fd7abbb | 812 | $option->attributes->name = 'answer'; |
813 | $option->attributes->type = 'radio'; | |
3c0c2bf0 | 814 | $option->attributes->id = 'answer'.html_writer::random_id(); |
2fd7abbb | 815 | |
816 | $labeltext = $option->text; | |
817 | if (!empty($option->attributes->disabled)) { | |
818 | $labeltext .= ' ' . get_string('full', 'choice'); | |
819 | $availableoption--; | |
820 | } | |
821 | ||
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)); | |
831 | ||
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 | } | |
838 | ||
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 | } | |
846 | ||
847 | $html .= html_writer::end_tag('ul'); | |
848 | $html .= html_writer::end_tag('form'); | |
849 | ||
850 | return $html; | |
851 | } | |
852 | ||
853 | /** | |
854 | * Returns HTML to display choices result | |
3c0c2bf0 SH |
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 | * | |
2fd7abbb | 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')); | |
867 | ||
868 | $attributes = array('method'=>'POST'); | |
869 | $attributes['action'] = new moodle_url('/mod/choice/view.php'); | |
870 | $attributes['id'] = 'attemptsform'; | |
871 | ||
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 | } | |
878 | ||
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(); | |
885 | ||
886 | $count = 0; | |
887 | ksort($choices->options); | |
888 | ||
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 | } | |
901 | ||
902 | $coldata .= html_writer::tag('div', ' ('.$numberofuser. ')', array('class'=>'numberofuser', 'title' => get_string('numberofuser', 'choice'))); | |
903 | $columns[] = $coldata; | |
904 | } | |
905 | ||
906 | $table->head = $columns; | |
907 | ||
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 | } | |
919 | ||
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')); | |
926 | ||
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 | } | |
935 | ||
936 | $columns[] = $coldata; | |
937 | $count++; | |
938 | } | |
939 | ||
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')); | |
945 | ||
946 | $actiondata = ''; | |
947 | if ($choices->viewresponsecapability && $choices->deleterepsonsecapability) { | |
948 | $selecturl = new moodle_url('#'); | |
949 | ||
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) . ' / '; | |
953 | ||
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')); | |
959 | ||
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'); | |
962 | ||
963 | $actiondata .= $this->output->render($select); | |
964 | } | |
965 | $html .= html_writer::tag('div', $actiondata, array('class'=>'responseaction')); | |
966 | ||
967 | if ($choices->viewresponsecapability) { | |
968 | $html .= html_writer::end_tag('form'); | |
969 | } | |
970 | ||
971 | return $html; | |
972 | } | |
cf2de1cf | 973 | } |