1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-20 14:11:35 +02:00

fix inline matching, add matching arrays, closes #3174 #3191

This commit is contained in:
Ian Storm Taylor
2019-12-02 18:54:22 -05:00
parent e39f1e77ea
commit ea62ad9e44
22 changed files with 170 additions and 64 deletions

View File

@@ -70,8 +70,9 @@ export const checkNode = (
}
if ('marks' in v && v.marks != null) {
for (const [mark, index, n, p] of Node.marks(node)) {
if (!v.marks.some(m => Mark.matches(mark, m))) {
for (const entry of Node.marks(node)) {
if (!Editor.isMarkMatch(editor, entry, v.marks)) {
const [mark, index, n, p] = entry
return { code: 'mark_invalid', node: n, path: p, mark, index }
}
}

View File

@@ -13,19 +13,19 @@ export interface MarkRule {
}
export interface ChildValidation {
match?: NodeMatch | NodeMatch[]
match?: NodeMatch
min?: number
max?: number
}
export interface NodeValidation {
children?: ChildValidation[]
first?: NodeMatch[]
last?: NodeMatch[]
marks?: MarkMatch[]
next?: NodeMatch[]
parent?: NodeMatch[]
previous?: NodeMatch[]
first?: NodeMatch
last?: NodeMatch
marks?: MarkMatch
next?: NodeMatch
parent?: NodeMatch
previous?: NodeMatch
properties?: Record<string, any>
text?: (text: string) => boolean
}

View File

@@ -0,0 +1,27 @@
/** @jsx jsx */
import { jsx } from 'slate-hyperscript'
export const schema = [
{
for: 'node',
match: 'element',
validate: {
marks: [{ a: true }, { b: true }],
},
},
]
export const input = (
<editor>
<element>
<mark c>text</mark>
</element>
</editor>
)
export const output = (
<editor>
<element>text</element>
</editor>
)

View File

@@ -4,6 +4,7 @@ import { ElementQueries } from './queries/element'
import { GeneralTransforms } from './transforms/general'
import { GeneralQueries } from './queries/general'
import { LocationQueries } from './queries/location'
import { MarkQueries } from './queries/mark'
import { MarkTransforms } from './transforms/mark'
import { NodeTransforms } from './transforms/node'
import { NodeQueries } from './queries/node'
@@ -34,6 +35,7 @@ export const Editor = {
...GeneralQueries,
...GeneralTransforms,
...LocationQueries,
...MarkQueries,
...MarkTransforms,
...NodeQueries,
...NodeTransforms,

View File

@@ -350,13 +350,6 @@ export const LocationQueries = {
for (const entry of Editor.texts(editor, { reverse, at })) {
const [node, path] = entry
const isMatch = (m: MarkMatch, entry: MarkEntry) => {
if (typeof m === 'function') {
return m(entry)
} else {
return Mark.matches(entry[0], m)
}
}
if (mode === 'universal') {
if (first) {
@@ -384,7 +377,7 @@ export const LocationQueries = {
const mark = node.marks[index]
const markEntry: MarkEntry = [mark, index, node, path]
if (match != null && !isMatch(match, markEntry)) {
if (match != null && !Editor.isMarkMatch(editor, markEntry, match)) {
continue
}

View File

@@ -0,0 +1,17 @@
import { Editor, Mark, MarkEntry, MarkMatch } from '../../..'
export const MarkQueries = {
/**
* Check if a mark entry is a match.
*/
isMarkMatch(editor: Editor, entry: MarkEntry, match: MarkMatch): boolean {
if (Array.isArray(match)) {
return match.some(m => Editor.isMarkMatch(editor, entry, m))
} else if (typeof match === 'function') {
return match(entry)
} else {
return Mark.matches(entry[0], match)
}
},
}

View File

@@ -5,20 +5,13 @@ export const NodeQueries = {
* Check if a node entry is a match.
*/
isMatch(editor: Editor, entry: NodeEntry, match: NodeMatch | NodeMatch[]) {
const [node] = entry
// If match is an array, treat it as an OR condition.
isMatch(editor: Editor, entry: NodeEntry, match: NodeMatch): boolean {
if (Array.isArray(match)) {
for (const m of match) {
if (Editor.isMatch(editor, entry, m)) {
return true
}
}
return false
return match.some(m => Editor.isMatch(editor, entry, m))
}
const [node] = entry
switch (match) {
case 'text':
return Text.isText(node)
@@ -27,11 +20,6 @@ export const NodeQueries = {
case 'element':
return Element.isElement(node)
case 'inline':
return (
(Element.isElement(node) && editor.isInline(node)) ||
Text.isText(node)
)
case 'inline-element':
return Element.isElement(node) && editor.isInline(node)
case 'block':
return (

View File

@@ -48,7 +48,7 @@ export const NodeTransforms = {
} else if (Text.isText(node)) {
match = 'text'
} else if (editor.isInline(node)) {
match = 'inline'
match = ['inline', 'text']
} else {
match = 'block'
}
@@ -682,7 +682,7 @@ export const NodeTransforms = {
const path = at
match = ([, p]) => Path.equals(p, path)
} else if (editor.isInline(element)) {
match = 'inline'
match = ['inline', 'text']
} else {
match = 'block'
}

View File

@@ -193,7 +193,7 @@ export const TextTransforms = {
// If the insert point is at the edge of an inline node, move it outside
// instead since it will need to be split otherwise.
const inlineElementMatch = Editor.match(editor, at, 'inline-element')
const inlineElementMatch = Editor.match(editor, at, 'inline')
if (inlineElementMatch) {
const [, inlinePath] = inlineElementMatch
@@ -270,7 +270,7 @@ export const TextTransforms = {
}
}
const inlineMatch = Editor.match(editor, at, 'inline')!
const inlineMatch = Editor.match(editor, at, ['inline', 'text'])!
const [, inlinePath] = inlineMatch
const isInlineStart = Editor.isStart(editor, at, inlinePath)
const isInlineEnd = Editor.isEnd(editor, at, inlinePath)
@@ -285,7 +285,10 @@ export const TextTransforms = {
isInlineEnd ? Path.next(inlinePath) : inlinePath
)
Editor.splitNodes(editor, { at, match: hasBlocks ? 'block' : 'inline' })
Editor.splitNodes(editor, {
at,
match: hasBlocks ? 'block' : ['inline', 'text'],
})
const startRef = Editor.pathRef(
editor,
@@ -296,13 +299,18 @@ export const TextTransforms = {
Editor.insertNodes(editor, starts, {
at: startRef.current!,
match: 'inline',
match: ['inline', 'text'],
})
Editor.insertNodes(editor, middles, {
at: middleRef.current!,
match: 'block',
})
Editor.insertNodes(editor, ends, { at: endRef.current!, match: 'inline' })
Editor.insertNodes(editor, ends, {
at: endRef.current!,
match: ['inline', 'text'],
})
if (!options.at) {
let path

View File

@@ -62,4 +62,7 @@ export type MarkEntry = [Mark, number, Text, Path]
* `MarkMatch` values are used as shorthands for matching mark objects.
*/
export type MarkMatch = Partial<Mark> | ((entry: MarkEntry) => boolean)
export type MarkMatch =
| Partial<Mark>
| ((entry: MarkEntry) => boolean)
| MarkMatch[]

View File

@@ -574,9 +574,9 @@ export type NodeMatch =
| 'block'
| 'element'
| 'inline'
| 'inline-element'
| 'text'
| 'editor'
| 'void'
| Partial<Node>
| ((entry: NodeEntry) => boolean)
| NodeMatch[]

View File

@@ -15,4 +15,4 @@ export const run = editor => {
)
}
export const output = [[<text>one</text>, [0, 0]]]
export const output = []

View File

@@ -18,9 +18,6 @@ export const run = editor => {
}
export const output = [
[<text>one</text>, [0, 0]],
[<inline>two</inline>, [0, 1]],
[<text>three</text>, [0, 2]],
[<inline>four</inline>, [0, 3]],
[<text>five</text>, [0, 4]],
]

View File

@@ -22,12 +22,10 @@ export const run = editor => {
}
export const output = [
[<text>one</text>, [0, 0]],
[
<inline>
two<inline>three</inline>four
</inline>,
[0, 1],
],
[<text>five</text>, [0, 2]],
]

View File

@@ -23,9 +23,6 @@ export const run = editor => {
}
export const output = [
[<text>five</text>, [0, 4]],
[<inline>four</inline>, [0, 3]],
[<text>three</text>, [0, 2]],
[<inline>two</inline>, [0, 1]],
[<text>one</text>, [0, 0]],
]

View File

@@ -17,8 +17,4 @@ export const run = editor => {
)
}
export const output = [
[<text>one</text>, [0, 0]],
[<inline void>two</inline>, [0, 1]],
[<text>three</text>, [0, 2]],
]
export const output = [[<inline void>two</inline>, [0, 1]]]

View File

@@ -17,8 +17,4 @@ export const run = editor => {
)
}
export const output = [
[<text>one</text>, [0, 0]],
[<inline>two</inline>, [0, 1]],
[<text>three</text>, [0, 2]],
]
export const output = [[<inline>two</inline>, [0, 1]]]

View File

@@ -0,0 +1,26 @@
/** @jsx jsx */
import { Editor } from 'slate'
import { jsx } from '../../..'
export const input = (
<editor>
<block>
one<inline>two</inline>three<inline>four</inline>five
</block>
</editor>
)
export const run = editor => {
return Array.from(
Editor.nodes(editor, { at: [], match: ['inline', 'text'], mode: 'highest' })
)
}
export const output = [
[<text>one</text>, [0, 0]],
[<inline>two</inline>, [0, 1]],
[<text>three</text>, [0, 2]],
[<inline>four</inline>, [0, 3]],
[<text>five</text>, [0, 4]],
]

View File

@@ -0,0 +1,33 @@
/** @jsx jsx */
import { Editor } from 'slate'
import { jsx } from '../../..'
export const input = (
<editor>
<block>
one
<inline>
two<inline>three</inline>four
</inline>
five
</block>
</editor>
)
export const run = editor => {
return Array.from(
Editor.nodes(editor, { at: [], match: ['inline', 'text'], mode: 'highest' })
)
}
export const output = [
[<text>one</text>, [0, 0]],
[
<inline>
two<inline>three</inline>four
</inline>,
[0, 1],
],
[<text>five</text>, [0, 2]],
]

View File

@@ -0,0 +1,24 @@
/** @jsx jsx */
import { Editor } from 'slate'
import { jsx } from '../../..'
export const input = (
<editor>
<block>
one<inline>two</inline>three
</block>
</editor>
)
export const run = editor => {
return Array.from(
Editor.nodes(editor, { at: [], match: ['inline', 'text'], mode: 'highest' })
)
}
export const output = [
[<text>one</text>, [0, 0]],
[<inline>two</inline>, [0, 1]],
[<text>three</text>, [0, 2]],
]

View File

@@ -36,10 +36,10 @@ export const output = (
<anchor />
word
</inline>
<text key />
<text />
</block>
<block>
<text key />
<text />
<inline key>
another
<focus />

View File

@@ -36,7 +36,7 @@ export const output = (
<anchor />
word
</inline>
<text key />
<text />
</block>
<block>
<text />