apostrophe 3.22.0 → 3.23.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 +17 -0
- package/modules/@apostrophecms/doc-type/index.js +101 -10
- package/modules/@apostrophecms/doc-type/ui/apos/components/AposDocContextMenu.vue +11 -7
- package/modules/@apostrophecms/doc-type/ui/apos/components/AposDocEditor.vue +8 -109
- package/modules/@apostrophecms/i18n/i18n/en.json +7 -1
- package/modules/@apostrophecms/i18n/i18n/es.json +7 -1
- package/modules/@apostrophecms/i18n/i18n/fr.json +7 -1
- package/modules/@apostrophecms/i18n/i18n/pt-BR.json +7 -1
- package/modules/@apostrophecms/i18n/i18n/sk.json +7 -1
- package/modules/@apostrophecms/image/ui/apos/components/AposMediaManager.vue +3 -1
- package/modules/@apostrophecms/image/ui/apos/components/AposMediaManagerEditor.vue +37 -2
- package/modules/@apostrophecms/login/index.js +10 -0
- package/modules/@apostrophecms/modal/ui/apos/components/AposModalShareDraft.vue +323 -0
- package/modules/@apostrophecms/modal/ui/apos/mixins/AposDocErrorsMixin.js +79 -0
- package/modules/@apostrophecms/modal/ui/apos/mixins/AposEditorMixin.js +2 -1
- package/modules/@apostrophecms/modal/ui/apos/mixins/AposModalTabsMixin.js +58 -0
- package/modules/@apostrophecms/module/index.js +11 -0
- package/modules/@apostrophecms/page/index.js +39 -5
- package/modules/@apostrophecms/permission/index.js +26 -1
- package/modules/@apostrophecms/piece-type/index.js +22 -0
- package/modules/@apostrophecms/piece-type/ui/apos/components/AposRelationshipEditor.vue +53 -10
- package/modules/@apostrophecms/soft-redirect/index.js +10 -1
- package/modules/@apostrophecms/template/index.js +0 -1
- package/package.json +9 -9
- package/test/docs.js +4 -4
- package/test/modules/test-page/views/page.html +10 -5
- package/test/pages.js +146 -0
- package/test/pieces.js +150 -0
- package/test-lib/util.js +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.23.0 (2022-06-22)
|
|
4
|
+
|
|
5
|
+
### Adds
|
|
6
|
+
|
|
7
|
+
* Shared Drafts: gives the possibility to share a link which can be used to preview the draft version of page, or a piece `show` page.
|
|
8
|
+
* Add `Localize` option to `@apostrophecms/image`. In Edit mode the context bar menu includes a "Localize" option to start cloning this image into other locales.
|
|
9
|
+
|
|
10
|
+
### Fixes
|
|
11
|
+
|
|
12
|
+
* Update `sass` to [`1.52.3`+](https://github.com/sass/dart-sass/pull/1713) to prevent the error `RangeError: Invalid value: Not in inclusive range 0..145: -1`. You can now fix that by upgrading with `npm update`. If it does not immediately clear up the issue in development, try `node app @apostrophecms/asset:clear-cache`.
|
|
13
|
+
* Fix a potential issue when URLs have a query string, in the `'@apostrophecms/page:notFound'` handler of the `soft-redirect` module.
|
|
14
|
+
|
|
15
|
+
## 3.22.1 (2022-06-17)
|
|
16
|
+
|
|
17
|
+
* Hotfix: temporarily pin versions of tiptap modules to work around packaging error that breaks import of the most recent releases. We will unpin as soon as this is fixed upstream. Fixes a bug where `npm update` would fail for A3 projects.
|
|
18
|
+
|
|
3
19
|
## 3.22.0 (2022-06-08)
|
|
4
20
|
|
|
5
21
|
### Adds
|
|
@@ -30,6 +46,7 @@
|
|
|
30
46
|
* Trigger only the relevant build when in a watch mode (development). The build paths should not contain comma (`,`).
|
|
31
47
|
* Adds an `unpublish` method, available for any doc-type.
|
|
32
48
|
An _Unpublish_ option has also been added to the context menu of the modal when editing a piece or a page.
|
|
49
|
+
* Allows developers to group fields in relationships the same way it's done for normal schemas.
|
|
33
50
|
|
|
34
51
|
### Fixes
|
|
35
52
|
|
|
@@ -91,6 +91,7 @@ module.exports = {
|
|
|
91
91
|
self.composeSchema();
|
|
92
92
|
self.apos.doc.setManager(self.name, self);
|
|
93
93
|
self.enableBrowserData();
|
|
94
|
+
self.addContextMenu();
|
|
94
95
|
},
|
|
95
96
|
handlers(self) {
|
|
96
97
|
return {
|
|
@@ -281,6 +282,16 @@ module.exports = {
|
|
|
281
282
|
|
|
282
283
|
methods(self) {
|
|
283
284
|
return {
|
|
285
|
+
addContextMenu() {
|
|
286
|
+
self.apos.doc.addContextOperation(self.__meta.name, {
|
|
287
|
+
action: 'shareDraft',
|
|
288
|
+
context: 'update',
|
|
289
|
+
label: 'apostrophe:shareDraft',
|
|
290
|
+
modal: 'AposModalShareDraft',
|
|
291
|
+
manuallyPublished: true,
|
|
292
|
+
hasUrl: true
|
|
293
|
+
});
|
|
294
|
+
},
|
|
284
295
|
getRelatedDocsIds(req, doc) {
|
|
285
296
|
const relatedDocsIds = [];
|
|
286
297
|
const handlers = {
|
|
@@ -1199,6 +1210,54 @@ module.exports = {
|
|
|
1199
1210
|
delete $set[name];
|
|
1200
1211
|
}
|
|
1201
1212
|
}
|
|
1213
|
+
},
|
|
1214
|
+
|
|
1215
|
+
async share(req, doc) {
|
|
1216
|
+
if (doc._edit !== true) {
|
|
1217
|
+
throw self.apos.error('notfound');
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
if (!doc._url) {
|
|
1221
|
+
return doc;
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
const { aposShareKey: _aposShareKey, ...draft } = doc;
|
|
1225
|
+
const aposShareKey = doc.aposShareKey || self.apos.util.generateId();
|
|
1226
|
+
|
|
1227
|
+
await self.apos.doc.db.updateOne({
|
|
1228
|
+
_id: doc._id
|
|
1229
|
+
}, {
|
|
1230
|
+
$set: {
|
|
1231
|
+
aposShareKey
|
|
1232
|
+
}
|
|
1233
|
+
});
|
|
1234
|
+
|
|
1235
|
+
return {
|
|
1236
|
+
...draft,
|
|
1237
|
+
aposShareKey
|
|
1238
|
+
};
|
|
1239
|
+
},
|
|
1240
|
+
|
|
1241
|
+
async unshare(req, doc) {
|
|
1242
|
+
if (doc._edit !== true) {
|
|
1243
|
+
throw self.apos.error('notfound');
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
if (!doc._url) {
|
|
1247
|
+
return doc;
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
const { aposShareKey: _aposShareKey, ...draft } = doc;
|
|
1251
|
+
|
|
1252
|
+
await self.apos.doc.db.updateOne({
|
|
1253
|
+
_id: doc._id
|
|
1254
|
+
}, {
|
|
1255
|
+
$unset: {
|
|
1256
|
+
aposShareKey: 1
|
|
1257
|
+
}
|
|
1258
|
+
});
|
|
1259
|
+
|
|
1260
|
+
return draft;
|
|
1202
1261
|
}
|
|
1203
1262
|
};
|
|
1204
1263
|
},
|
|
@@ -1232,6 +1291,28 @@ module.exports = {
|
|
|
1232
1291
|
queries(self, query) {
|
|
1233
1292
|
return {
|
|
1234
1293
|
builders: {
|
|
1294
|
+
transformDraftForSharing: {
|
|
1295
|
+
after(results) {
|
|
1296
|
+
if (!self.isShareDraftRequest(query.req)) {
|
|
1297
|
+
return;
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
const { aposShareId, aposShareKey } = query.req.query;
|
|
1301
|
+
|
|
1302
|
+
// Change drafts values to make it pass for a published document
|
|
1303
|
+
results.forEach(transformDraftToPublished);
|
|
1304
|
+
|
|
1305
|
+
function transformDraftToPublished (result) {
|
|
1306
|
+
if (result._id === aposShareId && result.aposShareKey === aposShareKey) {
|
|
1307
|
+
const changeToPublished = string => string.replace(':draft', ':published');
|
|
1308
|
+
|
|
1309
|
+
result._id = changeToPublished(result._id);
|
|
1310
|
+
result.aposLocale = changeToPublished(result.aposLocale);
|
|
1311
|
+
result.aposMode = 'published';
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
},
|
|
1235
1316
|
// `.criteria({...})` Sets the MongoDB criteria, discarding
|
|
1236
1317
|
// criteria previously added using this
|
|
1237
1318
|
// method or the `and` method. For this reason,
|
|
@@ -2061,16 +2142,26 @@ module.exports = {
|
|
|
2061
2142
|
queryLocale = `${query.req.locale}:${query.req.mode}`;
|
|
2062
2143
|
}
|
|
2063
2144
|
if (queryLocale) {
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2145
|
+
const $or = [
|
|
2146
|
+
{
|
|
2147
|
+
aposLocale: queryLocale
|
|
2148
|
+
},
|
|
2149
|
+
{
|
|
2150
|
+
aposLocale: null
|
|
2151
|
+
}
|
|
2152
|
+
];
|
|
2153
|
+
|
|
2154
|
+
if (self.isShareDraftRequest(query.req)) {
|
|
2155
|
+
const { aposShareId, aposShareKey } = query.req.query;
|
|
2156
|
+
|
|
2157
|
+
$or.push({
|
|
2158
|
+
_id: aposShareId,
|
|
2159
|
+
aposShareKey,
|
|
2160
|
+
aposLocale: queryLocale.replace(':published', ':draft')
|
|
2161
|
+
});
|
|
2162
|
+
}
|
|
2163
|
+
|
|
2164
|
+
query.and({ $or });
|
|
2074
2165
|
}
|
|
2075
2166
|
}
|
|
2076
2167
|
}
|
|
@@ -125,7 +125,7 @@ export default {
|
|
|
125
125
|
action: 'edit'
|
|
126
126
|
}
|
|
127
127
|
] : []),
|
|
128
|
-
...((this.showPreview && this.
|
|
128
|
+
...((this.showPreview && this.hasUrl) ? [
|
|
129
129
|
{
|
|
130
130
|
label: 'apostrophe:preview',
|
|
131
131
|
action: 'preview'
|
|
@@ -192,13 +192,14 @@ export default {
|
|
|
192
192
|
},
|
|
193
193
|
customOperationsByContext() {
|
|
194
194
|
return this.customOperations.filter(op => {
|
|
195
|
-
if (op.
|
|
196
|
-
|
|
197
|
-
return op.manuallyPublished === this.manuallyPublished;
|
|
198
|
-
}
|
|
199
|
-
return true;
|
|
195
|
+
if (typeof op.manuallyPublished === 'boolean' && op.manuallyPublished !== this.manuallyPublished) {
|
|
196
|
+
return false;
|
|
200
197
|
}
|
|
201
|
-
|
|
198
|
+
if (typeof op.hasUrl === 'boolean' && op.hasUrl !== this.hasUrl) {
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return op.context === 'update' && this.isUpdateOperation;
|
|
202
203
|
});
|
|
203
204
|
},
|
|
204
205
|
moduleName() {
|
|
@@ -214,6 +215,9 @@ export default {
|
|
|
214
215
|
isUpdateOperation() {
|
|
215
216
|
return !!this.context._id;
|
|
216
217
|
},
|
|
218
|
+
hasUrl() {
|
|
219
|
+
return !!this.context._url;
|
|
220
|
+
},
|
|
217
221
|
canPublish() {
|
|
218
222
|
if (this.context._id) {
|
|
219
223
|
return this.context._publish;
|
|
@@ -26,14 +26,14 @@
|
|
|
26
26
|
type="primary" :label="saveLabel"
|
|
27
27
|
:disabled="saveDisabled"
|
|
28
28
|
@click="onRestore"
|
|
29
|
-
:tooltip="
|
|
29
|
+
:tooltip="errorTooltip"
|
|
30
30
|
/>
|
|
31
31
|
<AposButtonSplit
|
|
32
32
|
v-else-if="saveMenu"
|
|
33
33
|
:menu="saveMenu"
|
|
34
34
|
menu-label="Select Save Method"
|
|
35
35
|
:disabled="saveDisabled"
|
|
36
|
-
:tooltip="
|
|
36
|
+
:tooltip="errorTooltip"
|
|
37
37
|
:selected="savePreference"
|
|
38
38
|
@click="saveHandler($event)"
|
|
39
39
|
/>
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
<AposModalRail>
|
|
43
43
|
<AposModalTabs
|
|
44
44
|
:key="tabKey"
|
|
45
|
-
v-if="tabs.length
|
|
45
|
+
v-if="tabs.length"
|
|
46
46
|
:current="currentTab"
|
|
47
47
|
:tabs="tabs"
|
|
48
48
|
:errors="fieldErrors"
|
|
@@ -105,15 +105,15 @@
|
|
|
105
105
|
</template>
|
|
106
106
|
|
|
107
107
|
<script>
|
|
108
|
+
import { klona } from 'klona';
|
|
108
109
|
import AposModifiedMixin from 'Modules/@apostrophecms/ui/mixins/AposModifiedMixin';
|
|
109
110
|
import AposModalTabsMixin from 'Modules/@apostrophecms/modal/mixins/AposModalTabsMixin';
|
|
110
111
|
import AposEditorMixin from 'Modules/@apostrophecms/modal/mixins/AposEditorMixin';
|
|
111
112
|
import AposPublishMixin from 'Modules/@apostrophecms/ui/mixins/AposPublishMixin';
|
|
112
113
|
import AposArchiveMixin from 'Modules/@apostrophecms/ui/mixins/AposArchiveMixin';
|
|
113
114
|
import AposAdvisoryLockMixin from 'Modules/@apostrophecms/ui/mixins/AposAdvisoryLockMixin';
|
|
115
|
+
import AposDocErrorsMixin from 'Modules/@apostrophecms/modal/mixins/AposDocErrorsMixin';
|
|
114
116
|
import { detectDocChange } from 'Modules/@apostrophecms/schema/lib/detectChange';
|
|
115
|
-
import { klona } from 'klona';
|
|
116
|
-
import cuid from 'cuid';
|
|
117
117
|
|
|
118
118
|
export default {
|
|
119
119
|
name: 'AposDocEditor',
|
|
@@ -123,7 +123,8 @@ export default {
|
|
|
123
123
|
AposEditorMixin,
|
|
124
124
|
AposPublishMixin,
|
|
125
125
|
AposAdvisoryLockMixin,
|
|
126
|
-
AposArchiveMixin
|
|
126
|
+
AposArchiveMixin,
|
|
127
|
+
AposDocErrorsMixin
|
|
127
128
|
],
|
|
128
129
|
provide () {
|
|
129
130
|
return {
|
|
@@ -147,7 +148,6 @@ export default {
|
|
|
147
148
|
emits: [ 'modal-result', 'safe-close' ],
|
|
148
149
|
data() {
|
|
149
150
|
return {
|
|
150
|
-
tabKey: cuid(),
|
|
151
151
|
docType: this.moduleName,
|
|
152
152
|
docReady: false,
|
|
153
153
|
fieldErrors: {},
|
|
@@ -162,7 +162,6 @@ export default {
|
|
|
162
162
|
ref: null
|
|
163
163
|
},
|
|
164
164
|
published: null,
|
|
165
|
-
errorCount: 0,
|
|
166
165
|
restoreOnly: false,
|
|
167
166
|
saveMenu: null,
|
|
168
167
|
generation: 0
|
|
@@ -172,16 +171,6 @@ export default {
|
|
|
172
171
|
getOnePath() {
|
|
173
172
|
return `${this.moduleAction}/${this.docId}`;
|
|
174
173
|
},
|
|
175
|
-
tooltip() {
|
|
176
|
-
let msg;
|
|
177
|
-
if (this.errorCount) {
|
|
178
|
-
msg = {
|
|
179
|
-
key: 'apostrophe:errorCount',
|
|
180
|
-
count: this.errorCount
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
return msg;
|
|
184
|
-
},
|
|
185
174
|
followingUtils() {
|
|
186
175
|
return this.followingValues('utility');
|
|
187
176
|
},
|
|
@@ -238,33 +227,6 @@ export default {
|
|
|
238
227
|
// `@apostrophecms/page` module action.
|
|
239
228
|
return (window.apos.modules[this.moduleName] || {}).action;
|
|
240
229
|
},
|
|
241
|
-
groups() {
|
|
242
|
-
const groupSet = {};
|
|
243
|
-
|
|
244
|
-
this.schema.forEach(field => {
|
|
245
|
-
if (!this.filterOutParkedFields([ field.name ]).length) {
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
248
|
-
if (field.group && !groupSet[field.group.name]) {
|
|
249
|
-
groupSet[field.group.name] = {
|
|
250
|
-
label: field.group.label,
|
|
251
|
-
fields: [ field.name ],
|
|
252
|
-
schema: [ field ]
|
|
253
|
-
};
|
|
254
|
-
} else if (field.group) {
|
|
255
|
-
groupSet[field.group.name].fields.push(field.name);
|
|
256
|
-
groupSet[field.group.name].schema.push(field);
|
|
257
|
-
}
|
|
258
|
-
});
|
|
259
|
-
if (!groupSet.utility) {
|
|
260
|
-
groupSet.utility = {
|
|
261
|
-
label: 'apostrophe:utility',
|
|
262
|
-
fields: [],
|
|
263
|
-
schema: []
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
return groupSet;
|
|
267
|
-
},
|
|
268
230
|
utilityFields() {
|
|
269
231
|
let fields = [];
|
|
270
232
|
if (this.groups.utility && this.groups.utility.fields) {
|
|
@@ -272,18 +234,6 @@ export default {
|
|
|
272
234
|
}
|
|
273
235
|
return this.filterOutParkedFields(fields);
|
|
274
236
|
},
|
|
275
|
-
tabs() {
|
|
276
|
-
const tabs = [];
|
|
277
|
-
for (const key in this.groups) {
|
|
278
|
-
if (key !== 'utility') {
|
|
279
|
-
tabs.push({
|
|
280
|
-
name: key,
|
|
281
|
-
label: this.groups[key].label
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
};
|
|
285
|
-
return tabs;
|
|
286
|
-
},
|
|
287
237
|
modalTitle() {
|
|
288
238
|
if (this.docId) {
|
|
289
239
|
return {
|
|
@@ -374,13 +324,7 @@ export default {
|
|
|
374
324
|
original(newVal) {
|
|
375
325
|
this.originalDoc.ref = newVal;
|
|
376
326
|
this.saveMenu = this.computeSaveMenu();
|
|
377
|
-
},
|
|
378
|
-
tabs() {
|
|
379
|
-
if ((!this.currentTab) || (!this.tabs.find(tab => tab.name === this.currentTab))) {
|
|
380
|
-
this.currentTab = this.tabs[0] && this.tabs[0].name;
|
|
381
|
-
}
|
|
382
327
|
}
|
|
383
|
-
|
|
384
328
|
},
|
|
385
329
|
async mounted() {
|
|
386
330
|
this.modal.active = true;
|
|
@@ -515,51 +459,6 @@ export default {
|
|
|
515
459
|
}
|
|
516
460
|
window.location = this.original._url;
|
|
517
461
|
},
|
|
518
|
-
updateFieldState(fieldState) {
|
|
519
|
-
this.tabKey = cuid();
|
|
520
|
-
for (const key in this.groups) {
|
|
521
|
-
this.groups[key].fields.forEach(field => {
|
|
522
|
-
if (fieldState[field]) {
|
|
523
|
-
this.fieldErrors[key][field] = fieldState[field].error;
|
|
524
|
-
}
|
|
525
|
-
});
|
|
526
|
-
}
|
|
527
|
-
this.updateErrorCount();
|
|
528
|
-
},
|
|
529
|
-
updateErrorCount() {
|
|
530
|
-
let count = 0;
|
|
531
|
-
for (const key in this.fieldErrors) {
|
|
532
|
-
for (const tabKey in this.fieldErrors[key]) {
|
|
533
|
-
if (this.fieldErrors[key][tabKey]) {
|
|
534
|
-
count++;
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
this.errorCount = count;
|
|
539
|
-
},
|
|
540
|
-
focusNextError() {
|
|
541
|
-
let field;
|
|
542
|
-
for (const key in this.fieldErrors) {
|
|
543
|
-
for (const tabKey in this.fieldErrors[key]) {
|
|
544
|
-
if (this.fieldErrors[key][tabKey] && !field) {
|
|
545
|
-
field = this.schema.filter(item => {
|
|
546
|
-
return item.name === tabKey;
|
|
547
|
-
})[0];
|
|
548
|
-
|
|
549
|
-
if (field.group.name !== 'utility') {
|
|
550
|
-
this.switchPane(field.group.name);
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
this.getAposSchema(field).scrollFieldIntoView(field.name);
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
},
|
|
558
|
-
prepErrors() {
|
|
559
|
-
for (const name in this.groups) {
|
|
560
|
-
this.fieldErrors[name] = {};
|
|
561
|
-
}
|
|
562
|
-
},
|
|
563
462
|
// Implementing a method expected by the advisory lock mixin
|
|
564
463
|
lockNotAvailable() {
|
|
565
464
|
this.modal.showModal = false;
|
|
@@ -729,7 +628,7 @@ export default {
|
|
|
729
628
|
});
|
|
730
629
|
},
|
|
731
630
|
updateDocFields(value) {
|
|
732
|
-
this.
|
|
631
|
+
this.updateFieldErrors(value.fieldState);
|
|
733
632
|
this.docFields.data = {
|
|
734
633
|
...this.docFields.data,
|
|
735
634
|
...value.data
|
|
@@ -355,6 +355,12 @@
|
|
|
355
355
|
"selectManyLabel": "Select {{ typeLabel }}",
|
|
356
356
|
"selectLocales": "Select Locales",
|
|
357
357
|
"sentenceJoiner": " ",
|
|
358
|
+
"shareDraft": "Share Draft",
|
|
359
|
+
"shareDraftCopyLink": "Copy draft link",
|
|
360
|
+
"shareDraftDescription": "Enabling draft sharing will allow anyone with this link to view the current draft",
|
|
361
|
+
"shareDraftEnable": "Enable draft sharing",
|
|
362
|
+
"shareDraftHeader": "Share this page",
|
|
363
|
+
"shareDraftError": "This document cannot be shared at this time",
|
|
358
364
|
"visibilityHelp": "Select whether this content is public or private",
|
|
359
365
|
"slug": "Slug",
|
|
360
366
|
"slugInUse": "Slug already in use",
|
|
@@ -368,7 +374,7 @@
|
|
|
368
374
|
"switchLocalesAndLocalizePage": "Switch locales and localize page to {{ label }}?",
|
|
369
375
|
"tags": "Tags",
|
|
370
376
|
"tagYourImages": "Tag your images to make searching and filtering the media manager easier",
|
|
371
|
-
"takeActionAndCreateNew": "{{ saveLabel }} and
|
|
377
|
+
"takeActionAndCreateNew": "{{ saveLabel }} and Create New",
|
|
372
378
|
"takeActionAndView": "{{ saveLabel }} and View",
|
|
373
379
|
"takeControlFromOther": "{{ who }} is editing that document. Do you want to take control?",
|
|
374
380
|
"takeControlFromSelf": "You are editing that document in another tab or window. Do you want to take control in this tab?",
|
|
@@ -324,6 +324,12 @@
|
|
|
324
324
|
"selectManyLabel": "Seleccionar {{ typeLabel }}",
|
|
325
325
|
"selectLocales": "Seleccionar Configuración Regional",
|
|
326
326
|
"sentenceJoiner": " ",
|
|
327
|
+
"shareDraft": "Compartir borrador",
|
|
328
|
+
"shareDraftCopyLink": "Copiar borrador de enlace",
|
|
329
|
+
"shareDraftDescription": "Habilitar el uso compartido de borradores permitirá que cualquier persona con este enlace vea el borrador actual",
|
|
330
|
+
"shareDraftEnable": "Habilitar borrador compartido",
|
|
331
|
+
"shareDraftHeader": "Comparte esta página",
|
|
332
|
+
"shareDraftError": "Este documento no se puede compartir en este momento",
|
|
327
333
|
"visibilityHelp": "Seleccione si este contenido es público o privado",
|
|
328
334
|
"slug": "Slug",
|
|
329
335
|
"slugInUse": "Este slug ya está en uso",
|
|
@@ -337,7 +343,7 @@
|
|
|
337
343
|
"switchLocalesAndLocalizePage": "¿Cambiar de configuracion regional y traducir la página a la configuracion regional {{ label }}?",
|
|
338
344
|
"tags": "Etiquetas",
|
|
339
345
|
"tagYourImages": "Etiquete sus imágenes para facilitar la busqueda y filtrado en el gestor multimedia",
|
|
340
|
-
"takeActionAndCreateNew": "{{ saveLabel }} y
|
|
346
|
+
"takeActionAndCreateNew": "{{ saveLabel }} y Crear Nuevo",
|
|
341
347
|
"takeActionAndView": "{{ saveLabel }} y Mirar",
|
|
342
348
|
"takeControlFromOther": "{{ who }} está editando ese documento. ¿Quiere tomar el control?",
|
|
343
349
|
"takeControlFromSelf": "Está editando ese documento en otra pestaña o ventana. ¿Quiere tomar control en esta pestaña?",
|
|
@@ -339,6 +339,12 @@
|
|
|
339
339
|
"selectManyLabel": "Sélectionner {{ typeLabel }}",
|
|
340
340
|
"selectLocales": "Sélectionner les langues",
|
|
341
341
|
"sentenceJoiner": " ",
|
|
342
|
+
"shareDraft": "Partager le brouillon",
|
|
343
|
+
"shareDraftCopyLink": "Copier le lien du brouillon",
|
|
344
|
+
"shareDraftDescription": "L'activation du partage de brouillon permettra à toute personne disposant de ce lien d'accéder au brouillon actuel",
|
|
345
|
+
"shareDraftEnable": "Activer le partage de brouillon",
|
|
346
|
+
"shareDraftHeader": "Partager cette page",
|
|
347
|
+
"shareDraftError": "Ce document ne peut pas être partagé actuellement",
|
|
342
348
|
"visibilityHelp": "Choisissez si ce contenu est public ou privé",
|
|
343
349
|
"slug": "Slug",
|
|
344
350
|
"slugInUse": "Slug déjà utilisé",
|
|
@@ -352,7 +358,7 @@
|
|
|
352
358
|
"switchLocalesAndLocalizePage": "Changer la langue et basculer la page vers {{ label }} ?",
|
|
353
359
|
"tags": "Tags",
|
|
354
360
|
"tagYourImages": "Taguez vos images pour faciliter la recherche et le filtrage du gestionnaire de médias",
|
|
355
|
-
"takeActionAndCreateNew": "{{ saveLabel }} et
|
|
361
|
+
"takeActionAndCreateNew": "{{ saveLabel }} et en créer de nouveau",
|
|
356
362
|
"takeActionAndView": "{{ saveLabel }} et voir",
|
|
357
363
|
"takeControlFromOther": "{{ who }} est en train de modifier ce document. Voulez-vous prendre le contrôle ?",
|
|
358
364
|
"takeControlFromSelf": "Vous modifiez ce document dans un autre onglet ou une autre fenêtre. Voulez-vous prendre le contrôle dans cet onglet ?",
|
|
@@ -321,6 +321,12 @@
|
|
|
321
321
|
"selectManyLabel": "Selecionar {{ typeLabel }}",
|
|
322
322
|
"selectLocales": "Selecionar Localidades",
|
|
323
323
|
"sentenceJoiner": " ",
|
|
324
|
+
"shareDraft": "Compartilhar rascunho",
|
|
325
|
+
"shareDraftCopyLink": "Copiar link de rascunho",
|
|
326
|
+
"shareDraftDescription": "Ativar o compartilhamento de rascunho permitirá que qualquer pessoa com este link visualize o rascunho atual",
|
|
327
|
+
"shareDraftEnable": "Ativar compartilhamento de rascunho",
|
|
328
|
+
"shareDraftHeader": "Compartilhe esta página",
|
|
329
|
+
"shareDraftError": "Este documento não pode ser compartilhado no momento",
|
|
324
330
|
"visibilityHelp": "Selecione se este conteúdo é público ou privado",
|
|
325
331
|
"slug": "Slug",
|
|
326
332
|
"slugInUse": "Este slug já está em uso",
|
|
@@ -334,7 +340,7 @@
|
|
|
334
340
|
"switchLocalesAndLocalizePage": "Mudar de localidade e localizar página para {{ label }}?",
|
|
335
341
|
"tags": "Tags",
|
|
336
342
|
"tagYourImages": "Adicione tags nas suas imagens para facilitar a pesquisa e a filtragem do gerenciador de mídia",
|
|
337
|
-
"takeActionAndCreateNew": "{{ saveLabel }} e
|
|
343
|
+
"takeActionAndCreateNew": "{{ saveLabel }} e Criar Novo",
|
|
338
344
|
"takeActionAndView": "{{ saveLabel }} e Vizualizar",
|
|
339
345
|
"takeControlFromOther": "{{ who }} está editando esse documento. Você quer assumir o controle?",
|
|
340
346
|
"takeControlFromSelf": "Você está editando esse documento em outra guia ou janela. Você deseja assumir o controle nesta guia?",
|
|
@@ -344,6 +344,12 @@
|
|
|
344
344
|
"selectManyLabel": "Vybrať {{ typeLabel }}",
|
|
345
345
|
"selectLocales": "Vybrať jazykové mutácie",
|
|
346
346
|
"sentenceJoiner": " ",
|
|
347
|
+
"shareDraft": "Zdieľať koncept",
|
|
348
|
+
"shareDraftCopyLink": "Kopírovať odkaz na koncept",
|
|
349
|
+
"shareDraftDescription": "Povolenie zdieľania konceptu umožní komukoľvek s týmto odkazom zobraziť aktuálny koncept",
|
|
350
|
+
"shareDraftEnable": "Povoliť zdieľanie konceptov",
|
|
351
|
+
"shareDraftHeader": "Zdieľajte túto stránku",
|
|
352
|
+
"shareDraftError": "Tento dokument momentálne nie je možné zdieľať",
|
|
347
353
|
"visibilityHelp": "Vyberte, či je tento obsah verejný alebo súkromný",
|
|
348
354
|
"slug": "Pochopiteľný text URL",
|
|
349
355
|
"slugInUse": "Pochopiteľný text URL sa už používa",
|
|
@@ -357,7 +363,7 @@
|
|
|
357
363
|
"switchLocalesAndLocalizePage": "Prepnúť jazyk a preložiť stránku na {{ label }}?",
|
|
358
364
|
"tags": "Značky",
|
|
359
365
|
"tagYourImages": "Označte svoje obrázky, aby ste uľahčili vyhľadávanie a filtrovanie médií",
|
|
360
|
-
"takeActionAndCreateNew": "{{ saveLabel }} a
|
|
366
|
+
"takeActionAndCreateNew": "{{ saveLabel }} a vytvoriť nové",
|
|
361
367
|
"takeActionAndView": "{{ saveLabel }} a zobraziť",
|
|
362
368
|
"takeControlFromOther": "{{ who }} upravuje tento dokument. Chcete prevziať kontrolu?",
|
|
363
369
|
"takeControlFromSelf": "Tento dokument upravujete na inej karte alebo v inom okne. Chcete na tejto karte prevziať kontrolu?",
|
|
@@ -90,7 +90,9 @@
|
|
|
90
90
|
>
|
|
91
91
|
<AposMediaManagerEditor
|
|
92
92
|
v-show="editing"
|
|
93
|
-
:media="editing"
|
|
93
|
+
:media="editing"
|
|
94
|
+
:selected="selected"
|
|
95
|
+
:is-modified="isModified"
|
|
94
96
|
:module-labels="moduleLabels"
|
|
95
97
|
@back="updateEditing(null)" @saved="updateMedia"
|
|
96
98
|
@modified="editorModified"
|
|
@@ -100,6 +100,7 @@
|
|
|
100
100
|
<script>
|
|
101
101
|
import AposEditorMixin from 'Modules/@apostrophecms/modal/mixins/AposEditorMixin';
|
|
102
102
|
import AposAdvisoryLockMixin from 'Modules/@apostrophecms/ui/mixins/AposAdvisoryLockMixin';
|
|
103
|
+
import AposModifiedMixin from 'Modules/@apostrophecms/ui/mixins/AposModifiedMixin';
|
|
103
104
|
import { detectDocChange } from 'Modules/@apostrophecms/schema/lib/detectChange';
|
|
104
105
|
import { klona } from 'klona';
|
|
105
106
|
import dayjs from 'dayjs';
|
|
@@ -110,7 +111,7 @@ import cuid from 'cuid';
|
|
|
110
111
|
dayjs.extend(advancedFormat);
|
|
111
112
|
|
|
112
113
|
export default {
|
|
113
|
-
mixins: [ AposEditorMixin, AposAdvisoryLockMixin ],
|
|
114
|
+
mixins: [ AposEditorMixin, AposAdvisoryLockMixin, AposModifiedMixin ],
|
|
114
115
|
props: {
|
|
115
116
|
media: {
|
|
116
117
|
type: Object,
|
|
@@ -124,6 +125,10 @@ export default {
|
|
|
124
125
|
return [];
|
|
125
126
|
}
|
|
126
127
|
},
|
|
128
|
+
isModified: {
|
|
129
|
+
type: Boolean,
|
|
130
|
+
default: false
|
|
131
|
+
},
|
|
127
132
|
moduleLabels: {
|
|
128
133
|
type: Object,
|
|
129
134
|
default() {
|
|
@@ -152,11 +157,20 @@ export default {
|
|
|
152
157
|
moduleOptions() {
|
|
153
158
|
return window.apos.modules[this.activeMedia.type] || {};
|
|
154
159
|
},
|
|
160
|
+
canLocalize() {
|
|
161
|
+
return (Object.keys(apos.i18n.locales).length > 1) && this.moduleOptions.localized && this.activeMedia._id;
|
|
162
|
+
},
|
|
155
163
|
moreMenu() {
|
|
156
164
|
const menu = [ {
|
|
157
165
|
label: 'apostrophe:discardChanges',
|
|
158
166
|
action: 'cancel'
|
|
159
167
|
} ];
|
|
168
|
+
if (this.canLocalize) {
|
|
169
|
+
menu.push({
|
|
170
|
+
label: 'apostrophe:localize',
|
|
171
|
+
action: 'localize'
|
|
172
|
+
});
|
|
173
|
+
}
|
|
160
174
|
if (this.activeMedia._id && !this.restoreOnly) {
|
|
161
175
|
menu.push({
|
|
162
176
|
label: 'apostrophe:archiveImage',
|
|
@@ -330,7 +344,7 @@ export default {
|
|
|
330
344
|
this.$emit('back');
|
|
331
345
|
},
|
|
332
346
|
lockNotAvailable() {
|
|
333
|
-
this
|
|
347
|
+
this.$emit('modified', false);
|
|
334
348
|
this.cancel();
|
|
335
349
|
},
|
|
336
350
|
updateActiveAttachment(attachment) {
|
|
@@ -338,6 +352,27 @@ export default {
|
|
|
338
352
|
},
|
|
339
353
|
viewMedia () {
|
|
340
354
|
window.open(this.activeMedia.attachment._urls.original, '_blank');
|
|
355
|
+
},
|
|
356
|
+
async localize(media) {
|
|
357
|
+
// If there are changes warn the user before discarding them before
|
|
358
|
+
// the localize operation
|
|
359
|
+
if (this.isModified) {
|
|
360
|
+
if (!await this.confirmAndCancel()) {
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
await this.cancel();
|
|
365
|
+
this.updateActiveDoc(this.activeMedia);
|
|
366
|
+
}
|
|
367
|
+
apos.bus.$emit('admin-menu-click', {
|
|
368
|
+
itemName: '@apostrophecms/i18n:localize',
|
|
369
|
+
props: {
|
|
370
|
+
doc: this.activeMedia
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
},
|
|
374
|
+
async close() {
|
|
375
|
+
await this.cancel();
|
|
341
376
|
}
|
|
342
377
|
}
|
|
343
378
|
};
|
|
@@ -806,6 +806,16 @@ module.exports = {
|
|
|
806
806
|
return (req, res, next) => req.user ? next() : passportSession(req, res, next);
|
|
807
807
|
})()
|
|
808
808
|
},
|
|
809
|
+
removeUserForDraftSharing: {
|
|
810
|
+
before: '@apostrophecms/i18n',
|
|
811
|
+
middleware(req, res, next) {
|
|
812
|
+
// Remove user to hide the admin UI, in order to simulate a logged-out page view
|
|
813
|
+
if (self.isShareDraftRequest(req)) {
|
|
814
|
+
delete req.user;
|
|
815
|
+
}
|
|
816
|
+
return next();
|
|
817
|
+
}
|
|
818
|
+
},
|
|
809
819
|
honorLoginInvalidBefore: {
|
|
810
820
|
before: '@apostrophecms/i18n',
|
|
811
821
|
middleware(req, res, next) {
|