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:
Paul van Tilburg 2017-12-29 23:56:24 +01:00
parent 7f36f116a6
commit 09db743a9e
4 changed files with 141 additions and 124 deletions

View File

@ -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())
}

View File

@ -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();
});

View File

@ -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>

View File

@ -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 %}