diff --git a/editor/package.json b/editor/package.json
index f7c5b63..e0f03be 100644
--- a/editor/package.json
+++ b/editor/package.json
@@ -59,7 +59,7 @@
},
"scripts": {
"test": "node_modules/.bin/mocha -r esm",
- "watch": "webpack --watch",
+ "watch": "webpack --watch --mode=development",
"start": "webpack-dev-server --open --hot",
"build": "webpack --progress --mode=production",
"docker": "webpack --no-color --mode=production"
diff --git a/editor/src/editor.js b/editor/src/editor.js
index 1e9a5d8..fe9917c 100644
--- a/editor/src/editor.js
+++ b/editor/src/editor.js
@@ -152,7 +152,7 @@ function showSearchResultsExtended(element, template, searchTool, query, input,
}
return results
- })
+ }).catch(e => console.log('searchtool', e))
}
function formatLineResult(hits, key) {
@@ -284,7 +284,7 @@ function Editor(holder, input) {
return td
})
])
- })
+ }).catch(e => console.log('while fetching metakv', e))
})
})
.then(mflatten)
@@ -313,8 +313,9 @@ function Editor(holder, input) {
div.classList.add('table-wrapper')
return element.html(div);
- })
+ }).catch(e => console.log('while creating table', e))
})
+ .catch(e => console.log('transformTable', e))
}
async function transformMathExpression(converted, scope) {
@@ -350,7 +351,6 @@ function Editor(holder, input) {
}
let converted = text
- let todo;
if (converted === '{{table}}') {
transformTable.call(this, editor, id, element);
@@ -368,30 +368,37 @@ function Editor(holder, input) {
})
.catch(e => console.warn(e))
} else {
- let re = /^([A-Z0-9 ]+)::\s*(.*)$/i;
- let res = text.match(re)
- if (res) {
- converted = '[[' + res[1] + ']]'
- if (res[2]) {
- converted += ': ' + res[2]
- }
- } else if (text.match(/#\[\[TODO]]/)) {
- converted = converted.replace('#[[TODO]]', '')
- todo = true;
- } else if (text.match(/#\[\[DONE]]/)) {
- converted = converted.replace('#[[DONE]]', '')
- todo = false;
- }
+ // let re = /^([A-Z0-9 ]+)::\s*(.*)$/i;
+ // let res = text.match(re)
+ // if (res) {
+ // converted = '[[' + res[1] + ']]'
+ // if (res[2]) {
+ // converted += ': ' + res[2]
+ // }
+ // } else if (text.match(/#\[\[TODO]]/)) {
+ // converted = converted.replace('#[[TODO]]', '')
+ // todo = true;
+ // } else if (text.match(/#\[\[DONE]]/)) {
+ // converted = converted.replace('#[[DONE]]', '')
+ // todo = false;
+ // }
MD.options.html = true
converted = MD.renderInline(converted)
MD.options.html = false
}
- if (todo !== undefined) {
- element.toggleClass('todo--done', todo === false)
- element.toggleClass('todo--todo', todo === true)
- } else {
- element.removeClass(['todo--todo', 'todo--done'])
+ try {
+ const todoItem = $(converted).find(':checkbox')
+ if (todoItem.length) {
+ const todo = !todoItem.is(':checked')
+ element.toggleClass('todo--done', todo === false)
+ element.toggleClass('todo--todo', todo === true)
+ } else {
+ element.removeClass(['todo--todo', 'todo--done'])
+ }
+ } catch (e) {
+ // problem with $(converted) is that it could be treated as a jQuery selector expression instead of normal text
+ // the wiki text is not quite like selectors
}
element.html(converted)
@@ -436,7 +443,9 @@ function Editor(holder, input) {
addIndicator(
addSaver(editor, saveUrl, page, beforeSave),
indicator
- ).save().then(() => indicator.done())
+ ).save()
+ .then(() => indicator.done())
+ .catch(e => console.log('editor.change', e))
})
// editor.on('rendered', function () {
@@ -612,11 +621,12 @@ function Editor(holder, input) {
if (insideSearch) {
let query = value.substring(start + 1, end);
- showSearchResults(commandSearch, query, input, value, 'command').then(results => {
- if (query.length > 0 && (!results || results.length === 0)) {
- searchEnabled = false
- }
- })
+ showSearchResults(commandSearch, query, input, value, 'command')
+ .then(results => {
+ if (query.length > 0 && (!results || results.length === 0)) {
+ searchEnabled = false
+ }
+ }).catch(e => console.log('showSearchResults', e))
return true
} else if (insideLink) {
let query = value.substring(start, end);
@@ -645,15 +655,17 @@ function Editor(holder, input) {
return search.startQuery(res[2])
.then(hits => _.uniqBy(_.flatMap(hits, formatTitleResult), _.property('text')))
.then(results => editor.replaceChildren(id, results))
+ .catch(e => console.log('search query', e))
.finally(() => editor.render())
} else {
return search.startQuery(res[2])
.then(hits => _.groupBy(hits, (it) => it.title))
.then(hits => _.flatMap(hits, formatLineResult))
.then(results => editor.replaceChildren(id, results))
+ .catch(e => console.log('search query', e))
.finally(() => editor.render())
}
- })
+ }).catch(e => {})
});
return editor
})
@@ -663,7 +675,7 @@ function match(s, re) {
return new Promise((resolve, reject) => {
let res = s.match(re)
if (res) resolve(res)
- else reject()
+ else reject(s + ' did not match ' + re)
});
}
diff --git a/editor/src/markdown.js b/editor/src/markdown.js
index 0da4d81..81f3658 100644
--- a/editor/src/markdown.js
+++ b/editor/src/markdown.js
@@ -1,10 +1,11 @@
import MarkdownIt from "markdown-it";
-import MarkdownItWikilinks from "./wikilinks";
+//import MarkdownItWikilinks from "./wikilinks";
+import MarkdownItWikilinks2 from "./wikilinks2";
import MarkdownItMark from "markdown-it-mark";
import MarkdownItKatex from "markdown-it-katex";
const MD = new MarkdownIt({
- linkify: true,
+ linkify: false,
highlight: function (str, lang) {
if (lang === 'mermaid') {
return '
' + str + '
';
@@ -12,14 +13,22 @@ const MD = new MarkdownIt({
return '';
}
})
-
-MD.use(MarkdownItWikilinks({
+MD.use(MarkdownItWikilinks2({
baseURL: document.querySelector('body').dataset.baseUrl,
uriSuffix: '',
relativeBaseURL: '/edit/',
htmlAttributes: {
class: 'wiki-link'
},
-})).use(MarkdownItMark).use(MarkdownItKatex)
+}))
+// MD.use(MarkdownItWikilinks({
+// baseURL: document.querySelector('body').dataset.baseUrl,
+// uriSuffix: '',
+// relativeBaseURL: '/edit/',
+// htmlAttributes: {
+// class: 'wiki-link'
+// },
+// }))
+// MD.use(MarkdownItMark).use(MarkdownItKatex)
export default MD;
diff --git a/editor/src/wikilinks.js b/editor/src/wikilinks.js
index 17fd6f7..2836237 100644
--- a/editor/src/wikilinks.js
+++ b/editor/src/wikilinks.js
@@ -2,7 +2,26 @@
import Plugin from "markdown-it-regexp";
import extend from "extend";
-import sanitize from "sanitize-filename";
+
+var illegalRe = /[\/\?<>\\\*\|"]/g;
+var controlRe = /[\x00-\x1f\x80-\x9f]/g;
+var reservedRe = /^\.+$/;
+var windowsReservedRe = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\..*)?$/i;
+var windowsTrailingRe = /[\. ]+$/;
+
+function sanitize(input) {
+ const replacement = '';
+ if (typeof input !== 'string') {
+ throw new Error('Input must be string');
+ }
+ var sanitized = input
+ .replace(illegalRe, replacement)
+ .replace(controlRe, replacement)
+ .replace(reservedRe, replacement)
+ .replace(windowsReservedRe, replacement)
+ .replace(windowsTrailingRe, replacement);
+ return sanitized;
+}
export default (options) => {
const defaults = {
@@ -17,7 +36,7 @@ export default (options) => {
},
postProcessPageName: (pageName) => {
pageName = pageName.trim()
- pageName = pageName.split('/').map(sanitize).join('/')
+ pageName = pageName.split('/').map(sanitize).map(sanitize).join('/')
pageName = pageName.replace(/\s+/g, '_')
return pageName
},
diff --git a/editor/src/wikilinks2.js b/editor/src/wikilinks2.js
new file mode 100644
index 0000000..ab8b35a
--- /dev/null
+++ b/editor/src/wikilinks2.js
@@ -0,0 +1,75 @@
+'use strict'
+
+var util = require('util')
+
+function Plugin(options) {
+ var self = function (md) {
+ self.options = options
+ self.init(md)
+ }
+
+ self.__proto__ = Plugin.prototype
+ self.id = 'wikilinks'
+
+ return self
+}
+
+util.inherits(Plugin, Function)
+
+Plugin.prototype.init = function (md) {
+ md.inline.ruler.push(this.id, this.parse.bind(this))
+ md.renderer.rules[this.id] = this.render.bind(this)
+}
+
+export function linkParser(id, state) {
+ let input = state.src.slice(state.pos);
+ const match = /^#?\[\[/.exec(input)
+ if (!match) {
+ return false
+ }
+
+ let prefixLength = match[0].length
+ let p = state.pos + prefixLength
+ let open = 2
+ while (p < state.src.length - 1 && open > 0) {
+ if (state.src[p] === '[' && state.src[p + 1] === '[') {
+ open += 2
+ p += 2
+ } else if (state.src[p] === ']' && state.src[p + 1] === ']') {
+ open -= 2
+ p += 2
+ } else {
+ p++
+ }
+ }
+
+ if (open === 0) {
+ let link = state.src.slice(state.pos + prefixLength, p - 2)
+ let token = state.push(id, '', 0)
+ token.meta = {match: link, tag: prefixLength === 3}
+ state.pos = p
+ return true
+ }
+
+ return false
+}
+
+Plugin.prototype.parse = function (state, silent) {
+ return linkParser(this.id, state)
+}
+
+Plugin.prototype.render = function (tokens, id, options, env) {
+ let {match: link, tag} = tokens[id].meta
+ if (tag) {
+ if (link === 'TODO') {
+ return '';
+ } else if (link === 'DONE') {
+ return '';
+ }
+ }
+ return '' + link + '';
+}
+
+export default (options) => {
+ return Plugin(options);
+}
diff --git a/editor/test/markdown.test.js b/editor/test/markdown.test.js
new file mode 100644
index 0000000..25ff763
--- /dev/null
+++ b/editor/test/markdown.test.js
@@ -0,0 +1,62 @@
+/*
+ * Wiki - A wiki with editor
+ * Copyright (c) 2021 Peter Stuifzand
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+import assert from 'assert'
+import MarkdownIt from "markdown-it";
+import MarkdownItWikilinks2 from "../src/wikilinks2";
+
+const MD = new MarkdownIt({
+ linkify: false,
+ highlight: function (str, lang) {
+ if (lang === 'mermaid') {
+ return '' + str + '
';
+ }
+ return '';
+ }
+})
+
+MD.use(MarkdownItWikilinks2({
+ baseURL: 'http://localhost/',
+ uriSuffix: '',
+ relativeBaseURL: '/edit/',
+ htmlAttributes: {
+ class: 'wiki-link'
+ },
+}))
+
+describe('MD', function () {
+ it('parseLinks', function () {
+ assert.deepStrictEqual(MD.renderInline("#[[TODO]]"), '')
+ assert.deepStrictEqual(MD.renderInline("#[[TODO]] #[[DONE]]"), ' ')
+ })
+ it('parseLinks 2', function () {
+ assert.deepStrictEqual(MD.renderInline("#[[TODO]] #[[DONE]]"), ' ')
+ })
+ it('parseLinks 3', function () {
+ assert.deepStrictEqual(MD.renderInline("test #[[TODO]] test2"), 'test test2')
+ })
+ it('parseLinks 4', function () {
+ assert.deepStrictEqual(MD.renderInline("test [[test]] [[test2]] [[test3]]"), 'test test test2 test3')
+ })
+ it('parseLinks 5', function () {
+ assert.deepStrictEqual(MD.renderInline("test [[test]]"), 'test test')
+ })
+ it('parseLinks 6', function () {
+ assert.deepStrictEqual(MD.renderInline("test [[test]] [[test2]]"), 'test test test2')
+ })
+})
diff --git a/editor/test/wikilinks2.test.js b/editor/test/wikilinks2.test.js
new file mode 100644
index 0000000..b1e43c9
--- /dev/null
+++ b/editor/test/wikilinks2.test.js
@@ -0,0 +1,117 @@
+/*
+ * Wiki - A wiki with editor
+ * Copyright (c) 2021 Peter Stuifzand
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+import assert from 'assert'
+import {linkParser} from '../src/wikilinks2'
+
+describe('linkParser', function () {
+ it('parse', function () {
+ let state = {src: '', pos: 0, tokens: []};
+ state.__proto__.push = function (id, s, x) {
+ let token = {id, s, x};
+ this.tokens.push(token)
+ return token
+ }
+ assert.deepStrictEqual(linkParser('test', state), false);
+ assert.deepStrictEqual(state, {
+ src: '',
+ pos: 0,
+ tokens: []
+ })
+ })
+
+ it('parse 2', function () {
+ let state = {src: '[[Link]]', pos: 0, tokens: []};
+ state.__proto__.push = function (id, s, x) {
+ let token = {id, s, x};
+ this.tokens.push(token)
+ return token
+ }
+ assert.deepStrictEqual(linkParser('test', state), true);
+ assert.deepStrictEqual(state, {
+ src: '[[Link]]',
+ pos: 8,
+ tokens: [{
+ id: 'test',
+ s: '',
+ x: 0,
+ meta: {match:'Link', tag: false}
+ }]
+ })
+ })
+
+ it('parse 3', function () {
+ let state = {src: '1234[[Link]]', pos: 4, tokens: []};
+ state.__proto__.push = function (id, s, x) {
+ let token = {id, s, x};
+ this.tokens.push(token)
+ return token
+ }
+ assert.deepStrictEqual(linkParser('test', state), true);
+ assert.deepStrictEqual(state, {
+ src: '1234[[Link]]',
+ pos: 12,
+ tokens: [{
+ id: 'test',
+ s: '',
+ x: 0,
+ meta: {match:'Link', tag: false}
+ }]
+ })
+ })
+
+ it('parse 4', function () {
+ let state = {src: '1234#[[TODO]]', pos: 4, tokens: []};
+ state.__proto__.push = function (id, s, x) {
+ let token = {id, s, x};
+ this.tokens.push(token)
+ return token
+ }
+ assert.deepStrictEqual(linkParser('test', state), true);
+ assert.deepStrictEqual(state, {
+ src: '1234#[[TODO]]',
+ pos: 13,
+ tokens: [{
+ id: 'test',
+ s: '',
+ x: 0,
+ meta: {match:'TODO', tag: true}
+ }]
+ })
+ })
+
+ it('parse text and two links', function () {
+ let state = {src: '1234 [[Link]] [[Link2]]', pos: 5, tokens: []};
+ state.__proto__.push = function (id, s, x) {
+ let token = {id, s, x};
+ this.tokens.push(token)
+ return token
+ }
+ assert.deepStrictEqual(linkParser('test', state), true);
+ assert.deepStrictEqual(state, {
+ src: '1234 [[Link]] [[Link2]]',
+ pos: 13,
+ tokens: [{
+ id: 'test',
+ s: '',
+ x: 0,
+ meta: {match:'Link', tag: false}
+ }]
+ })
+ })
+})