mirror of
https://github.com/docmost/docmost.git
synced 2026-08-25 07:32:13 +10:00
improve markdown import and export
This commit is contained in:
@@ -13,7 +13,8 @@ interface TabbedToken {
|
|||||||
activeTabIndex: number;
|
activeTabIndex: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const HEADER_RE = /^===([!+])?\s*["'“”‘’]([^"'“”‘’\n]+)["'“”‘’]\s*$/gm;
|
const HEADER_RE =
|
||||||
|
/^===([!+])?\s*["'“”‘’]((?:\\.|[^"'“”‘’\n])+?)["'“”‘’]\s*$/gm;
|
||||||
|
|
||||||
export const tabsExtension = {
|
export const tabsExtension = {
|
||||||
name: 'tabbed',
|
name: 'tabbed',
|
||||||
@@ -38,7 +39,7 @@ export const tabsExtension = {
|
|||||||
index: m.index,
|
index: m.index,
|
||||||
raw: m[0],
|
raw: m[0],
|
||||||
marker: m[1] ?? '',
|
marker: m[1] ?? '',
|
||||||
label: m[2].trim(),
|
label: unescapeTabLabel(m[2].trim()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,7 +88,7 @@ export const tabsExtension = {
|
|||||||
if (body.length > 0) {
|
if (body.length > 0) {
|
||||||
body = body
|
body = body
|
||||||
.split('\n')
|
.split('\n')
|
||||||
.map((line) => line.replace(/^\s{2,4}/, ''))
|
.map((line) => line.replace(/^(?:\t| {2,4})/, ''))
|
||||||
.join('\n');
|
.join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,6 +138,10 @@ export const tabsExtension = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function unescapeTabLabel(value: string): string {
|
||||||
|
return value.replace(/\\(["\\])/g, '$1');
|
||||||
|
}
|
||||||
|
|
||||||
function escapeHtml(value: string): string {
|
function escapeHtml(value: string): string {
|
||||||
return value
|
return value
|
||||||
.replace(/&/g, '&')
|
.replace(/&/g, '&')
|
||||||
|
|||||||
@@ -279,15 +279,16 @@ function video(turndownService: _TurndownService) {
|
|||||||
function sanitizeTabLabel(value: string): string {
|
function sanitizeTabLabel(value: string): string {
|
||||||
return value
|
return value
|
||||||
.replace(/[\r\n]+/g, ' ')
|
.replace(/[\r\n]+/g, ' ')
|
||||||
|
.replace(/\\/g, '\\\\')
|
||||||
.replace(/"/g, '\\"')
|
.replace(/"/g, '\\"')
|
||||||
.trim();
|
.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
function indentMarkdownBlock(content: string): string {
|
function indentMarkdownBlock(content: string): string {
|
||||||
if (!content) return ' ';
|
if (!content) return '\t';
|
||||||
|
|
||||||
return content
|
return content
|
||||||
.split('\n')
|
.split('\n')
|
||||||
.map((line) => (line.trim() ? ` ${line}` : ''))
|
.map((line) => (line.trim() ? `\t${line}` : ''))
|
||||||
.join('\n');
|
.join('\n');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export interface TabsOptions {
|
|||||||
view: ComponentType<ReactNodeViewProps<HTMLElement>> | null;
|
view: ComponentType<ReactNodeViewProps<HTMLElement>> | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TAB_INPUT_REGEX = /^\s*===\s*["'“”‘’]([^"'“”‘’\n]+)["'“”‘’]\s+$/;
|
const TAB_INPUT_REGEX = /^\s*===\s*["'“”‘’]((?:\\.|[^"'“”‘’\n])+?)["'“”‘’]\s+$/;
|
||||||
|
|
||||||
declare module '@tiptap/core' {
|
declare module '@tiptap/core' {
|
||||||
interface Commands<ReturnType> {
|
interface Commands<ReturnType> {
|
||||||
@@ -85,9 +85,8 @@ export const Tabs = Node.create<TabsOptions>({
|
|||||||
new InputRule({
|
new InputRule({
|
||||||
find: TAB_INPUT_REGEX,
|
find: TAB_INPUT_REGEX,
|
||||||
handler: ({ range, match }) => {
|
handler: ({ range, match }) => {
|
||||||
const label = (
|
const rawLabel = typeof match[1] === 'string' ? match[1] : 'Tab 1';
|
||||||
typeof match[1] === 'string' ? match[1] : 'Tab 1'
|
const label = rawLabel.replace(/\\(["\\])/g, '$1').trim();
|
||||||
).trim();
|
|
||||||
|
|
||||||
this.editor.commands.insertTabs(label, range);
|
this.editor.commands.insertTabs(label, range);
|
||||||
},
|
},
|
||||||
@@ -222,7 +221,10 @@ export const Tabs = Node.create<TabsOptions>({
|
|||||||
(pos: 'left' | 'right') =>
|
(pos: 'left' | 'right') =>
|
||||||
({ state, tr, dispatch }) => {
|
({ state, tr, dispatch }) => {
|
||||||
const { $from } = state.selection;
|
const { $from } = state.selection;
|
||||||
const tabs = findParentNode((node) => node.type.name === this.name, $from);
|
const tabs = findParentNode(
|
||||||
|
(node) => node.type.name === this.name,
|
||||||
|
$from,
|
||||||
|
);
|
||||||
if (!tabs || tabs.node.childCount <= 0) return false;
|
if (!tabs || tabs.node.childCount <= 0) return false;
|
||||||
|
|
||||||
const currentTabIndex = clampIndex(
|
const currentTabIndex = clampIndex(
|
||||||
@@ -265,7 +267,10 @@ export const Tabs = Node.create<TabsOptions>({
|
|||||||
(pos: 'left' | 'right') =>
|
(pos: 'left' | 'right') =>
|
||||||
({ state, tr, dispatch }) => {
|
({ state, tr, dispatch }) => {
|
||||||
const { $from } = state.selection;
|
const { $from } = state.selection;
|
||||||
const tabs = findParentNode((node) => node.type.name === this.name, $from);
|
const tabs = findParentNode(
|
||||||
|
(node) => node.type.name === this.name,
|
||||||
|
$from,
|
||||||
|
);
|
||||||
if (!tabs || tabs.node.childCount <= 1) return false;
|
if (!tabs || tabs.node.childCount <= 1) return false;
|
||||||
|
|
||||||
const currentTabIndex = clampIndex(
|
const currentTabIndex = clampIndex(
|
||||||
@@ -356,7 +361,10 @@ export const Tabs = Node.create<TabsOptions>({
|
|||||||
() =>
|
() =>
|
||||||
({ state, tr, dispatch }) => {
|
({ state, tr, dispatch }) => {
|
||||||
const { $from } = state.selection;
|
const { $from } = state.selection;
|
||||||
const tabs = findParentNode((node) => node.type.name === this.name, $from);
|
const tabs = findParentNode(
|
||||||
|
(node) => node.type.name === this.name,
|
||||||
|
$from,
|
||||||
|
);
|
||||||
if (!tabs) return false;
|
if (!tabs) return false;
|
||||||
|
|
||||||
if (tabs.node.childCount < 2) {
|
if (tabs.node.childCount < 2) {
|
||||||
@@ -398,8 +406,11 @@ export const Tabs = Node.create<TabsOptions>({
|
|||||||
() =>
|
() =>
|
||||||
({ state, tr, dispatch }) => {
|
({ state, tr, dispatch }) => {
|
||||||
const { $from } = state.selection;
|
const { $from } = state.selection;
|
||||||
const tabs = findParentNode((node) => node.type.name === this.name, $from);
|
const tabs = findParentNode(
|
||||||
if (!tabs || tabs.node.childCount < 0) return false;
|
(node) => node.type.name === this.name,
|
||||||
|
$from,
|
||||||
|
);
|
||||||
|
if (tabs?.node.childCount <= 0) return false;
|
||||||
|
|
||||||
tr.delete(tabs.pos, tabs.pos + tabs.node.nodeSize);
|
tr.delete(tabs.pos, tabs.pos + tabs.node.nodeSize);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user