PageRenderTime 62ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/theme/bootstrap/renderers.php

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

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