Finished custom fields in course popup. Added optional progress bar in course popup bar. Added progress circles to manual aggregation.
This commit is contained in:
		
							parent
							
								
									5544d57f6b
								
							
						
					
					
						commit
						bfcd41dd81
					
				
					 23 changed files with 494 additions and 150 deletions
				
			
		
							
								
								
									
										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/simpleline/simpleline.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								amd/build/simpleline/simpleline.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/treestudyplan-components.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								amd/build/treestudyplan-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||(d=new Date(d));let monthformat="short";return short&&(monthformat="numeric"),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.studyplanDates=studyplanDates,_exports.studyplanPageTiming=function(page){const now=(new Date).getTime(),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(),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||(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.studyplanDates=studyplanDates,_exports.studyplanPageTiming=function(page){const now=(new Date).getTime(),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(),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
											
										
									
								
							|  | @ -1099,6 +1099,26 @@ export default { | |||
|                     else { | ||||
|                         return this.text.noenddate; | ||||
|                     } | ||||
|                 }, | ||||
|                 courseprogress() { | ||||
|                     if (!this.value.course.enrolled) { | ||||
|                         return 0; | ||||
|                     } else if(this.value.course.completion) { | ||||
|                         return (this.value.course.completion.progress / this.value.course.completion.count);  | ||||
|                     } else if(this.value.course.competency) { | ||||
|                         return (this.value.course.competency.progress / this.value.course.competency.count);  | ||||
|                     } else if(this.value.course.grades) { | ||||
|                         return (this.gradeprogress(this.value.course.grades) / this.value.course.grades.length);  | ||||
|                     } else { | ||||
|                         return 0; | ||||
|                     } | ||||
|                 }, | ||||
|                 hasprogressinfo() { | ||||
|                     if (!this.value.course.enrolled) { | ||||
|                         return false; | ||||
|                     } else { | ||||
|                         return (this.value.course.completion || this.value.course.competency || this.value.course.grades); | ||||
|                     } | ||||
|                 } | ||||
|             }, | ||||
|             created(){ | ||||
|  | @ -1138,6 +1158,16 @@ export default { | |||
|                             return "check"; | ||||
|                     } | ||||
|                 }, | ||||
|                 gradeprogress(grades) { | ||||
|                     let progress = 0; | ||||
|                     for (const ix in grades) { | ||||
|                         const g = grades[ix]; | ||||
|                         if (["completed","excellent","good"].includes(g.completion)) { | ||||
|                             progress++; | ||||
|                         } | ||||
|                     } | ||||
|                     return progress; | ||||
|                 }, | ||||
|             }, | ||||
|             template: ` | ||||
|             <div :class="'r-item-competency completion-'+value.completion"> | ||||
|  | @ -1156,24 +1186,10 @@ export default { | |||
|                                     class="r-course-result fa fa-exclamation-triangle t-not-enrolled-alert" | ||||
|                                     :title="text.student_not_tracked"></i> | ||||
|                             </template> | ||||
|                             <template v-else-if='value.course.completion'> | ||||
|                             <template v-else-if='hasprogressinfo'> | ||||
|                                 <r-progress-circle v-if='["failed", "progress","incomplete"].includes(value.completion)' | ||||
|                                     :value='value.course.completion.progress' | ||||
|                                     :max='value.course.completion.count' | ||||
|                                     :min='0' | ||||
|                                     :class="'r-course-result r-completion-'+value.completion" | ||||
|                                     :icon='circle_icon(value.completion)' | ||||
|                                     :title="text['completion_'+value.completion]" | ||||
|                                 ></r-progress-circle> | ||||
|                                 <i v-else v-b-popover.top | ||||
|                                     :class="'r-course-result fa fa-'+completion_icon(value.completion)+ | ||||
|                                             ' r-completion-'+value.completion" | ||||
|                                     :title="text['completion_'+value.completion]"></i> | ||||
|                             </template> | ||||
|                             <template v-else-if='value.course.competency'> | ||||
|                                 <r-progress-circle v-if='["failed", "progress","incomplete"].includes(value.completion)' | ||||
|                                     :value='value.course.competency.progress' | ||||
|                                     :max='value.course.competency.count' | ||||
|                                     :value='courseprogress' | ||||
|                                     :max='1' | ||||
|                                     :min='0' | ||||
|                                     :class="'r-course-result r-completion-'+value.completion" | ||||
|                                     :icon='circle_icon(value.completion)' | ||||
|  | @ -1205,48 +1221,59 @@ export default { | |||
|                     ok-only | ||||
|                     centered | ||||
|                     scrollable | ||||
|                     header-class="r-item-course-header" | ||||
|                     > | ||||
|                     <template #modal-header> | ||||
|                         <div> | ||||
|                             <h1><a :href="(!guestmode)?('/course/view.php?id='+value.course.id):undefined" target="_blank" | ||||
|                                 ><i class="fa fa-graduation-cap"></i> {{ value.course.fullname }}</a></h1> | ||||
|                             {{ value.course.context.path.join(" / ")}} | ||||
|                         </div> | ||||
|                         <div class="r-course-detail-header-right"> | ||||
|                             <div class="r-completion-detail-header"> | ||||
|                                 <template v-if='!value.course.enrolled'> | ||||
|                                     {{text.not_enrolled}} | ||||
|                                     <i v-b-popover.top | ||||
|                                         class="r-course-result fa fa-exclamation-triangle t-not-enrolled-alert" | ||||
|                                         :title="text.student_not_tracked"></i> | ||||
|                                 </template> | ||||
|                                 <template v-else-if='value.course.completion'> | ||||
|                                     {{text['completion_'+value.completion]}} | ||||
|                                     <r-progress-circle v-if='["failed","progress","incomplete"].includes(value.completion)' | ||||
|                                         :value='value.course.completion.progress' | ||||
|                                         :max='value.course.completion.count' | ||||
|                                         :min='0' | ||||
|                                         :title="text['completion_'+value.completion]" | ||||
|                                         :class="'r-progress-circle-popup r-completion-'+value.completion" | ||||
|                                         :icon='circle_icon(value.completion)' | ||||
|                                     ></r-progress-circle | ||||
|                                     ><i v-else v-b-popover.top | ||||
|                                     :class="'fa fa-'+completion_icon(value.completion)+ | ||||
|                                             ' r-progress-icon-popup r-completion-'+value.completion" | ||||
|                                     :title="text['completion_'+value.completion]"></i> | ||||
|                                 </template> | ||||
|                                 <template v-else> | ||||
|                                     {{text['completion_'+value.completion]}} | ||||
|                                     <i  :class="'fa fa-'+completion_icon(value.completion)+' r-completion-'+value.completion" | ||||
|                                         :title="text['completion_'+value.completion]"></i> | ||||
|                                 </template> | ||||
|                     <template #modal-header > | ||||
|                         <div class="r-item-course-header-details"> | ||||
|                             <div> | ||||
|                                 <h1><a :href="(!guestmode)?('/course/view.php?id='+value.course.id):undefined" target="_blank" | ||||
|                                     ><i class="fa fa-graduation-cap"></i> {{ value.course.fullname }}</a></h1> | ||||
|                                 {{ value.course.context.path.join(" / ")}} | ||||
|                             </div> | ||||
|                             <div :class="'r-timing-'+value.course.timing"> | ||||
|                                 {{text['coursetiming_'+value.course.timing]}}<br> | ||||
|                                 {{ startdate }} - {{ enddate }} | ||||
|                             <div class="r-course-detail-header-right"> | ||||
|                                 <div class="r-completion-detail-header"> | ||||
|                                     <template v-if='!value.course.enrolled'> | ||||
|                                         {{text.not_enrolled}} | ||||
|                                         <i v-b-popover.top | ||||
|                                             class="r-course-result fa fa-exclamation-triangle t-not-enrolled-alert" | ||||
|                                             :title="text.student_not_tracked"></i> | ||||
|                                     </template> | ||||
|                                     <template v-else-if='hasprogressinfo'> | ||||
|                                         <r-progress-circle v-if='["failed", "progress","incomplete"].includes(value.completion)' | ||||
|                                             :value='courseprogress' | ||||
|                                             :max='1' | ||||
|                                             :min='0' | ||||
|                                             :class="'r-course-result r-completion-'+value.completion" | ||||
|                                             :icon='circle_icon(value.completion)' | ||||
|                                             :title="text['completion_'+value.completion]" | ||||
|                                         ></r-progress-circle> | ||||
|                                         <i v-else v-b-popover.top | ||||
|                                             :class="'r-course-result fa fa-'+completion_icon(value.completion)+ | ||||
|                                                     ' r-completion-'+value.completion" | ||||
|                                             :title="text['completion_'+value.completion]"></i> | ||||
|                                     </template> | ||||
|                                     <template v-else> | ||||
|                                         {{text['completion_'+value.completion]}} | ||||
|                                         <i  :class="'fa fa-'+completion_icon(value.completion)+' r-completion-'+value.completion" | ||||
|                                             :title="text['completion_'+value.completion]"></i> | ||||
|                                     </template> | ||||
|                                 </div> | ||||
|                                 <div :class="'r-timing-'+value.course.timing"> | ||||
|                                     {{text['coursetiming_'+value.course.timing]}}<br> | ||||
|                                     {{ startdate }} - {{ enddate }} | ||||
|                                 </div> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                         <s-progress-bar  | ||||
|                             v-if='value.course.showprogressbar && hasprogressinfo' | ||||
|                             v-model="courseprogress" | ||||
|                         ></s-progress-bar> | ||||
|                     </template> | ||||
|                     <s-course-extrafields  | ||||
|                         v-if="value.course.extrafields"  | ||||
|                         v-model="value.course.extrafields" | ||||
|                         position="above" | ||||
|                         ></s-course-extrafields> | ||||
|                     <r-item-studentgrades | ||||
|                         v-if='!!value.course.grades && value.course.grades.length > 0' | ||||
|                         v-model='value' | ||||
|  | @ -1261,6 +1288,11 @@ export default { | |||
|                         v-model='value.course.competency' | ||||
|                         :item='value' | ||||
|                         ></r-item-student-course-competency> | ||||
|                     <s-course-extrafields  | ||||
|                         v-if="value.course.extrafields"  | ||||
|                         v-model="value.course.extrafields" | ||||
|                         position="below" | ||||
|                         ></s-course-extrafields> | ||||
|                 </b-modal> | ||||
|             </b-card></div> | ||||
|             `,
 | ||||
|  | @ -1958,6 +1990,11 @@ export default { | |||
|                             </div> | ||||
|                         </div> | ||||
|                     </template> | ||||
|                     <s-course-extrafields  | ||||
|                         v-if="value.course.extrafields"  | ||||
|                         v-model="value.course.extrafields" | ||||
|                         position="above" | ||||
|                         ></s-course-extrafields> | ||||
|                     <r-item-teachergrades | ||||
|                         v-if='!!value.course.grades && value.course.grades.length > 0' | ||||
|                         v-model='value.course' | ||||
|  | @ -1973,6 +2010,11 @@ export default { | |||
|                         v-model='value.course.competency' | ||||
|                         :item='value' | ||||
|                         ></r-item-teacher-course-competency> | ||||
|                     <s-course-extrafields  | ||||
|                         v-if="value.course.extrafields"  | ||||
|                         v-model="value.course.extrafields" | ||||
|                         position="below" | ||||
|                         ></s-course-extrafields> | ||||
|                 </b-modal> | ||||
| 
 | ||||
|             </b-card> | ||||
|  | @ -2045,6 +2087,7 @@ export default { | |||
|                                     {{ value.course.startdate }} - {{ value.course.enddate }} | ||||
|                                 </div> | ||||
|                             </div> | ||||
|                             <s- | ||||
|                         </template> | ||||
|                         <b-form-group | ||||
|                             :label="text.select_grades" | ||||
|  |  | |||
|  | @ -152,9 +152,11 @@ export class SimpleLine { | |||
|         this.mutationObserver = new MutationObserver(function(mutations_list) { | ||||
|             mutations_list.forEach(function(mutation) { | ||||
|                 mutation.removedNodes.forEach(function(removed_node) { | ||||
|                     if(removed_node == this.start  || removed_node == this.end) { | ||||
|                         console.warning("Element removed",removed_node); | ||||
|                         this.remove(); | ||||
|                     if (this){ | ||||
|                         if(removed_node == this.start  || removed_node == this.end) { | ||||
|                             console.warning("Element removed",removed_node); | ||||
|                             this.remove(); | ||||
|                         } | ||||
|                     } | ||||
|                 }); | ||||
|             }); | ||||
|  |  | |||
|  | @ -3194,6 +3194,11 @@ export default { | |||
|                         </div> | ||||
|                     </template> | ||||
| 
 | ||||
|                     <s-course-extrafields  | ||||
|                         v-if="value.course.extrafields"  | ||||
|                         v-model="value.course.extrafields" | ||||
|                         position="above" | ||||
|                         ></s-course-extrafields> | ||||
|                     <t-item-course-grades | ||||
|                         v-if='!!value.course.grades && value.course.grades.length > 0' | ||||
|                         v-model='value' :plan="plan" | ||||
|  | @ -3208,7 +3213,11 @@ export default { | |||
|                         v-model='value.course.competency' | ||||
|                         :item='value' | ||||
|                         ></t-item-course-competency> | ||||
| 
 | ||||
|                     <s-course-extrafields  | ||||
|                         v-if="value.course.extrafields"  | ||||
|                         v-model="value.course.extrafields" | ||||
|                         position="below" | ||||
|                         ></s-course-extrafields> | ||||
|                     <template #modal-footer="{ ok, cancel, hide }" > | ||||
|                         <a href='#' @click='$emit("deleterq")' class="text-danger" | ||||
|                             ><i class="fa fa-trash"></i> | ||||
|  |  | |||
|  | @ -21,6 +21,9 @@ export default { | |||
|             }, | ||||
|             details: { | ||||
|                 details: "studyplan_details", | ||||
|             }, | ||||
|             extrafields: { | ||||
|                 show: "show@core" | ||||
|             } | ||||
|         }); | ||||
|         // Create new eventbus for interaction between item components
 | ||||
|  | @ -51,27 +54,7 @@ export default { | |||
|                         end: (dates.end)?format_date(dates.end):this.text.noenddate, | ||||
|                     }; | ||||
|                 }, | ||||
|                 width_completed() { | ||||
|                     if(this.value.progress) { | ||||
|                         return this.value.progress * 100; | ||||
|                     } else { | ||||
|                         return 0; | ||||
|                     } | ||||
|                 }, | ||||
|                 width_incomplete() { | ||||
|                     if(this.value.progress) { | ||||
|                         return (1-this.value.progress) * 100; | ||||
|                     } else { | ||||
|                         return 100; | ||||
|                     } | ||||
|                 }, | ||||
|                 percentage_complete() { | ||||
|                     if(this.value.progress) { | ||||
|                         return Math.round(this.value.progress * 100) + "%"; | ||||
|                     } else { | ||||
|                         return "0%"; | ||||
|                     } | ||||
|                 } | ||||
|                  | ||||
|             }, | ||||
|             methods: { | ||||
|                 onOpenClick(e) { | ||||
|  | @ -97,20 +80,10 @@ export default { | |||
|                         <div class='s-studyplan-card-idnumber' v-if='value.idnumber'> | ||||
|                         {{ text.idnumber }}: {{ value.idnumber }} | ||||
|                         </div> | ||||
|                         <div class='s-studyplan-card-progress' v-if='value.progress !== undefined && value.progress !== null'> | ||||
|                             <div class="s-studyplan-card-progressbar" | ||||
|                             ><span v-if="width_completed > 0" | ||||
|                                    :style="{width: width_completed+'%'}" | ||||
|                                    class='s-studyplan-card-progress-segment s-studyplan-card-progress-completed' | ||||
|                             ></span | ||||
|                             ><span :style="{width: width_incomplete+'%'}" | ||||
|                                    class='s-studyplan-card-progress-segment s-studyplan-card-progress-incomplete' | ||||
|                             ></span | ||||
|                             ></div> | ||||
|                             <div class="s-studyplan-card-progresstext"> | ||||
|                                 {{ percentage_complete}} {{ text.completed.toLowerCase() }}  | ||||
|                             </div> | ||||
|                         </div> | ||||
|                         <s-progress-bar  | ||||
|                             v-if='value.progress !== undefined && value.progress !== null' | ||||
|                             v-model="value.progress" | ||||
|                         ></s-progress-bar> | ||||
|                     </div> | ||||
|                      | ||||
|                 </div> | ||||
|  | @ -131,6 +104,71 @@ export default { | |||
|             `,
 | ||||
|         }); | ||||
| 
 | ||||
|         Vue.component('s-progress-bar', { | ||||
|             props: { | ||||
|                 value: { | ||||
|                     type: Number,  | ||||
|                 }, | ||||
|                 min: { | ||||
|                     type: Number, | ||||
|                     default() { return 0;} | ||||
|                 }, | ||||
|                 max: { | ||||
|                     type: Number, | ||||
|                     default() { return 1;} | ||||
|                 } | ||||
|             }, | ||||
|             data() { | ||||
|                 return { | ||||
|                     text: strings.studyplancard | ||||
|                 }; | ||||
|             }, | ||||
|             computed: { | ||||
|                 width_completed() { | ||||
|                     if(this.value) { | ||||
|                         const v = ( (this.value - this.min) / (this.max - this.min)); | ||||
|                         return v * 100; | ||||
|                     } else { | ||||
|                         return 0; | ||||
|                     } | ||||
|                 }, | ||||
|                 width_incomplete() { | ||||
|                     if(this.value) { | ||||
|                         const v = ( (this.value - this.min) / (this.max - this.min)); | ||||
|                         return (1-v) * 100; | ||||
|                     } else { | ||||
|                         return 100; | ||||
|                     } | ||||
|                 }, | ||||
|                 percentage_complete() { | ||||
|                     if(this.value) { | ||||
|                         const v = ( (this.value - this.min) / (this.max - this.min)); | ||||
|                         return Math.round(v * 100) + "%"; | ||||
|                     } else { | ||||
|                         return "0%"; | ||||
|                     } | ||||
|                 } | ||||
|             }, | ||||
|             template: ` | ||||
|             <div class='s-studyplan-card-progress' > | ||||
|                 <div class="s-studyplan-card-progressbar" | ||||
|                 ><span v-if="width_completed > 0" | ||||
|                     :style="{width: width_completed+'%'}" | ||||
|                     class='s-studyplan-card-progress-segment s-studyplan-card-progress-completed' | ||||
|                 ></span | ||||
|                 ><span :style="{width: width_incomplete+'%'}" | ||||
|                     class='s-studyplan-card-progress-segment s-studyplan-card-progress-incomplete' | ||||
|                 ></span | ||||
|                 ></div> | ||||
|                 <div class="s-studyplan-card-progresstext"> | ||||
|                     {{ percentage_complete}} {{ text.completed.toLowerCase() }}  | ||||
|                 </div> | ||||
|         </div> | ||||
|             `,
 | ||||
|         }); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|         /* | ||||
|         * S-STUDYLINE-HEADER-HEADING | ||||
|         * The only reasing this is not a simple empty div, is the fact that the header height | ||||
|  | @ -293,5 +331,73 @@ export default { | |||
|             `,
 | ||||
|         }); | ||||
| 
 | ||||
|         Vue.component('s-course-extrafields', { | ||||
|             props: { | ||||
|                 value: { | ||||
|                     type: Array,  | ||||
|                 }, | ||||
|                 variant: { | ||||
|                     type: String, | ||||
|                     default() { return "info"; } | ||||
|                 }, | ||||
|                 position: { | ||||
|                     type: String, | ||||
|                     default() { return "below"; } | ||||
|                 }, | ||||
|                 size: { | ||||
|                     type: String, | ||||
|                     default() { return "";} | ||||
|                 } | ||||
|             }, | ||||
|             data() { | ||||
|                 return { | ||||
|                     text: strings.extrafields, | ||||
|                 }; | ||||
|             }, | ||||
|             computed: { | ||||
|                 fields() { | ||||
|                     const fields = []; | ||||
|                     for (const ix in this.value) { | ||||
|                         const field = this.value[ix]; | ||||
|                         if (field.position == this.position && field.value && field.value.length > 0) { | ||||
|                             fields.push(field); | ||||
|                         } | ||||
|                     } | ||||
|                     return fields; | ||||
|                 }, | ||||
|             }, | ||||
|             methods: { | ||||
|                 displaydate(field) { | ||||
|                     return format_date(field.value,false); | ||||
|                 }, | ||||
|             }, | ||||
|             template: ` | ||||
|             <div :class="'s-course-extrafields ' + ((fields.length>0)?position:'empty')"> | ||||
|                 <table v-if="fields.length > 0"> | ||||
|                     <tr v-for="field in fields"> | ||||
|                         <td><span class='title' v-if='field.title'>{{ field.title}}</span></td> | ||||
|                         <td> | ||||
|                         <span v-if='field.type == "date"' class="value date">{{ displaydate(field) }}</span> | ||||
|                         <span v-else-if='field.type == "checkbox"'  | ||||
|                         :class="'value ' + (field.checked?'true':'false')">{{ field.value }}</span> | ||||
|                         <span v-else-if='field.type == "textarea"'> | ||||
|                             <a class='text-info' href='#' v-b-modal="field.courseid+'_'+field.fieldname">{{text.show}}...</a> | ||||
|                             <b-modal | ||||
|                                 :id="field.courseid+'_'+field.fieldname" | ||||
|                                 :title="field.title"" | ||||
|                                 scrollable | ||||
|                                 centered | ||||
|                                 ok-only | ||||
|                                 ><span v-html="field.value"></span | ||||
|                             ></b-modal> | ||||
|                         </span> | ||||
|                         <span v-else class="value"><span v-html="field.value"></span></span> | ||||
|                         </td> | ||||
|                     </tr> | ||||
|                 </table> | ||||
|             </div> | ||||
|             `,
 | ||||
|         }); | ||||
| 
 | ||||
|     } | ||||
| }; | ||||
|  | @ -10,8 +10,10 @@ export function format_date(d,short){ | |||
|     } | ||||
| 
 | ||||
|     let monthformat = "short"; | ||||
|     if(short){ | ||||
|     if(short === true){ | ||||
|         monthformat = "numeric"; | ||||
|     } else if (short === false) { | ||||
|         monthformat = "long"; | ||||
|     } | ||||
|     return d.toLocaleDateString(document.documentElement.lang,{ | ||||
|         year: 'numeric', month: monthformat, day: 'numeric' | ||||
|  |  | |||
|  | @ -768,9 +768,6 @@ class badgeinfo { | |||
|                 INNER JOIN {badge_criteria_param} p on p.critid = crit.id | ||||
|                 WHERE p.value = :courseid AND crit.criteriatype $ctypesql $conditions";
 | ||||
| 
 | ||||
|         debug::write("Sql query courses: "); | ||||
|         debug::write($sql); | ||||
|         debug::print_r($sqlparams); | ||||
| 
 | ||||
|         $courserelids = $DB->get_fieldset_sql($sql, $sqlparams); | ||||
| 
 | ||||
|  | @ -782,9 +779,6 @@ class badgeinfo { | |||
|             INNER JOIN {competency_coursecomp} cc on cc.competencyid = p.value | ||||
|             WHERE cc.courseid = :courseid AND crit.criteriatype $ctypesql $conditions";
 | ||||
| 
 | ||||
|         debug::write("Sql query through competencies: "); | ||||
|         debug::write($sql); | ||||
|         debug::print_r($sqlparams); | ||||
| 
 | ||||
|         $competencyrelids = $DB->get_fieldset_sql($sql,$sqlparams); | ||||
|          | ||||
|  |  | |||
|  | @ -219,6 +219,11 @@ class courseinfo { | |||
|             if (strlen($idnumber) > 0) { | ||||
|                 return $this->course->idnumber; | ||||
|             } | ||||
|         } else if ($displayfield == "fullname") { | ||||
|             $fullname = trim(preg_replace("/\s+/u", " ", $this->course->fullname)); | ||||
|             if (strlen($fullname) > 0) { | ||||
|                 return $fullname; | ||||
|             } | ||||
|         } else if (strpos( $displayfield , "customfield_") === 0) { | ||||
|             $fieldname = substr($displayfield, strlen("customfield_")); | ||||
| 
 | ||||
|  | @ -292,7 +297,7 @@ class courseinfo { | |||
|             "canselectgradables" => new \external_value(PARAM_BOOL, 'Requesting user can change selected gradables'), | ||||
|             "numenrolled" => new \external_value(PARAM_INT, 'number of students from this studyplan enrolled in the course'), | ||||
|             "tag" => new \external_value(PARAM_TEXT, 'Tag'), | ||||
|             "extrafields" => self::extrafields_structure(); | ||||
|             "extrafields" => self::extrafields_structure(), | ||||
|         ], 'referenced course information', $value); | ||||
|     } | ||||
| 
 | ||||
|  | @ -319,16 +324,15 @@ class courseinfo { | |||
|             'context' => $contextinfo->model(), | ||||
|             'ctxid' => $this->coursecontext->id, | ||||
|             'timing' => $timing, | ||||
|             'startdate' => date("Y-m-d", $this->course->startdate, ), | ||||
|             'startdate' => date("Y-m-d", $this->course->startdate), | ||||
|             'enddate' => date("Y-m-d", $this->course->enddate), | ||||
|             'amteacher' => $this->am_teacher(), | ||||
|             'canupdatecourse' => \has_capability("moodle/course:update", $this->coursecontext), | ||||
|             'canselectgradables' => $this->i_can_select_gradables(), | ||||
|             'tag' => "Editormodel", | ||||
|             'extrafields' => $this->extrafields_model(), | ||||
|             'extrafields' => $this->extrafields_model(true), | ||||
|             'grades' => [], | ||||
|             'numenrolled' => $numenrolled, | ||||
| 
 | ||||
|         ]; | ||||
| 
 | ||||
|         if (isset($this->studyitem)) { | ||||
|  | @ -373,7 +377,8 @@ class courseinfo { | |||
|             "startdate" => new \external_value(PARAM_TEXT, 'Course start date'), | ||||
|             "enddate" => new \external_value(PARAM_TEXT, 'Course end date'), | ||||
|             "enrolled" => new \external_value(PARAM_BOOL, 'True if student is enrolled as student in this course'), | ||||
|             "extrafields" => self::extrafields_structure(); | ||||
|             "extrafields" => self::extrafields_structure(), | ||||
|             "showprogressbar" => new \external_value(PARAM_BOOL, "Whether to show the progress bar in the header"), | ||||
|         ], 'course information', $value); | ||||
|     } | ||||
| 
 | ||||
|  | @ -450,6 +455,7 @@ class courseinfo { | |||
|             'grades' => [], | ||||
|             'enrolled' => $this->is_enrolled_student($userid), | ||||
|             'extrafields' => $this->extrafields_model(), | ||||
|             'showprogressbar' => get_config("local_treestudyplan","courseprogressbar"), | ||||
|         ]; | ||||
| 
 | ||||
| 
 | ||||
|  | @ -485,27 +491,37 @@ class courseinfo { | |||
|             "value" => new \external_value(PARAM_RAW, 'value'), | ||||
|             "position" => new \external_value(PARAM_TEXT, 'position'), | ||||
|             "type" => new \external_value(PARAM_TEXT, 'value type'), | ||||
|             "fieldname" => new \external_value(PARAM_TEXT, 'field name'), | ||||
|             "checked" => new \external_value(PARAM_BOOL, 'checkbox value',VALUE_OPTIONAL), | ||||
|             "courseid" => new \external_value(PARAM_TEXT, 'course id number'), | ||||
|         ], 'referenced course information'), $value); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Webservice model for basic info | ||||
|      * @param $includeteachervisible Include custom fiel | ||||
|      * @return array Webservice data model | ||||
|      */ | ||||
|     public function extrafields_model() { | ||||
|     public function extrafields_model($includeteachervisible=false) { | ||||
|         $list = []; | ||||
|         for ($i=1; $i <= 5; $i++) { | ||||
|             $field = get_config('local_treestudyplan','courseinfo'.$i.'_field'); | ||||
|             $title = self::extrafields_localize_title(get_config('local_treestudyplan','courseinfo'.$i.'_title')); | ||||
|             $pos = get_config('local_treestudyplan','courseinfo'.$i.'_position'); | ||||
|             [$value,$type] = $this->extrafields_value($field); | ||||
|             $list[] = [ | ||||
|                 "title" => $title, | ||||
|                 "value" => $value, | ||||
|                 "position" => $pos, | ||||
|                 "type" => $type, | ||||
|             ]; | ||||
| 
 | ||||
|             if ($field) { | ||||
|                 $title = self::extrafields_localize_title(get_config('local_treestudyplan','courseinfo'.$i.'_title')); | ||||
|                 $pos = get_config('local_treestudyplan','courseinfo'.$i.'_position'); | ||||
|                 [$value,$type, $raw] = $this->extrafields_value($field,$includeteachervisible); | ||||
|                 if ($type) { | ||||
|                     $list[] = [ | ||||
|                         "title" => $title, | ||||
|                         "value" => $value, | ||||
|                         "position" => $pos, | ||||
|                         "type" => $type, | ||||
|                         "fieldname" => $field, | ||||
|                         "courseid" => $this->course->id, | ||||
|                         "checked" => ($type=="checkbox")?($raw?true:false):null, | ||||
|                     ]; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return $list; | ||||
|     } | ||||
|  | @ -514,33 +530,51 @@ class courseinfo { | |||
|         $lang = trim(current_language()); | ||||
|         $lines = explode("\n",$field); | ||||
|         $title = ""; | ||||
|         $fallback = ""; // Fallback to first title
 | ||||
|         foreach ($lines as $l) { | ||||
|             $parts = explode("|",$l,2); | ||||
|             if (count($parts) > 0) { | ||||
|                 // Set the first line as fallback.
 | ||||
|                 if (empty($firsttitle) && !empty($parts[0])) { | ||||
|                     $fallback = $parts[0]; | ||||
|                 } | ||||
|                 if (count($parts) == 1 && empty($title)) { | ||||
|                     // Set line without language as default if no localized line found
 | ||||
|                     $title = trim($parts[0]); | ||||
|                 } | ||||
|                 else if (trim($parts[1]) == $lang) { | ||||
|                 } else if (trim($parts[1]) == $lang) { | ||||
|                     return trim($parts[0]); | ||||
|                 } | ||||
|                 }  | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return $title; | ||||
|         // Return default title or fall back to first localizef title.
 | ||||
|         return (strlen($title) > 0)?$title:$fallback; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Determine value and type of an extra field for this course | ||||
|      * @return array [value,type] of the field for this  | ||||
|      */ | ||||
|     protected function extrafields_value($fieldname) { | ||||
|         $fieldname = get_config("local_treestudyplan", "display_field"); | ||||
|     protected function extrafields_value($fieldname,$includeteachervisible=false) { | ||||
|          | ||||
|         if ($fieldname == "description") { | ||||
|             return [$this->course()->description, "textarea"]; | ||||
|             // Process embedded files.
 | ||||
|             $value = \file_rewrite_pluginfile_urls( | ||||
|                 // The description content
 | ||||
|                 $this->course()->summary, | ||||
|                 // The pluginfile URL which will serve the request.
 | ||||
|                 'pluginfile.php', | ||||
|                 // The combination of contextid / component / filearea / itemid
 | ||||
|                 // form the virtual bucket that file are stored in.
 | ||||
|                 $this->coursecontext->id, // System instance is always used for this
 | ||||
|                 'course', | ||||
|                 'summary', | ||||
|                 '' | ||||
|             ); | ||||
|             return [$value, "textarea", $this->course()->summary]; | ||||
|         } else if ($fieldname == "idnumber") { | ||||
|             $idnumber = trim(preg_replace("/\s+/u", " ", $this->course->idnumber)); | ||||
|             return [$idnumber, "text"]; | ||||
|             return [$idnumber, "text", $this->course->idnumber]; | ||||
|         }  else if ($fieldname == "contacts") { | ||||
|             $cle = new \core_course_list_element($this->course()); | ||||
|             $contacts = $cle->get_course_contacts(); | ||||
|  | @ -552,24 +586,41 @@ class courseinfo { | |||
|                 $value .= $contact["username"] . "(".$contact["role"]["name"].")"; | ||||
|             } | ||||
| 
 | ||||
|             return [$value, "text"]; | ||||
|             return [$value, "text", $value]; | ||||
|         }  else if (strpos( $fieldname , "customfield_") === 0) { | ||||
|             $fieldname = substr($fieldname, strlen("customfield_")); | ||||
|             $fieldshortname = substr($fieldname, strlen("customfield_")); | ||||
| 
 | ||||
|             $handler = \core_customfield\handler::get_handler('core_course', 'course'); | ||||
|             $datas = $handler->get_instance_data($this->course->id); | ||||
|             foreach ($datas as $data) { | ||||
|                 $field = $data->get_field(); | ||||
|                 if ($field->get('shortname') == $fieldname) { | ||||
|                     $value = trim(preg_replace("/\s+/u", " ", $data->get_value())); | ||||
|                 $fshortname = $field->get('shortname'); | ||||
|                 if ($fshortname == $fieldshortname) { | ||||
|                     $visibility = $field->get_configdata_property("visibility"); | ||||
|                     $raw = $data->get_value(); | ||||
|                     $type = $field->get('type'); | ||||
|                     if (strlen($value) > 0) { | ||||
|                         return [$value,$type]; | ||||
| 
 | ||||
|                     // Only show if visibility is "Everyone" or ("Teachers" and in teacher view )
 | ||||
|                     if ($visibility > 0 && ($visibility == 2 || $includeteachervisible)) { | ||||
|                         if ($type == "date") { | ||||
|                             // Date should be converted to YYYY-MM-DD so the javascript can properly format it.
 | ||||
|                             if ($raw == 0) { | ||||
|                                 $value = ""; | ||||
|                             } else { | ||||
|                                 // Convert to YYYY-MM-DD format.
 | ||||
|                                 $value = date("Y-m-d", $raw);  | ||||
|                             } | ||||
|                         } else { | ||||
|                             // Everything else can just use the export value.
 | ||||
|                             $value = $data->export_value(); | ||||
|                         } | ||||
| 
 | ||||
|                         return [$value,$type,$raw]; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         // Fallback to shortname when the specified display field fails, since shortname is never empty.
 | ||||
|         return ["",""]; | ||||
|         // Fallback to empty if finding a match fails.
 | ||||
|         return [null,null,null]; | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -407,7 +407,6 @@ class studentstudyplanservice extends \external_api { | |||
| 
 | ||||
|         if ($studyplan->exist_for_user($userid)) { | ||||
|            $model = $studyplan->user_model($userid); | ||||
|            debug::dump($model); | ||||
|            return $model; | ||||
|         } else { | ||||
|             throw new \moodle_exception("You do not have access to this studyplan"); | ||||
|  |  | |||
|  | @ -1336,6 +1336,25 @@ | |||
| .features-treestudyplan table.r-item-course-competency-list td { | ||||
|     padding-right: 1em; | ||||
| } | ||||
| .path-local-treestudyplan header.modal-header.r-item-course-header, | ||||
| .features-treestudyplan header.modal-header.r-item-course-header { | ||||
|     display: block; | ||||
|     padding-bottom: 0.2rem; | ||||
| } | ||||
| .path-local-treestudyplan header.modal-header.r-item-course-header .s-studyplan-card-progressbar, | ||||
| .features-treestudyplan header.modal-header.r-item-course-header .s-studyplan-card-progressbar { | ||||
|     margin-top: 0.5em; | ||||
| } | ||||
| .path-local-treestudyplan div.r-item-course-header-details, | ||||
| .features-treestudyplan div.r-item-course-header-details { | ||||
|     display: flex; | ||||
|     align-items: flex-start; | ||||
|     justify-content: space-between; | ||||
| } | ||||
| .path-local-treestudyplan div.r-item-course-header-details:last-child, | ||||
| .features-treestudyplan div.r-item-course-header-details:last-child { | ||||
|     margin-bottom: 0.3rem; | ||||
| } | ||||
| 
 | ||||
| .path-local-treestudyplan .card.s-studyplan-card, | ||||
| .features-treestudyplan .card.s-studyplan-card { | ||||
|  | @ -1467,6 +1486,31 @@ | |||
|     width: 128px; | ||||
|     height: 128px; | ||||
| } | ||||
| .path-local-treestudyplan .s-course-extrafields.above, | ||||
| .features-treestudyplan .s-course-extrafields.above { | ||||
|     border-bottom: 1px solid #dee2e6; | ||||
|     padding-bottom: 0.5em; | ||||
|     margin-bottom: 0.5em; | ||||
| } | ||||
| .path-local-treestudyplan .s-course-extrafields.below, | ||||
| .features-treestudyplan .s-course-extrafields.below { | ||||
|     border-top: 1px solid #dee2e6; | ||||
|     padding-top: 0.5em; | ||||
|     margin-top: 0.5em; | ||||
| } | ||||
| .path-local-treestudyplan .s-course-extrafields .title, | ||||
| .features-treestudyplan .s-course-extrafields .title { | ||||
|     font-weight: bold; | ||||
|     padding-right: 1em; | ||||
| } | ||||
| .path-local-treestudyplan .s-course-extrafields .value.true, | ||||
| .features-treestudyplan .s-course-extrafields .value.true { | ||||
|     color: var(--success); | ||||
| } | ||||
| .path-local-treestudyplan .s-course-extrafields .value.false, | ||||
| .features-treestudyplan .s-course-extrafields .value.false { | ||||
|     color: var(--danger); | ||||
| } | ||||
| 
 | ||||
| .path-local-treestudyplan .b-modal-justify-footer-between .modal-footer, | ||||
| .features-treestudyplan .b-modal-justify-footer-between .modal-footer { | ||||
|  |  | |||
|  | @ -1150,4 +1150,21 @@ | |||
| 
 | ||||
|     }     | ||||
| 
 | ||||
|     header.modal-header.r-item-course-header { | ||||
|         display: block; | ||||
|         .s-studyplan-card-progressbar { | ||||
|             margin-top: 0.5em; | ||||
|         } | ||||
|         padding-bottom: 0.2rem; | ||||
|     } | ||||
| 
 | ||||
|     div.r-item-course-header-details { | ||||
|         display: flex; | ||||
|         align-items: flex-start; | ||||
|         justify-content: space-between; | ||||
|         &:last-child { | ||||
|             margin-bottom: 0.3rem; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -129,4 +129,35 @@ | |||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     .s-course-extrafields { | ||||
|         &.above { | ||||
|             border-bottom: 1px solid #dee2e6; | ||||
|             padding-bottom: 0.5em; | ||||
|             margin-bottom: 0.5em; | ||||
|         } | ||||
| 
 | ||||
|         &.below { | ||||
|             border-top: 1px solid #dee2e6; | ||||
|             padding-top: 0.5em; | ||||
|             margin-top: 0.5em; | ||||
|         } | ||||
| 
 | ||||
|         .title { | ||||
|             font-weight: bold; | ||||
|             padding-right: 1em; | ||||
|         } | ||||
| 
 | ||||
|         .value { | ||||
|             &.true { | ||||
|                 color: var(--success); | ||||
|             } | ||||
|             &.false { | ||||
|                 color: var(--danger); | ||||
|             } | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										16
									
								
								settings.php
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								settings.php
									
									
									
									
									
								
							|  | @ -88,17 +88,21 @@ if ($hassiteconfig) { | |||
|         get_string('settingdesc_display_heading', 'local_treestudyplan') | ||||
|     )); | ||||
| 
 | ||||
|     $displayfields = ["shortname" => get_string("shortname"), "idnumber" => get_string("idnumber")]; | ||||
|     $displayfields = ["shortname" => get_string("shortname"), "idnumber" => get_string("idnumber"), "fullname" => get_string("fullname"), ]; | ||||
|     $infofields = ["" => get_string('none'), "description" => get_string("description"), "contacts" => get_string("teachers"), "idnumber" => get_string("idnumber")]; | ||||
|     $handler = \core_customfield\handler::get_handler('core_course', 'course'); | ||||
| 
 | ||||
|     foreach ($handler->get_categories_with_fields() as $cat) { | ||||
|         $catname = $cat->get_formatted_name(); | ||||
|         foreach ($cat->get_fields() as $field) { | ||||
|             $fieldname = $field->get_formatted_name(); | ||||
|             $fieldid = $field->get("shortname"); | ||||
|             $displayfields["customfield_".$fieldid] = $catname.": ".$fieldname; | ||||
|             $infofields["customfield_".$fieldid] = $catname.": ".$fieldname; | ||||
|             $visibility = $field->get_configdata_property("visibility"); | ||||
|             if ($visibility > 0) { | ||||
|                 // Only include fields that are visible to Teachers, or Everyone.
 | ||||
|                 $fieldname = $field->get_formatted_name(); | ||||
|                 $fieldid = $field->get("shortname"); | ||||
|                 $displayfields["customfield_".$fieldid] = $catname.": ".$fieldname; | ||||
|                 $infofields["customfield_".$fieldid] = $catname.": ".$fieldname; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -122,8 +126,6 @@ if ($hassiteconfig) { | |||
| 
 | ||||
|     $positions = [  "above" => get_string('infofield_position_above', 'local_treestudyplan'),  | ||||
|                     "below" => get_string("infofield_position_below", 'local_treestudyplan'),  | ||||
|                     "header" => get_string("infofield_position_header", 'local_treestudyplan'), | ||||
|                     "footer" => get_string("infofield_position_footer", 'local_treestudyplan') | ||||
|                 ]; | ||||
| 
 | ||||
|     for ($i=1;$i<=5;$i++) { | ||||
|  |  | |||
							
								
								
									
										44
									
								
								styles.css
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								styles.css
									
									
									
									
									
								
							|  | @ -1336,6 +1336,25 @@ | |||
| .features-treestudyplan table.r-item-course-competency-list td { | ||||
|     padding-right: 1em; | ||||
| } | ||||
| .path-local-treestudyplan header.modal-header.r-item-course-header, | ||||
| .features-treestudyplan header.modal-header.r-item-course-header { | ||||
|     display: block; | ||||
|     padding-bottom: 0.2rem; | ||||
| } | ||||
| .path-local-treestudyplan header.modal-header.r-item-course-header .s-studyplan-card-progressbar, | ||||
| .features-treestudyplan header.modal-header.r-item-course-header .s-studyplan-card-progressbar { | ||||
|     margin-top: 0.5em; | ||||
| } | ||||
| .path-local-treestudyplan div.r-item-course-header-details, | ||||
| .features-treestudyplan div.r-item-course-header-details { | ||||
|     display: flex; | ||||
|     align-items: flex-start; | ||||
|     justify-content: space-between; | ||||
| } | ||||
| .path-local-treestudyplan div.r-item-course-header-details:last-child, | ||||
| .features-treestudyplan div.r-item-course-header-details:last-child { | ||||
|     margin-bottom: 0.3rem; | ||||
| } | ||||
| 
 | ||||
| .path-local-treestudyplan .card.s-studyplan-card, | ||||
| .features-treestudyplan .card.s-studyplan-card { | ||||
|  | @ -1467,6 +1486,31 @@ | |||
|     width: 128px; | ||||
|     height: 128px; | ||||
| } | ||||
| .path-local-treestudyplan .s-course-extrafields.above, | ||||
| .features-treestudyplan .s-course-extrafields.above { | ||||
|     border-bottom: 1px solid #dee2e6; | ||||
|     padding-bottom: 0.5em; | ||||
|     margin-bottom: 0.5em; | ||||
| } | ||||
| .path-local-treestudyplan .s-course-extrafields.below, | ||||
| .features-treestudyplan .s-course-extrafields.below { | ||||
|     border-top: 1px solid #dee2e6; | ||||
|     padding-top: 0.5em; | ||||
|     margin-top: 0.5em; | ||||
| } | ||||
| .path-local-treestudyplan .s-course-extrafields .title, | ||||
| .features-treestudyplan .s-course-extrafields .title { | ||||
|     font-weight: bold; | ||||
|     padding-right: 1em; | ||||
| } | ||||
| .path-local-treestudyplan .s-course-extrafields .value.true, | ||||
| .features-treestudyplan .s-course-extrafields .value.true { | ||||
|     color: var(--success); | ||||
| } | ||||
| .path-local-treestudyplan .s-course-extrafields .value.false, | ||||
| .features-treestudyplan .s-course-extrafields .value.false { | ||||
|     color: var(--danger); | ||||
| } | ||||
| 
 | ||||
| .path-local-treestudyplan .b-modal-justify-footer-between .modal-footer, | ||||
| .features-treestudyplan .b-modal-justify-footer-between .modal-footer { | ||||
|  |  | |||
		Reference in a new issue
	
	 PMKuipers
						PMKuipers