@opensalt/ob3-definer 1.0.0
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/.vscode/extensions.json +3 -0
- package/LICENSE +21 -0
- package/README.md +86 -0
- package/dist/favicon.svg +7 -0
- package/dist/index.html +20 -0
- package/dist/ob3-definer.css +1 -0
- package/dist/ob3-definer.js +32 -0
- package/formkit.config.js +27 -0
- package/index.html +19 -0
- package/jsconfig.json +8 -0
- package/package.json +35 -0
- package/public/favicon.svg +7 -0
- package/src/App.vue +19 -0
- package/src/assets/base.css +86 -0
- package/src/assets/main.css +24 -0
- package/src/assets/style.scss +33 -0
- package/src/components/AchievementCriteria.vue +78 -0
- package/src/components/AchievementDefiner.vue +212 -0
- package/src/components/AchievementImage.vue +116 -0
- package/src/components/AchievementType.vue +111 -0
- package/src/components/AdditionalTab.vue +32 -0
- package/src/components/AddressComponent.vue +118 -0
- package/src/components/AlignmentComponent.vue +141 -0
- package/src/components/AlignmentsComponent.vue +13 -0
- package/src/components/AlignmentsTab.vue +18 -0
- package/src/components/BasicTab.vue +55 -0
- package/src/components/CreatorProfile.vue +166 -0
- package/src/components/CriterionLevels.vue +97 -0
- package/src/components/DetailTab.vue +72 -0
- package/src/components/IndividualName.vue +63 -0
- package/src/components/MarkdownRenderer.vue +20 -0
- package/src/components/OtherIdentifiers.vue +116 -0
- package/src/components/RelatedList.vue +89 -0
- package/src/components/ResultDescription.vue +120 -0
- package/src/components/ResultType.vue +94 -0
- package/src/components/TagList.vue +121 -0
- package/src/components/ValueList.vue +144 -0
- package/src/inputs/innerLabelTextInput.js +62 -0
- package/src/inputs/innerLabelTextareaInput.js +57 -0
- package/src/inputs/selectInputGroup.js +76 -0
- package/src/main.js +50 -0
- package/src/stores/credential.js +292 -0
- package/test-index.html +17 -0
- package/trial-key +3 -0
- package/vite.config.js +39 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import AlignmentComponent from "@/components/AlignmentComponent.vue";
|
|
3
|
+
|
|
4
|
+
const levels = defineModel({ default: {} });
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<template>
|
|
8
|
+
<FormKit
|
|
9
|
+
#default="{ items, node, value }"
|
|
10
|
+
type="list"
|
|
11
|
+
v-model="levels"
|
|
12
|
+
name="rubricCriterionLevel"
|
|
13
|
+
dynamic
|
|
14
|
+
>
|
|
15
|
+
<h5>Rubric Criterion Levels
|
|
16
|
+
<button type="button" @click="() => node.input(value.concat({}))" class="btn btn-sm btn-primary ms-3">
|
|
17
|
+
Add Level
|
|
18
|
+
</button>
|
|
19
|
+
</h5>
|
|
20
|
+
|
|
21
|
+
<FormKit
|
|
22
|
+
type="group"
|
|
23
|
+
wrapper-class="card"
|
|
24
|
+
v-for="(item, index) in items"
|
|
25
|
+
:key="item"
|
|
26
|
+
:index="index"
|
|
27
|
+
>
|
|
28
|
+
<div class="card mb-3">
|
|
29
|
+
<h5 class="card-header">Level {{index+1}}
|
|
30
|
+
<button type="button" @click="() => node.input(value.filter((_, i) => i !== index))" class="btn btn-secondary btn-sm float-end">
|
|
31
|
+
Remove
|
|
32
|
+
</button>
|
|
33
|
+
</h5>
|
|
34
|
+
|
|
35
|
+
<div class="card-body">
|
|
36
|
+
<FormKit
|
|
37
|
+
type="hidden"
|
|
38
|
+
name="type"
|
|
39
|
+
:value="[ 'RubricCriterionLevel' ]"
|
|
40
|
+
/>
|
|
41
|
+
|
|
42
|
+
<FormKit
|
|
43
|
+
type="innerLabelTextInput"
|
|
44
|
+
label="ID"
|
|
45
|
+
name="id"
|
|
46
|
+
inner-class="input-group"
|
|
47
|
+
label-class="input-group-text"
|
|
48
|
+
validation="required:trim"
|
|
49
|
+
wrapper-class="required"
|
|
50
|
+
/>
|
|
51
|
+
|
|
52
|
+
<FormKit
|
|
53
|
+
type="innerLabelTextInput"
|
|
54
|
+
label="Name"
|
|
55
|
+
name="name"
|
|
56
|
+
inner-class="input-group"
|
|
57
|
+
label-class="input-group-text"
|
|
58
|
+
validation="required:trim"
|
|
59
|
+
wrapper-class="required"
|
|
60
|
+
/>
|
|
61
|
+
|
|
62
|
+
<FormKit
|
|
63
|
+
type="innerLabelTextareaInput"
|
|
64
|
+
label="Description"
|
|
65
|
+
name="description"
|
|
66
|
+
inner-class="input-group"
|
|
67
|
+
label-class="input-group-text"
|
|
68
|
+
/>
|
|
69
|
+
|
|
70
|
+
<FormKit
|
|
71
|
+
type="innerLabelTextInput"
|
|
72
|
+
label="Level"
|
|
73
|
+
name="level"
|
|
74
|
+
inner-class="input-group"
|
|
75
|
+
label-class="input-group-text"
|
|
76
|
+
/>
|
|
77
|
+
|
|
78
|
+
<FormKit
|
|
79
|
+
type="innerLabelTextInput"
|
|
80
|
+
label="Points"
|
|
81
|
+
name="points"
|
|
82
|
+
inner-class="input-group"
|
|
83
|
+
label-class="input-group-text"
|
|
84
|
+
/>
|
|
85
|
+
|
|
86
|
+
<AlignmentComponent v-model="levels[index].alignment"/>
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
</FormKit>
|
|
90
|
+
</FormKit>
|
|
91
|
+
</template>
|
|
92
|
+
|
|
93
|
+
<style>
|
|
94
|
+
.input-group>.form-label {
|
|
95
|
+
margin-bottom: 0;
|
|
96
|
+
}
|
|
97
|
+
</style>
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
const credential = defineModel({ default: {
|
|
3
|
+
humanCode: null,
|
|
4
|
+
inLanguage: null,
|
|
5
|
+
version: null,
|
|
6
|
+
creditsAvailable: null,
|
|
7
|
+
additionalType: null,
|
|
8
|
+
} })
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<template>
|
|
12
|
+
<div class="tab-pane fade show active" id="tab-detail" role="tabpanel" aria-labelledby="detail-tab">
|
|
13
|
+
<FormKit
|
|
14
|
+
type="text"
|
|
15
|
+
label="Human Code"
|
|
16
|
+
v-model="credential.humanCode"
|
|
17
|
+
name="humanCode"
|
|
18
|
+
help="The code, generally human readable, associated with an achievement."
|
|
19
|
+
/>
|
|
20
|
+
|
|
21
|
+
<FormKit
|
|
22
|
+
type="text"
|
|
23
|
+
label="In Language"
|
|
24
|
+
v-model="credential.inLanguage"
|
|
25
|
+
name="inLanguage"
|
|
26
|
+
help="The language this credential is in as a BCP47 language code, such as 'en', 'en-US', or 'es-MX'"
|
|
27
|
+
:validation="[['matches', '/^[a-z]{2,4}(-[A-Z][a-z]{3})?(-([A-Z]{2}|[0-9]{3}))?$/']]"
|
|
28
|
+
:validation-messages="{
|
|
29
|
+
'matches': 'The language must formatted as a BCP47 language code, such as \'en\', \'en-US\', or \'es-MX\'.'
|
|
30
|
+
}"
|
|
31
|
+
/>
|
|
32
|
+
|
|
33
|
+
<FormKit
|
|
34
|
+
type="text"
|
|
35
|
+
label="Version"
|
|
36
|
+
v-model="credential.version"
|
|
37
|
+
name="version"
|
|
38
|
+
help="The version property allows issuers to set a version string for an Achievement. This is particularly useful when replacing a previous version with an update."
|
|
39
|
+
/>
|
|
40
|
+
|
|
41
|
+
<FormKit
|
|
42
|
+
type="number"
|
|
43
|
+
label="Credits Available"
|
|
44
|
+
number
|
|
45
|
+
name="creditsAvailable"
|
|
46
|
+
v-model="credential.creditsAvailable"
|
|
47
|
+
help="Credit hours associated with this entity, or credit hours possible. For example 3.0."
|
|
48
|
+
/>
|
|
49
|
+
|
|
50
|
+
<FormKit
|
|
51
|
+
type="text"
|
|
52
|
+
label="Specialization"
|
|
53
|
+
v-model="credential.specialization"
|
|
54
|
+
name="specialization"
|
|
55
|
+
help="Name given to the focus, concentration, or specific area of study defined in the achievement. Examples include 'Entrepreneurship', 'Technical Communication', and 'Finance'."
|
|
56
|
+
/>
|
|
57
|
+
|
|
58
|
+
<FormKit
|
|
59
|
+
type="text"
|
|
60
|
+
label="Field of Study"
|
|
61
|
+
v-model="credential.fieldOfStudy"
|
|
62
|
+
name="fieldOfStudy"
|
|
63
|
+
help="Category, subject, area of study, discipline, or general branch of knowledge. Examples include Business, Education, Psychology, and Technology."
|
|
64
|
+
/>
|
|
65
|
+
</div>
|
|
66
|
+
</template>
|
|
67
|
+
|
|
68
|
+
<style scoped>
|
|
69
|
+
#criteria-preview {
|
|
70
|
+
min-height: 250px;
|
|
71
|
+
}
|
|
72
|
+
</style>
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<template>
|
|
6
|
+
<FormKit
|
|
7
|
+
type="group"
|
|
8
|
+
>
|
|
9
|
+
<FormKit
|
|
10
|
+
type="text"
|
|
11
|
+
label="Given Name"
|
|
12
|
+
name="givenName"
|
|
13
|
+
help="Given name. In the western world, often referred to as the 'first name' of a person."
|
|
14
|
+
/>
|
|
15
|
+
|
|
16
|
+
<FormKit
|
|
17
|
+
type="text"
|
|
18
|
+
label="Additional Name"
|
|
19
|
+
name="additionalName"
|
|
20
|
+
help="Additional name. Includes what is often referred to as 'middle name' in the western world."
|
|
21
|
+
/>
|
|
22
|
+
|
|
23
|
+
<FormKit
|
|
24
|
+
type="text"
|
|
25
|
+
label="Family Name Prefix"
|
|
26
|
+
name="familyNamePrefix"
|
|
27
|
+
help="Family name prefix. As used in some locales, this is the leading part of a family name (e.g. 'de' in the name 'de Boer')."
|
|
28
|
+
/>
|
|
29
|
+
|
|
30
|
+
<FormKit
|
|
31
|
+
type="text"
|
|
32
|
+
label="Family Name"
|
|
33
|
+
name="familyName"
|
|
34
|
+
help="Family name. In the western world, often referred to as the 'last name' of a person."
|
|
35
|
+
/>
|
|
36
|
+
|
|
37
|
+
<FormKit
|
|
38
|
+
type="text"
|
|
39
|
+
label="Patronymic Name"
|
|
40
|
+
name="patronymicName"
|
|
41
|
+
help="Patronynmic name."
|
|
42
|
+
v-if="false"
|
|
43
|
+
/>
|
|
44
|
+
|
|
45
|
+
<FormKit
|
|
46
|
+
type="text"
|
|
47
|
+
label="Honorific Prefix"
|
|
48
|
+
name="honorificPrefix"
|
|
49
|
+
help="Honorific prefix(es) preceding a person's name (e.g. 'Dr', 'Mrs' or 'Mr')."
|
|
50
|
+
/>
|
|
51
|
+
|
|
52
|
+
<FormKit
|
|
53
|
+
type="text"
|
|
54
|
+
label="Honorific Suffix"
|
|
55
|
+
name="honorificSuffix"
|
|
56
|
+
help="Honorific suffix(es) following a person's name (e.g. 'M.D, PhD')."
|
|
57
|
+
/>
|
|
58
|
+
</FormKit>
|
|
59
|
+
</template>
|
|
60
|
+
|
|
61
|
+
<style scoped>
|
|
62
|
+
|
|
63
|
+
</style>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import MarkdownIt from "markdown-it";
|
|
3
|
+
|
|
4
|
+
const markdown = MarkdownIt();
|
|
5
|
+
|
|
6
|
+
const props = defineProps({
|
|
7
|
+
source: {
|
|
8
|
+
type: String,
|
|
9
|
+
default: ""
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<template>
|
|
15
|
+
<div class="mb-3" v-html="markdown.render(source)" />
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<style scoped>
|
|
19
|
+
|
|
20
|
+
</style>
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
const props = defineProps({
|
|
3
|
+
help: {
|
|
4
|
+
type: String,
|
|
5
|
+
default: 'Other identifiers for this credential.'
|
|
6
|
+
}
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const identifiers = defineModel({ default: [] });
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<template>
|
|
13
|
+
<FormKit
|
|
14
|
+
#default="{ items, node, value }"
|
|
15
|
+
type="list"
|
|
16
|
+
v-model="identifiers"
|
|
17
|
+
name="otherIdentifier"
|
|
18
|
+
dynamic
|
|
19
|
+
>
|
|
20
|
+
<h5>Other Identifiers
|
|
21
|
+
<button type="button" @click="() => node.input(value.concat({}))" class="btn btn-sm btn-primary ms-3">
|
|
22
|
+
Add Identifier
|
|
23
|
+
</button>
|
|
24
|
+
</h5>
|
|
25
|
+
<p class="form-text">{{ props.help }}</p>
|
|
26
|
+
|
|
27
|
+
<FormKit
|
|
28
|
+
type="group"
|
|
29
|
+
v-for="(item, index) in items"
|
|
30
|
+
:key="item"
|
|
31
|
+
:index="index"
|
|
32
|
+
>
|
|
33
|
+
<div class="card mb-3">
|
|
34
|
+
<h5 class="card-header">Other Identifier {{index+1}}
|
|
35
|
+
<button type="button" @click="() => node.input(value.filter((_, i) => i !== index))" class="btn btn-secondary btn-sm float-end">
|
|
36
|
+
Remove
|
|
37
|
+
</button>
|
|
38
|
+
</h5>
|
|
39
|
+
|
|
40
|
+
<div class="card-body pb-0">
|
|
41
|
+
<FormKit
|
|
42
|
+
type="hidden"
|
|
43
|
+
name="type"
|
|
44
|
+
:value="'IdentifierEntry'"
|
|
45
|
+
/>
|
|
46
|
+
|
|
47
|
+
<FormKit
|
|
48
|
+
type="innerLabelTextInput"
|
|
49
|
+
label="Identifier"
|
|
50
|
+
name="identifier"
|
|
51
|
+
aria-label="Identifier"
|
|
52
|
+
inner-class="input-group"
|
|
53
|
+
label-class="input-group-text"
|
|
54
|
+
wrapper-class="required"
|
|
55
|
+
validation="required:trim"
|
|
56
|
+
/>
|
|
57
|
+
<FormKit
|
|
58
|
+
type="selectInputGroup"
|
|
59
|
+
label="Identifier Type"
|
|
60
|
+
name="identifierType"
|
|
61
|
+
inner-class="input-group"
|
|
62
|
+
label-class="input-group-text"
|
|
63
|
+
input-class="$reset formkit-input form-select"
|
|
64
|
+
wrapper-class="required"
|
|
65
|
+
placeholder="Select the Identifier Type"
|
|
66
|
+
validation="required"
|
|
67
|
+
:options="{
|
|
68
|
+
'name': 'name',
|
|
69
|
+
'sourcedId': 'sourcedId',
|
|
70
|
+
'systemId': 'systemId',
|
|
71
|
+
'productId': 'productId',
|
|
72
|
+
'userName': 'userName',
|
|
73
|
+
'accountId': 'accountId',
|
|
74
|
+
'emailAddress': 'emailAddress',
|
|
75
|
+
'nationalIdentityNumber': 'nationalIdentityNumber',
|
|
76
|
+
'isbn': 'isbn',
|
|
77
|
+
'issn': 'issn',
|
|
78
|
+
'lisSourcedId': 'lisSourcedId',
|
|
79
|
+
'oneRosterSourcedId': 'oneRosterSourcedId',
|
|
80
|
+
'sisSourcedId': 'sisSourcedId',
|
|
81
|
+
'ltiContextId': 'ltiContextId',
|
|
82
|
+
'ltiDeploymentId': 'ltiDeploymentId',
|
|
83
|
+
'ltiToolId': 'ltiToolId',
|
|
84
|
+
'ltiPlatformId': 'ltiPlatformId',
|
|
85
|
+
'ltiUserId': 'ltiUserId',
|
|
86
|
+
'identifier': 'identifier',
|
|
87
|
+
'other': 'Other (ext:)',
|
|
88
|
+
}"
|
|
89
|
+
/>
|
|
90
|
+
<FormKit
|
|
91
|
+
v-if="value[index].identifierType === 'other'"
|
|
92
|
+
type="innerLabelTextInput"
|
|
93
|
+
label="Extended Type"
|
|
94
|
+
name="typeExt"
|
|
95
|
+
aria-label="Extended Identifier Type"
|
|
96
|
+
inner-class="input-group ms-3 me-5 pe-3"
|
|
97
|
+
outer-class="$reset"
|
|
98
|
+
label-class="visually-hidden"
|
|
99
|
+
before="ext:"
|
|
100
|
+
:validation="[['matches', '/^[a-z|A-Z|0-9|.|-|_]+$/']]"
|
|
101
|
+
>
|
|
102
|
+
<template #prefix>
|
|
103
|
+
<span class="input-group-text" aria-label="ext:">ext:</span>
|
|
104
|
+
</template>
|
|
105
|
+
</FormKit>
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
</FormKit>
|
|
109
|
+
</FormKit>
|
|
110
|
+
</template>
|
|
111
|
+
|
|
112
|
+
<style>
|
|
113
|
+
.input-group>.form-label {
|
|
114
|
+
margin-bottom: 0;
|
|
115
|
+
}
|
|
116
|
+
</style>
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import {ref, watch} from "vue";
|
|
3
|
+
|
|
4
|
+
const emit = defineEmits(['change']);
|
|
5
|
+
|
|
6
|
+
const related = ref([]);
|
|
7
|
+
|
|
8
|
+
watch(related, (newRelated) => {
|
|
9
|
+
//credential.alignment = newAlignment;
|
|
10
|
+
emit('change', newRelated);
|
|
11
|
+
});
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<template>
|
|
15
|
+
<FormKit
|
|
16
|
+
#default="{ items, node, value }"
|
|
17
|
+
type="list"
|
|
18
|
+
v-model="related"
|
|
19
|
+
name="alignment"
|
|
20
|
+
dynamic
|
|
21
|
+
>
|
|
22
|
+
<h5>Related Credentials
|
|
23
|
+
<button type="button" @click="() => node.input(value.concat({}))" class="btn btn-sm btn-primary ms-3">
|
|
24
|
+
Add Related Credential
|
|
25
|
+
</button>
|
|
26
|
+
</h5>
|
|
27
|
+
<p class="form-text">A list of credentials related to this one.</p>
|
|
28
|
+
|
|
29
|
+
<FormKit
|
|
30
|
+
type="group"
|
|
31
|
+
wrapper-class="card"
|
|
32
|
+
v-for="(item, index) in items"
|
|
33
|
+
:key="item"
|
|
34
|
+
:index="index"
|
|
35
|
+
>
|
|
36
|
+
<div class="card mb-3">
|
|
37
|
+
<h5 class="card-header">Credential {{index+1}}
|
|
38
|
+
<button type="button" @click="() => node.input(value.filter((_, i) => i !== index))" class="btn btn-secondary btn-sm float-end">
|
|
39
|
+
Remove
|
|
40
|
+
</button>
|
|
41
|
+
</h5>
|
|
42
|
+
|
|
43
|
+
<div class="card-body pb-0">
|
|
44
|
+
<FormKit
|
|
45
|
+
type="hidden"
|
|
46
|
+
name="type"
|
|
47
|
+
:value="[ 'Related' ]"
|
|
48
|
+
/>
|
|
49
|
+
|
|
50
|
+
<FormKit
|
|
51
|
+
type="innerLabelTextInput"
|
|
52
|
+
label="ID"
|
|
53
|
+
name="id"
|
|
54
|
+
inner-class="input-group"
|
|
55
|
+
label-class="input-group-text"
|
|
56
|
+
wrapper-class="required"
|
|
57
|
+
validation="required:trim"
|
|
58
|
+
help="The URI of the related achievement."
|
|
59
|
+
/>
|
|
60
|
+
|
|
61
|
+
<FormKit
|
|
62
|
+
type="innerLabelTextInput"
|
|
63
|
+
label="Language"
|
|
64
|
+
name="inLanguage"
|
|
65
|
+
inner-class="input-group"
|
|
66
|
+
label-class="input-group-text"
|
|
67
|
+
:validation="[['matches', '/^[a-z]{2,4}(-[A-Z][a-z]{3})?(-([A-Z]{2}|[0-9]{3}))?$/']]"
|
|
68
|
+
help="The language of the related achievement as a BCP47 language code."
|
|
69
|
+
/>
|
|
70
|
+
|
|
71
|
+
<FormKit
|
|
72
|
+
type="innerLabelTextInput"
|
|
73
|
+
label="Version"
|
|
74
|
+
name="version"
|
|
75
|
+
inner-class="input-group"
|
|
76
|
+
label-class="input-group-text"
|
|
77
|
+
help="The version of the related achievement."
|
|
78
|
+
/>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
</FormKit>
|
|
82
|
+
</FormKit>
|
|
83
|
+
</template>
|
|
84
|
+
|
|
85
|
+
<style>
|
|
86
|
+
.input-group>.form-label {
|
|
87
|
+
margin-bottom: 0;
|
|
88
|
+
}
|
|
89
|
+
</style>
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import AlignmentComponent from "@/components/AlignmentComponent.vue";
|
|
3
|
+
import ValueList from "@/components/ValueList.vue";
|
|
4
|
+
import CriterionLevels from "@/components/CriterionLevels.vue";
|
|
5
|
+
import ResultType from "@/components/ResultType.vue";
|
|
6
|
+
|
|
7
|
+
const results = defineModel({ default: [] });
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<FormKit
|
|
12
|
+
#default="{ items, node, value }"
|
|
13
|
+
type="list"
|
|
14
|
+
name="resultDescription"
|
|
15
|
+
v-model="results"
|
|
16
|
+
dynamic
|
|
17
|
+
>
|
|
18
|
+
<h5 class="mb-4">Result Descriptions
|
|
19
|
+
<button type="button" @click="() => node.input(value.concat({}))" class="btn btn-sm btn-primary ms-3">
|
|
20
|
+
Add Result Description
|
|
21
|
+
</button>
|
|
22
|
+
</h5>
|
|
23
|
+
|
|
24
|
+
<FormKit
|
|
25
|
+
type="group"
|
|
26
|
+
wrapper-class="card"
|
|
27
|
+
v-for="(item, index) in items"
|
|
28
|
+
:key="item"
|
|
29
|
+
:index="index"
|
|
30
|
+
>
|
|
31
|
+
<div class="card mb-3">
|
|
32
|
+
<h5 class="card-header">Result Description {{index+1}}
|
|
33
|
+
<button type="button" @click="() => node.input(value.filter((_, i) => i !== index))" class="btn btn-secondary btn-sm float-end">
|
|
34
|
+
Remove
|
|
35
|
+
</button>
|
|
36
|
+
</h5>
|
|
37
|
+
|
|
38
|
+
<div class="card-body">
|
|
39
|
+
<FormKit
|
|
40
|
+
type="innerLabelTextInput"
|
|
41
|
+
label="ID"
|
|
42
|
+
name="id"
|
|
43
|
+
inner-class="input-group"
|
|
44
|
+
label-class="input-group-text"
|
|
45
|
+
wrapper-class="required"
|
|
46
|
+
validation="required:trim"
|
|
47
|
+
help="The unique URI for this result description. Required so a result can link to this result description."
|
|
48
|
+
/>
|
|
49
|
+
|
|
50
|
+
<FormKit
|
|
51
|
+
type="hidden"
|
|
52
|
+
name="type"
|
|
53
|
+
:value="[ 'ResultDescription' ]"
|
|
54
|
+
/>
|
|
55
|
+
|
|
56
|
+
<FormKit
|
|
57
|
+
type="innerLabelTextInput"
|
|
58
|
+
label="Name"
|
|
59
|
+
name="name"
|
|
60
|
+
inner-class="input-group"
|
|
61
|
+
label-class="input-group-text"
|
|
62
|
+
wrapper-class="required"
|
|
63
|
+
validation="required:trim"
|
|
64
|
+
help="The name of the result."
|
|
65
|
+
/>
|
|
66
|
+
|
|
67
|
+
<ResultType v-model="results[index].resultType" />
|
|
68
|
+
|
|
69
|
+
<ValueList v-model="results[index].allowedValue"/>
|
|
70
|
+
|
|
71
|
+
<FormKit
|
|
72
|
+
type="innerLabelTextInput"
|
|
73
|
+
label="Minimum Value"
|
|
74
|
+
name="valueMin"
|
|
75
|
+
inner-class="input-group"
|
|
76
|
+
label-class="input-group-text"
|
|
77
|
+
help="The minimum possible `value` that may be asserted in a linked result."
|
|
78
|
+
/>
|
|
79
|
+
|
|
80
|
+
<FormKit
|
|
81
|
+
type="innerLabelTextInput"
|
|
82
|
+
label="Maximum Value"
|
|
83
|
+
name="valueMax"
|
|
84
|
+
inner-class="input-group"
|
|
85
|
+
label-class="input-group-text"
|
|
86
|
+
help="The maximum possible `value` that may be asserted in a linked result."
|
|
87
|
+
/>
|
|
88
|
+
|
|
89
|
+
<CriterionLevels v-model="results[index].rubricCriterionLevel"/>
|
|
90
|
+
|
|
91
|
+
<FormKit
|
|
92
|
+
type="innerLabelTextInput"
|
|
93
|
+
label="Required Level"
|
|
94
|
+
name="requiredLevel"
|
|
95
|
+
inner-class="input-group"
|
|
96
|
+
label-class="input-group-text"
|
|
97
|
+
help="The `id` of the rubric criterion level required to pass as determined by the achievement creator."
|
|
98
|
+
/>
|
|
99
|
+
|
|
100
|
+
<FormKit
|
|
101
|
+
type="innerLabelTextInput"
|
|
102
|
+
label="Required Value"
|
|
103
|
+
name="requiredValue"
|
|
104
|
+
inner-class="input-group"
|
|
105
|
+
label-class="input-group-text"
|
|
106
|
+
help="A value from `allowedValue` or within the range of `valueMin` to `valueMax` required to pass as determined by the achievement creator."
|
|
107
|
+
/>
|
|
108
|
+
|
|
109
|
+
<AlignmentComponent v-model="results[index].alignment"/>
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
</FormKit>
|
|
113
|
+
</FormKit>
|
|
114
|
+
</template>
|
|
115
|
+
|
|
116
|
+
<style>
|
|
117
|
+
.input-group>.form-label {
|
|
118
|
+
margin-bottom: 0;
|
|
119
|
+
}
|
|
120
|
+
</style>
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import {onMounted, ref, watch} from "vue";
|
|
3
|
+
|
|
4
|
+
const model = defineModel({ default: ''});
|
|
5
|
+
const selectedType = ref('');
|
|
6
|
+
const typeExt = ref('');
|
|
7
|
+
|
|
8
|
+
onMounted(() => {
|
|
9
|
+
if (model.value?.substring(0, 4) === 'ext:') {
|
|
10
|
+
selectedType.value = 'other';
|
|
11
|
+
typeExt.value = model.value.substring(4);
|
|
12
|
+
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
selectedType.value = model.value ? model.value : '';
|
|
17
|
+
typeExt.value = '';
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
watch(selectedType, (value) => {
|
|
21
|
+
if (value === 'other') {
|
|
22
|
+
model.value = 'ext:'+typeExt.value;
|
|
23
|
+
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
model.value = value;
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
watch(typeExt, (value) => {
|
|
31
|
+
if (selectedType.value === 'other') {
|
|
32
|
+
model.value = 'ext:'+value;
|
|
33
|
+
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
model.value = selectedType.value;
|
|
38
|
+
});
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
<template>
|
|
42
|
+
<FormKit
|
|
43
|
+
type="selectInputGroup"
|
|
44
|
+
label="Result Type"
|
|
45
|
+
v-model="selectedType"
|
|
46
|
+
name="selectedType"
|
|
47
|
+
inner-class="input-group"
|
|
48
|
+
label-class="input-group-text"
|
|
49
|
+
input-class="$reset formkit-input form-select"
|
|
50
|
+
wrapper-class="required"
|
|
51
|
+
placeholder="Select Result Type"
|
|
52
|
+
validation="required"
|
|
53
|
+
:options="{
|
|
54
|
+
'GradePointAverage': 'Grade Point Average',
|
|
55
|
+
'LetterGrade': 'Letter Grade',
|
|
56
|
+
'Percent': 'Percent',
|
|
57
|
+
'PerformanceLevel': 'Performance Level',
|
|
58
|
+
'PredictedScore': 'Predicted Score',
|
|
59
|
+
'RawScore': 'Raw Score',
|
|
60
|
+
'Result': 'Result',
|
|
61
|
+
'RubricCriterion': 'Rubric Criterion',
|
|
62
|
+
'RubricCriterionLevel': 'Rubric Criterion Level',
|
|
63
|
+
'RubricScore': 'Rubric Score',
|
|
64
|
+
'ScaledScore': 'Scaled Score',
|
|
65
|
+
'Status': 'Status',
|
|
66
|
+
'other': 'Other (ext:)'
|
|
67
|
+
}"
|
|
68
|
+
help="The type of result this description represents. This is an extensible enumerated vocabulary."
|
|
69
|
+
>
|
|
70
|
+
<template #suffix>
|
|
71
|
+
<FormKit
|
|
72
|
+
v-if="selectedType === 'other'"
|
|
73
|
+
type="innerLabelTextInput"
|
|
74
|
+
label="Extended Type"
|
|
75
|
+
v-model="typeExt"
|
|
76
|
+
name="typeExt"
|
|
77
|
+
aria-label="Extended Result Type"
|
|
78
|
+
inner-class="input-group ms-3 me-5 pe-3"
|
|
79
|
+
outer-class="$reset"
|
|
80
|
+
label-class="visually-hidden"
|
|
81
|
+
before="ext:"
|
|
82
|
+
:validation="[['matches', '/^[a-z|A-Z|0-9|.|-|_]+$/'], ['required']]"
|
|
83
|
+
>
|
|
84
|
+
<template #prefix>
|
|
85
|
+
<span class="input-group-text" aria-label="ext:">ext:</span>
|
|
86
|
+
</template>
|
|
87
|
+
</FormKit>
|
|
88
|
+
</template>
|
|
89
|
+
</FormKit>
|
|
90
|
+
</template>
|
|
91
|
+
|
|
92
|
+
<style scoped>
|
|
93
|
+
|
|
94
|
+
</style>
|