Rename list to note throughout the application

This commit is contained in:
Paul van Tilburg 2018-01-26 21:18:04 +01:00
parent 2c46179f4f
commit 67d55cadc4
18 changed files with 309 additions and 244 deletions

10
notes/_test.note Normal file
View File

@ -0,0 +1,10 @@
* Eerste item
* Tweede item
---
#### Nog veel meer, maar later
* Dit
* Dat
---
Nog een lijn?

1
notes/leeg.note Normal file
View File

@ -0,0 +1 @@

20
notes/markdown.note Normal file
View File

@ -0,0 +1,20 @@
## Kop 2
### Kop 3
#### Kop 4
_Schuingedrukt_
**Vetgedruk**
~Doorgestreept~
* Item 1
* Item 2
#####
* [ ] Wil ik graag
* [ ] Wil ik ook graag
* [x] Heb ik al!
[Linktekst](http://google.nl)
---
Horizontale lijn

11
notes/quoot.note Normal file
View File

@ -0,0 +1,11 @@
Wat zullen we eens wegzetten? Dit, misschien:
> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
> eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
> enim ad minim veniam, quis nostrud exercitation ullamco laboris
> nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
> reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
> pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
> culpa qui officia deserunt mollit anim id est laborum.
Van http://lipsum.com

23
notes/zandbak.note Normal file
View File

@ -0,0 +1,23 @@
_Niets!_
**Echt niets?**
Hier is een link: http://rust-lang.org/, maar deze is mooier: [Rust homepage](http://rust-lang.org)
Tralalaaaa!
Leuke <textarea>HTML nesting</textarea>?
~Nee, dat werkt niet~
##### Kop 5
* [ ] Item a
* [ ] Item b
* [x] Item c
UTF8 test⸘
3.1.3 2 continuation bytes: "<22><>" |
3.1.4 3 continuation bytes: "<22><><EFBFBD>" |
3.1.5 4 continuation bytes: "<22><><EFBFBD><EFBFBD>" |
3.1.6 5 continuation bytes: "<22><><EFBFBD><EFBFBD><EFBFBD>" |
3.1.7 6 continuation bytes: "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>" |
3.1.8 7 continuation bytes: "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>" |

View File

@ -1,27 +1,27 @@
use rocket::State; use rocket::State;
use rocket_contrib::Template; use rocket_contrib::Template;
use std::collections::HashMap; use std::collections::HashMap;
use super::super::ListStore; use super::super::NoteStore;
#[derive(Serialize)] #[derive(Serialize)]
struct IndexTemplateContext<'a> { struct IndexTemplateContext<'a> {
app_version: &'a str, app_version: &'a str,
lists: Vec<HashMap<&'a str, &'a str>> notes: Vec<HashMap<&'a str, &'a str>>
} }
#[get("/")] #[get("/")]
fn index(lists: State<ListStore>) -> Template { fn index(notes: State<NoteStore>) -> Template {
let lists = lists.read().unwrap(); let notes = notes.read().unwrap();
let mut list_kvs = vec![]; let mut note_kvs = vec![];
for list in lists.iter() { for note in notes.iter() {
let mut list_kv = HashMap::new(); let mut note_kv = HashMap::new();
list_kv.insert("id", list.id.as_ref()); note_kv.insert("id", note.id.as_ref());
list_kv.insert("name", list.name.as_ref()); note_kv.insert("name", note.name.as_ref());
list_kvs.push(list_kv); note_kvs.push(note_kv);
} }
let context = IndexTemplateContext { let context = IndexTemplateContext {
app_version: env!("CARGO_PKG_VERSION"), app_version: env!("CARGO_PKG_VERSION"),
lists: list_kvs notes: note_kvs
}; };
Template::render("index", &context) Template::render("index", &context)
} }
@ -42,6 +42,6 @@ mod tests {
let body = res.body_string().unwrap(); let body = res.body_string().unwrap();
println!("body: {}", body); println!("body: {}", body);
assert!(body.contains("<span id=\"list-name\">Test</span>")); assert!(body.contains("<span id=\"note-name\">Test</span>"));
} }
} }

View File

@ -1,3 +1,3 @@
pub mod home; pub mod home;
pub mod list; pub mod note;
pub mod static_files; pub mod static_files;

View File

@ -1,34 +1,34 @@
use rocket::State; use rocket::State;
use rocket_contrib::Json; use rocket_contrib::Json;
use super::super::ListStore; use super::super::NoteStore;
use super::super::models::list::List; use super::super::models::note::Note;
#[get("/", format = "application/json")] #[get("/", format = "application/json")]
fn index(lists: State<ListStore>) -> Option<Json<Vec<List>>> { fn index(notes: State<NoteStore>) -> Option<Json<Vec<Note>>> {
let lists = lists.read().unwrap(); let notes = notes.read().unwrap();
Some(Json(lists.clone())) Some(Json(notes.clone()))
} }
#[get("/<list_id>", format = "text/html")] #[get("/<note_id>", format = "text/html")]
fn show_html(list_id: String, lists: State<ListStore>) -> Option<String> { fn show_html(note_id: String, notes: State<NoteStore>) -> Option<String> {
let lists = lists.read().unwrap(); let notes = notes.read().unwrap();
let list = lists.iter().find( |list| list.id == list_id )?; let note = notes.iter().find( |note| note.id == note_id )?;
Some(list.to_html()) Some(note.to_html())
} }
#[get("/<list_id>", format = "application/json")] #[get("/<note_id>", format = "application/json")]
fn show_json(list_id: String, lists: State<ListStore>) -> Option<Json<List>> { fn show_json(note_id: String, notes: State<NoteStore>) -> Option<Json<Note>> {
let lists = lists.read().unwrap(); let notes = notes.read().unwrap();
let list = lists.iter().find( |list| list.id == list_id )?; let note = notes.iter().find( |note| note.id == note_id )?;
Some(Json(list.clone())) Some(Json(note.clone()))
} }
#[put("/<list_id>", format = "application/json", data = "<new_list>")] #[put("/<note_id>", format = "application/json", data = "<new_note>")]
fn update(list_id: String, new_list: Json<List>, lists: State<ListStore>) -> Option<Json<List>> { fn update(note_id: String, new_note: Json<Note>, notes: State<NoteStore>) -> Option<Json<Note>> {
let mut lists = lists.write().unwrap(); let mut notes = notes.write().unwrap();
let list = lists.iter_mut().find( |list| list.id == list_id )?; let note = notes.iter_mut().find( |note| note.id == note_id )?;
list.update_data(&new_list.data); note.update_data(&new_note.data);
Some(Json(list.clone())) Some(Json(note.clone()))
} }
#[cfg(test)] #[cfg(test)]
@ -43,21 +43,21 @@ mod tests {
fn index() { fn index() {
let client = Client::new(rocket(Some("test"))).unwrap(); let client = Client::new(rocket(Some("test"))).unwrap();
// Try to get all the lists // Try to get all the notes
let mut res = client.get("/lists").header(Accept::JSON).dispatch(); let mut res = client.get("/notes").header(Accept::JSON).dispatch();
assert_eq!(res.status(), Status::Ok); assert_eq!(res.status(), Status::Ok);
let body = res.body_string().unwrap(); let body = res.body_string().unwrap();
let lists = serde_json::from_str::<Vec<List>>(body.as_str()).unwrap(); let notes = serde_json::from_str::<Vec<Note>>(body.as_str()).unwrap();
assert_eq!(lists[0].id, "test"); assert_eq!(notes[0].id, "test");
assert_eq!(lists[0].index, 0); assert_eq!(notes[0].index, 0);
assert_eq!(lists[0].name, "Test"); assert_eq!(notes[0].name, "Test");
assert_eq!(lists[0].data, "This is a test list\n\n* One\n* Two\n* Three\n"); assert_eq!(notes[0].data, "This is a test list\n\n* One\n* Two\n* Three\n");
// The mtime field can vary, don't test for it // The mtime field can vary, don't test for it
// The path field is private, also don't test for it // The path field is private, also don't test for it
// Cannot get the lists in HTML format // Cannot get the notes in HTML format
let res = client.get("/lists").header(Accept::HTML).dispatch(); let res = client.get("/notes").header(Accept::HTML).dispatch();
assert_eq!(res.status(), Status::NotFound); assert_eq!(res.status(), Status::NotFound);
} }
@ -65,8 +65,8 @@ mod tests {
fn show_html() { fn show_html() {
let client = Client::new(rocket(Some("test"))).unwrap(); let client = Client::new(rocket(Some("test"))).unwrap();
// Try to get the list and verify the body // Try to get the note and verify the body
let mut res = client.get("/lists/test").header(Accept::HTML).dispatch(); let mut res = client.get("/notes/test").header(Accept::HTML).dispatch();
assert_eq!(res.status(), Status::Ok); assert_eq!(res.status(), Status::Ok);
let body = res.body_string().unwrap(); let body = res.body_string().unwrap();
@ -84,21 +84,21 @@ mod tests {
fn show_json() { fn show_json() {
let client = Client::new(rocket(Some("test"))).unwrap(); let client = Client::new(rocket(Some("test"))).unwrap();
// Try to get the list and verify the body // Try to get the note and verify the body
let mut res = client.get("/lists/test").header(Accept::JSON).dispatch(); let mut res = client.get("/notes/test").header(Accept::JSON).dispatch();
assert_eq!(res.status(), Status::Ok); assert_eq!(res.status(), Status::Ok);
let body = res.body_string().unwrap(); let body = res.body_string().unwrap();
let list = serde_json::from_str::<List>(body.as_str()).unwrap(); let note = serde_json::from_str::<Note>(body.as_str()).unwrap();
assert_eq!(list.id, "test"); assert_eq!(note.id, "test");
assert_eq!(list.index, 0); assert_eq!(note.index, 0);
assert_eq!(list.name, "Test"); assert_eq!(note.name, "Test");
assert_eq!(list.data, "This is a test list\n\n* One\n* Two\n* Three\n"); assert_eq!(note.data, "This is a test list\n\n* One\n* Two\n* Three\n");
// The mtime field can vary, don't test for it // The mtime field can vary, don't test for it
// The path field is private, also don't test for it // The path field is private, also don't test for it
// Try to get a list that doesn't exist // Try to get a note that doesn't exist
let res = client.get("/lists/doesntexit").header(Accept::JSON).dispatch(); let res = client.get("/notes/doesntexit").header(Accept::JSON).dispatch();
assert_eq!(res.status(), Status::NotFound); assert_eq!(res.status(), Status::NotFound);
// FIXME: Test that there is some kind of error in the JSON // FIXME: Test that there is some kind of error in the JSON
@ -108,13 +108,13 @@ mod tests {
fn update() { fn update() {
let client = Client::new(rocket(Some("test"))).unwrap(); let client = Client::new(rocket(Some("test"))).unwrap();
// Try to get the list and determine what to change it to // Try to get the note and determine what to change it to
let mut res = client.get("/lists/updatable").header(Accept::JSON).dispatch(); let mut res = client.get("/notes/updatable").header(Accept::JSON).dispatch();
let body = res.body_string().unwrap(); let body = res.body_string().unwrap();
let list = serde_json::from_str::<List>(body.as_str()).unwrap(); let note = serde_json::from_str::<Note>(body.as_str()).unwrap();
assert_eq!(list.data, "Some content"); assert_eq!(note.data, "Some content");
// Try to change the list data, then verify it was changed // Try to change the note data, then verify it was changed
let new_data = "New content"; let new_data = "New content";
let mut new_json: serde_json::Value = json!({ let mut new_json: serde_json::Value = json!({
"id": "updatable", "id": "updatable",
@ -125,45 +125,45 @@ mod tests {
"nanos_since_epoch": 0 "nanos_since_epoch": 0
}, },
"name": "Updatable", "name": "Updatable",
"path": "test/lists/updatablelist" "path": "test/notes/updatablenote"
}); });
let res = client.put("/lists/updatable") let res = client.put("/notes/updatable")
.header(ContentType::JSON) .header(ContentType::JSON)
.body(new_json.to_string()) .body(new_json.to_string())
.dispatch(); .dispatch();
assert_eq!(res.status(), Status::Ok); assert_eq!(res.status(), Status::Ok);
let mut res = client.get("/lists/updatable") let mut res = client.get("/notes/updatable")
.header(Accept::JSON) .header(Accept::JSON)
.dispatch(); .dispatch();
let body = res.body_string().unwrap(); let body = res.body_string().unwrap();
let list = serde_json::from_str::<List>(body.as_str()).unwrap(); let note = serde_json::from_str::<Note>(body.as_str()).unwrap();
assert_eq!(list.data, new_data); assert_eq!(note.data, new_data);
// ... and change it back // ... and change it back
*new_json.get_mut("data").unwrap() = json!("Some content"); *new_json.get_mut("data").unwrap() = json!("Some content");
let res = client.put("/lists/updatable") let res = client.put("/notes/updatable")
.header(ContentType::JSON) .header(ContentType::JSON)
.body(new_json.to_string()) .body(new_json.to_string())
.dispatch(); .dispatch();
assert_eq!(res.status(), Status::Ok); assert_eq!(res.status(), Status::Ok);
// Try to change a list that doesn't exist // Try to change a note that doesn't exist
let res = client.put("/lists/doesntexit") let res = client.put("/notes/doesntexit")
.header(ContentType::JSON) .header(ContentType::JSON)
.body(new_json.to_string()) .body(new_json.to_string())
.dispatch(); .dispatch();
assert_eq!(res.status(), Status::NotFound); assert_eq!(res.status(), Status::NotFound);
// Try to change a list without a proper body // Try to change a note without a proper body
let res = client.put("/lists/updatable") let res = client.put("/notes/updatable")
.header(ContentType::JSON) .header(ContentType::JSON)
.body(r#"{}"#) .body(r#"{}"#)
.dispatch(); .dispatch();
assert_eq!(res.status(), Status::BadRequest); assert_eq!(res.status(), Status::BadRequest);
// Try to change a list without a proper type (i.e. not JSON) // Try to change a note without a proper type (i.e. not JSON)
let res = client.put("/lists/updatable") let res = client.put("/notes/updatable")
.header(ContentType::Plain) .header(ContentType::Plain)
.body("foo bar baz") .body("foo bar baz")
.dispatch(); .dispatch();

View File

@ -15,17 +15,17 @@ mod models;
use rocket::Rocket; use rocket::Rocket;
use std::sync::RwLock; use std::sync::RwLock;
type ListStore = RwLock<Vec<models::list::List>>; type NoteStore = RwLock<Vec<models::note::Note>>;
fn rocket(lists_path: Option<&str>) -> Rocket { fn rocket(notes_path: Option<&str>) -> Rocket {
let lists = models::list::List::load_all(lists_path); let notes = models::note::Note::load_all(notes_path);
rocket::ignite() rocket::ignite()
.manage(RwLock::new(lists)) .manage(RwLock::new(notes))
.mount("/", routes![handlers::home::index, .mount("/", routes![handlers::home::index,
handlers::static_files::all]) handlers::static_files::all])
.mount("/lists", routes![handlers::list::index, .mount("/notes", routes![handlers::note::index,
handlers::list::show_html, handlers::list::show_json, handlers::note::show_html, handlers::note::show_json,
handlers::list::update]) handlers::note::update])
.attach(rocket_contrib::Template::fairing()) .attach(rocket_contrib::Template::fairing())
} }

View File

@ -1 +1 @@
pub mod list; pub mod note;

View File

@ -7,23 +7,23 @@ use std::path::PathBuf;
use std::time::SystemTime; use std::time::SystemTime;
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
/// Structure for representing a wish list /// Structure for representing a wish note
pub struct List { pub struct Note {
/// The ID of the list (unique string) /// The ID of the note (unique string)
pub id: String, pub id: String,
/// The index of the list (unique number) /// The index of the note (unique number)
pub index: i8, pub index: i8,
/// The raw list data /// The raw note data
pub data: String, pub data: String,
/// The time the list was last modified /// The time the note was last modified
pub mtime: SystemTime, pub mtime: SystemTime,
/// The name of the list, i.e. the person it is for /// The name of the note, i.e. the person it is for
pub name: String, pub name: String,
/// The path to the list file /// The path to the note file
path: PathBuf path: PathBuf
} }
impl List { impl Note {
pub fn to_html(&self) -> String { pub fn to_html(&self) -> String {
let mut options = comrak::ComrakOptions::default(); let mut options = comrak::ComrakOptions::default();
options.ext_strikethrough = true; options.ext_strikethrough = true;
@ -36,10 +36,10 @@ impl List {
pub fn update_data(&mut self, data : &String) { pub fn update_data(&mut self, data : &String) {
let mut file = File::create(&self.path) let mut file = File::create(&self.path)
.expect(&format!("Cannot open list file {}", .expect(&format!("Cannot open note file {}",
self.path.to_str().unwrap())); self.path.to_str().unwrap()));
file.write_all(data.as_bytes()) file.write_all(data.as_bytes())
.expect(&format!("Cannot write list file {}", .expect(&format!("Cannot write note file {}",
self.path.to_str().unwrap())); self.path.to_str().unwrap()));
self.data = data.clone(); self.data = data.clone();
@ -47,12 +47,12 @@ impl List {
self.mtime = metadata.modified().unwrap(); self.mtime = metadata.modified().unwrap();
} }
pub fn load_all(list_path: Option<&str>) -> Vec<Self> { pub fn load_all(note_path: Option<&str>) -> Vec<Self> {
let mut lists : Vec<List> = vec![]; let mut notes : Vec<Note> = vec![];
let mut index = 0; let mut index = 0;
let path_glob = match list_path { let path_glob = match note_path {
Some(dir) => format!("{}/lists/*.list", dir), Some(dir) => format!("{}/notes/*.note", dir),
None => format!("lists/*.list") None => format!("notes/*.note")
}; };
for entry in glob(path_glob.as_str()).unwrap().filter_map(Result::ok) { for entry in glob(path_glob.as_str()).unwrap().filter_map(Result::ok) {
let file_name = entry.file_name().unwrap().to_str().unwrap(); let file_name = entry.file_name().unwrap().to_str().unwrap();
@ -62,13 +62,13 @@ impl List {
}; };
let mut data = String::new(); let mut data = String::new();
let mut file = File::open(&entry) let mut file = File::open(&entry)
.expect(&format!("Cannot open list file {}", file_name)); .expect(&format!("Cannot open note file {}", file_name));
file.read_to_string(&mut data) file.read_to_string(&mut data)
.expect(&format!("Cannot read list file {}", file_name)); .expect(&format!("Cannot read note file {}", file_name));
let metadata = file.metadata() let metadata = file.metadata()
.expect(&format!("Cannot get metadata of list file {}", file_name)); .expect(&format!("Cannot get metadata of note file {}", file_name));
let mut list = List { let mut note = Note {
id: String::from(name), id: String::from(name),
index : index, index : index,
data: data, data: data,
@ -76,10 +76,10 @@ impl List {
name: String::from(name).to_title_case(), name: String::from(name).to_title_case(),
path: entry.clone() path: entry.clone()
}; };
lists.push(list); notes.push(note);
index += 1; index += 1;
} }
lists notes
} }
} }
@ -88,20 +88,20 @@ mod tests {
use super::*; use super::*;
#[test] #[test]
fn loads_all_lists() { fn loads_all_notes() {
let lists = List::load_all(Some("test")); let notes = Note::load_all(Some("test"));
let list_ids: Vec<&str> = lists.iter() let note_ids: Vec<&str> = notes.iter()
.map(|list| list.id.as_ref()).collect(); .map(|note| note.id.as_ref()).collect();
assert_eq!(list_ids, vec!["test", "updatable"]); assert_eq!(note_ids, vec!["test", "updatable"]);
} }
#[test] #[test]
fn converts_to_html() { fn converts_to_html() {
let lists = List::load_all(Some("test")); let notes = Note::load_all(Some("test"));
let list = lists.iter() let note = notes.iter()
.find(|list| list.id == "test") .find(|note| note.id == "test")
.unwrap(); .unwrap();
assert_eq!(list.to_html(), r#"<p>This is a test list</p> assert_eq!(note.to_html(), r#"<p>This is a test list</p>
<ul> <ul>
<li>One</li> <li>One</li>
<li>Two</li> <li>Two</li>
@ -112,26 +112,26 @@ mod tests {
#[test] #[test]
fn updates_data() { fn updates_data() {
let mut lists = List::load_all(Some("test")); let mut notes = Note::load_all(Some("test"));
let list = lists.iter_mut() let note = notes.iter_mut()
.find(|list| list.id == "updatable") .find(|note| note.id == "updatable")
.unwrap(); .unwrap();
assert_eq!(list.data, "Some content"); assert_eq!(note.data, "Some content");
// Update the data van verify it has changed // Update the data van verify it has changed
let new_data = "New content"; let new_data = "New content";
list.update_data(&String::from(new_data)); note.update_data(&String::from(new_data));
assert_eq!(list.data, new_data); assert_eq!(note.data, new_data);
// Verify that the data is written to the file of the list by // Verify that the data is written to the file of the note by
// loading them again // loading them again
let mut lists = List::load_all(Some("test")); let mut notes = Note::load_all(Some("test"));
let list = lists.iter_mut() let note = notes.iter_mut()
.find(|list| list.id == "updatable") .find(|note| note.id == "updatable")
.unwrap(); .unwrap();
assert_eq!(list.data, new_data); assert_eq!(note.data, new_data);
// ... and change it back again // ... and change it back again
list.update_data(&String::from("Some content")); note.update_data(&String::from("Some content"));
} }
} }

View File

@ -1,9 +1,9 @@
var lists; var notes;
var bgColors = ["info", "primary", "danger", "success", "warning", "secondary"]; var bgColors = ["info", "primary", "danger", "success", "warning", "secondary"];
var textColors = ["light", "light", "light", "light", "dark", "dark" ]; var textColors = ["light", "light", "light", "light", "dark", "dark" ];
function getUrlListId() { function getUrlNoteId() {
var hash = window.location.hash; var hash = window.location.hash;
if (hash.length <= 1) { if (hash.length <= 1) {
return undefined; return undefined;
@ -24,16 +24,16 @@ function showErrorDialog(title, html, buttons) {
errorDialog.modal(); errorDialog.modal();
} }
function initLists() { function initNotes() {
$.ajax({ $.ajax({
url: '/lists', url: '/notes',
headers: { 'Accept': 'application/json' } headers: { 'Accept': 'application/json' }
}).done(function(allLists) { }).done(function(allNotes) {
lists = allLists; notes = allNotes;
lists.forEach(updateList); notes.forEach(updateNote);
var curListId = getUrlListId(); var curNoteId = getUrlNoteId();
selectList(curListId); selectNote(curNoteId);
}).fail(function(jqXHR, textMsg, error) { }).fail(function(jqXHR, textMsg, error) {
showErrorDialog("Laden mislukt!", showErrorDialog("Laden mislukt!",
"<p>Kan de lijsten niet laden!</p>" + "<p>Kan de lijsten niet laden!</p>" +
@ -44,100 +44,100 @@ function initLists() {
}); });
} }
function getListElem(listId) { function getNoteElem(noteId) {
return $('.list[data-list-id="' + listId + '"]'); return $('.note[data-note-id="' + noteId + '"]');
} }
function selectList(listId) { function selectNote(noteId) {
if (listId) { if (noteId) {
console.debug("Selecting list " + listId); console.debug("Selecting note " + noteId);
lists.forEach(function(list) { notes.forEach(function(note) {
var listElem = getListElem(list.id); var noteElem = getNoteElem(note.id);
if (list.id == listId) { if (note.id == noteId) {
listElem.show(200); noteElem.show(200);
} else { } else {
listElem.hide(200); noteElem.hide(200);
} }
}); });
} else { } else {
console.debug("Showing all lists"); console.debug("Showing all notes");
lists.forEach(function(list) { notes.forEach(function(note) {
var listElem = getListElem(list.id); var noteElem = getNoteElem(note.id);
listElem.show(200); noteElem.show(200);
}); });
} }
$("#navbarNav").collapse('hide'); $("#navbarNav").collapse('hide');
} }
function updateList(list) { function updateNote(note) {
var listElem = $('.list[data-list-id="' + list.id + '"]'); var noteElem = $('.note[data-note-id="' + note.id + '"]');
listElem.addClass("bg-" + bgColors[list.index]) noteElem.addClass("bg-" + bgColors[note.index])
.addClass("text-" + textColors[list.index]); .addClass("text-" + textColors[note.index]);
$('.list-name', listElem).text(list.name); $('.note-name', noteElem).text(note.name);
mtime = new Date(list.mtime.secs_since_epoch * 1000); mtime = new Date(note.mtime.secs_since_epoch * 1000);
$('.list-updated-at', listElem).text('Laatste aanpassing op ' + $('.note-updated-at', noteElem).text('Laatste aanpassing op ' +
mtime.toLocaleDateString("nl") + ' om ' + mtime.toLocaleTimeString("nl")); mtime.toLocaleDateString("nl") + ' om ' + mtime.toLocaleTimeString("nl"));
$('.list-data', listElem).val(list.data); $('.note-data', noteElem).val(note.data);
updateListHTML(listElem); updateNoteHTML(noteElem);
disableListEditMode(listElem); disableNoteEditMode(noteElem);
} }
function updateListHTML(listElem) { function updateNoteHTML(noteElem) {
var listId = listElem.data("list-id"); var noteId = noteElem.data("note-id");
var listHtmlElem = $('.list-html', listElem) var noteHtmlElem = $('.note-html', noteElem)
$.ajax({ $.ajax({
url: '/lists/' + listId, url: '/notes/' + noteId,
headers: { 'Accept': 'text/html' } headers: { 'Accept': 'text/html' }
}).done(function(html) { }).done(function(html) {
listHtmlElem.html(html); noteHtmlElem.html(html);
$("ul > li", listHtmlElem).has('input[type="checkbox"]') $("ul > li", noteHtmlElem).has('input[type="checkbox"]')
.parent() .parent()
.addClass("tasklist"); .addClass("tasknote");
if (listHtmlElem.find('hr').length) { if (noteHtmlElem.find('hr').length) {
listHtmlElem.find('hr') noteHtmlElem.find('hr')
.nextAll() .nextAll()
.wrapAll('<div class="collapse list-more"/>') .wrapAll('<div class="collapse note-more"/>')
listHtmlElem.append('<div class="row justify-content-center">' + noteHtmlElem.append('<div class="row justify-content-center">' +
'<button class="btn btn-sm btn-light text-dark list-more-toggle" '+ '<button class="btn btn-sm btn-light text-dark note-more-toggle" '+
'data-toggle="collapse" ' + 'data-toggle="collapse" ' +
'data-target=".list[data-list-id=\'' + listId + '\'] .list-more">' + 'data-target=".note[data-note-id=\'' + noteId + '\'] .note-more">' +
'Meer…</button>' + 'Meer…</button>' +
'</div>'); '</div>');
var listMoreButton = listHtmlElem.find(".list-more-toggle"); var noteMoreButton = noteHtmlElem.find(".note-more-toggle");
listHtmlElem.find('.list-more') noteHtmlElem.find('.note-more')
.on('shown.bs.collapse', function() { .on('shown.bs.collapse', function() {
listMoreButton.text('Minder…'); noteMoreButton.text('Minder…');
}).on('hidden.bs.collapse', function() { }).on('hidden.bs.collapse', function() {
listMoreButton.text('Meer…'); noteMoreButton.text('Meer…');
}); });
} }
}).fail(function(html, textMsg, error) { }).fail(function(html, textMsg, error) {
listHtmlElem.html("<h3><i>Kan lijst niet tonen!</i></h3>" + noteHtmlElem.html("<h3><i>Kan lijst niet tonen!</i></h3>" +
"<p class='pt-2'><small><i>(Technische foutmelding: " + error + "<p class='pt-2'><small><i>(Technische foutmelding: " + error +
" (" + textMsg + "))<i></small></p>"); " (" + textMsg + "))<i></small></p>");
}); });
} }
function saveListChanges(listElem) { function saveNoteChanges(noteElem) {
var listId = listElem.data("list-id"); var noteId = noteElem.data("note-id");
var list = lists.find(function(list) { return list.id == listId }); var note = notes.find(function(note) { return note.id == noteId });
var old_data = list.data; var old_data = note.data;
list.data = $('.list-data', listElem).val(); note.data = $('.note-data', noteElem).val();
$.ajax({ $.ajax({
method: 'PUT', method: 'PUT',
url: '/lists/' + listId, url: '/notes/' + noteId,
headers: { 'Accept': 'application/json', headers: { 'Accept': 'application/json',
'Content-Type': 'application/json' }, 'Content-Type': 'application/json' },
data: JSON.stringify(list) data: JSON.stringify(note)
}).done(updateList) }).done(updateNote)
.fail(function(jqXHR, textMsg, error) { .fail(function(jqXHR, textMsg, error) {
list.data = old_data; note.data = old_data;
showErrorDialog("Opslaan mislukt!", showErrorDialog("Opslaan mislukt!",
"<p>Kan de lijst niet opslaan! Probeer later nog eens of " + "<p>Kan de lijst niet opslaan! Probeer later nog eens of " +
"annuleer de bewerking.</p>" + "annuleer de bewerking.</p>" +
@ -147,35 +147,35 @@ function saveListChanges(listElem) {
}); });
} }
function revertListChanges(listElem) { function revertNoteChanges(noteElem) {
var listId = listElem.data("list-id"); var noteId = noteElem.data("note-id");
var list = lists.find(function(list) { return list.id == listId }); var note = notes.find(function(note) { return note.id == noteId });
disableListEditMode(listElem); disableNoteEditMode(noteElem);
$('.list-data', listElem).val(list.data); $('.note-data', noteElem).val(note.data);
} }
function disableListEditMode(listElem) { function disableNoteEditMode(noteElem) {
$('.list-data', listElem).hide(200) $('.note-data', noteElem).hide(200)
.popover('hide'); .popover('hide');
$('.list-html', listElem).show(200); $('.note-html', noteElem).show(200);
$('.list-edit-buttons', listElem).hide(200); $('.note-edit-buttons', noteElem).hide(200);
$('.list-edit-mode-buttons', listElem).show(200); $('.note-edit-mode-buttons', noteElem).show(200);
$('.list-edit-help', listElem).removeClass('active') $('.note-edit-help', noteElem).removeClass('active')
.popover('hide'); .popover('hide');
} }
function enableListEditMode(listElem) { function enableNoteEditMode(noteElem) {
$('.list-data', listElem).show(200); $('.note-data', noteElem).show(200);
$('.list-html', listElem).hide(200); $('.note-html', noteElem).hide(200);
$('.list-edit-mode-buttons', listElem).hide(200); $('.note-edit-mode-buttons', noteElem).hide(200);
$('.list-edit-buttons', listElem).show(200); $('.note-edit-buttons', noteElem).show(200);
} }
$(function() { $(function() {
$('.lists-refresh').on('click', function() { $('.notes-refresh').on('click', function() {
if ($(".list-data:visible").length) { if ($(".note-data:visible").length) {
showErrorDialog("Kan niet verversen tijdens bewerken!", showErrorDialog("Kan niet verversen tijdens bewerken!",
"<p>Het is niet mogelijk om de lijsten te verversen als er " + "<p>Het is niet mogelijk om de lijsten te verversen als er " +
"op dit moment een lijst bewerkt wordt.</p>" + "op dit moment een lijst bewerkt wordt.</p>" +
@ -183,41 +183,41 @@ $(function() {
"bewerking.", "bewerking.",
true); true);
} else { } else {
initLists(); initNotes();
} }
}); });
$('.list-cancel-button').on('click', function() { $('.note-cancel-button').on('click', function() {
var listElem = $(this).parents(".list"); var noteElem = $(this).parents(".note");
console.debug("Cancelling the edit of list " + listElem.data("list-id")); console.debug("Cancelling the edit of note " + noteElem.data("note-id"));
revertListChanges(listElem); revertNoteChanges(noteElem);
}); });
$('.list-edit-button').on('click', function() { $('.note-edit-button').on('click', function() {
var listElem = $(this).parents(".list"); var noteElem = $(this).parents(".note");
console.debug("Going to edit list " + listElem.data("list-id")); console.debug("Going to edit note " + noteElem.data("note-id"));
enableListEditMode(listElem); enableNoteEditMode(noteElem);
}); });
$('.list-edit-help').on('click', function() { $('.note-edit-help').on('click', function() {
var listElem = $(this).parents(".list"); var noteElem = $(this).parents(".note");
var listDataElem = $('.list-data', listElem); var noteDataElem = $('.note-data', noteElem);
$(this).toggleClass('active') $(this).toggleClass('active')
listDataElem.popover('toggle'); noteDataElem.popover('toggle');
}); });
$('.list-save-button').on('click', function() { $('.note-save-button').on('click', function() {
var listElem = $(this).parents(".list"); var noteElem = $(this).parents(".note");
console.debug("Saving the changes for list " + listElem.data("list-id")); console.debug("Saving the changes for note " + noteElem.data("note-id"));
saveListChanges(listElem); saveNoteChanges(noteElem);
}); });
$('.list-select').on('click', function() { $('.note-select').on('click', function() {
listId = $(this).data('list-id'); noteId = $(this).data('note-id');
selectList(listId); selectNote(noteId);
}); });
initLists(); initNotes();
$('textarea').popover({ $('textarea').popover({
html: true, html: true,
trigger: 'manual' trigger: 'manual'

View File

@ -21,14 +21,14 @@ footer {
line-height: 24px; line-height: 24px;
} }
// Reduce the large padding for lists // Reduce the large padding for notes
.list-html ul, .note-html ul,
.list-html ol { .note-html ol {
padding-left: 1.2rem; padding-left: 1.2rem;
} }
.list-html ul.tasklist { .note-html ul.tasknote {
list-style-type: none; note-style-type: none;
padding-left: 0; padding-left: 0;
} }

View File

@ -34,7 +34,7 @@
{% block body %} {% block body %}
<nav class="navbar navbar-expand-md fixed-top navbar-dark bg-dark text-light" role="navigation"> <nav class="navbar navbar-expand-md fixed-top navbar-dark bg-dark text-light" role="navigation">
<div class="container"> <div class="container">
<a class="navbar-brand list-select" href="#">Online Prikbord</a> <a class="navbar-brand note-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"> <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> <span class="navbar-toggler-icon"></span>
</button> </button>

View File

@ -3,13 +3,13 @@
{% block navbar %} {% block navbar %}
<div class="collapse navbar-collapse" id="navbarNav"> <div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav mr-auto"> <ul class="navbar-nav mr-auto">
{% for list in lists %} {% for note in notes %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link list-select" data-list-id="{{ list.id }}" href="#{{ list.id }}">{{ list.name }}</a> <a class="nav-link note-select" data-note-id="{{ note.id }}" href="#{{ note.id }}">{{ note.name }}</a>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
<button class="btn btn-sm btn-light lists-refresh" title="Verversen"> <button class="btn btn-sm btn-light notes-refresh" title="Verversen">
<i class="fas fa-sync-alt"></i> Verversen <i class="fas fa-sync-alt"></i> Verversen
</button> </button>
</div> </div>
@ -18,27 +18,27 @@
{% block content %} {% block content %}
<div class="card-columns"> <div class="card-columns">
{% for list in lists %} {% for note in notes %}
<div class="card list mb-3" style="display:none"; data-list-id="{{ list.id }}"> <div class="card note mb-3" style="display:none"; data-note-id="{{ note.id }}">
<div class="card-header"> <div class="card-header">
<h1 class= "mb-0"> <h1 class= "mb-0">
<span id="list-name">{{ list.name }}</span> <span id="note-name">{{ note.name }}</span>
<div class="btn-toolbar float-right mt-1" role="toolbar" aria-label="List buttons"> <div class="btn-toolbar float-right mt-1" role="toolbar" aria-label="Note buttons">
<div class="btn-group list-edit-mode-buttons" <div class="btn-group note-edit-mode-buttons"
role="group" aria-label="Edit mode buttons"> role="group" aria-label="Edit mode buttons">
<button class="btn btn-dark list-edit-button" title="Bewerken"> <button class="btn btn-dark note-edit-button" title="Bewerken">
<i class="fas fa-edit"></i> <i class="fas fa-edit"></i>
</button> </button>
</div> </div>
<div class="btn-group list-edit-buttons" role="group" <div class="btn-group note-edit-buttons" role="group"
aria-label="Edit list buttons"> aria-label="Edit note buttons">
<button class="btn btn-light list-edit-help" title="Opmaakhulp"> <button class="btn btn-light note-edit-help" title="Opmaakhulp">
<i class="fas fa-question-circle"></i> <i class="fas fa-question-circle"></i>
</button> </button>
<button class="btn btn-light list-cancel-button" title="Annuleren"> <button class="btn btn-light note-cancel-button" title="Annuleren">
<i class="fas fa-ban"></i> <i class="fas fa-ban"></i>
</button> </button>
<button class="btn btn-dark list-save-button" title="Opslaan"> <button class="btn btn-dark note-save-button" title="Opslaan">
<i class="fas fa-save"></i> <i class="fas fa-save"></i>
</button> </button>
</div> </div>
@ -46,9 +46,9 @@
</h1> </h1>
</div> </div>
<div class="card-body"> <div class="card-body">
<div class="card-text list-html"></div> <div class="card-text note-html"></div>
<div class="card-text"> <div class="card-text">
<textarea class="form-control list-data" rows="16" <textarea class="form-control note-data" rows="16"
data-title="Opmaakhulp" data-title="Opmaakhulp"
data-content="<pre class='mb-0'> data-content="<pre class='mb-0'>
## Kop 2 ## Kop 2
@ -76,7 +76,7 @@ Horizontale lijn<pre>"></textarea>
<p class="card-text"> <p class="card-text">
<small> <small>
<i class="fas fa-clock"></i> <i class="fas fa-clock"></i>
<i class="list-updated-at"></i> <i class="note-updated-at"></i>
</small> </small>
</p> </p>
</div> </div>