apostrophe 4.4.3 → 4.5.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/CHANGELOG.md +44 -0
- package/index.js +2 -3
- package/lib/glob.js +12 -0
- package/lib/moog-require.js +3 -3
- package/modules/@apostrophecms/admin-bar/index.js +9 -2
- package/modules/@apostrophecms/admin-bar/ui/apos/apps/AposAdminBar.js +1 -1
- package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposContextBar.vue +2 -2
- package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposContextTitle.vue +0 -1
- package/modules/@apostrophecms/area/ui/apos/components/AposAreaContextualMenu.vue +2 -2
- package/modules/@apostrophecms/area/ui/apos/components/AposAreaEditor.vue +6 -6
- package/modules/@apostrophecms/area/ui/apos/components/AposAreaExpandedMenu.vue +7 -1
- package/modules/@apostrophecms/asset/index.js +5 -6
- package/modules/@apostrophecms/command-menu/index.js +7 -2
- package/modules/@apostrophecms/doc/index.js +2 -2
- package/modules/@apostrophecms/doc-type/index.js +1 -1
- package/modules/@apostrophecms/i18n/i18n/en.json +37 -1
- package/modules/@apostrophecms/i18n/index.js +2 -2
- package/modules/@apostrophecms/i18n/ui/apos/components/AposI18nLocalize.vue +5 -5
- package/modules/@apostrophecms/image/index.js +1 -1
- package/modules/@apostrophecms/image/ui/apos/components/AposImageRelationshipEditor.vue +4 -3
- package/modules/@apostrophecms/image/ui/apos/components/AposMediaManager.vue +221 -76
- package/modules/@apostrophecms/image/ui/apos/components/AposMediaManagerDisplay.vue +91 -24
- package/modules/@apostrophecms/image/ui/apos/components/AposMediaManagerEditor.vue +48 -51
- package/modules/@apostrophecms/image/ui/apos/components/AposMediaManagerSelections.vue +1 -0
- package/modules/@apostrophecms/login/index.js +3 -3
- package/modules/@apostrophecms/modal/ui/apos/components/AposDocsManagerToolbar.vue +3 -11
- package/modules/@apostrophecms/modal/ui/apos/components/AposModal.vue +4 -12
- package/modules/@apostrophecms/modal/ui/apos/components/AposModalBody.vue +20 -6
- package/modules/@apostrophecms/modal/ui/apos/components/AposModalBreadcrumbs.vue +1 -1
- package/modules/@apostrophecms/modal/ui/apos/components/AposModalShareDraft.vue +1 -1
- package/modules/@apostrophecms/modal/ui/apos/components/AposModalTabs.vue +3 -5
- package/modules/@apostrophecms/modal/ui/apos/components/AposWidgetModalTabs.vue +3 -5
- package/modules/@apostrophecms/modal/ui/apos/mixins/AposDocErrorsMixin.js +2 -2
- package/modules/@apostrophecms/modal/ui/apos/mixins/AposDocsManagerMixin.js +44 -39
- package/modules/@apostrophecms/modal/ui/apos/mixins/AposModalTabsMixin.js +2 -2
- package/modules/@apostrophecms/oembed/index.js +2 -2
- package/modules/@apostrophecms/oembed-field/ui/apos/components/AposInputOembed.vue +2 -2
- package/modules/@apostrophecms/page/ui/apos/components/AposPagesManager.vue +1 -2
- package/modules/@apostrophecms/page/ui/apos/logic/AposPagesManager.js +14 -7
- package/modules/@apostrophecms/piece-type/ui/apos/components/AposDocsManager.vue +23 -11
- package/modules/@apostrophecms/piece-type/ui/apos/components/AposDocsManagerDisplay.vue +4 -1
- package/modules/@apostrophecms/rich-text-widget/index.js +31 -3
- package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapColor.vue +285 -0
- package/modules/@apostrophecms/rich-text-widget/ui/apos/tiptap-extensions/Color.js +5 -0
- package/modules/@apostrophecms/schema/lib/addFieldTypes.js +26 -13
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputBoolean.vue +2 -2
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputColor.vue +0 -1
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputObject.vue +1 -0
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputWrapper.vue +13 -2
- package/modules/@apostrophecms/schema/ui/apos/logic/AposArrayEditor.js +11 -9
- package/modules/@apostrophecms/schema/ui/apos/logic/AposInputArea.js +4 -4
- package/modules/@apostrophecms/schema/ui/apos/logic/AposInputArray.js +7 -7
- package/modules/@apostrophecms/schema/ui/apos/logic/AposInputObject.js +11 -0
- package/modules/@apostrophecms/schema/ui/apos/logic/AposInputSlug.js +45 -51
- package/modules/@apostrophecms/schema/ui/apos/logic/AposSchema.js +3 -1
- package/modules/@apostrophecms/schema/ui/apos/mixins/AposInputMixin.js +1 -1
- package/modules/@apostrophecms/submitted-draft/index.js +2 -2
- package/modules/@apostrophecms/ui/ui/apos/components/AposButton.vue +7 -3
- package/modules/@apostrophecms/ui/ui/apos/components/AposButtonSplit.vue +0 -1
- package/modules/@apostrophecms/ui/ui/apos/components/AposContextMenu.vue +12 -4
- package/modules/@apostrophecms/ui/ui/apos/components/AposFile.vue +4 -4
- package/modules/@apostrophecms/ui/ui/apos/components/AposFilterMenu.vue +2 -1
- package/modules/@apostrophecms/ui/ui/apos/components/AposLoading.vue +1 -1
- package/modules/@apostrophecms/ui/ui/apos/components/AposLoadingBlock.vue +50 -0
- package/modules/@apostrophecms/ui/ui/apos/components/AposSlat.vue +0 -1
- package/modules/@apostrophecms/ui/ui/apos/components/AposSlatList.vue +6 -4
- package/modules/@apostrophecms/ui/ui/apos/components/AposTagApply.vue +17 -11
- package/modules/@apostrophecms/ui/ui/apos/components/AposTree.vue +2 -2
- package/modules/@apostrophecms/ui/ui/apos/components/AposTreeRows.vue +2 -2
- package/modules/@apostrophecms/ui/ui/apos/lib/tooltip.js +2 -2
- package/modules/@apostrophecms/ui/ui/apos/stores/modal.js +3 -3
- package/modules/@apostrophecms/user/index.js +1 -0
- package/modules/@apostrophecms/util/index.js +12 -4
- package/modules/@apostrophecms/widget-type/ui/apos/components/AposWidgetEditor.vue +2 -2
- package/package.json +8 -7
- package/scripts/lint-i18n.js +8 -3
- package/test/command-menu.js +76 -12
- package/test/pages-rest.js +2 -2
- package/test/pieces.js +11 -11
- package/test/recursionGuard.js +5 -5
- package/test/utils/commands.js +26 -0
- package/test-lib/util.js +2 -2
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="apos-color-control">
|
|
3
|
+
<AposButton
|
|
4
|
+
type="rich-text"
|
|
5
|
+
class="apos-rich-text-editor__control"
|
|
6
|
+
:class="['apos-color-button', { 'apos-is-active': active }]"
|
|
7
|
+
:icon-only="false"
|
|
8
|
+
icon="circle-icon"
|
|
9
|
+
:icon-fill="indicatorColor"
|
|
10
|
+
:label="'apostrophe:richTextColor'"
|
|
11
|
+
:modifiers="['no-border', 'no-motion']"
|
|
12
|
+
:tooltip="{
|
|
13
|
+
content: 'apostrophe:richTextColor',
|
|
14
|
+
placement: 'top',
|
|
15
|
+
delay: 650
|
|
16
|
+
}"
|
|
17
|
+
@click="click"
|
|
18
|
+
>
|
|
19
|
+
<template #label>
|
|
20
|
+
<AposIndicator icon="chevron-down-icon" />
|
|
21
|
+
</template>
|
|
22
|
+
</AposButton>
|
|
23
|
+
<div
|
|
24
|
+
v-if="active"
|
|
25
|
+
v-click-outside-element="close"
|
|
26
|
+
class="apos-popover apos-color-control__dialog"
|
|
27
|
+
x-placement="bottom"
|
|
28
|
+
:class="{
|
|
29
|
+
'apos-is-triggered': active,
|
|
30
|
+
'apos-has-selection': hasSelection
|
|
31
|
+
}"
|
|
32
|
+
>
|
|
33
|
+
<AposContextMenuDialog menu-placement="bottom-center">
|
|
34
|
+
<div
|
|
35
|
+
v-if="editor"
|
|
36
|
+
class="text-color-component"
|
|
37
|
+
@mousedown="handleMouseDown"
|
|
38
|
+
>
|
|
39
|
+
<Picker
|
|
40
|
+
v-bind="pickerOptions"
|
|
41
|
+
:model-value="pickerValue"
|
|
42
|
+
@update:model-value="update"
|
|
43
|
+
@focus="focus"
|
|
44
|
+
/>
|
|
45
|
+
</div>
|
|
46
|
+
<footer class="apos-color-control__footer">
|
|
47
|
+
<AposButton
|
|
48
|
+
type="primary"
|
|
49
|
+
label="apostrophe:close"
|
|
50
|
+
:modifiers="['small', 'margin-micro']"
|
|
51
|
+
@click="close"
|
|
52
|
+
/>
|
|
53
|
+
</footer>
|
|
54
|
+
</AposContextMenuDialog>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
</template>
|
|
58
|
+
|
|
59
|
+
<script>
|
|
60
|
+
import {
|
|
61
|
+
ref, watch, computed, defineComponent
|
|
62
|
+
} from 'vue';
|
|
63
|
+
import { Sketch as Picker } from '@ckpack/vue-color';
|
|
64
|
+
import tinycolor from 'tinycolor2';
|
|
65
|
+
|
|
66
|
+
export default defineComponent({
|
|
67
|
+
name: 'AposTiptapColor',
|
|
68
|
+
components: {
|
|
69
|
+
Picker
|
|
70
|
+
},
|
|
71
|
+
props: {
|
|
72
|
+
name: {
|
|
73
|
+
type: String,
|
|
74
|
+
required: true
|
|
75
|
+
},
|
|
76
|
+
options: {
|
|
77
|
+
type: Object,
|
|
78
|
+
required: true
|
|
79
|
+
},
|
|
80
|
+
tool: {
|
|
81
|
+
type: Object,
|
|
82
|
+
required: true
|
|
83
|
+
},
|
|
84
|
+
modelValue: {
|
|
85
|
+
type: Object,
|
|
86
|
+
default() {
|
|
87
|
+
return {};
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
editor: {
|
|
91
|
+
type: Object,
|
|
92
|
+
required: true
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
setup(props) {
|
|
96
|
+
const active = ref(false);
|
|
97
|
+
const next = ref('');
|
|
98
|
+
const tinyColorObj = ref(null);
|
|
99
|
+
const startsNull = ref(false);
|
|
100
|
+
const indicatorColor = ref('#000000');
|
|
101
|
+
|
|
102
|
+
const defaultOptions = {
|
|
103
|
+
presetColors: [
|
|
104
|
+
'#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321',
|
|
105
|
+
'#417505', '#BD10E0', '#9013FE', '#4A90E2', '#50E3C2',
|
|
106
|
+
'#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF'
|
|
107
|
+
],
|
|
108
|
+
disableAlpha: false,
|
|
109
|
+
disableFields: false,
|
|
110
|
+
format: 'hex8'
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const projectOptions = computed(() => {
|
|
114
|
+
return window.apos.modules['@apostrophecms/rich-text-widget'];
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
const areaOptions = props.options || {};
|
|
118
|
+
|
|
119
|
+
const userOptions = computed(() => {
|
|
120
|
+
return {
|
|
121
|
+
...projectOptions.value,
|
|
122
|
+
...areaOptions
|
|
123
|
+
};
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const mergedOptions = computed(() => {
|
|
127
|
+
return {
|
|
128
|
+
...defaultOptions,
|
|
129
|
+
...userOptions.value.color
|
|
130
|
+
};
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
const pickerOptions = computed(() => {
|
|
134
|
+
const {
|
|
135
|
+
presetColors, disableAlpha, disableFields
|
|
136
|
+
} = mergedOptions.value;
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
presetColors,
|
|
140
|
+
disableAlpha,
|
|
141
|
+
disableFields
|
|
142
|
+
};
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
const format = computed(() => {
|
|
146
|
+
return mergedOptions.value.format;
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
const pickerValue = ref(next.value || '');
|
|
150
|
+
|
|
151
|
+
const hasSelection = computed(() => !props.editor.state.selection.empty);
|
|
152
|
+
|
|
153
|
+
watch(
|
|
154
|
+
() => props.editor.state.selection,
|
|
155
|
+
() => {
|
|
156
|
+
if (hasSelection.value) {
|
|
157
|
+
const newColor = props.editor.getAttributes('textStyle').color;
|
|
158
|
+
next.value = newColor || '#000000';
|
|
159
|
+
indicatorColor.value = next.value;
|
|
160
|
+
} else {
|
|
161
|
+
next.value = '#000000';
|
|
162
|
+
indicatorColor.value = next.value;
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
deep: true,
|
|
167
|
+
immediate: true
|
|
168
|
+
}
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
watch(pickerValue, (newColor) => {
|
|
172
|
+
indicatorColor.value = newColor;
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
const open = () => {
|
|
176
|
+
active.value = true;
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const close = () => {
|
|
180
|
+
active.value = false;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const update = (value) => {
|
|
184
|
+
tinyColorObj.value = tinycolor(value.hsl);
|
|
185
|
+
next.value = tinyColorObj.value.toString(format.value);
|
|
186
|
+
props.editor.chain().focus().setColor(next.value).run();
|
|
187
|
+
indicatorColor.value = next.value;
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
const click = () => {
|
|
191
|
+
active.value = !active.value;
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const focus = () => {
|
|
195
|
+
// Keep focus on the toolbar to prevent it from closing
|
|
196
|
+
props.editor.view.dom.focus();
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const handleMouseDown = (event) => {
|
|
200
|
+
const target = event.target;
|
|
201
|
+
if (target.closest('.vc-sketch-saturation-wrap') || target.closest('.vc-sketch-presets')) {
|
|
202
|
+
event.preventDefault();
|
|
203
|
+
} else {
|
|
204
|
+
props.editor.view.dom.focus();
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
active,
|
|
210
|
+
indicatorColor,
|
|
211
|
+
pickerOptions,
|
|
212
|
+
pickerValue,
|
|
213
|
+
hasSelection,
|
|
214
|
+
startsNull,
|
|
215
|
+
open,
|
|
216
|
+
close,
|
|
217
|
+
update,
|
|
218
|
+
click,
|
|
219
|
+
focus,
|
|
220
|
+
handleMouseDown
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
</script>
|
|
225
|
+
|
|
226
|
+
<style lang="scss" scoped>
|
|
227
|
+
.apos-color-control {
|
|
228
|
+
position: relative;
|
|
229
|
+
display: inline-block;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.apos-color-button {
|
|
233
|
+
display: flex;
|
|
234
|
+
align-items: center;
|
|
235
|
+
border: none;
|
|
236
|
+
background-color: transparent;
|
|
237
|
+
cursor: pointer;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.color-indicator {
|
|
241
|
+
flex-shrink: 0;
|
|
242
|
+
width: 12px;
|
|
243
|
+
height: 12px;
|
|
244
|
+
margin-right: 5px;
|
|
245
|
+
border-radius: 50%;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.button-label {
|
|
249
|
+
margin-right: 5px;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
.chevron-down {
|
|
253
|
+
display: inline-block;
|
|
254
|
+
padding: 3px;
|
|
255
|
+
border: solid var(--a-base-8);
|
|
256
|
+
border-width: 0 2px 2px 0;
|
|
257
|
+
transform: rotate(45deg);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.apos-color-control__dialog {
|
|
261
|
+
z-index: $z-index-modal;
|
|
262
|
+
position: absolute;
|
|
263
|
+
top: calc(100% + 15px);
|
|
264
|
+
left: 5px;
|
|
265
|
+
opacity: 0;
|
|
266
|
+
pointer-events: none;
|
|
267
|
+
width: auto;
|
|
268
|
+
max-width: 90%;
|
|
269
|
+
|
|
270
|
+
&.apos-is-triggered.apos-has-selection {
|
|
271
|
+
opacity: 1;
|
|
272
|
+
pointer-events: auto;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.apos-is-active {
|
|
277
|
+
background-color: var(--a-base-7);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.apos-color-control__footer {
|
|
281
|
+
display: flex;
|
|
282
|
+
justify-content: flex-end;
|
|
283
|
+
margin-top: 10px;
|
|
284
|
+
}
|
|
285
|
+
</style>
|
|
@@ -722,7 +722,8 @@ module.exports = (self) => {
|
|
|
722
722
|
|
|
723
723
|
destination[field.name] = checkStringLength(destination[field.name], field.min, field.max);
|
|
724
724
|
}
|
|
725
|
-
}
|
|
725
|
+
},
|
|
726
|
+
def: ''
|
|
726
727
|
});
|
|
727
728
|
|
|
728
729
|
self.addFieldType({
|
|
@@ -889,11 +890,12 @@ module.exports = (self) => {
|
|
|
889
890
|
try {
|
|
890
891
|
await self.convert(req, schema, data, result);
|
|
891
892
|
} catch (e) {
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
893
|
+
if (Array.isArray(e)) {
|
|
894
|
+
for (const error of e) {
|
|
895
|
+
errors.push(error);
|
|
896
|
+
}
|
|
897
|
+
} else {
|
|
898
|
+
throw e;
|
|
897
899
|
}
|
|
898
900
|
}
|
|
899
901
|
result.metaType = 'objectItem';
|
|
@@ -912,7 +914,7 @@ module.exports = (self) => {
|
|
|
912
914
|
self.register(metaType, type, field.schema);
|
|
913
915
|
},
|
|
914
916
|
validate: function (field, options, warn, fail) {
|
|
915
|
-
for (const subField of field.schema
|
|
917
|
+
for (const subField of field.schema) {
|
|
916
918
|
self.validateField(subField, options, field);
|
|
917
919
|
}
|
|
918
920
|
},
|
|
@@ -1139,12 +1141,7 @@ module.exports = (self) => {
|
|
|
1139
1141
|
field.schema = self.fieldsToArray(`Relationship field ${field.name}`, field.fields);
|
|
1140
1142
|
}
|
|
1141
1143
|
}
|
|
1142
|
-
|
|
1143
|
-
field.fieldsStorage = field.name.replace(/^_/, '') + 'Fields';
|
|
1144
|
-
}
|
|
1145
|
-
if (field.schema && !Array.isArray(field.schema)) {
|
|
1146
|
-
fail('schema property should be an array if present at this stage');
|
|
1147
|
-
}
|
|
1144
|
+
validateSchema(field);
|
|
1148
1145
|
if (field.filters) {
|
|
1149
1146
|
fail('"filters" property should be changed to "builders" for 3.x');
|
|
1150
1147
|
}
|
|
@@ -1157,6 +1154,22 @@ module.exports = (self) => {
|
|
|
1157
1154
|
fail('withType property, ' + type + ', does not match the name of any piece or page type module.');
|
|
1158
1155
|
}
|
|
1159
1156
|
}
|
|
1157
|
+
|
|
1158
|
+
function validateSchema(_field) {
|
|
1159
|
+
if (!_field.schema) {
|
|
1160
|
+
return;
|
|
1161
|
+
}
|
|
1162
|
+
if (!Array.isArray(_field.schema)) {
|
|
1163
|
+
fail('schema property should be an array if present at this stage');
|
|
1164
|
+
}
|
|
1165
|
+
self.validate(_field.schema, {
|
|
1166
|
+
type: 'relationship',
|
|
1167
|
+
subtype: _field.withType
|
|
1168
|
+
});
|
|
1169
|
+
if (!_field.fieldsStorage) {
|
|
1170
|
+
_field.fieldsStorage = _field.name.replace(/^_/, '') + 'Fields';
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1160
1173
|
},
|
|
1161
1174
|
isEqual(req, field, one, two) {
|
|
1162
1175
|
const ids1 = one[field.idsStorage] || [];
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
class="apos-boolean__icon"
|
|
26
26
|
title=""
|
|
27
27
|
/>
|
|
28
|
-
{{ trueLabel || '
|
|
28
|
+
{{ trueLabel || $t('apostrophe:yes') }}
|
|
29
29
|
</label>
|
|
30
30
|
<input
|
|
31
31
|
:id="`${uid}-false`"
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
class="apos-boolean__icon"
|
|
45
45
|
title=""
|
|
46
46
|
/>
|
|
47
|
-
{{ falseLabel || '
|
|
47
|
+
{{ falseLabel || $t('apostrophe:no') }}
|
|
48
48
|
</label>
|
|
49
49
|
</div>
|
|
50
50
|
</template>
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
class="apos-field__error"
|
|
92
92
|
data-apos-test="field-error"
|
|
93
93
|
>
|
|
94
|
-
{{
|
|
94
|
+
{{ getTranslatedErrorMessage(errorMessage) }}
|
|
95
95
|
</div>
|
|
96
96
|
</component>
|
|
97
97
|
<!-- CSS Escape hatch for additional interfaces like relatipnship managers -->
|
|
@@ -103,7 +103,18 @@
|
|
|
103
103
|
import AposInputWrapperLogic from '../logic/AposInputWrapper';
|
|
104
104
|
export default {
|
|
105
105
|
name: 'AposInputWrapper',
|
|
106
|
-
mixins: [ AposInputWrapperLogic ]
|
|
106
|
+
mixins: [ AposInputWrapperLogic ],
|
|
107
|
+
methods: {
|
|
108
|
+
getTranslatedErrorMessage(message) {
|
|
109
|
+
if (message === 'required') {
|
|
110
|
+
return this.$t('apostrophe:required');
|
|
111
|
+
}
|
|
112
|
+
if (message === 'invalid') {
|
|
113
|
+
return this.$t('apostrophe:invalid');
|
|
114
|
+
}
|
|
115
|
+
return this.$t(message);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
107
118
|
};
|
|
108
119
|
</script>
|
|
109
120
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import AposModifiedMixin from 'Modules/@apostrophecms/ui/mixins/AposModifiedMixin';
|
|
2
2
|
import AposEditorMixin from 'Modules/@apostrophecms/modal/mixins/AposEditorMixin';
|
|
3
|
-
import
|
|
3
|
+
import { createId } from '@paralleldrive/cuid2';
|
|
4
4
|
import { klona } from 'klona';
|
|
5
5
|
import { get } from 'lodash';
|
|
6
6
|
import { detectDocChange } from 'Modules/@apostrophecms/schema/lib/detectChange';
|
|
@@ -42,7 +42,7 @@ export default {
|
|
|
42
42
|
// Automatically add `_id` to default items
|
|
43
43
|
const items = this.items.map(item => ({
|
|
44
44
|
...item,
|
|
45
|
-
_id: item._id ||
|
|
45
|
+
_id: item._id || createId()
|
|
46
46
|
}));
|
|
47
47
|
|
|
48
48
|
return {
|
|
@@ -144,13 +144,15 @@ export default {
|
|
|
144
144
|
if (this.next.length) {
|
|
145
145
|
this.setCurrentDoc(this.next.at(0)._id);
|
|
146
146
|
}
|
|
147
|
-
if (this.serverError
|
|
147
|
+
if (this.serverError?.data?.errors?.length) {
|
|
148
148
|
const first = this.serverError.data.errors[0];
|
|
149
|
-
const [ _id, name ] = first.path
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
149
|
+
const [ _id, name ] = first.path?.split('.') || [];
|
|
150
|
+
if (_id) {
|
|
151
|
+
await this.select(_id);
|
|
152
|
+
const aposSchema = this.$refs.schema;
|
|
153
|
+
await this.$nextTick();
|
|
154
|
+
name && aposSchema.scrollFieldIntoView(name);
|
|
155
|
+
}
|
|
154
156
|
}
|
|
155
157
|
this.titleFieldChoices = await this.getTitleFieldChoices();
|
|
156
158
|
},
|
|
@@ -193,7 +195,7 @@ export default {
|
|
|
193
195
|
async add() {
|
|
194
196
|
if (await this.validate(true, false)) {
|
|
195
197
|
const item = this.newInstance();
|
|
196
|
-
item._id =
|
|
198
|
+
item._id = createId();
|
|
197
199
|
this.next.push(item);
|
|
198
200
|
await this.select(item._id);
|
|
199
201
|
this.updateMinMax();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
import AposInputMixin from 'Modules/@apostrophecms/schema/mixins/AposInputMixin';
|
|
3
|
-
import
|
|
3
|
+
import { createId } from '@paralleldrive/cuid2';
|
|
4
4
|
|
|
5
5
|
export default {
|
|
6
6
|
name: 'AposInputArea',
|
|
@@ -43,8 +43,8 @@ export default {
|
|
|
43
43
|
for (const [ name, options ] of Object.entries(widgets)) {
|
|
44
44
|
result.push({
|
|
45
45
|
name,
|
|
46
|
-
label: options.addLabel || apos.modules[`${name}-widget`]
|
|
47
|
-
icon: apos.modules[`${name}-widget`]
|
|
46
|
+
label: options.addLabel || apos.modules[`${name}-widget`]?.label,
|
|
47
|
+
icon: apos.modules[`${name}-widget`]?.icon
|
|
48
48
|
});
|
|
49
49
|
}
|
|
50
50
|
return result;
|
|
@@ -65,7 +65,7 @@ export default {
|
|
|
65
65
|
getEmptyValue() {
|
|
66
66
|
return {
|
|
67
67
|
metaType: 'area',
|
|
68
|
-
_id:
|
|
68
|
+
_id: createId(),
|
|
69
69
|
items: []
|
|
70
70
|
};
|
|
71
71
|
},
|
|
@@ -3,7 +3,7 @@ import AposInputFollowingMixin from 'Modules/@apostrophecms/schema/mixins/AposIn
|
|
|
3
3
|
import AposInputConditionalFieldsMixin from 'Modules/@apostrophecms/schema/mixins/AposInputConditionalFieldsMixin';
|
|
4
4
|
import { getConditionTypesObject } from 'Modules/@apostrophecms/schema/lib/conditionalFields';
|
|
5
5
|
|
|
6
|
-
import
|
|
6
|
+
import { createId } from '@paralleldrive/cuid2';
|
|
7
7
|
import { klona } from 'klona';
|
|
8
8
|
import { get } from 'lodash';
|
|
9
9
|
import { Sortable } from 'sortablejs-vue3';
|
|
@@ -45,7 +45,7 @@ export default {
|
|
|
45
45
|
return alwaysExpand(this.field, this.schema);
|
|
46
46
|
},
|
|
47
47
|
listId() {
|
|
48
|
-
return `sortableList-${
|
|
48
|
+
return `sortableList-${createId()}`;
|
|
49
49
|
},
|
|
50
50
|
dragOptions() {
|
|
51
51
|
return {
|
|
@@ -72,9 +72,9 @@ export default {
|
|
|
72
72
|
const error = this.error || this.serverError;
|
|
73
73
|
// Server-side errors behave differently
|
|
74
74
|
const name = error?.name || error;
|
|
75
|
-
if (name === 'invalid') {
|
|
76
|
-
//
|
|
77
|
-
// don't confuse the user
|
|
75
|
+
if (name === 'invalid' && !this.serverError) {
|
|
76
|
+
// Not always due to a subproperty which will display its own error,
|
|
77
|
+
// don't confuse the user if so
|
|
78
78
|
return false;
|
|
79
79
|
}
|
|
80
80
|
return error;
|
|
@@ -222,7 +222,7 @@ export default {
|
|
|
222
222
|
delete this.itemsConditionalFields[_id];
|
|
223
223
|
},
|
|
224
224
|
add() {
|
|
225
|
-
const _id =
|
|
225
|
+
const _id = createId();
|
|
226
226
|
this.items.push({
|
|
227
227
|
_id,
|
|
228
228
|
schemaInput: {
|
|
@@ -280,7 +280,7 @@ function modelItems(items, field, schema) {
|
|
|
280
280
|
return items.map(item => {
|
|
281
281
|
const open = alwaysExpand(field, schema);
|
|
282
282
|
return {
|
|
283
|
-
_id: item._id ||
|
|
283
|
+
_id: item._id || createId(),
|
|
284
284
|
schemaInput: {
|
|
285
285
|
data: item || {}
|
|
286
286
|
},
|
|
@@ -67,6 +67,17 @@ export default {
|
|
|
67
67
|
},
|
|
68
68
|
currentDocMeta() {
|
|
69
69
|
return this.objectMeta.aposMeta || {};
|
|
70
|
+
},
|
|
71
|
+
currentDocServerErrors() {
|
|
72
|
+
let serverErrors = null;
|
|
73
|
+
(this.serverError?.data?.errors || [])
|
|
74
|
+
.forEach(error => {
|
|
75
|
+
if (error.path) {
|
|
76
|
+
serverErrors = serverErrors || {};
|
|
77
|
+
serverErrors[error.path] = error;
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
return serverErrors;
|
|
70
81
|
}
|
|
71
82
|
},
|
|
72
83
|
watch: {
|