rsdrsd
January 21, 2019, 6:14pm
1
I am using the following code to clear the formatting:
import { liftTarget } from 'prosemirror-transform';
export const FORMATTING_NODE_TYPES = [
'heading',
'code_block',
'blockquote',
'ordered_list',
'bullet_list',
'list_item',
];
export const FORMATTING_MARK_TYPES = [
'link',
'em',
'code',
'strike',
'strong',
'underline',
];
export function clearFormatting(state, dispatch) {
const { tr } = state;
FORMATTING_MARK_TYPES.forEach(mark => {
const { from, to } = tr.selection;
if (state.schema.marks[mark]) {
tr.removeMark(from, to, state.schema.marks[mark]);
}
});
FORMATTING_NODE_TYPES.forEach(nodeName => {
const formattedNodeType = state.schema.nodes[nodeName];
const { $from, $to } = tr.selection;
tr.doc.nodesBetween($from.pos, $to.pos, (node, pos) => {
if (node.type === formattedNodeType) {
if (formattedNodeType.isTextblock) {
tr.setNodeMarkup(pos, state.schema.nodes.paragraph);
return false;
} else {
let fromPos = tr.doc.resolve(pos + 1);
let toPos = tr.doc.resolve(pos + node.nodeSize - 1);
const nodeRange = fromPos.blockRange(toPos);
if (nodeRange) {
const targetLiftDepth = liftTarget(nodeRange);
if (targetLiftDepth || targetLiftDepth === 0) {
tr.lift(nodeRange, targetLiftDepth);
}
}
}
}
return true;
});
});
tr.setStoredMarks([]);
if (dispatch) {
dispatch(tr);
}
return true;
}
But for lists this doesn’t work as expected. Because if I have 6 list items and I select from the 2nd list item to
the 5th list item and I run the clearFormatting command. It only clears the format for the first 2 list items. What am I doing wrong?
List isn’t really a format (mark) of the texts. Instead, it’d defined as the structure of the texts.
That said, you should implement the transform that convert list into paragraph.
Note that the actual implementation depends on the specs of the list, list_item and paragraph nodes.
For instance, the implementation could be quite different depends on whether nested lists is supported.
I’ve wrote one implementation that unwraps list into paragraphs for non-nested list nodes.
listNodeAttrs,
Fragment.from(listItemNodes),
);
tr = tr.delete(fromPos, toPos);
tr = tr.insert(fromPos, Fragment.from(listNode));
}
return tr;
}
function unwrapNodesFromListInternal(
memo: SelectionMemo,
listNodePos: number,
unwrapParagraphNode?: ?(Node) => Node,
): Transform {
const {schema} = memo;
let {tr} = memo;
if (!tr.doc || !tr.selection) {
return tr;
}
Is there an update to what implementation you ended up using @rsdrsd
I ended up with
function (state: EditorState, dispatch: any, editorView: EditorView) => {
let { tr }: { tr: Transaction } = editorView.state;
const { $from, $to }: { $from: ResolvedPos; $to: ResolvedPos } = tr.selection;
// remove marks
tr.removeMark($from.pos, $to.pos);
// traverse all nodes within selection recursively and deal with each
tr.doc.nodesBetween($from.pos, $to.pos, (node: ProsemirrorNode, pos: number) => {
const formattedNodeType: NodeType = state.schema.nodes[node.type.name];
if (
(formattedNodeType && formattedNodeType.name !== 'paragraph') ||
formattedNodeType.name !== 'text' ||
// dont want to perform any lift on ordered or bullet lists
!isListNode(formattedNodeType) // is not a bullet or ordered list node
) {
let fromPos = tr.doc.resolve(tr.mapping.map(pos + 1));
let toPos = tr.doc.resolve(tr.mapping.map(pos + node.nodeSize - 1));
const nodeRange = fromPos.blockRange(toPos);
if (nodeRange) {
const targetLiftDepth: number | undefined | null = liftTarget(nodeRange);
if (formattedNodeType.isTextblock) {
// remove headers
tr.setNodeMarkup(nodeRange.start, state.schema.nodes.paragraph);
return false;
} else if (targetLiftDepth || targetLiftDepth === 0) {
// remove list_items, links, blockquotes
tr.lift(nodeRange, targetLiftDepth);
return false;
}
}
}
});
tr.setStoredMarks([]);
editorView.dispatch(tr);
return true;
}
i found that doing
let fromPos = tr.doc.resolve(tr.mapping.map(pos + 1));
let toPos = tr.doc.resolve(tr.mapping.map(pos + node.nodeSize - 1));
helped me to traverse all nodes within selection recursively and deal with each and not cause any replace step errors.