Fixed badge search and some other things

This commit is contained in:
PMKuipers 2024-02-02 23:09:16 +01:00
parent 9fe71f1800
commit 5a88761f22
17 changed files with 480 additions and 43 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,3 +1,3 @@
define("local_treestudyplan/primary-nav-tools",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.hide_primary=function(hrefs){let element=document.createElement("style");document.head.appendChild(element);let sheet=element.sheet;("string"==typeof hrefs||hrefs instanceof String)&&(hrefs=[hrefs]);if("object"==typeof hrefs&&Array.isArray(hrefs))for(const ix in hrefs){const href=hrefs[ix];let style=`\n li > a[href*="${href}"] {\n display: none;\n }\n `;sheet.insertRule(style,sheet.cssRules.length),style=`\n #usernavigation a[href*="${href}"] {\n display: none;\n }\n `,sheet.insertRule(style,sheet.cssRules.length)}}})); define("local_treestudyplan/primary-nav-tools",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.hide_primary=function(hrefs){("string"==typeof hrefs||hrefs instanceof String)&&(hrefs=[hrefs]);if("object"==typeof hrefs&&Array.isArray(hrefs)){let element=document.createElement("style");document.head.appendChild(element);let sheet=element.sheet;for(const ix in hrefs){const href=hrefs[ix];console.info(`Hiding ${href}`);let style=`\n li > a[href*="${href}"] {\n display: none;\n }\n `;sheet.insertRule(style,sheet.cssRules.length),style=`\n #usernavigation a[href*="${href}"] {\n display: none;\n }\n `,sheet.insertRule(style,sheet.cssRules.length)}console.info(element),console.info(sheet)}}}));
//# sourceMappingURL=primary-nav-tools.min.js.map //# sourceMappingURL=primary-nav-tools.min.js.map

View File

@ -1 +1 @@
{"version":3,"file":"primary-nav-tools.min.js","sources":["../src/primary-nav-tools.js"],"sourcesContent":["/*eslint-env es6*/\n\n/**\n * Hide a primary navigation item by href\n * @param {string|Array} hrefs The link that should be hidden\n */\nexport function hide_primary(hrefs) {\n let element = document.createElement('style');\n document.head.appendChild(element);\n let sheet = element.sheet;\n\n if(typeof hrefs === 'string' || hrefs instanceof String){\n hrefs = [hrefs];\n }\n\n if(typeof hrefs === 'object' && Array.isArray(hrefs)){\n for(const ix in hrefs){\n const href = hrefs[ix];\n let style = `\n li > a[href*=\"${href}\"] {\n display: none;\n }\n `;\n sheet.insertRule(style, sheet.cssRules.length);\n style = `\n #usernavigation a[href*=\"${href}\"] {\n display: none;\n }\n `;\n sheet.insertRule(style, sheet.cssRules.length);\n }\n }\n}\n"],"names":["hrefs","element","document","createElement","head","appendChild","sheet","String","Array","isArray","ix","href","style","insertRule","cssRules","length"],"mappings":"sKAM6BA,WACrBC,QAAUC,SAASC,cAAc,SACrCD,SAASE,KAAKC,YAAYJ,aACtBK,MAAQL,QAAQK,OAEA,iBAAVN,OAAsBA,iBAAiBO,UAC7CP,MAAQ,CAACA,WAGO,iBAAVA,OAAsBQ,MAAMC,QAAQT,WACtC,MAAMU,MAAMV,MAAM,OACZW,KAAOX,MAAMU,QACfE,MAAS,mCACOD,gFAIpBL,MAAMO,WAAWD,MAAON,MAAMQ,SAASC,QACvCH,MAAS,8CACsBD,gFAI/BL,MAAMO,WAAWD,MAAON,MAAMQ,SAASC"} {"version":3,"file":"primary-nav-tools.min.js","sources":["../src/primary-nav-tools.js"],"sourcesContent":["/*eslint-env es6*/\n/*eslint no-console: \"off\"*/\n\n/**\n * Hide a primary navigation item by href\n * @param {string|Array} hrefs The link that should be hidden\n */\nexport function hide_primary(hrefs) {\n if(typeof hrefs === 'string' || hrefs instanceof String){\n hrefs = [hrefs];\n }\n\n if(typeof hrefs === 'object' && Array.isArray(hrefs)){\n let element = document.createElement('style');\n document.head.appendChild(element);\n let sheet = element.sheet;\n for(const ix in hrefs){\n const href = hrefs[ix];\n console.info(`Hiding ${href}`);\n let style = `\n li > a[href*=\"${href}\"] {\n display: none;\n }\n `;\n sheet.insertRule(style, sheet.cssRules.length);\n style = `\n #usernavigation a[href*=\"${href}\"] {\n display: none;\n }\n `;\n sheet.insertRule(style, sheet.cssRules.length);\n }\n console.info(element);\n console.info(sheet);\n }\n}\n"],"names":["hrefs","String","Array","isArray","element","document","createElement","head","appendChild","sheet","ix","href","console","info","style","insertRule","cssRules","length"],"mappings":"sKAO6BA,QACL,iBAAVA,OAAsBA,iBAAiBC,UAC7CD,MAAQ,CAACA,WAGO,iBAAVA,OAAsBE,MAAMC,QAAQH,OAAO,KAC7CI,QAAUC,SAASC,cAAc,SACrCD,SAASE,KAAKC,YAAYJ,aACtBK,MAAQL,QAAQK,UAChB,MAAMC,MAAMV,MAAM,OACZW,KAAOX,MAAMU,IACnBE,QAAQC,KAAM,UAASF,YACnBG,MAAS,mCACOH,gFAIpBF,MAAMM,WAAWD,MAAOL,MAAMO,SAASC,QACvCH,MAAS,8CACsBH,gFAI/BF,MAAMM,WAAWD,MAAOL,MAAMO,SAASC,QAE3CL,QAAQC,KAAKT,SACbQ,QAAQC,KAAKJ"}

View File

@ -182,12 +182,8 @@ export function init(contextid,categoryid,options) {
// load studyplan from hash if applicable // load studyplan from hash if applicable
const hash = location.hash.replace('#',''); const hash = location.hash.replace('#','');
if(hash){ if(hash){
for(let idx in app.studyplans){ const id = hash;
if(app.studyplans[idx].id == hash){ app.selectStudyplan(id);
app.selectStudyplan(app.studyplans[idx]);
break;
}
}
} }
}).catch(notification.exception); }).catch(notification.exception);
call([{ call([{
@ -242,13 +238,13 @@ export function init(contextid,categoryid,options) {
window.location.href = window.location.pathname + "?" + params.toString(); window.location.href = window.location.pathname + "?" + params.toString();
},50); },50);
}, },
selectStudyplan(studyplan){ selectStudyplan(studyplanid){
// fetch studyplan // fetch studyplan
app.loadingstudyplan = true; app.loadingstudyplan = true;
app.activestudyplan = null; app.activestudyplan = null;
call([{ call([{
methodname: 'local_treestudyplan_get_studyplan_map', methodname: 'local_treestudyplan_get_studyplan_map',
args: { id: studyplan.id} args: { id: studyplanid}
}])[0].then(function(response){ }])[0].then(function(response){
app.activestudyplan = ProcessStudyplan(response); app.activestudyplan = ProcessStudyplan(response);
debug.info('studyplan processed'); debug.info('studyplan processed');

View File

@ -1,21 +1,22 @@
/*eslint-env es6*/ /*eslint-env es6*/
/*eslint no-console: "off"*/
/** /**
* Hide a primary navigation item by href * Hide a primary navigation item by href
* @param {string|Array} hrefs The link that should be hidden * @param {string|Array} hrefs The link that should be hidden
*/ */
export function hide_primary(hrefs) { export function hide_primary(hrefs) {
let element = document.createElement('style');
document.head.appendChild(element);
let sheet = element.sheet;
if(typeof hrefs === 'string' || hrefs instanceof String){ if(typeof hrefs === 'string' || hrefs instanceof String){
hrefs = [hrefs]; hrefs = [hrefs];
} }
if(typeof hrefs === 'object' && Array.isArray(hrefs)){ if(typeof hrefs === 'object' && Array.isArray(hrefs)){
let element = document.createElement('style');
document.head.appendChild(element);
let sheet = element.sheet;
for(const ix in hrefs){ for(const ix in hrefs){
const href = hrefs[ix]; const href = hrefs[ix];
console.info(`Hiding ${href}`);
let style = ` let style = `
li > a[href*="${href}"] { li > a[href*="${href}"] {
display: none; display: none;
@ -29,5 +30,7 @@ export function hide_primary(hrefs) {
`; `;
sheet.insertRule(style, sheet.cssRules.length); sheet.insertRule(style, sheet.cssRules.length);
} }
console.info(element);
console.info(sheet);
} }
} }

View File

@ -107,14 +107,14 @@ class badgeinfo {
public static function editor_structure($value = VALUE_REQUIRED) : \external_description { public static function editor_structure($value = VALUE_REQUIRED) : \external_description {
return new \external_single_structure([ return new \external_single_structure([
"id" => new \external_value(PARAM_INT, 'id of badge'), "id" => new \external_value(PARAM_INT, 'id of badge'),
"infolink" => new \external_value(PARAM_TEXT, 'badge issue information link', VALUE_OPTIONAL), "infolink" => new \external_value(PARAM_RAW, 'badge issue information link', VALUE_OPTIONAL),
"name" => new \external_value(PARAM_TEXT, 'badge name'), "name" => new \external_value(PARAM_RAW, 'badge name'),
"status" => new \external_value(PARAM_TEXT, 'badge status'), "status" => new \external_value(PARAM_TEXT, 'badge status'),
"locked" => new \external_value(PARAM_TEXT, 'badge lock status'), "locked" => new \external_value(PARAM_TEXT, 'badge lock status'),
"criteria" => new \external_multiple_structure( "criteria" => new \external_multiple_structure(
new \external_value(PARAM_RAW, 'criteria text'), 'badge criteria', VALUE_OPTIONAL), new \external_value(PARAM_RAW, 'criteria text'), 'badge criteria', VALUE_OPTIONAL),
"description" => new \external_value(PARAM_TEXT, 'badge description'), "description" => new \external_value(PARAM_RAW, 'badge description'),
"imageurl" => new \external_value(PARAM_TEXT, 'url of badge image'), "imageurl" => new \external_value(PARAM_RAW, 'url of badge image'),
"studentcount" => new \external_value(PARAM_INT, "studentcount" => new \external_value(PARAM_INT,
'number of studyplan students that can get this badge', VALUE_OPTIONAL), 'number of studyplan students that can get this badge', VALUE_OPTIONAL),
"issuedcount" => new \external_value(PARAM_INT, "issuedcount" => new \external_value(PARAM_INT,
@ -823,17 +823,16 @@ class badgeinfo {
[$insql, $inparams] = $DB->get_in_or_equal([BADGE_STATUS_ACTIVE, BADGE_STATUS_ACTIVE_LOCKED]); [$insql, $inparams] = $DB->get_in_or_equal([BADGE_STATUS_ACTIVE, BADGE_STATUS_ACTIVE_LOCKED]);
$conditions .= " AND b.status $insql"; $conditions .= " AND b.status $insql";
$basesqlparams = array_merge($basesqlparams,$inparams); $basesqlparams = array_merge($basesqlparams,$inparams);
} }
// Get all course badges for this course // Get all course badges for this course
$coursebadges = []; $badgesids = [];
$sql = "SELECT DISTINCT b.id from {badge} b $sql = "SELECT DISTINCT b.id from {badge} b
WHERE b.courseid = :courseid AND $conditions"; WHERE b.courseid = :courseid AND $conditions";
$coursebadgesids = $DB->get_fieldset_sql($sql,$basesqlparams); $badgesids = $DB->get_fieldset_sql($sql,$basesqlparams);
return $coursebadgesids; return $badgesids;
} }
/** /**
@ -879,4 +878,46 @@ class badgeinfo {
return $badges; return $badges;
} }
/**
* Search site badges
* @param string $search An optional search string to filter by
* @param bool $active Only list active badges
* @return array of badge
*/
public static function search_site_badges($search='', $active=false) {
global $DB;
$search = trim($search);
$conditions = "TRUE";
$basesqlparams = ['type' => \BADGE_TYPE_SITE];
if (strlen($search) > 0) {
$conditions .= " AND ".$DB->sql_like('b.name',':search');
$basesqlparams["search"] = "%$search%";
}
if ($active) {
[$insql, $inparams] = $DB->get_in_or_equal([BADGE_STATUS_ACTIVE, BADGE_STATUS_ACTIVE_LOCKED]);
$conditions .= " AND b.status $insql";
$basesqlparams = array_merge($basesqlparams,$inparams);
}
// Get all course badges for this course
$sql = "SELECT DISTINCT b.id from {badge} b
WHERE $conditions";
$badgeids = $DB->get_fieldset_sql($sql,$basesqlparams);
$badges = [];
foreach (array_unique($badgeids) as $id) {
$badges[] = new self(new badge($id));
}
usort($badges,function($a,$b) {
return $a->name() <=> $b->name();
});
return $badges;
}
} }

View File

@ -0,0 +1,174 @@
<?php
// This file is part of the Studyplan plugin for Moodle
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <https://www.gnu.org/licenses/>.
/**
* Generate random grades and feedback to initialize development environment
* @package local_treestudyplan
* @copyright 2023 P.M. Kuipers - Chris Zuber
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace local_treestudyplan\local;
use Exception;
/**
* Generate random grades and feedback to initialize development environment
*/
class randomimage {
/**
* Image width
* @var integer
*/
private $width;
/**
* Image height
* @var integer
*/
private $height ;
/**
* Number of shapes to draw
* @var integer
*/
private $shapes;
/**
* Image name
* @var string
*/
public $name;
/**
* Image temporary file
* @var string
*/
public $tempfile;
/**
* Various available styles for arcs
* @var Arary
*/
const ARC_STYLES = [
IMG_ARC_PIE,
IMG_ARC_CHORD,
IMG_ARC_EDGED,
IMG_ARC_NOFILL
];
/**
* Create a random polygon with number of points between 0 & $max_pts
* @param \GdImage $im The image reource
* @param integer $max_pts Max number of point to use
* @return void
*/
private function random_polygon($im, Int $max_pts = 20)
{
$color = imagecolorallocatealpha($im, ...$this->random_color_alpha());
$pts = $this->random_pts(\random_int(3, $max_pts));
imagefilledpolygon($im, $pts, $color);
}
/**
* Creates a random arc of a random color
* @param \GdImage $im The image resource
* @return void
*/
private function random_arc($im)
{
$cx = \random_int(0, $this->width);
$cy = \random_int(0, $this->height);
$w = \random_int(0, $this->width);
$h = \random_int(0, $this->height);
$s = \random_int(0, 360);
$e = \random_int(0, 360);
$col = imagecolorallocatealpha($im, ...$this->random_color_alpha());
$style = self::ARC_STYLES[\random_int(0, 3)];
imagefilledarc($im, $cx, $cy, $w, $h, $s, $e, $col, $style);
}
/**
* Generates an array of random alpha color values.
* @return Array [r, g, b, a]
*/
private function random_color_alpha(): Array
{
return [
\random_int(0, 255),
\random_int(0, 255),
\random_int(0, 255),
\random_int(0, 127)
];
}
/**
* Generates a set of random points for a polygon [x1,y1, x2,y2,...]
* @param integer $length Number of sets of points to generate
* @return Array The resulting array of points
*/
private function random_pts($length): Array
{
$pts = [];
for($n = 0; $n < $length; $n++) {
$pts[] = \random_int(0, $this->width);
$pts[] = \random_int(0, $this->height);
}
return $pts;
}
public function __construct($shapes=3,$width=256,$height=256) {
$this->shapes = $shapes;
$this->width = $width;
$this->height = $height;
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$string = '';
for ($i = 0; $i < 20; $i++) {
$string .= $characters[\mt_rand(0, strlen($characters) - 1)];
}
$this->name = $string.".png";
$im = imagecreatetruecolor($this->width, $this->height);
for ($i = 0; $i < $this->shapes; $i++) {
switch(\random_int(1, 2)) {
case 1:
$this->random_arc($im);
break;
case 2:
$this->random_polygon($im);
break;
}
}
$this->tempfile = \tempnam("/tmp","tsp");
imagepng($im,$this->tempfile);
imagedestroy($im);
}
public function content() {
return $this->content = \file_get_contents($this->tempfile);
}
public function __destruct()
{
if (isset($this->tempfile) && file_exists($this->tempfile)) {
unlink($this->tempfile);
}
}
}

View File

@ -875,20 +875,15 @@ class studyplanservice extends \external_api {
*/ */
public static function search_badges($search,$active=false) { public static function search_badges($search,$active=false) {
$systemcontext = webservicehelper::system_context(); $systemcontext = webservicehelper::system_context();
$search = trim($search); // Check system permission to
webservicehelper::require_capabilities("moodle/badges:viewbadges",$systemcontext);
$result = []; $results = [];
$badges = badges_get_badges(BADGE_TYPE_SITE, "timemodified"); $badges = badgeinfo::search_site_badges($search,$active);
foreach ($badges as $badgeinfo) {
foreach ($badges as $badge) { $results[] = $badgeinfo->editor_model();
if (!$active || $badge->is_active()) {
if (strlen($search) == 0 || mb_stristr($badge->name,$search) ) {
$result[] = (new badgeinfo($badge))->editor_model();
} }
} return $results;
}
return $result;
} }

146
cli/generate_badges.php Normal file
View File

@ -0,0 +1,146 @@
<?php
// This file is part of the Studyplan plugin for Moodle
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <https://www.gnu.org/licenses/>.
/**
* Developer CLI tool. Primes grade generator with random student properties
* @package local_treestudyplan
* @copyright 2023 P.M. Kuipers
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace local_treestudyplan;
define('CLI_SCRIPT', true);
require(__DIR__ . '/../../../config.php');
require_once($CFG->libdir . '/clilib.php');
use \core_badges\badge;
use local_treestudyplan\local\randomimage;
require_once($CFG->libdir.'/badgeslib.php');
$usage = "Generate a number of random badges
Usage:
# php generate_badges.php [--amount|-a=<amount>]
# php generate_badges.php --help|-h
Options:
-h --help Print this help.
-a --amount=<amount> The amount of badges to generate.
";
list($options, $unrecognised) = cli_get_params([
'help' => false,
'amount' => null
], [
'h' => 'help',
'a' => 'amount',
]);
if ($unrecognised) {
$unrecognised = implode(PHP_EOL . ' ', $unrecognised);
cli_error(get_string('cliunknowoption', 'core_admin', $unrecognised));
}
if ($options['help']) {
cli_writeln($usage);
exit(2);
}
print_r($options);
if (empty($options['amount']) || !is_numeric($options['amount'])) {
cli_error('Missing mandatory integer argument "amount"', 2);
}
$amount = intval($options['amount']);
cli_writeln("Creating {$amount} new badges");
$fortunepath = "/usr/games/fortune";
if (!is_executable($fortunepath)) {
// Get a fortune if it is available.
cli_error('/usr/bin/fortune not found, which is needed for this script. Please install fortune',2);
}
// Get administrator role and log in as.
$user = get_admin();
if (!$user) {
cli_error("Unable to find admin user in DB.");
}
$auth = empty($user->auth) ? 'manual' : $user->auth;
if ($auth == 'nologin' || !is_enabled_auth($auth)) {
cli_error(sprintf("User authentication is either 'nologin' or disabled. Check Moodle authentication method for '%s'",
$user->username));
}
$authplugin = get_auth_plugin($auth);
$authplugin->sync_roles($user);
login_attempt_valid($user);
complete_user_login($user);
for ($i=0; $i<$amount; $i++) {
$fortune = shell_exec("{$fortunepath} -n 160 ");
$pieces = explode(" ", $fortune);
$name = implode(" ", array_splice($pieces, 0, 4));
$fordb = new \stdClass();
$fordb->id = null;
$now = time();
$randomicon = new randomimage(10,256,256);
$fordb->name = $name;
$fordb->version = 1;
$fordb->language = "en";
$fordb->description = $fortune;
$fordb->imageauthorname = "Generator";
$fordb->imageauthoremail = "generator@null.null";
$fordb->imageauthorurl = "";
$fordb->imagecaption = $name;
$fordb->timecreated = $now;
$fordb->timemodified = $now;
$fordb->usercreated = $USER->id;
$fordb->usermodified = $USER->id;
$url = parse_url($CFG->wwwroot);
$fordb->issuerurl = $url['scheme'] . '://' . $url['host'];
$fordb->issuername = $CFG->badges_defaultissuername;
$fordb->issuercontact = $CFG->badges_defaultissuercontact;
$fordb->expiredate = null;
$fordb->expireperiod = null;
$fordb->type = \BADGE_TYPE_SITE; // Site badge.
$fordb->courseid = null;
$fordb->messagesubject = get_string('messagesubject', 'badges');
$fordb->message = get_string('messagebody', 'badges',
\html_writer::link($CFG->wwwroot . '/badges/mybadges.php', get_string('managebadges', 'badges')));
$fordb->attachment = 1;
$fordb->notification = \BADGE_MESSAGE_NEVER;
$fordb->status = \BADGE_STATUS_INACTIVE;
$newid = $DB->insert_record('badge', $fordb, true);
// Trigger event, badge created.
$eventparams = array('objectid' => $newid, 'context' => $PAGE->context);
$event = \core\event\badge_created::create($eventparams);
$event->trigger();
$newbadge = new badge($newid);
badges_process_badge_image($newbadge, $randomicon->tempfile);
cli_writeln("Created new badge '{$name}'");
}

View File

@ -665,6 +665,7 @@
top: -5px; top: -5px;
right: -5px; right: -5px;
font-size: 16px; font-size: 16px;
background-color: transparent;
} }
.path-local-treestudyplan a.t-item-course-config, .path-local-treestudyplan a.t-item-course-config,
.features-treestudyplan a.t-item-course-config { .features-treestudyplan a.t-item-course-config {
@ -1537,3 +1538,16 @@
.features-treestudyplan .b-modal-justify-footer-between .modal-footer { .features-treestudyplan .b-modal-justify-footer-between .modal-footer {
justify-content: space-between; justify-content: space-between;
} }
.path-local-treestudyplan .collapse.show,
.features-treestudyplan .collapse.show {
height: auto;
}
body.path-local-treestudyplan.bootstrap-polyfill,
.features-treestudyplan.bootstrap-polyfill {
/* Contains a number of CSS tweaks only needed if the current theme is nog based on boost with bootstrap */
}
body.path-local-treestudyplan.bootstrap-polyfill .collapse.show,
.features-treestudyplan.bootstrap-polyfill .collapse.show {
height: auto;
}

View File

@ -106,7 +106,7 @@ print $OUTPUT->header();
</div> </div>
</div> </div>
<div v-cloak> <div v-cloak>
<div v-if='!activestudyplan && usedcontexts' class='ml-3 mb-3 s-context-selector'> <div v-if='!activestudyplan && usedcontexts && !loadingstudyplan' class='ml-3 mb-3 s-context-selector'>
<b-form-select text='<?php print($contextname);?>' :value="contextid" @change='switchContext' <b-form-select text='<?php print($contextname);?>' :value="contextid" @change='switchContext'
:class="(!(usedcontexts.length))?'text-primary':''"> :class="(!(usedcontexts.length))?'text-primary':''">
<b-form-select-option v-if='!(usedcontexts.length)' :value="contextid" <b-form-select-option v-if='!(usedcontexts.length)' :value="contextid"
@ -127,12 +127,12 @@ print $OUTPUT->header();
<a href='#' v-if='activestudyplan' @click.prevent='closeStudyplan' <a href='#' v-if='activestudyplan' @click.prevent='closeStudyplan'
><i style='font-size: 150%;' class='fa fa-chevron-left'></i> <?php t('back');?></a> ><i style='font-size: 150%;' class='fa fa-chevron-left'></i> <?php t('back');?></a>
<span v-if='activestudyplan'><?php t("studyplan_select"); ?></span>&nbsp; <span v-if='activestudyplan'><?php t("studyplan_select"); ?></span>&nbsp;
<b-form-select v-if='activestudyplan' lazy :text='dropdown_title' v-model='activestudyplan.id'> <b-form-select v-if='activestudyplan' lazy :text='dropdown_title' :value='activestudyplan.id' @change="selectStudyplan">
<b-form-select-option <b-form-select-option
v-for='(studyplan, planindex) in studyplans' v-for='(studyplan, planindex) in studyplans'
:value="studyplan.id" :value="studyplan.id"
:key='studyplan.id' :key='studyplan.id'
@click='selectStudyplan(studyplan)'>{{ studyplan.name }}</b-form-select-option> >{{ studyplan.name }}</b-form-select-option>
</b-form-select>&nbsp; </b-form-select>&nbsp;
<t-studyplan-edit <t-studyplan-edit
@created="onStudyPlanCreated" @created="onStudyPlanCreated"
@ -169,7 +169,7 @@ print $OUTPUT->header();
:key='studyplan.id' :key='studyplan.id'
v-model='studyplans[planindex]' v-model='studyplans[planindex]'
open open
@open='selectStudyplan(studyplan)' @open='selectStudyplan(studyplan.id)'
> >
<template #title> <template #title>
<span class='s-studyplan-card-title-buttons'> <span class='s-studyplan-card-title-buttons'>

43
lib.php
View File

@ -511,6 +511,49 @@ function local_treestudyplan_pluginfile(
return false; return false;
} }
}
/**
* Things to do on the start of every instance.
*
* Beware: do not access theme in this function, find another hook!!
*/
/*
function local_treestudyplan_after_config() {
global $PAGE;
/* WARNINGS from the documentation about this callback:
This callback is very "raw" and so there are a number of edge cases that you should think about and possibly protect against. If this callback throws an exception that means you can very easily brick your moodle site
- running while in unit tests
- during install
- during upgrade
- generic exceptions of any type
Also depending on the defines set before config.php is required, you may not have a $USER object, or other apis, eg if ABORT_AFTER_CONFIG or NO_MOODLE_COOKIES is defined. */
/*
// So, catch all exceptions to avoid page breaking. We should never break the page in this function.
try {
// Check if $PAGE is available and valid for use.
if (!empty($PAGE) && is_object($PAGE) && method_exists($PAGE,"add_body_class")) {
// Check to see if the theme is based on classic or boost to see if we need to add a polyfill...
$bootstrapbased = false;
foreach ($PAGE->theme->parents as $p) {
if ($p->name == 'boost' || $p->name == 'classic') {
$bootstrapbased = true;
break;
}
}
if (!$bootstrapbased) {
//$PAGE->add_body_class("bootstrap-polyfill"); // Enable the polyfill for boost styling.
}
}
} catch (\Exception $x) {
}
} }
*/

View File

@ -3,6 +3,16 @@
justify-content: space-between; justify-content: space-between;
} }
.collapse.show {
height: auto;
}
}
body.path-local-treestudyplan.bootstrap-polyfill, .features-treestudyplan.bootstrap-polyfill {
/* Contains a number of CSS tweaks only needed if the current theme is nog based on boost with bootstrap */
.collapse.show {
height: auto;
}
} }

View File

@ -561,6 +561,7 @@
top: -5px; top: -5px;
right: -5px; right: -5px;
font-size: 16px; font-size: 16px;
background-color: transparent;
} }

View File

@ -665,6 +665,7 @@
top: -5px; top: -5px;
right: -5px; right: -5px;
font-size: 16px; font-size: 16px;
background-color: transparent;
} }
.path-local-treestudyplan a.t-item-course-config, .path-local-treestudyplan a.t-item-course-config,
.features-treestudyplan a.t-item-course-config { .features-treestudyplan a.t-item-course-config {
@ -1537,3 +1538,16 @@
.features-treestudyplan .b-modal-justify-footer-between .modal-footer { .features-treestudyplan .b-modal-justify-footer-between .modal-footer {
justify-content: space-between; justify-content: space-between;
} }
.path-local-treestudyplan .collapse.show,
.features-treestudyplan .collapse.show {
height: auto;
}
body.path-local-treestudyplan.bootstrap-polyfill,
.features-treestudyplan.bootstrap-polyfill {
/* Contains a number of CSS tweaks only needed if the current theme is nog based on boost with bootstrap */
}
body.path-local-treestudyplan.bootstrap-polyfill .collapse.show,
.features-treestudyplan.bootstrap-polyfill .collapse.show {
height: auto;
}

View File

@ -22,7 +22,7 @@
defined('MOODLE_INTERNAL') || die(); defined('MOODLE_INTERNAL') || die();
$plugin->component = 'local_treestudyplan'; // Recommended since 2.0.2 (MDL-26035). Required since 3.0 (MDL-48494). $plugin->component = 'local_treestudyplan'; // Recommended since 2.0.2 (MDL-26035). Required since 3.0 (MDL-48494).
$plugin->version = 2024012800; // YYYYMMDDHH (year, month, day, iteration). $plugin->version = 2024020204; // YYYYMMDDHH (year, month, day, iteration).
$plugin->requires = 2021051700; // YYYYMMDDHH (This is the release version for Moodle 3.11). $plugin->requires = 2021051700; // YYYYMMDDHH (This is the release version for Moodle 3.11).
$plugin->release = "1.1.0"; $plugin->release = "1.1.0";