ÿØÿà JFIF    ÿÛ „  ( %!1"%)+...383-7(-.+  -%%--------+------------/----------------------------ÿÀ  ¶" ÿÄ     ÿÄ @    !1AQaq‘¡"±ÁÑð2’BRráS‚ñ3b¢CT²Ò #cÿÄ    ÿÄ '   1!AQ2a"‘±#ÿÚ   ? ò(/p‘—–¢·,M|¯G»R£üešT. ôŸEoCFñ‡ 4ÔkåóxR|µÁ¨ÓDà!Ç´µ˜‡p ÍQ‹§!þž^õWsŒy  åÁ§$á«%ºq˜™JyyË0y«^Ϗ -3ÃÏËÈ£Æ\P’ä„s&•‹Üs üô'àWt¹pñCp$bÚF`·7.^)¾!)ÒÙ˜–ÅÏš^h¾ø³·ìe±ŒaeÖ—Í,e=B}Jéߦ$$½—šÙÜCC¯¶è8β–Åkèwx LÉngT±æ¹£Ócœ¿Í/©Éÿ ‰ÚCÒ­mq;Tt¶–}0"zÖPcd1š­¤tˆ„ÐÓâqú[™öUCŠ2޿د­É(¸ßúçšmW,Ò ºf‹Ån™ÄLêÁ8üÁkÁ€L¥ÍuJ1œôrÂSŒÓöt!7EUíïb)AËi¬â-ÙHk8òÁiXYwÅ)O^"ÇØriÛô{»wRUKÙÏÚlÓ¬€‚’שT ] ªb—ÊîKC^×M“xùäñz¬zJ× {4[¹M'IÆeH1LCWÕ]œûº WDæà°OÅ‚¹c²ÞuA–rL`HšpCez‡V’— Ž‚Ë„–ñ­'µR0ÕÖ=À:±G»C\nÆÉ5*¢ †3šhQ4ýÒi$Õ1"Ü]¢p-q3zcQ$ªö¨¥æf›‘»´ÝÚHá„e²JÇ–iÊ:·à¬Øc5Åk»Laª*wi [0Ówk ¦a¦0Õ²ÅÅ‚T¸’³q:Æ<¹ú Ò˜Æ}2VE•Ѐp¡Ô3Úº …h³^LJºçì¥Ánó|˜ÖˆÎˆ+« ¦dø‘Mº–d\ªDðÛ„Ì×LÝ——Ð9Ç|•FèçVm™¨€™3õS–9Äå¢<̉Ìm¢±`·º˜&Z²ž Ë®D«¶»6™‰©­HÈ Àá«h­i³04æ’hxœi3ï¨(ÓL·†‹¶ËpŒ ƒÜÒ? :õdsÀ –3æÓ·Üjâ¬9—]8n¼&]I F£¼…ì–—Œ0v°LǐÅfÛ2TÖ’aµ˜N@ÖBSÏ^à´4-±°b×nÈÈœÆD=KdŒø…ÄÈK,›ÖR§fjü$^ÔÎ!„6^ s:Üun\ôkCÞò÷<—Lúl Í›G¹ÀPá¼Nc¡šÒ…ÙWͳœ±vÊáЄ×9‹P‰cEØ‘™›µŸP<×g1 º©Ø¬wiÁ^l5× I/';Ë+´Z‡ÓÄFÕp[Èð’ HÄ ó 9¬Dl4“é±Ï”V=^Hð;žLädÉa‚°Ë,#/Ž~²BÔÛ QãñQtIeórVB,ÏÂf‹4#Μc‹É3ZIÖ Œ¢¥·üxa‡Ãçè„jŠ[5 Ä!U?,3žÎ×…ðdÓ÷háŠA‰ìÄ4÷ÃÜZÃE{‰®+W\ZÍE[‰»µk»MÝ­`¢©†˜ÃV‹-f¢¡†¢a«eŠ%«Y¨©q%jâd,Ôq`) ¤¦…šˆ ¦E>0Ùb²t–Ÿ  ÷jsςҒKÈcø(é›;k(’#ôŒQ ™C> õ³M9óºÆµ¤çâ;uÀ)5>RÔ¸fÓ~Ȧ—’-$fe«"FâUˆÊwµPÏu w+"åÉó¨6s™Û9(À¨ù©hE°½†n`m~“@©›p!Vkhµ Á1šbEqqÊ@ºèl›2 –Yã%‘‚hÛ{a¶‡ÅÞM²¬çL34®Çl]®‹ŽØŒm'RÜe35æöˆ­Á­ cP9šeÁköo´L³Ì=p8]”‡B¶,šº|ɏdzXˆØk*ÇÚ{#ñ‰pã(€¶‡9ý'šÜ³½¯kƒ†Â’ëSOƒ•Å®H6+a¢µˆ‹Y¨b˜b+XˆÖ!°u!¢"µˆˆn2ˆ Å0Ä`Å Ô®c(ÓÜGº•Ä»Œ âWî%q.áÐÄ÷î%umÍ£+ÜQ,Vn¦-GphU¸¢X­&,Gt ·K¢ÅÅ·¥RÄÊÉbKn N­R2g$VµÕó Qr#–ÓZUÏð0ÎtÙÀœz ëöo“Îk¯n„T°"SÞ+³/…€½"ižãO%Í%&Δâ‘ËØ´IˆÓ°Ë‰ÞM3.™yçÁzit›`4C`k¢¼á!álÄï sÂ[×!¤l¾æo"ƒIÔ'@ªu)3›ô®“@Z à¾] üœ'‡4¸PÞkÁ-qÄH‰ÓÍBd´ÿ —¹°ÄA&ÊUC„öz‚‚RæŠtf¬>˜ÑidšEçÑL÷áý¡V±h§­c¿¥¨ƒ@g¼…Ýö^ÞËc.ž„æ“I[ ª+·zÐÒÚ,½Ð»¶€C›7jk$๖€Ž¾ÅÙpp¶ÍþéΤ ½ØÎŒq ñpæžÅ¥#Øâ49ÃÂK^MYV“,¶Éz_òæ:…;Õ«¦I3âJ£¤û5$7Èxün\â]Êe¯(Ÿ&Ž‹¶2<6Ćf× æ¢ƱqWı[(ÙÂŽç‚T7¨@ÈÉÍß‚ïÙ"&3TYlGށ†)†#5ŠA©^T2ÆÁ†)©†©†¤yGXÁ†©"†)©¼ÅV WS†#©]R–r‹q5ÕbâWþBh¯u+ªÅÄ×ü„nÑ^êkªÁj‰jeœWˆÕÕ`µDµ2Ì+Ä µDµµ5Ô{¤Þ0RF’H÷AÛ<ÊÁ§ ƈæ0Ñ£ê4 öÚµ[¬/1²€â<-¬šö²r×0o×w ´xÐÒË„ g01¬„åEM蛇Ã\6µE›‘fÙO k÷CºnÓ1`iîÒ² áÂ!ÑLÄÿ ³¬\õ*:M=Ç»c‹2[‰ØsÕLò\ŒK L^™üÄN\¶#» Ç\……ßïIœÉ$¸ÎñÍ®ÔHÇ Ûí/´>Li”„†g^$ 7NÍÑÑ2M2ªNg=k½Ð}Ÿl6‡ —JWˆ”ÞéT·+µ¦üÂFè¢Vs6ýÆ4»2+2IÝ9ô9®ÇGÙÇ1+Ä8;*Õ§ž½D*îÑWÚçá3Ma¤·ˆ¥t}š²Ü…Q+Æüµ8HíS”üxGéÁˆ¦Ël„éÈ 5 µÄƒ6äÜ(kIš¯S†fÖ&¸®×v|Äyˆ*禌Éù@7-®Ä[]ÎÖ¿ê`º…=:…žJVnݳvðÖKE¼‚ »mà ÷f®:Ë ™–4rð¡4` ܹçž~‹C=œ…¾Ïj|VDtK.ƒ"9 Ï ­–éXá³6WÒïIL-Ї Ç home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/blocks/settings/renderer.php000064400000013262152266541320024327 0ustar00. /** * Settings block * * @package block_settings * @copyright 2010 Sam Hemelryk * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class block_settings_renderer extends plugin_renderer_base { public function settings_tree(settings_navigation $navigation) { $count = 0; foreach ($navigation->children as &$child) { $child->preceedwithhr = ($count!==0); if ($child->display) { $count++; } } $navigationattrs = array( 'class' => 'block_tree list', 'role' => 'tree', 'data-ajax-loader' => 'block_navigation/site_admin_loader'); $content = $this->navigation_node($navigation, $navigationattrs); if (isset($navigation->id) && !is_numeric($navigation->id) && !empty($content)) { $content = $this->output->box($content, 'block_tree_box', $navigation->id); } return $content; } /** * Build the navigation node. * * @param navigation_node $node the navigation node object. * @param array $attrs list of attributes. * @param int $depth the depth, default to 1. * @return string the navigation node code. */ protected function navigation_node(navigation_node $node, $attrs=array(), $depth = 1) { $items = $node->children; // exit if empty, we don't want an empty ul element if ($items->count()==0) { return ''; } // array of nested li elements $lis = array(); $number = 0; foreach ($items as $item) { $number++; if (!$item->display) { continue; } $isbranch = ($item->children->count()>0 || $item->nodetype==navigation_node::NODETYPE_BRANCH); if ($isbranch) { $item->hideicon = true; } $content = $this->output->render($item); $id = $item->id ? $item->id : html_writer::random_id(); $ulattr = ['id' => $id . '_group', 'role' => 'group']; $liattr = ['class' => [$item->get_css_type(), 'depth_'.$depth], 'tabindex' => '-1', 'role' => 'treeitem']; $pattr = ['class' => ['tree_item']]; $pattr += !empty($item->id) ? ['id' => $item->id] : []; $hasicon = (!$isbranch && $item->icon instanceof renderable); if ($isbranch) { $liattr['class'][] = 'contains_branch'; if (!$item->forceopen || (!$item->forceopen && $item->collapse) || ($item->children->count() == 0 && $item->nodetype == navigation_node::NODETYPE_BRANCH)) { $liattr += ['aria-expanded' => 'false']; } else { $liattr += ['aria-expanded' => 'true']; } if ($item->requiresajaxloading) { $liattr['data-requires-ajax'] = 'true'; $liattr['data-loaded'] = 'false'; } else { $liattr += ['aria-owns' => $id . '_group']; } } else if ($hasicon) { $liattr['class'][] = 'item_with_icon'; $pattr['class'][] = 'hasicon'; } if ($item->isactive === true) { $liattr['class'][] = 'current_branch'; } if (!empty($item->classes) && count($item->classes) > 0) { $pattr['class'] = array_merge($pattr['class'], $item->classes); } // class attribute on the div item which only contains the item content $pattr['class'][] = 'tree_item'; if ($isbranch) { $pattr['class'][] = 'branch'; } else { $pattr['class'][] = 'leaf'; } $liattr['class'] = join(' ', $liattr['class']); $pattr['class'] = join(' ', $pattr['class']); if (isset($liattr['aria-expanded']) && $liattr['aria-expanded'] === 'false') { $ulattr += ['aria-hidden' => 'true']; } $content = html_writer::tag('p', $content, $pattr) . $this->navigation_node($item, $ulattr, $depth + 1); if (!empty($item->preceedwithhr) && $item->preceedwithhr===true) { $content = html_writer::empty_tag('hr') . $content; } $content = html_writer::tag('li', $content, $liattr); $lis[] = $content; } if (count($lis)) { if (empty($attrs['role'])) { $attrs['role'] = 'group'; } return html_writer::tag('ul', implode("\n", $lis), $attrs); } else { return ''; } } public function search_form(moodle_url $formtarget, $searchvalue) { $data = [ 'action' => $formtarget, 'inputname' => 'query', 'searchstring' => get_string('searchinsettings', 'admin'), 'query' => $searchvalue ]; return $this->render_from_template('core/search_input', $data); } } home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/calendar/renderer.php000064400000030557152266552650023001 0ustar00. /** * This file contains the renderers for the calendar within Moodle * * @copyright 2010 Sam Hemelryk * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @package calendar */ if (!defined('MOODLE_INTERNAL')) { die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page } /** * The primary renderer for the calendar. */ class core_calendar_renderer extends plugin_renderer_base { /** * Starts the standard layout for the page * * @return string */ public function start_layout() { return html_writer::start_tag('div', ['data-region' => 'calendar', 'class' => 'maincalendar']); } /** * Creates the remainder of the layout * * @return string */ public function complete_layout() { return html_writer::end_tag('div'); } /** * Adds a pretent calendar block * * @param block_contents $bc * @param mixed $pos BLOCK_POS_RIGHT | BLOCK_POS_LEFT */ public function add_pretend_calendar_block(block_contents $bc, $pos=BLOCK_POS_RIGHT) { $this->page->blocks->add_fake_block($bc, $pos); } /** * Creates a button to add a new event. * * @param int $courseid * @param int $unused1 * @param int $unused2 * @param int $unused3 * @param int $unused4 * @return string */ public function add_event_button($courseid, $unused1 = null, $unused2 = null, $unused3 = null, $unused4 = null) { $data = [ 'contextid' => (\context_course::instance($courseid))->id, ]; return $this->render_from_template('core_calendar/add_event_button', $data); } /** * @deprecated 3.9 */ #[\core\attribute\deprecated( replacement: 'event no longer used', since: '3.9', mdl: 'MDL-58866', final: true, )] public function event() { \core\deprecation::emit_deprecation(__FUNCTION__); } /** * Displays a course filter selector * * @param moodle_url $returnurl The URL that the user should be taken too upon selecting a course. * @param string $label The label to use for the course select. * @param int $courseid The id of the course to be selected. * @param int|null $calendarinstanceid The instance ID of the calendar we're generating this course filter for. * @return string */ public function course_filter_selector(moodle_url $returnurl, $label = null, $courseid = null, ?int $calendarinstanceid = null) { global $CFG, $DB; if (!isloggedin() or isguestuser()) { return ''; } $contextrecords = []; $courses = calendar_get_default_courses($courseid, 'id, shortname, fullname'); if (!empty($courses) && count($courses) > CONTEXT_CACHE_MAX_SIZE) { // We need to pull the context records from the DB to preload them // below. The calendar_get_default_courses code will actually preload // the contexts itself however the context cache is capped to a certain // amount before it starts recycling. Unfortunately that starts to happen // quite a bit if a user has access to a large number of courses (e.g. admin). // So in order to avoid hitting the DB for each context as we loop below we // can load all of the context records and add them to the cache just in time. $courseids = array_map(function($c) { return $c->id; }, $courses); list($insql, $params) = $DB->get_in_or_equal($courseids); $contextsql = "SELECT ctx.instanceid, " . context_helper::get_preload_record_columns_sql('ctx') . " FROM {context} ctx WHERE ctx.contextlevel = ? AND ctx.instanceid $insql"; array_unshift($params, CONTEXT_COURSE); $contextrecords = $DB->get_records_sql($contextsql, $params); } unset($courses[SITEID]); $courseoptions = array(); $courseoptions[SITEID] = get_string('fulllistofcourses'); foreach ($courses as $course) { if (isset($contextrecords[$course->id])) { context_helper::preload_from_record($contextrecords[$course->id]); } // Limit the displayed course name to prevent the dropdown from getting too wide. $coursename = format_string(get_course_display_name_for_list($course), true, [ 'context' => \core\context\course::instance($course->id), ]); $courseoptions[$course->id] = shorten_text($coursename, 50, true); } if ($courseid) { $selected = $courseid; } else if ($this->page->course->id !== SITEID) { $selected = $this->page->course->id; } else { $selected = ''; } $courseurl = new moodle_url($returnurl); $courseurl->remove_params('course'); $labelattributes = []; if (empty($label)) { $label = get_string('listofcourses'); $labelattributes['class'] = 'visually-hidden'; } $filterid = 'calendar-course-filter'; if ($calendarinstanceid) { $filterid .= "-$calendarinstanceid"; } $select = html_writer::label($label, $filterid, false, $labelattributes); $select .= html_writer::select($courseoptions, 'course', $selected, false, ['class' => 'cal_courses_flt ms-1 me-auto me-2 mb-2', 'id' => $filterid]); return $select; } /** * Render the subscriptions header * * @return string */ public function render_subscriptions_header(): string { $importcalendarbutton = new single_button(new moodle_url('/calendar/import.php', calendar_get_export_import_link_params()), get_string('importcalendar', 'calendar'), 'get', single_button::BUTTON_PRIMARY); $importcalendarbutton->class .= ' float-sm-end float-end'; $exportcalendarbutton = new single_button(new moodle_url('/calendar/export.php', calendar_get_export_import_link_params()), get_string('exportcalendar', 'calendar'), 'get', single_button::BUTTON_PRIMARY); $exportcalendarbutton->class .= ' float-sm-end float-end'; $output = $this->output->heading(get_string('managesubscriptions', 'calendar')); $output .= html_writer::start_div('header d-flex flex-wrap mt-5'); $headerattr = [ 'class' => 'me-auto', 'aria-describedby' => 'subscription_details_table', ]; $output .= html_writer::tag('h3', get_string('yoursubscriptions', 'calendar'), $headerattr); $output .= $this->output->render($importcalendarbutton); $output .= $this->output->render($exportcalendarbutton); $output .= html_writer::end_div(); return $output; } /** * Render the subscriptions blank state appearance * * @return string */ public function render_no_calendar_subscriptions(): string { $output = html_writer::start_div('mt-5'); $importlink = (new moodle_url('/calendar/import.php', calendar_get_export_import_link_params()))->out(); $output .= get_string('nocalendarsubscriptionsimportexternal', 'core_calendar', $importlink); $output .= html_writer::end_div(); return $output; } /** * Renders a table containing information about calendar subscriptions. * * @param int $unused * @param array $subscriptions * @param string $unused2 * @return string */ public function subscription_details($unused, $subscriptions, $unused2 = '') { $table = new html_table(); $table->head = array( get_string('colcalendar', 'calendar'), get_string('collastupdated', 'calendar'), get_string('eventkind', 'calendar'), get_string('colpoll', 'calendar'), get_string('colactions', 'calendar') ); $table->data = array(); $table->id = 'subscription_details_table'; if (empty($subscriptions)) { $importlink = (new moodle_url('/calendar/import.php', calendar_get_export_import_link_params()))->out(); $cell = new html_table_cell(get_string('nocalendarsubscriptionsimportexternal', 'core_calendar', $importlink)); $cell->colspan = 5; $table->data[] = new html_table_row(array($cell)); } $strnever = new lang_string('never', 'calendar'); foreach ($subscriptions as $sub) { $label = $sub->name; if (!empty($sub->url)) { $label = html_writer::link($sub->url, $label); } if (empty($sub->lastupdated)) { $lastupdated = $strnever->out(); } else { $lastupdated = userdate($sub->lastupdated, get_string('strftimedatetimeshort', 'langconfig')); } $type = $sub->eventtype . 'events'; $calendarname = new html_table_cell($label); $calendarname->header = true; $tablerow = new html_table_row(array( $calendarname, new html_table_cell($lastupdated), new html_table_cell(get_string($type, 'calendar')), new html_table_cell($this->render_subscription_update_interval($sub)), new html_table_cell($this->subscription_action_links()) )); $tablerow->attributes += [ 'data-subid' => $sub->id, 'data-subname' => $sub->name ]; $table->data[] = $tablerow; } $out = $this->output->box_start('generalbox calendarsubs'); $out .= html_writer::table($table); $out .= $this->output->box_end(); $this->page->requires->js_call_amd('core_calendar/manage_subscriptions', 'init'); return $out; } /** * Render subscription update interval form. * * @param stdClass $subscription * @return string */ protected function render_subscription_update_interval(stdClass $subscription): string { if (empty($subscription->url)) { return ''; } $tmpl = new \core_calendar\output\refreshintervalcollection($subscription); return $this->output->render_from_template('core/inplace_editable', $tmpl->export_for_template($this->output)); } /** * Creates a form to perform actions on a given subscription. * * @return string */ protected function subscription_action_links(): string { $html = html_writer::start_tag('div', array('class' => 'btn-group float-start')); $html .= html_writer::span(html_writer::link('#', get_string('delete'), ['data-action' => 'delete-subscription']), ''); $html .= html_writer::end_tag('div'); return $html; } /** * Render the event filter region. * * @return string */ public function event_filter() { $data = [ 'eventtypes' => calendar_get_filter_types(), ]; return $this->render_from_template('core_calendar/event_filter', $data); } /** * Render the calendar import result. * * @param array $result Import result * @return string|null */ public function render_import_result(array $result): ?string { $data = [ 'eventsimported' => $result['eventsimported'], 'eventsskipped' => $result['eventsskipped'], 'eventsupdated' => $result['eventsupdated'], 'eventsdeleted' => $result['eventsdeleted'], 'haserror' => $result['haserror'], 'errors' => $result['errors'] ]; return $this->render_from_template('core_calendar/subscription_update_result', $data); } } home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/enrol/renderer.php000064400000060377152266552760022354 0ustar00. /** * This is the main renderer for the enrol section. * * @package core_enrol * @copyright 2010 Sam Hemelryk * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ /** * This is the core renderer * * @copyright 2010 Sam Hemelryk * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class core_enrol_renderer extends plugin_renderer_base { /** * Renderers the enrol_user_button. * * @param enrol_user_button $button * @return string XHTML */ protected function render_enrol_user_button(enrol_user_button $button) { $buttoninfo = $button->export_for_template($this->output); $attributes = [ 'type' => 'submit', 'value' => $buttoninfo->label, 'disabled' => $buttoninfo->disabled ? 'disabled' : null, 'title' => $buttoninfo->tooltip, 'class' => 'btn ' . "btn-{$buttoninfo->type}", ]; if ($button->actions) { $id = html_writer::random_id('single_button'); $attributes['id'] = $id; foreach ($button->actions as $action) { $this->add_action_handler($action, $id); } } $button->initialise_js($this->page); // first the input element $output = html_writer::empty_tag('input', $attributes); // then hidden fields $params = $button->url->params(); if ($button->method === 'post') { $params['sesskey'] = sesskey(); } foreach ($params as $var => $val) { $output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => $var, 'value' => $val)); } // then div wrapper for xhtml strictness $output = html_writer::tag('div', $output); // now the form itself around it if ($button->method === 'get') { $url = $button->url->out_omit_querystring(true); // url without params, the anchor part allowed } else { $url = $button->url->out_omit_querystring(); // url without params, the anchor part not allowed } if ($url === '') { $url = '#'; // there has to be always some action } $attributes = array('method' => $button->method, 'action' => $url, 'id' => $button->formid); $output = html_writer::tag('form', $output, $attributes); // and finally one more wrapper with class return html_writer::tag('div', $output, array('class' => $button->class)); } /** * Renders a course enrolment table * * @param course_enrolment_table $table * @return string */ protected function render_course_enrolment_other_users_table(course_enrolment_other_users_table $table) { $table->initialise_javascript(); $content = ''; $content .= html_writer::tag('div', get_string('otheruserdesc', 'enrol'), array('class'=>'otherusersdesc')); $content .= $this->output->render($table->get_paging_bar()); $content .= html_writer::table($table); $content .= $this->output->render($table->get_paging_bar()); return $content; } /** * Generates HTML to display the users roles and any available actions * * @param int $userid * @param array $roles * @param array $assignableroles * @param moodle_url $pageurl * @return string */ public function user_roles_and_actions($userid, $roles, $assignableroles, $canassign, $pageurl) { // Get list of roles. $rolesoutput = ''; foreach ($roles as $roleid=>$role) { if ($canassign and (is_siteadmin() or isset($assignableroles[$roleid])) and !$role['unchangeable']) { $strunassign = get_string('unassignarole', 'role', $role['text']); $icon = $this->output->pix_icon('t/delete', $strunassign); $url = new moodle_url($pageurl, array('action'=>'unassign', 'roleid'=>$roleid, 'user'=>$userid)); $rolesoutput .= html_writer::tag('div', $role['text'] . html_writer::link($url, $icon, array('class'=>'unassignrolelink', 'rel'=>$roleid, 'title'=>$strunassign)), array('class'=>'role role_'.$roleid)); } else { $rolesoutput .= html_writer::tag('div', $role['text'], array('class'=>'role unchangeable', 'rel'=>$roleid)); } } $output = ''; if (!empty($assignableroles) && $canassign) { $roleids = array_keys($roles); $hasallroles = true; foreach (array_keys($assignableroles) as $key) { if (!in_array($key, $roleids)) { $hasallroles = false; break; } } if (!$hasallroles) { $url = new moodle_url($pageurl, array('action' => 'assign', 'user' => $userid)); $roleicon = $this->output->pix_icon('i/assignroles', get_string('assignroles', 'role')); $link = html_writer::link($url, $roleicon, array('class' => 'assignrolelink')); $output = html_writer::tag('div', $link, array('class'=>'addrole')); } } $output .= html_writer::tag('div', $rolesoutput, array('class'=>'roles')); return $output; } /** * Generates the HTML to view the users groups and available group actions * * @param int $userid * @param array $groups * @param array $allgroups * @param bool $canmanagegroups * @param moodle_url $pageurl * @return string */ public function user_groups_and_actions($userid, $groups, $allgroups, $canmanagegroups, $pageurl) { $groupicon = $this->output->pix_icon('i/group', get_string('addgroup', 'group')); $groupoutput = ''; foreach($groups as $groupid=>$name) { if ($canmanagegroups and groups_remove_member_allowed($groupid, $userid)) { $icon = $this->output->pix_icon('t/delete', get_string('removefromgroup', 'group', $name)); $url = new moodle_url($pageurl, array('action'=>'removemember', 'group'=>$groupid, 'user'=>$userid)); $groupoutput .= html_writer::tag('div', $name . html_writer::link($url, $icon), array('class'=>'group', 'rel'=>$groupid)); } else { $groupoutput .= html_writer::tag('div', $name, array('class'=>'group', 'rel'=>$groupid)); } } $output = ''; if ($canmanagegroups && (count($groups) < count($allgroups))) { $url = new moodle_url($pageurl, array('action'=>'addmember', 'user'=>$userid)); $output .= html_writer::tag('div', html_writer::link($url, $groupicon), array('class'=>'addgroup')); } $output = $output.html_writer::tag('div', $groupoutput, array('class'=>'groups')); return $output; } /** * Generates the HTML for the given enrolments + available actions * * @param int $userid * @param array $enrolments * @param moodle_url $pageurl * @return string */ public function user_enrolments_and_actions($enrolments) { $output = ''; foreach ($enrolments as $ue) { $enrolmentoutput = $ue['text'].' '.$ue['period']; if ($ue['dimmed']) { $enrolmentoutput = html_writer::tag('span', $enrolmentoutput, array('class'=>'dimmed_text')); } else { $enrolmentoutput = html_writer::tag('span', $enrolmentoutput); } foreach ($ue['actions'] as $action) { $enrolmentoutput .= $this->render($action); } $output .= html_writer::tag('div', $enrolmentoutput, array('class'=>'enrolment')); } return $output; } /** * Renders a user enrolment action * @param user_enrolment_action $icon * @return string */ protected function render_user_enrolment_action(user_enrolment_action $icon) { return html_writer::link($icon->get_url(), $this->output->render($icon->get_icon()), $icon->get_attributes()); } } /** * Main course enrolment table * * This table is used to display the enrolment information for a course. * It requires that a course enrolment manager be provided during constuct with * provides all of the information for the table. * The control then produces the table, the paging, and the associated JS actions * for the page. * * @package core * @subpackage enrol * @copyright 2010 Sam Hemelryk * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class course_enrolment_table extends html_table implements renderable { /** * The get/post variable that is used to identify the page. * Default: page */ const PAGEVAR = 'page'; /** * The get/post variable to is used to identify the number of items to display * per page. * Default: perpage */ const PERPAGEVAR = 'perpage'; /** * The get/post variable that is used to identify the sort field for the table. * Default: sort */ const SORTVAR = 'sort'; /** * The get/post variable that is used to identify the sort direction for the table. * Default: dir */ const SORTDIRECTIONVAR = 'dir'; /** * The default number of items per page. * Default: 100 */ const DEFAULTPERPAGE = 100; /** * The default sort, options are course_enrolment_table::$sortablefields * Default: lastname */ const DEFAULTSORT = 'lastname'; /** * The default direction * Default: ASC */ const DEFAULTSORTDIRECTION = 'ASC'; /** * The current page, starting from 0 * @var int */ public $page = 0; /** * The total number of pages * @var int */ public $pages = 0; /** * The number of items to display per page * @var int */ public $perpage = 0; /** * The sort field for this table, should be one of course_enrolment_table::$sortablefields * @var string */ public $sort; /** * The sort direction, either ASC or DESC * @var string */ public $sortdirection; /** * The course manager this table is displaying for * @var course_enrolment_manager */ protected $manager; /** * The paging bar that controls the paging for this table * @var paging_bar */ protected $pagingbar = null; /** * The total number of users enrolled in the course * @var int */ protected $totalusers = null; /** * The users enrolled in this course * @var array */ protected $users = null; /** * The fields for this table * @var array */ protected $fields = array(); /** * An array of bulk user enrolment operations * @var array */ protected $bulkoperations = array(); /** * An array of sortable fields * @static * @var array */ protected static $sortablefields = array('firstname', 'lastname', 'firstnamephonetic', 'lastnamephonetic', 'middlename', 'alternatename', 'username', 'idnumber', 'email', 'phone1', 'phone2', 'institution', 'department', 'lastaccess', 'lastcourseaccess'); /** @var bool To store status of Other users page. */ public $otherusers; /** * Constructs the table * * @param course_enrolment_manager $manager */ public function __construct(course_enrolment_manager $manager) { $this->manager = $manager; $this->page = optional_param(self::PAGEVAR, 0, PARAM_INT); $this->perpage = optional_param(self::PERPAGEVAR, self::DEFAULTPERPAGE, PARAM_INT); $this->sort = optional_param(self::SORTVAR, self::DEFAULTSORT, PARAM_ALPHANUM); $this->sortdirection = optional_param(self::SORTDIRECTIONVAR, self::DEFAULTSORTDIRECTION, PARAM_ALPHA); $this->attributes = ['class' => 'userenrolment table table-striped table-hover generaltable']; if (!in_array($this->sort, self::$sortablefields)) { $this->sort = self::DEFAULTSORT; } if ($this->page < 0) { $this->page = 0; } if ($this->sortdirection !== 'ASC' && $this->sortdirection !== 'DESC') { $this->sortdirection = self::DEFAULTSORTDIRECTION; } $this->id = html_writer::random_id(); // Collect the bulk operations for the currently filtered plugin if there is one. $plugin = $manager->get_filtered_enrolment_plugin(); if ($plugin and enrol_is_enabled($plugin->get_name())) { $this->bulkoperations = $plugin->get_bulk_operations($manager); } } /** * Returns an array of enrol_user_buttons that are created by the different * enrolment plugins available. * * @return array */ public function get_manual_enrol_buttons() { return $this->manager->get_manual_enrol_buttons(); } /** * Gets the sort direction for a given field * * @param string $field * @return string ASC or DESC */ public function get_field_sort_direction($field) { if ($field == $this->sort) { return ($this->sortdirection == 'ASC')?'DESC':'ASC'; } return self::DEFAULTSORTDIRECTION; } /** * Sets the fields for this table. These get added to the tables head as well. * * You can also use a multi dimensional array for this to have multiple fields * in a single column * * @param array $fields An array of fields to set * @param string $output */ public function set_fields($fields, $output) { $this->fields = $fields; $this->head = array(); $this->colclasses = array(); $this->align = array(); $url = $this->manager->get_moodlepage()->url; if (!empty($this->bulkoperations)) { // If there are bulk operations add a column for checkboxes. $this->head[] = ''; $this->colclasses[] = 'field col_bulkops'; } foreach ($fields as $name => $label) { $newlabel = ''; if (is_array($label)) { $bits = array(); foreach ($label as $n => $l) { if ($l === false) { continue; } if (!in_array($n, self::$sortablefields)) { $bits[] = $l; } else { $sorturl = new moodle_url($url, array(self::SORTVAR => $n, self::SORTDIRECTIONVAR => $this->get_field_sort_direction($n))); $link = html_writer::link($sorturl, $fields[$name][$n]); if ($this->sort == $n) { $link .= $this->get_direction_icon($output, $n); } $bits[] = html_writer::tag('span', $link, array('class'=>'subheading_'.$n)); } } $newlabel = join(' / ', $bits); } else { if (!in_array($name, self::$sortablefields)) { $newlabel = $label; } else { $sorturl = new moodle_url($url, array(self::SORTVAR => $name, self::SORTDIRECTIONVAR => $this->get_field_sort_direction($name))); $newlabel = html_writer::link($sorturl, $fields[$name]); if ($this->sort == $name) { $newlabel .= $this->get_direction_icon($output, $name); } } } $this->head[] = $newlabel; $this->colclasses[] = 'field col_'.$name; } } /** * Sets the total number of users * * @param int $totalusers */ public function set_total_users($totalusers) { $this->totalusers = $totalusers; $this->pages = ceil($this->totalusers / $this->perpage); if ($this->page > $this->pages) { $this->page = $this->pages; } } /** * Sets the users for this table * * @param array $users * @return void */ public function set_users(array $users) { $this->users = $users; $hasbulkops = !empty($this->bulkoperations); foreach ($users as $userid=>$user) { $user = (array)$user; $row = new html_table_row(); $row->attributes = array('class' => 'userinforow'); $row->id = 'user_'.$userid; $row->cells = array(); if ($hasbulkops) { // Add a checkbox into the first column. $input = html_writer::empty_tag('input', array('type' => 'checkbox', 'name' => 'bulkuser[]', 'value' => $userid)); $row->cells[] = new html_table_cell($input); } foreach ($this->fields as $field => $label) { if (is_array($label)) { $bits = array(); foreach (array_keys($label) as $subfield) { if (array_key_exists($subfield, $user)) { $bits[] = html_writer::tag('div', $user[$subfield], array('class'=>'subfield subfield_'.$subfield)); } } if (empty($bits)) { $bits[] = ' '; } $row->cells[] = new html_table_cell(join(' ', $bits)); } else { if (!array_key_exists($field, $user)) { $user[$field] = ' '; } $row->cells[] = new html_table_cell($user[$field]); } } $this->data[] = $row; } } public function initialise_javascript() { if (has_capability('moodle/role:assign', $this->manager->get_context())) { $this->manager->get_moodlepage()->requires->strings_for_js(array( 'assignroles', 'confirmunassign', 'confirmunassigntitle', 'confirmunassignyes', 'confirmunassignno' ), 'role'); $modules = array('moodle-enrol-rolemanager', 'moodle-enrol-rolemanager-skin'); $function = 'M.enrol.rolemanager.init'; $arguments = array( 'containerId'=>$this->id, 'userIds'=>array_keys($this->users), 'courseId'=>$this->manager->get_course()->id, 'otherusers'=>isset($this->otherusers)); $this->manager->get_moodlepage()->requires->yui_module($modules, $function, array($arguments)); } } /** * Gets the paging bar instance for this table * * @return paging_bar */ public function get_paging_bar() { if ($this->pagingbar == null) { $this->pagingbar = new paging_bar($this->totalusers, $this->page, $this->perpage, $this->manager->get_moodlepage()->url, self::PAGEVAR); } return $this->pagingbar; } /** * Gets the direction icon for the sortable field within this table * * @param core_renderer $output * @param string $field * @return string */ protected function get_direction_icon($output, $field) { $direction = self::DEFAULTSORTDIRECTION; if ($this->sort == $field) { $direction = $this->sortdirection; } if ($direction === 'ASC') { return $output->pix_icon('t/sort_asc', get_string('sort')); } else { return $output->pix_icon('t/sort_desc', get_string('sort')); } } /** * Gets the params that will need to be added to the url in order to return to this page. * * @return array */ public function get_url_params() { return array( self::PAGEVAR => $this->page, self::PERPAGEVAR => $this->perpage, self::SORTVAR => $this->sort, self::SORTDIRECTIONVAR => $this->sortdirection ); } /** * Returns an array of URL params for both the table and the manager. * * @return array */ public function get_combined_url_params() { return $this->get_url_params() + $this->manager->get_url_params(); } /** * Sets the bulk operations for this table. * * @param array $bulkoperations */ public function set_bulk_user_enrolment_operations(array $bulkoperations) { $this->bulkoperations = $bulkoperations; } /** * Returns an array of bulk operations. * * @return array */ public function get_bulk_user_enrolment_operations() { return $this->bulkoperations; } /** * Returns true fi the table is aware of any bulk operations that can be performed on users * selected from the currently filtered enrolment plugins. * * @return bool */ public function has_bulk_user_enrolment_operations() { return !empty($this->bulkoperations); } } /** * Table control used for enrolled users * * @copyright 2010 Sam Hemelryk * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class course_enrolment_users_table extends course_enrolment_table { } /** * Table used for other users * * Other users are users who have roles but are not enrolled. * * @copyright 2010 Sam Hemelryk * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class course_enrolment_other_users_table extends course_enrolment_table { /** * Constructs the table * * @param course_enrolment_manager $manager */ public function __construct(course_enrolment_manager $manager) { parent::__construct($manager); $this->attributes['class'] .= ' otheruserenrolment'; } /** * Gets a button to search users and assign them roles in the course. * * @staticvar int $count * @param int $page * @return single_button */ public function get_user_search_button() { static $count = 0; if (!has_capability('moodle/role:assign', $this->manager->get_context())) { return false; } $count++; $url = new moodle_url('/admin/roles/assign.php', array('contextid'=>$this->manager->get_context()->id, 'sesskey'=>sesskey())); $control = new single_button($url, get_string('assignroles', 'role'), 'get'); $control->class = 'singlebutton assignuserrole instance'.$count; if ($count == 1) { $this->manager->get_moodlepage()->requires->strings_for_js(array( 'ajaxoneuserfound', 'ajaxxusersfound', 'ajaxxmoreusersfound', 'ajaxnext25', 'enrol', 'enrolmentoptions', 'enrolusers', 'enrolxusers', 'errajaxfailedenrol', 'errajaxsearch', 'foundxcohorts', 'none', 'usersearch', 'unlimitedduration', 'startdatetoday', 'durationdays', 'enrolperiod'), 'enrol'); $this->manager->get_moodlepage()->requires->string_for_js('assignrole', 'role'); $modules = array('moodle-enrol-otherusersmanager', 'moodle-enrol-otherusersmanager-skin'); $function = 'M.enrol.otherusersmanager.init'; $arguments = array( 'courseId'=> $this->manager->get_course()->id, 'ajaxUrl' => '/enrol/ajax.php', 'url' => $this->manager->get_moodlepage()->url->out(false)); $this->manager->get_moodlepage()->requires->yui_module($modules, $function, array($arguments)); } return $control; } } home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/files/renderer.php000064400000060400152266553450022317 0ustar00. // // // /////////////////////////////////////////////////////////////////////////// defined('MOODLE_INTERNAL') || die(); /** * Rendering of files viewer related widgets. * @package core * @subpackage file * @copyright 2010 Dongsheng Cai * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @since Moodle 2.0 */ /** * File browser render * * @copyright 2010 Dongsheng Cai * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @since Moodle 2.0 */ class core_files_renderer extends plugin_renderer_base { public function files_tree_viewer(file_info $file_info, ?array $options = null) { $tree = new files_tree_viewer($file_info, $options); return $this->render($tree); } public function render_files_tree_viewer(files_tree_viewer $tree) { $html = $this->output->heading_with_help(get_string('coursefiles'), 'courselegacyfiles', 'moodle'); $html .= $this->output->container_start('coursefilesbreadcrumb'); foreach($tree->path as $path) { $html .= $path; $html .= ' / '; } $html .= $this->output->container_end(); $html .= $this->output->box_start(); $table = new html_table(); $table->head = array(get_string('name'), get_string('lastmodified'), get_string('size', 'repository'), get_string('type', 'repository')); $table->align = array('left', 'left', 'left', 'left'); $table->width = '100%'; $table->data = array(); foreach ($tree->tree as $file) { $filedate = $filesize = $filetype = ''; if ($file['filedate']) { $filedate = userdate($file['filedate'], get_string('strftimedatetimeshort', 'langconfig')); } if (empty($file['isdir'])) { if ($file['filesize']) { $filesize = display_size($file['filesize']); } $fileicon = file_file_icon($file); $filetype = get_mimetype_description($file); } else { $fileicon = file_folder_icon(); } $table->data[] = array( html_writer::link($file['url'], $this->output->pix_icon($fileicon, get_string('icon')) . ' ' . $file['filename']), $filedate, $filesize, $filetype ); } $html .= html_writer::table($table); $html .= $this->output->single_button(new moodle_url('/files/coursefilesedit.php', array('contextid'=>$tree->context->id)), get_string('coursefilesedit'), 'get'); $html .= $this->output->box_end(); return $html; } /** * Prints the file manager and initializes all necessary libraries * *
     * $fm = new form_filemanager($options);
     * $output = get_renderer('core', 'files');
     * echo $output->render($fm);
     * 
* * @param form_filemanager $fm File manager to render * @return string HTML fragment */ public function render_form_filemanager($fm) { $html = $this->fm_print_generallayout($fm); $module = array( 'name'=>'form_filemanager', 'fullpath'=>'/lib/form/filemanager.js', 'requires' => array('moodle-core-notification-dialogue', 'core_filepicker', 'base', 'io-base', 'node', 'json', 'core_dndupload', 'panel', 'resize-plugin', 'dd-plugin'), 'strings' => array( array('error', 'moodle'), array('info', 'moodle'), array('confirmdeletefile', 'repository'), array('draftareanofiles', 'repository'), array('entername', 'repository'), array('enternewname', 'repository'), array('invalidjson', 'repository'), array('popupblockeddownload', 'repository'), array('unknownoriginal', 'repository'), array('confirmdeletefolder', 'repository'), array('confirmdeletefilewithhref', 'repository'), array('confirmrenamefolder', 'repository'), array('confirmrenamefile', 'repository'), array('newfolder', 'repository'), array('edit', 'moodle'), array('originalextensionchange', 'repository'), array('originalextensionremove', 'repository'), array('aliaseschange', 'repository'), ['nofilesselected', 'repository'], ['confirmdeleteselectedfile', 'repository'], ['selectall', 'moodle'], ['deselectall', 'moodle'], ['selectallornone', 'form'], ) ); if ($this->page->requires->should_create_one_time_item_now('core_file_managertemplate')) { $this->page->requires->js_init_call('M.form_filemanager.set_templates', array($this->filemanager_js_templates()), true, $module); } $this->page->requires->js_call_amd('core/checkbox-toggleall', 'init'); $this->page->requires->js_init_call('M.form_filemanager.init', array($fm->options), true, $module); // non javascript file manager $html .= ''; return $html; } /** * Returns html for displaying one file manager * * @param form_filemanager $fm * @return string */ protected function fm_print_generallayout($fm) { $context = [ 'client_id' => $fm->options->client_id, 'helpicon' => $this->help_icon('setmainfile', 'repository'), 'restrictions' => $this->fm_print_restrictions($fm) ]; return $this->render_from_template('core/filemanager_page_generallayout', $context); } /** * FileManager JS template for displaying one file in 'icon view' mode. * * Except for elements described in fp_js_template_iconfilename, this template may also * contain element with class 'fp-contextmenu'. If context menu is available for this * file, the top element will receive the additional class 'fp-hascontextmenu' and * the element with class 'fp-contextmenu' will hold onclick event for displaying * the context menu. * * @see fp_js_template_iconfilename() * @return string */ protected function fm_js_template_iconfilename() { $rv = '
'.$this->pix_icon('i/menu', '▶').'
'; return $rv; } /** * FileManager JS template for displaying file name in 'table view' and 'tree view' modes. * * Except for elements described in fp_js_template_listfilename, this template may also * contain element with class 'fp-contextmenu'. If context menu is available for this * file, the top element will receive the additional class 'fp-hascontextmenu' and * the element with class 'fp-contextmenu' will hold onclick event for displaying * the context menu. * * @todo MDL-32736 remove onclick="return false;" * @see fp_js_template_listfilename() * @return string */ protected function fm_js_template_listfilename() { $rv = ' '.$this->pix_icon('i/menu', '▶').' '; return $rv; } /** * FileManager JS template for displaying 'Make new folder' dialog. * * Must be wrapped in an element, CSS for this element must define width and height of the window; * * Must have one input element with type="text" (for users to enter the new folder name); * * content of element with class 'fp-dlg-curpath' will be replaced with current path where * new folder is about to be created; * elements with classes 'fp-dlg-butcreate' and 'fp-dlg-butcancel' will hold onclick events; * * @return string */ protected function fm_js_template_mkdir() { $rv = ' '; return $rv; } /** * FileManager JS template for error/info message displayed as a separate popup window. * * @see fp_js_template_message() * @return string */ protected function fm_js_template_message() { return $this->fp_js_template_message(); } /** * FileManager JS template for window with file information/actions. * */ protected function fm_js_template_fileselectlayout() { $context = [ 'helpicon' => $this->help_icon('setmainfile', 'repository'), 'licensehelpicon' => $this->create_license_help_icon_context(), 'columns' => true ]; return $this->render_from_template('core/filemanager_fileselect', $context); } /** * FileManager JS template for popup confirm dialogue window. * * @return string */ protected function fm_js_template_confirmdialog() { return $this->render_from_template('core/filemanager_confirmdialog', []); } /** * Returns all FileManager JavaScript templates as an array. * * @return array */ public function filemanager_js_templates() { $class_methods = get_class_methods($this); $templates = array(); foreach ($class_methods as $method_name) { if (preg_match('/^fm_js_template_(.*)$/', $method_name, $matches)) $templates[$matches[1]] = $this->$method_name(); } return $templates; } /** * Displays restrictions for the file manager * * @param form_filemanager $fm * @return string */ protected function fm_print_restrictions($fm) { $maxbytes = display_size($fm->options->maxbytes, 0); $strparam = (object) array('size' => $maxbytes, 'attachments' => $fm->options->maxfiles, 'areasize' => display_size($fm->options->areamaxbytes, 0)); $hasmaxfiles = !empty($fm->options->maxfiles) && $fm->options->maxfiles > 0; $hasarealimit = !empty($fm->options->areamaxbytes) && $fm->options->areamaxbytes != -1; if ($hasmaxfiles && $hasarealimit) { $maxsize = get_string('maxsizeandattachmentsandareasize', 'moodle', $strparam); } else if ($hasmaxfiles) { $maxsize = get_string('maxsizeandattachments', 'moodle', $strparam); } else if ($hasarealimit) { $maxsize = get_string('maxsizeandareasize', 'moodle', $strparam); } else { $maxsize = get_string('maxfilesize', 'moodle', $maxbytes); } return ''. $maxsize . ''; } /** * Template for FilePicker with general layout (not QuickUpload). * * * @return string */ protected function fp_js_template_generallayout() { return $this->render_from_template('core/filemanager_modal_generallayout', []); } /** * FilePicker JS template for displaying one file in 'icon view' mode. * * the element with class 'fp-thumbnail' will be resized to the repository thumbnail size * (both width and height, unless min-width and/or min-height is set in CSS) and the content of * an element will be replaced with an appropriate img; * * the width of element with class 'fp-filename' will be set to the repository thumbnail width * (unless min-width is set in css) and the content of an element will be replaced with filename * supplied by repository; * * top element(s) will have class fp-folder if the element is a folder; * * List of files will have parent
element with class 'fp-iconview' * * @return string */ protected function fp_js_template_iconfilename() { $rv = '

'; return $rv; } /** * FilePicker JS template for displaying file name in 'table view' and 'tree view' modes. * * content of the element with class 'fp-icon' will be replaced with an appropriate img; * * content of element with class 'fp-filename' will be replaced with filename supplied by * repository; * * top element(s) will have class fp-folder if the element is a folder; * * Note that tree view and table view are the YUI widgets and therefore there are no * other templates. The widgets will be wrapped in
with class fp-treeview or * fp-tableview (respectfully). * * @return string */ protected function fp_js_template_listfilename() { $rv = ' '; return $rv; } /** * FilePicker JS template for displaying link/loading progress for fetching of the next page * * This text is added to .fp-content AFTER .fp-iconview/.fp-treeview/.fp-tableview * * Must have one parent element with class 'fp-nextpage'. It will be assigned additional * class 'loading' during loading of the next page (it is recommended that in this case the link * becomes unavailable). Also must contain one element or
'; return $rv; } /** * FilePicker JS template for popup dialogue window asking for action when file with the same name already exists. * * @return string */ protected function fp_js_template_processexistingfile() { return $this->render_from_template('core/filemanager_processexistingfile', []); } /** * FilePicker JS template for popup dialogue window asking for action when file with the same name already exists * (multiple-file version). * * @return string */ protected function fp_js_template_processexistingfilemultiple() { return $this->render_from_template('core/filemanager_processexistingfilemultiple', []); } /** * FilePicker JS template for repository login form including templates for each element type * * @return string */ protected function fp_js_template_loginform() { return $this->render_from_template('core/filemanager_loginform', []); } /** * Returns all FilePicker JavaScript templates as an array. * * @return array */ public function filepicker_js_templates() { $class_methods = get_class_methods($this); $templates = array(); foreach ($class_methods as $method_name) { if (preg_match('/^fp_js_template_(.*)$/', $method_name, $matches)) $templates[$matches[1]] = $this->$method_name(); } return $templates; } /** * Returns HTML for default repository searchform to be passed to Filepicker * * This will be used as contents for search form defined in generallayout template * (form with id {TOOLSEARCHID}). * Default contents is one text input field with name="s" */ public function repository_default_searchform() { return $this->render_from_template('core/filemanager_default_searchform', []); } /** * Create the context for rendering help icon with license links displaying all licenses and sources. * * @return \stdClass $iconcontext the context for rendering license help info. */ protected function create_license_help_icon_context(): stdClass { $licensecontext = new stdClass(); $licenses = []; // Discard licenses without a name or source from enabled licenses. foreach (license_manager::get_active_licenses() as $license) { if (!empty($license->fullname) && !empty($license->source)) { $licenses[] = $license; } } $licensecontext->licenses = $licenses; $helptext = $this->render_from_template('core/filemanager_licenselinks', $licensecontext); $iconcontext = new stdClass(); $iconcontext->text = $helptext; $iconcontext->alt = get_string('helpprefix2', 'moodle', get_string('chooselicense', 'repository')); return $iconcontext; } } /** * Data structure representing a general moodle file tree viewer * * @copyright 2010 Dongsheng Cai * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @since Moodle 2.0 */ class files_tree_viewer implements renderable { public $tree; public $path; public $context; /** @var array file tree viewer options. */ protected array $options = []; /** * Constructor of moodle_file_tree_viewer class * @param file_info $file_info * @param array $options */ public function __construct(file_info $file_info, ?array $options = null) { global $CFG; //note: this MUST NOT use get_file_storage() !!!!!!!!!!!!!!!!!!!!!!!!!!!! $this->options = (array)$options; $this->context = $options['context']; $this->tree = array(); $children = $file_info->get_children(); $current_file_params = $file_info->get_params(); $parent_info = $file_info->get_parent(); $level = $parent_info; $this->path = array(); while ($level) { $params = $level->get_params(); $context = context::instance_by_id($params['contextid']); // $this->context is current context if ($context->id != $this->context->id or empty($params['filearea'])) { break; } // unset unused parameters unset($params['component']); unset($params['filearea']); unset($params['filename']); unset($params['itemid']); $url = new moodle_url('/files/index.php', $params); $this->path[] = html_writer::link($url, $level->get_visible_name()); $level = $level->get_parent(); } $this->path = array_reverse($this->path); if ($current_file_params['filepath'] != '/') { $this->path[] = $file_info->get_visible_name(); } foreach ($children as $child) { $filedate = $child->get_timemodified(); $filesize = $child->get_filesize(); $mimetype = $child->get_mimetype(); $params = $child->get_params(); unset($params['component']); unset($params['filearea']); unset($params['filename']); unset($params['itemid']); $fileitem = array( 'params' => $params, 'filename' => $child->get_visible_name(), 'mimetype' => $child->get_mimetype(), 'filedate' => $filedate ? $filedate : '', 'filesize' => $filesize ? $filesize : '' ); $url = new moodle_url('/files/index.php', $params); if ($child->is_directory()) { $fileitem['isdir'] = true; $fileitem['url'] = $url->out(false); } else { $fileitem['url'] = $child->get_url(); } $this->tree[] = $fileitem; } } } home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/webservice/renderer.php000064400000115257152266557040023365 0ustar00. use core_external\external_api; use core_external\external_multiple_structure; use core_external\external_single_structure; /** * Web service documentation renderer. * * @package core_webservice * @category output * @copyright 2009 Jerome Mouneyrac * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class core_webservice_renderer extends plugin_renderer_base { /** * Display the authorised user selector * * @param stdClass $options It contains alloweduserselector, potentialuserselector and serviceid * @return string html */ public function admin_authorised_user_selector(&$options) { global $CFG; $formcontent = html_writer::empty_tag('input', array('name' => 'sesskey', 'value' => sesskey(), 'type' => 'hidden')); $table = new html_table(); $table->size = array('45%', '10%', '45%'); $table->attributes['class'] = 'roleassigntable generaltable generalbox boxaligncenter table table-hover'; $table->summary = ''; $table->cellspacing = 0; $table->cellpadding = 0; // LTR/RTL support, for drawing button arrows in the right direction if (right_to_left()) { $addarrow = '▶'; $removearrow = '◀'; } else { $addarrow = '◀'; $removearrow = '▶'; } //create the add and remove button $addinput = html_writer::empty_tag('input', array('name' => 'add', 'id' => 'add', 'type' => 'submit', 'value' => $addarrow . ' ' . get_string('add'), 'title' => get_string('add'))); $addbutton = html_writer::tag('div', $addinput, array('id' => 'addcontrols')); $removeinput = html_writer::empty_tag('input', array('name' => 'remove', 'id' => 'remove', 'type' => 'submit', 'value' => $removearrow . ' ' . get_string('remove'), 'title' => get_string('remove'))); $removebutton = html_writer::tag('div', $removeinput, array('id' => 'removecontrols')); //create the three cells $label = html_writer::tag('label', get_string('serviceusers', 'webservice'), array('for' => 'removeselect')); $label = html_writer::tag('p', $label); $authoriseduserscell = new html_table_cell($label . $options->alloweduserselector->display(true)); $authoriseduserscell->id = 'existingcell'; $buttonscell = new html_table_cell($addbutton . html_writer::empty_tag('br') . $removebutton); $buttonscell->id = 'buttonscell'; $label = html_writer::tag('label', get_string('potusers', 'webservice'), array('for' => 'addselect')); $label = html_writer::tag('p', $label); $otheruserscell = new html_table_cell($label . $options->potentialuserselector->display(true)); $otheruserscell->id = 'potentialcell'; $cells = array($authoriseduserscell, $buttonscell, $otheruserscell); $row = new html_table_row($cells); $table->data[] = $row; $formcontent .= html_writer::table($table); $formcontent = html_writer::tag('div', $formcontent); $actionurl = new moodle_url('/' . $CFG->admin . '/webservice/service_users.php', array('id' => $options->serviceid)); $html = html_writer::tag('form', $formcontent, array('id' => 'assignform', 'action' => $actionurl, 'method' => 'post')); return $html; } /** * Display list of authorised users for the given external service. * * @param array $users authorised users * @param int $serviceid service id * @return string $html */ public function admin_authorised_user_list($users, $serviceid) { global $CFG; $listitems = []; $extrafields = \core_user\fields::get_identity_fields(context_system::instance()); foreach ($users as $user) { $settingsurl = new moodle_url('/admin/webservice/service_user_settings.php', ['userid' => $user->id, 'serviceid' => $serviceid]); $identity = []; foreach ($extrafields as $extrafield) { if (isset($user->{$extrafield})) { $identity[] = s($user->{$extrafield}); } } $identity = $identity ? html_writer::div(implode(', ', $identity), 'small') : ''; $link = html_writer::link($settingsurl, fullname($user)); if (!empty($user->missingcapabilities)) { $count = html_writer::span(count($user->missingcapabilities), 'badge bg-danger text-white'); $links = array_map(function($capname) { return get_capability_docs_link((object)['name' => $capname]) . html_writer::div($capname, 'text-muted'); }, $user->missingcapabilities); $list = html_writer::alist($links); $help = $this->output->help_icon('missingcaps', 'webservice'); $missingcaps = print_collapsible_region(html_writer::div($list . $help, 'missingcaps'), 'small', html_writer::random_id('usermissingcaps'), get_string('usermissingcaps', 'webservice', $count), '', true, true); } else { $missingcaps = ''; } $listitems[] = $link . $identity . $missingcaps; } $html = html_writer::div(html_writer::alist($listitems), 'alloweduserlist'); return $html; } /** * Display a confirmation page to remove a function from a service * * @param stdClass $function It needs function id + function name properties. * @param stdClass $service It needs service id + service name properties. * @return string html */ public function admin_remove_service_function_confirmation($function, $service) { $optionsyes = array('id' => $service->id, 'action' => 'delete', 'confirm' => 1, 'sesskey' => sesskey(), 'fid' => $function->id); $optionsno = array('id' => $service->id); $formcontinue = new single_button(new moodle_url('service_functions.php', $optionsyes), get_string('remove')); $formcancel = new single_button(new moodle_url('service_functions.php', $optionsno), get_string('cancel'), 'get'); return $this->output->confirm(get_string('removefunctionconfirm', 'webservice', (object) array('service' => $service->name, 'function' => $function->name)), $formcontinue, $formcancel); } /** * Display a confirmation page to remove a service * * @param stdClass $service It needs service id + service name properties. * @return string html */ public function admin_remove_service_confirmation($service) { global $CFG; $optionsyes = array('id' => $service->id, 'action' => 'delete', 'confirm' => 1, 'sesskey' => sesskey()); $optionsno = array('section' => 'externalservices'); $formcontinue = new single_button(new moodle_url('service.php', $optionsyes), get_string('delete'), 'post'); $formcancel = new single_button( new moodle_url($CFG->wwwroot . "/" . $CFG->admin . "/settings.php", $optionsno), get_string('cancel'), 'get'); return $this->output->confirm(get_string('deleteserviceconfirm', 'webservice', $service->name), $formcontinue, $formcancel); } /** * Display a list of functions for a given service * If the service is built-in, do not display remove/add operation (read-only) * * @param array $functions list of functions * @param stdClass $service the given service * @return string the table html + add operation html */ public function admin_service_function_list($functions, $service) { global $CFG; if (!empty($functions)) { $table = new html_table(); $table->head = array(get_string('function', 'webservice'), get_string('description'), get_string('requiredcaps', 'webservice')); $table->align = array('left', 'left', 'left'); $table->size = array('15%', '40%', '40%'); $table->width = '100%'; $table->align[] = 'left'; //display remove function operation (except for build-in service) if (empty($service->component)) { $table->head[] = get_string('edit'); $table->align[] = 'center'; } $anydeprecated = false; foreach ($functions as $function) { $function = external_api::external_function_info($function); if (!empty($function->deprecated)) { $anydeprecated = true; } $requiredcaps = html_writer::tag('div', empty($function->capabilities) ? '' : $function->capabilities, array('class' => 'functiondesc')); ; $description = html_writer::tag('div', $function->description, array('class' => 'functiondesc')); //display remove function operation (except for build-in service) if (empty($service->component)) { $removeurl = new moodle_url('/' . $CFG->admin . '/webservice/service_functions.php', array('sesskey' => sesskey(), 'fid' => $function->id, 'id' => $service->id, 'action' => 'delete')); $removelink = html_writer::tag('a', get_string('removefunction', 'webservice'), array('href' => $removeurl)); $table->data[] = array($function->name, $description, $requiredcaps, $removelink); } else { $table->data[] = array($function->name, $description, $requiredcaps); } } $html = html_writer::table($table); } else { $html = get_string('nofunctions', 'webservice') . html_writer::empty_tag('br'); } //display add function operation (except for build-in service) if (empty($service->component)) { if (!empty($anydeprecated)) { debugging('This service uses deprecated functions, replace them by the proposed ones and update your client/s.', DEBUG_DEVELOPER); } $addurl = new moodle_url('/' . $CFG->admin . '/webservice/service_functions.php', array('sesskey' => sesskey(), 'id' => $service->id, 'action' => 'add')); $html .= html_writer::tag('a', get_string('addfunctions', 'webservice'), array('href' => $addurl)); } return $html; } /** * Display Reset token confirmation box * * @param stdClass $token token to reset * @return string html */ public function user_reset_token_confirmation($token) { $managetokenurl = '/user/managetoken.php'; $optionsyes = ['tokenid' => $token->id, 'action' => 'resetwstoken', 'confirm' => 1]; $formcontinue = new single_button(new moodle_url($managetokenurl, $optionsyes), get_string('reset')); $formcancel = new single_button(new moodle_url($managetokenurl), get_string('cancel'), 'get'); $html = $this->output->confirm(get_string('resettokenconfirm', 'webservice', (object) array('user' => $token->firstname . " " . $token->lastname, 'service' => $token->name)), $formcontinue, $formcancel); return $html; } /** * Display user tokens with buttons to reset them * * @param stdClass $tokens user tokens * @param int $userid user id * @param bool $documentation if true display a link to the API documentation * @return string html code */ public function user_webservice_tokens_box($tokens, $userid, $documentation = false) { global $CFG, $DB; // display strings $stroperation = get_string('operation', 'webservice'); $strtoken = get_string('tokenname', 'webservice'); $strservice = get_string('service', 'webservice'); $strcreator = get_string('tokencreator', 'webservice'); $strvaliduntil = get_string('validuntil', 'webservice'); $strlastaccess = get_string('lastaccess'); $return = $this->output->heading(get_string('securitykeys', 'webservice'), 3, 'main', true); $return .= $this->output->box_start('generalbox webservicestokenui'); $return .= get_string('keyshelp', 'webservice'); $table = new html_table(); $table->head = array($strtoken, $strservice, $strvaliduntil, $strlastaccess, $strcreator, $stroperation); $table->align = array('left', 'left', 'left', 'center', 'center', 'left', 'center'); $table->width = '100%'; $table->data = array(); if ($documentation) { $table->head[] = get_string('doc', 'webservice'); $table->align[] = 'center'; } if (!empty($tokens)) { foreach ($tokens as $token) { if ($token->creatorid == $userid) { $reset = html_writer::link(new moodle_url('/user/managetoken.php', [ 'action' => 'resetwstoken', 'tokenid' => $token->id, ]), get_string('reset')); $creator = $token->firstname . " " . $token->lastname; } else { //retrieve administrator name $admincreator = $DB->get_record('user', array('id'=>$token->creatorid)); $creator = $admincreator->firstname . " " . $admincreator->lastname; $reset = ''; } $userprofilurl = new moodle_url('/user/view.php?id=' . $token->creatorid); $creatoratag = html_writer::start_tag('a', array('href' => $userprofilurl)); $creatoratag .= $creator; $creatoratag .= html_writer::end_tag('a'); $validuntil = ''; if (!empty($token->validuntil)) { $validuntil = userdate($token->validuntil, get_string('strftimedatetime', 'langconfig')); } $lastaccess = ''; if (!empty($token->lastaccess)) { $lastaccess = userdate($token->lastaccess, get_string('strftimedatetime', 'langconfig')); } $servicename = $token->servicename; if (!$token->enabled) { // That is the (1 token-1ws) related ws is not enabled. $servicename = ''.$token->servicename.''; } $row = array($token->tokenname, $servicename, $validuntil, $lastaccess, $creatoratag, $reset); if ($documentation) { $doclink = new moodle_url('/webservice/wsdoc.php', array('id' => $token->id)); $row[] = html_writer::tag('a', get_string('doc', 'webservice'), array('href' => $doclink)); } $table->data[] = $row; } $return .= html_writer::table($table); } else { $return .= get_string('notoken', 'webservice'); } $return .= $this->output->box_end(); return $return; } /** * Return documentation for a ws description object * ws description object can be 'external_multiple_structure', 'external_single_structure' * or 'external_value' * * Example of documentation for core_group_create_groups function: * list of ( * object { * courseid int //id of course * name string //multilang compatible name, course unique * description string //group description text * enrolmentkey string //group enrol secret phrase * } * ) * * @param stdClass $params a part of parameter/return description * @return string the html to display */ public function detailed_description_html($params) { // retrieve the description of the description object $paramdesc = ""; if (!empty($params->desc)) { $paramdesc .= html_writer::start_tag('span', array('style' => "color:#2A33A6")); if ($params->required == VALUE_REQUIRED) { $required = ''; } if ($params->required == VALUE_DEFAULT) { if ($params->default === null) { $params->default = "null"; } $required = html_writer::start_tag('b', array()) . get_string('default', 'webservice', print_r($params->default, true)) . html_writer::end_tag('b'); } if ($params->required == VALUE_OPTIONAL) { $required = html_writer::start_tag('b', array()) . get_string('optional', 'webservice') . html_writer::end_tag('b'); } $paramdesc .= " " . $required . " "; $paramdesc .= html_writer::start_tag('i', array()); $paramdesc .= "//"; $paramdesc .= s($params->desc); $paramdesc .= html_writer::end_tag('i'); $paramdesc .= html_writer::end_tag('span'); $paramdesc .= html_writer::empty_tag('br', array()); } // description object is a list if ($params instanceof external_multiple_structure) { return $paramdesc . "list of ( " . html_writer::empty_tag('br', array()) . $this->detailed_description_html($params->content) . ")"; } else if ($params instanceof external_single_structure) { // description object is an object $singlestructuredesc = $paramdesc . "object {" . html_writer::empty_tag('br', array()); foreach ($params->keys as $attributname => $attribut) { $singlestructuredesc .= html_writer::start_tag('b', array()); $singlestructuredesc .= $attributname; $singlestructuredesc .= html_writer::end_tag('b'); $singlestructuredesc .= " " . $this->detailed_description_html($params->keys[$attributname]); } $singlestructuredesc .= "} "; $singlestructuredesc .= html_writer::empty_tag('br', array()); return $singlestructuredesc; } else { // description object is a primary type (string, integer) switch ($params->type) { case PARAM_BOOL: // 0 or 1 only for now case PARAM_INT: $type = 'int'; break; case PARAM_FLOAT; $type = 'double'; break; default: $type = 'string'; } return $type . " " . $paramdesc; } } /** * Return a description object in indented xml format (for REST response) * It is indented to be output within
 tags
     *
     * @param external_description $returndescription the description structure of the web service function returned value
     * @param string $indentation Indentation in the generated HTML code; should contain only spaces.
     * @return string the html to diplay
     */
    public function description_in_indented_xml_format($returndescription, $indentation = "") {
        $indentation = $indentation . "    ";
        $brakeline = <<" . $brakeline;
            $return .= $this->description_in_indented_xml_format($returndescription->content,
                            $indentation);
            $return .= $indentation . "" . $brakeline;
            return $return;
        } else if ($returndescription instanceof external_single_structure) {
            // description object is an object
            $singlestructuredesc = $indentation . "" . $brakeline;
            $keyindentation = $indentation . "    ";
            foreach ($returndescription->keys as $attributname => $attribut) {
                $singlestructuredesc .= $keyindentation . ""
                        . $brakeline .
                        $this->description_in_indented_xml_format(
                                $returndescription->keys[$attributname], $keyindentation) .
                        $keyindentation . "" . $brakeline;
            }
            $singlestructuredesc .= $indentation . "" . $brakeline;
            return $singlestructuredesc;
        } else {
            // description object is a primary type (string, integer)
            switch ($returndescription->type) {
                case PARAM_BOOL: // 0 or 1 only for now
                case PARAM_INT:
                    $type = 'int';
                    break;
                case PARAM_FLOAT;
                    $type = 'double';
                    break;
                default:
                    $type = 'string';
            }
            return $indentation . "" . $type . "" . $brakeline;
        }
    }

    /**
     * Create indented XML-RPC  param description
     *
     * @todo MDL-76078 - Incorrect inter-communication, core cannot have plugin dependencies like this.
     *
     * @param external_description $paramdescription the description structure of the web service function parameters
     * @param string $indentation Indentation in the generated HTML code; should contain only spaces.
     * @return string the html to diplay
     */
    public function xmlrpc_param_description_html($paramdescription, $indentation = "") {
        $indentation = $indentation . "    ";
        $brakeline = <<";
            $return .= $this->xmlrpc_param_description_html($paramdescription->content, $indentation);
            $return .= $brakeline . $indentation . ")";
            return $return;
        } else if ($paramdescription instanceof external_single_structure) {
            // description object is an object
            $singlestructuredesc = $brakeline . $indentation . "Array ";
            $keyindentation = $indentation . "    ";
            $singlestructuredesc .= $brakeline . $keyindentation . "(";
            foreach ($paramdescription->keys as $attributname => $attribut) {
                $singlestructuredesc .= $brakeline . $keyindentation . "[" . $attributname . "] =>" .
                        $this->xmlrpc_param_description_html(
                                $paramdescription->keys[$attributname], $keyindentation) .
                        $keyindentation;
            }
            $singlestructuredesc .= $brakeline . $keyindentation . ")";
            return $singlestructuredesc;
        } else {
            // description object is a primary type (string, integer)
            switch ($paramdescription->type) {
                case PARAM_BOOL: // 0 or 1 only for now
                case PARAM_INT:
                    $type = 'int';
                    break;
                case PARAM_FLOAT;
                    $type = 'double';
                    break;
                default:
                    $type = 'string';
            }
            return " " . $type;
        }
    }

    /**
     * Return the html of a coloured box with content
     *
     * @param string $title - the title of the box
     * @param string $content - the content to displayed
     * @param string $rgb - the background color of the box
     * @return string HTML code
     */
    public function colored_box_with_pre_tag($title, $content, $rgb = 'FEEBE5') {
        $coloredbox = html_writer::start_tag('div', array());
        $coloredbox .= html_writer::start_tag('div',
                        array('style' => "border:solid 1px #DEDEDE;background:#" . $rgb
                            . ";color:#222222;padding:4px;"));
        $coloredbox .= html_writer::start_tag('pre', array());
        $coloredbox .= html_writer::start_tag('b', array());
        $coloredbox .= $title;
        $coloredbox .= html_writer::end_tag('b', array());
        $coloredbox .= html_writer::empty_tag('br', array());
        $coloredbox .= "\n" . $content . "\n";
        $coloredbox .= html_writer::end_tag('pre', array());
        $coloredbox .= html_writer::end_tag('div', array());
        $coloredbox .= html_writer::end_tag('div', array());
        return $coloredbox;
    }

    /**
     * Return indented REST param description
     *
     * @todo MDL-76078 - Incorrect inter-communication, core cannot have plugin dependencies like this.
     *
     * @param external_description $paramdescription the description structure of the web service function parameters
     * @param string $paramstring parameter
     * @return string the html to diplay
     */
    public function rest_param_description_html($paramdescription, $paramstring) {
        $brakeline = <<rest_param_description_html($paramdescription->content, $paramstring);
            return $return;
        } else if ($paramdescription instanceof external_single_structure) {
            // description object is an object
            $singlestructuredesc = "";
            $initialparamstring = $paramstring;
            foreach ($paramdescription->keys as $attributname => $attribut) {
                $paramstring = $initialparamstring . '[' . $attributname . ']';
                $singlestructuredesc .= $this->rest_param_description_html(
                                $paramdescription->keys[$attributname], $paramstring);
            }
            return $singlestructuredesc;
        } else {
            // description object is a primary type (string, integer)
            $paramstring = $paramstring . '=';
            switch ($paramdescription->type) {
                case PARAM_BOOL: // 0 or 1 only for now
                case PARAM_INT:
                    $type = 'int';
                    break;
                case PARAM_FLOAT;
                    $type = 'double';
                    break;
                default:
                    $type = 'string';
            }
            return $paramstring . " " . $type . $brakeline;
        }
    }

    /**
     * Displays all the documentation
     *
     * @todo MDL-76078 - Incorrect inter-communication, core cannot have plugin dependencies like this.
     *
     * @param array $functions external_description of all the web service functions
     * @param boolean $printableformat true if we want to display the documentation in a printable format
     * @param array $activatedprotocol the currently enabled protocol
     * @param array $authparams url parameters (it contains 'tokenid' and sometimes 'print')
     * @param string $parenturl url of the calling page - needed for the print button url:
     *               '/admin/documentation.php' or '/webservice/wsdoc.php' (default)
     * @return string the html to diplay
     */
    public function documentation_html($functions, $printableformat, $activatedprotocol,
            $authparams, $parenturl = '/webservice/wsdoc.php') {

        $documentationhtml = $this->output->heading(get_string('wsdocapi', 'webservice'));

        $br = html_writer::empty_tag('br', array());
        $brakeline = <<doclink = html_writer::tag('a',
                        get_string('wsclientdoc', 'webservice'), array('href' => $docurl));
        $documentationhtml .= get_string('wsdocumentationintro', 'webservice', $docinfo);
        $documentationhtml .= $br . $br;


        // Print button
        $authparams['print'] = true;
        $url = new moodle_url($parenturl, $authparams); // Required
        $documentationhtml .= $this->output->single_button($url, get_string('print', 'webservice'));
        $documentationhtml .= $br;


        // each functions will be displayed into a collapsible region
        //(opened if printableformat = true)
        foreach ($functions as $functionname => $description) {

            $tags = '';
            if (!empty($description->deprecated)) {
                $tags .= ' ' . html_writer::span(get_string('deprecated', 'core_webservice'), 'badge bg-warning text-dark');
            }

            if (empty($printableformat)) {
                $documentationhtml .= print_collapsible_region_start('',
                                'aera_' . $functionname,
                                html_writer::start_tag('strong', array())
                                . $functionname . html_writer::end_tag('strong') . $tags,
                                false,
                                !$printableformat,
                                true);
            } else {
                $documentationhtml .= html_writer::tag('strong', $functionname) . $tags;
                $documentationhtml .= $br;
            }

            // function global description
            $documentationhtml .= $br;
            $documentationhtml .= html_writer::start_tag('div',
                            array('style' => 'border:solid 1px #DEDEDE;background:#E2E0E0;
                        color:#222222;padding:4px;'));
            $documentationhtml .= s($description->description);
            $documentationhtml .= html_writer::end_tag('div');
            $documentationhtml .= $br . $br;

            // function arguments documentation
            $documentationhtml .= html_writer::start_tag('span', array('style' => 'color:#EA33A6'));
            $documentationhtml .= get_string('arguments', 'webservice');
            $documentationhtml .= html_writer::end_tag('span');
            $documentationhtml .= $br;
            foreach ($description->parameters_desc->keys as $paramname => $paramdesc) {
                // a argument documentation
                $documentationhtml .= html_writer::start_tag('div', ['style' => 'font-size:80%']);

                if ($paramdesc->required == VALUE_REQUIRED) {
                    $required = get_string('required', 'webservice');
                }
                if ($paramdesc->required == VALUE_DEFAULT) {
                    if ($paramdesc->default === null) {
                        $default = "null";
                    } else {
                        $default = print_r($paramdesc->default, true);
                    }
                    $required = get_string('default', 'webservice', $default);
                }
                if ($paramdesc->required == VALUE_OPTIONAL) {
                    $required = get_string('optional', 'webservice');
                }

                $documentationhtml .= html_writer::start_tag('b', array());
                $documentationhtml .= $paramname;
                $documentationhtml .= html_writer::end_tag('b');
                $documentationhtml .= " (" . $required . ")"; // argument is required or optional ?
                $documentationhtml .= $br;
                $documentationhtml .= "        "
                        . s($paramdesc->desc); // Argument description.
                $documentationhtml .= $br . $br;
                // general structure of the argument
                $documentationhtml .= $this->colored_box_with_pre_tag(
                                get_string('generalstructure', 'webservice'),
                                $this->detailed_description_html($paramdesc),
                                'FFF1BC');
                // xml-rpc structure of the argument in PHP format
                if (!empty($activatedprotocol['xmlrpc'])) {
                    $documentationhtml .= $this->colored_box_with_pre_tag(
                                    get_string('phpparam', 'webservice'),
                                    htmlentities('[' . $paramname . '] =>'
                                            . $this->xmlrpc_param_description_html($paramdesc), ENT_COMPAT),
                                    'DFEEE7');
                }
                // POST format for the REST protocol for the argument
                if (!empty($activatedprotocol['rest'])) {
                    $documentationhtml .= $this->colored_box_with_pre_tag(
                                    get_string('restparam', 'webservice'),
                                    htmlentities($this->rest_param_description_html(
                                                    $paramdesc, $paramname), ENT_COMPAT),
                                    'FEEBE5');
                }
                $documentationhtml .= html_writer::end_tag('div');
            }
            $documentationhtml .= $br . $br;


            // function response documentation
            $documentationhtml .= html_writer::start_tag('span', array('style' => 'color:#EA33A6'));
            $documentationhtml .= get_string('response', 'webservice');
            $documentationhtml .= html_writer::end_tag('span');
            $documentationhtml .= $br;
            // function response description
            $documentationhtml .= html_writer::start_tag('div', ['style' => 'font-size:80%']);
            if (!empty($description->returns_desc->desc)) {
                $documentationhtml .= $description->returns_desc->desc;
                $documentationhtml .= $br . $br;
            }
            if (!empty($description->returns_desc)) {
                // general structure of the response
                $documentationhtml .= $this->colored_box_with_pre_tag(
                                get_string('generalstructure', 'webservice'),
                                $this->detailed_description_html($description->returns_desc),
                                'FFF1BC');
                // xml-rpc structure of the response in PHP format
                if (!empty($activatedprotocol['xmlrpc'])) {
                    $documentationhtml .= $this->colored_box_with_pre_tag(
                                    get_string('phpresponse', 'webservice'),
                                    htmlentities($this->xmlrpc_param_description_html(
                                                    $description->returns_desc), ENT_COMPAT),
                                    'DFEEE7');
                }
                // XML response for the REST protocol
                if (!empty($activatedprotocol['rest'])) {
                    $restresponse = ""
                            . $brakeline . "" . $brakeline;
                    $restresponse .= $this->description_in_indented_xml_format(
                                    $description->returns_desc);
                    $restresponse .="" . $brakeline;
                    $documentationhtml .= $this->colored_box_with_pre_tag(
                                    get_string('restcode', 'webservice'),
                                    htmlentities($restresponse, ENT_COMPAT),
                                    'FEEBE5');
                }
            }
            $documentationhtml .= html_writer::end_tag('div');
            $documentationhtml .= $br . $br;

            // function errors documentation for REST protocol
            if (!empty($activatedprotocol['rest'])) {
                $documentationhtml .= html_writer::start_tag('span', array('style' => 'color:#EA33A6'));
                $documentationhtml .= get_string('errorcodes', 'webservice');
                $documentationhtml .= html_writer::end_tag('span');
                $documentationhtml .= $br . $br;
                $documentationhtml .= html_writer::start_tag('div', ['style' => 'font-size:80%']);
                $errormessage = get_string('invalidparameter', 'debug');
                $restexceptiontext = <<

    {$errormessage}
    

EOF;
                $documentationhtml .= $this->colored_box_with_pre_tag(
                                get_string('restexception', 'webservice'),
                                htmlentities($restexceptiontext, ENT_COMPAT),
                                'FEEBE5');

                $documentationhtml .= html_writer::end_tag('div');
            }
            $documentationhtml .= $br . $br;

            // Login required info.
            $documentationhtml .= html_writer::start_tag('span', array('style' => 'color:#EA33A6'));
            $documentationhtml .= get_string('loginrequired', 'webservice') . $br;
            $documentationhtml .= html_writer::end_tag('span');
            $documentationhtml .= $description->loginrequired ? get_string('yes') : get_string('no');
            $documentationhtml .= $br . $br;

            // Ajax info.
            $documentationhtml .= html_writer::start_tag('span', array('style' => 'color:#EA33A6'));
            $documentationhtml .= get_string('callablefromajax', 'webservice') . $br;
            $documentationhtml .= html_writer::end_tag('span');
            $documentationhtml .= $description->allowed_from_ajax ? get_string('yes') : get_string('no');
            $documentationhtml .= $br . $br;

            if (empty($printableformat)) {
                $documentationhtml .= print_collapsible_region_end(true);
            }
        }

        return $documentationhtml;
    }

}
home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/user/renderer.php000064400000026326152266563340022203 0ustar00.

/**
 * Provides user rendering functionality such as printing private files tree and displaying a search utility
 *
 * @package    core_user
 * @copyright  2010 Dongsheng Cai 
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

defined('MOODLE_INTERNAL') || die();

/**
 * Provides user rendering functionality such as printing private files tree and displaying a search utility
 * @copyright  2010 Dongsheng Cai 
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */
class core_user_renderer extends plugin_renderer_base {

    /**
     * Prints user search utility that can search user by first initial of firstname and/or first initial of lastname
     * Prints a header with a title and the number of users found within that subset
     * @param string $url the url to return to, complete with any parameters needed for the return
     * @param string $firstinitial the first initial of the firstname
     * @param string $lastinitial the first initial of the lastname
     * @param int $usercount the amount of users meeting the search criteria
     * @param int $totalcount the amount of users of the set/subset being searched
     * @param string $heading heading of the subset being searched, default is All Participants
     * @return string html output
     */
    public function user_search($url, $firstinitial, $lastinitial, $usercount, $totalcount, $heading = null) {

        if ($firstinitial !== 'all') {
            set_user_preference('ifirst', $firstinitial);
        }
        if ($lastinitial !== 'all') {
            set_user_preference('ilast', $lastinitial);
        }

        if (!isset($heading)) {
            $heading = get_string('allparticipants');
        }

        $content = html_writer::start_tag('form', array('action' => new moodle_url($url)));
        $content .= html_writer::start_tag('div');

        // Search utility heading.
        $content .= $this->output->heading($heading.get_string('labelsep', 'langconfig').$usercount.'/'.$totalcount, 3);

        // Initials bar.
        $prefixfirst = 'sifirst';
        $prefixlast = 'silast';
        $content .= $this->output->initials_bar($firstinitial, 'firstinitial', get_string('firstname'), $prefixfirst, $url);
        $content .= $this->output->initials_bar($lastinitial, 'lastinitial', get_string('lastname'), $prefixlast, $url);

        $content .= html_writer::end_tag('div');
        $content .= html_writer::tag('div', ' ');
        $content .= html_writer::end_tag('form');

        return $content;
    }

    /**
     * Construct a partial user search that'll require form handling implemented by the caller.
     * This allows the developer to have an initials bar setup that does not automatically redirect.
     *
     * @param string $url the url to return to, complete with any parameters needed for the return
     * @param string $firstinitial the first initial of the firstname
     * @param string $lastinitial the first initial of the lastname
     * @param bool $minirender Return a trimmed down view of the initials bar.
     * @return string html output
     * @throws coding_exception
     */
    public function partial_user_search(String $url, String $firstinitial, String $lastinitial, Bool $minirender = false): String {

        $content = '';

        if ($firstinitial !== 'all') {
            set_user_preference('ifirst', $firstinitial);
        }
        if ($lastinitial !== 'all') {
            set_user_preference('ilast', $lastinitial);
        }

        // Initials bar.
        $prefixfirst = 'sifirst';
        $prefixlast = 'silast';
        $content .= $this->output->initials_bar(
            $firstinitial,
            'firstinitial',
            get_string('firstname'),
            $prefixfirst,
            $url,
            null,
            $minirender
        );
        $content .= $this->output->initials_bar(
            $lastinitial,
            'lastinitial',
            get_string('lastname'),
            $prefixlast,
            $url,
            null,
            $minirender
        );

        return $content;
    }

    /**
     * Displays the list of tagged users
     *
     * @param array $userlist
     * @param bool $exclusivemode if set to true it means that no other entities tagged with this tag
     *             are displayed on the page and the per-page limit may be bigger
     * @return string
     */
    public function user_list($userlist, $exclusivemode) {
        $tagfeed = new core_tag\output\tagfeed();
        foreach ($userlist as $user) {
            $userpicture = $this->output->user_picture($user, array('size' => $exclusivemode ? 100 : 35));
            $fullname = fullname($user);
            if (user_can_view_profile($user)) {
                $profilelink = new moodle_url('/user/view.php', array('id' => $user->id));
                $fullname = html_writer::link($profilelink, $fullname);
            }
            $tagfeed->add($userpicture, $fullname);
        }

        $items = $tagfeed->export_for_template($this->output);

        if ($exclusivemode) {
            $output = '
    '; foreach ($items['items'] as $item) { $output .= '
  • '. $item['img'] . $item['heading'] ."
  • \n"; } $output .= "
\n"; return $output; } return $this->output->render_from_template('core_tag/tagfeed', $items); } /** * Renders the unified filter element for the course participants page. * @deprecated since 3.9 * @throws coding_exception */ public function unified_filter() { throw new coding_exception('unified_filter cannot be used any more, please use participants_filter instead'); } /** * Render the data required for the participants filter on the course participants page. * * @param context $context The context of the course being displayed * @param string $tableregionid Container of the table to be updated by this filter, is used to retrieve the table * @return string */ public function participants_filter(context $context, string $tableregionid): string { $renderable = new \core_user\output\participants_filter($context, $tableregionid); $templatecontext = $renderable->export_for_template($this->output); return $this->output->render_from_template('core_user/participantsfilter', $templatecontext); } /** * Returns a formatted filter option. * * @param int $filtertype The filter type (e.g. status, role, group, enrolment, last access). * @param string $criteria The string label of the filter type. * @param int $value The value for the filter option. * @param string $label The string representation of the filter option's value. * @return array The formatted option with the ['filtertype:value' => 'criteria: label'] format. */ protected function format_filter_option($filtertype, $criteria, $value, $label) { $optionlabel = get_string('filteroption', 'moodle', (object)['criteria' => $criteria, 'value' => $label]); $optionvalue = "$filtertype:$value"; return [$optionvalue => $optionlabel]; } /** * Handles cases when after reloading the applied filters are missing in the filter options. * * @param array $filtersapplied The applied filters. * @param array $filteroptions The filter options. * @return array The formatted options with the ['filtertype:value' => 'criteria: label'] format. */ private function handle_missing_applied_filters($filtersapplied, $filteroptions) { global $DB; foreach ($filtersapplied as $filter) { if (!array_key_exists($filter, $filteroptions)) { $filtervalue = explode(':', $filter); if (count($filtervalue) !== 2) { continue; } $key = $filtervalue[0]; $value = $filtervalue[1]; switch($key) { case USER_FILTER_LAST_ACCESS: $now = usergetmidnight(time()); $criteria = get_string('usersnoaccesssince'); // Days. for ($i = 1; $i < 7; $i++) { $timestamp = strtotime('-' . $i . ' days', $now); if ($timestamp < $value) { break; } $val = get_string('numdays', 'moodle', $i); $filteroptions += $this->format_filter_option(USER_FILTER_LAST_ACCESS, $criteria, $timestamp, $val); } // Weeks. for ($i = 1; $i < 10; $i++) { $timestamp = strtotime('-'.$i.' weeks', $now); if ($timestamp < $value) { break; } $val = get_string('numweeks', 'moodle', $i); $filteroptions += $this->format_filter_option(USER_FILTER_LAST_ACCESS, $criteria, $timestamp, $val); } // Months. for ($i = 2; $i < 12; $i++) { $timestamp = strtotime('-'.$i.' months', $now); if ($timestamp < $value) { break; } $val = get_string('nummonths', 'moodle', $i); $filteroptions += $this->format_filter_option(USER_FILTER_LAST_ACCESS, $criteria, $timestamp, $val); } // Try a year. $timestamp = strtotime('-1 year', $now); if ($timestamp >= $value) { $val = get_string('numyear', 'moodle', 1); $filteroptions += $this->format_filter_option(USER_FILTER_LAST_ACCESS, $criteria, $timestamp, $val); } break; case USER_FILTER_ROLE: $criteria = get_string('role'); if ($role = $DB->get_record('role', array('id' => $value))) { $role = role_get_name($role); $filteroptions += $this->format_filter_option(USER_FILTER_ROLE, $criteria, $value, $role); } break; } } } return $filteroptions; } } home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/backup/util/ui/renderer.php000064400000144340152266573200024055 0ustar00. /** * This file contains backup and restore output renderers * * @package core_backup * @copyright 2010 Sam Hemelryk * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ use core_course\output\activity_icon; use core\output\local\properties\iconsize; defined('MOODLE_INTERNAL') || die; global $CFG; require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php'); require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php'); require_once($CFG->dirroot . '/backup/moodle2/backup_plan_builder.class.php'); /** * The primary renderer for the backup. * * Can be retrieved with the following code: * get_renderer('core', 'backup'); * ?> * * @package core_backup * @copyright 2010 Sam Hemelryk * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class core_backup_renderer extends plugin_renderer_base { /** * Same site notification display. * * @var string */ private $samesitenotification = ''; /** * Renderers a progress bar for the backup or restore given the items that make it up. * * @param array $items An array of items * @return string */ public function progress_bar(array $items) { foreach ($items as &$item) { $text = $item['text']; unset($item['text']); if (array_key_exists('link', $item)) { $link = $item['link']; unset($item['link']); $item = html_writer::link($link, $text, $item); } else { $item = html_writer::tag('span', $text, $item); } } return html_writer::tag('div', join(get_separator(), $items), array('class' => 'backup_progress clearfix')); } /** * The backup and restore pages may display a log (if any) in a scrolling box. * * @param string $loghtml Log content in HTML format * @return string HTML content that shows the log */ public function log_display($loghtml) { $out = html_writer::start_div('backup_log'); $out .= $this->output->heading(get_string('backuplog', 'backup')); $out .= html_writer::start_div('backup_log_contents'); $out .= $loghtml; $out .= html_writer::end_div(); $out .= html_writer::end_div(); return $out; } /** * Set the same site backup notification. * */ public function set_samesite_notification() { $this->samesitenotification = $this->output->notification(get_string('samesitenotification', 'backup'), 'info'); } /** * Get the same site backup notification. * */ public function get_samesite_notification() { return $this->samesitenotification; } /** * Prints a dependency notification * * @param string $message * @return string */ public function dependency_notification($message) { return html_writer::tag('div', $message, array('class' => 'notification dependencies_enforced')); } /** * Displays the details of a backup file * * @param stdClass $details * @param moodle_url $nextstageurl * @return string */ public function backup_details($details, $nextstageurl) { $yestick = $this->output->pix_icon('i/valid', get_string('yes')); $notick = $this->output->pix_icon('i/invalid', get_string('no')); $html = html_writer::start_tag('div', array('class' => 'backup-restore')); $html .= html_writer::start_tag('div', ['class' => 'backup-section', 'role' => 'table', 'aria-labelledby' => 'backupdetailsheader']); $html .= $this->output->heading(get_string('backupdetails', 'backup'), 2, 'header', 'backupdetailsheader'); $html .= $this->backup_detail_pair(get_string('backuptype', 'backup'), get_string('backuptype'.$details->type, 'backup')); $html .= $this->backup_detail_pair(get_string('backupformat', 'backup'), get_string('backupformat'.$details->format, 'backup')); $html .= $this->backup_detail_pair(get_string('backupmode', 'backup'), get_string('backupmode'.$details->mode, 'backup')); $html .= $this->backup_detail_pair(get_string('backupdate', 'backup'), userdate($details->backup_date)); $html .= $this->backup_detail_pair(get_string('moodleversion', 'backup'), html_writer::tag('span', s($details->moodle_release), array('class' => 'moodle_release')). html_writer::tag('span', '[' . s($details->moodle_version) .']', array('class' => 'moodle_version sub-detail'))); $html .= $this->backup_detail_pair(get_string('backupversion', 'backup'), html_writer::tag('span', s($details->backup_release), array('class' => 'moodle_release')). html_writer::tag('span', '[' . s($details->backup_version) . ']', array('class' => 'moodle_version sub-detail'))); $html .= $this->backup_detail_pair(get_string('originalwwwroot', 'backup'), html_writer::tag('span', s($details->original_wwwroot), array('class' => 'originalwwwroot')). html_writer::tag('span', '[' . s($details->original_site_identifier_hash) . ']', array('class' => 'sitehash sub-detail'))); if (!empty($details->include_file_references_to_external_content)) { $message = ''; if (backup_general_helper::backup_is_samesite($details)) { $message = $yestick . ' ' . get_string('filereferencessamesite', 'backup'); } else { $message = $notick . ' ' . get_string('filereferencesnotsamesite', 'backup'); } $html .= $this->backup_detail_pair(get_string('includefilereferences', 'backup'), $message); } $html .= html_writer::end_tag('div'); $html .= html_writer::start_tag('div', ['class' => 'backup-section settings-section', 'role' => 'table', 'aria-labelledby' => 'backupsettingsheader']); $html .= $this->output->heading(get_string('backupsettings', 'backup'), 2, 'header', 'backupsettingsheader'); foreach ($details->root_settings as $label => $value) { if ($label == 'filename' or $label == 'user_files') { continue; } $html .= $this->backup_detail_pair(get_string('rootsetting'.str_replace('_', '', $label), 'backup'), $value ? $yestick : $notick); } $html .= html_writer::end_tag('div'); if ($details->type === 'course') { $html .= html_writer::start_tag('div', ['class' => 'backup-section', 'role' => 'table', 'aria-labelledby' => 'backupcoursedetailsheader']); $html .= $this->output->heading(get_string('backupcoursedetails', 'backup'), 2, 'header', 'backupcoursedetailsheader'); $html .= $this->backup_detail_pair(get_string('coursetitle', 'backup'), format_string($details->course->title)); $html .= $this->backup_detail_pair(get_string('courseid', 'backup'), clean_param($details->course->courseid, PARAM_INT)); // Warning users about front page backups. if ($details->original_course_format === 'site') { $html .= $this->backup_detail_pair(get_string('type_format', 'plugin'), get_string('sitecourseformatwarning', 'backup')); } $html .= html_writer::start_tag('div', array('class' => 'backup-sub-section')); $html .= $this->output->heading(get_string('backupcoursesections', 'backup'), 3, array('class' => 'subheader')); foreach ($details->sections as $key => $section) { $included = $key.'_included'; $userinfo = $key.'_userinfo'; if ($section->settings[$included] && $section->settings[$userinfo]) { $value = get_string('sectionincanduser', 'backup'); } else if ($section->settings[$included]) { $value = get_string('sectioninc', 'backup'); } else { continue; } $html .= $this->backup_detail_pair(get_string('backupcoursesection', 'backup', format_string($section->title)), $value); $table = null; foreach ($details->activities as $activitykey => $activity) { if ($activity->sectionid != $section->sectionid) { continue; } if (empty($table)) { $table = new html_table(); $table->head = array(get_string('module', 'backup'), get_string('title', 'backup'), get_string('userinfo', 'backup')); $table->colclasses = array('modulename', 'moduletitle', 'userinfoincluded'); $table->align = array('left', 'left', 'center'); $table->attributes = ['class' => 'activitytable table generaltable']; $table->data = array(); } $name = get_string('pluginname', $activity->modulename); $icon = activity_icon::from_modname($activity->modulename) ->set_icon_size(iconsize::SIZE4) ->set_colourize(false); $content = $this->output->container( contents: $this->output->render($icon) . $name, classes: 'd-flex align-items-center', ); $table->data[] = [ $content, format_string($activity->title), ($activity->settings[$activitykey.'_userinfo']) ? $yestick : $notick, ]; } if (!empty($table)) { $html .= $this->backup_detail_pair(get_string('sectionactivities', 'backup'), html_writer::table($table)); } } $html .= html_writer::end_tag('div'); $html .= html_writer::end_tag('div'); } $html .= $this->continue_button($nextstageurl, 'post'); $html .= html_writer::end_tag('div'); return $html; } /** * Displays the general information about a backup file with non-standard format * * @param moodle_url $nextstageurl URL to send user to * @param array $details basic info about the file (format, type) * @return string HTML code to display */ public function backup_details_nonstandard($nextstageurl, array $details) { $html = html_writer::start_tag('div', array('class' => 'backup-restore nonstandardformat')); $html .= html_writer::start_tag('div', array('class' => 'backup-section')); $html .= $this->output->heading(get_string('backupdetails', 'backup'), 2, 'header'); $html .= $this->output->box(get_string('backupdetailsnonstandardinfo', 'backup'), 'noticebox'); $html .= $this->backup_detail_pair( get_string('backupformat', 'backup'), get_string('backupformat'.$details['format'], 'backup')); $html .= $this->backup_detail_pair( get_string('backuptype', 'backup'), get_string('backuptype'.$details['type'], 'backup')); $html .= html_writer::end_tag('div'); $html .= $this->continue_button($nextstageurl, 'post'); $html .= html_writer::end_tag('div'); return $html; } /** * Displays the general information about a backup file with unknown format * * @param moodle_url $nextstageurl URL to send user to * @return string HTML code to display */ public function backup_details_unknown(moodle_url $nextstageurl) { $html = html_writer::start_div('unknownformat'); $html .= $this->output->heading(get_string('errorinvalidformat', 'backup'), 2); $html .= $this->output->notification(get_string('errorinvalidformatinfo', 'backup'), 'notifyproblem'); $html .= $this->continue_button($nextstageurl, 'post'); $html .= html_writer::end_div(); return $html; } /** * Displays a course selector for restore * * @param moodle_url $nextstageurl * @param bool $wholecourse true if we are restoring whole course (as with backup::TYPE_1COURSE), false otherwise * @param restore_category_search $categories * @param restore_course_search $courses * @param int $currentcourse * @return string */ public function course_selector(moodle_url $nextstageurl, $wholecourse = true, ?restore_category_search $categories = null, ?restore_course_search $courses = null, $currentcourse = null) { global $CFG; require_once($CFG->dirroot.'/course/lib.php'); // These variables are used to check if the form using this function was submitted. $target = optional_param('target', false, PARAM_INT); $targetid = optional_param('targetid', null, PARAM_INT); // Check if they submitted the form but did not provide all the data we need. $missingdata = false; if ($target and is_null($targetid)) { $missingdata = true; } $nextstageurl->param('sesskey', sesskey()); $form = html_writer::start_tag('form', array('method' => 'post', 'action' => $nextstageurl->out_omit_querystring(), 'class' => 'mform')); foreach ($nextstageurl->params() as $key => $value) { $form .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => $key, 'value' => $value)); } $hasrestoreoption = false; $html = html_writer::start_tag('div', array('class' => 'backup-course-selector backup-restore')); if ($wholecourse && !empty($categories) && ($categories->get_count() > 0 || $categories->get_search())) { // New course. $hasrestoreoption = true; $html .= $form; $html .= html_writer::start_tag('div', array('class' => 'bcs-new-course backup-section')); $html .= $this->output->heading(get_string('restoretonewcourse', 'backup'), 2, array('class' => 'header')); $html .= $this->backup_detail_input(get_string('restoretonewcourse', 'backup'), 'radio', 'target', backup::TARGET_NEW_COURSE, array('checked' => 'checked')); $selectacategoryhtml = $this->backup_detail_pair(get_string('selectacategory', 'backup'), $this->render($categories)); // Display the category selection as required if the form was submitted but this data was not supplied. if ($missingdata && $target == backup::TARGET_NEW_COURSE) { $html .= html_writer::span(get_string('required'), 'error'); $html .= html_writer::start_tag('fieldset', array('class' => 'error')); $html .= $selectacategoryhtml; $html .= html_writer::end_tag('fieldset'); } else { $html .= $selectacategoryhtml; } $attrs = array('type' => 'submit', 'value' => get_string('continue'), 'class' => 'btn btn-primary'); $html .= $this->backup_detail_pair('', html_writer::empty_tag('input', $attrs)); $html .= html_writer::end_tag('div'); $html .= html_writer::end_tag('form'); } if ($wholecourse && !empty($currentcourse)) { // Current course. $hasrestoreoption = true; $html .= $form; $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'targetid', 'value' => $currentcourse)); $html .= html_writer::start_tag('div', array('class' => 'bcs-current-course backup-section')); $html .= $this->output->heading(get_string('restoretocurrentcourse', 'backup'), 2, array('class' => 'header')); $html .= $this->backup_detail_input(get_string('restoretocurrentcourseadding', 'backup'), 'radio', 'target', backup::TARGET_CURRENT_ADDING, array('checked' => 'checked')); $html .= $this->backup_detail_input(get_string('restoretocurrentcoursedeleting', 'backup'), 'radio', 'target', backup::TARGET_CURRENT_DELETING); $attrs = array('type' => 'submit', 'value' => get_string('continue'), 'class' => 'btn btn-primary'); $html .= $this->backup_detail_pair('', html_writer::empty_tag('input', $attrs)); $html .= html_writer::end_tag('div'); $html .= html_writer::end_tag('form'); } // If we are restoring an activity, then include the current course. if (!$wholecourse) { $courses->invalidate_results(); // Clean list of courses. $courses->set_include_currentcourse(); } if (!empty($courses) && ($courses->get_count() > 0 || $courses->get_search())) { // Existing course. $hasrestoreoption = true; $html .= $form; $html .= html_writer::start_tag('div', array('class' => 'bcs-existing-course backup-section')); $html .= $this->output->heading(get_string('restoretoexistingcourse', 'backup'), 2, array('class' => 'header')); if ($wholecourse) { $html .= $this->backup_detail_input(get_string('restoretoexistingcourseadding', 'backup'), 'radio', 'target', backup::TARGET_EXISTING_ADDING, array('checked' => 'checked')); $html .= $this->backup_detail_input(get_string('restoretoexistingcoursedeleting', 'backup'), 'radio', 'target', backup::TARGET_EXISTING_DELETING); } else { $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'target', 'value' => backup::TARGET_EXISTING_ADDING)); } $selectacoursehtml = $this->backup_detail_pair(get_string('selectacourse', 'backup'), $this->render($courses)); // Display the course selection as required if the form was submitted but this data was not supplied. if ($missingdata && $target == backup::TARGET_EXISTING_ADDING) { $html .= html_writer::span(get_string('required'), 'error'); $html .= html_writer::start_tag('fieldset', array('class' => 'error')); $html .= $selectacoursehtml; $html .= html_writer::end_tag('fieldset'); } else { $html .= $selectacoursehtml; } $attrs = array('type' => 'submit', 'value' => get_string('continue'), 'class' => 'btn btn-primary'); $html .= $this->backup_detail_pair('', html_writer::empty_tag('input', $attrs)); $html .= html_writer::end_tag('div'); $html .= html_writer::end_tag('form'); } if (!$hasrestoreoption) { echo $this->output->notification(get_string('norestoreoptions', 'backup')); } $html .= html_writer::end_tag('div'); return $html; } /** * Displays the import course selector * * @param moodle_url $nextstageurl * @param import_course_search $courses * @return string */ public function import_course_selector(moodle_url $nextstageurl, ?import_course_search $courses = null) { $html = html_writer::start_tag('div', array('class' => 'import-course-selector backup-restore')); $html .= html_writer::start_tag('form', array('method' => 'post', 'action' => $nextstageurl->out_omit_querystring())); foreach ($nextstageurl->params() as $key => $value) { $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => $key, 'value' => $value)); } // We only allow import adding for now. Enforce it here. $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'target', 'value' => backup::TARGET_CURRENT_ADDING)); $html .= html_writer::start_tag('div', array('class' => 'ics-existing-course backup-section')); $html .= $this->output->heading(get_string('importdatafrom'), 2, array('class' => 'header')); $html .= $this->backup_detail_pair(get_string('selectacourse', 'backup'), $this->render($courses)); $attrs = array('type' => 'submit', 'value' => get_string('continue'), 'class' => 'btn btn-primary'); $html .= html_writer::start_tag('div', array('class' => 'mt-3')); $html .= $this->backup_detail_pair('', html_writer::empty_tag('input', $attrs)); $html .= html_writer::end_tag('div'); $html .= html_writer::end_tag('div'); $html .= html_writer::end_tag('form'); $html .= html_writer::end_tag('div'); return $html; } /** * Creates a detailed pairing (key + value) * * @staticvar int $count * @param string $label * @param string $value * @return string */ protected function backup_detail_pair($label, $value) { static $count = 0; $count ++; $html = html_writer::start_tag('div', ['class' => 'detail-pair', 'role' => 'row']); $html .= html_writer::tag('div', $label, ['class' => 'detail-pair-label mb-2', 'role' => 'cell']); $html .= html_writer::tag('div', $value, ['class' => 'detail-pair-value ps-2', 'role' => 'cell']); $html .= html_writer::end_tag('div'); return $html; } /** * Creates a unique id string by appending an incremental number to the prefix. * * @param string $prefix To be used as the left part of the id string. * @return string */ protected function make_unique_id(string $prefix): string { static $count = 0; return $prefix . '-' . $count++; } /** * Created a detailed pairing with an input * * @param string $label * @param string $type * @param string $name * @param string $value * @param array $attributes * @param string|null $description * @return string */ protected function backup_detail_input($label, $type, $name, $value, array $attributes = array(), $description = null) { if (!empty($description)) { $description = html_writer::tag('span', $description, array('class' => 'description')); } else { $description = ''; } $id = $this->make_unique_id('detail-pair-value'); return $this->backup_detail_pair( html_writer::label($label, $id), html_writer::empty_tag('input', $attributes + ['id' => $id, 'name' => $name, 'type' => $type, 'value' => $value]) . $description ); } /** * Creates a detailed pairing with a select * * @param string $label * @param string $name * @param array $options * @param string $selected * @param bool $nothing * @param array $attributes * @param string|null $description * @return string */ protected function backup_detail_select($label, $name, $options, $selected = '', $nothing = false, array $attributes = array(), $description = null) { if (!empty ($description)) { $description = html_writer::tag('span', $description, array('class' => 'description')); } else { $description = ''; } return $this->backup_detail_pair($label, html_writer::select($options, $name, $selected, false, $attributes).$description); } /** * Displays precheck notices * * @param array $results * @return string */ public function precheck_notices($results) { $output = html_writer::start_tag('div', array('class' => 'restore-precheck-notices')); if (array_key_exists('errors', $results)) { foreach ($results['errors'] as $error) { $output .= $this->output->notification($error); } } if (array_key_exists('warnings', $results)) { foreach ($results['warnings'] as $warning) { $output .= $this->output->notification($warning, 'notifyproblem'); } } return $output.html_writer::end_tag('div'); } /** * Displays substage buttons * * @param bool $haserrors * @return string */ public function substage_buttons($haserrors) { $output = html_writer::start_tag('div', array('continuebutton')); if (!$haserrors) { $attrs = ['type' => 'submit', 'value' => get_string('continue'), 'class' => 'btn btn-primary me-1']; $output .= html_writer::empty_tag('input', $attrs); } $attrs = array('type' => 'submit', 'name' => 'cancel', 'value' => get_string('cancel'), 'class' => 'btn btn-secondary'); $output .= html_writer::empty_tag('input', $attrs); $output .= html_writer::end_tag('div'); return $output; } /** * Displays a role mapping interface * * @param array $rolemappings * @param array $roles * @return string */ public function role_mappings($rolemappings, $roles) { $roles[0] = get_string('none'); $output = html_writer::start_tag('div', array('class' => 'restore-rolemappings')); $output .= $this->output->heading(get_string('restorerolemappings', 'backup'), 2); foreach ($rolemappings as $id => $mapping) { $label = $mapping->name; $name = 'mapping'.$id; $selected = $mapping->targetroleid; $output .= $this->backup_detail_select($label, $name, $roles, $mapping->targetroleid, false, array(), $mapping->description); } $output .= html_writer::end_tag('div'); return $output; } /** * Displays a continue button, overriding core renderer method of the same in order * to override submission method of the button form * * @param string|moodle_url $url * @param string $method * @return string */ public function continue_button($url, $method = 'post') { if (!($url instanceof moodle_url)) { $url = new moodle_url($url); } if ($method != 'post') { $method = 'get'; } $button = new single_button($url, get_string('continue'), $method, single_button::BUTTON_PRIMARY); $button->class = 'continuebutton'; return $this->render($button); } /** * Print a backup files tree * @param array $options * @return string */ public function backup_files_viewer(?array $options = null) { $files = new backup_files_viewer($options); return $this->render($files); } /** * Generate the status indicator markup for display in the * backup restore file area UI. * * @param int $statuscode The status code of the backup. * @param string $backupid The backup record id. * @return string|boolean $status The status indicator for the operation. */ public function get_status_display($statuscode, $backupid, $restoreid=null, $operation='backup') { if ($statuscode == backup::STATUS_AWAITING || $statuscode == backup::STATUS_EXECUTING || $statuscode == backup::STATUS_REQUIRE_CONV) { // In progress. $progresssetup = array( 'backupid' => $backupid, 'restoreid' => $restoreid, 'operation' => $operation, 'width' => '100' ); $status = $this->render_from_template('core/async_backup_progress', $progresssetup); } else if ($statuscode == backup::STATUS_FINISHED_ERR) { // Error. $icon = $this->output->render(new \pix_icon('i/delete', get_string('failed', 'backup'))); $status = \html_writer::span($icon, 'action-icon'); } else if ($statuscode == backup::STATUS_FINISHED_OK) { // Complete. $icon = $this->output->render(new \pix_icon('i/checked', get_string('successful', 'backup'))); $status = \html_writer::span($icon, 'action-icon'); } return $status; } /** * Displays a backup files viewer * * @global stdClass $USER * @param backup_files_viewer $viewer * @return string */ public function render_backup_files_viewer(backup_files_viewer $viewer) { $files = $viewer->files; $filestodisplay = false; foreach ($files as $file) { if (!$file->is_directory()) { $filestodisplay = true; break; } } $async = \async_helper::is_async_enabled(); switch($viewer->filearea) { case 'activity': $title = get_string('choosefilefromactivitybackup', 'backup'); $description = get_string('choosefilefromactivitybackup_help', 'backup'); $button = get_string('managefiles_activity', 'backup'); $nofilesstring = get_string('restorenofilesbackuparea_activity', 'backup'); break; case 'course': $title = get_string('choosefilefromcoursebackup', 'backup'); $description = get_string('choosefilefromcoursebackup_help', 'backup'); $button = get_string('managefiles_course', 'backup'); $nofilesstring = get_string('restorenofilesbackuparea_course', 'backup'); break; case 'backup': $title = get_string('choosefilefromuserbackup', 'backup'); $description = get_string('choosefilefromuserbackup_help', 'backup'); $button = get_string('managefiles_backup', 'backup'); $nofilesstring = get_string('restorenofilesbackuparea_backup', 'backup'); break; case 'automated': $title = get_string('choosefilefromautomatedbackup', 'backup'); $description = get_string('choosefilefromautomatedbackup_help', 'backup'); $button = get_string('managefiles_automated', 'backup'); $nofilesstring = get_string('restorenofilesbackuparea_automated', 'backup'); break; default: $title = ''; $description = ''; $button = get_string('managefiles', 'backup'); $nofilesstring = get_string('restorenofilesbackuparea', 'backup'); } $html = html_writer::tag('h3', $title, ['class' => 'mt-6']); $html .= html_writer::tag('div', $description, ['class' => 'mb-3']); if ($filestodisplay || $async) { $tablehead = [ get_string('filename', 'backup'), get_string('time'), get_string('size'), get_string('download'), get_string('restore'), ]; if ($async) { $tablehead[] = get_string('status', 'backup'); } $table = new html_table(); $table->attributes['class'] = 'backup-files-table table generaltable table-hover'; $table->head = $tablehead; $table->width = '100%'; $table->data = []; // First add in progress asynchronous backups. // Only if asynchronous backups are enabled. if ($async) { $tabledata = []; $backups = \async_helper::get_async_backups($viewer->filearea, $viewer->filecontext->instanceid); // For each backup get, new item name, time restore created and progress. foreach ($backups as $backup) { $status = $this->get_status_display($backup->status, $backup->backupid); $timecreated = $backup->timecreated; $tablerow = [$backup->filename, userdate($timecreated), '-', '-', '-', $status]; $tabledata[] = $tablerow; } $table->data = $tabledata; } // Add completed backups. foreach ($files as $file) { if ($file->is_directory()) { continue; } $fileurl = moodle_url::make_pluginfile_url( $file->get_contextid(), $file->get_component(), $file->get_filearea(), null, $file->get_filepath(), $file->get_filename(), true ); $params = []; $params['action'] = 'choosebackupfile'; $params['filename'] = $file->get_filename(); $params['filepath'] = $file->get_filepath(); $params['component'] = $file->get_component(); $params['filearea'] = $file->get_filearea(); $params['filecontextid'] = $file->get_contextid(); $params['contextid'] = $viewer->currentcontext->id; $params['itemid'] = $file->get_itemid(); $restoreurl = new moodle_url('/backup/restorefile.php', $params); $restorelink = html_writer::link($restoreurl, get_string('restore')); $downloadlink = html_writer::link($fileurl, get_string('download')); // Conditional display of the restore and download links, initially only for the 'automated' filearea. if ($params['filearea'] == 'automated') { if (!has_capability('moodle/restore:viewautomatedfilearea', $viewer->currentcontext)) { $restorelink = ''; } if (!can_download_from_backup_filearea($params['filearea'], $viewer->currentcontext)) { $downloadlink = ''; } } $tabledata = [ $file->get_filename(), userdate ($file->get_timemodified()), display_size ($file->get_filesize()), $downloadlink, $restorelink, ]; if ($async) { $tabledata[] = $this->get_status_display(backup::STATUS_FINISHED_OK, null); } $table->data[] = $tabledata; } $html .= html_writer::table($table); } else { // There are no files to display. $html .= $this->notification($nofilesstring, 'notifymessage'); } // For automated backups, the ability to manage backup files is controlled by the ability to download them. // All files must be from the same file area in a backup_files_viewer. $canmanagebackups = true; if ($viewer->filearea == 'automated') { if (!can_download_from_backup_filearea($viewer->filearea, $viewer->currentcontext)) { $canmanagebackups = false; } } if ($canmanagebackups) { $html .= $this->output->single_button( new moodle_url('/backup/backupfilesedit.php', array( 'currentcontext' => $viewer->currentcontext->id, 'contextid' => $viewer->filecontext->id, 'filearea' => $viewer->filearea, 'component' => $viewer->component, 'returnurl' => $this->page->url->out()) ), $button, 'post' ); } return $html; } /** * Renders a restore course search object * * @param restore_course_search $component * @return string */ public function render_restore_course_search(restore_course_search $component) { $output = html_writer::start_tag('div', array('class' => 'restore-course-search mb-1')); $output .= html_writer::start_tag('div', array('class' => 'rcs-results table-sm w-75')); $table = new html_table(); $table->head = array('', get_string('shortnamecourse'), get_string('fullnamecourse')); $table->data = array(); if ($component->get_count() !== 0) { foreach ($component->get_results() as $course) { $row = new html_table_row(); $row->attributes['class'] = 'rcs-course'; if (!$course->visible) { $row->attributes['class'] .= ' dimmed'; } $id = $this->make_unique_id('restore-course'); $attrs = ['type' => 'radio', 'name' => 'targetid', 'value' => $course->id, 'id' => $id]; if ($course->id == $component->get_current_course_id()) { $attrs['checked'] = 'checked'; } $row->cells = [ html_writer::empty_tag('input', $attrs), html_writer::label( format_string($course->shortname, true, ['context' => context_course::instance($course->id)]), $id, true, ['class' => 'd-block'] ), format_string($course->fullname, true, ['context' => context_course::instance($course->id)]) ]; $table->data[] = $row; } if ($component->has_more_results()) { $cell = new html_table_cell(get_string('moreresults', 'backup')); $cell->colspan = 3; $cell->attributes['class'] = 'notifyproblem'; $row = new html_table_row(array($cell)); $row->attributes['class'] = 'rcs-course'; $table->data[] = $row; } } else { $cell = new html_table_cell(get_string('nomatchingcourses', 'backup')); $cell->colspan = 3; $cell->attributes['class'] = 'notifyproblem'; $row = new html_table_row(array($cell)); $row->attributes['class'] = 'rcs-course'; $table->data[] = $row; } $output .= html_writer::table($table); $output .= html_writer::end_tag('div'); $data = [ 'inform' => true, 'extraclasses' => 'rcs-search mb-3 w-25', 'inputname' => restore_course_search::$VAR_SEARCH, 'searchstring' => get_string('searchcourses'), 'buttonattributes' => [ (object) ['key' => 'name', 'value' => 'searchcourses'], (object) ['key' => 'value', 'value' => 1], ], 'query' => $component->get_search(), ]; $output .= $this->output->render_from_template('core/search_input', $data); $output .= html_writer::end_tag('div'); return $output; } /** * Renders an import course search object * * @param import_course_search $component * @return string */ public function render_import_course_search(import_course_search $component) { $output = html_writer::start_tag('div', array('class' => 'import-course-search')); if ($component->get_count() === 0) { $output .= $this->output->notification(get_string('nomatchingcourses', 'backup')); $output .= html_writer::start_tag('div', ['class' => 'ics-search d-flex flex-wrap align-items-center']); $attrs = array( 'type' => 'text', 'name' => restore_course_search::$VAR_SEARCH, 'value' => $component->get_search(), 'aria-label' => get_string('searchcourses'), 'placeholder' => get_string('searchcourses'), 'class' => 'form-control' ); $output .= html_writer::empty_tag('input', $attrs); $attrs = array( 'type' => 'submit', 'name' => 'searchcourses', 'value' => get_string('search'), 'class' => 'btn btn-secondary ms-1' ); $output .= html_writer::empty_tag('input', $attrs); $output .= html_writer::end_tag('div'); $output .= html_writer::end_tag('div'); return $output; } $countstr = ''; if ($component->has_more_results()) { $countstr = get_string('morecoursesearchresults', 'backup', $component->get_count()); } else { $countstr = get_string('totalcoursesearchresults', 'backup', $component->get_count()); } $output .= html_writer::tag('div', $countstr, array('class' => 'ics-totalresults')); $output .= html_writer::start_tag('div', array('class' => 'ics-results')); $table = new html_table(); $table->head = array('', get_string('shortnamecourse'), get_string('fullnamecourse')); $table->data = array(); foreach ($component->get_results() as $course) { $row = new html_table_row(); $row->attributes['class'] = 'ics-course'; if (!$course->visible) { $row->attributes['class'] .= ' dimmed'; } $id = $this->make_unique_id('import-course'); $row->cells = [ html_writer::empty_tag('input', ['type' => 'radio', 'name' => 'importid', 'value' => $course->id, 'id' => $id]), html_writer::label( format_string($course->shortname, true, ['context' => context_course::instance($course->id)]), $id, true, ['class' => 'd-block'] ), format_string($course->fullname, true, ['context' => context_course::instance($course->id)]) ]; $table->data[] = $row; } if ($component->has_more_results()) { $cell = new html_table_cell(get_string('moreresults', 'backup')); $cell->colspan = 3; $cell->attributes['class'] = 'notifyproblem'; $row = new html_table_row(array($cell)); $row->attributes['class'] = 'rcs-course'; $table->data[] = $row; } $output .= html_writer::table($table); $output .= html_writer::end_tag('div'); $output .= html_writer::start_tag('div', ['class' => 'ics-search d-flex flex-wrap align-items-center']); $attrs = array( 'type' => 'text', 'name' => restore_course_search::$VAR_SEARCH, 'value' => $component->get_search(), 'aria-label' => get_string('searchcourses'), 'placeholder' => get_string('searchcourses'), 'class' => 'form-control'); $output .= html_writer::empty_tag('input', $attrs); $attrs = array( 'type' => 'submit', 'name' => 'searchcourses', 'value' => get_string('search'), 'class' => 'btn btn-secondary ms-1' ); $output .= html_writer::empty_tag('input', $attrs); $output .= html_writer::end_tag('div'); $output .= html_writer::end_tag('div'); return $output; } /** * Renders a restore category search object * * @param restore_category_search $component * @return string */ public function render_restore_category_search(restore_category_search $component) { $output = html_writer::start_tag('div', array('class' => 'restore-course-search mb-1')); $output .= html_writer::start_tag('div', array('class' => 'rcs-results table-sm w-75')); $table = new html_table(); $table->head = array('', get_string('name'), get_string('description')); $table->data = array(); if ($component->get_count() !== 0) { foreach ($component->get_results() as $category) { $row = new html_table_row(); $row->attributes['class'] = 'rcs-course'; if (!$category->visible) { $row->attributes['class'] .= ' dimmed'; } $context = context_coursecat::instance($category->id); $id = $this->make_unique_id('restore-category'); $row->cells = [ html_writer::empty_tag('input', ['type' => 'radio', 'name' => 'targetid', 'value' => $category->id, 'id' => $id]), html_writer::label( format_string($category->name, true, ['context' => context_coursecat::instance($category->id)]), $id, true, ['class' => 'd-block'] ), format_text(file_rewrite_pluginfile_urls($category->description, 'pluginfile.php', $context->id, 'coursecat', 'description', null), $category->descriptionformat, ['overflowdiv' => true]) ]; $table->data[] = $row; } if ($component->has_more_results()) { $cell = new html_table_cell(get_string('moreresults', 'backup')); $cell->attributes['class'] = 'notifyproblem'; $cell->colspan = 3; $row = new html_table_row(array($cell)); $row->attributes['class'] = 'rcs-course'; $table->data[] = $row; } } else { $cell = new html_table_cell(get_string('nomatchingcourses', 'backup')); $cell->colspan = 3; $cell->attributes['class'] = 'notifyproblem'; $row = new html_table_row(array($cell)); $row->attributes['class'] = 'rcs-course'; $table->data[] = $row; } $output .= html_writer::table($table); $output .= html_writer::end_tag('div'); $data = [ 'inform' => true, 'extraclasses' => 'rcs-search mb-3 w-25', 'inputname' => restore_category_search::$VAR_SEARCH, 'searchstring' => get_string('searchcoursecategories'), 'buttonattributes' => [ (object) ['key' => 'name', 'value' => 'searchcourses'], (object) ['key' => 'value', 'value' => 1], ], 'query' => $component->get_search(), ]; $output .= $this->output->render_from_template('core/search_input', $data); $output .= html_writer::end_tag('div'); return $output; } /** * Get markup to render table for all of a users async * in progress restores. * * @param int $userid The Moodle user id. * @param \context $context The Moodle context for these restores. * @return string $html The table HTML. */ public function restore_progress_viewer($userid, $context) { $tablehead = array(get_string('course'), get_string('time'), get_string('status', 'backup')); $table = new html_table(); $table->attributes['class'] = 'backup-files-table table generaltable table-hover'; $table->head = $tablehead; $tabledata = array(); // Get all in progress async restores for this user. $restores = \async_helper::get_async_restores($userid); // For each backup get, new item name, time restore created and progress. foreach ($restores as $restore) { $restorename = \async_helper::get_restore_name($context); $timecreated = $restore->timecreated; $status = $this->get_status_display($restore->status, $restore->backupid, $restore->backupid, null, 'restore'); $tablerow = array($restorename, userdate($timecreated), $status); $tabledata[] = $tablerow; } $table->data = $tabledata; $html = html_writer::table($table); return $html; } /** * Get markup to render table for all of a users course copies. * * @param int $userid The Moodle user id. * @param int $courseid The id of the course to get the backups for. * @return string $html The table HTML. */ public function copy_progress_viewer(int $userid, int $courseid): string { $tablehead = array( get_string('copysource', 'backup'), get_string('copydest', 'backup'), get_string('time'), get_string('copyop', 'backup'), get_string('status', 'backup') ); $table = new html_table(); $table->attributes['class'] = 'backup-files-table table generaltable table-hover'; $table->head = $tablehead; $tabledata = array(); // Get all in progress course copies for this user. $copies = \copy_helper::get_copies($userid, $courseid); foreach ($copies as $copy) { $sourceurl = new \moodle_url('/course/view.php', array('id' => $copy->sourceid)); $tablerow = array( html_writer::link($sourceurl, format_string($copy->source, true, ['context' => context_course::instance($copy->sourceid)])), format_string($copy->destination, true, ['context' => context_course::instance($copy->sourceid)]), userdate($copy->timecreated), get_string($copy->operation), $this->get_status_display($copy->status, $copy->backupid, $copy->restoreid, $copy->operation) ); $tabledata[] = $tablerow; } $table->data = $tabledata; $html = html_writer::table($table); return $html; } } /** * Data structure representing backup files viewer * * @copyright 2010 Dongsheng Cai * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @since Moodle 2.0 */ class backup_files_viewer implements renderable { /** * @var array */ public $files; /** * @var context */ public $filecontext; /** * @var string */ public $component; /** * @var string */ public $filearea; /** * @var context */ public $currentcontext; /** * Constructor of backup_files_viewer class * @param array $options */ public function __construct(?array $options = null) { global $CFG, $USER; $fs = get_file_storage(); $this->currentcontext = $options['currentcontext']; $this->filecontext = $options['filecontext']; $this->component = $options['component']; $this->filearea = $options['filearea']; $files = $fs->get_area_files($this->filecontext->id, $this->component, $this->filearea, false, 'timecreated'); $this->files = array_reverse($files); } } home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/grade/renderer.php000064400000025116152266574310022302 0ustar00. defined('MOODLE_INTERNAL') || die; use core\output\comboboxsearch; use core_grades\output\action_bar; use core_grades\output\penalty_indicator; use core_message\helper; use core_message\api; /** * Renderer class for the grade pages. * * @package core_grades * @copyright 2021 Mihail Geshoski * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class core_grades_renderer extends plugin_renderer_base { /** * Renders the action bar for a given page. * * @param action_bar $actionbar * @return string The HTML output */ public function render_action_bar(action_bar $actionbar): string { $data = $actionbar->export_for_template($this); return $this->render_from_template($actionbar->get_template(), $data); } /** * Renders the group selector trigger element. * * @param object $course The course object. * @param string|null $groupactionbaseurl This parameter has been deprecated since 4.4 and should not be used anymore. * @return string|null The raw HTML to render. * @deprecated since 4.5. See replacement renderable \core_course\output\actionbar\group_selector instead. * @todo Final deprecation in Moodle 6.0. See MDL-82116. */ #[\core\attribute\deprecated( replacement: null, since: '4.5', reason: 'See replacement renderable \core_course\output\actionbar\group_selector.' )] public function group_selector(object $course, ?string $groupactionbaseurl = null): ?string { global $USER; \core\deprecation::emit_deprecation([$this, __FUNCTION__]); if ($groupactionbaseurl !== null) { debugging( 'The $groupactionbaseurl argument has been deprecated. Please remove it from your method calls.', DEBUG_DEVELOPER, ); } // Make sure that group mode is enabled. if (!$groupmode = $course->groupmode) { return null; } $sbody = $this->render_from_template('core_group/comboboxsearch/searchbody', [ 'courseid' => $course->id, 'currentvalue' => optional_param('groupsearchvalue', '', PARAM_NOTAGS), 'instance' => rand(), ]); $label = $groupmode == VISIBLEGROUPS ? get_string('selectgroupsvisible') : get_string('selectgroupsseparate'); $buttondata = ['label' => $label]; $context = context_course::instance($course->id); if ($groupmode == VISIBLEGROUPS || has_capability('moodle/site:accessallgroups', $context)) { $allowedgroups = groups_get_all_groups($course->id, 0, $course->defaultgroupingid); } else { $allowedgroups = groups_get_all_groups($course->id, $USER->id, $course->defaultgroupingid); } $activegroup = groups_get_course_group($course, true, $allowedgroups); $buttondata['group'] = $activegroup; if ($activegroup) { $group = groups_get_group($activegroup); $buttondata['selectedgroup'] = format_string($group->name, true, ['context' => $context]); } else if ($activegroup === 0) { $buttondata['selectedgroup'] = get_string('allparticipants'); } $groupdropdown = new comboboxsearch( false, $this->render_from_template('core_group/comboboxsearch/group_selector', $buttondata), $sbody, 'group-search', 'groupsearchwidget', 'groupsearchdropdown overflow-auto', null, true, $label, 'group', $activegroup ); return $this->render($groupdropdown); } /** * Build the data to render the initials bar filter within the gradebook. * Using this initials selector means you'll have to retain the use of the templates & JS to handle form submission. * If a simple redirect on each selection is desired the standard user_search() within the user renderer is what you are after. * * @param object $course The course object. * @param context $context Our current context. * @param string $slug The slug for the report that called this function. * @return stdClass The data to output. * @deprecated since 4.5. See replacement renderable \core_course\output\actionbar\initials_selector instead. * @todo Final deprecation in Moodle 6.0. See MDL-82421. */ #[\core\attribute\deprecated( replacement: null, since: '4.5', reason: 'See replacement renderable \core_course\output\actionbar\initials_selector.' )] public function initials_selector( object $course, context $context, string $slug ): stdClass { global $SESSION, $COURSE; \core\deprecation::emit_deprecation([$this, __FUNCTION__]); // User search. $searchvalue = optional_param('gpr_search', null, PARAM_NOTAGS); $userid = optional_param('grp_userid', null, PARAM_INT); $url = new moodle_url($slug, ['id' => $course->id]); $firstinitial = $SESSION->gradereport["filterfirstname-{$context->id}"] ?? ''; $lastinitial = $SESSION->gradereport["filtersurname-{$context->id}"] ?? ''; $renderer = $this->page->get_renderer('core_user'); $initialsbar = $renderer->partial_user_search($url, $firstinitial, $lastinitial, true); $currentfilter = ''; if ($firstinitial !== '' && $lastinitial !== '') { $currentfilter = get_string('filterbothactive', 'grades', ['first' => $firstinitial, 'last' => $lastinitial]); } else if ($firstinitial !== '') { $currentfilter = get_string('filterfirstactive', 'grades', ['first' => $firstinitial]); } else if ($lastinitial !== '') { $currentfilter = get_string('filterlastactive', 'grades', ['last' => $lastinitial]); } $this->page->requires->js_call_amd('core_grades/searchwidget/initials', 'init', [$slug, $userid, $searchvalue]); $formdata = (object) [ 'courseid' => $COURSE->id, 'initialsbars' => $initialsbar, ]; $dropdowncontent = $this->render_from_template('core_grades/initials_dropdown_form', $formdata); return (object) [ 'buttoncontent' => $currentfilter !== '' ? $currentfilter : get_string('filterbyname', 'core_grades'), 'buttonheader' => $currentfilter !== '' ? get_string('name') : null, 'dropdowncontent' => $dropdowncontent, ]; } /** * Creates and renders a custom user heading. * * @param stdClass $user The user object. * @param int $courseid The course ID. * @param bool $showbuttons Whether to display buttons (message, add to contacts) within the heading. * @return string The raw HTML to render. */ public function user_heading(stdClass $user, int $courseid, bool $showbuttons = true): string { global $USER; $headingdata = [ 'userprofileurl' => (new moodle_url('/user/view.php', ['id' => $user->id, 'course' => $courseid]))->out(false), 'name' => fullname($user), 'image' => $this->user_picture($user, ['size' => 50, 'link' => false]) ]; if ($showbuttons) { // Generate the data for the 'message' button. $messagelinkattributes = array_map(function($name, $value) { return ['name' => $name, 'value' => $value]; }, array_keys(helper::messageuser_link_params($user->id)), helper::messageuser_link_params($user->id)); $messagelinkattributes[] = ['name' => 'class', 'value' => 'btn px-0']; $headingdata['buttons'][] = [ 'title' => get_string('message', 'message'), 'url' => (new moodle_url('/message/index.php', ['id' => $user->id]))->out(false), 'icon' => ['name' => 't/message', 'component' => 'core'], 'linkattributes' => $messagelinkattributes ]; // Include js for messaging. helper::messageuser_requirejs(); if ($USER->id != $user->id) { // Generate the data for the 'contact' button. $iscontact = api::is_contact($USER->id, $user->id); $contacttitle = $iscontact ? 'removefromyourcontacts' : 'addtoyourcontacts'; $contacturlaction = $iscontact ? 'removecontact' : 'addcontact'; $contacticon = $iscontact ? 't/removecontact' : 't/addcontact'; $togglelinkparams = helper::togglecontact_link_params($user, $iscontact, false); $togglecontactlinkattributes = array_map(function($name, $value) { if ($name === 'class') { $value .= ' btn px-0'; } return ['name' => $name, 'value' => $value]; }, array_keys($togglelinkparams), $togglelinkparams); $headingdata['buttons'][] = [ 'title' => get_string($contacttitle, 'message'), 'url' => (new moodle_url('/message/index.php', ['user1' => $USER->id, 'user2' => $user->id, $contacturlaction => $user->id, 'sesskey' => sesskey()]))->out(false), 'icon' => ['name' => $contacticon, 'component' => 'core'], 'linkattributes' => $togglecontactlinkattributes ]; // Include js for contact toggle. helper::togglecontact_requirejs(); } } return $this->render_from_template('core_grades/user_heading', $headingdata); } /** * Renders the penalty indicator. * * @param penalty_indicator $penaltyindicator * @return string The HTML output */ public function render_penalty_indicator(penalty_indicator $penaltyindicator): string { $data = $penaltyindicator->export_for_template($this); return $this->render_from_template($penaltyindicator->get_template(), $data); } } home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/auth/lti/classes/output/renderer.php000064400000007377152266761160025760 0ustar00. namespace auth_lti\output; use core\output\notification; /** * Renderer class for auth_lti. * * @package auth_lti * @copyright 2021 Jake Dallimore * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class renderer extends \plugin_renderer_base { /** * Render the account options view, displayed to instructors on first launch if no account binding exists. * * @param int $provisioningmode the desired account provisioning mode, see auth_plugin_lti constants for details. * @return string the html. */ public function render_account_binding_options_page(int $provisioningmode): string { $formaction = new \moodle_url('/auth/lti/login.php'); $notification = new notification(get_string('firstlaunchnotice', 'auth_lti'), \core\notification::INFO, false); $cancreateaccounts = !get_config('moodle', 'authpreventaccountcreation'); if ($provisioningmode == \auth_plugin_lti::PROVISIONING_MODE_PROMPT_EXISTING_ONLY) { $cancreateaccounts = false; } $accountinfo = []; if (isloggedin()) { global $USER; $accountinfo = [ 'firstname' => $USER->firstname, 'lastname' => $USER->lastname, 'email' => $USER->email, 'picturehtml' => $this->output->user_picture($USER, ['size' => 35, 'class' => 'round']), ]; } $context = [ 'isloggedin' => isloggedin(), 'info' => $notification->export_for_template($this), 'formaction' => $formaction->out(), 'sesskey' => sesskey(), 'accountinfo' => $accountinfo, 'cancreateaccounts' => $cancreateaccounts, ]; return parent::render_from_template('auth_lti/local/ltiadvantage/login', $context); } /** * Render the page displayed when the account binding is complete, letting the user continue to the launch. * * Callers can provide different messages depending on which type of binding took place. For example, a newly * provisioned account may require a slightly different message to an existing account being linked. * * The return URL is the page the user will be taken back to when they click 'Continue'. This is likely the launch * or deeplink launch endpoint but could be any calling code in LTI which wants to use the account binding workflow. * * @param notification $notification the notification containing the message describing the binding success. * @param \moodle_url $returnurl the URL to return to when the user clicks continue on the rendered page. * @return string the rendered HTML */ public function render_account_binding_complete(notification $notification, \moodle_url $returnurl): string { $context = (object) [ 'notification' => $notification->export_for_template($this), 'returnurl' => $returnurl->out() ]; return parent::render_from_template('auth_lti/local/ltiadvantage/account_binding_complete', $context); } } home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/mod/data/renderer.php000064400000030554152267010060022676 0ustar00. /** * Database activity renderer. * * @copyright 2010 Sam Hemelryk * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @package mod_data */ use mod_data\manager; defined('MOODLE_INTERNAL') || die(); class mod_data_renderer extends plugin_renderer_base { /** * @deprecated since Moodle 4.1 MDL-75140 - please do not use this class any more. */ #[\core\attribute\deprecated('mod_data_renderer::importing_preset()', since: '4.1', mdl: 'MDL-75140', final: true)] public function import_setting_mappings(): void { \core\deprecation::emit_deprecation([self::class, __FUNCTION__]); } /** * Importing a preset on a database module. * * @param stdClass $datamodule Database module to import to. * @param \mod_data\local\importer\preset_importer $importer Importer instance to use for the importing. * * @return string */ public function importing_preset(stdClass $datamodule, \mod_data\local\importer\preset_importer $importer): string { $strwarning = get_string('mappingwarning', 'data'); $params = $importer->settings; $newfields = $params->importfields; $currentfields = $params->currentfields; $html = html_writer::start_tag('div', ['class' => 'presetmapping']); $html .= html_writer::start_tag('form', ['method' => 'post', 'action' => '']); $html .= html_writer::start_tag('div'); $html .= html_writer::empty_tag('input', ['type' => 'hidden', 'name' => 'action', 'value' => 'finishimport']); $html .= html_writer::empty_tag('input', ['type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey()]); $html .= html_writer::empty_tag('input', ['type' => 'hidden', 'name' => 'd', 'value' => $datamodule->id]); $inputselector = $importer->get_preset_selector(); $html .= html_writer::empty_tag( 'input', ['type' => 'hidden', 'name' => $inputselector['name'], 'value' => $inputselector['value']] ); if (!empty($newfields)) { $table = new html_table(); $table->data = array(); foreach ($newfields as $nid => $newfield) { $row = array(); $row[0] = html_writer::tag('label', $newfield->name, array('for'=>'id_'.$newfield->name)); $attrs = ['name' => 'field_' . $nid, 'id' => 'id_' . $newfield->name, 'class' => 'form-select']; $row[1] = html_writer::start_tag('select', $attrs); $selected = false; foreach ($currentfields as $cid => $currentfield) { if ($currentfield->type != $newfield->type) { continue; } if ($currentfield->name == $newfield->name) { $row[1] .= html_writer::tag( 'option', get_string('mapexistingfield', 'data', $currentfield->name), ['value' => $cid, 'selected' => 'selected'] ); $selected = true; } else { $row[1] .= html_writer::tag( 'option', get_string('mapexistingfield', 'data', $currentfield->name), ['value' => $cid] ); } } if ($selected) { $row[1] .= html_writer::tag('option', get_string('mapnewfield', 'data'), array('value'=>'-1')); } else { $row[1] .= html_writer::tag('option', get_string('mapnewfield', 'data'), array('value'=>'-1', 'selected'=>'selected')); } $row[1] .= html_writer::end_tag('select'); $table->data[] = $row; } $html .= html_writer::table($table); $html .= html_writer::tag('p', $strwarning); } else { $html .= $this->output->notification(get_string('nodefinedfields', 'data')); } $html .= html_writer::start_tag('div', array('class'=>'overwritesettings')); $attrs = ['type' => 'checkbox', 'name' => 'overwritesettings', 'id' => 'overwritesettings', 'class' => 'me-2']; $html .= html_writer::empty_tag('input', $attrs); $html .= html_writer::tag('label', get_string('overwritesettings', 'data'), ['for' => 'overwritesettings']); $html .= html_writer::end_tag('div'); $actionbuttons = html_writer::start_div(); $cancelurl = new moodle_url('/mod/data/field.php', ['d' => $datamodule->id]); $actionbuttons .= html_writer::tag('a', get_string('cancel') , [ 'href' => $cancelurl->out(false), 'class' => 'btn btn-secondary mx-1', 'role' => 'button', ]); $actionbuttons .= html_writer::empty_tag('input', [ 'type' => 'submit', 'class' => 'btn btn-primary mx-1', 'value' => get_string('continue'), ]); $actionbuttons .= html_writer::end_div(); $stickyfooter = new core\output\sticky_footer($actionbuttons); $html .= $this->render($stickyfooter); $html .= html_writer::end_tag('div'); $html .= html_writer::end_tag('form'); $html .= html_writer::end_tag('div'); return $html; } /** * Renders the action bar for the field page. * * @param \mod_data\output\fields_action_bar $actionbar * @return string The HTML output */ public function render_fields_action_bar(\mod_data\output\fields_action_bar $actionbar): string { $data = $actionbar->export_for_template($this); return $this->render_from_template('mod_data/action_bar', $data); } /** * Renders the fields page footer. * * @param manager $manager the instance manager * @return string The HTML output * * @deprecated since Moodle 4.5 - please do not use this function anymore */ #[\core\attribute\deprecated(null, reason: 'It is no longer used', since: '4.5')] public function render_fields_footer(manager $manager): string { \core\deprecation::emit_deprecation([self::class, __FUNCTION__]); $cm = $manager->get_coursemodule(); $pageurl = new moodle_url('/mod/data/templates.php', ['id' => $cm->id]); return $this->render_from_template('mod_data/fields_footer', [ 'pageurl' => $pageurl->out(false), ]); } /** * Renders the action bar for the view page. * * @param \mod_data\output\view_action_bar $actionbar * @return string The HTML output */ public function render_view_action_bar(\mod_data\output\view_action_bar $actionbar): string { $data = $actionbar->export_for_template($this); return $this->render_from_template('mod_data/view_action_bar', $data); } /** * Renders the action bar for the template page. * * @param \mod_data\output\templates_action_bar $actionbar * @return string The HTML output */ public function render_templates_action_bar(\mod_data\output\templates_action_bar $actionbar): string { $data = $actionbar->export_for_template($this); return $this->render_from_template('mod_data/templates_action_bar', $data); } /** * Renders the action bar for the preset page. * * @param \mod_data\output\presets_action_bar $actionbar * @return string The HTML output */ public function render_presets_action_bar(\mod_data\output\presets_action_bar $actionbar): string { $data = $actionbar->export_for_template($this); return $this->render_from_template('mod_data/presets_action_bar', $data); } /** * Renders the presets table in the preset page. * * @param \mod_data\output\presets $presets * @return string The HTML output */ public function render_presets(\mod_data\output\presets $presets): string { $data = $presets->export_for_template($this); return $this->render_from_template('mod_data/presets', $data); } /** * Renders the default template. * * @param \mod_data\output\defaulttemplate $template * @return string The HTML output */ public function render_defaulttemplate(\mod_data\output\defaulttemplate $template): string { $data = $template->export_for_template($this); return $this->render_from_template($template->get_templatename(), $data); } /** * Renders the action bar for the zero state (no fields created) page. * * @param \mod_data\manager $manager The manager instance. * * @return string The HTML output */ public function render_database_zero_state(\mod_data\manager $manager): string { $actionbar = new \mod_data\output\zero_state_action_bar($manager); $data = $actionbar->export_for_template($this); if (empty($data)) { // No actions for the user. $data['title'] = get_string('activitynotready'); $data['intro'] = get_string('comebacklater'); $data['noitemsimgurl'] = $this->output->image_url('noentries_zero_state', 'mod_data')->out(); } else { $data['title'] = get_string('startbuilding', 'mod_data'); $data['intro'] = get_string('createactivity', 'mod_data'); $data['noitemsimgurl'] = $this->output->image_url('view_zero_state', 'mod_data')->out(); } return $this->render_from_template('mod_data/zero_state', $data); } /** * Renders the action bar for an empty database view page. * * @param \mod_data\manager $manager The manager instance. * * @return string The HTML output */ public function render_empty_database(\mod_data\manager $manager): string { $actionbar = new \mod_data\output\empty_database_action_bar($manager); $data = $actionbar->export_for_template($this); $data['noitemsimgurl'] = $this->output->image_url('view_zero_state', 'mod_data')->out(); return $this->render_from_template('mod_data/view_noentries', $data); } /** * Renders the action bar for the zero state (no fields created) page. * * @param \mod_data\manager $manager The manager instance. * * @return string The HTML output */ public function render_fields_zero_state(\mod_data\manager $manager): string { $data = [ 'noitemsimgurl' => $this->output->image_url('fields_zero_state', 'mod_data')->out(), 'title' => get_string('nofields', 'mod_data'), 'intro' => get_string('createfields', 'mod_data'), ]; if ($manager->can_manage_templates()) { $actionbar = new \mod_data\output\action_bar($manager->get_instance()->id, $this->page->url); $createfieldbutton = $actionbar->get_create_fields(); $data['createfieldbutton'] = $createfieldbutton->export_for_template($this); } return $this->render_from_template('mod_data/zero_state', $data); } /** * Renders the action bar for the templates zero state (no fields created) page. * * @param \mod_data\manager $manager The manager instance. * * @return string The HTML output */ public function render_templates_zero_state(\mod_data\manager $manager): string { $actionbar = new \mod_data\output\zero_state_action_bar($manager); $data = $actionbar->export_for_template($this); $data['title'] = get_string('notemplates', 'mod_data'); $data['intro'] = get_string('createtemplates', 'mod_data'); $data['noitemsimgurl'] = $this->output->image_url('templates_zero_state', 'mod_data')->out(); return $this->render_from_template('mod_data/zero_state', $data); } } home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/mod/subsection/renderer.php000064400000001664152267014750024155 0ustar00. /** * Subsection activity renderer. * * @copyright 2023 Amaia Anabitarte * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @package mod_subsection */ class mod_subsection_renderer extends plugin_renderer_base { } home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/mod/wiki/renderer.php000064400000062715152267057630022752 0ustar00. /** * Moodle Wiki 2.0 Renderer * * @package mod_wiki * @copyright 2010 Dongsheng Cai * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); class mod_wiki_renderer extends plugin_renderer_base { public function page_index() { global $CFG; $output = ''; // Checking wiki instance if (!$wiki = wiki_get_wiki($this->page->cm->instance)) { return false; } // @TODO: Fix call to wiki_get_subwiki_by_group $gid = groups_get_activity_group($this->page->cm); $gid = !empty($gid) ? $gid : 0; if (!$subwiki = wiki_get_subwiki_by_group($this->page->cm->instance, $gid)) { return false; } $swid = $subwiki->id; $pages = wiki_get_page_list($swid); $selectoptions = array(); foreach ($pages as $page) { $selectoptions[$page->id] = format_string($page->title, true, array('context' => $this->page->context)); } $label = get_string('pageindex', 'wiki') . ': '; $select = new single_select(new moodle_url('/mod/wiki/view.php'), 'pageid', $selectoptions); $select->label = $label; return $this->output->container($this->output->render($select), 'wiki_index'); } public function search_result($records, $subwiki) { global $CFG; $table = new html_table(); $context = context_module::instance($this->page->cm->id); $strsearchresults = get_string('searchresult', 'wiki'); $totalcount = count($records); $html = $this->output->heading("$strsearchresults $totalcount", 3); foreach ($records as $page) { $table->head = array('title' => format_string($page->title) . ' (' . html_writer::link($CFG->wwwroot . '/mod/wiki/view.php?pageid=' . $page->id, get_string('view', 'wiki')) . ')'); $table->align = array('title' => 'left'); $table->width = '100%'; $table->data = array(array(file_rewrite_pluginfile_urls(format_text($page->cachedcontent, FORMAT_HTML), 'pluginfile.php', $context->id, 'mod_wiki', 'attachments', $subwiki->id))); $table->colclasses = array('wikisearchresults'); $html .= html_writer::table($table); } $html = html_writer::tag('div', $html, array('class'=>'no-overflow')); return $this->output->container($html); } public function diff($pageid, $old, $new, $options = array()) { global $CFG; if (!empty($options['total'])) { $total = $options['total']; } else { $total = 0; } $diff1 = format_text($old->diff, FORMAT_HTML, array('overflowdiv'=>true)); $diff2 = format_text($new->diff, FORMAT_HTML, array('overflowdiv'=>true)); $strdatetime = get_string('strftimedatetime', 'langconfig'); $olduser = $old->user; $versionlink = new moodle_url('/mod/wiki/viewversion.php', array('pageid' => $pageid, 'versionid' => $old->id)); $restorelink = new moodle_url('/mod/wiki/restoreversion.php', array('pageid' => $pageid, 'versionid' => $old->id)); $userlink = new moodle_url('/user/view.php', array('id' => $olduser->id)); // view version link $oldversionview = ' '; $oldversionview .= html_writer::link($versionlink->out(false), get_string('view', 'wiki'), array('class' => 'wiki_diffview')); $oldversionview .= ' '; // restore version link $oldversionview .= html_writer::link($restorelink->out(false), get_string('restore', 'wiki'), array('class' => 'wiki_diffview')); // userinfo container $oldheading = $this->output->container_start('wiki_diffuserleft'); // username $oldheading .= html_writer::link($CFG->wwwroot . '/user/view.php?id=' . $olduser->id, fullname($olduser)) . ' '; // user picture $oldheading .= html_writer::link($userlink->out(false), $this->output->user_picture($olduser, array('popup' => true)), array('class' => 'notunderlined')); $oldheading .= $this->output->container_end(); // version number container $oldheading .= $this->output->container_start('wiki_diffversion'); $oldheading .= get_string('version') . ' ' . $old->version . $oldversionview; $oldheading .= $this->output->container_end(); // userdate container $oldheading .= $this->output->container_start('wiki_difftime'); $oldheading .= userdate($old->timecreated, $strdatetime); $oldheading .= $this->output->container_end(); $newuser = $new->user; $versionlink = new moodle_url('/mod/wiki/viewversion.php', array('pageid' => $pageid, 'versionid' => $new->id)); $restorelink = new moodle_url('/mod/wiki/restoreversion.php', array('pageid' => $pageid, 'versionid' => $new->id)); $userlink = new moodle_url('/user/view.php', array('id' => $newuser->id)); $newversionview = ' '; $newversionview .= html_writer::link($versionlink->out(false), get_string('view', 'wiki'), array('class' => 'wiki_diffview')); // new user info $newheading = $this->output->container_start('wiki_diffuserright'); $newheading .= $this->output->user_picture($newuser, array('popup' => true)); $newheading .= html_writer::link($userlink->out(false), fullname($newuser), array('class' => 'notunderlined')); $newheading .= $this->output->container_end(); // version $newheading .= $this->output->container_start('wiki_diffversion'); $newheading .= get_string('version') . ' ' . $new->version . $newversionview; $newheading .= $this->output->container_end(); // userdate $newheading .= $this->output->container_start('wiki_difftime'); $newheading .= userdate($new->timecreated, $strdatetime); $newheading .= $this->output->container_end(); $oldheading = html_writer::tag('div', $oldheading, array('class'=>'wiki-diff-heading header clearfix')); $newheading = html_writer::tag('div', $newheading, array('class'=>'wiki-diff-heading header clearfix')); $output = ''; $output .= html_writer::start_tag('div', array('class'=>'wiki-diff-container clearfix')); $output .= html_writer::tag('div', $oldheading.$diff1, array('class'=>'wiki-diff-leftside')); $output .= html_writer::tag('div', $newheading.$diff2, array('class'=>'wiki-diff-rightside')); $output .= html_writer::end_tag('div'); if (!empty($total)) { $output .= '
'; $output .= $this->output->container($this->diff_paging_bar(1, $new->version - 1, $old->version, $CFG->wwwroot . '/mod/wiki/diff.php?pageid=' . $pageid . '&comparewith=' . $new->version . '&', 'compare', false, true), 'wiki_diff_oldpaging'); $output .= $this->output->container($this->diff_paging_bar($old->version + 1, $total, $new->version, $CFG->wwwroot . '/mod/wiki/diff.php?pageid=' . $pageid . '&compare=' . $old->version . '&', 'comparewith', false, true), 'wiki_diff_newpaging'); $output .= '
'; } return $output; } /** * Prints a single paging bar to provide access to other versions * * @param int $minpage First page to be displayed in the bar * @param int $maxpage Last page to be displayed in the bar * @param int $page The page you are currently viewing * @param mixed $baseurl If this is a string then it is the url which will be appended with $pagevar, an equals sign and the page number. * If this is a moodle_url object then the pagevar param will be replaced by the page no, for each page. * @param string $pagevar This is the variable name that you use for the page number in your code (ie. 'tablepage', 'blogpage', etc) * @param bool $nocurr do not display the current page as a link * @param bool $return whether to return an output string or echo now * @return bool or string */ public function diff_paging_bar($minpage, $maxpage, $page, $baseurl, $pagevar = 'page', $nocurr = false) { $totalcount = $maxpage - $minpage; $maxdisplay = 2; $output = ''; if ($totalcount > 0) { $output .= '
'; $output .= get_string('version', 'wiki') . ':'; if ($page - $minpage > 0) { $pagenum = $page - 1; if (!is_a($baseurl, 'moodle_url')) { $output .= ' () '; } else { $output .= ' () '; } } if ($page - $minpage > 4) { $startpage = $page - 3; if (!is_a($baseurl, 'moodle_url')) { $output .= ' ' . $minpage . ' ...'; } else { $output .= ' ' . $minpage . ' ...'; } } else { $startpage = $minpage; } $currpage = $startpage; $displaycount = 0; while ($displaycount < $maxdisplay and $currpage <= $maxpage) { if ($page == $currpage && empty($nocurr)) { $output .= '  ' . $currpage; } else { if (!is_a($baseurl, 'moodle_url')) { $output .= '  ' . $currpage . ''; } else { $output .= '  ' . $currpage . ''; } } $displaycount++; $currpage++; } if ($currpage < $maxpage) { if (!is_a($baseurl, 'moodle_url')) { $output .= ' ...' . $maxpage . ' '; } else { $output .= ' ...' . $maxpage . ' '; } } else if ($currpage == $maxpage) { if (!is_a($baseurl, 'moodle_url')) { $output .= '  ' . $currpage . ''; } else { $output .= '  ' . $currpage . ''; } } $pagenum = $page + 1; if ($page != $maxpage) { if (!is_a($baseurl, 'moodle_url')) { $output .= '  ()'; } else { $output .= '  ()'; } } $output .= '
'; } return $output; } /** * @deprecated since Moodle 4.0 MDL-72413. Now handled in PAGE's activity header */ #[\core\attribute\deprecated(null, since: '4.3', mdl: 'MDL-72413', final: true)] public function wiki_info() { \core\deprecation::emit_deprecation([self::class, __FUNCTION__]); } public function tabs($page, $tabitems, $options) { $tabs = array(); $context = context_module::instance($this->page->cm->id); $pageid = null; if (!empty($page)) { $pageid = $page->id; } $selected = $options['activetab']; // make specific tab linked even it is active if (!empty($options['linkedwhenactive'])) { $linked = $options['linkedwhenactive']; } else { $linked = ''; } if (!empty($options['inactivetabs'])) { $inactive = $options['inactivetabs']; } else { $inactive = array(); } foreach ($tabitems as $tab) { if ($tab == 'edit' && !has_capability('mod/wiki:editpage', $context)) { continue; } if ($tab == 'comments' && !has_capability('mod/wiki:viewcomment', $context)) { continue; } if ($tab == 'files' && !has_capability('mod/wiki:viewpage', $context)) { continue; } if (($tab == 'view' || $tab == 'map' || $tab == 'history') && !has_capability('mod/wiki:viewpage', $context)) { continue; } if ($tab == 'admin' && !has_capability('mod/wiki:managewiki', $context)) { continue; } $link = new moodle_url('/mod/wiki/'. $tab. '.php', array('pageid' => $pageid)); if ($linked == $tab) { $tabs[] = new tabobject($tab, $link, get_string($tab, 'wiki'), '', true); } else { $tabs[] = new tabobject($tab, $link, get_string($tab, 'wiki')); } } return $this->tabtree($tabs, $selected, $inactive); } public function prettyview_link($page) { $html = ''; $link = new moodle_url('/mod/wiki/prettyview.php', array('pageid' => $page->id)); $html .= $this->output->container_start('wiki_right'); $html .= $this->output->action_link($link, get_string('prettyprint', 'wiki'), new popup_action('click', $link), array('class' => 'printicon')); $html .= $this->output->container_end(); return $html; } public function wiki_print_subwiki_selector($wiki, $subwiki, $page, $pagetype = 'view') { global $CFG, $USER; require_once($CFG->dirroot . '/user/lib.php'); $cm = get_coursemodule_from_instance('wiki', $wiki->id); switch ($pagetype) { case 'files': $baseurl = new moodle_url('/mod/wiki/files.php', array('wid' => $wiki->id, 'title' => $page->title, 'pageid' => $page->id)); break; case 'search': $search = optional_param('searchstring', null, PARAM_TEXT); $searchcontent = optional_param('searchwikicontent', 0, PARAM_INT); $baseurl = new moodle_url('/mod/wiki/search.php', array('cmid' => $cm->id, 'courseid' => $cm->course, 'searchstring' => $search, 'searchwikicontent' => $searchcontent)); break; case 'view': default: $baseurl = new moodle_url('/mod/wiki/view.php', array('wid' => $wiki->id, 'title' => $page->title)); break; } $context = context_module::instance($cm->id); // @TODO: A plenty of duplicated code below this lines. // Create private functions. switch (groups_get_activity_groupmode($cm)) { case NOGROUPS: if ($wiki->wikimode == 'collaborative') { // No need to print anything return; } else if ($wiki->wikimode == 'individual') { // We have private wikis here $view = has_capability('mod/wiki:viewpage', $context); $manage = has_capability('mod/wiki:managewiki', $context); // Only people with these capabilities can view all wikis if ($view && $manage) { // @TODO: Print here a combo that contains all users. $users = get_enrolled_users($context); $options = array(); foreach ($users as $user) { $options[$user->id] = fullname($user); } echo $this->output->container_start('wiki_right'); $name = 'uid'; $selected = $subwiki->userid; echo $this->output->single_select($baseurl, $name, $options, $selected, null, null, array('label' => get_string('user') . ':')); echo $this->output->container_end(); } return; } else { // error return; } case SEPARATEGROUPS: if ($wiki->wikimode == 'collaborative') { // We need to print a select to choose a course group echo $this->output->container_start('wiki_right'); groups_print_activity_menu($cm, $baseurl); echo $this->output->container_end(); return; } else if ($wiki->wikimode == 'individual') { // @TODO: Print here a combo that contains all users of that subwiki. $view = has_capability('mod/wiki:viewpage', $context); $manage = has_capability('mod/wiki:managewiki', $context); // Only people with these capabilities can view all wikis if ($view && $manage) { $users = get_enrolled_users($context); $options = array(); foreach ($users as $user) { $groups = groups_get_all_groups($cm->course, $user->id); if (!empty($groups)) { foreach ($groups as $group) { $options[$group->id][$group->name][$group->id . '-' . $user->id] = fullname($user); } } else { $name = get_string('notingroup', 'wiki'); $options[0][$name]['0' . '-' . $user->id] = fullname($user); } } } else { $group = groups_get_group($subwiki->groupid); if (!$group) { return; } $users = groups_get_members($subwiki->groupid); foreach ($users as $user) { $options[$group->id][$group->name][$group->id . '-' . $user->id] = fullname($user); } } echo $this->output->container_start('wiki_right'); $name = 'groupanduser'; $selected = $subwiki->groupid . '-' . $subwiki->userid; echo $this->output->single_select($baseurl, $name, $options, $selected, null, null, array('label' => get_string('user') . ':')); echo $this->output->container_end(); return; } else { // error return; } CASE VISIBLEGROUPS: if ($wiki->wikimode == 'collaborative') { // We need to print a select to choose a course group // moodle_url will take care of encoding for us echo $this->output->container_start('wiki_right'); groups_print_activity_menu($cm, $baseurl); echo $this->output->container_end(); return; } else if ($wiki->wikimode == 'individual') { $users = get_enrolled_users($context); $options = array(); foreach ($users as $user) { $groups = groups_get_all_groups($cm->course, $user->id); if (!empty($groups)) { foreach ($groups as $group) { $options[$group->id][$group->name][$group->id . '-' . $user->id] = fullname($user); } } else { $name = get_string('notingroup', 'wiki'); $options[0][$name]['0' . '-' . $user->id] = fullname($user); } } echo $this->output->container_start('wiki_right'); $name = 'groupanduser'; $selected = $subwiki->groupid . '-' . $subwiki->userid; echo $this->output->single_select($baseurl, $name, $options, $selected, null, null, array('label' => get_string('user') . ':')); echo $this->output->container_end(); return; } else { // error return; } default: // error return; } } function menu_map($pageid, $currentselect) { if (empty($currentselect)) { // The wiki uses digit number to match the options and 5 is the default one. $currentselect = 5; } $options = array('contributions', 'links', 'orphaned', 'pageindex', 'pagelist', 'updatedpages'); $items = array(); foreach ($options as $opt) { $items[] = get_string($opt, 'wiki'); } $selectoptions = array(); foreach ($items as $key => $item) { $selectoptions[$key + 1] = $item; } $select = new single_select(new moodle_url('/mod/wiki/map.php', array('pageid' => $pageid)), 'option', $selectoptions, $currentselect, null); $select->label = get_string('mapmenu', 'wiki') . ': '; return $this->output->container($this->output->render($select), 'midpad'); } public function wiki_files_tree($context, $subwiki) { return $this->render(new wiki_files_tree($context, $subwiki)); } public function render_wiki_files_tree(wiki_files_tree $tree) { if (empty($tree->dir['subdirs']) && empty($tree->dir['files'])) { $html = $this->output->box(get_string('nofilesavailable', 'repository')); } else { $htmlid = 'wiki_files_tree_'.uniqid(); $module = array('name'=>'mod_wiki', 'fullpath'=>'/mod/wiki/module.js'); $this->page->requires->js_init_call('M.mod_wiki.init_tree', array(false, $htmlid), false, $module); $html = '
'; $html .= $this->htmllize_tree($tree, $tree->dir); $html .= '
'; } return $html; } function menu_admin($pageid, $currentselect) { $options = array('removepages', 'deleteversions'); $items = array(); foreach ($options as $opt) { $items[] = get_string($opt, 'wiki'); } $selectoptions = array(); foreach ($items as $key => $item) { $selectoptions[$key + 1] = $item; } $select = new single_select(new moodle_url('/mod/wiki/admin.php', array('pageid' => $pageid)), 'option', $selectoptions, $currentselect, null); $select->label = get_string('adminmenu', 'wiki') . ': '; return $this->output->container($this->output->render($select), 'midpad'); } /** * Internal function - creates htmls structure suitable for YUI tree. */ protected function htmllize_tree($tree, $dir) { global $CFG; $yuiconfig = array(); $yuiconfig['type'] = 'html'; if (empty($dir['subdirs']) and empty($dir['files'])) { return ''; } $result = '
    '; foreach ($dir['subdirs'] as $subdir) { $image = $this->output->pix_icon(file_folder_icon(), $subdir['dirname'], 'moodle', array('class'=>'icon')); $result .= '
  • '.$image.' '.s($subdir['dirname']).'
    '.$this->htmllize_tree($tree, $subdir).'
  • '; } foreach ($dir['files'] as $file) { $url = file_encode_url("$CFG->wwwroot/pluginfile.php", '/'.$tree->context->id.'/mod_wiki/attachments/' . $tree->subwiki->id . '/'. $file->get_filepath() . $file->get_filename(), true); $filename = $file->get_filename(); $image = $this->output->pix_icon(file_file_icon($file), $filename, 'moodle', array('class'=>'icon')); $result .= '
  • '.$image.' '.html_writer::link($url, $filename).'
  • '; } $result .= '
'; return $result; } /** * Renders the action bar. * * @param \mod_wiki\output\action_bar $actionbar * @return string The HTML output */ public function render_action_bar(\mod_wiki\output\action_bar $actionbar): string { $data = $actionbar->export_for_template($this); return $this->render_from_template('mod_wiki/action_bar', $data); } } class wiki_files_tree implements renderable { public $context; public $dir; public $subwiki; public function __construct($context, $subwiki) { $fs = get_file_storage(); $this->context = $context; $this->subwiki = $subwiki; $this->dir = $fs->get_area_tree($context->id, 'mod_wiki', 'attachments', $subwiki->id); } } home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/mod/choice/renderer.php000064400000043470152267104270023227 0ustar00. /** * Moodle renderer used to display special elements of the lesson module * * @package mod_choice * @copyright 2010 Rossiani Wijaya * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later **/ class mod_choice_renderer extends plugin_renderer_base { /** * Returns HTML to display choices of option * @param object $options * @param int $coursemoduleid * @param bool $vertical * @return string */ public function display_options($options, $coursemoduleid, $vertical = false, $multiple = false) { $layoutclass = 'horizontal'; if ($vertical) { $layoutclass = 'vertical'; } $target = new moodle_url('/mod/choice/view.php'); $attributes = array('method'=>'POST', 'action'=>$target, 'class'=> $layoutclass); $disabled = empty($options['previewonly']) ? array() : array('disabled' => 'disabled'); $html = html_writer::start_tag('form', $attributes); $html .= html_writer::start_tag('ul', array('class' => 'choices list-unstyled unstyled')); $availableoption = count($options['options']); $choicecount = 0; foreach ($options['options'] as $option) { $choicecount++; $html .= html_writer::start_tag('li', array('class' => 'option me-3')); if ($multiple) { $option->attributes->name = 'answer[]'; $option->attributes->type = 'checkbox'; } else { $option->attributes->name = 'answer'; $option->attributes->type = 'radio'; } $option->attributes->id = 'choice_'.$choicecount; $option->attributes->class = 'mx-1'; $labeltext = $option->text; if (!empty($option->attributes->disabled)) { $labeltext .= ' ' . get_string('full', 'choice'); $availableoption--; } if (!empty($options['limitanswers']) && !empty($options['showavailable'])) { $labeltext .= html_writer::empty_tag('br'); $labeltext .= get_string("responsesa", "choice", $option->countanswers); $labeltext .= html_writer::empty_tag('br'); $labeltext .= get_string("limita", "choice", $option->maxanswers); } $html .= html_writer::empty_tag('input', (array)$option->attributes + $disabled); $html .= html_writer::tag('label', $labeltext, array('for'=>$option->attributes->id)); $html .= html_writer::end_tag('li'); } $html .= html_writer::tag('li','', array('class'=>'clearfloat')); $html .= html_writer::end_tag('ul'); $html .= html_writer::tag('div', '', array('class'=>'clearfloat')); $html .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'sesskey', 'value'=>sesskey())); $html .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'action', 'value'=>'makechoice')); $html .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'id', 'value'=>$coursemoduleid)); if (empty($options['previewonly'])) { if (!empty($options['hascapability']) && ($options['hascapability'])) { if ($availableoption < 1) { $html .= html_writer::tag('label', get_string('choicefull', 'choice')); } else { $html .= html_writer::empty_tag('input', array( 'type' => 'submit', 'value' => get_string('savemychoice', 'choice'), 'class' => 'btn btn-primary' )); } if (!empty($options['allowupdate']) && ($options['allowupdate'])) { $url = new moodle_url('view.php', array('id' => $coursemoduleid, 'action' => 'delchoice', 'sesskey' => sesskey())); $html .= html_writer::link($url, get_string('removemychoice', 'choice'), array('class' => 'ms-1')); } } else { $html .= html_writer::tag('label', get_string('havetologin', 'choice')); } } $html .= html_writer::end_tag('form'); return $html; } /** * Returns HTML to display choices result * @param object $choices * @param bool $forcepublish * @return string */ public function display_result($choices, $forcepublish = false) { if (empty($forcepublish)) { //allow the publish setting to be overridden $forcepublish = $choices->publish; } $displaylayout = $choices->display; if ($forcepublish) { //CHOICE_PUBLISH_NAMES return $this->display_publish_name_vertical($choices); } else { return $this->display_publish_anonymous($choices, $displaylayout); } } /** * Returns HTML to display choices result * @param object $choices * @return string */ public function display_publish_name_vertical($choices) { $html =''; $attributes = array('method'=>'POST'); $attributes['action'] = new moodle_url($this->page->url); $attributes['id'] = 'attemptsform'; if ($choices->viewresponsecapability) { $html .= html_writer::start_tag('form', $attributes); $html .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'id', 'value'=> $choices->coursemoduleid)); $html .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'sesskey', 'value'=> sesskey())); $html .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'mode', 'value'=>'overview')); } $table = new html_table(); $table->cellpadding = 0; $table->cellspacing = 0; $table->attributes['class'] = 'results names table table-bordered'; $table->tablealign = 'center'; $table->summary = get_string('responsesto', 'choice', format_string($choices->name)); $table->data = array(); $count = 0; ksort($choices->options); $columns = array(); $celldefault = new html_table_cell(); $celldefault->attributes['class'] = 'data'; // This extra cell is needed in order to support accessibility for screenreader. MDL-30816 $accessiblecell = new html_table_cell(); $accessiblecell->scope = 'row'; $accessiblecell->text = get_string('choiceoptions', 'choice'); $columns['options'][] = $accessiblecell; $usernumberheader = clone($celldefault); $usernumberheader->header = true; $usernumberheader->attributes['class'] = 'header data'; $usernumberheader->text = get_string('numberofuser', 'choice'); $columns['usernumber'][] = $usernumberheader; $optionsnames = []; foreach ($choices->options as $optionid => $options) { $celloption = clone($celldefault); $cellusernumber = clone($celldefault); if ($choices->showunanswered && $optionid == 0) { $headertitle = get_string('notanswered', 'choice'); } else if ($optionid > 0) { $headertitle = format_string($choices->options[$optionid]->text); if (!empty($choices->options[$optionid]->user) && count($choices->options[$optionid]->user) > 0) { if ( $choices->limitanswers && (count($choices->options[$optionid]->user) == $choices->options[$optionid]->maxanswer) ) { $headertitle .= ' ' . get_string('full', 'choice'); } } } $celltext = $headertitle; // Render select/deselect all checkbox for this option. if ($choices->viewresponsecapability && $choices->deleterepsonsecapability) { // Build the select/deselect all for this option. $selectallid = 'select-response-option-' . $optionid; $togglegroup = 'responses response-option-' . $optionid; $selectalltext = get_string('selectalloption', 'choice', $headertitle); $deselectalltext = get_string('deselectalloption', 'choice', $headertitle); $mastercheckbox = new \core\output\checkbox_toggleall($togglegroup, true, [ 'id' => $selectallid, 'name' => $selectallid, 'value' => 1, 'selectall' => $selectalltext, 'deselectall' => $deselectalltext, 'label' => $selectalltext, 'labelclasses' => 'accesshide', ]); $celltext .= html_writer::div($this->output->render($mastercheckbox)); } $numberofuser = 0; if (!empty($options->user) && count($options->user) > 0) { $numberofuser = count($options->user); } if (($choices->limitanswers) && ($choices->showavailable)) { $numberofuser .= html_writer::empty_tag('br'); $numberofuser .= get_string("limita", "choice", $options->maxanswer); } $celloption->text = html_writer::div($celltext, 'text-center'); $optionsnames[$optionid] = $celltext; $cellusernumber->text = html_writer::div($numberofuser, 'text-center'); $columns['options'][] = $celloption; $columns['usernumber'][] = $cellusernumber; } $table->head = $columns['options']; $table->data[] = new html_table_row($columns['usernumber']); $columns = array(); // This extra cell is needed in order to support accessibility for screenreader. MDL-30816 $accessiblecell = new html_table_cell(); $accessiblecell->text = get_string('userchoosethisoption', 'choice'); $accessiblecell->header = true; $accessiblecell->scope = 'row'; $accessiblecell->attributes['class'] = 'header data'; $columns[] = $accessiblecell; foreach ($choices->options as $optionid => $options) { $cell = new html_table_cell(); $cell->attributes['class'] = 'data'; if ($choices->showunanswered || $optionid > 0) { if (!empty($options->user)) { $optionusers = ''; foreach ($options->user as $user) { $data = ''; if (empty($user->imagealt)) { $user->imagealt = ''; } $userfullname = fullname($user, $choices->fullnamecapability); $checkbox = ''; if ($choices->viewresponsecapability && $choices->deleterepsonsecapability) { $checkboxid = 'attempt-user' . $user->id . '-option' . $optionid; if ($optionid > 0) { $checkboxname = 'attemptid[]'; $checkboxvalue = $user->answerid; } else { $checkboxname = 'userid[]'; $checkboxvalue = $user->id; } $togglegroup = 'responses response-option-' . $optionid; $slavecheckbox = new \core\output\checkbox_toggleall($togglegroup, false, [ 'id' => $checkboxid, 'name' => $checkboxname, 'classes' => 'me-1', 'value' => $checkboxvalue, 'label' => $userfullname . ' ' . $options->text, 'labelclasses' => 'accesshide', ]); $checkbox = $this->output->render($slavecheckbox); } $userimage = $this->output->user_picture($user, array('courseid' => $choices->courseid, 'link' => false)); $profileurl = new moodle_url('/user/view.php', array('id' => $user->id, 'course' => $choices->courseid)); $profilelink = html_writer::link($profileurl, $userimage . $userfullname); $data .= html_writer::div($checkbox . $profilelink, 'mb-1'); $optionusers .= $data; } $cell->text = $optionusers; } } $columns[] = $cell; $count++; } $row = new html_table_row($columns); $table->data[] = $row; $html .= html_writer::tag('div', html_writer::table($table), array('class'=>'response')); $actiondata = ''; if ($choices->viewresponsecapability && $choices->deleterepsonsecapability) { // Build the select/deselect all for all of options. $selectallid = 'select-all-responses'; $togglegroup = 'responses'; $selectallcheckbox = new \core\output\checkbox_toggleall($togglegroup, true, [ 'id' => $selectallid, 'name' => $selectallid, 'value' => 1, 'label' => get_string('selectall'), 'classes' => 'btn-secondary me-1' ], true); $actiondata .= $this->output->render($selectallcheckbox); $actionurl = new moodle_url($this->page->url, ['sesskey' => sesskey(), 'action' => 'delete_confirmation()']); $actionoptions = array('delete' => get_string('delete')); foreach ($choices->options as $optionid => $option) { if ($optionid > 0) { $actionoptions['choose_'.$optionid] = get_string('chooseoption', 'choice', $option->text); } } $selectattributes = [ 'data-action' => 'toggle', 'data-togglegroup' => 'responses', 'data-toggle' => 'action', ]; $selectnothing = ['' => get_string('chooseaction', 'choice')]; $select = new single_select($actionurl, 'action', $actionoptions, null, $selectnothing, 'attemptsform'); $select->set_label(get_string('withselected', 'choice')); $select->disabled = true; $select->attributes = $selectattributes; $actiondata .= $this->output->render($select); } $html .= html_writer::tag('div', $actiondata, array('class'=>'responseaction')); if ($choices->viewresponsecapability) { $html .= html_writer::end_tag('form'); } return $html; } /** * Returns HTML to display choices result * @deprecated since 3.2 * @param object $choices * @return string */ public function display_publish_anonymous_horizontal($choices) { debugging(__FUNCTION__.'() is deprecated. Please use mod_choice_renderer::display_publish_anonymous() instead.', DEBUG_DEVELOPER); return $this->display_publish_anonymous($choices, CHOICE_DISPLAY_VERTICAL); } /** * Returns HTML to display choices result * @deprecated since 3.2 * @param object $choices * @return string */ public function display_publish_anonymous_vertical($choices) { debugging(__FUNCTION__.'() is deprecated. Please use mod_choice_renderer::display_publish_anonymous() instead.', DEBUG_DEVELOPER); return $this->display_publish_anonymous($choices, CHOICE_DISPLAY_HORIZONTAL); } /** * Generate the choice result chart. * * Can be displayed either in the vertical or horizontal position. * * @param stdClass $choices Choices responses object. * @param int $displaylayout The constants CHOICE_DISPLAY_HORIZONTAL or CHOICE_DISPLAY_VERTICAL. * @return string the rendered chart. */ public function display_publish_anonymous($choices, $displaylayout) { $count = 0; $data = []; $numberofuser = 0; $percentageamount = 0; foreach ($choices->options as $optionid => $option) { if (!empty($option->user)) { $numberofuser = count($option->user); } if($choices->numberofuser > 0) { $percentageamount = ((float)$numberofuser / (float)$choices->numberofuser) * 100.0; } $data['labels'][$count] = $option->text; $data['series'][$count] = $numberofuser; $data['series_labels'][$count] = $numberofuser . ' (' . format_float($percentageamount, 1) . '%)'; $count++; $numberofuser = 0; } $chart = new \core\chart_bar(); if ($displaylayout == CHOICE_DISPLAY_VERTICAL) { $chart->set_horizontal(true); // Horizontal bars when choices are vertical. } $series = new \core\chart_series(format_string(get_string("responses", "choice")), $data['series']); $series->set_labels($data['series_labels']); $chart->add_series($series); $chart->set_labels($data['labels']); $yaxis = $chart->get_yaxis(0, true); $yaxis->set_stepsize(max(1, round(max($data['series']) / 10))); return $this->output->render($chart); } } home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/mod/folder/renderer.php000064400000015570152267112640023250 0ustar00. /** * Folder module renderer * * @package mod_folder * @copyright 2009 Petr Skoda {@link http://skodak.org} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); class mod_folder_renderer extends plugin_renderer_base { /** * Returns html to display the content of mod_folder * (Description, folder files and optionally Edit button) * * @param stdClass $folder record from 'folder' table (please note * it may not contain fields 'revision' and 'timemodified') * @return string */ public function display_folder(stdClass $folder) { static $treecounter = 0; $folderinstances = get_fast_modinfo($folder->course)->get_instances_of('folder'); if (!isset($folderinstances[$folder->id]) || !($cm = $folderinstances[$folder->id]) || !($context = context_module::instance($cm->id))) { // Some error in parameters. // Don't throw any errors in renderer, just return empty string. // Capability to view module must be checked before calling renderer. return ''; } $data = []; if (trim($folder->intro)) { if ($folder->display == FOLDER_DISPLAY_INLINE && $cm->showdescription) { // for "display inline" do not filter, filters run at display time. $data['intro'] = format_module_intro('folder', $folder, $cm->id, false); } } $buttons = []; // Display the "Edit" button if current user can edit folder contents. // Do not display it on the course page for the teachers because there // is an "Edit settings" option in the action menu with the same functionality. $canmanagefolderfiles = has_capability('mod/folder:managefiles', $context); $canmanagecourseactivities = has_capability('moodle/course:manageactivities', $context); if ($canmanagefolderfiles && ($folder->display != FOLDER_DISPLAY_INLINE || !$canmanagecourseactivities)) { $editbutton = new single_button(new moodle_url('/mod/folder/edit.php', ['id' => $cm->id]), get_string('edit'), 'post', single_button::BUTTON_PRIMARY); $editbutton->class = 'navitem'; $data['edit_button'] = $editbutton->export_for_template($this->output); $data['hasbuttons'] = true; } $downloadable = folder_archive_available($folder, $cm); if ($downloadable) { $downloadbutton = new single_button(new moodle_url('/mod/folder/download_folder.php', ['id' => $cm->id]), get_string('downloadfolder', 'folder'), 'get'); $downloadbutton->class = 'navitem ms-auto'; $data['download_button'] = $downloadbutton->export_for_template($this->output); $data['hasbuttons'] = true; } $foldertree = new folder_tree($folder, $cm); if ($folder->display == FOLDER_DISPLAY_INLINE) { // Display module name as the name of the root directory. $foldertree->dir['dirname'] = $cm->get_formatted_name(array('escape' => false)); } $data['id'] = 'folder_tree'. ($treecounter++); $data['showexpanded'] = !empty($foldertree->folder->showexpanded); $data['dir'] = $this->renderable_tree_elements($foldertree, ['files' => [], 'subdirs' => [$foldertree->dir]]); return $this->render_from_template('mod_folder/folder', $data); } /** * @deprecated since Moodle 4.3 */ #[\core\attribute\deprecated('renderable_tree_elements()', since: '4.3', mdl: 'MDL-78847', final: true)] protected function htmllize_tree() { \core\deprecation::emit_deprecation([self::class, __FUNCTION__]); } /** * Internal function - Creates elements structure suitable for mod_folder/folder template. * * @param folder_tree $tree The folder tree to work with. * @param array $dir The subdir and files structure to convert into a tree. * @return array The structure to be rendered by mod_folder/folder template. */ protected function renderable_tree_elements(folder_tree $tree, array $dir): array { if (empty($dir['subdirs']) && empty($dir['files'])) { return []; } $elements = []; foreach ($dir['subdirs'] as $subdir) { $htmllize = $this->renderable_tree_elements($tree, $subdir); $image = $this->output->pix_icon(file_folder_icon(), $subdir['dirname'], 'moodle'); $elements[] = [ 'name' => $subdir['dirname'], 'icon' => $image, 'subdirs' => $htmllize, 'hassubdirs' => !empty($htmllize), ]; } foreach ($dir['files'] as $file) { $filename = $file->get_filename(); $filenamedisplay = clean_filename($filename); $url = moodle_url::make_pluginfile_url($file->get_contextid(), $file->get_component(), $file->get_filearea(), $file->get_itemid(), $file->get_filepath(), $filename, false); if (file_extension_in_typegroup($filename, 'web_image')) { $image = $url->out(false, ['preview' => 'tinyicon', 'oid' => $file->get_timemodified()]); $image = html_writer::empty_tag('img', ['src' => $image]); } else { $image = $this->output->pix_icon(file_file_icon($file), $filenamedisplay, 'moodle'); } if ($tree->folder->forcedownload) { $url->param('forcedownload', 1); } $elements[] = [ 'name' => $filenamedisplay, 'icon' => $image, 'url' => $url, 'subdirs' => null, 'hassubdirs' => false, ]; } return $elements; } } class folder_tree implements renderable { public $context; public $folder; public $cm; public $dir; public function __construct($folder, $cm) { $this->folder = $folder; $this->cm = $cm; $this->context = context_module::instance($cm->id); $fs = get_file_storage(); $this->dir = $fs->get_area_tree($this->context->id, 'mod_folder', 'content', 0); } } home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/mod/workshop/renderer.php000064400000262021152267114660023650 0ustar00. /** * Workshop module renderering methods are defined here * * @package mod_workshop * @copyright 2009 David Mudrak * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); /** * Workshop module renderer class * * @copyright 2009 David Mudrak * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class mod_workshop_renderer extends plugin_renderer_base { //////////////////////////////////////////////////////////////////////////// // External API - methods to render workshop renderable components //////////////////////////////////////////////////////////////////////////// /** * Renders the tertiary nav for the allocation pages * * @param \mod_workshop\output\actionbar $actionbar * @return bool|string the rendered output */ public function render_allocation_menu(\mod_workshop\output\actionbar $actionbar): string { return $this->render_from_template('mod_workshop/action_bar', $actionbar->export_for_template($this)); } /** * Renders workshop message * * @param workshop_message $message to display * @return string html code */ protected function render_workshop_message(workshop_message $message) { $text = $message->get_message(); $url = $message->get_action_url(); $label = $message->get_action_label(); if (empty($text) and empty($label)) { return ''; } switch ($message->get_type()) { case workshop_message::TYPE_OK: $sty = 'ok'; break; case workshop_message::TYPE_ERROR: $sty = 'error'; break; default: $sty = 'info'; } $o = html_writer::tag('span', $message->get_message()); if (!is_null($url) and !is_null($label)) { $o .= $this->output->single_button($url, $label, 'get'); } return $this->output->container($o, array('message', $sty)); } /** * Renders full workshop submission * * @param workshop_submission $submission * @return string HTML */ protected function render_workshop_submission(workshop_submission $submission) { global $CFG; $o = ''; // output HTML code $anonymous = $submission->is_anonymous(); $classes = 'submission-full'; if ($anonymous) { $classes .= ' anonymous'; } $o .= $this->output->container_start($classes); $o .= $this->output->container_start('header'); $title = format_string($submission->title); if ($this->page->url != $submission->url) { $title = html_writer::link($submission->url, $title); } $o .= $this->output->heading($title, 3, 'title'); if (!$anonymous) { $author = new stdclass(); $additionalfields = explode(',', implode(',', \core_user\fields::get_picture_fields())); $author = username_load_fields_from_object($author, $submission, 'author', $additionalfields); $userpic = $this->output->user_picture($author, array('courseid' => $this->page->course->id, 'size' => 64)); $userurl = new moodle_url('/user/view.php', array('id' => $author->id, 'course' => $this->page->course->id)); $a = new stdclass(); $a->name = fullname($author); $a->url = $userurl->out(); $byfullname = get_string('byfullname', 'workshop', $a); $oo = $this->output->container($userpic, 'picture'); $oo .= $this->output->container($byfullname, 'fullname'); $o .= $this->output->container($oo, 'author'); } $created = get_string('userdatecreated', 'workshop', userdate($submission->timecreated)); $o .= $this->output->container($created, 'userdate created'); if ($submission->timemodified > $submission->timecreated) { $modified = get_string('userdatemodified', 'workshop', userdate($submission->timemodified)); $o .= $this->output->container($modified, 'userdate modified'); } $o .= $this->output->container_end(); // end of header $content = file_rewrite_pluginfile_urls($submission->content, 'pluginfile.php', $this->page->context->id, 'mod_workshop', 'submission_content', $submission->id); $content = format_text($content, $submission->contentformat, array('overflowdiv'=>true)); if (!empty($content)) { if (!empty($CFG->enableplagiarism)) { require_once($CFG->libdir.'/plagiarismlib.php'); $content .= plagiarism_get_links(array('userid' => $submission->authorid, 'content' => $submission->content, 'cmid' => $this->page->cm->id, 'course' => $this->page->course)); } } $o .= $this->output->container($content, 'content'); $o .= $this->helper_submission_attachments($submission->id, 'html'); $o .= $this->output->container_end(); // end of submission-full return $o; } /** * Renders short summary of the submission * * @param workshop_submission_summary $summary * @return string text to be echo'ed */ protected function render_workshop_submission_summary(workshop_submission_summary $summary) { $o = ''; // output HTML code $anonymous = $summary->is_anonymous(); $classes = 'submission-summary'; if ($anonymous) { $classes .= ' anonymous'; } $gradestatus = ''; if ($summary->status == 'notgraded') { $classes .= ' notgraded'; $gradestatus = $this->output->container(get_string('nogradeyet', 'workshop'), 'grade-status'); } else if ($summary->status == 'graded') { $classes .= ' graded'; $gradestatus = $this->output->container(get_string('alreadygraded', 'workshop'), 'grade-status'); } $o .= $this->output->container_start($classes); // main wrapper $o .= html_writer::link($summary->url, format_string($summary->title), array('class' => 'title')); if (!$anonymous) { $author = new stdClass(); $additionalfields = explode(',', implode(',', \core_user\fields::get_picture_fields())); $author = username_load_fields_from_object($author, $summary, 'author', $additionalfields); $userpic = $this->output->user_picture($author, array('courseid' => $this->page->course->id, 'size' => 35)); $userurl = new moodle_url('/user/view.php', array('id' => $author->id, 'course' => $this->page->course->id)); $a = new stdClass(); $a->name = fullname($author); $a->url = $userurl->out(); $byfullname = get_string('byfullname', 'workshop', $a); $oo = $this->output->container($userpic, 'picture'); $oo .= $this->output->container($byfullname, 'fullname'); $o .= $this->output->container($oo, 'author'); } $created = get_string('userdatecreated', 'workshop', userdate($summary->timecreated)); $o .= $this->output->container($created, 'userdate created'); if ($summary->timemodified > $summary->timecreated) { $modified = get_string('userdatemodified', 'workshop', userdate($summary->timemodified)); $o .= $this->output->container($modified, 'userdate modified'); } $o .= $gradestatus; $o .= $this->output->container_end(); // end of the main wrapper return $o; } /** * Renders full workshop example submission * * @param workshop_example_submission $example * @return string HTML */ protected function render_workshop_example_submission(workshop_example_submission $example) { $o = ''; // output HTML code $classes = 'submission-full example'; $o .= $this->output->container_start($classes); $o .= $this->output->container_start('header'); $o .= $this->output->container(format_string($example->title), array('class' => 'title')); $o .= $this->output->container_end(); // end of header $content = file_rewrite_pluginfile_urls($example->content, 'pluginfile.php', $this->page->context->id, 'mod_workshop', 'submission_content', $example->id); $content = format_text($content, $example->contentformat, array('overflowdiv'=>true)); $o .= $this->output->container($content, 'content'); $o .= $this->helper_submission_attachments($example->id, 'html'); $o .= $this->output->container_end(); // end of submission-full return $o; } /** * Renders short summary of the example submission * * @param workshop_example_submission_summary $summary * @return string text to be echo'ed */ protected function render_workshop_example_submission_summary(workshop_example_submission_summary $summary) { $o = ''; // output HTML code // wrapping box $o .= $this->output->box_start('generalbox example-summary ' . $summary->status); // title $o .= $this->output->container_start('example-title'); $o .= html_writer::link($summary->url, format_string($summary->title), array('class' => 'title')); if ($summary->editable) { $o .= $this->output->action_icon($summary->editurl, new pix_icon('i/edit', get_string('edit'))); } $o .= $this->output->container_end(); // additional info if ($summary->status == 'notgraded') { $o .= $this->output->container(get_string('nogradeyet', 'workshop'), 'example-info nograde'); } else { $o .= $this->output->container(get_string('gradeinfo', 'workshop' , $summary->gradeinfo), 'example-info grade'); } // button to assess $button = new single_button($summary->assessurl, $summary->assesslabel, 'get'); $o .= $this->output->container($this->output->render($button), 'example-actions'); // end of wrapping box $o .= $this->output->box_end(); return $o; } /** * Renders the user plannner tool * * @param workshop_user_plan $plan prepared for the user * @return string html code to be displayed */ protected function render_workshop_user_plan(workshop_user_plan $plan) { $o = ''; // Output HTML code. $numberofphases = count($plan->phases); $o .= html_writer::start_tag('div', array( 'class' => 'userplan', 'aria-labelledby' => 'mod_workshop-userplanheading', 'aria-describedby' => 'mod_workshop-userplanaccessibilitytitle', )); $o .= html_writer::span(get_string('userplanaccessibilitytitle', 'workshop', $numberofphases), 'accesshide', array('id' => 'mod_workshop-userplanaccessibilitytitle')); $o .= html_writer::link('#mod_workshop-userplancurrenttasks', get_string('userplanaccessibilityskip', 'workshop'), array('class' => 'accesshide')); foreach ($plan->phases as $phasecode => $phase) { $o .= html_writer::start_tag('dl', array('class' => 'phase')); $actions = ''; if ($phase->active) { // Mark the section as the current one. $icon = $this->output->pix_icon('i/marked', ''); $actions .= get_string('userplancurrentphase', 'workshop').' '.$icon; } else { // Display a control widget to switch to the given phase or mark the phase as the current one. foreach ($phase->actions as $action) { if ($action->type === 'switchphase') { if ($phasecode == workshop::PHASE_ASSESSMENT && $plan->workshop->phase == workshop::PHASE_SUBMISSION && $plan->workshop->phaseswitchassessment) { $icon = new pix_icon('i/scheduled', get_string('switchphaseauto', 'mod_workshop')); } else { $icon = new pix_icon('i/marker', get_string('switchphase'.$phasecode, 'mod_workshop')); } $actions .= $this->output->action_icon($action->url, $icon, null, null, true); } } } if (!empty($actions)) { $actions = $this->output->container($actions, 'actions'); } $classes = 'phase' . $phasecode; if ($phase->active) { $title = html_writer::span($phase->title, 'phasetitle', ['id' => 'mod_workshop-userplancurrenttasks']); $classes .= ' active'; } else { $title = html_writer::span($phase->title, 'phasetitle'); $classes .= ' nonactive'; } $o .= html_writer::start_tag('dt', array('class' => $classes)); $o .= $this->output->container($title . $actions); $o .= html_writer::start_tag('dd', array('class' => $classes. ' phasetasks')); $o .= $this->helper_user_plan_tasks($phase->tasks); $o .= html_writer::end_tag('dd'); $o .= html_writer::end_tag('dl'); } $o .= html_writer::end_tag('div'); return $o; } /** * Renders the result of the submissions allocation process * * @param workshop_allocation_result $result as returned by the allocator's init() method * @return string HTML to be echoed */ protected function render_workshop_allocation_result(workshop_allocation_result $result) { global $CFG; $status = $result->get_status(); if (is_null($status) or $status == workshop_allocation_result::STATUS_VOID) { debugging('Attempt to render workshop_allocation_result with empty status', DEBUG_DEVELOPER); return ''; } switch ($status) { case workshop_allocation_result::STATUS_FAILED: if ($message = $result->get_message()) { $message = new workshop_message($message, workshop_message::TYPE_ERROR); } else { $message = new workshop_message(get_string('allocationerror', 'workshop'), workshop_message::TYPE_ERROR); } break; case workshop_allocation_result::STATUS_CONFIGURED: if ($message = $result->get_message()) { $message = new workshop_message($message, workshop_message::TYPE_INFO); } else { $message = new workshop_message(get_string('allocationconfigured', 'workshop'), workshop_message::TYPE_INFO); } break; case workshop_allocation_result::STATUS_EXECUTED: if ($message = $result->get_message()) { $message = new workshop_message($message, workshop_message::TYPE_OK); } else { $message = new workshop_message(get_string('allocationdone', 'workshop'), workshop_message::TYPE_OK); } break; default: throw new coding_exception('Unknown allocation result status', $status); } // start with the message $o = $this->render($message); // display the details about the process if available $logs = $result->get_logs(); if (is_array($logs) and !empty($logs)) { $o .= html_writer::start_tag('ul', array('class' => 'allocation-init-results')); foreach ($logs as $log) { if ($log->type == 'debug' and !$CFG->debugdeveloper) { // display allocation debugging messages for developers only continue; } $class = $log->type; if ($log->indent) { $class .= ' indent'; } $o .= html_writer::tag('li', $log->message, array('class' => $class)).PHP_EOL; } $o .= html_writer::end_tag('ul'); } return $o; } /** * Renders the workshop grading report * * @param workshop_grading_report $gradingreport * @return string html code */ protected function render_workshop_grading_report(workshop_grading_report $gradingreport) { $data = $gradingreport->get_data(); $options = $gradingreport->get_options(); $grades = $data->grades; $userinfo = $data->userinfo; if (empty($grades)) { return $this->output->notification(get_string('nothingtodisplay'), 'info', false); } $table = new html_table(); $table->attributes['class'] = 'grading-report table-striped table-hover'; $sortbyfirstname = $this->helper_sortable_heading(get_string('firstname'), 'firstname', $options->sortby, $options->sorthow); $sortbylastname = $this->helper_sortable_heading(get_string('lastname'), 'lastname', $options->sortby, $options->sorthow); if (self::fullname_format() == 'lf') { $sortbyname = $sortbylastname . ' / ' . $sortbyfirstname; } else { $sortbyname = $sortbyfirstname . ' / ' . $sortbylastname; } $sortbysubmisstiontitle = $this->helper_sortable_heading(get_string('submission', 'workshop'), 'submissiontitle', $options->sortby, $options->sorthow); $sortbysubmisstionlastmodified = $this->helper_sortable_heading(get_string('submissionlastmodified', 'workshop'), 'submissionmodified', $options->sortby, $options->sorthow); $sortbysubmisstion = $sortbysubmisstiontitle . ' / ' . $sortbysubmisstionlastmodified; $table->head = array(); $table->head[] = $sortbyname; $table->head[] = $sortbysubmisstion; // If we are in submission phase ignore the following headers (columns). if ($options->workshopphase != workshop::PHASE_SUBMISSION) { $table->head[] = $this->helper_sortable_heading(get_string('receivedgrades', 'workshop')); if ($options->showsubmissiongrade) { $table->head[] = $this->helper_sortable_heading(get_string('submissiongradeof', 'workshop', $data->maxgrade), 'submissiongrade', $options->sortby, $options->sorthow); } $table->head[] = $this->helper_sortable_heading(get_string('givengrades', 'workshop')); if ($options->showgradinggrade) { $table->head[] = $this->helper_sortable_heading(get_string('gradinggradeof', 'workshop', $data->maxgradinggrade), 'gradinggrade', $options->sortby, $options->sorthow); } } $table->rowclasses = array(); $table->colclasses = array(); $table->data = array(); foreach ($grades as $participant) { $numofreceived = count($participant->reviewedby); $numofgiven = count($participant->reviewerof); $published = $participant->submissionpublished; // compute the number of table rows needed to display this participant if ($numofreceived > 0 and $numofgiven > 0) { $numoftrs = workshop::lcm($numofreceived, $numofgiven); $spanreceived = $numoftrs / $numofreceived; $spangiven = $numoftrs / $numofgiven; } elseif ($numofreceived == 0 and $numofgiven > 0) { $numoftrs = $numofgiven; $spanreceived = $numoftrs; $spangiven = $numoftrs / $numofgiven; } elseif ($numofreceived > 0 and $numofgiven == 0) { $numoftrs = $numofreceived; $spanreceived = $numoftrs / $numofreceived; $spangiven = $numoftrs; } else { $numoftrs = 1; $spanreceived = 1; $spangiven = 1; } for ($tr = 0; $tr < $numoftrs; $tr++) { $row = new html_table_row(); if ($published) { $row->attributes['class'] = 'published'; } // column #1 - participant - spans over all rows if ($tr == 0) { $cell = new html_table_cell(); $cell->text = $this->helper_grading_report_participant($participant, $userinfo); $cell->rowspan = $numoftrs; $cell->attributes['class'] = 'participant'; $row->cells[] = $cell; } // column #2 - submission - spans over all rows if ($tr == 0) { $cell = new html_table_cell(); $cell->text = $this->helper_grading_report_submission($participant); $cell->rowspan = $numoftrs; $cell->attributes['class'] = 'submission'; $row->cells[] = $cell; } // If we are in submission phase ignore the following columns. if ($options->workshopphase == workshop::PHASE_SUBMISSION) { $table->data[] = $row; continue; } // column #3 - received grades if ($tr % $spanreceived == 0) { $idx = intval($tr / $spanreceived); $assessment = self::array_nth($participant->reviewedby, $idx); $cell = new html_table_cell(); $cell->text = $this->helper_grading_report_assessment($assessment, $options->showreviewernames, $userinfo, get_string('gradereceivedfrom', 'workshop')); $cell->rowspan = $spanreceived; $cell->attributes['class'] = 'receivedgrade'; if (is_null($assessment) or is_null($assessment->grade)) { $cell->attributes['class'] .= ' null'; } else { $cell->attributes['class'] .= ' notnull'; } $row->cells[] = $cell; } // column #4 - total grade for submission if ($options->showsubmissiongrade and $tr == 0) { $cell = new html_table_cell(); $cell->text = $this->helper_grading_report_grade($participant->submissiongrade, $participant->submissiongradeover); $cell->rowspan = $numoftrs; $cell->attributes['class'] = 'submissiongrade'; $row->cells[] = $cell; } // column #5 - given grades if ($tr % $spangiven == 0) { $idx = intval($tr / $spangiven); $assessment = self::array_nth($participant->reviewerof, $idx); $cell = new html_table_cell(); $cell->text = $this->helper_grading_report_assessment($assessment, $options->showauthornames, $userinfo, get_string('gradegivento', 'workshop')); $cell->rowspan = $spangiven; $cell->attributes['class'] = 'givengrade'; if (is_null($assessment) or is_null($assessment->grade)) { $cell->attributes['class'] .= ' null'; } else { $cell->attributes['class'] .= ' notnull'; } $row->cells[] = $cell; } // column #6 - total grade for assessment if ($options->showgradinggrade and $tr == 0) { $cell = new html_table_cell(); $cell->text = $this->helper_grading_report_grade($participant->gradinggrade); $cell->rowspan = $numoftrs; $cell->attributes['class'] = 'gradinggrade'; $row->cells[] = $cell; } $table->data[] = $row; } } return html_writer::table($table); } /** * Renders the feedback for the author of the submission * * @param workshop_feedback_author $feedback * @return string HTML */ protected function render_workshop_feedback_author(workshop_feedback_author $feedback) { return $this->helper_render_feedback($feedback); } /** * Renders the feedback for the reviewer of the submission * * @param workshop_feedback_reviewer $feedback * @return string HTML */ protected function render_workshop_feedback_reviewer(workshop_feedback_reviewer $feedback) { return $this->helper_render_feedback($feedback); } /** * Helper method to rendering feedback * * @param workshop_feedback_author|workshop_feedback_reviewer $feedback * @return string HTML */ private function helper_render_feedback($feedback) { $o = ''; // output HTML code $o .= $this->output->container_start('feedback feedbackforauthor'); $o .= $this->output->container_start('header'); $o .= $this->output->heading(get_string('feedbackby', 'workshop', s(fullname($feedback->get_provider()))), 3, 'title'); $userpic = $this->output->user_picture($feedback->get_provider(), array('courseid' => $this->page->course->id, 'size' => 32)); $o .= $this->output->container($userpic, 'picture'); $o .= $this->output->container_end(); // end of header $content = format_text($feedback->get_content(), $feedback->get_format(), array('overflowdiv' => true)); $o .= $this->output->container($content, 'content'); $o .= $this->output->container_end(); return $o; } /** * Renders the full assessment * * @param workshop_assessment $assessment * @return string HTML */ protected function render_workshop_assessment(workshop_assessment $assessment) { $o = ''; // output HTML code $anonymous = is_null($assessment->reviewer); $classes = 'assessment-full'; if ($anonymous) { $classes .= ' anonymous'; } $o .= $this->output->container_start($classes); $o .= $this->output->container_start('header'); if (!empty($assessment->title)) { $title = s($assessment->title); } else { $title = get_string('assessment', 'workshop'); } if (($assessment->url instanceof moodle_url) and ($this->page->url != $assessment->url)) { $o .= $this->output->container(html_writer::link($assessment->url, $title), 'title'); } else { $o .= $this->output->container($title, 'title'); } if (!$anonymous) { $reviewer = $assessment->reviewer; $userpic = $this->output->user_picture($reviewer, array('courseid' => $this->page->course->id, 'size' => 32)); $userurl = new moodle_url('/user/view.php', array('id' => $reviewer->id, 'course' => $this->page->course->id)); $a = new stdClass(); $a->name = fullname($reviewer); $a->url = $userurl->out(); $byfullname = get_string('assessmentby', 'workshop', $a); $oo = $this->output->container($userpic, 'picture'); $oo .= $this->output->container($byfullname, 'fullname'); $o .= $this->output->container($oo, 'reviewer'); } if (is_null($assessment->realgrade)) { $o .= $this->output->container( get_string('notassessed', 'workshop'), 'grade nograde' ); } else { $a = new stdClass(); $a->max = $assessment->maxgrade; $a->received = $assessment->realgrade; $o .= $this->output->container( get_string('gradeinfo', 'workshop', $a), 'grade' ); if (!is_null($assessment->weight) and $assessment->weight != 1) { $o .= $this->output->container( get_string('weightinfo', 'workshop', $assessment->weight), 'weight' ); } } $o .= $this->output->container_start('actions'); foreach ($assessment->actions as $action) { $o .= $this->output->single_button($action->url, $action->label, $action->method); } $o .= $this->output->container_end(); // actions $o .= $this->output->container_end(); // header if (!is_null($assessment->form)) { $o .= print_collapsible_region_start('assessment-form-wrapper', uniqid('workshop-assessment'), get_string('assessmentform', 'workshop'), 'workshop-viewlet-assessmentform-collapsed', false, true); $o .= $this->output->container(self::moodleform($assessment->form), 'assessment-form'); $o .= print_collapsible_region_end(true); if (!$assessment->form->is_editable()) { $o .= $this->overall_feedback($assessment); } } $o .= $this->output->container_end(); // main wrapper return $o; } /** * Renders the assessment of an example submission * * @param workshop_example_assessment $assessment * @return string HTML */ protected function render_workshop_example_assessment(workshop_example_assessment $assessment) { return $this->render_workshop_assessment($assessment); } /** * Renders the reference assessment of an example submission * * @param workshop_example_reference_assessment $assessment * @return string HTML */ protected function render_workshop_example_reference_assessment(workshop_example_reference_assessment $assessment) { return $this->render_workshop_assessment($assessment); } /** * Renders the overall feedback for the author of the submission * * @param workshop_assessment $assessment * @return string HTML */ protected function overall_feedback(workshop_assessment $assessment) { $content = $assessment->get_overall_feedback_content(); if ($content === false) { return ''; } $o = ''; if (!is_null($content)) { $o .= $this->output->container($content, 'content'); } $attachments = $assessment->get_overall_feedback_attachments(); if (!empty($attachments)) { $o .= $this->output->container_start('attachments'); $images = ''; $files = ''; foreach ($attachments as $attachment) { $icon = $this->output->pix_icon(file_file_icon($attachment), get_mimetype_description($attachment), 'moodle', array('class' => 'icon')); $link = html_writer::link($attachment->fileurl, $icon.' '.substr($attachment->filepath.$attachment->filename, 1)); if (file_mimetype_in_typegroup($attachment->mimetype, 'web_image')) { $preview = html_writer::empty_tag('img', array('src' => $attachment->previewurl, 'alt' => '', 'class' => 'preview')); $preview = html_writer::tag('a', $preview, array('href' => $attachment->fileurl)); $images .= $this->output->container($preview); } else { $files .= html_writer::tag('li', $link, array('class' => $attachment->mimetype)); } } if ($images) { $images = $this->output->container($images, 'images'); } if ($files) { $files = html_writer::tag('ul', $files, array('class' => 'files')); } $o .= $images.$files; $o .= $this->output->container_end(); } if ($o === '') { return ''; } $o = $this->output->box($o, 'overallfeedback'); $o = print_collapsible_region($o, 'overall-feedback-wrapper', uniqid('workshop-overall-feedback'), get_string('overallfeedback', 'workshop'), 'workshop-viewlet-overallfeedback-collapsed', false, true); return $o; } /** * Renders a perpage selector for workshop listings * * The scripts using this have to define the $PAGE->url prior to calling this * and deal with eventually submitted value themselves. * * @param int $current current value of the perpage parameter * @return string HTML */ public function perpage_selector($current=10) { $options = array(); foreach (array(10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 200, 300, 400, 500, 1000) as $option) { if ($option != $current) { $options[$option] = $option; } } $select = new single_select($this->page->url, 'perpage', $options, '', array('' => get_string('showingperpagechange', 'mod_workshop'))); $select->label = get_string('showingperpage', 'mod_workshop', $current); $select->method = 'post'; return $this->output->container($this->output->render($select), 'perpagewidget'); } /** * Render the initials bars for workshop. * * @param workshop $workshop the current workshop of initial bars. * @param moodle_url $url base URL object. * @return string HTML. */ public function initials_bars(workshop $workshop, moodle_url $url): string { $ifirst = $workshop->get_initial_first(); $ilast = $workshop->get_initial_last(); $html = $this->output->initials_bar($ifirst, 'firstinitial', get_string('firstname'), 'ifirst', $url); $html .= $this->output->initials_bar($ilast, 'lastinitial', get_string('lastname'), 'ilast', $url); return $html; } /** * Renders the user's final grades * * @param workshop_final_grades $grades with the info about grades in the gradebook * @return string HTML */ protected function render_workshop_final_grades(workshop_final_grades $grades) { $out = html_writer::start_tag('div', array('class' => 'finalgrades')); if (!empty($grades->submissiongrade)) { $cssclass = 'grade submissiongrade'; if ($grades->submissiongrade->hidden) { $cssclass .= ' hiddengrade'; } $out .= html_writer::tag( 'div', html_writer::tag('div', get_string('submissiongrade', 'mod_workshop'), array('class' => 'gradetype')) . html_writer::tag('div', $grades->submissiongrade->str_long_grade, array('class' => 'gradevalue')), array('class' => $cssclass) ); } if (!empty($grades->assessmentgrade)) { $cssclass = 'grade assessmentgrade'; if ($grades->assessmentgrade->hidden) { $cssclass .= ' hiddengrade'; } $out .= html_writer::tag( 'div', html_writer::tag('div', get_string('gradinggrade', 'mod_workshop'), array('class' => 'gradetype')) . html_writer::tag('div', $grades->assessmentgrade->str_long_grade, array('class' => 'gradevalue')), array('class' => $cssclass) ); } $out .= html_writer::end_tag('div'); return $out; } //////////////////////////////////////////////////////////////////////////// // Internal rendering helper methods //////////////////////////////////////////////////////////////////////////// /** * Renders a list of files attached to the submission * * If format==html, then format a html string. If format==text, then format a text-only string. * Otherwise, returns html for non-images and html to display the image inline. * * @param int $submissionid submission identifier * @param string format the format of the returned string - html|text * @return string formatted text to be echoed */ protected function helper_submission_attachments($submissionid, $format = 'html') { global $CFG; require_once($CFG->libdir.'/filelib.php'); $fs = get_file_storage(); $ctx = $this->page->context; $files = $fs->get_area_files($ctx->id, 'mod_workshop', 'submission_attachment', $submissionid); $outputimgs = ''; // images to be displayed inline $outputfiles = ''; // list of attachment files foreach ($files as $file) { if ($file->is_directory()) { continue; } $filepath = $file->get_filepath(); $filename = $file->get_filename(); $fileurl = moodle_url::make_pluginfile_url($ctx->id, 'mod_workshop', 'submission_attachment', $submissionid, $filepath, $filename, true); $embedurl = moodle_url::make_pluginfile_url($ctx->id, 'mod_workshop', 'submission_attachment', $submissionid, $filepath, $filename, false); $embedurl = new moodle_url($embedurl, array('preview' => 'bigthumb')); $type = $file->get_mimetype(); $image = $this->output->pix_icon(file_file_icon($file), get_mimetype_description($file), 'moodle', array('class' => 'icon')); $linkhtml = html_writer::link($fileurl, $image . substr($filepath, 1) . $filename); $linktxt = "$filename [$fileurl]"; if ($format == 'html') { if (file_mimetype_in_typegroup($type, 'web_image')) { $preview = html_writer::empty_tag('img', array('src' => $embedurl, 'alt' => '', 'class' => 'preview')); $preview = html_writer::tag('a', $preview, array('href' => $fileurl)); $outputimgs .= $this->output->container($preview); } else { $outputfiles .= html_writer::tag('li', $linkhtml, array('class' => $type)); } } else if ($format == 'text') { $outputfiles .= $linktxt . PHP_EOL; } if (!empty($CFG->enableplagiarism)) { require_once($CFG->libdir.'/plagiarismlib.php'); $outputfiles .= plagiarism_get_links(array('userid' => $file->get_userid(), 'file' => $file, 'cmid' => $this->page->cm->id, 'course' => $this->page->course->id)); } } if ($format == 'html') { if ($outputimgs) { $outputimgs = $this->output->container($outputimgs, 'images'); } if ($outputfiles) { $outputfiles = html_writer::tag('ul', $outputfiles, array('class' => 'files')); } return $this->output->container($outputimgs . $outputfiles, 'attachments'); } else { return $outputfiles; } } /** * Renders the tasks for the single phase in the user plan * * @param stdClass $tasks * @return string html code */ protected function helper_user_plan_tasks(array $tasks) { $out = ''; foreach ($tasks as $taskcode => $task) { $classes = ''; $accessibilitytext = ''; $icon = null; if ($task->completed === true) { $classes .= ' completed'; $accessibilitytext .= get_string('taskdone', 'workshop') . ' '; } else if ($task->completed === false) { $classes .= ' fail'; $accessibilitytext .= get_string('taskfail', 'workshop') . ' '; } else if ($task->completed === 'info') { $classes .= ' info'; $accessibilitytext .= get_string('taskinfo', 'workshop') . ' '; } else { $accessibilitytext .= get_string('tasktodo', 'workshop') . ' '; } if (is_null($task->link)) { $title = html_writer::tag('span', $accessibilitytext, array('class' => 'accesshide')); $title .= $task->title; } else { $title = html_writer::tag('span', $accessibilitytext, array('class' => 'accesshide')); $title .= html_writer::link($task->link, $task->title); } $title = $this->output->container($title, 'title'); $details = $this->output->container($task->details, 'details'); $out .= html_writer::tag('li', $title . $details, array('class' => $classes)); } if ($out) { $out = html_writer::tag('ul', $out, array('class' => 'tasks')); } return $out; } /** * Renders a text with icons to sort by the given column * * This is intended for table headings. * * @param string $text The heading text * @param string $sortid The column id used for sorting * @param string $sortby Currently sorted by (column id) * @param string $sorthow Currently sorted how (ASC|DESC) * * @return string */ protected function helper_sortable_heading($text, $sortid=null, $sortby=null, $sorthow=null) { $out = html_writer::tag('span', $text, array('class'=>'text')); if (!is_null($sortid)) { if ($sortby !== $sortid or $sorthow !== 'ASC') { $url = new moodle_url($this->page->url); $url->params(array('sortby' => $sortid, 'sorthow' => 'ASC')); $out .= $this->output->action_icon($url, new pix_icon('t/sort_asc', get_string('sortasc', 'workshop')), null, ['class' => 'sort asc']); } if ($sortby !== $sortid or $sorthow !== 'DESC') { $url = new moodle_url($this->page->url); $url->params(array('sortby' => $sortid, 'sorthow' => 'DESC')); $out .= $this->output->action_icon($url, new pix_icon('t/sort_desc', get_string('sortdesc', 'workshop')), null, ['class' => 'sort desc']); } } return $out; } /** * @param stdClass $participant * @param array $userinfo * @return string */ protected function helper_grading_report_participant(stdclass $participant, array $userinfo) { $userid = $participant->userid; $out = $this->output->user_picture($userinfo[$userid], array('courseid' => $this->page->course->id, 'size' => 35)); $out .= html_writer::tag('span', fullname($userinfo[$userid])); return $out; } /** * @param stdClass $participant * @return string */ protected function helper_grading_report_submission(stdclass $participant) { global $CFG; if (is_null($participant->submissionid)) { $out = $this->output->container(get_string('nosubmissionfound', 'workshop'), 'info'); } else { $url = new moodle_url('/mod/workshop/submission.php', array('cmid' => $this->page->context->instanceid, 'id' => $participant->submissionid)); $out = html_writer::link($url, format_string($participant->submissiontitle), array('class'=>'title')); $lastmodified = get_string('userdatemodified', 'workshop', userdate($participant->submissionmodified)); $out .= html_writer::tag('div', $lastmodified, array('class' => 'lastmodified')); } return $out; } /** * @todo Highlight the nulls * @param stdClass|null $assessment * @param bool $shownames * @param string $separator between the grade and the reviewer/author * @return string */ protected function helper_grading_report_assessment($assessment, $shownames, array $userinfo, $separator) { global $CFG; if (is_null($assessment)) { return get_string('nullgrade', 'workshop'); } $a = new stdclass(); $a->grade = is_null($assessment->grade) ? get_string('nullgrade', 'workshop') : $assessment->grade; $a->gradinggrade = is_null($assessment->gradinggrade) ? get_string('nullgrade', 'workshop') : $assessment->gradinggrade; $a->weight = $assessment->weight; // grrr the following logic should really be handled by a future language pack feature if (is_null($assessment->gradinggradeover)) { if ($a->weight == 1) { $grade = get_string('formatpeergrade', 'workshop', $a); } else { $grade = get_string('formatpeergradeweighted', 'workshop', $a); } } else { $a->gradinggradeover = $assessment->gradinggradeover; if ($a->weight == 1) { $grade = get_string('formatpeergradeover', 'workshop', $a); } else { $grade = get_string('formatpeergradeoverweighted', 'workshop', $a); } } $url = new moodle_url('/mod/workshop/assessment.php', array('asid' => $assessment->assessmentid)); $grade = html_writer::link($url, $grade, array('class'=>'grade')); if ($shownames) { $userid = $assessment->userid; $name = $this->output->user_picture($userinfo[$userid], array('courseid' => $this->page->course->id, 'size' => 16)); $name .= html_writer::tag('span', fullname($userinfo[$userid]), array('class' => 'fullname')); $name = $separator . html_writer::tag('span', $name, array('class' => 'user')); } else { $name = ''; } return $this->output->container($grade . $name, 'assessmentdetails'); } /** * Formats the aggreagated grades */ protected function helper_grading_report_grade($grade, $over=null) { $a = new stdclass(); $a->grade = is_null($grade) ? get_string('nullgrade', 'workshop') : $grade; if (is_null($over)) { $text = get_string('formataggregatedgrade', 'workshop', $a); } else { $a->over = is_null($over) ? get_string('nullgrade', 'workshop') : $over; $text = get_string('formataggregatedgradeover', 'workshop', $a); } return $text; } //////////////////////////////////////////////////////////////////////////// // Static helpers //////////////////////////////////////////////////////////////////////////// /** * Helper method dealing with the fact we can not just fetch the output of moodleforms * * @param moodleform $mform * @return string HTML */ protected static function moodleform(moodleform $mform) { ob_start(); $mform->display(); $o = ob_get_contents(); ob_end_clean(); return $o; } /** * Helper function returning the n-th item of the array * * @param array $a * @param int $n from 0 to m, where m is th number of items in the array * @return mixed the $n-th element of $a */ protected static function array_nth(array $a, $n) { $keys = array_keys($a); if ($n < 0 or $n > count($keys) - 1) { return null; } $key = $keys[$n]; return $a[$key]; } /** * Tries to guess the fullname format set at the site * * @return string fl|lf */ protected static function fullname_format() { $fake = new stdclass(); // fake user $fake->lastname = 'LLLL'; $fake->firstname = 'FFFF'; $fullname = get_string('fullnamedisplay', '', $fake); if (strpos($fullname, 'LLLL') < strpos($fullname, 'FFFF')) { return 'lf'; } else { return 'fl'; } } /** * Generates the action buttons. * * @param workshop $workshop The current workshop. * @param workshop_user_plan $userplan An individual workshop plan for the user. * @return string HTML to display. */ public function render_action_buttons(workshop $workshop, workshop_user_plan $userplan): string { global $USER; $output = ''; switch ($workshop->phase) { case workshop::PHASE_SUBMISSION: // Does the user have to assess examples before submitting their own work? $examplesmust = ($workshop->useexamples && $workshop->examplesmode == workshop::EXAMPLES_BEFORE_SUBMISSION); // Is the assessment of example submissions considered finished? $examplesdone = has_capability('mod/workshop:manageexamples', $workshop->context); if ($workshop->assessing_examples_allowed() && has_capability('mod/workshop:submit', $workshop->context) && !has_capability('mod/workshop:manageexamples', $workshop->context)) { $examples = $userplan->get_examples(); $left = 0; // Make sure the current user has all examples allocated. foreach ($examples as $exampleid => $example) { if (is_null($example->grade)) { $left++; break; } } if ($left > 0 && $workshop->examplesmode != workshop::EXAMPLES_VOLUNTARY) { $examplesdone = false; } else { $examplesdone = true; } } if (has_capability('mod/workshop:submit', $this->page->context) && (!$examplesmust || $examplesdone)) { if (!$workshop->get_submission_by_author($USER->id)) { $btnurl = new moodle_url($workshop->submission_url(), ['edit' => 'on']); $btntxt = get_string('createsubmission', 'workshop'); $output .= $this->single_button($btnurl, $btntxt, 'get', ['type' => single_button::BUTTON_PRIMARY]); } } break; case workshop::PHASE_ASSESSMENT: if (has_capability('mod/workshop:submit', $this->page->context)) { if (!$workshop->get_submission_by_author($USER->id)) { if ($workshop->creating_submission_allowed($USER->id)) { $btnurl = new moodle_url($workshop->submission_url(), ['edit' => 'on']); $btntxt = get_string('createsubmission', 'workshop'); $output .= $this->single_button($btnurl, $btntxt, 'get', ['type' => single_button::BUTTON_PRIMARY]); } } } } return $output; } /** * Generates the view page. * * @param workshop $workshop The current workshop. * @param workshop_user_plan $userplan An individual workshop plan for the user. * @param string $currentphasetitle The current phase title. * @param int $page The current page (for the pagination). * @param string $sortby Lastname|firstname|submissiontitle|submissiongrade|gradinggrade. * @param string $sorthow ASC|DESC. * @return string HTML to display. */ public function view_page(workshop $workshop, workshop_user_plan $userplan, string $currentphasetitle, int $page, string $sortby, string $sorthow): string { $output = ''; $output .= $this->render_action_buttons($workshop, $userplan); $output .= $this->heading(format_string($currentphasetitle), 2, null, 'mod_workshop-userplanheading'); $output .= $this->render($userplan); $output .= $this->view_submissions_report($workshop, $userplan, $page, $sortby, $sorthow); return $output; } /** * Generates the submission report. * * @param workshop $workshop The current workshop. * @param workshop_user_plan $userplan An individual workshop plan for the user. * @param int $page The current page (for the pagination). * @param string $sortby Lastname|firstname|submissiontitle|submissiongrade|gradinggrade. * @param string $sorthow ASC|DESC. * @return string HTML to display. */ public function view_submissions_report(workshop $workshop, workshop_user_plan $userplan, int $page, string $sortby, string $sorthow): string { global $USER; $output = ''; switch ($workshop->phase) { case workshop::PHASE_SETUP: if (trim($workshop->intro)) { $output .= print_collapsible_region_start('', 'workshop-viewlet-intro', get_string('introduction', 'workshop'), 'workshop-viewlet-intro-collapsed', false, true); $output .= $this->box(format_module_intro('workshop', $workshop, $workshop->cm->id), 'generalbox'); $output .= print_collapsible_region_end(true); } if ($workshop->useexamples && has_capability('mod/workshop:manageexamples', $this->page->context)) { $output .= print_collapsible_region_start('', 'workshop-viewlet-allexamples', get_string('examplesubmissions', 'workshop'), 'workshop-viewlet-allexamples-collapsed', false, true); $output .= $this->box_start('generalbox examples'); if ($workshop->grading_strategy_instance()->form_ready()) { if (!$examples = $workshop->get_examples_for_manager()) { $output .= $this->container(get_string('noexamples', 'workshop'), 'noexamples'); } foreach ($examples as $example) { $summary = $workshop->prepare_example_summary($example); $summary->editable = true; $output .= $this->render($summary); } $aurl = new moodle_url($workshop->exsubmission_url(0), ['edit' => 'on']); $output .= $this->single_button($aurl, get_string('exampleadd', 'workshop'), 'get'); } else { $output .= $this->container(get_string('noexamplesformready', 'workshop')); } $output .= $this->box_end(); $output .= print_collapsible_region_end(true); } break; case workshop::PHASE_SUBMISSION: $examplesmust = ($workshop->useexamples && $workshop->examplesmode == workshop::EXAMPLES_BEFORE_SUBMISSION); $examplesdone = has_capability('mod/workshop:manageexamples', $workshop->context); if (trim($workshop->instructauthors)) { $instructions = file_rewrite_pluginfile_urls($workshop->instructauthors, 'pluginfile.php', $this->page->context->id, 'mod_workshop', 'instructauthors', null, workshop::instruction_editors_options($this->page->context)); $output .= print_collapsible_region_start('', 'workshop-viewlet-instructauthors', get_string('instructauthors', 'workshop'), 'workshop-viewlet-instructauthors-collapsed', false, true); $output .= $this->box(format_text($instructions, $workshop->instructauthorsformat, ['overflowdiv' => true]), ['generalbox', 'instructions']); $output .= print_collapsible_region_end(true); } if ($workshop->assessing_examples_allowed() && has_capability('mod/workshop:submit', $workshop->context) && !has_capability('mod/workshop:manageexamples', $workshop->context)) { $examples = $userplan->get_examples(); $total = count($examples); $output .= print_collapsible_region_start('', 'workshop-viewlet-examples', get_string('exampleassessments', 'workshop'), 'workshop-viewlet-examples-collapsed', $examplesdone, true); $output .= $this->box_start('generalbox exampleassessments'); if ($total == 0) { $output .= $this->heading(get_string('noexamples', 'workshop'), 3); } else { foreach ($examples as $example) { $summary = $workshop->prepare_example_summary($example); $output .= $this->render($summary); } } $output .= $this->box_end(); $output .= print_collapsible_region_end(true); } if (has_capability('mod/workshop:submit', $this->page->context) && (!$examplesmust || $examplesdone)) { $output .= print_collapsible_region_start('', 'workshop-viewlet-ownsubmission', get_string('yoursubmission', 'workshop'), 'workshop-viewlet-ownsubmission-collapsed', false, true); $output .= $this->box_start('generalbox ownsubmission'); if ($submission = $workshop->get_submission_by_author($USER->id)) { $output .= $this->render($workshop->prepare_submission_summary($submission, true)); } else { $output .= $this->container(get_string('noyoursubmission', 'workshop')); } $output .= $this->box_end(); $output .= print_collapsible_region_end(true); } if (has_capability('mod/workshop:viewallsubmissions', $this->page->context)) { $groupmode = groups_get_activity_groupmode($workshop->cm); $groupid = groups_get_activity_group($workshop->cm, true); if ($groupmode == SEPARATEGROUPS && !has_capability('moodle/site:accessallgroups', $workshop->context)) { $allowedgroups = groups_get_activity_allowed_groups($workshop->cm); if (empty($allowedgroups)) { $output .= $this->container(get_string('groupnoallowed', 'mod_workshop'), 'groupwidget error'); break; } if (!in_array($groupid, array_keys($allowedgroups))) { $output .= $this->container(get_string('groupnotamember', 'core_group'), 'groupwidget error'); break; } } $output .= print_collapsible_region_start('', 'workshop-viewlet-allsubmissions', get_string('submissionsreport', 'workshop'), 'workshop-viewlet-allsubmissions-collapsed', false, true); $perpage = get_user_preferences('workshop_perpage', 10); $data = $workshop->prepare_grading_report_data($USER->id, $groupid, $page, $perpage, $sortby, $sorthow); if ($data) { $countparticipants = $workshop->count_participants(); $countsubmissions = $workshop->count_submissions(array_keys($data->grades), $groupid); $a = new stdClass(); $a->submitted = $countsubmissions; $a->notsubmitted = $data->totalcount - $countsubmissions; $output .= html_writer::tag('div', get_string('submittednotsubmitted', 'workshop', $a)); $output .= $this->container( groups_print_activity_menu($workshop->cm, $this->page->url, true), 'groupwidget'); // Prepare the paging bar. $baseurl = new moodle_url($this->page->url, ['sortby' => $sortby, 'sorthow' => $sorthow]); $pagingbar = new paging_bar($data->totalcount, $page, $perpage, $baseurl, 'page'); // Populate the display options for the submissions report. $reportopts = new stdclass(); $reportopts->showauthornames = has_capability('mod/workshop:viewauthornames', $workshop->context); $reportopts->showreviewernames = has_capability('mod/workshop:viewreviewernames', $workshop->context); $reportopts->sortby = $sortby; $reportopts->sorthow = $sorthow; $reportopts->showsubmissiongrade = false; $reportopts->showgradinggrade = false; $reportopts->workshopphase = $workshop->phase; $output .= $this->initials_bars($workshop, $baseurl); $output .= $this->render($pagingbar); $output .= $this->render(new workshop_grading_report($data, $reportopts)); $output .= $this->render($pagingbar); $output .= $this->perpage_selector($perpage); } else { $output .= html_writer::tag('div', get_string('nothingfound', 'workshop'), 'info', false); } $output .= print_collapsible_region_end(true); } break; case workshop::PHASE_ASSESSMENT: $ownsubmissionexists = null; if (has_capability('mod/workshop:submit', $this->page->context)) { if ($ownsubmission = $workshop->get_submission_by_author($USER->id)) { $output .= print_collapsible_region_start('', 'workshop-viewlet-ownsubmission', get_string('yoursubmission', 'workshop'), 'workshop-viewlet-ownsubmission-collapsed', true, true); $output .= $this->box_start('generalbox ownsubmission'); $output .= $this->render($workshop->prepare_submission_summary($ownsubmission, true)); $ownsubmissionexists = true; } else { $output .= print_collapsible_region_start('', 'workshop-viewlet-ownsubmission', get_string('yoursubmission', 'workshop'), 'workshop-viewlet-ownsubmission-collapsed', false, true); $output .= $this->box_start('generalbox ownsubmission'); $output .= $this->container(get_string('noyoursubmission', 'workshop')); $ownsubmissionexists = false; } $output .= $this->box_end(); $output .= print_collapsible_region_end(true); } if (has_capability('mod/workshop:viewallassessments', $this->page->context)) { $perpage = get_user_preferences('workshop_perpage', 10); $groupid = groups_get_activity_group($workshop->cm, true); $data = $workshop->prepare_grading_report_data($USER->id, $groupid, $page, $perpage, $sortby, $sorthow); if ($data) { $showauthornames = has_capability('mod/workshop:viewauthornames', $workshop->context); $showreviewernames = has_capability('mod/workshop:viewreviewernames', $workshop->context); // Prepare paging bar. $baseurl = new moodle_url($this->page->url, ['sortby' => $sortby, 'sorthow' => $sorthow]); $pagingbar = new paging_bar($data->totalcount, $page, $perpage, $baseurl, 'page'); // Grading report display options. $reportopts = new stdclass(); $reportopts->showauthornames = $showauthornames; $reportopts->showreviewernames = $showreviewernames; $reportopts->sortby = $sortby; $reportopts->sorthow = $sorthow; $reportopts->showsubmissiongrade = false; $reportopts->showgradinggrade = false; $reportopts->workshopphase = $workshop->phase; $output .= print_collapsible_region_start('', 'workshop-viewlet-gradereport', get_string('gradesreport', 'workshop'), 'workshop-viewlet-gradereport-collapsed', false, true); $output .= $this->box_start('generalbox gradesreport'); $output .= $this->container(groups_print_activity_menu($workshop->cm, $this->page->url, true), 'groupwidget'); $output .= $this->initials_bars($workshop, $baseurl); $output .= $this->render($pagingbar); $output .= $this->render(new workshop_grading_report($data, $reportopts)); $output .= $this->render($pagingbar); $output .= $this->perpage_selector($perpage); $output .= $this->box_end(); $output .= print_collapsible_region_end(true); } } if (trim($workshop->instructreviewers)) { $instructions = file_rewrite_pluginfile_urls($workshop->instructreviewers, 'pluginfile.php', $this->page->context->id, 'mod_workshop', 'instructreviewers', null, workshop::instruction_editors_options($this->page->context)); $output .= print_collapsible_region_start('', 'workshop-viewlet-instructreviewers', get_string('instructreviewers', 'workshop'), 'workshop-viewlet-instructreviewers-collapsed', false, true); $output .= $this->box(format_text($instructions, $workshop->instructreviewersformat, ['overflowdiv' => true]), ['generalbox', 'instructions']); $output .= print_collapsible_region_end(true); } // Does the user have to assess examples before assessing other's work? $examplesmust = ($workshop->useexamples && $workshop->examplesmode == workshop::EXAMPLES_BEFORE_ASSESSMENT); // Is the assessment of example submissions considered finished? $examplesdone = has_capability('mod/workshop:manageexamples', $workshop->context); // Can the examples be assessed? $examplesavailable = true; if (!$examplesdone && $examplesmust && ($ownsubmissionexists === false)) { $output .= print_collapsible_region_start('', 'workshop-viewlet-examplesfail', get_string('exampleassessments', 'workshop'), 'workshop-viewlet-examplesfail-collapsed', false, true); $output .= $this->box(get_string('exampleneedsubmission', 'workshop')); $output .= print_collapsible_region_end(true); $examplesavailable = false; } if ($workshop->assessing_examples_allowed() && has_capability('mod/workshop:submit', $workshop->context) && !has_capability('mod/workshop:manageexamples', $workshop->context) && $examplesavailable) { $examples = $userplan->get_examples(); $total = count($examples); $left = 0; // Make sure the current user has all examples allocated. foreach ($examples as $exampleid => $example) { if (is_null($example->assessmentid)) { $examples[$exampleid]->assessmentid = $workshop->add_allocation($example, $USER->id, 0); } if (is_null($example->grade)) { $left++; } } if ($left > 0 && $workshop->examplesmode != workshop::EXAMPLES_VOLUNTARY) { $examplesdone = false; } else { $examplesdone = true; } $output .= print_collapsible_region_start('', 'workshop-viewlet-examples', get_string('exampleassessments', 'workshop'), 'workshop-viewlet-examples-collapsed', $examplesdone, true); $output .= $this->box_start('generalbox exampleassessments'); if ($total == 0) { $output .= $this->heading(get_string('noexamples', 'workshop'), 3); } else { foreach ($examples as $example) { $summary = $workshop->prepare_example_summary($example); $output .= $this->render($summary); } } $output .= $this->box_end(); $output .= print_collapsible_region_end(true); } if (!$examplesmust || $examplesdone) { $output .= print_collapsible_region_start('', 'workshop-viewlet-assignedassessments', get_string('assignedassessments', 'workshop'), 'workshop-viewlet-assignedassessments-collapsed', false, true); if (!$assessments = $workshop->get_assessments_by_reviewer($USER->id)) { $output .= $this->box_start('generalbox assessment-none'); $output .= $this->notification(get_string('assignedassessmentsnone', 'workshop')); $output .= $this->box_end(); } else { $shownames = has_capability('mod/workshop:viewauthornames', $this->page->context); foreach ($assessments as $assessment) { $submission = new stdClass(); $submission->id = $assessment->submissionid; $submission->title = $assessment->submissiontitle; $submission->timecreated = $assessment->submissioncreated; $submission->timemodified = $assessment->submissionmodified; $userpicturefields = explode(',', implode(',', \core_user\fields::get_picture_fields())); foreach ($userpicturefields as $userpicturefield) { $prefixedusernamefield = 'author' . $userpicturefield; $submission->$prefixedusernamefield = $assessment->$prefixedusernamefield; } // Transform the submission object into renderable component. $submission = $workshop->prepare_submission_summary($submission, $shownames); if (is_null($assessment->grade)) { $submission->status = 'notgraded'; $class = ' notgraded'; $buttontext = get_string('assess', 'workshop'); } else { $submission->status = 'graded'; $class = ' graded'; $buttontext = get_string('reassess', 'workshop'); } $output .= $this->box_start('generalbox assessment-summary' . $class); $output .= $this->render($submission); $aurl = $workshop->assess_url($assessment->id); $output .= $this->single_button($aurl, $buttontext, 'get'); $output .= $this->box_end(); } } $output .= print_collapsible_region_end(true); } break; case workshop::PHASE_EVALUATION: if (has_capability('mod/workshop:viewallassessments', $this->page->context)) { $perpage = get_user_preferences('workshop_perpage', 10); $groupid = groups_get_activity_group($workshop->cm, true); $data = $workshop->prepare_grading_report_data($USER->id, $groupid, $page, $perpage, $sortby, $sorthow); if ($data) { $showauthornames = has_capability('mod/workshop:viewauthornames', $workshop->context); $showreviewernames = has_capability('mod/workshop:viewreviewernames', $workshop->context); if (has_capability('mod/workshop:overridegrades', $this->page->context)) { // Print a drop-down selector to change the current evaluation method. $selector = new single_select($this->page->url, 'eval', workshop::available_evaluators_list(), $workshop->evaluation, false, 'evaluationmethodchooser'); $selector->set_label(get_string('evaluationmethod', 'mod_workshop')); $selector->set_help_icon('evaluationmethod', 'mod_workshop'); $selector->method = 'post'; $output .= $this->render($selector); // Load the grading evaluator. $evaluator = $workshop->grading_evaluation_instance(); $form = $evaluator->get_settings_form(new moodle_url($workshop->aggregate_url(), compact('sortby', 'sorthow', 'page'))); $form->display(); } // Prepare paging bar. $baseurl = new moodle_url($this->page->url, ['sortby' => $sortby, 'sorthow' => $sorthow]); $pagingbar = new paging_bar($data->totalcount, $page, $perpage, $baseurl, 'page'); // Grading report display options. $reportopts = new stdclass(); $reportopts->showauthornames = $showauthornames; $reportopts->showreviewernames = $showreviewernames; $reportopts->sortby = $sortby; $reportopts->sorthow = $sorthow; $reportopts->showsubmissiongrade = true; $reportopts->showgradinggrade = true; $reportopts->workshopphase = $workshop->phase; $output .= print_collapsible_region_start('', 'workshop-viewlet-gradereport', get_string('gradesreport', 'workshop'), 'workshop-viewlet-gradereport-collapsed', false, true); $output .= $this->box_start('generalbox gradesreport'); $output .= $this->container(groups_print_activity_menu($workshop->cm, $this->page->url, true), 'groupwidget'); $output .= $this->initials_bars($workshop, $baseurl); $output .= $this->render($pagingbar); $output .= $this->render(new workshop_grading_report($data, $reportopts)); $output .= $this->render($pagingbar); $output .= $this->perpage_selector($perpage); $output .= $this->box_end(); $output .= print_collapsible_region_end(true); } } if (has_capability('mod/workshop:overridegrades', $workshop->context)) { $output .= print_collapsible_region_start('', 'workshop-viewlet-cleargrades', get_string('toolbox', 'workshop'), 'workshop-viewlet-cleargrades-collapsed', true, true); $output .= $this->box_start('generalbox toolbox'); // Clear aggregated grades. $url = new moodle_url($workshop->toolbox_url('clearaggregatedgrades')); $btn = new single_button($url, get_string('clearaggregatedgrades', 'workshop'), 'post'); $btn->add_confirm_action(get_string('clearaggregatedgradesconfirm', 'workshop')); $output .= $this->container_start('toolboxaction'); $output .= $this->render($btn); $output .= $this->help_icon('clearaggregatedgrades', 'workshop'); $output .= $this->container_end(); // Clear assessments. $url = new moodle_url($workshop->toolbox_url('clearassessments')); $btn = new single_button($url, get_string('clearassessments', 'workshop'), 'post'); $btn->add_confirm_action(get_string('clearassessmentsconfirm', 'workshop')); $output .= $this->container_start('toolboxaction'); $output .= $this->render($btn); $output .= $this->help_icon('clearassessments', 'workshop'); $output .= $this->output->pix_icon('i/risk_dataloss', get_string('riskdatalossshort', 'admin')); $output .= $this->container_end(); $output .= $this->box_end(); $output .= print_collapsible_region_end(true); } if (has_capability('mod/workshop:submit', $this->page->context)) { $output .= print_collapsible_region_start('', 'workshop-viewlet-ownsubmission', get_string('yoursubmission', 'workshop'), 'workshop-viewlet-ownsubmission-collapsed', false, true); $output .= $this->box_start('generalbox ownsubmission'); if ($submission = $workshop->get_submission_by_author($USER->id)) { $output .= $this->render($workshop->prepare_submission_summary($submission, true)); } else { $output .= $this->container(get_string('noyoursubmission', 'workshop')); } $output .= $this->box_end(); $output .= print_collapsible_region_end(true); } if ($assessments = $workshop->get_assessments_by_reviewer($USER->id)) { $output .= print_collapsible_region_start('', 'workshop-viewlet-assignedassessments', get_string('assignedassessments', 'workshop'), 'workshop-viewlet-assignedassessments-collapsed', false, true); $shownames = has_capability('mod/workshop:viewauthornames', $this->page->context); foreach ($assessments as $assessment) { $submission = new stdclass(); $submission->id = $assessment->submissionid; $submission->title = $assessment->submissiontitle; $submission->timecreated = $assessment->submissioncreated; $submission->timemodified = $assessment->submissionmodified; $userpicturefields = explode(',', implode(',', \core_user\fields::get_picture_fields())); foreach ($userpicturefields as $userpicturefield) { $prefixedusernamefield = 'author' . $userpicturefield; $submission->$prefixedusernamefield = $assessment->$prefixedusernamefield; } if (is_null($assessment->grade)) { $class = ' notgraded'; $submission->status = 'notgraded'; $buttontext = get_string('assess', 'workshop'); } else { $class = ' graded'; $submission->status = 'graded'; $buttontext = get_string('reassess', 'workshop'); } $output .= $this->box_start('generalbox assessment-summary' . $class); $output .= $this->render($workshop->prepare_submission_summary($submission, $shownames)); $output .= $this->box_end(); } $output .= print_collapsible_region_end(true); } break; case workshop::PHASE_CLOSED: if (trim($workshop->conclusion)) { $conclusion = file_rewrite_pluginfile_urls($workshop->conclusion, 'pluginfile.php', $workshop->context->id, 'mod_workshop', 'conclusion', null, workshop::instruction_editors_options($workshop->context)); $output .= print_collapsible_region_start('', 'workshop-viewlet-conclusion', get_string('conclusion', 'workshop'), 'workshop-viewlet-conclusion-collapsed', false, true); $output .= $this->box(format_text($conclusion, $workshop->conclusionformat, ['overflowdiv' => true]), ['generalbox', 'conclusion']); $output .= print_collapsible_region_end(true); } $finalgrades = $workshop->get_gradebook_grades($USER->id); if (!empty($finalgrades)) { $output .= print_collapsible_region_start('', 'workshop-viewlet-yourgrades', get_string('yourgrades', 'workshop'), 'workshop-viewlet-yourgrades-collapsed', false, true); $output .= $this->box_start('generalbox grades-yourgrades'); $output .= $this->render($finalgrades); $output .= $this->box_end(); $output .= print_collapsible_region_end(true); } if (has_capability('mod/workshop:viewallassessments', $this->page->context)) { $perpage = get_user_preferences('workshop_perpage', 10); $groupid = groups_get_activity_group($workshop->cm, true); $data = $workshop->prepare_grading_report_data($USER->id, $groupid, $page, $perpage, $sortby, $sorthow); if ($data) { $showauthornames = has_capability('mod/workshop:viewauthornames', $workshop->context); $showreviewernames = has_capability('mod/workshop:viewreviewernames', $workshop->context); // Prepare paging bar. $baseurl = new moodle_url($this->page->url, ['sortby' => $sortby, 'sorthow' => $sorthow]); $pagingbar = new paging_bar($data->totalcount, $page, $perpage, $baseurl, 'page'); // Grading report display options. $reportopts = new stdclass(); $reportopts->showauthornames = $showauthornames; $reportopts->showreviewernames = $showreviewernames; $reportopts->sortby = $sortby; $reportopts->sorthow = $sorthow; $reportopts->showsubmissiongrade = true; $reportopts->showgradinggrade = true; $reportopts->workshopphase = $workshop->phase; $output .= print_collapsible_region_start('', 'workshop-viewlet-gradereport', get_string('gradesreport', 'workshop'), 'workshop-viewlet-gradereport-collapsed', false, true); $output .= $this->box_start('generalbox gradesreport'); $output .= $this->container(groups_print_activity_menu($workshop->cm, $this->page->url, true), 'groupwidget'); $output .= $this->initials_bars($workshop, $baseurl); $output .= $this->render($pagingbar); $output .= $this->render(new workshop_grading_report($data, $reportopts)); $output .= $this->render($pagingbar); $output .= $this->perpage_selector($perpage); $output .= $this->box_end(); $output .= print_collapsible_region_end(true); } } if (has_capability('mod/workshop:submit', $this->page->context)) { $output .= print_collapsible_region_start('', 'workshop-viewlet-ownsubmission', get_string('yoursubmissionwithassessments', 'workshop'), 'workshop-viewlet-ownsubmission-collapsed', false, true); $output .= $this->box_start('generalbox ownsubmission'); if ($submission = $workshop->get_submission_by_author($USER->id)) { $output .= $this->render($workshop->prepare_submission_summary($submission, true)); } else { $output .= $this->container(get_string('noyoursubmission', 'workshop')); } $output .= $this->box_end(); if (!empty($submission->gradeoverby) && strlen(trim($submission->feedbackauthor)) > 0) { $output .= $this->render(new workshop_feedback_author($submission)); } $output .= print_collapsible_region_end(true); } if (has_capability('mod/workshop:viewpublishedsubmissions', $workshop->context)) { $shownames = has_capability('mod/workshop:viewauthorpublished', $workshop->context); if ($submissions = $workshop->get_published_submissions()) { $output .= print_collapsible_region_start('', 'workshop-viewlet-publicsubmissions', get_string('publishedsubmissions', 'workshop'), 'workshop-viewlet-publicsubmissions-collapsed', false, true); foreach ($submissions as $submission) { $output .= $this->box_start('generalbox submission-summary'); $output .= $this->render($workshop->prepare_submission_summary($submission, $shownames)); $output .= $this->box_end(); } $output .= print_collapsible_region_end(); } } if ($assessments = $workshop->get_assessments_by_reviewer($USER->id)) { $output .= print_collapsible_region_start('', 'workshop-viewlet-assignedassessments', get_string('assignedassessments', 'workshop'), 'workshop-viewlet-assignedassessments-collapsed', false, true); $shownames = has_capability('mod/workshop:viewauthornames', $this->page->context); foreach ($assessments as $assessment) { $submission = new stdclass(); $submission->id = $assessment->submissionid; $submission->title = $assessment->submissiontitle; $submission->timecreated = $assessment->submissioncreated; $submission->timemodified = $assessment->submissionmodified; $userpicturefields = explode(',', implode(',', \core_user\fields::get_picture_fields())); foreach ($userpicturefields as $userpicturefield) { $prefixedusernamefield = 'author' . $userpicturefield; $submission->$prefixedusernamefield = $assessment->$prefixedusernamefield; } if (is_null($assessment->grade)) { $class = ' notgraded'; $submission->status = 'notgraded'; $buttontext = get_string('assess', 'workshop'); } else { $class = ' graded'; $submission->status = 'graded'; $buttontext = get_string('reassess', 'workshop'); } $output .= $this->box_start('generalbox assessment-summary' . $class); $output .= $this->render($workshop->prepare_submission_summary($submission, $shownames)); $output .= $this->box_end(); if (!empty($assessment->feedbackreviewer) && strlen(trim($assessment->feedbackreviewer)) > 0) { $output .= $this->render(new workshop_feedback_reviewer($assessment)); } } $output .= print_collapsible_region_end(true); } break; default: } return $output; } } home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/mod/forum/renderer.php000064400000027403152267116240023123 0ustar00. /** * This file contains a custom renderer class used by the forum module. * * @package mod_forum * @copyright 2009 Sam Hemelryk * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ /** * A custom renderer class that extends the plugin_renderer_base and * is used by the forum module. * * @package mod_forum * @copyright 2009 Sam Hemelryk * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later **/ class mod_forum_renderer extends plugin_renderer_base { /** * Returns the navigation to the previous and next discussion. * * @param mixed $prev Previous discussion record, or false. * @param mixed $next Next discussion record, or false. * @return string The output. */ public function neighbouring_discussion_navigation($prev, $next) { $html = ''; if ($prev || $next) { $html .= html_writer::start_tag('nav', [ 'class' => 'discussion-nav clearfix', 'aria-label' => get_string('browsediscussions', 'mod_forum'), ]); $html .= html_writer::start_tag('ul'); if ($prev) { $url = new moodle_url('/mod/forum/discuss.php', array('d' => $prev->id)); $html .= html_writer::start_tag('li', array('class' => 'prev-discussion')); $html .= html_writer::link($url, $this->output->larrow() . ' ' . format_string($prev->name), array('aria-label' => get_string('prevdiscussiona', 'mod_forum', format_string($prev->name)), 'class' => 'btn btn-link')); $html .= html_writer::end_tag('li'); } if ($next) { $url = new moodle_url('/mod/forum/discuss.php', array('d' => $next->id)); $html .= html_writer::start_tag('li', array('class' => 'next-discussion')); $html .= html_writer::link($url, format_string($next->name) . ' ' . $this->output->rarrow(), array('aria-label' => get_string('nextdiscussiona', 'mod_forum', format_string($next->name)), 'class' => 'btn btn-link')); $html .= html_writer::end_tag('li'); } $html .= html_writer::end_tag('ul'); $html .= html_writer::end_tag('nav'); } return $html; } /** * This method is used to generate HTML for a subscriber selection form that * uses two user_selector controls * * @param user_selector_base $existinguc * @param user_selector_base $potentialuc * @return string */ public function subscriber_selection_form(user_selector_base $existinguc, user_selector_base $potentialuc) { $output = ''; $formattributes = array(); $formattributes['id'] = 'subscriberform'; $formattributes['action'] = ''; $formattributes['method'] = 'post'; $output .= html_writer::start_tag('form', $formattributes); $output .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'sesskey', 'value'=>sesskey())); $existingcell = new html_table_cell(); $existingcell->text = $existinguc->display(true); $existingcell->attributes['class'] = 'existing'; $actioncell = new html_table_cell(); $actioncell->text = html_writer::start_tag('div', array()); $actioncell->text .= html_writer::empty_tag('input', array('type'=>'submit', 'name'=>'subscribe', 'value'=>$this->page->theme->larrow.' '.get_string('add'), 'class'=>'actionbutton')); $actioncell->text .= html_writer::empty_tag('br', array()); $actioncell->text .= html_writer::empty_tag('input', array('type'=>'submit', 'name'=>'unsubscribe', 'value'=>$this->page->theme->rarrow.' '.get_string('remove'), 'class'=>'actionbutton')); $actioncell->text .= html_writer::end_tag('div', array()); $actioncell->attributes['class'] = 'actions'; $potentialcell = new html_table_cell(); $potentialcell->text = $potentialuc->display(true); $potentialcell->attributes['class'] = 'potential'; $table = new html_table(); $table->attributes['class'] = 'subscribertable boxaligncenter'; $table->data = array(new html_table_row(array($existingcell, $actioncell, $potentialcell))); $output .= html_writer::table($table); $output .= html_writer::end_tag('form'); return $output; } /** * This function generates HTML to display a subscriber overview, primarily used on * the subscribers page if editing was turned off * * @param array $users * @param object $forum * @param object $course * @return string */ public function subscriber_overview($users, $forum , $course) { $output = ''; $modinfo = get_fast_modinfo($course); if (!$users || !is_array($users) || count($users)===0) { $output .= $this->output->notification( get_string("nosubscribers", "forum"), \core\output\notification::NOTIFY_INFO, false); } else if (!isset($modinfo->instances['forum'][$forum->id])) { $output .= $this->output->heading(get_string("invalidmodule", "error")); } else { $cm = $modinfo->instances['forum'][$forum->id]; // TODO Does not support custom user profile fields (MDL-70456). $canviewemail = in_array('email', \core_user\fields::get_identity_fields(context_module::instance($cm->id), false)); $strparams = new stdclass(); $strparams->name = format_string($forum->name); $strparams->count = count($users); $output .= $this->output->heading(get_string("subscriberstowithcount", "forum", $strparams)); $table = new html_table(); $table->id = 'subscribers-table'; $table->head = []; $table->head[] = get_string('pictureofuser'); $table->head[] = get_string('fullname'); if ($canviewemail) { $table->head[] = get_string('email'); } $table->cellpadding = 5; $table->cellspacing = 5; $table->tablealign = 'center'; $table->data = array(); foreach ($users as $user) { $info = array($this->output->user_picture($user, array('courseid'=>$course->id)), fullname($user)); if ($canviewemail) { array_push($info, $user->email); } $table->data[] = $info; } $output .= html_writer::table($table); } return $output; } /** * This is used to display a control containing all of the subscribed users so that * it can be searched * * @param user_selector_base $existingusers * @return string */ public function subscribed_users(user_selector_base $existingusers) { $output = $this->output->box_start('subscriberdiv boxaligncenter'); $output .= html_writer::tag('p', get_string('forcesubscribed', 'forum')); $output .= $existingusers->display(true); $output .= $this->output->box_end(); return $output; } /** * Generate the HTML for an icon to be displayed beside the subject of a timed discussion. * * @param object $discussion * @param bool $visiblenow Indicicates that the discussion is currently * visible to all users. * @return string */ public function timed_discussion_tooltip($discussion, $visiblenow) { $dates = array(); if ($discussion->timestart) { $dates[] = get_string('displaystart', 'mod_forum').': '.userdate($discussion->timestart); } if ($discussion->timeend) { $dates[] = get_string('displayend', 'mod_forum').': '.userdate($discussion->timeend); } $str = $visiblenow ? 'timedvisible' : 'timedhidden'; $dates[] = get_string($str, 'mod_forum'); $tooltip = implode("\n", $dates); return $this->pix_icon('i/calendar', $tooltip, 'moodle', array('class' => 'smallicon timedpost')); } /** * Display a forum post in the relevant context. * * @param \mod_forum\output\forum_post $post The post to display. * @return string */ public function render_forum_post_email(\mod_forum\output\forum_post_email $post) { $data = $post->export_for_template($this, $this->target === RENDERER_TARGET_TEXTEMAIL); return $this->render_from_template('mod_forum/' . $this->forum_post_template(), $data); } /** * The template name for this renderer. * * @return string */ public function forum_post_template() { return 'forum_post'; } /** * Create the inplace_editable used to select forum digest options. * * @param stdClass $forum The forum to create the editable for. * @param int $value The current value for this user * @return inplace_editable */ public function render_digest_options($forum, $value) { $options = forum_get_user_digest_options(); $editable = new \core\output\inplace_editable( 'mod_forum', 'digestoptions', $forum->id, true, $options[$value], $value ); $editable->set_type_select($options); return $editable; } /** * Render quick search form. * * @param \mod_forum\output\quick_search_form $form The renderable. * @return string rendered HTML string from the template. */ public function render_quick_search_form(\mod_forum\output\quick_search_form $form) { if (strpos($this->page->url->get_path(), "index.php")) { return $this->render_from_template('mod_forum/quick_search_form', $form->export_for_template($this)); } return $this->render_from_template('mod_forum/forum_new_discussion_actionbar', $form->export_for_template($this)); } /** * Render the view action area. * * @param \mod_forum\output\forum_actionbar $actionbar forum_actionbar object. * @return string rendered HTML string */ public function render_activity_actionbar(\mod_forum\output\forum_actionbar $actionbar): string { return $this->render_from_template('mod_forum/forum_actionbar', $actionbar->export_for_template($this)); } /** * Render the subscription action area. * * @param \mod_forum\output\subscription_actionbar $subscriptionactionbar subscription_actionbar object. * @return bool|string rendered HTML string. */ public function subscription_actionbar(\mod_forum\output\subscription_actionbar $subscriptionactionbar): string { return $this->render_from_template('mod_forum/forum_subscription_action', $subscriptionactionbar->export_for_template($this)); } /** * Render big search form. * * @param \mod_forum\output\big_search_form $form The renderable. * @return string */ public function render_big_search_form(\mod_forum\output\big_search_form $form) { return $this->render_from_template('mod_forum/big_search_form', $form->export_for_template($this)); } } home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/mod/quiz/renderer.php000064400000002232152267120230022746 0ustar00. /** * File only retained to prevent fatal errors in code that tries to require/include this. * * @todo MDL-76612 delete this file as part of Moodle 4.6 development. * @deprecated This file is no longer required in Moodle 4.2+. */ // Normally I would debug-output // 'This file is no longer required in Moodle 4.2+. Please do not include/require it.' // but this file gets automatically included by the renderer factories in a way that // is hard to prevent, so not doing that here. home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/mod/lesson/renderer.php000064400000067763152267122740023315 0ustar00. /** * Moodle renderer used to display special elements of the lesson module * * @package mod_lesson * @copyright 2009 Sam Hemelryk * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later **/ defined('MOODLE_INTERNAL') || die(); class mod_lesson_renderer extends plugin_renderer_base { /** * Returns the header for the lesson module * * @param lesson $lesson a lesson object. * @param string $currenttab current tab that is shown. * @param bool $extraeditbuttons if extra edit buttons should be displayed. * @param int $lessonpageid id of the lesson page that needs to be displayed. * @param string $extrapagetitle String to appent to the page title. * @return string */ public function header($lesson, $cm, $currenttab = '', $extraeditbuttons = false, $lessonpageid = null, $extrapagetitle = null) { global $CFG, $USER; $activityname = format_string($lesson->name, true, $lesson->course); if (empty($extrapagetitle)) { $title = $this->page->course->shortname.": ".$activityname; } else { $title = $this->page->course->shortname.": ".$activityname.": ".$extrapagetitle; } // Build the buttons $context = context_module::instance($cm->id); // Header setup. $this->page->set_title($title); $this->page->set_heading($this->page->course->fullname); $canmanage = has_capability('mod/lesson:manage', $context); $activityheader = $this->page->activityheader; $activitypage = new moodle_url('/mod/' . $this->page->activityname . '/view.php'); $setactive = $activitypage->compare($this->page->url, URL_MATCH_BASE); if ($activityheader->is_title_allowed()) { $title = $canmanage && $setactive ? $this->output->heading_with_help($activityname, 'overview', 'lesson') : $activityname; $activityheader->set_title($title); } // If we have the capability to manage the lesson but not within the view page, // there's no reason to show activity/completion information. if ($canmanage && !$setactive) { $activityheader->set_hidecompletion(true); } $output = $this->output->header(); foreach ($lesson->messages as $message) { $output .= $this->output->notification($message[0], $message[1], $message[2]); } return $output; } /** * Returns the footer * @return string */ public function footer() { return $this->output->footer(); } /** * Returns HTML for a lesson inaccessible message * * @param string $message * @return */ public function lesson_inaccessible($message) { global $CFG; $output = $this->output->box_start('generalbox boxaligncenter'); $output .= $this->output->box_start('center'); $output .= $message; $output .= $this->output->box(''. get_string('returnto', 'lesson', format_string($this->page->course->fullname, true)) .'', 'lessonbutton standardbutton'); $output .= $this->output->box_end(); $output .= $this->output->box_end(); return $output; } /** * Returns HTML to prompt the user to log in * @param lesson $lesson * @param bool $failedattempt * @return string */ public function login_prompt(lesson $lesson, $failedattempt = false) { global $CFG; $output = $this->output->box_start('password-form'); $output .= $this->output->box_start('generalbox boxaligncenter'); $output .= '
'; $output .= '
'; $output .= ''; $output .= ''; if ($failedattempt) { $output .= $this->output->notification(get_string('loginfail', 'lesson')); } $output .= get_string('passwordprotectedlesson', 'lesson', format_string($lesson->name)).'

'; $output .= get_string('enterpassword', 'lesson')."

"; $output .= "
"; $output .= "
"; $output .= '
'; $output .= $this->output->box_end(); $output .= $this->output->box_end(); return $output; } /** * Returns HTML to display dependancy errors * * @param object $dependentlesson * @param array $errors * @return string */ public function dependancy_errors($dependentlesson, $errors) { $output = $this->output->box_start('generalbox boxaligncenter'); $output .= get_string('completethefollowingconditions', 'lesson', $dependentlesson->name); $output .= $this->output->box(implode('
'.get_string('and', 'lesson').'
', $errors),'center'); $output .= $this->output->box_end(); return $output; } /** * Returns HTML to display a message * @param string $message * @param single_button $button * @return string */ public function message($message, ?single_button $button = null) { $output = $this->output->box_start('generalbox boxaligncenter'); $output .= $message; if ($button !== null) { $output .= $this->output->box($this->output->render($button), 'lessonbutton standardbutton'); } $output .= $this->output->box_end(); return $output; } /** * Returns HTML to display a continue button * @param lesson $lesson * @param int $lastpageseen * @return string */ public function continue_links(lesson $lesson, $lastpageseenid) { global $CFG; $output = $this->output->box(get_string('youhaveseen','lesson'), 'generalbox boxaligncenter'); $output .= $this->output->box_start('center'); $yeslink = html_writer::link(new moodle_url('/mod/lesson/view.php', array('id' => $this->page->cm->id, 'pageid' => $lastpageseenid, 'startlastseen' => 'yes')), get_string('yes'), array('class' => 'btn btn-primary')); $output .= html_writer::tag('span', $yeslink, array('class'=>'lessonbutton standardbutton')); $output .= ' '; $nolink = html_writer::link(new moodle_url('/mod/lesson/view.php', array('id' => $this->page->cm->id, 'pageid' => $lesson->firstpageid, 'startlastseen' => 'no')), get_string('no'), array('class' => 'btn btn-secondary')); $output .= html_writer::tag('span', $nolink, array('class'=>'lessonbutton standardbutton')); $output .= $this->output->box_end(); return $output; } /** * Returns HTML to display a page to the user * @param lesson $lesson * @param lesson_page $page * @param object $attempt * @return string */ public function display_page(lesson $lesson, lesson_page $page, $attempt) { // We need to buffer here as there is an mforms display call ob_start(); echo $page->display($this, $attempt); $output = ob_get_contents(); ob_end_clean(); return $output; } /** * Returns HTML to display a collapsed edit form * * @param lesson $lesson * @param int $pageid * @return string */ public function display_edit_collapsed(lesson $lesson, $pageid) { global $DB, $CFG; $manager = lesson_page_type_manager::get($lesson); $qtypes = $manager->get_page_type_strings(); $npages = count($lesson->load_all_pages()); $table = new html_table(); $table->head = array(get_string('pagetitle', 'lesson'), get_string('qtype', 'lesson'), get_string('jumps', 'lesson'), get_string('actions', 'lesson')); $table->align = array('left', 'left', 'left', 'center'); $table->data = array(); $canedit = has_capability('mod/lesson:edit', context_module::instance($this->page->cm->id)); while ($pageid != 0) { $page = $lesson->load_page($pageid); $data = array(); $url = new moodle_url('/mod/lesson/edit.php', array( 'id' => $this->page->cm->id, 'mode' => 'single', 'pageid' => $page->id )); $data[] = html_writer::link($url, format_string($page->title, true), array('id' => 'lesson-' . $page->id)); $data[] = $qtypes[$page->qtype]; $data[] = implode("
\n", $page->jumps); if ($canedit) { $data[] = $this->page_action_links($page, $npages, true); } else { $data[] = ''; } $table->data[] = $data; $pageid = $page->nextpageid; } return html_writer::table($table); } /** * Returns HTML to display the full edit page * * @param lesson $lesson * @param int $pageid * @param int $prevpageid * @param bool $single * @return string */ public function display_edit_full(lesson $lesson, $pageid, $prevpageid, $single=false) { global $DB, $CFG; $manager = lesson_page_type_manager::get($lesson); $qtypes = $manager->get_page_type_strings(); $npages = count($lesson->load_all_pages()); $canedit = has_capability('mod/lesson:edit', context_module::instance($this->page->cm->id)); $content = ''; if ($canedit) { $content = $this->add_page_links($lesson, $prevpageid); } $options = new stdClass; $options->noclean = true; while ($pageid != 0 && $single!=='stop') { $page = $lesson->load_page($pageid); $pagetable = new html_table(); $pagetable->align = array('right','left'); $pagetable->width = '100%'; $pagetable->tablealign = 'center'; $pagetable->cellspacing = 0; $pagetable->cellpadding = '5px'; $pagetable->data = array(); $pageheading = new html_table_cell(); $pageheading->text = html_writer::tag('a', '', array('id' => 'lesson-' . $pageid)) . format_string($page->title); if ($canedit) { $pageheading->text .= ' '.$this->page_action_links($page, $npages); } $pageheading->style = 'text-align:center'; $pageheading->colspan = 2; $pageheading->scope = 'col'; $pagetable->head = array($pageheading); $cell = new html_table_cell(); $cell->colspan = 2; $cell->style = 'text-align:left'; $cell->text = $page->contents; $pagetable->data[] = new html_table_row(array($cell)); $cell = new html_table_cell(); $cell->colspan = 2; $cell->style = 'text-align:center'; $cell->text = ''.$qtypes[$page->qtype] . $page->option_description_string().''; $pagetable->data[] = new html_table_row(array($cell)); $pagetable = $page->display_answers($pagetable); $content .= html_writer::start_tag('div'); $content .= html_writer::table($pagetable); $content .= html_writer::end_tag('div'); if ($canedit) { $content .= $this->add_page_links($lesson, $pageid); } // check the prev links - fix (silently) if necessary - there was a bug in // versions 1 and 2 when add new pages. Not serious then as the backwards // links were not used in those versions if ($page->prevpageid != $prevpageid) { // fix it $DB->set_field("lesson_pages", "prevpageid", $prevpageid, array("id" => $page->id)); debugging("

***prevpageid of page $page->id set to $prevpageid***"); } $prevpageid = $page->id; $pageid = $page->nextpageid; if ($single === true) { $single = 'stop'; } } return $this->output->box($content, 'edit_pages_box'); } /** * Returns HTML to display the add page links * * @param lesson $lesson * @param int $prevpageid * @return string */ public function add_page_links(lesson $lesson, $prevpageid=false) { global $CFG; $links = array(); $importquestionsurl = new moodle_url('/mod/lesson/import.php',array('id'=>$this->page->cm->id, 'pageid'=>$prevpageid)); $links[] = html_writer::link($importquestionsurl, get_string('importquestions', 'lesson')); $manager = lesson_page_type_manager::get($lesson); foreach($manager->get_add_page_type_links($prevpageid) as $link) { $links[] = html_writer::link($link['addurl'], $link['name']); } $addquestionurl = new moodle_url('/mod/lesson/editpage.php', array('id'=>$this->page->cm->id, 'pageid'=>$prevpageid)); $links[] = html_writer::link($addquestionurl, get_string('addaquestionpagehere', 'lesson')); return $this->output->box(implode(" | \n", $links), 'addlinks'); } /** * Return HTML to display add first page links * @param lesson $lesson * @return string */ public function add_first_page_links(lesson $lesson) { $prevpageid = 0; $headinglevel = $this->page->activityheader->get_heading_level(3); $output = $this->output->heading(get_string("whatdofirst", "lesson"), $headinglevel); $links = array(); $importquestionsurl = new moodle_url('/mod/lesson/import.php',array('id'=>$this->page->cm->id, 'pageid'=>$prevpageid)); $links[] = html_writer::link($importquestionsurl, get_string('importquestions', 'lesson')); $manager = lesson_page_type_manager::get($lesson); foreach ($manager->get_add_page_type_links($prevpageid) as $link) { $link['addurl']->param('firstpage', 1); $links[] = html_writer::link($link['addurl'], $link['name']); } $addquestionurl = new moodle_url('/mod/lesson/editpage.php', array('id'=>$this->page->cm->id, 'pageid'=>$prevpageid, 'firstpage'=>1)); $links[] = html_writer::link($addquestionurl, get_string('addaquestionpage', 'lesson')); return $this->output->box($output.'

'.implode('

', $links).'

', 'generalbox firstpageoptions'); } /** * Returns HTML to display action links for a page * * @param lesson_page $page * @param bool $printmove * @param bool $printaddpage * @return string */ public function page_action_links(lesson_page $page, $printmove, $printaddpage=false) { global $CFG; $actions = array(); if ($printmove) { $url = new moodle_url('/mod/lesson/lesson.php', array('id' => $this->page->cm->id, 'action' => 'move', 'pageid' => $page->id, 'sesskey' => sesskey())); $label = get_string('movepagenamed', 'lesson', format_string($page->title)); $img = $this->output->pix_icon('t/move', $label); $actions[] = html_writer::link($url, $img, array('title' => $label)); } $url = new moodle_url('/mod/lesson/editpage.php', array('id' => $this->page->cm->id, 'pageid' => $page->id, 'edit' => 1)); $label = get_string('updatepagenamed', 'lesson', format_string($page->title)); $img = $this->output->pix_icon('t/edit', $label); $actions[] = html_writer::link($url, $img, array('title' => $label)); // Duplicate action. $url = new moodle_url('/mod/lesson/lesson.php', array('id' => $this->page->cm->id, 'pageid' => $page->id, 'action' => 'duplicate', 'sesskey' => sesskey())); $label = get_string('duplicatepagenamed', 'lesson', format_string($page->title)); $img = $this->output->pix_icon('e/copy', $label, 'mod_lesson'); $actions[] = html_writer::link($url, $img, array('title' => $label)); $url = new moodle_url('/mod/lesson/view.php', array('id' => $this->page->cm->id, 'pageid' => $page->id)); $label = get_string('previewpagenamed', 'lesson', format_string($page->title)); $img = $this->output->pix_icon('t/preview', $label); $actions[] = html_writer::link($url, $img, array('title' => $label)); $url = new moodle_url('/mod/lesson/lesson.php', array('id' => $this->page->cm->id, 'action' => 'confirmdelete', 'pageid' => $page->id, 'sesskey' => sesskey())); $label = get_string('deletepagenamed', 'lesson', format_string($page->title)); $img = $this->output->pix_icon('t/delete', $label); $actions[] = html_writer::link($url, $img, array('title' => $label)); if ($printaddpage) { $options = array(); $manager = lesson_page_type_manager::get($page->lesson); $links = $manager->get_add_page_type_links($page->id); foreach ($links as $link) { $options[$link['type']] = $link['name']; } $options[0] = get_string('addaquestionpage', 'lesson'); $addpageurl = new moodle_url('/mod/lesson/editpage.php', array('id'=>$this->page->cm->id, 'pageid'=>$page->id, 'sesskey'=>sesskey())); $addpageselect = new single_select($addpageurl, 'qtype', $options, null, array(''=>get_string('addanewpage', 'lesson').'...'), 'addpageafter'.$page->id); $addpageselect->attributes = ['aria-label' => get_string('actions', 'lesson')]; $addpageselector = $this->output->render($addpageselect); } if (isset($addpageselector)) { $actions[] = $addpageselector; } return implode(' ', $actions); } /** * Prints the on going message to the user. * * With custom grading On, displays points * earned out of total points possible thus far. * With custom grading Off, displays number of correct * answers out of total attempted. * * @param object $lesson The lesson that the user is taking. * @return void **/ /** * Prints the on going message to the user. * * With custom grading On, displays points * earned out of total points possible thus far. * With custom grading Off, displays number of correct * answers out of total attempted. * * @param lesson $lesson * @return string */ public function ongoing_score(lesson $lesson) { return $this->output->box($lesson->get_ongoing_score_message(), "ongoing center"); } /** * Returns HTML to display a progress bar of progression through a lesson * * @param lesson $lesson * @param int $progress optional, if empty it will be calculated * @return string */ public function progress_bar(lesson $lesson, $progress = null) { $context = context_module::instance($this->page->cm->id); // lesson setting to turn progress bar on or off if (!$lesson->progressbar) { return ''; } // catch teachers if (has_capability('mod/lesson:manage', $context)) { return $this->output->notification(get_string('progressbarteacherwarning2', 'lesson')); } if ($progress === null) { $progress = $lesson->calculate_progress(); } $content = html_writer::start_tag('div'); $content .= html_writer::start_tag('div', array('class' => 'progress')); $content .= html_writer::start_tag('div', array('class' => 'progress-bar bar', 'role' => 'progressbar', 'style' => 'width: ' . $progress .'%', 'aria-valuenow' => $progress, 'aria-valuemin' => 0, 'aria-valuemax' => 100)); $content .= $progress . "%"; $content .= html_writer::end_tag('div'); $content .= html_writer::end_tag('div'); $printprogress = html_writer::tag('div', get_string('progresscompleted', 'lesson', $progress) . $content); return $this->output->box($printprogress, 'progress_bar'); } /** * Returns HTML to show the start of a slideshow * @param lesson $lesson */ public function slideshow_start(lesson $lesson) { $attributes = array(); $attributes['class'] = 'slideshow'; $attributes['style'] = 'background-color:'.$lesson->properties()->bgcolor.';height:'. $lesson->properties()->height.'px;width:'.$lesson->properties()->width.'px;'; $output = html_writer::start_tag('div', $attributes); return $output; } /** * Returns HTML to show the end of a slideshow */ public function slideshow_end() { $output = html_writer::end_tag('div'); return $output; } /** * Returns a P tag containing contents * @param string $contents * @param string $class */ public function paragraph($contents, $class='') { $attributes = array(); if ($class !== '') { $attributes['class'] = $class; } $output = html_writer::tag('p', $contents, $attributes); return $output; } /** * Returns the HTML for displaying the end of lesson page. * * @param lesson $lesson lesson instance * @param stdclass $data lesson data to be rendered * @return string HTML contents */ public function display_eol_page(lesson $lesson, $data) { $output = ''; $canmanage = $lesson->can_manage(); $course = $lesson->courserecord; if ($lesson->custom && !$canmanage && (($data->gradeinfo->nquestions < $lesson->minquestions))) { $output .= $this->box_start('generalbox boxaligncenter'); } if ($data->gradelesson) { $headinglevel = $this->page->activityheader->get_heading_level(); $output .= $this->heading(get_string("congratulations", "lesson"), $headinglevel); $output .= $this->box_start('generalbox boxaligncenter'); } if ($data->notenoughtimespent !== false) { $output .= $this->paragraph(get_string("notenoughtimespent", "lesson", $data->notenoughtimespent), 'center'); } if ($data->numberofpagesviewed !== false) { $output .= $this->paragraph(get_string("numberofpagesviewed", "lesson", $data->numberofpagesviewed), 'center'); } if ($data->youshouldview !== false) { $output .= $this->paragraph(get_string("youshouldview", "lesson", $data->youshouldview), 'center'); } if ($data->numberofcorrectanswers !== false) { $output .= $this->paragraph(get_string("numberofcorrectanswers", "lesson", $data->numberofcorrectanswers), 'center'); } if ($data->displayscorewithessays !== false) { $output .= $this->box(get_string("displayscorewithessays", "lesson", $data->displayscorewithessays), 'center'); } else if ($data->displayscorewithoutessays !== false) { $output .= $this->box(get_string("displayscorewithoutessays", "lesson", $data->displayscorewithoutessays), 'center'); } if ($data->yourcurrentgradeisoutof !== false) { $output .= $this->paragraph(get_string("yourcurrentgradeisoutof", "lesson", $data->yourcurrentgradeisoutof), 'center'); } if ($data->yourcurrentgradeis !== false) { $output .= $this->paragraph(get_string("yourcurrentgradeis", "lesson", $data->yourcurrentgradeis), 'center'); } if ($data->eolstudentoutoftimenoanswers !== false) { $output .= $this->paragraph(get_string("eolstudentoutoftimenoanswers", "lesson")); } if ($data->welldone !== false) { $output .= $this->paragraph(get_string("welldone", "lesson")); } if ($data->progresscompleted !== false) { $output .= $this->progress_bar($lesson, $data->progresscompleted); } if ($data->displayofgrade !== false) { $output .= $this->paragraph(get_string("displayofgrade", "lesson"), 'center'); } $output .= $this->box_end(); // End of Lesson button to Continue. if ($data->reviewlesson !== false) { $output .= html_writer::link($data->reviewlesson, get_string('reviewlesson', 'lesson'), array('class' => 'centerpadded lessonbutton standardbutton pe-3')); } if ($data->modattemptsnoteacher !== false) { $output .= $this->paragraph(get_string("modattemptsnoteacher", "lesson"), 'centerpadded'); } if ($data->activitylink !== false) { $output .= $data->activitylink; } $url = new moodle_url('/course/view.php', array('id' => $course->id)); $output .= html_writer::link($url, get_string('returnto', 'lesson', format_string($course->fullname, true)), array('class' => 'centerpadded lessonbutton standardbutton pe-3')); if (has_capability('gradereport/user:view', context_course::instance($course->id)) && $course->showgrades && $lesson->grade != 0 && !$lesson->practice) { $url = new moodle_url('/grade/index.php', array('id' => $course->id)); $output .= html_writer::link($url, get_string('viewgrades', 'lesson'), array('class' => 'centerpadded lessonbutton standardbutton pe-3')); } return $output; } /** * Render the override action menu. * * @param \mod_lesson\output\override_action_menu $overrideactionmenu The overrideactionmenu * * @return string The rendered override action menu. */ public function render_override_action_menu(\mod_lesson\output\override_action_menu $overrideactionmenu): string { $context = $overrideactionmenu->export_for_template($this); return $this->render_from_template('mod_lesson/override_action_menu', $context); } /** * Render the edit action buttons. * * @param \mod_lesson\output\edit_action_buttons $editbuttons The editbuttons * * @return string The rendered edit action buttons. */ public function render_edit_action_buttons(\mod_lesson\output\edit_action_buttons $editbuttons): string { $context = $editbuttons->export_for_template($this); return $this->render_from_template('mod_lesson/edit_action_buttons', $context); } /** * Render the edit action area. * * @param \mod_lesson\output\edit_action_area $editarea The edit area. * @return string The rendered edit action area. */ public function render_edit_action_area(\mod_lesson\output\edit_action_area $editarea): string { $context = $editarea->export_for_template($this); return $this->render_from_template('mod_lesson/edit_action_area', $context); } /** * Render the report action menu * * @param \mod\lesson\output\report_action_menu $reportmenu The reportmenu. * @return string The rendered report action menu. */ public function render_report_action_menu(\mod_lesson\output\report_action_menu $reportmenu): string { $context = $reportmenu->export_for_template($this); return $this->render_from_template('mod_lesson/report_action_menu', $context); } } home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/mod/scorm/renderer.php000064400000020712152267124330023111 0ustar00. /** * Defines the renderer for the scorm module. * * @package mod_scorm * @copyright 2013 Dan Marsden * @author Dan Marsden * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); /** * The renderer for the scorm module. * * @copyright 2013 Dan Marsden * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class mod_scorm_renderer extends plugin_renderer_base { public function view_user_heading($user, $course, $baseurl, $attempt, $attemptids) { $output = ''; $output .= $this->box_start('generalbox boxaligncenter'); $output .= html_writer::start_tag('div', array('class' => 'mdl-align')); $output .= $this->user_picture($user, array('courseid' => $course->id, 'link' => true)); $url = new moodle_url('/user/view.php', array('id' => $user->id, 'course' => $course->id)); $output .= html_writer::link($url, fullname($user)); $baseurl->param('attempt', ''); $pb = new mod_scorm_attempt_bar($attemptids, $attempt, $baseurl, 'attempt'); $output .= $this->render($pb); $output .= html_writer::end_tag('div'); $output .= $this->box_end(); return $output; } /** * scorm attempt bar renderer * * @param mod_scorm_attempt_bar $attemptbar * @return string */ protected function render_mod_scorm_attempt_bar(mod_scorm_attempt_bar $attemptbar) { $output = ''; $attemptbar = clone($attemptbar); $attemptbar->prepare($this, $this->page, $this->target); if (count($attemptbar->attemptids) > 1) { $output .= get_string('attempt', 'scorm') . ':'; if (!empty($attemptbar->previouslink)) { $output .= ' (' . $attemptbar->previouslink . ') '; } foreach ($attemptbar->attemptlinks as $link) { $output .= "  $link"; } if (!empty($attemptbar->nextlink)) { $output .= '  (' . $attemptbar->nextlink . ')'; } } return html_writer::tag('div', $output, array('class' => 'paging')); } /** * Rendered HTML for the report action is provided. * * @param \mod_scorm\output\actionbar $actionbar actionbar object. * @return bool|string rendered HTML for the report action. */ public function report_actionbar(\mod_scorm\output\actionbar $actionbar): string { return $this->render_from_template('mod_scorm/report_actionbar', $actionbar->export_for_template($this)); } /** * Rendered HTML for the user report action is provided * * @param \mod_scorm\output\userreportsactionbar $userreportsactionbar userreportsactionbar object * @return string rendered HTML for the user report action. */ public function user_report_actionbar(\mod_scorm\output\userreportsactionbar $userreportsactionbar): string { return $this->render_from_template('mod_scorm/user_report_actionbar', $userreportsactionbar->export_for_template($this)); } /** * Generate the SCORM's "Exit activity" button * * @param string $url The url to be hooked up to the exit button * @return string */ public function generate_exitbar(string $url): string { return $this->render_from_template('mod_scorm/player_exitbar', ['action' => $url]); } } /** * Component representing a SCORM attempts bar. * * @copyright 2013 Dan Marsden * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @package mod_scorm */ class mod_scorm_attempt_bar implements renderable { /** * @var array An array of the attemptids */ public $attemptids; /** * @var int The attempt you are currently viewing. */ public $attempt; /** * @var string|moodle_url If this is a string then it is the url which will be appended with $pagevar, * an equals sign and the attempt number. * If this is a moodle_url object then the pagevar param will be replaced by * the attempt no, for each attempt. */ public $baseurl; /** * @var string This is the variable name that you use for the attempt in your * code (ie. 'tablepage', 'blogpage', etc) */ public $pagevar; /** * @var string A HTML link representing the "previous" attempt. */ public $previouslink = null; /** * @var string A HTML link representing the "next" attempt. */ public $nextlink = null; /** * @var array An array of strings. One of them is just a string: the current attempt */ public $attemptlinks = array(); /** * Constructor mod_scorm_attempt_bar with only the required params. * * @param array $attemptids an array of attempts the user has made * @param int $attempt The attempt you are currently viewing * @param string|moodle_url $baseurl url of the current page, the $pagevar parameter is added * @param string $pagevar name of page parameter that holds the attempt number */ public function __construct($attemptids, $attempt, $baseurl, $pagevar = 'page') { $this->attemptids = $attemptids; $this->attempt = $attempt; $this->baseurl = $baseurl; $this->pagevar = $pagevar; } /** * Prepares the scorm attempt bar for output. * * This method validates the arguments set up for the scorm attempt bar and then * produces fragments of HTML to assist display later on. * * @param renderer_base $output * @param moodle_page $page * @param string $target * @throws coding_exception */ public function prepare(renderer_base $output, moodle_page $page, $target) { if (empty($this->attemptids)) { throw new coding_exception('mod_scorm_attempt_bar requires a attemptids value.'); } if (!isset($this->attempt) || is_null($this->attempt)) { throw new coding_exception('mod_scorm_attempt_bar requires a attempt value.'); } if (empty($this->baseurl)) { throw new coding_exception('mod_scorm_attempt_bar requires a baseurl value.'); } if (count($this->attemptids) > 1) { $lastattempt = end($this->attemptids); // Get last attempt. $firstattempt = reset($this->attemptids); // get first attempt. $nextattempt = 0; $prevattempt = null; $previous = 0; foreach ($this->attemptids as $attemptid) { if ($this->attempt == $attemptid) { $this->attemptlinks[] = $attemptid; $prevattempt = $previous; } else { $attemptlink = html_writer::link( new moodle_url($this->baseurl, array($this->pagevar => $attemptid)), $attemptid); $this->attemptlinks[] = $attemptlink; if (empty($nextattempt) && $prevattempt !== null) { // Set the nextattempt var as we have set previous attempt earlier. $nextattempt = $attemptid; } } $previous = $attemptid; // Store this attempt as previous in case we need it. } if ($this->attempt != $firstattempt) { $this->previouslink = html_writer::link( new moodle_url($this->baseurl, array($this->pagevar => $prevattempt)), get_string('previous'), array('class' => 'previous')); } if ($this->attempt != $lastattempt) { $this->nextlink = html_writer::link( new moodle_url($this->baseurl, array($this->pagevar => $nextattempt)), get_string('next'), array('class' => 'next')); } } } }home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/mod/quiz/classes/output/renderer.php000064400000170356152267163130025766 0ustar00. namespace mod_quiz\output; use cm_info; use coding_exception; use context; use context_module; use html_table; use html_table_cell; use html_writer; use mod_quiz\access_manager; use mod_quiz\form\preflight_check_form; use mod_quiz\output\grades\grade_out_of; use mod_quiz\question\display_options; use mod_quiz\quiz_attempt; use moodle_url; use plugin_renderer_base; use popup_action; use question_display_options; use mod_quiz\quiz_settings; use renderable; use single_button; use stdClass; /** * The main renderer for the quiz module. * * @package mod_quiz * @category output * @copyright 2011 The Open University * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class renderer extends plugin_renderer_base { /** * Builds the review page * * @param quiz_attempt $attemptobj an instance of quiz_attempt. * @param array $slots of slots to be displayed. * @param int $page the current page number * @param bool $showall whether to show entire attempt on one page. * @param bool $lastpage if true the current page is the last page. * @param display_options $displayoptions instance of display_options. * @param attempt_summary_information|array $summarydata summary information about the attempt. * Passing an array is deprecated. * @return string HTML to display. */ public function review_page(quiz_attempt $attemptobj, $slots, $page, $showall, $lastpage, display_options $displayoptions, $summarydata) { if (is_array($summarydata)) { debugging('Since Moodle 4.4, $summarydata passed to review_page should be a attempt_summary_information.', DEBUG_DEVELOPER); $summarydata = $this->filter_review_summary_table($summarydata, $page); $summarydata = attempt_summary_information::create_from_legacy_array($summarydata); } $output = ''; $output .= $this->header(); $output .= $this->review_attempt_summary($summarydata, $page); $output .= $this->review_form($page, $showall, $displayoptions, $this->questions($attemptobj, true, $slots, $page, $showall, $displayoptions), $attemptobj); $output .= $this->review_next_navigation($attemptobj, $page, $lastpage, $showall); $output .= $this->footer(); return $output; } /** * Renders the review question pop-up. * * @param quiz_attempt $attemptobj an instance of quiz_attempt. * @param int $slot which question to display. * @param int $seq which step of the question attempt to show. null = latest. * @param display_options $displayoptions instance of display_options. * @param attempt_summary_information|array $summarydata summary information about the attempt. * Passing an array is deprecated. * @return string HTML to display. */ public function review_question_page(quiz_attempt $attemptobj, $slot, $seq, display_options $displayoptions, $summarydata) { if (is_array($summarydata)) { debugging('Since Moodle 4.4, $summarydata passed to review_question_page should be a attempt_summary_information.', DEBUG_DEVELOPER); $summarydata = attempt_summary_information::create_from_legacy_array($summarydata); } $output = ''; $output .= $this->header(); $output .= html_writer::div($this->render($summarydata), 'mb-3'); if (!is_null($seq)) { $output .= $attemptobj->render_question_at_step($slot, $seq, true, $this); } else { $output .= $attemptobj->render_question($slot, true, $this); } $output .= $this->close_window_button(); $output .= $this->footer(); return $output; } /** * Renders the review question pop-up. * * @param quiz_attempt $attemptobj an instance of quiz_attempt. * @param string $message Why the review is not allowed. * @return string html to output. */ public function review_question_not_allowed(quiz_attempt $attemptobj, $message) { $output = ''; $output .= $this->header(); $output .= $this->heading(format_string($attemptobj->get_quiz_name(), true, ["context" => $attemptobj->get_quizobj()->get_context()])); $output .= $this->notification($message); $output .= $this->close_window_button(); $output .= $this->footer(); return $output; } /** * A chance to filter the information before display. * * Moodle core uses this to display less infomrmation on pages after the first. * This is a separate method, becaus it is a useful hook where themes can overrid things. * * @param attempt_summary_information $summarydata the data that will be displayed. Modify as desired. * @param int $page contains the current page number */ public function filter_review_attempt_summary( attempt_summary_information $summarydata, int $page ): void { if ($page > 0) { $summarydata->filter_keeping_only(['user', 'attemptlist']); } } /** * Outputs the overall summary of the attempt at the top of the review page. * * @param attempt_summary_information $summarydata contains row data for table. * @param int $page contains the current page number * @return string HTML to display. */ public function review_attempt_summary( attempt_summary_information $summarydata, int $page ): string { $this->filter_review_attempt_summary($summarydata, $page); return html_writer::div($this->render($summarydata), 'mb-3'); } /** * Filters the summarydata array. * * @param array $summarydata contains row data for table * @param int $page the current page number * @return array updated version of the $summarydata array. * @deprecated since Moodle 4.4. Replaced by filter_review_attempt_summary. */ protected function filter_review_summary_table($summarydata, $page) { debugging('filter_review_summary_table() is deprecated. Replaced by filter_review_attempt_summary().', DEBUG_DEVELOPER); if ($page == 0) { return $summarydata; } // Only show some of summary table on subsequent pages. foreach ($summarydata as $key => $rowdata) { if (!in_array($key, ['user', 'attemptlist'])) { unset($summarydata[$key]); } } return $summarydata; } /** * Outputs the table containing data from summary data array * * @param array $summarydata contains row data for table * @param int $page contains the current page number * @return string HTML to display. * @deprecated since Moodle 4.4. Replaced by review_attempt_summary. */ public function review_summary_table($summarydata, $page) { debugging('review_summary_table() is deprecated. Please use review_attempt_summary() instead.', DEBUG_DEVELOPER); $summarydata = $this->filter_review_summary_table($summarydata, $page); $this->render(attempt_summary_information::create_from_legacy_array($summarydata)); } /** * Renders each question * * @param quiz_attempt $attemptobj instance of quiz_attempt * @param bool $reviewing * @param array $slots array of integers relating to questions * @param int $page current page number * @param bool $showall if true shows attempt on single page * @param display_options $displayoptions instance of display_options */ public function questions(quiz_attempt $attemptobj, $reviewing, $slots, $page, $showall, display_options $displayoptions) { $output = ''; foreach ($slots as $slot) { $output .= $attemptobj->render_question($slot, $reviewing, $this, $attemptobj->review_url($slot, $page, $showall)); } return $output; } /** * Renders the main bit of the review page. * * @param int $page current page number * @param bool $showall if true display attempt on one page * @param display_options $displayoptions instance of display_options * @param string $content the rendered display of each question * @param quiz_attempt $attemptobj instance of quiz_attempt * @return string HTML to display. */ public function review_form($page, $showall, $displayoptions, $content, $attemptobj) { if ($displayoptions->flags != question_display_options::EDITABLE) { return $content; } $this->page->requires->js_init_call('M.mod_quiz.init_review_form', null, false, quiz_get_js_module()); $output = ''; $output .= html_writer::start_tag('form', ['action' => $attemptobj->review_url(null, $page, $showall), 'method' => 'post', 'class' => 'questionflagsaveform']); $output .= html_writer::start_tag('div'); $output .= $content; $output .= html_writer::empty_tag('input', ['type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey()]); $output .= html_writer::start_tag('div', ['class' => 'submitbtns']); $output .= html_writer::empty_tag('input', ['type' => 'submit', 'class' => 'questionflagsavebutton btn btn-secondary', 'name' => 'savingflags', 'value' => get_string('saveflags', 'question')]); $output .= html_writer::end_tag('div'); $output .= html_writer::end_tag('div'); $output .= html_writer::end_tag('form'); return $output; } /** * Returns either a link or button. * * @param quiz_attempt $attemptobj instance of quiz_attempt */ public function finish_review_link(quiz_attempt $attemptobj) { $url = $attemptobj->view_url(); if ($attemptobj->get_access_manager(time())->attempt_must_be_in_popup()) { $this->page->requires->js_init_call('M.mod_quiz.secure_window.init_close_button', [$url->out(false)], false, quiz_get_js_module()); return html_writer::empty_tag('input', ['type' => 'button', 'value' => get_string('finishreview', 'quiz'), 'id' => 'secureclosebutton', 'class' => 'mod_quiz-next-nav btn btn-primary']); } else { return html_writer::link($url, get_string('finishreview', 'quiz'), ['class' => 'mod_quiz-next-nav']); } } /** * Creates the navigation links/buttons at the bottom of the review attempt page. * * Note, the name of this function is no longer accurate, but when the design * changed, it was decided to keep the old name for backwards compatibility. * * @param quiz_attempt $attemptobj instance of quiz_attempt * @param int $page the current page * @param bool $lastpage if true current page is the last page * @param bool|null $showall if true, the URL will be to review the entire attempt on one page, * and $page will be ignored. If null, a sensible default will be chosen. * * @return string HTML fragment. */ public function review_next_navigation(quiz_attempt $attemptobj, $page, $lastpage, $showall = null) { $nav = ''; if ($page > 0) { $nav .= link_arrow_left(get_string('navigateprevious', 'quiz'), $attemptobj->review_url(null, $page - 1, $showall), false, 'mod_quiz-prev-nav'); } if ($lastpage) { $nav .= $this->finish_review_link($attemptobj); } else { $nav .= link_arrow_right(get_string('navigatenext', 'quiz'), $attemptobj->review_url(null, $page + 1, $showall), false, 'mod_quiz-next-nav'); } return html_writer::tag('div', $nav, ['class' => 'submitbtns']); } /** * Return the HTML of the quiz timer. * * @param quiz_attempt $attemptobj instance of quiz_attempt * @param int $timenow timestamp to use as 'now'. * @return string HTML content. */ public function countdown_timer(quiz_attempt $attemptobj, $timenow) { $timeleft = $attemptobj->get_time_left_display($timenow); if ($timeleft !== false) { $ispreview = $attemptobj->is_preview(); $timerstartvalue = $timeleft; if (!$ispreview) { // Make sure the timer starts just above zero. If $timeleft was <= 0, then // this will just have the effect of causing the quiz to be submitted immediately. $timerstartvalue = max($timerstartvalue, 1); } $this->initialise_timer($timerstartvalue, $ispreview); } return $this->output->render_from_template('mod_quiz/timer', (object) []); } /** * Create a preview link * * @param moodle_url $url URL to restart the attempt. */ public function restart_preview_button($url) { return $this->single_button($url, get_string('startnewpreview', 'quiz')); } /** * Outputs the navigation block panel * * @param navigation_panel_base $panel */ public function navigation_panel(navigation_panel_base $panel) { $output = ''; $userpicture = $panel->user_picture(); if ($userpicture) { $fullname = fullname($userpicture->user); if ($userpicture->size) { $fullname = html_writer::div($fullname); } $output .= html_writer::tag('div', $this->render($userpicture) . $fullname, ['id' => 'user-picture', 'class' => 'clearfix']); } $output .= $panel->render_before_button_bits($this); $bcc = $panel->get_button_container_class(); $output .= html_writer::start_tag('div', ['class' => "qn_buttons clearfix $bcc"]); foreach ($panel->get_question_buttons() as $button) { $output .= $this->render($button); } $output .= html_writer::end_tag('div'); $output .= html_writer::tag('div', $panel->render_end_bits($this), ['class' => 'othernav']); $this->page->requires->js_init_call('M.mod_quiz.nav.init', null, false, quiz_get_js_module()); return $output; } /** * Display a quiz navigation button. * * @param navigation_question_button $button * @return string HTML fragment. */ protected function render_navigation_question_button(navigation_question_button $button) { $classes = ['qnbutton', $button->stateclass, $button->navmethod, 'btn']; $extrainfo = []; if ($button->currentpage) { $classes[] = 'thispage'; $extrainfo[] = get_string('onthispage', 'quiz'); } // Flagged? if ($button->flagged) { $classes[] = 'flagged'; $flaglabel = get_string('flagged', 'question'); } else { $flaglabel = ''; } $extrainfo[] = html_writer::tag('span', $flaglabel, ['class' => 'flagstate']); if ($button->isrealquestion) { $qnostring = 'questionnonav'; } else { $qnostring = 'questionnonavinfo'; } $tooltip = get_string('questionx', 'question', s($button->number)) . ' - ' . $button->statestring; $a = new stdClass(); $a->number = s($button->number); $a->attributes = implode(' ', $extrainfo); $tagcontents = html_writer::tag('span', '', ['class' => 'thispageholder']) . html_writer::tag('span', '', ['class' => 'trafficlight']) . get_string($qnostring, 'quiz', $a); $tagattributes = ['class' => implode(' ', $classes), 'id' => $button->id, 'title' => $tooltip, 'data-quiz-page' => $button->page]; if ($button->url) { return html_writer::link($button->url, $tagcontents, $tagattributes); } else { return html_writer::tag('span', $tagcontents, $tagattributes); } } /** * Display a quiz navigation heading. * * @param navigation_section_heading $heading the heading. * @return string HTML fragment. */ protected function render_navigation_section_heading(navigation_section_heading $heading) { if (empty($heading->heading)) { $headingtext = get_string('sectionnoname', 'quiz'); $class = ' dimmed_text'; } else { $headingtext = $heading->heading; $class = ''; } return $this->heading($headingtext, 3, 'mod_quiz-section-heading' . $class); } /** * Renders a list of links the other attempts. * * @param links_to_other_attempts $links * @return string HTML fragment. */ protected function render_links_to_other_attempts( links_to_other_attempts $links) { $attemptlinks = []; foreach ($links->links as $attempt => $url) { if (!$url) { $attemptlinks[] = html_writer::tag('strong', $attempt); } else { if ($url instanceof renderable) { $attemptlinks[] = $this->render($url); } else { $attemptlinks[] = html_writer::link($url, $attempt); } } } return implode(', ', $attemptlinks); } /** * Render a {@see grade_out_of}. * * Most of the logic is in methods of the grade_out_of class. However, * having this renderer method allows themes to override the default rendering. * * @param grade_out_of $grade * @return string HTML to output. */ protected function render_grade_out_of(grade_out_of $grade): string { return get_string($grade->get_string_key(), 'quiz', $grade->style_formatted_values($grade->get_formatted_values())); } /** * Render the 'start attempt' page. * * The student gets here if their interaction with the preflight check * from fails in some way (e.g. they typed the wrong password). * * @param \mod_quiz\quiz_settings $quizobj * @param preflight_check_form $mform * @return string */ public function start_attempt_page(quiz_settings $quizobj, preflight_check_form $mform) { $output = ''; $output .= $this->header(); $output .= $this->during_attempt_tertiary_nav($quizobj->view_url()); $output .= $this->heading(format_string($quizobj->get_quiz_name(), true, ["context" => $quizobj->get_context()])); $output .= $this->quiz_intro($quizobj->get_quiz(), $quizobj->get_cm()); $output .= $mform->render(); $output .= $this->footer(); return $output; } /** * Attempt Page * * @param quiz_attempt $attemptobj Instance of quiz_attempt * @param int $page Current page number * @param access_manager $accessmanager Instance of access_manager * @param array $messages An array of messages * @param array $slots Contains an array of integers that relate to questions * @param int $id The ID of an attempt * @param int $nextpage The number of the next page * @return string HTML to output. */ public function attempt_page($attemptobj, $page, $accessmanager, $messages, $slots, $id, $nextpage) { $output = ''; $output .= $this->header(); $output .= $this->during_attempt_tertiary_nav($attemptobj->view_url()); $output .= $this->quiz_notices($messages); $output .= $this->countdown_timer($attemptobj, time()); $output .= $this->attempt_form($attemptobj, $page, $slots, $id, $nextpage); $output .= $this->footer(); return $output; } /** * Render the tertiary navigation for pages during the attempt. * * @param string|moodle_url $quizviewurl url of the view.php page for this quiz. * @return string HTML to output. */ public function during_attempt_tertiary_nav($quizviewurl): string { $output = ''; $output .= html_writer::start_div('tertiary-navigation'); $output .= html_writer::start_div('row'); $output .= html_writer::start_div('navitem'); $output .= html_writer::link($quizviewurl, get_string('back'), ['class' => 'btn btn-secondary']); $output .= html_writer::end_div(); $output .= html_writer::end_div(); $output .= html_writer::end_div(); return $output; } /** * Returns any notices. * * @param array $messages */ public function quiz_notices($messages) { if (!$messages) { return ''; } return $this->notification( html_writer::tag('p', get_string('accessnoticesheader', 'quiz')) . $this->access_messages($messages), 'warning', false ); } /** * Outputs the form for making an attempt * * @param quiz_attempt $attemptobj * @param int $page Current page number * @param array $slots Array of integers relating to questions * @param int $id ID of the attempt * @param int $nextpage Next page number */ public function attempt_form($attemptobj, $page, $slots, $id, $nextpage) { $output = ''; // Start the form. $output .= html_writer::start_tag('form', ['action' => new moodle_url($attemptobj->processattempt_url(), ['cmid' => $attemptobj->get_cmid()]), 'method' => 'post', 'enctype' => 'multipart/form-data', 'accept-charset' => 'utf-8', 'id' => 'responseform']); $output .= html_writer::start_tag('div'); // Print all the questions. foreach ($slots as $slot) { $output .= $attemptobj->render_question($slot, false, $this, $attemptobj->attempt_url($slot, $page)); } $navmethod = $attemptobj->get_quiz()->navmethod; $output .= $this->attempt_navigation_buttons($page, $attemptobj->is_last_page($page), $navmethod); // Some hidden fields to track what is going on. $output .= html_writer::empty_tag('input', ['type' => 'hidden', 'name' => 'attempt', 'value' => $attemptobj->get_attemptid()]); $output .= html_writer::empty_tag('input', ['type' => 'hidden', 'name' => 'thispage', 'value' => $page, 'id' => 'followingpage']); $output .= html_writer::empty_tag('input', ['type' => 'hidden', 'name' => 'nextpage', 'value' => $nextpage]); $output .= html_writer::empty_tag('input', ['type' => 'hidden', 'name' => 'timeup', 'value' => '0', 'id' => 'timeup']); $output .= html_writer::empty_tag('input', ['type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey()]); $output .= html_writer::empty_tag('input', ['type' => 'hidden', 'name' => 'mdlscrollto', 'value' => '', 'id' => 'mdlscrollto']); // Add a hidden field with questionids. Do this at the end of the form, so // if you navigate before the form has finished loading, it does not wipe all // the student's answers. $output .= html_writer::empty_tag('input', ['type' => 'hidden', 'name' => 'slots', 'value' => implode(',', $attemptobj->get_active_slots($page))]); // Finish the form. $output .= html_writer::end_tag('div'); $output .= html_writer::end_tag('form'); $output .= $this->connection_warning(); return $output; } /** * Display the prev/next buttons that go at the bottom of each page of the attempt. * * @param int $page the page number. Starts at 0 for the first page. * @param bool $lastpage is this the last page in the quiz? * @param string $navmethod Optional quiz attribute, 'free' (default) or 'sequential' * @return string HTML fragment. */ protected function attempt_navigation_buttons($page, $lastpage, $navmethod = 'free') { $output = ''; $output .= html_writer::start_tag('div', ['class' => 'submitbtns']); if ($page > 0 && $navmethod == 'free') { $output .= html_writer::empty_tag('input', ['type' => 'submit', 'name' => 'previous', 'value' => get_string('navigateprevious', 'quiz'), 'class' => 'mod_quiz-prev-nav btn btn-secondary', 'id' => 'mod_quiz-prev-nav']); $this->page->requires->js_call_amd('core_form/submit', 'init', ['mod_quiz-prev-nav']); } if ($lastpage) { $nextlabel = get_string('endtest', 'quiz'); } else { $nextlabel = get_string('navigatenext', 'quiz'); } $output .= html_writer::empty_tag('input', ['type' => 'submit', 'name' => 'next', 'value' => $nextlabel, 'class' => 'mod_quiz-next-nav btn btn-primary', 'id' => 'mod_quiz-next-nav']); $output .= html_writer::end_tag('div'); $this->page->requires->js_call_amd('core_form/submit', 'init', ['mod_quiz-next-nav']); return $output; } /** * Render a button which allows students to redo a question in the attempt. * * @param int $slot the number of the slot to generate the button for. * @param bool $disabled if true, output the button disabled. * @return string HTML fragment. */ public function redo_question_button($slot, $disabled) { $attributes = ['type' => 'submit', 'name' => 'redoslot' . $slot, 'value' => get_string('redoquestion', 'quiz'), 'class' => 'mod_quiz-redo_question_button btn btn-secondary', 'id' => 'redoslot' . $slot . '-submit', 'data-savescrollposition' => 'true', ]; if ($disabled) { $attributes['disabled'] = 'disabled'; } else { $this->page->requires->js_call_amd('core_question/question_engine', 'initSubmitButton', [$attributes['id']]); } return html_writer::div(html_writer::empty_tag('input', $attributes)); } /** * Initialise the JavaScript required to initialise the countdown timer. * * @param int $timerstartvalue time remaining, in seconds. * @param bool $ispreview true if this is a preview attempt. */ public function initialise_timer($timerstartvalue, $ispreview) { $options = [$timerstartvalue, (bool) $ispreview]; $this->page->requires->js_init_call('M.mod_quiz.timer.init', $options, false, quiz_get_js_module()); } /** * Output a page with an optional message, and JavaScript code to close the * current window and redirect the parent window to a new URL. * * @param moodle_url $url the URL to redirect the parent window to. * @param string $message message to display before closing the window. (optional) * @return string HTML to output. */ public function close_attempt_popup($url, $message = '') { $output = ''; $output .= $this->header(); $output .= $this->box_start(); if ($message) { $output .= html_writer::tag('p', $message); $output .= html_writer::tag('p', get_string('windowclosing', 'quiz')); $delay = 5; } else { $output .= html_writer::tag('p', get_string('pleaseclose', 'quiz')); $delay = 0; } $this->page->requires->js_init_call('M.mod_quiz.secure_window.close', [$url->out(false), $delay], false, quiz_get_js_module()); $output .= $this->box_end(); $output .= $this->footer(); return $output; } /** * Print each message in an array, surrounded by <p>, </p> tags. * * @param array $messages the array of message strings. * @return string HTML to output. */ public function access_messages($messages) { $output = ''; foreach ($messages as $message) { $output .= html_writer::tag('p', $message, ['class' => 'text-start']); } return $output; } /* * Summary Page */ /** * Create the summary page * * @param quiz_attempt $attemptobj * @param display_options $displayoptions */ public function summary_page($attemptobj, $displayoptions) { $output = ''; $output .= $this->header(); $output .= $this->during_attempt_tertiary_nav($attemptobj->view_url()); $output .= $this->heading(format_string($attemptobj->get_quiz_name())); $output .= $this->heading(get_string('summaryofattempt', 'quiz'), 3); $output .= $this->summary_table($attemptobj, $displayoptions); $output .= $this->summary_page_controls($attemptobj); $output .= $this->footer(); return $output; } /** * Generates the table of summarydata * * @param quiz_attempt $attemptobj * @param display_options $displayoptions */ public function summary_table($attemptobj, $displayoptions) { // Prepare the summary table header. $table = new html_table(); $table->attributes['class'] = 'generaltable quizsummaryofattempt boxaligncenter table table-striped table-hover'; $table->head = [get_string('question', 'quiz'), get_string('status', 'quiz')]; $table->align = ['left', 'left']; $table->size = ['', '']; $markscolumn = $displayoptions->marks >= question_display_options::MARK_AND_MAX; if ($markscolumn) { $table->head[] = get_string('marks', 'quiz'); $table->align[] = 'left'; $table->size[] = ''; } $tablewidth = count($table->align); $table->data = []; // Get the summary info for each question. $slots = $attemptobj->get_slots(); foreach ($slots as $slot) { // Add a section headings if we need one here. $heading = $attemptobj->get_heading_before_slot($slot); if ($heading !== null) { // There is a heading here. $rowclasses = 'quizsummaryheading'; if ($heading) { $heading = format_string($heading); } else { if (count($attemptobj->get_quizobj()->get_sections()) > 1) { // If this is the start of an unnamed section, and the quiz has more // than one section, then add a default heading. $heading = get_string('sectionnoname', 'quiz'); $rowclasses .= ' dimmed_text'; } } $cell = new html_table_cell(format_string($heading)); $cell->header = true; $cell->colspan = $tablewidth; $table->data[] = [$cell]; $table->rowclasses[] = $rowclasses; } // Don't display information items. if (!$attemptobj->is_real_question($slot)) { continue; } // Real question, show it. $flag = ''; if ($attemptobj->is_question_flagged($slot)) { // Quiz has custom JS manipulating these image tags - so we can't use the pix_icon method here. $flag = html_writer::empty_tag('img', ['src' => $this->image_url('i/flagged'), 'alt' => get_string('flagged', 'question'), 'class' => 'questionflag icon ms-2']); } if ($attemptobj->can_navigate_to($slot)) { $row = [html_writer::link($attemptobj->attempt_url($slot), $attemptobj->get_question_number($slot) . $flag), $attemptobj->get_question_status($slot, $displayoptions->correctness)]; } else { $row = [$attemptobj->get_question_number($slot) . $flag, $attemptobj->get_question_status($slot, $displayoptions->correctness)]; } if ($markscolumn) { $row[] = $attemptobj->get_question_mark($slot); } $table->data[] = $row; $table->rowclasses[] = 'quizsummary' . $slot . ' ' . $attemptobj->get_question_state_class( $slot, $displayoptions->correctness); } // Print the summary table. return html_writer::table($table); } /** * Creates any controls the page should have. * * @param quiz_attempt $attemptobj */ public function summary_page_controls($attemptobj) { $output = ''; // Return to place button. if ($attemptobj->get_state() == quiz_attempt::IN_PROGRESS) { $button = new single_button( new moodle_url($attemptobj->attempt_url(null, $attemptobj->get_currentpage())), get_string('returnattempt', 'quiz')); $output .= $this->container($this->container($this->render($button), 'controls'), 'submitbtns mdl-align'); } // Finish attempt button. $options = [ 'attempt' => $attemptobj->get_attemptid(), 'finishattempt' => 1, 'timeup' => 0, 'slots' => '', 'cmid' => $attemptobj->get_cmid(), 'sesskey' => sesskey(), ]; $button = new single_button( new moodle_url($attemptobj->processattempt_url(), $options), get_string('submitallandfinish', 'quiz')); $button->class = 'btn-finishattempt'; $button->formid = 'frm-finishattempt'; if ($attemptobj->get_state() == quiz_attempt::IN_PROGRESS) { $totalunanswered = 0; if ($attemptobj->get_quiz()->navmethod == 'free') { // Only count the unanswered question if the navigation method is set to free. $totalunanswered = $attemptobj->get_number_of_unanswered_questions(); } $this->page->requires->js_call_amd('mod_quiz/submission_confirmation', 'init', [$totalunanswered]); } $button->type = \single_button::BUTTON_PRIMARY; $duedate = $attemptobj->get_due_date(); $message = ''; if ($attemptobj->get_state() == quiz_attempt::OVERDUE) { $message = get_string('overduemustbesubmittedby', 'quiz', userdate($duedate)); } else { if ($duedate) { $message = get_string('mustbesubmittedby', 'quiz', userdate($duedate)); } } $output .= $this->countdown_timer($attemptobj, time()); $output .= $this->container($message . $this->container( $this->render($button), 'controls'), 'submitbtns mdl-align'); return $output; } /* * View Page */ /** * Generates the view page * * @param stdClass $course the course settings row from the database. * @param stdClass $quiz the quiz settings row from the database. * @param stdClass $cm the course_module settings row from the database. * @param context_module $context the quiz context. * @param view_page $viewobj * @return string HTML to display */ public function view_page($course, $quiz, $cm, $context, $viewobj) { $output = ''; $output .= $this->view_page_tertiary_nav($viewobj); $output .= $this->view_information($quiz, $cm, $context, $viewobj->infomessages); $output .= $this->view_result_info($quiz, $context, $cm, $viewobj); $output .= $this->render($viewobj->attemptslist); $output .= $this->box($this->view_page_buttons($viewobj), 'quizattempt'); return $output; } /** * Render the tertiary navigation for the view page. * * @param view_page $viewobj the information required to display the view page. * @return string HTML to output. */ public function view_page_tertiary_nav(view_page $viewobj): string { $content = ''; if ($viewobj->buttontext) { $attemptbtn = $this->start_attempt_button($viewobj->buttontext, $viewobj->startattempturl, $viewobj->preflightcheckform, $viewobj->popuprequired, $viewobj->popupoptions); $content .= html_writer::div($attemptbtn, 'navitem'); } if ($viewobj->canedit && !$viewobj->quizhasquestions) { $addquestionbutton = html_writer::link($viewobj->editurl, get_string('addquestion', 'quiz'), ['class' => 'btn btn-secondary']); $content .= html_writer::div($addquestionbutton, 'navitem'); } if ($content) { return html_writer::div(html_writer::div($content, 'd-flex'), 'tertiary-navigation'); } else { return ''; } } /** * Work out, and render, whatever buttons, and surrounding info, should appear * at the end of the review page. * * @param view_page $viewobj the information required to display the view page. * @return string HTML to output. */ public function view_page_buttons(view_page $viewobj) { $output = ''; if (!$viewobj->quizhasquestions) { $output .= html_writer::div( $this->notification(get_string('noquestions', 'quiz'), 'warning', false), 'text-start mb-3'); } $output .= $this->access_messages($viewobj->preventmessages); if ($viewobj->showbacktocourse) { $output .= $this->single_button($viewobj->backtocourseurl, get_string('backtocourse', 'quiz'), 'get', ['class' => 'continuebutton']); } return $output; } /** * Generates the view attempt button * * @param string $buttontext the label to display on the button. * @param moodle_url $url The URL to POST to in order to start the attempt. * @param preflight_check_form|null $preflightcheckform deprecated. * @param bool $popuprequired whether the attempt needs to be opened in a pop-up. * @param array $popupoptions the options to use if we are opening a popup. * @return string HTML fragment. */ public function start_attempt_button($buttontext, moodle_url $url, ?preflight_check_form $preflightcheckform = null, $popuprequired = false, $popupoptions = null) { $button = new single_button($url, $buttontext, 'post', single_button::BUTTON_PRIMARY); $button->class .= ' quizstartbuttondiv'; if ($popuprequired) { $button->class .= ' quizsecuremoderequired'; } $popupjsoptions = null; if ($popuprequired && $popupoptions) { $action = new popup_action('click', $url, 'popup', $popupoptions); $popupjsoptions = $action->get_js_options(); } $this->page->requires->js_call_amd('mod_quiz/preflightcheck', 'init', ['.quizstartbuttondiv [type=submit]', get_string('startattempt', 'quiz'), '#mod_quiz_preflight_form', $popupjsoptions]); return $this->render($button) . ($preflightcheckform ? $preflightcheckform->render() : ''); } /** * Generate a message saying that this quiz has no questions, with a button to * go to the edit page, if the user has the right capability. * * @param bool $canedit can the current user edit the quiz? * @param moodle_url $editurl URL of the edit quiz page. * @return string HTML to output. * * @deprecated since Moodle 4.0 MDL-71915 - please do not use this function any more. */ public function no_questions_message($canedit, $editurl) { debugging('no_questions_message() is deprecated, please use generate_no_questions_message() instead.', DEBUG_DEVELOPER); $output = html_writer::start_tag('div', ['class' => 'card text-center mb-3']); $output .= html_writer::start_tag('div', ['class' => 'card-body']); $output .= $this->notification(get_string('noquestions', 'quiz'), 'warning', false); if ($canedit) { $output .= $this->single_button($editurl, get_string('editquiz', 'quiz'), 'get'); } $output .= html_writer::end_tag('div'); $output .= html_writer::end_tag('div'); return $output; } /** * Outputs an error message for any guests accessing the quiz * * @param stdClass $course the course settings row from the database. * @param stdClass $quiz the quiz settings row from the database. * @param stdClass $cm the course_module settings row from the database. * @param context_module $context the quiz context. * @param array $messages Array containing any messages * @param view_page $viewobj */ public function view_page_guest($course, $quiz, $cm, $context, $messages, $viewobj) { $output = ''; $output .= $this->view_page_tertiary_nav($viewobj); $output .= $this->view_information($quiz, $cm, $context, $messages); $guestno = html_writer::tag('p', get_string('guestsno', 'quiz')); $liketologin = html_writer::tag('p', get_string('liketologin')); $referer = get_local_referer(false); $output .= $this->confirm($guestno . "\n\n" . $liketologin . "\n", get_login_url(), $referer); return $output; } /** * Outputs and error message for anyone who is not enrolled on the course. * * @param stdClass $course the course settings row from the database. * @param stdClass $quiz the quiz settings row from the database. * @param stdClass $cm the course_module settings row from the database. * @param context_module $context the quiz context. * @param array $messages Array containing any messages * @param view_page $viewobj */ public function view_page_notenrolled($course, $quiz, $cm, $context, $messages, $viewobj) { global $CFG; $output = ''; $output .= $this->view_page_tertiary_nav($viewobj); $output .= $this->view_information($quiz, $cm, $context, $messages); $youneedtoenrol = html_writer::tag('p', get_string('youneedtoenrol', 'quiz')); $button = html_writer::tag('p', $this->continue_button($CFG->wwwroot . '/course/view.php?id=' . $course->id)); $output .= $this->box($youneedtoenrol . "\n\n" . $button . "\n", 'generalbox', 'notice'); return $output; } /** * Output the page information * * @param stdClass $quiz the quiz settings. * @param cm_info|stdClass $cm the course_module object. * @param context $context the quiz context. * @param array $messages any access messages that should be described. * @param bool $quizhasquestions does quiz has questions added. * @return string HTML to output. */ public function view_information($quiz, $cm, $context, $messages, bool $quizhasquestions = false) { $output = ''; // Output any access messages. if ($messages) { $output .= $this->box($this->access_messages($messages), 'quizinfo'); } // Show number of attempts summary to those who can view reports. if (has_capability('mod/quiz:viewreports', $context)) { if ($strattemptnum = $this->quiz_attempt_summary_link_to_reports($quiz, $cm, $context)) { $output .= html_writer::tag('div', $strattemptnum, ['class' => 'quizattemptcounts']); } } if (has_any_capability(['mod/quiz:manageoverrides', 'mod/quiz:viewoverrides'], $context)) { if ($overrideinfo = $this->quiz_override_summary_links($quiz, $cm)) { $output .= html_writer::tag('div', $overrideinfo, ['class' => 'quizattemptcounts']); } } return $output; } /** * Output the quiz intro. * * @param stdClass $quiz the quiz settings. * @param stdClass $cm the course_module object. * @return string HTML to output. */ public function quiz_intro($quiz, $cm) { if (html_is_blank($quiz->intro)) { return ''; } return $this->box(format_module_intro('quiz', $quiz, $cm->id), 'generalbox', 'intro'); } /** * Generates the table heading. */ public function view_table_heading() { return $this->heading(get_string('summaryofattempts', 'quiz'), 3); } /** * Generates the table of data * * @param stdClass $quiz the quiz settings. * @param context_module $context the quiz context. * @param view_page $viewobj * @deprecated Since 4.4 please use the {@see list_of_attempts} renderable instead. */ public function view_table($quiz, $context, $viewobj) { debugging('view_table has been deprecated since 4.4 please use the list_of_attempts renderable instead.'); if (!$viewobj->attempts) { return ''; } // Prepare table header. $table = new html_table(); $table->attributes['class'] = 'generaltable table-striped quizattemptsummary table-hover'; $table->caption = get_string('summaryofattempts', 'quiz'); $table->captionhide = true; $table->head = []; $table->align = []; $table->size = []; if ($viewobj->attemptcolumn) { $table->head[] = get_string('attemptnumber', 'quiz'); $table->align[] = 'center'; $table->size[] = ''; } $table->head[] = get_string('attemptstate', 'quiz'); $table->align[] = 'left'; $table->size[] = ''; if ($viewobj->markcolumn) { $table->head[] = get_string('marks', 'quiz') . ' / ' . quiz_format_grade($quiz, $quiz->sumgrades); $table->align[] = 'center'; $table->size[] = ''; } if ($viewobj->gradecolumn) { $table->head[] = get_string('gradenoun') . ' / ' . quiz_format_grade($quiz, $quiz->grade); $table->align[] = 'center'; $table->size[] = ''; } if ($viewobj->canreviewmine) { $table->head[] = get_string('review', 'quiz'); $table->align[] = 'center'; $table->size[] = ''; } if ($viewobj->feedbackcolumn) { $table->head[] = get_string('feedback', 'quiz'); $table->align[] = 'left'; $table->size[] = ''; } // One row for each attempt. foreach ($viewobj->attemptobjs as $attemptobj) { $attemptoptions = $attemptobj->get_display_options(true); $row = []; // Add the attempt number. if ($viewobj->attemptcolumn) { if ($attemptobj->is_preview()) { $row[] = get_string('preview', 'quiz'); } else { $row[] = $attemptobj->get_attempt_number(); } } $row[] = $this->attempt_state($attemptobj); if ($viewobj->markcolumn) { if ($attemptoptions->marks >= question_display_options::MARK_AND_MAX && $attemptobj->is_finished()) { $row[] = quiz_format_grade($quiz, $attemptobj->get_sum_marks()); } else { $row[] = ''; } } // Outside the if because we may be showing feedback but not grades. $attemptgrade = quiz_rescale_grade($attemptobj->get_sum_marks(), $quiz, false); if ($viewobj->gradecolumn) { if ($attemptoptions->marks >= question_display_options::MARK_AND_MAX && $attemptobj->is_finished()) { // Highlight the highest grade if appropriate. if ($viewobj->overallstats && !$attemptobj->is_preview() && $viewobj->numattempts > 1 && !is_null($viewobj->mygrade) && $attemptobj->get_state() == quiz_attempt::FINISHED && $attemptgrade == $viewobj->mygrade && $quiz->grademethod == QUIZ_GRADEHIGHEST) { $table->rowclasses[$attemptobj->get_attempt_number()] = 'bestrow'; } $row[] = quiz_format_grade($quiz, $attemptgrade); } else { $row[] = ''; } } if ($viewobj->canreviewmine) { $row[] = $viewobj->accessmanager->make_review_link($attemptobj->get_attempt(), $attemptoptions, $this); } if ($viewobj->feedbackcolumn && $attemptobj->is_finished()) { if ($attemptoptions->overallfeedback) { $row[] = quiz_feedback_for_grade($attemptgrade, $quiz, $context); } else { $row[] = ''; } } if ($attemptobj->is_preview()) { $table->data['preview'] = $row; } else { $table->data[$attemptobj->get_attempt_number()] = $row; } } // End of loop over attempts. $output = ''; $output .= $this->view_table_heading(); $output .= html_writer::table($table); return $output; } /** * Generate a brief textual description of the current state of an attempt. * * @param quiz_attempt $attemptobj the attempt * @return string the appropriate lang string to describe the state. */ public function attempt_state($attemptobj) { switch ($attemptobj->get_state()) { case quiz_attempt::IN_PROGRESS: return get_string('stateinprogress', 'quiz'); case quiz_attempt::OVERDUE: return get_string('stateoverdue', 'quiz') . html_writer::tag('span', get_string('stateoverduedetails', 'quiz', userdate($attemptobj->get_due_date())), ['class' => 'statedetails']); case quiz_attempt::FINISHED: return get_string('statefinished', 'quiz') . html_writer::tag('span', get_string('statefinisheddetails', 'quiz', userdate($attemptobj->get_submitted_date())), ['class' => 'statedetails']); case quiz_attempt::ABANDONED: return get_string('stateabandoned', 'quiz'); default: throw new coding_exception('Unexpected attempt state'); } } /** * Generates data pertaining to quiz results * * @param stdClass $quiz Array containing quiz data * @param context_module $context The quiz context. * @param stdClass|cm_info $cm The course module information. * @param view_page $viewobj * @return string HTML to display. */ public function view_result_info($quiz, $context, $cm, $viewobj) { $output = ''; if (!$viewobj->numattempts && !$viewobj->gradecolumn && is_null($viewobj->mygrade)) { return $output; } $resultinfo = ''; if ($viewobj->overallstats) { if ($viewobj->moreattempts) { $a = new stdClass(); $a->method = quiz_get_grading_option_name($quiz->grademethod); $a->mygrade = quiz_format_grade($quiz, $viewobj->mygrade); $a->quizgrade = quiz_format_grade($quiz, $quiz->grade); $resultinfo .= $this->heading(get_string('gradesofar', 'quiz', $a), 3); } else { $a = new stdClass(); $a->grade = quiz_format_grade($quiz, $viewobj->mygrade); $a->maxgrade = quiz_format_grade($quiz, $quiz->grade); $a = get_string('outofshort', 'quiz', $a); $resultinfo .= $this->heading(get_string('yourfinalgradeis', 'quiz', $a), 3); } } if ($viewobj->mygradeoverridden) { $resultinfo .= html_writer::tag('p', get_string('overriddennotice', 'grades'), ['class' => 'overriddennotice']) . "\n"; } if ($viewobj->gradebookfeedback) { $resultinfo .= $this->heading(get_string('comment', 'quiz'), 3); $resultinfo .= html_writer::div($viewobj->gradebookfeedback, 'quizteacherfeedback') . "\n"; } if ($viewobj->feedbackcolumn) { $resultinfo .= $this->heading(get_string('overallfeedback', 'quiz'), 3); $resultinfo .= html_writer::div( quiz_feedback_for_grade($viewobj->mygrade, $quiz, $context), 'quizgradefeedback') . "\n"; } if ($resultinfo) { $output .= $this->box($resultinfo, 'generalbox', 'feedback'); } return $output; } /** * Output either a link to the review page for an attempt, or a button to * open the review in a popup window. * * @param moodle_url $url of the target page. * @param bool $reviewinpopup whether a pop-up is required. * @param array $popupoptions options to pass to the popup_action constructor. * @return string HTML to output. */ public function review_link($url, $reviewinpopup, $popupoptions) { if ($reviewinpopup) { $button = new single_button($url, get_string('review', 'quiz')); $button->add_action(new popup_action('click', $url, 'quizpopup', $popupoptions)); return $this->render($button); } else { return html_writer::link($url, get_string('review', 'quiz'), ['title' => get_string('reviewthisattempt', 'quiz')]); } } /** * Displayed where there might normally be a review link, to explain why the * review is not available at this time. * * @param string $message optional message explaining why the review is not possible. * @return string HTML to output. */ public function no_review_message($message) { return html_writer::nonempty_tag('span', $message, ['class' => 'noreviewmessage']); } /** * Returns the same as {@see quiz_num_attempt_summary()} but wrapped in a link to the quiz reports. * * @param stdClass $quiz the quiz object. Only $quiz->id is used at the moment. * @param stdClass $cm the cm object. Only $cm->course, $cm->groupmode and $cm->groupingid * fields are used at the moment. * @param context $context the quiz context. * @param bool $returnzero if false (default), when no attempts have been made '' is returned * instead of 'Attempts: 0'. * @param int $currentgroup if there is a concept of current group where this method is being * called (e.g. a report) pass it in here. Default 0 which means no current group. * @return string HTML fragment for the link. */ public function quiz_attempt_summary_link_to_reports($quiz, $cm, $context, $returnzero = false, $currentgroup = 0) { global $CFG; $summary = quiz_num_attempt_summary($quiz, $cm, $returnzero, $currentgroup); if (!$summary) { return ''; } require_once($CFG->dirroot . '/mod/quiz/report/reportlib.php'); $url = new moodle_url('/mod/quiz/report.php', [ 'id' => $cm->id, 'mode' => quiz_report_default_report($context)]); return html_writer::link($url, $summary); } /** * Render a summary of the number of group and user overrides, with corresponding links. * * @param stdClass $quiz the quiz settings. * @param cm_info|stdClass $cm the cm object. * @param int $currentgroup currently selected group, if there is one. * @return string HTML fragment for the link. */ public function quiz_override_summary_links(stdClass $quiz, cm_info|stdClass $cm, $currentgroup = 0): string { $baseurl = new moodle_url('/mod/quiz/overrides.php', ['cmid' => $cm->id]); $counts = quiz_override_summary($quiz, $cm, $currentgroup); $links = []; if ($counts['group']) { $links[] = html_writer::link(new moodle_url($baseurl, ['mode' => 'group']), get_string('overridessummarygroup', 'quiz', $counts['group'])); } if ($counts['user']) { $links[] = html_writer::link(new moodle_url($baseurl, ['mode' => 'user']), get_string('overridessummaryuser', 'quiz', $counts['user'])); } if (!$links) { return ''; } $links = implode(', ', $links); switch ($counts['mode']) { case 'onegroup': return get_string('overridessummarythisgroup', 'quiz', $links); case 'somegroups': return get_string('overridessummaryyourgroups', 'quiz', $links); case 'allgroups': return get_string('overridessummary', 'quiz', $links); default: throw new coding_exception('Unexpected mode ' . $counts['mode']); } } /** * Outputs a chart. * * @param \core\chart_base $chart The chart. * @param string $title The title to display above the graph. * @param array $attrs extra container html attributes. * @return string HTML of the graph. */ public function chart(\core\chart_base $chart, $title, $attrs = []) { return $this->heading($title, 3) . html_writer::tag('div', $this->render($chart), array_merge(['class' => 'graph'], $attrs)); } /** * Output a graph, or a message saying that GD is required. * * @param moodle_url $url the URL of the graph. * @param string $title the title to display above the graph. * @return string HTML of the graph. */ public function graph(moodle_url $url, $title) { $graph = html_writer::empty_tag('img', ['src' => $url, 'alt' => $title]); return $this->heading($title, 3) . html_writer::tag('div', $graph, ['class' => 'graph']); } /** * Output the connection warning messages, which are initially hidden, and * only revealed by JavaScript if necessary. */ public function connection_warning() { $options = ['filter' => false, 'newlines' => false]; $warning = format_text(get_string('connectionerror', 'quiz'), FORMAT_MARKDOWN, $options); $ok = format_text(get_string('connectionok', 'quiz'), FORMAT_MARKDOWN, $options); return html_writer::tag('div', $warning, ['id' => 'connection-error', 'style' => 'display: none;', 'role' => 'alert']) . html_writer::tag('div', $ok, ['id' => 'connection-ok', 'style' => 'display: none;', 'role' => 'alert']); } /** * Deprecated version of render_links_to_other_attempts. * * @param links_to_other_attempts $links * @return string HTML fragment. * @deprecated since Moodle 4.2. Please use render_links_to_other_attempts instead. * @todo MDL-76612 Final deprecation in Moodle 4.6 */ protected function render_mod_quiz_links_to_other_attempts(links_to_other_attempts $links) { return $this->render_links_to_other_attempts($links); } /** * Deprecated version of render_navigation_question_button. * * @param navigation_question_button $button * @return string HTML fragment. * @deprecated since Moodle 4.2. Please use render_links_to_other_attempts instead. * @todo MDL-76612 Final deprecation in Moodle 4.6 */ protected function render_quiz_nav_question_button(navigation_question_button $button) { return $this->render_navigation_question_button($button); } /** * Deprecated version of render_navigation_section_heading. * * @param navigation_section_heading $heading the heading. * @return string HTML fragment. * @deprecated since Moodle 4.2. Please use render_links_to_other_attempts instead. * @todo MDL-76612 Final deprecation in Moodle 4.6 */ protected function render_quiz_nav_section_heading(navigation_section_heading $heading) { return $this->render_navigation_section_heading($heading); } }