couchdb-todo/todo/js/app.js
2023-01-09 09:07:36 +01:00

217 lines
6.1 KiB
JavaScript
Executable file

(function () {
"use strict";
var ENTER_KEY = 13;
var newTodoDom = document.getElementById("new-todo");
var syncDom = document.getElementById("sync-wrapper");
var db = new PouchDB("todos");
var remoteCouch = "http://admin:123456@127.0.0.1:5984/todos";
var cookie;
db.info().then(function (info) {
db.changes({ since: info.update_seq, live: true }).on("change", function (change) {
showTodos();
});
});
// We have to create a new todo document and enter it in the database
function addTodo(text) {
var todo = {
title: text,
completed: false,
};
db.post(todo).then(function (response) {
console.log("Successfully posted a todo!");
});
}
// Show the current list of todos by reading them from the database
function showTodos() {
db.allDocs({ include_docs: true, conflicts: true })
.then(function (doc) {
console.log(doc);
redrawTodosUI(doc.rows);
})
.catch(function (err) {
console.log(err);
});
}
// Remove all conflicting revisions from the database
function resolveConflict(todo, rev) {
console.log(todo, rev)
todo._conflicts.forEach((r) => {
if (r !== rev) {
db.remove(todo._id, r);
}
});
if (todo._rev !== rev) {
db.remove(todo._id, todo._rev);
}
}
function checkboxChanged(todo, event) {
todo.completed = event.target.checked;
db.put(todo);
}
// User pressed the delete button for a todo, delete it
function deleteButtonPressed(todo) {
db.remove(todo);
}
// The input box when editing a todo has blurred, we should save
// the new title or delete the todo if the title is empty
function todoBlurred(todo, event) {
var trimmedText = event.target.value.trim();
if (!trimmedText) {
db.remove(todo);
} else {
todo.title = trimmedText;
db.put(todo);
}
}
// Initialise a sync with the remote server
function sync() {
// syncDom.setAttribute("data-sync-state", "syncing");
var remote = new PouchDB(remoteCouch, { headers: { Cookie: cookie } });
var pushRep = db.replicate
.to(remote, {
continuous: true,
})
.on("active", syncStarted)
.on("error", syncError)
.on("paused", syncComplete)
.on("complete", syncComplete);
var pullRep = db.replicate
.from(remote, {
continuous: true,
})
.on("active", syncStarted)
.on("error", syncError)
.on("paused", syncComplete)
.on("complete", syncComplete);
}
// EDITING STARTS HERE (you dont need to edit anything below this line)
// There was some form or error syncing
function syncStarted() {
syncDom.setAttribute("data-sync-state", "syncing");
}
function syncComplete() {
syncDom.setAttribute("data-sync-state", "complete");
}
function syncError() {
syncDom.setAttribute("data-sync-state", "error");
}
// User has double clicked a todo, display an input so they can edit the title
function todoDblClicked(todo) {
var div = document.getElementById("li_" + todo._id);
var inputEditTodo = document.getElementById("input_" + todo._id);
div.className = "editing";
inputEditTodo.focus();
}
// If they press enter while editing an entry, blur it to trigger save
// (or delete)
function todoKeyPressed(todo, event) {
if (event.keyCode === ENTER_KEY) {
var inputEditTodo = document.getElementById("input_" + todo._id);
inputEditTodo.blur();
}
}
// Given an object representing a todo, this will create a list item
// to display it.
function createTodoListItem(todo) {
var checkbox = document.createElement("input");
checkbox.className = "toggle";
checkbox.type = "checkbox";
checkbox.addEventListener("change", checkboxChanged.bind(this, todo));
var label = document.createElement("label");
label.appendChild(document.createTextNode(todo.title));
label.addEventListener("dblclick", todoDblClicked.bind(this, todo));
var deleteLink = document.createElement("button");
deleteLink.className = "destroy";
deleteLink.addEventListener("click", deleteButtonPressed.bind(this, todo));
var divDisplay = document.createElement("div");
divDisplay.className = "view";
divDisplay.appendChild(checkbox);
divDisplay.appendChild(label);
divDisplay.appendChild(deleteLink);
var inputEditTodo = document.createElement("input");
inputEditTodo.id = "input_" + todo._id;
inputEditTodo.className = "edit";
inputEditTodo.value = todo.title;
inputEditTodo.addEventListener("keypress", todoKeyPressed.bind(this, todo));
inputEditTodo.addEventListener("blur", todoBlurred.bind(this, todo));
var li = document.createElement("li");
li.id = "li_" + todo._id;
li.appendChild(divDisplay);
li.appendChild(inputEditTodo);
if (todo._conflicts) {
var conflictsP = document.createElement("p");
conflictsP.textContent = "conflicts with: ";
var ca = document.createElement("a");
ca.textContent = "(Keep this revision)";
ca.onclick = () => resolveConflict(todo, todo._rev);
conflictsP.appendChild(ca);
todo._conflicts.forEach((rev) => {
db.get(todo._id, { rev }).then(function (t) {
var ca = document.createElement("a");
ca.textContent = t.title;
ca.onclick = () => resolveConflict(todo, rev);
conflictsP.appendChild(ca);
});
});
li.appendChild(conflictsP);
}
if (todo.completed) {
li.className += "complete";
checkbox.checked = true;
}
return li;
}
function redrawTodosUI(todos) {
var ul = document.getElementById("todo-list");
ul.innerHTML = "";
todos.forEach(function (todo) {
ul.appendChild(createTodoListItem(todo.doc));
});
}
function newTodoKeyPressHandler(event) {
if (event.keyCode === ENTER_KEY) {
addTodo(newTodoDom.value);
newTodoDom.value = "";
}
}
function addEventListeners() {
newTodoDom.addEventListener("keypress", newTodoKeyPressHandler, false);
}
addEventListeners();
showTodos();
if (remoteCouch) {
sync();
}
})();