@opensalt/ob3-definer 1.2.3 → 1.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.html +3 -1
- package/dist/ob3-definer.js +11 -11
- package/package.json +4 -1
- package/.vscode/extensions.json +0 -3
- package/NOTES +0 -6
- package/Test Achievement-bug1.json +0 -42
- package/formkit.config.js +0 -27
- package/index-2.html +0 -22
- package/index.html +0 -19
- package/jsconfig.json +0 -8
- package/public/favicon.svg +0 -7
- package/src/App.vue +0 -23
- package/src/assets/base.css +0 -86
- package/src/assets/main.css +0 -24
- package/src/assets/style.scss +0 -33
- package/src/components/AchievementCriteria.vue +0 -78
- package/src/components/AchievementDefiner.vue +0 -223
- package/src/components/AchievementImage.vue +0 -167
- package/src/components/AchievementType.vue +0 -118
- package/src/components/AdditionalTab.vue +0 -33
- package/src/components/AddressComponent.vue +0 -118
- package/src/components/AlignmentComponent.vue +0 -103
- package/src/components/AlignmentType.vue +0 -98
- package/src/components/AlignmentsComponent.vue +0 -13
- package/src/components/AlignmentsTab.vue +0 -18
- package/src/components/BasicTab.vue +0 -55
- package/src/components/CreatorProfile.vue +0 -166
- package/src/components/CriterionLevels.vue +0 -97
- package/src/components/DetailTab.vue +0 -72
- package/src/components/IndividualName.vue +0 -63
- package/src/components/MarkdownRenderer.vue +0 -20
- package/src/components/OtherIdentifiers.vue +0 -116
- package/src/components/RelatedList.vue +0 -89
- package/src/components/ResultDescription.vue +0 -121
- package/src/components/ResultType.vue +0 -94
- package/src/components/TagList.vue +0 -121
- package/src/components/ValueList.vue +0 -144
- package/src/inputs/innerLabelTextInput.js +0 -62
- package/src/inputs/innerLabelTextareaInput.js +0 -57
- package/src/inputs/selectInputGroup.js +0 -76
- package/src/main.js +0 -57
- package/src/stores/credential.js +0 -292
- package/src/validation/uri.js +0 -13
- package/test-index.html +0 -17
- package/vite.config.js +0 -39
package/package.json
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opensalt/ob3-definer",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.5",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/opensalt/OB3DefinitionWidget.git"
|
|
8
8
|
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
9
12
|
"type": "module",
|
|
10
13
|
"description": "A widget to create an Open Badge achievement definition.",
|
|
11
14
|
"main": "dist/ob3-definer.js",
|
package/.vscode/extensions.json
DELETED
package/NOTES
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"id": "https://bismarckstate.edu/academics/programs/computersupport/",
|
|
3
|
-
"type": [
|
|
4
|
-
"Achievement"
|
|
5
|
-
],
|
|
6
|
-
"alignment": [],
|
|
7
|
-
"achievementType": null,
|
|
8
|
-
"creator": null,
|
|
9
|
-
"creditsAvailable": null,
|
|
10
|
-
"criteria": {
|
|
11
|
-
"id": null,
|
|
12
|
-
"narrative": "Test narrative"
|
|
13
|
-
},
|
|
14
|
-
"description": "This degree program combines cybersecurity with system and network administration. Classes focus on best practices in security, networking, operating systems, and their administration.\r\n\r\nOur students experience real-life scenarios through hands-on labs and simulations that are constructed based on feedback from the cybersecurity community and continually adapted to today\u0027s changing world. Not only do we teach security concepts and technologies, we also teach the information technology component that goes with it. Upon graduation, you will be ready to use your knowledge and skills in the workforce.\r\n\r\nThe curriculum contains core classes in computer hardware, Windows and Linux operating systems, networking, security, and programming. Students may have the opportunity to earn college credit for cooperative education or internship opportunities with local businesses.\r\n\r\nAll classes in the program can be taken online or on campus. We continue to evolve our advanced instructional methodologies to complement cutting-edge and remote learning technologies, providing our students with synchronous, virtual classroom environments. Our flexible, online and/or on-campus courses make it easier to achieve your educational goals. \r\n\r\nStudents can complete the program in two years, three years, or longer, depending upon prior preparation in Math, English, and Computers.",
|
|
15
|
-
"fieldOfStudy": "CIP Code Data Pulled From Campus Solutions",
|
|
16
|
-
"humanCode": null,
|
|
17
|
-
"image": null,
|
|
18
|
-
"inLanguage": null,
|
|
19
|
-
"name": "Cybersecurity\u0026Computer Network",
|
|
20
|
-
"otherIdentifier": null,
|
|
21
|
-
"related": null,
|
|
22
|
-
"resultDescription": [
|
|
23
|
-
{
|
|
24
|
-
"id": "urn:uuid:229c6a36-e66a-4096-b659-6258ef66ec02",
|
|
25
|
-
"type": [
|
|
26
|
-
"ResultDescription"
|
|
27
|
-
],
|
|
28
|
-
"alignment": null,
|
|
29
|
-
"allowedValue": null,
|
|
30
|
-
"name": "Program Completed",
|
|
31
|
-
"requiredLevel": null,
|
|
32
|
-
"requiredValue": null,
|
|
33
|
-
"resultType": "Status",
|
|
34
|
-
"rubricCriterionLevel": null,
|
|
35
|
-
"valueMax": null,
|
|
36
|
-
"valueMin": null
|
|
37
|
-
}
|
|
38
|
-
],
|
|
39
|
-
"specialization": null,
|
|
40
|
-
"tag": null,
|
|
41
|
-
"version": null
|
|
42
|
-
}
|
package/formkit.config.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { generateClasses } from '@formkit/themes'
|
|
2
|
-
|
|
3
|
-
const config = {
|
|
4
|
-
config: {
|
|
5
|
-
classes: generateClasses({
|
|
6
|
-
global: { // classes
|
|
7
|
-
outer: '$reset mb-4',
|
|
8
|
-
input: 'form-control',
|
|
9
|
-
label: 'form-label',
|
|
10
|
-
help: 'form-text',
|
|
11
|
-
message: 'invalid-feedback',
|
|
12
|
-
},
|
|
13
|
-
form: {
|
|
14
|
-
form: "mt-1 mx-auto p-3 border rounded"
|
|
15
|
-
},
|
|
16
|
-
range: {
|
|
17
|
-
input: '$reset form-range',
|
|
18
|
-
},
|
|
19
|
-
submit: {
|
|
20
|
-
outer: '$reset mt-3',
|
|
21
|
-
input: '$reset btn btn-primary'
|
|
22
|
-
}
|
|
23
|
-
})
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export default config
|
package/index-2.html
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<link rel="icon" href="/favicon.svg">
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
-
<title>OB3 Achievement Definer</title>
|
|
8
|
-
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
|
9
|
-
<script type="module" src="/src/main.js"></script>
|
|
10
|
-
</head>
|
|
11
|
-
<body>
|
|
12
|
-
<div id="ob3-definer"
|
|
13
|
-
data-achievement='{"id":"https://bismarckstate.edu/academics/programs/computersupport/","type":["Achievement"],"alignment":[],"achievementType":null,"creator":null,"creditsAvailable":null,"criteria":{"id":null,"narrative":"Test narrative"},"description":"This degree program combines cybersecurity with system and network administration. Classes focus on best practices in security, networking, operating systems, and their administration.\r\n\r\nOur students experience real-life scenarios through hands-on labs and simulations that are constructed based on feedback from the cybersecurity community and continually adapted to todays changing world. Not only do we teach security concepts and technologies, we also teach the information technology component that goes with it. Upon graduation, you will be ready to use your knowledge and skills in the workforce.\r\n\r\nThe curriculum contains core classes in computer hardware, Windows and Linux operating systems, networking, security, and programming. Students may have the opportunity to earn college credit for cooperative education or internship opportunities with local businesses.\r\n\r\nAll classes in the program can be taken online or on campus. We continue to evolve our advanced instructional methodologies to complement cutting-edge and remote learning technologies, providing our students with synchronous, virtual classroom environments. Our flexible, online and/or on-campus courses make it easier to achieve your educational goals. \r\n\r\nStudents can complete the program in two years, three years, or longer, depending upon prior preparation in Math, English, and Computers.","fieldOfStudy":"CIP Code Data Pulled From Campus Solutions","humanCode":null,"image":null,"inLanguage":null,"name":"Cybersecurity&Computer Network","otherIdentifier":null,"related":null,"resultDescription":[{"id":"urn:uuid:229c6a36-e66a-4096-b659-6258ef66ec02","type":["ResultDescription"],"alignment":null,"allowedValue":null,"name":"Program Completed","requiredLevel":null,"requiredValue":null,"resultType":"Status","rubricCriterionLevel":null,"valueMax":null,"valueMin":null}],"specialization":null,"tag":null,"version":null}'
|
|
14
|
-
></div>
|
|
15
|
-
<script>
|
|
16
|
-
document.addEventListener('DOMContentLoaded', () => {
|
|
17
|
-
window.dispatchEvent(new CustomEvent('ob3-open'));
|
|
18
|
-
});
|
|
19
|
-
window.addEventListener('saveDefinition', function(e) {console.log(e);});
|
|
20
|
-
</script>
|
|
21
|
-
</body>
|
|
22
|
-
</html>
|
package/index.html
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<link rel="icon" href="/favicon.svg">
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
-
<title>OB3 Achievement Definer</title>
|
|
8
|
-
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
|
9
|
-
<script type="module" src="/src/main.js"></script>
|
|
10
|
-
</head>
|
|
11
|
-
<body>
|
|
12
|
-
<div id="ob3-definer"></div>
|
|
13
|
-
<script>
|
|
14
|
-
document.addEventListener('DOMContentLoaded', () => {
|
|
15
|
-
window.dispatchEvent(new CustomEvent('ob3-open'));
|
|
16
|
-
})
|
|
17
|
-
</script>
|
|
18
|
-
</body>
|
|
19
|
-
</html>
|
package/jsconfig.json
DELETED
package/public/favicon.svg
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
-
<g id="Layer_1">
|
|
3
|
-
<g id="favicon" stroke-width="0"/>
|
|
4
|
-
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.586 5.062l7.876 7.878-9.063 9.156-3.39-3.387 9.063-9.157-2.977-2.977-5.502 4.086 3.993 4.007-1.414 1.415-4.007-4.008-1.472 1.374 5.502 4.086 2.836-2.838 3.888 3.89z" fill="#58B4AE"/>
|
|
5
|
-
<path d="M3.324 18.981l3.389 3.389 9.787-9.924-3.39-3.388-9.786 9.923zM7.51 22.27l-2.977-2.977-.732.866 2.836 2.838 3.112-2.256-.473-.47-2.766 2.999.232.125.284-.125 1.382-.811z" fill="#95E1D3"/>
|
|
6
|
-
</g>
|
|
7
|
-
</svg>
|
package/src/App.vue
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import AchievementDefiner from "@/components/AchievementDefiner.vue";
|
|
3
|
-
|
|
4
|
-
const props = defineProps({
|
|
5
|
-
achievement: {
|
|
6
|
-
type: String,
|
|
7
|
-
default: ""
|
|
8
|
-
},
|
|
9
|
-
submitText: {
|
|
10
|
-
type: String,
|
|
11
|
-
default: "Save"
|
|
12
|
-
}
|
|
13
|
-
});
|
|
14
|
-
</script>
|
|
15
|
-
|
|
16
|
-
<template>
|
|
17
|
-
<div class="container">
|
|
18
|
-
<AchievementDefiner :achievement="achievement" :submit-text="submitText"/>
|
|
19
|
-
</div>
|
|
20
|
-
</template>
|
|
21
|
-
|
|
22
|
-
<style scoped>
|
|
23
|
-
</style>
|
package/src/assets/base.css
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
/* color palette from <https://github.com/vuejs/theme> */
|
|
2
|
-
:root {
|
|
3
|
-
--vt-c-white: #ffffff;
|
|
4
|
-
--vt-c-white-soft: #f8f8f8;
|
|
5
|
-
--vt-c-white-mute: #f2f2f2;
|
|
6
|
-
|
|
7
|
-
--vt-c-black: #181818;
|
|
8
|
-
--vt-c-black-soft: #222222;
|
|
9
|
-
--vt-c-black-mute: #282828;
|
|
10
|
-
|
|
11
|
-
--vt-c-indigo: #2c3e50;
|
|
12
|
-
|
|
13
|
-
--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
|
|
14
|
-
--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
|
|
15
|
-
--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
|
|
16
|
-
--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
|
|
17
|
-
|
|
18
|
-
--vt-c-text-light-1: var(--vt-c-indigo);
|
|
19
|
-
--vt-c-text-light-2: rgba(60, 60, 60, 0.66);
|
|
20
|
-
--vt-c-text-dark-1: var(--vt-c-white);
|
|
21
|
-
--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/* semantic color variables for this project */
|
|
25
|
-
:root {
|
|
26
|
-
--color-background: var(--vt-c-white);
|
|
27
|
-
--color-background-soft: var(--vt-c-white-soft);
|
|
28
|
-
--color-background-mute: var(--vt-c-white-mute);
|
|
29
|
-
|
|
30
|
-
--color-border: var(--vt-c-divider-light-2);
|
|
31
|
-
--color-border-hover: var(--vt-c-divider-light-1);
|
|
32
|
-
|
|
33
|
-
--color-heading: var(--vt-c-text-light-1);
|
|
34
|
-
--color-text: var(--vt-c-text-light-1);
|
|
35
|
-
|
|
36
|
-
--section-gap: 160px;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
@media (prefers-color-scheme: dark) {
|
|
40
|
-
:root {
|
|
41
|
-
--color-background: var(--vt-c-black);
|
|
42
|
-
--color-background-soft: var(--vt-c-black-soft);
|
|
43
|
-
--color-background-mute: var(--vt-c-black-mute);
|
|
44
|
-
|
|
45
|
-
--color-border: var(--vt-c-divider-dark-2);
|
|
46
|
-
--color-border-hover: var(--vt-c-divider-dark-1);
|
|
47
|
-
|
|
48
|
-
--color-heading: var(--vt-c-text-dark-1);
|
|
49
|
-
--color-text: var(--vt-c-text-dark-2);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
*,
|
|
54
|
-
*::before,
|
|
55
|
-
*::after {
|
|
56
|
-
box-sizing: border-box;
|
|
57
|
-
margin: 0;
|
|
58
|
-
font-weight: normal;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
body {
|
|
62
|
-
min-height: 100vh;
|
|
63
|
-
color: var(--color-text);
|
|
64
|
-
background: var(--color-background);
|
|
65
|
-
transition:
|
|
66
|
-
color 0.5s,
|
|
67
|
-
background-color 0.5s;
|
|
68
|
-
line-height: 1.6;
|
|
69
|
-
font-family:
|
|
70
|
-
Inter,
|
|
71
|
-
-apple-system,
|
|
72
|
-
BlinkMacSystemFont,
|
|
73
|
-
'Segoe UI',
|
|
74
|
-
Roboto,
|
|
75
|
-
Oxygen,
|
|
76
|
-
Ubuntu,
|
|
77
|
-
Cantarell,
|
|
78
|
-
'Fira Sans',
|
|
79
|
-
'Droid Sans',
|
|
80
|
-
'Helvetica Neue',
|
|
81
|
-
sans-serif;
|
|
82
|
-
font-size: 15px;
|
|
83
|
-
text-rendering: optimizeLegibility;
|
|
84
|
-
-webkit-font-smoothing: antialiased;
|
|
85
|
-
-moz-osx-font-smoothing: grayscale;
|
|
86
|
-
}
|
package/src/assets/main.css
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
@import './base.css';
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
#app {
|
|
6
|
-
max-width: 1280px;
|
|
7
|
-
margin: 0 auto;
|
|
8
|
-
padding: 2rem;
|
|
9
|
-
font-weight: normal;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
@media (min-width: 1024px) {
|
|
13
|
-
body {
|
|
14
|
-
display: flex;
|
|
15
|
-
width: 1024px;
|
|
16
|
-
/*place-items: center;*/
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
#app {
|
|
20
|
-
display: grid;
|
|
21
|
-
grid-template-columns: 1fr 1fr;
|
|
22
|
-
padding: 0 2rem;
|
|
23
|
-
}
|
|
24
|
-
}
|
package/src/assets/style.scss
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
@import 'bootstrap/scss/bootstrap';
|
|
2
|
-
|
|
3
|
-
[data-complete="true"]:not([data-empty="true"]) .form-control {
|
|
4
|
-
//@extend .form-control, .is-valid;
|
|
5
|
-
/*
|
|
6
|
-
border-color: var(--bs-form-valid-border-color);
|
|
7
|
-
padding-right: calc(1.5em + 0.75rem);
|
|
8
|
-
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");
|
|
9
|
-
background-repeat: no-repeat;
|
|
10
|
-
background-position: right calc(0.375em + 0.1875rem) center;
|
|
11
|
-
background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
|
|
12
|
-
*/
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/*
|
|
16
|
-
[data-invalid="true"] .form-control {
|
|
17
|
-
//@extend .form-control, .is-invalid;
|
|
18
|
-
border-color: var(--bs-form-invalid-border-color);
|
|
19
|
-
padding-right: calc(1.5em + 0.75rem);
|
|
20
|
-
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");
|
|
21
|
-
background-repeat: no-repeat;
|
|
22
|
-
background-position: right calc(0.375em + 0.1875rem) center;
|
|
23
|
-
background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
[data-invalid="true"] .invalid-feedback {
|
|
27
|
-
display: inline;
|
|
28
|
-
width: 100%;
|
|
29
|
-
margin-top: 0.25rem;
|
|
30
|
-
font-size: 0.875em;
|
|
31
|
-
color: var(--bs-form-invalid-color);
|
|
32
|
-
}
|
|
33
|
-
*/
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import {onMounted, ref, watch} from "vue";
|
|
3
|
-
import MarkdownRenderer from "@/components/MarkdownRenderer.vue";
|
|
4
|
-
|
|
5
|
-
const model = defineModel({ default: {
|
|
6
|
-
}});
|
|
7
|
-
const preview = ref('');
|
|
8
|
-
|
|
9
|
-
watch(model, () => {
|
|
10
|
-
preview.value = model.value.narrative;
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
onMounted(() => {
|
|
14
|
-
preview.value = model.value.narrative ? model.value.narrative : '';
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
const criteriaTab = ref("edit");
|
|
18
|
-
|
|
19
|
-
function selectTab(tab) {
|
|
20
|
-
criteriaTab.value = tab;
|
|
21
|
-
}
|
|
22
|
-
</script>
|
|
23
|
-
|
|
24
|
-
<template>
|
|
25
|
-
<div class="formkit-wrapper required">
|
|
26
|
-
<label class="form-label">Earning Criteria</label>
|
|
27
|
-
</div>
|
|
28
|
-
|
|
29
|
-
<ul class="nav nav-tabs" role="tablist">
|
|
30
|
-
<li class="nav-item" role="presentation">
|
|
31
|
-
<button class="nav-link" :class='{"active": criteriaTab === "edit"}' type="button" id="edit-tab" aria-controls="criteria-edit"
|
|
32
|
-
role="tab" :aria-selected="criteriaTab === 'edit'" @click="selectTab('edit')">Edit
|
|
33
|
-
</button>
|
|
34
|
-
</li>
|
|
35
|
-
<li class="nav-item" role="presentation">
|
|
36
|
-
<button class="nav-link" :class='{"active": criteriaTab === "preview"}' type="button" id="preview-tab"
|
|
37
|
-
aria-controls="criteria-preview" role="tab" :aria-selected="criteriaTab === 'preview'"
|
|
38
|
-
@click="selectTab('preview')">Preview
|
|
39
|
-
</button>
|
|
40
|
-
</li>
|
|
41
|
-
</ul>
|
|
42
|
-
|
|
43
|
-
<div class="tab-content" id="criteria-tab">
|
|
44
|
-
<div class="tab-pane fade" :class="{'show': (criteriaTab === 'edit'), 'active': (criteriaTab === 'edit')}"
|
|
45
|
-
id="criteria-edit" role="tabpanel" aria-labelledby="edit-tab" v-show="criteriaTab === 'edit'">
|
|
46
|
-
<FormKit type="group" name="criteria" v-model="model">
|
|
47
|
-
<FormKit
|
|
48
|
-
type="textarea"
|
|
49
|
-
label="Narrative"
|
|
50
|
-
name="narrative"
|
|
51
|
-
rows="5"
|
|
52
|
-
validation="require_one:id"
|
|
53
|
-
help="A narrative of what is needed to earn the credential. Markdown is allowed."
|
|
54
|
-
/>
|
|
55
|
-
|
|
56
|
-
<FormKit
|
|
57
|
-
type="text"
|
|
58
|
-
label="Criteria URL"
|
|
59
|
-
name="id"
|
|
60
|
-
validation="require_one:narrative|url"
|
|
61
|
-
help="The URL of a webpage that describes in a human-readable format the criteria for the credential."
|
|
62
|
-
/>
|
|
63
|
-
</FormKit>
|
|
64
|
-
</div>
|
|
65
|
-
|
|
66
|
-
<div class="tab-pane fade" :class="{'show': (criteriaTab === 'preview'), 'active': (criteriaTab === 'preview')}"
|
|
67
|
-
id="criteria-preview" role="tabpanel" aria-labelledby="preview-tab" v-show="criteriaTab === 'preview'">
|
|
68
|
-
<label class="mt-3 mb-2">Narrative Preview</label>
|
|
69
|
-
<MarkdownRenderer :source="preview" class="border rounded p-3"/>
|
|
70
|
-
</div>
|
|
71
|
-
</div>
|
|
72
|
-
</template>
|
|
73
|
-
|
|
74
|
-
<style scoped>
|
|
75
|
-
#criteria-preview {
|
|
76
|
-
min-height: 302px;
|
|
77
|
-
}
|
|
78
|
-
</style>
|
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import {onBeforeMount, reactive, ref, watch} from "vue";
|
|
3
|
-
import BasicTab from "@/components/BasicTab.vue";
|
|
4
|
-
import DetailTab from "@/components/DetailTab.vue";
|
|
5
|
-
import AlignmentsTab from "@/components/AlignmentsTab.vue";
|
|
6
|
-
import AdditionalTab from "@/components/AdditionalTab.vue";
|
|
7
|
-
|
|
8
|
-
const props = defineProps({
|
|
9
|
-
achievement: {
|
|
10
|
-
type: String,
|
|
11
|
-
default: ""
|
|
12
|
-
},
|
|
13
|
-
submitText: {
|
|
14
|
-
type: String,
|
|
15
|
-
default: "Save"
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
const emit = defineEmits(['saveDefinition']);
|
|
19
|
-
|
|
20
|
-
const tab = ref("basic");
|
|
21
|
-
const submitted = ref(false);
|
|
22
|
-
const form = ref(null);
|
|
23
|
-
|
|
24
|
-
const formData = reactive({
|
|
25
|
-
type: ['Achievement'],
|
|
26
|
-
basic: {},
|
|
27
|
-
detail: {},
|
|
28
|
-
alignments: {},
|
|
29
|
-
additional: {},
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
const achievementData = reactive({});
|
|
33
|
-
|
|
34
|
-
onBeforeMount(() => {
|
|
35
|
-
try {
|
|
36
|
-
const achievement = JSON.parse(JSON.stringify(JSON.parse(props.achievement), (key, value) => {
|
|
37
|
-
return value == null ? undefined : value;
|
|
38
|
-
}));
|
|
39
|
-
|
|
40
|
-
formData.basic = {
|
|
41
|
-
name: achievement.name || '',
|
|
42
|
-
achievementType: achievement.achievementType || null,
|
|
43
|
-
image: achievement.image || {},
|
|
44
|
-
description: achievement.description || '',
|
|
45
|
-
criteria: achievement.criteria || {},
|
|
46
|
-
};
|
|
47
|
-
formData.detail = {
|
|
48
|
-
humanCode: achievement.humanCode || null,
|
|
49
|
-
inLanguage: achievement.inLanguage || null,
|
|
50
|
-
version: achievement.version || null,
|
|
51
|
-
creditsAvailable: achievement.creditsAvailable || null,
|
|
52
|
-
specialization: achievement.specialization || null,
|
|
53
|
-
fieldOfStudy: achievement.fieldOfStudy || null,
|
|
54
|
-
};
|
|
55
|
-
formData.alignments = {
|
|
56
|
-
resultDescription: achievement.resultDescription || [],
|
|
57
|
-
alignment: achievement.alignment || [],
|
|
58
|
-
};
|
|
59
|
-
formData.additional = {
|
|
60
|
-
id: achievement.id || null,
|
|
61
|
-
tag: achievement.tag || [],
|
|
62
|
-
related: achievement.related || [],
|
|
63
|
-
otherIdentifier: achievement.otherIdentifier || [],
|
|
64
|
-
creator: achievement.creator || {},
|
|
65
|
-
};
|
|
66
|
-
/*
|
|
67
|
-
achievementData.basic = {...achievement.basic };
|
|
68
|
-
achievementData.detail = {...achievement.detail };
|
|
69
|
-
achievementData.alignments = {...achievement.alignments };
|
|
70
|
-
achievementData.additional = {...achievement.additional };
|
|
71
|
-
*/
|
|
72
|
-
} catch (e) {
|
|
73
|
-
// No valid OB3 Achievement definition was passed
|
|
74
|
-
console.log('Error parsing passed achievement: ', e);
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
watch(formData, (value) => {
|
|
79
|
-
Object.assign(achievementData, value.basic);
|
|
80
|
-
Object.assign(achievementData, value.detail);
|
|
81
|
-
Object.assign(achievementData, value.alignments);
|
|
82
|
-
Object.assign(achievementData, value.additional);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
function selectTab(selected) {
|
|
86
|
-
tab.value = selected;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function removeEmpty(obj) {
|
|
90
|
-
/*
|
|
91
|
-
return Object.fromEntries(
|
|
92
|
-
Object.entries(obj)
|
|
93
|
-
.filter(([_, v]) => v != null && v !== '' && (!Array.isArray(v) || v.length > 0))
|
|
94
|
-
.map(([k, v]) => [k, (v === Object(v) && !Array.isArray(v)) ? removeEmpty(v) : v])
|
|
95
|
-
);
|
|
96
|
-
*/
|
|
97
|
-
return JSON.parse(JSON.stringify(obj, (key, value) => {
|
|
98
|
-
return ((value === null || value === '' || (Array.isArray(value) && value.length === 0)) ? undefined : value);
|
|
99
|
-
}));
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function save(formData) {
|
|
103
|
-
if (!formData.image.id) {
|
|
104
|
-
formData.image = null;
|
|
105
|
-
}
|
|
106
|
-
//console.log('formData', formData);
|
|
107
|
-
const cleaned = removeEmpty(formData);
|
|
108
|
-
//emit('saveDefinition', cleaned);
|
|
109
|
-
const formEl = document.getElementById(form.value.node.props.id);
|
|
110
|
-
formEl.dispatchEvent(new CustomEvent('saveDefinition', { bubbles: true, detail: JSON.stringify(cleaned) }));
|
|
111
|
-
//console.log('Submitting', cleaned);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function sendChange(formData) {
|
|
115
|
-
try {
|
|
116
|
-
const formEl = document.getElementById(form.value.node.props.id);
|
|
117
|
-
const valid = form.value.node.context.state.valid;
|
|
118
|
-
const cleaned = removeEmpty(form.value.node.value);
|
|
119
|
-
formEl.dispatchEvent(new CustomEvent('changed', {bubbles: true, detail: JSON.stringify(cleaned)}));
|
|
120
|
-
if (valid) {
|
|
121
|
-
formEl.dispatchEvent(new CustomEvent('updated', {bubbles: true, detail: JSON.stringify(cleaned)}));
|
|
122
|
-
}
|
|
123
|
-
} catch (e) {}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function showErrors(node) {
|
|
127
|
-
submitted.value = true;
|
|
128
|
-
}
|
|
129
|
-
</script>
|
|
130
|
-
|
|
131
|
-
<template>
|
|
132
|
-
<div>
|
|
133
|
-
<ul class="nav nav-tabs" role="tablist">
|
|
134
|
-
<li class="nav-item" role="presentation">
|
|
135
|
-
<button class="nav-link" :class='{"active": (tab === "basic")}' type="button" id="basic-tab" role="tab" aria-controls="tab-basic" :aria-selected="(tab === 'basic') ? 'true' : 'false'" @click="selectTab('basic')">Primary Details</button>
|
|
136
|
-
</li>
|
|
137
|
-
<li class="nav-item" role="presentation">
|
|
138
|
-
<button class="nav-link" :class='{"active": (tab === "detail")}' type="button" id="detail-tab" role="tab" aria-controls="tab-detail" :aria-selected="(tab === 'detail') ? 'true' : 'false'" @click="selectTab('detail')">Additional Details</button>
|
|
139
|
-
</li>
|
|
140
|
-
<li class="nav-item" role="presentation">
|
|
141
|
-
<button class="nav-link" :class='{"active": (tab === "alignments")}' type="button" id="detail-tab" role="tab" aria-controls="tab-alignments" :aria-selected="(tab === 'alignments') ? 'true' : 'false'" @click="selectTab('alignments')">Alignments</button>
|
|
142
|
-
</li>
|
|
143
|
-
<li class="nav-item" role="presentation">
|
|
144
|
-
<button class="nav-link" :class='{"active": (tab === "additional")}' type="button" id="additional-tab" role="tab" aria-controls="tab-additional" :aria-selected="(tab === 'additional') ? 'true' : 'false'" @click="selectTab('additional')">Additional Information</button>
|
|
145
|
-
</li>
|
|
146
|
-
</ul>
|
|
147
|
-
|
|
148
|
-
<div class="tab-content mt-3" id="tab-content">
|
|
149
|
-
<FormKit
|
|
150
|
-
type="form"
|
|
151
|
-
:actions="false"
|
|
152
|
-
ref="form"
|
|
153
|
-
@submit="save"
|
|
154
|
-
@submit-invalid="showErrors"
|
|
155
|
-
@change="sendChange"
|
|
156
|
-
#default="{ state: { valid } }"
|
|
157
|
-
validation-visibility="live"
|
|
158
|
-
>
|
|
159
|
-
<div class="alert alert-warning" role="alert" v-if="!valid && submitted">
|
|
160
|
-
There are some errors in the form submission. Please correct the errors and then resubmit the form.
|
|
161
|
-
</div>
|
|
162
|
-
|
|
163
|
-
<FormKit
|
|
164
|
-
type="hidden"
|
|
165
|
-
name="@context"
|
|
166
|
-
:value="[ 'https://www.w3.org/2018/credentials/v2', 'https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json' ]"
|
|
167
|
-
/>
|
|
168
|
-
|
|
169
|
-
<FormKit
|
|
170
|
-
type="hidden"
|
|
171
|
-
name="type"
|
|
172
|
-
v-model="formData.type"
|
|
173
|
-
:value="[ 'Achievement' ]"
|
|
174
|
-
/>
|
|
175
|
-
|
|
176
|
-
<BasicTab
|
|
177
|
-
v-model="formData.basic"
|
|
178
|
-
v-show="tab === 'basic'"
|
|
179
|
-
/>
|
|
180
|
-
<DetailTab
|
|
181
|
-
v-model="formData.detail"
|
|
182
|
-
v-show="tab === 'detail'"
|
|
183
|
-
/>
|
|
184
|
-
<AlignmentsTab
|
|
185
|
-
v-model="formData.alignments"
|
|
186
|
-
v-show="tab === 'alignments'"
|
|
187
|
-
/>
|
|
188
|
-
<AdditionalTab
|
|
189
|
-
v-model="formData.additional"
|
|
190
|
-
v-show="tab === 'additional'"
|
|
191
|
-
/>
|
|
192
|
-
|
|
193
|
-
<button class="btn btn-primary float-end mt-5" type="submit" :disabled="false">{{ submitText }}</button>
|
|
194
|
-
</FormKit>
|
|
195
|
-
</div>
|
|
196
|
-
</div>
|
|
197
|
-
</template>
|
|
198
|
-
|
|
199
|
-
<style>
|
|
200
|
-
.formkit-wrapper.required .form-label:before{
|
|
201
|
-
color: red;
|
|
202
|
-
content: "*";
|
|
203
|
-
position: absolute;
|
|
204
|
-
margin-left: -10px;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
[data-invalid="true"] .form-control {
|
|
208
|
-
border-color: #dc3545;
|
|
209
|
-
padding-right: calc(1.5em + 0.75rem);
|
|
210
|
-
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");
|
|
211
|
-
background-repeat: no-repeat;
|
|
212
|
-
background-position: right calc(0.375em + 0.1875rem) center;
|
|
213
|
-
background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
[data-invalid="true"] .invalid-feedback {
|
|
217
|
-
display: inline;
|
|
218
|
-
width: 100%;
|
|
219
|
-
margin-top: 0.25rem;
|
|
220
|
-
font-size: 0.875em;
|
|
221
|
-
color: #dc3545;
|
|
222
|
-
}
|
|
223
|
-
</style>
|