Add table rendering

This commit is contained in:
Peter Stuifzand 2020-10-25 15:22:49 +01:00
parent 0db1197daa
commit 84dd04d107
2 changed files with 161 additions and 91 deletions

View File

@ -142,19 +142,81 @@ function renderGraphs() {
}) })
} }
function createElement(tag, children) {
let el = document.createElement(tag)
_.each(children, item => {
el.appendChild(item)
})
return el
}
function Editor(holder, input) { function Editor(holder, input) {
let scope = {} let scope = {}
function renderInline(cellText) {
if (!cellText) return document.createTextNode('')
MD.options.html = true
let rendered = MD.renderInline(cellText)
let span = $("<span>"+rendered+"</span>")
MD.options.html = false
return span[0];
}
const options = { const options = {
transform(text, element) { transform(text, element, id, editor) {
if (text === undefined) { if (text === undefined) {
return; return;
} }
let converted = text let converted = text
if (converted.startsWith("```", 0) || converted.startsWith("$$", 0)) { if (converted === '{{table}}') {
editor.treeForId(id).then(tree => {
let [header, rows] = tree[0].children
let rowData = _.map(rows.children, row => {
let page = row.text.substring(2).substring(0, row.text.length-4)
return fetch('/'+page+'?format=metakv')
.then(res => res.json())
.then(res => [page, res.meta])
})
// FIXME: don't wait for promises here, but at the end
Promise.all(rowData).then(res => {
return _.fromPairs(res)
}).then(data => {
return createElement("table", [
createElement("thead", [
createElement("tr", [
createElement("th", [
document.createTextNode("Title")
]),
..._.map(header.children, col => {
return createElement("th", [
document.createTextNode(col.text)
])
})
]
),
]),
createElement("tbody",
_.map(rows.children, row => {
let page = row.text.substring(2).substring(0, row.text.length-4)
return createElement("tr", [
createElement("td", [renderInline(row.text)]),
..._.map(header.children, col => {
let td = createElement("td", []);
this.transform(data[page][col.text.toLowerCase()], $(td), id, editor)
return td
})
])
})
)
])
}).then(table => element.html(table))
})
return
} else if (converted.startsWith("```", 0) || converted.startsWith("$$", 0)) {
converted = MD.render(converted) converted = MD.render(converted)
} else if (converted.startsWith("=", 0)) { } else if (converted.startsWith("=", 0)) {
try { try {

View File

@ -10,21 +10,9 @@ import Store from './store'
textareaAutosizeInit($) textareaAutosizeInit($)
function editor(root, inputData, options) { function editor(root, inputData, options) {
root.classList.add('root')
root.setAttribute('tabindex', '-1')
let cursor = createCursor() let cursor = createCursor()
let selection = createSelection() let selection = createSelection()
let store = createStore(inputData);
let defaults = {
transform(text, element) {
element.html(he.encode(text))
}
}
options = _.merge(defaults, options)
let drake = null;
function createStore(inputData) { function createStore(inputData) {
let data = [ let data = [
@ -36,7 +24,98 @@ function editor(root, inputData, options) {
return Store(data); return Store(data);
} }
let store = createStore(inputData); function save() {
return new Promise(function (resolve, reject) {
if (store.hasChanged()) {
resolve(store.debug().result)
store.clearChanged()
} else {
reject()
}
});
}
function saveTree(from) {
return new Promise(function (resolve, reject) {
if (store.hasChanged()) {
resolve(store.tree(from))
store.clearChanged()
}
});
}
function treeForId(id) {
return new Promise(function (resolve, reject) {
resolve(store.tree(id))
})
}
function copy(element, opt) {
let item = $(element).parents('.list-item')
let id = item.data('id')
if (opt.recursive) {
return saveTree(id)
}
return new Promise(function (resolve, reject) {
resolve(store.value(id));
});
}
function zoomin(element, opt) {
let item = $(element).parents('.list-item')
let id = item.data('id')
return new Promise(function (resolve, reject) {
resolve(id);
});
}
function on(evt, handler) {
events[evt].push(handler)
}
function trigger(event) {
let args = [...arguments]
args.splice(0, 1)
_.each(events[event], function (handler) {
handler(...args)
})
}
function start() {
disableDragging(drake)
render(root, store);
drake = enableDragging(root)
cursor.set(0)
startEditing(root, store, cursor)
}
let EDITOR = {
on,
save,
saveTree,
copy,
update,
start,
zoomin,
treeForId
};
root.classList.add('root')
root.setAttribute('tabindex', '-1')
let defaults = {
transform(text, element) {
element.html(he.encode(text))
}
}
options = _.merge(defaults, options)
let drake = null;
let events = { let events = {
change: [], change: [],
@ -61,7 +140,7 @@ function editor(root, inputData, options) {
let line = $('<div class="line">') let line = $('<div class="line">')
let content = $('<div class="content">') let content = $('<div class="content">')
line.prepend(content) line.prepend(content)
options.transform(value.text, content) options.transform(value.text, content, value.id, EDITOR)
line.prepend($('<span class="marker"></span>')) line.prepend($('<span class="marker"></span>'))
line.prepend($('<span class="fold">&#9654;</span>')) line.prepend($('<span class="fold">&#9654;</span>'))
el.prepend(line) el.prepend(line)
@ -109,7 +188,7 @@ function editor(root, inputData, options) {
.find('.content') .find('.content')
value.hidden = value.indented >= hideLevel value.hidden = value.indented >= hideLevel
options.transform(value.text, $li) options.transform(value.text, $li, value.id, EDITOR)
if (value.indented < hideLevel) { if (value.indented < hideLevel) {
if (value.fold !== 'open') { if (value.fold !== 'open') {
@ -226,7 +305,7 @@ function editor(root, inputData, options) {
} }
let $span = $('<div class="content">'); let $span = $('<div class="content">');
options.transform(text, $span) options.transform(text, $span, element.data('id'), EDITOR)
element.replaceWith($span); element.replaceWith($span);
trigger('stop-editing', currentEditor[0]) trigger('stop-editing', currentEditor[0])
editing = false editing = false
@ -259,69 +338,6 @@ function editor(root, inputData, options) {
return $textarea return $textarea
} }
function save() {
return new Promise(function (resolve, reject) {
if (store.hasChanged()) {
resolve(store.debug().result)
store.clearChanged()
} else {
reject()
}
});
}
function saveTree(from) {
return new Promise(function (resolve, reject) {
if (store.hasChanged()) {
resolve(store.tree(from))
store.clearChanged()
}
});
}
function copy(element, opt) {
let item = $(element).parents('.list-item')
let id = item.data('id')
if (opt.recursive) {
return saveTree(id)
}
return new Promise(function (resolve, reject) {
resolve(store.value(id));
});
}
function zoomin(element, opt) {
let item = $(element).parents('.list-item')
let id = item.data('id')
return new Promise(function (resolve, reject) {
resolve(id);
});
}
function on(evt, handler) {
events[evt].push(handler)
}
function trigger(event) {
let args = [...arguments]
args.splice(0, 1)
_.each(events[event], function (handler) {
handler(...args)
})
}
function start() {
disableDragging(drake)
render(root, store);
drake = enableDragging(root)
cursor.set(0)
startEditing(root, store, cursor)
}
$(root).on('paste', '.input-line', function (event) { $(root).on('paste', '.input-line', function (event) {
let tag = event.target.tagName.toLowerCase(); let tag = event.target.tagName.toLowerCase();
if (tag === 'textarea' && currentEditor[0].value.substring(0, 3) === '```') { if (tag === 'textarea' && currentEditor[0].value.substring(0, 3) === '```') {
@ -510,15 +526,7 @@ function editor(root, inputData, options) {
} }
} }
return { return EDITOR;
on,
save,
saveTree,
copy,
update,
start,
zoomin
};
} }
export default editor export default editor