domma-cms 0.102.0 → 0.102.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/package.json
CHANGED
|
@@ -176,8 +176,10 @@ export function formatDate(value, fmt) {
|
|
|
176
176
|
export function interpolate(tpl, vars) {
|
|
177
177
|
return String(tpl ?? '')
|
|
178
178
|
.replace(/<!--[\s\S]*?-->/g, '')
|
|
179
|
-
|
|
180
|
-
|
|
179
|
+
// One pass, so a value put in is never read again for placeholders: a post that
|
|
180
|
+
// shows "{{date}}" in its text keeps it, instead of getting today's date.
|
|
181
|
+
.replace(/\{\{\{(\w+)\}\}\}|\{\{(\w+)(?::([^{}]+))?\}\}/g, (_, raw, k, fmt) => {
|
|
182
|
+
if (raw !== undefined) return String(vars[raw] ?? '');
|
|
181
183
|
const v = vars[k] ?? '';
|
|
182
184
|
if (fmt) {
|
|
183
185
|
const f = formatDate(v, fmt);
|
package/plugins/blog/plugin.json
CHANGED
|
@@ -130,3 +130,9 @@ test('a card shows its date as dd/mm/yyyy; the machine value stays ISO', () => {
|
|
|
130
130
|
assert.equal(v.date, '07/09/2026');
|
|
131
131
|
assert.equal(v.publishedAt, '2026-09-07T10:00:00Z');
|
|
132
132
|
});
|
|
133
|
+
|
|
134
|
+
test('interpolate: a raw value is never read again for placeholders', () => {
|
|
135
|
+
// A post that shows "{{date}}" in its text keeps it.
|
|
136
|
+
assert.equal(interpolate('<div>{{{content}}}</div><p>{{title}}</p>', {content: '<code>{{date}} {{title}}</code>', title: 'T', date: 'X'}),
|
|
137
|
+
'<div><code>{{date}} {{title}}</code></div><p>T</p>');
|
|
138
|
+
});
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"note": "Written by `make sync-free-tier` in dcms-marketplace. Do not edit these plugins here - edit them there and sync.",
|
|
3
|
-
"source": "dcms-marketplace@
|
|
3
|
+
"source": "dcms-marketplace@f79220a",
|
|
4
4
|
"plugins": {
|
|
5
5
|
"blog": {
|
|
6
|
-
"version": "1.9.
|
|
6
|
+
"version": "1.9.4",
|
|
7
7
|
"files": {
|
|
8
8
|
"CLAUDE.md": "926730d510cc38f6764ffcb9afbed1c3ae3a547117c6c0243b14f899271350fb",
|
|
9
9
|
"admin/css/index.css": "6142a6b756e1218157842528830b1e84f592f0b84b7d5ce6449db421b6f4b039",
|
|
@@ -43,14 +43,14 @@
|
|
|
43
43
|
"config.js": "ee67396262762f5c31269d258affd75f7392a3e364f72f7792c2f1cdafd94bba",
|
|
44
44
|
"docs/guide.md": "6a7466881851797789a18e0d32c4fcb515f2259b110948c55be03923c38e0de5",
|
|
45
45
|
"lib/access.js": "af47440c7233a56000641a3231d7e9ff81b12f40dfb9528aa6dd4e2dd9bca8df",
|
|
46
|
-
"lib/layouts.js": "
|
|
46
|
+
"lib/layouts.js": "dbb6ae9e514ccaf600a732702925b905131dea166d90fe759a62b6652e78e1de",
|
|
47
47
|
"lib/nav-link.js": "6a8f9368bb8aee1c21e90fb335a691859cb9a9bc250c2b9167a33ca9189fa2ff",
|
|
48
48
|
"lib/notices.js": "a9a2918ee6f5f7e0bbaeced0d3539584279bdbe68d15472a8615bdddb4ef905b",
|
|
49
49
|
"lib/page.js": "bfb6a355a027feaf775d6d8ac871fc6d999354774e018f8e16caec551e99f40a",
|
|
50
50
|
"lib/render.js": "0e97c6a950bc962c8d8ea4b2f21d06cb73fbcdc738d8942d6935d01309a29b1d",
|
|
51
51
|
"lib/samples.js": "e8cdb77ce22e43937707f6854d3a5cb722437dc584e22ac7b24480bef686cf85",
|
|
52
52
|
"plugin.js": "0aa46a01b5298065497f39729b88e34a9f56ac684b0a14f8d94ab6007f0221d0",
|
|
53
|
-
"plugin.json": "
|
|
53
|
+
"plugin.json": "7bfba248651527bb98fa388a66234a53e9808c6a28e878504a1fa9fae216b658",
|
|
54
54
|
"plugin.public.js": "67e109da613237d9ec52e7cc2f3442bb61ca5a51cb184448b9f0d993e50f7ae3",
|
|
55
55
|
"public/blog.css": "fd733e6b624190da1e70dc1b6613e2376efd7f7570a28fab311d81006d03d960",
|
|
56
56
|
"public/blog.js": "d01c72a9834dcc7c5241923371f2b164ac30d20ac9f1a5c5dc5b71fa3cb09f08",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"templates/post.html": "28e9f06071115ecc4fbba007b35782732bf12ef72528525893d424e3c4f0313f",
|
|
67
67
|
"tests/access.test.js": "65b760910117c3a44195543acdcff91074f39b4e5567911a2bd8676204152cb2",
|
|
68
68
|
"tests/comment-notices.test.js": "34026cc9a2a4746cf87bc41df8be849fadaa43091a72ac2aa1d06c1f437bf618",
|
|
69
|
-
"tests/layouts.test.js": "
|
|
69
|
+
"tests/layouts.test.js": "554cff8194bd650cfb5f2a83c1f51c25f427c07f7dbfdc2ad9ad69bb38fca6a0",
|
|
70
70
|
"tests/nav-link.test.js": "d36e33ad7483abca27ae6e2098ad2f75bafa18d91f3beba70372ebe6b9b88994",
|
|
71
71
|
"tests/notices.test.js": "2b02aa84e780dc4c82e6c503fc8fe17c64a63bee0709627866ef97c99cb4e131",
|
|
72
72
|
"tests/public.test.js": "a6fcdc4ede242aa050ffe5a52f970d6bec1f4a70ae78967eb8a7bdeec73df19d"
|
|
@@ -330,9 +330,8 @@ export function buildBlockStyleTag(blockName, css) {
|
|
|
330
330
|
* Interpolate a block template against a single collection entry.
|
|
331
331
|
*
|
|
332
332
|
* Triple-brace `{{{field}}}` - raw HTML pass-through (no escape). Use for
|
|
333
|
-
* fields that contain pre-rendered HTML.
|
|
334
|
-
*
|
|
335
|
-
* regex. Double-brace `{{field}}` - HTML-escaped (default, safe), with an
|
|
333
|
+
* fields that contain pre-rendered HTML. Both kinds are filled in ONE pass, so
|
|
334
|
+
* an inserted value is never scanned for placeholders again. Double-brace `{{field}}` - HTML-escaped (default, safe), with an
|
|
336
335
|
* optional `:format` suffix (e.g. `{{_createdAt:DD MMM YYYY}}`) that applies
|
|
337
336
|
* moment-style date formatting when the value parses as a Date.
|
|
338
337
|
*
|
|
@@ -341,10 +340,10 @@ export function buildBlockStyleTag(blockName, css) {
|
|
|
341
340
|
* @returns {string}
|
|
342
341
|
*/
|
|
343
342
|
function interpolateBlockTemplate(blockTemplate, e) {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
})
|
|
347
|
-
|
|
343
|
+
// One pass: a raw value put in (pre-rendered HTML) is never read again for
|
|
344
|
+
// placeholders - text that shows "{{title}}" keeps it.
|
|
345
|
+
return blockTemplate.replace(/\{\{\{(\w+)\}\}\}|\{\{([\w_]+)(?::([^{}]+))?\}\}/g, (_, raw, key, fmt) => {
|
|
346
|
+
if (raw !== undefined) return String(e.data?.[raw] ?? '');
|
|
348
347
|
let value;
|
|
349
348
|
if (key === '_id') value = e.id ?? '';
|
|
350
349
|
else if (key === '_createdAt') value = e.meta?.createdAt ?? '';
|
|
@@ -356,7 +355,6 @@ function interpolateBlockTemplate(blockTemplate, e) {
|
|
|
356
355
|
}
|
|
357
356
|
return escapeHtmlText(value);
|
|
358
357
|
});
|
|
359
|
-
return html;
|
|
360
358
|
}
|
|
361
359
|
|
|
362
360
|
/**
|
|
@@ -408,10 +406,10 @@ function renderCollectionBlocks(entries, blockTemplate, emptyMsg, ctaOpts, cols,
|
|
|
408
406
|
}
|
|
409
407
|
|
|
410
408
|
function renderBlockFromAttrs(tmpl, attrs, blockName = '') {
|
|
411
|
-
// Triple-brace raw pass-through
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
409
|
+
// Triple-brace raw pass-through and `{{field}}` (optional `:format`, e.g. `{{date:DD MMM YYYY}}`)
|
|
410
|
+
// in one pass, so a raw value is never read again for placeholders.
|
|
411
|
+
const rendered = tmpl.replace(/\{\{\{(\w+)\}\}\}|\{\{([\w_]+)(?::([^{}]+))?\}\}/g, (_, rawKey, key, fmt) => {
|
|
412
|
+
if (rawKey !== undefined) return String(attrs[rawKey] ?? '');
|
|
415
413
|
const raw = attrs[key] ?? '';
|
|
416
414
|
if (fmt) {
|
|
417
415
|
const formatted = formatDate(raw, fmt);
|