@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opensalt/ob3-definer",
3
- "version": "1.0.2",
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">Save</button>
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, onMounted, ref, watch} from "vue";
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: 'Image', caption: ''} });
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
- // console.log('Mounted', model.value);
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
- model.value.id = newImage;
31
- model.value.type = newImage ? 'Image' : null;
32
- emit('update:modelValue', model.value);
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 = (e) => {
60
+ reader.onerror = (err) => {
50
61
  // console.log('image error');
51
62
  image.value = null;
52
63
  };
53
- reader.onload = (e) => {
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
- <FormKit
77
- type="group"
78
- ignore="true"
79
- >
80
- <FormKit
81
- label="Image"
82
- type="file"
83
- accept="image/png, image/svg+xml"
84
- :help="props.help"
85
- inner-class=""
86
- @input="handleImage"
87
- ignore="true"
88
- >
89
- <template #fileList></template>
90
- <template #suffix>
91
- <figure class="figure ms-3 mt-2" v-show="image">
92
- <img :src="image" alt="Image preview" class="img-thumbnail figure-img img-fluid rounded" id="cm-image-thumbnail" v-show="image">
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
- </template>
96
- </FormKit>
97
-
98
- <FormKit
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>
@@ -14,6 +14,7 @@ const model = defineModel({ default: {} });
14
14
  name="id"
15
15
  label="ID"
16
16
  v-model="model.id"
17
+ validation="uri:trim"
17
18
  help="Unique URI for the Achievement."
18
19
  />
19
20
 
@@ -9,7 +9,7 @@ const creatorIs=ref('noCreator');
9
9
 
10
10
  onBeforeMount(() => {
11
11
  if (Object.keys(creator.value).length === 0) {
12
- creator.value = 'noCreator';
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
- noCreator: 'Do not add a creator field',
36
- organization: 'The creator is an Organization',
37
- individual: 'The creator is a Person',
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
 
@@ -54,7 +54,7 @@ watch(related, (newRelated) => {
54
54
  inner-class="input-group"
55
55
  label-class="input-group-text"
56
56
  wrapper-class="required"
57
- validation="required:trim"
57
+ validation="uri:required:trim"
58
58
  help="The URI of the related achievement."
59
59
  />
60
60
 
@@ -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() {
@@ -0,0 +1,13 @@
1
+ import * as URI from 'uri-js'
2
+
3
+ const uri = function (node) {
4
+ try {
5
+ const checkUri = URI.parse(node.value, {reference: 'absolute', absolutePath: true});
6
+
7
+ return !checkUri.error;
8
+ } catch (e) {
9
+ return false;
10
+ }
11
+ }
12
+
13
+ export default uri