Compare commits

...

4 Commits

Author SHA1 Message Date
Elio Struyf
b5b7dcf6b5 Merge branch 'dev' into issue/747 2024-02-12 10:57:19 +01:00
Elio Struyf
c81d5240f4 Merge pull request #750 from estruyf/issue/673
Git settings on welcome view and settings
2024-02-12 10:56:47 +01:00
Elio Struyf
d59d9a98d5 #746 - placeholder support for slug field 2024-01-30 21:45:01 +01:00
Elio Struyf
83cf0eb8f5 #746 - Placeholder support in slug 2024-01-29 16:58:25 +01:00
30 changed files with 487 additions and 304 deletions

View File

@@ -5,6 +5,7 @@
### ✨ New features
- [#731](https://github.com/estruyf/vscode-front-matter/issues/731): Added the ability to map/unmap taxonomy to multiple pages at once
- [#746](https://github.com/estruyf/vscode-front-matter/issues/746): Placeholder support added to to the `slug` field
- [#749](https://github.com/estruyf/vscode-front-matter/issues/749): Ability to set your own filters on the content dashboard with the `frontMatter.content.filters` setting
### 🎨 Enhancements

View File

@@ -10,8 +10,7 @@
"color": "#0e131f",
"theme": "dark"
},
"badges": [
{
"badges": [{
"description": "version",
"url": "https://img.shields.io/github/package-json/v/estruyf/vscode-front-matter?color=green&label=vscode-front-matter&style=flat-square",
"href": "https://github.com/estruyf/vscode-front-matter"
@@ -71,8 +70,7 @@
"**/.frontmatter/config/*.json": "jsonc"
}
},
"keybindings": [
{
"keybindings": [{
"command": "frontMatter.dashboard",
"key": "alt+d"
},
@@ -90,23 +88,19 @@
}
],
"viewsContainers": {
"activitybar": [
{
"id": "frontmatter-explorer",
"title": "FM",
"icon": "$(fm-logo)"
}
]
"activitybar": [{
"id": "frontmatter-explorer",
"title": "FM",
"icon": "$(fm-logo)"
}]
},
"views": {
"frontmatter-explorer": [
{
"id": "frontMatter.explorer",
"name": "Front Matter",
"icon": "$(fm-logo)",
"type": "webview"
}
]
"frontmatter-explorer": [{
"id": "frontMatter.explorer",
"name": "Front Matter",
"icon": "$(fm-logo)",
"type": "webview"
}]
},
"configuration": {
"title": "%settings.configuration.title%",
@@ -174,8 +168,7 @@
"frontMatter.content.defaultFileType": {
"type": "string",
"default": "md",
"oneOf": [
{
"oneOf": [{
"enum": [
"md",
"mdx"
@@ -191,8 +184,7 @@
"frontMatter.content.defaultSorting": {
"type": "string",
"default": "",
"oneOf": [
{
"oneOf": [{
"enum": [
"LastModifiedAsc",
"LastModifiedDesc",
@@ -569,8 +561,7 @@
"command": {
"$id": "#scriptCommand",
"type": "string",
"anyOf": [
{
"anyOf": [{
"enum": [
"node",
"bash",
@@ -777,8 +768,7 @@
"title",
"file"
],
"anyOf": [
{
"anyOf": [{
"required": [
"schema"
]
@@ -832,8 +822,7 @@
"id",
"path"
],
"anyOf": [
{
"anyOf": [{
"required": [
"schema"
]
@@ -1234,8 +1223,7 @@
"default": "",
"description": "%setting.frontMatter.taxonomy.contentTypes.items.properties.fields.items.properties.taxonomyId.description%",
"not": {
"anyOf": [
{
"anyOf": [{
"const": ""
},
{
@@ -1429,8 +1417,7 @@
"type",
"name"
],
"allOf": [
{
"allOf": [{
"if": {
"properties": {
"type": {
@@ -1601,6 +1588,14 @@
"default": null,
"description": "%setting.frontMatter.taxonomy.contentTypes.items.properties.previewPath.description%"
},
"slugTemplate": {
"type": [
"null",
"string"
],
"default": null,
"description": "%setting.frontMatter.content.pageFolders.items.properties.slugTemplate.description%"
},
"template": {
"type": "string",
"default": "",
@@ -1630,51 +1625,48 @@
"fields"
]
},
"default": [
{
"name": "default",
"pageBundle": false,
"fields": [
{
"title": "Title",
"name": "title",
"type": "string"
},
{
"title": "Description",
"name": "description",
"type": "string"
},
{
"title": "Publishing date",
"name": "date",
"type": "datetime",
"default": "{{now}}",
"isPublishDate": true
},
{
"title": "Content preview",
"name": "preview",
"type": "image"
},
{
"title": "Is in draft",
"name": "draft",
"type": "boolean"
},
{
"title": "Tags",
"name": "tags",
"type": "tags"
},
{
"title": "Categories",
"name": "categories",
"type": "categories"
}
]
}
],
"default": [{
"name": "default",
"pageBundle": false,
"fields": [{
"title": "Title",
"name": "title",
"type": "string"
},
{
"title": "Description",
"name": "description",
"type": "string"
},
{
"title": "Publishing date",
"name": "date",
"type": "datetime",
"default": "{{now}}",
"isPublishDate": true
},
{
"title": "Content preview",
"name": "preview",
"type": "image"
},
{
"title": "Is in draft",
"name": "draft",
"type": "boolean"
},
{
"title": "Tags",
"name": "tags",
"type": "tags"
},
{
"title": "Categories",
"name": "categories",
"type": "categories"
}
]
}],
"scope": "Taxonomy"
},
"frontMatter.taxonomy.customTaxonomy": {
@@ -1687,8 +1679,7 @@
"type": "string",
"description": "%setting.frontMatter.taxonomy.customTaxonomy.items.properties.id.description%",
"not": {
"anyOf": [
{
"anyOf": [{
"const": ""
},
{
@@ -1843,6 +1834,11 @@
"markdownDescription": "%setting.frontMatter.taxonomy.slugSuffix.markdownDescription%",
"scope": "Taxonomy"
},
"frontMatter.taxonomy.slugTemplate": {
"type": "string",
"markdownDescription": "%setting.frontMatter.taxonomy.slugTemplate.markdownDescription%",
"scope": "Taxonomy"
},
"frontMatter.taxonomy.tags": {
"type": "array",
"markdownDescription": "%setting.frontMatter.taxonomy.tags.markdownDescription%",
@@ -1880,8 +1876,7 @@
}
}
},
"commands": [
{
"commands": [{
"command": "frontMatter.project.switch",
"title": "%command.frontMatter.project.switch%",
"category": "Front Matter",
@@ -2198,21 +2193,16 @@
"category": "Front Matter"
}
],
"submenus": [
{
"id": "frontmatter.submenu",
"label": "Front Matter"
}
],
"submenus": [{
"id": "frontmatter.submenu",
"label": "Front Matter"
}],
"menus": {
"webview/context": [
{
"command": "workbench.action.webview.openDeveloperTools",
"when": "frontMatter:isDevelopment"
}
],
"editor/title": [
{
"webview/context": [{
"command": "workbench.action.webview.openDeveloperTools",
"when": "frontMatter:isDevelopment"
}],
"editor/title": [{
"command": "frontMatter.markup.heading",
"group": "navigation@-133",
"when": "frontMatter:file:isValid == true && frontMatter:markdown:wysiwyg"
@@ -2293,14 +2283,11 @@
"when": "resourceFilename == 'frontmatter.json'"
}
],
"explorer/context": [
{
"submenu": "frontmatter.submenu",
"group": "frontmatter@1"
}
],
"frontmatter.submenu": [
{
"explorer/context": [{
"submenu": "frontmatter.submenu",
"group": "frontmatter@1"
}],
"frontmatter.submenu": [{
"command": "frontMatter.createFromTemplate",
"when": "explorerResourceIsFolder",
"group": "frontmatter@1"
@@ -2316,8 +2303,7 @@
"group": "frontmatter@3"
}
],
"commandPalette": [
{
"commandPalette": [{
"command": "frontMatter.init",
"when": "frontMatterCanInit"
},
@@ -2466,8 +2452,7 @@
"when": "frontMatter:file:isValid == true"
}
],
"view/title": [
{
"view/title": [{
"command": "frontMatter.chatbot",
"group": "navigation@0",
"when": "view == frontMatter.explorer"
@@ -2499,57 +2484,52 @@
}
]
},
"grammars": [
{
"path": "./syntaxes/hugo.tmLanguage.json",
"scopeName": "frontmatter.markdown.hugo",
"injectTo": [
"text.html.markdown"
]
}
],
"walkthroughs": [
{
"id": "frontmatter.welcome",
"title": "Get started with Front Matter",
"description": "Discover the features of Front Matter and learn how to use the CMS for your SSG or static site.",
"steps": [
{
"id": "frontmatter.welcome.init",
"title": "Get started",
"description": "Initial steps to get started.\n[Open dashboard](command:frontMatter.dashboard)",
"media": {
"markdown": "assets/walkthrough/get-started.md"
},
"completionEvents": [
"onContext:frontMatterInitialized"
]
"grammars": [{
"path": "./syntaxes/hugo.tmLanguage.json",
"scopeName": "frontmatter.markdown.hugo",
"injectTo": [
"text.html.markdown"
]
}],
"walkthroughs": [{
"id": "frontmatter.welcome",
"title": "Get started with Front Matter",
"description": "Discover the features of Front Matter and learn how to use the CMS for your SSG or static site.",
"steps": [{
"id": "frontmatter.welcome.init",
"title": "Get started",
"description": "Initial steps to get started.\n[Open dashboard](command:frontMatter.dashboard)",
"media": {
"markdown": "assets/walkthrough/get-started.md"
},
{
"id": "frontmatter.welcome.documentation",
"title": "Documentation",
"description": "Check out the documentation for Front Matter.\n[View our documentation](https://frontmatter.codes/docs)",
"media": {
"markdown": "assets/walkthrough/documentation.md"
},
"completionEvents": [
"onLink:https://frontmatter.codes/docs"
]
"completionEvents": [
"onContext:frontMatterInitialized"
]
},
{
"id": "frontmatter.welcome.documentation",
"title": "Documentation",
"description": "Check out the documentation for Front Matter.\n[View our documentation](https://frontmatter.codes/docs)",
"media": {
"markdown": "assets/walkthrough/documentation.md"
},
{
"id": "frontmatter.welcome.supporter",
"title": "Support the project",
"description": "Become a supporter.\n[Support the project](https://github.com/sponsors/estruyf)",
"media": {
"markdown": "assets/walkthrough/support-the-project.md"
},
"completionEvents": [
"onLink:https://github.com/sponsors/estruyf"
]
}
]
}
]
"completionEvents": [
"onLink:https://frontmatter.codes/docs"
]
},
{
"id": "frontmatter.welcome.supporter",
"title": "Support the project",
"description": "Become a supporter.\n[Support the project](https://github.com/sponsors/estruyf)",
"media": {
"markdown": "assets/walkthrough/support-the-project.md"
},
"completionEvents": [
"onLink:https://github.com/sponsors/estruyf"
]
}
]
}]
},
"scripts": {
"dev:ext": "npm run clean && npm run localization:generate && npm-run-all --parallel watch:*",
@@ -2674,4 +2654,4 @@
"vsce": {
"dependencies": false
}
}
}

View File

@@ -211,6 +211,7 @@
"setting.frontMatter.taxonomy.contentTypes.items.properties.fields.items.properties.when.properties.caseSensitive.description": "Specify if the comparison is case sensitive. Default: true",
"setting.frontMatter.taxonomy.contentTypes.items.properties.pageBundle.description": "Specify if you want to create a folder when creating new content.",
"setting.frontMatter.taxonomy.contentTypes.items.properties.previewPath.description": "Defines a custom preview path for the content type.",
"setting.frontMatter.taxonomy.contentTypes.items.properties.slugTemplate.description": "Defines a custom slug template for the content type.",
"setting.frontMatter.taxonomy.contentTypes.items.properties.template.description": "An optional template that can be used for creating new content.",
"setting.frontMatter.taxonomy.contentTypes.items.properties.postScript.description": "An optional post script that can be used after new content creation.",
"setting.frontMatter.taxonomy.contentTypes.items.properties.filePrefix.description": "Defines a prefix for the file name.",
@@ -237,6 +238,7 @@
"setting.frontMatter.taxonomy.seoTitleLength.markdownDescription": "Specifies the optimal title length for SEO (set to `-1` to turn it off). [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontmatter.taxonomy.seotitlelength)",
"setting.frontMatter.taxonomy.slugPrefix.markdownDescription": "Specify a prefix for the slug. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontmatter.taxonomy.slugprefix)",
"setting.frontMatter.taxonomy.slugSuffix.markdownDescription": "Specify a suffix for the slug. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontmatter.taxonomy.slugsuffix)",
"setting.frontMatter.taxonomy.slugTemplate.markdownDescription": "Defines a custom slug template for the content you will create. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontmatter.taxonomy.slugtemplate)",
"setting.frontMatter.taxonomy.tags.markdownDescription": "Specifies the tags which can be used in the Front Matter. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontmatter.taxonomy.tags)",
"setting.frontMatter.telemetry.disable.markdownDescription": "Specify if you want to disable the telemetry. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontmatter.telemetry.disable)",
"setting.frontMatter.templates.enabled.markdownDescription": "Specify if you want to use templates. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontmatter.templates.enabled)",

View File

@@ -15,18 +15,23 @@ import {
import * as vscode from 'vscode';
import { CustomPlaceholder, Field } from '../models';
import { format } from 'date-fns';
import { ArticleHelper, Settings, SlugHelper } from '../helpers';
import {
ArticleHelper,
Settings,
SlugHelper,
processArticlePlaceholdersFromData,
processTimePlaceholders
} from '../helpers';
import { Notifications } from '../helpers/Notifications';
import { extname, basename, parse, dirname } from 'path';
import { COMMAND_NAME, DefaultFields } from '../constants';
import { DashboardData, SnippetRange } from '../models/DashboardData';
import { DashboardData, SnippetInfo, SnippetRange } from '../models/DashboardData';
import { DateHelper } from '../helpers/DateHelper';
import { parseWinPath } from '../helpers/parseWinPath';
import { Telemetry } from '../helpers/Telemetry';
import { ParsedFrontMatter } from '../parsers';
import { MediaListener } from '../listeners/panel';
import { NavigationType } from '../dashboardWebView/models';
import { processKnownPlaceholders } from '../helpers/PlaceholderHelper';
import { Position } from 'vscode';
import { SNIPPET } from '../constants/Snippet';
import * as l10n from '@vscode/l10n';
@@ -124,7 +129,7 @@ export class Article {
/**
* Generate the new slug
*/
public static generateSlug(title: string) {
public static generateSlug(title: string, article?: ParsedFrontMatter, slugTemplate?: string) {
if (!title) {
return;
}
@@ -132,13 +137,15 @@ export class Article {
const prefix = Settings.get(SETTING_SLUG_PREFIX) as string;
const suffix = Settings.get(SETTING_SLUG_SUFFIX) as string;
const slug = SlugHelper.createSlug(title);
if (article?.data) {
const slug = SlugHelper.createSlug(title, article?.data, slugTemplate);
if (slug) {
return {
slug,
slugWithPrefixAndSuffix: `${prefix}${slug}${suffix}`
};
if (slug) {
return {
slug,
slugWithPrefixAndSuffix: `${prefix}${slug}${suffix}`
};
}
}
return undefined;
@@ -168,7 +175,7 @@ export class Article {
const titleField = 'title';
const articleTitle: string = article.data[titleField];
const slugInfo = Article.generateSlug(articleTitle);
const slugInfo = Article.generateSlug(articleTitle, article, contentType.slugTemplate);
if (slugInfo && slugInfo.slug && slugInfo.slugWithPrefixAndSuffix) {
article.data['slug'] = slugInfo.slugWithPrefixAndSuffix;
@@ -192,9 +199,13 @@ export class Article {
);
for (const pField of customPlaceholderFields) {
article.data[pField.name] = customPlaceholder.value;
article.data[pField.name] = processKnownPlaceholders(
article.data[pField.name] = processArticlePlaceholdersFromData(
article.data[pField.name],
article.data,
contentType
);
article.data[pField.name] = processTimePlaceholders(
article.data[pField.name],
articleTitle,
dateFormat
);
}
@@ -388,7 +399,7 @@ export class Article {
snippetStartBeforePos = linesBeforeSelection.length - snippetStartBeforePos - 1;
}
let snippetInfo: { id: string; fields: any[] } | undefined = undefined;
let snippetInfo: SnippetInfo | undefined = undefined;
let range: SnippetRange | undefined = undefined;
if (
snippetEndAfterPos > -1 &&
@@ -412,6 +423,7 @@ export class Article {
}
const article = ArticleHelper.getFrontMatter(editor);
const contentType = article ? ArticleHelper.getContentType(article) : undefined;
await vscode.commands.executeCommand(COMMAND_NAME.dashboard, {
type: NavigationType.Snippets,
@@ -419,6 +431,7 @@ export class Article {
fileTitle: article?.data.title || '',
filePath: editor.document.uri.fsPath,
fieldName: basename(editor.document.uri.fsPath),
contentType,
position,
range,
selection: selectionText,

View File

@@ -31,6 +31,7 @@ import { GitListener, ModeListener } from '../listeners/general';
import { Folders } from './Folders';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../localization';
import { DashboardMessage } from '../dashboardWebView/DashboardMessage';
export class Dashboard {
private static webview: WebviewPanel | null = null;
@@ -204,7 +205,7 @@ export class Dashboard {
* @param msg
*/
public static postWebviewMessage(msg: {
command: DashboardCommand;
command: DashboardCommand | DashboardMessage;
requestId?: string;
payload?: unknown;
error?: unknown;

View File

@@ -13,7 +13,7 @@ import { ContentFolder, FileInfo, FolderInfo, StaticFolder } from '../models';
import uniqBy = require('lodash.uniqby');
import { Template } from './Template';
import { Notifications } from '../helpers/Notifications';
import { Logger, processKnownPlaceholders, Settings } from '../helpers';
import { Logger, Settings, processTimePlaceholders } from '../helpers';
import { existsSync } from 'fs';
import { format } from 'date-fns';
import { Dashboard } from './Dashboard';
@@ -377,7 +377,7 @@ export class Folders {
let folderPath: string | undefined = Folders.absWsFolder(folder, wsFolder);
if (folderPath.includes(`{{`) && folderPath.includes(`}}`)) {
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
folderPath = processKnownPlaceholders(folderPath, undefined, dateFormat);
folderPath = processTimePlaceholders(folderPath, dateFormat);
} else {
if (folderPath && !existsSync(folderPath)) {
Notifications.errorShowOnce(

View File

@@ -14,7 +14,7 @@ import {
import { ArticleHelper } from './../helpers/ArticleHelper';
import { join, parse } from 'path';
import { commands, env, Uri, ViewColumn, window, WebviewPanel, extensions } from 'vscode';
import { Extension, parseWinPath, processKnownPlaceholders, Settings } from '../helpers';
import { Extension, parseWinPath, processTimePlaceholders, Settings } from '../helpers';
import { ContentFolder, ContentType, PreviewSettings } from '../models';
import { format } from 'date-fns';
import { DateHelper } from '../helpers/DateHelper';
@@ -294,7 +294,7 @@ export class Preview {
if (pathname) {
// Known placeholders
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
pathname = processKnownPlaceholders(pathname, article?.data?.title, dateFormat);
pathname = processTimePlaceholders(pathname, dateFormat);
// Custom placeholders
pathname = await ArticleHelper.processCustomPlaceholders(
@@ -318,7 +318,7 @@ export class Preview {
}
// Support front matter placeholders - {{fm.<field>}}
pathname = processFmPlaceholders(pathname, article?.data);
pathname = article?.data ? processFmPlaceholders(pathname, article?.data) : pathname;
try {
const articleDate = ArticleHelper.getDate(article);

View File

@@ -25,6 +25,7 @@ export const SETTING_TAXONOMY_CONTENT_TYPES = 'taxonomy.contentTypes';
export const SETTING_SLUG_PREFIX = 'taxonomy.slugPrefix';
export const SETTING_SLUG_SUFFIX = 'taxonomy.slugSuffix';
export const SETTING_SLUG_TEMPLATE = 'taxonomy.slugTemplate';
export const SETTING_SLUG_UPDATE_FILE_NAME = 'taxonomy.alignFilename';
export const SETTING_INDENT_ARRAY = 'taxonomy.indentArrays';

View File

@@ -54,6 +54,7 @@ export enum DashboardMessage {
insertSnippet = 'insertSnippet',
addSnippet = 'addSnippet',
updateSnippet = 'updateSnippet',
updateSnippetPlaceholders = 'updateSnippetPlaceholders',
// Taxonomy dashboard
getTaxonomyData = 'getTaxonomyData',

View File

@@ -260,6 +260,7 @@ export const Item: React.FunctionComponent<IItemProps> = ({
ref={formRef}
snippetKey={snippetKey}
snippet={snippet}
filePath={viewData?.data?.filePath}
fieldInfo={viewData?.data?.snippetInfo?.fields}
selection={viewData?.data?.selection} />
</FormDialog>

View File

@@ -1,8 +1,7 @@
import { Messenger } from '@estruyf/vscode/dist/client';
import { Messenger, messageHandler } from '@estruyf/vscode/dist/client';
import * as React from 'react';
import { useCallback, useEffect, useImperativeHandle, useMemo, useState } from 'react';
import { useRecoilValue } from 'recoil';
import { processKnownPlaceholders } from '../../../helpers/PlaceholderHelper';
import { SnippetParser } from '../../../helpers/SnippetParser';
import { Snippet, SnippetField, SnippetInfoField, SnippetSpecialPlaceholders } from '../../../models';
import { DashboardMessage } from '../../DashboardMessage';
@@ -14,6 +13,7 @@ export interface ISnippetFormProps {
snippetKey?: string;
snippet: Snippet;
selection: string | undefined;
filePath?: string;
fieldInfo?: SnippetInfoField[];
mediaData?: any;
onInsert?: (mediaData: any) => void;
@@ -24,7 +24,7 @@ export interface SnippetFormHandle {
}
const SnippetForm: React.ForwardRefRenderFunction<SnippetFormHandle, ISnippetFormProps> = (
{ snippetKey, snippet, selection, fieldInfo, mediaData, onInsert },
{ snippetKey, snippet, selection, filePath, fieldInfo, mediaData, onInsert },
ref
) => {
const viewData = useRecoilValue(ViewDataSelector);
@@ -41,20 +41,19 @@ const SnippetForm: React.ForwardRefRenderFunction<SnippetFormHandle, ISnippetFor
);
const insertPlaceholderValues = useCallback(
(value: SnippetSpecialPlaceholders) => {
async (value: SnippetSpecialPlaceholders) => {
if (value === 'FM_SELECTED_TEXT') {
return selection || '';
}
value = processKnownPlaceholders(
value = await messageHandler.request<string>(DashboardMessage.updateSnippetPlaceholders, {
value,
viewData?.data?.fileTitle || '',
settings?.date.format || ''
);
filePath
});
return value;
},
[selection]
[selection, filePath]
);
const insertValueFromMedia = useCallback(
@@ -124,7 +123,7 @@ ${snippetBody}
}
}));
useEffect(() => {
const processFields = useCallback(async () => {
// Get all placeholder variables from the snippet
const body = typeof snippet.body === 'string' ? snippet.body : snippet.body.join(`\n`);
@@ -143,7 +142,7 @@ ${snippetBody}
if (idx > -1) {
allFields.push({
...field,
value: insertPlaceholderValues(field.default || '')
value: await insertPlaceholderValues(field.default || '')
});
}
}
@@ -163,6 +162,10 @@ ${snippetBody}
}
setFields(allFields);
}, [snippet, insertPlaceholderValues, insertValueFromMedia]);
useEffect(() => {
processFields();
}, [snippet]);
return (

View File

@@ -23,7 +23,17 @@ import {
} from '../constants';
import { DumpOptions } from 'js-yaml';
import { FrontMatterParser, ParsedFrontMatter } from '../parsers';
import { ContentType, Extension, Logger, Settings, SlugHelper, isValidFile, parseWinPath } from '.';
import {
ContentType,
Extension,
Logger,
Settings,
SlugHelper,
isValidFile,
parseWinPath,
processArticlePlaceholdersFromPath,
processTimePlaceholders
} from '.';
import { format, parse } from 'date-fns';
import { Notifications } from './Notifications';
import { Article } from '../commands';
@@ -37,7 +47,6 @@ import { DEFAULT_FILE_TYPES } from '../constants/DefaultFileTypes';
import { fromMarkdown } from 'mdast-util-from-markdown';
import { Link, Parent } from 'mdast-util-from-markdown/lib';
import { Content } from 'mdast';
import { processKnownPlaceholders } from './PlaceholderHelper';
import { CustomScript } from './CustomScript';
import { Folders } from '../commands/Folders';
import { existsAsync, readFileAsync } from '../utils';
@@ -57,6 +66,19 @@ export class ArticleHelper {
return ArticleHelper.getFrontMatterFromDocument(editor.document);
}
/**
* Retrieves the front matter from the current active document.
* @returns The front matter object if found, otherwise undefined.
*/
public static getFrontMatterFromCurrentDocument() {
const editor = vscode.window.activeTextEditor;
if (!editor) {
return;
}
return ArticleHelper.getFrontMatterFromDocument(editor.document);
}
/**
* Get the contents of the specified document
*
@@ -524,7 +546,12 @@ export class ArticleHelper {
* @param title
* @returns
*/
public static async updatePlaceholders(data: any, title: string, filePath: string) {
public static async updatePlaceholders(
data: any,
title: string,
filePath: string,
slugTemplate?: string
) {
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
const fmData = Object.assign({}, data);
@@ -536,10 +563,11 @@ export class ArticleHelper {
}
if (fieldName === 'slug' && (fieldValue === null || fieldValue === '')) {
fmData[fieldName] = SlugHelper.createSlug(title);
fmData[fieldName] = SlugHelper.createSlug(title, fmData, slugTemplate);
}
fmData[fieldName] = processKnownPlaceholders(fmData[fieldName], title, dateFormat);
fmData[fieldName] = await processArticlePlaceholdersFromPath(fmData[fieldName], filePath);
fmData[fieldName] = processTimePlaceholders(fmData[fieldName], dateFormat);
fmData[fieldName] = await this.processCustomPlaceholders(fmData[fieldName], title, filePath);
}
@@ -597,7 +625,11 @@ export class ArticleHelper {
}
const regex = new RegExp(`{{${placeholder.id}}}`, 'g');
const updatedValue = processKnownPlaceholders(placeHolderValue, title, dateFormat);
let updatedValue = filePath
? await processArticlePlaceholdersFromPath(placeHolderValue, filePath)
: placeHolderValue;
updatedValue = processTimePlaceholders(updatedValue, dateFormat);
if (value === `{{${placeholder.id}}}`) {
value = updatedValue;

View File

@@ -1,6 +1,13 @@
import { ModeListener } from './../listeners/general/ModeListener';
import { PagesListener } from './../listeners/dashboard';
import { ArticleHelper, CustomScript, Logger, Settings } from '.';
import {
ArticleHelper,
CustomScript,
Logger,
Settings,
processArticlePlaceholdersFromData,
processTimePlaceholders
} from '.';
import {
DefaultFieldValues,
EXTENSION_NAME,
@@ -26,7 +33,6 @@ import { Questions } from './Questions';
import { Notifications } from './Notifications';
import { DEFAULT_CONTENT_TYPE_NAME } from '../constants/ContentType';
import { Telemetry } from './Telemetry';
import { processKnownPlaceholders } from './PlaceholderHelper';
import { basename } from 'path';
import { ParsedFrontMatter } from '../parsers';
import { encodeEmoji, existsAsync, fieldWhenClause, writeFileAsync } from '../utils';
@@ -299,17 +305,17 @@ export class ContentType {
Telemetry.send(TelemetryEvent.addMissingFields);
const content = ArticleHelper.getCurrent();
const article = ArticleHelper.getCurrent();
if (!content || !content.data) {
if (!article || !article.data) {
Notifications.warning(
l10n.t(LocalizationKey.helpersContentTypeAddMissingFieldsNoFrontMatterWarning)
);
return;
}
const contentType = ArticleHelper.getContentType(content);
const updatedFields = ContentType.generateFields(content.data, contentType.fields);
const contentType = ArticleHelper.getContentType(article);
const updatedFields = ContentType.generateFields(article.data, contentType.fields);
const contentTypes = ContentType.getAll() || [];
const index = contentTypes.findIndex((ct) => ct.name === contentType.name);
@@ -927,7 +933,8 @@ export class ContentType {
titleValue,
templateData?.data || {},
newFilePath,
!!contentType.clearEmpty
!!contentType.clearEmpty,
contentType
);
const article: ParsedFrontMatter = {
@@ -982,6 +989,7 @@ export class ContentType {
data: any,
filePath: string,
clearEmpty: boolean,
contentType: IContentType,
isRoot: boolean = true
): Promise<any> {
if (obj.fields) {
@@ -995,9 +1003,9 @@ export class ContentType {
if (field.name === 'title') {
if (field.default) {
data[field.name] = processKnownPlaceholders(
field.default,
titleValue,
data[field.name] = processArticlePlaceholdersFromData(field.default, data, contentType);
data[field.name] = processTimePlaceholders(
data[field.name],
field.dateFormat || dateFormat
);
data[field.name] = await ArticleHelper.processCustomPlaceholders(
@@ -1018,6 +1026,7 @@ export class ContentType {
{},
filePath,
clearEmpty,
contentType,
false
);
@@ -1028,9 +1037,13 @@ export class ContentType {
const defaultValue = field.default;
if (typeof defaultValue === 'string') {
data[field.name] = processKnownPlaceholders(
data[field.name] = processArticlePlaceholdersFromData(
defaultValue,
titleValue,
data,
contentType
);
data[field.name] = processTimePlaceholders(
data[field.name],
field.dateFormat || dateFormat
);
data[field.name] = await ArticleHelper.processCustomPlaceholders(

View File

@@ -1,4 +1,6 @@
import { stopWords, charMap } from '../constants';
import { Settings } from '.';
import { stopWords, charMap, SETTING_DATE_FORMAT, SETTING_SLUG_TEMPLATE } from '../constants';
import { processTimePlaceholders, processFmPlaceholders } from '.';
export class SlugHelper {
/**
@@ -6,13 +8,41 @@ export class SlugHelper {
*
* @param articleTitle
*/
public static createSlug(articleTitle: string): string | null {
public static createSlug(
articleTitle: string,
articleData: { [key: string]: any },
slugTemplate?: string
): string | null {
if (!articleTitle) {
return null;
}
// Remove punctuation from input string, and split it into words.
let cleanTitle = this.removePunctuation(articleTitle).trim();
if (!slugTemplate) {
slugTemplate = Settings.get<string>(SETTING_SLUG_TEMPLATE) || undefined;
}
if (slugTemplate) {
if (slugTemplate.includes('{{title}}')) {
const regex = new RegExp('{{title}}', 'g');
slugTemplate = slugTemplate.replace(regex, SlugHelper.slugify(articleTitle));
}
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
articleTitle = processTimePlaceholders(slugTemplate, dateFormat);
articleTitle = processFmPlaceholders(articleTitle, articleData);
return articleTitle;
}
return SlugHelper.slugify(articleTitle);
}
/**
* Converts a title into a slug by removing punctuation, stop words, and replacing characters.
* @param title - The title to be slugified.
* @returns The slugified version of the title.
*/
public static slugify(title: string): string {
let cleanTitle = this.removePunctuation(title).trim();
if (cleanTitle) {
cleanTitle = cleanTitle.toLowerCase();
// Split into words
@@ -23,8 +53,7 @@ export class SlugHelper {
cleanTitle = this.replaceCharacters(cleanTitle);
return cleanTitle;
}
return null;
return '';
}
/**

View File

@@ -15,7 +15,6 @@ export * from './MediaHelpers';
export * from './MediaLibrary';
export * from './Notifications';
export * from './PanelSettings';
export * from './PlaceholderHelper';
export * from './Questions';
export * from './Sanitize';
export * from './SeoHelper';
@@ -32,5 +31,7 @@ export * from './getTaxonomyField';
export * from './isValidFile';
export * from './openFileInEditor';
export * from './parseWinPath';
export * from './processArticlePlaceholders';
export * from './processFmPlaceholders';
export * from './processPathPlaceholders';
export * from './processTimePlaceholders';

View File

@@ -0,0 +1,53 @@
import { ContentType } from '../models';
import { ArticleHelper } from './ArticleHelper';
import { SlugHelper } from './SlugHelper';
export const processArticlePlaceholdersFromData = (
value: string,
data: { [key: string]: any },
contentType: ContentType
): string => {
if (value.includes('{{title}}') && data.title) {
const regex = new RegExp('{{title}}', 'g');
value = value.replace(regex, data.title || '');
}
if (value.includes('{{slug}}')) {
const regex = new RegExp('{{slug}}', 'g');
value = value.replace(
regex,
SlugHelper.createSlug(data.title || '', data, contentType.slugTemplate) || ''
);
}
return value;
};
export const processArticlePlaceholdersFromPath = async (
value: string,
filePath: string
): Promise<string> => {
const article = await ArticleHelper.getFrontMatterByPath(filePath);
if (!article) {
return value;
}
if (value.includes('{{title}}')) {
const regex = new RegExp('{{title}}', 'g');
value = value.replace(regex, article.data.title || '');
}
if (value.includes('{{slug}}') && filePath) {
const contentType = article ? ArticleHelper.getContentType(article) : undefined;
if (contentType) {
const regex = new RegExp('{{slug}}', 'g');
value = value.replace(
regex,
SlugHelper.createSlug(article.data.title || '', article.data, contentType.slugTemplate) ||
''
);
}
}
return value;
};

View File

@@ -1,6 +1,6 @@
import { format } from 'date-fns';
export const processFmPlaceholders = (value: string, fmData: any) => {
export const processFmPlaceholders = (value: string, fmData: { [key: string]: any }) => {
// Example: {{fm.date}} or {{fm.date | dateFormat 'DD.MM.YYYY'}}
if (value && value.includes('{{fm.')) {
const regex = /{{fm.[^}]*}}/g;

View File

@@ -1,29 +1,14 @@
import { format } from 'date-fns';
import { DateHelper } from './DateHelper';
import { SlugHelper } from './SlugHelper';
/**
* Replace the known placeholders
* Replace the time placeholders
* @param value
* @param title
* @returns
*/
export const processKnownPlaceholders = (
value: string,
title: string | undefined,
dateFormat: string
) => {
export const processTimePlaceholders = (value: string, dateFormat?: string) => {
if (value && typeof value === 'string') {
if (value.includes('{{title}}')) {
const regex = new RegExp('{{title}}', 'g');
value = value.replace(regex, title || '');
}
if (value.includes('{{slug}}')) {
const regex = new RegExp('{{slug}}', 'g');
value = value.replace(regex, SlugHelper.createSlug(title || '') || '');
}
if (value.includes('{{now}}')) {
const regex = new RegExp('{{now}}', 'g');

View File

@@ -1,5 +1,6 @@
import { Dashboard } from '../../commands/Dashboard';
import { DashboardCommand } from '../../dashboardWebView/DashboardCommand';
import { DashboardMessage } from '../../dashboardWebView/DashboardMessage';
import { Logger } from '../../helpers/Logger';
import { PostMessageData } from '../../models';
@@ -20,7 +21,11 @@ export abstract class BaseListener {
});
}
public static sendRequest(command: DashboardCommand, requestId: string, payload: any) {
public static sendRequest(
command: DashboardCommand | DashboardMessage,
requestId: string,
payload: any
) {
Dashboard.postWebviewMessage({
command,
requestId,

View File

@@ -1,9 +1,16 @@
import { EditorHelper } from '@estruyf/vscode';
import { window, Range, Position } from 'vscode';
import { Dashboard } from '../../commands/Dashboard';
import { SETTING_CONTENT_SNIPPETS, TelemetryEvent } from '../../constants';
import { SETTING_CONTENT_SNIPPETS, SETTING_DATE_FORMAT, TelemetryEvent } from '../../constants';
import { DashboardMessage } from '../../dashboardWebView/DashboardMessage';
import { Notifications, Settings, Telemetry } from '../../helpers';
import {
ArticleHelper,
Notifications,
Settings,
Telemetry,
processArticlePlaceholdersFromPath,
processTimePlaceholders
} from '../../helpers';
import { PostMessageData, Snippets } from '../../models';
import { BaseListener } from './BaseListener';
import { SettingsListener } from './SettingsListener';
@@ -25,6 +32,9 @@ export class SnippetListener extends BaseListener {
Telemetry.send(TelemetryEvent.insertContentSnippet);
this.insertSnippet(msg.payload);
break;
case DashboardMessage.updateSnippetPlaceholders:
this.updateSnippetPlaceholders(msg.command, msg.payload, msg.requestId);
break;
}
}
@@ -124,4 +134,25 @@ export class SnippetListener extends BaseListener {
});
}
}
private static async updateSnippetPlaceholders(
command: DashboardMessage,
data: { value: string; filePath: string },
requestId?: string
) {
if (!data.value || !command || !requestId) {
return;
}
let value = data.value;
if (data.filePath) {
value = await processArticlePlaceholdersFromPath(data.value, data.filePath);
}
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
value = processTimePlaceholders(value, dateFormat);
this.sendRequest(command, requestId, value);
}
}

View File

@@ -19,7 +19,7 @@ import {
Extension,
Logger,
Notifications,
processKnownPlaceholders,
processTimePlaceholders,
Telemetry
} from '../../helpers';
import { GeneralCommands } from './../../constants/GeneralCommands';
@@ -165,7 +165,7 @@ export class GitListener {
if (commitMsg) {
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
commitMsg = processKnownPlaceholders(commitMsg, undefined, dateFormat);
commitMsg = processTimePlaceholders(commitMsg, dateFormat);
commitMsg = await ArticleHelper.processCustomPlaceholders(commitMsg, undefined, undefined);
}

View File

@@ -1,6 +1,6 @@
import { Article } from '../../commands';
import { ArticleHelper } from '../../helpers';
import { PostMessageData } from '../../models';
import { Command } from '../../panelWebView/Command';
import { CommandToCode } from '../../panelWebView/CommandToCode';
import { BaseListener } from './BaseListener';
@@ -17,7 +17,7 @@ export class ArticleListener extends BaseListener {
Article.updateSlug();
break;
case CommandToCode.generateSlug:
this.generateSlug(msg.payload);
this.generateSlug(msg.command, msg.payload, msg.requestId);
break;
case CommandToCode.updateLastMod:
Article.setLastModifiedDate();
@@ -32,10 +32,19 @@ export class ArticleListener extends BaseListener {
* Generate a slug
* @param title
*/
private static generateSlug(title: string) {
const slug = Article.generateSlug(title);
private static generateSlug(
command: CommandToCode,
{ title, slugTemplate }: { title: string; slugTemplate?: string },
requestId?: string
) {
if (!command || !requestId) {
return;
}
const article = ArticleHelper.getFrontMatterFromCurrentDocument();
const slug = Article.generateSlug(title, article, slugTemplate);
if (slug) {
this.sendMsg(Command.updatedSlug, slug);
this.sendRequest(command, requestId, slug);
}
}
}

View File

@@ -6,7 +6,16 @@ import { Command } from '../../panelWebView/Command';
import { CommandToCode } from '../../panelWebView/CommandToCode';
import { BaseListener } from './BaseListener';
import { authentication, commands, window } from 'vscode';
import { ArticleHelper, ContentType, Extension, Logger, Settings } from '../../helpers';
import {
ArticleHelper,
Extension,
Logger,
Settings,
ContentType,
processArticlePlaceholdersFromData,
processTimePlaceholders,
processFmPlaceholders
} from '../../helpers';
import {
COMMAND_NAME,
DefaultFields,
@@ -20,8 +29,7 @@ import {
} from '../../constants';
import { Article, Preview } from '../../commands';
import { ParsedFrontMatter } from '../../parsers';
import { processKnownPlaceholders } from '../../helpers/PlaceholderHelper';
import { Field, Mode, PostMessageData } from '../../models';
import { Field, Mode, PostMessageData, ContentType as IContentType } from '../../models';
import { encodeEmoji, fieldWhenClause } from '../../utils';
import { PanelProvider } from '../../panelWebView/PanelProvider';
import { MessageHandlerData } from '@estruyf/vscode';
@@ -66,7 +74,11 @@ export class DataListener extends BaseListener {
this.isServerStarted(msg.command, msg?.requestId);
break;
case CommandToCode.updatePlaceholder:
this.updatePlaceholder(msg?.payload?.field, msg?.payload?.value, msg?.payload?.title);
this.updatePlaceholder(
msg.command,
msg.payload as { field: string; value: string; data: { [key: string]: any } },
msg.requestId
);
break;
case CommandToCode.generateContentType:
commands.executeCommand(COMMAND_NAME.generateContentType);
@@ -211,7 +223,11 @@ export class DataListener extends BaseListener {
if (keys.length > 0 && contentTypes && wsFolder) {
// Get the current content type
const contentType = ArticleHelper.getContentType(updatedMetadata);
const contentType = ArticleHelper.getContentType({
content: '',
data: updatedMetadata,
path: filePath
});
let slugField;
if (contentType) {
ImageHelper.processImageFields(updatedMetadata, contentType.fields);
@@ -597,18 +613,37 @@ export class DataListener extends BaseListener {
* @param value
* @param title
*/
private static async updatePlaceholder(field: string, value: string, title: string) {
if (field && value) {
private static async updatePlaceholder(
command: CommandToCode,
articleData: {
field: string;
value: string;
data: { [key: string]: any };
contentType?: IContentType;
},
requestId?: string
) {
if (!command || !requestId || !articleData) {
return;
}
let { field, value, data, contentType } = articleData;
value = value || '';
if (field) {
const crntFile = window.activeTextEditor?.document;
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
value = processKnownPlaceholders(value, title || '', dateFormat);
value =
data && contentType ? processArticlePlaceholdersFromData(value, data, contentType) : value;
value = processTimePlaceholders(value, dateFormat);
value = processFmPlaceholders(value, data);
value = await ArticleHelper.processCustomPlaceholders(
value,
title || '',
data.title || '',
crntFile?.uri.fsPath || ''
);
}
this.sendMsg(Command.updatePlaceholder, { field, value });
this.sendRequest(Command.updatePlaceholder, requestId, { field, value });
}
}

View File

@@ -1,6 +1,7 @@
import { Position } from 'vscode';
import { NavigationType } from '../dashboardWebView/models';
import { BlockFieldData } from './BlockFieldData';
import { ContentType } from '.';
export interface DashboardData {
type: NavigationType;
@@ -12,6 +13,7 @@ export interface ViewData {
fieldName?: string;
position?: Position;
fileTitle?: string;
contentType?: ContentType;
selection?: string;
range?: SnippetRange;
snippetInfo?: SnippetInfo;

View File

@@ -59,6 +59,7 @@ export interface ContentType {
fileType?: 'md' | 'mdx' | string;
previewPath?: string | null;
slugTemplate?: string;
pageBundle?: boolean;
defaultFileName?: string;
template?: string;

View File

@@ -10,6 +10,5 @@ export enum Command {
sendMediaUrl = 'sendMediaUrl',
updatePlaceholder = 'updatePlaceholder',
dataFileEntries = 'dataFileEntries',
updatedSlug = 'updatedSlug',
serverStarted = 'server-started'
}

View File

@@ -1,10 +1,8 @@
import { Messenger } from '@estruyf/vscode/dist/client';
import { EventData } from '@estruyf/vscode/dist/models';
import { Messenger, messageHandler } from '@estruyf/vscode/dist/client';
import { LinkIcon, ArrowPathIcon } from '@heroicons/react/24/outline';
import * as React from 'react';
import { useCallback, useEffect, useMemo } from 'react';
import { useEffect, useMemo } from 'react';
import { BaseFieldProps } from '../../../models';
import { Command } from '../../Command';
import { CommandToCode } from '../../CommandToCode';
import { FieldTitle } from './FieldTitle';
import { FieldMessage } from './FieldMessage';
@@ -14,6 +12,7 @@ import { LocalizationKey } from '../../../localization';
export interface ISlugFieldProps extends BaseFieldProps<string> {
titleValue: string | null;
editable?: boolean;
slugTemplate?: string;
onChange: (txtValue: string) => void;
}
@@ -23,6 +22,7 @@ export const SlugField: React.FunctionComponent<ISlugFieldProps> = ({
editable,
value,
titleValue,
slugTemplate,
onChange,
required
}: React.PropsWithChildren<ISlugFieldProps>) => {
@@ -38,16 +38,6 @@ export const SlugField: React.FunctionComponent<ISlugFieldProps> = ({
Messenger.send(CommandToCode.updateSlug);
};
const messageListener = useCallback(
(message: MessageEvent<EventData<any>>) => {
const { command, payload } = message.data;
if (command === Command.updatedSlug) {
setSlug(payload?.slugWithPrefixAndSuffix);
}
},
[text]
);
const showRequiredState = useMemo(() => {
return required && !text;
}, [required, text]);
@@ -60,17 +50,18 @@ export const SlugField: React.FunctionComponent<ISlugFieldProps> = ({
useEffect(() => {
if (titleValue) {
Messenger.send(CommandToCode.generateSlug, titleValue);
messageHandler.request<{ slug: string; slugWithPrefixAndSuffix: string; }>(CommandToCode.generateSlug, {
title: titleValue,
slugTemplate
}).then((slug) => {
if (slug.slugWithPrefixAndSuffix) {
setSlug(slug.slugWithPrefixAndSuffix);
}
}).catch((_) => {
setSlug(null);
});
}
}, [titleValue]);
useEffect(() => {
Messenger.listen(messageListener);
return () => {
Messenger.unlisten(messageListener);
};
}, []);
}, [titleValue, slugTemplate]);
return (
<div className={`metadata_field`}>

View File

@@ -1,9 +1,8 @@
import { Messenger } from '@estruyf/vscode/dist/client';
import { messageHandler } from '@estruyf/vscode/dist/client';
import * as React from 'react';
import { useCallback, useEffect, useState } from 'react';
import { DateHelper } from '../../../helpers/DateHelper';
import { BlockFieldData, CustomPanelViewResult, Field, PanelSettings } from '../../../models';
import { Command } from '../../Command';
import { BlockFieldData, ContentType, CustomPanelViewResult, Field, PanelSettings } from '../../../models';
import { CommandToCode } from '../../CommandToCode';
import { TagType } from '../../TagType';
import { DataBlockField } from '../DataBlock';
@@ -41,6 +40,7 @@ export interface IWrapperFieldProps {
parentFields: string[];
metadata: IMetadata;
settings: PanelSettings;
contentType: ContentType | null;
blockData: BlockFieldData | undefined;
focusElm: TagType | null;
parentBlock: string | null | undefined;
@@ -63,6 +63,7 @@ export const WrapperField: React.FunctionComponent<IWrapperFieldProps> = ({
parentFields,
metadata,
settings,
contentType,
blockData,
focusElm,
parentBlock,
@@ -76,21 +77,6 @@ export const WrapperField: React.FunctionComponent<IWrapperFieldProps> = ({
html: (data: any, onChange: (value: any) => void) => Promise<CustomPanelViewResult | undefined>;
}[]>([]);
const listener = useCallback(
(event: any) => {
const message = event.data;
if (message.command === Command.updatePlaceholder) {
const data = message.payload;
if (data.field === field.name) {
setFieldValue(data.value);
onSendUpdate(field.name, data.value, parentFields);
}
}
},
[field]
);
const getDate = (date: string | Date): Date | null => {
const parsedDate = DateHelper.tryParse(date, settings?.date?.format);
return parsedDate || (date as Date | null);
@@ -126,11 +112,18 @@ export const WrapperField: React.FunctionComponent<IWrapperFieldProps> = ({
// Check if the field value contains a placeholder
if (value && typeof value === 'string' && value.includes(`{{`) && value.includes(`}}`)) {
window.addEventListener('message', listener);
Messenger.send(CommandToCode.updatePlaceholder, {
messageHandler.request<{ field: string; value: any; }>(CommandToCode.updatePlaceholder, {
field: field.name,
title: metadata['title'],
value
value,
data: metadata,
contentType
}).then((data) => {
if (data.field === field.name) {
setFieldValue(data.value);
onSendUpdate(field.name, data.value, parentFields);
}
}).catch((err) => {
console.error(err);
});
} else {
// Did not contain a placeholder, so value can be set
@@ -138,10 +131,6 @@ export const WrapperField: React.FunctionComponent<IWrapperFieldProps> = ({
setFieldValue(value || null);
}
}
return () => {
window.removeEventListener('message', listener);
};
}, [field, parent]);
useEffect(() => {
@@ -509,6 +498,7 @@ export const WrapperField: React.FunctionComponent<IWrapperFieldProps> = ({
description={field.description}
titleValue={metadata.title as string}
value={fieldValue}
slugTemplate={contentType?.slugTemplate}
required={!!field.required}
editable={field.editable}
onChange={onFieldChange}

View File

@@ -66,6 +66,7 @@ const Metadata: React.FunctionComponent<IMetadataProps> = ({
parent={parent}
parentFields={parentFields}
metadata={metadata}
contentType={contentType}
settings={settings}
blockData={blockData}
parentBlock={parentBlock}

View File

@@ -233,7 +233,10 @@ export class PagesParser {
// Make sure these are always set
title: escapedTitle,
description: escapedDescription,
slug: article?.data.slug || Article.generateSlug(escapedTitle)?.slugWithPrefixAndSuffix,
slug:
article?.data.slug ||
Article.generateSlug(escapedTitle, article, contentType.slugTemplate)
?.slugWithPrefixAndSuffix,
date: article?.data[dateField] || '',
draft: article?.data.draft
};