Add edit page and callbacks
This commit is contained in:
parent
d8f37f27f8
commit
2ddb1281c1
|
@ -63,13 +63,7 @@ class TagOptions:
|
||||||
_PRIVATE_KEY = 'private'
|
_PRIVATE_KEY = 'private'
|
||||||
|
|
||||||
def __init__(self, **kwargs) -> None:
|
def __init__(self, **kwargs) -> None:
|
||||||
self.options = OrderedDict(**kwargs)
|
self.options: dict = OrderedDict(**kwargs)
|
||||||
# Tag value is a hyperlink
|
|
||||||
self.hyperlink: bool = kwargs.get('hyperlink', False)
|
|
||||||
# Tag value contains redstring interlinks
|
|
||||||
self.interlink: bool = kwargs.get('interlink', False)
|
|
||||||
# Hide the tag from unauthenticated viewers
|
|
||||||
self.private: bool = kwargs.get('private', False)
|
|
||||||
|
|
||||||
def to_json(self):
|
def to_json(self):
|
||||||
return self.options
|
return self.options
|
||||||
|
|
|
@ -10,12 +10,13 @@ from flask import (
|
||||||
Flask,
|
Flask,
|
||||||
redirect,
|
redirect,
|
||||||
render_template,
|
render_template,
|
||||||
|
request,
|
||||||
safe_join,
|
safe_join,
|
||||||
url_for,
|
url_for,
|
||||||
)
|
)
|
||||||
|
|
||||||
from redstring.library import generate_index_document, generate_default_document
|
from redstring.library import generate_index_document, generate_default_document
|
||||||
from redstring.parser import load, dump
|
from redstring.parser import load, dump, DocumentTab, DocumentTag, TagOptions, DocumentSubtag
|
||||||
|
|
||||||
|
|
||||||
CONFIG_ENVVAR = 'REDSTRING_CONFIG'
|
CONFIG_ENVVAR = 'REDSTRING_CONFIG'
|
||||||
|
@ -54,6 +55,47 @@ def new():
|
||||||
return redirect(url_for('document', document_id=document_id))
|
return redirect(url_for('document', document_id=document_id))
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/edit/<document_id>', methods=['GET', 'POST'])
|
||||||
|
def edit(document_id):
|
||||||
|
# Load the document to edit
|
||||||
|
doc_path = safe_join(current_app.config['root'], f'{document_id}.json')
|
||||||
|
if not os.path.isfile(doc_path):
|
||||||
|
return abort(404)
|
||||||
|
with open(doc_path) as f:
|
||||||
|
doc = load(f)
|
||||||
|
|
||||||
|
# Check for structural change requests
|
||||||
|
if add := request.args.get('add'):
|
||||||
|
if add == 'tab':
|
||||||
|
new_tab = DocumentTab('newtab', [])
|
||||||
|
doc.tabs.append(new_tab)
|
||||||
|
with open(doc_path, 'w') as f:
|
||||||
|
dump(doc, f)
|
||||||
|
return redirect(url_for('edit', document_id=document_id))
|
||||||
|
elif add == 'tag':
|
||||||
|
if tab_name := request.args.get('tab'):
|
||||||
|
tab = doc.get_tab(tab_name)
|
||||||
|
new_tag = DocumentTag('tag', '', TagOptions(private=True))
|
||||||
|
tab.tags.append(new_tag)
|
||||||
|
with open(doc_path, 'w') as f:
|
||||||
|
dump(doc, f)
|
||||||
|
return redirect(url_for('edit', document_id=document_id))
|
||||||
|
return abort(400)
|
||||||
|
elif add == 'subtag':
|
||||||
|
if tag_name := request.args.get('tag'):
|
||||||
|
tag = doc.get_tag(tag_name)
|
||||||
|
new_subtag = DocumentSubtag('subtag', '', TagOptions(private=True))
|
||||||
|
tag.subtags.append(new_subtag)
|
||||||
|
with open(doc_path, 'w') as f:
|
||||||
|
dump(doc, f)
|
||||||
|
return redirect(url_for('edit', document_id=document_id))
|
||||||
|
return abort(400)
|
||||||
|
|
||||||
|
# Otherwise, return the editor page
|
||||||
|
else:
|
||||||
|
return render_template('edit.jinja', document=doc, index=False)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description="Run the redstring server.")
|
parser = argparse.ArgumentParser(description="Run the redstring server.")
|
||||||
parser.add_argument("--config", help="Config file path.")
|
parser.add_argument("--config", help="Config file path.")
|
||||||
|
|
|
@ -101,12 +101,20 @@
|
||||||
table.page-table td:nth-child(2) {
|
table.page-table td:nth-child(2) {
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
table.page-table td:nth-child(2) a {
|
table.page-table a {
|
||||||
color: #8af;
|
color: #8af;
|
||||||
}
|
}
|
||||||
table.page-table td:nth-child(2) a:visited {
|
table.page-table a:visited {
|
||||||
color: #88f;
|
color: #88f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Edit page styling */
|
||||||
|
input.tag-name {
|
||||||
|
}
|
||||||
|
textarea.tag-value {
|
||||||
|
resize: none;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
{% block page_scripts %}{% endblock %}
|
{% block page_scripts %}{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
|
|
|
@ -0,0 +1,135 @@
|
||||||
|
{% extends 'base.jinja' %}
|
||||||
|
|
||||||
|
{% set page_title = document.get_tag_value('title', document.get_tag('id').value) -%}
|
||||||
|
{% set page_summary = document.get_tag_value('summary', '') %}
|
||||||
|
|
||||||
|
{% block page_scripts %}
|
||||||
|
<script>
|
||||||
|
var newTabCounter = 0;
|
||||||
|
|
||||||
|
function selectTab(name) {
|
||||||
|
|
||||||
|
let tab = document.getElementById("tab-" + name);
|
||||||
|
if (tab)
|
||||||
|
{
|
||||||
|
// Unselect all tabs and content
|
||||||
|
Array.from(document.getElementsByClassName("tab-content"))
|
||||||
|
.forEach(e => e.classList.remove("tab-down"));
|
||||||
|
Array.from(document.getElementsByClassName("tab-page"))
|
||||||
|
.forEach(e => e.classList.remove("tab-page-selected"));
|
||||||
|
// Select the new tab and content
|
||||||
|
tab.classList.add("tab-down");
|
||||||
|
let content = document.getElementById(name + "-page");
|
||||||
|
content.classList.add("tab-page-selected");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addTab() {
|
||||||
|
let newTabName = "newtab" + ++newTabCounter;
|
||||||
|
let tabsDiv = document.querySelector("#tabs");
|
||||||
|
let wrapper = document.querySelector("#wrapper");
|
||||||
|
let newTabTab = document.querySelector("#newtab");
|
||||||
|
|
||||||
|
// Add tab div
|
||||||
|
let newTab = document.createElement("div");
|
||||||
|
newTab.id = "tab-" + newTabName;
|
||||||
|
newTab.classList = "tab tab-content";
|
||||||
|
newTab.contenteditable = true;
|
||||||
|
newTab.innerText = newTabName;
|
||||||
|
newTab.onclick = function() { selectTab(newTabName); };
|
||||||
|
tabsDiv.insertBefore(newTab, newTabTab);
|
||||||
|
|
||||||
|
// Add page div
|
||||||
|
let newPage = document.createElement("div");
|
||||||
|
newPage.id = newTabName + "-page";
|
||||||
|
newPage.classList = "tag-page";
|
||||||
|
let newPageTable = document.createElement("table");
|
||||||
|
newPageTable.id = newTabName + "-page-table";
|
||||||
|
newPageTable.classList = "page-table";
|
||||||
|
wrapper.appendChild(newPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onload = function () {
|
||||||
|
// Respect fragment as a tab selector shortcut
|
||||||
|
if (window.location.hash) {
|
||||||
|
selectTab(window.location.hash.substring(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
{% endblock page_scripts %}
|
||||||
|
|
||||||
|
{% macro make_content_tab(tab, selected) -%}
|
||||||
|
<div id="tab-{{ tab.name }}" class="tab tab-content{% if selected %} tab-down{% endif %}{% if index %} tab-right{% endif %}" onclick="javascript:selectTab('{{ tab.name }}')">{{ tab.name }}</div>
|
||||||
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{% macro make_tab_page(tab, selected) %}
|
||||||
|
<div id="{{ tab.name }}-page" class="tab-page{% if selected %} tab-page-selected{% endif %}">
|
||||||
|
<table id="{{ tab.name }}-page-table" class="page-table">
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td><i>tab name</i></td>
|
||||||
|
<td><div contenteditable>{{ tab.name }}</div></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{% for tag in tab.tags %}
|
||||||
|
<tr>
|
||||||
|
{%- if tag.name == 'id' -%}
|
||||||
|
<td>{{ tag.name }}</td>
|
||||||
|
{%- else -%}
|
||||||
|
<td><div contenteditable>{{ tag.name }}</div></td>
|
||||||
|
{% endif %}
|
||||||
|
<td><div contenteditable>{{ tag.value }}</div></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
{%- if tag.subtags -%}
|
||||||
|
│
|
||||||
|
{%- else -%}
|
||||||
|
<a href="/edit/{{ document.get_tag('id').value }}?add=subtag&tag={{ tag.name }}">└ +</a>
|
||||||
|
{%- endif -%}</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{% for subtag in tag.subtags %}
|
||||||
|
<tr>
|
||||||
|
<td><div contenteditable>{{ subtag.name }}</div></td>
|
||||||
|
<td><div contenteditable>{{ subtag.value }}</div></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
{%- if not loop.last -%}
|
||||||
|
│
|
||||||
|
{%- else -%}
|
||||||
|
<a href="/edit/{{ document.get_tag('id').value }}?add=subtag&tag={{ tag.name }}">└ +</a>
|
||||||
|
{%- endif -%}
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td><a href="/edit/{{ document.get_tag('id').value }}?add=tag&tab={{ tab.name }}">Add tag</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
{# TODO: tab.priority support #}
|
||||||
|
{% block page_content %}
|
||||||
|
<div id="tabs">
|
||||||
|
{%- for tab in document -%}
|
||||||
|
{{ make_content_tab(tab, loop.first) }}
|
||||||
|
{%- endfor -%}
|
||||||
|
<div id="newtab" class="tab"><a href="/edit/{{ document.get_tag('id').value }}?add=tab">+</div>
|
||||||
|
<div id="index" class="tab tab-right"><a href="/index/">index</a></div>
|
||||||
|
</div>
|
||||||
|
{% for tab in document -%}
|
||||||
|
{{ make_tab_page(tab, loop.first) }}
|
||||||
|
{%- endfor -%}
|
||||||
|
{% endblock page_content %}
|
Loading…
Reference in New Issue