apostrophe 3.43.0 → 3.45.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 +56 -0
- package/force-deploy +1 -0
- package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposContextBar.vue +12 -6
- package/modules/@apostrophecms/doc-type/index.js +10 -0
- package/modules/@apostrophecms/doc-type/ui/apos/components/AposDocContextMenu.vue +17 -3
- package/modules/@apostrophecms/doc-type/ui/apos/components/AposDocEditor.vue +37 -6
- package/modules/@apostrophecms/i18n/i18n/de.json +1 -0
- package/modules/@apostrophecms/i18n/i18n/en.json +5 -0
- package/modules/@apostrophecms/i18n/i18n/es.json +1 -0
- package/modules/@apostrophecms/i18n/i18n/fr.json +1 -0
- package/modules/@apostrophecms/i18n/i18n/pt-BR.json +1 -0
- package/modules/@apostrophecms/i18n/i18n/sk.json +1 -0
- package/modules/@apostrophecms/i18n/index.js +3 -0
- package/modules/@apostrophecms/i18n/ui/apos/components/AposI18nLocalize.vue +25 -13
- package/modules/@apostrophecms/image/ui/apos/components/AposMediaManagerEditor.vue +1 -1
- package/modules/@apostrophecms/modal/ui/apos/apps/AposModals.js +33 -0
- package/modules/@apostrophecms/modal/ui/apos/components/AposModal.vue +1 -0
- package/modules/@apostrophecms/modal/ui/apos/components/TheAposModals.vue +3 -1
- package/modules/@apostrophecms/modal/ui/apos/mixins/AposEditorMixin.js +8 -4
- package/modules/@apostrophecms/modal/ui/apos/mixins/AposModalTabsMixin.js +3 -2
- package/modules/@apostrophecms/module/index.js +11 -0
- package/modules/@apostrophecms/page/index.js +13 -5
- package/modules/@apostrophecms/piece-type/index.js +18 -7
- package/modules/@apostrophecms/piece-type/ui/apos/components/AposDocsManagerDisplay.vue +3 -3
- package/modules/@apostrophecms/rich-text-widget/index.js +30 -5
- package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposImageControlDialog.vue +237 -0
- package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposRichTextWidgetEditor.vue +184 -23
- package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapImage.vue +11 -206
- package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapLink.vue +5 -2
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputArray.vue +1 -0
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputCheckboxes.vue +27 -3
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputRelationship.vue +20 -2
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputSelect.vue +0 -18
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputSlug.vue +37 -18
- package/modules/@apostrophecms/schema/ui/apos/components/AposSearchList.vue +15 -1
- package/modules/@apostrophecms/schema/ui/apos/lib/detectChange.js +1 -1
- package/modules/@apostrophecms/schema/ui/apos/mixins/AposInputChoicesMixin.js +21 -0
- package/modules/@apostrophecms/ui/ui/apos/components/AposCombo.vue +381 -0
- package/modules/@apostrophecms/ui/ui/apos/lib/click-outside-element.js +17 -0
- package/modules/@apostrophecms/ui/ui/apos/lib/vue.js +2 -2
- package/modules/@apostrophecms/ui/ui/apos/scss/global/import-all.scss +1 -1
- package/modules/@apostrophecms/widget-type/ui/apos/components/AposWidgetEditor.vue +23 -3
- package/package.json +3 -2
- package/test/pieces-public-api.js +32 -0
- package/test/pieces.js +16 -48
- package/test-lib/util.js +52 -15
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,61 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.45.0 (2023-04-27)
|
|
4
|
+
|
|
5
|
+
### Adds
|
|
6
|
+
|
|
7
|
+
* Rich text widgets now support the `insert` option, an array
|
|
8
|
+
which currently may contain the strings `image` and `table` in order to add a
|
|
9
|
+
convenient "insert menu" that pops up when the slash key is pressed.
|
|
10
|
+
This provides a better user experience for rich text features that shouldn't
|
|
11
|
+
require that the user select existing text before using them.
|
|
12
|
+
* Auto expand inline array width if needed using `width: max-content` in the admin UI.
|
|
13
|
+
* The "browse" button is now available when selecting pages and pieces
|
|
14
|
+
to link to in the rich text editor.
|
|
15
|
+
* The "browse" button is also available when selecting inline images
|
|
16
|
+
in the rich text editor.
|
|
17
|
+
* Images are now previewed in the relationship field's compact list view.
|
|
18
|
+
* The new `apos-refreshing` Apostrophe bus event can be used to prevent
|
|
19
|
+
Apostrophe from refreshing the main content zone of the page when images
|
|
20
|
+
and pieces are edited, by clearing the `refresh` property of the object
|
|
21
|
+
passed to the event.
|
|
22
|
+
* To facilitate custom click handlers, an `apos.modal.onTopOf(el1, el2)` function is now
|
|
23
|
+
available to check whether an element is considered to be "on top of" another element in
|
|
24
|
+
the modal stack.
|
|
25
|
+
|
|
26
|
+
### Changes
|
|
27
|
+
|
|
28
|
+
* The `v-click-outside-element` Vue directive now understands that modals "on top of"
|
|
29
|
+
an element should be considered to be "inside" the element, e.g. clicks on them
|
|
30
|
+
shouldn't close the link dialog etc.
|
|
31
|
+
|
|
32
|
+
### Fixes
|
|
33
|
+
|
|
34
|
+
* Rich text widgets save more reliably when many actions are taken quickly just before save.
|
|
35
|
+
|
|
36
|
+
## 3.44.0 (2023-04-13)
|
|
37
|
+
|
|
38
|
+
### Adds
|
|
39
|
+
|
|
40
|
+
* `checkboxes` fields now support a new `style: 'combobox'` option for a better multiple-select experience when there
|
|
41
|
+
are many choices.
|
|
42
|
+
* If the new `guestApiAccess` option is set to `true` for a piece type or for `@apostrophecms/page`,
|
|
43
|
+
Apostrophe will allow all logged-in users to access the GET-method REST APIs of that
|
|
44
|
+
module, not just users with editing privileges, even if `publicApiProjection` is not set.
|
|
45
|
+
This is useful when the goal is to allow REST API access to "guest" users who have
|
|
46
|
+
project-specific reasons to fetch access content via REST APIs.
|
|
47
|
+
* `test-lib/utils.js` has new `createUser` and `loginAs` methods for the convenience of
|
|
48
|
+
those writing mocha tests of Apostrophe modules.
|
|
49
|
+
* `batchOperations` permissions: if a `permission` property is added to any entry in the `batchOperations` cascade of a piece-type module, this permission will be checked for every user. See `batchOperations` configuration in `modules/@apostrophecms/piece-type/index.js`. The check function `checkBatchOperationsPermissions` can be extended. Please note that this permission is checked only to determine whether to offer the operation.
|
|
50
|
+
|
|
51
|
+
### Fixes
|
|
52
|
+
* Fix child page slug when title is deleted
|
|
53
|
+
|
|
54
|
+
### Fixes
|
|
55
|
+
|
|
56
|
+
* Fix various issues on conditional fields that were occurring when adding new widgets with default values or selecting a falsy value in a field that has a conditional field relying on it.
|
|
57
|
+
Populate new or existing doc instances with default values and add an empty `null` choice to select fields that do not have a default value (required or not) and to the ones configured with dynamic choices.
|
|
58
|
+
|
|
3
59
|
## 3.43.0 (2023-03-29)
|
|
4
60
|
|
|
5
61
|
### Adds
|
package/force-deploy
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
4
|
|
@@ -79,10 +79,11 @@ export default {
|
|
|
79
79
|
},
|
|
80
80
|
computed: {
|
|
81
81
|
contextBarActive() {
|
|
82
|
-
return window.apos.adminBar.contextBar && this.canEdit;
|
|
82
|
+
return window.apos.adminBar.contextBar && (this.canEdit || this.moduleOptions.canLocalize);
|
|
83
83
|
},
|
|
84
84
|
canEdit() {
|
|
85
|
-
return this.context._edit || ((this.context.aposLocale && this.context.aposLocale.endsWith(':published')) &&
|
|
85
|
+
return this.context._edit || ((this.context.aposLocale && this.context.aposLocale.endsWith(':published')) &&
|
|
86
|
+
this.draftIsEditable);
|
|
86
87
|
},
|
|
87
88
|
classes() {
|
|
88
89
|
if (!this.contextBarActive) {
|
|
@@ -468,7 +469,6 @@ export default {
|
|
|
468
469
|
}
|
|
469
470
|
},
|
|
470
471
|
async onContentChanged(e) {
|
|
471
|
-
|
|
472
472
|
if (
|
|
473
473
|
(e.doc && (e.doc._id === this.context._id)) ||
|
|
474
474
|
(e.docIds && e.docIds.includes(this.context._id))
|
|
@@ -484,9 +484,15 @@ export default {
|
|
|
484
484
|
});
|
|
485
485
|
}
|
|
486
486
|
}
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
}
|
|
487
|
+
const refreshOptions = {
|
|
488
|
+
refresh: true
|
|
489
|
+
};
|
|
490
|
+
apos.bus.$emit('apos-refreshing', refreshOptions);
|
|
491
|
+
if (refreshOptions.refresh) {
|
|
492
|
+
await this.refresh({
|
|
493
|
+
scrollcheck: e.action === 'history'
|
|
494
|
+
});
|
|
495
|
+
}
|
|
490
496
|
},
|
|
491
497
|
async switchEditMode(editing) {
|
|
492
498
|
this.editMode = editing;
|
|
@@ -763,6 +763,11 @@ module.exports = {
|
|
|
763
763
|
async findOneForCopying(req, criteria) {
|
|
764
764
|
return self.findOneForEditing(req, criteria);
|
|
765
765
|
},
|
|
766
|
+
// Identical to findOneForEditing by default, but could be
|
|
767
|
+
// overridden usefully in subclasses.
|
|
768
|
+
async findOneForLocalizing(req, criteria) {
|
|
769
|
+
return self.findOneForEditing(req, criteria);
|
|
770
|
+
},
|
|
766
771
|
// Submit the current draft for review. The identity
|
|
767
772
|
// of `req.user` is associated with the submission.
|
|
768
773
|
// Returns the `submitted` object, with `by`, `byId`,
|
|
@@ -1424,8 +1429,13 @@ module.exports = {
|
|
|
1424
1429
|
label,
|
|
1425
1430
|
pluralLabel,
|
|
1426
1431
|
relatedDocument: self.options.relatedDocument,
|
|
1432
|
+
canEdit: self.apos.permission.can(req, 'edit', self.name, 'draft'),
|
|
1427
1433
|
canPublish: self.apos.permission.can(req, 'publish', self.name)
|
|
1428
1434
|
};
|
|
1435
|
+
browserOptions.canLocalize = browserOptions.canEdit &&
|
|
1436
|
+
self.options.localized &&
|
|
1437
|
+
Object.keys(self.apos.i18n.locales).length > 1 &&
|
|
1438
|
+
Object.values(self.apos.i18n.locales).some(locale => locale._edit);
|
|
1429
1439
|
browserOptions.action = self.action;
|
|
1430
1440
|
browserOptions.schema = self.allowedSchema(req);
|
|
1431
1441
|
browserOptions.localized = self.isLocalized();
|
|
@@ -181,6 +181,10 @@ export default {
|
|
|
181
181
|
return menu;
|
|
182
182
|
},
|
|
183
183
|
customMenusByContext() {
|
|
184
|
+
if (!this.canEdit) {
|
|
185
|
+
return [];
|
|
186
|
+
}
|
|
187
|
+
|
|
184
188
|
const menus = this.customOperationsByContext
|
|
185
189
|
.map(op => ({
|
|
186
190
|
label: op.label,
|
|
@@ -233,7 +237,7 @@ export default {
|
|
|
233
237
|
}
|
|
234
238
|
},
|
|
235
239
|
canDismissSubmission() {
|
|
236
|
-
return this.context.submitted && (this.canPublish || (this.context.submitted.byId === apos.login.user._id));
|
|
240
|
+
return this.canEdit && this.context.submitted && (this.canPublish || (this.context.submitted.byId === apos.login.user._id));
|
|
237
241
|
},
|
|
238
242
|
canDiscardDraft() {
|
|
239
243
|
if (!this.manuallyPublished) {
|
|
@@ -242,6 +246,9 @@ export default {
|
|
|
242
246
|
if (!this.context._id) {
|
|
243
247
|
return false;
|
|
244
248
|
}
|
|
249
|
+
if (!this.canEdit) {
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
245
252
|
return (
|
|
246
253
|
(!this.context.lastPublishedAt) &&
|
|
247
254
|
!this.moduleOptions.singleton
|
|
@@ -251,10 +258,12 @@ export default {
|
|
|
251
258
|
);
|
|
252
259
|
},
|
|
253
260
|
canLocalize() {
|
|
254
|
-
return
|
|
261
|
+
return this.moduleOptions.canLocalize &&
|
|
262
|
+
this.context._id;
|
|
255
263
|
},
|
|
256
264
|
canArchive() {
|
|
257
265
|
return (
|
|
266
|
+
this.canEdit &&
|
|
258
267
|
this.context._id &&
|
|
259
268
|
!this.moduleOptions.singleton &&
|
|
260
269
|
!this.context.archived &&
|
|
@@ -264,6 +273,7 @@ export default {
|
|
|
264
273
|
},
|
|
265
274
|
canUnpublish() {
|
|
266
275
|
return (
|
|
276
|
+
this.canEdit &&
|
|
267
277
|
!this.context.parked &&
|
|
268
278
|
this.moduleOptions.canPublish &&
|
|
269
279
|
this.context.lastPublishedAt &&
|
|
@@ -271,10 +281,14 @@ export default {
|
|
|
271
281
|
);
|
|
272
282
|
},
|
|
273
283
|
canCopy() {
|
|
274
|
-
return this.canEdit &&
|
|
284
|
+
return this.canEdit &&
|
|
285
|
+
this.moduleOptions.canEdit &&
|
|
286
|
+
!this.moduleOptions.singleton &&
|
|
287
|
+
this.context._id;
|
|
275
288
|
},
|
|
276
289
|
canRestore() {
|
|
277
290
|
return (
|
|
291
|
+
this.canEdit &&
|
|
278
292
|
this.context._id &&
|
|
279
293
|
this.context.archived &&
|
|
280
294
|
((this.moduleOptions.canPublish && this.context.lastPublishedAt) || !this.manuallyPublished)
|
|
@@ -162,6 +162,7 @@ export default {
|
|
|
162
162
|
ref: null
|
|
163
163
|
},
|
|
164
164
|
published: null,
|
|
165
|
+
readOnly: false,
|
|
165
166
|
restoreOnly: false,
|
|
166
167
|
saveMenu: null,
|
|
167
168
|
generation: 0
|
|
@@ -174,14 +175,24 @@ export default {
|
|
|
174
175
|
followingUtils() {
|
|
175
176
|
return this.followingValues('utility');
|
|
176
177
|
},
|
|
178
|
+
canEdit() {
|
|
179
|
+
if (this.original && this.original._id) {
|
|
180
|
+
return this.original._edit || this.moduleOptions.canEdit;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return this.moduleOptions.canEdit;
|
|
184
|
+
},
|
|
177
185
|
canPublish() {
|
|
178
186
|
if (this.original && this.original._id) {
|
|
179
|
-
return this.original._publish;
|
|
187
|
+
return this.original._publish || this.moduleOptions.canPublish;
|
|
180
188
|
}
|
|
181
189
|
|
|
182
190
|
return this.moduleOptions.canPublish;
|
|
183
191
|
},
|
|
184
192
|
saveDisabled() {
|
|
193
|
+
if (!this.canEdit) {
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
185
196
|
if (this.restoreOnly) {
|
|
186
197
|
// Can always restore if it's a read-only view of the archive
|
|
187
198
|
return false;
|
|
@@ -421,10 +432,6 @@ export default {
|
|
|
421
432
|
async loadDoc() {
|
|
422
433
|
let docData;
|
|
423
434
|
try {
|
|
424
|
-
if (!await this.lock(this.getOnePath, this.docId)) {
|
|
425
|
-
await this.lockNotAvailable();
|
|
426
|
-
return;
|
|
427
|
-
}
|
|
428
435
|
docData = await apos.http.get(this.getOnePath, {
|
|
429
436
|
busy: true,
|
|
430
437
|
qs: {
|
|
@@ -438,6 +445,12 @@ export default {
|
|
|
438
445
|
} else {
|
|
439
446
|
this.restoreOnly = false;
|
|
440
447
|
}
|
|
448
|
+
const canEdit = docData._edit || this.moduleOptions.canEdit;
|
|
449
|
+
this.readOnly = canEdit === false;
|
|
450
|
+
if (canEdit && !await this.lock(this.getOnePath, this.docId)) {
|
|
451
|
+
await this.lockNotAvailable();
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
441
454
|
} catch {
|
|
442
455
|
await apos.notify('apostrophe:loadDocFailed', {
|
|
443
456
|
type: 'warning',
|
|
@@ -451,7 +464,10 @@ export default {
|
|
|
451
464
|
this.docType = docData.type;
|
|
452
465
|
}
|
|
453
466
|
this.original = klona(docData);
|
|
454
|
-
this.docFields.data =
|
|
467
|
+
this.docFields.data = {
|
|
468
|
+
...this.getDefault(),
|
|
469
|
+
...docData
|
|
470
|
+
};
|
|
455
471
|
if (this.published) {
|
|
456
472
|
this.changed = detectDocChange(this.schema, this.original, this.published, { differences: true });
|
|
457
473
|
}
|
|
@@ -460,6 +476,21 @@ export default {
|
|
|
460
476
|
}
|
|
461
477
|
}
|
|
462
478
|
},
|
|
479
|
+
getDefault() {
|
|
480
|
+
const doc = {};
|
|
481
|
+
this.schema.forEach(field => {
|
|
482
|
+
if (field.name.startsWith('_')) {
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
// Using `hasOwn` here, not simply checking if `field.def` is truthy
|
|
486
|
+
// so that `false`, `null`, `''` or `0` are taken into account:
|
|
487
|
+
const hasDefaultValue = Object.hasOwn(field, 'def');
|
|
488
|
+
doc[field.name] = hasDefaultValue
|
|
489
|
+
? klona(field.def)
|
|
490
|
+
: null;
|
|
491
|
+
});
|
|
492
|
+
return doc;
|
|
493
|
+
},
|
|
463
494
|
async preview() {
|
|
464
495
|
if (!await this.confirmAndCancel()) {
|
|
465
496
|
return;
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
"addWidgetType": "{{ label }} hinzufügen",
|
|
5
5
|
"admin": "Administrator",
|
|
6
6
|
"affirmativeLabel": "Ja, fortsetzen.",
|
|
7
|
+
"allSelected": "Alle ausgewählt",
|
|
7
8
|
"altText": "Alternativtext",
|
|
8
9
|
"altTextHelp": "Bildbeschreibung oder alternativer Text, der für Bildschirmleser verwendet wird.",
|
|
9
10
|
"any": "Irgendwas",
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"addWidgetType": "Add {{ label }}",
|
|
10
10
|
"admin": "Admin",
|
|
11
11
|
"affirmativeLabel": "Yes, continue.",
|
|
12
|
+
"allSelected": "All Selected",
|
|
12
13
|
"altText": "Alt Text",
|
|
13
14
|
"altTextHelp": "Image description used for accessibility",
|
|
14
15
|
"anchorId": "Anchor ID",
|
|
@@ -192,6 +193,7 @@
|
|
|
192
193
|
"hideInNavigation": "Hide in Navigation",
|
|
193
194
|
"home": "Home",
|
|
194
195
|
"image": "Image",
|
|
196
|
+
"imageDescription": "Add an inline image",
|
|
195
197
|
"imageFile": "Image File",
|
|
196
198
|
"imagePlaceholder": "Image placeholder",
|
|
197
199
|
"imageTag": "Image Tag",
|
|
@@ -374,11 +376,13 @@
|
|
|
374
376
|
"richTextH4": "Heading 4 (H4)",
|
|
375
377
|
"richTextHighlight": "Mark",
|
|
376
378
|
"richTextHorizontalRule": "Horizontal Rule",
|
|
379
|
+
"richTextInsertMenuHeading": "Insert...",
|
|
377
380
|
"richTextItalic": "Italic",
|
|
378
381
|
"richTextLink": "Link",
|
|
379
382
|
"richTextOrderedList": "Ordered List",
|
|
380
383
|
"richTextParagraph": "Paragraph (P)",
|
|
381
384
|
"richTextPlaceholder": "Start Typing Here...",
|
|
385
|
+
"richTextPlaceholderWithInsertMenu": "Start Typing Here or Press /...",
|
|
382
386
|
"richTextRedo": "Redo",
|
|
383
387
|
"richTextStrikethrough": "Strike",
|
|
384
388
|
"richTextStyleConfigWarning": "Misconfigured rich text style: label: {{ label }}, {{ tag }}",
|
|
@@ -437,6 +441,7 @@
|
|
|
437
441
|
"superscript": "Superscript",
|
|
438
442
|
"switchLocalesAndLocalizePage": "Switch locales and localize page to {{ label }}?",
|
|
439
443
|
"table": "Table",
|
|
444
|
+
"tableDescription": "Add tabular content to your page",
|
|
440
445
|
"tagYourImages": "Tag your images to make searching and filtering the media manager easier",
|
|
441
446
|
"tags": "Tags",
|
|
442
447
|
"takeActionAndCreateNew": "{{ saveLabel }} and Create New",
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
"addItem": "Ajouter un élément",
|
|
4
4
|
"addWidgetType": "Ajouter {{ label }}",
|
|
5
5
|
"affirmativeLabel": "Oui, continuer.",
|
|
6
|
+
"allSelected": "Tout Selectionné",
|
|
6
7
|
"altText": "Texte alternatif",
|
|
7
8
|
"altTextHelp": "Description d'image utilisée pour l'accessibilité",
|
|
8
9
|
"any": "Quelconque",
|
|
@@ -278,7 +278,8 @@ export default {
|
|
|
278
278
|
([ locale, options ]) => {
|
|
279
279
|
return {
|
|
280
280
|
name: locale,
|
|
281
|
-
label: options.label || locale
|
|
281
|
+
label: options.label || locale,
|
|
282
|
+
_edit: options._edit
|
|
282
283
|
};
|
|
283
284
|
}
|
|
284
285
|
),
|
|
@@ -382,12 +383,12 @@ export default {
|
|
|
382
383
|
: apos.modules[this.doc.type].action;
|
|
383
384
|
},
|
|
384
385
|
filteredLocales() {
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
.includes(this.wizard.sections.selectLocales.filter.toLowerCase());
|
|
386
|
+
const matches = term =>
|
|
387
|
+
term
|
|
388
|
+
.toLowerCase()
|
|
389
|
+
.includes(this.wizard.sections.selectLocales.filter.toLowerCase());
|
|
390
390
|
|
|
391
|
+
return this.locales.filter(({ name, label }) => {
|
|
391
392
|
return matches(name) || matches(label);
|
|
392
393
|
});
|
|
393
394
|
},
|
|
@@ -395,7 +396,7 @@ export default {
|
|
|
395
396
|
return this.wizard.values.toLocales.data;
|
|
396
397
|
},
|
|
397
398
|
allSelected() {
|
|
398
|
-
return this.selectedLocales.length === this.locales.filter(locale => !this.isCurrentLocale(locale)).length;
|
|
399
|
+
return this.selectedLocales.length === this.locales.filter(locale => !this.isCurrentLocale(locale) && this.canEditLocale(locale)).length;
|
|
399
400
|
},
|
|
400
401
|
relatedDocTypes() {
|
|
401
402
|
const types = {};
|
|
@@ -532,6 +533,9 @@ export default {
|
|
|
532
533
|
isCurrentLocale(locale) {
|
|
533
534
|
return window.apos.i18n.locale === locale.name;
|
|
534
535
|
},
|
|
536
|
+
canEditLocale(locale) {
|
|
537
|
+
return !!locale._edit;
|
|
538
|
+
},
|
|
535
539
|
isSelected(locale) {
|
|
536
540
|
return this.wizard.values.toLocales.data.some(
|
|
537
541
|
({ name }) => name === locale.name
|
|
@@ -541,13 +545,13 @@ export default {
|
|
|
541
545
|
return !!this.localized[locale.name];
|
|
542
546
|
},
|
|
543
547
|
selectAll() {
|
|
544
|
-
this.wizard.values.toLocales.data = this.locales.filter(locale => !this.isCurrentLocale(locale));
|
|
548
|
+
this.wizard.values.toLocales.data = this.locales.filter(locale => !this.isCurrentLocale(locale) && this.canEditLocale(locale));
|
|
545
549
|
},
|
|
546
550
|
deselectAll() {
|
|
547
551
|
this.wizard.values.toLocales.data = [];
|
|
548
552
|
},
|
|
549
553
|
toggleLocale(locale) {
|
|
550
|
-
if (!this.isSelected(locale) && !this.isCurrentLocale(locale)) {
|
|
554
|
+
if (!this.isSelected(locale) && !this.isCurrentLocale(locale) && this.canEditLocale(locale)) {
|
|
551
555
|
this.wizard.values.toLocales.data.push(locale);
|
|
552
556
|
} else if (this.isSelected(locale)) {
|
|
553
557
|
this.wizard.values.toLocales.data = this.wizard.values.toLocales.data.filter(l => l !== locale);
|
|
@@ -590,6 +594,9 @@ export default {
|
|
|
590
594
|
if (this.isCurrentLocale(locale)) {
|
|
591
595
|
classes['apos-current-locale'] = true;
|
|
592
596
|
}
|
|
597
|
+
if (!this.canEditLocale(locale)) {
|
|
598
|
+
classes['apos-disabled-locale'] = true;
|
|
599
|
+
}
|
|
593
600
|
return classes;
|
|
594
601
|
},
|
|
595
602
|
// Singular type name for label (returns an i18next key)
|
|
@@ -948,15 +955,18 @@ export default {
|
|
|
948
955
|
line-height: 1;
|
|
949
956
|
border-radius: var(--a-border-radius);
|
|
950
957
|
|
|
951
|
-
&:not(.apos-current-locale)
|
|
958
|
+
&:not(.apos-current-locale),
|
|
959
|
+
&:not(.apos-disabled-locale) {
|
|
952
960
|
cursor: pointer;
|
|
953
961
|
}
|
|
954
962
|
|
|
955
|
-
&:not(.apos-current-locale):hover
|
|
963
|
+
&:not(.apos-current-locale):hover,
|
|
964
|
+
&:not(.apos-disabled-locale):hover {
|
|
956
965
|
background-color: var(--a-base-10);
|
|
957
966
|
}
|
|
958
967
|
|
|
959
|
-
&:not(.apos-current-locale):active
|
|
968
|
+
&:not(.apos-current-locale):active,
|
|
969
|
+
&:not(.apos-disabled-locale):active {
|
|
960
970
|
background-color: var(--a-base-9);
|
|
961
971
|
}
|
|
962
972
|
|
|
@@ -974,11 +984,13 @@ export default {
|
|
|
974
984
|
}
|
|
975
985
|
|
|
976
986
|
&.apos-current-locale,
|
|
987
|
+
&.apos-disabled-locale,
|
|
977
988
|
.apos-current-locale-icon {
|
|
978
989
|
color: var(--a-base-5);
|
|
979
990
|
}
|
|
980
991
|
|
|
981
|
-
&.apos-current-locale
|
|
992
|
+
&.apos-current-locale,
|
|
993
|
+
&.apos-disabled-locale {
|
|
982
994
|
font-style: italic;
|
|
983
995
|
}
|
|
984
996
|
|
|
@@ -158,7 +158,7 @@ export default {
|
|
|
158
158
|
return window.apos.modules[this.activeMedia.type] || {};
|
|
159
159
|
},
|
|
160
160
|
canLocalize() {
|
|
161
|
-
return
|
|
161
|
+
return this.moduleOptions.canLocalize && this.activeMedia._id;
|
|
162
162
|
},
|
|
163
163
|
moreMenu() {
|
|
164
164
|
const menu = [ {
|
|
@@ -31,6 +31,38 @@ export default function() {
|
|
|
31
31
|
},
|
|
32
32
|
getProperties(id) {
|
|
33
33
|
return this.$refs.modals.getProperties(id);
|
|
34
|
+
},
|
|
35
|
+
// Returns true if el1 is "on top of" el2 in the
|
|
36
|
+
// modal stack, as viewed by the user. If el1 is a
|
|
37
|
+
// modal that appears later in the stack than el2
|
|
38
|
+
// (visually stacked on top), this method returns true.
|
|
39
|
+
// If el2 is `document` and el1 is a modal, this
|
|
40
|
+
// method returns true. For convenenience, if el1
|
|
41
|
+
// or el2 is not a modal, it is treated as its DOM
|
|
42
|
+
// parent modal, or as `document`. If el1 has no
|
|
43
|
+
// parent modal this method always returns false.
|
|
44
|
+
onTopOf(el1, el2) {
|
|
45
|
+
if (!el1.matches('[data-apos-modal]')) {
|
|
46
|
+
el1 = el1.closest('[data-apos-modal]') || document;
|
|
47
|
+
}
|
|
48
|
+
if (!el2.matches('[data-apos-modal]')) {
|
|
49
|
+
el2 = el2.closest('[data-apos-modal]') || document;
|
|
50
|
+
}
|
|
51
|
+
if (el1 === document) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
if (el2 === document) {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
const index1 = apos.modal.stack.findIndex(modal => modal.$el === el1);
|
|
58
|
+
const index2 = apos.modal.stack.findIndex(modal => modal.$el === el2);
|
|
59
|
+
if (index1 === -1) {
|
|
60
|
+
throw new Error('apos.modal.onTopOf: el1 is not in the modal stack');
|
|
61
|
+
}
|
|
62
|
+
if (index2 === -1) {
|
|
63
|
+
throw new Error('apos.modal.onTopOf: el2 is not in the modal stack');
|
|
64
|
+
}
|
|
65
|
+
return index1 > index2;
|
|
34
66
|
}
|
|
35
67
|
},
|
|
36
68
|
render(h) {
|
|
@@ -45,6 +77,7 @@ export default function() {
|
|
|
45
77
|
apos.modal.execute = theAposModals.execute;
|
|
46
78
|
apos.modal.getAt = theAposModals.getAt;
|
|
47
79
|
apos.modal.getProperties = theAposModals.getProperties;
|
|
80
|
+
apos.modal.onTopOf = theAposModals.onTopOf;
|
|
48
81
|
apos.modal.stack = [];
|
|
49
82
|
apos.confirm = theAposModals.confirm;
|
|
50
83
|
apos.alert = theAposModals.alert;
|
|
@@ -24,6 +24,7 @@ export default {
|
|
|
24
24
|
},
|
|
25
25
|
serverErrors: null,
|
|
26
26
|
restoreOnly: false,
|
|
27
|
+
readOnly: false,
|
|
27
28
|
changed: [],
|
|
28
29
|
externalConditionsResults: {}
|
|
29
30
|
};
|
|
@@ -32,7 +33,7 @@ export default {
|
|
|
32
33
|
computed: {
|
|
33
34
|
schema() {
|
|
34
35
|
let schema = (this.moduleOptions.schema || []).filter(field => apos.schema.components.fields[field.type]);
|
|
35
|
-
if (this.restoreOnly) {
|
|
36
|
+
if (this.restoreOnly || this.readOnly) {
|
|
36
37
|
schema = klona(schema);
|
|
37
38
|
for (const field of schema) {
|
|
38
39
|
field.readOnly = true;
|
|
@@ -251,11 +252,14 @@ export default {
|
|
|
251
252
|
result = false;
|
|
252
253
|
break;
|
|
253
254
|
}
|
|
254
|
-
|
|
255
|
-
|
|
255
|
+
|
|
256
|
+
const fieldValue = self.getFieldValue(key);
|
|
257
|
+
|
|
258
|
+
if (Array.isArray(fieldValue)) {
|
|
259
|
+
result = fieldValue.includes(val);
|
|
256
260
|
break;
|
|
257
261
|
}
|
|
258
|
-
if (val !==
|
|
262
|
+
if (val !== fieldValue) {
|
|
259
263
|
result = false;
|
|
260
264
|
break;
|
|
261
265
|
}
|
|
@@ -802,6 +802,17 @@ module.exports = {
|
|
|
802
802
|
}
|
|
803
803
|
},
|
|
804
804
|
|
|
805
|
+
// Modules that have REST APIs use this method
|
|
806
|
+
// to determine if a request is qualified to access
|
|
807
|
+
// it without restriction to the `publicApiProjection`
|
|
808
|
+
canAccessApi(req) {
|
|
809
|
+
if (self.options.guestApiAccess) {
|
|
810
|
+
return !!req.user;
|
|
811
|
+
} else {
|
|
812
|
+
return self.apos.permission.can(req, 'view-draft');
|
|
813
|
+
}
|
|
814
|
+
},
|
|
815
|
+
|
|
805
816
|
// Merge in the event emitter / responder capabilities
|
|
806
817
|
...require('./lib/events.js')(self)
|
|
807
818
|
};
|