@opensalt/ob3-definer 1.0.2 → 1.1.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/README.md +4 -0
- package/dist/ob3-definer.css +1 -1
- package/dist/ob3-definer.js +19 -19
- package/package.json +2 -1
- package/src/App.vue +5 -1
- package/src/components/AchievementDefiner.vue +9 -1
- package/src/components/AchievementImage.vue +94 -43
- package/src/components/AdditionalTab.vue +1 -0
- package/src/components/CreatorProfile.vue +6 -6
- package/src/components/RelatedList.vue +1 -1
- package/src/components/ResultDescription.vue +3 -2
- package/src/main.js +7 -0
- package/src/validation/uri.js +13 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opensalt/ob3-definer",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"@popperjs/core": "^2.11.8",
|
|
25
25
|
"bootstrap": "^5.3.3",
|
|
26
26
|
"markdown-it": "^14.1.0",
|
|
27
|
+
"uri-js": "^4.4.1",
|
|
27
28
|
"uuid": "^10.0.0",
|
|
28
29
|
"vue": "^3.4.29"
|
|
29
30
|
},
|
package/src/App.vue
CHANGED
|
@@ -5,13 +5,17 @@ const props = defineProps({
|
|
|
5
5
|
achievement: {
|
|
6
6
|
type: String,
|
|
7
7
|
default: ""
|
|
8
|
+
},
|
|
9
|
+
submitText: {
|
|
10
|
+
type: String,
|
|
11
|
+
default: "Save"
|
|
8
12
|
}
|
|
9
13
|
});
|
|
10
14
|
</script>
|
|
11
15
|
|
|
12
16
|
<template>
|
|
13
17
|
<div class="container">
|
|
14
|
-
<AchievementDefiner :achievement="achievement"/>
|
|
18
|
+
<AchievementDefiner :achievement="achievement" :submit-text="submitText"/>
|
|
15
19
|
</div>
|
|
16
20
|
</template>
|
|
17
21
|
|
|
@@ -9,6 +9,10 @@ const props = defineProps({
|
|
|
9
9
|
achievement: {
|
|
10
10
|
type: String,
|
|
11
11
|
default: ""
|
|
12
|
+
},
|
|
13
|
+
submitText: {
|
|
14
|
+
type: String,
|
|
15
|
+
default: "Save"
|
|
12
16
|
}
|
|
13
17
|
});
|
|
14
18
|
const emit = defineEmits(['saveDefinition']);
|
|
@@ -93,6 +97,10 @@ function removeEmpty(obj) {
|
|
|
93
97
|
}
|
|
94
98
|
|
|
95
99
|
function save(formData) {
|
|
100
|
+
if (!formData.image.id) {
|
|
101
|
+
formData.image = null;
|
|
102
|
+
}
|
|
103
|
+
//console.log('formData', formData);
|
|
96
104
|
const cleaned = removeEmpty(formData);
|
|
97
105
|
//emit('saveDefinition', cleaned);
|
|
98
106
|
const formEl = document.getElementById(form.value.node.props.id);
|
|
@@ -179,7 +187,7 @@ function showErrors(node) {
|
|
|
179
187
|
v-show="tab === 'additional'"
|
|
180
188
|
/>
|
|
181
189
|
|
|
182
|
-
<button class="btn btn-primary float-end mt-5" type="submit" :disabled="false">
|
|
190
|
+
<button class="btn btn-primary float-end mt-5" type="submit" :disabled="false">{{ submitText }}</button>
|
|
183
191
|
</FormKit>
|
|
184
192
|
</div>
|
|
185
193
|
</div>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import {onBeforeMount,
|
|
2
|
+
import {onBeforeMount, ref, watch} from "vue";
|
|
3
|
+
import { getNode } from "@formkit/core";
|
|
3
4
|
|
|
4
5
|
const props = defineProps({
|
|
5
6
|
help: {
|
|
@@ -8,37 +9,47 @@ const props = defineProps({
|
|
|
8
9
|
}
|
|
9
10
|
})
|
|
10
11
|
|
|
11
|
-
const model = defineModel({ default: { id: '', type: '
|
|
12
|
+
const model = defineModel({ default: { id: '', type: '', caption: ''} });
|
|
12
13
|
const emit = defineEmits(['update:modelValue']);
|
|
13
14
|
const image = ref('');
|
|
14
15
|
const caption = ref('');
|
|
16
|
+
const id = ref('');
|
|
15
17
|
|
|
16
18
|
onBeforeMount(() => {
|
|
17
|
-
|
|
18
|
-
image.value = model.value.id || null;
|
|
19
|
+
id.value = model.value.id || null;
|
|
19
20
|
caption.value = model.value.caption || null;
|
|
20
|
-
|
|
21
|
+
if (id.value) {
|
|
22
|
+
model.value.type = 'Image';
|
|
23
|
+
}
|
|
24
|
+
});
|
|
21
25
|
|
|
22
26
|
watch(caption, (newCaption) => {
|
|
23
27
|
// console.log('watching caption', newCaption);
|
|
24
28
|
model.value.caption = newCaption;
|
|
25
|
-
emit('update:modelValue', model.value);
|
|
26
29
|
});
|
|
27
30
|
|
|
31
|
+
watch(id, (newId) => {
|
|
32
|
+
// console.log('watching id', newId);
|
|
33
|
+
model.value.id = newId;
|
|
34
|
+
model.value.type = newId ? 'Image' : null;
|
|
35
|
+
model.value.caption = newId ? caption.value : null;
|
|
36
|
+
})
|
|
37
|
+
|
|
28
38
|
watch(image, (newImage) => {
|
|
29
|
-
// console.log('watching', newImage);
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
39
|
+
// console.log('watching image', newImage);
|
|
40
|
+
if (!newImage) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
id.value = newImage;
|
|
33
45
|
});
|
|
34
46
|
|
|
35
47
|
function handleImage(e) {
|
|
36
|
-
// console.log('handle image');
|
|
48
|
+
// console.log('handle image', e);
|
|
37
49
|
|
|
38
50
|
if (0 === Object.keys(e).length) {
|
|
39
51
|
// console.log('no keys');
|
|
40
52
|
image.value = null;
|
|
41
|
-
caption.value = null;
|
|
42
53
|
|
|
43
54
|
return;
|
|
44
55
|
}
|
|
@@ -46,11 +57,11 @@ function handleImage(e) {
|
|
|
46
57
|
const file = e[0].file;
|
|
47
58
|
const reader = new FileReader();
|
|
48
59
|
|
|
49
|
-
reader.onerror = (
|
|
60
|
+
reader.onerror = (err) => {
|
|
50
61
|
// console.log('image error');
|
|
51
62
|
image.value = null;
|
|
52
63
|
};
|
|
53
|
-
reader.onload = (
|
|
64
|
+
reader.onload = (evt) => {
|
|
54
65
|
// Use the loaded image data to set the badgeImage
|
|
55
66
|
image.value = reader.result;
|
|
56
67
|
// console.log('onload');
|
|
@@ -61,6 +72,10 @@ function handleImage(e) {
|
|
|
61
72
|
|
|
62
73
|
return false;
|
|
63
74
|
}
|
|
75
|
+
|
|
76
|
+
let f = getNode('ob3-file-upload-input');
|
|
77
|
+
// console.log(f);
|
|
78
|
+
f.context.handlers.resetFiles(evt);
|
|
64
79
|
};
|
|
65
80
|
|
|
66
81
|
try {
|
|
@@ -73,37 +88,73 @@ function handleImage(e) {
|
|
|
73
88
|
</script>
|
|
74
89
|
|
|
75
90
|
<template>
|
|
76
|
-
<
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
<
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
<div class="card mb-3">
|
|
92
|
+
<div class="card-header">
|
|
93
|
+
Image for the Credential
|
|
94
|
+
</div>
|
|
95
|
+
<div class="card-body">
|
|
96
|
+
<FormKit
|
|
97
|
+
type="group"
|
|
98
|
+
name="image"
|
|
99
|
+
>
|
|
100
|
+
<div class="row">
|
|
101
|
+
<div class="col-md-8">
|
|
102
|
+
<FormKit
|
|
103
|
+
label="ID"
|
|
104
|
+
type="innerLabelTextInput"
|
|
105
|
+
v-model="id"
|
|
106
|
+
name="id"
|
|
107
|
+
:help="props.help+' Can be a URL or data URI.'"
|
|
108
|
+
inner-class="input-group"
|
|
109
|
+
label-class="input-group-text"
|
|
110
|
+
validation="uri"
|
|
111
|
+
:validation-messages="{
|
|
112
|
+
uri: 'Please enter a valid URL or upload an image.'
|
|
113
|
+
}"
|
|
114
|
+
/>
|
|
115
|
+
<FormKit
|
|
116
|
+
type="hidden"
|
|
117
|
+
name="type"
|
|
118
|
+
value="Image"
|
|
119
|
+
/>
|
|
120
|
+
</div>
|
|
121
|
+
<div class="col-md-4">
|
|
122
|
+
<FormKit
|
|
123
|
+
label="Upload Image"
|
|
124
|
+
type="file"
|
|
125
|
+
id="ob3-file-upload-input"
|
|
126
|
+
accept="image/png, image/svg+xml"
|
|
127
|
+
inner-class="d-none"
|
|
128
|
+
label-class="btn btn-secondary"
|
|
129
|
+
help="You can upload an image to save it as a data URI."
|
|
130
|
+
@input="handleImage"
|
|
131
|
+
ignore="true"
|
|
132
|
+
>
|
|
133
|
+
<template #fileList></template>
|
|
134
|
+
<template #noFiles></template>
|
|
135
|
+
</FormKit>
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
138
|
+
|
|
139
|
+
<FormKit
|
|
140
|
+
label="Caption"
|
|
141
|
+
type="innerLabelTextInput"
|
|
142
|
+
v-model="caption"
|
|
143
|
+
name="caption"
|
|
144
|
+
help="A caption for the image."
|
|
145
|
+
inner-class="input-group"
|
|
146
|
+
label-class="input-group-text"
|
|
147
|
+
v-show="id"
|
|
148
|
+
/>
|
|
149
|
+
|
|
150
|
+
<figure class="figure ms-3 mt-2" v-show="id">
|
|
151
|
+
<img :src="id" alt="Image preview" class="img-thumbnail figure-img img-fluid rounded" id="cm-image-thumbnail">
|
|
93
152
|
<figcaption class="figure-caption text-center">Image preview</figcaption>
|
|
94
153
|
</figure>
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
label="Image Caption"
|
|
100
|
-
type="text"
|
|
101
|
-
v-model="caption"
|
|
102
|
-
help="A caption for the image."
|
|
103
|
-
v-show="image"
|
|
104
|
-
ignore="true"
|
|
105
|
-
/>
|
|
106
|
-
</FormKit>
|
|
154
|
+
|
|
155
|
+
</FormKit>
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
107
158
|
</template>
|
|
108
159
|
|
|
109
160
|
<style scoped>
|
|
@@ -9,7 +9,7 @@ const creatorIs=ref('noCreator');
|
|
|
9
9
|
|
|
10
10
|
onBeforeMount(() => {
|
|
11
11
|
if (Object.keys(creator.value).length === 0) {
|
|
12
|
-
|
|
12
|
+
creatorIs.value = 'noCreator';
|
|
13
13
|
|
|
14
14
|
return;
|
|
15
15
|
}
|
|
@@ -32,10 +32,10 @@ onBeforeMount(() => {
|
|
|
32
32
|
v-model="creatorIs"
|
|
33
33
|
input-class="$reset formkit-input form-select"
|
|
34
34
|
:options="{
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
noCreator: 'Do not add a creator field',
|
|
36
|
+
organization: 'The creator is an Organization',
|
|
37
|
+
individual: 'The creator is a Person',
|
|
38
|
+
}"
|
|
39
39
|
ignore="true"
|
|
40
40
|
/>
|
|
41
41
|
</h5>
|
|
@@ -52,7 +52,7 @@ onBeforeMount(() => {
|
|
|
52
52
|
label="ID"
|
|
53
53
|
name="id"
|
|
54
54
|
wrapper-class="required"
|
|
55
|
-
validation="required:trim"
|
|
55
|
+
validation="uri:required:trim"
|
|
56
56
|
help="Unique URI for the creator."
|
|
57
57
|
/>
|
|
58
58
|
|
|
@@ -3,6 +3,7 @@ import AlignmentComponent from "@/components/AlignmentComponent.vue";
|
|
|
3
3
|
import ValueList from "@/components/ValueList.vue";
|
|
4
4
|
import CriterionLevels from "@/components/CriterionLevels.vue";
|
|
5
5
|
import ResultType from "@/components/ResultType.vue";
|
|
6
|
+
import { v4 as uuidV4 } from "uuid";
|
|
6
7
|
|
|
7
8
|
const results = defineModel({ default: [] });
|
|
8
9
|
</script>
|
|
@@ -16,7 +17,7 @@ const results = defineModel({ default: [] });
|
|
|
16
17
|
dynamic
|
|
17
18
|
>
|
|
18
19
|
<h5 class="mb-4">Result Descriptions
|
|
19
|
-
<button type="button" @click="() => node.input(value.concat({}))" class="btn btn-sm btn-primary ms-3">
|
|
20
|
+
<button type="button" @click="() => node.input(value.concat({id: 'urn:uuid:'+uuidV4()}))" class="btn btn-sm btn-primary ms-3">
|
|
20
21
|
Add Result Description
|
|
21
22
|
</button>
|
|
22
23
|
</h5>
|
|
@@ -43,7 +44,7 @@ const results = defineModel({ default: [] });
|
|
|
43
44
|
inner-class="input-group"
|
|
44
45
|
label-class="input-group-text"
|
|
45
46
|
wrapper-class="required"
|
|
46
|
-
validation="required:trim"
|
|
47
|
+
validation="uri:required:trim"
|
|
47
48
|
help="The unique URI for this result description. Required so a result can link to this result description."
|
|
48
49
|
/>
|
|
49
50
|
|
package/src/main.js
CHANGED
|
@@ -10,6 +10,7 @@ import customConfig from '../formkit.config.js';
|
|
|
10
10
|
import { innerLabelTextInput } from '@/inputs/innerLabelTextInput.js';
|
|
11
11
|
import { innerLabelTextareaInput } from '@/inputs/innerLabelTextareaInput.js';
|
|
12
12
|
import { selectInputGroup } from '@/inputs/selectInputGroup.js';
|
|
13
|
+
import uri from "@/validation/uri.js";
|
|
13
14
|
|
|
14
15
|
const createDefiner = (el, props) => {
|
|
15
16
|
const app = createApp(App, props);
|
|
@@ -20,6 +21,9 @@ const createDefiner = (el, props) => {
|
|
|
20
21
|
innerLabelTextareaInput,
|
|
21
22
|
selectInputGroup,
|
|
22
23
|
},
|
|
24
|
+
rules: {
|
|
25
|
+
uri,
|
|
26
|
+
},
|
|
23
27
|
}));
|
|
24
28
|
return app;
|
|
25
29
|
}
|
|
@@ -39,6 +43,9 @@ window.addEventListener('ob3-open', function(event) {
|
|
|
39
43
|
props.achievement = JSON.stringify(event.detail.achievement);
|
|
40
44
|
}
|
|
41
45
|
}
|
|
46
|
+
if (event.detail?.submitText) {
|
|
47
|
+
props.submitText = event.detail.submitText;
|
|
48
|
+
}
|
|
42
49
|
const app = createDefiner(selector, props);
|
|
43
50
|
app.mount(selector);
|
|
44
51
|
window.addEventListener('ob3-close', function close() {
|