78 lines
1.8 KiB
TypeScript
78 lines
1.8 KiB
TypeScript
// BLOCKQUOTE
|
|
|
|
import {
|
|
Decoration,
|
|
DecorationSet,
|
|
EditorView,
|
|
ViewPlugin,
|
|
ViewUpdate,
|
|
} from "../deps.ts";
|
|
import {
|
|
editorLines,
|
|
isCursorInRange,
|
|
iterateTreeInVisibleRanges,
|
|
} from "./util.ts";
|
|
|
|
const quoteMarkRE = /^(\s*>+)/gm;
|
|
/**
|
|
* Plugin to add style blockquotes.
|
|
*/
|
|
class BlockQuotePlugin {
|
|
decorations: DecorationSet;
|
|
constructor(view: EditorView) {
|
|
this.decorations = this.styleBlockquote(view);
|
|
}
|
|
update(update: ViewUpdate) {
|
|
if (
|
|
update.docChanged ||
|
|
update.viewportChanged ||
|
|
update.selectionSet
|
|
) {
|
|
this.decorations = this.styleBlockquote(update.view);
|
|
}
|
|
}
|
|
/**
|
|
* @param view - The editor view
|
|
* @returns The blockquote decorations to add to the editor
|
|
*/
|
|
private styleBlockquote(view: EditorView): DecorationSet {
|
|
const widgets: any[] = [];
|
|
iterateTreeInVisibleRanges(view, {
|
|
enter: ({ name, from, to }) => {
|
|
if (name !== "Blockquote") return;
|
|
const lines = editorLines(view, from, to);
|
|
|
|
lines.forEach((line) => {
|
|
const lineDec = Decoration.line({
|
|
class: "sb-blockquote",
|
|
});
|
|
widgets.push(lineDec.range(line.from));
|
|
});
|
|
|
|
if (
|
|
lines.every(
|
|
(line) => !isCursorInRange(view.state, [line.from, line.to]),
|
|
)
|
|
) {
|
|
const marks = Array.from(
|
|
view.state.sliceDoc(from, to).matchAll(quoteMarkRE),
|
|
)
|
|
.map((x) => from + x.index!)
|
|
.map((i) =>
|
|
Decoration.line({
|
|
class: "sb-blockquote-outside",
|
|
}).range(i)
|
|
);
|
|
|
|
widgets.push(...marks);
|
|
}
|
|
},
|
|
});
|
|
return Decoration.set(widgets, true);
|
|
}
|
|
}
|
|
|
|
export const blockQuotePlugin = ViewPlugin.fromClass(BlockQuotePlugin, {
|
|
decorations: (v) => v.decorations,
|
|
});
|