apostrophe 4.6.0 → 4.7.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.
Files changed (126) hide show
  1. package/.github/workflows/main.yml +1 -1
  2. package/CHANGELOG.md +47 -1
  3. package/lib/big-upload-client.js +100 -0
  4. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposAdminBar.vue +5 -3
  5. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposAdminBarLocale.vue +6 -3
  6. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposAdminBarUser.vue +4 -1
  7. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposContextBar.vue +24 -16
  8. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposContextTitle.vue +1 -0
  9. package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposSavingIndicator.vue +7 -5
  10. package/modules/@apostrophecms/area/index.js +5 -2
  11. package/modules/@apostrophecms/area/ui/apos/components/AposAreaContextualMenu.vue +27 -15
  12. package/modules/@apostrophecms/area/ui/apos/components/AposAreaExpandedMenu.vue +11 -7
  13. package/modules/@apostrophecms/area/ui/apos/components/AposAreaMenu.vue +25 -12
  14. package/modules/@apostrophecms/area/ui/apos/components/AposAreaMenuItem.vue +3 -1
  15. package/modules/@apostrophecms/area/ui/apos/components/AposAreaWidget.vue +80 -30
  16. package/modules/@apostrophecms/asset/index.js +8 -4
  17. package/modules/@apostrophecms/attachment/index.js +4 -2
  18. package/modules/@apostrophecms/command-menu/ui/apos/components/AposCommandMenuKey.vue +28 -24
  19. package/modules/@apostrophecms/command-menu/ui/apos/components/AposCommandMenuShortcut.vue +17 -11
  20. package/modules/@apostrophecms/doc/index.js +22 -19
  21. package/modules/@apostrophecms/doc-type/index.js +6 -2
  22. package/modules/@apostrophecms/doc-type/ui/apos/components/AposDocEditor.vue +9 -5
  23. package/modules/@apostrophecms/doc-type/ui/apos/components/AposDocLocalePicker.vue +10 -5
  24. package/modules/@apostrophecms/doc-type/ui/apos/logic/AposDocContextMenu.js +12 -0
  25. package/modules/@apostrophecms/http/index.js +19 -3
  26. package/modules/@apostrophecms/http/lib/big-upload-middleware.js +251 -0
  27. package/modules/@apostrophecms/i18n/i18n/de.json +1 -1
  28. package/modules/@apostrophecms/i18n/i18n/en.json +9 -1
  29. package/modules/@apostrophecms/i18n/i18n/es.json +1 -1
  30. package/modules/@apostrophecms/i18n/i18n/fr.json +1 -1
  31. package/modules/@apostrophecms/i18n/i18n/it.json +1 -1
  32. package/modules/@apostrophecms/i18n/i18n/pt-BR.json +1 -1
  33. package/modules/@apostrophecms/i18n/i18n/sk.json +1 -1
  34. package/modules/@apostrophecms/i18n/index.js +3 -0
  35. package/modules/@apostrophecms/i18n/ui/apos/components/AposI18nLocalize.vue +30 -16
  36. package/modules/@apostrophecms/i18n/ui/apos/components/AposI18nLocalizeErrors.vue +7 -5
  37. package/modules/@apostrophecms/image/ui/apos/components/AposImageCropper.vue +5 -1
  38. package/modules/@apostrophecms/image/ui/apos/components/AposImageRelationshipEditor.vue +10 -6
  39. package/modules/@apostrophecms/image/ui/apos/components/AposMediaManager.vue +40 -18
  40. package/modules/@apostrophecms/image/ui/apos/components/AposMediaManagerDisplay.vue +35 -25
  41. package/modules/@apostrophecms/image/ui/apos/components/AposMediaManagerEditor.vue +11 -5
  42. package/modules/@apostrophecms/image/ui/apos/components/AposMediaManagerSelections.vue +15 -9
  43. package/modules/@apostrophecms/image/ui/apos/components/AposMediaUploader.vue +39 -31
  44. package/modules/@apostrophecms/job/index.js +1 -1
  45. package/modules/@apostrophecms/login/ui/apos/components/AposLoginForm.vue +9 -7
  46. package/modules/@apostrophecms/login/ui/apos/components/TheAposLogin.vue +17 -13
  47. package/modules/@apostrophecms/login/ui/apos/components/TheAposLoginHeader.vue +30 -20
  48. package/modules/@apostrophecms/modal/ui/apos/components/AposDocsManagerToolbar.vue +5 -0
  49. package/modules/@apostrophecms/modal/ui/apos/components/AposModal.vue +4 -1
  50. package/modules/@apostrophecms/modal/ui/apos/components/AposModalBreadcrumbs.vue +8 -4
  51. package/modules/@apostrophecms/modal/ui/apos/components/AposModalConfirm.vue +14 -8
  52. package/modules/@apostrophecms/modal/ui/apos/components/AposModalShareDraft.vue +32 -22
  53. package/modules/@apostrophecms/modal/ui/apos/components/AposModalTabs.vue +16 -14
  54. package/modules/@apostrophecms/modal/ui/apos/components/AposWidgetModalTabs.vue +16 -14
  55. package/modules/@apostrophecms/notification/ui/apos/components/AposNotification.vue +93 -91
  56. package/modules/@apostrophecms/page/index.js +482 -13
  57. package/modules/@apostrophecms/page/ui/apos/components/AposPagesManager.vue +43 -23
  58. package/modules/@apostrophecms/page/ui/apos/logic/AposPagesManager.js +248 -156
  59. package/modules/@apostrophecms/permission/ui/apos/components/AposPermissionGrid.vue +9 -5
  60. package/modules/@apostrophecms/piece-type/index.js +7 -7
  61. package/modules/@apostrophecms/piece-type/ui/apos/components/AposDocsManager.vue +92 -36
  62. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposRichTextWidgetEditor.vue +32 -24
  63. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapDivider.vue +4 -2
  64. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapLink.vue +2 -1
  65. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapMarks.vue +5 -3
  66. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapStyles.vue +5 -3
  67. package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapTable.vue +5 -2
  68. package/modules/@apostrophecms/schema/index.js +26 -5
  69. package/modules/@apostrophecms/schema/lib/addFieldTypes.js +42 -9
  70. package/modules/@apostrophecms/schema/ui/apos/components/AposInputColor.vue +4 -2
  71. package/modules/@apostrophecms/schema/ui/apos/components/AposInputRange.vue +8 -4
  72. package/modules/@apostrophecms/schema/ui/apos/components/AposInputRelationship.vue +6 -4
  73. package/modules/@apostrophecms/schema/ui/apos/components/AposInputSlug.vue +5 -3
  74. package/modules/@apostrophecms/schema/ui/apos/components/AposInputWrapper.vue +19 -13
  75. package/modules/@apostrophecms/schema/ui/apos/components/AposSearchList.vue +6 -2
  76. package/modules/@apostrophecms/schema/ui/apos/components/AposSubform.vue +6 -4
  77. package/modules/@apostrophecms/schema/ui/apos/logic/AposInputSlug.js +28 -25
  78. package/modules/@apostrophecms/schema/ui/apos/scss/AposInputArray.scss +13 -7
  79. package/modules/@apostrophecms/settings/ui/apos/components/AposSettingsManager.vue +11 -6
  80. package/modules/@apostrophecms/translation/ui/apos/components/AposTranslationIndicator.vue +5 -3
  81. package/modules/@apostrophecms/ui/ui/apos/components/AposAvatar.vue +14 -12
  82. package/modules/@apostrophecms/ui/ui/apos/components/AposButton.vue +14 -11
  83. package/modules/@apostrophecms/ui/ui/apos/components/AposButtonSplit.vue +7 -3
  84. package/modules/@apostrophecms/ui/ui/apos/components/AposCellContextMenu.vue +4 -2
  85. package/modules/@apostrophecms/ui/ui/apos/components/AposCombo.vue +23 -17
  86. package/modules/@apostrophecms/ui/ui/apos/components/AposContextMenu.vue +41 -18
  87. package/modules/@apostrophecms/ui/ui/apos/components/AposContextMenuDialog.vue +7 -5
  88. package/modules/@apostrophecms/ui/ui/apos/components/AposContextMenuItem.vue +10 -8
  89. package/modules/@apostrophecms/ui/ui/apos/components/AposEmptyState.vue +9 -5
  90. package/modules/@apostrophecms/ui/ui/apos/components/AposFile.vue +9 -6
  91. package/modules/@apostrophecms/ui/ui/apos/components/AposIndicator.vue +5 -0
  92. package/modules/@apostrophecms/ui/ui/apos/components/AposLoadingBlock.vue +3 -1
  93. package/modules/@apostrophecms/ui/ui/apos/components/AposLocale.vue +3 -1
  94. package/modules/@apostrophecms/ui/ui/apos/components/AposLocalePicker.vue +11 -9
  95. package/modules/@apostrophecms/ui/ui/apos/components/AposMinMaxCount.vue +5 -3
  96. package/modules/@apostrophecms/ui/ui/apos/components/AposPager.vue +4 -2
  97. package/modules/@apostrophecms/ui/ui/apos/components/AposPagerDots.vue +8 -6
  98. package/modules/@apostrophecms/ui/ui/apos/components/AposSlat.vue +25 -17
  99. package/modules/@apostrophecms/ui/ui/apos/components/AposSlatList.vue +5 -9
  100. package/modules/@apostrophecms/ui/ui/apos/components/AposSubformPreview.vue +10 -6
  101. package/modules/@apostrophecms/ui/ui/apos/components/AposTag.vue +9 -7
  102. package/modules/@apostrophecms/ui/ui/apos/components/AposTagApply.vue +8 -4
  103. package/modules/@apostrophecms/ui/ui/apos/components/AposTagList.vue +4 -2
  104. package/modules/@apostrophecms/ui/ui/apos/components/AposTagListItem.vue +7 -5
  105. package/modules/@apostrophecms/ui/ui/apos/components/AposToggle.vue +16 -0
  106. package/modules/@apostrophecms/ui/ui/apos/components/AposTree.vue +3 -1
  107. package/modules/@apostrophecms/ui/ui/apos/components/AposTreeRows.vue +11 -9
  108. package/modules/@apostrophecms/ui/ui/apos/mixins/AposArchiveMixin.js +2 -2
  109. package/modules/@apostrophecms/ui/ui/apos/mixins/AposPublishMixin.js +6 -6
  110. package/modules/@apostrophecms/ui/ui/apos/scss/global/_inputs.scss +30 -22
  111. package/modules/@apostrophecms/ui/ui/apos/scss/global/_theme.scss +22 -18
  112. package/modules/@apostrophecms/ui/ui/apos/scss/global/_tooltips.scss +18 -15
  113. package/modules/@apostrophecms/ui/ui/apos/scss/mixins/_input_mixins.scss +8 -6
  114. package/modules/@apostrophecms/ui/ui/apos/scss/mixins/_mixins.scss +3 -1
  115. package/modules/@apostrophecms/ui/ui/apos/scss/mixins/_theme_mixins.scss +34 -19
  116. package/modules/@apostrophecms/ui/ui/apos/scss/mixins/_type_mixins.scss +3 -1
  117. package/modules/@apostrophecms/ui/ui/apos/scss/mixins/_zindex.scss +1 -0
  118. package/modules/@apostrophecms/ui/ui/apos/utils/index.js +140 -51
  119. package/modules/@apostrophecms/widget-type/index.js +3 -2
  120. package/modules/@apostrophecms/widget-type/ui/apos/mixins/AposWidgetMixin.js +5 -1
  121. package/package.json +5 -6
  122. package/test/big-upload.js +111 -0
  123. package/test/change-doc-ids.js +60 -1
  124. package/test/pages.js +488 -0
  125. package/test/schemas.js +327 -0
  126. package/test/utils.js +266 -5
@@ -3,7 +3,7 @@ name: Tests
3
3
  # Controls when the action will run.
4
4
  on:
5
5
  push:
6
- branches: ["main"]
6
+ branches: ["main", "a3"]
7
7
  pull_request:
8
8
  branches: ["*"]
9
9
 
package/CHANGELOG.md CHANGED
@@ -1,15 +1,61 @@
1
1
  # Changelog
2
2
 
3
+ ## 4.7.0 (2024-09-05)
4
+
5
+ ### Adds
6
+
7
+ * To aid debugging, when a file extension is unacceptable as an Apostrophe attachment the rejected extension is now printed as part of the error message.
8
+ * The new `big-upload-client` module can now be used to upload very large files to any route that uses the new `big-upload-middleware`.
9
+ * Add option `skipReplace` for `apos.doc.changeDocIds` method to skip the replacing of the "old" document in the database.
10
+ * The `@apostrophecms/i18n` module now exposes a `locales` HTTP GET API to aid in implementation of native apps for localized sites.
11
+ * Context menus can be supplied a `menuId` so that interested components can listen to their opening/closing.
12
+ * Allow to set mode in `AposWidget` component through props.
13
+ * Add batch operations to pages.
14
+ * Add shortcuts to pages manager.
15
+ * Add `replaces` (boolean, `false` by default) option to the context operation definition (registered via `apos.doc.addContextOperation()`) to allow the operation to require a replace confirmation before being executed. The user confirmation results in the Editor modal being closed and the operation being executed. The operation is not executed if the user cancels the confirmation.
16
+
17
+ ### Changes
18
+
19
+ * Wait for notify before navigating to a new page.
20
+ * Send also `checkedTypes` via the pages body toolbar operations (e.g. 'batch') to the modal.
21
+
22
+ ### Fixes
23
+
24
+ * Fix link to pages in rich-text not showing UI to select page during edit.
25
+ * Bumps `uploadfs` dependency to ensure `.tar.gz`, `.tgz` and `.gz` files uploaded to S3 download without double-gzipping.
26
+ This resolves the issue for new uploads.
27
+ * Registering duplicate icon is no longer breaking the build.
28
+ * Fix widget focus state so that the in-context Add Content menu stays visible during animation
29
+ * Fix UI of areas in schemas so that their context menus are layered overtop sibling schema fields UI
30
+ * Fix unhandled promise rejections and guard against potential memory leaks, remove 3rd party `debounce-async` dependency
31
+ * Adds an option to center the context menu arrow on the button icon. Sets this new option on some context menus in the admin UI.
32
+ * Fixes the update function of `AposSlatLists` so that elements are properly reordered on drag
33
+
34
+ ## 4.6.1 (2024-08-26)
35
+
36
+ ### Fixes
37
+
38
+ * Registering duplicate icon is no longer breaking the build.
39
+ * Fix widget focus state so that the in-context Add Content menu stays visible during animation.
40
+ * Fix UI of areas in schemas so that their context menus are layered overtop sibling schema fields UI.
41
+
3
42
  ## 4.6.0 (2024-08-08)
4
43
 
5
44
  ### Adds
6
45
 
7
46
  * Add a locale switcher in pieces and pages editor modals. This is available for localized documents only, and allows you to switch between locales for the same document.
8
- The locale can be switche at only one level, meaning that sub documents of a document that already switched locale will not be able to switch locale itself.
47
+ The locale can be switched at only one level, meaning that sub documents of a document that already switched locale will not be able to switch locale itself.
9
48
  * Adds visual focus states and keyboard handlers for engaging with areas and widgets in-context
49
+ * Adds method `simulateRelationshipsFromStorage` method in schema module.
50
+ This method populates the relationship field with just enough information to allow convert to accept it. It does not fully fetch the related documents. It does the opposite of prepareForStorage.
51
+ * A new options object has been added to the convert method.
52
+ Setting the `fetchRelationships` option to false will prevent convert from actually fetching relationships to check which related documents currently exist.
53
+ The shape of the relationship field is still validated.
10
54
 
11
55
  ### Changes
12
56
 
57
+ * Refactors Admin UI SASS to eliminate deprecation warnings from declarations coming after nested rules.
58
+ * Bumps the sass-loader version and adds a webpack option to suppress mixed declaration deprecation warnings to be removed when all modules are updated.
13
59
  * Add `title` and `_url` to select all projection.
14
60
  * Display `Select all` message on all pages in the manager modal.
15
61
  * Refresh `checked` in manager modal after archive action.
@@ -0,0 +1,100 @@
1
+ // Upload files in 4MB chunks, well under the typical
2
+ // proxy server limit on POST size
3
+
4
+ const defaultChunkSize = 1024 * 1024 * 4;
5
+
6
+ // Used to upload very large files, large enough that they
7
+ // might exceed the max body size or max uploaded file size
8
+ // configured on a proxy server, etc.
9
+ //
10
+ // `options` is required and may contain a `files` object
11
+ // property containing HTML5 `File` objects. It will become
12
+ // `req.files` on the receiving end, just like with more typical
13
+ // file upload middleware.
14
+ //
15
+ // `qs` and `body` become `req.query` and `req.body` on the
16
+ // receiving end. You may use them for non-file parameters.
17
+ //
18
+ // An existing query string in `url` is NOT supported. Use `qs`.
19
+ //
20
+ // The receiving route must use the `self.apos.http.bigUploadMiddleware`
21
+ // function to obtain the middleware and it must be a `post` route.
22
+ //
23
+ // The query parameter `aposBigUpload` is reserved for internal use.
24
+ //
25
+ // If a `progress` function is supplied, it is periodically invoked
26
+ // with a proportion (between 0.0 and 1.0) as the upload progresses.
27
+ // Be aware the receiving end will typically do quite a bit of processing
28
+ // after that.
29
+ //
30
+ // If `chunkSize` is specified (in bytes) it is used instead of the usual
31
+ // 4MB. The chunk size should be big enough for efficiency but small
32
+ // enough to avoid proxy server POST limits.
33
+ //
34
+ // For testing and server-side use an `http` object and a `FormData` constructor
35
+ // may be specified otherwise the standard Apostrophe `apos.http` object
36
+ // and the browser's `FormData` are used.
37
+
38
+ module.exports = async (url, options) => {
39
+ const chunkSize = options.chunkSize || defaultChunkSize;
40
+ const http = options.http || window.apos?.http;
41
+ const progress = options.progress || (n => {});
42
+ const files = options.files || [];
43
+ const info = {};
44
+ let totalBytes = 0;
45
+ let sentBytes = 0;
46
+ for (const [ param, file ] of Object.entries(files)) {
47
+ totalBytes += file.size;
48
+ info[param] = {
49
+ name: file.name,
50
+ size: file.size,
51
+ chunks: Math.ceil(file.size / chunkSize)
52
+ };
53
+ }
54
+ const { id } = await http.post(url, {
55
+ qs: {
56
+ aposBigUpload: {
57
+ type: 'start'
58
+ }
59
+ },
60
+ body: {
61
+ files: info
62
+ }
63
+ });
64
+ let n = 0;
65
+ for (const file of Object.values(files)) {
66
+ const { size } = file;
67
+ let chunk = 0;
68
+ for (let offset = 0; (offset < size); offset += chunkSize) {
69
+ const formData = new FormData();
70
+ const thisChunkSize = Math.min(chunkSize, size - offset);
71
+ formData.append('chunk', file.slice(offset, offset + thisChunkSize));
72
+ await http.post(url, {
73
+ qs: {
74
+ aposBigUpload: {
75
+ type: 'chunk',
76
+ id,
77
+ n,
78
+ chunk
79
+ }
80
+ },
81
+ body: formData
82
+ });
83
+ sentBytes += thisChunkSize;
84
+ progress(sentBytes / totalBytes);
85
+ chunk++;
86
+ }
87
+ n++;
88
+ }
89
+ const result = await http.post(url, {
90
+ qs: {
91
+ aposBigUpload: {
92
+ type: 'end',
93
+ id
94
+ },
95
+ ...options.qs
96
+ },
97
+ body: options.body
98
+ });
99
+ return result;
100
+ };
@@ -107,9 +107,11 @@ export default {
107
107
  :deep(.apos-admin-bar__control-set) {
108
108
  @include type-base;
109
109
 
110
- display: flex;
111
- width: 100%;
112
- height: 100%;
110
+ & {
111
+ display: flex;
112
+ width: 100%;
113
+ height: 100%;
114
+ }
113
115
  }
114
116
 
115
117
  .apos-admin-bar__user {
@@ -5,6 +5,7 @@
5
5
  identifier="localePickerTrigger"
6
6
  :button="button"
7
7
  :unpadded="true"
8
+ :center-on-icon="true"
8
9
  menu-placement="bottom-end"
9
10
  @open="open"
10
11
  @close="isOpen = false"
@@ -162,9 +163,11 @@ export default {
162
163
  &:deep(.apos-button__label) {
163
164
  @include type-small;
164
165
 
165
- color: var(--a-primary);
166
- font-weight: var(--a-weight-bold);
167
- letter-spacing: 1px;
166
+ & {
167
+ color: var(--a-primary);
168
+ font-weight: var(--a-weight-bold);
169
+ letter-spacing: 1px;
170
+ }
168
171
  }
169
172
  }
170
173
  </style>
@@ -3,6 +3,7 @@
3
3
  class="apos-admin-user"
4
4
  :button="button"
5
5
  :menu="items"
6
+ :center-on-icon="true"
6
7
  menu-placement="bottom-end"
7
8
  @item-clicked="emitEvent"
8
9
  >
@@ -57,7 +58,9 @@ export default {
57
58
  :deep(.apos-button) {
58
59
  @include type-base;
59
60
 
60
- color: var(--a-text-primary);
61
+ & {
62
+ color: var(--a-text-primary);
63
+ }
61
64
  }
62
65
 
63
66
  :deep(.apos-context-menu__popup) {
@@ -615,7 +615,7 @@ export default {
615
615
  body: {},
616
616
  busy: true
617
617
  });
618
- apos.notify('apostrophe:restoredPrevious', {
618
+ await apos.notify('apostrophe:restoredPrevious', {
619
619
  type: 'success',
620
620
  dismiss: true
621
621
  });
@@ -720,14 +720,18 @@ export default {
720
720
  async updateDraftIsEditable() {
721
721
  if (this.context.aposLocale && this.context.aposLocale.endsWith('published') && !this.context._edit) {
722
722
  // A contributor might be able to edit the draft
723
- const draftContext = await apos.http.get(`${this.action}/${this.context._id}`, {
724
- busy: true,
725
- qs: {
726
- aposMode: 'draft',
727
- aposLocale: this.context.aposLocale.split(':')[0]
728
- }
729
- });
730
- this.draftIsEditable = draftContext && draftContext._edit;
723
+ try {
724
+ const draftContext = await apos.http.get(`${this.action}/${this.context._id}`, {
725
+ busy: true,
726
+ qs: {
727
+ aposMode: 'draft',
728
+ aposLocale: this.context.aposLocale.split(':')[0]
729
+ }
730
+ });
731
+ this.draftIsEditable = draftContext && draftContext._edit;
732
+ } catch (e) {
733
+ console.error(e);
734
+ }
731
735
  }
732
736
  },
733
737
  async getPublished() {
@@ -735,13 +739,17 @@ export default {
735
739
  const manuallyPublished = moduleOptions.localized && !this.autopublish;
736
740
  if (manuallyPublished && this.context.lastPublishedAt) {
737
741
  const action = window.apos.modules[this.context.type].action;
738
- const doc = await apos.http.get(`${action}/${this.context._id}`, {
739
- busy: true,
740
- qs: {
741
- aposMode: 'published'
742
- }
743
- });
744
- return doc;
742
+ try {
743
+ const doc = await apos.http.get(`${action}/${this.context._id}`, {
744
+ busy: true,
745
+ qs: {
746
+ aposMode: 'published'
747
+ }
748
+ });
749
+ return doc;
750
+ } catch (error) {
751
+ console.error(error);
752
+ }
745
753
  }
746
754
  return null;
747
755
  },
@@ -31,6 +31,7 @@
31
31
  :button="draftButton"
32
32
  :menu="draftMenu"
33
33
  :disabled="hasCustomUi || isUnpublished"
34
+ :center-on-icon="true"
34
35
  menu-placement="bottom-end"
35
36
  @item-clicked="switchDraftMode"
36
37
  />
@@ -122,11 +122,13 @@ export default {
122
122
  .apos-admin-bar__status {
123
123
  @include type-help;
124
124
 
125
- position: relative;
126
- margin-left: 7.5px;
127
- opacity: 1;
128
- color: var(--a-base-2);
129
- transition: opacity 200ms;
125
+ & {
126
+ position: relative;
127
+ margin-left: 7.5px;
128
+ opacity: 1;
129
+ color: var(--a-base-2);
130
+ transition: opacity 200ms;
131
+ }
130
132
 
131
133
  &.apos-is-hidden {
132
134
  opacity: 0;
@@ -294,12 +294,15 @@ module.exports = {
294
294
  // options to sanitize against. Thus h5 can be legal
295
295
  // in one rich text widget and not in another.
296
296
  //
297
+ // The `convertOptions` parameter allows to pass options
298
+ // to the convert method to alter them.
299
+ //
297
300
  // If any errors occur sanitizing the individual widgets,
298
301
  // an array of errors with `path` and `error` properties
299
302
  // is thrown.
300
303
  //
301
304
  // Returns a new array of sanitized items.
302
- async sanitizeItems(req, items, options) {
305
+ async sanitizeItems(req, items, options, convertOptions = {}) {
303
306
  options = options || {};
304
307
  const result = [];
305
308
  const errors = [];
@@ -322,7 +325,7 @@ module.exports = {
322
325
  }
323
326
  let newItem;
324
327
  try {
325
- newItem = await manager.sanitize(req, item, widgetOptions);
328
+ newItem = await manager.sanitize(req, item, widgetOptions, convertOptions);
326
329
  newItem._id = self.apos.launder.id(item._id) || self.apos.util.generateId();
327
330
  } catch (e) {
328
331
  if (Array.isArray(e)) {
@@ -6,6 +6,7 @@
6
6
  :disabled="isDisabled"
7
7
  :button="buttonOptions"
8
8
  :popover-modifiers="inContext ? ['z-index-in-context'] : []"
9
+ :menu-id="menuId"
9
10
  >
10
11
  <ul class="apos-area-menu__wrapper">
11
12
  <li
@@ -117,6 +118,12 @@ export default {
117
118
  default: function() {
118
119
  return {};
119
120
  }
121
+ },
122
+ menuId: {
123
+ type: String,
124
+ default() {
125
+ return `areaMenu-${createId()}`;
126
+ }
120
127
  }
121
128
  },
122
129
  emits: [ 'add' ],
@@ -182,9 +189,6 @@ export default {
182
189
  } else {
183
190
  return menu;
184
191
  }
185
- },
186
- menuId() {
187
- return `areaMenu-${createId()}`;
188
192
  }
189
193
  },
190
194
  mounted() {
@@ -295,10 +299,12 @@ export default {
295
299
  @include apos-button-reset();
296
300
  @include type-base;
297
301
 
298
- box-sizing: border-box;
299
- width: 100%;
300
- padding: 5px 20px;
301
- color: var(--a-base-1);
302
+ & {
303
+ box-sizing: border-box;
304
+ width: 100%;
305
+ padding: 5px 20px;
306
+ color: var(--a-base-1);
307
+ }
302
308
 
303
309
  &:hover,
304
310
  &:focus {
@@ -331,11 +337,13 @@ export default {
331
337
  .apos-area-menu__group-label {
332
338
  @include apos-button-reset();
333
339
 
334
- display: flex;
335
- box-sizing: border-box;
336
- justify-content: space-between;
337
- width: 100%;
338
- padding: 10px 20px;
340
+ & {
341
+ display: flex;
342
+ box-sizing: border-box;
343
+ justify-content: space-between;
344
+ width: 100%;
345
+ padding: 10px 20px;
346
+ }
339
347
 
340
348
  &:hover {
341
349
  cursor: pointer;
@@ -350,7 +358,9 @@ export default {
350
358
  .apos-area-menu__group-chevron {
351
359
  @include apos-transition();
352
360
 
353
- transform: rotate(90deg);
361
+ & {
362
+ transform: rotate(90deg);
363
+ }
354
364
  }
355
365
 
356
366
  .apos-area-menu__group-chevron.apos-is-active {
@@ -371,8 +381,10 @@ export default {
371
381
  .apos-area-menu__items--accordion {
372
382
  @include apos-transition($duration:0.3s);
373
383
 
374
- overflow: hidden;
375
- max-height: 0;
384
+ & {
385
+ overflow: hidden;
386
+ max-height: 0;
387
+ }
376
388
  }
377
389
 
378
390
  .apos-area-menu__items--accordion.apos-is-active {
@@ -256,10 +256,12 @@ export default {
256
256
  .apos-widget {
257
257
  @include type-base;
258
258
 
259
- padding: 0;
260
- border: none;
261
- background: none;
262
- text-align: inherit;
259
+ & {
260
+ padding: 0;
261
+ border: none;
262
+ background: none;
263
+ text-align: inherit;
264
+ }
263
265
 
264
266
  .apos-widget__preview {
265
267
  transition: opacity 250ms ease-in-out;
@@ -316,9 +318,11 @@ export default {
316
318
  .apos-widget__help {
317
319
  @include type-base;
318
320
 
319
- margin-top: 0;
320
- line-height: var(--a-line-tall);
321
- text-align: left;
321
+ & {
322
+ margin-top: 0;
323
+ line-height: var(--a-line-tall);
324
+ text-align: left;
325
+ }
322
326
  }
323
327
 
324
328
  .apos-widget__help {
@@ -16,6 +16,7 @@
16
16
  :options="options"
17
17
  :max-reached="maxReached"
18
18
  :disabled="disabled"
19
+ :menu-id="menuId"
19
20
  @add="$emit('add', $event);"
20
21
  />
21
22
  </template>
@@ -58,6 +59,10 @@ export default {
58
59
  tabbable: {
59
60
  type: Boolean,
60
61
  default: false
62
+ },
63
+ menuId: {
64
+ type: String,
65
+ default: null
61
66
  }
62
67
  },
63
68
  emits: [ 'add' ],
@@ -113,10 +118,12 @@ export default {
113
118
  @include apos-button-reset();
114
119
  @include type-base;
115
120
 
116
- box-sizing: border-box;
117
- width: 100%;
118
- padding: 5px 20px;
119
- color: var(--a-base-1);
121
+ & {
122
+ box-sizing: border-box;
123
+ width: 100%;
124
+ padding: 5px 20px;
125
+ color: var(--a-base-1);
126
+ }
120
127
 
121
128
  &:hover,
122
129
  &:focus {
@@ -149,11 +156,13 @@ export default {
149
156
  .apos-area-menu__group-label {
150
157
  @include apos-button-reset();
151
158
 
152
- display: flex;
153
- box-sizing: border-box;
154
- justify-content: space-between;
155
- width: 100%;
156
- padding: 10px 20px;
159
+ & {
160
+ display: flex;
161
+ box-sizing: border-box;
162
+ justify-content: space-between;
163
+ width: 100%;
164
+ padding: 10px 20px;
165
+ }
157
166
 
158
167
  &:hover {
159
168
  cursor: pointer;
@@ -168,7 +177,9 @@ export default {
168
177
  .apos-area-menu__group-chevron {
169
178
  @include apos-transition();
170
179
 
171
- transform: rotate(90deg);
180
+ & {
181
+ transform: rotate(90deg);
182
+ }
172
183
  }
173
184
 
174
185
  .apos-area-menu__group-chevron.apos-is-active {
@@ -189,8 +200,10 @@ export default {
189
200
  .apos-area-menu__items--accordion {
190
201
  @include apos-transition($duration:0.3s);
191
202
 
192
- overflow: hidden;
193
- max-height: 0;
203
+ & {
204
+ overflow: hidden;
205
+ max-height: 0;
206
+ }
194
207
  }
195
208
 
196
209
  .apos-area-menu__items--accordion.apos-is-active {
@@ -67,7 +67,9 @@ export default {
67
67
  .apos-area-menu__item-icon {
68
68
  @include apos-align-icon();
69
69
 
70
- margin-right: 10px;
70
+ & {
71
+ margin-right: 10px;
72
+ }
71
73
  }
72
74
 
73
75
  .apos-area-menu__item-content {