Continuation of rudimentary page implementation

This commit is contained in:
PMKuipers 2023-07-26 16:42:34 +02:00
parent f1479c8afa
commit 6b43b2eb73
4 changed files with 57 additions and 139 deletions

View file

@ -288,7 +288,6 @@ export default {
</template>
</r-studyline>
</template>
<div :id="'studyplan-linewrapper-'+(value?value.id:'null')" class='l-leaderline-linewrapper'></div>
</div>
`,
});

View file

@ -9,7 +9,6 @@
import {SimpleLine} from "./simpleline";
import {call} from 'core/ajax';
import notification from 'core/notification';
import {debounce} from './debounce';
import {get_strings} from 'core/str';
import {load_stringkeys, load_strings} from './string-helper';
import {objCopy,transportItem} from './studyplan-processor';
@ -1107,7 +1106,7 @@ export default {
},
mounted() {
if(this.value.studylines.length == 0){
if(this.page.studylines.length == 0){
// start in editmode if studylines are empty
this.edit.studyline.editmode = true;
}
@ -1120,15 +1119,19 @@ export default {
},
computed: {
columns() {
return 1+ (this.value.slots * 2);
return 1+ (this.page.periods * 2);
},
columns_stylerule() {
// Uses css variables, so width for slots and filters can be configured in css
let s = "grid-template-columns: var(--studyplan-filter-width)"; // use css variable here
for(let i=0; i<this.value.slots;i++){
for(let i=0; i<this.page.periods;i++){
s+= " var(--studyplan-course-width) var(--studyplan-filter-width)";
}
return s+";";
},
page(){
// FIXME: Temporary hack until real page management is implemented
return this.value.pages[0];
}
},
methods: {
@ -1171,19 +1174,19 @@ export default {
movedStudyplan(plan,from,to) {
this.$emit('moved',plan,from,to); // Throw the event up....
},
addStudyLine(studyplan,newlineinfo) {
addStudyLine(page,newlineinfo) {
call([{
methodname: 'local_treestudyplan_add_studyline',
args: {
'studyplan_id': studyplan.id,
'page_id': page.id,
'name': newlineinfo.name,
'shortname': newlineinfo.shortname,
'color': newlineinfo.color,
'sequence': studyplan.studylines.length,
'sequence': page.studylines.length,
}
}])[0].done(function(response){
debug.info("New studyline:",response);
studyplan.studylines.push(response);
page.studylines.push(response);
newlineinfo.name = '';
newlineinfo.shortname = '';
newlineinfo.color = "#dddddd";
@ -1211,7 +1214,7 @@ export default {
originalline['color'] = response['color'];
}).fail(notification.exception);
},
deleteLine(studyplan,line) {
deleteLine(page,line) {
debug.info('Delete Line',line);
const self=this;
get_strings([
@ -1229,8 +1232,8 @@ export default {
}])[0].done(function(response){
debug.info('Delete response:', response);
if(response.success == true){
let index = studyplan.studylines.indexOf(line);
studyplan.studylines.splice(index, 1);
let index = page.studylines.indexOf(line);
page.studylines.splice(index, 1);
}
}).fail(notification.exception);
}
@ -1312,7 +1315,7 @@ export default {
><i class='fa fa-trash'></i>
</drop>
<span class='control deletable'>
<a v-if='value.studylines.length == 0' href='#' @click='deletePlan(value)'
<a v-if='page.studylines.length == 0' href='#' @click='deletePlan(value)'
><i class='text-danger fa fa-trash'></i></a>
</span>
<span class='control editable'>
@ -1329,11 +1332,11 @@ export default {
</div>
<div class='t-studyplan-content-edit' v-if="edit.studyline.editmode">
<drop-list
:items="value.studylines"
:items="page.studylines"
class="t-slot-droplist"
:accepts-type="'studyline-'+value.id"
xreorder="$event.apply(value.studylines)"
@reorder="reorderLines($event,value.studylines)"
:accepts-type="'studyline-'+page.id"
xreorder="$event.apply(page.studylines)"
@reorder="reorderLines($event,page.studylines)"
mode="copy"
row
>
@ -1342,16 +1345,16 @@ export default {
:key="item.id"
class='t-studyplan-drag'
:data="item"
:type="'studyline-'+value.id"
:type="'studyline-'+page.id"
>
<template v-slot:drag-image>
<i class="fa fa-arrows text-primary"></i>
</template>
<t-studyline-edit
v-model="item"
:numlines='value.studylines.length'
:numlines='page.studylines.length'
@edit='editLineStart(item)'
@delete='deleteLine(value,item)'
@delete='deleteLine(page,item)'
>
<div v-if="!slotsempty(item.slots)"> {{ text.editmode_modules_hidden}} </div>
</t-studyline-edit>
@ -1362,10 +1365,10 @@ export default {
<div class='t-studyplan-content' v-else>
<!-- First paint the headings-->
<div class='t-studyplan-headings'>
<t-studyline-heading v-for="(line,lineindex) in value.studylines"
<t-studyline-heading v-for="(line,lineindex) in page.studylines"
:key="line.id"
v-model="value.studylines[lineindex]"
:numlines='value.studylines.length'
v-model="page.studylines[lineindex]"
:numlines='page.studylines.length'
:layers='countLineLayers(line)+1'
></t-studyline-heading>
</div>
@ -1374,9 +1377,9 @@ export default {
<div class="t-studyplan-timeline" :style="columns_stylerule">
<!-- Line by line add the items -->
<!-- The grid layout handles putting it in rows and columns -->
<template v-for="(line,lineindex) in value.studylines"
<template v-for="(line,lineindex) in page.studylines"
><template v-for="layeridx in countLineLayers(line)+1"
><template v-for="(n,index) in (value.slots+1)"
><template v-for="(n,index) in (page.periods+1)"
>
<t-studyline-slot
v-if="index > 0"
@ -1386,9 +1389,10 @@ export default {
:slotindex="index"
:line="line"
:plan="value"
:page="page"
:layer="layeridx-1"
:class= "'t-studyline ' + ((line.sequence==1 && layeridx==1)?' first':'') +
(line.sequence==value.studylines.length?' last':'')"
(line.sequence==page.studylines.length?' last':'')"
></t-studyline-slot
><t-studyline-slot
type='filter'
@ -1397,30 +1401,31 @@ export default {
:slotindex="index"
:line="line"
:plan="value"
:page="page"
:layer="layeridx-1"
:class=" 't-studyline '
+ ((line.sequence==1 && layeridx==1)?' first':'')
+ (line.sequence==value.studylines.length?' last':'')
+ (index==value.slots?' end':'')"
+ (line.sequence==page.studylines.length?' last':'')
+ (index==page.slots?' end':'')"
>
</t-studyline-slot
></template
></template
></template
></div><div :id="'studyplan-linewrapper-'+value.id" class='l-leaderline-linewrapper'></div>
></div>
</div>
</div>
<div v-if="edit.studyline.editmode" class='t-studyline-add'>
<a href="#" v-b-modal="'modal-add-studyline-'+value.id" @click="false;"
<a href="#" v-b-modal="'modal-add-studyline-'+page.id" @click="false;"
><i class='fa fa-plus'></i>{{ text.studyline_add }}</a>
</div>
<b-modal
:id="'modal-add-studyline-'+value.id"
:id="'modal-add-studyline-'+page.id"
size="lg"
:ok-title="text.add$core"
ok-variant="primary"
:title="text.studyline_add"
@ok="addStudyLine(value,create.studyline)"
@ok="addStudyLine(page,create.studyline)"
:ok-disabled="Math.min(create.studyline.name.length,create.studyline.shortname.length) == 0"
>
<b-container>
@ -1441,7 +1446,7 @@ export default {
<b-row>
<b-col cols="3">{{text.studyline_color}}</b-col>
<b-col>
<input type='color' v-model="create.studyline.color" />
<input type="color" v-model="create.studyline.color" />
<!-- hsluv-picker v-model="create.studyline.color" horizontal displaysize="175" ></hsluv-picker -->
</b-col>
</b-row>
@ -1475,10 +1480,7 @@ export default {
<b-row>
<b-col cols="3">{{ text.studyline_color}}</b-col>
<b-col>
<input type='color' v-model="edit.studyline.data.color" />
<!--hsluv-picker
v-model="edit.studyline.data.color"
horizontal displaysize="175" ></hsluv-picker -->
<input type="color" v-model="edit.studyline.data.color" />
</b-col>
</b-row>
</b-container>
@ -1494,7 +1496,7 @@ export default {
Vue.component('t-studyline-heading', {
props: {
value : {
type: Object,
type: Object, // Studyline
default: function(){ return {};},
},
numlines: {
@ -1561,7 +1563,7 @@ export default {
Vue.component('t-studyline-edit', {
props: {
value : {
type: Object,
type: Object, // Studyline
default: function(){ return {};},
},
numlines: {
@ -1636,7 +1638,7 @@ export default {
/*
* During a redisign it was decided to have the studyline still get the entire array as a value,
* even though it only shows one drop slot for the layer it is in. This is to make repainting easier,
* since we modify the array for the layer we handle
* since we modify the array for the layer we handle. FIXME: Make this less weird
*/
Vue.component('t-studyline-slot', {
props: {
@ -1660,10 +1662,10 @@ export default {
default(){ return [];},
},
plan: {
type: Object,
type: Object, // Studyplan data
default(){ return null;},
},
},
mounted() {
const self=this;
@ -1879,7 +1881,7 @@ export default {
default() { return false;},
},
'plan': {
type: Object,
type: Object, // Studyplan page
default() { return null;},
},
},

View file

@ -181,93 +181,6 @@ class studyplanpage {
}
}
public static function find_all($contextid=-1){
global $DB, $USER;
$list = [];
if($contextid <= 0){
$ids = $DB->get_fieldset_select(self::TABLE,"id","");
}
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,["contextid" => $contextid]);
}
foreach($ids as $id)
{
$list[] = self::findById($id);
}
return $list;
}
public static function find_by_shortname($shortname, $contextid = 0): array{
global $DB;
$list = [];
$where = "shortname = :shortname AND context_id = :contextid";
if($contextid == 0){
$where .= "OR context_id IS NULL";
}
$ids = $DB->get_fieldset_select(self::TABLE,"id",$where,["shortname"=>$shortname, "contextid" => $contextid]);
foreach($ids as $id)
{
$list[] = self::findById($id);
}
return $list;
}
public static function find_for_user($userid)
{
global $DB;
$sql = "SELECT s.id FROM {local_treestudyplan} s
INNER JOIN {local_treestudyplan_cohort} j ON j.studyplan_id = s.id
INNER JOIN {cohort_members} cm ON j.cohort_id = cm.cohortid
WHERE cm.userid = :userid";
$cohort_plan_ids = $DB->get_fieldset_sql($sql, ['userid' => $userid]);
$sql = "SELECT s.id FROM {local_treestudyplan} s
INNER JOIN {local_treestudyplan_user} j ON j.studyplan_id = s.id
WHERE j.user_id = :userid";
$user_plan_ids = $DB->get_fieldset_sql($sql, ['userid' => $userid]);
$plans = [];
foreach($cohort_plan_ids as $id) {
$plans[$id] = self::findById($id);
}
foreach($user_plan_ids as $id) {
if(!array_key_exists($id,$plans)){
$plans[$id] = self::findById($id);
}
}
return $plans;
}
static public function exist_for_user($userid)
{
global $DB;
$count = 0;
$sql = "SELECT s.* FROM {local_treestudyplan} s
INNER JOIN {local_treestudyplan_cohort} j ON j.studyplan_id = s.id
INNER JOIN {cohort_members} cm ON j.cohort_id = cm.cohortid
WHERE cm.userid = :userid";
$count += $DB->count_records_sql($sql, ['userid' => $userid]);
$sql = "SELECT s.* FROM {local_treestudyplan} s
INNER JOIN {local_treestudyplan_user} j ON j.studyplan_id = s.id
WHERE j.user_id = :userid";
$count += $DB->count_records_sql($sql, ['userid' => $userid]);
return ($count > 0);
}
public static function user_structure($value=VALUE_REQUIRED){
return new \external_single_structure([
"id" => new \external_value(PARAM_INT, 'id of studyplan page'),

View file

@ -240,7 +240,7 @@ class studyplanservice extends \external_api
public static function add_studyline_parameters()
{
return new \external_function_parameters( [
"studyplan_id" => new \external_value(PARAM_INT, 'id of studyplan to add line to'),
"page_id" => new \external_value(PARAM_INT, 'id of studyplan to add line to'),
"name" => new \external_value(PARAM_TEXT, 'shortname of studyline'),
"shortname"=> new \external_value(PARAM_TEXT, 'idnumber of studyline'),
"color"=> new \external_value(PARAM_TEXT, 'description of studyline'),
@ -253,14 +253,14 @@ class studyplanservice extends \external_api
return studyline::editor_structure();
}
public static function add_studyline($studyplan_id, $name, $shortname,$color,$sequence)
public static function add_studyline($page_id, $name, $shortname,$color,$sequence)
{
// validate if the requesting user has the right to edit the plan in it's current context
$studyplan = studyplan::findById($studyplan_id);
webservicehelper::require_capabilities(self::CAP_EDIT,$studyplan->context());
$page = studyplanpage::findById($page_id);
webservicehelper::require_capabilities(self::CAP_EDIT,$page->studyplan()->context());
$o = studyline::add([
'studyplan_id' => $studyplan_id,
'page_id' => $page_id,
'name' => $name,
'shortname' => $shortname,
'color' => $color,
@ -956,7 +956,8 @@ class studyplanservice extends \external_api
$plan = studyplan::findById($studyplan_id);
if($format == "csv"){
return $plan->export_plan_csv();
// FIXME: MAke sure this gets called for the page instead of the studyplan
return $plan->pages()[0]->export_plan_csv();
}
else{
return $plan->export_plan();
@ -986,7 +987,8 @@ class studyplanservice extends \external_api
try{
webservicehelper::require_capabilities(self::CAP_EDIT,studyplan::findById($studyplan_id)->context());
$plan = studyplan::findById($studyplan_id);
return $plan->export_studylines();
// FIXME: Make sure this gets called for the page instead of the studyplan
return $plan->pages()[0]->export_studylines();
}
catch(\webservice_access_exception $x) {
return [ "format" => "", "content" => ""];
@ -1050,7 +1052,8 @@ class studyplanservice extends \external_api
// Validate import context
webservicehelper::require_capabilities(self::CAP_EDIT,$plan->context());
$result = $plan->import_studylines($content,$format);
// FIXME: Make sure this gets called for the page instead of the studyplan
$result = $plan->pages()[0]->import_studylines($content,$format);
return ($result?success::success():success::fail())->model();
}
catch(\webservice_access_exception $x) {
@ -1061,7 +1064,7 @@ class studyplanservice extends \external_api
/************************************************
* *
* Read and write course module title and desc *
* Read and write course display name *
* TODO: FINISH OR REMOVE *
* *
************************************************/
@ -1111,6 +1114,7 @@ class studyplanservice extends \external_api
return success::structure();
}
/** DEPRECATED, will remove hacked edit form in the future */
public static function submit_cm_editform($cmid,$formdata){
global $CFG;
global $DB;