mirror of https://github.com/fantasticit/think.git
close #107
parent
b068b4ef06
commit
27d4261c1d
|
@ -43,15 +43,11 @@ export const Callout = Node.create({
|
||||||
},
|
},
|
||||||
|
|
||||||
parseHTML() {
|
parseHTML() {
|
||||||
return [
|
return [{ tag: 'div[class=callout]' }];
|
||||||
{
|
|
||||||
tag: 'div',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
},
|
||||||
|
|
||||||
renderHTML({ HTMLAttributes }) {
|
renderHTML({ HTMLAttributes }) {
|
||||||
return ['div', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)];
|
return ['div', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0];
|
||||||
},
|
},
|
||||||
|
|
||||||
addCommands() {
|
addCommands() {
|
||||||
|
|
|
@ -63,41 +63,41 @@ export const Clipboard = Extension.create<IClipboardOptions>({
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
clipboardTextSerializer: (slice) => {
|
// clipboardTextSerializer: (slice) => {
|
||||||
const json = slice.content.toJSON();
|
// const json = slice.content.toJSON();
|
||||||
const isSelectAll = slice.openStart === slice.openEnd && slice.openEnd === 0;
|
// const isSelectAll = slice.openStart === slice.openEnd && slice.openEnd === 0;
|
||||||
|
|
||||||
if (Array.isArray(json) && !isSelectAll) {
|
// if (Array.isArray(json) && !isSelectAll) {
|
||||||
const type = json[0].type;
|
// const type = json[0].type;
|
||||||
|
|
||||||
// 列表项返回文字内容
|
// // 列表项返回文字内容
|
||||||
if (['bulletList', 'orderedList', 'taskList'].includes(type)) {
|
// if (['bulletList', 'orderedList', 'taskList'].includes(type)) {
|
||||||
return slice.content.textBetween(0, slice.content.size, '\n\n');
|
// return slice.content.textBetween(0, slice.content.size, '\n\n');
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (typeof json === 'object' || isSelectAll) {
|
// if (typeof json === 'object' || isSelectAll) {
|
||||||
return extensionThis.options.prosemirrorToMarkdown({
|
// return extensionThis.options.prosemirrorToMarkdown({
|
||||||
content: slice.content,
|
// content: slice.content,
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
const isText = isPureText(json) && !isSelectAll;
|
// const isText = isPureText(json) && !isSelectAll;
|
||||||
|
|
||||||
if (isText) {
|
// if (isText) {
|
||||||
return slice.content.textBetween(0, slice.content.size, '\n\n');
|
// return slice.content.textBetween(0, slice.content.size, '\n\n');
|
||||||
}
|
// }
|
||||||
const doc = slice.content;
|
// const doc = slice.content;
|
||||||
|
|
||||||
if (!doc) {
|
// if (!doc) {
|
||||||
return '';
|
// return '';
|
||||||
}
|
// }
|
||||||
|
|
||||||
const content = extensionThis.options.prosemirrorToMarkdown({
|
// const content = extensionThis.options.prosemirrorToMarkdown({
|
||||||
content: doc,
|
// content: doc,
|
||||||
});
|
// });
|
||||||
return content;
|
// return content;
|
||||||
},
|
// },
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|
|
@ -43,7 +43,7 @@ export const Countdown = Node.create({
|
||||||
parseHTML() {
|
parseHTML() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
tag: 'div',
|
tag: 'div[class=countdown]',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
|
|
|
@ -60,7 +60,7 @@ export const Flow = Node.create({
|
||||||
parseHTML() {
|
parseHTML() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
tag: 'div',
|
tag: 'div[class=flow]',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { IUser } from '@think/domains';
|
||||||
import { mergeAttributes, Node, nodeInputRule } from '@tiptap/core';
|
import { mergeAttributes, Node, nodeInputRule } from '@tiptap/core';
|
||||||
import { ReactNodeViewRenderer } from '@tiptap/react';
|
import { ReactNodeViewRenderer } from '@tiptap/react';
|
||||||
import { KatexWrapper } from 'tiptap/core/wrappers/katex';
|
import { KatexWrapper } from 'tiptap/core/wrappers/katex';
|
||||||
|
import { getDatasetAttribute } from 'tiptap/prose-utils';
|
||||||
|
|
||||||
export type IKatexAttrs = {
|
export type IKatexAttrs = {
|
||||||
text?: string;
|
text?: string;
|
||||||
|
@ -35,9 +36,7 @@ export const Katex = Node.create({
|
||||||
return {
|
return {
|
||||||
text: {
|
text: {
|
||||||
default: '',
|
default: '',
|
||||||
parseHTML: (element) => {
|
parseHTML: getDatasetAttribute('text'),
|
||||||
return element.getAttribute('data-text');
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
defaultShowPicker: {
|
defaultShowPicker: {
|
||||||
default: false,
|
default: false,
|
||||||
|
|
|
@ -71,7 +71,7 @@ export const Mind = Node.create({
|
||||||
parseHTML() {
|
parseHTML() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
tag: 'div',
|
tag: 'div[class=mind]',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
|
|
|
@ -144,6 +144,13 @@ export const Paste = Extension.create<IPasteOptions>({
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the HTML on the clipboard is from Prosemirror then the best
|
||||||
|
// compatability is to just use the HTML parser, regardless of
|
||||||
|
// whether it "looks" like Markdown, see: outline/outline#2416
|
||||||
|
if (html?.includes('data-pm-slice')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// 处理 markdown
|
// 处理 markdown
|
||||||
if (markdownText || isMarkdown(text) || html.length === 0 || pasteCodeLanguage === 'markdown') {
|
if (markdownText || isMarkdown(text) || html.length === 0 || pasteCodeLanguage === 'markdown') {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
|
@ -68,7 +68,7 @@ export const TitleWrapper = ({ editor, node }) => {
|
||||||
<NodeViewWrapper className={cls(styles.wrap, 'title')}>
|
<NodeViewWrapper className={cls(styles.wrap, 'title')}>
|
||||||
{cover ? (
|
{cover ? (
|
||||||
<div className={styles.coverWrap} contentEditable={false}>
|
<div className={styles.coverWrap} contentEditable={false}>
|
||||||
<LazyLoadImage src={cover} alt="cover" />
|
<LazyLoadImage src={cover} alt="请选择或移除封面" />
|
||||||
{isEditable ? (
|
{isEditable ? (
|
||||||
<div className={styles.toolbar}>
|
<div className={styles.toolbar}>
|
||||||
<ImageUploader images={images} selectImage={setCover}>
|
<ImageUploader images={images} selectImage={setCover}>
|
||||||
|
|
|
@ -50,7 +50,29 @@ export const getDatasetAttribute =
|
||||||
(attribute: string, transformToJSON = false) =>
|
(attribute: string, transformToJSON = false) =>
|
||||||
(element: HTMLElement) => {
|
(element: HTMLElement) => {
|
||||||
const dataKey = attribute.startsWith('data-') ? attribute : `data-${attribute}`;
|
const dataKey = attribute.startsWith('data-') ? attribute : `data-${attribute}`;
|
||||||
const value = decodeURIComponent(element.getAttribute(dataKey));
|
let value = decodeURIComponent(element.getAttribute(dataKey));
|
||||||
|
|
||||||
|
if (value == null || (typeof value === 'string' && value === 'null')) {
|
||||||
|
try {
|
||||||
|
const html = element.outerHTML;
|
||||||
|
// eslint-disable-next-line no-useless-escape
|
||||||
|
const texts = html.match(/(.|\s)+?\="(.|\s)+?"/gi);
|
||||||
|
if (texts && texts.length) {
|
||||||
|
const params = texts
|
||||||
|
.map((str) => str.trim())
|
||||||
|
.reduce((accu, item) => {
|
||||||
|
const i = item.indexOf('=');
|
||||||
|
const arr = [item.slice(0, i), item.slice(i + 1).slice(1, -1)];
|
||||||
|
accu[arr[0]] = arr[1];
|
||||||
|
return accu;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
value = (params[attribute.toLowerCase()] || '').replaceAll('"', '"');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('解析 element 失败!', e.message, element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (transformToJSON) {
|
if (transformToJSON) {
|
||||||
try {
|
try {
|
||||||
|
|
Loading…
Reference in New Issue