diff --git a/prose/markdownParser.js b/prose/markdownParser.js index f50b627..757a47e 100644 --- a/prose/markdownParser.js +++ b/prose/markdownParser.js @@ -4,54 +4,54 @@ import markdownit from "markdown-it"; import { writeFreelySchema } from "./schema"; export const writeAsMarkdownParser = new MarkdownParser( - writeFreelySchema, - markdownit("commonmark", { html: true }), - { - // blockquote: { block: "blockquote" }, - paragraph: { block: "paragraph" }, - list_item: { block: "list_item" }, - bullet_list: { block: "bullet_list" }, - ordered_list: { - block: "ordered_list", - getAttrs: (tok) => ({ order: +tok.attrGet("start") || 1 }), - }, - heading: { - block: "heading", - getAttrs: (tok) => ({ level: +tok.tag.slice(1) }), - }, - code_block: { block: "code_block", noCloseToken: true }, - fence: { - block: "code_block", - getAttrs: (tok) => ({ params: tok.info || "" }), - noCloseToken: true, - }, - // hr: { node: "horizontal_rule" }, - image: { - node: "image", - getAttrs: (tok) => ({ - src: tok.attrGet("src"), - title: tok.attrGet("title") || null, - alt: tok.children?.[0].content || null, - }), - }, - hardbreak: { node: "hard_break" }, - - em: { mark: "em" }, - strong: { mark: "strong" }, - link: { - mark: "link", - getAttrs: (tok) => ({ - href: tok.attrGet("href"), - title: tok.attrGet("title") || null, - }), - }, - code_inline: { mark: "code", noCloseToken: true }, - html_block: { - node: "readmore", - getAttrs(token) { - // TODO: Give different attributes depending on the token content - return {}; - }, - }, + writeFreelySchema, + markdownit("commonmark", { html: true }), + { + // blockquote: { block: "blockquote" }, + paragraph: { block: "paragraph" }, + list_item: { block: "list_item" }, + bullet_list: { block: "bullet_list" }, + ordered_list: { + block: "ordered_list", + getAttrs: (tok) => ({ order: +tok.attrGet("start") || 1 }), }, + heading: { + block: "heading", + getAttrs: (tok) => ({ level: +tok.tag.slice(1) }), + }, + code_block: { block: "code_block", noCloseToken: true }, + fence: { + block: "code_block", + getAttrs: (tok) => ({ params: tok.info || "" }), + noCloseToken: true, + }, + // hr: { node: "horizontal_rule" }, + image: { + node: "image", + getAttrs: (tok) => ({ + src: tok.attrGet("src"), + title: tok.attrGet("title") || null, + alt: tok.children?.[0].content || null, + }), + }, + hardbreak: { node: "hard_break" }, + + em: { mark: "em" }, + strong: { mark: "strong" }, + link: { + mark: "link", + getAttrs: (tok) => ({ + href: tok.attrGet("href"), + title: tok.attrGet("title") || null, + }), + }, + code_inline: { mark: "code", noCloseToken: true }, + html_block: { + node: "readmore", + getAttrs(token) { + // TODO: Give different attributes depending on the token content + return {}; + }, + }, + } ); diff --git a/prose/markdownSerializer.js b/prose/markdownSerializer.js index bffbc98..ef068df 100644 --- a/prose/markdownSerializer.js +++ b/prose/markdownSerializer.js @@ -47,10 +47,6 @@ export const writeAsMarkdownSerializer = new MarkdownSerializer( state.renderInline(node); state.closeBlock(node); }, - // horizontal_rule(state, node) { - // state.write(node.attrs.markup || "---"); - // state.closeBlock(node); - // }, bullet_list(state, node) { state.renderList(node, " ", () => `${node.attrs.bullet || "*"} `); }, @@ -75,13 +71,13 @@ export const writeAsMarkdownSerializer = new MarkdownSerializer( state.write( `![${state.esc(node.attrs.alt || "")}](${state.esc(node.attrs.src)}${ node.attrs.title ? ` ${state.quote(node.attrs.title)}` : "" - })`, + })` ); }, hard_break(state, node, parent, index) { for (let i = index + 1; i < parent.childCount; i += 1) if (parent.child(i).type !== node.type) { - state.write("\n"); + state.write("\\\n"); return; } }, @@ -123,5 +119,5 @@ export const writeAsMarkdownSerializer = new MarkdownSerializer( }, escape: false, }, - }, + } ); diff --git a/prose/menu.js b/prose/menu.js index 263f1b8..c534f61 100644 --- a/prose/menu.js +++ b/prose/menu.js @@ -4,23 +4,29 @@ import { buildMenuItems } from "prosemirror-example-setup"; import { writeFreelySchema } from "./schema"; function canInsert(state, nodeType, attrs) { - let $from = state.selection.$from - for (let d = $from.depth; d >= 0; d--) { - let index = $from.index(d) - if ($from.node(d).canReplaceWith(index, index, nodeType, attrs)) return true - } - return false + let $from = state.selection.$from; + for (let d = $from.depth; d >= 0; d--) { + let index = $from.index(d); + if ($from.node(d).canReplaceWith(index, index, nodeType, attrs)) + return true; } + return false; +} const ReadMoreItem = new MenuItem({ - label: "Read more", - select: (state) => canInsert(state, writeFreelySchema.nodes.readmore), - run(state, dispatch) { - dispatch(state.tr.replaceSelectionWith(writeFreelySchema.nodes.readmore.create())) - }, + label: "Read more", + select: (state) => canInsert(state, writeFreelySchema.nodes.readmore), + run(state, dispatch) { + dispatch( + state.tr.replaceSelectionWith(writeFreelySchema.nodes.readmore.create()) + ); + }, }); -export const getMenu = ()=> { - const menuContent = [...buildMenuItems(writeFreelySchema).fullMenu, [ReadMoreItem]]; - return menuContent -} +export const getMenu = () => { + const menuContent = [ + ...buildMenuItems(writeFreelySchema).fullMenu, + [ReadMoreItem], + ]; + return menuContent; +}; diff --git a/prose/prose.html b/prose/prose.html index 07dee82..ae2addc 100644 --- a/prose/prose.html +++ b/prose/prose.html @@ -6,5 +6,9 @@ -
+
+ +
diff --git a/prose/prose.js b/prose/prose.js index bc7f319..7c21116 100644 --- a/prose/prose.js +++ b/prose/prose.js @@ -9,89 +9,101 @@ // destroy() { this.textarea.remove() } // } -import { EditorView } from "prosemirror-view" -import { EditorState } from "prosemirror-state" -import { exampleSetup } from "prosemirror-example-setup" +import { EditorView } from "prosemirror-view"; +import { EditorState, TextSelection } from "prosemirror-state"; +import { exampleSetup } from "prosemirror-example-setup"; import { keymap } from "prosemirror-keymap"; -import { writeAsMarkdownParser } from "./markdownParser" -import { writeAsMarkdownSerializer } from "./markdownSerializer" -import { writeFreelySchema } from "./schema" -import { getMenu } from "./menu" +import { writeAsMarkdownParser } from "./markdownParser"; +import { writeAsMarkdownSerializer } from "./markdownSerializer"; +import { writeFreelySchema } from "./schema"; +import { getMenu } from "./menu"; -let $title = document.querySelector('#title') -let $content = document.querySelector('#content') +let $title = document.querySelector("#title"); +let $content = document.querySelector("#content"); + +// Bugs: +// 1. When there's just an empty line and a hard break is inserted with shift-enter then two enters are inserted +// which do not show up in the markdown ( maybe bc. they are training enters ) class ProseMirrorView { - constructor(target, content) { - this.view = new EditorView(target, { - state: EditorState.create({ - doc: function (content) { - // console.log('loading '+window.draftKey) - let localDraft = localStorage.getItem(window.draftKey); - if (localDraft != null) { - content = localDraft - } - if (content.indexOf("# ") === 0) { - let eol = content.indexOf("\n"); - let title = content.substring("# ".length, eol); - content = content.substring(eol + "\n\n".length); - $title.value = title; - } - return writeAsMarkdownParser.parse(content) - }(content), - plugins: [ - keymap({ - "Mod-Enter": () => { - document.getElementById("publish").click(); - return true; - }, - "Mod-k": ()=> { - console.log("TODO-link"); - return true; - } - }), - ...exampleSetup({ schema: writeFreelySchema, menuContent: getMenu() }), - - ] - }), - dispatchTransaction(transaction) { - // console.log('saving to '+window.draftKey) - const newContent = writeAsMarkdownSerializer.serialize(transaction.doc) - console.log({newContent}) - $content.value = newContent - localStorage.setItem(window.draftKey, function () { - let draft = ""; - if ($title.value != null && $title.value !== "") { - draft = "# " + $title.value + "\n\n" - } - draft += $content.value - return draft - }()); - let newState = this.state.apply(transaction) - this.updateState(newState) - } - }) + constructor(target, content) { + let localDraft = localStorage.getItem(window.draftKey); + if (localDraft != null) { + content = localDraft; + } + if (content.indexOf("# ") === 0) { + let eol = content.indexOf("\n"); + let title = content.substring("# ".length, eol); + content = content.substring(eol + "\n\n".length); + $title.value = title; } - get content() { - return defaultMarkdownSerializer.serialize(this.view.state.doc) - } - focus() { this.view.focus() } - destroy() { this.view.destroy() } + const doc = writeAsMarkdownParser.parse( + // Replace all "solo" \n's with \\\n for correct markdown parsing + content.replaceAll(/(? { + document.getElementById("publish").click(); + return true; + }, + "Mod-k": () => { + const linkButton = document.querySelector(".ProseMirror-icon[title='Add or remove link']") + linkButton.dispatchEvent(new Event('mousedown')); + return true; + }, + }), + ...exampleSetup({ + schema: writeFreelySchema, + menuContent: getMenu(), + }), + ], + }), + dispatchTransaction(transaction) { + const newContent = writeAsMarkdownSerializer + .serialize(transaction.doc) + // Replace all \\\ns ( not followed by a \n ) with \n + .replaceAll(/\\\n(?!\n)/g, "\n"); + $content.value = newContent; + let draft = ""; + if ($title.value != null && $title.value !== "") { + draft = "# " + $title.value + "\n\n"; + } + draft += newContent; + localStorage.setItem(window.draftKey, draft); + let newState = this.state.apply(transaction); + this.updateState(newState); + }, + }); + // Editor is focused to the last position. This is a workaround for a bug: + // 1. 1 type something in an existing entry + // 2. reload - works fine, the draft is reloaded + // 3. reload again - the draft is somehow removed from localStorage and the original content is loaded + // When the editor is focused the content is re-saved to localStorage + + // This is also useful for editing, so it's not a bad thing even + const lastPosition = this.view.state.doc.content.size; + const selection = TextSelection.create(this.view.state.doc, lastPosition); + this.view.dispatch(this.view.state.tr.setSelection(selection)); + this.view.focus(); + } + + get content() { + return defaultMarkdownSerializer.serialize(this.view.state.doc); + } + focus() { + this.view.focus(); + } + destroy() { + this.view.destroy(); + } } -let place = document.querySelector("#editor") -let view = new ProseMirrorView(place, $content.value) - -// document.querySelectorAll("input[type=radio]").forEach(button => { -// button.addEventListener("change", () => { -// if (!button.checked) return -// let View = button.value == "markdown" ? MarkdownView : ProseMirrorView -// if (view instanceof View) return -// let content = view.content -// view.destroy() -// view = new View(place, content) -// view.focus() -// }) -// }) +let place = document.querySelector("#editor"); +let view = new ProseMirrorView(place, $content.value); diff --git a/prose/schema.js b/prose/schema.js index 2fa6e2d..518bb3f 100644 --- a/prose/schema.js +++ b/prose/schema.js @@ -1,16 +1,21 @@ -import { schema } from "prosemirror-markdown" +import { schema } from "prosemirror-markdown"; import { Schema } from "prosemirror-model"; export const writeFreelySchema = new Schema({ - nodes: schema.spec.nodes.remove("blockquote") - .remove("horizontal_rule") - .addToEnd("readmore", { - inline: false, - content: "", - group: "block", - draggable: true, - toDOM: (node) => ["div", { class: "editorreadmore", style: "width: 100%;text-align:center" }, "Read more..."], - parseDOM: [{ tag: "div.editorreadmore" }], - }), - marks: schema.spec.marks, + nodes: schema.spec.nodes + .remove("blockquote") + .remove("horizontal_rule") + .addToEnd("readmore", { + inline: false, + content: "", + group: "block", + draggable: true, + toDOM: (node) => [ + "div", + { class: "editorreadmore", style: "width: 100%;text-align:center" }, + "Read more...", + ], + parseDOM: [{ tag: "div.editorreadmore" }], + }), + marks: schema.spec.marks, }); diff --git a/static/js/prose.bundle.js b/static/js/prose.bundle.js index 9b5031e..7c79102 100644 --- a/static/js/prose.bundle.js +++ b/static/js/prose.bundle.js @@ -106,7 +106,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) * /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"writeAsMarkdownSerializer\", function() { return writeAsMarkdownSerializer; });\n/* harmony import */ var prosemirror_markdown__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! prosemirror-markdown */ \"./node_modules/prosemirror-markdown/dist/index.es.js\");\n\n\nfunction backticksFor(node, side) {\n var ticks = /`+/g;\n var m;\n var len = 0;\n if (node.isText) while (m = ticks.exec(node.text)) {\n len = Math.max(len, m[0].length);\n }\n var result = len > 0 && side > 0 ? \" `\" : \"`\";\n\n for (var i = 0; i < len; i++) {\n result += \"`\";\n }\n\n if (len > 0 && side < 0) result += \" \";\n return result;\n}\n\nfunction isPlainURL(link, parent, index, side) {\n if (link.attrs.title || !/^\\w+:/.test(link.attrs.href)) return false;\n var content = parent.child(index + (side < 0 ? -1 : 0));\n if (!content.isText || content.text != link.attrs.href || content.marks[content.marks.length - 1] != link) return false;\n if (index == (side < 0 ? 1 : parent.childCount - 1)) return true;\n var next = parent.child(index + (side < 0 ? -2 : 1));\n return !link.isInSet(next.marks);\n}\n\nvar writeAsMarkdownSerializer = new prosemirror_markdown__WEBPACK_IMPORTED_MODULE_0__[\"MarkdownSerializer\"]({\n readmore: function readmore(state, node) {\n state.write(\"\\n\");\n state.closeBlock(node);\n },\n // blockquote(state, node) {\n // state.wrapBlock(\"> \", undefined, node, () => state.renderContent(node));\n // },\n code_block: function code_block(state, node) {\n state.write(\"```\".concat(node.attrs.params || \"\", \"\\n\"));\n state.text(node.textContent, false);\n state.ensureNewLine();\n state.write(\"```\");\n state.closeBlock(node);\n },\n heading: function heading(state, node) {\n state.write(\"\".concat(state.repeat(\"#\", node.attrs.level), \" \"));\n state.renderInline(node);\n state.closeBlock(node);\n },\n // horizontal_rule(state, node) {\n // state.write(node.attrs.markup || \"---\");\n // state.closeBlock(node);\n // },\n bullet_list: function bullet_list(state, node) {\n state.renderList(node, \" \", function () {\n return \"\".concat(node.attrs.bullet || \"*\", \" \");\n });\n },\n ordered_list: function ordered_list(state, node) {\n var start = node.attrs.order || 1;\n var maxW = String(start + node.childCount - 1).length;\n var space = state.repeat(\" \", maxW + 2);\n state.renderList(node, space, function (i) {\n var nStr = String(start + i);\n return \"\".concat(state.repeat(\" \", maxW - nStr.length) + nStr, \". \");\n });\n },\n list_item: function list_item(state, node) {\n state.renderContent(node);\n },\n paragraph: function paragraph(state, node) {\n state.renderInline(node);\n state.closeBlock(node);\n },\n image: function image(state, node) {\n state.write(\"![\".concat(state.esc(node.attrs.alt || \"\"), \"](\").concat(state.esc(node.attrs.src)).concat(node.attrs.title ? \" \".concat(state.quote(node.attrs.title)) : \"\", \")\"));\n },\n hard_break: function hard_break(state, node, parent, index) {\n for (var i = index + 1; i < parent.childCount; i += 1) {\n if (parent.child(i).type !== node.type) {\n state.write(\"\\n\");\n return;\n }\n }\n },\n text: function text(state, node) {\n state.text(node.text || \"\");\n }\n}, {\n em: {\n open: \"*\",\n close: \"*\",\n mixable: true,\n expelEnclosingWhitespace: true\n },\n strong: {\n open: \"**\",\n close: \"**\",\n mixable: true,\n expelEnclosingWhitespace: true\n },\n link: {\n open: function open(_state, mark, parent, index) {\n return isPlainURL(mark, parent, index, 1) ? \"<\" : \"[\";\n },\n close: function close(state, mark, parent, index) {\n return isPlainURL(mark, parent, index, -1) ? \">\" : \"](\".concat(state.esc(mark.attrs.href)).concat(mark.attrs.title ? \" \".concat(state.quote(mark.attrs.title)) : \"\", \")\");\n }\n },\n code: {\n open: function open(_state, _mark, parent, index) {\n return backticksFor(parent.child(index), -1);\n },\n close: function close(_state, _mark, parent, index) {\n return backticksFor(parent.child(index - 1), 1);\n },\n escape: false\n }\n});\n\n//# sourceURL=webpack:///./markdownSerializer.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"writeAsMarkdownSerializer\", function() { return writeAsMarkdownSerializer; });\n/* harmony import */ var prosemirror_markdown__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! prosemirror-markdown */ \"./node_modules/prosemirror-markdown/dist/index.es.js\");\n\n\nfunction backticksFor(node, side) {\n var ticks = /`+/g;\n var m;\n var len = 0;\n if (node.isText) while (m = ticks.exec(node.text)) {\n len = Math.max(len, m[0].length);\n }\n var result = len > 0 && side > 0 ? \" `\" : \"`\";\n\n for (var i = 0; i < len; i++) {\n result += \"`\";\n }\n\n if (len > 0 && side < 0) result += \" \";\n return result;\n}\n\nfunction isPlainURL(link, parent, index, side) {\n if (link.attrs.title || !/^\\w+:/.test(link.attrs.href)) return false;\n var content = parent.child(index + (side < 0 ? -1 : 0));\n if (!content.isText || content.text != link.attrs.href || content.marks[content.marks.length - 1] != link) return false;\n if (index == (side < 0 ? 1 : parent.childCount - 1)) return true;\n var next = parent.child(index + (side < 0 ? -2 : 1));\n return !link.isInSet(next.marks);\n}\n\nvar writeAsMarkdownSerializer = new prosemirror_markdown__WEBPACK_IMPORTED_MODULE_0__[\"MarkdownSerializer\"]({\n readmore: function readmore(state, node) {\n state.write(\"\\n\");\n state.closeBlock(node);\n },\n // blockquote(state, node) {\n // state.wrapBlock(\"> \", undefined, node, () => state.renderContent(node));\n // },\n code_block: function code_block(state, node) {\n state.write(\"```\".concat(node.attrs.params || \"\", \"\\n\"));\n state.text(node.textContent, false);\n state.ensureNewLine();\n state.write(\"```\");\n state.closeBlock(node);\n },\n heading: function heading(state, node) {\n state.write(\"\".concat(state.repeat(\"#\", node.attrs.level), \" \"));\n state.renderInline(node);\n state.closeBlock(node);\n },\n bullet_list: function bullet_list(state, node) {\n state.renderList(node, \" \", function () {\n return \"\".concat(node.attrs.bullet || \"*\", \" \");\n });\n },\n ordered_list: function ordered_list(state, node) {\n var start = node.attrs.order || 1;\n var maxW = String(start + node.childCount - 1).length;\n var space = state.repeat(\" \", maxW + 2);\n state.renderList(node, space, function (i) {\n var nStr = String(start + i);\n return \"\".concat(state.repeat(\" \", maxW - nStr.length) + nStr, \". \");\n });\n },\n list_item: function list_item(state, node) {\n state.renderContent(node);\n },\n paragraph: function paragraph(state, node) {\n state.renderInline(node);\n state.closeBlock(node);\n },\n image: function image(state, node) {\n state.write(\"![\".concat(state.esc(node.attrs.alt || \"\"), \"](\").concat(state.esc(node.attrs.src)).concat(node.attrs.title ? \" \".concat(state.quote(node.attrs.title)) : \"\", \")\"));\n },\n hard_break: function hard_break(state, node, parent, index) {\n for (var i = index + 1; i < parent.childCount; i += 1) {\n if (parent.child(i).type !== node.type) {\n state.write(\"\\\\\\n\");\n return;\n }\n }\n },\n text: function text(state, node) {\n state.text(node.text || \"\");\n }\n}, {\n em: {\n open: \"*\",\n close: \"*\",\n mixable: true,\n expelEnclosingWhitespace: true\n },\n strong: {\n open: \"**\",\n close: \"**\",\n mixable: true,\n expelEnclosingWhitespace: true\n },\n link: {\n open: function open(_state, mark, parent, index) {\n return isPlainURL(mark, parent, index, 1) ? \"<\" : \"[\";\n },\n close: function close(state, mark, parent, index) {\n return isPlainURL(mark, parent, index, -1) ? \">\" : \"](\".concat(state.esc(mark.attrs.href)).concat(mark.attrs.title ? \" \".concat(state.quote(mark.attrs.title)) : \"\", \")\");\n }\n },\n code: {\n open: function open(_state, _mark, parent, index) {\n return backticksFor(parent.child(index), -1);\n },\n close: function close(_state, _mark, parent, index) {\n return backticksFor(parent.child(index - 1), 1);\n },\n escape: false\n }\n});\n\n//# sourceURL=webpack:///./markdownSerializer.js?"); /***/ }), @@ -1176,7 +1176,7 @@ eval("module.exports = function (module) {\n if (!module.webpackPolyfill) {\n /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var prosemirror_view__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! prosemirror-view */ \"./node_modules/prosemirror-view/dist/index.es.js\");\n/* harmony import */ var prosemirror_state__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! prosemirror-state */ \"./node_modules/prosemirror-state/dist/index.es.js\");\n/* harmony import */ var prosemirror_example_setup__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! prosemirror-example-setup */ \"./node_modules/prosemirror-example-setup/dist/index.es.js\");\n/* harmony import */ var prosemirror_keymap__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! prosemirror-keymap */ \"./node_modules/prosemirror-keymap/dist/index.es.js\");\n/* harmony import */ var _markdownParser__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./markdownParser */ \"./markdownParser.js\");\n/* harmony import */ var _markdownSerializer__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./markdownSerializer */ \"./markdownSerializer.js\");\n/* harmony import */ var _schema__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./schema */ \"./schema.js\");\n/* harmony import */ var _menu__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./menu */ \"./menu.js\");\nfunction _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }\n\nfunction _nonIterableSpread() { throw new TypeError(\"Invalid attempt to spread non-iterable instance\"); }\n\nfunction _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === \"[object Arguments]\") return Array.from(iter); }\n\nfunction _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\n// class MarkdownView {\n// constructor(target, content) {\n// this.textarea = target.appendChild(document.createElement(\"textarea\"))\n// this.textarea.value = content\n// }\n// get content() { return this.textarea.value }\n// focus() { this.textarea.focus() }\n// destroy() { this.textarea.remove() }\n// }\n\n\n\n\n\n\n\n\nvar $title = document.querySelector('#title');\nvar $content = document.querySelector('#content');\n\nvar ProseMirrorView = /*#__PURE__*/function () {\n function ProseMirrorView(target, content) {\n _classCallCheck(this, ProseMirrorView);\n\n this.view = new prosemirror_view__WEBPACK_IMPORTED_MODULE_0__[\"EditorView\"](target, {\n state: prosemirror_state__WEBPACK_IMPORTED_MODULE_1__[\"EditorState\"].create({\n doc: function (content) {\n // console.log('loading '+window.draftKey)\n var localDraft = localStorage.getItem(window.draftKey);\n\n if (localDraft != null) {\n content = localDraft;\n }\n\n if (content.indexOf(\"# \") === 0) {\n var eol = content.indexOf(\"\\n\");\n var title = content.substring(\"# \".length, eol);\n content = content.substring(eol + \"\\n\\n\".length);\n $title.value = title;\n }\n\n return _markdownParser__WEBPACK_IMPORTED_MODULE_4__[\"writeAsMarkdownParser\"].parse(content);\n }(content),\n plugins: [Object(prosemirror_keymap__WEBPACK_IMPORTED_MODULE_3__[\"keymap\"])({\n \"Mod-Enter\": function ModEnter() {\n document.getElementById(\"publish\").click();\n return true;\n },\n \"Mod-k\": function ModK() {\n console.log(\"TODO-link\");\n return true;\n }\n })].concat(_toConsumableArray(Object(prosemirror_example_setup__WEBPACK_IMPORTED_MODULE_2__[\"exampleSetup\"])({\n schema: _schema__WEBPACK_IMPORTED_MODULE_6__[\"writeFreelySchema\"],\n menuContent: Object(_menu__WEBPACK_IMPORTED_MODULE_7__[\"getMenu\"])()\n })))\n }),\n dispatchTransaction: function dispatchTransaction(transaction) {\n // console.log('saving to '+window.draftKey)\n var newContent = _markdownSerializer__WEBPACK_IMPORTED_MODULE_5__[\"writeAsMarkdownSerializer\"].serialize(transaction.doc);\n console.log({\n newContent: newContent\n });\n $content.value = newContent;\n localStorage.setItem(window.draftKey, function () {\n var draft = \"\";\n\n if ($title.value != null && $title.value !== \"\") {\n draft = \"# \" + $title.value + \"\\n\\n\";\n }\n\n draft += $content.value;\n return draft;\n }());\n var newState = this.state.apply(transaction);\n this.updateState(newState);\n }\n });\n }\n\n _createClass(ProseMirrorView, [{\n key: \"focus\",\n value: function focus() {\n this.view.focus();\n }\n }, {\n key: \"destroy\",\n value: function destroy() {\n this.view.destroy();\n }\n }, {\n key: \"content\",\n get: function get() {\n return defaultMarkdownSerializer.serialize(this.view.state.doc);\n }\n }]);\n\n return ProseMirrorView;\n}();\n\nvar place = document.querySelector(\"#editor\");\nvar view = new ProseMirrorView(place, $content.value); // document.querySelectorAll(\"input[type=radio]\").forEach(button => {\n// button.addEventListener(\"change\", () => {\n// if (!button.checked) return\n// let View = button.value == \"markdown\" ? MarkdownView : ProseMirrorView\n// if (view instanceof View) return\n// let content = view.content\n// view.destroy()\n// view = new View(place, content)\n// view.focus()\n// })\n// })\n\n//# sourceURL=webpack:///./prose.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var prosemirror_view__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! prosemirror-view */ \"./node_modules/prosemirror-view/dist/index.es.js\");\n/* harmony import */ var prosemirror_state__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! prosemirror-state */ \"./node_modules/prosemirror-state/dist/index.es.js\");\n/* harmony import */ var prosemirror_example_setup__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! prosemirror-example-setup */ \"./node_modules/prosemirror-example-setup/dist/index.es.js\");\n/* harmony import */ var prosemirror_keymap__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! prosemirror-keymap */ \"./node_modules/prosemirror-keymap/dist/index.es.js\");\n/* harmony import */ var _markdownParser__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./markdownParser */ \"./markdownParser.js\");\n/* harmony import */ var _markdownSerializer__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./markdownSerializer */ \"./markdownSerializer.js\");\n/* harmony import */ var _schema__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./schema */ \"./schema.js\");\n/* harmony import */ var _menu__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./menu */ \"./menu.js\");\nfunction _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }\n\nfunction _nonIterableSpread() { throw new TypeError(\"Invalid attempt to spread non-iterable instance\"); }\n\nfunction _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === \"[object Arguments]\") return Array.from(iter); }\n\nfunction _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\n// class MarkdownView {\n// constructor(target, content) {\n// this.textarea = target.appendChild(document.createElement(\"textarea\"))\n// this.textarea.value = content\n// }\n// get content() { return this.textarea.value }\n// focus() { this.textarea.focus() }\n// destroy() { this.textarea.remove() }\n// }\n\n\n\n\n\n\n\n\nvar $title = document.querySelector(\"#title\");\nvar $content = document.querySelector(\"#content\"); // Bugs:\n// 1. When there's just an empty line and a hard break is inserted with shift-enter then two enters are inserted \n// which do not show up in the markdown ( maybe bc. they are training enters )\n\nvar ProseMirrorView = /*#__PURE__*/function () {\n function ProseMirrorView(target, content) {\n _classCallCheck(this, ProseMirrorView);\n\n var localDraft = localStorage.getItem(window.draftKey);\n\n if (localDraft != null) {\n content = localDraft;\n }\n\n if (content.indexOf(\"# \") === 0) {\n var eol = content.indexOf(\"\\n\");\n var title = content.substring(\"# \".length, eol);\n content = content.substring(eol + \"\\n\\n\".length);\n $title.value = title;\n }\n\n var doc = _markdownParser__WEBPACK_IMPORTED_MODULE_4__[\"writeAsMarkdownParser\"].parse( // Replace all \"solo\" \\n's with \\\\\\n for correct markdown parsing\n content.replaceAll(/(?