PageRenderTime 59ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/theme/gu23/renderers.php

https://github.com/thepurpleblob/gumoodle
PHP | 1380 lines | 1009 code | 198 blank | 173 comment | 202 complexity | 1b76fb8b162ccb30469aa1d94d520de2 MD5 | raw file
Possible License(s): Apache-2.0, GPL-3.0, BSD-3-Clause, LGPL-2.1, AGPL-3.0, MPL-2.0-no-copyleft-exception, LGPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /* renderers to align Moodle's HTML with that expected by Bootstrap */
  3. class theme_gu23_core_renderer extends core_renderer {
  4. static $icons_ignore = array(
  5. 'icon' => '?', // all the module icons have this name
  6. 't/groups' => '?',
  7. 't/groupn' => '?',
  8. 't/groupv' => '?' );
  9. static $icons = array(
  10. 'docs' => 'question-sign',
  11. 'book' => 'book',
  12. 'chapter' => 'file',
  13. 'spacer' => 'spacer',
  14. 'generate' => 'gift',
  15. 'add' => 'plus',
  16. 't/hide' => 'eye-open',
  17. 'i/hide' => 'eye-open',
  18. 't/show' => 'eye-close',
  19. 'i/show' => 'eye-close',
  20. 't/add' => 'plus',
  21. 't/right' => 'arrow-right',
  22. 't/left' => 'arrow-left',
  23. 't/up' => 'arrow-up',
  24. 't/down' => 'arrow-down',
  25. 't/edit' => 'edit',
  26. 't/editstring' => 'tag',
  27. 't/delete' => 'remove',
  28. 'i/edit' => 'pencil',
  29. 't/copy' => 'copy', // created png from font awesome
  30. 'i/settings' => 'list-alt',
  31. 'i/grades' => 'grades',
  32. 'i/group' => 'user',
  33. 't/switch_plus' => 'plus-sign',
  34. 't/switch_minus' => 'minus-sign',
  35. 'i/filter' => 'filter',
  36. 't/move' => 'resize-vertical',
  37. 'i/move_2d' => 'move',
  38. 'i/backup' => 'cog',
  39. 'i/restore' => 'cog',
  40. 't/backup' => 'download',
  41. 't/restore' => 'upload',
  42. 'i/return' => 'repeat',
  43. 'i/reload' => 'refresh',
  44. 'i/roles' => 'user',
  45. 'i/user' => 'user',
  46. 'i/users' => 'user',
  47. 'i/publish' => 'publish',
  48. 'i/navigationitem' => 'chevron-right' );
  49. protected static function icon($name, $text=null) {
  50. if (!$text) {$text = $name;}
  51. return "<i class=icon-$name>$text</i>";
  52. }
  53. protected static function moodle_icon($name) {
  54. return self::icon(self::$icons[$name]);
  55. }
  56. public function icon_help() {
  57. return self::icon('question-sign');
  58. }
  59. protected static function a($attributes, $content) {
  60. return html_writer::tag('a', $content, $attributes);
  61. }
  62. protected static function div($attributes, $content) {
  63. return html_writer::tag('div', $content, $attributes);
  64. }
  65. protected static function span($attributes, $content) {
  66. return html_writer::tag('span', $content, $attributes);
  67. }
  68. protected static function ul($items) {
  69. $lis = array();
  70. foreach ($items as $key => $string) {
  71. $lis[] = "<li>$string</li>";
  72. }
  73. return '<ul class=unstyled>'.implode($lis).'</ul>';
  74. }
  75. public function action_icon($url, pix_icon $pixicon, component_action $action = null, array $attributes = null, $linktext=false) {
  76. if (!($url instanceof moodle_url)) {
  77. $url = new moodle_url($url);
  78. }
  79. $attributes = (array)$attributes;
  80. if (empty($attributes['class'])) {
  81. // let ppl override the class via $options
  82. $attributes['class'] = 'action-icon';
  83. }
  84. $icon = $this->render($pixicon);
  85. $attributes['title'] = $pixicon->attributes['alt'];
  86. if ($linktext) {
  87. $text = $pixicon->attributes['alt'];
  88. } else {
  89. $text = '';
  90. }
  91. return $this->action_link($url, $text.$icon, $action, $attributes);
  92. }
  93. public function home_link() {
  94. global $CFG, $SITE;
  95. $text = '';
  96. $linktext = 'Moodle';
  97. if ($this->page->pagetype == 'site-index') {
  98. $div_attributes['class'] = "sitelink";
  99. $text = 'Made with ';
  100. $a_attributes['href'] = 'http://moodle.org/';
  101. } else if (!empty($CFG->target_release) &&
  102. $CFG->target_release != $CFG->release) {
  103. // Special case for during install/upgrade.
  104. $div_attributes['class'] = "sitelink";
  105. $text = 'help with ';
  106. $a_attributes['href'] = 'http://docs.moodle.org/en/Administrator_documentation';
  107. $a_attributes['target'] = '_blank';
  108. } else if ($this->page->course->id == $SITE->id ||
  109. strpos($this->page->pagetype, 'course-view') === 0) {
  110. $div_attributes['class'] = "homelink";
  111. $linktext = get_string('home');
  112. $a_attributes['href'] = $CFG->wwwroot . '/';
  113. } else {
  114. $div_attributes['class'] = "homelink";
  115. $linktext = format_string($this->page->course->shortname, true, array('context' => $this->page->context));
  116. $a_attributes['href'] = $CFG->wwwroot . '/course/view.php?id=' . $this->page->course->id;
  117. }
  118. return self::div($div_attributes, $text . self::a($a_attributes, $linktext));
  119. }
  120. protected function render_pix_icon(pix_icon $icon) {
  121. if (isset(self::$icons_ignore[$icon->pix])) {
  122. return parent::render_pix_icon($icon);
  123. } else if (isset(self::$icons[$icon->pix])) {
  124. return self::icon(self::$icons[$icon->pix]);
  125. } else {
  126. return parent::render_pix_icon($icon);
  127. //return '<i class=icon-not-assigned data-debug-icon="'.$icon->pix.'"></i>';
  128. }
  129. }
  130. protected function render_custom_menu(custom_menu $menu) {
  131. if (!$menu->has_children()) {
  132. return '';
  133. }
  134. $content = '<div class="navbar navbar-fixed-top">' .
  135. '<div class=navbar-inner>' .
  136. '<div class=container>' .
  137. '<ul class=nav>';
  138. foreach ($menu->get_children() as $item) {
  139. $content .= $this->render_custom_menu_item($item);
  140. }
  141. $content .= '</ul></div></div><div>';
  142. return $content;
  143. }
  144. protected function render_custom_menu_item(custom_menu_item $menunode) {
  145. // Required to ensure we get unique trackable id's
  146. static $submenucount = 0;
  147. if ($menunode->has_children()) {
  148. $content = '<li class=dropdown>';
  149. // If the child has menus render it as a sub menu
  150. $submenucount++;
  151. if ($menunode->get_url() !== null) {
  152. $url = $menunode->get_url();
  153. } else {
  154. $url = '#cm_submenu_'.$submenucount;
  155. }
  156. //$content .= html_writer::link($url, $menunode->get_text(), array('title'=>,));
  157. $content .= '<a href="'.$url.'" class=dropdown-toggle data-toggle=dropdown>';
  158. $content .= $menunode->get_title();
  159. $content .= '<b class=caret></b></a>';
  160. $content .= '<ul class=dropdown-menu>';
  161. foreach ($menunode->get_children() as $menunode) {
  162. $content .= $this->render_custom_menu_item($menunode);
  163. }
  164. $content .= '</ul>';
  165. } else {
  166. $content = '<li>';
  167. // The node doesn't have children so produce a final menuitem
  168. if ($menunode->get_url() !== null) {
  169. $url = $menunode->get_url();
  170. } else {
  171. $url = '#';
  172. }
  173. $content .= html_writer::link($url, $menunode->get_text(), array('title'=>$menunode->get_title()));
  174. }
  175. $content .= '<li>';
  176. return $content;
  177. }
  178. public function block_controls($controls) {
  179. if (empty($controls)) {
  180. return '';
  181. }
  182. $controlshtml = array();
  183. foreach ($controls as $control) {
  184. $controlshtml[] = self::a(array('href'=>$control['url'], 'title'=>$control['caption']), self::moodle_icon($control['icon']));
  185. }
  186. return self::div(array('class'=>'commands'), implode($controlshtml));
  187. }
  188. public function list_block_contents($icons, $items) {
  189. return self::ul($items);
  190. }
  191. public function doc_link($path, $text = '') {
  192. $attributes['href'] = new moodle_url(get_docs_url($path));
  193. if ($text == '') {
  194. $linktext = $this->icon_help();
  195. } else {
  196. $linktext = $this->icon_help().' '.$text; }
  197. return self::a($attributes, $linktext);
  198. }
  199. public function icon_spacer(array $attributes = null, $br = false) {
  200. return self::icon('spacer', '');
  201. // don't output br's or attributes
  202. }
  203. public function error_text($message) {
  204. if (empty($message)) { return ''; }
  205. return self::span(array('class'=>'label label-important'), $message);
  206. }
  207. public function notification($message, $classes = 'notifyproblem') {
  208. // TODO rewrite recognized classnames to bootstrap alert equivalent
  209. if ($classes = 'notifyproblem') { $classes = 'alert-error';}
  210. if ($classes = 'notifysuccess') { $classes = 'alert-success';}
  211. return self::div(array('class'=>'alert '.$classes), clean_text($message));
  212. }
  213. protected function render_paging_bar(paging_bar $pagingbar) {
  214. // this is more complicated than it needs to be, see MDL-35367
  215. $pagingbar->maxdisplay = 11; // odd number for symmetry
  216. $pagingbar = clone($pagingbar);
  217. $pagingbar->prepare($this, $this->page, $this->target);
  218. $show_pagingbar = ($pagingbar->totalcount > $pagingbar->perpage);
  219. if ($show_pagingbar) {
  220. $baseurl = $pagingbar->baseurl;
  221. $pagevar = $pagingbar->pagevar;
  222. $maxdisplay = max($pagingbar->maxdisplay, 5);
  223. $page = $pagingbar->page;
  224. $output = '<div class="pagination pagination-centered"><ul>';
  225. // Note: page 0 is displayed to users as page 1 and so on.
  226. if ($pagingbar->perpage > 0) {
  227. $lastpage = floor($pagingbar->totalcount / $pagingbar->perpage);
  228. } else {
  229. $lastpage = 0;
  230. }
  231. if ($page != 0) {
  232. $previouslink = html_writer::link(new moodle_url($baseurl, array($pagevar=>$page-1)), get_string('previous'));
  233. $output .= "<li>$previouslink</li>";
  234. } else {
  235. $output .= '<li class=disabled><span>'.get_string('previous').'</span></li>';
  236. }
  237. $start = 0;
  238. $stop = $lastpage;
  239. $truncate = $lastpage + 1 > $maxdisplay ;
  240. $start_margin = floor($maxdisplay / 2);
  241. $end_margin = $lastpage - ceil($maxdisplay / 2);
  242. $near_to_start = $page < $start_margin;
  243. $near_to_end = $page > $end_margin;
  244. if ($truncate && $near_to_start) {
  245. $stop = $maxdisplay - 3;
  246. } else if ($truncate && $near_to_end) {
  247. $start = $lastpage - $maxdisplay + 3;
  248. } else if ($truncate) { // truncate both sides, centered on current page
  249. $before_current = ceil(($maxdisplay - 5) / 2) ;
  250. $start = $page - $before_current;
  251. $stop = $start + $maxdisplay - 5;
  252. }
  253. if ($truncate && !$near_to_start) {
  254. $link = html_writer::link(new moodle_url($baseurl, array($pagevar=>'0')), '1');
  255. $output .= "<li>$link</li>" . "<li class=disabled><span>…</span></li>";
  256. }
  257. for ($i = $start; $i <= $stop; $i++) {
  258. if ($page == $i) {
  259. $pagename = $page + 1;
  260. $output .= "<li class=active><span>$pagename</span></li>";
  261. } else {
  262. $link = html_writer::link(new moodle_url($baseurl, array($pagevar=>$i)), $i+1);
  263. $output .= "<li>$link</li>";
  264. }
  265. }
  266. if ($truncate && !$near_to_end) {
  267. $output .= "<li class=disabled><span>…</span>";
  268. $link = html_writer::link(new moodle_url($baseurl, array($pagevar=>$lastpage)), $lastpage + 1);
  269. $output .= "<li>$link</li>";
  270. }
  271. if ($page != $lastpage) {
  272. $nextlink = html_writer::link(new moodle_url($baseurl, array($pagevar=>$page+1)), get_string('next'));
  273. $output .= "<li>$nextlink</li>";
  274. } else {
  275. $output .= '<li class=disabled><span>'.get_string('next').'</span></li>';
  276. }
  277. return $output."</ul></div>";
  278. }
  279. }
  280. public function navbar() {
  281. $items = $this->page->navbar->get_items();
  282. $htmlblocks = array();
  283. //$divider = '<span class="divider">'.get_separator().'</span>';
  284. $divider = self::span(array('class'=>'divider'), '/');
  285. $navbarcontent = '<ul class=breadcrumb>';
  286. $itemcount = count($items);
  287. $lis = array();
  288. for ($i=1;$i <= $itemcount;$i++) {
  289. $item = $items[$i-1];
  290. $item->hideicon = true;
  291. if ($i===$itemcount) {
  292. $li= "<li>".$this->render($item)."</li>";
  293. } else {
  294. $li= "<li>".$this->render($item)." $divider</li>";
  295. }
  296. $lis[] = $li;
  297. }
  298. $navbarcontent .= join('', $lis).'</ul>';
  299. return $navbarcontent;
  300. }
  301. protected function render_single_button(single_button $button) {
  302. $attributes = array('type' => 'submit',
  303. 'class' => 'btn',
  304. 'value' => $button->label,
  305. 'disabled' => $button->disabled ? 'disabled' : null,
  306. 'title' => $button->tooltip);
  307. if ($button->actions) {
  308. $id = html_writer::random_id('single_button');
  309. $attributes['id'] = $id;
  310. foreach ($button->actions as $action) {
  311. $this->add_action_handler($action, $id);
  312. }
  313. }
  314. // first the input element
  315. $output = html_writer::empty_tag('input', $attributes);
  316. // then hidden fields
  317. $params = $button->url->params();
  318. if ($button->method === 'post') {
  319. $params['sesskey'] = sesskey();
  320. }
  321. foreach ($params as $var => $val) {
  322. $output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => $var, 'value' => $val));
  323. }
  324. // then div wrapper for xhtml strictness
  325. $output = html_writer::tag('div', $output);
  326. // now the form itself around it
  327. if ($button->method === 'get') {
  328. $url = $button->url->out_omit_querystring(true); // url without params, the anchor part allowed
  329. } else {
  330. $url = $button->url->out_omit_querystring(); // url without params, the anchor part not allowed
  331. }
  332. if ($url === '') {
  333. $url = '#'; // there has to be always some action
  334. }
  335. $attributes = array('method' => $button->method,
  336. 'class' => 'form-inline',
  337. 'action' => $url,
  338. 'id' => $button->formid);
  339. $output = html_writer::tag('form', $output, $attributes);
  340. return self::div(array('class' => $button->class), $output);
  341. }
  342. protected function render_single_select(single_select $select) {
  343. $select = clone($select);
  344. if (empty($select->formid)) {
  345. $select->formid = html_writer::random_id('single_select_f');
  346. }
  347. $output = '';
  348. $params = $select->url->params();
  349. if ($select->method === 'post') {
  350. $params['sesskey'] = sesskey();
  351. }
  352. foreach ($params as $name=>$value) {
  353. $output .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>$name, 'value'=>$value));
  354. }
  355. if (empty($select->attributes['id'])) {
  356. $select->attributes['id'] = html_writer::random_id('single_select');
  357. }
  358. if ($select->disabled) {
  359. $select->attributes['disabled'] = 'disabled';
  360. }
  361. if ($select->tooltip) {
  362. $select->attributes['title'] = $select->tooltip;
  363. }
  364. if ($select->label) {
  365. $output .= html_writer::label($select->label, $select->attributes['id'], false, $select->labelattributes);
  366. }
  367. if ($select->helpicon instanceof help_icon) {
  368. $output .= $this->render($select->helpicon);
  369. } else if ($select->helpicon instanceof old_help_icon) {
  370. $output .= $this->render($select->helpicon);
  371. }
  372. $output .= html_writer::select($select->options, $select->name, $select->selected, $select->nothing, $select->attributes);
  373. $go = html_writer::empty_tag('input', array('type'=>'submit', 'value'=>get_string('go')));
  374. $output .= html_writer::tag('noscript', $go);
  375. $nothing = empty($select->nothing) ? false : key($select->nothing);
  376. $this->page->requires->js_init_call('M.util.init_select_autosubmit', array($select->formid, $select->attributes['id'], $nothing));
  377. // then div wrapper for xhtml strictness
  378. $output = html_writer::tag('div', $output);
  379. // now the form itself around it
  380. if ($select->method === 'get') {
  381. $url = $select->url->out_omit_querystring(true); // url without params, the anchor part allowed
  382. } else {
  383. $url = $select->url->out_omit_querystring(); // url without params, the anchor part not allowed
  384. }
  385. $formattributes = array('method' => $select->method,
  386. 'class' => 'form-inline',
  387. 'action' => $url,
  388. 'id' => $select->formid);
  389. $output = html_writer::tag('form', $output, $formattributes);
  390. // and finally one more wrapper with class
  391. return self::div(array('class' => $select->class), $output);
  392. }
  393. protected function init_block_hider_js(block_contents $bc) { }
  394. }
  395. include_once($CFG->dirroot . "/admin/renderer.php");
  396. class theme_gu23_core_admin_renderer extends core_admin_renderer {
  397. /**
  398. * Display the 'Do you acknowledge the terms of the GPL' page. The first page
  399. * during install.
  400. * @return string HTML to output.
  401. */
  402. public function install_licence_page() {
  403. global $CFG;
  404. $output = '';
  405. $copyrightnotice = text_to_html(get_string('gpl3'));
  406. $copyrightnotice = str_replace('target="_blank"', 'onclick="this.target=\'_blank\'"', $copyrightnotice); // extremely ugly validation hack
  407. $continue = new single_button(new moodle_url('/admin/index.php', array('lang'=>$CFG->lang, 'agreelicense'=>1)), get_string('continue'), 'get');
  408. $output .= $this->header();
  409. $output .= $this->heading('<a href="http://moodle.org">Moodle</a> - Modular Object-Oriented Dynamic Learning Environment');
  410. $output .= $this->heading(get_string('copyrightnotice'));
  411. $output .= $this->box($copyrightnotice, 'copyrightnotice');
  412. $output .= html_writer::empty_tag('br');
  413. $output .= $this->confirm(get_string('doyouagree'), $continue, "http://docs.moodle.org/dev/License");
  414. $output .= $this->footer();
  415. return $output;
  416. }
  417. /**
  418. * Display page explaining proper upgrade process,
  419. * there can not be any PHP file leftovers...
  420. *
  421. * @return string HTML to output.
  422. */
  423. public function upgrade_stale_php_files_page() {
  424. $output = '';
  425. $output .= $this->header();
  426. $output .= $this->heading(get_string('upgradestalefiles', 'admin'));
  427. $output .= $this->box_start('generalbox', 'notice');
  428. $output .= format_text(get_string('upgradestalefilesinfo', 'admin', get_docs_url('Upgrading')), FORMAT_MARKDOWN);
  429. $output .= html_writer::empty_tag('br');
  430. $output .= html_writer::tag('div', $this->single_button($this->page->url, get_string('reload'), 'get'), array('class' => 'buttons'));
  431. $output .= $this->box_end();
  432. $output .= $this->footer();
  433. return $output;
  434. }
  435. /**
  436. * Display the 'environment check' page that is displayed during install.
  437. * @param int $maturity
  438. * @param boolean $envstatus final result of the check (true/false)
  439. * @param array $environment_results array of results gathered
  440. * @param string $release moodle release
  441. * @return string HTML to output.
  442. */
  443. public function install_environment_page($maturity, $envstatus, $environment_results, $release) {
  444. global $CFG;
  445. $output = '';
  446. $output .= $this->header();
  447. $output .= $this->maturity_warning($maturity);
  448. $output .= $this->heading("Moodle $release");
  449. $output .= $this->release_notes_link();
  450. $output .= $this->environment_check_table($envstatus, $environment_results);
  451. if (!$envstatus) {
  452. $output .= $this->upgrade_reload(new moodle_url('/admin/index.php', array('agreelicense' => 1, 'lang' => $CFG->lang)));
  453. } else {
  454. $output .= $this->notification(get_string('environmentok', 'admin'), 'notifysuccess');
  455. $output .= $this->continue_button(new moodle_url('/admin/index.php', array('agreelicense'=>1, 'confirmrelease'=>1, 'lang'=>$CFG->lang)));
  456. }
  457. $output .= $this->footer();
  458. return $output;
  459. }
  460. /**
  461. * Displays the list of plugins with unsatisfied dependencies
  462. *
  463. * @param double|string|int $version Moodle on-disk version
  464. * @param array $failed list of plugins with unsatisfied dependecies
  465. * @param moodle_url $reloadurl URL of the page to recheck the dependencies
  466. * @return string HTML
  467. */
  468. public function unsatisfied_dependencies_page($version, array $failed, moodle_url $reloadurl) {
  469. $output = '';
  470. $output .= $this->header();
  471. $output .= $this->heading(get_string('pluginscheck', 'admin'));
  472. $output .= $this->warning(get_string('pluginscheckfailed', 'admin', array('pluginslist' => implode(', ', array_unique($failed)))));
  473. $output .= $this->plugins_check_table(plugin_manager::instance(), $version, array('xdep' => true));
  474. $output .= $this->warning(get_string('pluginschecktodo', 'admin'));
  475. $output .= $this->continue_button($reloadurl);
  476. $output .= $this->footer();
  477. return $output;
  478. }
  479. /**
  480. * Display the 'You are about to upgrade Moodle' page. The first page
  481. * during upgrade.
  482. * @param string $strnewversion
  483. * @param int $maturity
  484. * @return string HTML to output.
  485. */
  486. public function upgrade_confirm_page($strnewversion, $maturity) {
  487. $output = '';
  488. $continueurl = new moodle_url('index.php', array('confirmupgrade' => 1));
  489. $cancelurl = new moodle_url('index.php');
  490. $output .= $this->header();
  491. $output .= $this->maturity_warning($maturity);
  492. $output .= $this->confirm(get_string('upgradesure', 'admin', $strnewversion), $continueurl, $cancelurl);
  493. $output .= $this->footer();
  494. return $output;
  495. }
  496. /**
  497. * Display the environment page during the upgrade process.
  498. * @param string $release
  499. * @param boolean $envstatus final result of env check (true/false)
  500. * @param array $environment_results array of results gathered
  501. * @return string HTML to output.
  502. */
  503. public function upgrade_environment_page($release, $envstatus, $environment_results) {
  504. global $CFG;
  505. $output = '';
  506. $output .= $this->header();
  507. $output .= $this->heading("Moodle $release");
  508. $output .= $this->release_notes_link();
  509. $output .= $this->environment_check_table($envstatus, $environment_results);
  510. if (!$envstatus) {
  511. $output .= $this->upgrade_reload(new moodle_url('/admin/index.php'), array('confirmupgrade' => 1));
  512. } else {
  513. $output .= $this->notification(get_string('environmentok', 'admin'), 'notifysuccess');
  514. if (empty($CFG->skiplangupgrade) and current_language() !== 'en') {
  515. $output .= $this->box(get_string('langpackwillbeupdated', 'admin'), 'generalbox', 'notice');
  516. }
  517. $output .= $this->continue_button(new moodle_url('/admin/index.php', array('confirmupgrade' => 1, 'confirmrelease' => 1)));
  518. }
  519. $output .= $this->footer();
  520. return $output;
  521. }
  522. /**
  523. * Display the upgrade page that lists all the plugins that require attention.
  524. * @param plugin_manager $pluginman provides information about the plugins.
  525. * @param available_update_checker $checker provides information about available updates.
  526. * @param int $version the version of the Moodle code from version.php.
  527. * @param bool $showallplugins
  528. * @param moodle_url $reloadurl
  529. * @param moodle_url $continueurl
  530. * @return string HTML to output.
  531. */
  532. public function upgrade_plugin_check_page(plugin_manager $pluginman, available_update_checker $checker,
  533. $version, $showallplugins, $reloadurl, $continueurl) {
  534. global $CFG;
  535. $output = '';
  536. $output .= $this->header();
  537. $output .= $this->box_start('generalbox');
  538. $output .= $this->container_start('generalbox', 'notice');
  539. $output .= html_writer::tag('p', get_string('pluginchecknotice', 'core_plugin'));
  540. if (empty($CFG->disableupdatenotifications)) {
  541. $output .= $this->container_start('checkforupdates');
  542. $output .= $this->single_button(new moodle_url($reloadurl, array('fetchupdates' => 1)), get_string('checkforupdates', 'core_plugin'));
  543. if ($timefetched = $checker->get_last_timefetched()) {
  544. $output .= $this->container(get_string('checkforupdateslast', 'core_plugin',
  545. userdate($timefetched, get_string('strftimedatetime', 'core_langconfig'))));
  546. }
  547. $output .= $this->container_end();
  548. }
  549. $output .= $this->container_end();
  550. $output .= $this->plugins_check_table($pluginman, $version, array('full' => $showallplugins));
  551. $output .= $this->box_end();
  552. $output .= $this->upgrade_reload($reloadurl);
  553. if ($pluginman->some_plugins_updatable()) {
  554. $output .= $this->container_start('upgradepluginsinfo');
  555. $output .= $this->help_icon('upgradepluginsinfo', 'core_admin', get_string('upgradepluginsfirst', 'core_admin'));
  556. $output .= $this->container_end();
  557. }
  558. $button = new single_button($continueurl, get_string('upgradestart', 'admin'), 'get');
  559. $button->class = 'continuebutton';
  560. $output .= $this->render($button);
  561. $output .= $this->footer();
  562. return $output;
  563. }
  564. /**
  565. * Output a warning message, of the type that appears on the admin notifications page.
  566. * @param string $message the message to display.
  567. * @param string $type type class
  568. * @return string HTML to output.
  569. */
  570. protected function warning($message, $type = '') {
  571. if ($type == 'error') { $type = ' alert-error';}
  572. return html_writer::tag('div', $message, array('class'=>('alert' . $type)));
  573. }
  574. /**
  575. * Display a warning about installing development code if necesary.
  576. * @param int $maturity
  577. * @return string HTML to output.
  578. */
  579. protected function maturity_warning($maturity) {
  580. if ($maturity == MATURITY_STABLE) {
  581. return ''; // No worries.
  582. }
  583. $maturitylevel = get_string('maturity' . $maturity, 'admin');
  584. return html_writer::tag('div',
  585. $this->container(get_string('maturitycorewarning', 'admin', $maturitylevel)) .
  586. $this->container($this->doc_link('admin/versions', get_string('morehelp'))),
  587. 'alert maturitywarning');
  588. }
  589. /**
  590. * Output the copyright notice.
  591. * @return string HTML to output.
  592. */
  593. protected function moodle_copyright() {
  594. global $CFG;
  595. //////////////////////////////////////////////////////////////////////////////////////////////////
  596. //// IT IS ILLEGAL AND A VIOLATION OF THE GPL TO HIDE, REMOVE OR MODIFY THIS COPYRIGHT NOTICE ///
  597. $copyrighttext = '<p><a href="http://moodle.org/">Moodle</a> '.
  598. '<a href="http://docs.moodle.org/dev/Releases" title="'.$CFG->version.'">'.$CFG->release.'</a></p>'.
  599. '<p>Copyright &copy; 1999 onwards, Martin Dougiamas '.
  600. 'and <a href="http://docs.moodle.org/dev/Credits">many other contributors</a>.</p>'.
  601. '<p><a href="http://docs.moodle.org/dev/License">GNU Public License</a><p>';
  602. //////////////////////////////////////////////////////////////////////////////////////////////////
  603. return html_writer::tag('div', $copyrighttext, array('class'=>'alert alert-info copyright'));
  604. }
  605. /**
  606. * Display a warning about installing development code if necesary.
  607. * @param int $maturity
  608. * @return string HTML to output.
  609. */
  610. protected function maturity_info($maturity) {
  611. if ($maturity == MATURITY_STABLE) {
  612. return ''; // No worries.
  613. }
  614. $maturitylevel = get_string('maturity' . $maturity, 'admin');
  615. return $this->box(
  616. get_string('maturitycoreinfo', 'admin', $maturitylevel) . ' ' .
  617. $this->doc_link('admin/versions', get_string('morehelp')),
  618. 'alert maturityinfo maturity'.$maturity);
  619. }
  620. /**
  621. * Displays the info about available Moodle updates
  622. *
  623. * @param array|null $updates array of available_update_info objects or null
  624. * @param int|null $fetch timestamp of the most recent updates fetch or null (unknown)
  625. * @return string
  626. */
  627. protected function available_updates($updates, $fetch) {
  628. $updateinfo = $this->box_start('alert alert-info availableupdatesinfo');
  629. if (is_array($updates)) {
  630. $updateinfo .= $this->heading(get_string('updateavailable', 'core_admin'), 3);
  631. foreach ($updates as $update) {
  632. $updateinfo .= $this->moodle_available_update_info($update);
  633. }
  634. } else {
  635. $now = time();
  636. if ($fetch and ($fetch <= $now) and ($now - $fetch < HOURSECS)) {
  637. $updateinfo .= $this->heading(get_string('updateavailablenot', 'core_admin'), 3);
  638. }
  639. }
  640. $updateinfo .= $this->container_start('checkforupdates');
  641. $updateinfo .= $this->single_button(new moodle_url($this->page->url, array('fetchupdates' => 1)), get_string('checkforupdates', 'core_plugin'));
  642. if ($fetch) {
  643. $updateinfo .= $this->container(get_string('checkforupdateslast', 'core_plugin',
  644. userdate($fetch, get_string('strftimedatetime', 'core_langconfig'))));
  645. }
  646. $updateinfo .= $this->container_end();
  647. $updateinfo .= $this->box_end();
  648. return $updateinfo;
  649. }
  650. function upgrade_reload($url) {
  651. return '<div><a class=btn href="' . $url. '"><i class=icon-refresh></i> ' . get_string('reload') . '</a></div>';
  652. }
  653. /**
  654. * Displays all known plugins and information about their installation or upgrade
  655. *
  656. * This default implementation renders all plugins into one big table. The rendering
  657. * options support:
  658. * (bool)full = false: whether to display up-to-date plugins, too
  659. * (bool)xdep = false: display the plugins with unsatisified dependecies only
  660. *
  661. * @param plugin_manager $pluginman provides information about the plugins.
  662. * @param int $version the version of the Moodle code from version.php.
  663. * @param array $options rendering options
  664. * @return string HTML code
  665. */
  666. public function plugins_check_table(plugin_manager $pluginman, $version, array $options = array()) {
  667. global $CFG;
  668. $plugininfo = $pluginman->get_plugins();
  669. if (empty($plugininfo)) {
  670. return '';
  671. }
  672. $options['full'] = isset($options['full']) ? (bool)$options['full'] : false;
  673. $options['xdep'] = isset($options['xdep']) ? (bool)$options['xdep'] : false;
  674. $table = new html_table();
  675. $table->id = 'plugins-check';
  676. $table->head = array(
  677. get_string('displayname', 'core_plugin'),
  678. get_string('rootdir', 'core_plugin'),
  679. get_string('source', 'core_plugin'),
  680. get_string('versiondb', 'core_plugin'),
  681. get_string('versiondisk', 'core_plugin'),
  682. get_string('requires', 'core_plugin'),
  683. get_string('status', 'core_plugin'),
  684. );
  685. $table->colclasses = array(
  686. 'displayname', 'rootdir', 'source', 'versiondb', 'versiondisk', 'requires', 'status',
  687. );
  688. $table->data = array();
  689. $numofhighlighted = array(); // number of highlighted rows per this subsection
  690. foreach ($plugininfo as $type => $plugins) {
  691. $header = new html_table_cell($pluginman->plugintype_name_plural($type));
  692. $header->header = true;
  693. $header->colspan = count($table->head);
  694. $header = new html_table_row(array($header));
  695. $header->attributes['class'] = 'plugintypeheader type-' . $type;
  696. $numofhighlighted[$type] = 0;
  697. if (empty($plugins) and $options['full']) {
  698. $msg = new html_table_cell(get_string('noneinstalled', 'core_plugin'));
  699. $msg->colspan = count($table->head);
  700. $row = new html_table_row(array($msg));
  701. $row->attributes['class'] .= 'warning msg-noneinstalled';
  702. $table->data[] = $header;
  703. $table->data[] = $row;
  704. continue;
  705. }
  706. $plugintyperows = array();
  707. foreach ($plugins as $name => $plugin) {
  708. $row = new html_table_row();
  709. $row->attributes['class'] = 'type-' . $plugin->type . ' name-' . $plugin->type . '_' . $plugin->name;
  710. if ($this->page->theme->resolve_image_location('icon', $plugin->type . '_' . $plugin->name)) {
  711. $icon = $this->output->pix_icon('icon', '', $plugin->type . '_' . $plugin->name, array('class' => 'smallicon pluginicon'));
  712. } else {
  713. $icon = self::icon_spacer();
  714. }
  715. $displayname = $icon . ' ' . $plugin->displayname;
  716. $displayname = new html_table_cell($displayname);
  717. $rootdir = new html_table_cell($plugin->get_dir());
  718. if ($isstandard = $plugin->is_standard()) {
  719. $row->attributes['class'] .= ' standard';
  720. $source = new html_table_cell(get_string('sourcestd', 'core_plugin'));
  721. } else {
  722. $row->attributes['class'] .= ' extension';
  723. $source = new html_table_cell(get_string('sourceext', 'core_plugin'));
  724. }
  725. $versiondb = new html_table_cell($plugin->versiondb);
  726. $versiondisk = new html_table_cell($plugin->versiondisk);
  727. $statuscode = $plugin->get_status();
  728. $row->attributes['class'] .= ' status-' . $statuscode;
  729. $status = get_string('status_' . $statuscode, 'core_plugin');
  730. $availableupdates = $plugin->available_updates();
  731. if (!empty($availableupdates) and empty($CFG->disableupdatenotifications)) {
  732. foreach ($availableupdates as $availableupdate) {
  733. $status .= $this->plugin_available_update_info($availableupdate);
  734. }
  735. }
  736. $status = new html_table_cell($status);
  737. $requires = new html_table_cell($this->required_column($plugin, $pluginman, $version));
  738. $statusisboring = in_array($statuscode, array(
  739. plugin_manager::PLUGIN_STATUS_NODB, plugin_manager::PLUGIN_STATUS_UPTODATE));
  740. $coredependency = $plugin->is_core_dependency_satisfied($version);
  741. $otherpluginsdependencies = $pluginman->are_dependencies_satisfied($plugin->get_other_required_plugins());
  742. $dependenciesok = $coredependency && $otherpluginsdependencies;
  743. if ($options['xdep']) {
  744. // we want to see only plugins with failed dependencies
  745. if ($dependenciesok) {
  746. continue;
  747. }
  748. } else if ($isstandard and $statusisboring and $dependenciesok and empty($availableupdates)) {
  749. // no change is going to happen to the plugin - display it only
  750. // if the user wants to see the full list
  751. if (empty($options['full'])) {
  752. continue;
  753. }
  754. }
  755. // ok, the plugin should be displayed
  756. $numofhighlighted[$type]++;
  757. $row->cells = array($displayname, $rootdir, $source,
  758. $versiondb, $versiondisk, $requires, $status);
  759. $plugintyperows[] = $row;
  760. }
  761. if (empty($numofhighlighted[$type]) and empty($options['full'])) {
  762. continue;
  763. }
  764. $table->data[] = $header;
  765. $table->data = array_merge($table->data, $plugintyperows);
  766. }
  767. $sumofhighlighted = array_sum($numofhighlighted);
  768. if ($options['xdep']) {
  769. // we do not want to display no heading and links in this mode
  770. $out = '';
  771. } else if ($sumofhighlighted == 0) {
  772. $out = $this->output->container_start('nonehighlighted', 'plugins-check-info');
  773. $out .= $this->output->heading(get_string('nonehighlighted', 'core_plugin'));
  774. if (empty($options['full'])) {
  775. $out .= html_writer::link(new moodle_url('/admin/index.php',
  776. array('confirmupgrade' => 1, 'confirmrelease' => 1, 'showallplugins' => 1)),
  777. get_string('nonehighlightedinfo', 'core_plugin'));
  778. }
  779. $out .= $this->output->container_end();
  780. } else {
  781. $out = $this->output->container_start('somehighlighted', 'plugins-check-info');
  782. $out .= $this->output->heading(get_string('somehighlighted', 'core_plugin', $sumofhighlighted));
  783. if (empty($options['full'])) {
  784. $out .= html_writer::link(new moodle_url('/admin/index.php',
  785. array('confirmupgrade' => 1, 'confirmrelease' => 1, 'showallplugins' => 1)),
  786. get_string('somehighlightedinfo', 'core_plugin'));
  787. } else {
  788. $out .= html_writer::link(new moodle_url('/admin/index.php',
  789. array('confirmupgrade' => 1, 'confirmrelease' => 1, 'showallplugins' => 0)),
  790. get_string('somehighlightedonly', 'core_plugin'));
  791. }
  792. $out .= $this->output->container_end();
  793. }
  794. if ($sumofhighlighted > 0 or $options['full']) {
  795. $out .= html_writer::table($table);
  796. }
  797. return $out;
  798. }
  799. /**
  800. * Formats the information that needs to go in the 'Requires' column.
  801. * @param plugininfo_base $plugin the plugin we are rendering the row for.
  802. * @param plugin_manager $pluginman provides data on all the plugins.
  803. * @param string $version
  804. * @return string HTML code
  805. */
  806. protected function required_column(plugininfo_base $plugin, plugin_manager $pluginman, $version) {
  807. $requires = array();
  808. if (!empty($plugin->versionrequires)) {
  809. if ($plugin->versionrequires <= $version) {
  810. $class = 'requires-ok';
  811. } else {
  812. $class = 'requires-failed';
  813. }
  814. $requires[] = html_writer::tag('li',
  815. get_string('moodleversion', 'core_plugin', $plugin->versionrequires),
  816. array('class' => $class));
  817. }
  818. foreach ($plugin->get_other_required_plugins() as $component => $requiredversion) {
  819. $ok = true;
  820. $otherplugin = $pluginman->get_plugin_info($component);
  821. if (is_null($otherplugin)) {
  822. $ok = false;
  823. } else if ($requiredversion != ANY_VERSION and $otherplugin->versiondisk < $requiredversion) {
  824. $ok = false;
  825. }
  826. if ($ok) {
  827. $class = 'requires-ok';
  828. } else {
  829. $class = 'requires-failed';
  830. }
  831. if ($requiredversion != ANY_VERSION) {
  832. $str = 'otherpluginversion';
  833. } else {
  834. $str = 'otherplugin';
  835. }
  836. $requires[] = html_writer::tag('li',
  837. get_string($str, 'core_plugin',
  838. array('component' => $component, 'version' => $requiredversion)),
  839. array('class' => $class));
  840. }
  841. if (!$requires) {
  842. return '';
  843. }
  844. return html_writer::tag('ul', implode("\n", $requires));
  845. }
  846. /**
  847. * Prints an overview about the plugins - number of installed, number of extensions etc.
  848. *
  849. * @param plugin_manager $pluginman provides information about the plugins
  850. * @return string as usually
  851. */
  852. public function plugins_overview_panel(plugin_manager $pluginman) {
  853. global $CFG;
  854. $plugininfo = $pluginman->get_plugins();
  855. $numtotal = $numdisabled = $numextension = $numupdatable = 0;
  856. foreach ($plugininfo as $type => $plugins) {
  857. foreach ($plugins as $name => $plugin) {
  858. if ($plugin->get_status() === plugin_manager::PLUGIN_STATUS_MISSING) {
  859. continue;
  860. }
  861. $numtotal++;
  862. if ($plugin->is_enabled() === false) {
  863. $numdisabled++;
  864. }
  865. if (!$plugin->is_standard()) {
  866. $numextension++;
  867. }
  868. if (empty($CFG->disableupdatenotifications) and $plugin->available_updates()) {
  869. $numupdatable++;
  870. }
  871. }
  872. }
  873. $info = array();
  874. $info[] = html_writer::tag('span', get_string('numtotal', 'core_plugin', $numtotal), array('class' => 'info total'));
  875. $info[] = html_writer::tag('span', get_string('numdisabled', 'core_plugin', $numdisabled), array('class' => 'info disabled'));
  876. $info[] = html_writer::tag('span', get_string('numextension', 'core_plugin', $numextension), array('class' => 'info extension'));
  877. if ($numupdatable > 0) {
  878. $info[] = html_writer::tag('span', get_string('numupdatable', 'core_plugin', $numupdatable), array('class' => 'info updatable'));
  879. }
  880. return $this->output->box(implode(html_writer::tag('span', ' ', array('class' => 'separator')), $info), '', 'plugins-overview-panel');
  881. }
  882. /**
  883. * Displays all known plugins and links to manage them
  884. *
  885. * This default implementation renders all plugins into one big table.
  886. *
  887. * @param plugin_manager $pluginman provides information about the plugins.
  888. * @return string HTML code
  889. */
  890. public function plugins_control_panel(plugin_manager $pluginman) {
  891. global $CFG;
  892. $plugininfo = $pluginman->get_plugins();
  893. if (empty($plugininfo)) {
  894. return '';
  895. }
  896. $table = new html_table();
  897. $table->id = 'plugins-control-panel';
  898. $table->head = array(
  899. get_string('displayname', 'core_plugin'),
  900. get_string('source', 'core_plugin'),
  901. get_string('version', 'core_plugin'),
  902. get_string('availability', 'core_plugin'),
  903. get_string('actions', 'core_plugin'),
  904. get_string('notes','core_plugin'),
  905. );
  906. $table->colclasses = array(
  907. 'pluginname', 'source', 'version', 'availability', 'actions', 'notes'
  908. );
  909. foreach ($plugininfo as $type => $plugins) {
  910. $header = new html_table_cell($pluginman->plugintype_name_plural($type));
  911. $header->header = true;
  912. $header->colspan = count($table->head);
  913. $header = new html_table_row(array($header));
  914. $header->attributes['class'] = 'plugintypeheader type-' . $type;
  915. $table->data[] = $header;
  916. if (empty($plugins)) {
  917. $msg = new html_table_cell(get_string('noneinstalled', 'core_plugin'));
  918. $msg->colspan = count($table->head);
  919. $row = new html_table_row(array($msg));
  920. $row->attributes['class'] .= 'msg msg-noneinstalled';
  921. $table->data[] = $row;
  922. continue;
  923. }
  924. foreach ($plugins as $name => $plugin) {
  925. $row = new html_table_row();
  926. $row->attributes['class'] = 'type-' . $plugin->type . ' name-' . $plugin->type . '_' . $plugin->name;
  927. if ($this->page->theme->resolve_image_location('icon', $plugin->type . '_' . $plugin->name)) {
  928. $icon = $this->output->pix_icon('icon', '', $plugin->type . '_' . $plugin->name, array('class' => 'smallicon pluginicon'));
  929. } else {
  930. $icon = $this->output->pix_icon('spacer', '', 'moodle', array('class' => 'smallicon pluginicon noicon'));
  931. }
  932. if ($plugin->get_status() === plugin_manager::PLUGIN_STATUS_MISSING) {
  933. $msg = html_writer::tag('span', get_string('status_missing', 'core_plugin'), array('class' => 'notifyproblem'));
  934. $row->attributes['class'] .= ' missingfromdisk';
  935. } else {
  936. $msg = '';
  937. }
  938. $pluginname = html_writer::tag('div', $icon . ' ' . $plugin->displayname . ' ' . $msg, array('class' => 'displayname')).
  939. html_writer::tag('div', $plugin->component, array('class' => 'componentname'));
  940. $pluginname = new html_table_cell($pluginname);
  941. if ($plugin->is_standard()) {
  942. $row->attributes['class'] .= ' standard';
  943. $source = new html_table_cell(get_string('sourcestd', 'core_plugin'));
  944. } else {
  945. $row->attributes['class'] .= ' extension';
  946. $source = new html_table_cell(get_string('sourceext', 'core_plugin'));
  947. }
  948. $version = new html_table_cell($plugin->versiondb);
  949. $isenabled = $plugin->is_enabled();
  950. if (is_null($isenabled)) {
  951. $availability = new html_table_cell('');
  952. } else if ($isenabled) {
  953. $row->attributes['class'] .= ' enabled';
  954. $icon = $this->output->pix_icon('i/hide', get_string('pluginenabled', 'core_plugin'));
  955. $availability = new html_table_cell($icon . ' ' . get_string('pluginenabled', 'core_plugin'));
  956. } else {
  957. $row->attributes['class'] .= ' disabled';
  958. $icon = $this->output->pix_icon('i/show', get_string('plugindisabled', 'core_plugin'));
  959. $availability = new html_table_cell($icon . ' ' . get_string('plugindisabled', 'core_plugin'));
  960. }
  961. $actions = array();
  962. $settingsurl = $plugin->get_settings_url();
  963. if (!is_null($settingsurl)) {
  964. $actions[] = html_writer::link($settingsurl, get_string('settings', 'core_plugin'), array('class' => 'settings'));
  965. }
  966. $uninstallurl = $plugin->get_uninstall_url();
  967. if (!is_null($uninstallurl)) {
  968. $actions[] = html_writer::link($uninstallurl, get_string('uninstall', 'core_plugin'), array('class' => 'uninstall'));
  969. }
  970. $actions = new html_table_cell(implode(html_writer::tag('span', ' ', array('class' => 'separator')), $actions));
  971. $requriedby = $pluginman->other_plugins_that_require($plugin->component);
  972. if ($requriedby) {
  973. $requiredby = html_writer::tag('div', get_string('requiredby', 'core_plugin', implode(', ', $requriedby)),
  974. array('class' => 'requiredby'));
  975. } else {
  976. $requiredby = '';
  977. }
  978. $updateinfo = '';
  979. if (empty($CFG->disableupdatenotifications) and is_array($plugin->available_updates())) {
  980. foreach ($plugin->available_updates() as $availableupdate) {
  981. $updateinfo .= $this->plugin_available_update_info($availableupdate);
  982. }
  983. }
  984. $notes = new html_table_cell($requiredby.$updateinfo);
  985. $row->cells = array(
  986. $pluginname, $source, $version, $availability, $actions, $notes
  987. );
  988. $table->data[] = $row;
  989. }
  990. }
  991. return html_writer::table($table);
  992. }
  993. /**
  994. * Helper method to render the information about the available plugin update
  995. *
  996. * The passed objects always provides at least the 'version' property containing
  997. * the (higher) version of the plugin available.
  998. *
  999. * @param available_update_info $updateinfo information about the available update for the plugin
  1000. */
  1001. protected function plugin_available_update_info(available_update_info $updateinfo) {
  1002. $boxclasses = 'pluginupdateinfo';
  1003. $info = array();
  1004. if (isset($updateinfo->release)) {
  1005. $info[] = html_writer::tag('span', get_string('updateavailable_release', 'core_plugin', $updateinfo->release),
  1006. array('class' => 'info release'));
  1007. }
  1008. if (isset($updateinfo->maturity)) {
  1009. $info[] = html_writer::tag('span', get_string('maturity'.$updateinfo->maturity, 'core_admin'),
  1010. array('class' => 'info maturity'));
  1011. $boxclasses .= ' maturity'.$updateinfo->maturity;
  1012. }
  1013. if (isset($updateinfo->download)) {
  1014. $info[] = ht

Large files files are truncated, but you can click here to view the full file