Rework the entire UI to support multiple lists in one view
* The root location now shows all lists * The specific list locations show only the specified list * Each list can be individually edited * Use the card columns (masonry) layout when showing all lists * No longer support HTML previewing, just switch between editing and viewing (ala Github comments)
This commit is contained in:
parent
7f36f116a6
commit
09db743a9e
10
src/main.rs
10
src/main.rs
|
@ -39,10 +39,10 @@ fn index(lists: State<ListStore>) -> Template {
|
|||
Template::render("index", &context)
|
||||
}
|
||||
|
||||
#[post("/lists", format = "application/json", data = "<tmp_list>")]
|
||||
fn list_new(tmp_list: Json<List>) -> Option<String> {
|
||||
let html = list::data_to_html(&tmp_list.data);
|
||||
Some(html)
|
||||
#[get("/lists", format = "application/json")]
|
||||
fn lists(lists: State<ListStore>) -> Option<Json<Vec<List>>> {
|
||||
let lists = lists.read().unwrap();
|
||||
Some(Json(lists.clone()))
|
||||
}
|
||||
|
||||
#[get("/lists/<list_id>", format = "text/html")]
|
||||
|
@ -71,7 +71,7 @@ fn rocket() -> Rocket {
|
|||
let lists = list::List::load_all();
|
||||
rocket::ignite()
|
||||
.manage(RwLock::new(lists))
|
||||
.mount("/", routes![index, list_new, list_show_html, list_show_json, list_update, static_files::all])
|
||||
.mount("/", routes![index, lists, list_show_html, list_show_json, list_update, static_files::all])
|
||||
.attach(Template::fairing())
|
||||
}
|
||||
|
||||
|
|
|
@ -1,129 +1,146 @@
|
|||
var curList;
|
||||
var lists;
|
||||
|
||||
var bgColors = ["info", "primary", "danger", "success", "warning", "secondary"];
|
||||
var textColors = ["light", "light", "light", "light", "dark", "dark" ];
|
||||
var bgColors = ["info", "primary", "danger", "success", "warning", "secondary"];
|
||||
var textColors = ["light", "light", "light", "light", "dark", "dark" ];
|
||||
|
||||
function getUrlListId() {
|
||||
var hash = window.location.hash;
|
||||
if (hash.length == 0) {
|
||||
if (hash.length <= 1) {
|
||||
return undefined;
|
||||
} else {
|
||||
return hash.substr(1, hash.length);
|
||||
}
|
||||
}
|
||||
|
||||
function enableEditMode() {
|
||||
if (curList) {
|
||||
$('#listData').html(curList.data);
|
||||
}
|
||||
$('#listData').show(250);
|
||||
$('#cancelButton').show(250);
|
||||
$('#editButton').hide(250);
|
||||
$('#saveButton').show(250);
|
||||
}
|
||||
|
||||
function disableEditMode() {
|
||||
$('#listData').hide();
|
||||
$('#cancelButton').hide();
|
||||
if (curList) {
|
||||
$('#editButton').show();
|
||||
} else {
|
||||
$('#editButton').hide();
|
||||
}
|
||||
$('#saveButton').hide();
|
||||
}
|
||||
|
||||
function triggerSelect(listId) {
|
||||
console.debug('Switch selection to list ' + listId);
|
||||
if (curList) {
|
||||
$('.nav-link[data-list-id="' + curList.id + '"]').removeClass('active');
|
||||
$('#listBox').removeClass("bg-" + bgColors[curList.index])
|
||||
.removeClass("text-" + textColors[curList.index]);
|
||||
}
|
||||
$('.nav-link[data-list-id="' + listId + '"]').addClass('active');
|
||||
disableEditMode();
|
||||
|
||||
function initLists() {
|
||||
$.ajax({
|
||||
url: '/lists/' + listId,
|
||||
headers: { 'Accept': 'text/html' }
|
||||
}).done(function(html) { $('#listHtml').html(html); });
|
||||
|
||||
$.ajax({
|
||||
url: '/lists/' + listId,
|
||||
url: '/lists',
|
||||
headers: { 'Accept': 'application/json' }
|
||||
}).done(function(list) {
|
||||
curList = list;
|
||||
$('#listBox').addClass("bg-" + bgColors[list.index])
|
||||
.addClass("text-" + textColors[list.index]);
|
||||
$('#listName').text(list.name);
|
||||
mtime = new Date(list.mtime.secs_since_epoch * 1000);
|
||||
$('#listUpdatedAt').text('Laaste aanpassing op ' +
|
||||
mtime.toLocaleDateString("nl") + ' om ' + mtime.toLocaleTimeString("nl"));
|
||||
$('#listData').val(list.data);
|
||||
$('#editButton').show();
|
||||
}).done(function(allLists) {
|
||||
lists = allLists;
|
||||
lists.forEach(updateList);
|
||||
|
||||
var curListId = getUrlListId();
|
||||
selectList(curListId);
|
||||
});
|
||||
}
|
||||
|
||||
function triggerUpdate(listId, data) {
|
||||
console.debug('Triggering HTML update for list ' + listId + ', data: ' + data);
|
||||
listCopy = Object.assign({}, curList);
|
||||
listCopy.data = data;
|
||||
|
||||
$.ajax({
|
||||
method: 'POST',
|
||||
url: '/lists',
|
||||
headers: { 'Accept': 'text/html',
|
||||
'Content-Type': 'application/json' },
|
||||
data: JSON.stringify(listCopy)
|
||||
}).done(function(html) { $("#listHtml").html(html) });
|
||||
function getListElem(listId) {
|
||||
return $('.list[data-list-id="' + listId + '"]');
|
||||
}
|
||||
|
||||
function saveUpdate(listId, data) {
|
||||
console.debug('Saving data update for list ' + listId);
|
||||
disableEditMode();
|
||||
curList.data = data;
|
||||
function selectList(listId) {
|
||||
if (listId) {
|
||||
console.debug("Selecting list " + listId);
|
||||
lists.forEach(function(list) {
|
||||
var listElem = getListElem(list.id);
|
||||
if (list.id == listId) {
|
||||
listElem.fadeIn(250);
|
||||
} else {
|
||||
listElem.fadeOut(250);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.debug("Showing all lists");
|
||||
lists.forEach(function(list) {
|
||||
var listElem = getListElem(list.id);
|
||||
listElem.fadeIn(250);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function updateList(list) {
|
||||
var listElem = $('.list[data-list-id="' + list.id + '"]');
|
||||
listElem.addClass("bg-" + bgColors[list.index])
|
||||
.addClass("text-" + textColors[list.index]);
|
||||
$('.list-name', listElem).text(list.name);
|
||||
mtime = new Date(list.mtime.secs_since_epoch * 1000);
|
||||
$('.list-updated-at', listElem).text('Laaste aanpassing op ' +
|
||||
mtime.toLocaleDateString("nl") + ' om ' + mtime.toLocaleTimeString("nl"));
|
||||
$('.list-data', listElem).val(list.data);
|
||||
|
||||
updateListHTML(listElem);
|
||||
|
||||
disableListEditMode(listElem);
|
||||
}
|
||||
|
||||
function updateListHTML(listElem) {
|
||||
var listId = listElem.data("list-id");
|
||||
$.ajax({
|
||||
url: '/lists/' + listId,
|
||||
headers: { 'Accept': 'text/html' }
|
||||
}).done(function(html) { $('.list-html', listElem).html(html); });
|
||||
}
|
||||
|
||||
function saveListChanges(listElem) {
|
||||
var listId = listElem.data("list-id");
|
||||
var list = lists.find(function(list) { return list.id == listId });
|
||||
list.data = $('.list-data', listElem).val();
|
||||
|
||||
$.ajax({
|
||||
method: 'PUT',
|
||||
url: '/lists/' + listId,
|
||||
headers: { 'Accept': 'application/json',
|
||||
'Content-Type': 'application/json' },
|
||||
data: JSON.stringify(curList)
|
||||
data: JSON.stringify(list)
|
||||
}).done(function(list) {
|
||||
mtime = new Date(list.mtime.secs_since_epoch * 1000);
|
||||
$('#listUpdatedAt').text('Laaste aanpassing op ' +
|
||||
$('.list-updated-at', listElem).text('Laaste aanpassing op ' +
|
||||
mtime.toLocaleDateString("nl") + ' om ' + mtime.toLocaleTimeString("nl"));
|
||||
$('#listData').val(list.data);
|
||||
$('.list-data', listElem).val(list.data);
|
||||
updateListHTML(listElem);
|
||||
disableListEditMode(listElem);
|
||||
});
|
||||
}
|
||||
|
||||
function revertListChanges(listElem) {
|
||||
var listId = listElem.data("list-id");
|
||||
var list = lists.find(function(list) { return list.id == listId });
|
||||
|
||||
disableListEditMode(listElem);
|
||||
|
||||
$('.list-data', listElem).val(list.data);
|
||||
}
|
||||
|
||||
function disableListEditMode(listElem) {
|
||||
$('.list-data', listElem).hide();
|
||||
$('.list-html', listElem).show();
|
||||
$('.list-cancel-button', listElem).hide();
|
||||
$('.list-edit-button', listElem).show();
|
||||
$('.list-save-button', listElem).hide();
|
||||
}
|
||||
|
||||
function enableListEditMode(listElem) {
|
||||
$('.list-data', listElem).show();
|
||||
$('.list-html', listElem).hide();
|
||||
$('.list-cancel-button', listElem).show();
|
||||
$('.list-edit-button', listElem).hide();
|
||||
$('.list-save-button', listElem).show();
|
||||
}
|
||||
|
||||
$(function() {
|
||||
$('#cancelButton').on('click', function() {
|
||||
disableEditMode();
|
||||
triggerUpdate(curList.id, curList.data);
|
||||
$('#listData').val(curList.data);
|
||||
$('.list-cancel-button').on('click', function() {
|
||||
var listElem = $(this).parents(".list");
|
||||
console.debug("Cancelling the edit of list " + listElem.data("list-id"));
|
||||
revertListChanges(listElem);
|
||||
});
|
||||
|
||||
$('#editButton').on('click', function() { enableEditMode(); });
|
||||
|
||||
$('#saveButton').on('click', function() {
|
||||
data = $('#listData').val();
|
||||
saveUpdate(curList.id, data);
|
||||
$('.list-edit-button').on('click', function() {
|
||||
var listElem = $(this).parents(".list");
|
||||
console.debug("Going to edit list " + listElem.data("list-id"));
|
||||
enableListEditMode(listElem);
|
||||
});
|
||||
|
||||
$('#listData').on('input', function() {
|
||||
data = this.value;
|
||||
triggerUpdate(curList.id, data);
|
||||
$('.list-save-button').on('click', function() {
|
||||
var listElem = $(this).parents(".list");
|
||||
console.debug("Saving the changes for list " + listElem.data("list-id"));
|
||||
saveListChanges(listElem);
|
||||
});
|
||||
|
||||
$('.listSelect').on('click', function() {
|
||||
listId = $(this).data("list-id");
|
||||
triggerSelect(listId);
|
||||
$('.list-select').on('click', function() {
|
||||
listId = $(this).data('list-id');
|
||||
selectList(listId);
|
||||
});
|
||||
|
||||
var listId = getUrlListId();
|
||||
if (listId) {
|
||||
triggerSelect(getUrlListId());
|
||||
}
|
||||
disableEditMode();
|
||||
initLists();
|
||||
});
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
{% block body %}
|
||||
<nav class="navbar navbar-expand-md fixed-top navbar-dark bg-dark" role="navigation">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="/">Online Prikbord</a>
|
||||
<a class="navbar-brand list-select" href="#">Online Prikbord</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
|
|
@ -5,45 +5,45 @@
|
|||
<ul class="navbar-nav mr-auto">
|
||||
{% for list in lists %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link listSelect" data-list-id="{{ list.id }}" href="#{{ list.id }}">{{ list.name }}</a>
|
||||
<a class="nav-link list-select" data-list-id="{{ list.id }}" href="#{{ list.id }}">{{ list.name }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<button class="btn btn-primary btn-sm float-right" id="editButton">
|
||||
<span class="glyphicon glyphicon-edit"></span>
|
||||
Bewerk
|
||||
</button>
|
||||
<div class="btn-group" role="group" aria-label="Edit buttons">
|
||||
<button class="btn btn-light btn-sm float-right" id="cancelButton">
|
||||
<span class="glyphicon glyphicon-save"></span>
|
||||
Annuleren
|
||||
</button>
|
||||
<button class="btn btn-primary btn-sm float-right" id="saveButton">
|
||||
<span class="glyphicon glyphicon-save"></span>
|
||||
Opslaan
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock navbar %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-3" id="listBox">
|
||||
<div class="card-header">
|
||||
<h1 class= "mb-0" id="listName"></h1>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="card-text" id="listHtml"></div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<p class="card-text"><small id="listUpdatedAt"></small></p>
|
||||
<div class="card-columns">
|
||||
{% for list in lists %}
|
||||
<div class="card list mb-3" style="display:none"; data-list-id="{{ list.id }}">
|
||||
<div class="card-header">
|
||||
<h1 class= "mb-0">
|
||||
<span id="list-name">{{ list.name }}</span>
|
||||
<button class="btn btn-dark btn-sm float-right list-edit-button">
|
||||
Bewerk
|
||||
</button>
|
||||
<div class="btn-group float-right" role="group" aria-label="Edit buttons">
|
||||
<button class="btn btn-light btn-sm list-cancel-button">
|
||||
Annuleren
|
||||
</button>
|
||||
<button class="btn btn-dark btn-sm list-save-button">
|
||||
Opslaan
|
||||
</button>
|
||||
</div>
|
||||
</h1>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="card-text list-html"></div>
|
||||
<div class="card-text">
|
||||
<textarea class="form-control list-data" rows="15"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<p class="card-text"><small class="list-updated-at"></small></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<textarea class="form-control" id="listData" rows="25"></textarea>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
||||
|
|
Loading…
Reference in New Issue