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> </template>
</r-studyline> </r-studyline>
</template> </template>
<div :id="'studyplan-linewrapper-'+(value?value.id:'null')" class='l-leaderline-linewrapper'></div>
</div> </div>
`, `,
}); });

View File

@ -9,7 +9,6 @@
import {SimpleLine} from "./simpleline"; import {SimpleLine} from "./simpleline";
import {call} from 'core/ajax'; import {call} from 'core/ajax';
import notification from 'core/notification'; import notification from 'core/notification';
import {debounce} from './debounce';
import {get_strings} from 'core/str'; import {get_strings} from 'core/str';
import {load_stringkeys, load_strings} from './string-helper'; import {load_stringkeys, load_strings} from './string-helper';
import {objCopy,transportItem} from './studyplan-processor'; import {objCopy,transportItem} from './studyplan-processor';
@ -1107,7 +1106,7 @@ export default {
}, },
mounted() { mounted() {
if(this.value.studylines.length == 0){ if(this.page.studylines.length == 0){
// start in editmode if studylines are empty // start in editmode if studylines are empty
this.edit.studyline.editmode = true; this.edit.studyline.editmode = true;
} }
@ -1120,15 +1119,19 @@ export default {
}, },
computed: { computed: {
columns() { columns() {
return 1+ (this.value.slots * 2); return 1+ (this.page.periods * 2);
}, },
columns_stylerule() { columns_stylerule() {
// Uses css variables, so width for slots and filters can be configured in css // 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 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)"; s+= " var(--studyplan-course-width) var(--studyplan-filter-width)";
} }
return s+";"; return s+";";
},
page(){
// FIXME: Temporary hack until real page management is implemented
return this.value.pages[0];
} }
}, },
methods: { methods: {
@ -1171,19 +1174,19 @@ export default {
movedStudyplan(plan,from,to) { movedStudyplan(plan,from,to) {
this.$emit('moved',plan,from,to); // Throw the event up.... this.$emit('moved',plan,from,to); // Throw the event up....
}, },
addStudyLine(studyplan,newlineinfo) { addStudyLine(page,newlineinfo) {
call([{ call([{
methodname: 'local_treestudyplan_add_studyline', methodname: 'local_treestudyplan_add_studyline',
args: { args: {
'studyplan_id': studyplan.id, 'page_id': page.id,
'name': newlineinfo.name, 'name': newlineinfo.name,
'shortname': newlineinfo.shortname, 'shortname': newlineinfo.shortname,
'color': newlineinfo.color, 'color': newlineinfo.color,
'sequence': studyplan.studylines.length, 'sequence': page.studylines.length,
} }
}])[0].done(function(response){ }])[0].done(function(response){
debug.info("New studyline:",response); debug.info("New studyline:",response);
studyplan.studylines.push(response); page.studylines.push(response);
newlineinfo.name = ''; newlineinfo.name = '';
newlineinfo.shortname = ''; newlineinfo.shortname = '';
newlineinfo.color = "#dddddd"; newlineinfo.color = "#dddddd";
@ -1211,7 +1214,7 @@ export default {
originalline['color'] = response['color']; originalline['color'] = response['color'];
}).fail(notification.exception); }).fail(notification.exception);
}, },
deleteLine(studyplan,line) { deleteLine(page,line) {
debug.info('Delete Line',line); debug.info('Delete Line',line);
const self=this; const self=this;
get_strings([ get_strings([
@ -1229,8 +1232,8 @@ export default {
}])[0].done(function(response){ }])[0].done(function(response){
debug.info('Delete response:', response); debug.info('Delete response:', response);
if(response.success == true){ if(response.success == true){
let index = studyplan.studylines.indexOf(line); let index = page.studylines.indexOf(line);
studyplan.studylines.splice(index, 1); page.studylines.splice(index, 1);
} }
}).fail(notification.exception); }).fail(notification.exception);
} }
@ -1312,7 +1315,7 @@ export default {
><i class='fa fa-trash'></i> ><i class='fa fa-trash'></i>
</drop> </drop>
<span class='control deletable'> <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> ><i class='text-danger fa fa-trash'></i></a>
</span> </span>
<span class='control editable'> <span class='control editable'>
@ -1329,11 +1332,11 @@ export default {
</div> </div>
<div class='t-studyplan-content-edit' v-if="edit.studyline.editmode"> <div class='t-studyplan-content-edit' v-if="edit.studyline.editmode">
<drop-list <drop-list
:items="value.studylines" :items="page.studylines"
class="t-slot-droplist" class="t-slot-droplist"
:accepts-type="'studyline-'+value.id" :accepts-type="'studyline-'+page.id"
xreorder="$event.apply(value.studylines)" xreorder="$event.apply(page.studylines)"
@reorder="reorderLines($event,value.studylines)" @reorder="reorderLines($event,page.studylines)"
mode="copy" mode="copy"
row row
> >
@ -1342,16 +1345,16 @@ export default {
:key="item.id" :key="item.id"
class='t-studyplan-drag' class='t-studyplan-drag'
:data="item" :data="item"
:type="'studyline-'+value.id" :type="'studyline-'+page.id"
> >
<template v-slot:drag-image> <template v-slot:drag-image>
<i class="fa fa-arrows text-primary"></i> <i class="fa fa-arrows text-primary"></i>
</template> </template>
<t-studyline-edit <t-studyline-edit
v-model="item" v-model="item"
:numlines='value.studylines.length' :numlines='page.studylines.length'
@edit='editLineStart(item)' @edit='editLineStart(item)'
@delete='deleteLine(value,item)' @delete='deleteLine(page,item)'
> >
<div v-if="!slotsempty(item.slots)"> {{ text.editmode_modules_hidden}} </div> <div v-if="!slotsempty(item.slots)"> {{ text.editmode_modules_hidden}} </div>
</t-studyline-edit> </t-studyline-edit>
@ -1362,10 +1365,10 @@ export default {
<div class='t-studyplan-content' v-else> <div class='t-studyplan-content' v-else>
<!-- First paint the headings--> <!-- First paint the headings-->
<div class='t-studyplan-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" :key="line.id"
v-model="value.studylines[lineindex]" v-model="page.studylines[lineindex]"
:numlines='value.studylines.length' :numlines='page.studylines.length'
:layers='countLineLayers(line)+1' :layers='countLineLayers(line)+1'
></t-studyline-heading> ></t-studyline-heading>
</div> </div>
@ -1374,9 +1377,9 @@ export default {
<div class="t-studyplan-timeline" :style="columns_stylerule"> <div class="t-studyplan-timeline" :style="columns_stylerule">
<!-- Line by line add the items --> <!-- Line by line add the items -->
<!-- The grid layout handles putting it in rows and columns --> <!-- 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="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 <t-studyline-slot
v-if="index > 0" v-if="index > 0"
@ -1386,9 +1389,10 @@ export default {
:slotindex="index" :slotindex="index"
:line="line" :line="line"
:plan="value" :plan="value"
:page="page"
:layer="layeridx-1" :layer="layeridx-1"
:class= "'t-studyline ' + ((line.sequence==1 && layeridx==1)?' first':'') + :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
><t-studyline-slot ><t-studyline-slot
type='filter' type='filter'
@ -1397,30 +1401,31 @@ export default {
:slotindex="index" :slotindex="index"
:line="line" :line="line"
:plan="value" :plan="value"
:page="page"
:layer="layeridx-1" :layer="layeridx-1"
:class=" 't-studyline ' :class=" 't-studyline '
+ ((line.sequence==1 && layeridx==1)?' first':'') + ((line.sequence==1 && layeridx==1)?' first':'')
+ (line.sequence==value.studylines.length?' last':'') + (line.sequence==page.studylines.length?' last':'')
+ (index==value.slots?' end':'')" + (index==page.slots?' end':'')"
> >
</t-studyline-slot </t-studyline-slot
></template ></template
></template ></template
></template ></template
></div><div :id="'studyplan-linewrapper-'+value.id" class='l-leaderline-linewrapper'></div> ></div>
</div> </div>
</div> </div>
<div v-if="edit.studyline.editmode" class='t-studyline-add'> <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> ><i class='fa fa-plus'></i>{{ text.studyline_add }}</a>
</div> </div>
<b-modal <b-modal
:id="'modal-add-studyline-'+value.id" :id="'modal-add-studyline-'+page.id"
size="lg" size="lg"
:ok-title="text.add$core" :ok-title="text.add$core"
ok-variant="primary" ok-variant="primary"
:title="text.studyline_add" :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" :ok-disabled="Math.min(create.studyline.name.length,create.studyline.shortname.length) == 0"
> >
<b-container> <b-container>
@ -1441,7 +1446,7 @@ export default {
<b-row> <b-row>
<b-col cols="3">{{text.studyline_color}}</b-col> <b-col cols="3">{{text.studyline_color}}</b-col>
<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 --> <!-- hsluv-picker v-model="create.studyline.color" horizontal displaysize="175" ></hsluv-picker -->
</b-col> </b-col>
</b-row> </b-row>
@ -1475,10 +1480,7 @@ export default {
<b-row> <b-row>
<b-col cols="3">{{ text.studyline_color}}</b-col> <b-col cols="3">{{ text.studyline_color}}</b-col>
<b-col> <b-col>
<input type='color' v-model="edit.studyline.data.color" /> <input type="color" v-model="edit.studyline.data.color" />
<!--hsluv-picker
v-model="edit.studyline.data.color"
horizontal displaysize="175" ></hsluv-picker -->
</b-col> </b-col>
</b-row> </b-row>
</b-container> </b-container>
@ -1494,7 +1496,7 @@ export default {
Vue.component('t-studyline-heading', { Vue.component('t-studyline-heading', {
props: { props: {
value : { value : {
type: Object, type: Object, // Studyline
default: function(){ return {};}, default: function(){ return {};},
}, },
numlines: { numlines: {
@ -1561,7 +1563,7 @@ export default {
Vue.component('t-studyline-edit', { Vue.component('t-studyline-edit', {
props: { props: {
value : { value : {
type: Object, type: Object, // Studyline
default: function(){ return {};}, default: function(){ return {};},
}, },
numlines: { 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, * 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, * 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', { Vue.component('t-studyline-slot', {
props: { props: {
@ -1660,7 +1662,7 @@ export default {
default(){ return [];}, default(){ return [];},
}, },
plan: { plan: {
type: Object, type: Object, // Studyplan data
default(){ return null;}, default(){ return null;},
}, },
@ -1879,7 +1881,7 @@ export default {
default() { return false;}, default() { return false;},
}, },
'plan': { 'plan': {
type: Object, type: Object, // Studyplan page
default() { return null;}, 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){ public static function user_structure($value=VALUE_REQUIRED){
return new \external_single_structure([ return new \external_single_structure([
"id" => new \external_value(PARAM_INT, 'id of studyplan page'), "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() public static function add_studyline_parameters()
{ {
return new \external_function_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'), "name" => new \external_value(PARAM_TEXT, 'shortname of studyline'),
"shortname"=> new \external_value(PARAM_TEXT, 'idnumber of studyline'), "shortname"=> new \external_value(PARAM_TEXT, 'idnumber of studyline'),
"color"=> new \external_value(PARAM_TEXT, 'description of studyline'), "color"=> new \external_value(PARAM_TEXT, 'description of studyline'),
@ -253,14 +253,14 @@ class studyplanservice extends \external_api
return studyline::editor_structure(); 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 // validate if the requesting user has the right to edit the plan in it's current context
$studyplan = studyplan::findById($studyplan_id); $page = studyplanpage::findById($page_id);
webservicehelper::require_capabilities(self::CAP_EDIT,$studyplan->context()); webservicehelper::require_capabilities(self::CAP_EDIT,$page->studyplan()->context());
$o = studyline::add([ $o = studyline::add([
'studyplan_id' => $studyplan_id, 'page_id' => $page_id,
'name' => $name, 'name' => $name,
'shortname' => $shortname, 'shortname' => $shortname,
'color' => $color, 'color' => $color,
@ -956,7 +956,8 @@ class studyplanservice extends \external_api
$plan = studyplan::findById($studyplan_id); $plan = studyplan::findById($studyplan_id);
if($format == "csv"){ 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{ else{
return $plan->export_plan(); return $plan->export_plan();
@ -986,7 +987,8 @@ class studyplanservice extends \external_api
try{ try{
webservicehelper::require_capabilities(self::CAP_EDIT,studyplan::findById($studyplan_id)->context()); webservicehelper::require_capabilities(self::CAP_EDIT,studyplan::findById($studyplan_id)->context());
$plan = studyplan::findById($studyplan_id); $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) { catch(\webservice_access_exception $x) {
return [ "format" => "", "content" => ""]; return [ "format" => "", "content" => ""];
@ -1050,7 +1052,8 @@ class studyplanservice extends \external_api
// Validate import context // Validate import context
webservicehelper::require_capabilities(self::CAP_EDIT,$plan->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(); return ($result?success::success():success::fail())->model();
} }
catch(\webservice_access_exception $x) { 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 * * TODO: FINISH OR REMOVE *
* * * *
************************************************/ ************************************************/
@ -1111,6 +1114,7 @@ class studyplanservice extends \external_api
return success::structure(); return success::structure();
} }
/** DEPRECATED, will remove hacked edit form in the future */
public static function submit_cm_editform($cmid,$formdata){ public static function submit_cm_editform($cmid,$formdata){
global $CFG; global $CFG;
global $DB; global $DB;