apostrophe 4.26.0 → 4.27.0-alpha.1
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 +12 -0
- package/lib/locales.js +10 -0
- package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposAdminBar.vue +11 -1
- package/modules/@apostrophecms/area/ui/apos/components/AposAreaWidget.vue +12 -1
- package/modules/@apostrophecms/box-field/index.js +4 -0
- package/modules/@apostrophecms/box-field/ui/apos/components/AposInputBox.vue +2 -2
- package/modules/@apostrophecms/box-field/ui/apos/logic/AposInputBox.js +12 -4
- package/modules/@apostrophecms/command-menu/ui/apos/components/TheAposCommandMenu.vue +11 -3
- package/modules/@apostrophecms/i18n/index.js +25 -3
- package/modules/@apostrophecms/modal/ui/apos/apps/AposModals.js +1 -0
- package/modules/@apostrophecms/modal/ui/apos/components/AposModal.vue +6 -1
- package/modules/@apostrophecms/notification/ui/apos/components/AposNotification.vue +8 -1
- package/modules/@apostrophecms/rich-text-widget/index.js +12 -0
- package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposRichTextWidgetEditor.vue +21 -2
- package/modules/@apostrophecms/schema/lib/addFieldTypes.js +36 -0
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputDateAndTime.vue +2 -2
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputPassword.vue +1 -0
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputRange.vue +1 -1
- package/modules/@apostrophecms/schema/ui/apos/logic/AposInputDateAndTime.js +12 -3
- package/modules/@apostrophecms/schema/ui/apos/logic/AposInputPassword.js +7 -4
- package/modules/@apostrophecms/schema/ui/apos/logic/AposInputRange.js +6 -2
- package/modules/@apostrophecms/schema/ui/apos/logic/AposInputSlug.js +34 -14
- package/modules/@apostrophecms/schema/ui/apos/logic/AposInputString.js +16 -8
- package/modules/@apostrophecms/schema/ui/apos/mixins/AposFieldDirection.js +16 -0
- package/modules/@apostrophecms/template/views/outerLayoutBase.html +1 -1
- package/modules/@apostrophecms/ui/ui/apos/components/AposContextMenu.vue +17 -1
- package/modules/@apostrophecms/ui/ui/apos/scss/global/_utilities.scss +8 -0
- package/modules/@apostrophecms/ui/ui/apos/stores/modal.js +57 -0
- package/package.json +5 -5
- package/test/content-i18n.js +7 -5
- package/test/i18n.js +77 -5
- package/test/modules/default-page/views/page.html +1 -1
- package/test/modules/i18n-test-page/views/page.html +6 -0
- package/test/schemas.js +392 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 4.27.0-alpha.1
|
|
4
|
+
|
|
5
|
+
### Adds
|
|
6
|
+
|
|
7
|
+
- In `@apostrophecms/i18n` add `direction` property to locale configuration to support RTL languages (e.g., `he`, `ar`), `slugDirection` option to control default direction of slug fields. Add `direction` property in the schema field definitions to override and validate text direction (supports `ltr` and `rtl`) of input fields. Note that the admin UI layout and labels overall are still LTR only for now, but these changes accommodate editing RTL locale content within that. For best results the feature should be combined with `adminLocales` and `defaultAdminLocale` module options, e.g. the admin UI itself should remain in English or another LTR language for now.
|
|
8
|
+
|
|
9
|
+
## 4.26.1-alpha.1
|
|
10
|
+
|
|
11
|
+
### Fixes
|
|
12
|
+
|
|
13
|
+
- Fix a bug where rich text images and permalinks are not properly rendered in public external front (e.g. Astro) views.
|
|
14
|
+
|
|
3
15
|
## 4.26.0
|
|
4
16
|
|
|
5
17
|
### Adds
|
package/lib/locales.js
CHANGED
|
@@ -10,6 +10,16 @@ module.exports = {
|
|
|
10
10
|
const hostname = options.hostname || '__none';
|
|
11
11
|
const prefix = options.prefix || '__none';
|
|
12
12
|
const key = `${hostname}:${prefix}`;
|
|
13
|
+
const direction = options.direction;
|
|
14
|
+
|
|
15
|
+
// Note that default `ltr` directions should have been set
|
|
16
|
+
// already by the `getLocales` method in the i18n module.
|
|
17
|
+
if ([ 'ltr', 'rtl' ].indexOf(direction) === -1) {
|
|
18
|
+
throw new Error(stripIndent`
|
|
19
|
+
The locale "${name}" has an invalid direction option "${direction || 'undefined'}".
|
|
20
|
+
The direction option must be either "ltr" (left to right) or "rtl" (right to left).
|
|
21
|
+
`);
|
|
22
|
+
}
|
|
13
23
|
|
|
14
24
|
hostnamesCount += options.hostname ? 1 : 0;
|
|
15
25
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
/>
|
|
11
11
|
<nav
|
|
12
12
|
ref="adminBar"
|
|
13
|
-
class="
|
|
13
|
+
:class="classes"
|
|
14
14
|
role="menubar"
|
|
15
15
|
aria-label="Apostrophe Admin Bar"
|
|
16
16
|
>
|
|
@@ -36,7 +36,9 @@
|
|
|
36
36
|
</template>
|
|
37
37
|
|
|
38
38
|
<script>
|
|
39
|
+
import { mapState } from 'pinia';
|
|
39
40
|
import AposThemeMixin from 'Modules/@apostrophecms/ui/mixins/AposThemeMixin';
|
|
41
|
+
import { useModalStore } from 'Modules/@apostrophecms/ui/stores/modal';
|
|
40
42
|
|
|
41
43
|
export default {
|
|
42
44
|
name: 'TheAposAdminBar',
|
|
@@ -48,6 +50,7 @@ export default {
|
|
|
48
50
|
}
|
|
49
51
|
},
|
|
50
52
|
computed: {
|
|
53
|
+
...mapState(useModalStore, [ 'getAdminDirectionClass' ]),
|
|
51
54
|
menuItems() {
|
|
52
55
|
return this.items.filter(item => !item.options?.user);
|
|
53
56
|
},
|
|
@@ -59,6 +62,13 @@ export default {
|
|
|
59
62
|
},
|
|
60
63
|
bars() {
|
|
61
64
|
return this.moduleOptions.bars;
|
|
65
|
+
},
|
|
66
|
+
classes() {
|
|
67
|
+
const directionClass = this.getAdminDirectionClass();
|
|
68
|
+
return {
|
|
69
|
+
'apos-admin-bar': true,
|
|
70
|
+
[directionClass]: !!directionClass
|
|
71
|
+
};
|
|
62
72
|
}
|
|
63
73
|
},
|
|
64
74
|
mounted() {
|
|
@@ -149,6 +149,7 @@
|
|
|
149
149
|
:is="widgetEditorComponent(widget.type)"
|
|
150
150
|
v-if="isContextual && !foreign"
|
|
151
151
|
:key="generation"
|
|
152
|
+
:class="adminContentDirectionClass"
|
|
152
153
|
:options="widgetOptions"
|
|
153
154
|
:type="widget.type"
|
|
154
155
|
:model-value="widget"
|
|
@@ -163,6 +164,7 @@
|
|
|
163
164
|
v-else
|
|
164
165
|
:id="widget._id"
|
|
165
166
|
:key="`${generation}-preview`"
|
|
167
|
+
:class="adminContentDirectionClass"
|
|
166
168
|
:options="widgetOptions"
|
|
167
169
|
:type="widget.type"
|
|
168
170
|
:area-field-id="fieldId"
|
|
@@ -209,6 +211,8 @@
|
|
|
209
211
|
import { mapState, mapActions } from 'pinia';
|
|
210
212
|
import { useWidgetStore } from 'Modules/@apostrophecms/ui/stores/widget';
|
|
211
213
|
import { useBreakpointPreviewStore } from 'Modules/@apostrophecms/ui/stores/breakpointPreview.js';
|
|
214
|
+
import { useModalStore } from 'Modules/@apostrophecms/ui/stores/modal.js';
|
|
215
|
+
|
|
212
216
|
export default {
|
|
213
217
|
name: 'AposAreaWidget',
|
|
214
218
|
props: {
|
|
@@ -356,6 +360,9 @@ export default {
|
|
|
356
360
|
'emphasizedWidgets'
|
|
357
361
|
]),
|
|
358
362
|
...mapState(useBreakpointPreviewStore, { breakpointPreviewMode: 'mode' }),
|
|
363
|
+
adminContentDirectionClass() {
|
|
364
|
+
return this.getAdminContentDirectionClass();
|
|
365
|
+
},
|
|
359
366
|
// Passed only to the preview layer (custom preview components).
|
|
360
367
|
followingValuesWithParent() {
|
|
361
368
|
return Object.entries(this.followingValues || {})
|
|
@@ -440,7 +447,10 @@ export default {
|
|
|
440
447
|
},
|
|
441
448
|
labelsClasses() {
|
|
442
449
|
return {
|
|
443
|
-
[this.classes.show]: this.isHovered || this.isFocused || this.isEmphasized
|
|
450
|
+
[this.classes.show]: this.isHovered || this.isFocused || this.isEmphasized,
|
|
451
|
+
// Force LTR for breadcrumbs for now so that nested AreaWidgets
|
|
452
|
+
// behave properly.
|
|
453
|
+
'apos-ltr': true
|
|
444
454
|
};
|
|
445
455
|
},
|
|
446
456
|
addClasses() {
|
|
@@ -544,6 +554,7 @@ export default {
|
|
|
544
554
|
},
|
|
545
555
|
methods: {
|
|
546
556
|
...mapActions(useWidgetStore, [ 'setFocusedWidget', 'setHoveredWidget' ]),
|
|
557
|
+
...mapActions(useModalStore, [ 'getAdminContentDirectionClass' ]),
|
|
547
558
|
// Emits same actions as the native operations,
|
|
548
559
|
// e.g ('edit', { index }), ('remove', { index }), etc.
|
|
549
560
|
onOperation({ name, payload }) {
|
|
@@ -64,6 +64,10 @@ module.exports = {
|
|
|
64
64
|
const defProps = [ 'top', 'right', 'bottom', 'left' ];
|
|
65
65
|
let defMin = 0;
|
|
66
66
|
|
|
67
|
+
if (field.direction && ![ 'ltr', 'rtl' ].includes(field.direction)) {
|
|
68
|
+
fail('The direction property must be "ltr" or "rtl" if specified');
|
|
69
|
+
}
|
|
70
|
+
|
|
67
71
|
if (field.max && typeof field.max !== 'number') {
|
|
68
72
|
fail('Property "max" must be a number');
|
|
69
73
|
}
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
v-model="shorthand"
|
|
17
17
|
type="number"
|
|
18
18
|
placeholder="--"
|
|
19
|
-
class="
|
|
19
|
+
:class="classesShorthand"
|
|
20
20
|
data-apos-test="box-input-all"
|
|
21
21
|
:aria-label="`${$t(field.label)} ${$t('apostrophe:boxFieldAriaLabelAll')}`"
|
|
22
22
|
:disabled="field.readOnly || field.disabled || mode === 'individual'"
|
|
@@ -96,7 +96,7 @@
|
|
|
96
96
|
class="apos-input-box__individual-input apos-input apos-input--number"
|
|
97
97
|
:data-apos-test="`box-input-side-${side}`"
|
|
98
98
|
:aria-label="`${$t(field.label)} ${$t('apostrophe:boxFieldAriaLabelIndividual', { side })}`"
|
|
99
|
-
:class="`apos-input-box__individual-input--${side}
|
|
99
|
+
:class="[ `apos-input-box__individual-input--${side}`, ...classesIndividual ]"
|
|
100
100
|
:disabled="field.readOnly || field.disabled"
|
|
101
101
|
:min="field.min"
|
|
102
102
|
:max="field.max ? field.max : null"
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import AposInputMixin from 'Modules/@apostrophecms/schema/mixins/AposInputMixin';
|
|
2
|
+
import AposFieldDirectionMixin from 'Modules/@apostrophecms/schema/mixins/AposFieldDirection.js';
|
|
2
3
|
|
|
3
4
|
export default {
|
|
4
5
|
name: 'AposInputBox',
|
|
5
|
-
mixins: [ AposInputMixin ],
|
|
6
|
+
mixins: [ AposInputMixin, AposFieldDirectionMixin ],
|
|
6
7
|
emits: [ 'return' ],
|
|
7
8
|
props: {
|
|
8
9
|
},
|
|
@@ -38,11 +39,18 @@ export default {
|
|
|
38
39
|
tabindex () {
|
|
39
40
|
return this.field.disableFocus ? '-1' : '0';
|
|
40
41
|
},
|
|
41
|
-
|
|
42
|
+
classesShorthand() {
|
|
42
43
|
return [
|
|
44
|
+
'apos-input-box__shorthand-input',
|
|
43
45
|
'apos-input',
|
|
44
|
-
'apos-input--
|
|
45
|
-
|
|
46
|
+
'apos-input--number',
|
|
47
|
+
this.directionClass
|
|
48
|
+
].filter(Boolean);
|
|
49
|
+
},
|
|
50
|
+
classesIndividual() {
|
|
51
|
+
return [
|
|
52
|
+
this.directionClass
|
|
53
|
+
].filter(Boolean);
|
|
46
54
|
}
|
|
47
55
|
},
|
|
48
56
|
mounted() {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
|
-
class="
|
|
4
|
-
:class="themeClass"
|
|
3
|
+
:class="classes"
|
|
5
4
|
>
|
|
6
5
|
<!-- nothing for the moment -->
|
|
7
6
|
</div>
|
|
@@ -30,7 +29,16 @@ export default {
|
|
|
30
29
|
};
|
|
31
30
|
},
|
|
32
31
|
computed: {
|
|
33
|
-
...mapState(useModalStore, [ 'stack' ]),
|
|
32
|
+
...mapState(useModalStore, [ 'stack', 'getAdminDirectionClass' ]),
|
|
33
|
+
classes() {
|
|
34
|
+
const directionClass = this.getAdminDirectionClass();
|
|
35
|
+
const classes = this.themeClass;
|
|
36
|
+
classes.push('apos-command-menu');
|
|
37
|
+
if (directionClass) {
|
|
38
|
+
classes.push(directionClass);
|
|
39
|
+
}
|
|
40
|
+
return classes;
|
|
41
|
+
},
|
|
34
42
|
shortcuts() {
|
|
35
43
|
const modals = Object.values(this.modals[this.modal] || {});
|
|
36
44
|
|
|
@@ -32,6 +32,11 @@
|
|
|
32
32
|
// ### `encoding`
|
|
33
33
|
//
|
|
34
34
|
// Defaults to `'utf-8'`. You almost certainly do not want to change this.
|
|
35
|
+
//
|
|
36
|
+
// ### `slugDirection`
|
|
37
|
+
//
|
|
38
|
+
// Controls the default `direction` value of slug schema. Can be `ltr`, `rtl` or
|
|
39
|
+
// `undefined|null` to not set a default. Defaults to `ltr`.
|
|
35
40
|
|
|
36
41
|
const i18next = require('i18next');
|
|
37
42
|
const fs = require('fs');
|
|
@@ -77,7 +82,8 @@ module.exports = {
|
|
|
77
82
|
// If true, slugifying will strip accents from Latin characters
|
|
78
83
|
stripUrlAccents: false,
|
|
79
84
|
// You almost certainly do not want to change this
|
|
80
|
-
encoding: 'utf-8'
|
|
85
|
+
encoding: 'utf-8',
|
|
86
|
+
slugDirection: 'ltr'
|
|
81
87
|
},
|
|
82
88
|
async init(self) {
|
|
83
89
|
self.defaultNamespace = 'default';
|
|
@@ -93,6 +99,12 @@ module.exports = {
|
|
|
93
99
|
// If adminLocales are configured, it should be one of them. Otherwise,
|
|
94
100
|
// it can be any valid locale string identifier.
|
|
95
101
|
self.defaultAdminLocale = self.options.defaultAdminLocale || null;
|
|
102
|
+
if (self.options.slugDirection && ![ 'ltr', 'rtl' ].includes(self.options.slugDirection)) {
|
|
103
|
+
throw self.apos.error(
|
|
104
|
+
'invalid',
|
|
105
|
+
`The "slugDirection" option of "${self.__meta.name}" module must be "ltr", "rtl" or "null".`
|
|
106
|
+
);
|
|
107
|
+
}
|
|
96
108
|
// Lint the locale configurations
|
|
97
109
|
for (const [ key, options ] of Object.entries(self.locales)) {
|
|
98
110
|
if (!options) {
|
|
@@ -175,6 +187,12 @@ module.exports = {
|
|
|
175
187
|
// The array is provided in the order in which locales are configured.
|
|
176
188
|
// The current locale is included and has the property `current: true`.
|
|
177
189
|
async addLocalizations(req) {
|
|
190
|
+
const locale = req.locale || self.defaultLocale;
|
|
191
|
+
req.data.i18n = {
|
|
192
|
+
locale,
|
|
193
|
+
direction: self.locales[locale]?.direction || 'ltr',
|
|
194
|
+
label: self.locales[locale]?.label || locale
|
|
195
|
+
};
|
|
178
196
|
const context = req.data.piece || req.data.page;
|
|
179
197
|
if (!context) {
|
|
180
198
|
return;
|
|
@@ -212,6 +230,7 @@ module.exports = {
|
|
|
212
230
|
const info = doc || {};
|
|
213
231
|
info.locale = name;
|
|
214
232
|
info.label = self.locales[name].label;
|
|
233
|
+
info.direction = self.locales[name].direction;
|
|
215
234
|
info.homePageUrl = `${localeReq.prefix}/`;
|
|
216
235
|
req.data.localizations.push(info);
|
|
217
236
|
}
|
|
@@ -686,7 +705,8 @@ module.exports = {
|
|
|
686
705
|
show: self.show,
|
|
687
706
|
action: self.action,
|
|
688
707
|
crossDomainClipboard: req.session && req.session.aposCrossDomainClipboard,
|
|
689
|
-
stripUrlAccents: self.options.stripUrlAccents
|
|
708
|
+
stripUrlAccents: self.options.stripUrlAccents,
|
|
709
|
+
slugDirection: self.options.slugDirection
|
|
690
710
|
};
|
|
691
711
|
if (req.session && req.session.aposCrossDomainClipboard) {
|
|
692
712
|
req.session.aposCrossDomainClipboard = null;
|
|
@@ -715,11 +735,13 @@ module.exports = {
|
|
|
715
735
|
getLocales() {
|
|
716
736
|
const locales = self.options.locales || {
|
|
717
737
|
en: {
|
|
718
|
-
label: 'English'
|
|
738
|
+
label: 'English',
|
|
739
|
+
direction: 'ltr'
|
|
719
740
|
}
|
|
720
741
|
};
|
|
721
742
|
for (const locale in locales) {
|
|
722
743
|
locales[locale]._edit = true;
|
|
744
|
+
locales[locale].direction ??= 'ltr';
|
|
723
745
|
}
|
|
724
746
|
verifyLocales(locales, self.apos.options.baseUrl);
|
|
725
747
|
return locales;
|
|
@@ -18,6 +18,7 @@ export default function() {
|
|
|
18
18
|
apos.modal.getProperties = modalStore.getProperties;
|
|
19
19
|
apos.modal.onTopOf = modalStore.onTopOf;
|
|
20
20
|
apos.modal.getActiveLocale = modalStore.getActiveLocale;
|
|
21
|
+
apos.modal.getAdminDirectionClass = modalStore.getAdminDirectionClass;
|
|
21
22
|
apos.confirm = modalStore.confirm;
|
|
22
23
|
apos.alert = modalStore.alert;
|
|
23
24
|
apos.report = modalStore.report;
|
|
@@ -211,6 +211,7 @@ function hasSlot(slotName) {
|
|
|
211
211
|
}
|
|
212
212
|
|
|
213
213
|
const classes = computed(() => {
|
|
214
|
+
const directionClass = store.getAdminDirectionClass();
|
|
214
215
|
const classes = [ 'apos-modal' ];
|
|
215
216
|
classes.push(`apos-modal--${props.modal.type}`);
|
|
216
217
|
if (props.modal.type === 'slide') {
|
|
@@ -224,7 +225,11 @@ const classes = computed(() => {
|
|
|
224
225
|
if (props.modal.busy) {
|
|
225
226
|
classes.push('apos-modal--busy');
|
|
226
227
|
}
|
|
227
|
-
|
|
228
|
+
if (directionClass) {
|
|
229
|
+
classes.push(directionClass);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return classes;
|
|
228
233
|
});
|
|
229
234
|
|
|
230
235
|
const innerClasses = computed(() => {
|
|
@@ -66,6 +66,7 @@ import {
|
|
|
66
66
|
} from 'vue';
|
|
67
67
|
import Close from '@apostrophecms/vue-material-design-icons/Close.vue';
|
|
68
68
|
import { useNotificationStore } from 'Modules/@apostrophecms/ui/stores/notification.js';
|
|
69
|
+
import { useModalStore } from 'Modules/@apostrophecms/ui/stores/modal.js';
|
|
69
70
|
|
|
70
71
|
const props = defineProps({
|
|
71
72
|
notification: {
|
|
@@ -77,6 +78,7 @@ const props = defineProps({
|
|
|
77
78
|
const $t = inject('i18n');
|
|
78
79
|
const emit = defineEmits([ 'close' ]);
|
|
79
80
|
const store = useNotificationStore();
|
|
81
|
+
const modalStore = useModalStore();
|
|
80
82
|
|
|
81
83
|
const hasJob = props.notification.job && props.notification.job._id;
|
|
82
84
|
const job = ref(
|
|
@@ -96,6 +98,7 @@ const process = computed(() => {
|
|
|
96
98
|
|
|
97
99
|
const classList = computed(() => {
|
|
98
100
|
const classes = [ 'apos-notification' ];
|
|
101
|
+
const directionClass = modalStore.getAdminDirectionClass();
|
|
99
102
|
|
|
100
103
|
if (Array.isArray(props.notification.classes) && props.notification.classes.length) {
|
|
101
104
|
classes.push(...props.notification.classes);
|
|
@@ -119,7 +122,11 @@ const classList = computed(() => {
|
|
|
119
122
|
classes.push('apos-notification--long');
|
|
120
123
|
}
|
|
121
124
|
|
|
122
|
-
|
|
125
|
+
if (directionClass) {
|
|
126
|
+
classes.push(directionClass);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return classes;
|
|
123
130
|
});
|
|
124
131
|
|
|
125
132
|
const iconComponent = computed(() => {
|
|
@@ -1152,6 +1152,18 @@ module.exports = {
|
|
|
1152
1152
|
};
|
|
1153
1153
|
return _super(req, _widget, options, _with);
|
|
1154
1154
|
},
|
|
1155
|
+
annotateWidgetForExternalFront(_super, widget, { scene } = {}) {
|
|
1156
|
+
if (scene !== 'apos') {
|
|
1157
|
+
let content = widget.content || '';
|
|
1158
|
+
content = self.linkPermalinks(widget, content);
|
|
1159
|
+
content = self.linkImages(widget, content);
|
|
1160
|
+
// It should be safe to modify the widget data here because
|
|
1161
|
+
// the external front-end data is read-only. The Admin UI
|
|
1162
|
+
// and actual data is not affected.
|
|
1163
|
+
widget.content = content;
|
|
1164
|
+
}
|
|
1165
|
+
return _super(widget, { scene });
|
|
1166
|
+
},
|
|
1155
1167
|
// Add on the core default options to use, if needed.
|
|
1156
1168
|
getBrowserData(_super, req) {
|
|
1157
1169
|
const initialData = _super(req);
|
package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposRichTextWidgetEditor.vue
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
>
|
|
25
25
|
<AposContextMenuDialog
|
|
26
26
|
menu-placement="top"
|
|
27
|
-
class-list="
|
|
27
|
+
:class-list="contextMenuClasses"
|
|
28
28
|
:has-tip="false"
|
|
29
29
|
>
|
|
30
30
|
<div
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
:id="`insert-menu-${modelValue._id}`"
|
|
52
52
|
ref="insertMenu"
|
|
53
53
|
plugin-key="insertMenu"
|
|
54
|
-
class="
|
|
54
|
+
:class="insertMenuClasses"
|
|
55
55
|
:tippy-options="{ duration: 100, zIndex: 999, placement: 'bottom-start' }"
|
|
56
56
|
:should-show="showFloatingMenu"
|
|
57
57
|
:editor="editor"
|
|
@@ -115,6 +115,7 @@
|
|
|
115
115
|
</template>
|
|
116
116
|
|
|
117
117
|
<script>
|
|
118
|
+
import { mapState } from 'pinia';
|
|
118
119
|
import {
|
|
119
120
|
Editor,
|
|
120
121
|
EditorContent,
|
|
@@ -153,6 +154,7 @@ import { klona } from 'klona';
|
|
|
153
154
|
import newInstance from 'apostrophe/modules/@apostrophecms/schema/lib/newInstance.js';
|
|
154
155
|
import merge from 'lodash/merge';
|
|
155
156
|
import { useAposStyles } from 'Modules/@apostrophecms/styles/composables/AposStyles.js';
|
|
157
|
+
import { useModalStore } from 'Modules/@apostrophecms/ui/stores/modal';
|
|
156
158
|
|
|
157
159
|
export default {
|
|
158
160
|
name: 'AposRichTextWidgetEditor',
|
|
@@ -222,6 +224,23 @@ export default {
|
|
|
222
224
|
};
|
|
223
225
|
},
|
|
224
226
|
computed: {
|
|
227
|
+
...mapState(useModalStore, [ 'getAdminDirectionClass' ]),
|
|
228
|
+
// Note that context menu class-list expects a string
|
|
229
|
+
contextMenuClasses() {
|
|
230
|
+
const directionClass = this.getAdminDirectionClass();
|
|
231
|
+
const classes = [ 'apos-rich-text-toolbar' ];
|
|
232
|
+
if (directionClass) {
|
|
233
|
+
classes.push(directionClass);
|
|
234
|
+
}
|
|
235
|
+
return classes.join(' ');
|
|
236
|
+
},
|
|
237
|
+
insertMenuClasses() {
|
|
238
|
+
const directionClass = this.getAdminDirectionClass();
|
|
239
|
+
return {
|
|
240
|
+
'apos-rich-text-insert-menu': true,
|
|
241
|
+
[directionClass]: !!directionClass
|
|
242
|
+
};
|
|
243
|
+
},
|
|
225
244
|
tableOptions() {
|
|
226
245
|
const options = this.moduleOptions.tableOptions || {};
|
|
227
246
|
|
|
@@ -147,6 +147,10 @@ module.exports = (self) => {
|
|
|
147
147
|
return !value.length;
|
|
148
148
|
},
|
|
149
149
|
validate(field, options, warn, fail) {
|
|
150
|
+
if (field.direction && !_.includes([ 'ltr', 'rtl' ], field.direction)) {
|
|
151
|
+
fail('The direction property must be "ltr" or "rtl" if specified');
|
|
152
|
+
}
|
|
153
|
+
|
|
150
154
|
if (!field.pattern) {
|
|
151
155
|
return;
|
|
152
156
|
}
|
|
@@ -455,6 +459,11 @@ module.exports = (self) => {
|
|
|
455
459
|
destination[field.name] = null;
|
|
456
460
|
}
|
|
457
461
|
},
|
|
462
|
+
validate(field, options, warn, fail) {
|
|
463
|
+
if (field.direction && !_.includes([ 'ltr', 'rtl' ], field.direction)) {
|
|
464
|
+
fail('The direction property must be "ltr" or "rtl" if specified');
|
|
465
|
+
}
|
|
466
|
+
},
|
|
458
467
|
addQueryBuilder(field, query) {
|
|
459
468
|
return query.addBuilder(field.name, {
|
|
460
469
|
finalize: function () {
|
|
@@ -514,6 +523,11 @@ module.exports = (self) => {
|
|
|
514
523
|
destination[field.name] = null;
|
|
515
524
|
}
|
|
516
525
|
},
|
|
526
|
+
validate(field, options, warn, fail) {
|
|
527
|
+
if (field.direction && !_.includes([ 'ltr', 'rtl' ], field.direction)) {
|
|
528
|
+
fail('The direction property must be "ltr" or "rtl" if specified');
|
|
529
|
+
}
|
|
530
|
+
},
|
|
517
531
|
addQueryBuilder(field, query) {
|
|
518
532
|
return query.addBuilder(field.name, {
|
|
519
533
|
finalize: function () {
|
|
@@ -567,6 +581,11 @@ module.exports = (self) => {
|
|
|
567
581
|
}
|
|
568
582
|
}
|
|
569
583
|
destination[field.name] = data[field.name];
|
|
584
|
+
},
|
|
585
|
+
validate(field, options, warn, fail) {
|
|
586
|
+
if (field.direction && !_.includes([ 'ltr', 'rtl' ], field.direction)) {
|
|
587
|
+
fail('The direction property must be "ltr" or "rtl" if specified');
|
|
588
|
+
}
|
|
570
589
|
}
|
|
571
590
|
});
|
|
572
591
|
|
|
@@ -600,6 +619,10 @@ module.exports = (self) => {
|
|
|
600
619
|
return '';
|
|
601
620
|
},
|
|
602
621
|
validate(field, options, warn, fail) {
|
|
622
|
+
if (field.direction && !_.includes([ 'ltr', 'rtl' ], field.direction)) {
|
|
623
|
+
fail('The direction property must be "ltr" or "rtl" if specified');
|
|
624
|
+
}
|
|
625
|
+
|
|
603
626
|
if (!field.pattern) {
|
|
604
627
|
return;
|
|
605
628
|
}
|
|
@@ -659,6 +682,9 @@ module.exports = (self) => {
|
|
|
659
682
|
destination[field.name] = self.apos.launder.date(newDateVal);
|
|
660
683
|
},
|
|
661
684
|
validate: function (field, options, warn, fail) {
|
|
685
|
+
if (field.direction && !_.includes([ 'ltr', 'rtl' ], field.direction)) {
|
|
686
|
+
fail('The direction property must be "ltr" or "rtl" if specified');
|
|
687
|
+
}
|
|
662
688
|
if (field.max && !field.max.match(dateRegex)) {
|
|
663
689
|
fail('Property "max" must be in the date format, YYYY-MM-DD');
|
|
664
690
|
}
|
|
@@ -723,6 +749,11 @@ module.exports = (self) => {
|
|
|
723
749
|
destination[field.name] = data[field.name]
|
|
724
750
|
? self.apos.launder.date(data[field.name])
|
|
725
751
|
: null;
|
|
752
|
+
},
|
|
753
|
+
validate: function (field, options, warn, fail) {
|
|
754
|
+
if (field.direction && !_.includes([ 'ltr', 'rtl' ], field.direction)) {
|
|
755
|
+
fail('The direction property must be "ltr" or "rtl" if specified');
|
|
756
|
+
}
|
|
726
757
|
}
|
|
727
758
|
});
|
|
728
759
|
|
|
@@ -741,6 +772,11 @@ module.exports = (self) => {
|
|
|
741
772
|
);
|
|
742
773
|
}
|
|
743
774
|
},
|
|
775
|
+
validate: function (field, options, warn, fail) {
|
|
776
|
+
if (field.direction && !_.includes([ 'ltr', 'rtl' ], field.direction)) {
|
|
777
|
+
fail('The direction property must be "ltr" or "rtl" if specified');
|
|
778
|
+
}
|
|
779
|
+
},
|
|
744
780
|
def: ''
|
|
745
781
|
});
|
|
746
782
|
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
<input
|
|
18
18
|
v-model="date"
|
|
19
19
|
class="apos-input apos-input--date"
|
|
20
|
-
:class="
|
|
20
|
+
:class="classes"
|
|
21
21
|
type="date"
|
|
22
22
|
@change="setDateAndTime"
|
|
23
23
|
>
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
<input
|
|
28
28
|
v-model="time"
|
|
29
29
|
class="apos-input apos-input--time"
|
|
30
|
-
:class="
|
|
30
|
+
:class="classes"
|
|
31
31
|
type="time"
|
|
32
32
|
@change="setDateAndTime"
|
|
33
33
|
>
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import AposInputMixin from 'Modules/@apostrophecms/schema/mixins/AposInputMixin';
|
|
2
1
|
import dayjs from 'dayjs';
|
|
2
|
+
import AposInputMixin from 'Modules/@apostrophecms/schema/mixins/AposInputMixin.js';
|
|
3
|
+
import AposFieldDirectionMixin from 'Modules/@apostrophecms/schema/mixins/AposFieldDirection.js';
|
|
3
4
|
|
|
4
5
|
export default {
|
|
5
|
-
mixins: [ AposInputMixin ],
|
|
6
|
+
mixins: [ AposInputMixin, AposFieldDirectionMixin ],
|
|
6
7
|
emits: [ 'return' ],
|
|
7
8
|
data() {
|
|
8
9
|
return {
|
|
@@ -12,7 +13,7 @@ export default {
|
|
|
12
13
|
disabled: !this.field.required
|
|
13
14
|
};
|
|
14
15
|
},
|
|
15
|
-
mounted
|
|
16
|
+
mounted() {
|
|
16
17
|
this.initDateAndTime();
|
|
17
18
|
},
|
|
18
19
|
watch: {
|
|
@@ -25,6 +26,14 @@ export default {
|
|
|
25
26
|
}
|
|
26
27
|
}
|
|
27
28
|
},
|
|
29
|
+
computed: {
|
|
30
|
+
classes() {
|
|
31
|
+
return [
|
|
32
|
+
{ 'apos-input--disabled': this.disabled },
|
|
33
|
+
this.directionClass
|
|
34
|
+
].filter(Boolean);
|
|
35
|
+
}
|
|
36
|
+
},
|
|
28
37
|
methods: {
|
|
29
38
|
toggle() {
|
|
30
39
|
this.disabled = !this.disabled;
|
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
1
|
+
import AposInputMixin from 'Modules/@apostrophecms/schema/mixins/AposInputMixin.js';
|
|
2
|
+
import AposFieldDirectionMixin from 'Modules/@apostrophecms/schema/mixins/AposFieldDirection.js';
|
|
3
3
|
|
|
4
4
|
export default {
|
|
5
5
|
name: 'AposInputPassword',
|
|
6
|
-
mixins: [ AposInputMixin ],
|
|
6
|
+
mixins: [ AposInputMixin, AposFieldDirectionMixin ],
|
|
7
7
|
emits: [ 'return' ],
|
|
8
8
|
computed: {
|
|
9
|
-
tabindex
|
|
9
|
+
tabindex() {
|
|
10
10
|
return this.field.disableFocus ? '-1' : '0';
|
|
11
|
+
},
|
|
12
|
+
classes() {
|
|
13
|
+
return [ this.directionClass ].filter(Boolean);
|
|
11
14
|
}
|
|
12
15
|
},
|
|
13
16
|
methods: {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import AposInputMixin from 'Modules/@apostrophecms/schema/mixins/AposInputMixin';
|
|
1
|
+
import AposInputMixin from 'Modules/@apostrophecms/schema/mixins/AposInputMixin.js';
|
|
2
2
|
|
|
3
3
|
export default {
|
|
4
4
|
name: 'AposInputRange',
|
|
@@ -34,6 +34,9 @@ export default {
|
|
|
34
34
|
} else {
|
|
35
35
|
return false;
|
|
36
36
|
}
|
|
37
|
+
},
|
|
38
|
+
classes() {
|
|
39
|
+
return [ 'apos-range__input' ];
|
|
37
40
|
}
|
|
38
41
|
},
|
|
39
42
|
methods: {
|
|
@@ -57,7 +60,8 @@ export default {
|
|
|
57
60
|
const min = this.$refs.range.min;
|
|
58
61
|
const max = this.$refs.range.max;
|
|
59
62
|
const val = this.next < min ? min : this.next;
|
|
60
|
-
this.$refs.range.style.backgroundSize =
|
|
63
|
+
this.$refs.range.style.backgroundSize =
|
|
64
|
+
((val - min) * 100) / (max - min) + '% 100%';
|
|
61
65
|
},
|
|
62
66
|
validate(value) {
|
|
63
67
|
if (this.field.required) {
|