PageRenderTime 44ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/renderers.php

https://github.com/roelmann/krystle
PHP | 404 lines | 286 code | 47 blank | 71 comment | 92 complexity | 67c2abf1b4dca8ef38ccf2a475cf5129 MD5 | raw file
  1. <?php
  2. class theme_krystle_core_renderer extends core_renderer {
  3. protected $really_editing = false;
  4. public function set_really_editing($editing) {
  5. $this->really_editing = $editing;
  6. }
  7. /**
  8. * Outputs the page's footer
  9. * @return string HTML fragment
  10. */
  11. public function footer() {
  12. global $CFG, $DB, $USER;
  13. $output = $this->container_end_all(true);
  14. $footer = $this->opencontainers->pop('header/footer');
  15. if (debugging() and $DB and $DB->is_transaction_started()) {
  16. // TODO: MDL-20625 print warning - transaction will be rolled back
  17. }
  18. // Provide some performance info if required
  19. $performanceinfo = '';
  20. if (defined('MDL_PERF') || (!empty($CFG->perfdebug) and $CFG->perfdebug > 7)) {
  21. $perf = get_performance_info();
  22. if (defined('MDL_PERFTOLOG') && !function_exists('register_shutdown_function')) {
  23. error_log("PERF: " . $perf['txt']);
  24. }
  25. if (defined('MDL_PERFTOFOOT') || debugging() || $CFG->perfdebug > 7) {
  26. $performanceinfo = krystle_performance_output($perf);
  27. }
  28. }
  29. $perftoken = (property_exists($this, "unique_performance_info_token"))?$this->unique_performance_info_token:self::PERFORMANCE_INFO_TOKEN;
  30. $endhtmltoken = (property_exists($this, "unique_end_html_token"))?$this->unique_end_html_token:self::END_HTML_TOKEN;
  31. $footer = str_replace($perftoken, $performanceinfo, $footer);
  32. $footer = str_replace($endhtmltoken, $this->page->requires->get_end_code(), $footer);
  33. $this->page->set_state(moodle_page::STATE_DONE);
  34. if(!empty($this->page->theme->settings->persistentedit) && property_exists($USER, 'editing') && $USER->editing && !$this->really_editing) {
  35. $USER->editing = false;
  36. }
  37. return $output . $footer;
  38. }
  39. /**
  40. * The standard tags (typically performance information and validation links,
  41. * if we are in developer debug mode) that should be output in the footer area
  42. * of the page. Designed to be called in theme layout.php files.
  43. * @return string HTML fragment.
  44. */
  45. public function standard_footer_html() {
  46. global $CFG;
  47. // This function is normally called from a layout.php file in {@link header()}
  48. // but some of the content won't be known until later, so we return a placeholder
  49. // for now. This will be replaced with the real content in {@link footer()}.
  50. $output = (property_exists($this, "unique_performance_info_token"))?$this->unique_performance_info_token:self::PERFORMANCE_INFO_TOKEN;
  51. // Moodle 2.1 uses a magic accessor for $this->page->devicetypeinuse so we need to
  52. // check for the existence of the function that uses as
  53. // isset($this->page->devicetypeinuse) returns false
  54. if (function_exists('get_user_device_type')?($this->page->devicetypeinuse=='legacy'):$this->page->legacythemeinuse) {
  55. // The legacy theme is in use print the notification
  56. $output .= html_writer::tag('div', get_string('legacythemeinuse'), array('class'=>'legacythemeinuse'));
  57. }
  58. // Get links to switch device types (only shown for users not on a default device)
  59. if(method_exists($this, 'theme_switch_links')) {
  60. $output .= $this->theme_switch_links();
  61. }
  62. // if (!empty($CFG->debugpageinfo)) {
  63. // $output .= '<div class="performanceinfo">This page is: ' . $this->page->debug_summary() . '</div>';
  64. // }
  65. if (debugging(null, DEBUG_DEVELOPER)) { // Only in developer mode
  66. $output .= '<div class="purgecaches"><a href="'.$CFG->wwwroot.'/admin/purgecaches.php?confirm=1&amp;sesskey='.sesskey().'">'.get_string('purgecaches', 'admin').'</a></div>';
  67. }
  68. if (!empty($CFG->debugvalidators)) {
  69. $output .= '<div class="validators"><ul>
  70. <li><a href="http://validator.w3.org/check?verbose=1&amp;ss=1&amp;uri=' . urlencode(qualified_me()) . '">Validate HTML</a></li>
  71. <li><a href="http://www.contentquality.com/mynewtester/cynthia.exe?rptmode=-1&amp;url1=' . urlencode(qualified_me()) . '">Section 508 Check</a></li>
  72. <li><a href="http://www.contentquality.com/mynewtester/cynthia.exe?rptmode=0&amp;warnp2n3e=1&amp;url1=' . urlencode(qualified_me()) . '">WCAG 1 (2,3) Check</a></li>
  73. </ul></div>';
  74. }
  75. if (!empty($CFG->additionalhtmlfooter)) {
  76. $output .= "\n".$CFG->additionalhtmlfooter;
  77. }
  78. return $output;
  79. }
  80. /**
  81. * Renders a custom menu object (located in outputcomponents.php)
  82. *
  83. * The custom menu this method override the render_custom_menu function
  84. * in outputrenderers.php
  85. * @staticvar int $menucount
  86. * @param custom_menu $menu
  87. * @return string
  88. */
  89. protected function render_custom_menu(custom_menu $menu) {
  90. // If the menu has no children return an empty string
  91. if (!$menu->has_children()) {
  92. return '';
  93. }
  94. // Initialise this custom menu
  95. $content = html_writer::start_tag('ul', array('class'=>'dropdown dropdown-horizontal krystle-custom-menu'));
  96. // Render each child
  97. foreach ($menu->get_children() as $item) {
  98. $content .= $this->render_custom_menu_item($item);
  99. }
  100. // Close the open tags
  101. $content .= html_writer::end_tag('ul');
  102. // Return the custom menu
  103. return $content;
  104. }
  105. /**
  106. * Renders a custom menu node as part of a submenu
  107. *
  108. * The custom menu this method override the render_custom_menu_item function
  109. * in outputrenderers.php
  110. *
  111. * @see render_custom_menu()
  112. *
  113. * @staticvar int $submenucount
  114. * @param custom_menu_item $menunode
  115. * @return string
  116. */
  117. protected function render_custom_menu_item(custom_menu_item $menunode) {
  118. // Required to ensure we get unique trackable id's
  119. static $submenucount = 0;
  120. $content = html_writer::start_tag('li');
  121. if ($menunode->has_children()) {
  122. // If the child has menus render it as a sub menu
  123. $submenucount++;
  124. $extra = '';
  125. if ($menunode->get_url() === null) {
  126. $extra = ' customitem-nolink';
  127. }
  128. $content .= html_writer::start_tag('span', array('class'=>'customitem'.$extra));
  129. if ($menunode->get_url() !== null) {
  130. $content .= html_writer::link($menunode->get_url(), $menunode->get_text(), array('title'=>$menunode->get_title()));
  131. } else {
  132. $content .= $menunode->get_text();
  133. }
  134. $content .= html_writer::end_tag('span');
  135. $content .= html_writer::start_tag('ul');
  136. foreach ($menunode->get_children() as $menunode) {
  137. $content .= $this->render_custom_menu_item($menunode);
  138. }
  139. $content .= html_writer::end_tag('ul');
  140. } else {
  141. // The node doesn't have children so produce a final menuitem
  142. if ($menunode->get_url() !== null) {
  143. $url = $menunode->get_url();
  144. } else {
  145. $url = '#';
  146. }
  147. $content .= html_writer::link($url, $menunode->get_text(), array('title'=>$menunode->get_title(), 'class'=>'customitem-no-children'));
  148. }
  149. $content .= html_writer::end_tag('li');
  150. // Return the sub menu
  151. return $content;
  152. }
  153. // Copied from core_renderer with one minor change - changed $this->output->render() call to $this->render()
  154. protected function render_navigation_node(navigation_node $item) {
  155. $content = $item->get_content();
  156. $title = $item->get_title();
  157. if ($item->icon instanceof renderable && !$item->hideicon) {
  158. $icon = $this->render($item->icon);
  159. $content = $icon.$content; // use CSS for spacing of icons
  160. }
  161. if ($item->helpbutton !== null) {
  162. $content = trim($item->helpbutton).html_writer::tag('span', $content, array('class'=>'clearhelpbutton'));
  163. }
  164. if ($content === '') {
  165. return '';
  166. }
  167. if ($item->action instanceof action_link) {
  168. //TODO: to be replaced with something else
  169. $link = $item->action;
  170. if ($item->hidden) {
  171. $link->add_class('dimmed');
  172. }
  173. $content = $this->render($link);
  174. } else if ($item->action instanceof moodle_url) {
  175. $attributes = array();
  176. if ($title !== '') {
  177. $attributes['title'] = $title;
  178. }
  179. if ($item->hidden) {
  180. $attributes['class'] = 'dimmed_text';
  181. }
  182. $content = html_writer::link($item->action, $content, $attributes);
  183. } else if (is_string($item->action) || empty($item->action)) {
  184. $attributes = array();
  185. if ($title !== '') {
  186. $attributes['title'] = $title;
  187. }
  188. if ($item->hidden) {
  189. $attributes['class'] = 'dimmed_text';
  190. }
  191. $content = html_writer::tag('span', $content, $attributes);
  192. }
  193. return $content;
  194. }
  195. /**
  196. * blocks_for_region() overrides core_renderer::blocks_for_region()
  197. * in moodlelib.php. Returns a string
  198. * values ready for use.
  199. *
  200. * @return string
  201. */
  202. public function blocks_for_region($region) {
  203. if (!$this->page->blocks->is_known_region($region)) {
  204. return '';
  205. }
  206. $blockcontents = $this->page->blocks->get_content_for_region($region, $this);
  207. $output = '';
  208. foreach ($blockcontents as $bc) {
  209. if ($bc instanceof block_contents) {
  210. if (!($this->page->theme->settings->hidesettingsblock && substr($bc->attributes['class'], 0, 15) == 'block_settings ')
  211. && !($this->page->theme->settings->hidenavigationblock && substr($bc->attributes['class'], 0, 17) == 'block_navigation ')) {
  212. $output .= $this->block($bc, $region);
  213. }
  214. } else if ($bc instanceof block_move_target) {
  215. $output .= $this->block_move_target($bc);
  216. } else {
  217. throw new coding_exception('Unexpected type of thing (' . get_class($bc) . ') found in list of block contents.');
  218. }
  219. }
  220. return $output;
  221. }
  222. }
  223. class theme_krystle_topsettings_renderer extends plugin_renderer_base {
  224. public function settings_tree(settings_navigation $navigation) {
  225. global $CFG;
  226. $content = $this->navigation_node($navigation, array('class' => 'dropdown dropdown-horizontal'));
  227. return $content;
  228. }
  229. public function settings_search_box() {
  230. global $CFG;
  231. $content = "";
  232. if (has_capability('moodle/site:config', context_system::instance())) {
  233. $content .= $this->search_form(new moodle_url("$CFG->wwwroot/$CFG->admin/search.php"), optional_param('query', '', PARAM_RAW));
  234. }
  235. $content .= html_writer::empty_tag('br', array('clear' => 'all'));
  236. return $content;
  237. }
  238. public function navigation_tree(global_navigation $navigation) {
  239. global $CFG;
  240. $content = html_writer::start_tag('ul', array('id' => 'awesomeHomeMenu', 'class' => 'dropdown dropdown-horizontal'));
  241. $content .= html_writer::start_tag('li');
  242. $content .= html_writer::start_tag('a', array('href' => "$CFG->wwwroot", 'id' =>'home'));
  243. $content .= html_writer::empty_tag('img', array('alt' => '', 'src' =>$this->pix_url('home_icon', 'theme')));
  244. $content .= html_writer::end_tag('a');
  245. $content .= html_writer::end_tag('li');
  246. $content .= html_writer::start_tag('li');
  247. $content .= html_writer::start_tag('span', array('id' =>'awesomeNavMenu'));
  248. $content .= html_writer::empty_tag('img', array('alt' => '', 'src' =>$this->pix_url('user_silhouette', 'theme')));
  249. $content .= html_writer::end_tag('span');
  250. $content .= $this->navigation_node($navigation, array());
  251. $content .= html_writer::end_tag('li');
  252. $content .= html_writer::end_tag('ul');
  253. return $content;
  254. }
  255. protected function navigation_node(navigation_node $node, $attrs=array()) {
  256. global $CFG, $PAGE;
  257. static $mainsubnav;
  258. static $coursessubnav;
  259. $items = $node->children;
  260. $hidecourses = (property_exists($PAGE->theme->settings, 'coursesloggedinonly') && $PAGE->theme->settings->coursesloggedinonly && !isloggedin());
  261. // exit if empty, we don't want an empty ul element
  262. if ($items->count() == 0) {
  263. return '';
  264. }
  265. // array of nested li elements
  266. $lis = array();
  267. foreach ($items as $item) {
  268. if (!$item->display) {
  269. continue;
  270. }
  271. if ($item->key === 'courses' && $hidecourses) {
  272. continue;
  273. }
  274. // Skip pointless "Current course" node, go straight to its last (sole) child
  275. if ($item->key === 'currentcourse') {
  276. $item = $item->children->last();
  277. }
  278. $isbranch = ($item->children->count() > 0 || $item->nodetype == navigation_node::NODETYPE_BRANCH || (property_exists($item, 'isexpandable') && $item->isexpandable));
  279. $hasicon = (!$isbranch && $item->icon instanceof renderable);
  280. if ($isbranch) {
  281. $item->hideicon = true;
  282. }
  283. if ($item->action instanceof action_link && $hasicon && !$item->hideicon && (strip_tags($item->action->text)==$item->action->text)) {
  284. // Icon hasn't already been rendered - render it now.
  285. $item->action->text = $this->output->render($item->icon) . $item->action->text;
  286. }
  287. $content = $this->output->render($item);
  288. if($isbranch && $item->children->count()==0) {
  289. $expanded = false;
  290. // Navigation block does this via AJAX - we'll merge it in directly instead
  291. if (!empty($CFG->navshowallcourses) && $item->key === 'courses') {
  292. if(!$coursessubnav) {
  293. // Prepare dummy page for subnav initialisation
  294. $dummypage = new krystle_dummy_page();
  295. $dummypage->set_context($PAGE->context);
  296. $dummypage->set_url($PAGE->url);
  297. $coursessubnav = new krystle_expand_navigation($dummypage, $item->type, $item->key);
  298. $expanded = true;
  299. }
  300. $subnav = $coursessubnav;
  301. } else {
  302. if(!$mainsubnav) {
  303. // Prepare dummy page for subnav initialisation
  304. $dummypage = new krystle_dummy_page();
  305. $dummypage->set_context($PAGE->context);
  306. $dummypage->set_url($PAGE->url);
  307. $mainsubnav = new krystle_expand_navigation($dummypage, $item->type, $item->key);
  308. $expanded = true;
  309. }
  310. $subnav = $mainsubnav;
  311. }
  312. $branch = $subnav->find($item->key, $item->type);
  313. if ($branch === false) {
  314. if (!$expanded) {
  315. // re-use subnav so we don't have to reinitialise everything
  316. $subnav->expand($item->type, $item->key);
  317. }
  318. if (!isloggedin() || isguestuser()) {
  319. $subnav->set_expansion_limit(navigation_node::TYPE_COURSE);
  320. }
  321. $branch = $subnav->find($item->key, $item->type);
  322. }
  323. if($branch!==false) $content .= $this->navigation_node($branch);
  324. } else {
  325. $content .= $this->navigation_node($item);
  326. }
  327. if($isbranch && !(is_string($item->action) || empty($item->action))) {
  328. $content = html_writer::tag('li', $content, array('class' => 'clickable-with-children'));
  329. } else {
  330. $content = html_writer::tag('li', $content);
  331. }
  332. $lis[] = $content;
  333. }
  334. if (count($lis)) {
  335. return html_writer::nonempty_tag('ul', implode("\n", $lis), $attrs);
  336. } else {
  337. return '';
  338. }
  339. }
  340. public function search_form(moodle_url $formtarget, $searchvalue) {
  341. global $CFG;
  342. if (empty($searchvalue)) {
  343. $searchvalue = 'Search Settings..';
  344. }
  345. $content = html_writer::start_tag('form', array('class' => 'topadminsearchform', 'method' => 'get', 'action' => $formtarget));
  346. $content .= html_writer::start_tag('div', array('class' => 'search-box'));
  347. $content .= html_writer::tag('label', s(get_string('searchinsettings', 'admin')), array('for' => 'adminsearchquery', 'class' => 'accesshide'));
  348. $content .= html_writer::empty_tag('input', array('id' => 'topadminsearchquery', 'type' => 'text', 'name' => 'query', 'value' => s($searchvalue),
  349. 'onfocus' => "if(this.value == 'Search Settings..') {this.value = '';}",
  350. 'onblur' => "if (this.value == '') {this.value = 'Search Settings..';}"));
  351. //$content .= html_writer::empty_tag('input', array('class'=>'search-go','type'=>'submit', 'value'=>''));
  352. $content .= html_writer::end_tag('div');
  353. $content .= html_writer::end_tag('form');
  354. return $content;
  355. }
  356. }
  357. ?>