Added new placeholders

This commit is contained in:
Elio Struyf
2022-03-14 16:46:57 +01:00
parent bb9795952d
commit e77672dfc7
10 changed files with 100 additions and 40 deletions
+1
View File
@@ -13,6 +13,7 @@
- Light color theme enhancements to folder cards
- Added collapse and dashboard button to the view title of the FM Panel
- Show content commands only when a supported file type is active
- Added `{{year}}`, `{{month}}`, and `{{day}}` placeholders for fields
- [#272](https://github.com/estruyf/vscode-front-matter/issues/272): New slide over panel for showing details of media files
- [#276](https://github.com/estruyf/vscode-front-matter/issues/276): Add a Front Matter walkthrough for VS Code
- [#270](https://github.com/estruyf/vscode-front-matter/issues/270): Only show media files from public folder if `pageBundle` is not enabled on any of the content types
+6 -1
View File
@@ -15,6 +15,7 @@ import { Telemetry } from '../helpers/Telemetry';
import { ParsedFrontMatter } from '../parsers';
import { MediaListener } from '../listeners/panel';
import { NavigationType } from '../dashboardWebView/models';
import { processKnownPlaceholders } from '../helpers/PlaceholderHelper';
export class Article {
@@ -205,11 +206,12 @@ export class Article {
// Update the fields containing a custom placeholder that depends on slug
const placeholders = Settings.get<{id: string, value: string}[]>(SETTING_CONTENT_PLACEHOLDERS);
const customPlaceholders = placeholders?.filter(p => p.value.includes("{{slug}}"));
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
for (const customPlaceholder of (customPlaceholders || [])) {
const customPlaceholderFields = contentType.fields.filter(f => f.default === `{{${customPlaceholder.id}}}`);
for (const pField of customPlaceholderFields) {
article.data[pField.name] = customPlaceholder.value;
article.data[pField.name] = ArticleHelper.processKnownPlaceholders(article.data[pField.name], articleTitle);
article.data[pField.name] = processKnownPlaceholders(article.data[pField.name], articleTitle, dateFormat);
}
}
}
@@ -359,9 +361,12 @@ export class Article {
const position = editor.selection.active;
const selectionText = editor.document.getText(editor.selection);
const article = ArticleHelper.getFrontMatter(editor);
await vscode.commands.executeCommand(COMMAND_NAME.dashboard, {
type: NavigationType.Snippets,
data: {
fileTitle: article?.data.title || "",
filePath: editor.document.uri.fsPath,
fieldName: basename(editor.document.uri.fsPath),
position,
@@ -2,10 +2,11 @@ import { Messenger } 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, SnippetSpecialPlaceholders } from '../../../models';
import { DashboardMessage } from '../../DashboardMessage';
import { ViewDataSelector } from '../../state';
import { SettingsAtom, ViewDataSelector } from '../../state';
import { SnippetInputField } from './SnippetInputField';
@@ -21,16 +22,19 @@ export interface SnippetFormHandle {
const SnippetForm: React.ForwardRefRenderFunction<SnippetFormHandle, ISnippetFormProps> = ({ snippet, selection }, ref) => {
const viewData = useRecoilValue(ViewDataSelector);
const [ fields, setFields ] = useState<SnippetField[]>([]);
const settings = useRecoilValue(SettingsAtom);
const onTextChange = useCallback((field: SnippetField, value: string) => {
setFields(prevFields => prevFields.map(f => f.name === field.name ? { ...f, value } : f));
}, [setFields]);
const insertSelectionValue = useCallback((value: SnippetSpecialPlaceholders) => {
const insertPlaceholderValues = useCallback((value: SnippetSpecialPlaceholders) => {
if (value === "FM_SELECTED_TEXT") {
return selection || "";
}
value = processKnownPlaceholders(value, viewData?.data?.fileTitle || "", settings?.date.format || "");
return value;
}, [selection]);
@@ -81,7 +85,7 @@ const SnippetForm: React.ForwardRefRenderFunction<SnippetFormHandle, ISnippetFor
if (field) {
allFields.push({
...field,
value: insertSelectionValue(field.default || "")
value: insertPlaceholderValues(field.default || "")
});
} else {
allFields.push({
+1
View File
@@ -30,6 +30,7 @@ export interface Settings {
dataTypes: DataType[] | undefined;
isBacker: boolean | undefined;
snippets: Snippets | undefined;
date: { format: string };
}
export interface DashboardState {
+5 -29
View File
@@ -20,6 +20,7 @@ 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';
export class ArticleHelper {
private static notifiedFiles: string[] = [];
@@ -321,6 +322,7 @@ export class ArticleHelper {
* @returns
*/
public static updatePlaceholders(data: any, title: string) {
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
const fmData = Object.assign({}, data);
for (const fieldName of Object.keys(fmData)) {
@@ -334,40 +336,13 @@ export class ArticleHelper {
fmData[fieldName] = SlugHelper.createSlug(title);
}
fmData[fieldName] = this.processKnownPlaceholders(fmData[fieldName], title);
fmData[fieldName] = processKnownPlaceholders(fmData[fieldName], title, dateFormat);
fmData[fieldName] = this.processCustomPlaceholders(fmData[fieldName], title);
}
return fmData;
}
/**
* Replace the known placeholders
* @param value
* @param title
* @returns
*/
public static processKnownPlaceholders(value: string, title: 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");
value = value.replace(regex, Article.formatDate(new Date()));
}
}
return value;
}
/**
* Replace the custom placeholders
* @param value
@@ -376,12 +351,13 @@ export class ArticleHelper {
*/
public static processCustomPlaceholders(value: string, title: string) {
if (value && typeof value === "string") {
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
const placeholders = Settings.get<{id: string, value: string}[]>(SETTING_CONTENT_PLACEHOLDERS);
if (placeholders && placeholders.length > 0) {
for (const placeholder of placeholders) {
if (value.includes(`{{${placeholder.id}}}`)) {
const regex = new RegExp(`{{${placeholder.id}}}`, "g");
const updatedValue = this.processKnownPlaceholders(placeholder.value, title);
const updatedValue = processKnownPlaceholders(placeholder.value, title, dateFormat);
value = value.replace(regex, updatedValue);
}
}
+5 -3
View File
@@ -1,6 +1,6 @@
import { PagesListener } from './../listeners/dashboard';
import { ArticleHelper, Settings } from ".";
import { SETTING_CONTENT_DRAFT_FIELD, SETTING_TAXONOMY_CONTENT_TYPES, TelemetryEvent } from "../constants";
import { SETTING_CONTENT_DRAFT_FIELD, SETTING_DATE_FORMAT, SETTING_TAXONOMY_CONTENT_TYPES, TelemetryEvent } from "../constants";
import { ContentType as IContentType, DraftField, Field } from '../models';
import { Uri, commands } from 'vscode';
import { Folders } from "../commands/Folders";
@@ -9,6 +9,7 @@ import { writeFileSync } from "fs";
import { Notifications } from "./Notifications";
import { DEFAULT_CONTENT_TYPE_NAME } from "../constants/ContentType";
import { Telemetry } from './Telemetry';
import { processKnownPlaceholders } from './PlaceholderHelper';
export class ContentType {
@@ -140,10 +141,11 @@ export class ContentType {
private static processFields(obj: IContentType | Field, titleValue: string, data: any) {
if (obj.fields) {
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
for (const field of obj.fields) {
if (field.name === "title") {
if (field.default) {
data[field.name] = ArticleHelper.processKnownPlaceholders(field.default, titleValue);
data[field.name] = processKnownPlaceholders(field.default, titleValue, dateFormat);
data[field.name] = ArticleHelper.processCustomPlaceholders(data[field.name], titleValue);
} else {
data[field.name] = titleValue;
@@ -152,7 +154,7 @@ export class ContentType {
if (field.type === "fields") {
data[field.name] = this.processFields(field, titleValue, {});
} else {
data[field.name] = field.default ? ArticleHelper.processKnownPlaceholders(field.default, titleValue) : "";
data[field.name] = field.default ? processKnownPlaceholders(field.default, titleValue, dateFormat) : "";
data[field.name] = field.default ? ArticleHelper.processCustomPlaceholders(data[field.name], titleValue) : "";
}
}
+4 -1
View File
@@ -2,7 +2,7 @@ import { basename, join } from "path";
import { workspace } from "vscode";
import { Folders } from "../commands/Folders";
import { Template } from "../commands/Template";
import { CONTEXT, ExtensionState, SETTING_CONTENT_DRAFT_FIELD, SETTING_CONTENT_SORTING, SETTING_CONTENT_SORTING_DEFAULT, SETTING_CONTENT_STATIC_FOLDER, SETTING_DASHBOARD_MEDIA_SNIPPET, SETTING_DASHBOARD_OPENONSTART, SETTING_DATA_FILES, SETTING_DATA_FOLDERS, SETTING_DATA_TYPES, SETTING_FRAMEWORK_ID, SETTING_MEDIA_SORTING_DEFAULT, SETTING_CUSTOM_SCRIPTS, SETTING_TAXONOMY_CONTENT_TYPES, SETTING_CONTENT_SNIPPETS } from "../constants";
import { CONTEXT, ExtensionState, SETTING_CONTENT_DRAFT_FIELD, SETTING_CONTENT_SORTING, SETTING_CONTENT_SORTING_DEFAULT, SETTING_CONTENT_STATIC_FOLDER, SETTING_DASHBOARD_MEDIA_SNIPPET, SETTING_DASHBOARD_OPENONSTART, SETTING_DATA_FILES, SETTING_DATA_FOLDERS, SETTING_DATA_TYPES, SETTING_FRAMEWORK_ID, SETTING_MEDIA_SORTING_DEFAULT, SETTING_CUSTOM_SCRIPTS, SETTING_TAXONOMY_CONTENT_TYPES, SETTING_CONTENT_SNIPPETS, SETTING_DATE_FORMAT } from "../constants";
import { DashboardViewType, SortingOption, Settings as ISettings } from "../dashboardWebView/models";
import { CustomScript, DraftField, ScriptType, Snippets, SortingSetting, TaxonomyType } from "../models";
import { DataFile } from "../models/DataFile";
@@ -39,6 +39,9 @@ export class DashboardSettings {
crntFramework: Settings.get<string>(SETTING_FRAMEWORK_ID),
framework: (!isInitialized && wsFolder) ? FrameworkDetector.get(wsFolder.fsPath) : null,
scripts: (Settings.get<CustomScript[]>(SETTING_CUSTOM_SCRIPTS) || []),
date: {
format: Settings.get<string>(SETTING_DATE_FORMAT) || ""
},
dashboardState: {
contents: {
sorting: await ext.getState<SortingOption | undefined>(ExtensionState.Dashboard.Contents.Sorting, "workspace"),
+50
View File
@@ -0,0 +1,50 @@
import { format } from "date-fns";
import { DateHelper } from "./DateHelper";
import { SlugHelper } from "./SlugHelper";
/**
* Replace the known placeholders
* @param value
* @param title
* @returns
*/
export const processKnownPlaceholders = (value: string, title: 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");
if (dateFormat && typeof dateFormat === "string") {
value = value.replace(regex, format(new Date(), DateHelper.formatUpdate(dateFormat) as string));
} else {
return (new Date()).toISOString();
}
}
if (value.includes("{{year}}")) {
const regex = new RegExp("{{year}}", "g");
value = value.replace(regex, format(new Date(), "yyyy"));
}
if (value.includes("{{month}}")) {
const regex = new RegExp("{{month}}", "g");
value = value.replace(regex, format(new Date(), "MM"));
}
if (value.includes("{{day}}")) {
const regex = new RegExp("{{day}}", "g");
value = value.replace(regex, format(new Date(), "dd"));
}
}
return value;
}
+4 -2
View File
@@ -6,9 +6,10 @@ import { CommandToCode } from "../../panelWebView/CommandToCode";
import { BaseListener } from "./BaseListener";
import { commands, ThemeIcon, window } from 'vscode';
import { ArticleHelper, Logger, Settings } from "../../helpers";
import { COMMAND_NAME, DefaultFields, SETTING_COMMA_SEPARATED_FIELDS, SETTING_TAXONOMY_CONTENT_TYPES } from "../../constants";
import { COMMAND_NAME, DefaultFields, SETTING_COMMA_SEPARATED_FIELDS, SETTING_DATE_FORMAT, SETTING_TAXONOMY_CONTENT_TYPES } from "../../constants";
import { Article } from '../../commands';
import { ParsedFrontMatter } from '../../parsers';
import { processKnownPlaceholders } from '../../helpers/PlaceholderHelper';
const FILE_LIMIT = 10;
@@ -287,7 +288,8 @@ export class DataListener extends BaseListener {
private static updatePlaceholder(field: string, value: string, title: string) {
if (field && value) {
value = ArticleHelper.processKnownPlaceholders(value, title || "");
const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string;
value = processKnownPlaceholders(value, title || "", dateFormat);
value = ArticleHelper.processCustomPlaceholders(value, title || "");
}
+17 -1
View File
@@ -1,6 +1,22 @@
import { Position } from 'vscode';
import { NavigationType } from '../dashboardWebView/models';
import { BlockFieldData } from './BlockFieldData';
export interface DashboardData {
type: NavigationType;
data?: any;
data?: ViewData;
}
export interface ViewData {
filePath?: string;
fieldName?: string;
position?: Position;
fileTitle?: string;
selection?: string;
pageBundle?: boolean;
metadataInsert?: boolean;
blockData?: BlockFieldData;
parents?: string[];
multiple?: string[];
value?: string;
}