mirror of https://github.com/fantasticit/think.git
refactor: lint code
This commit is contained in:
parent
76cdcff589
commit
d0165bad1e
|
@ -20,6 +20,7 @@ export const Blockquote = BuiltInBlockquote.extend({
|
||||||
addInputRules() {
|
addInputRules() {
|
||||||
const multilineInputRegex = /^\s*>>>\s$/gm;
|
const multilineInputRegex = /^\s*>>>\s$/gm;
|
||||||
return [
|
return [
|
||||||
|
// eslint-disable-next-line no-unsafe-optional-chaining
|
||||||
...this.parent?.(),
|
...this.parent?.(),
|
||||||
wrappingInputRule({
|
wrappingInputRule({
|
||||||
find: multilineInputRegex,
|
find: multilineInputRegex,
|
||||||
|
|
|
@ -101,7 +101,9 @@ const lockCollaborationUserEditingNodes = (extensionThis, users) => {
|
||||||
options.collaborationUserCursorCache.set(user.clientId, { user, cursor });
|
options.collaborationUserCursorCache.set(user.clientId, { user, cursor });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {}
|
} catch (e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -61,7 +61,7 @@ export const Paste = Extension.create({
|
||||||
|
|
||||||
if (node) {
|
if (node) {
|
||||||
const doc = safeJSONParse(node);
|
const doc = safeJSONParse(node);
|
||||||
let tr = view.state.tr;
|
const tr = view.state.tr;
|
||||||
const selection = tr.selection;
|
const selection = tr.selection;
|
||||||
view.dispatch(tr.insert(selection.from - 1, view.state.schema.nodeFromJSON(doc)).scrollIntoView());
|
view.dispatch(tr.insert(selection.from - 1, view.state.schema.nodeFromJSON(doc)).scrollIntoView());
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -182,7 +182,7 @@ const gotoSearchResult = ({ view, tr, searchResults, searchResultCurrentClass, g
|
||||||
const result = searchResults[gotoIndex];
|
const result = searchResults[gotoIndex];
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
let transaction = tr.setMeta('directDecoration', {
|
const transaction = tr.setMeta('directDecoration', {
|
||||||
fromPos: result.from,
|
fromPos: result.from,
|
||||||
toPos: result.to,
|
toPos: result.to,
|
||||||
attrs: { class: searchResultCurrentClass },
|
attrs: { class: searchResultCurrentClass },
|
||||||
|
|
|
@ -116,7 +116,7 @@ export class Renderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
renderChildren(node) {
|
renderChildren(node) {
|
||||||
let nodes = [];
|
const nodes = [];
|
||||||
|
|
||||||
node.childNodes.forEach((child) => {
|
node.childNodes.forEach((child) => {
|
||||||
const NodeClass = this.getMatchingNode(child);
|
const NodeClass = this.getMatchingNode(child);
|
||||||
|
@ -180,7 +180,7 @@ export class Renderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
getMatchingClass(node, classes) {
|
getMatchingClass(node, classes) {
|
||||||
for (let i in classes) {
|
for (const i in classes) {
|
||||||
const Class = classes[i];
|
const Class = classes[i];
|
||||||
const instance = new Class(node);
|
const instance = new Class(node);
|
||||||
if (instance.matching()) {
|
if (instance.matching()) {
|
||||||
|
|
|
@ -18,6 +18,7 @@ export * from './markdown-source-map';
|
||||||
const extractImage = (html) => {
|
const extractImage = (html) => {
|
||||||
let matches = [];
|
let matches = [];
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-useless-escape
|
||||||
while ((matches = html.match(/\<p.*?\>\<img(.|\s)*?\>\<\/p\>/g))) {
|
while ((matches = html.match(/\<p.*?\>\<img(.|\s)*?\>\<\/p\>/g))) {
|
||||||
const target = matches[0].match(/<img.*?>/)[0];
|
const target = matches[0].match(/<img.*?>/)[0];
|
||||||
html = html.replace(matches[0], target);
|
html = html.replace(matches[0], target);
|
||||||
|
|
|
@ -20,7 +20,7 @@ export const createMarkdownContainer = (types: string | Array<string>) => (md) =
|
||||||
if (tag.nesting === 1) {
|
if (tag.nesting === 1) {
|
||||||
tag.attrSet('class', type);
|
tag.attrSet('class', type);
|
||||||
|
|
||||||
var m = tag.info.trim().match(regexp);
|
const m = tag.info.trim().match(regexp);
|
||||||
if (m[1]) {
|
if (m[1]) {
|
||||||
const data = strToJSON(m[1]);
|
const data = strToJSON(m[1]);
|
||||||
jsonToDOMDataset(data).forEach(({ key, value }) => {
|
jsonToDOMDataset(data).forEach(({ key, value }) => {
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
|
/* eslint-disable */
|
||||||
// var katex = require('katex');
|
// var katex = require('katex');
|
||||||
|
|
||||||
// Test if potential opening or closing delimieter
|
// Test if potential opening or closing delimieter
|
||||||
// Assumes that there is a "$" at state.src[pos]
|
// Assumes that there is a "$" at state.src[pos]
|
||||||
function isValidDelim(state, pos) {
|
function isValidDelim(state, pos) {
|
||||||
var prevChar,
|
let prevChar,
|
||||||
nextChar,
|
nextChar,
|
||||||
max = state.posMax,
|
max = state.posMax,
|
||||||
can_open = true,
|
can_open = true,
|
||||||
|
@ -32,7 +33,7 @@ function isValidDelim(state, pos) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function math_inline(state, silent) {
|
function math_inline(state, silent) {
|
||||||
var start, match, token, res, pos, esc_count;
|
let start, match, token, res, pos, esc_count;
|
||||||
|
|
||||||
if (state.src[state.pos] !== '$') {
|
if (state.src[state.pos] !== '$') {
|
||||||
return false;
|
return false;
|
||||||
|
@ -107,7 +108,7 @@ function math_inline(state, silent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function math_block(state, start, end, silent) {
|
function math_block(state, start, end, silent) {
|
||||||
var firstLine,
|
let firstLine,
|
||||||
lastLine,
|
lastLine,
|
||||||
next,
|
next,
|
||||||
lastPos,
|
lastPos,
|
||||||
|
@ -179,7 +180,7 @@ function escapeHtml(unsafe) {
|
||||||
.replace(/'/g, ''');
|
.replace(/'/g, ''');
|
||||||
}
|
}
|
||||||
|
|
||||||
var katex = {
|
let katex = {
|
||||||
renderToString: (s, opts) => s,
|
renderToString: (s, opts) => s,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -194,7 +195,7 @@ export default function math_plugin(md, options) {
|
||||||
options.blockClass = '';
|
options.blockClass = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
var inlineRenderer = function (tokens, idx) {
|
const inlineRenderer = function (tokens, idx) {
|
||||||
return katexBlock(tokens[idx].content);
|
return katexBlock(tokens[idx].content);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -212,7 +213,7 @@ export default function math_plugin(md, options) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var blockRenderer = function (tokens, idx) {
|
const blockRenderer = function (tokens, idx) {
|
||||||
return katexBlock(tokens[idx].content) + '\n';
|
return katexBlock(tokens[idx].content) + '\n';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
// Copied from https://github.com/markdown-it/markdown-it/blob/master/lib/rules_block/table.js
|
// Copied from https://github.com/markdown-it/markdown-it/blob/master/lib/rules_block/table.js
|
||||||
|
|
||||||
function isSpace(code) {
|
function isSpace(code) {
|
||||||
|
@ -10,14 +12,14 @@ function isSpace(code) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLine(state, line) {
|
function getLine(state, line) {
|
||||||
var pos = state.bMarks[line] + state.tShift[line],
|
const pos = state.bMarks[line] + state.tShift[line],
|
||||||
max = state.eMarks[line];
|
max = state.eMarks[line];
|
||||||
|
|
||||||
return state.src.substr(pos, max - pos);
|
return state.src.substr(pos, max - pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
function escapedSplit(str) {
|
function escapedSplit(str) {
|
||||||
var result = [],
|
let result = [],
|
||||||
pos = 0,
|
pos = 0,
|
||||||
max = str.length,
|
max = str.length,
|
||||||
ch,
|
ch,
|
||||||
|
@ -53,7 +55,7 @@ function escapedSplit(str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function table(state, startLine, endLine, silent) {
|
function table(state, startLine, endLine, silent) {
|
||||||
var ch,
|
let ch,
|
||||||
lineText,
|
lineText,
|
||||||
pos,
|
pos,
|
||||||
i,
|
i,
|
||||||
|
|
|
@ -50,8 +50,8 @@ export default function markdownItTaskLists(
|
||||||
}
|
}
|
||||||
|
|
||||||
function attrSet(token, name, value) {
|
function attrSet(token, name, value) {
|
||||||
var index = token.attrIndex(name);
|
const index = token.attrIndex(name);
|
||||||
var attr = [name, value];
|
const attr = [name, value];
|
||||||
|
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
token.attrPush(attr);
|
token.attrPush(attr);
|
||||||
|
|
|
@ -130,6 +130,7 @@ const SerializerConfig = {
|
||||||
[Image.name]: renderImage,
|
[Image.name]: renderImage,
|
||||||
[Katex.name]: (state, node) => {
|
[Katex.name]: (state, node) => {
|
||||||
state.ensureNewLine();
|
state.ensureNewLine();
|
||||||
|
// eslint-disable-next-line no-useless-escape
|
||||||
state.write(`\$\$${node.attrs.text || ''}\$\$`);
|
state.write(`\$\$${node.attrs.text || ''}\$\$`);
|
||||||
state.closeBlock(node);
|
state.closeBlock(node);
|
||||||
},
|
},
|
||||||
|
|
|
@ -17,7 +17,7 @@ export const Size: React.FC<{ width: number; maxWidth?: number; height: number;
|
||||||
$form.current.validate().then((values) => {
|
$form.current.validate().then((values) => {
|
||||||
onOk(values as ISize);
|
onOk(values as ISize);
|
||||||
});
|
});
|
||||||
}, []);
|
}, [onOk]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown
|
<Dropdown
|
||||||
|
|
|
@ -17,7 +17,7 @@ export const CountdownSettingModal: React.FC<IProps> = ({ editor }) => {
|
||||||
editor.chain().focus().setCountdown({ title: values.title, date: values.date.valueOf() }).run();
|
editor.chain().focus().setCountdown({ title: values.title, date: values.date.valueOf() }).run();
|
||||||
toggleVisible(false);
|
toggleVisible(false);
|
||||||
});
|
});
|
||||||
}, []);
|
}, [editor, toggleVisible]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handler = (data) => {
|
const handler = (data) => {
|
||||||
|
@ -30,7 +30,7 @@ export const CountdownSettingModal: React.FC<IProps> = ({ editor }) => {
|
||||||
return () => {
|
return () => {
|
||||||
event.off(OPEN_COUNT_SETTING_MODAL, handler);
|
event.off(OPEN_COUNT_SETTING_MODAL, handler);
|
||||||
};
|
};
|
||||||
}, []);
|
}, [toggleVisible]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal centered title="倒计时" visible={visible} onOk={handleOk} onCancel={() => toggleVisible(false)}>
|
<Modal centered title="倒计时" visible={visible} onOk={handleOk} onCancel={() => toggleVisible(false)}>
|
||||||
|
|
|
@ -6,11 +6,14 @@ import { IconEmoji } from 'components/icons';
|
||||||
import { EmojiPicker } from 'components/emoji-picker';
|
import { EmojiPicker } from 'components/emoji-picker';
|
||||||
|
|
||||||
export const Emoji: React.FC<{ editor: Editor }> = ({ editor }) => {
|
export const Emoji: React.FC<{ editor: Editor }> = ({ editor }) => {
|
||||||
const setEmoji = useCallback((emoji) => {
|
const setEmoji = useCallback(
|
||||||
|
(emoji) => {
|
||||||
const { selection } = editor.state;
|
const { selection } = editor.state;
|
||||||
const { $anchor } = selection;
|
const { $anchor } = selection;
|
||||||
return editor.chain().insertContentAt($anchor.pos, emoji).run();
|
return editor.chain().insertContentAt($anchor.pos, emoji).run();
|
||||||
}, []);
|
},
|
||||||
|
[editor]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EmojiPicker onSelectEmoji={setEmoji}>
|
<EmojiPicker onSelectEmoji={setEmoji}>
|
||||||
|
|
|
@ -9,13 +9,16 @@ export const FontSize: React.FC<{ editor: Editor }> = ({ editor }) => {
|
||||||
const currentFontSizePx = editor.getAttributes('textStyle').fontSize || '16px';
|
const currentFontSizePx = editor.getAttributes('textStyle').fontSize || '16px';
|
||||||
const currentFontSize = +currentFontSizePx.replace('px', '');
|
const currentFontSize = +currentFontSizePx.replace('px', '');
|
||||||
|
|
||||||
const toggle = useCallback((val) => {
|
const toggle = useCallback(
|
||||||
|
(val) => {
|
||||||
editor
|
editor
|
||||||
.chain()
|
.chain()
|
||||||
.focus()
|
.focus()
|
||||||
.setFontSize(val + 'px')
|
.setFontSize(val + 'px')
|
||||||
.run();
|
.run();
|
||||||
}, []);
|
},
|
||||||
|
[editor]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Select
|
<Select
|
||||||
|
|
|
@ -14,13 +14,16 @@ const getCurrentCaretTitle = (editor) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Heading: React.FC<{ editor: Editor }> = ({ editor }) => {
|
export const Heading: React.FC<{ editor: Editor }> = ({ editor }) => {
|
||||||
const toggle = useCallback((level) => {
|
const toggle = useCallback(
|
||||||
|
(level) => {
|
||||||
if (level === 'paragraph') {
|
if (level === 'paragraph') {
|
||||||
editor.chain().focus().setParagraph().run();
|
editor.chain().focus().setParagraph().run();
|
||||||
} else {
|
} else {
|
||||||
editor.chain().focus().toggleHeading({ level }).run();
|
editor.chain().focus().toggleHeading({ level }).run();
|
||||||
}
|
}
|
||||||
}, []);
|
},
|
||||||
|
[editor]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Select
|
<Select
|
||||||
|
|
|
@ -27,7 +27,7 @@ export const IframeBubbleMenu = ({ editor }) => {
|
||||||
|
|
||||||
const handleCancel = useCallback(() => {
|
const handleCancel = useCallback(() => {
|
||||||
toggleVisible(false);
|
toggleVisible(false);
|
||||||
}, []);
|
}, [toggleVisible]);
|
||||||
|
|
||||||
const handleOk = useCallback(() => {
|
const handleOk = useCallback(() => {
|
||||||
$form.current.validate().then((values) => {
|
$form.current.validate().then((values) => {
|
||||||
|
@ -41,7 +41,7 @@ export const IframeBubbleMenu = ({ editor }) => {
|
||||||
.run();
|
.run();
|
||||||
toggleVisible(false);
|
toggleVisible(false);
|
||||||
});
|
});
|
||||||
}, []);
|
}, [editor, toggleVisible]);
|
||||||
|
|
||||||
const visitLink = useCallback(() => {
|
const visitLink = useCallback(() => {
|
||||||
window.open(url, '_blank');
|
window.open(url, '_blank');
|
||||||
|
@ -49,7 +49,7 @@ export const IframeBubbleMenu = ({ editor }) => {
|
||||||
|
|
||||||
const openEditLinkModal = useCallback(() => {
|
const openEditLinkModal = useCallback(() => {
|
||||||
toggleVisible(true);
|
toggleVisible(true);
|
||||||
}, []);
|
}, [toggleVisible]);
|
||||||
|
|
||||||
const setSize = useCallback(
|
const setSize = useCallback(
|
||||||
(size) => {
|
(size) => {
|
||||||
|
|
|
@ -154,14 +154,14 @@ export const Insert: React.FC<{ editor: Editor }> = ({ editor }) => {
|
||||||
toggleVisible(false);
|
toggleVisible(false);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
[editor, toggleVisible]
|
[editor, toggleVisible, transformToCommands, user]
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!visible) return;
|
if (!visible) return;
|
||||||
insertMenuLRUCache.syncFromStorage();
|
insertMenuLRUCache.syncFromStorage();
|
||||||
setRecentUsed(transformToCommands(insertMenuLRUCache.get() as string[]));
|
setRecentUsed(transformToCommands(insertMenuLRUCache.get() as string[]));
|
||||||
}, [visible]);
|
}, [visible, transformToCommands]);
|
||||||
|
|
||||||
if (!editor) {
|
if (!editor) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
import { useEffect, useState, useRef, useCallback } from 'react';
|
import { useEffect, useState, useRef, useCallback } from 'react';
|
||||||
import { Space, Button } from '@douyinfe/semi-ui';
|
import { Space, Button } from '@douyinfe/semi-ui';
|
||||||
import { IconExternalOpen, IconUnlink, IconEdit } from '@douyinfe/semi-icons';
|
import { IconExternalOpen, IconUnlink, IconEdit } from '@douyinfe/semi-icons';
|
||||||
|
|
|
@ -27,7 +27,7 @@ export const LinkSettingModal: React.FC<IProps> = ({ editor }) => {
|
||||||
view.dispatch(view.state.tr.scrollIntoView());
|
view.dispatch(view.state.tr.scrollIntoView());
|
||||||
toggleVisible(false);
|
toggleVisible(false);
|
||||||
});
|
});
|
||||||
}, [initialState]);
|
}, [initialState, editor, toggleVisible]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handler = (data) => {
|
const handler = (data) => {
|
||||||
|
@ -40,7 +40,7 @@ export const LinkSettingModal: React.FC<IProps> = ({ editor }) => {
|
||||||
return () => {
|
return () => {
|
||||||
event.off(OPEN_LINK_SETTING_MODAL, handler);
|
event.off(OPEN_LINK_SETTING_MODAL, handler);
|
||||||
};
|
};
|
||||||
}, [editor]);
|
}, [editor, toggleVisible]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal title="编辑链接" visible={visible} onOk={handleOk} onCancel={() => toggleVisible(false)} centered>
|
<Modal title="编辑链接" visible={visible} onOk={handleOk} onCancel={() => toggleVisible(false)} centered>
|
||||||
|
|
|
@ -15,12 +15,16 @@ export const Search: React.FC<{ editor: Editor }> = ({ editor }) => {
|
||||||
const [replaceValue, setReplaceValue] = useState('');
|
const [replaceValue, setReplaceValue] = useState('');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
editor?.commands?.setSearchTerm(searchValue);
|
if (editor && editor.commands && editor.commands.setSearchTerm) {
|
||||||
}, [searchValue]);
|
editor.commands.setSearchTerm(searchValue);
|
||||||
|
}
|
||||||
|
}, [searchValue, editor]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
editor?.commands?.setReplaceTerm(replaceValue);
|
if (editor && editor.commands && editor.commands.setReplaceTerm) {
|
||||||
}, [replaceValue]);
|
editor.commands.setReplaceTerm(replaceValue);
|
||||||
|
}
|
||||||
|
}, [replaceValue, editor]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover
|
<Popover
|
||||||
|
|
|
@ -44,7 +44,9 @@ export function copyNode(nodeOrNodeName: string | Node, editor?: Editor) {
|
||||||
toCopy.push({ text: markdown, format: 'text/markdown' });
|
toCopy.push({ text: markdown, format: 'text/markdown' });
|
||||||
const html = markdownToHTML(markdown);
|
const html = markdownToHTML(markdown);
|
||||||
toCopy.push({ text: html, format: 'text/html' });
|
toCopy.push({ text: html, format: 'text/html' });
|
||||||
} catch (e) {}
|
} catch (e) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
copy(toCopy);
|
copy(toCopy);
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ export const jsonToDOMDataset = (json: Record<string, unknown>) => {
|
||||||
* @param transformToJSON 是否要转为 JSON
|
* @param transformToJSON 是否要转为 JSON
|
||||||
*/
|
*/
|
||||||
export const getDatasetAttribute =
|
export const getDatasetAttribute =
|
||||||
(attribute: string, transformToJSON: boolean = 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));
|
const value = decodeURIComponent(element.getAttribute(dataKey));
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export function isValidURL(str) {
|
export function isValidURL(str) {
|
||||||
var pattern = new RegExp(
|
const pattern = new RegExp(
|
||||||
'^(https?:\\/\\/)?' + // protocol
|
'^(https?:\\/\\/)?' + // protocol
|
||||||
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name
|
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name
|
||||||
'((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address
|
'((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
export function uuid() {
|
export function uuid() {
|
||||||
var s = [];
|
const s = [];
|
||||||
|
|
||||||
var hexDigits = '0123456789abcdef';
|
const hexDigits = '0123456789abcdef';
|
||||||
|
|
||||||
for (var i = 0; i < 36; i++) {
|
for (let i = 0; i < 36; i++) {
|
||||||
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
|
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
s[14] = '4'; // bits 12-15 of the time_hi_and_version field to 0010
|
s[14] = '4'; // bits 12-15 of the time_hi_and_version field to 0010
|
||||||
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
|
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
|
||||||
s[8] = s[13] = s[18] = s[23] = '-';
|
s[8] = s[13] = s[18] = s[23] = '-';
|
||||||
var uuid = s.join('');
|
const uuid = s.join('');
|
||||||
return uuid;
|
return uuid;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,6 @@ export const getProvider = ({
|
||||||
docType,
|
docType,
|
||||||
},
|
},
|
||||||
maxAttempts: 5,
|
maxAttempts: 5,
|
||||||
forceSyncInterval: 100,
|
|
||||||
...events,
|
...events,
|
||||||
} as any);
|
} as any);
|
||||||
pool.set(targetId, provider);
|
pool.set(targetId, provider);
|
||||||
|
|
|
@ -40,7 +40,8 @@ export const BubbleMenu: React.FC<BubbleMenuProps> = (props) => {
|
||||||
|
|
||||||
editor.registerPlugin(plugin);
|
editor.registerPlugin(plugin);
|
||||||
return () => editor.unregisterPlugin(pluginKey);
|
return () => editor.unregisterPlugin(pluginKey);
|
||||||
}, [props.editor, element]);
|
// TODO: 检验是否应该是 props.editor
|
||||||
|
}, [props, element]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={setElement} className={props.className} style={{ visibility: 'hidden' }}>
|
<div ref={setElement} className={props.className} style={{ visibility: 'hidden' }}>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { useEffect, useRef } from 'react';
|
import { useCallback, useEffect, useRef } from 'react';
|
||||||
import cls from 'classnames';
|
import cls from 'classnames';
|
||||||
import { NodeViewWrapper } from '@tiptap/react';
|
import { NodeViewWrapper } from '@tiptap/react';
|
||||||
import { Button, Typography, Spin, Collapsible, Space } from '@douyinfe/semi-ui';
|
import { Button, Typography, Spin, Collapsible, Space } from '@douyinfe/semi-ui';
|
||||||
|
@ -20,12 +20,13 @@ export const AttachmentWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
const [loading, toggleLoading] = useToggle(false);
|
const [loading, toggleLoading] = useToggle(false);
|
||||||
const [visible, toggleVisible] = useToggle(false);
|
const [visible, toggleVisible] = useToggle(false);
|
||||||
|
|
||||||
const selectFile = () => {
|
const selectFile = useCallback(() => {
|
||||||
if (!isEditable || url) return;
|
if (!isEditable || url) return;
|
||||||
isEditable && $upload.current.click();
|
isEditable && $upload.current.click();
|
||||||
};
|
}, [isEditable, url]);
|
||||||
|
|
||||||
const handleFile = async (e) => {
|
const handleFile = useCallback(
|
||||||
|
async (e) => {
|
||||||
const file = e.target.files && e.target.files[0];
|
const file = e.target.files && e.target.files[0];
|
||||||
const fileInfo = {
|
const fileInfo = {
|
||||||
fileName: extractFilename(file.name),
|
fileName: extractFilename(file.name),
|
||||||
|
@ -42,14 +43,16 @@ export const AttachmentWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
updateAttributes({ error: '文件上传失败:' + (error && error.message) || '未知错误' });
|
updateAttributes({ error: '文件上传失败:' + (error && error.message) || '未知错误' });
|
||||||
toggleLoading(false);
|
toggleLoading(false);
|
||||||
}
|
}
|
||||||
};
|
},
|
||||||
|
[toggleLoading, updateAttributes]
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!url && !hasTrigger) {
|
if (!url && !hasTrigger) {
|
||||||
selectFile();
|
selectFile();
|
||||||
updateAttributes({ hasTrigger: true });
|
updateAttributes({ hasTrigger: true });
|
||||||
}
|
}
|
||||||
}, [url, hasTrigger]);
|
}, [url, hasTrigger, selectFile, updateAttributes]);
|
||||||
|
|
||||||
const content = (() => {
|
const content = (() => {
|
||||||
if (isEditable && !url) {
|
if (isEditable && !url) {
|
||||||
|
|
|
@ -8,9 +8,12 @@ export const CalloutWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
const { isEditable } = editor;
|
const { isEditable } = editor;
|
||||||
const { emoji, textColor, borderColor, backgroundColor } = node.attrs;
|
const { emoji, textColor, borderColor, backgroundColor } = node.attrs;
|
||||||
|
|
||||||
const onSelectEmoji = useCallback((emoji) => {
|
const onSelectEmoji = useCallback(
|
||||||
|
(emoji) => {
|
||||||
updateAttributes({ emoji });
|
updateAttributes({ emoji });
|
||||||
}, []);
|
},
|
||||||
|
[updateAttributes]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NodeViewWrapper id="js-bannber-container" className={cls(styles.wrap)}>
|
<NodeViewWrapper id="js-bannber-container" className={cls(styles.wrap)}>
|
||||||
|
|
|
@ -17,7 +17,7 @@ export const DocumentChildrenWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
const { pathname, query } = useRouter();
|
const { pathname, query } = useRouter();
|
||||||
let { wikiId, documentId } = node.attrs;
|
let { wikiId, documentId } = node.attrs;
|
||||||
if (!wikiId) {
|
if (!wikiId) {
|
||||||
query?.wikiId;
|
wikiId = query?.wikiId;
|
||||||
}
|
}
|
||||||
if (!documentId) {
|
if (!documentId) {
|
||||||
documentId = query?.documentId;
|
documentId = query?.documentId;
|
||||||
|
@ -31,7 +31,7 @@ export const DocumentChildrenWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
if (attrs.wikiId !== wikiId || attrs.documentId !== documentId) {
|
if (attrs.wikiId !== wikiId || attrs.documentId !== documentId) {
|
||||||
updateAttributes({ wikiId, documentId });
|
updateAttributes({ wikiId, documentId });
|
||||||
}
|
}
|
||||||
}, [node.attrs, wikiId, documentId]);
|
}, [node.attrs, wikiId, documentId, updateAttributes]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NodeViewWrapper
|
<NodeViewWrapper
|
||||||
|
|
|
@ -44,7 +44,7 @@ export const DocumentReferenceWrapper = ({ editor, node, updateAttributes }) =>
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
}, [wikiId, documentId]);
|
}, [wikiId, documentId, isEditable, isShare, title]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NodeViewWrapper as="div" className={cls(styles.wrap, isEditable && 'render-wrapper')}>
|
<NodeViewWrapper as="div" className={cls(styles.wrap, isEditable && 'render-wrapper')}>
|
||||||
|
|
|
@ -81,3 +81,5 @@ export const EmojiList: React.FC<IProps> = forwardRef((props, ref) => {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
EmojiList.displayName = 'EmojiList';
|
||||||
|
|
|
@ -13,9 +13,12 @@ export const IframeWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
const { url, width, height } = node.attrs;
|
const { url, width, height } = node.attrs;
|
||||||
const { width: maxWidth } = getEditorContainerDOMSize(editor);
|
const { width: maxWidth } = getEditorContainerDOMSize(editor);
|
||||||
|
|
||||||
const onResize = useCallback((size) => {
|
const onResize = useCallback(
|
||||||
|
(size) => {
|
||||||
updateAttributes({ width: size.width, height: size.height });
|
updateAttributes({ width: size.width, height: size.height });
|
||||||
}, []);
|
},
|
||||||
|
[updateAttributes]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NodeViewWrapper>
|
<NodeViewWrapper>
|
||||||
|
|
|
@ -22,16 +22,20 @@ export const ImageWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
const $upload = useRef<HTMLInputElement>();
|
const $upload = useRef<HTMLInputElement>();
|
||||||
const [loading, toggleLoading] = useToggle(false);
|
const [loading, toggleLoading] = useToggle(false);
|
||||||
|
|
||||||
const onResize = useCallback((size) => {
|
const onResize = useCallback(
|
||||||
|
(size) => {
|
||||||
updateAttributes({ height: size.height, width: size.width });
|
updateAttributes({ height: size.height, width: size.width });
|
||||||
}, []);
|
},
|
||||||
|
[updateAttributes]
|
||||||
|
);
|
||||||
|
|
||||||
const selectFile = useCallback(() => {
|
const selectFile = useCallback(() => {
|
||||||
if (!isEditable || error || src) return;
|
if (!isEditable || error || src) return;
|
||||||
isEditable && $upload.current.click();
|
isEditable && $upload.current.click();
|
||||||
}, [isEditable, error, src]);
|
}, [isEditable, error, src]);
|
||||||
|
|
||||||
const handleFile = useCallback(async (e) => {
|
const handleFile = useCallback(
|
||||||
|
async (e) => {
|
||||||
const file = e.target.files && e.target.files[0];
|
const file = e.target.files && e.target.files[0];
|
||||||
|
|
||||||
const fileInfo = {
|
const fileInfo = {
|
||||||
|
@ -52,14 +56,16 @@ export const ImageWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
updateAttributes({ error: '图片上传失败:' + (error && error.message) || '未知错误' });
|
updateAttributes({ error: '图片上传失败:' + (error && error.message) || '未知错误' });
|
||||||
toggleLoading(false);
|
toggleLoading(false);
|
||||||
}
|
}
|
||||||
}, []);
|
},
|
||||||
|
[updateAttributes, toggleLoading]
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!src && !hasTrigger) {
|
if (!src && !hasTrigger) {
|
||||||
selectFile();
|
selectFile();
|
||||||
updateAttributes({ hasTrigger: true });
|
updateAttributes({ hasTrigger: true });
|
||||||
}
|
}
|
||||||
}, [src, hasTrigger]);
|
}, [src, hasTrigger, selectFile, updateAttributes]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NodeViewWrapper as="div" style={{ textAlign, fontSize: 0, maxWidth: '100%' }}>
|
<NodeViewWrapper as="div" style={{ textAlign, fontSize: 0, maxWidth: '100%' }}>
|
||||||
|
|
|
@ -32,7 +32,7 @@ export const KatexWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
) : (
|
) : (
|
||||||
<span contentEditable={false}>点击输入公式</span>
|
<span contentEditable={false}>点击输入公式</span>
|
||||||
),
|
),
|
||||||
[text]
|
[text, formatText]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onVisibleChange = useCallback(
|
const onVisibleChange = useCallback(
|
||||||
|
@ -42,7 +42,7 @@ export const KatexWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
updateAttributes({ defaultShowPicker: false });
|
updateAttributes({ defaultShowPicker: false });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[defaultShowPicker, updateAttributes, createUser, user]
|
[defaultShowPicker, toggleVisible, updateAttributes, createUser, user]
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -50,7 +50,7 @@ export const KatexWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
toggleVisible(true);
|
toggleVisible(true);
|
||||||
setTimeout(() => ref.current?.focus(), 100);
|
setTimeout(() => ref.current?.focus(), 100);
|
||||||
}
|
}
|
||||||
}, [defaultShowPicker, createUser, user]);
|
}, [defaultShowPicker, toggleVisible, createUser, user]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NodeViewWrapper as="span" className={cls(styles.wrap, 'render-wrapper')} contentEditable={false}>
|
<NodeViewWrapper as="span" className={cls(styles.wrap, 'render-wrapper')} contentEditable={false}>
|
||||||
|
|
|
@ -81,3 +81,5 @@ export const MentionList: React.FC<IProps> = forwardRef((props, ref) => {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
MentionList.displayName = 'MentionList';
|
||||||
|
|
|
@ -87,3 +87,5 @@ export const MenuList: React.FC<IProps> = forwardRef((props, ref) => {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
MenuList.displayName = 'MenuList';
|
||||||
|
|
|
@ -47,7 +47,7 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
style={{ ...INHERIT_SIZE_STYLE, overflow: 'hidden' }}
|
style={{ ...INHERIT_SIZE_STYLE, overflow: 'hidden' }}
|
||||||
></div>
|
></div>
|
||||||
);
|
);
|
||||||
}, [loading, error, width, height]);
|
}, [loading, error]);
|
||||||
|
|
||||||
const onResize = useCallback(
|
const onResize = useCallback(
|
||||||
(size) => {
|
(size) => {
|
||||||
|
@ -69,11 +69,12 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
setError(e);
|
setError(e);
|
||||||
});
|
});
|
||||||
}, []);
|
}, [toggleLoading]);
|
||||||
|
|
||||||
// 初始化渲染
|
// 初始化渲染
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (loading || !$container.current) return;
|
const container = $container.current;
|
||||||
|
if (loading || !container) return;
|
||||||
|
|
||||||
const onChange = () => {
|
const onChange = () => {
|
||||||
updateAttributes({ data: mind.getAllData() });
|
updateAttributes({ data: mind.getAllData() });
|
||||||
|
@ -89,8 +90,8 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
isEnter = false;
|
isEnter = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
$container.current.addEventListener('onmouseenter', onMouseEnter);
|
container.addEventListener('onmouseenter', onMouseEnter);
|
||||||
$container.current.addEventListener('onMouseLeave', onMouseLeave);
|
container.addEventListener('onMouseLeave', onMouseLeave);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mind = new window.MindElixir({
|
mind = new window.MindElixir({
|
||||||
|
@ -115,16 +116,18 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if ($container.current) {
|
if (container) {
|
||||||
$container.current.removeEventListener('onmouseenter', onMouseEnter);
|
container.removeEventListener('onmouseenter', onMouseEnter);
|
||||||
$container.current.removeEventListener('onMouseLeave', onMouseLeave);
|
container.removeEventListener('onMouseLeave', onMouseLeave);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mind) {
|
if (mind) {
|
||||||
mind.destroy();
|
mind.destroy();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, [loading, editor, updateAttributes]);
|
// data 的更新交给下方 effect
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [loading, editor, updateAttributes, toggleLoading]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const mind = $mind.current;
|
const mind = $mind.current;
|
||||||
|
|
|
@ -14,8 +14,8 @@ import { SIDE, GAP, TURNPOINT_R, PRIMARY_NODE_HORIZONTAL_GAP, PRIMARY_NODE_VERTI
|
||||||
* @param {object} primaryNode process the specific primary node only
|
* @param {object} primaryNode process the specific primary node only
|
||||||
*/
|
*/
|
||||||
export default function linkDiv(primaryNode) {
|
export default function linkDiv(primaryNode) {
|
||||||
var primaryNodeHorizontalGap = this.primaryNodeHorizontalGap || PRIMARY_NODE_HORIZONTAL_GAP;
|
const primaryNodeHorizontalGap = this.primaryNodeHorizontalGap || PRIMARY_NODE_HORIZONTAL_GAP;
|
||||||
var primaryNodeVerticalGap = this.primaryNodeVerticalGap || PRIMARY_NODE_VERTICAL_GAP;
|
const primaryNodeVerticalGap = this.primaryNodeVerticalGap || PRIMARY_NODE_VERTICAL_GAP;
|
||||||
console.time('linkDiv');
|
console.time('linkDiv');
|
||||||
const root = this.root;
|
const root = this.root;
|
||||||
root.style.cssText = `top:${10000 - root.offsetHeight / 2}px;left:${10000 - root.offsetWidth / 2}px;`;
|
root.style.cssText = `top:${10000 - root.offsetHeight / 2}px;left:${10000 - root.offsetWidth / 2}px;`;
|
||||||
|
|
|
@ -86,6 +86,7 @@ const Toolbar = ({ mind, toggleBold, setFontColor, setBackgroundColor, setLink }
|
||||||
return () => {
|
return () => {
|
||||||
mind.bus.removeListener('selectNode', listener);
|
mind.bus.removeListener('selectNode', listener);
|
||||||
};
|
};
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -137,6 +137,7 @@ export function createInputDiv(tpc: Topic) {
|
||||||
div.addEventListener('blur', () => {
|
div.addEventListener('blur', () => {
|
||||||
if (!div) return; // 防止重复blur
|
if (!div) return; // 防止重复blur
|
||||||
const node = tpc.nodeObj;
|
const node = tpc.nodeObj;
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
const topic = div.textContent!.trim();
|
const topic = div.textContent!.trim();
|
||||||
if (topic === '') node.topic = origin;
|
if (topic === '') node.topic = origin;
|
||||||
else node.topic = topic;
|
else node.topic = topic;
|
||||||
|
|
|
@ -51,11 +51,12 @@ export function refreshIds(data: NodeObj) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const throttle = (fn: (any) => void, wait: number) => {
|
export const throttle = (fn: (any) => void, wait: number) => {
|
||||||
var pre = Date.now();
|
let pre = Date.now();
|
||||||
return function () {
|
return function () {
|
||||||
var context = this;
|
const context = this;
|
||||||
var args = arguments;
|
// eslint-disable-next-line prefer-rest-params
|
||||||
var now = Date.now();
|
const args = arguments;
|
||||||
|
const now = Date.now();
|
||||||
if (now - pre >= wait) {
|
if (now - pre >= wait) {
|
||||||
fn.apply(context, args);
|
fn.apply(context, args);
|
||||||
pre = Date.now();
|
pre = Date.now();
|
||||||
|
@ -78,7 +79,7 @@ export function getArrowPoints(p3x: number, p3y: number, p4x: number, p4y: numbe
|
||||||
}
|
}
|
||||||
const arrowLength = 20;
|
const arrowLength = 20;
|
||||||
const arrowAngle = 30;
|
const arrowAngle = 30;
|
||||||
var a1 = angle + arrowAngle;
|
const a1 = angle + arrowAngle;
|
||||||
const a2 = angle - arrowAngle;
|
const a2 = angle - arrowAngle;
|
||||||
return {
|
return {
|
||||||
x1: p4x + Math.cos((Math.PI * a1) / 180) * arrowLength,
|
x1: p4x + Math.cos((Math.PI * a1) / 180) * arrowLength,
|
||||||
|
|
|
@ -11,19 +11,19 @@ Bus.prototype = {
|
||||||
},
|
},
|
||||||
fire: function (type, ...payload) {
|
fire: function (type, ...payload) {
|
||||||
if (this.handlers[type] instanceof Array) {
|
if (this.handlers[type] instanceof Array) {
|
||||||
var handlers = this.handlers[type];
|
const handlers = this.handlers[type];
|
||||||
for (var i = 0; i < handlers.length; i++) {
|
for (let i = 0; i < handlers.length; i++) {
|
||||||
handlers[i](...payload);
|
handlers[i](...payload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
removeListener: function (type, handler) {
|
removeListener: function (type, handler) {
|
||||||
if (!this.handlers[type]) return;
|
if (!this.handlers[type]) return;
|
||||||
var handlers = this.handlers[type];
|
const handlers = this.handlers[type];
|
||||||
if (!handler) {
|
if (!handler) {
|
||||||
handlers.length = 0;
|
handlers.length = 0;
|
||||||
} else if (handlers.length) {
|
} else if (handlers.length) {
|
||||||
for (var i = 0; i < handlers.length; i++) {
|
for (let i = 0; i < handlers.length; i++) {
|
||||||
if (handlers[i] === handler) {
|
if (handlers[i] === handler) {
|
||||||
this.handlers[type].splice(i, 1);
|
this.handlers[type].splice(i, 1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@ export const StatusWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
updateAttributes({ defaultShowPicker: false });
|
updateAttributes({ defaultShowPicker: false });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[defaultShowPicker, updateAttributes, createUser, user]
|
[defaultShowPicker, toggleVisible, updateAttributes, createUser, user]
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -80,7 +80,7 @@ export const StatusWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
toggleVisible(true);
|
toggleVisible(true);
|
||||||
setTimeout(() => ref.current?.focus(), 100);
|
setTimeout(() => ref.current?.focus(), 100);
|
||||||
}
|
}
|
||||||
}, [defaultShowPicker, createUser, user]);
|
}, [defaultShowPicker, toggleVisible, createUser, user]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
|
|
Loading…
Reference in New Issue