Reworked html/vue code from php rendering to mustache template.

This commit is contained in:
PMKuipers 2024-12-30 23:29:28 +01:00
parent 697d67bab4
commit 5934bace66
10 changed files with 566 additions and 381 deletions

View file

@ -48,84 +48,5 @@ if ($CFG->debugdeveloper) {
$PAGE->requires->js_call_amd('local_treestudyplan/page-coach', 'init', []);
print $OUTPUT->header();
$text = (object)[
'studyplan_select' => get_string("studyplan_select", 'local_treestudyplan'),
'coacheditmode' => get_string("coacheditmode", 'local_treestudyplan'),
'showoverview' => get_string("showoverview", 'local_treestudyplan'),
'studyplan_noneselected' => get_string("studyplan_noneselected", 'local_treestudyplan'),
'selectstudent_btn' => get_string('selectstudent_btn', 'local_treestudyplan'),
'back' => get_string('back', 'local_treestudyplan'),
];
print <<<END
<div id='root' class="t-studyplan-limit-width">
<div class='vue-loader' v-show='false'>
<div class="spinner-border text-primary" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>
<div v-cloak>
<div class="m-buttonbar" style="margin-bottom: 1em;">
<template v-if="displayedstudyplan">
<a href='#' @click.prevent='closeStudyplan'
><i style='font-size: 150%;' class='fa fa-chevron-left'></i> {$text->back}</a>
<s-studyplan-details
v-model="displayedstudyplan"
v-if="displayedstudyplan.description"
></s-studyplan-details>
<div class="flex-grow-1"><!-- Spacer to align student selector right --></div>
<span>{$text->selectstudent_btn}</span>
<s-prevnext-selector
:options="associatedstudents"
title="firstname"
v-model="selectedstudent"
defaultselectable
grouped
optionsfield='users'
arrows
@change="showStudentView"
class="ml-2"
variant="primary"
>
<template v-slot="{value}">{{value.firstname}} {{value.lastname}}</template>
<template #defaultlabel><span class='text-primary'>{$text->coacheditmode}</span></template>
</s-prevnext-selector>
</template>
</div>
<div class='t-studyplan-container'>
<h2 v-if='displayedstudyplan&& selectedstudent'
><span v-if="studentcount > 1">{{selectedstudent.firstname}} {{selectedstudent.lastname}} - </span
>{{displayedstudyplan.name}}</h2>
<h2 v-else-if='displayedstudyplan'>{$text->showoverview} - {{displayedstudyplan.name}}</h2>
<template v-if="!loadingstudyplan && displayedstudyplan">
<r-studyplan v-if="selectedstudent"
v-model='displayedstudyplan'
coaching
></r-studyplan>
<t-studyplan
v-else
v-model='displayedstudyplan'
coaching
></t-studyplan>
</template>
<div v-else-if='loadingstudyplan' class="spinner-border text-primary" role="status">
<span class="sr-only">Loading...</span>
</div>
<div v-else class='t-studyplan-notselected'>
<p>{$text->studyplan_noneselected}</p>
<b-card-group deck>
<s-studyplan-card
v-for='(studyplan, planindex) in studyplans'
:key='studyplan.id'
v-model='studyplans[planindex]'
open
@open='selectStudyplan(studyplan)'
></s-studyplan-card>
</b-card-group>
</div>
</div>
</div>
</div>
END;
print $OUTPUT->render_from_template('local_treestudyplan/edit_plan', []);
print $OUTPUT->footer();

View file

@ -40,9 +40,14 @@ $categoryid = optional_param('categoryid', 0, PARAM_INT); // Category id.
$contextid = optional_param('contextid', 0, PARAM_INT); // Context id.
if ($categoryid > 0) {
$studyplancontext = context_coursecat::instance($categoryid);
if (!is_object($studyplancontext)) {
$studyplancontext = $systemcontext;
}
} else if ($contextid > 0) {
$studyplancontext = context::instance_by_id($contextid);
if (!is_object($studyplancontext)) {
$studyplancontext = $systemcontext;
}
if (in_array($studyplancontext->contextlevel, [CONTEXT_SYSTEM, CONTEXT_COURSECAT])) {
$categoryid = $studyplancontext->instanceid;
} else {
@ -79,7 +84,7 @@ if ($studyplancontext->id > 1) {
$cat = \core_course_category::top();
}
if (!$cat->is_uservisible()) {
if (!is_object($cat) || !$cat->is_uservisible()) {
throw new \moodle_exception(
"error:cannotviewcategory",
@ -108,110 +113,5 @@ $PAGE->requires->js_call_amd('local_treestudyplan/page-edit-plan', 'init', [$stu
]]);
print $OUTPUT->header();
$text = (object)[
'loading' => get_string("loading", "core"),
'studyplan_select' => get_string("studyplan_select", 'local_treestudyplan'),
'studyplan_noneselected' => get_string("studyplan_noneselected", 'local_treestudyplan'),
'defaultaggregation' => get_config("local_treestudyplan", "aggregation_mode"),
'back' => get_string('back', 'local_treestudyplan'),
];
print <<<END
<div id='root' class="t-studyplan-limit-width">
<div class='vue-loader' v-show='false'>
<div class="spinner-border text-primary" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>
<div v-cloak>
<div v-if='!activestudyplan && usedcontexts && !loadingstudyplan' class='ml-3 mb-3 s-context-selector'>
<b-form-select text='{$contextname}' :value="contextid" @change='switchContext'
:class="(!(usedcontexts.length)) ? 'text-primary' : ''">
<b-form-select-option v-if='!(usedcontexts.length)' :value="contextid"
:class="'text-primary'">
<span>{$text->loading}...</span></b-form-select-option>
<b-form-select-option v-for='ctx in usedcontexts' :key='ctx.id' :value="ctx.context_id"
:class="(ctx.studyplancount > 0) ? 'font-weight-bold' : ''"
><span v-for="(p, i) in ctx.category.path"
><span v-if="i>0"> / </span>{{ p }}</span> <span>({{ ctx.studyplancount }})</span>
</b-form-select-option>
</b-form-select>
<div v-if="!(usedcontexts.length)"
style="position: relative; top: 0.3rem; width: 1.2rem; height: 1.2rem; font-size: 0.7rem;"
class="spinner-border text-primary" role="status"></div>
</div>
<h3 v-else>{$contextname}</h3>
<div class="m-buttonbar" style="margin-bottom: 1em;">
<a href='#' v-if='activestudyplan' @click.prevent='closeStudyplan'
><i style='font-size: 150%;' class='fa fa-chevron-left'></i> {$text->back}</a>
<span v-if='activestudyplan'>{$text->studyplan_select}</span>&nbsp;
<b-form-select v-if='activestudyplan' lazy :text='dropdownTitle' :value='activestudyplan.id' @change="selectStudyplan">
<b-form-select-option
v-for='(studyplan, planindex) in studyplans'
:value="studyplan.id"
:key='studyplan.id'
>{{ studyplan.name }}</b-form-select-option>
</b-form-select>&nbsp;
<template v-if='!activestudyplan && !loadingstudyplan'>
<t-studyplan-edit
@created="onStudyPlanCreated"
mode="create"
v-model="create.studyplan"
type="button"
variant="primary"
default-aggregation="{$text->defaultaggregation}"
:contextid='contextid'
><i class='fa fa-plus'></i> {{ text.studyplan_add }}</t-studyplan-edit>
<b-button
variant='danger' href='#' role='presentation' @click="importStudyplan "
><i class='fa fa-upload'></i> {{ text.advanced_import_from_file }}</b-button
><mform v-if="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'>
<t-studyplan
v-if='activestudyplan'
v-model='activestudyplan'
@moved="movedStudyplan"
></t-studyplan>
<div v-else-if='loadingstudyplan' class="spinner-border text-primary" role="status">
<span class="sr-only">Loading...</span>
</div>
<div v-else class='t-studyplan-notselected'>
<p>{$text->studyplan_noneselected}</p>
<b-card-group deck>
<s-studyplan-card
v-for='(studyplan, planindex) in studyplans'
:key='studyplan.id'
v-model='studyplans[planindex]'
open
ignoresuspend
@open='selectStudyplan(studyplan.id)'
>
<template #title>
<span class='s-studyplan-card-title-buttons'>
<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>
</s-studyplan-card>
</b-card-group>
</div>
</div>
</div>
</div>
END;
print $OUTPUT->render_from_template('local_treestudyplan/edit_plan', ["contextname" => $contextname]);
print $OUTPUT->footer();

View file

@ -55,29 +55,9 @@ if ($CFG->debugdeveloper) {
$PAGE->requires->js_call_amd('local_treestudyplan/page-myreport', 'init', [$amteaching ? 'teaching' : 'own']);
print $OUTPUT->header();
print '<div class="m-buttonbar" style="margin-bottom: 1em; text-align: right;">';
if (get_config("local_treestudyplan", "enableplansharing") && !$amteaching) {
print '<a class="btn btn-primary" href="invitations.php" id="manage_invites">';
print '&nbsp;<i class="fa fa-share"></i>&nbsp;'.get_string('manage_invites', 'local_treestudyplan').'</a>';
}
print "</div>";
print "<div id='root'>";
print " <div class='vue-loader' v-show='false'>";
print " <div class='spinner-border text-primary' role='status'>";
print " <span class='sr-only'>Loading...</span>";
print " </div>";
print " </div>";
print " <div v-cloak>";
if ($amteaching) {
print " <r-report type='teaching' teachermode ></r-report>";
} else {
print " <r-report type='own' :userid='userid'></r-report>";
}
print " </div>";
print "</div>";
$data = new \stdClass;
$data->enableplansharing = get_config("local_treestudyplan", "enableplansharing") && !$amteaching;
$data->teachermode = $amteaching;
print $OUTPUT->render_from_template('local_treestudyplan/myreport', $data);
print $OUTPUT->footer();

View file

@ -63,74 +63,13 @@ $PAGE->requires->js_call_amd(
);
print $OUTPUT->header();
print "<h3><b>{$contextname}</b> / {$studyplan->name()}</h3>";
$data = new \stdClass; // Use an object instead of an array to make next lines easier to read.
$data->contextname = $contextname;
$data->studyplanname = $studyplan->name();
if ($studyplan->name() != $page->fullname()) {
print "<h4>{$page->fullname()}</h4>";
$data->pagename = $page->fullname();
}
print <<<END
<div id='root'>
<div class='vue-loader' v-show='false'>
<div class='spinner-border text-primary' role='status'>
<span class='sr-only'>Loading...</span>
</div>
</div>
<div v-cloak>
<div class='vue-loader' v-if='!structure'>
<div class='spinner-border text-primary' role='status'>
<span class='sr-only'>Loading...</span>
</div>
</div>
<template v-else>
<div class='container q-pageperiodselection'>
<div class='row'>
<div class='col-sm-2 q-label'>{{text.page}}</div>
<div class='col-sm-6'>
<select class='custom-select' :value='page.id' @change='selectedPage'>
<template v-if='studyplan'>
<option v-for='p in studyplan.pages'
:key='p.id'
:value='p.id'
:selected='(page.id == p.id) ? true : false'
>{{p.fullname}}</option>
</template>
<option v-else disabled>{{text.loading}}</option>
</select>
</div>
</div>
<div class='row'>
<div class='col-sm-2 q-label' >{{text.period}} ({{text.from}} / {{text.to}})</div>
<div class='col-sm-2'>
<select class='custom-select' @change='selectedFirstPeriod'>
<template v-if='page'>
<option v-for='p in page.perioddesc'
:key='p.id'
:value='p.period'
:selected='(structure.firstperiod == p.period) ? true : false'
>{{p.fullname}}</option>
</template>
<option v-else disabled>{{text.loading}}</option>
</select>
</div>
<div class='col-sm-2 '>
<select class='custom-select' @change='selectedLastPeriod'>
<template v-if='page'>
<template v-for='p in page.perioddesc'>
<option v-if='p.period >= structure.firstperiod'
:key='p.id'
:value='p.period'
:selected='(structure.lastperiod == p.period) ? true : false'
>{{p.fullname}}</option>
</template>
</template>
<option v-else disabled>{{text.loading}}</option>
</select>
</div>
</div>
</div>
<q-studyplanreport :structure='structure' ></s-studyplanreport>
</template>
</div>
</div>
END;
print $OUTPUT->render_from_template('local_treestudyplan/result_overview', $data);
print $OUTPUT->footer();

105
templates/coach.mustache Normal file
View file

@ -0,0 +1,105 @@
{{!
This file is part of Moodle - https://moodle.org/
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 <http://www.gnu.org/licenses/>.
}}
{{!
@template local_treestudyplan/coach
Template for rendering the coach page
Classes required for JS:
* vue-loader
Data attributes required for JS:
* none
Context variables required for this template:
* none
Example context (json):
{
"contextname": "System",
}
}}
{{! Next line replaces mustache double curly braces with << and >> for this template,
so it does not mess up vue double curly braces}}
{{= << >> =}}
<div class="local_treestudyplan_coach t-studyplan-limit-width" id='root'>
<div class='vue-loader' v-show='false'>
<div class="spinner-border text-primary" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>
<div v-cloak>
<div class="m-buttonbar" style="margin-bottom: 1em;">
<template v-if="displayedstudyplan">
<a href='#' @click.prevent='closeStudyplan'
><i style='font-size: 150%;' class='fa fa-chevron-left'></i> <<#str>> back, local_treestudyplan <</str>></a>
<s-studyplan-details
v-model="displayedstudyplan"
v-if="displayedstudyplan.description"
></s-studyplan-details>
<div class="flex-grow-1"><!-- Spacer to align student selector right --></div>
<span><<#str>> selectstudent_btn, local_treestudyplan <</str>></span>
<s-prevnext-selector
:options="associatedstudents"
title="firstname"
v-model="selectedstudent"
defaultselectable
grouped
optionsfield='users'
arrows
@change="showStudentView"
class="ml-2"
variant="primary"
>
<template v-slot="{value}">{{value.firstname}} {{value.lastname}}</template>
<template #defaultlabel><span class='text-primary'><<#str>> coacheditmode, local_treestudyplan <</str>></span></template>
</s-prevnext-selector>
</template>
</div>
<div class='t-studyplan-container'>
<h2 v-if='displayedstudyplan&& selectedstudent'
><span v-if="studentcount > 1">{{selectedstudent.firstname}} {{selectedstudent.lastname}} - </span
>{{displayedstudyplan.name}}</h2>
<h2 v-else-if='displayedstudyplan'><<#str>> showoverview, local_treestudyplan <</str>> - {{displayedstudyplan.name}}</h2>
<template v-if="!loadingstudyplan && displayedstudyplan">
<r-studyplan v-if="selectedstudent"
v-model='displayedstudyplan'
coaching
></r-studyplan>
<t-studyplan
v-else
v-model='displayedstudyplan'
coaching
></t-studyplan>
</template>
<div v-else-if='loadingstudyplan' class="spinner-border text-primary" role="status">
<span class="sr-only">Loading...</span>
</div>
<div v-else class='t-studyplan-notselected'>
<b-card-group deck>
<s-studyplan-card
v-for='(studyplan, planindex) in studyplans'
:key='studyplan.id'
v-model='studyplans[planindex]'
open
@open='selectStudyplan(studyplan)'
></s-studyplan-card>
</b-card-group>
</div>
</div>
</div>
</div>

View file

@ -0,0 +1,134 @@
{{!
This file is part of Moodle - https://moodle.org/
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 <http://www.gnu.org/licenses/>.
}}
{{!
@template local_treestudyplan/edit_plan
Template for rendering the manage studyplans page
Classes required for JS:
* vue-loader
Data attributes required for JS:
* none
Context variables required for this template:
* none
Example context (json):
{
"contextname": "System",
}
}}
{{! Next line replaces mustache double curly braces with << and >> for this template,
so it does not mess up vue double curly braces}}
{{= << >> =}}
<div class="local_treestudyplan_edit_plan t-studyplan-limit-width" id='root'>
<div class='vue-loader' v-show='false'>
<div class="spinner-border text-primary" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>
<div v-cloak>
<div v-if='!activestudyplan && usedcontexts && !loadingstudyplan' class='ml-3 mb-3 s-context-selector'>
<b-form-select text='<< contextname >>' :value="contextid" @change='switchContext'
:class="(!(usedcontexts.length)) ? 'text-primary' : ''">
<b-form-select-option v-if='!(usedcontexts.length)' :value="contextid"
:class="'text-primary'">
<span><<#str>> loading, core<</str>>...</span></b-form-select-option>
<b-form-select-option v-for='ctx in usedcontexts' :key='ctx.id' :value="ctx.context_id"
:class="(ctx.studyplancount > 0) ? 'font-weight-bold' : ''"
><span v-for="(p, i) in ctx.category.path"
><span v-if="i>0"> / </span>{{ p }}</span> <span>({{ ctx.studyplancount }})</span>
</b-form-select-option>
</b-form-select>
<div v-if="!(usedcontexts.length)"
style="position: relative; top: 0.3rem; width: 1.2rem; height: 1.2rem; font-size: 0.7rem;"
class="spinner-border text-primary" role="status"></div>
</div>
<h3 v-else><< contextname >></h3>
<div class="m-buttonbar" style="margin-bottom: 1em;">
<a href='#' v-if='activestudyplan' @click.prevent='closeStudyplan'
><i style='font-size: 150%;' class='fa fa-chevron-left'></i> <<#str>> back, local_treestudyplan <</str>></a>
<span v-if='activestudyplan'><<#str>> studyplan_select, local_treestudyplan <</str>></span>&nbsp;
<b-form-select v-if='activestudyplan' lazy :text='dropdownTitle' :value='activestudyplan.id' @change="selectStudyplan">
<b-form-select-option
v-for='(studyplan, planindex) in studyplans'
:value="studyplan.id"
:key='studyplan.id'
>{{ studyplan.name }}</b-form-select-option>
</b-form-select>&nbsp;
<template v-if='!activestudyplan && !loadingstudyplan'>
<t-studyplan-edit
@created="onStudyPlanCreated"
mode="create"
v-model="create.studyplan"
type="button"
variant="primary"
default-aggregation="<<#str>> defaultaggregation, local_treestudyplan <</str>>"
:contextid='contextid'
><i class='fa fa-plus'></i> {{ text.studyplan_add }}</t-studyplan-edit>
<b-button
variant='danger' href='#' role='presentation' @click="importStudyplan "
><i class='fa fa-upload'></i> {{ text.advanced_import_from_file }}</b-button
><mform v-if="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'>
<t-studyplan
v-if='activestudyplan'
v-model='activestudyplan'
@moved="movedStudyplan"
></t-studyplan>
<div v-else-if='loadingstudyplan' class="spinner-border text-primary" role="status">
<span class="sr-only">Loading...</span>
</div>
<div v-else class='t-studyplan-notselected'>
<p><<#str>> studyplan_noneselected, local_treestudyplan <</str>></p>
<b-card-group deck>
<s-studyplan-card
v-for='(studyplan, planindex) in studyplans'
:key='studyplan.id'
v-model='studyplans[planindex]'
open
ignoresuspend
@open='selectStudyplan(studyplan.id)'
>
<template #title>
<span class='s-studyplan-card-title-buttons'>
<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>
</s-studyplan-card>
</b-card-group>
</div>
</div>
</div>
</div>

View file

@ -0,0 +1,62 @@
{{!
This file is part of Moodle - https://moodle.org/
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 <http://www.gnu.org/licenses/>.
}}
{{!
@template local_treestudyplan/myreport
Template for rendering the student's "My studyplan" page
Classes required for JS:
* vue-loader
Data attributes required for JS:
* none
Context variables required for this template:
* none
Example context (json):
{
"enableplansharing": true,
"teachermode": false
}
}}
{{! Next line replaces mustache double curly braces with << and >> for this template,
so it does not mess up vue double curly braces}}
{{= << >> =}}
<div class="local_treestudyplan_myreport">
<div class="m-buttonbar" style="margin-bottom: 1em; text-align: right;">
<<#enableplansharing>>
<a class="btn btn-primary" href="invitations.php" id="manage_invites">
&nbsp;<i class="fa fa-share"></i>&nbsp;<<#str>> manage_invites, local_treestudyplan <</str>></a>
<</enableplansharing>>
</div>
<div id='root'>
<div class='vue-loader' v-show='false'>
<div class='spinner-border text-primary' role='status'>
<span class='sr-only'>Loading...</span>
</div>
</div>
<div v-cloak>
<<#teachermode>>
<r-report type='teaching' teachermode ></r-report>
<</teachermode>>
<<^teachermode>>
<r-report type='own' :userid='userid'></r-report>
<</teachermode>>
</div>
</div>
</div>

View file

@ -0,0 +1,109 @@
{{!
This file is part of Moodle - https://moodle.org/
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 <http://www.gnu.org/licenses/>.
}}
{{!
@template local_treestudyplan/result_overview
Template for rendering the invitations page
Classes required for JS:
* vue-loader
Data attributes required for JS:
* none
Context variables required for this template:
* none
Example context (json):
{
"contextname": "System",
"studyplanname": "Name of studyplan",
"pagename": "Name of studyplan page"
}
}}
{{! Next line replaces mustache double curly braces with << and >> for this template,
so it does not mess up vue double curly braces in the rest of the code.}}
{{= << >> =}}
<div class="local_treestudyplan_result_overview">
<h3><b><<contextname>></b> / <<studyplanname>></h3>
<<#pagename>>
<h4><<pagename>></h4>
<</pagename>>
<div id='root'>
<div class='vue-loader' v-show='false'>
<div class='spinner-border text-primary' role='status'>
<span class='sr-only'>Loading...</span>
</div>
</div>
<div v-cloak>
<div class='vue-loader' v-if='!structure'>
<div class='spinner-border text-primary' role='status'>
<span class='sr-only'>Loading...</span>
</div>
</div>
<template v-else>
<div class='container q-pageperiodselection'>
<div class='row'>
<div class='col-sm-2 q-label'>{{text.page}}</div>
<div class='col-sm-6'>
<select class='custom-select' :value='page.id' @change='selectedPage'>
<template v-if='studyplan'>
<option v-for='p in studyplan.pages'
:key='p.id'
:value='p.id'
:selected='(page.id == p.id) ? true : false'
>{{p.fullname}}</option>
</template>
<option v-else disabled>{{text.loading}}</option>
</select>
</div>
</div>
<div class='row'>
<div class='col-sm-2 q-label' >{{text.period}} ({{text.from}} / {{text.to}})</div>
<div class='col-sm-2'>
<select class='custom-select' @change='selectedFirstPeriod'>
<template v-if='page'>
<option v-for='p in page.perioddesc'
:key='p.id'
:value='p.period'
:selected='(structure.firstperiod == p.period) ? true : false'
>{{p.fullname}}</option>
</template>
<option v-else disabled>{{text.loading}}</option>
</select>
</div>
<div class='col-sm-2 '>
<select class='custom-select' @change='selectedLastPeriod'>
<template v-if='page'>
<template v-for='p in page.perioddesc'>
<option v-if='p.period >= structure.firstperiod'
:key='p.id'
:value='p.period'
:selected='(structure.lastperiod == p.period) ? true : false'
>{{p.fullname}}</option>
</template>
</template>
<option v-else disabled>{{text.loading}}</option>
</select>
</div>
</div>
</div>
<q-studyplanreport :structure='structure' ></s-studyplanreport>
</template>
</div>
</div>
</div>

View file

@ -0,0 +1,124 @@
{{!
This file is part of Moodle - https://moodle.org/
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 <http://www.gnu.org/licenses/>.
}}
{{!
@template local_treestudyplan/view_plan
Template for rendering the studyplan view page
Classes required for JS:
* vue-loader
Data attributes required for JS:
* none
Context variables required for this template:
* none
Example context (json):
{
"contextname": "System",
}
}}
{{! Next line replaces mustache double curly braces with << and >> for this template,
so it does not mess up vue double curly braces}}
{{= << >> =}}
<div class="local_treestudyplan_view_plan" id='root'>
<div class='vue-loader' v-show='false'>
<div class="spinner-border text-primary" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>
<div v-cloak>
<div v-if='!activestudyplan && usedcontexts' class='ml-3 mb-3 s-context-selector'>
<b-form-select text='<< contextname >>' :value="contextid" @change='switchContext'
:class="(!(usedcontexts.length)) ? 'text-primary' : ''">
<b-form-select-option v-if='!(usedcontexts.length)' :value="contextid"
:class="'text-primary'">
<span><<#str>> loading, core <</str>>...</span></b-form-select-option>
<b-form-select-option v-for='ctx in usedcontexts' :key='ctx.id' :value="ctx.context_id"
:class="(ctx.studyplancount > 0) ? 'font-weight-bold' : ''"
><span v-for="(p, i) in ctx.category.path"><span v-if="i>0"> / </span>{{ p }}</span>
<span>({{ ctx.studyplancount }})</span></b-form-select-option>
</b-form-select>
<div v-if="!(usedcontexts.length)"
style="position: relative; top: 0.3rem; width: 1.2rem; height: 1.2rem; font-size: 0.7rem;"
class="spinner-border text-primary" role="status"></div>
</div>
<h3 v-else><<contextname>></h3>
<div class="m-buttonbar" style="margin-bottom: 1em;">
<template v-if="displayedstudyplan">
<a href='#' @click.prevent='closeStudyplan'
><i style='font-size: 150%;' class='fa fa-chevron-left'></i> <<#str>> back, local_treestudyplan <</str>></a>
<span><<#str>> studyplan_select, local_treestudyplan <</str>></span>&nbsp;
<b-form-select lazy :text='dropdownTitle' :value='displayedstudyplan.id'>
<b-form-select-option
v-for='(studyplan, planindex) in studyplans'
:key='studyplan.id'
@click='selectStudyplan(studyplan)'
:value='studyplan.id'
>{{ studyplan.name }}</b-form-select-option>
</b-form-select>&nbsp;
<s-studyplan-details
v-model="displayedstudyplan"
v-if="displayedstudyplan.description"
></s-studyplan-details>
<div class="flex-grow-1"><!-- Spacer to align student selector right --></div>
<div>
<span><<#str>> selectstudent_btn, local_treestudyplan <</str>></span>
<s-prevnext-selector
:options="associatedstudents"
title="firstname"
v-model="selectedstudent"
defaultselectable
grouped
optionsfield='users'
arrows
@change="showStudentView"
class="ml-2"
variant="primary"
>
<template v-slot="{value}">{{value.firstname}} {{value.lastname}}</template>
<template #defaultlabel><span class='text-primary'><<#str>> showoverview, local_treestudyplan <</str>></span></template>
</s-prevnext-selector>
</div>
</template>
</div>
<div class='t-studyplan-container'>
<h2 v-if='displayedstudyplan&& selectedstudent'
>{{selectedstudent.firstname}} {{selectedstudent.lastname}} - {{displayedstudyplan.name}}</h2>
<h2 v-else-if='displayedstudyplan'><<#str>> showoverview, local_treestudyplan <</str>> - {{displayedstudyplan.name}}</h2>
<r-studyplan v-if='!loadingstudyplan && displayedstudyplan'
v-model='displayedstudyplan' :teachermode='!selectedstudent'
></r-studyplan>
<div v-else-if='loadingstudyplan' class="spinner-border text-primary" role="status">
<span class="sr-only">Loading...</span>
</div>
<div v-else class='t-studyplan-notselected'>
<p><<#str>> studyplan_noneselected, local_treestudyplan <</str>></p>
<b-card-group deck>
<s-studyplan-card
v-for='(studyplan, planindex) in studyplans'
:key='studyplan.id'
v-model='studyplans[planindex]'
open
@open='selectStudyplan(studyplan)'
></s-studyplan-card>
</b-card-group>
</div>
</div>
</div>
</div>

View file

@ -29,6 +29,7 @@ use local_treestudyplan\courseservice;
require_once($CFG->libdir.'/weblib.php');
$systemcontext = context_system::instance();
$PAGE->set_context($systemcontext);
$PAGE->set_url("/local/treestudyplan/view-plan.php", []);
require_login();
@ -38,13 +39,19 @@ $categoryid = optional_param('categoryid', 0, PARAM_INT); // Category id.
$contextid = optional_param('contextid', 0, PARAM_INT); // Context id.
if ($categoryid > 0) {
$studyplancontext = context_coursecat::instance($categoryid);
if (!is_object($studyplancontext)) {
$studyplancontext = $systemcontext;
}
} else if ($contextid > 0) {
$studyplancontext = context::instance_by_id($contextid);
if (in_array($studyplancontext->contextlevel, [CONTEXT_SYSTEM, CONTEXT_COURSECAT])) {
$categoryid = $studyplancontext->instanceid;
} else {
if (!is_object($studyplancontext)) {
$studyplancontext = $systemcontext;
} else {
if (in_array($studyplancontext->contextlevel, [CONTEXT_SYSTEM, CONTEXT_COURSECAT])) {
$categoryid = $studyplancontext->instanceid;
} else {
$studyplancontext = $systemcontext;
}
}
} else {
// If no context is selected, find the first available one.
@ -80,7 +87,7 @@ if ($studyplancontext->id > 1) {
$cat = \core_course_category::top();
}
if (!$cat->is_uservisible()) {
if (!is_object($cat) || !$cat->is_uservisible()) {
throw new \moodle_exception(
"error:cannotviewcategory",
"local_treestudyplan",
@ -106,101 +113,5 @@ if ($CFG->debugdeveloper) {
$PAGE->requires->js_call_amd('local_treestudyplan/page-view-plan', 'init', [$studyplancontext->id, $categoryid]);
print $OUTPUT->header();
$text = (object)[
'loading' => get_string("loading", "core"),
'back' => get_string('back', 'local_treestudyplan'),
'studyplan_select' => get_string("studyplan_select", 'local_treestudyplan'),
'selectstudent_btn' => get_string('selectstudent_btn', 'local_treestudyplan'),
'showoverview' => get_string("showoverview", 'local_treestudyplan'),
'studyplan_noneselected' => get_string("studyplan_noneselected", 'local_treestudyplan'),
];
print <<<END
<div id='root'>
<div class='vue-loader' v-show='false'>
<div class="spinner-border text-primary" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>
<div v-cloak>
<div v-if='!activestudyplan && usedcontexts' class='ml-3 mb-3 s-context-selector'>
<b-form-select text='{$contextname}' :value="contextid" @change='switchContext'
:class="(!(usedcontexts.length)) ? 'text-primary' : ''">
<b-form-select-option v-if='!(usedcontexts.length)' :value="contextid"
:class="'text-primary'">
<span>{$text->loading}...</span></b-form-select-option>
<b-form-select-option v-for='ctx in usedcontexts' :key='ctx.id' :value="ctx.context_id"
:class="(ctx.studyplancount > 0) ? 'font-weight-bold' : ''"
><span v-for="(p, i) in ctx.category.path"><span v-if="i>0"> / </span>{{ p }}</span>
<span>({{ ctx.studyplancount }})</span></b-form-select-option>
</b-form-select>
<div v-if="!(usedcontexts.length)"
style="position: relative; top: 0.3rem; width: 1.2rem; height: 1.2rem; font-size: 0.7rem;"
class="spinner-border text-primary" role="status"></div>
</div>
<h3 v-else>{$contextname}</h3>
<div class="m-buttonbar" style="margin-bottom: 1em;">
<template v-if="displayedstudyplan">
<a href='#' @click.prevent='closeStudyplan'
><i style='font-size: 150%;' class='fa fa-chevron-left'></i> {$text->back}</a>
<span>{$text->studyplan_select}</span>&nbsp;
<b-form-select lazy :text='dropdownTitle' :value='displayedstudyplan.id'>
<b-form-select-option
v-for='(studyplan, planindex) in studyplans'
:key='studyplan.id'
@click='selectStudyplan(studyplan)'
:value='studyplan.id'
>{{ studyplan.name }}</b-form-select-option>
</b-form-select>&nbsp;
<s-studyplan-details
v-model="displayedstudyplan"
v-if="displayedstudyplan.description"
></s-studyplan-details>
<div class="flex-grow-1"><!-- Spacer to align student selector right --></div>
<div>
<span>{$text->selectstudent_btn}</span>
<s-prevnext-selector
:options="associatedstudents"
title="firstname"
v-model="selectedstudent"
defaultselectable
grouped
optionsfield='users'
arrows
@change="showStudentView"
class="ml-2"
variant="primary"
>
<template v-slot="{value}">{{value.firstname}} {{value.lastname}}</template>
<template #defaultlabel><span class='text-primary'>{$text->showoverview}</span></template>
</s-prevnext-selector>
</div>
</template>
</div>
<div class='t-studyplan-container'>
<h2 v-if='displayedstudyplan&& selectedstudent'
>{{selectedstudent.firstname}} {{selectedstudent.lastname}} - {{displayedstudyplan.name}}</h2>
<h2 v-else-if='displayedstudyplan'>{$text->showoverview} - {{displayedstudyplan.name}}</h2>
<r-studyplan v-if='!loadingstudyplan && displayedstudyplan'
v-model='displayedstudyplan' :teachermode='!selectedstudent'
></r-studyplan>
<div v-else-if='loadingstudyplan' class="spinner-border text-primary" role="status">
<span class="sr-only">Loading...</span>
</div>
<div v-else class='t-studyplan-notselected'>
<p>{$text->studyplan_noneselected}</p>
<b-card-group deck>
<s-studyplan-card
v-for='(studyplan, planindex) in studyplans'
:key='studyplan.id'
v-model='studyplans[planindex]'
open
@open='selectStudyplan(studyplan)'
></s-studyplan-card>
</b-card-group>
</div>
</div>
</div>
</div>
END;
print $OUTPUT->render_from_template('local_treestudyplan/view_plan', ["contextname" => $contextname]);
print $OUTPUT->footer();