Added delete handles on all items in context modals

This commit is contained in:
PMKuipers 2023-09-02 23:25:21 +02:00
parent 207c638a66
commit d432f77494
14 changed files with 198 additions and 40 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,3 +1,3 @@
define("local_treestudyplan/util/string-helper",["exports","core/str"],(function(_exports,_str){function format_date(d,short){d instanceof Date||(d=new Date(d));var monthformat="short";return short&&(monthformat="numeric"),d.toLocaleDateString(document.documentElement.lang,{year:"numeric",month:monthformat,day:"numeric"})}Object.defineProperty(_exports,"__esModule",{value:!0}),_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);var 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.load_stringkeys=function(string_keys){var _loop2=function(idx){var stringkeys=[];for(var i in string_keys[idx]){var parts=string_keys[idx][i].textkey.split("$"),identifier=parts[0],component=parts.length>1?parts[1]:"local_treestudyplan";stringkeys.push({key:identifier,component:component})}(0,_str.get_strings)(stringkeys).then((function(strings){for(var _i in strings){var s=strings[_i];string_keys[idx][_i].text=s}}))};for(var idx in string_keys)_loop2(idx);return string_keys},_exports.load_strings=function(strings){var _loop=function(idx){var stringkeys=[];for(var handle in strings[idx]){var parts=strings[idx][handle].split(/[$@]/),identifier=parts[0],component=parts.length>1?parts[1]:"local_treestudyplan";stringkeys.push({key:identifier,component:component})}(0,_str.get_strings)(stringkeys).then((function(str){var i=0;for(var _key in strings[idx])strings[idx][_key]=str[i],i++}))};for(var idx in strings)_loop(idx);return strings}})); define("local_treestudyplan/util/string-helper",["exports","core/str"],(function(_exports,_str){function format_date(d,short){d instanceof Date||(d=new Date(d));var monthformat="short";return short&&(monthformat="numeric"),d.toLocaleDateString(document.documentElement.lang,{year:"numeric",month:monthformat,day:"numeric"})}Object.defineProperty(_exports,"__esModule",{value:!0}),_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);var 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.load_stringkeys=function(string_keys){var _loop2=function(idx){var stringkeys=[];for(var i in string_keys[idx]){var parts=string_keys[idx][i].textkey.split("$"),identifier=parts[0],component=parts.length>1?parts[1]:"local_treestudyplan";stringkeys.push({key:identifier,component:component})}(0,_str.get_strings)(stringkeys).then((function(strings){for(var _i in strings){var s=strings[_i];string_keys[idx][_i].text=s}}))};for(var idx in string_keys)_loop2(idx);return string_keys},_exports.load_strings=function(strings){var _loop=function(idx){var stringkeys=[];for(var handle in strings[idx]){var parts=strings[idx][handle].split(/[$@]/),identifier=parts[0],component=parts.length>1?parts[1]:"local_treestudyplan";stringkeys.push({key:identifier,component:component})}(0,_str.get_strings)(stringkeys).then((function(str){var i=0;for(var _key in strings[idx])strings[idx][_key]=str[i],i++}))};for(var idx in strings)_loop(idx);return strings},_exports.strformat=function(str,values){return str.replace(/\{(\w+)\}/g,(function(m,m1){return m1&&values.hasOwnProperty(m1)?values[m1]:m}))}}));
//# sourceMappingURL=string-helper.min.js.map //# sourceMappingURL=string-helper.min.js.map

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@ import {SimpleLine} from "./simpleline/simpleline";
import {call} from 'core/ajax'; import {call} from 'core/ajax';
import notification from 'core/notification'; import notification from 'core/notification';
import {get_strings} from 'core/str'; import {get_strings} from 'core/str';
import {load_stringkeys, load_strings, format_date, datespaninfo} from './util/string-helper'; import {load_stringkeys, load_strings, format_date, datespaninfo, strformat } from './util/string-helper';
import {objCopy,transportItem} from './studyplan-processor'; import {objCopy,transportItem} from './studyplan-processor';
import Debugger from './util/debugger'; import Debugger from './util/debugger';
import {download,upload} from './downloader'; import {download,upload} from './downloader';
@ -61,10 +61,7 @@ export default {
let string_keys = load_stringkeys({ let string_keys = load_stringkeys({
conditions: [ conditions: [
{ value: null, textkey: 'condition_default'},
{ value: 'ALL', textkey: 'condition_all'}, { value: 'ALL', textkey: 'condition_all'},
{ value: '67', textkey: 'condition_67'},
{ value: '50', textkey: 'condition_50'},
{ value: 'ANY', textkey: 'condition_any'}, { value: 'ANY', textkey: 'condition_any'},
], ],
}); });
@ -174,7 +171,7 @@ export default {
warning: 'course_timing_warning', warning: 'course_timing_warning',
timing_ok: 'course_timing_ok', timing_ok: 'course_timing_ok',
timing_off: 'course_timing_off', timing_off: 'course_timing_off',
course: 'course$core', course: 'course@core',
period: 'period', period: 'period',
yes: 'yes$core', yes: 'yes$core',
no: 'no$core', no: 'no$core',
@ -210,6 +207,15 @@ export default {
item_text: { item_text: {
select_conditions: "select_conditions", select_conditions: "select_conditions",
item_configuration: "item_configuration", item_configuration: "item_configuration",
ok: "ok@core",
delete: "delete@core",
item_delete_message: "item_delete_message",
type_course: "course@core",
type_junction: "tool-junction",
type_start: "tool-start",
type_finish: "tool-finish",
type_badge: "tool-badge",
type_invalid: "course-invalid",
}, },
item_course_text: { item_course_text: {
select_conditions: "select_conditions", select_conditions: "select_conditions",
@ -219,7 +225,9 @@ export default {
coursetiming_future: "coursetiming_future", coursetiming_future: "coursetiming_future",
grade_include: "grade_include", grade_include: "grade_include",
grade_require: "grade_require", grade_require: "grade_require",
ok: "ok$core", ok: "ok@core",
cancel: "cancel@core",
delete: "delete@core",
}, },
invalid: { invalid: {
error: 'error', error: 'error',
@ -2187,7 +2195,15 @@ export default {
:data="item" :data="item"
:type="makeType(item)" :type="makeType(item)"
@cut="onCut" @cut="onCut"
><t-item v-model="value[itemidx]" :plan="plan" :page='page' :period='period' :maxspan='maxSpan()'></t-item ><t-item
@deleted="onCut"
v-model="value[itemidx]"
:plan="plan"
:line='line'
:page='page'
:period='period'
:maxspan='maxSpan()'
></t-item
></drag ></drag
><drop v-else ><drop v-else
:class="'t-slot-drop '+type + (layer > 0?' secondary':' primary')" :class="'t-slot-drop '+type + (layer > 0?' secondary':' primary')"
@ -2487,6 +2503,10 @@ export default {
type: Object, // Studyplan page type: Object, // Studyplan page
default() { return null;}, default() { return null;},
}, },
line: {
type: Object, // Studyplan page
default() { return null;},
},
page: { page: {
type: Object, // Studyplan page type: Object, // Studyplan page
default() { return null;}, default() { return null;},
@ -2705,6 +2725,36 @@ export default {
delete this.lines[conn.to_id]; delete this.lines[conn.to_id];
} }
}, },
deleteItem(){
const self = this;
const msgparams = {
item: this.text['type_' + this.value.type].toLocaleLowerCase(),
name: (this.value.type=='course')?this.value.course.displayname:"",
line: (this.line) ? this.line.name : "",
period: (this.period) ? this.period.fullname : this.plan.name,
};
this.$bvModal.msgBoxConfirm(strformat(this.text.item_delete_message, msgparams), {
okVariant : 'danger',
okTitle : this.text.ok,
cancelTitle: this.text.cancel,
}).then(value => {
if ( value ) {
// Confirmed to delete.
call([{
methodname: 'local_treestudyplan_delete_studyitem',
args: { 'id': self.value.id, }
}])[0].done(function(response){
if(response.success == true){
self.$emit("deleted",{ data: self.value });
}
}).fail(notification.exception);
}
}).catch(err => {
debug.console.error(err);
});
}
}, },
computed: { computed: {
@ -2715,7 +2765,7 @@ export default {
return !(["start",].includes(this.value.type)); return !(["start",].includes(this.value.type));
}, },
hasContext() { hasContext() {
return ['junction','finish'].includes(this.value.type); return ['start','junction','finish'].includes(this.value.type);
} }
}, },
created(){ created(){
@ -2782,13 +2832,40 @@ export default {
}, },
template: ` template: `
<div class="t-item-base" :id="'studyitem-'+value.id"> <div class="t-item-base" :id="'studyitem-'+value.id">
<t-item-course v-model="value" v-if="value.type == 'course'" <t-item-course
:plan='plan' :page='page' :period='period' :maxspan='maxspan'></t-item-course> v-if="value.type == 'course'"
<t-item-junction v-model="value" v-if="value.type == 'junction'" ></t-item-junction> @deleterq="deleteItem"
<t-item-start v-model="value" v-if="value.type == 'start'" ></t-item-start> v-model="value"
<t-item-finish v-model="value" v-if="value.type == 'finish'" ></t-item-finish> :plan='plan'
<t-item-badge v-model="value" v-if="value.type == 'badge'" ></t-item-badge> :page='page'
<t-item-invalid v-model="value" v-if="value.type == 'invalid'" ></t-item-invalid> :period='period'
:maxspan='maxspan'
></t-item-course>
<t-item-junction
v-if="value.type == 'junction'"
@deleterq="deleteItem"
v-model="value"
></t-item-junction>
<t-item-start
v-if="value.type == 'start'"
@deleterq="deleteItem"
v-model="value"
></t-item-start>
<t-item-finish
v-if="value.type == 'finish'"
@deleterq="deleteItem"
v-model="value"
></t-item-finish>
<t-item-badge
v-if="value.type == 'badge'"
@deleterq="deleteItem"
v-model="value"
></t-item-badge>
<t-item-invalid
v-if="value.type == 'invalid'"
@deleterq="deleteItem"
v-model="value"
></t-item-invalid>
<drop v-if='!dummy && hasConnectionsIn' accepts-type="linestart" <drop v-if='!dummy && hasConnectionsIn' accepts-type="linestart"
:id="'t-item-cend-'+value.id" :id="'t-item-cend-'+value.id"
class="t-item-connector-end" class="t-item-connector-end"
@ -2820,13 +2897,15 @@ export default {
</div> </div>
<a v-if="hasContext" class="t-item-config" <a v-if="hasContext" class="t-item-config"
v-b-modal="'t-item-config-'+value.id" href="#" @click.prevent=""><i class="fa fa-gear"></i></a> v-b-modal="'t-item-config-'+value.id" href="#" @click.prevent=""><i class="fa fa-gear"></i></a>
<b-modal no-body class='t-item-contextview' <b-modal no-body class=""
:id="'t-item-config-'+value.id" :id="'t-item-config-'+value.id"
:title="text['item_configuration']" :title="text['item_configuration']"
scrollable scrollable
ok-only ok-only
class="t-item-contextview b-modal-justify-footer-between"
> >
<b-form-group <b-form-group
v-if="value.type != 'start'"
:label="text.select_conditions" :label="text.select_conditions"
> >
<b-form-select size="sm" <b-form-select size="sm"
@ -2835,6 +2914,17 @@ export default {
:options="condition_options" :options="condition_options"
></b-form-select> ></b-form-select>
</b-form-group> </b-form-group>
<template #modal-footer="{ ok, cancel, hide }" >
<a href='#' @click='deleteItem()' class="text-danger"
><i class="fa fa-trash"></i>
{{ text.delete }}
</a>
<b-button size="sm" variant="primary" @click="ok()">
{{ text.ok }}
</b-button>
</template>
</b-modal> </b-modal>
</div> </div>
`, `,
@ -2864,6 +2954,8 @@ export default {
<b-col md="11"> <b-col md="11">
<b-card-body class="align-items-center"> <b-card-body class="align-items-center">
<i class="fa fa-exclamation"></i> {{text.error}} <i class="fa fa-exclamation"></i> {{text.error}}
<a href='#' @click='$emit("deleterq")' class="text-danger"
><i class="fa fa-trash"></i></a>
</b-card-body> </b-card-body>
</b-col> </b-col>
</b-row> </b-row>
@ -3015,12 +3107,13 @@ export default {
</b-card-body> </b-card-body>
</div> </div>
</div> </div>
<b-modal <b-modal class=""
:id="'t-item-course-config-'+value.id" :id="'t-item-course-config-'+value.id"
:title="value.course.displayname + ' - ' + value.course.fullname" :title="value.course.displayname + ' - ' + value.course.fullname"
ok-only ok-only
size="lg" size="lg"
scrollable scrollable
class="b-modal-justify-footer-between"
> >
<template #modal-header> <template #modal-header>
<div> <div>
@ -3056,6 +3149,16 @@ export default {
v-model='value.course.completion' v-model='value.course.completion'
:course='value.course' :course='value.course'
></t-item-course-completion> ></t-item-course-completion>
<template #modal-footer="{ ok, cancel, hide }" >
<a href='#' @click='$emit("deleterq")' class="text-danger"
><i class="fa fa-trash"></i>
{{ text.delete }}
</a>
<b-button size="sm" variant="primary" @click="ok()">
{{ text.ok }}
</b-button>
</template>
</b-modal> </b-modal>
</b-card></div> </b-card></div>
`, `,
@ -3333,6 +3436,7 @@ export default {
data() { data() {
return { return {
txt: strings, txt: strings,
text: strings.item_text,
}; };
}, },
methods: { methods: {
@ -3348,13 +3452,14 @@ export default {
</svg> </svg>
<a class="t-item-config badge" <a class="t-item-config badge"
v-b-modal="'t-item-badge-details-'+value.id" href="#" @click.prevent=""><i class="fa fa-gear"></i></a> v-b-modal="'t-item-badge-details-'+value.id" href="#" @click.prevent=""><i class="fa fa-gear"></i></a>
<b-modal <b-modal class=""
:id="'t-item-badge-details-'+value.id" :id="'t-item-badge-details-'+value.id"
:title="value.badge.name" :title="value.badge.name"
size="lg" size="lg"
ok-only ok-only
centered centered
scrollable scrollable
class="b-modal-justify-footer-between"
> >
<template #modal-header> <template #modal-header>
<div> <div>
@ -3376,6 +3481,15 @@ export default {
<a :href="value.badge.infolink">{{ txt.badge.badgeinfo }}</a></strong></p> <a :href="value.badge.infolink">{{ txt.badge.badgeinfo }}</a></strong></p>
</b-col></b-row> </b-col></b-row>
</b-container> </b-container>
<template #modal-footer="{ ok, cancel, hide }" >
<a href='#' @click='$emit("deleterq")' class="text-danger"
><i class="fa fa-trash"></i>
{{ text.delete }}
</a>
<b-button size="sm" variant="primary" @click="ok()">
{{ text.ok }}
</b-button>
</template>
</b-modal> </b-modal>
</div> </div>

View file

@ -117,3 +117,18 @@ export function datespaninfo(first,last){
} }
/**
* String formatting function - replaces {name} in string by value of same key in values parameter
* @param {string} str String t
* @param {object} values Object containing keys to replace {key} strings with
* @returns Formatted string
*/
export function strformat(str,values) {
return str.replace(/\{(\w+)\}/g, (m, m1) => {
if (m1 && values.hasOwnProperty(m1)) {
return values[m1];
} else {
return m;
}
});
}

View file

@ -14,17 +14,21 @@
--incomplete: var(--gray); --incomplete: var(--gray);
} }
.path-local-treestudyplan div.tab-pane:target { .path-local-treestudyplan div.tab-pane:target,
.features-treestudyplan div.tab-pane:target {
margin-top: 0; margin-top: 0;
} }
.path-local-treestudyplan [v-cloak] { .path-local-treestudyplan [v-cloak],
.features-treestudyplan [v-cloak] {
visibility: hidden; visibility: hidden;
} }
.path-local-treestudyplan .vue-loader { .path-local-treestudyplan .vue-loader,
.features-treestudyplan .vue-loader {
width: 32px; width: 32px;
margin: auto; margin: auto;
} }
.path-local-treestudyplan .special { .path-local-treestudyplan .special,
.features-treestudyplan .special {
color: gold; color: gold;
} }
@ -640,7 +644,7 @@
.path-local-treestudyplan a.t-item-config, .path-local-treestudyplan a.t-item-config,
.features-treestudyplan a.t-item-config { .features-treestudyplan a.t-item-config {
position: absolute; position: absolute;
top: -5px; top: -10px;
right: -5px; right: -5px;
} }
.path-local-treestudyplan a.t-item-config.badge, .path-local-treestudyplan a.t-item-config.badge,
@ -1327,3 +1331,8 @@
.features-treestudyplan .border-grey { .features-treestudyplan .border-grey {
border-color: #aaa; border-color: #aaa;
} }
.path-local-treestudyplan .b-modal-justify-footer-between .modal-footer,
.features-treestudyplan .b-modal-justify-footer-between .modal-footer {
justify-content: space-between;
}

View file

@ -143,6 +143,7 @@ $string["tool-junction"] = 'Junction';
$string["tool-start"] = 'Start/continue'; $string["tool-start"] = 'Start/continue';
$string["tool-finish"] = 'Finish'; $string["tool-finish"] = 'Finish';
$string["tool-badge"] = 'Badge'; $string["tool-badge"] = 'Badge';
$string["course-invalid"] = "Error";
$string["badges"] = 'Badges'; $string["badges"] = 'Badges';
@ -330,7 +331,7 @@ $string["course_timing_off"] = 'Course timing does not match period timing. Clic
$string["course_period_span"] = 'Spans'; $string["course_period_span"] = 'Spans';
$string["course_period_span_desc"] = 'If the space directly after this course is free, the course can be expanded to span multiple periods.'; $string["course_period_span_desc"] = 'If the space directly after this course is free, the course can be expanded to span multiple periods.';
$string["view_completion_report"] = 'View detailed course completion report'; $string["view_completion_report"] = 'View detailed course completion report';
$string["item_delete_message"] = 'Are you sure you want to delete {$a->item} {$a->name} from studyline {$a->line} in period {$a->period}?'; $string["item_delete_message"] = 'Are you sure you want to delete the {item} {name} from studyline {line} in {period}?';
$string["student_not_tracked"] = 'Not enrolled in this course'; $string["student_not_tracked"] = 'Not enrolled in this course';
$string["completion_not_enabled"] = 'Completion is not enabled in this course'; $string["completion_not_enabled"] = 'Completion is not enabled in this course';

View file

@ -143,6 +143,7 @@ $string["tool-junction"] = 'Kruispunt';
$string["tool-start"] = 'Start/Vervolgpunt'; $string["tool-start"] = 'Start/Vervolgpunt';
$string["tool-finish"] = 'Eindpunt'; $string["tool-finish"] = 'Eindpunt';
$string["tool-badge"] = 'Badge'; $string["tool-badge"] = 'Badge';
$string["course-invalid"] = "Storing";
$string["badges"] = 'Badges'; $string["badges"] = 'Badges';
@ -331,7 +332,7 @@ $string["course_timing_off"] = 'Cursustiming en periodetiming komen niet overeen
$string["course_period_span"] = 'Duurt'; $string["course_period_span"] = 'Duurt';
$string["course_period_span_desc"] = 'Als de ruimte na deze cursus leeg is, kan de cursus worden uitgespreid over meerdere perioden.'; $string["course_period_span_desc"] = 'Als de ruimte na deze cursus leeg is, kan de cursus worden uitgespreid over meerdere perioden.';
$string["view_completion_report"] = 'Bekijk gedetailleerd voltooiingsoverzicht'; $string["view_completion_report"] = 'Bekijk gedetailleerd voltooiingsoverzicht';
$string["item_delete_message"] = 'Weet je zeker dat je {$a->item} {$a->name} wilt verwijderen uit leerlijn {$a->line} in periode {$a->period}?'; $string["item_delete_message"] = 'Weet je zeker dat je {item} {name} wilt verwijderen uit leerlijn {line} in {period}?';
$string["student_not_tracked"] = 'Niet ingeschreven in deze cursus'; $string["student_not_tracked"] = 'Niet ingeschreven in deze cursus';
$string["completion_not_enabled"] = 'Cursusvoltooiing is niet ingeschakeld'; $string["completion_not_enabled"] = 'Cursusvoltooiing is niet ingeschakeld';

8
scss/bootstraptweaking.scss vendored Normal file
View file

@ -0,0 +1,8 @@
.path-local-treestudyplan, .features-treestudyplan {
.b-modal-justify-footer-between .modal-footer {
justify-content: space-between;
}
}

View file

@ -1,4 +1,4 @@
.path-local-treestudyplan { .path-local-treestudyplan, .features-treestudyplan {
div.tab-pane:target { div.tab-pane:target {
margin-top: 0; margin-top: 0;
} }

View file

@ -539,7 +539,7 @@
a.t-item-config { a.t-item-config {
position: absolute; position: absolute;
top: -5px; top: -10px;
right: -5px; right: -5px;
} }

View file

@ -1,4 +1,5 @@
@import "colors.scss"; @import "colors.scss";
@import "generic.scss"; @import "generic.scss";
@import "invitemanager.scss"; @import "invitemanager.scss";
@import "studyplan.scss" @import "studyplan.scss";
@import "bootstraptweaking.scss";

View file

@ -14,17 +14,21 @@
--incomplete: var(--gray); --incomplete: var(--gray);
} }
.path-local-treestudyplan div.tab-pane:target { .path-local-treestudyplan div.tab-pane:target,
.features-treestudyplan div.tab-pane:target {
margin-top: 0; margin-top: 0;
} }
.path-local-treestudyplan [v-cloak] { .path-local-treestudyplan [v-cloak],
.features-treestudyplan [v-cloak] {
visibility: hidden; visibility: hidden;
} }
.path-local-treestudyplan .vue-loader { .path-local-treestudyplan .vue-loader,
.features-treestudyplan .vue-loader {
width: 32px; width: 32px;
margin: auto; margin: auto;
} }
.path-local-treestudyplan .special { .path-local-treestudyplan .special,
.features-treestudyplan .special {
color: gold; color: gold;
} }
@ -640,7 +644,7 @@
.path-local-treestudyplan a.t-item-config, .path-local-treestudyplan a.t-item-config,
.features-treestudyplan a.t-item-config { .features-treestudyplan a.t-item-config {
position: absolute; position: absolute;
top: -5px; top: -10px;
right: -5px; right: -5px;
} }
.path-local-treestudyplan a.t-item-config.badge, .path-local-treestudyplan a.t-item-config.badge,
@ -1327,3 +1331,8 @@
.features-treestudyplan .border-grey { .features-treestudyplan .border-grey {
border-color: #aaa; border-color: #aaa;
} }
.path-local-treestudyplan .b-modal-justify-footer-between .modal-footer,
.features-treestudyplan .b-modal-justify-footer-between .modal-footer {
justify-content: space-between;
}