mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-25 02:13:00 +08:00
Compare commits
2 Commits
v0.26.3-be
...
fix/checkb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9bee2cb0fa | ||
|
|
1addd17d64 |
@@ -30,7 +30,10 @@ export const tableBlockHtmlAdapterMatcher: BlockHtmlAdapterMatcher = {
|
|||||||
}
|
}
|
||||||
const { walkerContext } = context;
|
const { walkerContext } = context;
|
||||||
if (o.node.tagName === 'table') {
|
if (o.node.tagName === 'table') {
|
||||||
const tableProps = parseTableFromHtml(o.node);
|
const astToDelta = context.deltaConverter.astToDelta.bind(
|
||||||
|
context.deltaConverter
|
||||||
|
);
|
||||||
|
const tableProps = parseTableFromHtml(o.node, astToDelta);
|
||||||
walkerContext.openNode(
|
walkerContext.openNode(
|
||||||
{
|
{
|
||||||
type: 'block',
|
type: 'block',
|
||||||
|
|||||||
@@ -25,12 +25,15 @@ export const tableBlockMarkdownAdapterMatcher: BlockMarkdownAdapterMatcher = {
|
|||||||
enter: (o, context) => {
|
enter: (o, context) => {
|
||||||
const { walkerContext } = context;
|
const { walkerContext } = context;
|
||||||
if (o.node.type === 'table') {
|
if (o.node.type === 'table') {
|
||||||
|
const astToDelta = context.deltaConverter.astToDelta.bind(
|
||||||
|
context.deltaConverter
|
||||||
|
);
|
||||||
walkerContext.openNode(
|
walkerContext.openNode(
|
||||||
{
|
{
|
||||||
type: 'block',
|
type: 'block',
|
||||||
id: nanoid(),
|
id: nanoid(),
|
||||||
flavour: TableModelFlavour,
|
flavour: TableModelFlavour,
|
||||||
props: parseTableFromMarkdown(o.node),
|
props: parseTableFromMarkdown(o.node, astToDelta),
|
||||||
children: [],
|
children: [],
|
||||||
},
|
},
|
||||||
'children'
|
'children'
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
BlockPlainTextAdapterExtension,
|
BlockPlainTextAdapterExtension,
|
||||||
type BlockPlainTextAdapterMatcher,
|
type BlockPlainTextAdapterMatcher,
|
||||||
} from '@blocksuite/affine-shared/adapters';
|
} from '@blocksuite/affine-shared/adapters';
|
||||||
|
import type { DeltaInsert } from '@blocksuite/inline';
|
||||||
import { nanoid } from '@blocksuite/store';
|
import { nanoid } from '@blocksuite/store';
|
||||||
|
|
||||||
import { createTableProps, formatTable, processTable } from './utils.js';
|
import { createTableProps, formatTable, processTable } from './utils.js';
|
||||||
@@ -21,10 +22,14 @@ export const tableBlockPlainTextAdapterMatcher: BlockPlainTextAdapterMatcher = {
|
|||||||
const text = o.node.content;
|
const text = o.node.content;
|
||||||
const rowTexts = text.split('\n');
|
const rowTexts = text.split('\n');
|
||||||
if (rowTexts.length <= 1) return;
|
if (rowTexts.length <= 1) return;
|
||||||
const rowTextLists: string[][] = [];
|
const rowTextLists: DeltaInsert[][][] = [];
|
||||||
let columnCount: number | null = null;
|
let columnCount: number | null = null;
|
||||||
for (const row of rowTexts) {
|
for (const row of rowTexts) {
|
||||||
const cells = row.split('\t');
|
const cells = row.split('\t').map<DeltaInsert[]>(text => [
|
||||||
|
{
|
||||||
|
insert: text,
|
||||||
|
},
|
||||||
|
]);
|
||||||
if (cells.length <= 1) return;
|
if (cells.length <= 1) return;
|
||||||
if (columnCount == null) {
|
if (columnCount == null) {
|
||||||
columnCount = cells.length;
|
columnCount = cells.length;
|
||||||
|
|||||||
@@ -5,14 +5,23 @@ import type {
|
|||||||
TableRow,
|
TableRow,
|
||||||
} from '@blocksuite/affine-model';
|
} from '@blocksuite/affine-model';
|
||||||
import {
|
import {
|
||||||
AdapterTextUtils,
|
type HtmlAST,
|
||||||
HastUtils,
|
type MarkdownAST,
|
||||||
} from '@blocksuite/affine-shared/adapters';
|
} from '@blocksuite/affine-shared/adapters';
|
||||||
|
import { HastUtils } from '@blocksuite/affine-shared/adapters';
|
||||||
import { generateFractionalIndexingKeyBetween } from '@blocksuite/affine-shared/utils';
|
import { generateFractionalIndexingKeyBetween } from '@blocksuite/affine-shared/utils';
|
||||||
import type { DeltaInsert } from '@blocksuite/inline';
|
import type { DeltaInsert } from '@blocksuite/inline';
|
||||||
import { nanoid } from '@blocksuite/store';
|
import { nanoid } from '@blocksuite/store';
|
||||||
import type { Element, ElementContent } from 'hast';
|
import type { Element } from 'hast';
|
||||||
import type { PhrasingContent, Table as MarkdownTable, TableCell } from 'mdast';
|
import type { Table as MarkdownTable } from 'mdast';
|
||||||
|
|
||||||
|
type RichTextType = DeltaInsert[];
|
||||||
|
const createRichText = (text: RichTextType) => {
|
||||||
|
return {
|
||||||
|
'$blocksuite:internal:text$': true,
|
||||||
|
delta: text,
|
||||||
|
};
|
||||||
|
};
|
||||||
function calculateColumnWidths(rows: string[][]): number[] {
|
function calculateColumnWidths(rows: string[][]): number[] {
|
||||||
return (
|
return (
|
||||||
rows[0]?.map((_, colIndex) =>
|
rows[0]?.map((_, colIndex) =>
|
||||||
@@ -92,15 +101,6 @@ export const processTable = (
|
|||||||
});
|
});
|
||||||
return table;
|
return table;
|
||||||
};
|
};
|
||||||
const getTextFromElement = (element: ElementContent): string => {
|
|
||||||
if (element.type === 'text') {
|
|
||||||
return element.value.trim();
|
|
||||||
}
|
|
||||||
if (element.type === 'element') {
|
|
||||||
return element.children.map(child => getTextFromElement(child)).join('');
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
};
|
|
||||||
|
|
||||||
const getAllTag = (node: Element | undefined, tagName: string): Element[] => {
|
const getAllTag = (node: Element | undefined, tagName: string): Element[] => {
|
||||||
if (!node) {
|
if (!node) {
|
||||||
@@ -120,7 +120,7 @@ const getAllTag = (node: Element | undefined, tagName: string): Element[] => {
|
|||||||
return [];
|
return [];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createTableProps = (rowTextLists: string[][]) => {
|
export const createTableProps = (deltasLists: RichTextType[][]) => {
|
||||||
const createIdAndOrder = (count: number) => {
|
const createIdAndOrder = (count: number) => {
|
||||||
const result: { id: string; order: string }[] = Array.from({
|
const result: { id: string; order: string }[] = Array.from({
|
||||||
length: count,
|
length: count,
|
||||||
@@ -135,8 +135,8 @@ export const createTableProps = (rowTextLists: string[][]) => {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
const columnCount = Math.max(...rowTextLists.map(row => row.length));
|
const columnCount = Math.max(...deltasLists.map(row => row.length));
|
||||||
const rowCount = rowTextLists.length;
|
const rowCount = deltasLists.length;
|
||||||
|
|
||||||
const columns: TableColumn[] = createIdAndOrder(columnCount).map(v => ({
|
const columns: TableColumn[] = createIdAndOrder(columnCount).map(v => ({
|
||||||
columnId: v.id,
|
columnId: v.id,
|
||||||
@@ -156,9 +156,9 @@ export const createTableProps = (rowTextLists: string[][]) => {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const cellId = `${row.rowId}:${column.columnId}`;
|
const cellId = `${row.rowId}:${column.columnId}`;
|
||||||
const text = rowTextLists[i]?.[j];
|
const text = deltasLists[i]?.[j];
|
||||||
cells[cellId] = {
|
cells[cellId] = {
|
||||||
text: AdapterTextUtils.createText(text ?? ''),
|
text: createRichText(text ?? []),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -172,7 +172,8 @@ export const createTableProps = (rowTextLists: string[][]) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const parseTableFromHtml = (
|
export const parseTableFromHtml = (
|
||||||
element: Element
|
element: Element,
|
||||||
|
astToDelta: (ast: HtmlAST) => RichTextType
|
||||||
): TableBlockPropsSerialized => {
|
): TableBlockPropsSerialized => {
|
||||||
const headerRows = getAllTag(element, 'thead').flatMap(node =>
|
const headerRows = getAllTag(element, 'thead').flatMap(node =>
|
||||||
getAllTag(node, 'tr').map(tr => getAllTag(tr, 'th'))
|
getAllTag(node, 'tr').map(tr => getAllTag(tr, 'th'))
|
||||||
@@ -184,33 +185,26 @@ export const parseTableFromHtml = (
|
|||||||
getAllTag(node, 'tr').map(tr => getAllTag(tr, 'td'))
|
getAllTag(node, 'tr').map(tr => getAllTag(tr, 'td'))
|
||||||
);
|
);
|
||||||
const allRows = [...headerRows, ...bodyRows, ...footerRows];
|
const allRows = [...headerRows, ...bodyRows, ...footerRows];
|
||||||
const rowTextLists: string[][] = [];
|
const rowTextLists: RichTextType[][] = [];
|
||||||
allRows.forEach(cells => {
|
allRows.forEach(cells => {
|
||||||
const row: string[] = [];
|
const row: RichTextType[] = [];
|
||||||
cells.forEach(cell => {
|
cells.forEach(cell => {
|
||||||
row.push(getTextFromElement(cell));
|
row.push(astToDelta(cell));
|
||||||
});
|
});
|
||||||
rowTextLists.push(row);
|
rowTextLists.push(row);
|
||||||
});
|
});
|
||||||
return createTableProps(rowTextLists);
|
return createTableProps(rowTextLists);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getTextFromTableCell = (node: TableCell) => {
|
export const parseTableFromMarkdown = (
|
||||||
const getTextFromPhrasingContent = (node: PhrasingContent) => {
|
node: MarkdownTable,
|
||||||
if (node.type === 'text') {
|
astToDelta: (ast: MarkdownAST) => RichTextType
|
||||||
return node.value;
|
) => {
|
||||||
}
|
const rowTextLists: RichTextType[][] = [];
|
||||||
return '';
|
|
||||||
};
|
|
||||||
return node.children.map(child => getTextFromPhrasingContent(child)).join('');
|
|
||||||
};
|
|
||||||
|
|
||||||
export const parseTableFromMarkdown = (node: MarkdownTable) => {
|
|
||||||
const rowTextLists: string[][] = [];
|
|
||||||
node.children.forEach(row => {
|
node.children.forEach(row => {
|
||||||
const rowText: string[] = [];
|
const rowText: RichTextType[] = [];
|
||||||
row.children.forEach(cell => {
|
row.children.forEach(cell => {
|
||||||
rowText.push(getTextFromTableCell(cell));
|
rowText.push(astToDelta(cell));
|
||||||
});
|
});
|
||||||
rowTextLists.push(rowText);
|
rowTextLists.push(rowText);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,17 +3,30 @@ import { propertyType } from '../../core/property/property-config.js';
|
|||||||
|
|
||||||
export const checkboxPropertyType = propertyType('checkbox');
|
export const checkboxPropertyType = propertyType('checkbox');
|
||||||
|
|
||||||
|
const FALSE_VALUES = new Set([
|
||||||
|
'false',
|
||||||
|
'no',
|
||||||
|
'0',
|
||||||
|
'',
|
||||||
|
'undefined',
|
||||||
|
'null',
|
||||||
|
'否',
|
||||||
|
'不',
|
||||||
|
'错',
|
||||||
|
'错误',
|
||||||
|
'取消',
|
||||||
|
'关闭',
|
||||||
|
]);
|
||||||
|
|
||||||
export const checkboxPropertyModelConfig =
|
export const checkboxPropertyModelConfig =
|
||||||
checkboxPropertyType.modelConfig<boolean>({
|
checkboxPropertyType.modelConfig<boolean>({
|
||||||
name: 'Checkbox',
|
name: 'Checkbox',
|
||||||
type: () => t.boolean.instance(),
|
type: () => t.boolean.instance(),
|
||||||
defaultData: () => ({}),
|
defaultData: () => ({}),
|
||||||
cellToString: ({ value }) => (value ? 'True' : 'False'),
|
cellToString: ({ value }) => (value ? 'True' : 'False'),
|
||||||
cellFromString: ({ value }) => {
|
cellFromString: ({ value }) => ({
|
||||||
return {
|
value: !FALSE_VALUES.has((value?.trim() ?? '').toLowerCase()),
|
||||||
value: value !== 'False',
|
}),
|
||||||
};
|
|
||||||
},
|
|
||||||
cellToJson: ({ value }) => value ?? null,
|
cellToJson: ({ value }) => value ?? null,
|
||||||
cellFromJson: ({ value }) =>
|
cellFromJson: ({ value }) =>
|
||||||
typeof value !== 'boolean' ? undefined : value,
|
typeof value !== 'boolean' ? undefined : value,
|
||||||
|
|||||||
Reference in New Issue
Block a user