@concretecms/bedrock 1.6.3 → 1.6.5
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.
|
@@ -340,6 +340,13 @@ export default {
|
|
|
340
340
|
height: 'auto'
|
|
341
341
|
})
|
|
342
342
|
})
|
|
343
|
+
|
|
344
|
+
// Remove the data-dialog=theme-customizer-custom-css div if it appears
|
|
345
|
+
// inside a div with the [role=dialog]. Fixes https://github.com/concretecms/concretecms/issues/12575
|
|
346
|
+
const $customCssDialog = $('div[role=dialog] div[data-dialog=theme-customizer-custom-css]')
|
|
347
|
+
if ($customCssDialog.length) {
|
|
348
|
+
$customCssDialog.remove()
|
|
349
|
+
}
|
|
343
350
|
},
|
|
344
351
|
props: {
|
|
345
352
|
previewAction: {
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
;(function(global) {
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Recursively add fields to URLSearchParams.
|
|
6
|
+
* Used by buildRequestBody().
|
|
7
|
+
*
|
|
8
|
+
* @param {string} prefix
|
|
9
|
+
* @param {Record|Array|any} value
|
|
10
|
+
* @param {URLSearchParams} urlSearchParams
|
|
11
|
+
*
|
|
12
|
+
* @returns {void}
|
|
13
|
+
*/
|
|
14
|
+
function addToUrlSearchParams(prefix, value, urlSearchParams) {
|
|
15
|
+
if (value === null || value === undefined || typeof value !== 'object') {
|
|
16
|
+
return
|
|
17
|
+
}
|
|
18
|
+
if (!prefix && Array.isArray(value)) {
|
|
19
|
+
return
|
|
20
|
+
}
|
|
21
|
+
for (const [key, val] of Object.entries(value)) {
|
|
22
|
+
if (val === null || val === undefined) {
|
|
23
|
+
continue
|
|
24
|
+
}
|
|
25
|
+
const fieldName = prefix ? `${prefix}[${key}]` : key
|
|
26
|
+
if (typeof val === 'object') {
|
|
27
|
+
addToUrlSearchParams(fieldName, val, urlSearchParams)
|
|
28
|
+
} else {
|
|
29
|
+
urlSearchParams.append(fieldName, String(val))
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Build the request body for an AJAX request.
|
|
36
|
+
*
|
|
37
|
+
* @param {Record|any} data The object to build the body from
|
|
38
|
+
*
|
|
39
|
+
* @returns {URLSearchParams} The request body
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* buildRequestBody({key: 'value', arr: [1, 2, 3], nested: {a: 'b'}})
|
|
43
|
+
*/
|
|
44
|
+
function buildRequestBody(data) {
|
|
45
|
+
const urlSearchParams = new URLSearchParams()
|
|
46
|
+
addToUrlSearchParams('', data, urlSearchParams)
|
|
47
|
+
return urlSearchParams
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Prepare the request options for window.fetch().
|
|
52
|
+
*
|
|
53
|
+
* @param {RequestInit|Record<string, any>|null|undefined} request
|
|
54
|
+
* @param {Record<string, string>|null|undefined} headers Additional headers to add (will not override existing ones)
|
|
55
|
+
*
|
|
56
|
+
* @returns {RequestInit}
|
|
57
|
+
*/
|
|
58
|
+
function prepareRequest(request, headers) {
|
|
59
|
+
if (request) {
|
|
60
|
+
try {
|
|
61
|
+
request = global.structuredClone(request)
|
|
62
|
+
} catch {}
|
|
63
|
+
} else {
|
|
64
|
+
request = {}
|
|
65
|
+
}
|
|
66
|
+
// Default to GET if no method is specified
|
|
67
|
+
request.method = String(request.method || 'GET').toUpperCase()
|
|
68
|
+
if (request.body?.constructor === Object) {
|
|
69
|
+
// Convert body object to URLSearchParams
|
|
70
|
+
request.body = buildRequestBody(request.body)
|
|
71
|
+
}
|
|
72
|
+
if (!request.headers) {
|
|
73
|
+
request.headers = {}
|
|
74
|
+
}
|
|
75
|
+
if (!request.cache && request.method !== 'GET') {
|
|
76
|
+
// Disable caching for non-GET requests by default
|
|
77
|
+
request.cache = 'no-cache'
|
|
78
|
+
}
|
|
79
|
+
const existingHeaderKeys = Object.keys(request.headers).map((key) => key.toLowerCase())
|
|
80
|
+
if (headers) {
|
|
81
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
82
|
+
const lowerCaseName = name.toLowerCase()
|
|
83
|
+
if (!existingHeaderKeys.includes(lowerCaseName)) {
|
|
84
|
+
request.headers[name] = value
|
|
85
|
+
existingHeaderKeys.push(lowerCaseName)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (!existingHeaderKeys.includes('x-requested-with')) {
|
|
90
|
+
// Just to let the server know this is an AJAX request
|
|
91
|
+
request.headers['X-Requested-With'] = 'XMLHttpRequest'
|
|
92
|
+
}
|
|
93
|
+
if (request.method !== 'GET' && request.body && !existingHeaderKeys.includes('content-type')) {
|
|
94
|
+
// We want to use $_POST on the server side
|
|
95
|
+
request.headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'
|
|
96
|
+
}
|
|
97
|
+
return request
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Check a JSON response for errors.
|
|
102
|
+
*
|
|
103
|
+
* @param {any} responseData
|
|
104
|
+
*
|
|
105
|
+
* @throws {Error} If the response data contains errors (the thrown error will have a responseData property)
|
|
106
|
+
*/
|
|
107
|
+
function checkJsonResponse(responseData) {
|
|
108
|
+
if (responseData?.errors?.length) {
|
|
109
|
+
const error = new Error(responseData.errors[0])
|
|
110
|
+
error.responseData = responseData
|
|
111
|
+
throw error
|
|
112
|
+
}
|
|
113
|
+
if (responseData?.error) {
|
|
114
|
+
const error = new Error(responseData.error)
|
|
115
|
+
error.responseData = responseData
|
|
116
|
+
throw error
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Fetch JSON data from a URL.
|
|
122
|
+
*
|
|
123
|
+
* @param {string} url The URL to fetch data from
|
|
124
|
+
* @param {RequestInit|Record<string, any>|null|undefined} request The request options and body
|
|
125
|
+
*
|
|
126
|
+
* @throws {Error} If the response contains an error or is not ok
|
|
127
|
+
*
|
|
128
|
+
* @returns {Promise<any>} The JSON response
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* try {
|
|
132
|
+
* const data = await fetchJson('/api/data', {
|
|
133
|
+
* method: 'POST',
|
|
134
|
+
* body: {
|
|
135
|
+
* key: 'value'
|
|
136
|
+
* }
|
|
137
|
+
* });
|
|
138
|
+
* } catch (error) {
|
|
139
|
+
* window.alert(error.message);
|
|
140
|
+
* }
|
|
141
|
+
*/
|
|
142
|
+
async function fetchJson(url, request) {
|
|
143
|
+
request = prepareRequest(request, { Accept: 'application/json' })
|
|
144
|
+
const response = await fetch(url, request)
|
|
145
|
+
const responseText = await response.text()
|
|
146
|
+
let responseData
|
|
147
|
+
try {
|
|
148
|
+
responseData = JSON.parse(responseText)
|
|
149
|
+
} catch {
|
|
150
|
+
throw new Error(responseText)
|
|
151
|
+
}
|
|
152
|
+
checkJsonResponse(responseData)
|
|
153
|
+
if (!response.ok) {
|
|
154
|
+
throw new Error(responseText)
|
|
155
|
+
}
|
|
156
|
+
return responseData
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Fetch an HTML chunk from a URL.
|
|
161
|
+
*
|
|
162
|
+
* @param {string} url The URL to fetch data from
|
|
163
|
+
* @param {RequestInit|Record<string, any>|undefined} request The request options and body
|
|
164
|
+
*
|
|
165
|
+
* @throws {Error} If the response contains an error or is not ok
|
|
166
|
+
*
|
|
167
|
+
* @returns {Promise<string>} The HTML response
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* try {
|
|
171
|
+
* const data = await fetchHtml('/api/render', {
|
|
172
|
+
* method: 'POST',
|
|
173
|
+
* body: {
|
|
174
|
+
* key: 'value'
|
|
175
|
+
* }
|
|
176
|
+
* });
|
|
177
|
+
* } catch (error) {
|
|
178
|
+
* window.alert(error.message);
|
|
179
|
+
* }
|
|
180
|
+
*/
|
|
181
|
+
async function fetchHtml(url, request) {
|
|
182
|
+
request = prepareRequest(
|
|
183
|
+
request,
|
|
184
|
+
{
|
|
185
|
+
Accept: [
|
|
186
|
+
// Prefer HTML
|
|
187
|
+
'text/html',
|
|
188
|
+
// ... but accept JSON in case of errors
|
|
189
|
+
'application/json;q=0.9',
|
|
190
|
+
// ... or plain text as a last resort fallback
|
|
191
|
+
'text/plain;q=0.8'
|
|
192
|
+
].join(', ')
|
|
193
|
+
}
|
|
194
|
+
)
|
|
195
|
+
const response = await fetch(url, request)
|
|
196
|
+
const responseText = await response.text()
|
|
197
|
+
let responseData
|
|
198
|
+
try {
|
|
199
|
+
// Try to see if it's JSON with errors
|
|
200
|
+
responseData = JSON.parse(responseText)
|
|
201
|
+
} catch {
|
|
202
|
+
// Not JSON, that's fine
|
|
203
|
+
responseData = null
|
|
204
|
+
}
|
|
205
|
+
if (responseData) {
|
|
206
|
+
checkJsonResponse(responseData)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (!response.ok) {
|
|
210
|
+
throw new Error(responseText)
|
|
211
|
+
}
|
|
212
|
+
return responseText
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
global.ConcreteFetch = {
|
|
216
|
+
buildRequestBody,
|
|
217
|
+
json: fetchJson,
|
|
218
|
+
html: fetchHtml
|
|
219
|
+
}
|
|
220
|
+
})(global)
|
|
@@ -59,6 +59,24 @@ export default class Manager {
|
|
|
59
59
|
}, 10)
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Activates a particular context (and its components) for a particular selector, returning a promise.
|
|
64
|
+
*
|
|
65
|
+
* @param {String} context
|
|
66
|
+
*
|
|
67
|
+
* @returns {Promise<{Vue: typeof Vue, options: Record<string, any>}>
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* const {Vue, options} = await Concrete.Vue.activateContextAsync('cms')
|
|
71
|
+
*/
|
|
72
|
+
activateContextAsync(context) {
|
|
73
|
+
return new Promise((resolve) => {
|
|
74
|
+
this.activateContext(context, (Vue, options) => {
|
|
75
|
+
resolve({ Vue, options })
|
|
76
|
+
})
|
|
77
|
+
})
|
|
78
|
+
}
|
|
79
|
+
|
|
62
80
|
/**
|
|
63
81
|
* For a given string `context`, adds the passed components to make them available within that context.
|
|
64
82
|
*
|
package/package.json
CHANGED