UNPKG

@dodona/papyros

Version:

Scratchpad for multiple programming languages in the browser.

134 lines 5.22 kB
import { Decoration, WidgetType } from "@codemirror/view"; import readOnlyRangesExtension from "codemirror-readonly-ranges"; import { t } from "../util/Util"; import { LineEffectExtension } from "./LineEffectExtension"; const highlightDecoration = Decoration.line({ class: "papyros-test-code" }); // Widget to manage the test code class TestCodeWidget extends WidgetType { constructor(testCodeExtension) { super(); this.testCodeExtension = testCodeExtension; } toDOM() { const element = document.createElement("div"); element.classList.add("papyros-test-code-widget"); const span = document.createElement("span"); span.innerText = t("Papyros.editor.test_code.description"); element.appendChild(span); const buttons = document.createElement("div"); buttons.classList.add("papyros-test-code-buttons"); const editButton = document.createElement("a"); editButton.classList.add("papyros-icon-link"); editButton.innerHTML = "<i class=\"mdi mdi-pencil\"></i>"; editButton.addEventListener("click", () => { console.log("edit test code"); this.testCodeExtension.reset(true); }); editButton.title = t("Papyros.editor.test_code.edit"); buttons.appendChild(editButton); const deleteButton = document.createElement("a"); deleteButton.classList.add("papyros-icon-link"); deleteButton.innerHTML = "<i class=\"mdi mdi-close\"></i>"; deleteButton.addEventListener("click", () => { console.log("remove test code"); this.testCodeExtension.reset(); }); deleteButton.title = t("Papyros.editor.test_code.remove"); buttons.appendChild(deleteButton); element.appendChild(buttons); return element; } ignoreEvent() { return false; } } class BottomPaddingWidget extends WidgetType { toDOM() { const element = document.createElement("div"); element.classList.add("papyros-bottom-padding-widget"); element.appendChild(document.createElement("div")); return element; } } const bottomPaddingDecoration = Decoration.widget({ widget: new BottomPaddingWidget(), side: 1, block: true }); export class TestCodeExtension { constructor(view) { this.lines = ""; this.allowEdit = true; this.view = view; this.widget = Decoration.widget({ widget: new TestCodeWidget(this), block: true, side: 1 }); this.lineEffect = new LineEffectExtension(view); } get numberOfTestLines() { return this.lines.split("\n").length; } lineFromEnd(line, state = undefined) { const currentState = state || this.view.state; const lineFromEnd = currentState.doc.lines - line; return currentState.doc.line(lineFromEnd); } highlightLines() { for (let i = 0; i < this.numberOfTestLines; i++) { this.lineEffect.add([highlightDecoration.range(this.lineFromEnd(i).from)]); } } addWidget() { this.lineEffect.add([ this.widget.range(this.lineFromEnd(this.numberOfTestLines).to), bottomPaddingDecoration.range(this.lineFromEnd(0).to) ]); } clearAllLineEffects() { this.lineEffect.clear(); } getReadOnlyRanges(state) { if (this.allowEdit) { return []; } return [{ from: this.lineFromEnd(this.numberOfTestLines - 1, state).from, to: undefined // until last line }]; } insertTestCode(code) { var _a; // insert up to two new lines to separate the test code from the user code // but only if they are not already there const finalNewLineCount = ((_a = this.view.state.doc.toString().match(/\n*$/)) === null || _a === void 0 ? void 0 : _a[0].length) || 0; const newLinesToInsert = Math.max(0, 2 - finalNewLineCount); this.view.dispatch({ changes: { from: this.lineFromEnd(0).to, insert: "\n".repeat(newLinesToInsert) } }); this.view.dispatch({ changes: { from: this.lineFromEnd(0).to, insert: code } }); this.lines = code; } reset(keepCode = false) { this.allowEdit = true; this.clearAllLineEffects(); if (this.lines === "") { return; } if (!keepCode) { this.view.dispatch({ changes: { from: this.lineFromEnd(this.numberOfTestLines).to, to: this.lineFromEnd(0).to, insert: "" } }); } this.lines = ""; } set testCode(code) { this.reset(); if (code === "") { return; } this.insertTestCode(code); this.allowEdit = false; this.highlightLines(); this.addWidget(); } getNonTestCode() { if (this.allowEdit) { return this.view.state.doc.toString(); } return this.view.state.doc.sliceString(0, this.lineFromEnd(this.numberOfTestLines).to); } toExtension() { return [this.lineEffect.toExtension(), readOnlyRangesExtension(this.getReadOnlyRanges.bind(this))]; } } //# sourceMappingURL=TestCodeExtension.js.map