Skip to content

Commit

Permalink
feat(adapter): SylApi: support selectNode in setSelection and ret…
Browse files Browse the repository at this point in the history
…urn `node` in `getSelection`

closes #18
  • Loading branch information
lastnigtic committed Aug 10, 2021
1 parent 3436909 commit 815fe26
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 24 deletions.
29 changes: 20 additions & 9 deletions docs/en/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ Whether the editor is destroyed.

```typescript
// types
(config?: {layerType?: string; mergeEmpty?: boolean }) => string | undefined;
(config?: { layerType?: string; mergeEmpty?: boolean }) => string | undefined;
```

Get the content of the editor `html`.
Expand Down Expand Up @@ -140,16 +140,19 @@ Disable quick input capability.

### getSelection

`getSelection: () => IRangeStatic`
`getSelection: () => IGetSelectionInfo`

Get the current selection, index represents the cursor position; length represents the selected length, pay attention to the non-text length.
Get the current selection, `index` represent the cursor position; `length` represent the selected length, pay attention to the non-text length.
`anchor` represent anchor index of selection, `head` represent head index of selection. Used to distinguish directions.
It will return `node` when selected `node`

### setSelection

`setSelection: (range: IRangeStatic & {scrollIntoView?: boolean }) => void`
`setSelection: (range: IRangeStatic & {scrollIntoView?: boolean, selectNode?: boolean }) => void`

Set the selection, `index` represents the cursor position, `length` represents the length of the selection.
Add the `scrollIntoView` parameter to control whether to scroll the selection to the window, the default is `true`.
the `scrollIntoView` parameter to control whether to scroll the selection to the window, the default is `true`.
the `selectNode` parameter to indicates whether to select the `node`.

### getText

Expand Down Expand Up @@ -184,8 +187,7 @@ nodesBetween: (

Used to traverse the document

- The `walker` function is used to traverse the document, returning `true` to perform a deep traversal on the current node, and returning `false` to jump out of the current node, and the default deep traversal.
-`range` is the range to be traversed. To traverse the full text, you can pass in `{ index: 0, length: SylApi.length }`, and the default range is the current selection.
- The `walker` function is used to traverse the document, returning `true` to perform a deep traversal on the current node, and returning `false` to jump out of the current node, and the default deep traversal. -`range` is the range to be traversed. To traverse the full text, you can pass in `{ index: 0, length: SylApi.length }`, and the default range is the current selection.

### insert

Expand Down Expand Up @@ -334,6 +336,15 @@ Decorate existing nodes.
}
```

### IGetSelectionInfo

````typescript
interface IGetSelectionInfo extends Types.IRangeStatic {
anchor: number;
head: number;
node?: ProsemirrorNode;
}

### InsertOption

```typescript
Expand All @@ -344,7 +355,7 @@ Decorate existing nodes.
focus?: boolean; // focus, the default is true
inheritMarks?: boolean; // Whether to inherit the current style when inserting in-line nodes, the default is true
}
```
````
### IUpdateOption
Expand Down Expand Up @@ -410,4 +421,4 @@ EventChannel: {
If `SylApi` cannot meet the demand, the following methods can be used:

- Through [Issues](https://github.com/bytedance/syllepsis/issues), provide requirements and application scenarios. After confirming the support, we will schedule development or the demand side will meet it through `Pull Request`.
- You can get the native `EditorView` object through the `view` property mounted on the editor instance to perform lower-level operations. For details, please refer to [Prosemirror](https://prosemirror.net/docs/ref/).
- You can get the native `EditorView` object through the `view` property mounted on the editor instance to perform lower-level operations. For details, please refer to [Prosemirror](https://prosemirror.net/docs/ref/).
21 changes: 17 additions & 4 deletions docs/zh-cn/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,16 +138,19 @@

### getSelection

`getSelection: () => IRangeStatic`
`getSelection: () => IGetSelectionInfo`

获取当前选区,index 代表光标位置;length 代表选中长度,注意非文本长度。
获取当前选区,`index` 代表光标位置;`length` 代表选中长度,注意非文本长度。
`anchor`为锚点位置,`head`为终止位置,用于区分选中方向
当选中节点时返回选中的`node`

### setSelection

`setSelection: (range: IRangeStatic & { scrollIntoView?: boolean }) => void`
`setSelection: (range: IRangeStatic & { scrollIntoView?: boolean, selectNode?: boolean }) => void`

设置选区,`index`代表光标位置,`length`代表选区长度。
增加`scrollIntoView`参数,控制是否将选区滚动到视窗,默认为`true`
`scrollIntoView`参数,控制是否将选区滚动到视窗,默认为`true`
`selectNode`参数,控制是否选中节点,默认为 `false`

### getText

Expand Down Expand Up @@ -332,6 +335,16 @@ nodesBetween: (
}
```

### IGetSelectionInfo

```typescript
interface IGetSelectionInfo extends Types.IRangeStatic {
anchor: number;
head: number;
node?: ProsemirrorNode;
}
```

### InsertOption

```typescript
Expand Down
24 changes: 18 additions & 6 deletions packages/adapter/src/api.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { redo } from 'prosemirror-history';
import { DOMParser, Node as ProsemirrorNode } from 'prosemirror-model';
import { EditorState, TextSelection } from 'prosemirror-state';
import { EditorState, NodeSelection, TextSelection } from 'prosemirror-state';
import { EditorView } from 'prosemirror-view';

import { IDecoState } from './basic/decoration';
Expand Down Expand Up @@ -56,10 +56,17 @@ interface ISetHTMLOptions {
keepWhiteSpace?: boolean;
}

interface IGetSelectionInfo extends Types.IRangeStatic {
anchor: number;
head: number;
node?: ProsemirrorNode;
}

interface ISetSelectionOptions extends Partial<Types.IRangeStatic> {
anchor?: number;
head?: number;
scrollIntoView?: boolean;
selectNode?: boolean;
}

type TSylApiCommand = (...args: any[]) => any;
Expand Down Expand Up @@ -267,18 +274,21 @@ class SylApi {
}

public getSelection = () => {
// anchor, head can
const { from, to, anchor, head } = getRealSelectionInfo(this.view.state.selection);
return {
const selection = this.view.state.selection;
const { from, to, anchor, head } = getRealSelectionInfo(selection);
const selectionInfo: IGetSelectionInfo = {
index: from,
length: to - from,
anchor,
head,
};
if (selection instanceof NodeSelection) selectionInfo.node = selection.node;

return selectionInfo;
};

public setSelection(config: ISetSelectionOptions) {
const { index, length = 0, scrollIntoView = true, anchor, head } = config;
const { index, length = 0, scrollIntoView = true, anchor, head, selectNode = false } = config;
if (index === undefined && anchor === undefined && head === undefined) {
throw new TypeError('must provide one of these parameters: [index, anchor, head]');
}
Expand All @@ -298,7 +308,9 @@ class SylApi {
}
}

const selection = TextSelection.create(doc, resultAnchor, resultHead);
const selection = selectNode
? NodeSelection.create(doc, resultAnchor)
: TextSelection.create(doc, resultAnchor, resultHead);
const tr = state.tr.setSelection(selection);
dispatch(scrollIntoView === false ? tr : tr.scrollIntoView());
}
Expand Down
23 changes: 18 additions & 5 deletions test/case/adapter/sylApi.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,15 @@ describe('single API test', () => {
expect(count).toEqual(1);
});

test('can setSelection to select node', async () => {
const nodeName = await page.evaluate(() => {
editor.setHTML(CARD_HTML);
editor.setSelection({ index: 0, selectNode: true });
return editor.getSelection().node.type.name;
});
expect(nodeName).toBe('card');
});

test('it can setContent', async () => {
const html = await page.evaluate(() => {
const json = {
Expand Down Expand Up @@ -678,23 +687,27 @@ describe('insert API test', () => {
const res1 = await page.evaluate(() => {
editor.setHTML('');
editor.insertCard('card', {}, { replaceEmpty: true });

return {
html: editor.getHTML(),
selection: editor.getSelection(),
};
});

expect(res1.html).toBe(CardView());
expect(res1.selection).toMatchObject({ index: 2, length: 0 });

const res2 = await page.evaluate(() => {
editor.setHTML(`<p></p>${CARD_HTML}`);
editor.setSelection({ index: 1, scrollIntoView: false });

editor.insertCard('card');
return {
html: editor.getHTML(),
selection: editor.getSelection(),
};

return JSON.parse(
JSON.stringify({
html: editor.getHTML(),
selection: editor.getSelection(),
}),
);
});

expect(res2.html).toBe(`${CardView()}${CardView()}`);
Expand Down

0 comments on commit 815fe26

Please sign in to comment.