Use wiki-list-editor
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Peter Stuifzand 2020-05-11 23:34:10 +02:00
parent 6c04d9871f
commit d6ad4e7a18
6 changed files with 710 additions and 310 deletions

793
editor/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,29 +1,20 @@
{ {
"devDependencies": { "devDependencies": {
"@editorjs/attaches": "^1.0.1",
"clean-webpack-plugin": "^3.0.0", "clean-webpack-plugin": "^3.0.0",
"html-webpack-plugin": "^3.2.0", "html-webpack-plugin": "^3.2.0",
"scss-loader": "0.0.1", "scss-loader": "0.0.1",
"webpack": "^4.39.2", "webpack": "^4.39.2",
"webpack-cli": "^3.3.7" "webpack-cli": "^3.3.7",
"webpack-dev-server": "^3.8.0"
}, },
"dependencies": { "dependencies": {
"@editorjs/checklist": "^1.1.0",
"@editorjs/code": "^2.4.1",
"@editorjs/editorjs": "^2.15.0",
"@editorjs/header": "^2.3.0",
"@editorjs/image": "^2.3.1",
"@editorjs/link": "^2.1.3",
"@editorjs/list": "^1.4.0",
"@editorjs/marker": "^1.2.1",
"@editorjs/table": "^1.2.0",
"axios": "^0.19.0", "axios": "^0.19.0",
"bulma": "^0.7.5", "bulma": "^0.7.5",
"css-loader": "^3.2.0", "css-loader": "^3.2.0",
"node-sass": "^4.12.0", "node-sass": "^4.12.0",
"sass-loader": "^7.3.1", "sass-loader": "^7.3.1",
"style-loader": "^1.0.0", "style-loader": "^1.0.0",
"webpack-dev-server": "^3.8.0" "wiki-list-editor": "^0.3.0"
}, },
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",

View File

@ -1,15 +1,4 @@
import EditorJS from '@editorjs/editorjs'; import listEditor from 'wiki-list-editor';
import Header from '@editorjs/header';
import List from '@editorjs/list';
import Table from '@editorjs/table';
import Checklist from '@editorjs/checklist';
import Code from '@editorjs/code';
import Marker from '@editorjs/marker';
import Link from '@editorjs/link';
import Attaches from '@editorjs/attaches';
import Image from '@editorjs/image';
import axios from 'axios'; import axios from 'axios';
import qs from 'querystring' import qs from 'querystring'
@ -64,46 +53,19 @@ function addIndicator(editor, indicator) {
} }
} }
const editor = new EditorJS({
holder: 'editor',
tools: {
header: {
class: Header
},
list: List,
table: Table,
checklist: Checklist,
code: Code,
marker: Marker,
link: {
class: Link,
config: {
endpoint: '/fetchLink'
}
},
attaches: {
class: Attaches
},
image: {
class: Image
}
},
onChange() {
let element = document.getElementById('editor');
let indicator = Indicator(document.getElementById('save-indicator'), 2);
let saveUrl = element.dataset.saveurl;
let page = element.dataset.page;
indicator.setText('has changes...'); let holder = document.getElementById('editor');
addIndicator( let editor = listEditor(holder, JSON.parse(holder.dataset.input));
addSaver(editor, saveUrl, page, () => indicator.setText('saving...')),
indicator editor.on('change', function () {
).save() let element = document.getElementById('editor');
}, let indicator = Indicator(document.getElementById('save-indicator'), 2);
onReady() { let saveUrl = element.dataset.saveurl;
let data = document.getElementById('editor').dataset.input; let page = element.dataset.page;
if (data) {
editor.blocks.render(JSON.parse(data)); indicator.setText('has changes...');
} addIndicator(
} addSaver(editor, saveUrl, page, () => indicator.setText('saving...')),
}); indicator
).save()
})

View File

@ -1,8 +1,6 @@
@import "~bulma"; @import "~bulma";
#editor { #editor {
max-width: 650px;
margin: 0 auto;
} }
#save-indicator { #save-indicator {

62
main.go
View File

@ -348,7 +348,7 @@ func (h *editHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
mpPage := mp.Get(page) mpPage := mp.Get(page)
pageText := mpPage.Content pageText := mpPage.Content
jsonEditor := pageText != "" && pageText[0] == '{' jsonEditor := pageText != "" && (pageText[0] == '{' || pageText[0] == '[')
var editor template.HTML var editor template.HTML
if jsonEditor { if jsonEditor {
@ -419,41 +419,51 @@ func (h *indexHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return return
} }
jsonPage := pageText != "" && pageText[0] == '{' jsonPage := pageText != "" && (pageText[0] == '[' || pageText[0] == '{')
if jsonPage { if jsonPage {
pageText, err = renderJSON(pageText) //pageText, err = renderJSON(pageText)
var listItems []struct {
Id int
Indented int
Text string
}
err = json.NewDecoder(strings.NewReader(pageText)).Decode(&listItems)
if err != nil { if err != nil {
http.Error(w, err.Error(), 500) http.Error(w, err.Error(), 500)
return return
} }
pageText = ""
for _, item := range listItems {
pageText += strings.Repeat(" ", item.Indented) + "* " + item.Text + "\n"
}
} }
if !jsonPage { hrefRE := regexp.MustCompile(`#?\[\[\s*([\w.\- ]+)\s*\]\]`)
hrefRE := regexp.MustCompile(`#?\[\[\s*([\w.\- ]+)\s*\]\]`)
pageText = hrefRE.ReplaceAllStringFunc(pageText, func(s string) string { pageText = hrefRE.ReplaceAllStringFunc(pageText, func(s string) string {
tag := false tag := false
if s[0] == '#' { if s[0] == '#' {
s = strings.TrimPrefix(s, "#[[") s = strings.TrimPrefix(s, "#[[")
tag = true tag = true
} else { } else {
s = strings.TrimPrefix(s, "[[") s = strings.TrimPrefix(s, "[[")
} }
s = strings.TrimSuffix(s, "]]") s = strings.TrimSuffix(s, "]]")
s = strings.TrimSpace(s) s = strings.TrimSpace(s)
if tag { if tag {
return fmt.Sprintf(`<a href=%q class="tag">%s</a>`, strings.Replace(s, " ", "_", -1), s) return fmt.Sprintf(`<a href=%q class="tag">%s</a>`, strings.Replace(s, " ", "_", -1), s)
} }
return fmt.Sprintf("[%s](/%s)", s, strings.Replace(s, " ", "_", -1)) return fmt.Sprintf("[%s](/%s)", s, strings.Replace(s, " ", "_", -1))
}) })
md := markdown.New( md := markdown.New(
markdown.HTML(true), markdown.HTML(true),
markdown.XHTMLOutput(true), markdown.XHTMLOutput(true),
) )
pageText = md.RenderToString([]byte(pageText)) pageText = md.RenderToString([]byte(pageText))
}
data := indexPage{ data := indexPage{
Session: sess, Session: sess,

View File

@ -33,6 +33,84 @@
align-self: center; align-self: center;
} }
</style> </style>
<style>
@import url('https://rsms.me/inter/inter.css');
html { font-family: 'Inter', sans-serif; }
input.input { font-family: 'Inter', sans-serif; }
@supports (font-variation-settings: normal) {
html { font-family: 'Inter var', sans-serif; }
input.input { font-family: 'Inter var', sans-serif; }
}
.list-item {
padding: 3px;
display: flex;
cursor: pointer;
margin-left: 32px;
flex-direction: column;
}
.line {
display: flex;
flex-direction: row;
align-items: center;
}
.marker {
border-radius: 50%;
background: black;
width: 6px;
height: 6px;
display: inline-block;
margin-right: 4px;
}
textarea {
border: none;
resize: none;
}
.selected {
background: lightblue;
}
.editor.selected {
background: none;
}
input.input {
border: none;
outline: none;
margin: 0;
padding: 0;
width: 100%;
font-size: 16px;
}
.gu-mirror {
position: fixed !important;
margin: 0 !important;
z-index: 9999 !important;
opacity: 0.8;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=80)";
filter: alpha(opacity=80);
}
.gu-hide {
display: none !important;
}
.gu-unselectable {
-webkit-user-select: none !important;
-moz-user-select: none !important;
-ms-user-select: none !important;
user-select: none !important;
}
.gu-transit {
opacity: 0.2;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=20)";
filter: alpha(opacity=20);
}
</style>
</head> </head>
<body> <body>
<div class="container"> <div class="container">