Improved category listing and link hiding
This commit is contained in:
parent
29f11982ff
commit
8aed72af70
2
amd/build/page-edit-plan.min.js
vendored
2
amd/build/page-edit-plan.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
amd/build/page-view-plan.min.js
vendored
2
amd/build/page-view-plan.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
amd/build/primary-nav-tools.min.js
vendored
2
amd/build/primary-nav-tools.min.js
vendored
|
@ -1,3 +1,3 @@
|
||||||
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)}}}));
|
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 css="";for(const ix in hrefs){const href=hrefs[ix];console.info(`Hiding ${href}`),css+=`\n li > a[href*="${href}"] {\n display: none !important; \n }\n `,css+=`\n #usernavigation a[href*="${href}"] {\n display: none !important;\n }\n `}const element=document.createElement("style");element.setAttribute("type","text/css"),"textContent"in element?element.textContent=css:element.styleSheet.cssText=css,document.head.appendChild(element),console.info(element)}}}));
|
||||||
|
|
||||||
//# sourceMappingURL=primary-nav-tools.min.js.map
|
//# sourceMappingURL=primary-nav-tools.min.js.map
|
|
@ -1 +1 @@
|
||||||
{"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"}
|
{"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 css = '' ;\n for(const ix in hrefs){\n const href = hrefs[ix];\n console.info(`Hiding ${href}`);\n css += `\n li > a[href*=\"${href}\"] {\n display: none !important; \n }\n `;\n css += `\n #usernavigation a[href*=\"${href}\"] {\n display: none !important;\n }\n `;\n }\n\n\n const element = document.createElement('style');\n element.setAttribute('type', 'text/css');\n\n if ('textContent' in element) {\n element.textContent = css;\n } else {\n element.styleSheet.cssText = css;\n }\n\n document.head.appendChild(element);\n\n console.info(element);\n }\n}\n"],"names":["hrefs","String","Array","isArray","css","ix","href","console","info","element","document","createElement","setAttribute","textContent","styleSheet","cssText","head","appendChild"],"mappings":"sKAO6BA,QACL,iBAAVA,OAAsBA,iBAAiBC,UAC7CD,MAAQ,CAACA,WAGO,iBAAVA,OAAsBE,MAAMC,QAAQH,OAAO,KAC7CI,IAAM,OACN,MAAMC,MAAML,MAAM,OACZM,KAAON,MAAMK,IACnBE,QAAQC,KAAM,UAASF,QACvBF,KAAQ,mCACYE,4FAIpBF,KAAQ,8CACuBE,iGAO7BG,QAAUC,SAASC,cAAc,SACvCF,QAAQG,aAAa,OAAQ,YAEzB,gBAAiBH,QACjBA,QAAQI,YAAcT,IAEtBK,QAAQK,WAAWC,QAAUX,IAGjCM,SAASM,KAAKC,YAAYR,SAE1BF,QAAQC,KAAKC"}
|
|
@ -193,7 +193,7 @@ export function init(contextid,categoryid,options) {
|
||||||
app.courses = response;
|
app.courses = response;
|
||||||
}).catch(notification.exception);
|
}).catch(notification.exception);
|
||||||
call([{
|
call([{
|
||||||
methodname: 'local_treestudyplan_list_used_categories',
|
methodname: 'local_treestudyplan_list_available_categories',
|
||||||
args: { operation: 'edit', refcontext_id: contextid}
|
args: { operation: 'edit', refcontext_id: contextid}
|
||||||
}])[0].then(function(response){
|
}])[0].then(function(response){
|
||||||
app.usedcontexts = response;
|
app.usedcontexts = response;
|
||||||
|
|
|
@ -100,13 +100,14 @@ export function init(contextid,categoryid) {
|
||||||
}
|
}
|
||||||
}).catch(notification.exception);
|
}).catch(notification.exception);
|
||||||
call([{
|
call([{
|
||||||
methodname: 'local_treestudyplan_list_used_categories',
|
methodname: 'local_treestudyplan_list_available_categories',
|
||||||
args: { operation: 'view', refcontext_id: contextid}
|
args: { operation: 'view', refcontext_id: contextid}
|
||||||
}])[0].then(function(response){
|
}])[0].then(function(response){
|
||||||
const contexts = [];
|
const contexts = [];
|
||||||
for(const ix in response){
|
for(const ix in response){
|
||||||
if(response[ix].studyplancount >0){
|
const cat = response[ix];
|
||||||
contexts.push(response[ix]);
|
if(cat.studyplancount > 0 || cat.context_id == contextid){
|
||||||
|
contexts.push(cat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
app.usedcontexts = contexts;
|
app.usedcontexts = contexts;
|
||||||
|
|
|
@ -11,26 +11,34 @@ export function hide_primary(hrefs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(typeof hrefs === 'object' && Array.isArray(hrefs)){
|
if(typeof hrefs === 'object' && Array.isArray(hrefs)){
|
||||||
let element = document.createElement('style');
|
let css = '' ;
|
||||||
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}`);
|
console.info(`Hiding ${href}`);
|
||||||
let style = `
|
css += `
|
||||||
li > a[href*="${href}"] {
|
li > a[href*="${href}"] {
|
||||||
display: none;
|
display: none !important;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
sheet.insertRule(style, sheet.cssRules.length);
|
css += `
|
||||||
style = `
|
|
||||||
#usernavigation a[href*="${href}"] {
|
#usernavigation a[href*="${href}"] {
|
||||||
display: none;
|
display: none !important;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
sheet.insertRule(style, sheet.cssRules.length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const element = document.createElement('style');
|
||||||
|
element.setAttribute('type', 'text/css');
|
||||||
|
|
||||||
|
if ('textContent' in element) {
|
||||||
|
element.textContent = css;
|
||||||
|
} else {
|
||||||
|
element.styleSheet.cssText = css;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.head.appendChild(element);
|
||||||
|
|
||||||
console.info(element);
|
console.info(element);
|
||||||
console.info(sheet);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,8 +54,11 @@ class courseservice extends \external_api {
|
||||||
* @param int $userid Id of the user
|
* @param int $userid Id of the user
|
||||||
* @return array of core_course_category
|
* @return array of core_course_category
|
||||||
*/
|
*/
|
||||||
public static function user_tops($userid) {
|
public static function user_tops($userid=null,$capability='moodle/category:viewcourselist') {
|
||||||
global $DB;
|
global $DB, $USER;
|
||||||
|
if ($userid == null) {
|
||||||
|
$userid = $USER->id;
|
||||||
|
}
|
||||||
$tops = [];
|
$tops = [];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -300,35 +303,22 @@ class courseservice extends \external_api {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [Description for categories_by_capability]
|
* List all user visible categories the current user has a given capability for.
|
||||||
* @param mixed $capability
|
* @param mixed $capability
|
||||||
* @param core_course_category|null $parent
|
* @param core_course_category|null $parent
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public static function categories_by_capability($capability, core_course_category $parent = null) {
|
public static function categories_by_capability($capability) {
|
||||||
|
global $USER;
|
||||||
// List the categories in which the user has a specific capability.
|
// List the categories in which the user has a specific capability.
|
||||||
$list = [];
|
$list = [];
|
||||||
// Initialize parent if needed.
|
$parents = self::user_tops($USER->id,$capability);
|
||||||
if ($parent == null) {
|
array_merge($list,$parents);
|
||||||
$parent = \core_course_category::user_top();
|
|
||||||
if (has_capability($capability, $parent->get_context())) {
|
|
||||||
$list[] = $parent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$children = $parent->get_children();
|
foreach ($parents as $parent) {
|
||||||
foreach ($children as $child) {
|
// For optimization purposes, we include all its children now, since they will have inherited the permission.
|
||||||
// Check if we should add this category.
|
// #PREMATURE_OPTIMIZATION ???.
|
||||||
if (has_capability($capability, $child->get_context())) {
|
$list = array_merge($list, self::recursive_child_categories($parent));
|
||||||
$list[] = $child;
|
|
||||||
// For optimization purposes, we include all its children now, since they will have inherited the permission.
|
|
||||||
// #PREMATURE_OPTIMIZATION ???.
|
|
||||||
$list = array_merge($list, self::recursive_child_categories($child));
|
|
||||||
} else {
|
|
||||||
if ($child->get_children_count() > 0) {
|
|
||||||
$list = array_merge($list, self::categories_by_capability($capability, $child));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $list;
|
return $list;
|
||||||
|
@ -352,9 +342,9 @@ class courseservice extends \external_api {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return value description for list_used_categories function
|
* Return value description for list_available_categories function
|
||||||
*/
|
*/
|
||||||
public static function list_used_categories_parameters() : \external_function_parameters {
|
public static function list_available_categories_parameters() : \external_function_parameters {
|
||||||
return new \external_function_parameters( [
|
return new \external_function_parameters( [
|
||||||
"operation" => new \external_value(PARAM_TEXT, 'type of operation ["view"|"edit"]', VALUE_DEFAULT),
|
"operation" => new \external_value(PARAM_TEXT, 'type of operation ["view"|"edit"]', VALUE_DEFAULT),
|
||||||
"refcontext_id" => new \external_value(PARAM_INT, 'id of reference context', VALUE_DEFAULT),
|
"refcontext_id" => new \external_value(PARAM_INT, 'id of reference context', VALUE_DEFAULT),
|
||||||
|
@ -362,9 +352,9 @@ class courseservice extends \external_api {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parameter description for list_used_categories function
|
* Parameter description for list_available_categories function
|
||||||
*/
|
*/
|
||||||
public static function list_used_categories_returns() : \external_description {
|
public static function list_available_categories_returns() : \external_description {
|
||||||
return new \external_multiple_structure(static::map_category_structure(true));
|
return new \external_multiple_structure(static::map_category_structure(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,75 +364,96 @@ class courseservice extends \external_api {
|
||||||
* @param int $refctxid Reference context id
|
* @param int $refctxid Reference context id
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public static function list_used_categories($operation = 'edit', $refctxid = 0) {
|
public static function list_available_categories($operation = 'edit', $refctxid = 0) {
|
||||||
global $DB;
|
global $DB;
|
||||||
if ($operation == "edit") {
|
if ($operation == "edit") {
|
||||||
$capability = self::CAP_EDIT;
|
$capability = self::CAP_EDIT;
|
||||||
} else { // Operation == "view" || default.
|
} else { // Operation == "view" || default.
|
||||||
$capability = self::CAP_VIEW;
|
$capability = self::CAP_VIEW;
|
||||||
}
|
}
|
||||||
$contextcounts = [];
|
|
||||||
|
// Get the context ids of all categories the user has access to view and wich have the given permission.
|
||||||
$contextids = [];
|
$contextids = [];
|
||||||
|
$tops = self::user_tops(null,$capability);
|
||||||
|
foreach ($tops as $cat) {
|
||||||
|
$ctx = \context_coursecat::instance($cat->id);
|
||||||
|
$contextids[] = $ctx->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now get an overview of the number of study plans in a given context.
|
||||||
|
$contextcounts = [];
|
||||||
|
$insertctxs = [];
|
||||||
$rs = $DB->get_recordset_sql("SELECT DISTINCT context_id, COUNT(*) as num FROM {local_treestudyplan}
|
$rs = $DB->get_recordset_sql("SELECT DISTINCT context_id, COUNT(*) as num FROM {local_treestudyplan}
|
||||||
GROUP BY context_id");
|
GROUP BY context_id");
|
||||||
foreach ($rs as $r) {
|
foreach ($rs as $r) {
|
||||||
|
// Build the counts.
|
||||||
$contextcounts[$r->context_id] = $r->num;
|
$contextcounts[$r->context_id] = $r->num;
|
||||||
$contextids[] = $r->context_id;
|
// Add any of the categories containing studyplans to the list.
|
||||||
}
|
$ctx = \context::instance_by_id($r->context_id);
|
||||||
|
if (has_capability($capability,$ctx) && !in_array($r->context_id,$contextids)) {
|
||||||
// Add system context to list if needed.
|
$insertctxs[] = $ctx;
|
||||||
if (!in_array(1,$contextids)) {
|
}
|
||||||
array_unshift($contextids,1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$rs->close();
|
$rs->close();
|
||||||
|
|
||||||
$cats = [];
|
$cats = [];
|
||||||
// If the reference context id is not in the list, push it there
|
|
||||||
|
// If the reference context id is not in the list, push it there if the user has proper permissions in that context
|
||||||
if ($refctxid > 1 && !in_array($refctxid, $contextids)) {
|
if ($refctxid > 1 && !in_array($refctxid, $contextids)) {
|
||||||
try {
|
try {
|
||||||
|
// Get the context.
|
||||||
$refctx = \context::instance_by_id($refctxid);
|
$refctx = \context::instance_by_id($refctxid);
|
||||||
$refpath = $refctx->get_parent_context_ids(true);
|
// Double check permissions.
|
||||||
$found = false;
|
if (has_capability($capability,$refctx)) {
|
||||||
foreach ($refpath as $i => $pid) {
|
$insertctxs[] = $refctx;
|
||||||
$idx = array_search($pid,$contextids);
|
|
||||||
if($idx !== false) {
|
|
||||||
|
|
||||||
$contextids = array_merge(
|
|
||||||
array_slice($contextids, 0, $idx+1),
|
|
||||||
array_reverse(array_slice($refpath,0,$i)),
|
|
||||||
array_slice($contextids, $idx+1, count($contextids) - 1)
|
|
||||||
) ;
|
|
||||||
|
|
||||||
$found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!$found) {
|
|
||||||
array_unshift($contextids,$refctxid);
|
|
||||||
}
|
}
|
||||||
} catch(\dml_missing_record_exception $x) {
|
} catch(\dml_missing_record_exception $x) {
|
||||||
// ignore context
|
// ignore context
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// we only have to check the contexts having a study plan for access permissions
|
|
||||||
|
foreach ($insertctxs as $ictx) {
|
||||||
|
// Place this context and all relevant direct parents in the correct spots.
|
||||||
|
$ipath = $ictx->get_parent_context_ids(true);
|
||||||
|
$found = false;
|
||||||
|
foreach ($ipath as $i => $pid) {
|
||||||
|
$idx = array_search($pid,$contextids);
|
||||||
|
if($idx !== false) {
|
||||||
|
|
||||||
|
$contextids = array_merge(
|
||||||
|
array_slice($contextids, 0, $idx+1),
|
||||||
|
array_reverse(array_slice($ipath,0,$i)),
|
||||||
|
array_slice($contextids, $idx+1, count($contextids) - 1)
|
||||||
|
) ;
|
||||||
|
|
||||||
|
$found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!$found) {
|
||||||
|
array_unshift($contextids,$ictx->id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Now translate this to the list of categories.
|
||||||
foreach ($contextids as $ctxid ) {
|
foreach ($contextids as $ctxid ) {
|
||||||
try {
|
try {
|
||||||
$ctx = \context::instance_by_id($ctxid);
|
$ctx = \context::instance_by_id($ctxid);
|
||||||
if (has_capability($capability, $ctx)) {
|
if ($ctx->contextlevel == CONTEXT_SYSTEM) {
|
||||||
if ($ctx->contextlevel == CONTEXT_SYSTEM) {
|
$cat = \core_course_category::top();
|
||||||
$cat = \core_course_category::top();
|
} else if ($ctx->contextlevel == CONTEXT_COURSECAT) {
|
||||||
} else if ($ctx->contextlevel == CONTEXT_COURSECAT) {
|
$cat = \core_course_category::get($ctx->instanceid,\MUST_EXIST,false);
|
||||||
$cat = \core_course_category::get($ctx->instanceid,\MUST_EXIST,true);
|
}
|
||||||
}
|
$cats[] = $cat;
|
||||||
$cats[] = $cat;
|
// In edit mode, also include direct children of the currently selected context.
|
||||||
if ($operation == "edit" && $ctxid == $refctxid) {
|
if ($operation == "edit" && $ctxid == $refctxid) {
|
||||||
// Include direct children for navigation purposes
|
// Include direct children for navigation purposes.
|
||||||
foreach ($cat->get_children() as $ccat) {
|
foreach ($cat->get_children() as $ccat) {
|
||||||
$ccatctx = \context_coursecat::instance($ccat->id);
|
$ccatctx = \context_coursecat::instance($ccat->id);
|
||||||
if (!in_array($ccatctx->id,$contextids)) {
|
if (!in_array($ccatctx->id,$contextids)) {
|
||||||
$cats[] = $ccat;
|
$cats[] = $ccat;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -451,6 +462,7 @@ class courseservice extends \external_api {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// And finally build the proper models, including studyplan count in the category context.
|
||||||
$list = [];
|
$list = [];
|
||||||
foreach ($cats as $cat) {
|
foreach ($cats as $cat) {
|
||||||
$count = 0;
|
$count = 0;
|
||||||
|
|
|
@ -484,9 +484,9 @@ $functions = [
|
||||||
'ajax' => true,
|
'ajax' => true,
|
||||||
'loginrequired' => true,
|
'loginrequired' => true,
|
||||||
],
|
],
|
||||||
'local_treestudyplan_list_used_categories' => [ // Web service function name.
|
'local_treestudyplan_list_available_categories' => [ // Web service function name.
|
||||||
'classname' => '\local_treestudyplan\courseservice', // Class containing the external function.
|
'classname' => '\local_treestudyplan\courseservice', // Class containing the external function.
|
||||||
'methodname' => 'list_used_categories', // External function name.
|
'methodname' => 'list_available_categories', // External function name.
|
||||||
'description' => 'Get categories hosting a studyplan',
|
'description' => 'Get categories hosting a studyplan',
|
||||||
'type' => 'read', // Database rights of the web service function (read, write).
|
'type' => 'read', // Database rights of the web service function (read, write).
|
||||||
'capabilities' => 'local/treestudyplan:editstudyplan',
|
'capabilities' => 'local/treestudyplan:editstudyplan',
|
||||||
|
|
|
@ -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 = 2024020204; // YYYYMMDDHH (year, month, day, iteration).
|
$plugin->version = 2024020400; // 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";
|
||||||
|
|
Loading…
Reference in New Issue
Block a user