mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-08-14 21:00:37 +03:00
Replace RS editor and fix colors in dark mode
This commit is contained in:
parent
83e08ca7fc
commit
2bab898032
|
@ -15,21 +15,21 @@ createTheme('customDark', {
|
||||||
disabled: 'rgba(228, 228, 231, 0.54)'
|
disabled: 'rgba(228, 228, 231, 0.54)'
|
||||||
},
|
},
|
||||||
background: {
|
background: {
|
||||||
default: '#002b36'
|
default: '#002129'
|
||||||
},
|
},
|
||||||
context: {
|
context: {
|
||||||
background: '#3e014d',
|
background: '#3e014d',
|
||||||
text: 'rgba(228, 228, 231, 0.87)'
|
text: 'rgba(228, 228, 231, 0.87)'
|
||||||
},
|
},
|
||||||
highlightOnHover: {
|
highlightOnHover: {
|
||||||
default: '#3e014d',
|
default: '#2d0138',
|
||||||
text: 'rgba(228, 228, 231, 1)'
|
text: 'rgba(228, 228, 231, 1)'
|
||||||
},
|
},
|
||||||
divider: {
|
divider: {
|
||||||
default: '#6b6b6b'
|
default: '#6b6b6b'
|
||||||
},
|
},
|
||||||
striped: {
|
striped: {
|
||||||
default: '#004859',
|
default: '#003845',
|
||||||
text: 'rgba(228, 228, 231, 1)'
|
text: 'rgba(228, 228, 231, 1)'
|
||||||
},
|
},
|
||||||
selected: {
|
selected: {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
.rdt_TableCell{
|
.rdt_TableCell{
|
||||||
font-size: 14px;
|
font-size: 0.875rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-color-scheme="dark"] {
|
[data-color-scheme="dark"] {
|
||||||
|
@ -59,7 +59,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.clr-input {
|
.clr-input {
|
||||||
@apply dark:bg-black bg-white disabled:bg-[#f0f2f7] dark:disabled:bg-gray-700
|
@apply dark:bg-[#070b12] bg-white disabled:bg-[#f0f2f7] dark:disabled:bg-gray-700
|
||||||
}
|
}
|
||||||
|
|
||||||
.clr-footer {
|
.clr-footer {
|
||||||
|
|
|
@ -171,8 +171,8 @@ function EditorConstituenta({ activeID, onShowAST, onCreateCst, onOpenEdit, onDe
|
||||||
<p>- столбец "Описание" содержит один из непустых текстовых атрибутов</p>
|
<p>- столбец "Описание" содержит один из непустых текстовых атрибутов</p>
|
||||||
<Divider margins='mt-2' />
|
<Divider margins='mt-2' />
|
||||||
<h1>Статусы</h1>
|
<h1>Статусы</h1>
|
||||||
{ [... mapStatusInfo.values()].map(info => {
|
{ [... mapStatusInfo.values()].map((info, index) => {
|
||||||
return (<p className='py-1'>
|
return (<p className='py-1' key={`status-info-${index}`}>
|
||||||
<span className={`inline-block font-semibold min-w-[4rem] text-center border ${info.color}`}>
|
<span className={`inline-block font-semibold min-w-[4rem] text-center border ${info.color}`}>
|
||||||
{info.text}
|
{info.text}
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -4,7 +4,6 @@ import { useCallback, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
||||||
import Button from '../../components/Common/Button';
|
import Button from '../../components/Common/Button';
|
||||||
import Label from '../../components/Common/Label';
|
import Label from '../../components/Common/Label';
|
||||||
import { Loader } from '../../components/Common/Loader';
|
import { Loader } from '../../components/Common/Loader';
|
||||||
import { useAuth } from '../../context/AuthContext';
|
|
||||||
import { useRSForm } from '../../context/RSFormContext';
|
import { useRSForm } from '../../context/RSFormContext';
|
||||||
import useCheckExpression from '../../hooks/useCheckExpression';
|
import useCheckExpression from '../../hooks/useCheckExpression';
|
||||||
import { TokenID } from '../../utils/enums';
|
import { TokenID } from '../../utils/enums';
|
||||||
|
@ -33,15 +32,13 @@ interface EditorRSExpressionProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
function EditorRSExpression({
|
function EditorRSExpression({
|
||||||
id, activeCst, label, disabled, isActive, placeholder, value, setValue, onShowAST,
|
id, activeCst, label, disabled, isActive, placeholder, value, onShowAST,
|
||||||
toggleEditMode, setTypification, onChange
|
toggleEditMode, setTypification, onChange
|
||||||
}: EditorRSExpressionProps) {
|
}: EditorRSExpressionProps) {
|
||||||
const { user } = useAuth();
|
|
||||||
const { schema } = useRSForm();
|
const { schema } = useRSForm();
|
||||||
|
|
||||||
const [isModified, setIsModified] = useState(false);
|
const [isModified, setIsModified] = useState(false);
|
||||||
const { parseData, checkExpression, resetParse, loading } = useCheckExpression({ schema });
|
const { parseData, checkExpression, resetParse, loading } = useCheckExpression({ schema });
|
||||||
const expressionCtrl = useRef<HTMLTextAreaElement>(null);
|
|
||||||
const rsInput = useRef<ReactCodeMirrorRef>(null);
|
const rsInput = useRef<ReactCodeMirrorRef>(null);
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
|
@ -66,11 +63,10 @@ function EditorRSExpression({
|
||||||
const expression = prefix + value;
|
const expression = prefix + value;
|
||||||
checkExpression(expression, parse => {
|
checkExpression(expression, parse => {
|
||||||
if (parse.errors.length > 0) {
|
if (parse.errors.length > 0) {
|
||||||
const errorPosition = parse.errors[0].position - prefix.length
|
onShowError(parse.errors[0]);
|
||||||
expressionCtrl.current!.selectionStart = errorPosition;
|
} else {
|
||||||
expressionCtrl.current!.selectionEnd = errorPosition;
|
rsInput.current?.view?.focus();
|
||||||
}
|
}
|
||||||
expressionCtrl.current!.focus();
|
|
||||||
setIsModified(false);
|
setIsModified(false);
|
||||||
setTypification(getTypificationLabel({
|
setTypification(getTypificationLabel({
|
||||||
isValid: parse.parseResult,
|
isValid: parse.parseResult,
|
||||||
|
@ -82,38 +78,40 @@ function EditorRSExpression({
|
||||||
|
|
||||||
const onShowError = useCallback(
|
const onShowError = useCallback(
|
||||||
(error: IRSErrorDescription) => {
|
(error: IRSErrorDescription) => {
|
||||||
if (!activeCst || !expressionCtrl.current) {
|
if (!activeCst || !rsInput.current) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
const prefix = getCstExpressionPrefix(activeCst);
|
||||||
|
const errorPosition = error.position - prefix.length;
|
||||||
|
rsInput.current?.view?.dispatch({
|
||||||
|
selection: {
|
||||||
|
anchor: errorPosition,
|
||||||
|
head: errorPosition
|
||||||
}
|
}
|
||||||
const errorPosition = error.position - getCstExpressionPrefix(activeCst).length
|
});
|
||||||
expressionCtrl.current.selectionStart = errorPosition;
|
rsInput.current?.view?.focus();
|
||||||
expressionCtrl.current.selectionEnd = errorPosition;
|
|
||||||
expressionCtrl.current.focus();
|
|
||||||
}, [activeCst]);
|
}, [activeCst]);
|
||||||
|
|
||||||
const handleEdit = useCallback((id: TokenID, key?: string) => {
|
const handleEdit = useCallback((id: TokenID, key?: string) => {
|
||||||
if (!expressionCtrl.current) {
|
if (!rsInput.current || !rsInput.current.editor || !rsInput.current.state || !rsInput.current.view) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const text = new TextWrapper(expressionCtrl.current);
|
const text = new TextWrapper(rsInput.current as Required<ReactCodeMirrorRef>);
|
||||||
if (id === TokenID.ID_LOCAL) {
|
if (id === TokenID.ID_LOCAL) {
|
||||||
text.insertChar(key ?? 'unknown_local');
|
text.insertChar(key ?? 'unknown_local');
|
||||||
} else {
|
} else {
|
||||||
text.insertToken(id);
|
text.insertToken(id);
|
||||||
}
|
}
|
||||||
text.finalize();
|
rsInput.current?.view?.focus();
|
||||||
text.focus();
|
|
||||||
setValue(text.value);
|
|
||||||
setIsModified(true);
|
setIsModified(true);
|
||||||
}, [setValue]);
|
}, []);
|
||||||
|
|
||||||
const handleInput = useCallback(
|
const handleInput = useCallback(
|
||||||
(event: React.KeyboardEvent<HTMLTextAreaElement>) => {
|
(event: React.KeyboardEvent<HTMLDivElement>) => {
|
||||||
if (!expressionCtrl.current) {
|
if (!rsInput.current) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const text = new TextWrapper(expressionCtrl.current);
|
const text = new TextWrapper(rsInput.current as Required<ReactCodeMirrorRef>);
|
||||||
// rsInput.current?.state?.selection
|
|
||||||
if (event.shiftKey && event.key === '*' && !event.altKey) {
|
if (event.shiftKey && event.key === '*' && !event.altKey) {
|
||||||
text.insertToken(TokenID.DECART);
|
text.insertToken(TokenID.DECART);
|
||||||
} else if (event.altKey) {
|
} else if (event.altKey) {
|
||||||
|
@ -130,10 +128,8 @@ function EditorRSExpression({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
text.finalize();
|
|
||||||
setValue(text.value);
|
|
||||||
setIsModified(true);
|
setIsModified(true);
|
||||||
}, [expressionCtrl, setValue]);
|
}, []);
|
||||||
|
|
||||||
const EditButtons = useMemo(() => {
|
const EditButtons = useMemo(() => {
|
||||||
return (<div className='flex items-center justify-between w-full'>
|
return (<div className='flex items-center justify-between w-full'>
|
||||||
|
@ -229,24 +225,15 @@ function EditorRSExpression({
|
||||||
required={false}
|
required={false}
|
||||||
htmlFor={id}
|
htmlFor={id}
|
||||||
/>
|
/>
|
||||||
<textarea id={id} ref={expressionCtrl}
|
<RSInput innerref={rsInput}
|
||||||
className='w-full px-3 py-2 mt-2 leading-tight border shadow clr-input'
|
className='mt-2'
|
||||||
rows={6}
|
value={value}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
value={value}
|
editable={!disabled}
|
||||||
onChange={event => handleChange(event.target.value)}
|
|
||||||
onFocus={handleFocusIn}
|
|
||||||
onKeyDown={handleInput}
|
|
||||||
disabled={disabled}
|
|
||||||
spellCheck={false}
|
|
||||||
/>
|
|
||||||
{ user?.is_staff &&
|
|
||||||
<RSInput ref={rsInput}
|
|
||||||
value={value}
|
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
placeholder={placeholder}
|
onKeyDown={handleInput}
|
||||||
disabled={disabled}
|
onFocus={handleFocusIn}
|
||||||
/> }
|
/>
|
||||||
<div className='flex w-full gap-4 py-1 mt-1 justify-stretch'>
|
<div className='flex w-full gap-4 py-1 mt-1 justify-stretch'>
|
||||||
<div className='flex flex-col gap-2'>
|
<div className='flex flex-col gap-2'>
|
||||||
<Button
|
<Button
|
||||||
|
@ -257,7 +244,7 @@ function EditorRSExpression({
|
||||||
onClick={handleCheckExpression}
|
onClick={handleCheckExpression}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{isActive && EditButtons}
|
{isActive && !disabled && EditButtons}
|
||||||
</div>
|
</div>
|
||||||
{ (loading || parseData) &&
|
{ (loading || parseData) &&
|
||||||
<div className='w-full overflow-y-auto border mt-2 max-h-[14rem] min-h-[7rem]'>
|
<div className='w-full overflow-y-auto border mt-2 max-h-[14rem] min-h-[7rem]'>
|
||||||
|
|
|
@ -18,9 +18,9 @@ function ParsingResult({ data, onShowAST, onShowError }: ParsingResultProps) {
|
||||||
return (
|
return (
|
||||||
<div className='px-3 py-2'>
|
<div className='px-3 py-2'>
|
||||||
<p>Ошибок: <b>{errorCount}</b> | Предупреждений: <b>{warningsCount}</b></p>
|
<p>Ошибок: <b>{errorCount}</b> | Предупреждений: <b>{warningsCount}</b></p>
|
||||||
{data.errors.map(error => {
|
{data.errors.map((error, index) => {
|
||||||
return (
|
return (
|
||||||
<p className='cursor-pointer text-red' onClick={() => onShowError(error)}>
|
<p key={`error-${index}`} className='cursor-pointer text-red' onClick={() => onShowError(error)}>
|
||||||
<span className='mr-1 font-semibold underline'>{error.isCritical ? 'Ошибка' : 'Предупреждение'} {getRSErrorPrefix(error)}:</span>
|
<span className='mr-1 font-semibold underline'>{error.isCritical ? 'Ошибка' : 'Предупреждение'} {getRSErrorPrefix(error)}:</span>
|
||||||
<span> {getRSErrorMessage(error)}</span>
|
<span> {getRSErrorMessage(error)}</span>
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -1,43 +1,12 @@
|
||||||
|
import { bracketMatching } from '@codemirror/language';
|
||||||
import { Extension } from '@codemirror/state';
|
import { Extension } from '@codemirror/state';
|
||||||
import { createTheme } from '@uiw/codemirror-themes';
|
import { createTheme } from '@uiw/codemirror-themes';
|
||||||
import CodeMirror, { BasicSetupOptions, ReactCodeMirrorRef } from '@uiw/react-codemirror';
|
import CodeMirror, { BasicSetupOptions, ReactCodeMirrorProps, ReactCodeMirrorRef } from '@uiw/react-codemirror';
|
||||||
import { EditorView } from 'codemirror';
|
import { EditorView } from 'codemirror';
|
||||||
import { Ref } from 'react';
|
import { Ref, useMemo } from 'react';
|
||||||
|
|
||||||
import { useConceptTheme } from '../../../context/ThemeContext';
|
import { useConceptTheme } from '../../../context/ThemeContext';
|
||||||
|
|
||||||
const lightTheme: Extension = createTheme({
|
|
||||||
theme: 'light',
|
|
||||||
settings: {
|
|
||||||
fontFamily: 'inherit',
|
|
||||||
background: '#ffffff',
|
|
||||||
foreground: '#000000',
|
|
||||||
selection: '#036dd626'
|
|
||||||
},
|
|
||||||
styles: [
|
|
||||||
// { tag: t.comment, color: '#787b8099' },
|
|
||||||
// { tag: t.variableName, color: '#0080ff' },
|
|
||||||
// { tag: [t.string, t.special(t.brace)], color: '#5c6166' },
|
|
||||||
// { tag: t.definition(t.typeName), color: '#5c6166' },
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
const darkTheme: Extension = createTheme({
|
|
||||||
theme: 'dark',
|
|
||||||
settings: {
|
|
||||||
fontFamily: 'inherit',
|
|
||||||
background: '#000000',
|
|
||||||
foreground: '#ffffff',
|
|
||||||
selection: '#036dd626'
|
|
||||||
},
|
|
||||||
styles: [
|
|
||||||
// { tag: t.comment, color: '#787b8099' },
|
|
||||||
// { tag: t.variableName, color: '#0080ff' },
|
|
||||||
// { tag: [t.string, t.special(t.brace)], color: '#5c6166' },
|
|
||||||
// { tag: t.definition(t.typeName), color: '#5c6166' },
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
const editorSetup: BasicSetupOptions = {
|
const editorSetup: BasicSetupOptions = {
|
||||||
highlightSpecialChars: true,
|
highlightSpecialChars: true,
|
||||||
history: true,
|
history: true,
|
||||||
|
@ -52,7 +21,7 @@ const editorSetup: BasicSetupOptions = {
|
||||||
dropCursor: false,
|
dropCursor: false,
|
||||||
allowMultipleSelections: false,
|
allowMultipleSelections: false,
|
||||||
indentOnInput: false,
|
indentOnInput: false,
|
||||||
bracketMatching: true,
|
bracketMatching: false,
|
||||||
closeBrackets: false,
|
closeBrackets: false,
|
||||||
autocompletion: false,
|
autocompletion: false,
|
||||||
rectangularSelection: false,
|
rectangularSelection: false,
|
||||||
|
@ -67,35 +36,74 @@ const editorSetup: BasicSetupOptions = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const editorExtensions = [
|
const editorExtensions = [
|
||||||
EditorView.lineWrapping
|
EditorView.lineWrapping,
|
||||||
|
bracketMatching()
|
||||||
];
|
];
|
||||||
|
|
||||||
interface RSInputProps {
|
interface RSInputProps
|
||||||
ref?: Ref<ReactCodeMirrorRef>
|
extends Omit<ReactCodeMirrorProps, 'onChange'> {
|
||||||
value?: string
|
innerref?: Ref<ReactCodeMirrorRef> | undefined
|
||||||
disabled?: boolean
|
|
||||||
height?: string
|
|
||||||
placeholder?: string
|
|
||||||
onChange: (newValue: string) => void
|
onChange: (newValue: string) => void
|
||||||
|
onKeyDown: (event: React.KeyboardEvent<HTMLDivElement>) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
function RSInput({
|
function RSInput({
|
||||||
disabled, onChange,
|
innerref, onChange, editable,
|
||||||
height='10rem',
|
height='10rem',
|
||||||
...props
|
...props
|
||||||
}: RSInputProps) {
|
}: RSInputProps) {
|
||||||
const { darkMode } = useConceptTheme();
|
const { darkMode } = useConceptTheme();
|
||||||
|
|
||||||
|
const cursor = useMemo(() => editable ? 'cursor-text': 'cursor-default', [editable]);
|
||||||
|
const lightTheme: Extension = useMemo(
|
||||||
|
() => createTheme({
|
||||||
|
theme: 'light',
|
||||||
|
settings: {
|
||||||
|
fontFamily: 'inherit',
|
||||||
|
background: editable ? '#ffffff' : '#f0f2f7',
|
||||||
|
foreground: '#000000',
|
||||||
|
selection: '#036dd626',
|
||||||
|
selectionMatch: '#036dd626',
|
||||||
|
caret: '#5d00ff',
|
||||||
|
},
|
||||||
|
styles: [
|
||||||
|
// { tag: t.comment, color: '#787b8099' },
|
||||||
|
// { tag: t.variableName, color: '#0080ff' },
|
||||||
|
// { tag: [t.string, t.special(t.brace)], color: '#5c6166' },
|
||||||
|
// { tag: t.definition(t.typeName), color: '#5c6166' },
|
||||||
|
]
|
||||||
|
}), [editable]);
|
||||||
|
|
||||||
|
const darkTheme: Extension = useMemo(
|
||||||
|
() => createTheme({
|
||||||
|
theme: 'dark',
|
||||||
|
settings: {
|
||||||
|
fontFamily: 'inherit',
|
||||||
|
background: editable ? '#070b12' : '#374151',
|
||||||
|
foreground: '#e4e4e7',
|
||||||
|
selection: '#ffae00b0',
|
||||||
|
selectionMatch: '#ffae00b0',
|
||||||
|
caret: '#ffaa00'
|
||||||
|
},
|
||||||
|
styles: [
|
||||||
|
// { tag: t.comment, color: '#787b8099' },
|
||||||
|
// { tag: t.variableName, color: '#0080ff' },
|
||||||
|
// { tag: [t.string, t.special(t.brace)], color: '#5c6166' },
|
||||||
|
// { tag: t.definition(t.typeName), color: '#5c6166' },
|
||||||
|
]
|
||||||
|
}), [editable]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`w-full h-[${height}]`}>
|
<div className={`w-full h-[${height}] ${cursor}`}>
|
||||||
<CodeMirror
|
<CodeMirror
|
||||||
|
ref={innerref}
|
||||||
basicSetup={editorSetup}
|
basicSetup={editorSetup}
|
||||||
extensions={editorExtensions}
|
extensions={editorExtensions}
|
||||||
editable={!disabled}
|
|
||||||
height={height}
|
height={height}
|
||||||
indentWithTab={false}
|
indentWithTab={false}
|
||||||
theme={darkMode ? darkTheme : lightTheme}
|
theme={darkMode ? darkTheme : lightTheme}
|
||||||
onChange={(value) => onChange(value)}
|
onChange={value => onChange(value)}
|
||||||
|
editable={editable}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
// Formatted text editing helpers
|
// Formatted text editing helpers
|
||||||
|
|
||||||
|
import { ReactCodeMirrorRef } from '@uiw/react-codemirror';
|
||||||
|
|
||||||
import { TokenID } from '../../../utils/enums';
|
import { TokenID } from '../../../utils/enums';
|
||||||
|
|
||||||
export function getSymbolSubstitute(input: string): string | undefined {
|
export function getSymbolSubstitute(input: string): string | undefined {
|
||||||
|
@ -34,65 +36,31 @@ export function getSymbolSubstitute(input: string): string | undefined {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IManagedText {
|
|
||||||
value: string
|
|
||||||
selStart: number
|
|
||||||
selEnd: number
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: Wrapper class for textareafield.
|
// Note: Wrapper class for textareafield.
|
||||||
// WARNING! Manipulations on value do not support UNDO browser
|
// WARNING! Manipulations on value do not support UNDO browser
|
||||||
// WARNING! No checks for selection out of text boundaries
|
// WARNING! No checks for selection out of text boundaries
|
||||||
export class TextWrapper implements IManagedText {
|
export class TextWrapper {
|
||||||
value: string
|
ref: Required<ReactCodeMirrorRef>
|
||||||
selStart: number
|
|
||||||
selEnd: number
|
|
||||||
object: HTMLTextAreaElement
|
|
||||||
|
|
||||||
constructor(element: HTMLTextAreaElement) {
|
constructor(object: Required<ReactCodeMirrorRef>) {
|
||||||
this.object = element;
|
this.ref = object;
|
||||||
this.value = this.object.value;
|
|
||||||
this.selStart = this.object.selectionStart;
|
|
||||||
this.selEnd = this.object.selectionEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
focus() {
|
|
||||||
this.object.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
refresh() {
|
|
||||||
this.value = this.object.value;
|
|
||||||
this.selStart = this.object.selectionStart;
|
|
||||||
this.selEnd = this.object.selectionEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
finalize() {
|
|
||||||
this.object.value = this.value;
|
|
||||||
this.object.selectionStart = this.selStart;
|
|
||||||
this.object.selectionEnd = this.selEnd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
replaceWith(data: string) {
|
replaceWith(data: string) {
|
||||||
this.value = this.value.substring(0, this.selStart) + data + this.value.substring(this.selEnd, this.value.length);
|
this.ref.view.dispatch(this.ref.view.state.replaceSelection(data));
|
||||||
this.selEnd += data.length - this.selEnd + this.selStart;
|
|
||||||
this.selStart = this.selEnd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
envelopeWith(left: string, right: string) {
|
envelopeWith(left: string, right: string) {
|
||||||
this.value = this.value.substring(0, this.selStart) + left +
|
this.ref.view.dispatch({
|
||||||
this.value.substring(this.selStart, this.selEnd) + right +
|
changes: [
|
||||||
this.value.substring(this.selEnd, this.value.length);
|
{from: this.ref.view.state.selection.main.from, insert: left},
|
||||||
this.selEnd += left.length + right.length;
|
{from: this.ref.view.state.selection.main.to, insert: right}
|
||||||
}
|
],
|
||||||
|
selection: {
|
||||||
moveSel(shift: number) {
|
anchor: this.ref.view.state.selection.main.from,
|
||||||
this.selStart += shift;
|
head: this.ref.view.state.selection.main.to + left.length + right.length
|
||||||
this.selEnd += shift;
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
setSel(start: number, end: number) {
|
|
||||||
this.selStart = start;
|
|
||||||
this.selEnd = end;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
insertChar(key: string) {
|
insertChar(key: string) {
|
||||||
|
@ -114,18 +82,26 @@ export class TextWrapper implements IManagedText {
|
||||||
|
|
||||||
case TokenID.PUNC_PL: {
|
case TokenID.PUNC_PL: {
|
||||||
this.envelopeWith('(', ')');
|
this.envelopeWith('(', ')');
|
||||||
this.selEnd = this.selStart + 1;
|
this.ref.view.dispatch({
|
||||||
this.selStart = this.selEnd;
|
selection: {
|
||||||
|
anchor: this.ref.view.state.selection.main.from + 1,
|
||||||
|
}
|
||||||
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case TokenID.PUNC_SL: {
|
case TokenID.PUNC_SL: {
|
||||||
this.envelopeWith('[', ']');
|
this.envelopeWith('[', ']');
|
||||||
this.selEnd = this.selStart + 1;
|
this.ref.view.dispatch({
|
||||||
this.selStart = this.selEnd;
|
selection: {
|
||||||
|
anchor: this.ref.view.state.selection.main.from + 1,
|
||||||
|
}
|
||||||
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case TokenID.BOOLEAN: {
|
case TokenID.BOOLEAN: {
|
||||||
if (this.selEnd !== this.selStart && this.value[this.selStart] === 'ℬ') {
|
const selStart = this.ref.view.state.selection.main.from;
|
||||||
|
if (selStart !== this.ref.view.state.selection.main.to &&
|
||||||
|
this.ref.view.state.sliceDoc(selStart, selStart + 1) === 'ℬ') {
|
||||||
this.envelopeWith('ℬ', '');
|
this.envelopeWith('ℬ', '');
|
||||||
} else {
|
} else {
|
||||||
this.envelopeWith('ℬ(', ')');
|
this.envelopeWith('ℬ(', ')');
|
||||||
|
|
Loading…
Reference in New Issue
Block a user