Compare commits

...

198 Commits

Author SHA1 Message Date
PMKuipers
5e3d610451 Switched to moodle param validation 2024-11-01 18:03:44 +01:00
PMKuipers
6b707cc595 Removed custom debugger 2024-11-01 13:08:28 +01:00
PMKuipers
108a612e8c Removed PHP code from language file. 2024-11-01 12:56:41 +01:00
PMKuipers
9988ed1a3d Cleanup 2024-11-01 12:43:44 +01:00
PMKuipers
8c1be03e5d Cleanup 2024-08-30 12:42:52 +02:00
PMKuipers
95fabecc60 Reintroduced hiding in user navigation, just in case someone wants to put the links there.... 2024-08-29 00:19:28 +02:00
PMKuipers
9737398629 Version bump 2024-08-29 00:17:05 +02:00
PMKuipers
bc774533f4 fix for hiding navigation links 2024-08-29 00:16:33 +02:00
PMKuipers
6518e00a31 Build script tweak and version bump 2024-08-25 21:46:11 +02:00
PMKuipers
d5b8d8993a Version bump 2024-08-22 10:46:38 +02:00
PMKuipers
1eb862a3ea Ensured all available contexts are listed in the edit form 2024-08-22 10:46:32 +02:00
PMKuipers
b0a61d018c Fixed minor issue with sidebar not always loading 2024-08-20 17:58:57 +02:00
PMKuipers
a00af55f66 Added comment 2024-08-20 17:58:46 +02:00
PMKuipers
b5e8033680 Enlarged the width of periods in pages having only 1, 2 or 3 periods. 2024-08-15 15:10:54 +02:00
PMKuipers
65c9537bd3 Disabled display of student name when only one student is in the plan 2024-08-15 14:41:43 +02:00
PMKuipers
9c89038baa Navigation hiding of non-accessible links now works in drawer menu too 2024-08-15 14:15:39 +02:00
PMKuipers
de57dc063c fixed layout issues 2024-08-15 12:36:11 +02:00
PMKuipers
1e4f399baf Update to transition system 2024-08-15 10:57:51 +02:00
PMKuipers
743cb82cc9 Fixed appear disappear of sidebar not going properly 2024-08-15 09:47:40 +02:00
PMKuipers
fd9d50873e Added some config features for display 2024-08-14 12:17:55 +02:00
PMKuipers
13523670cb Added option to remove arrow buttons 2024-08-08 19:27:51 +02:00
PMKuipers
a9595974bb Added function to hide badges and flow from toolbox. Also respects the enable badges settings in moodle core 2024-08-08 12:59:34 +02:00
PMKuipers
b1c6ddd665 Removed some leftover text 2024-08-08 12:24:19 +02:00
PMKuipers
073e8e0b28 Changed invited page to force guest login (even when disabled) instead of no login at all 2024-08-08 12:23:54 +02:00
PMKuipers
8299d4c9d1 Fixed coach disassociation not giving visual result in front end 2024-08-08 12:22:34 +02:00
PMKuipers
53be9d3cce Minified rebuild 2024-07-19 17:52:16 +02:00
PMKuipers
0f8d6d8a59 Some cleanup 2024-07-19 17:48:21 +02:00
PMKuipers
fbe34189f6 Removed non-functional premium handling code. All features now normally available. 2024-07-19 17:41:49 +02:00
PMKuipers
30fb9dd149 Code cleanup 2024-07-19 14:38:29 +02:00
PMKuipers
c2c5383e10 Code Cleanup 2024-07-19 14:26:08 +02:00
PMKuipers
3bef1118b2 Code style fixes 2024-07-19 12:31:26 +02:00
PMKuipers
1b89bb87a6 Fix for typo in code cleanup 2024-07-10 19:39:05 +02:00
PMKuipers
ae8f2b6841 FIxed bugs from code style fix 2024-07-10 09:08:12 +02:00
PMKuipers
31c4e758ea Cleanup bug fixed 2024-07-04 12:24:04 +02:00
PMKuipers
8adaf04cd3 Version bump 2024-06-28 17:28:05 +02:00
PMKuipers
4cc04371a0 Fixed minor bug caused by code style cleanup 2024-06-28 17:27:56 +02:00
PMKuipers
675455630d Disabled premium check for now 2024-06-28 17:27:17 +02:00
PMKuipers
9b4ead935e Removed unused component 2024-06-28 17:26:45 +02:00
PMKuipers
e6307a9308 Minor ui fix 2024-06-12 21:19:26 +02:00
PMKuipers
aaa8c79df4 Code cleanup and minor ui fixes 2024-06-12 21:12:00 +02:00
PMKuipers
ba9d58c01d Fixed feedback display 2024-06-05 23:38:38 +02:00
PMKuipers
6b9826934f Cleanup of eslint warnings 2024-06-05 23:27:00 +02:00
PMKuipers
b60e5065f0 Code cleanup of eslint warnings 2024-06-05 22:32:18 +02:00
PMKuipers
46f8575291 Cleanup of eslint warnings 2024-06-05 22:22:19 +02:00
PMKuipers
5c1f21cee0 ESLint Code cleanup 2024-06-03 23:24:16 +02:00
PMKuipers
e999fdb125 Cleanup 2024-06-03 10:51:18 +02:00
PMKuipers
dbb1386b7d Cleanup 2024-06-03 10:48:07 +02:00
PMKuipers
2268aba9d5 Fixed phpdocs 2024-06-03 04:00:46 +02:00
PMKuipers
520034bb5f Tweaks 2024-06-02 23:28:43 +02:00
PMKuipers
64c821bbe9 Completed code guidelines rework 2024-06-02 23:23:32 +02:00
PMKuipers
e72be595aa Code style 2024-06-02 19:23:40 +02:00
PMKuipers
4c669ff08c Code checking - 2024-06-02 18:47:23 +02:00
PMKuipers
ebdb39c5ca Added back button catching 2024-06-02 17:21:30 +02:00
PMKuipers
3d53966b5a Layout tweaks 2024-06-01 14:50:14 +02:00
PMKuipers
8b5cad01f8 Fixed layout of item labels 2024-06-01 14:00:32 +02:00
PMKuipers
742f9ef772 Fixed issue in search for cohorts/users 2024-06-01 08:42:18 +02:00
PMKuipers
3d48f290d6 Tweak to flow control layout 2024-05-31 22:33:10 +02:00
PMKuipers
de8e8199ca Side bar now has proper scrolling 2024-05-31 22:32:43 +02:00
PMKuipers
ee0a9c3d3a Fixed some minor warnings 2024-05-31 20:41:18 +02:00
PMKuipers
4fd1e3a547 Implemented HiViz dropslot big "drop here" feature 2024-05-27 22:11:32 +02:00
PMKuipers
c88f132201 Added hack to limit length of edit screen 2024-05-24 13:16:43 +02:00
PMKuipers
582db40016 Risplay improvements in studyplan overview 2024-05-24 10:42:29 +02:00
PMKuipers
09c6e4b029 Made debug log better able to handle write errors without breaking things for no good reason 2024-05-24 09:30:16 +02:00
PMKuipers
3dd1682f5a style fixes 2024-05-24 09:20:23 +02:00
PMKuipers
ebc3632788 Reworked card view to better handle long course titles 2024-05-23 23:32:59 +02:00
PMKuipers
5dc94a7525 Typo fix 2024-05-22 23:24:06 +02:00
PMKuipers
ff9044ae9a Version bump 2024-05-22 23:19:02 +02:00
PMKuipers
3ba4d4d4c5 Added clauses to exclude deleted users from the queries 2024-05-22 23:18:05 +02:00
PMKuipers
5bd10de529 Cleanup - and added proper check on available coaching studyplans 2024-05-22 22:16:47 +02:00
PMKuipers
39d184c2e9 fixed issue with premium key not properly handling unicode spaces in key wrappers 2024-05-22 21:46:56 +02:00
PMKuipers
50110a3e0f Minor spell checking 2024-05-18 16:55:50 +02:00
PMKuipers
9caf652ff5 Made some code less confusing 2024-05-18 16:48:35 +02:00
PMKuipers
bcb288bac8 Enabled coach progress bar 2024-05-18 16:46:27 +02:00
PMKuipers
9a1b32855f Added IDNumber getter and did some polishing 2024-05-15 22:57:54 +02:00
PMKuipers
c938b994a1 Fixes 2024-05-10 15:22:52 +02:00
PMKuipers
97ce14fe20 Fixed bug with gradebookroles 2024-04-30 10:36:01 +02:00
PMKuipers
be0141eb7b version bump 2024-04-21 23:43:25 +02:00
PMKuipers
12efb061f1 Reworked sidebar 2024-04-21 23:08:03 +02:00
PMKuipers
886a11d99e Added extra warning if no templates are available 2024-04-19 17:01:17 +02:00
PMKuipers
82838c57c5 Added templating function 2024-04-19 16:46:30 +02:00
PMKuipers
2369610903 Fixed issue with recursive scan for categories with a given permission causing system hangup 2024-03-25 23:43:27 +01:00
PMKuipers
88744c2b66 fixed issues with Moodle 3.11 compatibility 2024-03-25 23:42:40 +01:00
PMKuipers
d225d82038 Number of minor changes 2024-03-22 22:01:42 +01:00
PMKuipers
0163471a92 Added course filter 2024-03-11 23:21:59 +01:00
PMKuipers
383c07becd Tweaks to timeless mode 2024-03-10 23:11:54 +01:00
PMKuipers
310f042772 Added option to remove timing from periods 2024-03-10 23:09:33 +01:00
PMKuipers
3002a866bb Added coaching navigation links and enable/disable setting 2024-03-10 21:51:37 +01:00
PMKuipers
747e1decd1 Implemended studyplan suspension 2024-03-10 15:56:35 +01:00
PMKuipers
f2fac43139 Added option to limit course list to studyplan context. Added suspended field in studyplan db table 2024-03-09 23:29:58 +01:00
PMKuipers
7dbcb437c3 Implemented coach view 2024-03-09 22:51:34 +01:00
PMKuipers
6bb13de5cf Removed unneeded minified files 2024-03-09 22:51:14 +01:00
PMKuipers
500555e785 Moved toolbox to studyplan components to better support coaching role 2024-03-09 08:23:42 +01:00
PMKuipers
25a5ff8398 Started work on coaching page 2024-03-09 00:11:42 +01:00
PMKuipers
c480c20098 added coach association to studyplan 2024-03-08 17:05:07 +01:00
PMKuipers
a57ee3d884 Removed debug statements 2024-03-08 16:57:34 +01:00
PMKuipers
35afe06a91 Implemented enrollable lines in cohort and user sync 2024-03-08 11:54:39 +01:00
PMKuipers
d713e24e32 Implemented hiding of non-enrolled lines in student result views 2024-03-07 22:44:29 +01:00
PMKuipers
079e2f77cc Implemented line enrolling management panel 2024-03-06 23:49:50 +01:00
PMKuipers
8938facdef Added proper sorting of time field 2024-03-04 23:05:01 +01:00
PMKuipers
f20a724c52 Prepared sorting of enrolled students list 2024-03-04 23:03:18 +01:00
PMKuipers
d07e6170f3 Updated API functions to yied more useful results 2024-03-04 22:51:51 +01:00
PMKuipers
8382c4a117 Implemented self enrol buttons 2024-03-04 22:39:29 +01:00
PMKuipers
61256207be Minfied files for last commit 2024-03-01 16:06:21 +01:00
PMKuipers
7ea7576ac8 Fix students seeing the result overview links 2024-03-01 16:06:07 +01:00
PMKuipers
1fe4db6328 Added code to edit enrolment config on study lines 2024-02-25 23:45:39 +01:00
PMKuipers
9619fd17de version bump 2024-02-25 16:23:30 +01:00
PMKuipers
247562ecdd Renamed studyplan-report to result-overview 2024-02-24 23:43:57 +01:00
PMKuipers
0efde4a773 Finished full functional prototype of result overview 2024-02-24 23:42:01 +01:00
PMKuipers
8f2673c4a4 Replaced student email by last course access time 2024-02-24 16:09:47 +01:00
PMKuipers
6b616c0a6a Got sorting working and polished up the table view 2024-02-23 23:19:46 +01:00
PMKuipers
b3af1fa8c4 Results display properly 2024-02-23 09:20:10 +01:00
PMKuipers
f8b18d4d6e Update 2024-02-20 20:40:18 +01:00
PMKuipers
ed353540f0 Reworked to use tables. Untested. 2024-02-19 23:50:47 +01:00
PMKuipers
4bb98b73eb Inline doc 2024-02-19 12:18:07 +01:00
PMKuipers
a663a038c7 WIP 2024-02-19 11:34:56 +01:00
PMKuipers
8f6d48b981 WIP 2024-02-19 11:34:40 +01:00
PMKuipers
e1c6d07b2c Typo fix 2024-02-18 23:28:14 +01:00
PMKuipers
1f16c0b1ee Progress on front-end 2024-02-18 23:27:57 +01:00
PMKuipers
9f69b7bc15 Implemented backend for studyplan-reports and start of frontend 2024-02-18 13:47:08 +01:00
PMKuipers
0e4cf45a80 Tweaksed premium backend 2024-02-14 23:34:32 +01:00
PMKuipers
3cf6459ce8 Added premium key option 2024-02-14 23:01:34 +01:00
PMKuipers
dadbd6331f Cleanup 2024-02-09 14:56:41 +01:00
PMKuipers
a717acf4e4 Added foundation for overview report 2024-02-09 14:48:15 +01:00
PMKuipers
e42323a2e4 Untangled study line editing from moodle editmode 2024-02-09 11:15:05 +01:00
PMKuipers
32a09a7c44 Make sure forms are not considered dirty before loading a new page. 2024-02-07 23:10:19 +01:00
PMKuipers
626e2c9aac Fixed bugs in Urls. Simplified category listing functions and fixed bug therein. 2024-02-07 22:33:16 +01:00
PMKuipers
0ec51885a0 Version bump and cleanup 2024-02-05 23:34:16 +01:00
PMKuipers
dfc9f86d1d Bugfixes in access control and tweaked user_tops to properly handle permissions on one category while visiblity is only granted on subcategories of it. 2024-02-05 23:32:22 +01:00
PMKuipers
8aed72af70 Improved category listing and link hiding 2024-02-04 23:18:11 +01:00
PMKuipers
29f11982ff Cleanup 2024-02-03 23:51:12 +01:00
PMKuipers
737da8c051 Implemented custom user-tops and did somestyling in the courses list 2024-02-03 23:50:58 +01:00
PMKuipers
29c8dd9aa4 Fixed some issues with listing categories and other rights issues 2024-02-02 23:36:56 +01:00
PMKuipers
5a88761f22 Fixed badge search and some other things 2024-02-02 23:09:16 +01:00
PMKuipers
9fe71f1800 Implemented student list in viewer grouped by cohort 2024-01-28 22:45:55 +01:00
PMKuipers
2967f4a5bb Replaced studentpicker sidebar by dropdown with arrows 2024-01-28 14:41:35 +01:00
PMKuipers
fd1ab079a1 Fixed highlight of current period not playing nice with courses spanning multiple periods 2024-01-27 16:21:04 +01:00
PMKuipers
546bff0659 Reworked resizing a course to shift collisions down a layer instead of blocking 2024-01-26 23:43:02 +01:00
PMKuipers
d9bcb71a46 Bugfix 2024-01-26 23:42:28 +01:00
PMKuipers
17febe83be Added spinner when loading contexts 2024-01-26 23:42:15 +01:00
PMKuipers
414c900b34 Bugfixes 2024-01-26 12:26:01 +01:00
PMKuipers
88321ec703 Removed debug statement 2023-12-15 21:08:53 +01:00
PMKuipers
6587200239 Fixed student appearing multiple times in search 2023-12-14 22:03:39 +01:00
PMKuipers
7b980405f3 Fixed context switch not working in chrome 2023-12-14 21:42:34 +01:00
PMKuipers
b8c0f910c1 Reworked category selection 2023-12-13 23:49:06 +01:00
PMKuipers
32bab2de5e Fixed lost context bug 2023-12-13 21:19:45 +01:00
PMKuipers
4ca2c875ef Bugfix and simplification in privacy provider 2023-12-13 21:15:49 +01:00
PMKuipers
ad02879928 Bugfixes 2023-12-13 12:22:34 +01:00
PMKuipers
a704436564 Bugfixes in competency display 2023-12-13 00:13:07 +01:00
PMKuipers
de97031326 Fixed context selection bugs 2023-12-12 23:44:02 +01:00
PMKuipers
0de002bf3a Implemented import and export of images 2023-12-12 22:42:37 +01:00
PMKuipers
11c5b0fa8a Minor tweak to help future admins 2023-12-12 00:07:52 +01:00
PMKuipers
43c0af4730 Finished enable/disable setting for studyplan sharing 2023-12-11 23:57:56 +01:00
PMKuipers
f6b53a1623 Fixed bugs in invitation system 2023-12-11 23:52:00 +01:00
PMKuipers
b8a3394fe4 Bugfixes in invitation system 2023-12-11 23:41:03 +01:00
PMKuipers
f3bf55598d Styling tweaks 2023-12-11 22:56:59 +01:00
PMKuipers
bfcd41dd81 Finished custom fields in course popup. Added optional progress bar in course popup bar. Added progress circles to manual aggregation. 2023-12-11 22:30:30 +01:00
PMKuipers
5544d57f6b Added course extra infofields back-end 2023-12-11 09:30:55 +01:00
PMKuipers
c4966de6fd Fix for navigation breaking when students have no view rights on one of the level one categories 2023-12-06 22:28:11 +01:00
PMKuipers
0c459b9a8b Cleanup and Finalized badge search feature 2023-12-02 23:22:00 +01:00
PMKuipers
e092758ff1 Category selected defaults to first one available instead of first with studyplans 2023-12-01 11:14:46 +01:00
PMKuipers
97552704ce Debugging 2023-12-01 11:14:14 +01:00
PMKuipers
41eee1a7aa Tweaked debug tools 2023-12-01 11:13:13 +01:00
PMKuipers
c9d9703a04 Bufgix where checking page progress on an empty page would result in division by sero 2023-12-01 11:12:21 +01:00
PMKuipers
5ca74f8b1a Added userid to user studyplan data 2023-11-27 23:18:55 +01:00
PMKuipers
96caeb895a Implemented teacher view for competencies 2023-11-27 23:11:17 +01:00
PMKuipers
456e9b503e Implemented student view. Added feedback view 2023-11-26 22:58:26 +01:00
PMKuipers
82e92eed45 added service to mark course competency as required in study plan 2023-11-24 23:10:21 +01:00
PMKuipers
932587d2af Better configurable backend for couse competency aggregation 2023-11-24 23:00:53 +01:00
PMKuipers
54a8823bbd Competency backend/frontend 2023-11-23 07:44:04 +01:00
PMKuipers
4a97078405 Polished up my report view 2023-11-13 22:18:28 +01:00
PMKuipers
a208d0023a Lot of work on student view with multiple pages, plans and plan progress 2023-11-12 23:49:50 +01:00
PMKuipers
fe8d8d0a0f Bugfix 2023-11-11 21:13:07 +01:00
PMKuipers
942c02ac40 Fixed bug where lines didn't show on subsequent pages 2023-11-11 20:18:05 +01:00
PMKuipers
c3278f687c Reworked advanced tools 2023-11-11 20:17:45 +01:00
PMKuipers
a60c259408 Finished implementing frontend CRU for pages 2023-11-05 22:33:57 +01:00
PMKuipers
702435566d Updated mform helpers. some work on full page support 2023-11-05 15:49:32 +01:00
PMKuipers
93e174967f Added indicator to student if badge is not available 2023-11-02 07:18:37 +01:00
PMKuipers
24370631ab Added active info for badge 2023-11-01 23:48:47 +01:00
PMKuipers
dd7fa5f620 Polished up badge view for users 2023-11-01 23:47:54 +01:00
PMKuipers
3fcf0095ea Implemented badge subriteria parsing... 2023-10-28 21:49:48 +02:00
PMKuipers
8af1152ae2 Added badge criteria completion structure to user model 2023-10-25 21:49:42 +02:00
PMKuipers
b44e7f2a9f Reworked form bases and added integer text field 2023-10-24 21:55:53 +02:00
PMKuipers
2622b102bf Removed debug option for studyplan progress 2023-10-23 23:19:38 +02:00
PMKuipers
1975952c8f Implemented progress option on studyplan card 2023-10-23 23:19:14 +02:00
PMKuipers
c6882b916a Added icons, finished description editor 2023-10-23 21:54:09 +02:00
PMKuipers
0dda0c6a45 got editor working 2023-10-21 23:24:25 +02:00
PMKuipers
602bb6e0b3 Bugfixes and learning things 2023-10-20 15:08:54 +02:00
PMKuipers
abb74795ca Version bump 2023-10-20 14:04:09 +02:00
PMKuipers
5439f30464 Replaced description part with experimental editor 2023-10-20 14:04:02 +02:00
PMKuipers
77d7d74c2f Implemented descriptionformat in edit function 2023-10-20 14:03:34 +02:00
PMKuipers
324567a2ca Added file storage access 2023-10-20 14:03:13 +02:00
PMKuipers
3c7369ce6b Documentation fix 2023-10-19 17:48:43 +02:00
PMKuipers
f0847a0f14 Added descriptionformat to studyplan class 2023-10-19 17:48:29 +02:00
PMKuipers
1c19a92772 Release name change 2023-10-19 17:39:52 +02:00
PMKuipers
d4e4a8fca9 Minor fix in mfom helper javascript 2023-10-19 17:38:16 +02:00
PMKuipers
49fa4b2ed3 Added mform through ajax features to support rich editor for studyplan description 2023-10-19 17:35:51 +02:00
PMKuipers
2a642f33c8 Added field for studyplan description format to support rich editor 2023-10-19 17:35:08 +02:00
PMKuipers
bcc3cb5a2c Dev for rich edit in studyplan description 2023-10-18 08:46:44 +02:00
206 changed files with 21401 additions and 5686 deletions

10
.vscode/settings.json vendored
View File

@ -2,5 +2,13 @@
"intelephense.environment.includePaths": [
"/srv/moodle4/moodle"
],
"intelephense.diagnostics.undefinedProperties": false
"intelephense.diagnostics.undefinedProperties": false,
"spellright.language": [
"en"
],
"spellright.documentTypes": [
"markdown",
"latex",
"plaintext"
]
}

View File

@ -1,3 +1,4 @@
/* eslint no-console: "off" */
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
@ -16,13 +17,16 @@
/* eslint-env node */
/**
* Grunt configuration for local_treestudyplan
* Grunt configuration for local_treestudyplan.
* Note that currently on the 4.1 developement environment, the method described
* on https://moodledev.io/general/development/tools/nodejs#using-grunt-in-additional-plugins
* is not working as expected. Once development environment is changed to 4.3 or 4.4 I will
* try this again.
*
* @copyright 2023 P.M. Kuipers
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Grunt configuration.
*
@ -34,48 +38,48 @@ module.exports = function(grunt) {
const sass = require('sass');
// Import grunt configuration for moodle base
process.chdir("../.."); // change dir to moodle base
process.chdir("../.."); // Change dir to moodle base
require(path.resolve(`./Gruntfile.js`))(grunt); // Run Gruntfile module from moodle base
grunt.registerTask('scssplugin','Compile scss/*.sccs into styles.css and css/devstyles.css', () => {
grunt.registerTask('scssplugin', 'Compile scss/styles.sccs into styles.css and css/devstyles.css', () => {
const devoutput = 'css/devstyles.css';
const prodoutput = 'styles.css';
// Get full path of compenent and scss folder
const componentPath = path.join(grunt.moodleEnv.gruntFilePath,grunt.moodleEnv.componentDirectory);
const scssPath = path.join(componentPath, 'scss','styles.scss');
const componentPath = path.join(grunt.moodleEnv.gruntFilePath, grunt.moodleEnv.componentDirectory);
const scssPath = path.join(componentPath, 'scss', 'styles.scss');
console.log(`Compiling ${scssPath} including any imported files therein`);
process.chdir(path.join(componentPath, 'scss'));
const result = sass.compile(scssPath);
if ( result ) {
if (result) {
console.info("got result");
// Some regex processing to match moodle stylelint styles
// change tab indent to 4 instead of 2
let css = result.css.replace(/^ ([^ ])/gm ," $1");
// Change tab indent to 4 instead of 2
let css = result.css.replace(/^ {2}([^ ])/gm, " $1");
// insert a newline after every comma in a css selector
// Insert a newline after every comma in a css selector
// (only combined selectors will get that long)
css = css.replace(/^[^ ].*[\{,]$/gm , (m) => { // Find CSS selector lines
return m.replace(/, /g,",\n"); // replace comma followed by space with comma newline
css = css.replace(/^[^ ].*[{,]$/gm, (m) => { // Find CSS selector lines
return m.replace(/, /g, ",\n"); // Replace comma followed by space with comma newline
});
// replace hex color codes with lowercase (convenience function since I don't really care for the hex codes lowercase only rule)
// Replace hex color codes with lowercase.
const hexCodeToLower = (match, m1, m2) => {
return '#'+m1.toLowerCase()+m2;
}
css = css.replace(/#([A-F0-9a-f]{3})([^A-F0-9a-f]?)/gm , hexCodeToLower); // 3 digit color codes
css = css.replace(/#([A-F0-9a-f]{6})([^A-F0-9a-f]?)/gm , hexCodeToLower); // 6 digit color codes
css = css.replace(/#([A-F0-9a-f]{8})([^A-F0-9a-f]?)/gm , hexCodeToLower); // 8 digit color codes (with alpha)
return '#' + m1.toLowerCase() + m2;
};
css = css.replace(/#([A-F0-9a-f]{3})([^A-F0-9a-f]?)/gm, hexCodeToLower); // 3 digit color codes
css = css.replace(/#([A-F0-9a-f]{6})([^A-F0-9a-f]?)/gm, hexCodeToLower); // 6 digit color codes
css = css.replace(/#([A-F0-9a-f]{8})([^A-F0-9a-f]?)/gm, hexCodeToLower); // 8 digit color codes (with alpha)
// All other errors should really be fixed in the scss files :)
[devoutput,prodoutput].forEach((output) => {
[devoutput, prodoutput].forEach((output) => {
console.info(`Storing ${output}`);
grunt.file.write(path.join(componentPath, output),css);
grunt.file.write(path.join(componentPath, output), css);
});
}
@ -92,7 +96,7 @@ module.exports = function(grunt) {
});
// Remove gherkinlint from the startup list, since it exits with an error because of errors in moodle's own code
grunt.moodleEnv.startupTasks.splice(grunt.moodleEnv.startupTasks.indexOf("gherkinlint"),1);
grunt.moodleEnv.startupTasks.splice(grunt.moodleEnv.startupTasks.indexOf("gherkinlint"), 1);
// Add the 'scssplugin' task as a startup task.
grunt.moodleEnv.startupTasks.push('scssplugin');

View File

@ -1,13 +1,13 @@
# Moodle studyplan plugin
Plugin to organize a curriculum into an easy to read graphical respresentation of courses and student progress therein.
Plugin to organize a curriculum into an easy to read graphical representation of courses and student progress therein.
The studyplan plugin extends Moodle with the ability to show students and teachers an overview of their curriculum and results therein.
By showing students an easy to read graphical overview of their progress over multiple courses, students are more in control of their own
learning process than by just listing results alone
## Installing
Install the plugin by adding the zip file manually to the installed plugins in your moodle version
Install the plugin by adding the zip file manually to the installed plugins in your Moodle version
## Configuration post install

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/bootstrap-vue/vue-functional-data-merge",["exports"],(function(_exports){function _slicedToArray(arr,i){return function(arr){if(Array.isArray(arr))return arr}(arr)||function(arr,i){var _i=null==arr?null:"undefined"!=typeof Symbol&&arr[Symbol.iterator]||arr["@@iterator"];if(null==_i)return;var _s,_e,_arr=[],_n=!0,_d=!1;try{for(_i=_i.call(arr);!(_n=(_s=_i.next()).done)&&(_arr.push(_s.value),!i||_arr.length!==i);_n=!0);}catch(err){_d=!0,_e=err}finally{try{_n||null==_i.return||_i.return()}finally{if(_d)throw _e}}return _arr}(arr,i)||_unsupportedIterableToArray(arr,i)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function _unsupportedIterableToArray(o,minLen){if(o){if("string"==typeof o)return _arrayLikeToArray(o,minLen);var n=Object.prototype.toString.call(o).slice(8,-1);return"Object"===n&&o.constructor&&(n=o.constructor.name),"Map"===n||"Set"===n?Array.from(o):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?_arrayLikeToArray(o,minLen):void 0}}function _arrayLikeToArray(arr,len){(null==len||len>arr.length)&&(len=arr.length);for(var i=0,arr2=new Array(len);i<len;i++)arr2[i]=arr[i];return arr2}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.mergeData=function(){var prop,mergeTarget={},i=arguments.length;for(;i--;)for(var _i2=0,_Object$keys=Object.keys(arguments[i]);_i2<_Object$keys.length;_i2++)if(prop=_Object$keys[_i2],null!=arguments[i][prop]){switch(prop){case"class":var classes=[],value=mergeTarget.class;Array.isArray(value)&&(classes=value),mergeTarget.class=classes.concat(arguments[i].class);continue;case"style":var styles=[],_value=mergeTarget.style;Array.isArray(_value)&&(styles=_value);var thisStyle=[];Array.isArray(arguments[i].style)?thisStyle=arguments[i].style:thisStyle.push(arguments[i].style);for(var j=0;j<thisStyle.length;j++){var s=thisStyle[j];"string"==typeof s&&(thisStyle[j]=parseStyle(s))}mergeTarget[prop]=styles.concat(thisStyle);continue;case"id":case"key":case"ref":case"keepAlive":mergeTarget[prop]||(mergeTarget[prop]=arguments[i][prop]);continue}if(prop.startsWith("on")&&"on"!==prop){if(mergeTarget[prop]&&!Array.isArray(mergeTarget[prop])){mergeTarget[prop]=[mergeTarget[prop],arguments[i][prop]];continue}var targetValue=mergeTarget[prop],thisValue=arguments[i][prop];if(Array.isArray(targetValue)){Array.isArray(thisValue)?targetValue.push.apply(targetValue,function(arr){if(Array.isArray(arr))return _arrayLikeToArray(arr)}(arr=thisValue)||function(iter){if("undefined"!=typeof Symbol&&null!=iter[Symbol.iterator]||null!=iter["@@iterator"])return Array.from(iter)}(arr)||_unsupportedIterableToArray(arr)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()):targetValue.push(thisValue);continue}}mergeTarget[prop]=arguments[i][prop]}var arr;return mergeTarget};var pattern={kebab:/-(\w)/g,styleProp:/:(.*)/,styleList:/;(?![^(]*\))/g};function camelReplace(_substr,match){return match.toUpperCase()}function parseStyle(style){var _step,str,styleMap={},_iterator=function(o,allowArrayLike){var it="undefined"!=typeof Symbol&&o[Symbol.iterator]||o["@@iterator"];if(!it){if(Array.isArray(o)||(it=_unsupportedIterableToArray(o))||allowArrayLike&&o&&"number"==typeof o.length){it&&(o=it);var i=0,F=function(){};return{s:F,n:function(){return i>=o.length?{done:!0}:{done:!1,value:o[i++]}},e:function(_e2){throw _e2},f:F}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var err,normalCompletion=!0,didErr=!1;return{s:function(){it=it.call(o)},n:function(){var step=it.next();return normalCompletion=step.done,step},e:function(_e3){didErr=!0,err=_e3},f:function(){try{normalCompletion||null==it.return||it.return()}finally{if(didErr)throw err}}}}(style.split(pattern.styleList));try{for(_iterator.s();!(_step=_iterator.n()).done;){var _s$split2=_slicedToArray(_step.value.split(pattern.styleProp),2),key=_s$split2[0],val=_s$split2[1];(key=key.trim())&&(val=val.trim(),styleMap[(str=key,str.replace(pattern.kebab,camelReplace))]=val)}}catch(err){_iterator.e(err)}finally{_iterator.f()}return styleMap}}));
define("local_treestudyplan/bootstrap-vue/vue-functional-data-merge",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.mergeData=function(){let prop,mergeTarget={},i=arguments.length;for(;i--;)for(prop of Object.keys(arguments[i]))if(null!=arguments[i][prop]){switch(prop){case"class":{let classes=[];{let value=mergeTarget.class;Array.isArray(value)&&(classes=value)}mergeTarget.class=classes.concat(arguments[i].class);continue}case"style":{let styles=[];{let value=mergeTarget.style;Array.isArray(value)&&(styles=value)}let thisStyle=[];Array.isArray(arguments[i].style)?thisStyle=arguments[i].style:thisStyle.push(arguments[i].style);for(let j=0;j<thisStyle.length;j++){let s=thisStyle[j];"string"==typeof s&&(thisStyle[j]=parseStyle(s))}mergeTarget[prop]=styles.concat(thisStyle);continue}case"id":case"key":case"ref":case"keepAlive":mergeTarget[prop]||(mergeTarget[prop]=arguments[i][prop]);continue}if(prop.startsWith("on")&&"on"!==prop){if(mergeTarget[prop]&&!Array.isArray(mergeTarget[prop])){mergeTarget[prop]=[mergeTarget[prop],arguments[i][prop]];continue}let targetValue=mergeTarget[prop],thisValue=arguments[i][prop];if(Array.isArray(targetValue)){Array.isArray(thisValue)?targetValue.push(...thisValue):targetValue.push(thisValue);continue}}mergeTarget[prop]=arguments[i][prop]}return mergeTarget};const pattern={kebab:/-(\w)/g,styleProp:/:(.*)/,styleList:/;(?![^(]*\))/g};function camelReplace(_substr,match){return match.toUpperCase()}function parseStyle(style){let styleMap={};for(let s of style.split(pattern.styleList)){let[key,val]=s.split(pattern.styleProp);key=key.trim(),key&&(val=val.trim(),styleMap[(str=key,str.replace(pattern.kebab,camelReplace))]=val)}var str;return styleMap}}));
//# sourceMappingURL=vue-functional-data-merge.min.js.map

File diff suppressed because one or more lines are too long

View File

@ -1,3 +1,3 @@
define("local_treestudyplan/cfg-grades",["exports","core/str","core/ajax","./debugger","./string-helper"],(function(_exports,_str,_ajax,_debugger,_stringHelper){var obj;function _createForOfIteratorHelper(o,allowArrayLike){var it="undefined"!=typeof Symbol&&o[Symbol.iterator]||o["@@iterator"];if(!it){if(Array.isArray(o)||(it=function(o,minLen){if(!o)return;if("string"==typeof o)return _arrayLikeToArray(o,minLen);var n=Object.prototype.toString.call(o).slice(8,-1);"Object"===n&&o.constructor&&(n=o.constructor.name);if("Map"===n||"Set"===n)return Array.from(o);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return _arrayLikeToArray(o,minLen)}(o))||allowArrayLike&&o&&"number"==typeof o.length){it&&(o=it);var i=0,F=function(){};return{s:F,n:function(){return i>=o.length?{done:!0}:{done:!1,value:o[i++]}},e:function(_e){throw _e},f:F}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var err,normalCompletion=!0,didErr=!1;return{s:function(){it=it.call(o)},n:function(){var step=it.next();return normalCompletion=step.done,step},e:function(_e2){didErr=!0,err=_e2},f:function(){try{normalCompletion||null==it.return||it.return()}finally{if(didErr)throw err}}}}function _arrayLikeToArray(arr,len){(null==len||len>arr.length)&&(len=arr.length);for(var i=0,arr2=new Array(len);i<len;i++)arr2[i]=arr[i];return arr2}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=function(){var _step,intRx=/\d/,integerChange=function(event){event.key.length>1||intRx.test(event.key)||event.preventDefault()},_iterator=_createForOfIteratorHelper(document.querySelectorAll('input[type="number"][step="1"][min="0"]'));try{for(_iterator.s();!(_step=_iterator.n()).done;){_step.value.addEventListener("keydown",integerChange)}}catch(err){_iterator.e(err)}finally{_iterator.f()}var _step2,decimal=/^[0-9]*?\.[0-9]*?$/,_intRx=/\d/,floatChange=function(event){event.key.length>1||"."===event.key&&!event.currentTarget.value.match(decimal)||_intRx.test(event.key)||event.preventDefault()},_iterator2=_createForOfIteratorHelper(document.querySelectorAll('input[type="number"][min="0"]:not([step])'));try{for(_iterator2.s();!(_step2=_iterator2.n()).done;){_step2.value.addEventListener("keydown",floatChange)}}catch(err){_iterator2.e(err)}finally{_iterator2.f()}var _step3,_iterator3=_createForOfIteratorHelper(document.querySelectorAll('input[type="text"].float'));try{for(_iterator3.s();!(_step3=_iterator3.n()).done;){_step3.value.addEventListener("keydown",floatChange)}}catch(err){_iterator3.e(err)}finally{_iterator3.f()}};new(_debugger=(obj=_debugger)&&obj.__esModule?obj:{default:obj}).default("treestudyplan-config-grades")}));
define("local_treestudyplan/cfg-grades",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=function(){{const intRx=/\d/,integerChange=event=>{event.key.length>1||intRx.test(event.key)||event.preventDefault()};for(let input of document.querySelectorAll('input[type="number"][step="1"][min="0"]'))input.addEventListener("keydown",integerChange)}{const decimal=/^[0-9]*?\.[0-9]*?$/,intRx=/\d/,floatChange=event=>{event.key.length>1||"."===event.key&&!event.currentTarget.value.match(decimal)||intRx.test(event.key)||event.preventDefault()};for(let input of document.querySelectorAll('input[type="number"][min="0"]:not([step])'))input.addEventListener("keydown",floatChange);for(let input of document.querySelectorAll('input[type="text"].float'))input.addEventListener("keydown",floatChange)}}}));
//# sourceMappingURL=cfg-grades.min.js.map

View File

@ -1 +1 @@
{"version":3,"file":"cfg-grades.min.js","sources":["../src/cfg-grades.js"],"sourcesContent":["/*eslint no-var: \"error\" */\n/*eslint no-unused-vars: \"off\" */\n/*eslint linebreak-style: \"off\" */\n/*eslint no-trailing-spaces: \"off\" */\n/*eslint-env es6*/\n// Put this file in path/to/plugin/amd/src\n// You can call it anything you like\n\nimport {get_string,get_strings} from 'core/str';\nimport {call} from 'core/ajax';\nimport Debugger from './debugger';\n\nimport {load_strings} from './string-helper';\n\nlet debug = new Debugger(\"treestudyplan-config-grades\");\n\n/*\nlet strings = load_strings({\n studyplan: {\n studyplan_select_placeholder: 'studyplan_select_placeholder',\n },\n});\n*/\n\n/**\n * Initialize grade cfg page\n */\nexport function init() {\n { const\n intRx = /\\d/,\n integerChange = (event) => {\n if ( (event.key.length > 1) || intRx.test(event.key)\n ) {\n return;\n }\n event.preventDefault();\n };\n\n for (let input of document.querySelectorAll( 'input[type=\"number\"][step=\"1\"][min=\"0\"]' )){\n input.addEventListener(\"keydown\", integerChange);\n }\n\n }\n\n { const\n decimal= /^[0-9]*?\\.[0-9]*?$/,\n intRx = /\\d/,\n floatChange = (event) => {\n if ( (event.key.length > 1) || ( (event.key === \".\") && (!event.currentTarget.value.match(decimal)) )\n || intRx.test(event.key)\n ) {\n return;\n }\n event.preventDefault();\n };\n\n for (let input of document.querySelectorAll( 'input[type=\"number\"][min=\"0\"]:not([step])' )){\n input.addEventListener(\"keydown\", floatChange);\n }\n for (let input of document.querySelectorAll( 'input[type=\"text\"].float' )){\n input.addEventListener(\"keydown\", floatChange);\n }\n\n }\n\n\n}\n\n"],"names":["intRx","integerChange","event","key","length","test","preventDefault","document","querySelectorAll","addEventListener","decimal","floatChange","currentTarget","value","match"],"mappings":"kgDA6BQA,MAAQ,KACRC,cAAgB,SAACC,OACTA,MAAMC,IAAIC,OAAS,GAAMJ,MAAMK,KAAKH,MAAMC,MAIhDD,MAAMI,uDAGQC,SAASC,iBAAkB,+FAA4C,aACjFC,iBAAiB,UAAWR,6EAMlCS,QAAS,qBACTV,OAAQ,KACRW,YAAc,SAACT,OACPA,MAAMC,IAAIC,OAAS,GAAuB,MAAdF,MAAMC,MAAkBD,MAAMU,cAAcC,MAAMC,MAAMJ,UACjFV,OAAMK,KAAKH,MAAMC,MAI1BD,MAAMI,wDAGQC,SAASC,iBAAkB,oGAA8C,cACnFC,iBAAiB,UAAWE,mHAElBJ,SAASC,iBAAkB,mFAA6B,cAClEC,iBAAiB,UAAWE,oEA9C9B,yEAAa"}
{"version":3,"file":"cfg-grades.min.js","sources":["../src/cfg-grades.js"],"sourcesContent":["/* eslint-env es6*/\n// Put this file in path/to/plugin/amd/src\n// You can call it anything you like\n\n/**\n * Initialize grade cfg page\n */\nexport function init() {\n { const\n intRx = /\\d/,\n integerChange = (event) => {\n if ((event.key.length > 1) || intRx.test(event.key)\n ) {\n return;\n }\n event.preventDefault();\n };\n\n for (let input of document.querySelectorAll('input[type=\"number\"][step=\"1\"][min=\"0\"]')) {\n input.addEventListener(\"keydown\", integerChange);\n }\n\n }\n\n { const\n decimal = /^[0-9]*?\\.[0-9]*?$/,\n intRx = /\\d/,\n floatChange = (event) => {\n if ((event.key.length > 1) || ((event.key === \".\") && (!event.currentTarget.value.match(decimal)))\n || intRx.test(event.key)\n ) {\n return;\n }\n event.preventDefault();\n };\n\n for (let input of document.querySelectorAll('input[type=\"number\"][min=\"0\"]:not([step])')) {\n input.addEventListener(\"keydown\", floatChange);\n }\n for (let input of document.querySelectorAll('input[type=\"text\"].float')) {\n input.addEventListener(\"keydown\", floatChange);\n }\n\n }\n\n\n}\n\n"],"names":["intRx","integerChange","event","key","length","test","preventDefault","input","document","querySelectorAll","addEventListener","decimal","floatChange","currentTarget","value","match"],"mappings":"gKASQA,MAAQ,KACRC,cAAiBC,QACVA,MAAMC,IAAIC,OAAS,GAAMJ,MAAMK,KAAKH,MAAMC,MAI/CD,MAAMI,sBAGL,IAAIC,SAASC,SAASC,iBAAiB,2CAC1CF,MAAMG,iBAAiB,UAAWT,sBAMlCU,QAAU,qBACVX,MAAQ,KACRY,YAAeV,QACRA,MAAMC,IAAIC,OAAS,GAAsB,MAAdF,MAAMC,MAAkBD,MAAMW,cAAcC,MAAMC,MAAMJ,UAC/EX,MAAMK,KAAKH,MAAMC,MAI1BD,MAAMI,sBAGL,IAAIC,SAASC,SAASC,iBAAiB,6CAC1CF,MAAMG,iBAAiB,UAAWE,iBAE/B,IAAIL,SAASC,SAASC,iBAAiB,4BAC1CF,MAAMG,iBAAiB,UAAWE"}

View File

@ -1,3 +1,3 @@
define("local_treestudyplan/downloader",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.download=function(filename,text,type){null==type&&(type="text/plain");var pom=document.createElement("a");if(pom.setAttribute("href","data:"+type+";charset=utf-8,"+encodeURIComponent(text)),pom.setAttribute("download",filename),document.createEvent){var event=document.createEvent("MouseEvents");event.initEvent("click",!0,!0),pom.dispatchEvent(event)}else pom.click()},_exports.upload=function(onready,accept){var input=document.createElement("input");input.type="file",Array.isArray(accept)?accept.count>0&&(input.accept=accept.join(", ")):void 0!==accept&&(input.accept=accept);if(input.onchange=function(){var files=Array.from(input.files);if(files.length>0){var file=files[0],reader=new FileReader;reader.onload=function(e){var contents=e.target.result;onready instanceof Function&&onready(file,contents)},reader.readAsText(file)}},document.createEvent){var event=document.createEvent("MouseEvents");event.initEvent("click",!0,!0),input.dispatchEvent(event)}else input.click()}}));
define("local_treestudyplan/downloader",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.download=function(filename,text,type){null==type&&(type="text/plain");var pom=document.createElement("a");if(pom.setAttribute("href","data:"+type+";charset=utf-8,"+encodeURIComponent(text)),pom.setAttribute("download",filename),document.createEvent){var event=document.createEvent("MouseEvents");event.initEvent("click",!0,!0),pom.dispatchEvent(event)}else pom.click()},_exports.upload=function(onready,accept){let input=document.createElement("input");input.type="file",Array.isArray(accept)?accept.count>0&&(input.accept=accept.join(", ")):void 0!==accept&&(input.accept=accept);if(input.onchange=()=>{let files=Array.from(input.files);if(files.length>0){let file=files[0];var reader=new FileReader;reader.onload=function(e){var contents=e.target.result;onready instanceof Function&&onready(file,contents)},reader.readAsText(file)}},document.createEvent){var event=document.createEvent("MouseEvents");event.initEvent("click",!0,!0),input.dispatchEvent(event)}else input.click()}}));
//# sourceMappingURL=downloader.min.js.map

View File

@ -1 +1 @@
{"version":3,"file":"downloader.min.js","sources":["../src/downloader.js"],"sourcesContent":["/*eslint no-console: \"off\"*/\n\n/**\n * Save a piece of text to file as if it was downloaded\n * @param {string} filename\n * @param {string} text\n * @param {string} type\n */\nexport function download(filename, text, type) {\n if(undefined == type) { type = \"text/plain\"; }\n var pom = document.createElement('a');\n pom.setAttribute('href', 'data:'+type+';charset=utf-8,' + encodeURIComponent(text));\n pom.setAttribute('download', filename);\n\n if (document.createEvent) {\n var event = document.createEvent('MouseEvents');\n event.initEvent('click', true, true);\n pom.dispatchEvent(event);\n }\n else {\n pom.click();\n }\n}\n\n/**\n * This callback type is called `requestCallback` and is displayed as a global symbol.\n *\n * @callback fileOpenedCallback\n * @param {File} file File name\n * @param {string} content File Contents\n */\n\n/**\n * Open a file from disk and read its contents\n * @param {fileOpenedCallback} onready Callback to run when file is opened\n * @param {Array} accept Array of mime types that the file dialog will accept\n */\nexport function upload(onready,accept) {\n let input = document.createElement('input');\n input.type = 'file';\n if(Array.isArray(accept)){\n if(accept.count > 0){\n input.accept = accept.join(\", \");\n }\n } else if (undefined !== accept){\n input.accept = accept;\n }\n input.onchange = () => {\n let files = Array.from(input.files);\n if(files.length > 0){\n let file = files[0];\n var reader = new FileReader();\n reader.onload = function(e) {\n var contents = e.target.result;\n if(onready instanceof Function){\n onready(file,contents);\n }\n };\n reader.readAsText(file);\n }\n };\n\n if (document.createEvent) {\n var event = document.createEvent('MouseEvents');\n event.initEvent('click', true, true);\n input.dispatchEvent(event);\n }\n else {\n input.click();\n }\n}"],"names":["filename","text","type","undefined","pom","document","createElement","setAttribute","encodeURIComponent","createEvent","event","initEvent","dispatchEvent","click","onready","accept","input","Array","isArray","count","join","onchange","files","from","length","file","reader","FileReader","onload","e","contents","target","result","Function","readAsText"],"mappings":"2JAQyBA,SAAUC,KAAMC,MAClCC,MAAaD,OAAQA,KAAO,kBAC3BE,IAAMC,SAASC,cAAc,QACjCF,IAAIG,aAAa,OAAQ,QAAQL,KAAK,kBAAoBM,mBAAmBP,OAC7EG,IAAIG,aAAa,WAAYP,UAEzBK,SAASI,YAAa,KAClBC,MAAQL,SAASI,YAAY,eACjCC,MAAMC,UAAU,SAAS,GAAM,GAC/BP,IAAIQ,cAAcF,YAGlBN,IAAIS,kCAiBWC,QAAQC,YACvBC,MAAQX,SAASC,cAAc,SACnCU,MAAMd,KAAO,OACVe,MAAMC,QAAQH,QACVA,OAAOI,MAAQ,IACdH,MAAMD,OAASA,OAAOK,KAAK,YAExBjB,IAAcY,SACrBC,MAAMD,OAASA,WAEnBC,MAAMK,SAAW,eACLC,MAAUL,MAAMM,KAAKP,MAAMM,UAC5BA,MAAME,OAAS,EAAE,KACZC,KAAOH,MAAM,GACbI,OAAS,IAAIC,WACjBD,OAAOE,OAAS,SAASC,OACjBC,SAAWD,EAAEE,OAAOC,OACrBlB,mBAAmBmB,UAClBnB,QAAQW,KAAKK,WAGrBJ,OAAOQ,WAAWT,QAI1BpB,SAASI,YAAa,KAClBC,MAAQL,SAASI,YAAY,eACjCC,MAAMC,UAAU,SAAS,GAAM,GAC/BK,MAAMJ,cAAcF,YAGpBM,MAAMH"}
{"version":3,"file":"downloader.min.js","sources":["../src/downloader.js"],"sourcesContent":["/**\n * Save a piece of text to file as if it was downloaded\n * @param {string} filename\n * @param {string} text\n * @param {string} type\n */\nexport function download(filename, text, type) {\n if (undefined == type) {\n type = \"text/plain\";\n }\n var pom = document.createElement('a');\n pom.setAttribute('href', 'data:' + type + ';charset=utf-8,' + encodeURIComponent(text));\n pom.setAttribute('download', filename);\n\n if (document.createEvent) {\n var event = document.createEvent('MouseEvents');\n event.initEvent('click', true, true);\n pom.dispatchEvent(event);\n } else {\n pom.click();\n }\n}\n\n/**\n * This callback type is called `requestCallback` and is displayed as a global symbol.\n *\n * @callback fileOpenedCallback\n * @param {File} file File name\n * @param {string} content File Contents\n */\n\n/**\n * Open a file from disk and read its contents\n * @param {fileOpenedCallback} onready Callback to run when file is opened\n * @param {Array} accept Array of mime types that the file dialog will accept\n */\nexport function upload(onready, accept) {\n let input = document.createElement('input');\n input.type = 'file';\n if (Array.isArray(accept)) {\n if (accept.count > 0) {\n input.accept = accept.join(\", \");\n }\n } else if (undefined !== accept) {\n input.accept = accept;\n }\n input.onchange = () => {\n let files = Array.from(input.files);\n if (files.length > 0) {\n let file = files[0];\n var reader = new FileReader();\n reader.onload = function(e) {\n var contents = e.target.result;\n if (onready instanceof Function) {\n onready(file, contents);\n }\n };\n reader.readAsText(file);\n }\n };\n\n if (document.createEvent) {\n var event = document.createEvent('MouseEvents');\n event.initEvent('click', true, true);\n input.dispatchEvent(event);\n } else {\n input.click();\n }\n}"],"names":["filename","text","type","undefined","pom","document","createElement","setAttribute","encodeURIComponent","createEvent","event","initEvent","dispatchEvent","click","onready","accept","input","Array","isArray","count","join","onchange","files","from","length","file","reader","FileReader","onload","e","contents","target","result","Function","readAsText"],"mappings":"2JAMyBA,SAAUC,KAAMC,MACjCC,MAAaD,OACbA,KAAO,kBAEPE,IAAMC,SAASC,cAAc,QACjCF,IAAIG,aAAa,OAAQ,QAAUL,KAAO,kBAAoBM,mBAAmBP,OACjFG,IAAIG,aAAa,WAAYP,UAEzBK,SAASI,YAAa,KAClBC,MAAQL,SAASI,YAAY,eACjCC,MAAMC,UAAU,SAAS,GAAM,GAC/BP,IAAIQ,cAAcF,YAElBN,IAAIS,kCAiBWC,QAASC,YACxBC,MAAQX,SAASC,cAAc,SACnCU,MAAMd,KAAO,OACTe,MAAMC,QAAQH,QACVA,OAAOI,MAAQ,IACfH,MAAMD,OAASA,OAAOK,KAAK,YAExBjB,IAAcY,SACrBC,MAAMD,OAASA,WAEnBC,MAAMK,SAAW,SACLC,MAAQL,MAAMM,KAAKP,MAAMM,UACzBA,MAAME,OAAS,EAAG,KACdC,KAAOH,MAAM,OACbI,OAAS,IAAIC,WACjBD,OAAOE,OAAS,SAASC,OACjBC,SAAWD,EAAEE,OAAOC,OACpBlB,mBAAmBmB,UACnBnB,QAAQW,KAAMK,WAGtBJ,OAAOQ,WAAWT,QAI1BpB,SAASI,YAAa,KAClBC,MAAQL,SAASI,YAAY,eACjCC,MAAMC,UAAU,SAAS,GAAM,GAC/BK,MAAMJ,cAAcF,YAEpBM,MAAMH"}

View File

@ -1,3 +1,3 @@
define("local_treestudyplan/modedit-modal",["exports","core/fragment","./util/string-helper","core/ajax","core/notification","core/templates"],(function(_exports,_fragment,_stringHelper,_ajax,_notification,_templates){var obj;Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_notification=(obj=_notification)&&obj.__esModule?obj:{default:obj};var _default={install:function(Vue){var strings=(0,_stringHelper.load_strings)({editmod:{save$core:"save$core",cancel$core:"cancel$core"}});Vue.component("s-edit-mod",{props:{cmid:{type:Number},coursectxid:{type:Number},title:{type:String,default:""},genericonly:{type:Boolean,default:!1}},data:function(){return{content:"",text:strings.editmod}},computed:{},methods:{openForm:function(){this.$refs.editormodal.show()},onShown:function(){var self=this,params={cmid:this.cmid};console.info("Loading form"),(0,_fragment.loadFragment)("local_treestudyplan","mod_edit_form",this.coursectxid,params).then((function(html,js){(0,_templates.replaceNodeContents)(self.$refs.content,html,js)})).catch(_notification.default.exception)},onSave:function(){var self=this,form=this.$refs.content.getElementsByTagName("form")[0];form.dispatchEvent(new Event("save-form-state"));var formdata=new FormData(form),data=new URLSearchParams(formdata).toString();(0,_ajax.call)([{methodname:"local_treestudyplan_submit_cm_editform",args:{cmid:this.cmid,formdata:data}}])[0].done((function(){self.$emit("saved",formdata)})).fail(_notification.default.exception)}},template:'\n <span class=\'s-edit-mod\'><a href=\'#\' @click.prevent="openForm"><slot><i class="fa fa-cog"></i></slot></a>\n <b-modal\n ref="editormodal"\n scrollable\n centered\n size="xl"\n id="\'modal-cm-\'+cmid"\n @shown="onShown"\n @ok="onSave"\n :title="title"\n :ok-title="text.save$core"\n ><div :class="\'s-edit-mod-form \'+ (genericonly?\'genericonly\':\'\')" ref="content"\n ><div class="d-flex justify-content-center mb-3"><b-spinner variant="primary"></b-spinner></div\n ></div\n ></b-modal>\n </span>\n '})}};return _exports.default=_default,_exports.default}));
define("local_treestudyplan/modedit-modal",["exports","core/fragment","./util/string-helper","core/ajax","core/notification","core/templates"],(function(_exports,_fragment,_stringHelper,_ajax,_notification,_templates){var obj;Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_notification=(obj=_notification)&&obj.__esModule?obj:{default:obj};var _default={install(Vue){let strings=(0,_stringHelper.loadStrings)({editmod:{save$core:"save$core",cancel$core:"cancel$core"}});Vue.component("s-edit-mod",{props:{cmid:{type:Number},coursectxid:{type:Number},title:{type:String,default:""},genericonly:{type:Boolean,default:!1}},data:()=>({content:"",text:strings.editmod}),computed:{},methods:{openForm(){this.$refs.editormodal.show()},onShown(){const self=this;let params={cmid:this.cmid};(0,_fragment.loadFragment)("local_treestudyplan","mod_edit_form",this.coursectxid,params).then(((html,js)=>((0,_templates.replaceNodeContents)(self.$refs.content,html,js),null))).catch(_notification.default.exception)},onSave(){const self=this;let form=this.$refs.content.getElementsByTagName("form")[0];form.dispatchEvent(new Event("save-form-state"));const formdata=new FormData(form),data=new URLSearchParams(formdata).toString();(0,_ajax.call)([{methodname:"local_treestudyplan_submit_cm_editform",args:{cmid:this.cmid,formdata:data}}])[0].then((()=>(self.$emit("saved",formdata),null))).catch(_notification.default.exception)}},template:'\n <span class=\'s-edit-mod\'><a href=\'#\' @click.prevent="openForm"><slot><i class="fa fa-cog"></i></slot></a>\n <b-modal\n ref="editormodal"\n scrollable\n centered\n size="xl"\n id="\'modal-cm-\'+cmid"\n @shown="onShown"\n @ok="onSave"\n :title="title"\n :ok-title="text.save$core"\n ><div :class="\'s-edit-mod-form \'+ (genericonly?\'genericonly\':\'\')" ref="content"\n ><div class="d-flex justify-content-center mb-3"><b-spinner variant="primary"></b-spinner></div\n ></div\n ></b-modal>\n </span>\n '})}};return _exports.default=_default,_exports.default}));
//# sourceMappingURL=modedit-modal.min.js.map

File diff suppressed because one or more lines are too long

3
amd/build/page-coach.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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/page-invitemanager",["jquery","core/str","core/ajax","core/modal_factory","core/modal_events","local_treestudyplan/handlers","local_treestudyplan/debugger"],(function($,str,ajax,ModalFactory,ModalEvents,handlers,Debugger){var debug=new Debugger("treestudyplan");return{init:function(){$(".path-local-treestudyplan a.m-action-confirm").on("click",(function(e){e.preventDefault();var $link=$(e.currentTarget),href=$link.attr("data-actionhref"),text=$link.attr("data-confirmtext"),oktext=$link.attr("data-confirmbtn");debug.info("Ok",oktext),null==oktext&&(oktext=str.get_string("ok"));var title=$link.attr("data-confirmtitle");debug.info("Title",title),null==title&&(title=str.get_string("confirm")),debug.info("Link, href, text",$link,href,text),ModalFactory.create({type:ModalFactory.types.SAVE_CANCEL,title:title,body:text}).then((function(modal){modal.setSaveButtonText(oktext),modal.getRoot().on(ModalEvents.save,(function(){window.location=href})),$(modal.modal).css("max-width","345px"),modal.show()}))}))}}}));
define("local_treestudyplan/page-invitemanager",["exports","./util/debugger","core/str","core/modal_factory","core/modal_events"],(function(_exports,_debugger,_str,_modal_factory,_modal_events){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=function(){getstrFunc([{key:"ok",component:"core"},{key:"confirm",component:"core"}]).then((s=>{const strOk=s[0],strConfirm=s[1];document.querySelectorAll(".path-local-treestudyplan a.m-action-confirm").forEach((el=>{el.addEventListener("click",(e=>{e.preventDefault();const link=e.currentTarget;let href=link.getAttribute("data-actionhref"),text=link.getAttribute("data-confirmtext"),oktext=link.getAttribute("data-confirmbtn");null==oktext&&(oktext=strOk);let title=link.getAttribute("data-confirmtitle");null==title&&(title=strConfirm),_modal_factory.default.create({type:_modal_factory.default.types.SAVE_CANCEL,title:title,body:text}).then((modal=>(modal.setSaveButtonText(oktext),modal.getRoot().on(_modal_events.default.save,(()=>{window.location=href})),modal.modal[0].style["max-width"]="345px",modal.show(),modal))).catch((x=>{debug.warn(x)}))}))}))})).catch((x=>{debug.warn(x)}))},_debugger=_interopRequireDefault(_debugger),_modal_factory=_interopRequireDefault(_modal_factory),_modal_events=_interopRequireDefault(_modal_events);const getstrFunc=void 0!==_str.getStrings?_str.getStrings:_str.get_strings;let debug=new _debugger.default("treestudyplan-invitemanager")}));
//# sourceMappingURL=page-invitemanager.min.js.map

View File

@ -1 +1 @@
{"version":3,"file":"page-invitemanager.min.js","sources":["../src/page-invitemanager.js"],"sourcesContent":["/*eslint no-var: \"error\" */\n/*eslint no-unused-vars: \"off\" */\n/*eslint linebreak-style: \"off\" */\n/*eslint-env es6*/\n// Put this file in path/to/plugin/amd/src\n// You can call it anything you like\n\ndefine(['jquery', 'core/str', 'core/ajax', 'core/modal_factory', 'core/modal_events',\n 'local_treestudyplan/handlers', 'local_treestudyplan/debugger'],\nfunction ($, str, ajax, ModalFactory, ModalEvents,\n handlers, Debugger) {\n let debug = new Debugger(\"treestudyplan\");\n\n let self = {\n init: function init() {\n $('.path-local-treestudyplan a.m-action-confirm').on('click', function (e) {\n e.preventDefault();\n let $link = $(e.currentTarget);\n let href = $link.attr('data-actionhref');\n let text = $link.attr('data-confirmtext');\n let oktext = $link.attr('data-confirmbtn');\n debug.info(\"Ok\", oktext);\n if (undefined == oktext) { oktext = str.get_string('ok'); }\n let title = $link.attr('data-confirmtitle');\n debug.info(\"Title\", title);\n if (undefined == title) { title = str.get_string('confirm'); }\n\n debug.info(\"Link, href, text\", $link, href, text);\n\n ModalFactory.create({\n type: ModalFactory.types.SAVE_CANCEL,\n title: title,\n body: text,\n }).then(function (modal) {\n modal.setSaveButtonText(oktext);\n\n let root = modal.getRoot();\n root.on(ModalEvents.save, function () {\n window.location = href;\n });\n\n $(modal.modal).css(\"max-width\", \"345px\");\n modal.show();\n });\n });\n },\n\n\n };\n return self;\n});"],"names":["define","$","str","ajax","ModalFactory","ModalEvents","handlers","Debugger","debug","init","on","e","preventDefault","$link","currentTarget","href","attr","text","oktext","info","undefined","get_string","title","create","type","types","SAVE_CANCEL","body","then","modal","setSaveButtonText","getRoot","save","window","location","css","show"],"mappings":"AAOAA,gDAAO,CAAC,SAAU,WAAY,YAAa,qBAAsB,oBACzD,+BAAgC,iCACxC,SAAUC,EAAGC,IAAKC,KAAMC,aAAcC,YAC5BC,SAAUC,cACZC,MAAQ,IAAID,SAAS,uBAEd,CACPE,KAAM,WACFR,EAAE,gDAAgDS,GAAG,SAAS,SAAUC,GACpEA,EAAEC,qBACEC,MAAQZ,EAAEU,EAAEG,eACZC,KAAOF,MAAMG,KAAK,mBAClBC,KAAOJ,MAAMG,KAAK,oBAClBE,OAASL,MAAMG,KAAK,mBACxBR,MAAMW,KAAK,KAAMD,QACbE,MAAaF,SAAUA,OAAShB,IAAImB,WAAW,WAC/CC,MAAQT,MAAMG,KAAK,qBACvBR,MAAMW,KAAK,QAASG,OAChBF,MAAaE,QAASA,MAAQpB,IAAImB,WAAW,YAEjDb,MAAMW,KAAK,mBAAoBN,MAAOE,KAAME,MAE5Cb,aAAamB,OAAO,CAChBC,KAAMpB,aAAaqB,MAAMC,YACzBJ,MAAOA,MACPK,KAAMV,OACPW,MAAK,SAAUC,OACdA,MAAMC,kBAAkBZ,QAEbW,MAAME,UACZrB,GAAGL,YAAY2B,MAAM,WACtBC,OAAOC,SAAWnB,QAGtBd,EAAE4B,MAAMA,OAAOM,IAAI,YAAa,SAChCN,MAAMO,cAQzB"}
{"version":3,"file":"page-invitemanager.min.js","sources":["../src/page-invitemanager.js"],"sourcesContent":["/* eslint no-var: \"error\" */\n/* eslint no-unused-vars: \"off\" */\n/* eslint linebreak-style: \"off\" */\n/* eslint promise/no-nesting: \"off\" */\n/* eslint-env es6*/\n/* eslint camelcase: \"off\" */\n// Put this file in path/to/plugin/amd/src\n// You can call it anything you like\n\nimport Debugger from './util/debugger';\nimport {get_strings} from 'core/str';\nimport {getStrings} from 'core/str';\nimport ModalFactory from 'core/modal_factory';\nimport ModalEvents from 'core/modal_events';\n\n/* Determine the proper getstrings function to use (MDL4.3+ recommends use of getStrings, which is jquery independent) */\nconst getstrFunc = (getStrings !== undefined) ? getStrings : get_strings;\n\nlet debug = new Debugger(\"treestudyplan-invitemanager\");\n\n /**\n * Init function for page-invitemanager\n */\nexport function init() {\n getstrFunc([\n {key: 'ok', component: 'core'},\n {key: 'confirm', component: 'core'},\n ]).then((s) => {\n const strOk = s[0];\n const strConfirm = s[1];\n\n const els = document.querySelectorAll('.path-local-treestudyplan a.m-action-confirm');\n els.forEach((el) => {\n el.addEventListener('click', (e) => {\n e.preventDefault();\n const link = e.currentTarget;\n let href = link.getAttribute('data-actionhref');\n let text = link.getAttribute('data-confirmtext');\n let oktext = link.getAttribute('data-confirmbtn');\n if (undefined == oktext) {\n oktext = strOk;\n }\n let title = link.getAttribute('data-confirmtitle');\n if (undefined == title) {\n title = strConfirm;\n }\n\n ModalFactory.create({\n type: ModalFactory.types.SAVE_CANCEL,\n title: title,\n body: text,\n }).then((modal) => {\n modal.setSaveButtonText(oktext);\n\n let root = modal.getRoot();\n root.on(ModalEvents.save, () => {\n window.location = href;\n });\n modal.modal[0].style[\"max-width\"] = \"345px\";\n modal.show();\n return modal;\n }).catch((x) => {\n debug.warn(x);\n });\n });\n });\n return;\n }).catch((x) => {\n debug.warn(x);\n });\n}\n"],"names":["getstrFunc","key","component","then","s","strOk","strConfirm","document","querySelectorAll","forEach","el","addEventListener","e","preventDefault","link","currentTarget","href","getAttribute","text","oktext","undefined","title","create","type","ModalFactory","types","SAVE_CANCEL","body","modal","setSaveButtonText","getRoot","on","ModalEvents","save","window","location","style","show","catch","x","debug","warn","getStrings","get_strings","Debugger"],"mappings":"qWAwBIA,WAAW,CACP,CAACC,IAAK,KAAMC,UAAW,QACvB,CAACD,IAAK,UAAWC,UAAW,UAC7BC,MAAMC,UACCC,MAAQD,EAAE,GACVE,WAAaF,EAAE,GAETG,SAASC,iBAAiB,gDAClCC,SAASC,KACTA,GAAGC,iBAAiB,SAAUC,IAC1BA,EAAEC,uBACIC,KAAOF,EAAEG,kBACXC,KAAOF,KAAKG,aAAa,mBACzBC,KAAOJ,KAAKG,aAAa,oBACzBE,OAASL,KAAKG,aAAa,mBAC3BG,MAAaD,SACbA,OAASd,WAETgB,MAAQP,KAAKG,aAAa,qBAC1BG,MAAaC,QACbA,MAAQf,mCAGCgB,OAAO,CAChBC,KAAMC,uBAAaC,MAAMC,YACzBL,MAAOA,MACPM,KAAMT,OACPf,MAAMyB,QACLA,MAAMC,kBAAkBV,QAEbS,MAAME,UACZC,GAAGC,sBAAYC,MAAM,KACtBC,OAAOC,SAAWnB,IAAlB,IAEJY,MAAMA,MAAM,GAAGQ,MAAM,aAAe,QACpCR,MAAMS,OACCT,SACRU,OAAOC,IACNC,MAAMC,KAAKF,eAKxBD,OAAOC,IACNC,MAAMC,KAAKF,mKApDbvC,gBAA6BoB,IAAfsB,gBAA4BA,gBAAaC,qBAEzDH,MAAQ,IAAII,kBAAS"}

View File

@ -1,3 +1,3 @@
define("local_treestudyplan/page-myreport",["exports","core/ajax","core/notification","./vue/vue","./report-viewer-components","./treestudyplan-components","./util/debugger","./studyplan-processor","./portal-vue/portal-vue.esm","./bootstrap-vue/bootstrap-vue"],(function(_exports,_ajax,_notification,_vue,_reportViewerComponents,_treestudyplanComponents,_debugger,_studyplanProcessor,_portalVue,_bootstrapVue){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=function(){var type=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"myreport",arg=arguments.length>1?arguments[1]:void 0,app=new _vue.default({el:"#root",data:{studyplans:[]},mounted:function(){var call_method,call_args;"invited"==type?(call_method="local_treestudyplan_get_invited_studyplan",call_args={invitekey:arg}):"other"==type?(call_method="local_treestudyplan_get_user_studyplans",call_args={userid:arg}):"teaching"==type?(call_method="local_treestudyplan_get_teaching_studyplans",call_args={}):(call_method="local_treestudyplan_get_own_studyplan",call_args={}),(0,_ajax.call)([{methodname:call_method,args:call_args}])[0].done((function(response){debug.info("Studyplans:",response);var timingval={future:0,present:1,past:2};response.sort((function(a,b){var timinga=_treestudyplanComponents.default.studyplanTiming(a),timingb=_treestudyplanComponents.default.studyplanTiming(b),t=timingval[timinga]-timingval[timingb];return 0==t&&0==(t=new Date(b.startdate).getTime()-new Date(a.startdate).getTime())&&(t=a.name.localeCompare(b.name)),t})),app.studyplans=(0,_studyplanProcessor.ProcessStudyplans)(response)})).fail(_notification.default.exception)},methods:{}})},_notification=_interopRequireDefault(_notification),_vue=_interopRequireDefault(_vue),_reportViewerComponents=_interopRequireDefault(_reportViewerComponents),_treestudyplanComponents=_interopRequireDefault(_treestudyplanComponents),_debugger=_interopRequireDefault(_debugger),_portalVue=_interopRequireDefault(_portalVue),_bootstrapVue=_interopRequireDefault(_bootstrapVue),_vue.default.use(_reportViewerComponents.default),_vue.default.use(_portalVue.default),_vue.default.use(_bootstrapVue.default);var debug=new _debugger.default("treestudyplan-report")}));
define("local_treestudyplan/page-myreport",["exports","./vue/vue","./report-viewer-components","./portal-vue/portal-vue.esm","./bootstrap-vue/bootstrap-vue"],(function(_exports,_vue,_reportViewerComponents,_portalVue,_bootstrapVue){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=function(){let type=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"own",arg1=arguments.length>1?arguments[1]:void 0;new _vue.default({el:"#root",data:{studyplans:[],type:type,invitekey:"invited"==type?arg1:null,userid:"other"==type?arg1:null},methods:{}})},_vue=_interopRequireDefault(_vue),_reportViewerComponents=_interopRequireDefault(_reportViewerComponents),_portalVue=_interopRequireDefault(_portalVue),_bootstrapVue=_interopRequireDefault(_bootstrapVue),_vue.default.use(_reportViewerComponents.default),_vue.default.use(_portalVue.default),_vue.default.use(_bootstrapVue.default)}));
//# sourceMappingURL=page-myreport.min.js.map

View File

@ -1 +1 @@
{"version":3,"file":"page-myreport.min.js","sources":["../src/page-myreport.js"],"sourcesContent":["/*eslint no-var: \"error\" */\n/*eslint no-unused-vars: \"off\" */\n/*eslint linebreak-style: \"off\" */\n/*eslint no-trailing-spaces: \"off\" */\n/*eslint no-console: \"off\" */\n/*eslint-env es6*/\n// Put this file in path/to/plugin/amd/src\n// You can call it anything you like\n\nimport {call} from 'core/ajax';\nimport notification from 'core/notification';\n\nimport Vue from './vue/vue';\n\nimport RVComponents from './report-viewer-components';\nVue.use(RVComponents);\nimport TSComponents from './treestudyplan-components';\n\nimport Debugger from './util/debugger';\n\nimport {ProcessStudyplans} from './studyplan-processor';\n\n\nimport PortalVue from './portal-vue/portal-vue.esm';\nVue.use(PortalVue);\nimport BootstrapVue from './bootstrap-vue/bootstrap-vue';\nVue.use(BootstrapVue);\n\nlet debug = new Debugger(\"treestudyplan-report\");\n\n/**\n * Initialize the Page\n * @param {string} type Type of page to show\n * @param {Object} arg Arguments passed\n */\n export function init(type=\"myreport\",arg) {\n let app = new Vue({\n el: '#root',\n data: {\n \"studyplans\": [],\n },\n mounted() {\n let call_method;\n let call_args;\n if(type == \"invited\"){\n call_method = 'local_treestudyplan_get_invited_studyplan';\n call_args = {\"invitekey\": arg};\n }\n else if(type == \"other\"){\n call_method = 'local_treestudyplan_get_user_studyplans';\n call_args = {\"userid\": arg};\n }\n else if(type == \"teaching\"){\n call_method = 'local_treestudyplan_get_teaching_studyplans';\n call_args = {};\n }\n else{\n call_method = 'local_treestudyplan_get_own_studyplan';\n call_args = {};\n }\n call([{\n methodname: call_method,\n args: call_args\n }])[0].done(function(response){\n debug.info(\"Studyplans:\",response);\n const timingval = { future: 0, present: 1, past: 2, };\n response.sort((a,b) => {\n const timinga = TSComponents.studyplanTiming(a);\n const timingb = TSComponents.studyplanTiming(b);\n\n let t = timingval[timinga] - timingval[timingb];\n if(t == 0){\n // sort by start date if timing is equal\n t = new Date(b.startdate).getTime() - new Date(a.startdate).getTime();\n\n if (t == 0) {\n // sort by name if timing is equal\n t = a.name.localeCompare(b.name);\n }\n }\n return t;\n });\n app.studyplans = ProcessStudyplans(response);\n }).fail(notification.exception);\n\n },\n\n methods: {\n\n },\n });\n\n}\n\n"],"names":["type","arg","app","Vue","el","data","mounted","call_method","call_args","methodname","args","done","response","debug","info","timingval","future","present","past","sort","a","b","timinga","TSComponents","studyplanTiming","timingb","t","Date","startdate","getTime","name","localeCompare","studyplans","fail","notification","exception","methods","use","RVComponents","PortalVue","BootstrapVue","Debugger"],"mappings":"ikBAmCsBA,4DAAK,WAAWC,2CAC9BC,IAAM,IAAIC,aAAI,CACdC,GAAI,QACJC,KAAM,YACY,IAElBC,uBACQC,YACAC,UACO,WAARR,MACCO,YAAc,4CACdC,UAAY,WAAcP,MAEd,SAARD,MACJO,YAAc,0CACdC,UAAY,QAAWP,MAEX,YAARD,MACJO,YAAc,8CACdC,UAAY,KAGZD,YAAc,wCACdC,UAAY,mBAEX,CAAC,CACFC,WAAYF,YACZG,KAAMF,aACN,GAAGG,MAAK,SAASC,UACjBC,MAAMC,KAAK,cAAcF,cACnBG,UAAY,CAAEC,OAAQ,EAAGC,QAAS,EAAGC,KAAM,GACjDN,SAASO,MAAK,SAACC,EAAEC,OACPC,QAAUC,iCAAaC,gBAAgBJ,GACvCK,QAAUF,iCAAaC,gBAAgBH,GAEzCK,EAAIX,UAAUO,SAAWP,UAAUU,gBAC/B,GAALC,GAIU,IAFTA,EAAI,IAAIC,KAAKN,EAAEO,WAAWC,UAAY,IAAIF,KAAKP,EAAEQ,WAAWC,aAIxDH,EAAIN,EAAEU,KAAKC,cAAcV,EAAES,OAG5BJ,KAEXxB,IAAI8B,YAAa,yCAAkBpB,aACpCqB,KAAKC,sBAAaC,YAIzBC,QAAS,yYAxEbC,IAAIC,8CASJD,IAAIE,iCAEJF,IAAIG,2BAEJ3B,MAAQ,IAAI4B,kBAAS"}
{"version":3,"file":"page-myreport.min.js","sources":["../src/page-myreport.js"],"sourcesContent":["/* eslint no-unused-vars: \"off\" */\n/* eslint-env es6*/\n// Put this file in path/to/plugin/amd/src\n// You can call it anything you like\n\nimport Vue from './vue/vue';\n\nimport RVComponents from './report-viewer-components';\nVue.use(RVComponents);\n\nimport PortalVue from './portal-vue/portal-vue.esm';\nVue.use(PortalVue);\nimport BootstrapVue from './bootstrap-vue/bootstrap-vue';\nVue.use(BootstrapVue);\n\n/**\n * Initialize the Page\n * @param {string} type Type of page to show\n * @param {Object} arg1 Argument1 as passed\n */\n export function init(type = \"own\", arg1) {\n let app = new Vue({\n el: '#root',\n data: {\n \"studyplans\": [],\n \"type\": type,\n \"invitekey\": (type == \"invited\") ? arg1 : null,\n \"userid\": (type == \"other\") ? arg1 : null,\n },\n methods: {\n\n },\n });\n\n}\n\n"],"names":["type","arg1","Vue","el","data","methods","use","RVComponents","PortalVue","BootstrapVue"],"mappings":"+YAoBsBA,4DAAO,MAAOC,4CACtB,IAAIC,aAAI,CACdC,GAAI,QACJC,KAAM,YACY,QACNJ,eACc,WAARA,KAAqBC,KAAO,YACvB,SAARD,KAAmBC,KAAO,MAEzCI,QAAS,+NArBbC,IAAIC,8CAGJD,IAAIE,iCAEJF,IAAIG"}

3
amd/build/page-result-overview.min.js vendored Normal file
View File

@ -0,0 +1,3 @@
define("local_treestudyplan/page-result-overview",["exports","core/ajax","core/notification","./vue/vue","./util/debugger","./util/string-helper","./studyplan-report-components","./report-viewer-components","./modedit-modal","./portal-vue/portal-vue.esm","./bootstrap-vue/bootstrap-vue"],(function(_exports,_ajax,_notification,_vue,_debugger,_stringHelper,_studyplanReportComponents,_reportViewerComponents,_modeditModal,_portalVue,_bootstrapVue){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=function(studyplanid,pageid,firstperiod,lastperiod){if(void 0===pageid||!Number.isInteger(Number(pageid))||void 0===studyplanid||!Number.isInteger(Number(studyplanid)))return void debug.error("Error: studyplan id and page id not provided as integer numbers to script.",studyplanid,pageid,firstperiod,lastperiod);studyplanid=Number(studyplanid),pageid=Number(pageid);new _vue.default({el:"#root",data:{structure:null,studyplan:null,page:null,text:strings.studyplanReport},created(){this.loadStructure(pageid,firstperiod,lastperiod)},computed:{},methods:{loadStructure(pageid,firstperiod,lastperiod){const self=this;this.structure=null,(0,_ajax.call)([{methodname:"local_treestudyplan_get_report_structure",args:{pageid:pageid,firstperiod:firstperiod,lastperiod:lastperiod}}])[0].then((response=>{self.structure=response,self.studyplan=response.studyplan,self.page=response.page})).catch(_notification.default.exception)},selectedPage(e){debug.info("SelectedPage",e);const pageid=e.target.value;this.loadStructure(pageid)},selectedFirstPeriod(e){debug.info("selectedFirstPeriod",e);let f=e.target.value,l=this.structure.lastperiod;l<f&&(l=f),this.loadStructure(this.page.id,f,l)},selectedLastPeriod(e){debug.info("selectedLastPeriod",e);let f=this.structure.firstperiod,l=e.target.value;l<f&&(l=f),this.loadStructure(this.page.id,f,l)}}})},_notification=_interopRequireDefault(_notification),_vue=_interopRequireDefault(_vue),_debugger=_interopRequireDefault(_debugger),_studyplanReportComponents=_interopRequireDefault(_studyplanReportComponents),_reportViewerComponents=_interopRequireDefault(_reportViewerComponents),_modeditModal=_interopRequireDefault(_modeditModal),_portalVue=_interopRequireDefault(_portalVue),_bootstrapVue=_interopRequireDefault(_bootstrapVue),_vue.default.use(_studyplanReportComponents.default),_vue.default.use(_reportViewerComponents.default),_vue.default.use(_modeditModal.default),_vue.default.use(_portalVue.default),_vue.default.use(_bootstrapVue.default);let debug=new _debugger.default("treestudyplanviewer"),strings=(0,_stringHelper.loadStrings)({studyplanReport:{studyplan:"studyplan",page:"studyplanpage",periods:"periods",period:"period",loading:"loading@core",all:"all@core",from:"from@core",to:"to@core"}})}));
//# sourceMappingURL=page-result-overview.min.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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/primary-nav-tools",["exports"],(function(_exports){function _typeof(obj){return _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(obj){return typeof obj}:function(obj){return obj&&"function"==typeof Symbol&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj},_typeof(obj)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.hide_primary=function(hrefs){var element=document.createElement("style");document.head.appendChild(element);var sheet=element.sheet;("string"==typeof hrefs||hrefs instanceof String)&&(hrefs=[hrefs]);if("object"===_typeof(hrefs)&&Array.isArray(hrefs))for(var ix in hrefs){var href=hrefs[ix],style='\n .primary-navigation li.nav-item > a[href*="'.concat(href,'"] {\n display: none;\n }\n ');sheet.insertRule(style,sheet.cssRules.length)}}}));
define("local_treestudyplan/primary-nav-tools",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.hidePrimary=function(hrefs){("string"==typeof hrefs||hrefs instanceof String)&&(hrefs=[hrefs]);if("object"==typeof hrefs&&Array.isArray(hrefs)){let css="";for(const ix in hrefs){const href=hrefs[ix];css+=`\n .primary-navigation a[href*="${href}"],\n #usernavigation a[href*="${href}"],\n .drawer-primary a[href*="${href}"] {\n display: none !important;\n }\n `}const element=document.createElement("style");element.setAttribute("type","text/css"),"textContent"in element?element.textContent=css:element.styleSheet.cssText=css,document.head.appendChild(element)}}}));
//# sourceMappingURL=primary-nav-tools.min.js.map

View File

@ -1 +1 @@
{"version":3,"file":"primary-nav-tools.min.js","sources":["../src/primary-nav-tools.js"],"sourcesContent":["/*eslint-env es6*/\n\n/**\n * Hide a primary navigation item by href\n * @param {string|Array} hrefs The link that should be hidden\n */\nexport function hide_primary(hrefs) {\n let element = document.createElement('style');\n document.head.appendChild(element);\n let sheet = element.sheet;\n\n if(typeof hrefs === 'string' || hrefs instanceof String){\n hrefs = [hrefs];\n }\n\n if(typeof hrefs === 'object' && Array.isArray(hrefs)){\n for(const ix in hrefs){\n const href = hrefs[ix];\n let style = `\n .primary-navigation li.nav-item > a[href*=\"${href}\"] {\n display: none;\n }\n `;\n sheet.insertRule(style, sheet.cssRules.length);\n }\n }\n}\n"],"names":["hrefs","element","document","createElement","head","appendChild","sheet","String","_typeof","Array","isArray","ix","href","style","insertRule","cssRules","length"],"mappings":"gbAM6BA,WACrBC,QAAUC,SAASC,cAAc,SACrCD,SAASE,KAAKC,YAAYJ,aACtBK,MAAQL,QAAQK,OAEA,iBAAVN,OAAsBA,iBAAiBO,UAC7CP,MAAQ,CAACA,WAGO,WAAjBQ,QAAOR,QAAsBS,MAAMC,QAAQV,WACtC,IAAMW,MAAMX,MAAM,KACZY,KAAOZ,MAAMW,IACfE,6EAC6CD,kFAIjDN,MAAMQ,WAAWD,MAAOP,MAAMS,SAASC"}
{"version":3,"file":"primary-nav-tools.min.js","sources":["../src/primary-nav-tools.js"],"sourcesContent":["/* eslint-env es6*/\n/* eslint no-console: \"off\"*/\n\n/**\n * Hide a primary navigation item by href\n * @param {string|Array} hrefs The link that should be hidden\n */\nexport function hidePrimary(hrefs) {\n if (typeof hrefs === 'string' || hrefs instanceof String) {\n hrefs = [hrefs];\n }\n\n if (typeof hrefs === 'object' && Array.isArray(hrefs)) {\n let css = '';\n for (const ix in hrefs) {\n const href = hrefs[ix];\n css += `\n .primary-navigation a[href*=\"${href}\"],\n #usernavigation a[href*=\"${href}\"],\n .drawer-primary a[href*=\"${href}\"] {\n display: none !important;\n }\n `;\n }\n\n\n const element = document.createElement('style');\n element.setAttribute('type', 'text/css');\n\n if ('textContent' in element) {\n element.textContent = css;\n } else {\n element.styleSheet.cssText = css;\n }\n\n document.head.appendChild(element);\n\n }\n}\n"],"names":["hrefs","String","Array","isArray","css","ix","href","element","document","createElement","setAttribute","textContent","styleSheet","cssText","head","appendChild"],"mappings":"qKAO4BA,QACH,iBAAVA,OAAsBA,iBAAiBC,UAC9CD,MAAQ,CAACA,WAGQ,iBAAVA,OAAsBE,MAAMC,QAAQH,OAAQ,KAC/CI,IAAM,OACL,MAAMC,MAAML,MAAO,OACdM,KAAON,MAAMK,IACnBD,KAAQ,kDAC2BE,qDACJA,qDACAA,iGAO7BC,QAAUC,SAASC,cAAc,SACvCF,QAAQG,aAAa,OAAQ,YAEzB,gBAAiBH,QACjBA,QAAQI,YAAcP,IAEtBG,QAAQK,WAAWC,QAAUT,IAGjCI,SAASM,KAAKC,YAAYR"}

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/simpleline/css-calc",["exports"],(function(_exports){function ownKeys(object,enumerableOnly){var keys=Object.keys(object);if(Object.getOwnPropertySymbols){var symbols=Object.getOwnPropertySymbols(object);enumerableOnly&&(symbols=symbols.filter((function(sym){return Object.getOwnPropertyDescriptor(object,sym).enumerable}))),keys.push.apply(keys,symbols)}return keys}function _objectSpread(target){for(var i=1;i<arguments.length;i++){var source=null!=arguments[i]?arguments[i]:{};i%2?ownKeys(Object(source),!0).forEach((function(key){_defineProperty(target,key,source[key])})):Object.getOwnPropertyDescriptors?Object.defineProperties(target,Object.getOwnPropertyDescriptors(source)):ownKeys(Object(source)).forEach((function(key){Object.defineProperty(target,key,Object.getOwnPropertyDescriptor(source,key))}))}return target}function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.Units=_exports.UnitRegexpStr=_exports.UnitRegexpGM=_exports.UnitRegexp=_exports.Relative=_exports.Absolute=void 0,_exports.calc=calc,_exports.calcCtx=calcCtx,_exports.convert=convert,_exports.convertAllInStr=convertAllInStr;var Absolute={px:1,cm:96/2.54,mm:96/25.4,Q:96/101.6,in:96,pc:16,pt:96/72};_exports.Absolute=Absolute;var Relative={vh:function(){var count=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,ctx=arguments.length>1?arguments[1]:void 0;return(ctx?ctx.viewportHeight:window.innerHeight)/100*count},vw:function(){var count=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,ctx=arguments.length>1?arguments[1]:void 0;return(ctx?ctx.viewportWidth:window.innerWidth)/100*count},vmin:function(){var count=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,ctx=arguments.length>1?arguments[1]:void 0;return(ctx?Math.min(ctx.viewportWidth,ctx.viewportHeight):Math.min(window.innerWidth,window.innerHeight))/100*count},vmax:function(){var count=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,ctx=arguments.length>1?arguments[1]:void 0;return(ctx?Math.max(ctx.viewportWidth,ctx.viewportHeight):Math.max(window.innerWidth,window.innerHeight))/100*count},rem:function(){var count=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,ctx=arguments.length>1?arguments[1]:void 0;return(ctx?ctx.htmlFontSize:parseFloat(window.getComputedStyle(document.querySelector("html")).fontSize))*count},"%w":function(){var count=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,ctx=arguments.length>1?arguments[1]:void 0;return(ctx?ctx.width:document.body.clientWidth)/100*count},"%h":function(){var count=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,ctx=arguments.length>1?arguments[1]:void 0;return(ctx?ctx.height:document.body.clientHeight)/100*count}};_exports.Relative=Relative;var Units=_objectSpread(_objectSpread({},Relative),Absolute);_exports.Units=Units;var UnitRegexpStr="(?:\\s|^)(\\d*(?:\\.\\d+)?)(".concat(Object.keys(Units).join("|"),")(?:\\s|$|\\n)");_exports.UnitRegexpStr=UnitRegexpStr;var UnitRegexp=new RegExp(UnitRegexpStr);_exports.UnitRegexp=UnitRegexp;var UnitRegexpGM=new RegExp(UnitRegexpStr,"gm");function convert(count,fromUnits,toUnits){var ctx=arguments.length>3&&void 0!==arguments[3]?arguments[3]:calcCtx(),baseUnit=Units[fromUnits],basePx="function"==typeof baseUnit?baseUnit(count,ctx):baseUnit*count,dstUnit=Units[toUnits];return basePx/("function"==typeof dstUnit?dstUnit(1,ctx):dstUnit)}function convertAllInStr(expr,toUnits){var ctx=arguments.length>2&&void 0!==arguments[2]?arguments[2]:calcCtx();return expr.replace(UnitRegexpGM,(function(substr,count,unit){return convert(parseFloat(count),unit,toUnits,ctx).toString()}))}function calcCtx(el){if(el){var rect=el.getBoundingClientRect();return{width:rect.width,height:rect.height,viewportWidth:window.innerWidth,viewportHeight:window.innerHeight,htmlFontSize:parseFloat(window.getComputedStyle(document.querySelector("html")).fontSize)}}return{width:document.body.clientWidth,height:document.body.clientHeight,viewportWidth:window.innerWidth,viewportHeight:window.innerHeight,htmlFontSize:parseFloat(window.getComputedStyle(document.querySelector("html")).fontSize)}}function calc(expression,el_ctx,ctx){return void 0===el_ctx?ctx=calcCtx():el_ctx instanceof HTMLElement?ctx||(ctx=calcCtx(el_ctx)):ctx=el_ctx,eval(convertAllInStr(expression,"px",ctx))}_exports.UnitRegexpGM=UnitRegexpGM}));
define("local_treestudyplan/simpleline/css-calc",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.Units=_exports.UnitRegexpStr=_exports.UnitRegexpGM=_exports.UnitRegexp=_exports.Relative=_exports.Absolute=void 0,_exports.calc=calc,_exports.calcCtx=calcCtx,_exports.convert=convert,_exports.convertAllInStr=convertAllInStr;const Absolute={px:1,cm:96/2.54,mm:96/25.4,Q:96/101.6,in:96,pc:16,pt:96/72};_exports.Absolute=Absolute;const Relative={vh:function(){let count=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,ctx=arguments.length>1?arguments[1]:void 0;return(ctx?ctx.viewportHeight:window.innerHeight)/100*count},vw:function(){let count=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,ctx=arguments.length>1?arguments[1]:void 0;return(ctx?ctx.viewportWidth:window.innerWidth)/100*count},vmin:function(){let count=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,ctx=arguments.length>1?arguments[1]:void 0;return(ctx?Math.min(ctx.viewportWidth,ctx.viewportHeight):Math.min(window.innerWidth,window.innerHeight))/100*count},vmax:function(){let count=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,ctx=arguments.length>1?arguments[1]:void 0;return(ctx?Math.max(ctx.viewportWidth,ctx.viewportHeight):Math.max(window.innerWidth,window.innerHeight))/100*count},rem:function(){let count=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,ctx=arguments.length>1?arguments[1]:void 0;return(ctx?ctx.htmlFontSize:parseFloat(window.getComputedStyle(document.querySelector("html")).fontSize))*count},"%w":function(){let count=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,ctx=arguments.length>1?arguments[1]:void 0;return(ctx?ctx.width:document.body.clientWidth)/100*count},"%h":function(){let count=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,ctx=arguments.length>1?arguments[1]:void 0;return(ctx?ctx.height:document.body.clientHeight)/100*count}};_exports.Relative=Relative;const Units={...Relative,...Absolute};_exports.Units=Units;const UnitRegexpStr=`(?:\\s|^)(\\d*(?:\\.\\d+)?)(${Object.keys(Units).join("|")})(?:\\s|$|\\n)`;_exports.UnitRegexpStr=UnitRegexpStr;const UnitRegexp=new RegExp(UnitRegexpStr);_exports.UnitRegexp=UnitRegexp;const UnitRegexpGM=new RegExp(UnitRegexpStr,"gm");function convert(count,fromUnits,toUnits){let ctx=arguments.length>3&&void 0!==arguments[3]?arguments[3]:calcCtx();const baseUnit=Units[fromUnits],basePx="function"==typeof baseUnit?baseUnit(count,ctx):baseUnit*count,dstUnit=Units[toUnits];return basePx/("function"==typeof dstUnit?dstUnit(1,ctx):dstUnit)}function convertAllInStr(expr,toUnits){let ctx=arguments.length>2&&void 0!==arguments[2]?arguments[2]:calcCtx();return expr.replace(UnitRegexpGM,((substr,count,unit)=>convert(parseFloat(count),unit,toUnits,ctx).toString()))}function calcCtx(el){if(el){const rect=el.getBoundingClientRect();return{width:rect.width,height:rect.height,viewportWidth:window.innerWidth,viewportHeight:window.innerHeight,htmlFontSize:parseFloat(window.getComputedStyle(document.querySelector("html")).fontSize)}}return{width:document.body.clientWidth,height:document.body.clientHeight,viewportWidth:window.innerWidth,viewportHeight:window.innerHeight,htmlFontSize:parseFloat(window.getComputedStyle(document.querySelector("html")).fontSize)}}function calc(expression,el_ctx,ctx){return void 0===el_ctx?ctx=calcCtx():el_ctx instanceof HTMLElement?ctx||(ctx=calcCtx(el_ctx)):ctx=el_ctx,eval(convertAllInStr(expression,"px",ctx))}_exports.UnitRegexpGM=UnitRegexpGM}));
//# sourceMappingURL=css-calc.min.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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/studyplan-processor",["exports"],(function(_exports){function ProcessStudyplan(studyplan){var connections={};for(var ip in studyplan.pages){var page=studyplan.pages[ip];for(var il in page.studylines){var line=page.studylines[il];for(var is in line.slots){var slot=line.slots[is];if(void 0!==slot.courses)for(var ic in slot.courses){var itm=slot.courses[ic];for(var idx in itm.connections.in){var conn=itm.connections.in[idx];conn.id in connections?itm.connections[idx]=connections[conn.id]:connections[conn.id]=conn}for(var _idx in itm.connections.out){var _conn=itm.connections.out[_idx];_conn.id in connections?itm.connections[_idx]=connections[_conn.id]:connections[_conn.id]=_conn}}if(void 0!==slot.filters)for(var ix in slot.filters){var _itm=slot.filters[ix];for(var _idx2 in _itm.connections.in){var _conn2=_itm.connections.in[_idx2];_conn2.id in connections?_itm.connections[_idx2]=connections[_conn2.id]:connections[_conn2.id]=_conn2}for(var _idx3 in _itm.connections.out){var _conn3=_itm.connections.out[_idx3];_conn3.id in connections?_itm.connections[_idx3]=connections[_conn3.id]:connections[_conn3.id]=_conn3}}}}}return studyplan}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.ProcessStudyplan=ProcessStudyplan,_exports.ProcessStudyplans=function(studyplans){for(var isx in studyplans){ProcessStudyplan(studyplans[isx])}return studyplans},_exports.objCopy=function(target,source,fields){for(var ix in fields){var field=fields[ix];target[field]=source[field]}},_exports.transportItem=function(target,source,identifier,param){param||(param="value");var item,itemindex;for(var ix in source)if(source[ix][param]==identifier){item=source[ix],itemindex=ix;break}item&&(target.push(item),source.splice(itemindex,1))}}));
define("local_treestudyplan/studyplan-processor",["exports"],(function(_exports){function processStudyplan(studyplan){for(const ip in studyplan.pages){processStudyplanPage(studyplan.pages[ip])}return studyplan}function processStudyplanPage(page){let connections={};for(const il in page.studylines){const line=page.studylines[il];for(const is in line.slots){const slot=line.slots[is];if(void 0!==slot.courses)for(const ic in slot.courses){const itm=slot.courses[ic];for(const idx in itm.connections.in){const conn=itm.connections.in[idx];conn.id in connections?itm.connections[idx]=connections[conn.id]:connections[conn.id]=conn}for(const idx in itm.connections.out){const conn=itm.connections.out[idx];conn.id in connections?itm.connections[idx]=connections[conn.id]:connections[conn.id]=conn}}if(void 0!==slot.filters)for(const ix in slot.filters){const itm=slot.filters[ix];for(const idx in itm.connections.in){const conn=itm.connections.in[idx];conn.id in connections?itm.connections[idx]=connections[conn.id]:connections[conn.id]=conn}for(const idx in itm.connections.out){const conn=itm.connections.out[idx];conn.id in connections?itm.connections[idx]=connections[conn.id]:connections[conn.id]=conn}}}}return page}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.objCopy=function(target,source,fields){null==fields&&(fields=Object.getOwnPropertyNames(source));for(const ix in fields){const field=fields[ix];target[field]=source[field]}return target},_exports.processStudyplan=processStudyplan,_exports.processStudyplanPage=processStudyplanPage,_exports.processStudyplans=function(studyplans){for(const isx in studyplans){processStudyplan(studyplans[isx])}return studyplans},_exports.transportItem=function(target,source,identifier,param){param||(param="value");let item,itemindex;for(const ix in source)if(source[ix][param]==identifier){item=source[ix],itemindex=ix;break}item&&(target.push(item),source.splice(itemindex,1))}}));
//# sourceMappingURL=studyplan-processor.min.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,3 @@
define("local_treestudyplan/util/browserbuttonevents",["exports","./debugger"],(function(_exports,_debugger){var obj;Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.addBrowserButtonEvent=function(backwardCB){let forwardCB=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,reloadCB=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;debug.log("Registering navigation events",backwardCB,forwardCB,reloadCB);addEventListener("popstate",(e=>{const positionLastShown=Number(sessionStorage.getItem("positionLastShown"));let position=history.state;null===position&&(position=positionLastShown+1,history.replaceState(position,"")),sessionStorage.setItem("positionLastShown",String(position));const direction=Math.sign(position-positionLastShown);debug.log("Travel direction is "+direction),-1==direction&&backwardCB&&backwardCB(),1==direction&&forwardCB&&forwardCB(),0==direction&&reloadCB&&reloadCB()}))};const debug=new(_debugger=(obj=_debugger)&&obj.__esModule?obj:{default:obj}).default("browserbuttonevents")}));
//# sourceMappingURL=browserbuttonevents.min.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"browserbuttonevents.min.js","sources":["../../src/util/browserbuttonevents.js"],"sourcesContent":["/* eslint no-var: \"error\" */\n/* eslint no-unused-vars: \"off\" */\n/* eslint linebreak-style: \"off\" */\n/* eslint no-trailing-spaces: \"off\" */\n/* eslint capitalized-comments: \"off\" */\n/* eslint-env es6 */\n\nimport Debugger from './debugger';\nconst debug = new Debugger(\"browserbuttonevents\");\n\n/**\n * \n * @param {function} backwardCB \n * @param {function} forwardCB \n * @param {function} reloadCB \n */\nexport function addBrowserButtonEvent(backwardCB, forwardCB = null, reloadCB = null) {\n debug.log(\"Registering navigation events\", backwardCB, forwardCB, reloadCB);\n const reorient = (e) => { // After travelling in the history stack\n const positionLastShown = Number( // If none, then zero\n sessionStorage.getItem('positionLastShown'));\n // debug.log(\"Popstate event\",e,positionLastShown,history);\n let position = history.state; // Absolute position in stack\n if (position === null) { // Meaning a new entry on the stack\n position = positionLastShown + 1; // Top of stack\n \n // (1) Stamp the entry with its own position in the stack\n history.replaceState(position, /* no title */''); \n }\n \n // (2) Keep track of the last position shown\n sessionStorage.setItem('positionLastShown', String(position));\n \n // (3) Discover the direction of travel by comparing the two\n const direction = Math.sign(position - positionLastShown);\n debug.log('Travel direction is ' + direction); \n // One of backward (-1), reload (0) and forward (1)\n if (direction == -1 && backwardCB) {\n backwardCB();\n }\n if (direction == 1 && forwardCB) {\n forwardCB();\n }\n if (direction == 0 && reloadCB) {\n reloadCB();\n }\n };\n // addEventListener( 'pageshow', reorient );\n addEventListener('popstate', reorient); // Travel in same page\n}"],"names":["backwardCB","forwardCB","reloadCB","debug","log","addEventListener","e","positionLastShown","Number","sessionStorage","getItem","position","history","state","replaceState","setItem","String","direction","Math","sign"],"mappings":"qNAgBsCA,gBAAYC,iEAAY,KAAMC,gEAAW,KAC3EC,MAAMC,IAAI,gCAAiCJ,WAAYC,UAAWC,UA+BlEG,iBAAiB,YA9BCC,UACRC,kBAAoBC,OACxBC,eAAeC,QAAQ,0BAErBC,SAAWC,QAAQC,MACN,OAAbF,WACAA,SAAWJ,kBAAoB,EAG/BK,QAAQE,aAAaH,SAAwB,KAIjDF,eAAeM,QAAQ,oBAAqBC,OAAOL,iBAG7CM,UAAYC,KAAKC,KAAKR,SAAWJ,mBACvCJ,MAAMC,IAAI,uBAAyBa,YAEjB,GAAdA,WAAmBjB,YACnBA,aAEa,GAAbiB,WAAkBhB,WAClBA,YAEa,GAAbgB,WAAkBf,UAClBA,qBApCNC,MAAQ,yEAAa"}

3
amd/build/util/css-calc.min.js vendored Normal file
View File

@ -0,0 +1,3 @@
define("local_treestudyplan/util/css-calc",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.Units=_exports.UnitRegexpStr=_exports.UnitRegexpGM=_exports.UnitRegexp=_exports.Relative=_exports.Absolute=void 0,_exports.calc=calc,_exports.calcCtx=calcCtx,_exports.convert=convert,_exports.convertAllInStr=convertAllInStr;const Absolute={px:1,cm:96/2.54,mm:96/25.4,Q:96/101.6,in:96,pc:16,pt:96/72};_exports.Absolute=Absolute;const Relative={vh:function(){let count=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,ctx=arguments.length>1?arguments[1]:void 0;return(ctx?ctx.viewportHeight:window.innerHeight)/100*count},vw:function(){let count=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,ctx=arguments.length>1?arguments[1]:void 0;return(ctx?ctx.viewportWidth:window.innerWidth)/100*count},vmin:function(){let count=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,ctx=arguments.length>1?arguments[1]:void 0;return(ctx?Math.min(ctx.viewportWidth,ctx.viewportHeight):Math.min(window.innerWidth,window.innerHeight))/100*count},vmax:function(){let count=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,ctx=arguments.length>1?arguments[1]:void 0;return(ctx?Math.max(ctx.viewportWidth,ctx.viewportHeight):Math.max(window.innerWidth,window.innerHeight))/100*count},rem:function(){let count=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,ctx=arguments.length>1?arguments[1]:void 0;return(ctx?ctx.htmlFontSize:parseFloat(window.getComputedStyle(document.querySelector("html")).fontSize))*count},"%w":function(){let count=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,ctx=arguments.length>1?arguments[1]:void 0;return(ctx?ctx.width:document.body.clientWidth)/100*count},"%h":function(){let count=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,ctx=arguments.length>1?arguments[1]:void 0;return(ctx?ctx.height:document.body.clientHeight)/100*count}};_exports.Relative=Relative;const Units={...Relative,...Absolute};_exports.Units=Units;const UnitRegexpStr=`(?:\\s|^)(\\d*(?:\\.\\d+)?)(${Object.keys(Units).join("|")})(?:\\s|$|\\n)`;_exports.UnitRegexpStr=UnitRegexpStr;const UnitRegexp=new RegExp(UnitRegexpStr);_exports.UnitRegexp=UnitRegexp;const UnitRegexpGM=new RegExp(UnitRegexpStr,"gm");function convert(count,fromUnits,toUnits){let ctx=arguments.length>3&&void 0!==arguments[3]?arguments[3]:calcCtx();const baseUnit=Units[fromUnits],basePx="function"==typeof baseUnit?baseUnit(count,ctx):baseUnit*count,dstUnit=Units[toUnits];return basePx/("function"==typeof dstUnit?dstUnit(1,ctx):dstUnit)}function convertAllInStr(expr,toUnits){let ctx=arguments.length>2&&void 0!==arguments[2]?arguments[2]:calcCtx();return expr.replace(UnitRegexpGM,((substr,count,unit)=>convert(parseFloat(count),unit,toUnits,ctx).toString()))}function calcCtx(el){if(el){const rect=el.getBoundingClientRect();return{width:rect.width,height:rect.height,viewportWidth:window.innerWidth,viewportHeight:window.innerHeight,htmlFontSize:parseFloat(window.getComputedStyle(document.querySelector("html")).fontSize)}}return{width:document.body.clientWidth,height:document.body.clientHeight,viewportWidth:window.innerWidth,viewportHeight:window.innerHeight,htmlFontSize:parseFloat(window.getComputedStyle(document.querySelector("html")).fontSize)}}function calc(expression,el_ctx,ctx){return void 0===el_ctx?ctx=calcCtx():el_ctx instanceof HTMLElement?ctx||(ctx=calcCtx(el_ctx)):ctx=el_ctx,eval(convertAllInStr(expression,"px",ctx))}_exports.UnitRegexpGM=UnitRegexpGM}));
//# sourceMappingURL=css-calc.min.js.map

File diff suppressed because one or more lines are too long

View File

@ -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));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.add_days=function(datestr,days){var date=new Date(datestr);return function(date){var d=new Date(date),month=""+(d.getMonth()+1),day=""+d.getDate(),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);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}));
define("local_treestudyplan/util/date-helper",["exports"],(function(_exports){function formatDate(d,short){d instanceof Date||("number"==typeof d&&(d*=1e3),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.addDays=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:formatDate(first),last:formatDate(last)}}},_exports.formatDate=formatDate,_exports.formatDatetime=function(d,short){d instanceof Date||("number"==typeof d&&(d*=1e3),d=new Date(d));let monthformat="short";!0===short?monthformat="numeric":!1===short&&(monthformat="long");return d.toLocaleDateString(document.documentElement.lang,{year:"numeric",month:monthformat,day:"numeric"})+" "+d.toLocaleTimeString(document.documentElement.lang,{timeStyle:"short"})},_exports.studyplanDates=studyplanDates,_exports.studyplanPageTiming=function(page){const now=(new Date).getTime();if(page.timeless)return"present";const 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();if(!plan.pages&&0==plan.pages.length||plan.pages[0]&&plan.pages[0].timeless)return"present";const 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

View File

@ -1,3 +1,3 @@
define("local_treestudyplan/util/debounce",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.debounce=function(func,wait,immediate){var timeout;return function(){var context=this,args=arguments,callNow=immediate&&!timeout;clearTimeout(timeout),timeout=setTimeout((function(){timeout=null,immediate||func.apply(context,args)}),wait),callNow&&func.apply(context,args)}}}));
define("local_treestudyplan/util/debounce",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.debounce=function(func,wait,immediate){let timeout;return function(){let context=this,args=arguments,callNow=immediate&&!timeout;clearTimeout(timeout),timeout=setTimeout((function(){timeout=null,immediate||func.apply(context,args)}),wait),callNow&&func.apply(context,args)}}}));
//# sourceMappingURL=debounce.min.js.map

View File

@ -1 +1 @@
{"version":3,"file":"debounce.min.js","sources":["../../src/util/debounce.js"],"sourcesContent":["/*eslint no-var: \"error\"*/\n/*eslint no-console: \"off\"*/\n/*eslint-env es6*/\n// Put this file in path/to/plugin/amd/src\n// You can call it anything you like\n\n/**\n * Limits consecutive function calls.\n * @param {function} func The function to wrap.\n * @param {int} wait The time limit between function calls.\n * @param {bool} immediate perform the actual function call first rather than after the timout passed.\n * @returns {function} a new function that wraps the debounce.\n */\nfunction debounce(func, wait, immediate) {\n let timeout;\n return function() {\n let context = this, args = arguments;\n let later = function() {\n timeout = null;\n if (!immediate){ func.apply(context, args); }\n };\n let callNow = immediate && !timeout;\n clearTimeout(timeout);\n timeout = setTimeout(later, wait);\n if (callNow){ func.apply(context, args); }\n };\n}\n\nexport {debounce};"],"names":["func","wait","immediate","timeout","context","this","args","arguments","callNow","clearTimeout","setTimeout","apply"],"mappings":"8JAakBA,KAAMC,KAAMC,eACtBC,eACG,eACCC,QAAUC,KAAMC,KAAOC,UAKvBC,QAAUN,YAAcC,QAC5BM,aAAaN,SACbA,QAAUO,YANE,WACRP,QAAU,KACLD,WAAYF,KAAKW,MAAMP,QAASE,QAIbL,MACxBO,SAAUR,KAAKW,MAAMP,QAASE"}
{"version":3,"file":"debounce.min.js","sources":["../../src/util/debounce.js"],"sourcesContent":["/* eslint no-var: \"error\"*/\n/* eslint no-console: \"off\"*/\n/* eslint-env es6*/\n// Put this file in path/to/plugin/amd/src\n// You can call it anything you like\n\n/**\n * Limits consecutive function calls.\n * @param {function} func The function to wrap.\n * @param {int} wait The time limit between function calls.\n * @param {bool} immediate perform the actual function call first rather than after the timout passed.\n * @returns {function} a new function that wraps the debounce.\n */\nfunction debounce(func, wait, immediate) {\n let timeout;\n return function() {\n let context = this;\n let args = arguments;\n let later = function() {\n timeout = null;\n if (!immediate) {\n func.apply(context, args);\n }\n };\n let callNow = immediate && !timeout;\n clearTimeout(timeout);\n timeout = setTimeout(later, wait);\n if (callNow) {\n func.apply(context, args);\n }\n };\n}\n\nexport {debounce};"],"names":["func","wait","immediate","timeout","context","this","args","arguments","callNow","clearTimeout","setTimeout","apply"],"mappings":"8JAakBA,KAAMC,KAAMC,eACtBC,eACG,eACCC,QAAUC,KACVC,KAAOC,UAOPC,QAAUN,YAAcC,QAC5BM,aAAaN,SACbA,QAAUO,YARE,WACRP,QAAU,KACLD,WACDF,KAAKW,MAAMP,QAASE,QAKAL,MACxBO,SACAR,KAAKW,MAAMP,QAASE"}

View File

@ -1,3 +1,3 @@
define("local_treestudyplan/util/debugger",["exports","core/config"],(function(_exports,_config){var obj;return Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=function(handle){var output_enabled=_config.default.developerdebug;output_enabled?console.warn("In development environment. Debugger output enabled for ".concat(handle)):console.warn("In production environment. Debugger output disabled for ".concat(handle));return{write:function(){if(output_enabled){var args=Array.prototype.slice.call(arguments);args.unshift(handle+": "),console.info.apply(console,args)}},info:function(){if(output_enabled){var args=Array.prototype.slice.call(arguments);args.unshift(handle+": "),console.info.apply(console,args)}},warn:function(){if(output_enabled){var args=Array.prototype.slice.call(arguments);args.unshift(handle+": "),console.warn.apply(console,args)}},error:function(){if(output_enabled){var args=Array.prototype.slice.call(arguments);args.unshift(handle+": "),console.error.apply(console,args)}},enable:function(){output_enabled=!0},disable:function(){output_enabled=!1}}},_config=(obj=_config)&&obj.__esModule?obj:{default:obj},_exports.default}));
define("local_treestudyplan/util/debugger",["exports","core/config"],(function(_exports,_config){var obj;return Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=function(handle){let outputEnabled=_config.default.developerdebug;outputEnabled?console.warn(`In development environment. Debugger output enabled for ${handle}`):console.warn(`In production environment. Debugger output disabled for ${handle}`);return{write(){if(outputEnabled){let args=Array.prototype.slice.call(arguments);args.unshift(handle+": "),console.info.apply(console,args)}},log(){if(outputEnabled){let args=Array.prototype.slice.call(arguments);args.unshift(handle+": "),console.log.apply(console,args)}},info(){if(outputEnabled){let args=Array.prototype.slice.call(arguments);args.unshift(handle+": "),console.info.apply(console,args)}},warn(){if(outputEnabled){let args=Array.prototype.slice.call(arguments);args.unshift(handle+": "),console.warn.apply(console,args)}},error(){if(outputEnabled){let args=Array.prototype.slice.call(arguments);args.unshift(handle+": "),console.error.apply(console,args)}},time(){if(outputEnabled){let args=Array.prototype.slice.call(arguments);args.unshift(handle+": "),console.time.apply(console,args)}},timeEnd(){if(outputEnabled){let args=Array.prototype.slice.call(arguments);args.unshift(handle+": "),console.timeEnd.apply(console,args)}},timeLog(){if(outputEnabled){let args=Array.prototype.slice.call(arguments);args.unshift(handle+": "),console.timeLog.apply(console,args)}},timeStamp(){if(outputEnabled){let args=Array.prototype.slice.call(arguments);args.unshift(handle+": "),console.timeStamp.apply(console,args)}},enable(){outputEnabled=!0},disable(){outputEnabled=!1}}},_config=(obj=_config)&&obj.__esModule?obj:{default:obj},_exports.default}));
//# sourceMappingURL=debugger.min.js.map

View File

@ -1 +1 @@
{"version":3,"file":"debugger.min.js","sources":["../../src/util/debugger.js"],"sourcesContent":["/*eslint no-var: \"error\"*/\n/*eslint no-console: \"off\"*/\n/*eslint-env es6*/\n\nimport Config from \"core/config\";\n\n/**\n * Start a new debugger\n * @param {*} handle The string to attach to all messages from this debugger\n * @returns Debugger object\n */\nexport default function (handle) {\n let output_enabled = Config.developerdebug;\n if(output_enabled){\n console.warn(`In development environment. Debugger output enabled for ${handle}`);\n } else {\n console.warn(`In production environment. Debugger output disabled for ${handle}`);\n }\n\n return {\n write: function debugger_write() {\n if (output_enabled) {\n let args = Array.prototype.slice.call(arguments);\n args.unshift(handle + \": \");\n console.info.apply(console, args);\n }\n },\n info: function debugger_info() {\n if (output_enabled) {\n let args = Array.prototype.slice.call(arguments);\n args.unshift(handle + \": \");\n console.info.apply(console, args);\n }\n },\n warn: function debugger_warn() {\n if (output_enabled) {\n let args = Array.prototype.slice.call(arguments);\n args.unshift(handle + \": \");\n console.warn.apply(console, args);\n }\n },\n error: function debugger_error() {\n if (output_enabled) {\n let args = Array.prototype.slice.call(arguments);\n args.unshift(handle + \": \");\n console.error.apply(console, args);\n }\n },\n enable: function debugger_enable() {\n output_enabled = true;\n },\n\n disable: function debugger_disable() {\n output_enabled = false;\n }\n };\n\n}\n"],"names":["handle","output_enabled","Config","developerdebug","console","warn","write","args","Array","prototype","slice","call","arguments","unshift","info","apply","error","enable","disable"],"mappings":"kMAWyBA,YACjBC,eAAiBC,gBAAOC,eACzBF,eACCG,QAAQC,uEAAgEL,SAExEI,QAAQC,uEAAgEL,eAGrE,CACHM,MAAO,cACCL,eAAgB,KACZM,KAAOC,MAAMC,UAAUC,MAAMC,KAAKC,WACtCL,KAAKM,QAAQb,OAAS,MACtBI,QAAQU,KAAKC,MAAMX,QAASG,QAGpCO,KAAM,cACEb,eAAgB,KACZM,KAAOC,MAAMC,UAAUC,MAAMC,KAAKC,WACtCL,KAAKM,QAAQb,OAAS,MACtBI,QAAQU,KAAKC,MAAMX,QAASG,QAGpCF,KAAM,cACEJ,eAAgB,KACZM,KAAOC,MAAMC,UAAUC,MAAMC,KAAKC,WACtCL,KAAKM,QAAQb,OAAS,MACtBI,QAAQC,KAAKU,MAAMX,QAASG,QAGpCS,MAAO,cACCf,eAAgB,KACZM,KAAOC,MAAMC,UAAUC,MAAMC,KAAKC,WACtCL,KAAKM,QAAQb,OAAS,MACtBI,QAAQY,MAAMD,MAAMX,QAASG,QAGrCU,OAAQ,WACJhB,gBAAiB,GAGrBiB,QAAS,WACLjB,gBAAiB"}
{"version":3,"file":"debugger.min.js","sources":["../../src/util/debugger.js"],"sourcesContent":["/* eslint no-var: \"error\"*/\n/* eslint no-console: \"off\"*/\n/* eslint-env es6*/\n\nimport Config from \"core/config\";\n\n/**\n * Start a new debugger\n * @param {*} handle The string to attach to all messages from this debugger\n * @returns {object} Debugger object\n */\nexport default function(handle) {\n let outputEnabled = Config.developerdebug;\n if (outputEnabled) {\n console.warn(`In development environment. Debugger output enabled for ${handle}`);\n } else {\n console.warn(`In production environment. Debugger output disabled for ${handle}`);\n }\n\n return {\n write() {\n if (outputEnabled) {\n let args = Array.prototype.slice.call(arguments);\n args.unshift(handle + \": \");\n console.info.apply(console, args);\n }\n },\n log() {\n if (outputEnabled) {\n let args = Array.prototype.slice.call(arguments);\n args.unshift(handle + \": \");\n console.log.apply(console, args);\n }\n },\n info() {\n if (outputEnabled) {\n let args = Array.prototype.slice.call(arguments);\n args.unshift(handle + \": \");\n console.info.apply(console, args);\n }\n },\n warn() {\n if (outputEnabled) {\n let args = Array.prototype.slice.call(arguments);\n args.unshift(handle + \": \");\n console.warn.apply(console, args);\n }\n },\n error() {\n if (outputEnabled) {\n let args = Array.prototype.slice.call(arguments);\n args.unshift(handle + \": \");\n console.error.apply(console, args);\n }\n },\n time() {\n if (outputEnabled) {\n let args = Array.prototype.slice.call(arguments);\n args.unshift(handle + \": \");\n console.time.apply(console, args);\n }\n },\n timeEnd() {\n if (outputEnabled) {\n let args = Array.prototype.slice.call(arguments);\n args.unshift(handle + \": \");\n console.timeEnd.apply(console, args);\n }\n },\n timeLog() {\n if (outputEnabled) {\n let args = Array.prototype.slice.call(arguments);\n args.unshift(handle + \": \");\n console.timeLog.apply(console, args);\n }\n },\n timeStamp() {\n if (outputEnabled) {\n let args = Array.prototype.slice.call(arguments);\n args.unshift(handle + \": \");\n console.timeStamp.apply(console, args);\n }\n },\n enable() {\n outputEnabled = true;\n },\n disable() {\n outputEnabled = false;\n }\n };\n\n}\n"],"names":["handle","outputEnabled","Config","developerdebug","console","warn","write","args","Array","prototype","slice","call","arguments","unshift","info","apply","log","error","time","timeEnd","timeLog","timeStamp","enable","disable"],"mappings":"kMAWwBA,YAChBC,cAAgBC,gBAAOC,eACvBF,cACAG,QAAQC,KAAM,2DAA0DL,UAExEI,QAAQC,KAAM,2DAA0DL,gBAGrE,CACHM,WACQL,cAAe,KACXM,KAAOC,MAAMC,UAAUC,MAAMC,KAAKC,WACtCL,KAAKM,QAAQb,OAAS,MACtBI,QAAQU,KAAKC,MAAMX,QAASG,QAGpCS,SACQf,cAAe,KACXM,KAAOC,MAAMC,UAAUC,MAAMC,KAAKC,WACtCL,KAAKM,QAAQb,OAAS,MACtBI,QAAQY,IAAID,MAAMX,QAASG,QAGnCO,UACQb,cAAe,KACXM,KAAOC,MAAMC,UAAUC,MAAMC,KAAKC,WACtCL,KAAKM,QAAQb,OAAS,MACtBI,QAAQU,KAAKC,MAAMX,QAASG,QAGpCF,UACQJ,cAAe,KACXM,KAAOC,MAAMC,UAAUC,MAAMC,KAAKC,WACtCL,KAAKM,QAAQb,OAAS,MACtBI,QAAQC,KAAKU,MAAMX,QAASG,QAGpCU,WACQhB,cAAe,KACXM,KAAOC,MAAMC,UAAUC,MAAMC,KAAKC,WACtCL,KAAKM,QAAQb,OAAS,MACtBI,QAAQa,MAAMF,MAAMX,QAASG,QAGrCW,UACQjB,cAAe,KACXM,KAAOC,MAAMC,UAAUC,MAAMC,KAAKC,WACtCL,KAAKM,QAAQb,OAAS,MACtBI,QAAQc,KAAKH,MAAMX,QAASG,QAGpCY,aACQlB,cAAe,KACXM,KAAOC,MAAMC,UAAUC,MAAMC,KAAKC,WACtCL,KAAKM,QAAQb,OAAS,MACtBI,QAAQe,QAAQJ,MAAMX,QAASG,QAGvCa,aACQnB,cAAe,KACXM,KAAOC,MAAMC,UAAUC,MAAMC,KAAKC,WACtCL,KAAKM,QAAQb,OAAS,MACtBI,QAAQgB,QAAQL,MAAMX,QAASG,QAGvCc,eACQpB,cAAe,KACXM,KAAOC,MAAMC,UAAUC,MAAMC,KAAKC,WACtCL,KAAKM,QAAQb,OAAS,MACtBI,QAAQiB,UAAUN,MAAMX,QAASG,QAGzCe,SACIrB,eAAgB,GAEpBsB,UACItB,eAAgB"}

3
amd/build/util/fittext-vue.min.js vendored Normal file
View File

@ -0,0 +1,3 @@
define("local_treestudyplan/util/fittext-vue",["exports","./css-calc","./fitty"],(function(_exports,_cssCalc,_fitty){var obj;Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_fitty=(obj=_fitty)&&obj.__esModule?obj:{default:obj};var _default={install(Vue){Vue.component("fittext",{props:{maxsize:{type:String,default:"512px"},minsize:{type:String,default:"10px"},vertical:Boolean,singleline:Boolean,dynamic:Boolean},data:()=>({resizeObserver:null,mutationObserver:null}),computed:{rootStyle(){return this.vertical?"height: 100%;":"width: 100%;"}},methods:{},mounted(){(0,_fitty.default)(this.$refs.text,{minSize:(0,_cssCalc.calc)(this.minsize),maxSize:(0,_cssCalc.calc)(this.maxsize),vertical:this.vertical,multiline:!this.singleline})},unmounted(){this.mutationObserver&&this.mutationObserver.disconnect(),this.resizeObserver&&this.resizeObserver.disconnect()},template:"\n <div class='q-fittext' ref='container' :style=\"rootStyle + ';min-height:0;min-width:0;'\">\n <span :style=\"'display:block; white-space:'+ ((singleline)?'nowrap':'normal')+';' + rootStyle\" class='q-fittext-text' ref='text'><slot></slot>\n </span\n ></div>\n "})}};return _exports.default=_default,_exports.default}));
//# sourceMappingURL=fittext-vue.min.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"fittext-vue.min.js","sources":["../../src/util/fittext-vue.js"],"sourcesContent":["/* eslint no-unused-vars: warn */\n/* eslint max-len: [\"error\", { \"code\": 160 }] */\n/* eslint capitalized-comments: \"off\" */\n/* eslint-env es6*/\n\nimport {calc} from \"./css-calc\";\nimport fitty from \"./fitty\";\n\nexport default {\n install(Vue/* ,options */) {\n Vue.component('fittext', {\n props: {\n maxsize: {\n type: String,\n 'default': \"512px\",\n },\n minsize: {\n type: String,\n 'default': \"10px\",\n },\n vertical: Boolean,\n singleline: Boolean,\n dynamic: Boolean,\n },\n data() {\n return {\n resizeObserver: null,\n mutationObserver: null,\n };\n },\n computed: {\n rootStyle() {\n if (this.vertical) {\n return `height: 100%;`;\n } else {\n return `width: 100%;`;\n }\n }\n },\n methods: {\n },\n mounted() {\n const self = this;\n // If the content could change after initial presentation,\n // Use the fitty method. It is slightly worse on multiline horizontal text,\n // but better supports content that can change later on.\n fitty(self.$refs.text,\n {\n minSize: calc(self.minsize),\n maxSize: calc(self.maxsize),\n vertical: self.vertical,\n multiline: !self.singleline,\n });\n },\n unmounted() {\n if (this.mutationObserver) {\n this.mutationObserver.disconnect();\n }\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n }\n },\n template: `\n <div class='q-fittext' ref='container' :style=\"rootStyle + ';min-height:0;min-width:0;'\">\n <span :style=\"'display:block; white-space:'+ ((singleline)?'nowrap':'normal')+';' + rootStyle\" class='q-fittext-text' ref='text'><slot></slot>\n </span\n ></div>\n `,\n });\n },\n};"],"names":["install","Vue","component","props","maxsize","type","String","minsize","vertical","Boolean","singleline","dynamic","data","resizeObserver","mutationObserver","computed","rootStyle","this","methods","mounted","$refs","text","minSize","maxSize","multiline","unmounted","disconnect","template"],"mappings":"gRAQe,CACXA,QAAQC,KACJA,IAAIC,UAAU,UAAW,CACzBC,MAAO,CACHC,QAAS,CACLC,KAAMC,eACK,SAEfC,QAAS,CACLF,KAAMC,eACK,QAEfE,SAAUC,QACVC,WAAYD,QACZE,QAASF,SAEbG,KAAI,KACO,CACHC,eAAgB,KAChBC,iBAAkB,OAG1BC,SAAU,CACNC,mBACQC,KAAKT,SACG,gBAEA,iBAIpBU,QAAS,GAETC,6BACiBF,KAIFG,MAAMC,KACb,CACAC,SAAS,iBANAL,KAMUV,SACnBgB,SAAS,iBAPAN,KAOUb,SACnBI,SARSS,KAQMT,SACfgB,WATSP,KASQP,cAGzBe,YACQR,KAAKH,uBACAA,iBAAiBY,aAEtBT,KAAKJ,qBACAA,eAAea,cAG5BC,SAAW"}

3
amd/build/util/fitty.min.js vendored Normal file
View File

@ -0,0 +1,3 @@
define("local_treestudyplan/util/fitty",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0;var _default=(w=>{if(!w)return;const DrawState={IDLE:0,DIRTY_CONTENT:1,DIRTY_LAYOUT:2,DIRTY:3};let fitties=[],redrawFrame=null;const requestRedraw="requestAnimationFrame"in w?function(){let options=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{sync:!1};w.cancelAnimationFrame(redrawFrame);const redrawFn=()=>redraw(fitties.filter((f=>f.dirty&&f.active)));if(options.sync)return redrawFn();redrawFrame=w.requestAnimationFrame(redrawFn)}:()=>{},redrawAll=type=>options=>{fitties.forEach((f=>f.dirty=type)),requestRedraw(options)},redraw=fitties=>{fitties.filter((f=>!f.styleComputed)).forEach((f=>{f.styleComputed=computeStyle(f)})),fitties.filter(shouldPreStyle).forEach(applyStyle);const fittiesToRedraw=fitties.filter(shouldRedraw);fittiesToRedraw.forEach(calculateStyles),fittiesToRedraw.forEach((f=>{applyStyle(f),markAsClean(f)})),fittiesToRedraw.forEach(dispatchFitEvent)},markAsClean=f=>f.dirty=DrawState.IDLE,calculateStyles=f=>{f.vertical?(f.availableHeight=f.element.parentNode.clientHeight,f.currentHeight=f.element.scrollHeight,f.previousFontSize=f.currentFontSize,f.currentFontSize=Math.min(Math.max(f.minSize,f.availableHeight/f.currentHeight*f.previousFontSize),f.maxSize)):(f.availableWidth=f.element.parentNode.clientWidth,f.currentWidth=f.element.scrollWidth,f.previousFontSize=f.currentFontSize,f.currentFontSize=Math.min(Math.max(f.minSize,f.availableWidth/f.currentWidth*f.previousFontSize),f.maxSize)),f.whiteSpace=f.multiLine&&f.currentFontSize===f.minSize?"normal":"nowrap"},shouldRedraw=f=>f.vertical?f.dirty!==DrawState.DIRTY_LAYOUT||f.dirty===DrawState.DIRTY_LAYOUT&&f.element.parentNode.clientHeight!==f.availableHeight:f.dirty!==DrawState.DIRTY_LAYOUT||f.dirty===DrawState.DIRTY_LAYOUT&&f.element.parentNode.clientWidth!==f.availableWidth,computeStyle=f=>{const style=w.getComputedStyle(f.element,null);return f.currentFontSize=parseFloat(style.getPropertyValue("font-size")),f.display=style.getPropertyValue("display"),f.whiteSpace=style.getPropertyValue("white-space"),!0},shouldPreStyle=f=>{let preStyle=!1;return!f.preStyleTestCompleted&&(/inline-/.test(f.display)||(preStyle=!0,f.display="inline-block"),"nowrap"!==f.whiteSpace&&(preStyle=!0,f.whiteSpace="nowrap"),f.preStyleTestCompleted=!0,preStyle)},applyStyle=f=>{f.element.style.whiteSpace=f.whiteSpace,f.element.style.display=f.display,f.element.style.fontSize=f.currentFontSize+"px"},dispatchFitEvent=f=>{f.element.dispatchEvent(new CustomEvent("fit",{detail:{oldValue:f.previousFontSize,newValue:f.currentFontSize,scaleFactor:f.currentFontSize/f.previousFontSize}}))},fit=(f,type)=>options=>{f.dirty=type,f.active&&requestRedraw(options)},init=f=>{f.originalStyle={whiteSpace:f.element.style.whiteSpace,display:f.element.style.display,fontSize:f.element.style.fontSize},observeMutations(f),f.newbie=!0,f.dirty=!0,fitties.push(f)},destroy=f=>()=>{fitties=fitties.filter((_=>_.element!==f.element)),f.observeMutations&&f.observer.disconnect(),f.element.style.whiteSpace=f.originalStyle.whiteSpace,f.element.style.display=f.originalStyle.display,f.element.style.fontSize=f.originalStyle.fontSize},subscribe=f=>()=>{f.active||(f.active=!0,requestRedraw())},unsubscribe=f=>()=>f.active=!1,observeMutations=f=>{f.observeMutations&&(f.observer=new MutationObserver(fit(f,DrawState.DIRTY_CONTENT)),f.observer.observe(f.element,f.observeMutations))},defaultOptions={minSize:16,maxSize:512,multiLine:!0,vertical:!1,observeMutations:"MutationObserver"in w&&{subtree:!0,childList:!0,characterData:!0}};function fittyCreate(elements,options){const fittyOptions=Object.assign({},defaultOptions,options),publicFitties=elements.map((element=>{const f=Object.assign({},fittyOptions,{element:element,active:!0});return init(f),{element:element,fit:fit(f,DrawState.DIRTY),unfreeze:subscribe(f),freeze:unsubscribe(f),unsubscribe:destroy(f)}}));return requestRedraw(),publicFitties}function fitty(target){let options=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return"string"==typeof target?fittyCreate((nl=document.querySelectorAll(target),[].slice.call(nl)),options):fittyCreate([target],options)[0];var nl}let resizeDebounce=null;const onWindowResized=()=>{w.clearTimeout(resizeDebounce),resizeDebounce=w.setTimeout(redrawAll(DrawState.DIRTY_LAYOUT),fitty.observeWindowDelay)},events=["resize","orientationchange"];return Object.defineProperty(fitty,"observeWindow",{set:enabled=>{const method=(enabled?"add":"remove")+"EventListener";events.forEach((e=>{w[method](e,onWindowResized)}))}}),fitty.observeWindow=!0,fitty.observeWindowDelay=100,fitty.fitAll=redrawAll(DrawState.DIRTY),fitty})("undefined"==typeof window?null:window);return _exports.default=_default,_exports.default}));
//# sourceMappingURL=fitty.min.js.map

File diff suppressed because one or more lines are too long

3
amd/build/util/formfields.min.js vendored Normal file
View File

@ -0,0 +1,3 @@
define("local_treestudyplan/util/formfields",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.textInteger=function(id){let unsigned=arguments.length>1&&void 0!==arguments[1]&&arguments[1],nonzero=arguments.length>2&&void 0!==arguments[2]&&arguments[2];const element=document.getElementById(id);element&&element.addEventListener("input",(()=>{var val=element.value;return""!=val?!(isNaN(val)&&(unsigned||"-"!=val)||unsigned&&val<0||nonzero&&0==val)||(unsigned?(element.value=val.replace(/[^0-9]/g,""),nonzero&&0==val&&(element.value="")):element.value=val.replace(/[^0-9-]/g,"").replace(/(.{1})(-)/g,"$1"),!1):null}))}}));
//# sourceMappingURL=formfields.min.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"formfields.min.js","sources":["../../src/util/formfields.js"],"sourcesContent":["/**\n * Convert a text field into an integer only text field\n * @param {string} id The Id of the form field\n * @param {bool} unsigned Allow only unsigned values\n * @param {bool} nonzero Do not allow zero values\n */\nexport function textInteger(id, unsigned = false, nonzero = false) {\n const element = document.getElementById(id);\n\n if (element) {\n element.addEventListener(\"input\", () => {\n var val = element.value;\n if (val != '') {\n if ((isNaN(val) && !(!unsigned && val == '-')) || (unsigned && val < 0) || (nonzero && val == 0)) {\n // Set input value empty\n if (unsigned) {\n element.value = val.replace(/[^0-9]/g, '');\n if (nonzero && val == 0) {\n element.value = '';\n }\n } else {\n element.value = val.replace(/[^0-9-]/g, '').replace(/(.{1})(-)/g, '$1');\n }\n return false;\n } else {\n return true;\n }\n }\n return null;\n });\n }\n}"],"names":["id","unsigned","nonzero","element","document","getElementById","addEventListener","val","value","isNaN","replace"],"mappings":"mKAM4BA,QAAIC,iEAAkBC,sEACxCC,QAAUC,SAASC,eAAeL,IAEpCG,SACAA,QAAQG,iBAAiB,SAAS,SAC1BC,IAAMJ,QAAQK,YACP,IAAPD,MACKE,MAAMF,OAAWN,UAAmB,KAAPM,MAAiBN,UAAYM,IAAM,GAAOL,SAAkB,GAAPK,OAE/EN,UACAE,QAAQK,MAAQD,IAAIG,QAAQ,UAAW,IACnCR,SAAkB,GAAPK,MACXJ,QAAQK,MAAQ,KAGpBL,QAAQK,MAAQD,IAAIG,QAAQ,WAAY,IAAIA,QAAQ,aAAc,OAE/D,GAKR,IAAP"}

3
amd/build/util/mform-helper.min.js vendored Normal file
View File

@ -0,0 +1,3 @@
define("local_treestudyplan/util/mform-helper",["exports","core/ajax","core/fragment","core/templates","core/notification","./string-helper","./debugger"],(function(_exports,_ajax,_fragment,_templates,_notification,_stringHelper,_debugger){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_notification=_interopRequireDefault(_notification),_debugger=_interopRequireDefault(_debugger);var _default={install(Vue){let debug=new _debugger.default("treestudyplan-mform-helper"),strings=(0,_stringHelper.loadStrings)({editmod:{save$core:"save$core",cancel$core:"cancel$core"}});Vue.component("mform",{props:{name:{type:String},params:{type:Object},title:{type:String,default:""},variant:{type:String,default:"primary"},type:{type:String,default:"link"}},data:()=>({content:"",loading:!0,uuid:void 0!==crypto.randomUUID?crypto.randomUUID():"10000000-1000-4000-8000-100000000000".replace(/[018]/g,(c=>(c^crypto.getRandomValues(new Uint8Array(1))[0]&15>>c/4).toString(16))),text:strings,submitok:!1,observer:null,inputs:[]}),computed:{},methods:{openForm(){this.$refs.editormodal.show()},onShown(){const self=this;debug.info(`Loading form "${self.name}" with params`,self.params),self.loading=!1,(0,_ajax.call)([{methodname:"local_treestudyplan_get_mform",args:{formname:self.name,params:JSON.stringify(self.params)}}])[0].then((data=>{const html=data.html;self.loading=!1;const js=(0,_fragment.processCollectedJavascript)(data.javascript);(0,_templates.replaceNodeContents)(self.$refs.content,html,js),self.initListenChanges()})).catch(_notification.default.exception)},onSave(){const self=this;let form=this.$refs.content.getElementsByTagName("form")[0];form.dispatchEvent(new Event("save-form-state"));const formdata=new FormData(form),data=new URLSearchParams(formdata).toString();this.checkSave()&&(0,_ajax.call)([{methodname:"local_treestudyplan_submit_mform",args:{formname:self.name,params:JSON.stringify(self.params),formdata:data}}])[0].then((response=>{const updatedplan=JSON.parse(response.data);self.$emit("saved",updatedplan,formdata)})).catch(_notification.default.exception)},checkSave(){let canSave=!0;return this.inputs.forEach((el=>{el.focus(),el.blur(),el.classList.contains("is-invalid")&&(canSave=!1)}),this),this.submitok=canSave,canSave},initListenChanges(){const content=this.$refs.content;this.inputs=content.querySelectorAll("input.form-control"),setTimeout(this.checkSave,100),this.observer&&this.observer.disconnect(),this.observer=new MutationObserver((mutationList=>{for(const mix in mutationList){const mutation=mutationList[mix];"attributes"===mutation.type&&"class"===mutation.attributeName&&this.checkSave()}})),this.inputs.forEach((el=>{this.observer.observe(el,{attributes:!0})}),this)}},unmount(){this.observer&&this.observer.disconnect()},template:'\n <span class=\'mform-container\'>\n <b-button :variant="variant" v-if=\'type == "button"\' @click.prevent=\'openForm\'\n ><slot><i class=\'fa fa-gear\'></i></slot></b-button>\n <a variant="variant" v-else href=\'#\' @click.prevent=\'openForm\'\n ><slot><i class=\'fa fa-gear\'></i></slot></a>\n <b-modal\n ref="editormodal"\n scrollable\n centered\n size="xl"\n id="\'modal-\'+uuid"\n @shown="onShown"\n @ok="onSave"\n :ok-disabled="!submitok"\n :title="title"\n :ok-title="text.save$core"\n ><div :class="\'s-mform-content\'" ref="content"\n ><div class="d-flex justify-content-center mb-3"\n ><b-spinner variant="primary"></b-spinner\n ></div\n ></div\n ></b-modal>\n </span>\n '})}};return _exports.default=_default,_exports.default}));
//# sourceMappingURL=mform-helper.min.js.map

File diff suppressed because one or more lines are too long

3
amd/build/util/psidebar-vue.min.js vendored Normal file
View File

@ -0,0 +1,3 @@
define("local_treestudyplan/util/psidebar-vue",["exports","../portal-vue/portal-vue.esm","./debugger"],(function(_exports,_portalVue,_debugger){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_portalVue=_interopRequireDefault(_portalVue);let wrapper,contentwrapper,resizeObserver,debug=new((_debugger=_interopRequireDefault(_debugger)).default)("p-sidebar");function createPortalTarget(target,offsetref){let initializeWrapperContent=!1;if(debug.info("Creating portal target"),wrapper=document.querySelector("#p-sidebar-wrapper"),wrapper||(initializeWrapperContent=!0,wrapper=document.createElement("div"),wrapper.setAttribute("id","p-sidebar-wrapper")),contentwrapper=document.querySelector("#p-sidebar-contentwrapper"),contentwrapper||(initializeWrapperContent=!0,contentwrapper=document.createElement("div"),contentwrapper.setAttribute("id","p-sidebar-contentwrapper"),wrapper.appendChild(contentwrapper)),initializeWrapperContent){let targetEl=document.querySelector(target);for(targetEl&&"HTML"!=targetEl.nodeType||(targetEl=document.querySelector("body")),console.info(`Targeting '${target}' to `,targetEl);targetEl.childNodes.length>0;)contentwrapper.appendChild(targetEl.childNodes[0]);targetEl.appendChild(wrapper)}rePosition(!1),setOffset(offsetref)}function rePosition(right){let el=document.querySelector("#p-sidebar-mount");el||(el=document.createElement("div"),el.setAttribute("id","p-sidebar-mount"),resizeObserver=new ResizeObserver((()=>{let wx=0-el.getBoundingClientRect().width;wx+=0!=wx?"px":"",el.style.setProperty("--p-sidebar-hideoffset",wx)})),resizeObserver.observe(el)),right?wrapper.insertBefore(el,contentwrapper.nextSibling):wrapper.insertBefore(el,contentwrapper)}function setOffset(reference){const ref=reference?document.querySelector(reference):null;if(ref){let offsetTop=ref?ref.offsetTop:0;offsetTop+=0!=offsetTop?"px":"";const el=document.querySelector("#p-sidebar-mount");el&&(el.style.height=`calc( 100vh - ${offsetTop})`,el.style.marginTop=offsetTop)}}var _default={install(Vue){Vue.use(_portalVue.default),"ready"===document.readyState||"complete"===document.readyState?(debug.info("Page already loaded"),createPortalTarget()):window.addEventListener("load",(()=>{debug.info("Page not yet loaded"),createPortalTarget()})),Vue.component("p-easeinout",{template:'\n <transition name="p-easeinout"\n ><slot></slot>\n </transition>'}),Vue.component("p-sidebar",{props:{value:{type:Boolean,default:!0},right:{type:Boolean,default:!1},shadow:{type:Boolean,default:!1},target:{type:String,default:"body"},offsetRef:{type:String,default:""}},data:()=>({wrapper:null,contentwrapper:null,resizeobserver:null}),computed:{},methods:{},watch:{right(newVal){rePosition(newVal)},offsetRef(reference){setOffset(reference,this.$refs.portal)}},mounted(){debug.info("OffsetRef",this.offsetRef),setOffset(this.offsetRef),debug.info("Right",this.right),rePosition(this.right)},template:"\n <div\n ><mounting-portal ref='portal'\n mount-to=\"#p-sidebar-mount\"\n class=\"(right?'p-sidebar-right ':'')\"\n append\n transition=\"p-easeinout\"\n ><div ref='container' v-if=\"value\"\n :class=\"'p-sidebar ' + (right?'p-sidebar-right ':'') + (shadow?'p-sidebar-shadow ':'')\"\n ><slot></slot></div\n ></mounting-portal>\n </div>\n "})}};return _exports.default=_default,_exports.default}));
//# sourceMappingURL=psidebar-vue.min.js.map

File diff suppressed because one or more lines are too long

3
amd/build/util/settings.min.js vendored Normal file
View File

@ -0,0 +1,3 @@
define("local_treestudyplan/util/settings",["exports","core/ajax","core/notification"],(function(_exports,_ajax,_notification){var obj;Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.settings=function(key){const settings=loadsettings();return key in settings?settings[key]:null},_notification=(obj=_notification)&&obj.__esModule?obj:{default:obj};let settingcache=null;function loadsettings(){return settingcache||(0,_ajax.call)([{methodname:"local_treestudyplan_getsettings",args:{}}])[0].then((response=>{settingcache=response})).catch(_notification.default.exception),settingcache}loadsettings()}));
//# sourceMappingURL=settings.min.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"settings.min.js","sources":["../../src/util/settings.js"],"sourcesContent":["/* eslint no-var: \"error\" */\n/* eslint-env es6*/\n\nimport {call} from 'core/ajax';\nimport notification from 'core/notification';\n\n// Prepare default value.\nlet settingcache = null;\n\n/**\n * Retrieve settings.\n * @param {String} key\n * @returns {*}\n */\nexport function settings(key) {\n const settings = loadsettings();\n if (key in settings) {\n return settings[key];\n } else {\n return null;\n }\n}\n\n/**\n * Get settings from server or cache\n * @returns {Object} The settings object\n */\nfunction loadsettings() {\n if (!settingcache) {\n // Retrieve setting cache if needed.\n call([{\n methodname: 'local_treestudyplan_getsettings',\n args: {}\n }])[0].then((response) => {\n settingcache = response;\n return;\n }).catch(notification.exception);\n }\n return settingcache;\n}\n\n// Preload settings.\nloadsettings();"],"names":["key","settings","loadsettings","settingcache","methodname","args","then","response","catch","notification","exception"],"mappings":"0NAcyBA,WACfC,SAAWC,sBACbF,OAAOC,SACAA,SAASD,KAET,8EAZXG,aAAe,cAoBVD,sBACAC,6BAEI,CAAC,CACFC,WAAY,kCACZC,KAAM,MACN,GAAGC,MAAMC,WACTJ,aAAeI,YAEhBC,MAAMC,sBAAaC,WAEnBP,aAIXD"}

View File

@ -1,3 +1,3 @@
define("local_treestudyplan/util/string-helper",["exports","core/str"],(function(_exports,_str){Object.defineProperty(_exports,"__esModule",{value:!0}),_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}))}}));
define("local_treestudyplan/util/string-helper",["exports","core/str","./debugger"],(function(_exports,_str,_debugger){var obj;Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.loadStringKeys=function(string_keys,plugin){void 0===plugin&&(plugin="local_treestudyplan");for(let idx in string_keys){let stringkeys=[];for(const i in string_keys[idx]){let parts=string_keys[idx][i].textkey.split("$"),identifier=parts[0],component=parts.length>1?parts[1]:plugin;stringkeys.push({key:identifier,component:component})}getstrFunc(stringkeys).then((function(strings){for(const i in strings){const s=strings[i];string_keys[idx][i].text=s}})).catch((x=>{debug.warn(x)}))}return string_keys},_exports.loadStrings=function(strings,plugin){void 0===plugin&&(plugin="local_treestudyplan");for(let idx in strings){let stringkeys=[];for(const handle in strings[idx]){let parts=strings[idx][handle].split(/[$@]/),identifier=parts[0],component=parts.length>1?parts[1]:plugin;stringkeys.push({key:identifier,component:component})}getstrFunc(stringkeys).then((function(str){let i=0;for(const handle in strings[idx])strings[idx][handle]=str[i],i++})).catch((x=>{debug.warn(x)}))}return strings},_exports.strformat=function(str,values){return str.replace(/\{(\w+)\}/g,((m,m1)=>m1&&values.hasOwnProperty(m1)?values[m1]:m))};let debug=new(_debugger=(obj=_debugger)&&obj.__esModule?obj:{default:obj}).default("string-helper");const getstrFunc=void 0!==_str.getStrings?_str.getStrings:_str.get_strings}));
//# sourceMappingURL=string-helper.min.js.map

View File

@ -1 +1 @@
{"version":3,"file":"string-helper.min.js","sources":["../../src/util/string-helper.js"],"sourcesContent":["import {get_strings} from 'core/str';\n\n/**\n * Load the translation of strings from a strings object\n * @param {Object} strings The map of strings\n * @returns {Object} The map with strings loaded in\n */\nexport function load_strings(strings){\n for(let idx in strings){\n let stringkeys = [];\n for(const handle in strings[idx]){\n const key = strings[idx][handle];\n let parts = key.split(/[$@]/);\n let identifier = parts[0];\n let component = (parts.length > 1)?parts[1]:'local_treestudyplan';\n stringkeys.push({ key: identifier, component: component});\n }\n get_strings(stringkeys).then(function(str){\n let i = 0;\n for(const key in strings[idx]){\n strings[idx][key] = str[i];\n i++;\n }\n });\n }\n\n return strings;\n}\n\n/**\n * Load the translation of strings from a strings object based on keys\n * Used for loading values for a drop down menu or the like\n * @param {Object} string_keys The map of stringkeys\n * @returns {Object} The map with strings loaded in\n */\nexport function load_stringkeys(string_keys){\n for(let idx in string_keys){\n // Get text strings for condition settings\n let stringkeys = [];\n for(const i in string_keys[idx]){\n const key = string_keys[idx][i].textkey;\n let parts = key.split(\"$\");\n let identifier = parts[0];\n let component = (parts.length > 1)?parts[1]:'local_treestudyplan';\n stringkeys.push({ key: identifier, component: component});\n }\n get_strings(stringkeys).then(function(strings){\n for(const i in strings) {\n const s = strings[i];\n const l = string_keys[idx][i];\n l.text = s;\n }\n });\n }\n return string_keys;\n}\n\n/**\n * String formatting function - replaces {name} in string by value of same key in values parameter\n * @param {string} str String t\n * @param {object} values Object containing keys to replace {key} strings with\n * @returns Formatted string\n */\nexport function strformat(str,values) {\n return str.replace(/\\{(\\w+)\\}/g, (m, m1) => {\n if (m1 && values.hasOwnProperty(m1)) {\n return values[m1];\n } else {\n return m;\n }\n });\n}"],"names":["string_keys","idx","stringkeys","i","parts","textkey","split","identifier","component","length","push","key","then","strings","s","text","handle","str","values","replace","m","m1","hasOwnProperty"],"mappings":"0LAmCgCA,iCACpBC,SAEAC,WAAa,OACb,IAAMC,KAAMH,YAAYC,KAAK,KAEzBG,MADQJ,YAAYC,KAAKE,GAAGE,QAChBC,MAAM,KAClBC,WAAaH,MAAM,GACnBI,UAAaJ,MAAMK,OAAS,EAAGL,MAAM,GAAG,sBAC5CF,WAAWQ,KAAK,CAAEC,IAAKJ,WAAYC,UAAWA,iCAEtCN,YAAYU,MAAK,SAASC,aAC9B,IAAMV,MAAKU,QAAS,KACdC,EAAID,QAAQV,IACRH,YAAYC,KAAKE,IACzBY,KAAOD,WAdjB,IAAIb,OAAOD,mBAAPC,YAkBDD,4CA/CkBa,4BACjBZ,SACAC,WAAa,OACb,IAAMc,UAAWH,QAAQZ,KAAK,KAE1BG,MADQS,QAAQZ,KAAKe,QACTV,MAAM,QAClBC,WAAaH,MAAM,GACnBI,UAAaJ,MAAMK,OAAS,EAAGL,MAAM,GAAG,sBAC5CF,WAAWQ,KAAK,CAAEC,IAAKJ,WAAYC,UAAWA,iCAEtCN,YAAYU,MAAK,SAASK,SAC9Bd,EAAI,MACJ,IAAMQ,QAAOE,QAAQZ,KACrBY,QAAQZ,KAAKU,MAAOM,IAAId,GACxBA,YAbR,IAAIF,OAAOY,cAAPZ,YAkBDY,qCAqCeI,IAAIC,eACnBD,IAAIE,QAAQ,cAAc,SAACC,EAAGC,WAC7BA,IAAMH,OAAOI,eAAeD,IACrBH,OAAOG,IAEPD"}
{"version":3,"file":"string-helper.min.js","sources":["../../src/util/string-helper.js"],"sourcesContent":["/* eslint camelcase: \"off\" */\nimport {get_strings} from 'core/str';\nimport {getStrings} from 'core/str';\nimport Debugger from './debugger';\nlet debug = new Debugger(\"string-helper\");\n\n/* Determine the proper getstrings function to use (MDL4.3+ recommends use of getStrings, which is jquery independent) */\nconst getstrFunc = (getStrings !== undefined) ? getStrings : get_strings;\n\n/**\n * Load the translation of strings from a strings object\n * @param {Object} strings The map of strings\n * @param {String} plugin Name of plugin to load for by default (leave empty for 'local_treestudyplan')\n * @returns {Object} The map with strings loaded in\n */\nexport function loadStrings(strings, plugin) {\n if (plugin === undefined) {\n plugin = 'local_treestudyplan';\n }\n for (let idx in strings) {\n let stringkeys = [];\n for (const handle in strings[idx]) {\n const key = strings[idx][handle];\n let parts = key.split(/[$@]/);\n let identifier = parts[0];\n let component = (parts.length > 1) ? parts[1] : plugin;\n stringkeys.push({key: identifier, component: component});\n }\n getstrFunc(stringkeys).then(function(str) {\n let i = 0;\n for (const handle in strings[idx]) {\n strings[idx][handle] = str[i];\n i++;\n }\n return;\n }).catch((x) => {\n debug.warn(x);\n });\n }\n\n return strings;\n}\n\n/**\n * Load the translation of strings from a strings object based on keys\n * Used for loading values for a drop down menu or the like\n * @param {Object} string_keys The map of stringkeys\n * @param {String} plugin Name of plugin to load for by default (leave empty for 'local_treestudyplan')\n * @returns {Object} The map with strings loaded in\n */\nexport function loadStringKeys(string_keys, plugin) {\n if (plugin === undefined) {\n plugin = 'local_treestudyplan';\n }\n for (let idx in string_keys) {\n // Get text strings for condition settings\n let stringkeys = [];\n for (const i in string_keys[idx]) {\n const key = string_keys[idx][i].textkey;\n let parts = key.split(\"$\");\n let identifier = parts[0];\n let component = (parts.length > 1) ? parts[1] : plugin;\n stringkeys.push({key: identifier, component: component});\n }\n getstrFunc(stringkeys).then(function(strings) {\n for (const i in strings) {\n const s = strings[i];\n const l = string_keys[idx][i];\n l.text = s;\n }\n return;\n }).catch((x) => {\n debug.warn(x);\n });\n }\n return string_keys;\n}\n\n/**\n * String formatting function - replaces {name} in string by value of same key in values parameter\n * @param {string} str String t\n * @param {object} values Object containing keys to replace {key} strings with\n * @returns {string} Formatted string\n */\nexport function strformat(str, values) {\n return str.replace(/\\{(\\w+)\\}/g, (m, m1) => {\n if (m1 && values.hasOwnProperty(m1)) {\n return values[m1];\n } else {\n return m;\n }\n });\n}"],"names":["string_keys","plugin","undefined","idx","stringkeys","i","parts","textkey","split","identifier","component","length","push","key","getstrFunc","then","strings","s","text","catch","x","debug","warn","handle","str","values","replace","m","m1","hasOwnProperty","getStrings","get_strings"],"mappings":"wNAkD+BA,YAAaC,aACzBC,IAAXD,SACAA,OAAS,2BAER,IAAIE,OAAOH,YAAa,KAErBI,WAAa,OACZ,MAAMC,KAAKL,YAAYG,KAAM,KAE1BG,MADQN,YAAYG,KAAKE,GAAGE,QAChBC,MAAM,KAClBC,WAAaH,MAAM,GACnBI,UAAaJ,MAAMK,OAAS,EAAKL,MAAM,GAAKL,OAChDG,WAAWQ,KAAK,CAACC,IAAKJ,WAAYC,UAAWA,YAEjDI,WAAWV,YAAYW,MAAK,SAASC,aAC5B,MAAMX,KAAKW,QAAS,OACfC,EAAID,QAAQX,GACRL,YAAYG,KAAKE,GACzBa,KAAOD,MAGdE,OAAOC,IACNC,MAAMC,KAAKF,aAGZpB,2CA5DiBgB,QAASf,aAClBC,IAAXD,SACAA,OAAS,2BAER,IAAIE,OAAOa,QAAS,KACjBZ,WAAa,OACZ,MAAMmB,UAAUP,QAAQb,KAAM,KAE3BG,MADQU,QAAQb,KAAKoB,QACTf,MAAM,QAClBC,WAAaH,MAAM,GACnBI,UAAaJ,MAAMK,OAAS,EAAKL,MAAM,GAAKL,OAChDG,WAAWQ,KAAK,CAACC,IAAKJ,WAAYC,UAAWA,YAEjDI,WAAWV,YAAYW,MAAK,SAASS,SAC7BnB,EAAI,MACH,MAAMkB,UAAUP,QAAQb,KACzBa,QAAQb,KAAKoB,QAAUC,IAAInB,GAC3BA,OAGLc,OAAOC,IACNC,MAAMC,KAAKF,aAIZJ,qCA4CeQ,IAAKC,eACpBD,IAAIE,QAAQ,cAAc,CAACC,EAAGC,KAC7BA,IAAMH,OAAOI,eAAeD,IACrBH,OAAOG,IAEPD,SArFfN,MAAQ,yEAAa,uBAGnBP,gBAA6BZ,IAAf4B,gBAA4BA,gBAAaC"}

View File

@ -1,3 +1,3 @@
define("local_treestudyplan/util/svgarc",["exports"],(function(_exports){function _slicedToArray(arr,i){return function(arr){if(Array.isArray(arr))return arr}(arr)||function(arr,i){var _i=null==arr?null:"undefined"!=typeof Symbol&&arr[Symbol.iterator]||arr["@@iterator"];if(null==_i)return;var _s,_e,_arr=[],_n=!0,_d=!1;try{for(_i=_i.call(arr);!(_n=(_s=_i.next()).done)&&(_arr.push(_s.value),!i||_arr.length!==i);_n=!0);}catch(err){_d=!0,_e=err}finally{try{_n||null==_i.return||_i.return()}finally{if(_d)throw _e}}return _arr}(arr,i)||function(o,minLen){if(!o)return;if("string"==typeof o)return _arrayLikeToArray(o,minLen);var n=Object.prototype.toString.call(o).slice(8,-1);"Object"===n&&o.constructor&&(n=o.constructor.name);if("Map"===n||"Set"===n)return Array.from(o);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return _arrayLikeToArray(o,minLen)}(arr,i)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function _arrayLikeToArray(arr,len){(null==len||len>arr.length)&&(len=arr.length);for(var i=0,arr2=new Array(len);i<len;i++)arr2[i]=arr[i];return arr2}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.svgarcpath=_exports.svgarc=void 0;var cos=Math.cos,sin=Math.sin,π=Math.PI,f_matrix_times=function(_ref,_ref2){var _ref3=_slicedToArray(_ref,2),_ref3$=_slicedToArray(_ref3[0],2),a=_ref3$[0],b=_ref3$[1],_ref3$2=_slicedToArray(_ref3[1],2),c=_ref3$2[0],d=_ref3$2[1],_ref4=_slicedToArray(_ref2,2),x=_ref4[0],y=_ref4[1];return[a*x+b*y,c*x+d*y]},f_vec_add=function(_ref5,_ref6){var _ref7=_slicedToArray(_ref5,2),a1=_ref7[0],a2=_ref7[1],_ref8=_slicedToArray(_ref6,2);return[a1+_ref8[0],a2+_ref8[1]]},svgarcpath=function(_ref9,_ref10,_ref11,φ){var _ref12=_slicedToArray(_ref9,2),cx=_ref12[0],cy=_ref12[1],_ref13=_slicedToArray(_ref10,2),rx=_ref13[0],ry=_ref13[1],_ref14=_slicedToArray(_ref11,2),t1=_ref14[0],Δ=_ref14[1];Δ%=2*π;var x,rotMatrix=[[cos(x=φ),-sin(x)],[sin(x),cos(x)]],_f_vec_add2=_slicedToArray(f_vec_add(f_matrix_times(rotMatrix,[rx*cos(t1),ry*sin(t1)]),[cx,cy]),2),sX=_f_vec_add2[0],sY=_f_vec_add2[1],_f_vec_add4=_slicedToArray(f_vec_add(f_matrix_times(rotMatrix,[rx*cos(t1+Δ),ry*sin(t1+Δ)]),[cx,cy]),2),eX=_f_vec_add4[0],eY=_f_vec_add4[1];return"M "+sX+" "+sY+" A "+[rx,ry,φ/(2*π)*360,Δ>π?1:0,Δ>0?1:0,eX,eY].join(" ")};_exports.svgarcpath=svgarcpath;_exports.svgarc=function(_ref15,_ref16,_ref17,φ){var _ref18=_slicedToArray(_ref15,2),cx=_ref18[0],cy=_ref18[1],_ref19=_slicedToArray(_ref16,2),rx=_ref19[0],ry=_ref19[1],_ref20=_slicedToArray(_ref17,2),t1=_ref20[0],Δ=_ref20[1],path_2wk2r=document.createElementNS("http://www.w3.org/2000/svg","path"),d=svgarcpath([cx,cy],[rx,ry],[t1,Δ],φ);return path_2wk2r.setAttribute("d",d),path_2wk2r}}));
define("local_treestudyplan/util/svgarc",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.svgarcpath=_exports.svgarc=void 0;const cos=Math.cos,sin=Math.sin,π=Math.PI,fMatrixTimes=(_ref,_ref2)=>{let[[a,b],[c,d]]=_ref,[x,y]=_ref2;return[a*x+b*y,c*x+d*y]},fVecAdd=(_ref3,_ref4)=>{let[a1,a2]=_ref3,[b1,b2]=_ref4;return[a1+b1,a2+b2]},svgarcpath=(_ref5,_ref6,_ref7,φ)=>{let[cx,cy]=_ref5,[rx,ry]=_ref6,[t1,Δ]=_ref7;Δ%=2*π;const rotMatrix=[[cos(x=φ),-sin(x)],[sin(x),cos(x)]];var x;const[sX,sY]=fVecAdd(fMatrixTimes(rotMatrix,[rx*cos(t1),ry*sin(t1)]),[cx,cy]),[eX,eY]=fVecAdd(fMatrixTimes(rotMatrix,[rx*cos(t1+Δ),ry*sin(t1+Δ)]),[cx,cy]),fA=Δ>π?1:0,fS=Δ>0?1:0;return isNaN(eY)||isNaN(eX)?"":"M "+sX+" "+sY+" A "+[rx,ry,φ/(2*π)*360,fA,fS,eX,eY].join(" ")};_exports.svgarcpath=svgarcpath;_exports.svgarc=(_ref8,_ref9,_ref10,φ)=>{let[cx,cy]=_ref8,[rx,ry]=_ref9,[t1,Δ]=_ref10;const path2wk2r=document.createElementNS("http://www.w3.org/2000/svg","path"),d=svgarcpath([cx,cy],[rx,ry],[t1,Δ],φ);return path2wk2r.setAttribute("d",d),path2wk2r}}));
//# sourceMappingURL=svgarc.min.js.map

View File

@ -1 +1 @@
{"version":3,"file":"svgarc.min.js","sources":["../../src/util/svgarc.js"],"sourcesContent":["/*\nCopyright © 2020 Xah Lee, © 2023 P.M Kuipers\nPermission is hereby granted, free of charge, to any person obtaining a\ncopy of this software and associated documentation files (the “Software”),\nto deal in the Software without restriction, including without limitation\nthe rights to use, copy, modify, merge, publish, distribute, sublicense,\nand/or sell copies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following conditions:\nThe above copyright notice and this permission notice shall be included\nin all copies or substantial portions of the Software.\nTHE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\nTHE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\nDEALINGS IN THE SOFTWARE.\nURL: SVG Circle Arc http://xahlee.info/js/svg_circle_arc.html\n*/\n\nconst cos = Math.cos;\nconst sin = Math.sin;\nconst π = Math.PI;\n\nconst f_matrix_times = (( [[a,b], [c,d]], [x,y]) => [ a * x + b * y, c * x + d * y]);\nconst f_rotate_matrix = (x => [[cos(x),-sin(x)], [sin(x), cos(x)]]);\nconst f_vec_add = (([a1, a2], [b1, b2]) => [a1 + b1, a2 + b2]);\n\n// function modified by pmkuipers for text params\n/**\n * Create svg path text for an arc\n * @param {*} center [cx,cy] center of ellipse\n * @param {*} radius [rx,ry] major minor radius\n * @param {*} angle [t1, Δ] start angle, in radian, angle to sweep, in radian. positive.\n * @param {*} φ rotation on the whole, in radian\n * @returns a SVG path element that represent a ellipse. Text describing the arc path in an svg path element\n */\nconst svgarcpath = (([cx,cy],[rx,ry], [t1, Δ], φ ) => {\n Δ = Δ % (2*π);\n const rotMatrix = f_rotate_matrix (φ);\n const [sX, sY] = ( f_vec_add ( f_matrix_times ( rotMatrix, [rx * cos(t1), ry * sin(t1)] ), [cx,cy] ) );\n const [eX, eY] = ( f_vec_add ( f_matrix_times ( rotMatrix, [rx * cos(t1+Δ), ry * sin(t1+Δ)] ), [cx,cy] ) );\n const fA = ( ( Δ > π ) ? 1 : 0 );\n const fS = ( ( Δ > 0 ) ? 1 : 0 );\n return \"M \" + sX + \" \" + sY + \" A \" + [ rx , ry , φ / (2*π) *360, fA, fS, eX, eY ].join(\" \");\n});\n\n/**\n * Create an svg arc element\n * @param {*} center [cx,cy] center of ellipse\n * @param {*} radius [rx,ry] major minor radius\n * @param {*} angle [t1, Δ] start angle, in radian, angle to sweep, in radian. positive.\n * @param {*} φ rotation on the whole, in radian\n * @returns a SVG path element that represent a ellipse.\n */\nconst svgarc = (([cx,cy],[rx,ry], [t1, Δ], φ ) => {\n const path_2wk2r = document.createElementNS(\"http://www.w3.org/2000/svg\", \"path\");\n const d = svgarcpath([cx,cy],[rx,ry], [t1, Δ], φ );\n path_2wk2r.setAttribute(\"d\", d);\n return path_2wk2r;\n});\n\nexport {svgarc, svgarcpath};"],"names":["cos","Math","sin","π","PI","f_matrix_times","a","b","c","d","x","y","f_vec_add","a1","a2","svgarcpath","φ","cx","cy","rx","ry","t1","Δ","rotMatrix","sX","sY","eX","eY","join","path_2wk2r","document","createElementNS","setAttribute"],"mappings":"qyCAoBMA,IAAMC,KAAKD,IACXE,IAAMD,KAAKC,IACXC,EAAIF,KAAKG,GAETC,eAAkB,wFAAIC,YAAEC,+CAAKC,aAAEC,2CAAMC,WAAEC,iBAAO,CAAEL,EAAII,EAAIH,EAAII,EAAGH,EAAIE,EAAID,EAAIE,IAE3EC,UAAa,wDAAEC,YAAIC,gDAAkB,CAACD,YAASC,cAW/CC,WAAc,6BAA2BC,sCAAzBC,aAAGC,6CAAKC,aAAGC,6CAAMC,aAAIC,YACvCA,GAAS,EAAEnB,MAbUO,EAcfa,UAdoB,CAAC,CAACvB,IAAPU,EAccM,IAdCd,IAAIQ,IAAK,CAACR,IAAIQ,GAAIV,IAAIU,gCAevCE,UAAYP,eAAiBkB,UAAW,CAACJ,GAAKnB,IAAIqB,IAAKD,GAAKlB,IAAImB,MAAQ,CAACJ,GAAGC,QAAxFM,kBAAIC,6CACQb,UAAYP,eAAiBkB,UAAW,CAACJ,GAAKnB,IAAIqB,GAAGC,GAAIF,GAAKlB,IAAImB,GAAGC,KAAO,CAACL,GAAGC,QAA5FQ,kBAAIC,wBAGJ,KAAOH,GAAK,IAAMC,GAAK,MAAQ,CAAEN,GAAKC,GAAKJ,GAAK,EAAEb,GAAI,IAF7CmB,EAAInB,EAAM,EAAI,EACdmB,EAAI,EAAM,EAAI,EAC4CI,GAAIC,IAAKC,KAAK,qDAW5E,8BAA2BZ,uCAAzBC,aAAGC,6CAAKC,aAAGC,6CAAMC,aAAIC,YAC7BO,WAAaC,SAASC,gBAAgB,6BAA8B,QACpEtB,EAAIM,WAAW,CAACE,GAAGC,IAAI,CAACC,GAAGC,IAAK,CAACC,GAAIC,GAAIN,UAC/Ca,WAAWG,aAAa,IAAKvB,GACtBoB"}
{"version":3,"file":"svgarc.min.js","sources":["../../src/util/svgarc.js"],"sourcesContent":["/*\nCopyright © 2020 Xah Lee, © 2023 P.M Kuipers\nPermission is hereby granted, free of charge, to any person obtaining a\ncopy of this software and associated documentation files (the “Software”),\nto deal in the Software without restriction, including without limitation\nthe rights to use, copy, modify, merge, publish, distribute, sublicense,\nand/or sell copies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following conditions:\nThe above copyright notice and this permission notice shall be included\nin all copies or substantial portions of the Software.\nTHE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\nTHE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\nDEALINGS IN THE SOFTWARE.\nURL: SVG Circle Arc http://xahlee.info/js/svg_circle_arc.html\n*/\n\nconst cos = Math.cos;\nconst sin = Math.sin;\nconst π = Math.PI;\n\nconst fMatrixTimes = (([[a, b], [c, d]], [x, y]) => [a * x + b * y, c * x + d * y]);\nconst fRotateMatrix = (x => [[cos(x), -sin(x)], [sin(x), cos(x)]]);\nconst fVecAdd = (([a1, a2], [b1, b2]) => [a1 + b1, a2 + b2]);\n\n// Function modified by pmkuipers for text params\n/**\n * Create svg path text for an arc\n * @param {*} center [cx,cy] center of ellipse\n * @param {*} radius [rx,ry] major minor radius\n * @param {*} angle [t1, Δ] start angle, in radian, angle to sweep, in radian. positive.\n * @param {*} φ rotation on the whole, in radian\n * @returns {string} a SVG path description that represent a ellipse. Text describing the arc path in an svg path element\n */\nconst svgarcpath = (([cx, cy], [rx, ry], [t1, Δ], φ) => {\n Δ = Δ % (2 * π);\n const rotMatrix = fRotateMatrix(φ);\n const [sX, sY] = (fVecAdd(fMatrixTimes(rotMatrix, [rx * cos(t1), ry * sin(t1)]), [cx, cy]));\n const [eX, eY] = (fVecAdd(fMatrixTimes(rotMatrix, [rx * cos(t1 + Δ), ry * sin(t1 + Δ)]), [cx, cy]));\n const fA = ((Δ > π) ? 1 : 0);\n const fS = ((Δ > 0) ? 1 : 0);\n if (isNaN(eY) || isNaN(eX)) {\n return \"\";\n } else {\n return \"M \" + sX + \" \" + sY + \" A \" + [rx, ry, φ / (2 * π) * 360, fA, fS, eX, eY].join(\" \");\n }\n});\n\n/**\n * Create an svg arc element\n * @param {*} center [cx,cy] center of ellipse\n * @param {*} radius [rx,ry] major minor radius\n * @param {*} angle [t1, Δ] start angle, in radian, angle to sweep, in radian. positive.\n * @param {*} φ rotation on the whole, in radian\n * @returns {string} a SVG path element that represent a ellipse.\n */\nconst svgarc = (([cx, cy], [rx, ry], [t1, Δ], φ) => {\n const path2wk2r = document.createElementNS(\"http://www.w3.org/2000/svg\", \"path\");\n const d = svgarcpath([cx, cy], [rx, ry], [t1, Δ], φ);\n path2wk2r.setAttribute(\"d\", d);\n return path2wk2r;\n});\n\nexport {svgarc, svgarcpath};"],"names":["cos","Math","sin","π","PI","fMatrixTimes","a","b","c","d","x","y","fVecAdd","a1","a2","b1","b2","svgarcpath","φ","cx","cy","rx","ry","t1","Δ","rotMatrix","sX","sY","eX","eY","fA","fS","isNaN","join","path2wk2r","document","createElementNS","setAttribute"],"mappings":"kLAoBMA,IAAMC,KAAKD,IACXE,IAAMD,KAAKC,IACXC,EAAIF,KAAKG,GAETC,aAAgB,oBAAGC,EAAGC,IAAKC,EAAGC,UAAMC,EAAGC,eAAO,CAACL,EAAII,EAAIH,EAAII,EAAGH,EAAIE,EAAID,EAAIE,EAA1D,EAEhBC,QAAW,oBAAEC,GAAIC,WAAMC,GAAIC,gBAAQ,CAACH,GAAKE,GAAID,GAAKE,GAAvC,EAWXC,WAAc,mBAA8BC,SAA5BC,GAAIC,WAAMC,GAAIC,WAAMC,GAAIC,SAC1CA,GAAS,EAAIrB,QACPsB,UAdkB,CAAC,CAACzB,IAAPU,EAcaQ,IAdGhB,IAAIQ,IAAK,CAACR,IAAIQ,GAAIV,IAAIU,KAAtCA,YAeZgB,GAAIC,IAAOf,QAAQP,aAAaoB,UAAW,CAACJ,GAAKrB,IAAIuB,IAAKD,GAAKpB,IAAIqB,MAAO,CAACJ,GAAIC,MAC/EQ,GAAIC,IAAOjB,QAAQP,aAAaoB,UAAW,CAACJ,GAAKrB,IAAIuB,GAAKC,GAAIF,GAAKpB,IAAIqB,GAAKC,KAAM,CAACL,GAAIC,KACxFU,GAAON,EAAIrB,EAAK,EAAI,EACpB4B,GAAOP,EAAI,EAAK,EAAI,SACtBQ,MAAMH,KAAOG,MAAMJ,IACZ,GAEA,KAAOF,GAAK,IAAMC,GAAK,MAAQ,CAACN,GAAIC,GAAIJ,GAAK,EAAIf,GAAK,IAAK2B,GAAIC,GAAIH,GAAIC,IAAII,KAAK,qDAY/E,oBAA8Bf,SAA5BC,GAAIC,WAAMC,GAAIC,WAAMC,GAAIC,gBAChCU,UAAYC,SAASC,gBAAgB,6BAA8B,QACnE3B,EAAIQ,WAAW,CAACE,GAAIC,IAAK,CAACC,GAAIC,IAAK,CAACC,GAAIC,GAAIN,UAClDgB,UAAUG,aAAa,IAAK5B,GACrByB,SAAP"}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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,4 @@
/* eslint-disable */
/*!
* BootstrapVue 2.23.1
*

View File

@ -1,52 +1,32 @@
/*eslint no-var: "error" */
/*eslint no-unused-vars: "off" */
/*eslint linebreak-style: "off" */
/*eslint no-trailing-spaces: "off" */
/*eslint-env es6*/
/* eslint-env es6*/
// Put this file in path/to/plugin/amd/src
// You can call it anything you like
import {get_string,get_strings} from 'core/str';
import {call} from 'core/ajax';
import Debugger from './debugger';
import {load_strings} from './string-helper';
let debug = new Debugger("treestudyplan-config-grades");
/*
let strings = load_strings({
studyplan: {
studyplan_select_placeholder: 'studyplan_select_placeholder',
},
});
*/
/**
* Initialize grade cfg page
*/
export function init() {
{ const
{ const
intRx = /\d/,
integerChange = (event) => {
if ( (event.key.length > 1) || intRx.test(event.key)
if ((event.key.length > 1) || intRx.test(event.key)
) {
return;
}
event.preventDefault();
};
for (let input of document.querySelectorAll( 'input[type="number"][step="1"][min="0"]' )){
for (let input of document.querySelectorAll('input[type="number"][step="1"][min="0"]')) {
input.addEventListener("keydown", integerChange);
}
}
{ const
decimal= /^[0-9]*?\.[0-9]*?$/,
{ const
decimal = /^[0-9]*?\.[0-9]*?$/,
intRx = /\d/,
floatChange = (event) => {
if ( (event.key.length > 1) || ( (event.key === ".") && (!event.currentTarget.value.match(decimal)) )
if ((event.key.length > 1) || ((event.key === ".") && (!event.currentTarget.value.match(decimal)))
|| intRx.test(event.key)
) {
return;
@ -54,10 +34,10 @@ export function init() {
event.preventDefault();
};
for (let input of document.querySelectorAll( 'input[type="number"][min="0"]:not([step])' )){
for (let input of document.querySelectorAll('input[type="number"][min="0"]:not([step])')) {
input.addEventListener("keydown", floatChange);
}
for (let input of document.querySelectorAll( 'input[type="text"].float' )){
for (let input of document.querySelectorAll('input[type="text"].float')) {
input.addEventListener("keydown", floatChange);
}

View File

@ -1,5 +1,3 @@
/*eslint no-console: "off"*/
/**
* Save a piece of text to file as if it was downloaded
* @param {string} filename
@ -7,17 +5,18 @@
* @param {string} type
*/
export function download(filename, text, type) {
if(undefined == type) { type = "text/plain"; }
if (undefined == type) {
type = "text/plain";
}
var pom = document.createElement('a');
pom.setAttribute('href', 'data:'+type+';charset=utf-8,' + encodeURIComponent(text));
pom.setAttribute('href', 'data:' + type + ';charset=utf-8,' + encodeURIComponent(text));
pom.setAttribute('download', filename);
if (document.createEvent) {
var event = document.createEvent('MouseEvents');
event.initEvent('click', true, true);
pom.dispatchEvent(event);
}
else {
} else {
pom.click();
}
}
@ -35,25 +34,25 @@ export function download(filename, text, type) {
* @param {fileOpenedCallback} onready Callback to run when file is opened
* @param {Array} accept Array of mime types that the file dialog will accept
*/
export function upload(onready,accept) {
export function upload(onready, accept) {
let input = document.createElement('input');
input.type = 'file';
if(Array.isArray(accept)){
if(accept.count > 0){
if (Array.isArray(accept)) {
if (accept.count > 0) {
input.accept = accept.join(", ");
}
} else if (undefined !== accept){
} else if (undefined !== accept) {
input.accept = accept;
}
input.onchange = () => {
let files = Array.from(input.files);
if(files.length > 0){
let files = Array.from(input.files);
if (files.length > 0) {
let file = files[0];
var reader = new FileReader();
reader.onload = function(e) {
var contents = e.target.result;
if(onready instanceof Function){
onready(file,contents);
if (onready instanceof Function) {
onready(file, contents);
}
};
reader.readAsText(file);
@ -64,8 +63,7 @@ export function upload(onready,accept) {
var event = document.createEvent('MouseEvents');
event.initEvent('click', true, true);
input.dispatchEvent(event);
}
else {
} else {
input.click();
}
}

View File

@ -1,21 +1,34 @@
/*eslint no-var: "error"*/
/*eslint no-console: "off"*/
/*eslint-disable no-trailing-spaces */
/*eslint-env es6*/
// Put this file in path/to/plugin/amd/src
/* eslint no-var: "error" */
/* eslint capitalized-comments: "off" */
/* eslint-env es6 */
import {loadFragment} from 'core/fragment';
import {load_strings} from './util/string-helper';
import {loadStrings} from './util/string-helper';
import {call} from 'core/ajax';
import notification from 'core/notification';
import {replaceNodeContents} from 'core/templates';
//import {markFormSubmitted} from 'core_form/changechecker'; // Moodle 4.00+ only
//import {notifyFormSubmittedByJavascript} from 'core_form/events'; // Moodle 4.00+ only
// import {markFormSubmitted} from 'core_form/changechecker'; // Moodle 4.00+ only
// import {notifyFormSubmittedByJavascript} from 'core_form/events'; // Moodle 4.00+ only
/* Moodle 3.11 safe import for when needed
let markFormSubmitted = () => {};
let notifyFormSubmittedByJavascript = () => {};
import('core_form/changechecker').then((ns) => {
debug.info(ns);
if(ns.markFormSubmitted) {
markFormSubmitted = ns.markFormSubmitted;
}
if(ns.notifyFormSubmittedByJavascript) {
notifyFormSubmittedByJavascript = ns.notifyFormSubmittedByJavascript;
}
}).catch(()=>{});
*/
export default {
install(Vue/*,options*/){
install(Vue/* ,options */) {
let strings = load_strings({
let strings = loadStrings({
editmod: {
save$core: "save$core",
cancel$core: "cancel$core",
@ -27,16 +40,16 @@ export default {
cmid: {
type: Number,
},
coursectxid:{
coursectxid: {
type: Number,
},
title: {
type: String,
default: "",
'default': "",
},
genericonly: {
type: Boolean,
default: false,
'default': false,
}
},
data() {
@ -48,22 +61,22 @@ export default {
computed: {
},
methods: {
openForm(){
openForm() {
const self = this;
self.$refs["editormodal"].show();
self.$refs.editormodal.show();
},
onShown(){
onShown() {
const self = this;
let params = {cmid: this.cmid};
console.info("Loading form");
loadFragment('local_treestudyplan', 'mod_edit_form', this.coursectxid, params).then((html,js) =>{
replaceNodeContents(self.$refs["content"], html, js);
loadFragment('local_treestudyplan', 'mod_edit_form', this.coursectxid, params).then((html, js) => {
replaceNodeContents(self.$refs.content, html, js);
return null;
}).catch(notification.exception);
},
onSave(){
onSave() {
const self = this;
let form = this.$refs["content"].getElementsByTagName("form")[0];
let form = this.$refs.content.getElementsByTagName("form")[0];
// markFormSubmitted(form); // Moodle 4.00+ only
// We call this, so other modules can update the form with the latest state.
@ -72,18 +85,18 @@ export default {
// notifyFormSubmittedByJavascript(form); // Moodle 4.00+ only
const formdata = new FormData(form);
const data =new URLSearchParams(formdata).toString();
//const formdata = new FormData(form);
//const data = {};
//formdata.forEach((value, key) => (data[key] = value));
const data = new URLSearchParams(formdata).toString();
// const formdata = new FormData(form);
// const data = {};
// formdata.forEach((value, key) => (data[key] = value));
call([{
methodname: 'local_treestudyplan_submit_cm_editform',
args: {cmid: this.cmid, formdata: data}
}])[0].done(()=>{
self.$emit("saved",formdata);
}).fail(notification.exception);
}])[0].then(() => {
self.$emit("saved", formdata);
return null;
}).catch(notification.exception);
}
},
template: `

261
amd/src/page-coach.js Normal file
View File

@ -0,0 +1,261 @@
/* eslint no-var: "error" */
/* eslint no-unused-vars: "off" */
/* eslint linebreak-style: "off" */
/* eslint no-trailing-spaces: "off" */
/* eslint promise/no-nesting: "off" */
/* eslint max-depth: ["error", 6]*/
/* eslint-env es6*/
// Put this file in path/to/plugin/amd/src
// You can call it anything you like
import {call} from 'core/ajax';
import notification from 'core/notification';
import Vue from './vue/vue';
import Debugger from './util/debugger';
import {loadStrings} from './util/string-helper';
import {processStudyplan} from './studyplan-processor';
import {studyplanTiming} from './util/date-helper';
import {addBrowserButtonEvent} from './util/browserbuttonevents';
import EditorComponents from './studyplan-editor-components';
Vue.use(EditorComponents);
import TSComponents from './treestudyplan-components';
Vue.use(TSComponents);
import RVComponents from './report-viewer-components';
Vue.use(RVComponents);
import ModalComponents from './modedit-modal';
Vue.use(ModalComponents);
import PortalVue from './portal-vue/portal-vue.esm';
Vue.use(PortalVue);
import BootstrapVue from './bootstrap-vue/bootstrap-vue';
Vue.use(BootstrapVue);
let debug = new Debugger("treestudyplancoach");
let strings = loadStrings({
coach: {
},
});
/**
* Initialize the Page
*/
export function init() {
let app = new Vue({
el: '#root',
data: {
selected: {
planid: 0,
studentid: 0,
},
displayedstudyplan: null,
activestudyplan: null,
associatedstudents: [],
selectedstudent: null,
studentstudyplan: null,
loadingstudyplan: false,
studyplans: [],
text: strings.coach,
toolbox: {
right: true,
},
usedcontexts: [],
editmode: false,
},
async mounted() {
call([{
methodname: 'local_treestudyplan_list_coaching_studyplans',
args: {}
}])[0].then(function(response) {
const timingval = {present: 0, past: 1, future: 2};
response.sort((a, b) => {
const timinga = studyplanTiming(a);
const timingb = studyplanTiming(b);
const t = timingval[timinga] - timingval[timingb];
if (t == 0) {
// Sort by name if timing is equal
return a.name.localeCompare(b.name);
} else {
return t;
}
});
app.studyplans = response;
// Load studyplan from hash if applicable
const hash = window.location.hash.replace('#', '');
const parts = hash.split("-");
if (!!parts && parts.length > 0 && parts[0] != '') {
for (let idx in app.studyplans) {
if (app.studyplans[idx].id == parts[0]) {
app.selectStudyplan(app.studyplans[idx], parts[1], false);
break;
}
}
}
return;
}).catch(notification.exception);
addBrowserButtonEvent(this.navChanged, this.navChanged);
},
computed: {
studentcount() {
let count = 0;
for (const group of app.associatedstudents) {
count += group.users.length;
}
return count;
}
},
methods: {
navChanged() {
const hash = window.location.hash.replace('#', '');
const parts = hash.split("-");
debug.log("Navigation changed", hash, parts);
if (!!parts && parts.length > 0) {
const planid = Number(parts[0]);
const studentid = (parts.length > 1) ? Number(parts[1]) : 0;
debug.log("Selected ids", planid, studentid, this.selected.planid, this.selected.studentid);
if (planid == 0) {
if (planid != this.selected.planid) {
this.closeStudyplan(false);
}
} else if (this.selected.planid != planid || (studentid == 0 && this.selected.studentid != 0)) {
debug.info("Requested plan changed - loading studyplan");
for (let idx in app.studyplans) {
const plan = this.studyplans[idx];
if (Number(plan.id) == planid) {
this.selectStudyplan(plan, studentid, false);
break;
}
}
} else if (this.selected.studentid != studentid) {
for (const group of app.associatedstudents) {
for (const student of group.users) {
if (Number(student.id) == studentid) {
app.showStudentView(student, false);
break;
}
}
}
}
}
},
closeStudyplan(updatehash = true) {
app.selected.planid = 0;
app.selected.studentid = 0;
app.activestudyplan = null;
app.associatedstudents = [];
app.studentstudyplan = [];
app.displayedstudyplan = null;
if (updatehash) {
window.location.hash = '';
}
},
selectStudyplan(studyplan, studentid, updatehash = true) {
app.selected.planid = Number(studyplan.id);
app.selected.studentid = studentid ? Number(studentid) : 0;
// Fetch studyplan
const self = this;
self.loadingstudyplan = true;
self.associatedstudents = [];
self.selectedstudent = null;
self.studentstudyplan = null;
call([{
methodname: 'local_treestudyplan_get_studyplan_map',
args: {id: studyplan.id}
}])[0].then((response) => {
self.activestudyplan = processStudyplan(response, true);
call([{
methodname: 'local_treestudyplan_all_associated_grouped',
args: {'studyplan_id': studyplan.id}
}])[0].then(function(response) {
self.associatedstudents = response;
let foundstudent = false;
if (studentid) {
for (const group of self.associatedstudents) {
for (const student of group.users) {
if (student.id == studentid) {
foundstudent = true;
self.showStudentView(student);
break;
}
}
}
}
if (!foundstudent) {
// Select first student available.
for (const group of self.associatedstudents) {
for (const student of group.users) {
foundstudent = true;
self.showStudentView(student);
break;
}
}
}
if (!foundstudent) {
// Update hash with just the studyplan if no student was available for display
app.selected.studentid = 0;
if (updatehash) {
window.location.hash = app.activestudyplan.id;
}
self.displayedstudyplan = self.activestudyplan;
self.loadingstudyplan = false;
}
return;
}).catch(notification.exception);
return;
}).catch(function(error) {
notification.exception(error);
app.loadingstudyplan = false;
});
},
showStudentView(student, updatehash = true) {
app.selected.studentid = student ? Number(student.id) : 0;
if (student) {
app.selectedstudent = student;
app.studentstudyplan = null;
app.loadingstudyplan = true;
call([{
methodname: 'local_treestudyplan_get_user_studyplan',
args: {userid: student.id, studyplanid: app.activestudyplan.id}
}])[0].then((response) => {
app.studentstudyplan = processStudyplan(response, false);
app.displayedstudyplan = app.studentstudyplan;
app.loadingstudyplan = false;
if (updatehash) {
window.location.hash = app.activestudyplan.id + "-" + student.id;
}
return;
}).catch(function(error) {
notification.exception(error);
app.loadingstudyplan = false;
});
} else {
this.showOverview(updatehash);
}
},
showOverview(updatehash = true) {
debug.info("Switch to overview", updatehash);
app.selected.studentid = 0;
app.selectedstudent = null;
app.studentstudyplan = null;
app.displayedstudyplan = app.activestudyplan;
if (updatehash) {
window.location.hash = app.activestudyplan.id;
}
}
},
});
}

View File

@ -1,17 +1,18 @@
/*eslint no-var: "error" */
/*eslint no-unused-vars: "off" */
/*eslint linebreak-style: "off" */
/*eslint no-trailing-spaces: "off" */
/*eslint-env es6*/
/* eslint no-var: "error" */
/* eslint no-unused-vars: "off" */
/* eslint linebreak-style: "off" */
/* eslint no-trailing-spaces: "off" */
/* eslint no-empty-function: "off" */
/* eslint-env es6*/
// Put this file in path/to/plugin/amd/src
// You can call it anything you like
import {get_string,get_strings} from 'core/str';
import {call} from 'core/ajax';
import notification from 'core/notification';
import Vue from './vue/vue';
// Commented out: import {resetAllFormDirtyStates} from 'core_form/changechecker'; // Moodle 4.00+ only
import Vue from './vue/vue';
import EditorComponents from './studyplan-editor-components';
Vue.use(EditorComponents);
@ -22,26 +23,38 @@ Vue.use(TSComponents);
import ModalComponents from './modedit-modal';
Vue.use(ModalComponents);
import Debugger from './util/debugger';
import {addBrowserButtonEvent} from './util/browserbuttonevents';
import {load_strings} from './util/string-helper';
import {ProcessStudyplan} from './studyplan-processor';
import {download,upload} from './downloader';
import {loadStrings} from './util/string-helper';
import {processStudyplan} from './studyplan-processor';
import {download, upload} from './downloader';
import {studyplanTiming} from './util/date-helper';
import mFormComponents from "./util/mform-helper";
Vue.use(mFormComponents);
import PortalVue from './portal-vue/portal-vue.esm';
Vue.use(PortalVue);
import BootstrapVue from './bootstrap-vue/bootstrap-vue';
Vue.use(BootstrapVue);
import {Drag, Drop, DropList} from './vue-easy-dnd/vue-easy-dnd.esm';
Vue.component('drag',Drag);
Vue.component('drop',Drop);
Vue.component('drop-list',DropList);
const debug = new Debugger("treestudyplan");
let strings = load_strings({
let resetAllFormDirtyStates = () => { };
import('core_form/changechecker').then((ns) => {
debug.info(ns);
if (ns.resetAllFormDirtyStates) {
resetAllFormDirtyStates = ns.resetAllFormDirtyStates;
}
return;
}).catch(()=>{});
let strings = loadStrings({
studyplan: {
studyplan_select_placeholder: 'studyplan_select_placeholder',
'studyplan_select_placeholder': 'studyplan_select_placeholder',
'advanced_import_from_file': 'advanced_import_from_file',
'advanced_create_from_template': 'advanced_create_from_template',
'studyplan_add': "studyplan_add",
},
});
@ -51,23 +64,28 @@ let strings = load_strings({
* @param {int} categoryid The category we shoud attempt to work in (1:1 related to the context)
* @param {object} options Options to be passed to this script
*/
export function init(contextid,categoryid,options) {
export function init(contextid, categoryid, options) {
// Make sure the id's are numeric and integer
if(undefined === contextid || !Number.isInteger(Number(contextid)) || contextid < 1 ){ contextid = 1;}
else { contextid = Number(contextid);} // ensure a numeric value instead of string
if(undefined === categoryid || !Number.isInteger(Number(categoryid))){ categoryid = 0;}
else { categoryid = Number(categoryid);} // ensure a numeric value instead of string
debug.info("options",options);
if ( options !== null && typeof options === 'object' && !Array.isArray(options) ) {
if ( !options.defaultAggregation ) {
options.defaultAggregation = "core";
}
if (undefined === contextid || !Number.isInteger(Number(contextid)) || contextid < 1) {
contextid = 1;
} else {
options = { defaultAggregation: "core"};
contextid = Number(contextid); // Ensure a numeric value instead of string
}
if (undefined === categoryid || !Number.isInteger(Number(categoryid))) {
categoryid = 0;
} else {
categoryid = Number(categoryid); // Ensure a numeric value instead of string
}
const in_systemcontext = (contextid <= 1);
debug.info("options", options);
if (options !== null && typeof options === 'object' && !Array.isArray(options)) {
if (!options.defaultAggregation) {
options.defaultAggregation = "core";
}
} else {
options = {defaultAggregation: "core"};
}
// Setup the initial Vue app for this page
let app = new Vue({
@ -79,203 +97,205 @@ export function init(contextid,categoryid,options) {
shortname: '',
description: '',
idnumber: '',
slots : 4,
slots: 4,
startdate: '2020-08-01',
enddate: '',
context: contextid,
aggregation: options.defaultAggregation,
aggregation_config: '',
'aggregation_config': '',
}
},
toolbox: {
shown: false,
right: true,
},
activestudyplan: null,
activepage: null,
loadingstudyplan: false,
studyplans: [],
frameworks: [],
badges: [],
courses: [],
templatecount: 0,
text: strings.studyplan,
usedcontexts: [],
},
created() {
this.$root.$on('studyplanRemoved',(studyplan)=>{
this.$root.$on('studyplanRemoved', (studyplan)=>{
if(app.activestudyplan == studyplan){
if (app.activestudyplan == studyplan) {
app.activestudyplan = null;
}
// remove studyplan from index list
// Remove studyplan from index list
let index = null;
for(let idx in app.studyplans){
if(app.studyplans[idx].id == studyplan.id){
for (let idx in app.studyplans) {
if (app.studyplans[idx].id == studyplan.id) {
index = idx;
break;
}
}
if(index){
if (index) {
app.studyplans.splice(index, 1);
}
});
},
mounted() {
call([{
methodname: 'local_treestudyplan_list_studyplans',
args: { context_id: contextid}
}])[0].done(function(response){
const timingval = { future: 0, present: 1, past: 2, };
response.sort((a,b) => {
const timinga = TSComponents.studyplanTiming(a);
const timingb = TSComponents.studyplanTiming(b);
let t = timingval[timinga] - timingval[timingb];
if(t == 0){
// sort by start date if timing is equal
t = new Date(b.startdate).getTime() - new Date(a.startdate).getTime();
if (t == 0) {
// sort by name if timing is equal
t = a.name.localeCompare(b.name);
}
}
return t;
});
app.studyplans = response;
// load studyplan from hash if applicable
const hash = location.hash.replace('#','');
if(hash){
for(let idx in app.studyplans){
if(app.studyplans[idx].id == hash){
app.selectStudyplan(app.studyplans[idx]);
break;
}
}
}
}).fail(notification.exception);
call([{
methodname: 'local_treestudyplan_list_badges',
args: {}
}])[0].done(function(response){
app.badges = response;
}).fail(notification.exception);
call([{
methodname: 'local_treestudyplan_map_categories',
args: {root_id: categoryid}
}])[0].done(function(response){
app.courses = response;
}).fail(notification.exception);
call([{
methodname: 'local_treestudyplan_list_used_categories',
args: { operation: 'edit'}
}])[0].done(function(response){
app.usedcontexts = response;
}).fail(notification.exception);
this.initialize();
addBrowserButtonEvent(this.backPressed);
},
beforeunmount() {
},
computed: {
dropdown_title(){
if(this.activestudyplan && this.activestudyplan.name){
dropdownTitle() {
if (this.activestudyplan && this.activestudyplan.name) {
return this.activestudyplan.name;
}
else{
} else {
return this.text.studyplan_select_placeholder;
}
},
contextid(){
contextid() {
return contextid;
},
filterComponentType(){
return {
item: false,
component: true,
span: 1,
type: 'filter',
};
},
},
methods: {
backPressed() {
debug.log("Back button pressed");
if (app.activestudyplan) {
debug.log("Closing studyplan");
this.closeStudyplan();
}
},
initialize() {
call([{
methodname: 'local_treestudyplan_list_studyplans',
args: {'context_id': contextid}
}])[0].then(function(response) {
const timingval = {future: 0, present: 1, past: 2};
response.sort((a, b) => {
const timinga = studyplanTiming(a);
const timingb = studyplanTiming(b);
let t = timingval[timinga] - timingval[timingb];
if (t == 0) {
// Sort by start date if timing is equal
t = new Date(b.startdate).getTime() - new Date(a.startdate).getTime();
if (t == 0) {
// Sort by name if timing is equal
t = a.name.localeCompare(b.name);
}
}
return t;
});
app.studyplans = response;
// Load studyplan from hash if applicable
const hash = location.hash.replace('#', '');
if (hash) {
const id = hash;
for (const p of app.studyplans) {
if (p.id == id) {
app.selectStudyplan(id);
break;
}
}
}
return;
}).catch(notification.exception);
call([{
methodname: 'local_treestudyplan_list_available_categories',
args: {operation: 'edit', 'refcontext_id': contextid}
}])[0].then(function(response) {
app.usedcontexts = response;
return;
}).catch(notification.exception);
this.refreshTemplateCount();
},
refreshTemplateCount() {
call([{
methodname: 'local_treestudyplan_count_templates',
args: { }
}])[0].then(function(response) {
app.templatecount = response;
return;
}).catch(notification.exception);
},
closeStudyplan() {
app.activestudyplan = null;
window.location.hash = '';
},
movedStudyplan(plan,from,to) {
// reload the page in the new context (needed, since a number of links are not reactive in the page)
movedStudyplan(plan, from, to) {
// Reload the page in the new context (needed, since a number of links are not reactive in the page)
const params = new URLSearchParams(location.search);
params.delete('categoryid');
params.set("contextid", to);
window.location.search = params.toString();
setTimeout(() => {
// Reload page in a timeout to give other form javasccript the change to remove the beforeunload handler.
window.location.search = params.toString();
}, 50);
},
onStudyPlanCreated(newstudyplan){
app.studyplans.push(newstudyplan);
app.selectStudyplan(newstudyplan);
onStudyPlanCreated(newstudyplan) {
if (newstudyplan.context_id != contextid) {
// Study plan has changed context id - reload page into new context id and show the plan
const params = new URLSearchParams(location.search);
params.delete('categoryid');
params.set("contextid", newstudyplan.context_id);
// Make sure the form is no longer dirty before reloading the page - avoid beforeunload handler triggering.
resetAllFormDirtyStates();
window.location = window.location.pathname + "?" + params.toString() + "#" + newstudyplan.id;
} else {
app.studyplans.push(newstudyplan);
app.selectStudyplan(newstudyplan.id);
}
},
switchContext(ctx){
switchContext(ctxid) {
const params = new URLSearchParams(location.search);
params.set('categoryid', ctx.id);
window.location.search = params.toString();
params.delete('categoryid');
params.set('contextid', ctxid);
setTimeout(() => {
// Reload page in a timeout to give other form javasccript the change to remove the beforeunload handler.
window.location.href = window.location.pathname + "?" + params.toString();
}, 50);
},
selectStudyplan(studyplan){
// fetch studyplan
selectStudyplan(studyplanid) {
// Fetch studyplan
app.loadingstudyplan = true;
app.activestudyplan = null;
call([{
methodname: 'local_treestudyplan_get_studyplan_map',
args: { id: studyplan.id}
}])[0].done(function(response){
app.activestudyplan = ProcessStudyplan(response,true);
args: {id: studyplanid}
}])[0].then(function(response) {
app.activestudyplan = processStudyplan(response);
debug.info('studyplan processed');
app.loadingstudyplan = false;
window.location.hash = app.activestudyplan.id;
}).fail(function(error){
return;
}).catch(function(error) {
notification.exception(error);
app.loadingstudyplan = false;
});
},
import_studyplan(){
upload((filename,content)=>{
importStudyplan() {
const self = this;
upload((filename, content)=>{
call([{
methodname: 'local_treestudyplan_import_plan',
args: {
content: content,
format: "application/json",
context_id: contextid,
'context_id': contextid,
},
}])[0].done(function(response){
if(response.success){
location.reload();
}])[0].then(function(response) {
if (response.success) {
self.initialize();
} else {
debug.error("Import failed: ",response.msg);
debug.error("Import failed: ", response.msg);
}
}).fail(notification.exception);
return;
}).catch(notification.exception);
}, "application/json");
},
export_plan(plan,format){
let self = this;
if(format == undefined || !["json","csv"].includes(format)){
format = "json";
}
call([{
methodname: 'local_treestudyplan_export_plan',
args: {
studyplan_id: plan.id,
format: format
},
}])[0].done(function(response){
download(plan.shortname+".json",response.content,response.format);
}).fail(notification.exception);
},
toggletoolbox(event) {
debug.info(event);
this.toolbox.shown = event;
}
},
});
}

View File

@ -1,51 +1,71 @@
/*eslint no-var: "error" */
/*eslint no-unused-vars: "off" */
/*eslint linebreak-style: "off" */
/*eslint-env es6*/
/* eslint no-var: "error" */
/* eslint no-unused-vars: "off" */
/* eslint linebreak-style: "off" */
/* eslint promise/no-nesting: "off" */
/* eslint-env es6*/
/* eslint camelcase: "off" */
// Put this file in path/to/plugin/amd/src
// You can call it anything you like
define(['jquery', 'core/str', 'core/ajax', 'core/modal_factory', 'core/modal_events',
'local_treestudyplan/handlers', 'local_treestudyplan/debugger'],
function ($, str, ajax, ModalFactory, ModalEvents,
handlers, Debugger) {
let debug = new Debugger("treestudyplan");
import Debugger from './util/debugger';
import {get_strings} from 'core/str';
import {getStrings} from 'core/str';
import ModalFactory from 'core/modal_factory';
import ModalEvents from 'core/modal_events';
let self = {
init: function init() {
$('.path-local-treestudyplan a.m-action-confirm').on('click', function (e) {
/* Determine the proper getstrings function to use (MDL4.3+ recommends use of getStrings, which is jquery independent) */
const getstrFunc = (getStrings !== undefined) ? getStrings : get_strings;
let debug = new Debugger("treestudyplan-invitemanager");
/**
* Init function for page-invitemanager
*/
export function init() {
getstrFunc([
{key: 'ok', component: 'core'},
{key: 'confirm', component: 'core'},
]).then((s) => {
const strOk = s[0];
const strConfirm = s[1];
const els = document.querySelectorAll('.path-local-treestudyplan a.m-action-confirm');
els.forEach((el) => {
el.addEventListener('click', (e) => {
e.preventDefault();
let $link = $(e.currentTarget);
let href = $link.attr('data-actionhref');
let text = $link.attr('data-confirmtext');
let oktext = $link.attr('data-confirmbtn');
debug.info("Ok", oktext);
if (undefined == oktext) { oktext = str.get_string('ok'); }
let title = $link.attr('data-confirmtitle');
debug.info("Title", title);
if (undefined == title) { title = str.get_string('confirm'); }
debug.info("Link, href, text", $link, href, text);
const link = e.currentTarget;
let href = link.getAttribute('data-actionhref');
let text = link.getAttribute('data-confirmtext');
let oktext = link.getAttribute('data-confirmbtn');
if (undefined == oktext) {
oktext = strOk;
}
let title = link.getAttribute('data-confirmtitle');
if (undefined == title) {
title = strConfirm;
}
ModalFactory.create({
type: ModalFactory.types.SAVE_CANCEL,
title: title,
body: text,
}).then(function (modal) {
}).then((modal) => {
modal.setSaveButtonText(oktext);
let root = modal.getRoot();
root.on(ModalEvents.save, function () {
root.on(ModalEvents.save, () => {
window.location = href;
});
$(modal.modal).css("max-width", "345px");
modal.modal[0].style["max-width"] = "345px";
modal.show();
return modal;
}).catch((x) => {
debug.warn(x);
});
});
},
};
return self;
});
});
return;
}).catch((x) => {
debug.warn(x);
});
}

View File

@ -1,90 +1,32 @@
/*eslint no-var: "error" */
/*eslint no-unused-vars: "off" */
/*eslint linebreak-style: "off" */
/*eslint no-trailing-spaces: "off" */
/*eslint no-console: "off" */
/*eslint-env es6*/
/* eslint no-unused-vars: "off" */
/* eslint-env es6*/
// Put this file in path/to/plugin/amd/src
// You can call it anything you like
import {call} from 'core/ajax';
import notification from 'core/notification';
import Vue from './vue/vue';
import RVComponents from './report-viewer-components';
Vue.use(RVComponents);
import TSComponents from './treestudyplan-components';
import Debugger from './util/debugger';
import {ProcessStudyplans} from './studyplan-processor';
import PortalVue from './portal-vue/portal-vue.esm';
Vue.use(PortalVue);
import BootstrapVue from './bootstrap-vue/bootstrap-vue';
Vue.use(BootstrapVue);
let debug = new Debugger("treestudyplan-report");
/**
* Initialize the Page
* @param {string} type Type of page to show
* @param {Object} arg Arguments passed
* @param {Object} arg1 Argument1 as passed
*/
export function init(type="myreport",arg) {
export function init(type = "own", arg1) {
let app = new Vue({
el: '#root',
data: {
"studyplans": [],
"type": type,
"invitekey": (type == "invited") ? arg1 : null,
"userid": (type == "other") ? arg1 : null,
},
mounted() {
let call_method;
let call_args;
if(type == "invited"){
call_method = 'local_treestudyplan_get_invited_studyplan';
call_args = {"invitekey": arg};
}
else if(type == "other"){
call_method = 'local_treestudyplan_get_user_studyplans';
call_args = {"userid": arg};
}
else if(type == "teaching"){
call_method = 'local_treestudyplan_get_teaching_studyplans';
call_args = {};
}
else{
call_method = 'local_treestudyplan_get_own_studyplan';
call_args = {};
}
call([{
methodname: call_method,
args: call_args
}])[0].done(function(response){
debug.info("Studyplans:",response);
const timingval = { future: 0, present: 1, past: 2, };
response.sort((a,b) => {
const timinga = TSComponents.studyplanTiming(a);
const timingb = TSComponents.studyplanTiming(b);
let t = timingval[timinga] - timingval[timingb];
if(t == 0){
// sort by start date if timing is equal
t = new Date(b.startdate).getTime() - new Date(a.startdate).getTime();
if (t == 0) {
// sort by name if timing is equal
t = a.name.localeCompare(b.name);
}
}
return t;
});
app.studyplans = ProcessStudyplans(response);
}).fail(notification.exception);
},
methods: {
},

View File

@ -0,0 +1,121 @@
/* eslint no-var: "error" */
/* eslint no-unused-vars: "off" */
/* eslint linebreak-style: "off" */
/* eslint no-trailing-spaces: "off" */
/* eslint-env es6*/
import {call} from 'core/ajax';
import notification from 'core/notification';
import Vue from './vue/vue';
import Debugger from './util/debugger';
import {loadStrings} from './util/string-helper';
import SRComponents from './studyplan-report-components';
Vue.use(SRComponents);
import RVComponents from './report-viewer-components';
Vue.use(RVComponents);
import ModalComponents from './modedit-modal';
Vue.use(ModalComponents);
import PortalVue from './portal-vue/portal-vue.esm';
Vue.use(PortalVue);
import BootstrapVue from './bootstrap-vue/bootstrap-vue';
Vue.use(BootstrapVue);
let debug = new Debugger("treestudyplanviewer");
let strings = loadStrings({
studyplanReport: {
studyplan: 'studyplan',
page: 'studyplanpage',
periods: 'periods',
period: 'period',
loading: 'loading@core',
all: 'all@core',
from: 'from@core',
to: 'to@core',
},
});
/**
* Initialize the Page
* @param {Number} studyplanid The id of the studyplan we need to view
* @param {Number} pageid The id of the studyplan page we need to view
* @param {Number} firstperiod The number of the first period to view
* @param {Number} lastperiod The number of the last period to view
*/
export function init(studyplanid, pageid, firstperiod, lastperiod) {
if (undefined === pageid || !Number.isInteger(Number(pageid)) ||
undefined === studyplanid || !Number.isInteger(Number(studyplanid))) {
debug.error("Error: studyplan id and page id not provided as integer numbers to script.",
studyplanid, pageid, firstperiod, lastperiod);
return; // Do not continue if plan and page are not proper integers
}
// Ensure a numeric value instead of string.
studyplanid = Number(studyplanid);
pageid = Number(pageid);
// Startup app.
const app = new Vue({
el: '#root',
data: {
structure: null,
studyplan: null,
page: null,
text: strings.studyplanReport,
},
created() {
// On creation, load the page as specified
this.loadStructure(pageid, firstperiod, lastperiod);
},
computed: {
},
methods: {
loadStructure(pageid, firstperiod, lastperiod) {
const self = this;
this.structure = null; // Starts loading icon. Hides old data.
call([{
methodname: 'local_treestudyplan_get_report_structure',
args: {pageid: pageid,
firstperiod: firstperiod,
lastperiod: lastperiod
}
}])[0].then((response) => {
self.structure = response;
self.studyplan = response.studyplan;
self.page = response.page;
return;
}).catch(notification.exception);
},
selectedPage(e) {
debug.info("SelectedPage", e);
const pageid = e.target.value;
this.loadStructure(pageid);
},
selectedFirstPeriod(e) {
debug.info("selectedFirstPeriod", e);
let f = e.target.value;
let l = this.structure.lastperiod;
if (l < f) {
l = f;
}
this.loadStructure(this.page.id, f, l);
},
selectedLastPeriod(e) {
debug.info("selectedLastPeriod", e);
let f = this.structure.firstperiod;
let l = e.target.value;
if (l < f) {
l = f;
}
this.loadStructure(this.page.id, f, l);
},
},
});
}

View File

@ -1,8 +1,7 @@
/*eslint no-var: "error" */
/*eslint no-unused-vars: "off" */
/*eslint linebreak-style: "off" */
/*eslint no-trailing-spaces: "off" */
/*eslint-env es6*/
/* eslint no-unused-vars: "off" */
/* eslint no-trailing-spaces: "off" */
/* eslint promise/no-nesting: "off" */
/* eslint max-depth: ["error", 5] */
// Put this file in path/to/plugin/amd/src
// You can call it anything you like
@ -12,12 +11,13 @@ import notification from 'core/notification';
import Vue from './vue/vue';
import Debugger from './util/debugger';
import {load_strings} from './util/string-helper';
import {ProcessStudyplan} from './studyplan-processor';
import {loadStrings} from './util/string-helper';
import {processStudyplan} from './studyplan-processor';
import {studyplanTiming} from './util/date-helper';
import {addBrowserButtonEvent} from './util/browserbuttonevents';
import RVComponents from './report-viewer-components';
Vue.use(RVComponents);
import TSComponents from './treestudyplan-components';
import ModalComponents from './modedit-modal';
Vue.use(ModalComponents);
@ -29,29 +29,37 @@ Vue.use(BootstrapVue);
let debug = new Debugger("treestudyplanviewer");
let strings = load_strings({
let strings = loadStrings({
studyplan: {
studyplan_select_placeholder: 'studyplan_select_placeholder',
studyplanSelectPlaceholder: 'studyplan_select_placeholder',
},
});
/**
* Initialize the Page
* @param {int} contextid The context we should attempt to work in (1:1 related to the category)
* @param {int} categoryid The category we shoud attempt to work in (1:1 related to the context)
* @param {number} contextid The context we should attempt to work in (1:1 related to the category)
* @param {number} categoryid The category we shoud attempt to work in (1:1 related to the context)
*/
export function init(contextid,categoryid) {
export function init(contextid, categoryid) {
// Make sure the id's are numeric and integer
if(undefined === contextid || !Number.isInteger(Number(contextid)) || contextid < 1 ){ contextid = 1;}
else { contextid = Number(contextid);} // ensure a numeric value instead of string
if(undefined === categoryid || !Number.isInteger(Number(categoryid))){ categoryid = 0;}
else { categoryid = Number(categoryid);} // ensure a numeric value instead of string
const in_systemcontext = (contextid <= 1);
if (undefined === contextid || !Number.isInteger(Number(contextid)) || contextid < 1) {
contextid = 1;
} else { // Ensure a numeric value instead of string
contextid = Number(contextid);
}
if (undefined === categoryid || !Number.isInteger(Number(categoryid))) {
categoryid = 0;
} else { // Ensure a numeric value instead of string
categoryid = Number(categoryid);
}
let app = new Vue({
el: '#root',
data: {
selected: {
planid: 0,
studentid: 0,
},
displayedstudyplan: null,
activestudyplan: null,
associatedstudents: [],
@ -68,136 +76,201 @@ export function init(contextid,categoryid) {
async mounted() {
call([{
methodname: 'local_treestudyplan_list_studyplans',
args: {context_id: contextid}
}])[0].done(function(response){
const timingval = { present: 0, past: 1, future: 2};
response.sort((a,b) => {
const timinga = TSComponents.studyplanTiming(a);
const timingb = TSComponents.studyplanTiming(b);
args: {'context_id': contextid}
}])[0].then((response) => {
const timingval = {present: 0, past: 1, future: 2};
response.sort((a, b) => {
const timinga = studyplanTiming(a);
const timingb = studyplanTiming(b);
const t = timingval[timinga] - timingval[timingb];
if(t == 0){
// sort by name if timing is equal
if (t == 0) {
// Sort by name if timing is equal
return a.name.localeCompare(b.name);
}
else {
} else {
return t;
}
});
app.studyplans = response;
// load studyplan from hash if applicable
const hash = window.location.hash.replace('#','');
// Load studyplan from hash if applicable
const hash = window.location.hash.replace('#', '');
const parts = hash.split("-");
if(!!parts && parts.length > 0){
for(let idx in app.studyplans){
if(app.studyplans[idx].id == parts[0]){
app.selectStudyplan(app.studyplans[idx],parts[1]);
if (!!parts && parts.length > 0 && parts[0] != '') {
for (let idx in app.studyplans) {
if (app.studyplans[idx].id == parts[0]) {
app.selectStudyplan(app.studyplans[idx], parts[1]);
break;
}
}
}
}).fail(notification.exception);
return;
}).catch(notification.exception);
call([{
methodname: 'local_treestudyplan_list_used_categories',
args: { operation: 'view'}
}])[0].done(function(response){
methodname: 'local_treestudyplan_list_available_categories',
args: {operation: 'view', 'refcontext_id': contextid}
}])[0].then((response) => {
const contexts = [];
for(const ix in response){
if(response[ix].studyplancount >0){
contexts.push(response[ix]);
for (const ix in response) {
const cat = response[ix];
if (cat.studyplancount > 0 || cat.context_id == contextid) {
contexts.push(cat);
}
}
app.usedcontexts = contexts;
}).fail(notification.exception);
return;
}).catch(notification.exception);
addBrowserButtonEvent(this.navChanged, this.navChanged);
},
computed: {
dropdown_title(){
if(this.activestudyplan && this.activestudyplan.name){
dropdownTitle() {
if (this.activestudyplan && this.activestudyplan.name) {
return this.activestudyplan.name;
}
else{
return this.text.studyplan_select_placeholder;
} else {
return this.text.studyplanSelectPlaceholder;
}
},
contextid(){
contextid() {
return contextid;
}
},
methods: {
switchContext(ctx){
const params = new URLSearchParams(location.search);
params.set('categoryid', ctx.id);
window.location.search = params.toString();
navChanged() {
const hash = window.location.hash.replace('#', '');
const parts = hash.split("-");
debug.log("Navigation changed", hash, parts);
if (!!parts && parts.length > 0) {
const planid = Number(parts[0]);
const studentid = (parts.length > 1) ? Number(parts[1]) : 0;
debug.log("Selected ids", planid, studentid, this.selected.planid, this.selected.studentid);
if (planid == 0) {
if (planid != this.selected.planid) {
this.closeStudyplan(false);
}
} else if (this.selected.planid != planid || (studentid == 0 && this.selected.studentid != 0)) {
debug.info("Requested plan changed - loading studyplan");
for (let idx in app.studyplans) {
const plan = this.studyplans[idx];
if (Number(plan.id) == planid) {
this.selectStudyplan(plan, studentid, false);
break;
}
}
} else if (this.selected.studentid != studentid) {
for (const group of app.associatedstudents) {
for (const student of group.users) {
if (Number(student.id) == studentid) {
app.showStudentView(student, false);
break;
}
}
}
}
}
},
closeStudyplan() {
switchContext(ctxid) {
const params = new URLSearchParams(location.search);
params.delete('categoryid');
params.set('contextid', ctxid);
setTimeout(() => {
// Reload page in a timeout to give other form javasccript the change to remove the beforeunload handler.
window.location.href = window.location.pathname + "?" + params.toString();
}, 50);
},
closeStudyplan(updatehash = true) {
app.selected.planid = 0;
app.selected.studentid = 0;
app.activestudyplan = null;
app.associatedstudents = [];
app.studentstudyplan = [];
app.displayedstudyplan = null;
window.location.hash = '';
if (updatehash) {
window.location.hash = '';
}
},
selectStudyplan(studyplan,studentid){
// fetch studyplan
selectStudyplan(studyplan, studentid, updatehash = true) {
app.selected.planid = Number(studyplan.id);
app.selected.studentid = studentid ? Number(studentid) : 0;
// Fetch studyplan
app.loadingstudyplan = true;
app.activestudyplan = null;
app.associatedstudents = [];
app.selectedstudent = null;
app.studentstudyplan = null;
call([{
methodname: 'local_treestudyplan_get_studyplan_map',
args: { id: studyplan.id}
}])[0].done(function(response){
app.activestudyplan = ProcessStudyplan(response,true);
app.displayedstudyplan = app.activestudyplan;
app.loadingstudyplan = false;
window.location.hash = app.activestudyplan.id;
args: {id: studyplan.id}
}])[0].then((response) => {
app.activestudyplan = processStudyplan(response, true);
call([{
methodname: 'local_treestudyplan_all_associated',
args: { studyplan_id: studyplan.id}
}])[0].done(function(response){
methodname: 'local_treestudyplan_all_associated_grouped',
args: {'studyplan_id': studyplan.id}
}])[0].then((response) => {
app.associatedstudents = response;
if(studentid){
for(const student of app.associatedstudents){
if(student.id == studentid){
app.showStudentView(student);
break;
let foundstudent = false;
if (studentid) {
for (const group of app.associatedstudents) {
for (const student of group.users) {
if (student.id == studentid) {
foundstudent = true;
app.showStudentView(student, updatehash);
break;
}
}
}
}
}).fail(notification.exception);
}).fail(function(error){
if (!foundstudent) {
app.selected.studentid = 0;
if (updatehash) {
window.location.hash = app.activestudyplan.id;
}
app.displayedstudyplan = app.activestudyplan;
app.loadingstudyplan = false;
}
return;
}).catch(notification.exception);
return;
}).catch(function(error) {
notification.exception(error);
app.loadingstudyplan = false;
});
},
showStudentView(student){
app.selectedstudent = student;
app.studentstudyplan = null;
app.loadingstudyplan = true;
call([{
methodname: 'local_treestudyplan_get_user_studyplan',
args: { userid: student.id, studyplanid: app.activestudyplan.id}
}])[0].done(function(response){
app.studentstudyplan = ProcessStudyplan(response,false);
app.displayedstudyplan = app.studentstudyplan;
app.loadingstudyplan = false;
window.location.hash = app.activestudyplan.id + "-" + student.id;
}).fail(function(error){
notification.exception(error);
app.loadingstudyplan = false;
});
showStudentView(student, updatehash = true) {
app.selected.studentid = student ? Number(student.id) : 0;
if (student) {
app.selectedstudent = student;
app.studentstudyplan = null;
app.loadingstudyplan = true;
call([{
methodname: 'local_treestudyplan_get_user_studyplan',
args: {userid: student.id, studyplanid: app.selected.planid}
}])[0].then((response) => {
app.studentstudyplan = processStudyplan(response, false);
app.displayedstudyplan = app.studentstudyplan;
app.loadingstudyplan = false;
if (updatehash) {
window.location.hash = app.activestudyplan.id + "-" + student.id;
}
return;
}).catch((error) => {
notification.exception(error);
app.loadingstudyplan = false;
});
} else {
this.showOverview(updatehash);
}
},
showOverview(){
showOverview(updatehash = true) {
app.selected.studentid = 0;
app.selectedstudent = null;
app.studentstudyplan = null;
app.displayedstudyplan = app.activestudyplan;
window.location.hash = app.activestudyplan.id;
if (updatehash) {
window.location.hash = app.activestudyplan.id;
}
}
},

View File

@ -1,27 +1,39 @@
/*eslint-env es6*/
/* eslint-env es6*/
/* eslint no-console: "off"*/
/**
* Hide a primary navigation item by href
* @param {string|Array} hrefs The link that should be hidden
*/
export function hide_primary(hrefs) {
let element = document.createElement('style');
document.head.appendChild(element);
let sheet = element.sheet;
if(typeof hrefs === 'string' || hrefs instanceof String){
export function hidePrimary(hrefs) {
if (typeof hrefs === 'string' || hrefs instanceof String) {
hrefs = [hrefs];
}
if(typeof hrefs === 'object' && Array.isArray(hrefs)){
for(const ix in hrefs){
if (typeof hrefs === 'object' && Array.isArray(hrefs)) {
let css = '';
for (const ix in hrefs) {
const href = hrefs[ix];
let style = `
.primary-navigation li.nav-item > a[href*="${href}"] {
display: none;
css += `
.primary-navigation a[href*="${href}"],
#usernavigation a[href*="${href}"],
.drawer-primary a[href*="${href}"] {
display: none !important;
}
`;
sheet.insertRule(style, sheet.cssRules.length);
}
const element = document.createElement('style');
element.setAttribute('type', 'text/css');
if ('textContent' in element) {
element.textContent = css;
} else {
element.styleSheet.cssText = css;
}
document.head.appendChild(element);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/*eslint no-trailing-spaces: "off"*/
/*eslint no-eval: "off"*/
/* eslint no-trailing-spaces: "off"*/
/* eslint no-eval: "off"*/
/***********************************
* Licence: MIT

View File

@ -1,5 +1,5 @@
/*eslint no-console: "off"*/
/*eslint no-trailing-spaces: "off"*/
/* eslint no-console: "off"*/
/* eslint no-trailing-spaces: "off"*/
/*
The MIT License (MIT)
@ -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();
}
}
});
});

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +1,21 @@
/*eslint no-console: "off"*/
/* eslint no-console: "off"*/
/* eslint max-depth: ["error", 6]*/
/**
* Copy fields from one object to another
* @param {Object} target The target to move to
* @param {Object} source The source to move from
* @param {Object} target The target to copy to
* @param {Object} source The source to copy from
* @param {Array} fields The field names to copy
* @returns {Object} The map with strings loaded in
* @returns {Object} Reference to target
*/
export function objCopy(target,source,fields){
for(const ix in fields) {
export function objCopy(target, source, fields) {
if (fields === undefined || fields === null) {
fields = Object.getOwnPropertyNames(source);
}
for (const ix in fields) {
const field = fields[ix];
target[field] = source[field];
}
return target;
}
/**
@ -20,23 +25,23 @@ export function objCopy(target,source,fields){
* @param {*} identifier The value used to match the item
* @param {string} param The field name to match on (default: 'value')
*/
export function transportItem(target,source,identifier,param){
if(!param){
export function transportItem(target, source, identifier, param) {
if (!param) {
param = 'value';
}
// find item
// Find item
let item;
let itemindex;
for(const ix in source){
if(source[ix][param] == identifier){
for (const ix in source) {
if (source[ix][param] == identifier) {
item = source[ix];
itemindex = ix;
break;
}
}
if(item){
if (item) {
target.push(item);
source.splice(itemindex,1);
source.splice(itemindex, 1);
}
}
@ -45,14 +50,12 @@ export function transportItem(target,source,identifier,param){
* @param {Array} studyplans The list of studyplans to load
* @returns {Array} List of updated studyplans
*/
export function ProcessStudyplans(studyplans){
export function processStudyplans(studyplans) {
// Unify object references to connections between items, so there are no duplicates
for(const isx in studyplans)
{
for (const isx in studyplans) {
const studyplan = studyplans[isx];
ProcessStudyplan(studyplan);
processStudyplan(studyplan);
}
return studyplans;
}
@ -60,69 +63,80 @@ export function ProcessStudyplans(studyplans){
* Perform initial processing on a downloaded studyplan
* Mainly used to create the proper references between items
* @param {Object} studyplan The studyplan to process
* @returns Processed studyplan
* @returns {object} Processed studyplan
*/
export function ProcessStudyplan(studyplan){
let connections = {};
for(const ip in studyplan.pages){
export function processStudyplan(studyplan) {
for (const ip in studyplan.pages) {
const page = studyplan.pages[ip];
for(const il in page.studylines) {
const line = page.studylines[il];
processStudyplanPage(page);
}
return studyplan;
}
for(const is in line.slots ) {
const slot = line.slots[is];
/**
* Perform initial processing on a downloaded studyplan'page
* Mainly used to create the proper references between items
* @param {Object} page The studyplan page to process
* @returns {object} Processed studyplan
*/
export function processStudyplanPage(page) {
let connections = {};
for (const il in page.studylines) {
const line = page.studylines[il];
if(slot.courses !== undefined){
for(const ic in slot.courses){
const itm = slot.courses[ic];
for (const is in line.slots) {
const slot = line.slots[is];
for(const idx in itm.connections.in) {
const conn = itm.connections.in[idx];
if (slot.courses !== undefined) {
for (const ic in slot.courses) {
const itm = slot.courses[ic];
if(conn.id in connections){
itm.connections[idx] = connections[conn.id];
} else {
connections[conn.id] = conn;
}
for (const idx in itm.connections.in) {
const conn = itm.connections.in[idx];
if (conn.id in connections) {
itm.connections[idx] = connections[conn.id];
} else {
connections[conn.id] = conn;
}
for(const idx in itm.connections.out) {
const conn = itm.connections.out[idx];
}
for (const idx in itm.connections.out) {
const conn = itm.connections.out[idx];
if(conn.id in connections){
itm.connections[idx] = connections[conn.id];
} else {
connections[conn.id] = conn;
}
if (conn.id in connections) {
itm.connections[idx] = connections[conn.id];
} else {
connections[conn.id] = conn;
}
}
}
}
if(slot.filters !== undefined){
for(const ix in slot.filters){
const itm = slot.filters[ix];
if (slot.filters !== undefined) {
for (const ix in slot.filters) {
const itm = slot.filters[ix];
for(const idx in itm.connections.in) {
const conn = itm.connections.in[idx];
for (const idx in itm.connections.in) {
const conn = itm.connections.in[idx];
if(conn.id in connections){
itm.connections[idx] = connections[conn.id];
} else {
connections[conn.id] = conn;
}
if (conn.id in connections) {
itm.connections[idx] = connections[conn.id];
} else {
connections[conn.id] = conn;
}
for(const idx in itm.connections.out) {
const conn = itm.connections.out[idx];
}
for (const idx in itm.connections.out) {
const conn = itm.connections.out[idx];
if(conn.id in connections){
itm.connections[idx] = connections[conn.id];
} else {
connections[conn.id] = conn;
}
if (conn.id in connections) {
itm.connections[idx] = connections[conn.id];
} else {
connections[conn.id] = conn;
}
}
}
}
}
}
return studyplan;
return page;
}

View File

@ -0,0 +1,941 @@
/* eslint no-var: "error"*/
/* eslint no-unused-vars: warn */
/* eslint max-depth: ["error", 6] */
/* eslint promise/no-nesting: "off" */
/* eslint camelcase: "off" */
/* eslint-env es6*/
// Put this file in path/to/plugin/amd/src
import {loadStrings} from './util/string-helper';
import {call} from 'core/ajax';
import notification from 'core/notification';
import TSComponents from './treestudyplan-components';
import FitTextVue from './util/fittext-vue';
import {formatDatetime} from "./util/date-helper";
/**
* Strip tags from html
* @param {*} html
* @returns {string}
*/
function striptags(html) {
const tmp = document.createElement("DIV");
tmp.innerHTML = html;
const text = tmp.textContent || tmp.innerText;
tmp.remove();
return text;
}
/**
* Retrieve condition headers
* @param {Object} item
* @returns {Array}
*/
function conditionHeaders(item) {
const course = item.course;
const list = [];
if (course.competency) {
for (const cmp of course.competency.competencies) {
list.push({
name: (cmp.details ? (`${cmp.title} - ${cmp.details}`) : cmp.title),
tooltip: cmp.description,
});
}
} else if (course.completion) {
for (const cnd of course.completion.conditions) {
for (const itm of cnd.items) {
list.push({
name: itm.title,
tooltip: `${itm.details.type}: ${itm.details.requirement}`,
});
}
}
} else if (course.grades) {
for (const g of course.grades) {
if (g.selected) {
list.push({
name: g.name,
tooltip: `${g.typename}: ${striptags(g.name)}`,
});
}
}
}
return list;
}
/**
* Retrieve conditions
* @param {Object} item
* @returns {Array}
*/
function conditions(item) {
const course = item.course;
const list = [];
if (course.competency) {
for (const cmp of course.competency.competencies) {
list.push(cmp);
}
} else if (course.completion) {
for (const cnd of course.completion.conditions) {
for (const itm of cnd.items) {
list.push(itm);
}
}
} else if (course.grades) {
for (const g of course.grades) {
if (g.selected) {
list.push(g);
}
}
}
return list;
}
export default {
install(Vue /* ,options */) {
Vue.use(TSComponents);
Vue.use(FitTextVue);
let strings = loadStrings({
report: {
loading: "loadinghelp@core",
studyplan_past: "studyplan_past",
studyplan_present: "studyplan_present",
studyplan_future: "studyplan_future",
back: "back",
},
invalid: {
error: 'error',
},
header: {
overall: 'overall',
students: 'students@core',
firstname: 'firstname@core',
lastname: 'lastname@core',
email: 'email@core',
lastaccess: 'lastaccess@core',
},
studentresults: {
completion_incomplete: "completion_incomplete",
completion_failed: "completion_failed",
completion_pending: "completion_pending",
completion_progress: "completion_progress",
completion_completed: "completion_completed",
completion_good: "completion_good",
completion_excellent: "completion_excellent",
student_not_tracked: "student_not_tracked",
never: "never@core",
}
});
/* **********************************
* *
* Treestudyplan Viewer components *
* *
* **********************************/
Vue.component('q-studyplanreport', {
props: {
structure: {
type: Object,
},
},
data() {
return {
students: [],
studentresults: {},
studentsloading: true,
expansioninfo: {
periods: {},
lines: {},
items: {},
},
groupinfo: {},
sorting: {
header: 'lastname',
asc: true,
}
};
},
watch: {
structure: {
immediate: true,
handler(structure) {
this.loadStudents(); // Reload the student list
// (Re)build expansion info structure
let firstperiod = true;
for (const period of structure.periods) {
const pid = period.period.id;
if (!this.expansioninfo.periods[pid]) {
// Use this.$set to make sure the properties are reactive.
this.$set(
this.expansioninfo.periods,
pid,
{
expanded: ((firstperiod && period.lines.length > 0) ? true : false),
}
);
this.$set(
this.expansioninfo.lines,
period.period.id,
{}
);
}
for (const line of period.lines) {
const lid = line.line.id;
if (!this.expansioninfo.lines[lid]) {
// Use this.$set to make sure the properties are reactive.
this.$set(
this.expansioninfo.lines[pid],
lid,
{
expanded: true,
}
);
}
for (const item of line.items) {
if (!this.expansioninfo.items[item.id]) {
// Use this.$set to make sure the properties are reactive.
this.$set(
this.expansioninfo.items,
item.id,
{
expanded: false,
}
);
}
}
}
firstperiod = false;
}
}
}
},
computed: {
sortedstudents() {
// Probably could make a deep copy for purity's sake, but this works just as well.
const students = this.students;
for (const group of this.students) {
group.users.sort((a, b) => {
let d = a;
let e = b;
if (!this.sorting.asc) {
d = b;
e = a;
}
if (this.sorting.header == "lastaccess") {
const dvalue = (d[this.sorting.header] ? d[this.sorting.header] : 0);
const evalue = (e[this.sorting.header] ? e[this.sorting.header] : 0);
return dvalue - evalue;
} else {
return String(d[this.sorting.header]).localeCompare(String(e[this.sorting.header]));
}
});
}
return students;
},
resultColCount() {
let count = 0;
for (const period of this.structure.periods) {
const pid = period.period.id;
if (!this.expansioninfo.periods[pid].expanded) {
// This period is not expanded. Make it 3 units wide
count += 2;
} else {
for (const line of period.lines) {
const lid = line.line.id;
if (!this.expansioninfo.lines[pid][lid].expanded) {
count += 1;
} else {
for (const item of line.items) {
if (!this.expansioninfo.items[item.id].expanded) {
count += 1;
} else {
count += 1 + conditions(item).length;
}
}
}
}
}
}
return count;
}
},
methods: {
loadStudents() {
const self = this;
self.studentsloading = true;
call([{
methodname: 'local_treestudyplan_all_associated_grouped',
args: {'studyplan_id': this.structure.studyplan.id}
}])[0].then((response) => {
self.students = response;
for (const group of self.students) {
self.$set(
self.groupinfo,
group.id,
{
expanded: true,
}
);
for (const student of group.users) {
self.$set(
self.studentresults,
student.id,
{
loading: true,
results: [],
}
);
call([{
methodname: 'local_treestudyplan_get_report_data',
args: {
pageid: self.structure.page.id,
userid: student.id,
firstperiod: self.structure.firstperiod,
lastperiod: self.structure.lastperiod,
}
}])[0].then((response) => {
self.studentresults[student.id].loading = false;
self.studentresults[student.id].results = response;
return;
}).catch(notification.exception);
}
}
self.studentsloading = false;
return;
}).catch(notification.exception);
},
expansionChanged(parm, id, val) {
if (parm[0] == 'p') {
parm = 'periods';
} else if (parm[0] == 'l') {
parm = 'lines';
} else {
parm = 'items';
}
if (parm == 'lines') {
this.expansioninfo[parm][id[0]][id[1]].expanded = val;
} else {
this.expansioninfo[parm][id].expanded = val;
}
},
groupExpansionChanged(group) {
this.groupinfo[group.id].expanded = !this.groupinfo[group.id].expanded;
},
toggleSort(header) {
if (this.sorting.header == header) {
this.sorting.asc = !this.sorting.asc;
} else {
this.sorting.header = header;
this.sorting.asc = true;
}
}
},
template: `
<table class='q-studyplanreport'
:style="'--resultColCount: '+resultColCount+';'">
<colgroup class="q-col-studentinfo">
<col class="q-name"></col>
<col class="q-lastaccess"></col>
</colgroup>
<colgroup class="q-col-resultinfo">
<col v-for="n in resultColCount"></col>
</colgroup>
<q-header
:sorting='sorting'
:structure='structure'
:expansion='expansioninfo'
@expansion='expansionChanged'
@togglesort="toggleSort"
></q-header>
<template v-if="!studentsloading">
<template v-for="group in sortedstudents">
<q-groupheading
v-if="group.users && group.users.length > 0"
:group="group"
:expanded="groupinfo[group.id].expanded"
@togglegroup="groupExpansionChanged"
:resultcolumns="resultColCount"
:studentinfocolumns="2"
></q-groupheading>
<template v-if='groupinfo[group.id].expanded'>
<q-studentresults v-for="(student,idx) in group.users"
:key="student.id"
:student='student'
:even="(idx%2==1)"
:structure='structure'
:results='studentresults[student.id].results'
:loading='studentresults[student.id].loading'
:expansion='expansioninfo'
></q-studentresults>
</template>
</template>
</template>
<q-inforow v-else
:resultcolumns="resultColCount"
:studentinfocolumns="2"><div class="spinner-border spinner-border-sm text-info" role="status"></div></q-inforow>
</table>
`,
});
Vue.component('q-header', {
props: {
structure: {
type: Object,
},
sorting: {
type: Object,
},
expansion: {
type: Object
},
},
data() {
return {
text: strings.header,
};
},
computed: {
},
methods: {
conditions(item) {
return conditionHeaders(item);
},
colspanPeriod(period) {
const pid = period.period.id;
if (this.expansion.periods[pid].expanded) {
let sum = 0;
for (const l of period.lines) {
sum += this.colspanLine(period, l);
}
return sum;
} else {
return 2;
}
},
colspanLine(period, line) {
const pid = period.period.id;
const lid = line.line.id;
if (this.expansion.lines[pid][lid].expanded) {
let sum = 0;
for (const i of line.items) {
sum += this.colspanItem(i);
}
return sum;
} else {
return 1;
}
},
colspanItem(item) {
if (this.expansion.items[item.id].expanded) {
const cs = this.conditions(item);
return 1 + cs.length;
} else {
return 1;
}
},
togglePeriod(period, val) {
if (val === undefined) {
val = !(this.expansion.periods[period.id].expanded);
}
this.$emit('expansion', 'periods', period.id, val);
},
toggleLine(period, line, val) {
if (val === undefined) {
val = !(this.expansion.lines[period.id][line.id].expanded);
}
this.$emit('expansion', 'lines', [period.id, line.id], val);
},
toggleItem(item, val) {
if (val === undefined) {
val = !(this.expansion.items[item.id].expanded);
}
this.$emit('expansion', 'items', item.id, val);
},
toggleSort(heading) {
this.$emit('togglesort', heading);
}
},
/* TODO: https://css-tricks.com/position-sticky-and-table-headers/ */
template: `
<thead class='q-header'>
<tr> <!-- period heading -->
<th rowspan='4' colspan='2' class='q-studentinfo q-generic'><span>{{text.students}}</span></th>
<th v-for="p in structure.periods"
:class="'q-period-heading '+ ((expansion.periods[p.period.id].expanded)?'expanded':'collapsed')"
:colspan='colspanPeriod(p)'
:rowspan='(expansion.periods[p.period.id].expanded && p.lines.length > 0)?1:5'
><span class="q-wrap"><a v-if='(p.lines.length > 0)' href='#' @click.prevent="togglePeriod(p.period)"
><i v-if="expansion.periods[p.period.id].expanded"
class='q-chevron fa fa-minus'></i
><i v-else class='q-chevron fa fa-plus'></i
>&nbsp;{{ p.period.fullname}}</a
><span v-else>{{ p.period.fullname}}</span></span
></th>
</tr>
<tr> <!-- line heading -->
<template v-for="p in structure.periods">
<template v-if="expansion.periods[p.period.id].expanded">
<th v-for="l in p.lines"
:class="'q-line-heading '
+ ((expansion.lines[p.period.id][l.line.id].expanded)?'expanded':'collapsed')"
:colspan="colspanLine(p,l)"
:rowspan='(expansion.lines[p.period.id][l.line.id].expanded)?1:4'
><span class="q-wrap"><fittext vertical maxsize="18pt"
><span class='q-label'
:title="l.line.shortname"
v-html="l.line.shortname"
></span
></fittext></span
></th>
</template>
</template>
</tr>
<tr> <!-- item heading -->
<template v-for="p in structure.periods">
<template v-if="expansion.periods[p.period.id].expanded">
<template v-for="l in p.lines">
<template v-if="expansion.lines[p.period.id][l.line.id].expanded">
<th v-for="item in l.items"
:class="'q-item-heading ' + ((expansion.items[item.id].expanded)?'expanded':'collapsed')"
:colspan="colspanItem(item)"
:rowspan='(expansion.items[item.id].expanded)?1:3'
><a class="q-wrap" href='#' @click.prevent="toggleItem(item)"
><div class="q-toggle"
><i v-if="expansion.items[item.id].expanded"
class='q-chevron fa fa-minus'></i
><i v-else
class='q-chevron fa fa-plus'></i
></div><div class="q-title"
><fittext vertical maxsize="12pt" minsize="9pt"
><span class='q-label'
:title="item.course.displayname"
v-html="item.course.displayname"
></span
></fittext
></div
></a
></th>
</template>
</template>
</template>
</template>
</tr>
<tr> <!-- condition heading -->
<template v-for="p in structure.periods">
<template v-if="expansion.periods[p.period.id].expanded">
<template v-for="l in p.lines">
<template v-if="expansion.lines[p.period.id][l.line.id].expanded">
<template v-for="item in l.items">
<template v-if="expansion.items[item.id].expanded">
<th class='q-condition-heading overall' rowspan="2"
><span class='q-wrap'>{{ text.overall }}</span></th>
<th v-for="c in conditions(item)"
rowspan="2"
class='q-condition-heading'
><span class="q-wrap"
><fittext vertical maxsize="14pt"><a class='q-label q-condition-label'
:title="c.tooltip" href="#" @click.prevent
v-b-tooltip.focus
v-html="c.name"></a
></fittext></span
></th>
</template>
</template>
</template>
</template>
</template>
</template>
</tr>
<tr> <!-- student info heading -->
<th class="q-studentinfo q-name">
<fittext maxsize="12pt"
><a href="#" @click.prevent="toggleSort('firstname')">{{text.firstname}}</a
><i v-if="sorting.header=='firstname' && sorting.asc" class='fa fa-sort-asc fa-fw'></i
><i v-else-if="sorting.header=='firstname' && !sorting.asc" class='fa fa-sort-desc fa-fw'></i>
/ <a href="#" @click.prevent="toggleSort('lastname')">{{text.lastname}}</a
><i v-if="sorting.header=='lastname' && sorting.asc" class='fa fa-sort-asc fa-fw'></i
><i v-else-if="sorting.header=='lastname' && !sorting.asc" class='fa fa-sort-desc fa-fw'></i
></fittext>
</th>
<th class="q-studentinfo q-email">
<fittext maxsize="12pt"
><a href="#" @click.prevent="toggleSort('lastaccess')">{{text.lastaccess}}</a
><i v-if="sorting.header=='lastaccess' && sorting.asc" class='fa fa-sort-asc fa-fw'></i
><i v-else-if="sorting.header=='lastaccess' && !sorting.asc" class='fa fa-sort-desc fa-fw'></i
></fittext>
</th>
</tr>
</thead>
`,
});
Vue.component('q-groupheading', {
props: {
group: {
type: Object,
},
resultcolumns: {
type: Number,
'default': 1
},
studentinfocolumns: {
type: Number,
'default': 1
},
expanded: {
type: Boolean,
}
},
data() {
return {
};
},
computed: {
},
methods: {
toggleGroup() {
this.$emit('togglegroup', this.group);
}
},
template: `
<tr class='q-groupheading'>
<th :colspan="studentinfocolumns"><a href="#" @click.prevent="toggleGroup"
><i v-if="expanded" class="fa fa-minus"></i
><i v-else class="fa fa-plus"></i
>&nbsp;{{group.label}}</a></th>
<td :colspan="resultcolumns"></td>
</tr>
`,
});
Vue.component('q-inforow', {
props: {
resultcolumns: {
type: Number,
'default': 1
},
studentinfocolumns: {
type: Number,
'default': 1
},
},
data() {
return {
};
},
computed: {
},
methods: {
},
template: `
<tr class='q-inforow'>
<td :colspan="studentinfocolumns"><slot></slot></td>
<td :colspan="resultcolumns"></td>
</tr>
`,
});
Vue.component('q-studentresults', {
props: {
student: {
type: Object,
},
structure: {
type: Object,
},
results: {
type: Array,
},
loading: {
type: Boolean,
'default': false
},
expansion: {
type: Object,
},
even: {
type: Boolean,
'default': false,
}
},
data() {
return {
text: strings.studentresults,
};
},
computed: {
lastaccess() {
if (this.student.lastaccess) {
return formatDatetime(this.student.lastaccess); // Takes date in milliseconds
} else {
return this.text.never;
}
}
},
methods: {
useritems(line) {
const list = [];
for (const item of line.items) {
let newitm = item;
for (const itm of this.results) {
if (item.id == itm.id) {
newitm = itm;
break;
}
}
list.push(newitm);
}
return list;
},
conditions(item) {
return conditions(item);
},
},
/* https://css-tricks.com/position-sticky-and-table-headers/ */
template: `
<tr :class="'q-student-results userrow ' + (even?'even':'odd')">
<td class='q-studentinfo q-name'><fittext maxsize="12pt">{{student.firstname}} {{student.lastname}}</fittext></td>
<td class='q-studentinfo q-email'><fittext maxsize="12pt">{{lastaccess}}</fittext></td>
<template v-for="p in structure.periods">
<template v-if="expansion.periods[p.period.id].expanded && p.lines.length > 0">
<template v-for="l in p.lines">
<template v-if="expansion.lines[p.period.id][l.line.id].expanded">
<template v-for="item in useritems(l)">
<td class='q-result overall'
><q-courseresult
:item="item"
:student="student"
:loading="loading"
></q-courseresult
></td>
<template v-if="expansion.items[item.id].expanded">
<td v-for="(c,idx) in conditions(item)"
class='q-result'
><q-conditionresult
:item="item"
:conditionidx="idx"
:student="student"
:loading="loading"
></q-conditionresult
></td>
</template>
</template>
</template>
<td v-else class='q-result collapsed'>&nbsp;</td>
</template>
</template>
<td v-else colspan="2" class='q-result collapsed'>&nbsp;</td>
</template>
</tr>
`,
});
Vue.component('q-courseresult', {
props: {
student: {
type: Object,
},
item: {
type: Object,
},
loading: {
type: Boolean,
'default': false
},
},
data() {
return {
text: strings.studentresults,
};
},
computed: {
hasprogressinfo() {
const course = this.item.course;
if (!course.enrolled) {
return false;
} else {
return (course.completion || course.competency || course.grades) ? true : false;
}
},
completion_icon() {
const completion = this.item.completion;
switch (completion) {
default: // Case "incomplete"
return "circle-o";
case "pending":
return "question-circle";
case "failed":
return "times-circle";
case "progress":
return "exclamation-circle";
case "completed":
return "check-circle";
case "good":
return "check-circle";
case "excellent":
return "check-circle";
}
},
},
methods: {
},
template: `
<span class='q-courseresult'>
<template v-if="loading">
<div class="spinner-border spinner-border-sm text-info" role="status"></div>
</template>
<template v-else-if='!item.course.enrolled'>
<i v-b-popover.top
class="fa fa-exclamation-triangle t-not-enrolled-alert"
:title="text.student_not_tracked"></i>
</template>
<template v-else-if="item.lineenrolled" >
<i v-b-popover.top
:class="'fa fa-'+completion_icon+
' r-completion-'+item.completion"
:title="text['completion_'+item.completion]"></i>
</template>
</span>
`,
});
Vue.component('q-conditionresult', {
props: {
student: {
type: Object,
},
item: {
type: Object,
},
loading: {
type: Boolean,
'default': false
},
conditionidx: {
type: Number,
}
},
data() {
return {
text: strings.studentresults,
};
},
computed: {
conditions() {
return conditions(this.item);
},
condition() {
if (this.conditionidx >= 0 && this.conditionidx < this.conditions.length) {
return this.conditions[this.conditionidx];
} else {
return null;
}
},
hasprogressinfo() {
const course = this.item.course;
if (!course.enrolled) {
return false;
} else {
return (course.completion || course.competency || course.grades);
}
},
completion_icon() {
const completion = this.condition_completion();
switch (completion) {
default: // Case "incomplete"
return "circle-o";
case "pending":
return "question-circle";
case "failed":
return "times-circle";
case "progress":
return "exclamation-circle";
case "completed":
return "check-circle";
case "good":
return "check-circle";
case "excellent":
return "check-circle";
}
},
condition_value() {
const course = this.item.course;
if (course.competency) {
if (this.condition.grade) {
// Return grade if possible.
return this.condition.grade;
}
} else if (course.completion) {
if (this.condition.grade) {
// Return grade if possible.
return this.condition.grade;
}
} else if (course.grades) {
return this.condition.grade;
}
// Fallback to completion icon.
const icon = this.completion_icon();
return `<i class='fa fa-${icon}'></i>`;
},
condition_completion() {
// Unify completion information
const course = this.item.course;
if (course.competency) {
const competency = this.condition;
if (competency.proficient && competency.courseproficient) {
return "completed";
} else if (competency.proficient) {
return "completed";
} else if (competency.proficient === false) {
return "failed";
} else if (competency.progress) {
return "progress";
} else {
return "incomplete";
}
} else if (course.completion) {
return this.condition.status;
} else if (course.grades) {
return this.condition.completion;
} else {
return "incomplete";
}
}
},
methods: {
},
template: `
<span class='q-conditionresult'>
<fittext v-if="item.lineenrolled" maxsize="10pt" singleline dynamic>
<template v-if="loading">
<div class="spinner-border spinner-border-sm text-info" role="status"></div>
</template>
<template v-else-if='!item.course.enrolled'>
<i class="fa fa-ellipsis-h"
:title="text.student_not_tracked"></i>
</template>
<template v-else>
<span
:class="'r-completion-'+condition_completion"
:title="text['completion_'+condition_completion]"
>{{condition_value}}</span
>
</template>
</fittext>
</span>
`,
});
},
};

Some files were not shown because too many files have changed in this diff Show More