File size: 1,568 Bytes
f56a29b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import type { Schema, Node, NodeType } from 'prosemirror-model';
import type { Transaction } from 'prosemirror-state';
import type { EditorView } from 'prosemirror-view';

export const setTextAlign = (tr: Transaction, schema: Schema, alignment: string) => {
  const { selection, doc } = tr;
  if (!selection || !doc) return tr;

  const { from, to } = selection;
  const { nodes } = schema;

  const blockquote = nodes.blockquote;
  const listItem = nodes.list_item;
  const paragraph = nodes.paragraph;

  interface Task {
    node: Node;
    pos: number;
    nodeType: NodeType;
  }

  const tasks: Task[] = [];
  alignment = alignment || '';

  const allowedNodeTypes = new Set([blockquote, listItem, paragraph]);

  doc.nodesBetween(from, to, (node, pos) => {
    const nodeType = node.type;
    const align = node.attrs.align || '';
    if (align !== alignment && allowedNodeTypes.has(nodeType)) {
      tasks.push({
        node,
        pos,
        nodeType,
      });
    }
    return true;
  });

  if (!tasks.length) return tr;

  tasks.forEach((task) => {
    const { node, pos, nodeType } = task;
    let { attrs } = node;
    if (alignment) attrs = { ...attrs, align: alignment };
    else attrs = { ...attrs, align: null };
    tr = tr.setNodeMarkup(pos, nodeType, attrs, node.marks);
  });

  return tr;
};

export const alignmentCommand = (view: EditorView, alignment: string) => {
  const { state } = view;
  const { schema, selection } = state;
  const tr = setTextAlign(state.tr.setSelection(selection), schema, alignment);
  view.dispatch(tr);
};