UNPKG

@firecms/core

Version:

Awesome Firebase/Firestore-based headless open-source CMS

109 lines (99 loc) 4.12 kB
import { EditorState } from "prosemirror-state"; export function isMarkActive(state: EditorState, type: any) { if (!state || !type) return false; const { from, $from, to, empty } = state.selection; if (empty) return !!type.isInSet(state.storedMarks || $from.marks()); return state.doc.rangeHasMark(from, to, type); } export function isNodeActive(state: EditorState, type: any, attrs: any = {}) { if (!state || !type) return false; const { $from, to, node } = state.selection as any; if (node) { return node.type === type && (!attrs || Object.keys(attrs).every((key) => node.attrs[key] === attrs[key])); } return to <= $from.end() && $from.parent.type === type && (!attrs || Object.keys(attrs).every((key) => $from.parent.attrs[key] === attrs[key])); } export function getMarkAttributes(state: EditorState, type: any) { if (!state || !type) return {}; const { from, $from, to, empty } = state.selection; let mark; if (empty) { mark = type.isInSet(state.storedMarks || $from.marks()); } else { let found = false; state.doc.nodesBetween(from, to, (node) => { if (found) return false; const m = type.isInSet(node.marks); if (m) { mark = m; found = true; } return true; }); } return mark ? mark.attrs : {}; } export function setMark(type: any, attrs?: any) { return (state: EditorState, dispatch?: (tr: any) => void) => { const { empty, $cursor, ranges } = state.selection as any; if ((empty && !$cursor) || !type) return false; if (dispatch) { if ($cursor) { dispatch(state.tr.addStoredMark(type.create(attrs))); } else { let tr = state.tr; for (let i = 0; i < ranges.length; i++) { let { $from, $to } = ranges[i]; tr.addMark($from.pos, $to.pos, type.create(attrs)); } dispatch(tr.scrollIntoView()); } } return true; }; } export function unsetMark(type: any) { return (state: EditorState, dispatch?: (tr: any) => void) => { const { empty, $cursor, ranges } = state.selection as any; if ((empty && !$cursor) || !type) return false; if (dispatch) { let tr = state.tr; if ($cursor) { const parent = $cursor.parent; let markStart = -1; let markEnd = -1; let currentMarkStart = -1; parent.forEach((child: any, offset: number) => { const childStart = $cursor.start() + offset; const childEnd = childStart + child.nodeSize; if (type.isInSet(child.marks)) { if (currentMarkStart === -1) currentMarkStart = childStart; if ($cursor.pos >= childStart && $cursor.pos <= childEnd) { markStart = currentMarkStart; } } else { if (currentMarkStart !== -1) { if (markStart !== -1 && markEnd === -1) markEnd = childStart; currentMarkStart = -1; } } }); if (markStart !== -1 && markEnd === -1) { markEnd = $cursor.end(); } if (markStart !== -1 && markEnd !== -1) { tr.removeMark(markStart, markEnd, type); } tr.removeStoredMark(type); dispatch(tr.scrollIntoView()); } else { for (let i = 0; i < ranges.length; i++) { let { $from, $to } = ranges[i]; tr.removeMark($from.pos, $to.pos, type); } dispatch(tr.scrollIntoView()); } } return true; }; }