apostrophe 3.4.1 → 3.8.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/.eslintrc +4 -0
- package/.scratch.md +2 -0
- package/CHANGELOG.md +114 -2
- package/README.md +1 -1
- package/deploy-test-count +1 -1
- package/index.js +125 -5
- package/lib/moog-require.js +41 -3
- package/lib/moog.js +20 -8
- package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposAdminBarLocale.vue +42 -23
- package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposContextBar.vue +30 -14
- package/modules/@apostrophecms/area/index.js +9 -0
- package/modules/@apostrophecms/area/lib/custom-tags/area.js +1 -1
- package/modules/@apostrophecms/area/lib/custom-tags/widget.js +1 -1
- package/modules/@apostrophecms/area/ui/apos/apps/AposAreas.js +3 -0
- package/modules/@apostrophecms/area/ui/apos/components/AposAreaWidget.vue +6 -6
- package/modules/@apostrophecms/asset/index.js +85 -21
- package/modules/@apostrophecms/asset/lib/globalIcons.js +2 -0
- package/modules/@apostrophecms/asset/lib/webpack/src/webpack.scss.js +5 -2
- package/modules/@apostrophecms/attachment/index.js +1 -0
- package/modules/@apostrophecms/db/index.js +5 -6
- package/modules/@apostrophecms/doc/index.js +13 -3
- package/modules/@apostrophecms/doc-type/index.js +24 -4
- package/modules/@apostrophecms/doc-type/ui/apos/components/AposDocContextMenu.vue +13 -1
- package/modules/@apostrophecms/doc-type/ui/apos/components/AposDocEditor.vue +3 -0
- package/modules/@apostrophecms/i18n/i18n/en.json +26 -6
- package/modules/@apostrophecms/i18n/i18n/es.json +382 -0
- package/modules/@apostrophecms/i18n/i18n/pt-BR.json +379 -0
- package/modules/@apostrophecms/i18n/i18n/sk.json +380 -0
- package/modules/@apostrophecms/i18n/index.js +10 -1
- package/modules/@apostrophecms/i18n/ui/apos/components/AposI18nLocalize.vue +153 -121
- package/modules/@apostrophecms/image/index.js +2 -1
- package/modules/@apostrophecms/image/ui/apos/components/AposMediaManager.vue +6 -3
- package/modules/@apostrophecms/image/ui/apos/components/AposMediaManagerEditor.vue +24 -13
- package/modules/@apostrophecms/image-widget/index.js +2 -1
- package/modules/@apostrophecms/image-widget/views/widget.html +12 -2
- package/modules/@apostrophecms/job/index.js +164 -212
- package/modules/@apostrophecms/login/index.js +36 -17
- package/modules/@apostrophecms/login/ui/apos/components/TheAposLogin.vue +8 -0
- package/modules/@apostrophecms/migration/index.js +1 -1
- package/modules/@apostrophecms/modal/ui/apos/components/AposDocsManagerToolbar.vue +151 -61
- package/modules/@apostrophecms/modal/ui/apos/components/AposModal.vue +6 -2
- package/modules/@apostrophecms/modal/ui/apos/components/AposModalConfirm.vue +9 -7
- package/modules/@apostrophecms/modal/ui/apos/mixins/AposDocsManagerMixin.js +12 -15
- package/modules/@apostrophecms/modal/ui/apos/mixins/AposEditorMixin.js +6 -0
- package/modules/@apostrophecms/module/index.js +1 -1
- package/modules/@apostrophecms/notification/index.js +116 -8
- package/modules/@apostrophecms/notification/ui/apos/components/AposNotification.vue +89 -11
- package/modules/@apostrophecms/notification/ui/apos/components/TheAposNotifications.vue +1 -1
- package/modules/@apostrophecms/page/index.js +37 -30
- package/modules/@apostrophecms/permission/index.js +1 -1
- package/modules/@apostrophecms/permission/ui/apos/components/AposInputRole.vue +4 -2
- package/modules/@apostrophecms/piece-type/index.js +178 -61
- package/modules/@apostrophecms/piece-type/ui/apos/components/AposDocsManager.vue +179 -47
- package/modules/@apostrophecms/piece-type/ui/apos/components/AposDocsManagerDisplay.vue +1 -3
- package/modules/@apostrophecms/piece-type/ui/apos/components/AposDocsManagerSelectBox.vue +138 -0
- package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposRichTextWidgetEditor.vue +42 -10
- package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapStyles.vue +3 -0
- package/modules/@apostrophecms/rich-text-widget/ui/apos/tiptap-extensions/Classes.js +6 -10
- package/modules/@apostrophecms/rich-text-widget/ui/apos/tiptap-extensions/Default.js +64 -0
- package/modules/@apostrophecms/rich-text-widget/ui/apos/tiptap-extensions/Document.js +15 -0
- package/modules/@apostrophecms/rich-text-widget/ui/apos/tiptap-extensions/Heading.js +23 -0
- package/modules/@apostrophecms/schema/index.js +97 -20
- package/modules/@apostrophecms/schema/ui/apos/components/AposArrayEditor.vue +1 -0
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputArray.vue +4 -1
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputAttachment.vue +11 -160
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputRadio.vue +8 -5
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputRelationship.vue +24 -2
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputSelect.vue +24 -6
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputSlug.vue +0 -4
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputString.vue +0 -7
- package/modules/@apostrophecms/schema/ui/apos/components/AposSchema.vue +25 -3
- package/modules/@apostrophecms/schema/ui/apos/mixins/AposInputMixin.js +10 -2
- package/modules/@apostrophecms/task/index.js +2 -2
- package/modules/@apostrophecms/template/index.js +63 -36
- package/modules/@apostrophecms/template/lib/custom-tags/component.js +1 -1
- package/modules/@apostrophecms/template/lib/custom-tags/render.js +6 -2
- package/modules/@apostrophecms/ui/index.js +6 -2
- package/modules/@apostrophecms/ui/ui/apos/components/AposButton.vue +21 -3
- package/modules/@apostrophecms/ui/ui/apos/components/AposCellContextMenu.vue +1 -1
- package/modules/@apostrophecms/ui/ui/apos/components/AposFile.vue +205 -0
- package/modules/@apostrophecms/ui/ui/apos/components/AposIndicator.vue +5 -0
- package/modules/@apostrophecms/ui/ui/apos/lib/i18next.js +16 -2
- package/modules/@apostrophecms/ui/ui/apos/scss/global/_tables.scss +4 -3
- package/modules/@apostrophecms/ui/ui/apos/scss/global/_theme.scss +3 -0
- package/modules/@apostrophecms/ui/ui/apos/scss/global/_widgets.scss +3 -0
- package/modules/@apostrophecms/ui/ui/apos/scss/global/import-all.scss +2 -1
- package/modules/@apostrophecms/user/index.js +21 -0
- package/modules/@apostrophecms/util/index.js +2 -2
- package/modules/@apostrophecms/util/ui/src/http.js +12 -8
- package/modules/@apostrophecms/util/ui/src/util.js +15 -0
- package/modules/@apostrophecms/widget-type/index.js +1 -1
- package/modules/@apostrophecms/widget-type/ui/apos/components/AposWidgetEditor.vue +1 -0
- package/modules/@apostrophecms/widget-type/ui/apos/mixins/AposWidgetMixin.js +15 -7
- package/package.json +4 -4
- package/test/extra_node_modules/improve-global/index.js +7 -0
- package/test/extra_node_modules/improve-piece-type/index.js +7 -0
- package/test/improve-overrides.js +30 -0
- package/test/job.js +224 -0
- package/test/login.js +183 -0
- package/test/modules/@apostrophecms/global/index.js +8 -0
- package/test/modules/fragment-all/views/aux-test.html +7 -0
- package/test/modules/fragment-all/views/fragment.html +5 -0
- package/test/moog.js +47 -0
- package/test/package.json +5 -4
- package/test/pieces.js +17 -0
- package/test/reverse-relationship.js +170 -0
- package/test/subdir-project/app.js +3 -0
- package/test/subdir-project.js +26 -0
- package/test/templates.js +7 -1
- package/test-lib/test.js +23 -12
- package/test-lib/util.js +33 -0
|
@@ -19,10 +19,10 @@
|
|
|
19
19
|
</template>
|
|
20
20
|
<template #primaryControls>
|
|
21
21
|
<AposContextMenu
|
|
22
|
-
v-if="
|
|
23
|
-
:button="
|
|
24
|
-
:menu="
|
|
25
|
-
@item-clicked="
|
|
22
|
+
v-if="utilityOperations.menu.length"
|
|
23
|
+
:button="utilityOperations.button"
|
|
24
|
+
:menu="utilityOperations.menu"
|
|
25
|
+
@item-clicked="utilityOperationsHandler"
|
|
26
26
|
/>
|
|
27
27
|
<AposButton
|
|
28
28
|
v-if="relationshipField"
|
|
@@ -66,19 +66,33 @@
|
|
|
66
66
|
:selected-state="selectAllState"
|
|
67
67
|
:total-pages="totalPages"
|
|
68
68
|
:current-page="currentPage"
|
|
69
|
-
:filters="moduleOptions.filters"
|
|
70
69
|
:filter-choices="filterChoices"
|
|
71
70
|
:filter-values="filterValues"
|
|
71
|
+
:filters="moduleOptions.filters"
|
|
72
72
|
:labels="moduleLabels"
|
|
73
|
+
:displayed-items="items.length"
|
|
74
|
+
:is-relationship="!!relationshipField"
|
|
75
|
+
:checked-count="checked.length"
|
|
76
|
+
:batch-operations="moduleOptions.batchOperations"
|
|
73
77
|
@select-click="selectAll"
|
|
74
78
|
@search="search"
|
|
75
79
|
@page-change="updatePage"
|
|
76
80
|
@filter="filter"
|
|
81
|
+
@batch="handleBatchAction"
|
|
77
82
|
:options="{
|
|
78
|
-
disableUnchecked: maxReached()
|
|
79
|
-
hideSelectAll: !relationshipField
|
|
83
|
+
disableUnchecked: maxReached()
|
|
80
84
|
}"
|
|
81
85
|
/>
|
|
86
|
+
<AposDocsManagerSelectBox
|
|
87
|
+
:selected-state="selectAllState"
|
|
88
|
+
:module-labels="moduleLabels"
|
|
89
|
+
:filter-values="filterValues"
|
|
90
|
+
:checked-ids="checked"
|
|
91
|
+
:all-pieces-selection="allPiecesSelection"
|
|
92
|
+
:displayed-items="items.length"
|
|
93
|
+
@select-all="selectAllPieces"
|
|
94
|
+
@set-all-pieces-selection="setAllPiecesSelection"
|
|
95
|
+
/>
|
|
82
96
|
</template>
|
|
83
97
|
<template #bodyMain>
|
|
84
98
|
<AposDocsManagerDisplay
|
|
@@ -90,7 +104,6 @@
|
|
|
90
104
|
:options="{
|
|
91
105
|
...moduleOptions,
|
|
92
106
|
disableUnchecked: maxReached(),
|
|
93
|
-
hideCheckboxes: !relationshipField,
|
|
94
107
|
disableUnpublished: disableUnpublished,
|
|
95
108
|
manuallyPublished: manuallyPublished
|
|
96
109
|
}"
|
|
@@ -136,7 +149,7 @@ export default {
|
|
|
136
149
|
filterValues: {},
|
|
137
150
|
queryExtras: {},
|
|
138
151
|
holdQueries: false,
|
|
139
|
-
|
|
152
|
+
utilityOperations: {
|
|
140
153
|
button: {
|
|
141
154
|
label: 'apostrophe:moreOperations',
|
|
142
155
|
iconOnly: true,
|
|
@@ -145,7 +158,11 @@ export default {
|
|
|
145
158
|
},
|
|
146
159
|
menu: []
|
|
147
160
|
},
|
|
148
|
-
filterChoices: {}
|
|
161
|
+
filterChoices: {},
|
|
162
|
+
allPiecesSelection: {
|
|
163
|
+
isSelected: false,
|
|
164
|
+
total: 0
|
|
165
|
+
}
|
|
149
166
|
};
|
|
150
167
|
},
|
|
151
168
|
computed: {
|
|
@@ -190,6 +207,16 @@ export default {
|
|
|
190
207
|
},
|
|
191
208
|
disableUnpublished() {
|
|
192
209
|
return this.relationshipField && apos.modules[this.relationshipField.withType].localized;
|
|
210
|
+
},
|
|
211
|
+
selectAllChoice() {
|
|
212
|
+
const checkCount = this.checked.length;
|
|
213
|
+
const pageNotFullyChecked = this.items
|
|
214
|
+
.some((item) => !this.checked.includes(item._id));
|
|
215
|
+
|
|
216
|
+
return {
|
|
217
|
+
value: 'checked',
|
|
218
|
+
indeterminate: checkCount && pageNotFullyChecked
|
|
219
|
+
};
|
|
193
220
|
}
|
|
194
221
|
},
|
|
195
222
|
created() {
|
|
@@ -206,14 +233,10 @@ export default {
|
|
|
206
233
|
this.headers = this.computeHeaders();
|
|
207
234
|
// Get the data. This will be more complex in actuality.
|
|
208
235
|
this.modal.active = true;
|
|
209
|
-
this.
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
action: 'new',
|
|
214
|
-
label: `New ${this.moduleLabels.singular}`
|
|
215
|
-
});
|
|
216
|
-
}
|
|
236
|
+
this.setUtilityOperations();
|
|
237
|
+
await this.getPieces();
|
|
238
|
+
await this.getAllPiecesTotal();
|
|
239
|
+
|
|
217
240
|
apos.bus.$on('content-changed', this.getPieces);
|
|
218
241
|
},
|
|
219
242
|
destroyed() {
|
|
@@ -221,10 +244,13 @@ export default {
|
|
|
221
244
|
apos.bus.$off('content-changed', this.getPieces);
|
|
222
245
|
},
|
|
223
246
|
methods: {
|
|
224
|
-
|
|
247
|
+
utilityOperationsHandler(action) {
|
|
225
248
|
if (action === 'new') {
|
|
226
249
|
this.create();
|
|
250
|
+
return;
|
|
227
251
|
}
|
|
252
|
+
|
|
253
|
+
this.handleUtilityOperation(action);
|
|
228
254
|
},
|
|
229
255
|
setCheckedDocs(checked) {
|
|
230
256
|
this.checkedDocs = checked;
|
|
@@ -235,6 +261,29 @@ export default {
|
|
|
235
261
|
async create() {
|
|
236
262
|
await this.edit(null);
|
|
237
263
|
},
|
|
264
|
+
async handleUtilityOperation(action) {
|
|
265
|
+
const operation = this.utilityOperations.menu
|
|
266
|
+
.find((op) => op.action === action);
|
|
267
|
+
|
|
268
|
+
if (!operation) {
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const {
|
|
273
|
+
modal, ...modalOptions
|
|
274
|
+
} = operation.modalOptions || {};
|
|
275
|
+
|
|
276
|
+
if (modal) {
|
|
277
|
+
await apos.modal.execute(modal, {
|
|
278
|
+
moduleAction: this.moduleOptions.action,
|
|
279
|
+
action,
|
|
280
|
+
labels: this.moduleLabels,
|
|
281
|
+
messages: operation.messages,
|
|
282
|
+
...modalOptions
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
|
|
238
287
|
// If pieceOrId is null, a new piece is created
|
|
239
288
|
async edit(pieceOrId) {
|
|
240
289
|
let piece;
|
|
@@ -268,42 +317,68 @@ export default {
|
|
|
268
317
|
async finishSaved() {
|
|
269
318
|
await this.getPieces();
|
|
270
319
|
},
|
|
271
|
-
async
|
|
272
|
-
|
|
273
|
-
return;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
this.holdQueries = true;
|
|
277
|
-
|
|
278
|
-
const qs = {
|
|
320
|
+
async request (mergeOptions) {
|
|
321
|
+
const options = {
|
|
279
322
|
...this.filterValues,
|
|
280
|
-
page: this.currentPage,
|
|
281
323
|
...this.queryExtras,
|
|
282
|
-
|
|
324
|
+
...mergeOptions,
|
|
283
325
|
withPublished: 1
|
|
284
326
|
};
|
|
285
327
|
|
|
286
328
|
// Avoid undefined properties.
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
329
|
+
const qs = Object.entries(options)
|
|
330
|
+
.reduce((acc, [ key, val ]) => ({
|
|
331
|
+
...acc,
|
|
332
|
+
...val !== undefined && { [key]: val }
|
|
333
|
+
}), {});
|
|
334
|
+
|
|
335
|
+
return apos.http.get(this.moduleOptions.action, {
|
|
336
|
+
qs,
|
|
337
|
+
busy: true,
|
|
338
|
+
draft: true
|
|
339
|
+
});
|
|
340
|
+
},
|
|
341
|
+
async getPieces () {
|
|
342
|
+
if (this.holdQueries) {
|
|
343
|
+
return;
|
|
291
344
|
}
|
|
292
345
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
);
|
|
346
|
+
this.holdQueries = true;
|
|
347
|
+
|
|
348
|
+
const {
|
|
349
|
+
currentPage, pages, results, choices
|
|
350
|
+
} = await this.request({
|
|
351
|
+
page: this.currentPage
|
|
352
|
+
});
|
|
300
353
|
|
|
301
|
-
this.currentPage =
|
|
302
|
-
this.totalPages =
|
|
303
|
-
this.items =
|
|
304
|
-
this.filterChoices =
|
|
354
|
+
this.currentPage = currentPage;
|
|
355
|
+
this.totalPages = pages;
|
|
356
|
+
this.items = results;
|
|
357
|
+
this.filterChoices = choices;
|
|
305
358
|
this.holdQueries = false;
|
|
306
359
|
},
|
|
360
|
+
async getAllPiecesTotal () {
|
|
361
|
+
const { count: total } = await this.request({ count: 1 });
|
|
362
|
+
|
|
363
|
+
this.setAllPiecesSelection({
|
|
364
|
+
isSelected: false,
|
|
365
|
+
total
|
|
366
|
+
});
|
|
367
|
+
},
|
|
368
|
+
async selectAllPieces () {
|
|
369
|
+
const { results: docs } = await this.request({
|
|
370
|
+
project: {
|
|
371
|
+
_id: 1
|
|
372
|
+
},
|
|
373
|
+
attachments: false,
|
|
374
|
+
perPage: this.allPiecesSelection.total
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
this.setAllPiecesSelection({
|
|
378
|
+
isSelected: true,
|
|
379
|
+
docs
|
|
380
|
+
});
|
|
381
|
+
},
|
|
307
382
|
updatePage(num) {
|
|
308
383
|
if (num) {
|
|
309
384
|
this.currentPage = num;
|
|
@@ -322,6 +397,7 @@ export default {
|
|
|
322
397
|
this.currentPage = 1;
|
|
323
398
|
|
|
324
399
|
await this.getPieces();
|
|
400
|
+
await this.getAllPiecesTotal();
|
|
325
401
|
},
|
|
326
402
|
async filter(filter, value) {
|
|
327
403
|
if (this.filterValues[filter] === value) {
|
|
@@ -331,10 +407,12 @@ export default {
|
|
|
331
407
|
this.filterValues[filter] = value;
|
|
332
408
|
this.currentPage = 1;
|
|
333
409
|
|
|
334
|
-
this.getPieces();
|
|
410
|
+
await this.getPieces();
|
|
411
|
+
await this.getAllPiecesTotal();
|
|
335
412
|
this.headers = this.computeHeaders();
|
|
336
|
-
},
|
|
337
413
|
|
|
414
|
+
this.setCheckedDocs([]);
|
|
415
|
+
},
|
|
338
416
|
shortcutNew(event) {
|
|
339
417
|
const interesting = (event.keyCode === 78 || event.keyCode === 67); // C(reate) or N(ew)
|
|
340
418
|
const topModal = apos.modal.stack[apos.modal.stack.length - 1] ? apos.modal.stack[apos.modal.stack.length - 1].id : null;
|
|
@@ -346,7 +424,6 @@ export default {
|
|
|
346
424
|
this.create();
|
|
347
425
|
}
|
|
348
426
|
},
|
|
349
|
-
|
|
350
427
|
bindShortcuts() {
|
|
351
428
|
window.addEventListener('keydown', this.shortcutNew);
|
|
352
429
|
},
|
|
@@ -373,6 +450,61 @@ export default {
|
|
|
373
450
|
_fields: result
|
|
374
451
|
});
|
|
375
452
|
}
|
|
453
|
+
},
|
|
454
|
+
setAllPiecesSelection ({
|
|
455
|
+
isSelected, total, docs
|
|
456
|
+
}) {
|
|
457
|
+
if (typeof isSelected === 'boolean') {
|
|
458
|
+
this.allPiecesSelection.isSelected = isSelected;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
if (typeof total === 'number') {
|
|
462
|
+
this.allPiecesSelection.total = total;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
if (docs) {
|
|
466
|
+
this.setCheckedDocs(docs);
|
|
467
|
+
}
|
|
468
|
+
},
|
|
469
|
+
async handleBatchAction({
|
|
470
|
+
label, action, requestOptions = {}, messages
|
|
471
|
+
}) {
|
|
472
|
+
if (action) {
|
|
473
|
+
try {
|
|
474
|
+
await apos.http.post(`${this.moduleOptions.action}/${action}`, {
|
|
475
|
+
body: {
|
|
476
|
+
...requestOptions,
|
|
477
|
+
_ids: this.checked,
|
|
478
|
+
messages: messages,
|
|
479
|
+
type: this.checked.length === 1 ? this.moduleLabels.singular
|
|
480
|
+
: this.moduleLabels.plural
|
|
481
|
+
}
|
|
482
|
+
});
|
|
483
|
+
} catch (error) {
|
|
484
|
+
apos.notify('Batch operation {{ operation }} failed.', {
|
|
485
|
+
interpolate: { operation: label },
|
|
486
|
+
type: 'danger'
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
},
|
|
491
|
+
setUtilityOperations () {
|
|
492
|
+
const { utilityOperations } = this.moduleOptions;
|
|
493
|
+
|
|
494
|
+
const newPiece = {
|
|
495
|
+
action: 'new',
|
|
496
|
+
label: {
|
|
497
|
+
key: 'apostrophe:newDocType',
|
|
498
|
+
type: this.$t(this.moduleLabels.singular)
|
|
499
|
+
}
|
|
500
|
+
};
|
|
501
|
+
|
|
502
|
+
this.utilityOperations.menu = [
|
|
503
|
+
...this.relationshipField && this.moduleOptions.canEdit
|
|
504
|
+
? [ newPiece ] : [],
|
|
505
|
+
...this.utilityOperations.menu,
|
|
506
|
+
...(!this.relationshipField && Array.isArray(utilityOperations) && utilityOperations) || []
|
|
507
|
+
];
|
|
376
508
|
}
|
|
377
509
|
}
|
|
378
510
|
};
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
<tr>
|
|
5
5
|
<th
|
|
6
6
|
class="apos-table__header"
|
|
7
|
-
v-if="!options.hideCheckboxes"
|
|
8
7
|
/>
|
|
9
8
|
<th
|
|
10
9
|
v-for="header in headers" scope="col"
|
|
@@ -26,7 +25,7 @@
|
|
|
26
25
|
<th class="apos-table__header" key="contextMenu">
|
|
27
26
|
<component
|
|
28
27
|
:is="getEl({})"
|
|
29
|
-
class="apos-table__header-label is-hidden"
|
|
28
|
+
class="apos-table__header-label apos-is-hidden"
|
|
30
29
|
>
|
|
31
30
|
{{ $t('apostrophe:moreOperations') }}
|
|
32
31
|
</component>
|
|
@@ -41,7 +40,6 @@
|
|
|
41
40
|
>
|
|
42
41
|
<td
|
|
43
42
|
class="apos-table__cell"
|
|
44
|
-
v-if="!options.hideCheckboxes"
|
|
45
43
|
>
|
|
46
44
|
<AposCheckbox
|
|
47
45
|
v-if="item._id"
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<transition
|
|
3
|
+
name="collapse"
|
|
4
|
+
:duration="300"
|
|
5
|
+
>
|
|
6
|
+
<div
|
|
7
|
+
v-if="selectedState === 'checked' || allPiecesSelection.isSelected"
|
|
8
|
+
class="apos-select-box"
|
|
9
|
+
>
|
|
10
|
+
<div class="apos-select-box__content">
|
|
11
|
+
<p class="apos-select-box__text">
|
|
12
|
+
{{ selectBoxMessage }}
|
|
13
|
+
<button
|
|
14
|
+
v-if="!allPiecesSelection.isSelected"
|
|
15
|
+
class="apos-select-box__select-all"
|
|
16
|
+
@click="$emit('select-all')"
|
|
17
|
+
>
|
|
18
|
+
{{ selectBoxMessageButton }}
|
|
19
|
+
</button>
|
|
20
|
+
<button
|
|
21
|
+
v-else
|
|
22
|
+
class="apos-select-box__select-all"
|
|
23
|
+
@click="clearSelection"
|
|
24
|
+
>
|
|
25
|
+
{{ $t('apostrophe:clearSelection') }}.
|
|
26
|
+
</button>
|
|
27
|
+
</p>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
</transition>
|
|
31
|
+
</template>
|
|
32
|
+
|
|
33
|
+
<script>
|
|
34
|
+
export default {
|
|
35
|
+
props: {
|
|
36
|
+
selectedState: {
|
|
37
|
+
type: String,
|
|
38
|
+
required: true
|
|
39
|
+
},
|
|
40
|
+
moduleLabels: {
|
|
41
|
+
type: Object,
|
|
42
|
+
required: true
|
|
43
|
+
},
|
|
44
|
+
checkedIds: {
|
|
45
|
+
type: Array,
|
|
46
|
+
required: true
|
|
47
|
+
},
|
|
48
|
+
allPiecesSelection: {
|
|
49
|
+
type: Object,
|
|
50
|
+
required: true
|
|
51
|
+
},
|
|
52
|
+
displayedItems: {
|
|
53
|
+
type: Number,
|
|
54
|
+
required: true
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
emits: [ 'select-all', 'clear-select', 'set-all-pieces-selection' ],
|
|
58
|
+
computed: {
|
|
59
|
+
selectBoxMessage () {
|
|
60
|
+
const checkedCount = this.checkedIds.length;
|
|
61
|
+
const showAllWord = (checkedCount === this.allPiecesSelection.total) &&
|
|
62
|
+
checkedCount !== 1;
|
|
63
|
+
|
|
64
|
+
const translationKey = this.allPiecesSelection.isSelected
|
|
65
|
+
? showAllWord
|
|
66
|
+
? 'apostrophe:selectBoxMessageAllSelected'
|
|
67
|
+
: 'apostrophe:selectBoxMessageSelected'
|
|
68
|
+
: checkedCount > this.displayedItems
|
|
69
|
+
? 'apostrophe:selectBoxMessage'
|
|
70
|
+
: 'apostrophe:selectBoxMessagePage';
|
|
71
|
+
|
|
72
|
+
return this.$t(translationKey, {
|
|
73
|
+
num: this.checkedIds.length,
|
|
74
|
+
label: this.getLabel(this.checkedIds.length)
|
|
75
|
+
});
|
|
76
|
+
},
|
|
77
|
+
selectBoxMessageButton () {
|
|
78
|
+
const translationKey = this.allPiecesSelection.total === 1
|
|
79
|
+
? 'apostrophe:selectBoxMessageButton'
|
|
80
|
+
: 'apostrophe:selectBoxMessageAllButton';
|
|
81
|
+
|
|
82
|
+
return this.$t(translationKey, {
|
|
83
|
+
num: this.allPiecesSelection.total,
|
|
84
|
+
label: this.getLabel(this.allPiecesSelection.total)
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
methods: {
|
|
89
|
+
getLabel(number) {
|
|
90
|
+
return number === 1
|
|
91
|
+
? this.$t(this.moduleLabels.singular).toLowerCase()
|
|
92
|
+
: this.$t(this.moduleLabels.plural).toLowerCase();
|
|
93
|
+
},
|
|
94
|
+
clearSelection () {
|
|
95
|
+
this.$emit('set-all-pieces-selection', {
|
|
96
|
+
isSelected: false,
|
|
97
|
+
docs: []
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
</script>
|
|
103
|
+
<style lang='scss' scoped>
|
|
104
|
+
.apos-select-box {
|
|
105
|
+
box-sizing: border-box;
|
|
106
|
+
overflow: hidden;
|
|
107
|
+
height: 5rem;
|
|
108
|
+
transition: all 0.3s linear;
|
|
109
|
+
|
|
110
|
+
&.collapse-enter, &.collapse-leave-to {
|
|
111
|
+
height: 0;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
&__content {
|
|
115
|
+
display: flex;
|
|
116
|
+
align-items: center;
|
|
117
|
+
justify-content: center;
|
|
118
|
+
background-color: var(--a-base-9);
|
|
119
|
+
margin-top: 1rem;
|
|
120
|
+
color: var(--a-text-primary);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
&__text {
|
|
124
|
+
@include type-large;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
&__select-all {
|
|
128
|
+
color: var(--a-primary);
|
|
129
|
+
cursor: pointer;
|
|
130
|
+
margin-left: 0.4rem;
|
|
131
|
+
border: none;
|
|
132
|
+
|
|
133
|
+
&:hover {
|
|
134
|
+
text-decoration: underline;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
</style>
|
package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposRichTextWidgetEditor.vue
CHANGED
|
@@ -26,9 +26,8 @@
|
|
|
26
26
|
</AposContextMenuDialog>
|
|
27
27
|
</bubble-menu>
|
|
28
28
|
<div class="apos-rich-text-editor__editor" :class="editorModifiers">
|
|
29
|
-
<editor-content :editor="editor" :class="
|
|
29
|
+
<editor-content :editor="editor" :class="editorOptions.className" />
|
|
30
30
|
</div>
|
|
31
|
-
<!-- Using actual DOM element rather than :after to ease localization -->
|
|
32
31
|
<div class="apos-rich-text-editor__editor_after" :class="editorModifiers">
|
|
33
32
|
{{ $t('apostrophe:emptyRichTextWidget') }}
|
|
34
33
|
</div>
|
|
@@ -103,11 +102,27 @@ export default {
|
|
|
103
102
|
|
|
104
103
|
activeOptions.styles = this.enhanceStyles(activeOptions.styles || this.defaultOptions.styles);
|
|
105
104
|
|
|
105
|
+
activeOptions.className = (activeOptions.className !== undefined)
|
|
106
|
+
? activeOptions.className : this.moduleOptions.className;
|
|
107
|
+
|
|
106
108
|
return activeOptions;
|
|
107
109
|
},
|
|
108
|
-
|
|
110
|
+
autofocus() {
|
|
111
|
+
// Only true for a new rich text widget
|
|
112
|
+
return !this.stripPlaceholderBrs(this.value.content).length;
|
|
113
|
+
},
|
|
109
114
|
initialContent() {
|
|
110
|
-
|
|
115
|
+
const content = this.stripPlaceholderBrs(this.value.content);
|
|
116
|
+
if (!content.length) {
|
|
117
|
+
// If we don't supply a valid instance of the first style, then
|
|
118
|
+
// the text align control will not work until the user manually
|
|
119
|
+
// applies a style or refreshes the page
|
|
120
|
+
const defaultStyle = this.editorOptions.styles.find(style => style.def);
|
|
121
|
+
const _class = defaultStyle.class ? ` class="${defaultStyle.class}"` : '';
|
|
122
|
+
return `<${defaultStyle.tag}${_class}></${defaultStyle.tag}>`;
|
|
123
|
+
} else {
|
|
124
|
+
return content;
|
|
125
|
+
}
|
|
111
126
|
},
|
|
112
127
|
toolbar() {
|
|
113
128
|
return this.editorOptions.toolbar;
|
|
@@ -136,7 +151,7 @@ export default {
|
|
|
136
151
|
aposTiptapExtensions() {
|
|
137
152
|
return (apos.tiptapExtensions || [])
|
|
138
153
|
.map(extension => extension({
|
|
139
|
-
styles: this.editorOptions.styles,
|
|
154
|
+
styles: this.editorOptions.styles.map(this.localizeStyle),
|
|
140
155
|
types: this.tiptapTypes
|
|
141
156
|
}));
|
|
142
157
|
}
|
|
@@ -153,7 +168,7 @@ export default {
|
|
|
153
168
|
mounted() {
|
|
154
169
|
this.editor = new Editor({
|
|
155
170
|
content: this.initialContent,
|
|
156
|
-
autofocus:
|
|
171
|
+
autofocus: this.autofocus,
|
|
157
172
|
onUpdate: this.editorUpdate,
|
|
158
173
|
extensions: [
|
|
159
174
|
StarterKit,
|
|
@@ -217,7 +232,6 @@ export default {
|
|
|
217
232
|
// commands and parameters used internally.
|
|
218
233
|
enhanceStyles(styles) {
|
|
219
234
|
const self = this;
|
|
220
|
-
const enhanced = [];
|
|
221
235
|
(styles || []).forEach(style => {
|
|
222
236
|
style.options = {};
|
|
223
237
|
for (const key in self.tiptapTextCommands) {
|
|
@@ -242,9 +256,7 @@ export default {
|
|
|
242
256
|
style.options.class = style.class;
|
|
243
257
|
}
|
|
244
258
|
|
|
245
|
-
if (style.type) {
|
|
246
|
-
enhanced.push(style);
|
|
247
|
-
} else {
|
|
259
|
+
if (!style.type) {
|
|
248
260
|
apos.notify('apostrophe:richTextStyleConfigWarning', {
|
|
249
261
|
type: 'warning',
|
|
250
262
|
dismiss: true,
|
|
@@ -256,7 +268,27 @@ export default {
|
|
|
256
268
|
});
|
|
257
269
|
}
|
|
258
270
|
});
|
|
271
|
+
|
|
272
|
+
// ensure a default so we can rely on it throughout
|
|
273
|
+
const hasDefault = !!styles.find(style => style.def);
|
|
274
|
+
if (!hasDefault && styles.length) {
|
|
275
|
+
// If no dev set default, use the first paragraph we can find
|
|
276
|
+
if (styles.filter(style => style.type === 'paragraph').length) {
|
|
277
|
+
styles.filter(style => style.type === 'paragraph')[0].def = true;
|
|
278
|
+
} else {
|
|
279
|
+
// Otherwise, set the first style
|
|
280
|
+
styles[0].def = true;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
259
283
|
return styles;
|
|
284
|
+
},
|
|
285
|
+
localizeStyle(style) {
|
|
286
|
+
style.label = this.$t(style.label);
|
|
287
|
+
|
|
288
|
+
return {
|
|
289
|
+
...style,
|
|
290
|
+
label: this.$t(style.label)
|
|
291
|
+
};
|
|
260
292
|
}
|
|
261
293
|
}
|
|
262
294
|
};
|
|
@@ -52,6 +52,9 @@ export default {
|
|
|
52
52
|
const style = styles[i];
|
|
53
53
|
if (this.editor.isActive(style.type, (style.options || {}))) {
|
|
54
54
|
return i;
|
|
55
|
+
} else if (this.editor.state.selection.$head.parent.type.name === 'defaultNode' && style.def) {
|
|
56
|
+
// Look deeper to see if custom defaultNode is active
|
|
57
|
+
return i;
|
|
55
58
|
}
|
|
56
59
|
}
|
|
57
60
|
return 0;
|
|
@@ -25,9 +25,7 @@ export default (options) => {
|
|
|
25
25
|
const tag = element.tagName.toLowerCase();
|
|
26
26
|
// This tag is not configured
|
|
27
27
|
if (!allow[tag]) {
|
|
28
|
-
return
|
|
29
|
-
class: null
|
|
30
|
-
};
|
|
28
|
+
return null;
|
|
31
29
|
}
|
|
32
30
|
const classes = (element.getAttribute('class') || '')
|
|
33
31
|
.split(' ')
|
|
@@ -36,13 +34,11 @@ export default (options) => {
|
|
|
36
34
|
// If no valid classes for this parse, default to the
|
|
37
35
|
// the first setting for this tag (including null for tags defined without classes).
|
|
38
36
|
// else, remove classes.
|
|
39
|
-
return
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
:
|
|
43
|
-
|
|
44
|
-
)
|
|
45
|
-
};
|
|
37
|
+
return classes.length
|
|
38
|
+
? classes.join(' ')
|
|
39
|
+
: (
|
|
40
|
+
allow[tag].length ? allow[tag][0] : null
|
|
41
|
+
);
|
|
46
42
|
}
|
|
47
43
|
}
|
|
48
44
|
}
|