apostrophe 4.27.1 → 4.28.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 +35 -0
- package/index.js +3 -0
- package/lib/stream-proxy.js +49 -0
- package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposContextTitle.vue +2 -11
- package/modules/@apostrophecms/area/ui/apos/apps/AposAreas.js +38 -6
- package/modules/@apostrophecms/area/ui/apos/components/AposAreaEditor.vue +12 -1
- package/modules/@apostrophecms/area/ui/apos/components/AposAreaWidget.vue +111 -41
- package/modules/@apostrophecms/area/ui/apos/components/AposBreadcrumbOperations.vue +1 -0
- package/modules/@apostrophecms/area/ui/apos/components/AposWidgetControls.vue +22 -10
- package/modules/@apostrophecms/area/ui/apos/logic/AposAreaEditor.js +40 -0
- package/modules/@apostrophecms/asset/index.js +3 -2
- package/modules/@apostrophecms/attachment/index.js +270 -0
- package/modules/@apostrophecms/doc/index.js +8 -2
- package/modules/@apostrophecms/doc-type/index.js +81 -1
- package/modules/@apostrophecms/doc-type/ui/apos/components/AposDocEditor.vue +18 -2
- package/modules/@apostrophecms/express/index.js +30 -1
- package/modules/@apostrophecms/file/index.js +71 -6
- package/modules/@apostrophecms/i18n/index.js +20 -1
- package/modules/@apostrophecms/image/index.js +11 -0
- package/modules/@apostrophecms/layout-widget/ui/apos/components/AposAreaLayoutEditor.vue +31 -6
- package/modules/@apostrophecms/layout-widget/ui/apos/components/AposGridLayout.vue +12 -10
- package/modules/@apostrophecms/login/index.js +43 -11
- package/modules/@apostrophecms/modal/ui/apos/components/AposDocsManagerToolbar.vue +2 -1
- package/modules/@apostrophecms/modal/ui/apos/components/AposModal.vue +5 -0
- package/modules/@apostrophecms/page/index.js +9 -11
- package/modules/@apostrophecms/page-type/index.js +6 -1
- package/modules/@apostrophecms/piece-page-type/index.js +100 -13
- package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposImageControlDialog.vue +1 -0
- package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposRichTextWidgetEditor.vue +28 -12
- package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapLink.vue +1 -0
- package/modules/@apostrophecms/schema/ui/apos/components/AposSearchList.vue +1 -1
- package/modules/@apostrophecms/styles/lib/apiRoutes.js +25 -5
- package/modules/@apostrophecms/styles/lib/handlers.js +19 -0
- package/modules/@apostrophecms/styles/lib/methods.js +35 -12
- package/modules/@apostrophecms/styles/ui/apos/components/TheAposStyles.vue +7 -2
- package/modules/@apostrophecms/task/index.js +9 -1
- package/modules/@apostrophecms/template/views/outerLayoutBase.html +3 -0
- package/modules/@apostrophecms/ui/index.js +2 -0
- package/modules/@apostrophecms/ui/ui/apos/components/AposButtonGroup.vue +1 -1
- package/modules/@apostrophecms/ui/ui/apos/components/AposContextMenu.vue +5 -0
- package/modules/@apostrophecms/ui/ui/apos/components/AposContextMenuDialog.vue +5 -0
- package/modules/@apostrophecms/ui/ui/apos/lib/vue.js +2 -0
- package/modules/@apostrophecms/ui/ui/apos/stores/widget.js +12 -7
- package/modules/@apostrophecms/ui/ui/apos/stores/widgetGraph.js +461 -0
- package/modules/@apostrophecms/ui/ui/apos/universal/graph.js +452 -0
- package/modules/@apostrophecms/ui/ui/apos/universal/widgetGraph.js +10 -0
- package/modules/@apostrophecms/uploadfs/index.js +15 -1
- package/modules/@apostrophecms/url/index.js +419 -1
- package/package.json +6 -6
- package/test/add-missing-schema-fields-project/node_modules/.package-lock.json +131 -0
- package/test/external-front.js +1 -0
- package/test/files.js +135 -0
- package/test/login-requirements.js +145 -3
- package/test/static-build.js +2701 -0
- package/test/universal-graph.js +1135 -0
|
@@ -2,12 +2,32 @@ module.exports = self => {
|
|
|
2
2
|
return {
|
|
3
3
|
get: {
|
|
4
4
|
// This route serves the existing styles stylesheet,
|
|
5
|
-
// constructed from the global object
|
|
6
|
-
// We do it this way so the browser can cache the styles as often as possible
|
|
5
|
+
// constructed from the global object.
|
|
6
|
+
// We do it this way so the browser can cache the styles as often as possible.
|
|
7
|
+
//
|
|
8
|
+
// The locale-qualified alias (`stylesheet/locale/:locale/:mode`)
|
|
9
|
+
// produces a distinct path per locale so that static-build
|
|
10
|
+
// tools that key on the URL path (e.g. Astro) don't
|
|
11
|
+
// overwrite one locale's stylesheet with another's.
|
|
7
12
|
stylesheet(req) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
13
|
+
return self.serveStylesheet(req);
|
|
14
|
+
},
|
|
15
|
+
'stylesheet/locale/:locale/:mode': async function(req) {
|
|
16
|
+
const { locale, mode } = req.params;
|
|
17
|
+
if (!locale || !self.apos.i18n.isValidLocale(locale)) {
|
|
18
|
+
throw self.apos.error('invalid');
|
|
19
|
+
}
|
|
20
|
+
const validModes = [ 'published', 'draft' ];
|
|
21
|
+
const safeMode = validModes.includes(mode) ? mode : 'published';
|
|
22
|
+
if (safeMode === 'draft' && !self.apos.permission.can(req, 'view-draft')) {
|
|
23
|
+
throw self.apos.error('forbidden');
|
|
24
|
+
}
|
|
25
|
+
req.locale = locale;
|
|
26
|
+
req.mode = safeMode;
|
|
27
|
+
// Force re-fetch global for the correct locale
|
|
28
|
+
delete req.data.global;
|
|
29
|
+
await self.apos.global.addGlobalToData(req);
|
|
30
|
+
return self.serveStylesheet(req);
|
|
11
31
|
}
|
|
12
32
|
},
|
|
13
33
|
post: {
|
|
@@ -45,6 +45,25 @@ node app @apostrophecms-pro/palette:migrate-to-styles
|
|
|
45
45
|
}
|
|
46
46
|
self.apos.template.addBodyClass(req, classes.join(' '));
|
|
47
47
|
}
|
|
48
|
+
},
|
|
49
|
+
'@apostrophecms/url:getAllUrlMetadata': {
|
|
50
|
+
// Provide a literal content entry so static builds
|
|
51
|
+
// can include the dynamically generated stylesheet.
|
|
52
|
+
// Uses the locale-path URL so each locale produces a
|
|
53
|
+
// distinct path for static-build tools.
|
|
54
|
+
// The URL must be relative and prefix-free — the
|
|
55
|
+
// consumer prepends the prefix when fetching.
|
|
56
|
+
addStylesheetUrl(req, results) {
|
|
57
|
+
if (!req.data.global?.stylesStylesheet) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
results.push({
|
|
61
|
+
url: self.getStylesheetUrl(req, { relative: true }),
|
|
62
|
+
contentType: 'text/css',
|
|
63
|
+
i18nId: '@apostrophecms/styles:stylesheet',
|
|
64
|
+
sitemap: false
|
|
65
|
+
});
|
|
66
|
+
}
|
|
48
67
|
}
|
|
49
68
|
};
|
|
50
69
|
};
|
|
@@ -82,6 +82,27 @@ module.exports = (self, options) => {
|
|
|
82
82
|
|
|
83
83
|
return expanded;
|
|
84
84
|
},
|
|
85
|
+
// Returns the locale-qualified stylesheet URL for the given
|
|
86
|
+
// request. The path encodes the locale so that static-build
|
|
87
|
+
// tools produce a distinct file per locale.
|
|
88
|
+
//
|
|
89
|
+
// Options:
|
|
90
|
+
// `relative` - if true, return a prefix-free path suitable
|
|
91
|
+
// for route-relative contexts (e.g. `getAllUrlMetadata`).
|
|
92
|
+
// Defaults to `false`, which prepends `apos.prefix` so the
|
|
93
|
+
// URL works in rendered HTML (`<link>` tags, etc.).
|
|
94
|
+
getStylesheetUrl(req, { relative = false } = {}) {
|
|
95
|
+
const prefix = relative ? '' : (self.apos.prefix || '');
|
|
96
|
+
const version = req.data.global?.stylesStylesheetVersion;
|
|
97
|
+
return `${prefix}${self.action}/stylesheet/locale/${req.locale}/${req.mode}${version ? `?version=${version}` : ''}`;
|
|
98
|
+
},
|
|
99
|
+
// Shared implementation for the stylesheet API routes.
|
|
100
|
+
// Sets cache headers and returns the raw CSS string.
|
|
101
|
+
serveStylesheet(req) {
|
|
102
|
+
req.res.setHeader('Content-Type', 'text/css');
|
|
103
|
+
req.res.setHeader('Cache-Control', 'public, max-age=31557600');
|
|
104
|
+
return req.data.global?.stylesStylesheet || '';
|
|
105
|
+
},
|
|
85
106
|
stylesheet(req) {
|
|
86
107
|
// Stylesheet node should be created only for logged in users.
|
|
87
108
|
if (!req.data.global) {
|
|
@@ -94,7 +115,7 @@ module.exports = (self, options) => {
|
|
|
94
115
|
// and similar features from those who should just get the link tag
|
|
95
116
|
const hasLink = !self.apos.permission.can(req, 'view-draft');
|
|
96
117
|
if (req.data.global.stylesStylesheet && hasLink) {
|
|
97
|
-
const href =
|
|
118
|
+
const href = self.getStylesheetUrl(req);
|
|
98
119
|
nodes.push({
|
|
99
120
|
name: 'link',
|
|
100
121
|
attrs: {
|
|
@@ -103,17 +124,19 @@ module.exports = (self, options) => {
|
|
|
103
124
|
}
|
|
104
125
|
});
|
|
105
126
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
127
|
+
if (!hasLink) {
|
|
128
|
+
nodes.push({
|
|
129
|
+
name: 'style',
|
|
130
|
+
attrs: {
|
|
131
|
+
id: 'apos-styles-stylesheet'
|
|
132
|
+
},
|
|
133
|
+
body: [
|
|
134
|
+
{
|
|
135
|
+
raw: req.data.global.stylesStylesheet || ''
|
|
136
|
+
}
|
|
137
|
+
]
|
|
138
|
+
});
|
|
139
|
+
}
|
|
117
140
|
return nodes;
|
|
118
141
|
},
|
|
119
142
|
ui(req) {
|
|
@@ -431,6 +431,7 @@ export default {
|
|
|
431
431
|
);
|
|
432
432
|
},
|
|
433
433
|
async setStyleMarkup({ css, classes }) {
|
|
434
|
+
const stylesheetEl = document.querySelector('#apos-styles-stylesheet');
|
|
434
435
|
this.setBodyClasses(classes);
|
|
435
436
|
if (apos.adminBar.breakpointPreviewMode?.enable) {
|
|
436
437
|
const processed = breakpointPreviewTransformer(css, {
|
|
@@ -438,11 +439,15 @@ export default {
|
|
|
438
439
|
debug: apos.adminBar.breakpointPreviewMode?.debug === true,
|
|
439
440
|
transform: apos.adminBar.breakpointPreviewMode?.transform || null
|
|
440
441
|
});
|
|
441
|
-
|
|
442
|
+
if (stylesheetEl) {
|
|
443
|
+
stylesheetEl.textContent = processed;
|
|
444
|
+
}
|
|
442
445
|
return;
|
|
443
446
|
}
|
|
444
447
|
|
|
445
|
-
|
|
448
|
+
if (stylesheetEl) {
|
|
449
|
+
stylesheetEl.textContent = css;
|
|
450
|
+
}
|
|
446
451
|
},
|
|
447
452
|
setBodyClasses(classes) {
|
|
448
453
|
const previousClasses = document.body
|
|
@@ -300,7 +300,15 @@ module.exports = {
|
|
|
300
300
|
};
|
|
301
301
|
addCloneMethod(req);
|
|
302
302
|
req.res.__ = req.__;
|
|
303
|
-
const {
|
|
303
|
+
const {
|
|
304
|
+
role: _role, staticBuild: _staticBuild, ...properties
|
|
305
|
+
} = options || {};
|
|
306
|
+
|
|
307
|
+
// When staticBuild is requested, configure the req object
|
|
308
|
+
// with the same properties that Express middlewares
|
|
309
|
+
if (_staticBuild) {
|
|
310
|
+
self.apos.modules['@apostrophecms/express'].applyStaticBuildHeaders(req);
|
|
311
|
+
}
|
|
304
312
|
|
|
305
313
|
Object.assign(req, properties);
|
|
306
314
|
self.apos.i18n.setPrefixUrls(req);
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html lang="{% block locale %}{{ data.locale }}{% endblock %}" dir="{% block direction %}{{ data.i18n.direction or 'ltr' }}{% endblock %}" {% block extraHtml %}{% endblock %}>
|
|
3
3
|
<head>
|
|
4
|
+
{% block encoding %}
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
{% endblock %}
|
|
4
7
|
{% block startHead %}
|
|
5
8
|
{% endblock %}
|
|
6
9
|
{% component '@apostrophecms/template:inject' with { where: 'head', end: 'prepend', when: 'hmr' } %}
|
|
@@ -9,6 +9,7 @@ module.exports = {
|
|
|
9
9
|
},
|
|
10
10
|
init(self) {
|
|
11
11
|
self.enableBrowserData();
|
|
12
|
+
self.uiDebug = self.options.debug ?? process.env.NODE_ENV !== 'production';
|
|
12
13
|
},
|
|
13
14
|
methods(self) {
|
|
14
15
|
return {
|
|
@@ -23,6 +24,7 @@ module.exports = {
|
|
|
23
24
|
theme.primary = req.data.user.aposThemePrimary;
|
|
24
25
|
}
|
|
25
26
|
return {
|
|
27
|
+
debug: self.uiDebug,
|
|
26
28
|
theme,
|
|
27
29
|
widgetMargin: self.options.widgetMargin
|
|
28
30
|
};
|
|
@@ -86,6 +86,7 @@
|
|
|
86
86
|
:active-item="activeItem"
|
|
87
87
|
:is-open="isOpen"
|
|
88
88
|
:has-tip="hasTip"
|
|
89
|
+
:ignore-unfocus="ignoreUnfocus"
|
|
89
90
|
@item-clicked="menuItemClicked"
|
|
90
91
|
@set-arrow="setArrow"
|
|
91
92
|
>
|
|
@@ -210,6 +211,10 @@ const props = defineProps({
|
|
|
210
211
|
teleportContent: {
|
|
211
212
|
type: Boolean,
|
|
212
213
|
default: false
|
|
214
|
+
},
|
|
215
|
+
ignoreUnfocus: {
|
|
216
|
+
type: Boolean,
|
|
217
|
+
default: false
|
|
213
218
|
}
|
|
214
219
|
});
|
|
215
220
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
class="apos-primary-scrollbar apos-context-menu__dialog"
|
|
4
4
|
:class="classes"
|
|
5
5
|
role="dialog"
|
|
6
|
+
:data-apos-ignore-unfocus="props.ignoreUnfocus"
|
|
6
7
|
>
|
|
7
8
|
<AposContextMenuTip
|
|
8
9
|
v-if="hasTip"
|
|
@@ -37,6 +38,10 @@
|
|
|
37
38
|
import { computed } from 'vue';
|
|
38
39
|
|
|
39
40
|
const props = defineProps({
|
|
41
|
+
ignoreUnfocus: {
|
|
42
|
+
type: Boolean,
|
|
43
|
+
default: false
|
|
44
|
+
},
|
|
40
45
|
menuPlacement: {
|
|
41
46
|
type: String,
|
|
42
47
|
required: true
|
|
@@ -49,13 +49,18 @@ export const useWidgetStore = defineStore('widget', () => {
|
|
|
49
49
|
|
|
50
50
|
const headerHeight = window.apos.adminBar.height;
|
|
51
51
|
const bufferSpace = 40;
|
|
52
|
-
const
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
52
|
+
const rect = $el.getBoundingClientRect();
|
|
53
|
+
const visibleTop = headerHeight + bufferSpace;
|
|
54
|
+
const visibleBottom = window.innerHeight - bufferSpace;
|
|
55
|
+
const isInView = rect.top >= visibleTop && rect.bottom <= visibleBottom;
|
|
56
|
+
|
|
57
|
+
if (!isInView) {
|
|
58
|
+
const scrollPos = rect.top - headerHeight - bufferSpace;
|
|
59
|
+
window.scrollBy({
|
|
60
|
+
top: scrollPos,
|
|
61
|
+
behavior: 'smooth'
|
|
62
|
+
});
|
|
63
|
+
}
|
|
59
64
|
|
|
60
65
|
$el.focus({
|
|
61
66
|
preventScroll: true
|