From 944a09bff90920ff12f481971b7890aa83a817fe Mon Sep 17 00:00:00 2001 From: Mikhail Pavlovich Date: Thu, 23 Jan 2025 15:46:31 +0300 Subject: [PATCH 1/2] start --- src/core/markdown/MarkdownSerializer.js | 22 +++ src/extensions/markdown/Breaks/index.ts | 4 +- .../yfm/Checkbox/CheckboxSpecs/index.ts | 3 +- .../yfm/Checkbox/CheckboxSpecs/parsetTest.ts | 161 ++++++++++++++++++ .../yfm/Checkbox/CheckboxSpecs/serializer.ts | 2 +- src/extensions/yfm/Checkbox/index.scss | 7 +- src/extensions/yfm/Checkbox/plugin.ts | 1 - 7 files changed, 195 insertions(+), 5 deletions(-) create mode 100644 src/extensions/yfm/Checkbox/CheckboxSpecs/parsetTest.ts diff --git a/src/core/markdown/MarkdownSerializer.js b/src/core/markdown/MarkdownSerializer.js index f2063a7a1..6af6fe0f5 100644 --- a/src/core/markdown/MarkdownSerializer.js +++ b/src/core/markdown/MarkdownSerializer.js @@ -315,6 +315,28 @@ export class MarkdownSerializerState { this.inTightList = prevTight; } + renderCheckbox(node){ + let canSetBreak = false + node.forEach((child, _, i) => { + + if(child.type.name === "soft_break" || (child.type.name === 'text' && child.text === String.fromCharCode(160))){ + if(canSetBreak){ + const delim = i === 0 ? '' : '  ' + this.flushClose(1); + this.wrapBlock(delim, null, node, () => {}); + return + } + canSetBreak = true + return + } + + canSetBreak = false + const delim = i === 0 ? '' : ' ' + this.flushClose(1); + this.wrapBlock(delim, null, node, () => this.render(child, node, i)); + }); + } + // :: (string, ?bool) → string // Escape the given string so that it can safely appear in Markdown // content. If `startOfLine` is true, also escape characters that diff --git a/src/extensions/markdown/Breaks/index.ts b/src/extensions/markdown/Breaks/index.ts index 7b0432712..cb0e5de91 100644 --- a/src/extensions/markdown/Breaks/index.ts +++ b/src/extensions/markdown/Breaks/index.ts @@ -7,6 +7,7 @@ import {logger} from '../../../logger'; import {isMac} from '../../../utils/platform'; import {isTextSelection} from '../../../utils/selection'; import {pType} from '../../base/BaseSchema/BaseSchemaSpecs'; +import {checkboxLabelType} from '../../yfm/Checkbox/CheckboxSpecs/const'; import {BreaksSpecs, BreaksSpecsOptions, hbType, sbType} from './BreaksSpecs'; @@ -55,7 +56,8 @@ const addBr = (br: NodeType) => !isTextSelection(sel) || !sel.empty || // breaks can only be in the paragraph - sel.$cursor?.parent.type !== pType(schema) + (sel.$cursor?.parent.type !== pType(schema) && + sel.$cursor?.parent.type !== checkboxLabelType(schema)) ) return false; diff --git a/src/extensions/yfm/Checkbox/CheckboxSpecs/index.ts b/src/extensions/yfm/Checkbox/CheckboxSpecs/index.ts index edfb2dc13..d86b469d3 100644 --- a/src/extensions/yfm/Checkbox/CheckboxSpecs/index.ts +++ b/src/extensions/yfm/Checkbox/CheckboxSpecs/index.ts @@ -1,10 +1,11 @@ -import checkboxPlugin from '@diplodoc/transform/lib/plugins/checkbox'; +// import checkboxPlugin from '@diplodoc/transform/lib/plugins/checkbox'; import type {NodeSpec} from 'prosemirror-model'; import type {ExtensionAuto, ExtensionNodeSpec} from '../../../../core'; import {CheckboxNode, b, idPrefix} from './const'; import {parserTokens} from './parser'; +import checkboxPlugin from './parsetTest'; import {getSchemaSpecs} from './schema'; import {serializerTokens} from './serializer'; diff --git a/src/extensions/yfm/Checkbox/CheckboxSpecs/parsetTest.ts b/src/extensions/yfm/Checkbox/CheckboxSpecs/parsetTest.ts new file mode 100644 index 000000000..27a0f9fe2 --- /dev/null +++ b/src/extensions/yfm/Checkbox/CheckboxSpecs/parsetTest.ts @@ -0,0 +1,161 @@ +// Все доработки в diplodoc/transform +import type MarkdownIt from 'markdown-it'; +import type {PluginWithOptions} from 'markdown-it'; +import type Core from 'markdown-it/lib/parser_core'; +import type StateCore from 'markdown-it/lib/rules_core/state_core'; +import type Token from 'markdown-it/lib/token'; + +// eslint-disable-next-line no-useless-escape +export const pattern = /^\[(X|\s|\_|\-)\]\s((.|\s)*)/i; + +export const CheckboxTokenType = { + Checkbox: 'checkbox', + CheckboxOpen: 'checkbox_open', + CheckboxClose: 'checkbox_close', + CheckboxInput: 'checkbox_input', + CheckboxLabel: 'checkbox_label', + CheckboxLabelOpen: 'checkbox_label_open', + CheckboxLabelClose: 'checkbox_label_close', +} as const; + +function matchOpenToken(tokens: Token[], i: number) { + return ( + tokens[i].type === 'paragraph_open' && + tokens[i + 1].type === 'inline' && + tokens[i + 1].content.match(pattern) + ); +} + +export type CheckboxOptions = { + idPrefix?: string; + divClass?: string; + /** @default true */ + disabled?: boolean; +}; + +export const checkboxReplace = function (_md: MarkdownIt, opts?: CheckboxOptions): Core.RuleCore { + let lastId = 0; + const defaults: Required = { + divClass: 'checkbox', + idPrefix: 'checkbox', + disabled: true, + }; + const options = Object.assign(defaults, opts); + + const createTokens = function (state: StateCore, checked: boolean, label: string, i: number) { + let token: Token; + const nodes = []; + + /** + *
+ */ + token = new state.Token(CheckboxTokenType.CheckboxOpen, 'div', 1); + token.block = true; + token.map = state.tokens[i].map; + token.attrs = [['class', options.divClass]]; + nodes.push(token); + + /** + * + */ + const id = options.idPrefix + lastId; + lastId += 1; + token = new state.Token(CheckboxTokenType.CheckboxInput, 'input', 0); + token.block = true; + token.map = state.tokens[i].map; + token.attrs = [ + ['type', 'checkbox'], + ['id', id], + ]; + if (options.disabled) { + token.attrSet('disabled', ''); + } + if (checked === true) { + token.attrSet('checked', 'true'); + } + nodes.push(token); + + /** + *