Added templating function
This commit is contained in:
parent
2369610903
commit
82838c57c5
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/report-viewer-components.min.js
vendored
2
amd/build/report-viewer-components.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/studyplan-editor-components.min.js
vendored
2
amd/build/studyplan-editor-components.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/util/date-helper.min.js
vendored
2
amd/build/util/date-helper.min.js
vendored
|
@ -1,3 +1,3 @@
|
|||
define("local_treestudyplan/util/date-helper",["exports"],(function(_exports){function format_date(d,short){d instanceof Date||("number"==typeof d&&(d*=1e3),d=new Date(d));let monthformat="short";return!0===short?monthformat="numeric":!1===short&&(monthformat="long"),d.toLocaleDateString(document.documentElement.lang,{year:"numeric",month:monthformat,day:"numeric"})}function studyplanDates(plan){let earliestStart=null,latestEnd=null,openEnded=!1;for(const ix in plan.pages){const page=plan.pages[ix],s=new Date(page.startdate);if(page.enddate||(openEnded=!0),(!earliestStart||s<earliestStart)&&(earliestStart=s),page.enddate){const e=new Date(page.enddate);(!latestEnd||e>latestEnd)&&(latestEnd=e)}}return{start:earliestStart,end:openEnded?null:latestEnd}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.add_days=function(datestr,days){const date=new Date(datestr);return function(date){const d=new Date(date);let month=""+(d.getMonth()+1),day=""+d.getDate();const year=d.getFullYear();month.length<2&&(month="0"+month);day.length<2&&(day="0"+day);return[year,month,day].join("-")}(new Date(date.getTime()+864e5*days))},_exports.datespaninfo=function(first,last){first instanceof Date||(first=new Date(first));last instanceof Date||(last=new Date(last));first.setHours(0),first.setMinutes(0),first.setSeconds(0),first.setMilliseconds(0),last.setHours(23),last.setMinutes(59),last.setSeconds(59),last.setMilliseconds(999);const dayspan=Math.round((last-first+1)/864e5),years=Math.floor(dayspan/365),ydaysleft=dayspan%365,weeks=Math.floor(ydaysleft/7);return{first:first,last:last,totaldays:dayspan,years:years,weeks:weeks,days:ydaysleft%7,formatted:{first:format_date(first),last:format_date(last)}}},_exports.format_date=format_date,_exports.format_datetime=function(d,short){d instanceof Date||("number"==typeof d&&(d*=1e3),d=new Date(d));let monthformat="short";!0===short?monthformat="numeric":!1===short&&(monthformat="long");return d.toLocaleDateString(document.documentElement.lang,{year:"numeric",month:monthformat,day:"numeric"})+" "+d.toLocaleTimeString(document.documentElement.lang,{timeStyle:"short"})},_exports.studyplanDates=studyplanDates,_exports.studyplanPageTiming=function(page){const now=(new Date).getTime();if(page.timeless)return"present";const start=new Date(page.startdate),end=page.enddate?new Date(page.enddate):null;return start<now?end&&now>end?"past":"present":"future"},_exports.studyplanTiming=function(plan){const now=(new Date).getTime();if(!plan.pages&&0==plan.pages.length||plan.pages[0].timeless)return"present";const dates=studyplanDates(plan);return dates.start<now?dates.end&&now>dates.end?"past":"present":"future"}}));
|
||||
define("local_treestudyplan/util/date-helper",["exports"],(function(_exports){function format_date(d,short){d instanceof Date||("number"==typeof d&&(d*=1e3),d=new Date(d));let monthformat="short";return!0===short?monthformat="numeric":!1===short&&(monthformat="long"),d.toLocaleDateString(document.documentElement.lang,{year:"numeric",month:monthformat,day:"numeric"})}function studyplanDates(plan){let earliestStart=null,latestEnd=null,openEnded=!1;for(const ix in plan.pages){const page=plan.pages[ix],s=new Date(page.startdate);if(page.enddate||(openEnded=!0),(!earliestStart||s<earliestStart)&&(earliestStart=s),page.enddate){const e=new Date(page.enddate);(!latestEnd||e>latestEnd)&&(latestEnd=e)}}return{start:earliestStart,end:openEnded?null:latestEnd}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.add_days=function(datestr,days){const date=new Date(datestr);return function(date){const d=new Date(date);let month=""+(d.getMonth()+1),day=""+d.getDate();const year=d.getFullYear();month.length<2&&(month="0"+month);day.length<2&&(day="0"+day);return[year,month,day].join("-")}(new Date(date.getTime()+864e5*days))},_exports.datespaninfo=function(first,last){first instanceof Date||(first=new Date(first));last instanceof Date||(last=new Date(last));first.setHours(0),first.setMinutes(0),first.setSeconds(0),first.setMilliseconds(0),last.setHours(23),last.setMinutes(59),last.setSeconds(59),last.setMilliseconds(999);const dayspan=Math.round((last-first+1)/864e5),years=Math.floor(dayspan/365),ydaysleft=dayspan%365,weeks=Math.floor(ydaysleft/7);return{first:first,last:last,totaldays:dayspan,years:years,weeks:weeks,days:ydaysleft%7,formatted:{first:format_date(first),last:format_date(last)}}},_exports.format_date=format_date,_exports.format_datetime=function(d,short){d instanceof Date||("number"==typeof d&&(d*=1e3),d=new Date(d));let monthformat="short";!0===short?monthformat="numeric":!1===short&&(monthformat="long");return d.toLocaleDateString(document.documentElement.lang,{year:"numeric",month:monthformat,day:"numeric"})+" "+d.toLocaleTimeString(document.documentElement.lang,{timeStyle:"short"})},_exports.studyplanDates=studyplanDates,_exports.studyplanPageTiming=function(page){const now=(new Date).getTime();if(page.timeless)return"present";const start=new Date(page.startdate),end=page.enddate?new Date(page.enddate):null;return start<now?end&&now>end?"past":"present":"future"},_exports.studyplanTiming=function(plan){const now=(new Date).getTime();if(!plan.pages&&0==plan.pages.length||plan.pages[0]&&plan.pages[0].timeless)return"present";const dates=studyplanDates(plan);return dates.start<now?dates.end&&now>dates.end?"past":"present":"future"}}));
|
||||
|
||||
//# sourceMappingURL=date-helper.min.js.map
|
File diff suppressed because one or more lines are too long
11912
amd/build/vue/vue.min.js
vendored
11912
amd/build/vue/vue.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
|
@ -28,6 +28,9 @@ import {load_strings} from './util/string-helper';
|
|||
import {ProcessStudyplan} from './studyplan-processor';
|
||||
import {download,upload} from './downloader';
|
||||
import {studyplanTiming} from './util/date-helper';
|
||||
import { premiumenabled, premiumstatus } from "./util/premium";
|
||||
import mFormComponents from "./util/mform-helper";
|
||||
Vue.use(mFormComponents);
|
||||
|
||||
import PortalVue from './portal-vue/portal-vue.esm';
|
||||
Vue.use(PortalVue);
|
||||
|
@ -50,6 +53,9 @@ import('core_form/changechecker').then((ns) => {
|
|||
let strings = load_strings({
|
||||
studyplan: {
|
||||
studyplan_select_placeholder: 'studyplan_select_placeholder',
|
||||
advanced_import_from_file: 'advanced_import_from_file',
|
||||
advanced_create_from_template: 'advanced_create_from_template',
|
||||
studyplan_add: "studyplan_add",
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -99,6 +105,7 @@ export function init(contextid,categoryid,options) {
|
|||
activepage: null,
|
||||
loadingstudyplan: false,
|
||||
studyplans: [],
|
||||
templatecount: 0,
|
||||
|
||||
text: strings.studyplan,
|
||||
usedcontexts: [],
|
||||
|
@ -128,6 +135,7 @@ export function init(contextid,categoryid,options) {
|
|||
this.initialize();
|
||||
},
|
||||
computed: {
|
||||
premiumenabled,
|
||||
dropdown_title(){
|
||||
if(this.activestudyplan && this.activestudyplan.name){
|
||||
return this.activestudyplan.name;
|
||||
|
@ -170,7 +178,12 @@ export function init(contextid,categoryid,options) {
|
|||
const hash = location.hash.replace('#','');
|
||||
if(hash){
|
||||
const id = hash;
|
||||
app.selectStudyplan(id);
|
||||
for(const p of app.studyplans) {
|
||||
if (p.id == id) {
|
||||
app.selectStudyplan(id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}).catch(notification.exception);
|
||||
|
||||
|
@ -180,6 +193,16 @@ export function init(contextid,categoryid,options) {
|
|||
}])[0].then(function(response){
|
||||
app.usedcontexts = response;
|
||||
}).catch(notification.exception);
|
||||
|
||||
this.refreshTemplateCount();
|
||||
},
|
||||
refreshTemplateCount(){
|
||||
call([{
|
||||
methodname: 'local_treestudyplan_count_templates',
|
||||
args: { }
|
||||
}])[0].then(function(response){
|
||||
app.templatecount = response;
|
||||
}).catch(notification.exception);
|
||||
},
|
||||
closeStudyplan() {
|
||||
app.activestudyplan = null;
|
||||
|
|
|
@ -447,25 +447,23 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
if (self.studyplans.present.length == 1) {
|
||||
// Directly show the current study plan if it's the only current one
|
||||
const plan = self.studyplans.present[0];
|
||||
if (!plan.suspended) {
|
||||
self.selectStudyplan(plan);
|
||||
}
|
||||
} else {
|
||||
// If there is but a single studyplan, select it anyway, even if it is not current...
|
||||
if (this.studyplancount == 1) {
|
||||
if(self.studyplans.future.lengh > 0) {
|
||||
const plan = self.studyplans.future[0];
|
||||
if (!plan.suspended) {
|
||||
self.selectStudyplan(plan);
|
||||
}
|
||||
} else {
|
||||
const plan = self.studyplans.past[0];
|
||||
if (!plan.suspended) {
|
||||
self.selectStudyplan(plan);
|
||||
}
|
||||
// If there is but a single studyplan, select it anyway, even if it is not current...
|
||||
if (this.studyplancount == 1) {
|
||||
if (self.studyplans.present.length > 0) {
|
||||
// Directly show the current study plan if it's the only current one
|
||||
const plan = self.studyplans.present[0];
|
||||
if (!plan.suspended) {
|
||||
self.selectStudyplan(plan);
|
||||
}
|
||||
} else if(self.studyplans.future.lengh > 0) {
|
||||
const plan = self.studyplans.future[0];
|
||||
if (!plan.suspended) {
|
||||
self.selectStudyplan(plan);
|
||||
}
|
||||
} else {
|
||||
const plan = self.studyplans.past[0];
|
||||
if (!plan.suspended) {
|
||||
self.selectStudyplan(plan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -980,7 +980,7 @@ export default {
|
|||
{
|
||||
call([{
|
||||
methodname: 'local_treestudyplan_find_coach',
|
||||
args: { like: searchtext, exclude_id: self.value.id}
|
||||
args: { like: searchtext, studyplan_id: self.value.id}
|
||||
}])[0].then(function(response){
|
||||
self.search.coaches = response.map(self.userOptionModel);
|
||||
}).catch(notification.exception);
|
||||
|
|
|
@ -168,7 +168,7 @@ export function studyplanTiming(plan) {
|
|||
const now = new Date().getTime();
|
||||
|
||||
// If timeless or no timing info is available, all plans are present
|
||||
if (!plan.pages && plan.pages.length == 0 || plan.pages[0].timeless) {
|
||||
if (!plan.pages && plan.pages.length == 0 || (plan.pages[0] && plan.pages[0].timeless)) {
|
||||
return 'present';
|
||||
}
|
||||
|
||||
|
|
11907
amd/src/vue/vue.js
11907
amd/src/vue/vue.js
File diff suppressed because one or more lines are too long
|
@ -140,12 +140,10 @@ class associationservice extends \external_api {
|
|||
INNER JOIN {local_treestudyplan_page} p ON l.page_id = p.id
|
||||
WHERE a.userid = :userid AND p.studyplan_id = :studyplanid";
|
||||
$lastaccess = $DB->get_field_sql($lasql,["userid" => $userid, "studyplanid" => $studyplanid]);
|
||||
debug::write("Got lastaccess '{$lastaccess}' for user {$userid} in plan {$studyplanid}");
|
||||
} else {
|
||||
$lasql = "SELECT MAX(a.timeaccess) FROM {user_lastaccess} a
|
||||
WHERE a.userid = :userid";
|
||||
$lastaccess = $DB->get_field_sql($lasql,["userid" => $userid]);
|
||||
debug::write("Got lastaccess '{$lastaccess}' for user {$userid} in any course");
|
||||
}
|
||||
|
||||
|
||||
|
@ -819,8 +817,7 @@ class associationservice extends \external_api {
|
|||
public static function find_coach_parameters() : \external_function_parameters {
|
||||
return new \external_function_parameters( [
|
||||
'like' => new \external_value(PARAM_TEXT, 'search text'),
|
||||
'exclude_id' => new \external_value(PARAM_INT, 'exclude members of this studyplan', VALUE_OPTIONAL),
|
||||
'context_id' => new \external_value(PARAM_INT, 'context for this request', VALUE_OPTIONAL),
|
||||
'studyplan_id' => new \external_value(PARAM_INT, 'studyplan id to associate for', VALUE_OPTIONAL),
|
||||
] );
|
||||
}
|
||||
|
||||
|
@ -838,12 +835,13 @@ class associationservice extends \external_api {
|
|||
* @param int $contextid Context to search (default system)
|
||||
* @return array
|
||||
*/
|
||||
public static function find_coach($like, $excludeid = null, $contextid = 1) {
|
||||
public static function find_coach($like, $studyplan_id) {
|
||||
global $CFG, $DB;
|
||||
|
||||
|
||||
// Only allow this if the user has the right to edit in this context.
|
||||
$context = webservicehelper::find_context($contextid);
|
||||
$studyplan = studyplan::find_by_id($studyplan_id);
|
||||
$context = $studyplan->context();
|
||||
webservicehelper::require_capabilities(self::CAP_EDIT, $context);
|
||||
|
||||
$pattern = "%{$like}%";
|
||||
|
@ -855,7 +853,7 @@ class associationservice extends \external_api {
|
|||
WHERE u.deleted != 1 AND (firstname LIKE :pattern_fn OR lastname LIKE :pattern_ln OR username LIKE :pattern_un)";
|
||||
if (isset($excludeid) && is_numeric($excludeid)) {
|
||||
$sql .= " AND (j.studyplan_id IS NULL OR j.studyplan_id != :exclude_id)";
|
||||
$params['exclude_id'] = $excludeid;
|
||||
$params['exclude_id'] = $studyplan;
|
||||
}
|
||||
|
||||
$users = [];
|
||||
|
|
|
@ -69,7 +69,7 @@ abstract class formbase extends \moodleform {
|
|||
if($data) {
|
||||
return $this->process_submitted_data($data);
|
||||
} else {
|
||||
throw new \moodle_exception('no_form_data','local_treestudyplan');
|
||||
throw new \moodle_exception('no_form_data','local_treestudyplan','',null,$data);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ require_once($CFG->dirroot.'/repository/lib.php');
|
|||
use local_treestudyplan\aggregator;
|
||||
use local_treestudyplan\studyplan;
|
||||
use local_treestudyplan\premium;
|
||||
use local_treestudyplan\contextinfo;
|
||||
use local_treestudyplan\studyplanservice;
|
||||
use local_treestudyplan\courseservice;
|
||||
use local_treestudyplan\form\text_integer;
|
||||
|
@ -206,9 +207,10 @@ class studyplan_editform extends formbase {
|
|||
|
||||
$field = 'enddate';
|
||||
$mform->addElement('date_selector',$field,
|
||||
get_string('studyplan_startdate','local_treestudyplan'),
|
||||
get_string('studyplan_enddate','local_treestudyplan'),
|
||||
[]);
|
||||
$mform->addRule($field, null, 'required', null, 'client');
|
||||
|
||||
}
|
||||
$field = 'periods';
|
||||
$mform->addElement('text_integer',$field,
|
||||
|
@ -225,6 +227,15 @@ class studyplan_editform extends formbase {
|
|||
get_string('studyplan_suspend_details','local_treestudyplan'),
|
||||
[],
|
||||
);
|
||||
|
||||
if (premium::enabled()) {
|
||||
$field = 'template';
|
||||
$mform->addElement('advcheckbox',$field,
|
||||
get_string('studyplan_template','local_treestudyplan'),
|
||||
get_string('studyplan_template_details','local_treestudyplan'),
|
||||
[],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$aggregators = [];
|
||||
|
@ -234,7 +245,8 @@ class studyplan_editform extends formbase {
|
|||
$aggregators[$a['id']] = $a['name'];
|
||||
}
|
||||
}
|
||||
$mform->addElement('select','aggregation',
|
||||
$field = 'aggregation';
|
||||
$mform->addElement('select',$field,
|
||||
get_string('choose_aggregation_style','local_treestudyplan'),
|
||||
$aggregators);
|
||||
|
||||
|
@ -275,7 +287,7 @@ class studyplan_editform extends formbase {
|
|||
get_string('setting_bistate_accept_pending_submitted','local_treestudyplan'),
|
||||
[],
|
||||
);
|
||||
$mform->hideIf($field, "aggregation", "neq", "bistate");
|
||||
$mform->hideIf($field, "aggregation", "neq", "bistate");
|
||||
|
||||
/* End Bistate aggregation specific items */
|
||||
|
||||
|
@ -303,9 +315,9 @@ class studyplan_editform extends formbase {
|
|||
}
|
||||
$aggregation_config = json_encode($ag_cfg);
|
||||
|
||||
if($customdata->create) {
|
||||
if ($customdata->create) {
|
||||
|
||||
// Use our own abstraction to update the record, so caches are maintained
|
||||
// Use our own abstraction to create the record, so caches are maintained
|
||||
$plan = studyplan::add(['name' => $entry->name,
|
||||
'shortname' => $entry->shortname,
|
||||
'idnumber' => $entry->idnumber,
|
||||
|
@ -351,6 +363,7 @@ class studyplan_editform extends formbase {
|
|||
'aggregation' => $entry->aggregation,
|
||||
'aggregation_config' => $aggregation_config,
|
||||
'suspended' => $entry->suspended,
|
||||
'template' => $entry->template,
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
172
classes/form/studyplan_fromtemplateform.php
Normal file
172
classes/form/studyplan_fromtemplateform.php
Normal file
|
@ -0,0 +1,172 @@
|
|||
<?php
|
||||
|
||||
namespace local_treestudyplan\form;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot.'/repository/lib.php');
|
||||
use local_treestudyplan\aggregator;
|
||||
use local_treestudyplan\studyplan;
|
||||
use local_treestudyplan\premium;
|
||||
use local_treestudyplan\contextinfo;
|
||||
use local_treestudyplan\studyplanservice;
|
||||
use local_treestudyplan\courseservice;
|
||||
use local_treestudyplan\form\text_integer;
|
||||
use moodle_exception;
|
||||
use stdClass;
|
||||
|
||||
|
||||
/**
|
||||
* Moodleform class for the studyplan editor. A Moodleform is used here to facilitate a rich editor
|
||||
* in the studyplan description
|
||||
*/
|
||||
class studyplan_fromtemplateform extends formbase {
|
||||
/**
|
||||
* Capability required to edit study plans
|
||||
* @var string
|
||||
*/
|
||||
const CAP_EDIT = "local/treestudyplan:editstudyplan";
|
||||
|
||||
/**
|
||||
* Translate parameters into customdata.
|
||||
*
|
||||
* @param object $params The parameters for form initialization
|
||||
* @return array Form data based on parameters
|
||||
*/
|
||||
public static function init_customdata(object $params) {
|
||||
$customdata = new stdClass;
|
||||
$customdata->context = \context::instance_by_id($params->contextid);
|
||||
|
||||
|
||||
return $customdata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate security access for this form based on the customdata generated by init_customdata
|
||||
* Return true if validation passes, false or throw an exception if it does not.
|
||||
*
|
||||
* @param object $customdata The customdata for this form
|
||||
* @return bool True if security validation passes.
|
||||
* @throws \moodle_exception if access denied for a specific reason.
|
||||
*/
|
||||
public static function check_security(object $customdata) {
|
||||
/*webservicehelper::require_capabilities(self::CAP_EDIT,$customdata->context); */
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate form data from parameters
|
||||
* Also validate parameters and access permissions here
|
||||
*
|
||||
* @param object $customdata The parameters for form initialization
|
||||
* @return array Form data based on parameters
|
||||
*/
|
||||
public function init_formdata(object $customdata) {
|
||||
global $DB;
|
||||
/* Use direct database retrieval to avoid our abstractions causing trouble
|
||||
with existing moodle code assumptions.
|
||||
The form API does seem needlessly convoluted in it's use, but we need the editor...
|
||||
*/
|
||||
$entry = new stdClass;
|
||||
$entry->context_id = $customdata->context->id;
|
||||
|
||||
// Determine the next august 1st for default value purposes.
|
||||
$august = strtotime("first day of august this year");
|
||||
if($august < time()) {
|
||||
$august = strtotime("first day of august next year");
|
||||
}
|
||||
$entry->startdate = $august;
|
||||
$entry->enddate = $august + (364*24*60*60); // Not bothering about leap years here.
|
||||
$entry->periods = 4;
|
||||
$entry->template_id = 0;
|
||||
|
||||
return $entry;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the form definition
|
||||
*/
|
||||
public function definition() {
|
||||
$mform = $this->_form;
|
||||
$customdata = (object)$this->_customdata;
|
||||
|
||||
// Register integer type
|
||||
text_integer::Register();
|
||||
|
||||
// Define the form
|
||||
|
||||
$templatelist = [];
|
||||
foreach(studyplan::find_template() as $s){
|
||||
$c = (new contextinfo($s->context()))->model();
|
||||
$templatelist[$s->id()] = implode(" / ",$c['path']) . " / " . $s->name();
|
||||
}
|
||||
|
||||
$field = 'template_id';
|
||||
$mform->addElement('autocomplete', $field,
|
||||
get_string('studyplan_fromtemplate','local_treestudyplan'),
|
||||
$templatelist);
|
||||
$mform->addRule($field, null, 'required', null, 'client');
|
||||
|
||||
$field = 'name';
|
||||
$mform->addElement('text',$field,
|
||||
get_string('studyplan_name','local_treestudyplan'),
|
||||
[]);
|
||||
$mform->addRule($field, null, 'required', null, 'client');
|
||||
|
||||
$field = 'shortname';
|
||||
$mform->addElement('text',$field,
|
||||
get_string('studyplan_shortname','local_treestudyplan'),
|
||||
[]);
|
||||
$mform->addRule($field, null, 'required', null, 'client');
|
||||
|
||||
$field = 'idnumber';
|
||||
$mform->addElement('text',$field,
|
||||
get_string('studyplan_idnumber','local_treestudyplan'),
|
||||
[]);
|
||||
|
||||
$contextlist = [];
|
||||
foreach(courseservice::list_available_categories('edit') as $c){
|
||||
$contextlist[$c['context_id']] = implode(" / ",$c['category']['path']);
|
||||
}
|
||||
|
||||
$mform->addElement('autocomplete', 'context_id',
|
||||
get_string('studyplan_context','local_treestudyplan'),
|
||||
$contextlist);
|
||||
|
||||
$mform->addRule('context_id', null, 'required', null, 'client');
|
||||
|
||||
$timeless = \get_config("local_treestudyplan","timelessperiods");
|
||||
if ( !$timeless) {
|
||||
// Only add these fields if the studyplans are timed
|
||||
$field = 'startdate';
|
||||
$mform->addElement('date_selector',$field,
|
||||
get_string('studyplan_startdate','local_treestudyplan'),
|
||||
[]);
|
||||
$mform->addRule($field, null, 'required', null, 'client');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the submitted data and perform necessary actions
|
||||
* @param object $entry The processed form data;
|
||||
* @return bool false if submission not successful
|
||||
* @throws \moodle_exception if an error must be given for a specific reason.
|
||||
*/
|
||||
protected function process_submitted_data($entry) {
|
||||
$customdata = (object)$this->_customdata;
|
||||
|
||||
// Find template study plan.
|
||||
$template = studyplan::find_by_id($entry->template_id);
|
||||
// Copy template plan.
|
||||
$plan = $template->duplicate($entry->name,$entry->shortname,$entry->context_id,$entry->idnumber,$entry->startdate);
|
||||
|
||||
/* Return the simple model of the plan to make sure we can update stuff.
|
||||
Parse it through the clean_returnvalue function of exernal api (of which studyplanservice is a subclass)
|
||||
so we return it in a consistent way
|
||||
*/
|
||||
return studyplanservice::clean_returnvalue(studyplan::simple_structure(),$plan->simple_model());
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -802,14 +802,14 @@ class studyline {
|
|||
* @param studyplan $newstudyplan Studyplan to copy the line into
|
||||
* @param array $translation Mapping array of old item ids to new item ids for connection matching
|
||||
*/
|
||||
public function duplicate($newstudyplan, &$translation) : self {
|
||||
public function duplicate($newpage, &$translation) : self {
|
||||
global $DB;
|
||||
|
||||
// Clone the database fields.
|
||||
$fields = clone $this->r;
|
||||
// Set new studyplan id.
|
||||
unset($fields->id);
|
||||
$fields->studyplan_id = $newstudyplan->id();
|
||||
$fields->page_id = $newpage->id();
|
||||
// Create new record with the new data.
|
||||
$id = $DB->insert_record(self::TABLE, (array)$fields);
|
||||
$new = self::find_by_id($id);
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
*/
|
||||
|
||||
namespace local_treestudyplan;
|
||||
|
||||
use DateInterval;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir.'/externallib.php');
|
||||
|
@ -130,6 +133,20 @@ class studyplan {
|
|||
return boolval($this->r->suspended);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine earliest start date of a page
|
||||
* @return \DateTime|null
|
||||
*/
|
||||
public function startdate() {
|
||||
$date = null;
|
||||
foreach($this->pages() as $p) {
|
||||
if (!isset($date) || $p->startdate() < $date) {
|
||||
$date = $p->startdate();
|
||||
}
|
||||
}
|
||||
return $date;
|
||||
}
|
||||
|
||||
|
||||
private function icon() {
|
||||
global $CFG;
|
||||
|
@ -419,7 +436,8 @@ class studyplan {
|
|||
'context_id',
|
||||
'aggregation',
|
||||
'aggregation_config',
|
||||
'suspended'
|
||||
'suspended',
|
||||
'template'
|
||||
];
|
||||
$info = ['id' => $this->id, ];
|
||||
foreach ($editable as $f) {
|
||||
|
@ -464,7 +482,7 @@ class studyplan {
|
|||
|
||||
/**
|
||||
* Find all studyplans in a given context or the system context
|
||||
* @param int $contextid Optional contextid to search in. System context used if left empty
|
||||
* @param int $contextid Optional contextid to search in. ANY context used if left empty
|
||||
* @return studyplan[]
|
||||
*/
|
||||
public static function find_all($contextid = -1) : array {
|
||||
|
@ -489,6 +507,57 @@ class studyplan {
|
|||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all template studyplans in a given context or the system context
|
||||
* @param int $contextid Optional contextid to search in. ANY context used if left empty
|
||||
* @return studyplan[]
|
||||
*/
|
||||
public static function find_template($contextid = -1) : array {
|
||||
global $DB, $USER;
|
||||
$list = [];
|
||||
|
||||
$templatewhere = "template = 1";
|
||||
if ($contextid <= 0) {
|
||||
$ids = $DB->get_fieldset_select(self::TABLE, "id", $templatewhere);
|
||||
} else {
|
||||
if ($contextid == 1) {
|
||||
$contextid = 1;
|
||||
$where = "context_id <= :contextid OR context_id IS NULL";
|
||||
} else {
|
||||
$where = "context_id = :contextid";
|
||||
}
|
||||
$ids = $DB->get_fieldset_select(self::TABLE, "id", "{$where} AND {$templatewhere}", ["contextid" => $contextid]);
|
||||
}
|
||||
|
||||
foreach ($ids as $id) {
|
||||
$list[] = self::find_by_id($id);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count all template studyplans in a given context or the system context
|
||||
* @param int $contextid Optional contextid to search in. ANY context used if left empty
|
||||
* @return int
|
||||
*/
|
||||
public static function count_template($contextid = -1) : int {
|
||||
global $DB, $USER;
|
||||
$list = [];
|
||||
|
||||
$templatewhere = "template = 1";
|
||||
if ($contextid <= 0) {
|
||||
return $DB->count_records_select(self::TABLE, $templatewhere);
|
||||
} else {
|
||||
if ($contextid == 1) {
|
||||
$contextid = 1;
|
||||
$where = "context_id <= :contextid OR context_id IS NULL";
|
||||
} else {
|
||||
$where = "context_id = :contextid";
|
||||
}
|
||||
return $DB->count_records_select(self::TABLE, "{$where} AND {$templatewhere}", ["contextid" => $contextid]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all studyplans in a given context or the system context with a specific short name
|
||||
* (Used in generating random grades for development)
|
||||
|
@ -740,7 +809,7 @@ class studyplan {
|
|||
*/
|
||||
public static function duplicate_plan($planid, $name, $shortname) : array {
|
||||
$ori = self::find_by_id($planid);
|
||||
$new = $ori->duplicate($name, $shortname);
|
||||
$new = $ori->duplicate($name, $shortname,$ori->context()->id);
|
||||
return $new->simple_model();
|
||||
}
|
||||
|
||||
|
@ -749,23 +818,61 @@ class studyplan {
|
|||
* @param string $name New fullname of studyplan
|
||||
* @param string $shortname New shortname of studyplan
|
||||
*/
|
||||
public function duplicate($name, $shortname) : self {
|
||||
public function duplicate($name, $shortname, $contextid, $idnumber=null, $newstartdate = null) : self {
|
||||
// First duplicate the studyplan structure.
|
||||
$newplan = self::add([
|
||||
'name' => $name,
|
||||
'shortname' => $shortname,
|
||||
'idnumber' => ($idnumber?$idnumber:$this->r->idnumber),
|
||||
'context_id' => $contextid,
|
||||
'description' => $this->r->description,
|
||||
'descriptionformat' => $this->r->descriptionformat,
|
||||
'aggregation' => $this->r->aggregation,
|
||||
'aggregation_config' => $this->r->aggregation_config
|
||||
]);
|
||||
],true);
|
||||
|
||||
//TODO: Copy any files related to this userid....
|
||||
// Copy any files related to this studyplan.
|
||||
$areas = ["icon","studyplan"];
|
||||
$fs = \get_file_storage();
|
||||
foreach ($areas as $area) {
|
||||
$files = $fs->get_area_files(
|
||||
\context_system::instance()->id,
|
||||
"local_treestudyplan",
|
||||
$area,
|
||||
$this->id()
|
||||
);
|
||||
foreach ($files as $file) {
|
||||
$path = $file->get_filepath();
|
||||
$filename = $file->get_filename();
|
||||
if ($filename != ".") {
|
||||
// Prepare new file info for the target file.
|
||||
$fileinfo = [
|
||||
'contextid' => \context_system::instance()->id, // System context.
|
||||
'component' => 'local_treestudyplan', // Your component name.
|
||||
'filearea' => $area, // Area name.
|
||||
'itemid' => $newplan->id(), // Study plan id.
|
||||
'filepath' => $path, // Original file path.
|
||||
'filename' => $filename, // Original file name.
|
||||
];
|
||||
// Copy existing file into new file.
|
||||
$fs->create_file_from_storedfile($fileinfo, $file);
|
||||
debug::write("Copied {$area}::{$path}{$filename} from {$this->id} to {$newplan->id()}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Next, copy the studylines.
|
||||
$timeless = \get_config("local_treestudyplan","timelessperiods");
|
||||
if (!$timeless && $newstartdate) {
|
||||
$newstart = new \DateTime(date("Y-m-d",$newstartdate));
|
||||
$oldstart = $this->startdate();
|
||||
$timeoffset = $oldstart->diff($newstart);
|
||||
} else {
|
||||
$timeoffset = new \DateInterval("P0D");
|
||||
}
|
||||
|
||||
foreach ($this->pages() as $p) {
|
||||
$newchild = $p->duplicate($newplan);
|
||||
foreach ($this->pages() as $page) {
|
||||
$newchild = $page->duplicate($newplan,$timeoffset);
|
||||
}
|
||||
|
||||
return $newplan;
|
||||
|
|
|
@ -450,7 +450,11 @@ class studyplanpage {
|
|||
* Duplicate this studyplan page
|
||||
* @param studyplan $newstudyplan Studyplan to copy the page into
|
||||
*/
|
||||
public function duplicate(studyplan $newstudyplan) : self {
|
||||
public function duplicate(studyplan $newstudyplan, $timeoffset = null) : self {
|
||||
if ($timeoffset == null) {
|
||||
$timeoffset = new \DateInterval("P0D");
|
||||
}
|
||||
|
||||
// First duplicate the studyplan structure.
|
||||
$new = self::add([
|
||||
'studyplan_id' => $newstudyplan->id(),
|
||||
|
@ -458,18 +462,56 @@ class studyplanpage {
|
|||
'shortname' => $this->r->shortname,
|
||||
'description' => $this->r->description,
|
||||
'pages' => $this->r->pages,
|
||||
'startdate' => $this->r->startdate,
|
||||
'enddate' => empty($this->r->enddate) ? null : $this->r->enddate,
|
||||
'startdate' => $this->startdate()->add($timeoffset)->format("Y-m-d"),
|
||||
'enddate' => empty($this->r->enddate) ? null : ($this->enddate()->add($timeoffset)->format("Y-m-d")),
|
||||
]);
|
||||
|
||||
// Next, copy the studylines.
|
||||
// Copy any files related to this page.
|
||||
$areas = ["studyplanpage"];
|
||||
$fs = \get_file_storage();
|
||||
foreach ($areas as $area) {
|
||||
$files = $fs->get_area_files(
|
||||
\context_system::instance()->id,
|
||||
"local_treestudyplan",
|
||||
$area,
|
||||
$this->id()
|
||||
);
|
||||
foreach ($files as $file) {
|
||||
$path = $file->get_filepath();
|
||||
$filename = $file->get_filename();
|
||||
if ($filename != ".") {
|
||||
// Prepare new file info for the target file.
|
||||
$fileinfo = [
|
||||
'contextid' => \context_system::instance()->id, // System context.
|
||||
'component' => 'local_treestudyplan', // Your component name.
|
||||
'filearea' => $area, // Area name.
|
||||
'itemid' => $new->id(), // Study plan id.
|
||||
'filepath' => $path, // Original file path.
|
||||
'filename' => $filename, // Original file name.
|
||||
];
|
||||
// Copy existing file into new file.
|
||||
$fs->create_file_from_storedfile($fileinfo, $file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust the time offsets of the periods.
|
||||
foreach ($this->periods() as $p) {
|
||||
$p->edit([
|
||||
'startdate' => $p->startdate()->add($timeoffset)->format("Y-m-d"),
|
||||
'enddate' => $p->enddate()->add($timeoffset)->format("Y-m-d"),
|
||||
]);
|
||||
}
|
||||
|
||||
// Now , copy the studylines.
|
||||
$children = studyline::find_page_children($this);
|
||||
$itemtranslation = [];
|
||||
$linetranslation = [];
|
||||
$itemtranslation = []; // Stores ids of original and copied items.
|
||||
$linetranslation = []; // Stores ids of original and copied lines.
|
||||
foreach ($children as $c) {
|
||||
$newchild = $c->duplicate($this, $itemtranslation);
|
||||
$linetranslation[$c->id()] = $newchild->id();
|
||||
$translation = [];
|
||||
$newchild = $c->duplicate($new, $translation);
|
||||
$itemtranslation += $translation; // Fixes behaviour where translation array is reset on each call.
|
||||
$linetranslation[$c->id()] = $newchild->id();
|
||||
}
|
||||
|
||||
// Now the itemtranslation array contains all of the old child id's as keys and all of the related new ids as values.
|
||||
|
@ -479,7 +521,7 @@ class studyplanpage {
|
|||
// Copy based on the outgoing connections of each item, to avoid duplicates.
|
||||
$connections = studyitemconnection::find_outgoing($itemid);
|
||||
foreach ($connections as $conn) {
|
||||
studyitemconnection::connect($itemtranslation[$conn->from_id], $itemtranslation[$conn->to_id]);
|
||||
studyitemconnection::connect($itemtranslation[$conn->from_id()], $itemtranslation[$conn->to_id()]);
|
||||
}
|
||||
}
|
||||
return $new;
|
||||
|
@ -788,13 +830,17 @@ class studyplanpage {
|
|||
|
||||
// Next, let each study line import the study items.
|
||||
$itemtranslation = [];
|
||||
$connections = [];
|
||||
$itemconnections = [];
|
||||
foreach ($model as $ix => $linemodel) {
|
||||
$linemap[$ix]->import_studyitems($linemodel["slots"], $itemtranslation, $connections);
|
||||
$translation = [];
|
||||
$connections = [];
|
||||
$linemap[$ix]->import_studyitems($linemodel["slots"], $translation, $connections);
|
||||
$itemtranslation += $translation; // Fixes behaviour where translation array is reset on each call.
|
||||
$itemconnections += $connections;
|
||||
}
|
||||
|
||||
// Finally, create the links between the study items.
|
||||
foreach ($connections as $from => $dests) {
|
||||
foreach ($itemconnections as $from => $dests) {
|
||||
foreach ($dests as $to) {
|
||||
studyitemconnection::connect($from, $itemtranslation[$to]);
|
||||
}
|
||||
|
|
|
@ -2192,5 +2192,36 @@ class studyplanservice extends \external_api {
|
|||
"can_unenrol" => \has_capability('local/treestudyplan:lineunenrol', $context),
|
||||
];
|
||||
}
|
||||
|
||||
/***************************
|
||||
* *
|
||||
* count_templates *
|
||||
* *
|
||||
***************************/
|
||||
|
||||
/**
|
||||
* Parameter description for webservice function get_teaching_page
|
||||
*/
|
||||
public static function count_templates_parameters() : \external_function_parameters {
|
||||
return new \external_function_parameters( [
|
||||
|
||||
] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return value description for webservice function get_teaching_page
|
||||
*/
|
||||
public static function count_templates_returns() : \external_description {
|
||||
return new \external_value(PARAM_INT,"True if the requesting user can unenrol students");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all or one studyplan the current user is teaching in
|
||||
* @param int $studyplanid ID of studyplan to retrieve
|
||||
* @return array
|
||||
*/
|
||||
public static function count_templates() {
|
||||
\external_api::validate_context(\context_system::instance());
|
||||
return studyplan::count_template();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ class utilityservice extends \external_api {
|
|||
*/
|
||||
$modmoodleform = "$CFG->dirroot/local/treestudyplan/classes/form/{$formname}.php";
|
||||
if (!file_exists($modmoodleform)) {
|
||||
throw new \moodle_exception('noformfile', 'local_treestudyplan');
|
||||
throw new \moodle_exception('noformfile', 'local_treestudyplan','',$formname);
|
||||
}
|
||||
|
||||
$mformclassname = "\\local_treestudyplan\\form\\{$formname}";
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<XMLDB PATH="local/treestudyplan/db" VERSION="20240309" COMMENT="XMLDB file for Moodle local/treestudyplan"
|
||||
<XMLDB PATH="local/treestudyplan/db" VERSION="20240415" COMMENT="XMLDB file for Moodle local/treestudyplan"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
|
||||
>
|
||||
|
@ -34,6 +34,7 @@
|
|||
<FIELD NAME="context_id" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false"/>
|
||||
<FIELD NAME="csync_flag" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="1" SEQUENCE="false" COMMENT="Flags the studyplan as needing a csync update"/>
|
||||
<FIELD NAME="suspended" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
<FIELD NAME="template" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
|
|
|
@ -814,4 +814,14 @@ $functions = [
|
|||
'capabilities' => '',
|
||||
'loginrequired' => true,
|
||||
],
|
||||
'local_treestudyplan_count_templates' => [ // Web service function name.
|
||||
'classname' => '\local_treestudyplan\studyplanservice', // Class containing the external function.
|
||||
'methodname' => 'count_templates', // External function name.
|
||||
'description' => 'Count number of templates',
|
||||
'type' => 'read', // Database rights of the web service function (read, write).
|
||||
'ajax' => true,
|
||||
'capabilities' => '',
|
||||
'loginrequired' => true,
|
||||
],
|
||||
|
||||
];
|
||||
|
|
|
@ -618,5 +618,21 @@ function xmldb_local_treestudyplan_upgrade($oldversion) {
|
|||
upgrade_plugin_savepoint(true, 2024031000, 'local', 'treestudyplan');
|
||||
}
|
||||
|
||||
if ($oldversion < 2024041501) {
|
||||
|
||||
// Define field template to be added to local_treestudyplan.
|
||||
$table = new xmldb_table('local_treestudyplan');
|
||||
$field = new xmldb_field('template', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'suspended');
|
||||
|
||||
// Conditionally launch add field template.
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
// Treestudyplan savepoint reached.
|
||||
upgrade_plugin_savepoint(true, 2024041501, 'local', 'treestudyplan');
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ require_once("../../config.php");
|
|||
require_once($CFG->libdir.'/weblib.php');
|
||||
|
||||
use \local_treestudyplan\contextinfo;
|
||||
use \local_treestudyplan\studyplan;
|
||||
use \local_treestudyplan\courseservice;
|
||||
use \local_treestudyplan\debug;
|
||||
|
||||
|
@ -146,19 +147,28 @@ print $OUTPUT->header();
|
|||
:key='studyplan.id'
|
||||
>{{ studyplan.name }}</b-form-select-option>
|
||||
</b-form-select>
|
||||
<t-studyplan-edit
|
||||
@created="onStudyPlanCreated"
|
||||
v-if='!activestudyplan && !loadingstudyplan'
|
||||
mode="create"
|
||||
v-model="create.studyplan"
|
||||
type="button"
|
||||
variant="primary"
|
||||
default-aggregation="<?php print(get_config("local_treestudyplan","aggregation_mode")); ?>"
|
||||
:contextid='contextid'
|
||||
><i class='fa fa-plus'></i> <?php t("studyplan_add");?></t-studyplan-edit>
|
||||
<b-button v-if='!activestudyplan && !loadingstudyplan'
|
||||
variant='danger' href='#' role='presentation' @click="import_studyplan "
|
||||
><i class='fa fa-upload'></i> <?php t("advanced_import_from_file");?></b-button>
|
||||
<template v-if='!activestudyplan && !loadingstudyplan'>
|
||||
<t-studyplan-edit
|
||||
@created="onStudyPlanCreated"
|
||||
mode="create"
|
||||
v-model="create.studyplan"
|
||||
type="button"
|
||||
variant="primary"
|
||||
default-aggregation="<?php print(get_config("local_treestudyplan","aggregation_mode")); ?>"
|
||||
:contextid='contextid'
|
||||
><i class='fa fa-plus'></i> {{ text.studyplan_add }}</t-studyplan-edit>
|
||||
<b-button
|
||||
variant='danger' href='#' role='presentation' @click="import_studyplan "
|
||||
><i class='fa fa-upload'></i> {{ text.advanced_import_from_file }}</b-button
|
||||
><mform v-if="premiumenabled && templatecount > 0"
|
||||
name="studyplan_fromtemplateform"
|
||||
:params="{contextid: contextid }"
|
||||
@saved="onStudyPlanCreated"
|
||||
variant="success"
|
||||
type="button"
|
||||
:title="text.advanced_import_from_file"
|
||||
><slot><i class='fa fa-clone'></i> {{ text.advanced_create_from_template }}</slot></mform>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div class='t-studyplan-container'>
|
||||
|
@ -183,7 +193,7 @@ print $OUTPUT->header();
|
|||
>
|
||||
<template #title>
|
||||
<span class='s-studyplan-card-title-buttons'>
|
||||
<t-studyplan-edit v-model="studyplans[planindex]" @moved="movedStudyplan"></t-studyplan-edit>
|
||||
<t-studyplan-edit v-model="studyplans[planindex]" @moved="movedStudyplan" @input="refreshTemplateCount"></t-studyplan-edit>
|
||||
<t-studyplan-associate v-model="studyplans[planindex]"></t-studyplan-associate>
|
||||
</span>
|
||||
</template>
|
||||
|
|
|
@ -175,8 +175,12 @@ $string["studyplan_enddate"] = 'End date of plan';
|
|||
$string["studyplan_noneselected"] = "Pick a study plan to start editing";
|
||||
$string["studyplan_select"] = "Study plan:";
|
||||
$string["studyplan_select_placeholder"] = "Select study plan";
|
||||
$string["studyplan_suspend"] = 'Suspend studyplan';
|
||||
$string["studyplan_suspend"] = 'Suspend study plan';
|
||||
$string["studyplan_suspend_details"] = 'Suspend studyplan for all except studyplan managers';
|
||||
$string["studyplan_fromtemplate"] = 'Based on template';
|
||||
$string["studyplan_template"] = 'Mark as template';
|
||||
$string["studyplan_template_details"] = 'Mark this studyplan as a possible template for new studyplans';
|
||||
$string["studyplan_emptytemplate"] = "Empty study plan";
|
||||
|
||||
$string["studyline_add"] = 'Add study line';
|
||||
$string["studyline_edit"] = 'Edit study line';
|
||||
|
@ -387,7 +391,8 @@ $string["advanced_backup_page"] = 'Backup active studyplan page ';
|
|||
$string["advanced_export"] = 'Export to file';
|
||||
$string["advanced_export_csv_page"] = 'Export current page as CSV';
|
||||
$string["advanced_export_csv_plan"] = 'Export studyplan CSV';
|
||||
$string["advanced_import_from_file"] = "Restore studyplan from file";
|
||||
$string["advanced_import_from_file"] = "Load from file";
|
||||
$string["advanced_create_from_template"] = "Create from template";
|
||||
|
||||
$string["advanced_purge"] = "Delete";
|
||||
$string["advanced_purge_plan"] = "Delete entire study plan";
|
||||
|
|
|
@ -86,7 +86,7 @@ $string["setting_navigation_heading"] = 'Navigatie';
|
|||
$string["settingdesc_navigation_heading"] = 'Instellingen voor navigatie';
|
||||
$string["setting_primary_nav_autofill"] = '<i>Aangepast menu items</i> automatisch aanvullen';
|
||||
$string["settingdesc_primary_nav_autofill"] = 'Om in het primaire navigatiemenu de studieplan links te tonen (vooral in Moodle 4.x), moeten regels worden toegevoegd in <b>Uiterlijk</b> - <b>Thema instellingen</b> <b>Aangepast menu items</b><br>Zet deze functie hier uit als dat niet gewenst is, b.v. als je Moodle (3.11 of lager) thema flat navigation gebruikt.';
|
||||
$string["setting_defaulticon"] = 'Standaard afbeelding foor studieplan';
|
||||
$string["setting_defaulticon"] = 'Standaard afbeelding voor studieplan';
|
||||
$string["settingdesc_defaulticon"] = 'Stel standaard afbeelding in om weer te geven als een studieplan geen eigen afbeelding heeft ingesteld';
|
||||
|
||||
$string["settingspage_csync"] = 'Site-groepen en gebruikerskoppelingen doorzetten naar cursussen';
|
||||
|
@ -177,7 +177,10 @@ $string["studyplan_select"] = "Studieplan";
|
|||
$string["studyplan_select_placeholder"] = "Selecteer studieplan";
|
||||
$string["studyplan_suspend"] = 'Studieplan tijdelijk uitschakelen';
|
||||
$string["studyplan_suspend_details"] = 'Inkijken van studieplan tijdelijk uitschakelen, behalve voor beheerders.';
|
||||
|
||||
$string["studyplan_fromtemplate"] = 'Baseer plan op template';
|
||||
$string["studyplan_template"] = 'Bruikbaar als template';
|
||||
$string["studyplan_template_details"] = 'Dit studieplan kan worden gebruikt als template voor nieuwe studieplannen';
|
||||
$string["studyplan_emptytemplate"] = "Leeg studieplan";
|
||||
|
||||
$string["studyline_add"] = 'Nieuwe leerlijn';
|
||||
$string["studyline_edit"] = 'Leerlijn bewerken';
|
||||
|
@ -321,7 +324,7 @@ $string["competency_aggregator_title"] = 'Curuscompetenties';
|
|||
$string["competency_aggregator_desc"] = 'Gebruik de bij de cursus ingestelde competenties';
|
||||
|
||||
|
||||
$string["setting_bistate_heading"] = 'Standaardwaarden voor Behaald + Vereidte leerdoelen ';
|
||||
$string["setting_bistate_heading"] = 'Standaardwaarden voor Behaald + Vereiste leerdoelen ';
|
||||
$string["settingdesc_bistate_heading"] = 'Stel de standaardwaarden in voor deze verzamelmethode';
|
||||
|
||||
$string["choose_aggregation_style"] = 'Kies berekening van eindresultaten';
|
||||
|
@ -331,7 +334,7 @@ $string["select_scaleitem"] = 'Kies...';
|
|||
$string["setting_bistate_thresh_excellent"] = 'Drempelwaarde voor uitstekend (%)';
|
||||
$string["settingdesc_bistate_thresh_excellent"] = 'Minimumpercentage behaalde doelen voor "Uitstekend"';
|
||||
$string["setting_bistate_thresh_good"] = 'Drempelwaarde voor goed (%)';
|
||||
$string["settingdesc_bistate_thresh_good"] = 'Minimum ercentage behaalde doelen voor "Goed"';
|
||||
$string["settingdesc_bistate_thresh_good"] = 'Minimumpercentage behaalde doelen voor "Goed"';
|
||||
$string["setting_bistate_thresh_completed"] = 'Drempelwaarde voor voltooid (%)';
|
||||
$string["settingdesc_bistate_thresh_completed"] = 'Minimumpercentage behaalde doelen voor "Voltooid"';
|
||||
$string["setting_bistate_support_failed"] = 'Onvoldoende ingeschakeld';
|
||||
|
@ -391,6 +394,7 @@ $string["advanced_export"] = 'Exporteer naar bestand';
|
|||
$string["advanced_export_csv_page"] = 'Exporteer actieve tabblad naar CSV';
|
||||
$string["advanced_export_csv_plan"] = 'Exporteer studeeplan naar CSV';
|
||||
$string["advanced_import_from_file"] = "Vanuit bestand";
|
||||
$string["advanced_create_from_template"] = "Nieuw van template";
|
||||
|
||||
$string["advanced_purge"] = "Verwijderen";
|
||||
$string["advanced_purge_plan"] = "Studieplan verwijderen";
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->component = 'local_treestudyplan'; // Recommended since 2.0.2 (MDL-26035). Required since 3.0 (MDL-48494).
|
||||
$plugin->version = 2024032503; // YYYYMMDDHH (year, month, day, iteration).
|
||||
$plugin->version = 2024041901; // YYYYMMDDHH (year, month, day, iteration).
|
||||
$plugin->requires = 2021051700; // YYYYMMDDHH (This is the release version for Moodle 3.11).
|
||||
|
||||
$plugin->release = "1.1.6";
|
||||
|
|
Loading…
Reference in New Issue
Block a user