wiki/editor/src/index.js
Peter Stuifzand f2cc16341d
All checks were successful
continuous-integration/drone/push Build is passing
Add autocomplete of page links
2020-05-31 22:08:36 +02:00

228 lines
7.0 KiB
JavaScript

import listEditor from 'wiki-list-editor';
import axios from 'axios';
import qs from 'querystring'
import $ from 'jquery';
import search from './search';
import createPageSearch from './fuse';
import Mustache from 'mustache';
import 'jquery-contextmenu';
import getCaretCoordinates from './caret-position'
import './styles.scss';
import '../node_modules/jquery-contextmenu/dist/jquery.contextMenu.css';
function addSaver(editor, saveUrl, page, beforeSave) {
return {
save() {
return editor.save().then(outputData => {
beforeSave()
let data = {
'json': 1,
'p': page,
'summary': "",
'content': JSON.stringify(outputData),
};
return axios.post(saveUrl, qs.encode(data))
})
}
}
}
function Indicator(element, timeout) {
let timeoutId;
return {
done() {
timeoutId = setTimeout(() => {
element.classList.add('hidden')
}, timeout * 1000);
},
setText(text) {
if (timeoutId) {
clearTimeout(timeoutId);
timeoutId = null;
}
element.innerText = text;
element.classList.remove('hidden')
},
}
}
function addIndicator(editor, indicator) {
return {
save() {
editor.save().then(() => {
indicator.setText('saved!');
indicator.done();
})
}
}
}
let holder = document.getElementById('editor');
if (holder) {
let editor = listEditor(holder, JSON.parse(holder.dataset.input));
editor.on('change', function () {
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...');
addIndicator(
addSaver(editor, saveUrl, page, () => indicator.setText('saving...')),
indicator
).save()
})
$(document).on('keydown', '#link-complete', function (event) {
if (!$('#link-complete:visible')) {
return true;
}
const $popup = $('#link-complete')
if (event.key === 'Escape') {
$popup.fadeOut()
return false;
}
if (event.key === 'Enter') {
const linkName = $popup.find('li.selected').text()
$popup.trigger('popup:selected', [linkName])
$popup.fadeOut()
return false
}
if (event.key === 'ArrowUp') {
const selected = $popup.find('li.selected')
const prev = selected.prev('li')
if (prev.length) {
prev.addClass('selected')
selected.removeClass('selected')
}
return false;
}
if (event.key === 'ArrowDown') {
const selected = $popup.find('li.selected')
const next = selected.next('li');
if (next.length) {
next.addClass('selected')
selected.removeClass('selected')
}
return false
}
return true
})
createPageSearch().then(function ({search}) {
editor.on('start-editing', function (input) {
const $lc = $('#link-complete')
$lc.on('popup:selected', function (event, linkName) {
let value = input.value
let end = input.selectionEnd
let start = value.lastIndexOf("[[", end)
end += 2
let startAndLink = value.substring(0, start) + "[[" + linkName + "]]"
input.value = startAndLink + value.substring(end)
input.selectionStart = startAndLink.length
input.selectionEnd = startAndLink.length
input.focus()
return true
})
$(input).on('keydown', function (event) {
const isVisible = $('#link-complete:visible').length > 0;
const $lc = $('#link-complete')
if (event.key === 'Escape' && isVisible) {
$lc.fadeOut()
return true
}
if (event.key === 'ArrowDown' && isVisible) {
$lc.focus()
$lc.find('li:first-child').addClass('selected')
return false
}
return true
})
$(input).on('keyup', function () {
let value = input.value
let end = input.selectionEnd
let start = value.lastIndexOf("[[", end)
let linkEnd = value.lastIndexOf("]]", end - 1)
if (start < linkEnd) {
return
}
let query = value.substring(start, end);
let results = search.search(query)
let pos = getCaretCoordinates(input, value.selectionEnd, {})
let off = $(input).offset()
pos.top += off.top + pos.height
pos.left += off.left
const $lc = $('#link-complete')
$lc.offset(pos)
var template = document.getElementById('link-template').innerHTML;
var rendered = Mustache.render(template, {results: results}, {}, ['[[', ']]']);
$lc.html(rendered).fadeIn()
})
})
editor.on('stop-editing', function (input) {
$('#link-complete').off()
})
})
$.contextMenu({
selector: '.marker',
items: {
copy: {
name: 'Copy',
callback: function (key, opt) {
editor.copy(this).then(result => {
console.log(result)
})
}
}
}
});
}
let timeout = null;
let searchInput = document.getElementById('search-input');
search(searchInput).then(searcher => {
searchInput.addEventListener('keyup', function (e) {
clearTimeout(timeout);
if (e.key === 'Escape') {
$(searchInput).val('');
$('#autocomplete').hide();
return;
}
timeout = setTimeout(function () {
let query = $(searchInput).val()
if (query === '') {
let autocomplete = document.getElementById('autocomplete');
$(autocomplete).hide()
return
}
$('#autocomplete').show()
let result = searcher.search(query)
const newpage = query.replace(/\s+/g, '_')
var template = document.getElementById('result-template').innerHTML;
var rendered = Mustache.render(template, {page: newpage, results: result}, {}, ['[[', ']]']);
let autocomplete = document.getElementById('autocomplete');
autocomplete.innerHTML = rendered;
}, 500)
})
})