~~~~*))(\s*)$/,
- replacement: '$1$3'
- },
- TMBlankLine: {
- regexp: /^([ \t]*)$/,
- replacement: "$0"
- },
- TMSetextH1Marker: {
- regexp: /^ {0,3}=+\s*$/,
- replacement: '$0'
- },
- TMSetextH2Marker: {
- regexp: /^ {0,3}-+\s*$/,
- replacement: '$0'
- },
- TMHR: {
- regexp: /^( {0,3}(\*[ \t]*\*[ \t]*\*[ \t*]*)|(-[ \t]*-[ \t]*-[ \t-]*)|(_[ \t]*_[ \t]*_[ \t_]*))$/,
- replacement: '$0'
- },
- TMUL: {
- regexp: /^( {0,3}[+*-] {1,4})(.*)$/,
- replacement: '$1$$2'
- },
- TMOL: {
- regexp: /^( {0,3}\d{1,9}[.)] {1,4})(.*)$/,
- replacement: '$1$$2'
- },
- // TODO: This is currently preventing sublists (and any content within list items, really) from working
- TMIndentedCode: {
- regexp: /^( {4}|\t)(.*)$/,
- replacement: '$1$2'
- },
- TMLinkReferenceDefinition: {
- // TODO: Link destination can't include unbalanced parantheses, but we just ignore that here
- regexp: /^( {0,3}\[\s*)([^\s\]](?:[^\]]|\\\])*?)(\s*\]:\s*)((?:[^\s<>]+)|(?:<(?:[^<>\\]|\\.)*>))?(\s*)((?:\((?:[^()\\]|\\.)*\))|(?:"(?:[^"\\]|\\.)*")|(?:'(?:[^'\\]|\\.)*'))?(\s*)$/,
- replacement: '$1$2$3$4$5$6$7',
- labelPlaceholder: 2
- // this defines which placeholder in the above regex is the link "label"
- }
- };
- var htmlBlockGrammar = exports.htmlBlockGrammar = [{
- start: /^ {0,3}<(?:script|pre|style)(?:\s|>|$)/i,
- end: /(?:<\/script>|<\/pre>|<\/style>)/i,
- paraInterrupt: true
- }, {
- start: /^ {0,3}/,
- paraInterrupt: true
- }, {
- start: /^ {0,3}<\?/,
- end: /\?>/,
- paraInterrupt: true
- }, {
- start: /^ {0,3}/,
- paraInterrupt: true
- }, {
- start: /^ {0,3}/,
- paraInterrupt: true
- }, {
- start: /^ {0,3}(?:<|<\/)(?:KnownTag)(?:\s|>|\/>|$)/i,
- end: false,
- paraInterrupt: true
- }, {
- start: /^ {0,3}(?:HTMLOpenTag|HTMLCloseTag)\s*$/,
- end: false,
- paraInterrupt: false
- }];
- var inlineGrammar = exports.inlineGrammar = {
- escape: {
- regexp: /^\\(ASCIIPunctuation)/,
- replacement: '\\$1'
- },
- code: {
- regexp: /^(`+)((?:[^`])|(?:[^`].*?[^`]))(\1)/,
- replacement: '$1$2
$3'
- },
- autolink: {
- regexp: /^<((?:Scheme:[^\s<>]*)|(?:Email))>/,
- replacement: '<$1>'
- },
- html: {
- regexp: /^((?:HTMLOpenTag)|(?:HTMLCloseTag)|(?:HTMLComment)|(?:HTMLPI)|(?:HTMLDeclaration)|(?:HTMLCDATA))/,
- replacement: '$1'
- },
- linkOpen: {
- regexp: /^\[/,
- replacement: ""
- },
- imageOpen: {
- regexp: /^!\[/,
- replacement: ""
- },
- linkLabel: {
- regexp: /^(\[\s*)([^\]]*?)(\s*\])/,
- replacement: "",
- labelPlaceholder: 2
- },
- default: {
- regexp: /^(.|(?:NotTriggerChar+))/,
- replacement: "$1"
- }
- };
- var replacementRegexp = new RegExp(Object.keys(replacements).join("|"));
- var inlineRules = [...Object.keys(inlineGrammar)];
- for (let rule of inlineRules) {
- let re = inlineGrammar[rule].regexp.source;
- while (re.match(replacementRegexp)) {
- re = re.replace(replacementRegexp, (string) => {
- return replacements[string].source;
- });
- }
- inlineGrammar[rule].regexp = new RegExp(re, inlineGrammar[rule].regexp.flags);
- }
- for (let rule of htmlBlockGrammar) {
- let re = rule.start.source;
- while (re.match(replacementRegexp)) {
- re = re.replace(replacementRegexp, (string) => {
- return replacements[string].source;
- });
- }
- rule.start = new RegExp(re, rule.start.flags);
- }
- function htmlescape(string) {
- return (string ? string : "").replace(/&/g, "&").replace(//g, ">");
- }
- var commands = exports.commands = {
- // Replacements for unset for inline commands are '' by default
- bold: {
- type: "inline",
- className: "TMStrong",
- set: {
- pre: "**",
- post: "**"
- },
- unset: {
- prePattern: /(?:\*\*|__)$/,
- postPattern: /^(?:\*\*|__)/
- }
- },
- italic: {
- type: "inline",
- className: "TMEm",
- set: {
- pre: "*",
- post: "*"
- },
- unset: {
- prePattern: /(?:\*|_)$/,
- postPattern: /^(?:\*|_)/
- }
- },
- code: {
- type: "inline",
- className: "TMCode",
- set: {
- pre: "`",
- post: "`"
- },
- unset: {
- prePattern: /`+$/,
- postPattern: /^`+/
- }
- // FIXME this doesn't ensure balanced backticks right now
- },
- strikethrough: {
- type: "inline",
- className: "TMStrikethrough",
- set: {
- pre: "~~",
- post: "~~"
- },
- unset: {
- prePattern: /~~$/,
- postPattern: /^~~/
- }
- },
- h1: {
- type: "line",
- className: "TMH1",
- set: {
- pattern: /^( {0,3}(?:(?:#+|[0-9]{1,9}[).]|[>\-*+])\s+)?)(.*)$/,
- replacement: "# $2"
- },
- unset: {
- pattern: /^( {0,3}#\s+)(.*?)((?:\s+#+\s*)?)$/,
- replacement: "$2"
- }
- },
- h2: {
- type: "line",
- className: "TMH2",
- set: {
- pattern: /^( {0,3}(?:(?:#+|[0-9]{1,9}[).]|[>\-*+])\s+)?)(.*)$/,
- replacement: "## $2"
- },
- unset: {
- pattern: /^( {0,3}##\s+)(.*?)((?:\s+#+\s*)?)$/,
- replacement: "$2"
- }
- },
- h3: {
- type: "line",
- className: "TMH3",
- set: {
- pattern: /^( {0,3}(?:(?:#+|[0-9]{1,9}[).]|[>\-*+])\s+)?)(.*)$/,
- replacement: "### $2"
- },
- unset: {
- pattern: /^( {0,3}###\s+)(.*?)((?:\s+#+\s*)?)$/,
- replacement: "$2"
- }
- },
- h4: {
- type: "line",
- className: "TMH4",
- set: {
- pattern: /^( {0,3}(?:(?:#+|[0-9]{1,9}[).]|[>\-*+])\s+)?)(.*)$/,
- replacement: "#### $2"
- },
- unset: {
- pattern: /^( {0,3}####\s+)(.*?)((?:\s+#+\s*)?)$/,
- replacement: "$2"
- }
- },
- h5: {
- type: "line",
- className: "TMH5",
- set: {
- pattern: /^( {0,3}(?:(?:#+|[0-9]{1,9}[).]|[>\-*+])\s+)?)(.*)$/,
- replacement: "##### $2"
- },
- unset: {
- pattern: /^( {0,3}#####\s+)(.*?)((?:\s+#+\s*)?)$/,
- replacement: "$2"
- }
- },
- h6: {
- type: "line",
- className: "TMH6",
- set: {
- pattern: /^( {0,3}(?:(?:#+|[0-9]{1,9}[).]|[>\-*+])\s+)?)(.*)$/,
- replacement: "###### $2"
- },
- unset: {
- pattern: /^( {0,3}######\s+)(.*?)((?:\s+#+\s*)?)$/,
- replacement: "$2"
- }
- },
- ul: {
- type: "line",
- className: "TMUL",
- set: {
- pattern: /^( {0,3}(?:(?:#+|[0-9]{1,9}[).]|[>\-*+])\s+)?)(.*)$/,
- replacement: "- $2"
- },
- unset: {
- pattern: /^( {0,3}[+*-] {1,4})(.*)$/,
- replacement: "$2"
- }
- },
- ol: {
- type: "line",
- className: "TMOL",
- set: {
- pattern: /^( {0,3}(?:(?:#+|[0-9]{1,9}[).]|[>\-*+])\s+)?)(.*)$/,
- replacement: "$#. $2"
- },
- unset: {
- pattern: /^( {0,3}\d{1,9}[.)] {1,4})(.*)$/,
- replacement: "$2"
- }
- },
- blockquote: {
- type: "line",
- className: "TMBlockquote",
- set: {
- pattern: /^( {0,3}(?:(?:#+|[0-9]{1,9}[).]|[>\-*+])\s+)?)(.*)$/,
- replacement: "> $2"
- },
- unset: {
- pattern: /^( {0,3}>[ ]?)(.*)$/,
- replacement: "$2"
- }
- }
- };
- }
- });
-
- // node_modules/tiny-markdown-editor/lib/TinyMDE.js
- var require_TinyMDE = __commonJS({
- "node_modules/tiny-markdown-editor/lib/TinyMDE.js"(exports) {
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = void 0;
- var _grammar = require_grammar();
- var Editor = class {
- constructor() {
- let props = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
- this.e = null;
- this.textarea = null;
- this.lines = [];
- this.lineElements = [];
- this.lineTypes = [];
- this.lineCaptures = [];
- this.lineReplacements = [];
- this.linkLabels = [];
- this.lineDirty = [];
- this.lastCommandState = null;
- this.listeners = {
- change: [],
- selection: []
- };
- let element = props.element;
- this.textarea = props.textarea;
- if (this.textarea && !this.textarea.tagName) {
- this.textarea = document.getElementById(this.textarea);
- if (!element)
- element = this.textarea;
- }
- if (element && !element.tagName) {
- element = document.getElementById(props.element);
- }
- if (!element) {
- element = document.getElementsByTagName("body")[0];
- }
- if (element.tagName == "TEXTAREA") {
- this.textarea = element;
- element = this.textarea.parentNode;
- }
- if (this.textarea) {
- this.textarea.style.display = "none";
- }
- this.createEditorElement(element);
- this.setContent(props.content || (this.textarea ? this.textarea.value : false) || "# Hello TinyMDE!\nEdit **here**");
- }
- /**
- * Creates the editor element inside the target element of the DOM tree
- * @param element The target element of the DOM tree
- */
- createEditorElement(element) {
- this.e = document.createElement("div");
- this.e.className = "TinyMDE";
- this.e.contentEditable = true;
- this.e.style.whiteSpace = "pre-wrap";
- this.e.style.webkitUserModify = "read-write-plaintext-only";
- if (this.textarea && this.textarea.parentNode == element && this.textarea.nextSibling) {
- element.insertBefore(this.e, this.textarea.nextSibling);
- } else {
- element.appendChild(this.e);
- }
- this.e.addEventListener("input", (e) => this.handleInputEvent(e));
- document.addEventListener("selectionchange", (e) => this.handleSelectionChangeEvent(e));
- this.e.addEventListener("paste", (e) => this.handlePaste(e));
- this.lineElements = this.e.childNodes;
- }
- /**
- * Sets the editor content.
- * @param {string} content The new Markdown content
- */
- setContent(content) {
- while (this.e.firstChild) {
- this.e.removeChild(this.e.firstChild);
- }
- this.lines = content.split(/(?:\r\n|\r|\n)/);
- this.lineDirty = [];
- for (let lineNum = 0; lineNum < this.lines.length; lineNum++) {
- let le = document.createElement("div");
- this.e.appendChild(le);
- this.lineDirty.push(true);
- }
- this.lineTypes = new Array(this.lines.length);
- this.updateFormatting();
- this.fireChange();
- }
- /**
- * Gets the editor content as a Markdown string.
- * @returns {string} The editor content as a markdown string
- */
- getContent() {
- return this.lines.join("\n");
- }
- /**
- * This is the main method to update the formatting (from this.lines to HTML output)
- */
- updateFormatting() {
- this.updateLineTypes();
- this.updateLinkLabels();
- this.applyLineTypes();
- }
- /**
- * Updates this.linkLabels: For every link reference definition (line type TMLinkReferenceDefinition), we collect the label
- */
- updateLinkLabels() {
- this.linkLabels = [];
- for (let l = 0; l < this.lines.length; l++) {
- if (this.lineTypes[l] == "TMLinkReferenceDefinition") {
- this.linkLabels.push(this.lineCaptures[l][_grammar.lineGrammar.TMLinkReferenceDefinition.labelPlaceholder]);
- }
- }
- }
- /**
- * Helper function to replace placeholders from a RegExp capture. The replacement string can contain regular dollar placeholders (e.g., $1),
- * which are interpreted like in String.replace(), but also double dollar placeholders ($$1). In the case of double dollar placeholders,
- * Markdown inline grammar is applied on the content of the captured subgroup, i.e., $$1 processes inline Markdown grammar in the content of the
- * first captured subgroup, and replaces `$$1` with the result.
- *
- * @param {string} replacement The replacement string, including placeholders.
- * @param capture The result of a RegExp.exec() call
- * @returns The replacement string, with placeholders replaced from the capture result.
- */
- replace(replacement, capture) {
- return replacement.replace(/(\${1,2})([0-9])/g, (str, p1, p2) => {
- if (p1 == "$")
- return (0, _grammar.htmlescape)(capture[p2]);
- else
- return `${this.processInlineStyles(capture[p2])}`;
- });
- }
- /**
- * Applies the line types (from this.lineTypes as well as the capture result in this.lineReplacements and this.lineCaptures)
- * and processes inline formatting for all lines.
- */
- applyLineTypes() {
- for (let lineNum = 0; lineNum < this.lines.length; lineNum++) {
- if (this.lineDirty[lineNum]) {
- let contentHTML = this.replace(this.lineReplacements[lineNum], this.lineCaptures[lineNum]);
- this.lineElements[lineNum].className = this.lineTypes[lineNum];
- this.lineElements[lineNum].removeAttribute("style");
- this.lineElements[lineNum].innerHTML = contentHTML == "" ? "
" : contentHTML;
- }
- this.lineElements[lineNum].dataset.lineNum = lineNum;
- }
- }
- /**
- * Determines line types for all lines based on the line / block grammar. Captures the results of the respective line
- * grammar regular expressions.
- * Updates this.lineTypes, this.lineCaptures, and this.lineReplacements.
- */
- updateLineTypes() {
- let codeBlockType = false;
- let codeBlockSeqLength = 0;
- let htmlBlock = false;
- for (let lineNum = 0; lineNum < this.lines.length; lineNum++) {
- let lineType = "TMPara";
- let lineCapture = [this.lines[lineNum]];
- let lineReplacement = "$$0";
- if (codeBlockType == "TMCodeFenceBacktickOpen") {
- let capture = _grammar.lineGrammar.TMCodeFenceBacktickClose.regexp.exec(this.lines[lineNum]);
- if (capture && capture.groups["seq"].length >= codeBlockSeqLength) {
- lineType = "TMCodeFenceBacktickClose";
- lineReplacement = _grammar.lineGrammar.TMCodeFenceBacktickClose.replacement;
- lineCapture = capture;
- codeBlockType = false;
- } else {
- lineType = "TMFencedCodeBacktick";
- lineReplacement = "$0";
- lineCapture = [this.lines[lineNum]];
- }
- } else if (codeBlockType == "TMCodeFenceTildeOpen") {
- let capture = _grammar.lineGrammar.TMCodeFenceTildeClose.regexp.exec(this.lines[lineNum]);
- if (capture && capture.groups["seq"].length >= codeBlockSeqLength) {
- lineType = "TMCodeFenceTildeClose";
- lineReplacement = _grammar.lineGrammar.TMCodeFenceTildeClose.replacement;
- lineCapture = capture;
- codeBlockType = false;
- } else {
- lineType = "TMFencedCodeTilde";
- lineReplacement = "$0";
- lineCapture = [this.lines[lineNum]];
- }
- }
- if (lineType == "TMPara" && htmlBlock === false) {
- for (let htmlBlockType of _grammar.htmlBlockGrammar) {
- if (this.lines[lineNum].match(htmlBlockType.start)) {
- if (htmlBlockType.paraInterrupt || lineNum == 0 || !(this.lineTypes[lineNum - 1] == "TMPara" || this.lineTypes[lineNum - 1] == "TMUL" || this.lineTypes[lineNum - 1] == "TMOL" || this.lineTypes[lineNum - 1] == "TMBlockquote")) {
- htmlBlock = htmlBlockType;
- break;
- }
- }
- }
- }
- if (htmlBlock !== false) {
- lineType = "TMHTMLBlock";
- lineReplacement = "$0";
- lineCapture = [this.lines[lineNum]];
- if (htmlBlock.end) {
- if (this.lines[lineNum].match(htmlBlock.end)) {
- htmlBlock = false;
- }
- } else {
- if (lineNum == this.lines.length - 1 || this.lines[lineNum + 1].match(_grammar.lineGrammar.TMBlankLine.regexp)) {
- htmlBlock = false;
- }
- }
- }
- if (lineType == "TMPara") {
- for (let type in _grammar.lineGrammar) {
- if (_grammar.lineGrammar[type].regexp) {
- let capture = _grammar.lineGrammar[type].regexp.exec(this.lines[lineNum]);
- if (capture) {
- lineType = type;
- lineReplacement = _grammar.lineGrammar[type].replacement;
- lineCapture = capture;
- break;
- }
- }
- }
- }
- if (lineType == "TMCodeFenceBacktickOpen" || lineType == "TMCodeFenceTildeOpen") {
- codeBlockType = lineType;
- codeBlockSeqLength = lineCapture.groups["seq"].length;
- }
- if ((lineType == "TMIndentedCode" || lineType == "TMLinkReferenceDefinition") && lineNum > 0 && (this.lineTypes[lineNum - 1] == "TMPara" || this.lineTypes[lineNum - 1] == "TMUL" || this.lineTypes[lineNum - 1] == "TMOL" || this.lineTypes[lineNum - 1] == "TMBlockquote")) {
- lineType = "TMPara";
- lineCapture = [this.lines[lineNum]];
- lineReplacement = "$$0";
- }
- if (lineType == "TMSetextH2Marker") {
- let capture = _grammar.lineGrammar.TMUL.regexp.exec(this.lines[lineNum]);
- if (capture) {
- lineType = "TMUL";
- lineReplacement = _grammar.lineGrammar.TMUL.replacement;
- lineCapture = capture;
- }
- }
- if (lineType == "TMSetextH1Marker" || lineType == "TMSetextH2Marker") {
- if (lineNum == 0 || this.lineTypes[lineNum - 1] != "TMPara") {
- let capture = _grammar.lineGrammar.TMHR.regexp.exec(this.lines[lineNum]);
- if (capture) {
- lineType = "TMHR";
- lineCapture = capture;
- lineReplacement = _grammar.lineGrammar.TMHR.replacement;
- } else {
- lineType = "TMPara";
- lineCapture = [this.lines[lineNum]];
- lineReplacement = "$$0";
- }
- } else {
- let headingLine = lineNum - 1;
- const headingLineType = lineType == "TMSetextH1Marker" ? "TMSetextH1" : "TMSetextH2";
- do {
- if (this.lineTypes[headingLineType] != headingLineType) {
- this.lineTypes[headingLine] = headingLineType;
- this.lineDirty[headingLineType] = true;
- }
- this.lineReplacements[headingLine] = "$$0";
- this.lineCaptures[headingLine] = [this.lines[headingLine]];
- headingLine--;
- } while (headingLine >= 0 && this.lineTypes[headingLine] == "TMPara");
- }
- }
- if (this.lineTypes[lineNum] != lineType) {
- this.lineTypes[lineNum] = lineType;
- this.lineDirty[lineNum] = true;
- }
- this.lineReplacements[lineNum] = lineReplacement;
- this.lineCaptures[lineNum] = lineCapture;
- }
- }
- /**
- * Updates all line contents from the HTML, then re-applies formatting.
- */
- updateLineContentsAndFormatting() {
- this.clearDirtyFlag();
- this.updateLineContents();
- this.updateFormatting();
- }
- /**
- * Attempts to parse a link or image at the current position. This assumes that the opening [ or ![ has already been matched.
- * Returns false if this is not a valid link, image. See below for more information
- * @param {string} originalString The original string, starting at the opening marker ([ or ![)
- * @param {boolean} isImage Whether or not this is an image (opener == ![)
- * @returns false if not a valid link / image.
- * Otherwise returns an object with two properties: output is the string to be included in the processed output,
- * charCount is the number of input characters (from originalString) consumed.
- */
- parseLinkOrImage(originalString, isImage) {
- let textOffset = isImage ? 2 : 1;
- let opener = originalString.substr(0, textOffset);
- let type = isImage ? "TMImage" : "TMLink";
- let currentOffset = textOffset;
- let bracketLevel = 1;
- let linkText = false;
- let linkRef = false;
- let linkLabel = [];
- let linkDetails = [];
- textOuter:
- while (currentOffset < originalString.length && linkText === false) {
- let string = originalString.substr(currentOffset);
- for (let rule of ["escape", "code", "autolink", "html"]) {
- let cap = _grammar.inlineGrammar[rule].regexp.exec(string);
- if (cap) {
- currentOffset += cap[0].length;
- continue textOuter;
- }
- }
- if (string.match(_grammar.inlineGrammar.imageOpen.regexp)) {
- bracketLevel++;
- currentOffset += 2;
- continue textOuter;
- }
- if (string.match(_grammar.inlineGrammar.linkOpen.regexp)) {
- bracketLevel++;
- if (!isImage) {
- if (this.parseLinkOrImage(string, false)) {
- return false;
- }
- }
- currentOffset += 1;
- continue textOuter;
- }
- if (string.match(/^\]/)) {
- bracketLevel--;
- if (bracketLevel == 0) {
- linkText = originalString.substr(textOffset, currentOffset - textOffset);
- currentOffset++;
- continue textOuter;
- }
- }
- currentOffset++;
- }
- if (linkText === false)
- return false;
- let nextChar = currentOffset < originalString.length ? originalString.substr(currentOffset, 1) : "";
- if (nextChar == "[") {
- let string = originalString.substr(currentOffset);
- let cap = _grammar.inlineGrammar.linkLabel.regexp.exec(string);
- if (cap) {
- currentOffset += cap[0].length;
- linkLabel.push(cap[1], cap[2], cap[3]);
- if (cap[_grammar.inlineGrammar.linkLabel.labelPlaceholder]) {
- linkRef = cap[_grammar.inlineGrammar.linkLabel.labelPlaceholder];
- } else {
- linkRef = linkText.trim();
- }
- } else {
- return false;
- }
- } else if (nextChar != "(") {
- linkRef = linkText.trim();
- } else {
- currentOffset++;
- let parenthesisLevel = 1;
- inlineOuter:
- while (currentOffset < originalString.length && parenthesisLevel > 0) {
- let string = originalString.substr(currentOffset);
- let cap = /^\s+/.exec(string);
- if (cap) {
- switch (linkDetails.length) {
- case 0:
- linkDetails.push(cap[0]);
- break;
- case 1:
- linkDetails.push(cap[0]);
- break;
- case 2:
- if (linkDetails[0].match(/)) {
- linkDetails[1] = linkDetails[1].concat(cap[0]);
- } else {
- if (parenthesisLevel != 1)
- return false;
- linkDetails.push("");
- linkDetails.push(cap[0]);
- }
- break;
- case 3:
- linkDetails.push(cap[0]);
- break;
- case 4:
- return false;
- case 5:
- linkDetails.push("");
- case 6:
- linkDetails[5] = linkDetails[5].concat(cap[0]);
- break;
- case 7:
- linkDetails[6] = linkDetails[6].concat(cap[0]);
- break;
- default:
- return false;
- }
- currentOffset += cap[0].length;
- continue inlineOuter;
- }
- cap = _grammar.inlineGrammar.escape.regexp.exec(string);
- if (cap) {
- switch (linkDetails.length) {
- case 0:
- linkDetails.push("");
- case 1:
- linkDetails.push(cap[0]);
- break;
- case 2:
- linkDetails[1] = linkDetails[1].concat(cap[0]);
- break;
- case 3:
- return false;
- case 4:
- return false;
- case 5:
- linkDetails.push("");
- case 6:
- linkDetails[5] = linkDetails[5].concat(cap[0]);
- break;
- default:
- return false;
- }
- currentOffset += cap[0].length;
- continue inlineOuter;
- }
- if (linkDetails.length < 2 && string.match(/^)) {
- if (linkDetails.length == 0)
- linkDetails.push("");
- linkDetails[0] = linkDetails[0].concat("<");
- currentOffset++;
- continue inlineOuter;
- }
- if ((linkDetails.length == 1 || linkDetails.length == 2) && string.match(/^>/)) {
- if (linkDetails.length == 1)
- linkDetails.push("");
- linkDetails.push(">");
- currentOffset++;
- continue inlineOuter;
- }
- cap = /^["']/.exec(string);
- if (cap && (linkDetails.length == 0 || linkDetails.length == 1 || linkDetails.length == 4)) {
- while (linkDetails.length < 4)
- linkDetails.push("");
- linkDetails.push(cap[0]);
- currentOffset++;
- continue inlineOuter;
- }
- if (cap && (linkDetails.length == 5 || linkDetails.length == 6) && linkDetails[4] == cap[0]) {
- if (linkDetails.length == 5)
- linkDetails.push("");
- linkDetails.push(cap[0]);
- currentOffset++;
- continue inlineOuter;
- }
- if (string.match(/^\(/)) {
- switch (linkDetails.length) {
- case 0:
- linkDetails.push("");
- case 1:
- linkDetails.push("");
- case 2:
- linkDetails[1] = linkDetails[1].concat("(");
- if (!linkDetails[0].match(/<$/))
- parenthesisLevel++;
- break;
- case 3:
- linkDetails.push("");
- case 4:
- linkDetails.push("(");
- break;
- case 5:
- linkDetails.push("");
- case 6:
- if (linkDetails[4] == "(")
- return false;
- linkDetails[5] = linkDetails[5].concat("(");
- break;
- default:
- return false;
- }
- currentOffset++;
- continue inlineOuter;
- }
- if (string.match(/^\)/)) {
- if (linkDetails.length <= 2) {
- while (linkDetails.length < 2)
- linkDetails.push("");
- if (!linkDetails[0].match(/<$/))
- parenthesisLevel--;
- if (parenthesisLevel > 0) {
- linkDetails[1] = linkDetails[1].concat(")");
- }
- } else if (linkDetails.length == 5 || linkDetails.length == 6) {
- if (linkDetails[4] == "(") {
- if (linkDetails.length == 5)
- linkDetails.push("");
- linkDetails.push(")");
- } else {
- if (linkDetails.length == 5)
- linkDetails.push(")");
- else
- linkDetails[5] = linkDetails[5].concat(")");
- }
- } else {
- parenthesisLevel--;
- }
- if (parenthesisLevel == 0) {
- while (linkDetails.length < 7)
- linkDetails.push("");
- }
- currentOffset++;
- continue inlineOuter;
- }
- cap = /^./.exec(string);
- if (cap) {
- switch (linkDetails.length) {
- case 0:
- linkDetails.push("");
- case 1:
- linkDetails.push(cap[0]);
- break;
- case 2:
- linkDetails[1] = linkDetails[1].concat(cap[0]);
- break;
- case 3:
- return false;
- case 4:
- return false;
- case 5:
- linkDetails.push("");
- case 6:
- linkDetails[5] = linkDetails[5].concat(cap[0]);
- break;
- default:
- return false;
- }
- currentOffset += cap[0].length;
- continue inlineOuter;
- }
- throw "Infinite loop";
- }
- if (parenthesisLevel > 0)
- return false;
- }
- if (linkRef !== false) {
- let valid = false;
- for (let label2 of this.linkLabels) {
- if (label2 == linkRef) {
- valid = true;
- break;
- }
- }
- let label = valid ? "TMLinkLabel TMLinkLabel_Valid" : "TMLinkLabel TMLinkLabel_Invalid";
- let output = `${opener}${this.processInlineStyles(linkText)}]`;
- if (linkLabel.length >= 3) {
- output = output.concat(`${linkLabel[0]}`, `${linkLabel[1]}`, `${linkLabel[2]}`);
- }
- return {
- output,
- charCount: currentOffset
- };
- } else if (linkDetails) {
- while (linkDetails.length < 7) {
- linkDetails.push("");
- }
- return {
- output: `${opener}${this.processInlineStyles(linkText)}](${linkDetails[0]}${linkDetails[1]}${linkDetails[2]}${linkDetails[3]}${linkDetails[4]}${linkDetails[5]}${linkDetails[6]})`,
- charCount: currentOffset
- };
- }
- return false;
- }
- /**
- * Formats a markdown string as HTML, using Markdown inline formatting.
- * @param {string} originalString The input (markdown inline formatted) string
- * @returns {string} The HTML formatted output
- */
- processInlineStyles(originalString) {
- let processed = "";
- let stack = [];
- let offset = 0;
- let string = originalString;
- outer:
- while (string) {
- for (let rule of ["escape", "code", "autolink", "html"]) {
- let cap2 = _grammar.inlineGrammar[rule].regexp.exec(string);
- if (cap2) {
- string = string.substr(cap2[0].length);
- offset += cap2[0].length;
- processed += _grammar.inlineGrammar[rule].replacement.replace(/\$([1-9])/g, (str, p1) => (0, _grammar.htmlescape)(cap2[p1]));
- continue outer;
- }
- }
- let potentialLink = string.match(_grammar.inlineGrammar.linkOpen.regexp);
- let potentialImage = string.match(_grammar.inlineGrammar.imageOpen.regexp);
- if (potentialImage || potentialLink) {
- let result = this.parseLinkOrImage(string, potentialImage);
- if (result) {
- processed = `${processed}${result.output}`;
- string = string.substr(result.charCount);
- offset += result.charCount;
- continue outer;
- }
- }
- let cap = /(^\*+)|(^_+)/.exec(string);
- if (cap) {
- let delimCount = cap[0].length;
- const delimString = cap[0];
- const currentDelimiter = cap[0][0];
- string = string.substr(cap[0].length);
- const preceding = offset > 0 ? originalString.substr(0, offset) : " ";
- const following = offset + cap[0].length < originalString.length ? string : " ";
- const punctuationFollows = following.match(_grammar.punctuationLeading);
- const punctuationPrecedes = preceding.match(_grammar.punctuationTrailing);
- const whitespaceFollows = following.match(/^\s/);
- const whitespacePrecedes = preceding.match(/\s$/);
- let canOpen = !whitespaceFollows && (!punctuationFollows || !!whitespacePrecedes || !!punctuationPrecedes);
- let canClose = !whitespacePrecedes && (!punctuationPrecedes || !!whitespaceFollows || !!punctuationFollows);
- if (currentDelimiter == "_" && canOpen && canClose) {
- canOpen = punctuationPrecedes;
- canClose = punctuationFollows;
- }
- if (canClose) {
- let stackPointer = stack.length - 1;
- while (delimCount && stackPointer >= 0) {
- if (stack[stackPointer].delimiter == currentDelimiter) {
- while (stackPointer < stack.length - 1) {
- const entry = stack.pop();
- processed = `${entry.output}${entry.delimString.substr(0, entry.count)}${processed}`;
- }
- if (delimCount >= 2 && stack[stackPointer].count >= 2) {
- processed = `${currentDelimiter}${currentDelimiter}${processed}${currentDelimiter}${currentDelimiter}`;
- delimCount -= 2;
- stack[stackPointer].count -= 2;
- } else {
- processed = `${currentDelimiter}${processed}${currentDelimiter}`;
- delimCount -= 1;
- stack[stackPointer].count -= 1;
- }
- if (stack[stackPointer].count == 0) {
- let entry = stack.pop();
- processed = `${entry.output}${processed}`;
- stackPointer--;
- }
- } else {
- stackPointer--;
- }
- }
- }
- if (delimCount && canOpen) {
- stack.push({
- delimiter: currentDelimiter,
- delimString,
- count: delimCount,
- output: processed
- });
- processed = "";
- delimCount = 0;
- }
- if (delimCount) {
- processed = `${processed}${delimString.substr(0, delimCount)}`;
- }
- offset += cap[0].length;
- continue outer;
- }
- cap = /^~~/.exec(string);
- if (cap) {
- let consumed = false;
- let stackPointer = stack.length - 1;
- while (!consumed && stackPointer >= 0) {
- if (stack[stackPointer].delimiter == "~") {
- while (stackPointer < stack.length - 1) {
- const entry2 = stack.pop();
- processed = `${entry2.output}${entry2.delimString.substr(0, entry2.count)}${processed}`;
- }
- processed = `~~${processed}~~`;
- let entry = stack.pop();
- processed = `${entry.output}${processed}`;
- consumed = true;
- } else {
- stackPointer--;
- }
- }
- if (!consumed) {
- stack.push({
- delimiter: "~",
- delimString: "~~",
- count: 2,
- output: processed
- });
- processed = "";
- }
- offset += cap[0].length;
- string = string.substr(cap[0].length);
- continue outer;
- }
- cap = _grammar.inlineGrammar.default.regexp.exec(string);
- if (cap) {
- string = string.substr(cap[0].length);
- offset += cap[0].length;
- processed += _grammar.inlineGrammar.default.replacement.replace(/\$([1-9])/g, (str, p1) => (0, _grammar.htmlescape)(cap[p1]));
- continue outer;
- }
- throw "Infinite loop!";
- }
- while (stack.length) {
- const entry = stack.pop();
- processed = `${entry.output}${entry.delimString.substr(0, entry.count)}${processed}`;
- }
- return processed;
- }
- /**
- * Clears the line dirty flag (resets it to an array of false)
- */
- clearDirtyFlag() {
- this.lineDirty = new Array(this.lines.length);
- for (let i = 0; i < this.lineDirty.length; i++) {
- this.lineDirty[i] = false;
- }
- }
- /**
- * Updates the class properties (lines, lineElements) from the DOM.
- * @returns true if contents changed
- */
- updateLineContents() {
- let lineDelta = this.e.childElementCount - this.lines.length;
- if (lineDelta) {
- let firstChangedLine = 0;
- while (firstChangedLine <= this.lines.length && firstChangedLine <= this.lineElements.length && this.lineElements[firstChangedLine] && this.lines[firstChangedLine] == this.lineElements[firstChangedLine].textContent) {
- firstChangedLine++;
- }
- let lastChangedLine = -1;
- while (-lastChangedLine < this.lines.length && -lastChangedLine < this.lineElements.length && this.lines[this.lines.length + lastChangedLine] == this.lineElements[this.lineElements.length + lastChangedLine].textContent) {
- lastChangedLine--;
- }
- let linesToDelete = this.lines.length + lastChangedLine + 1 - firstChangedLine;
- if (linesToDelete < -lineDelta)
- linesToDelete = -lineDelta;
- if (linesToDelete < 0)
- linesToDelete = 0;
- let linesToAdd = [];
- for (let l = 0; l < linesToDelete + lineDelta; l++) {
- linesToAdd.push(this.lineElements[firstChangedLine + l].textContent);
- }
- this.spliceLines(firstChangedLine, linesToDelete, linesToAdd, false);
- } else {
- for (let line = 0; line < this.lineElements.length; line++) {
- let e = this.lineElements[line];
- let ct = e.textContent;
- if (this.lines[line] !== ct) {
- this.lines[line] = ct;
- this.lineDirty[line] = true;
- }
- }
- }
- }
- /**
- * Processes a new paragraph.
- * @param sel The current selection
- */
- processNewParagraph(sel) {
- if (!sel)
- return;
- this.updateLineContents();
- let continuableType = false;
- let checkLine = sel.col > 0 ? sel.row : sel.row - 1;
- switch (this.lineTypes[checkLine]) {
- case "TMUL":
- continuableType = "TMUL";
- break;
- case "TMOL":
- continuableType = "TMOL";
- break;
- case "TMIndentedCode":
- continuableType = "TMIndentedCode";
- break;
- }
- let lines = this.lines[sel.row].replace(/\n\n$/, "\n").split(/(?:\r\n|\n|\r)/);
- if (lines.length == 1) {
- this.updateFormatting();
- return;
- }
- this.spliceLines(sel.row, 1, lines, true);
- sel.row++;
- sel.col = 0;
- if (continuableType) {
- let capture = _grammar.lineGrammar[continuableType].regexp.exec(this.lines[sel.row - 1]);
- if (capture) {
- if (capture[2]) {
- if (continuableType == "TMOL") {
- capture[1] = capture[1].replace(/\d{1,9}/, (result) => {
- return parseInt(result[0]) + 1;
- });
- }
- this.lines[sel.row] = `${capture[1]}${this.lines[sel.row]}`;
- this.lineDirty[sel.row] = true;
- sel.col = capture[1].length;
- } else {
- this.lines[sel.row - 1] = "";
- this.lineDirty[sel.row - 1] = true;
- }
- }
- }
- this.updateFormatting();
- }
- // /**
- // * Processes a "delete" input action.
- // * @param {object} focus The selection
- // * @param {boolean} forward If true, performs a forward delete, otherwise performs a backward delete
- // */
- // processDelete(focus, forward) {
- // if (!focus) return;
- // let anchor = this.getSelection(true);
- // // Do we have a non-empty selection?
- // if (focus.col != anchor.col || focus.row != anchor.row) {
- // // non-empty. direction doesn't matter.
- // this.paste('', anchor, focus);
- // } else {
- // if (forward) {
- // if (focus.col < this.lines[focus.row].length) this.paste('', {row: focus.row, col: focus.col + 1}, focus);
- // else if (focus.col < this.lines.length) this.paste('', {row: focus.row + 1, col: 0}, focus);
- // // Otherwise, we're at the very end and can't delete forward
- // } else {
- // if (focus.col > 0) this.paste('', {row: focus.row, col: focus.col - 1}, focus);
- // else if (focus.row > 0) this.paste('', {row: focus.row - 1, col: this.lines[focus.row - 1].length - 1}, focus);
- // // Otherwise, we're at the very beginning and can't delete backwards
- // }
- // }
- // }
- /**
- * Gets the current position of the selection counted by row and column of the editor Markdown content (as opposed to the position in the DOM).
- *
- * @param {boolean} getAnchor if set to true, gets the selection anchor (start point of the selection), otherwise gets the focus (end point).
- * @return {object} An object representing the selection, with properties col and row.
- */
- getSelection() {
- let getAnchor = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : false;
- const selection = window.getSelection();
- let startNode = getAnchor ? selection.anchorNode : selection.focusNode;
- if (!startNode)
- return null;
- let offset = startNode.nodeType === Node.TEXT_NODE ? getAnchor ? selection.anchorOffset : selection.focusOffset : 0;
- if (startNode == this.e) {
- return {
- row: 0,
- col: offset
- };
- }
- let col = this.computeColumn(startNode, offset);
- if (col === null)
- return null;
- let node = startNode;
- while (node.parentElement != this.e) {
- node = node.parentElement;
- }
- let row = 0;
- if (node.dataset && node.dataset.lineNum && (!node.previousSibling || node.previousSibling.dataset.lineNum != node.dataset.lineNum)) {
- row = parseInt(node.dataset.lineNum);
- } else {
- while (node.previousSibling) {
- row++;
- node = node.previousSibling;
- }
- }
- return {
- row,
- col,
- node: startNode
- };
- }
- /**
- * Computes a column within an editor line from a node and offset within that node.
- * @param {Node} startNode The node
- * @param {int} offset THe selection
- * @returns {int} the column, or null if the node is not inside the editor
- */
- computeColumn(startNode, offset) {
- let node = startNode;
- let col = offset;
- while (node && node.parentNode != this.e) {
- node = node.parentNode;
- }
- if (node == null)
- return null;
- node = startNode;
- while (node.parentNode != this.e) {
- if (node.previousSibling) {
- node = node.previousSibling;
- col += node.textContent.length;
- } else {
- node = node.parentNode;
- }
- }
- return col;
- }
- /**
- * Computes DOM node and offset within that node from a position expressed as row and column.
- * @param {int} row Row (line number)
- * @param {int} col Column
- * @returns An object with two properties: node and offset. offset may be null;
- */
- computeNodeAndOffset(row, col) {
- let bindRight = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : false;
- if (row >= this.lineElements.length) {
- row = this.lineElements.length - 1;
- col = this.lines[row].length;
- }
- if (col > this.lines[row].length) {
- col = this.lines[row].length;
- }
- const parentNode = this.lineElements[row];
- let node = parentNode.firstChild;
- let childrenComplete = false;
- let rv = {
- node: parentNode.firstChild ? parentNode.firstChild : parentNode,
- offset: 0
- };
- while (node != parentNode) {
- if (!childrenComplete && node.nodeType === Node.TEXT_NODE) {
- if (node.nodeValue.length >= col) {
- if (bindRight && node.nodeValue.length == col) {
- rv = {
- node,
- offset: col
- };
- col = 0;
- } else {
- return {
- node,
- offset: col
- };
- }
- } else {
- col -= node.nodeValue.length;
- }
- }
- if (!childrenComplete && node.firstChild) {
- node = node.firstChild;
- } else if (node.nextSibling) {
- childrenComplete = false;
- node = node.nextSibling;
- } else {
- childrenComplete = true;
- node = node.parentNode;
- }
- }
- return rv;
- }
- /**
- * Sets the selection based on rows and columns within the editor Markdown content.
- * @param {object} focus Object representing the selection, needs to have properties row and col.
- */
- setSelection(focus) {
- let anchor = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : null;
- if (!focus)
- return;
- let range = document.createRange();
- let {
- node: focusNode,
- offset: focusOffset
- } = this.computeNodeAndOffset(focus.row, focus.col, anchor && anchor.row == focus.row && anchor.col > focus.col);
- let anchorNode = null, anchorOffset = null;
- if (anchor && (anchor.row != focus.row || anchor.col != focus.col)) {
- let {
- node,
- offset
- } = this.computeNodeAndOffset(anchor.row, anchor.col, focus.row == anchor.row && focus.col > anchor.col);
- anchorNode = node;
- anchorOffset = offset;
- }
- if (anchorNode)
- range.setStart(anchorNode, anchorOffset);
- else
- range.setStart(focusNode, focusOffset);
- range.setEnd(focusNode, focusOffset);
- let windowSelection = window.getSelection();
- windowSelection.removeAllRanges();
- windowSelection.addRange(range);
- }
- /**
- * Event handler for input events
- */
- handleInputEvent(event) {
- let focus = this.getSelection();
- if ((event.inputType == "insertParagraph" || event.inputType == "insertLineBreak") && focus) {
- this.clearDirtyFlag();
- this.processNewParagraph(focus);
- } else {
- if (!this.e.firstChild) {
- this.e.innerHTML = '
';
- } else {
- for (let childNode = this.e.firstChild; childNode; childNode = childNode.nextSibling) {
- if (childNode.nodeType != 3 || childNode.tagName != "DIV") {
- let divWrapper = document.createElement("div");
- this.e.insertBefore(divWrapper, childNode);
- this.e.removeChild(childNode);
- divWrapper.appendChild(childNode);
- }
- }
- }
- this.updateLineContentsAndFormatting();
- }
- if (focus)
- this.setSelection(focus);
- this.fireChange();
- }
- /**
- * Event handler for "selectionchange" events.
- */
- handleSelectionChangeEvent() {
- this.fireSelection();
- }
- /**
- * Convenience function to "splice" new lines into the arrays this.lines, this.lineDirty, this.lineTypes, and the DOM elements
- * underneath the editor element.
- * This method is essentially Array.splice, only that the third parameter takes an un-spread array (and the forth parameter)
- * determines whether the DOM should also be adjusted.
- *
- * @param {int} startLine Position at which to start changing the array of lines
- * @param {int} linesToDelete Number of lines to delete
- * @param {array} linesToInsert Array of strings representing the lines to be inserted
- * @param {boolean} adjustLineElements If true, then elements are also inserted in the DOM at the respective position
- */
- spliceLines(startLine) {
- let linesToDelete = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : 0;
- let linesToInsert = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : [];
- let adjustLineElements = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : true;
- if (adjustLineElements) {
- for (let i = 0; i < linesToDelete; i++) {
- this.e.removeChild(this.e.childNodes[startLine]);
- }
- }
- let insertedBlank = [];
- let insertedDirty = [];
- for (let i = 0; i < linesToInsert.length; i++) {
- insertedBlank.push("");
- insertedDirty.push(true);
- if (adjustLineElements) {
- if (this.e.childNodes[startLine])
- this.e.insertBefore(document.createElement("div"), this.e.childNodes[startLine]);
- else
- this.e.appendChild(document.createElement("div"));
- }
- }
- this.lines.splice(startLine, linesToDelete, ...linesToInsert);
- this.lineTypes.splice(startLine, linesToDelete, ...insertedBlank);
- this.lineDirty.splice(startLine, linesToDelete, ...insertedDirty);
- }
- /**
- * Event handler for the "paste" event
- */
- handlePaste(event) {
- event.preventDefault();
- let text = (event.originalEvent || event).clipboardData.getData("text/plain");
- this.paste(text);
- }
- /**
- * Pastes the text at the current selection (or at the end, if no current selection)
- * @param {string} text
- */
- paste(text) {
- let anchor = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : null;
- let focus = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : null;
- if (!anchor)
- anchor = this.getSelection(true);
- if (!focus)
- focus = this.getSelection(false);
- let beginning, end;
- if (!focus) {
- focus = {
- row: this.lines.length - 1,
- col: this.lines[this.lines.length - 1].length
- };
- }
- if (!anchor) {
- anchor = focus;
- }
- if (anchor.row < focus.row || anchor.row == focus.row && anchor.col <= focus.col) {
- beginning = anchor;
- end = focus;
- } else {
- beginning = focus;
- end = anchor;
- }
- let insertedLines = text.split(/(?:\r\n|\r|\n)/);
- let lineBefore = this.lines[beginning.row].substr(0, beginning.col);
- let lineEnd = this.lines[end.row].substr(end.col);
- insertedLines[0] = lineBefore.concat(insertedLines[0]);
- let endColPos = insertedLines[insertedLines.length - 1].length;
- insertedLines[insertedLines.length - 1] = insertedLines[insertedLines.length - 1].concat(lineEnd);
- this.spliceLines(beginning.row, 1 + end.row - beginning.row, insertedLines);
- focus.row = beginning.row + insertedLines.length - 1;
- focus.col = endColPos;
- this.updateFormatting();
- this.setSelection(focus);
- this.fireChange();
- }
- /**
- * Computes the (lowest in the DOM tree) common ancestor of two DOM nodes.
- * @param {Node} node1 the first node
- * @param {Node} node2 the second node
- * @returns {Node} The commen ancestor node, or null if there is no common ancestor
- */
- computeCommonAncestor(node1, node2) {
- if (!node1 || !node2)
- return null;
- if (node1 == node2)
- return node1;
- const ancestry = (node) => {
- let ancestry3 = [];
- while (node) {
- ancestry3.unshift(node);
- node = node.parentNode;
- }
- return ancestry3;
- };
- const ancestry1 = ancestry(node1);
- const ancestry2 = ancestry(node2);
- if (ancestry1[0] != ancestry2[0])
- return null;
- let i;
- for (i = 0; ancestry1[i] == ancestry2[i]; i++)
- ;
- return ancestry1[i - 1];
- }
- /**
- * Finds the (lowest in the DOM tree) enclosing DOM node with a given class.
- * @param {object} focus The focus selection object
- * @param {object} anchor The anchor selection object
- * @param {string} className The class name to find
- * @returns {Node} The enclosing DOM node with the respective class (inside the editor), if there is one; null otherwise.
- */
- computeEnclosingMarkupNode(focus, anchor, className) {
- let node = null;
- if (!focus)
- return null;
- if (!anchor) {
- node = focus.node;
- } else {
- if (focus.row != anchor.row)
- return null;
- node = this.computeCommonAncestor(focus.node, anchor.node);
- }
- if (!node)
- return null;
- while (node != this.e) {
- if (node.className && node.className.includes(className))
- return node;
- node = node.parentNode;
- }
- return null;
- }
- /**
- * Returns the state (true / false) of all commands.
- * @param focus Focus of the selection. If not given, assumes the current focus.
- */
- getCommandState() {
- let focus = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : null;
- let anchor = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : null;
- let commandState = {};
- if (!focus)
- focus = this.getSelection(false);
- if (!anchor)
- anchor = this.getSelection(true);
- if (!focus) {
- for (let cmd in _grammar.commands) {
- commandState[cmd] = null;
- }
- return commandState;
- }
- if (!anchor)
- anchor = focus;
- let start, end;
- if (anchor.row < focus.row || anchor.row == focus.row && anchor.col < focus.col) {
- start = anchor;
- end = focus;
- } else {
- start = focus;
- end = anchor;
- }
- if (end.row > start.row && end.col == 0) {
- end.row--;
- end.col = this.lines[end.row].length;
- }
- for (let cmd in _grammar.commands) {
- if (_grammar.commands[cmd].type == "inline") {
- if (!focus || focus.row != anchor.row || !this.isInlineFormattingAllowed(focus, anchor)) {
- commandState[cmd] = null;
- } else {
- commandState[cmd] = !!this.computeEnclosingMarkupNode(focus, anchor, _grammar.commands[cmd].className) || // ... or if it's an empty string preceded by and followed by formatting markers, e.g. **|** where | is the cursor
- focus.col == anchor.col && !!this.lines[focus.row].substr(0, focus.col).match(_grammar.commands[cmd].unset.prePattern) && !!this.lines[focus.row].substr(focus.col).match(_grammar.commands[cmd].unset.postPattern);
- }
- }
- if (_grammar.commands[cmd].type == "line") {
- if (!focus) {
- commandState[cmd] = null;
- } else {
- let state = this.lineTypes[start.row] == _grammar.commands[cmd].className;
- for (let line = start.row; line <= end.row; line++) {
- if (this.lineTypes[line] == _grammar.commands[cmd].className != state) {
- state = null;
- break;
- }
- }
- commandState[cmd] = state;
- }
- }
- }
- return commandState;
- }
- /**
- * Sets a command state
- * @param {string} command
- * @param {boolean} state
- */
- setCommandState(command, state) {
- if (_grammar.commands[command].type == "inline") {
- let anchor = this.getSelection(true);
- let focus = this.getSelection(false);
- if (!anchor)
- anchor = focus;
- if (!anchor)
- return;
- if (anchor.row != focus.row)
- return;
- if (!this.isInlineFormattingAllowed(focus, anchor))
- return;
- let markupNode = this.computeEnclosingMarkupNode(focus, anchor, _grammar.commands[command].className);
- this.clearDirtyFlag();
- if (markupNode) {
- this.lineDirty[focus.row] = true;
- const startCol = this.computeColumn(markupNode, 0);
- const len = markupNode.textContent.length;
- const left = this.lines[focus.row].substr(0, startCol).replace(_grammar.commands[command].unset.prePattern, "");
- const mid = this.lines[focus.row].substr(startCol, len);
- const right = this.lines[focus.row].substr(startCol + len).replace(_grammar.commands[command].unset.postPattern, "");
- this.lines[focus.row] = left.concat(mid, right);
- anchor.col = left.length;
- focus.col = anchor.col + len;
- this.updateFormatting();
- this.setSelection(focus, anchor);
- } else if (focus.col == anchor.col && !!this.lines[focus.row].substr(0, focus.col).match(_grammar.commands[command].unset.prePattern) && !!this.lines[focus.row].substr(focus.col).match(_grammar.commands[command].unset.postPattern)) {
- this.lineDirty[focus.row] = true;
- const left = this.lines[focus.row].substr(0, focus.col).replace(_grammar.commands[command].unset.prePattern, "");
- const right = this.lines[focus.row].substr(focus.col).replace(_grammar.commands[command].unset.postPattern, "");
- this.lines[focus.row] = left.concat(right);
- focus.col = anchor.col = left.length;
- this.updateFormatting();
- this.setSelection(focus, anchor);
- } else {
- let {
- startCol,
- endCol
- } = focus.col < anchor.col ? {
- startCol: focus.col,
- endCol: anchor.col
- } : {
- startCol: anchor.col,
- endCol: focus.col
- };
- let match = this.lines[focus.row].substr(startCol, endCol - startCol).match(/^(?\s*).*\S(?\s*)$/);
- if (match) {
- startCol += match.groups.leading.length;
- endCol -= match.groups.trailing.length;
- }
- focus.col = startCol;
- anchor.col = endCol;
- this.wrapSelection(_grammar.commands[command].set.pre, _grammar.commands[command].set.post, focus, anchor);
- }
- } else if (_grammar.commands[command].type == "line") {
- let anchor = this.getSelection(true);
- let focus = this.getSelection(false);
- if (!anchor)
- anchor = focus;
- if (!focus)
- return;
- this.clearDirtyFlag();
- let start = anchor.row > focus.row ? focus : anchor;
- let end = anchor.row > focus.row ? anchor : focus;
- if (end.row > start.row && end.col == 0) {
- end.row--;
- }
- for (let line = start.row; line <= end.row; line++) {
- if (state && this.lineTypes[line] != _grammar.commands[command].className) {
- this.lines[line] = this.lines[line].replace(_grammar.commands[command].set.pattern, _grammar.commands[command].set.replacement.replace("$#", line - start.row + 1));
- this.lineDirty[line] = true;
- }
- if (!state && this.lineTypes[line] == _grammar.commands[command].className) {
- this.lines[line] = this.lines[line].replace(_grammar.commands[command].unset.pattern, _grammar.commands[command].unset.replacement);
- this.lineDirty[line] = true;
- }
- }
- this.updateFormatting();
- this.setSelection({
- row: end.row,
- col: this.lines[end.row].length
- }, {
- row: start.row,
- col: 0
- });
- }
- }
- /**
- * Returns whether or not inline formatting is allowed at the current focus
- * @param {object} focus The current focus
- */
- isInlineFormattingAllowed() {
- const sel = window.getSelection();
- if (!sel)
- return false;
- if (sel.isCollapsed && sel.focusNode.nodeType == 3 && sel.focusOffset == sel.focusNode.nodeValue.length) {
- let node;
- for (node = sel.focusNode; node && node.nextSibling == null; node = node.parentNode)
- ;
- if (node && node.nextSibling.className && node.nextSibling.className.includes("TMInlineFormatted"))
- return true;
- }
- let ancestor = this.computeCommonAncestor(sel.focusNode, sel.anchorNode);
- if (!ancestor)
- return false;
- while (ancestor && ancestor != this.e) {
- if (ancestor.className && (ancestor.className.includes("TMInlineFormatted") || ancestor.className.includes("TMBlankLine")))
- return true;
- ancestor = ancestor.parentNode;
- }
- return false;
- }
- /**
- * Wraps the current selection in the strings pre and post. If the selection is not on one line, returns.
- * @param {string} pre The string to insert before the selection.
- * @param {string} post The string to insert after the selection.
- * @param {object} focus The current selection focus. If null, selection will be computed.
- * @param {object} anchor The current selection focus. If null, selection will be computed.
- */
- wrapSelection(pre, post) {
- let focus = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : null;
- let anchor = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : null;
- if (!focus)
- focus = this.getSelection(false);
- if (!anchor)
- anchor = this.getSelection(true);
- if (!focus || !anchor || focus.row != anchor.row)
- return;
- this.lineDirty[focus.row] = true;
- const startCol = focus.col < anchor.col ? focus.col : anchor.col;
- const endCol = focus.col < anchor.col ? anchor.col : focus.col;
- const left = this.lines[focus.row].substr(0, startCol).concat(pre);
- const mid = endCol == startCol ? "" : this.lines[focus.row].substr(startCol, endCol - startCol);
- const right = post.concat(this.lines[focus.row].substr(endCol));
- this.lines[focus.row] = left.concat(mid, right);
- anchor.col = left.length;
- focus.col = anchor.col + mid.length;
- this.updateFormatting();
- this.setSelection(focus, anchor);
- }
- /**
- * Toggles the command state for a command (true <-> false)
- * @param {string} command The editor command
- */
- toggleCommandState(command) {
- if (!this.lastCommandState)
- this.lastCommandState = this.getCommandState();
- this.setCommandState(command, !this.lastCommandState[command]);
- }
- /**
- * Fires a change event. Updates the linked textarea and notifies any event listeners.
- */
- fireChange() {
- if (!this.textarea && !this.listeners.change.length)
- return;
- const content = this.getContent();
- if (this.textarea)
- this.textarea.value = content;
- for (let listener of this.listeners.change) {
- listener({
- content,
- linesDirty: this.linesDirty
- });
- }
- }
- /**
- * Fires a "selection changed" event.
- */
- fireSelection() {
- if (this.listeners.selection && this.listeners.selection.length) {
- let focus = this.getSelection(false);
- let anchor = this.getSelection(true);
- let commandState = this.getCommandState(focus, anchor);
- if (this.lastCommandState) {
- Object.assign(this.lastCommandState, commandState);
- } else {
- this.lastCommandState = Object.assign({}, commandState);
- }
- for (let listener of this.listeners.selection) {
- listener({
- focus,
- anchor,
- commandState: this.lastCommandState
- });
- }
- }
- }
- /**
- * Adds an event listener.
- * @param {string} type The type of event to listen to. Can be 'change' or 'selection'
- * @param {*} listener Function of the type (event) => {} to be called when the event occurs.
- */
- addEventListener(type, listener) {
- if (type.match(/^(?:change|input)$/i)) {
- this.listeners.change.push(listener);
- }
- if (type.match(/^(?:selection|selectionchange)$/i)) {
- this.listeners.selection.push(listener);
- }
- }
- };
- var _default = exports.default = Editor;
- }
- });
-
- // node_modules/tiny-markdown-editor/lib/index.js
- var require_lib = __commonJS({
- "node_modules/tiny-markdown-editor/lib/index.js"(exports) {
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- Object.defineProperty(exports, "CommandBar", {
- enumerable: true,
- get: function() {
- return _TinyMDECommandBar.default;
- }
- });
- Object.defineProperty(exports, "Editor", {
- enumerable: true,
- get: function() {
- return _TinyMDE.default;
- }
- });
- var _TinyMDECommandBar = _interopRequireDefault(require_TinyMDECommandBar());
- var _TinyMDE = _interopRequireDefault(require_TinyMDE());
- function _interopRequireDefault(obj) {
- return obj && obj.__esModule ? obj : { default: obj };
- }
- }
- });
-
- // node_modules/@icelab/defo/dist/index.bundle.js
- var require_index_bundle = __commonJS({
- "node_modules/@icelab/defo/dist/index.bundle.js"(exports, module) {
- !function(e, t) {
- "object" == typeof exports && "undefined" != typeof module ? module.exports = t() : "function" == typeof define && define.amd ? define(t) : (e = e || self).Defo = t();
- }(exports, function() {
- "use strict";
- function e(e2, t2) {
- return function(e3, t3) {
- return Object.keys(e3.dataset).filter((e4) => 0 === e4.indexOf(t3));
- }(e2, t2).length > 0;
- }
- function t(e2) {
- return e2.charAt(0).toUpperCase() + e2.slice(1);
- }
- function r(e2) {
- try {
- return JSON.parse(e2);
- } catch (e3) {
- }
- return e2;
- }
- function o({ prefix: e2, scope: t2, views: r2 }) {
- Object.keys(r2).forEach((o2) => {
- const a2 = `data-${e2}-${s = o2, s.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase()}`;
- var s;
- let i = Array.prototype.slice.call(t2.querySelectorAll(`[${a2}]`));
- t2.hasAttribute(a2) && (i = [t2].concat(i)), i.forEach((t3) => {
- n(t3, e2, r2, o2);
- });
- });
- }
- function n(e2, o2, n2, a2) {
- if (e2._defoUpdate && e2._defoUpdate[a2])
- return;
- const s = n2[a2], i = function(e3, r2) {
- return `${o3 = e3, o3.replace(/^[_.\- ]+/, "").toLowerCase().replace(/[_.\- ]+(\w|$)/g, (e4, t2) => t2.toUpperCase()).replace(/\d+(\w|$)/g, (e4) => e4.toUpperCase())}${t(r2)}`;
- var o3;
- }(o2, a2);
- if (!s || !(i in e2.dataset))
- return;
- const c = s(e2, r(e2.dataset[i]));
- e2._defoUpdate = e2._defoUpdate || {}, e2._defoDestroy = e2._defoDestroy || {}, e2._defoUpdate[a2] = function(e3) {
- return function(t2, o3) {
- t2 = t2 ? r(t2) : t2, o3 = o3 ? r(o3) : o3, Promise.resolve(e3).then((e4) => {
- e4.update && e4.update(t2, o3);
- });
- };
- }(c), e2._defoDestroy[a2] = function(e3, t2, r2) {
- return function() {
- Promise.resolve(e3).then((e4) => {
- e4.destroy && (e4.destroy(), delete t2._defoUpdate[r2], delete t2._defoDestroy[r2]);
- });
- };
- }(c, e2, a2);
- }
- function a({ prefix: r2, scope: a2, views: s }) {
- const i = new MutationObserver((a3) => {
- a3.forEach((a4) => {
- const i2 = a4.target;
- if ("attributes" === a4.type && function(e2, t2) {
- return 0 === e2.indexOf(`data-${t2}-`);
- }(a4.attributeName, r2)) {
- const e2 = a4.attributeName.split("-").slice(2).map((e3, r3) => r3 > 0 ? t(e3) : e3).join("");
- i2.hasAttribute(a4.attributeName) ? null !== a4.oldValue ? i2._defoUpdate[e2](i2.getAttribute(a4.attributeName), a4.oldValue) : n(i2, r2, s, e2) : i2._defoDestroy[e2]();
- } else
- "childList" === a4.type && (Array.prototype.slice.call(a4.removedNodes).filter((e2) => e2.nodeType === e2.ELEMENT_NODE).filter((t2) => e(t2, r2)).forEach((e2) => {
- Object.keys(e2._defoDestroy).forEach((t2) => {
- e2._defoDestroy[t2]();
- });
- }), Array.prototype.slice.call(a4.addedNodes).filter((e2) => e2.nodeType === e2.ELEMENT_NODE).forEach((e2) => {
- Promise.resolve(e2).then((e3) => {
- o({ prefix: r2, scope: e3, views: s });
- });
- }));
- });
- });
- return i.observe(a2, { attributes: true, attributeOldValue: true, childList: true, characterData: false, subtree: true }), o({ prefix: r2, scope: a2, views: s }), i;
- }
- return function({ prefix: e2 = "defo", scope: t2 = document.documentElement, views: r2 = {} } = {}) {
- const o2 = a({ prefix: e2, scope: t2, views: r2 });
- return { destroy: () => {
- o2.disconnect();
- } };
- };
- });
- }
- });
-
// slices/admin/assets/js/app.js
- var import_tiny_markdown_editor = __toESM(require_lib(), 1);
- var import_defo = __toESM(require_index_bundle(), 1);
(function() {
document.addEventListener("alpine:init", () => {
Alpine.magic("clipboard", () => {
return (subject) => navigator.clipboard.writeText(subject);
});
});
- document.addEventListener("DOMContentLoaded", function() {
- const views = {
- markdown: (el, attrs) => {
- var tinyMDE = new import_tiny_markdown_editor.default.Editor({ textarea: attrs.editorId });
- return {
- update: (newName, oldName) => {
- },
- destroy: () => {
- }
- };
- }
- };
- (0, import_defo.default)({ views });
- });
})();
})();
diff --git a/slices/admin/assets/js/app.js b/slices/admin/assets/js/app.js
index 4afc554..2632e6f 100644
--- a/slices/admin/assets/js/app.js
+++ b/slices/admin/assets/js/app.js
@@ -1,29 +1,10 @@
import "../../../../slices/main/assets/builds/app.css";
import "../css/app.css";
-import TinyMDE from "tiny-markdown-editor";
-import defo from "@icelab/defo";
-
(function() {
document.addEventListener('alpine:init', () => {
Alpine.magic('clipboard', () => {
return subject => navigator.clipboard.writeText(subject)
})
})
-
- document.addEventListener("DOMContentLoaded", function () {
- const views = {
- markdown: (el, attrs) => {
-
- var tinyMDE = new TinyMDE.Editor({textarea: attrs.editorId});
-
- return {
- update: (newName, oldName) => {},
- destroy: () => {}
- };
- }
- };
-
- defo({views});
- });
})();
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index cfaeff3..5e86e5d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -303,11 +303,6 @@ commander@^4.0.0:
resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==
-core-js@^3.6.5:
- version "3.33.3"
- resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.33.3.tgz#3c644a323f0f533a0d360e9191e37f7fc059088d"
- integrity sha512-lo0kOocUlLKmm6kv/FswQL8zbkH7mVsLJ/FULClOhv8WRVmKLVcs6XPNQAzstfeJTCHMyButEwG+z1kHxHoDZw==
-
cross-spawn@^7.0.0:
version "7.0.3"
resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz"
@@ -897,13 +892,6 @@ thenify-all@^1.0.0:
dependencies:
any-promise "^1.0.0"
-tiny-markdown-editor@^0.1.8:
- version "0.1.8"
- resolved "https://registry.yarnpkg.com/tiny-markdown-editor/-/tiny-markdown-editor-0.1.8.tgz#bef845be1bea105224898a300bb27d0800a87a08"
- integrity sha512-NQNeVTwAwkzTOyL2KPm6jzpP08ygZ3eK7EQH2XZd5xwRLXuivYHArrGqsTbjfCk1Hla+PAA6uI1Uz5D15CP7uA==
- dependencies:
- core-js "^3.6.5"
-
to-regex-range@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"