diff --git a/db/test/DECISION_TAB.LOG b/db/test/DECISION_TAB.LOG index 9c6ae28..b27af22 100644 Binary files a/db/test/DECISION_TAB.LOG and b/db/test/DECISION_TAB.LOG differ diff --git a/db/test/LATEST.LOG b/db/test/LATEST.LOG index 874dd04..ffa11e2 100644 Binary files a/db/test/LATEST.LOG and b/db/test/LATEST.LOG differ diff --git a/db/test/id_counter.DCD b/db/test/id_counter.DCD index 7a3d9f7..ab5b807 100644 Binary files a/db/test/id_counter.DCD and b/db/test/id_counter.DCD differ diff --git a/db/test/id_counter.DCL b/db/test/id_counter.DCL deleted file mode 100644 index 54c43c2..0000000 Binary files a/db/test/id_counter.DCL and /dev/null differ diff --git a/db/test/ts_entry.DCD b/db/test/ts_entry.DCD index a1665e7..0bf29bf 100644 Binary files a/db/test/ts_entry.DCD and b/db/test/ts_entry.DCD differ diff --git a/db/test/ts_entry.DCL b/db/test/ts_entry.DCL index 4c00f63..3de99e6 100644 Binary files a/db/test/ts_entry.DCL and b/db/test/ts_entry.DCL differ diff --git a/src/ts_api.erl b/src/ts_api.erl index e40f760..b7cc81d 100644 --- a/src/ts_api.erl +++ b/src/ts_api.erl @@ -482,7 +482,22 @@ post_entry(YArg, Username, TimelineId, EntryId) -> _Error -> make_json_500(YArg) end. -delete_entry(_YArg, _Username, _TimelineId, _EntryId) -> todo. +delete_entry(YArg, Username, TimelineId, EntryId) -> + + % find the record to delete + case ts_entry:lookup(Username, TimelineId, EntryId) of + + Record -> + % try to delete + case ts_entry:delete(Record) of + ok -> {status, 200}; + Error -> + io:format("Error occurred deleting entry record: ~p", [Error]), + make_json_500(YArg) + end; + + no_record -> make_json_404(YArg) + end. % ============================== % % ======== UTIL METHODS ======== % diff --git a/src/ts_entry.erl b/src/ts_entry.erl index 525077a..8fe9072 100644 --- a/src/ts_entry.erl +++ b/src/ts_entry.erl @@ -1,5 +1,5 @@ -module(ts_entry). --export([create_table/1, new/1, update/1, lookup/3, list_asc/3, list_desc/3]). +-export([create_table/1, new/1, update/1, delete/1, lookup/3, list_asc/3, list_desc/3]). -include("ts_db_records.hrl"). -include_lib("stdlib/include/qlc.hrl"). @@ -35,6 +35,9 @@ lookup(Username, TimelineId, EntryId) -> [Entry] -> Entry end. +delete(ER = #ts_entry{}) -> mnesia:dirty_delete_object(ER). + + list({Username, Timeline}, Start, Length, OrderFun) when is_integer(Start) and is_integer(Length) -> diff --git a/www/css/ts-screen.css b/www/css/ts-screen.css index cffb29f..8189c2a 100644 --- a/www/css/ts-screen.css +++ b/www/css/ts-screen.css @@ -211,7 +211,7 @@ body { background: #b34c2b; color: #c5c5b9; font-weight: bold; - min-width: 2em; + width: 2em; text-align: right; } .entry-bar .details { float: left; } @@ -223,6 +223,13 @@ body { .entry-bar .details .entry-notes { display: none; padding-left: 1.5em; } + .entry-bar .entry-edit { + display: none; } + .entry-bar .entry-edit .id { + width: 2em; + padding: 0.2em 0.5em 0.2em 0.5em; } + .entry-bar .entry-edit .entry-notes { + padding: 0; } .top-entry { -moz-border-radius-topleft: 0.5em; diff --git a/www/css/ts-screen.scss b/www/css/ts-screen.scss index 14d5f7c..a294e05 100644 --- a/www/css/ts-screen.scss +++ b/www/css/ts-screen.scss @@ -264,7 +264,7 @@ body { background: $obor; color: lighten($greyTxt, 40%); font-weight: bold; - min-width: 2em; + width: 2em; text-align: right; } @@ -283,6 +283,19 @@ body { padding-left: 1.5em; } } + + .entry-edit { + display: none; + + .id { + width: 2em; + padding: 0.2em 0.5em 0.2em 0.5em; + } + + .entry-notes { + padding: 0; + } + } } .top-entry { diff --git a/www/js/ts.js b/www/js/ts.js index fc062f6..753d3c5 100644 --- a/www/js/ts.js +++ b/www/js/ts.js @@ -25,6 +25,9 @@ $(document).ready(function(){ buttons: { Login: function(){login()} } }); + // TODO: add a hook to AJAX requests to check for 401 unauth + // and re-display the login dialog. + // try to load user information for an authenticated user $.ajax({ url: "/ts_api/users/", @@ -109,6 +112,7 @@ function loadUser(username) { // update the timeline display $("#timeline-name").text(activeTimeline.timeline_id + " |"); $("#timeline-desc").text(activeTimeline.description); + $("#timeline-desc-input").val(activeTimeline.description); // TODO: populate the drop-down list for the available timeline // choices @@ -205,27 +209,12 @@ function displayOlderEntries(entries) { }); } -/* Show/hide the editable user-info panel. */ -function toggleUserInfo(event) { - $("#user-info").slideToggle("slow"); - event.preventDefault(); -} - -/* Show/hide the password change controls. */ -function showChangePwd(event) { $("#change-pwd").slideToggle("slow"); } - /* Update the user information based on the editable user-info panel. */ function updateUser(event) { alert("TODO: update user via AJAX."); event.preventDefault(); } -/* Show/hide the editable timeline-info panel. */ -function toggleTimelineInfo(event) { - $("#timeline-info").slideToggle("slow"); - event.preventDefault(); -} - /* Show the change timeline menu. */ function showTimelineMenu(event) { alert("TODO: show other timelines via a popup menu"); @@ -234,22 +223,24 @@ function showTimelineMenu(event) { /* Update the timeline details based on the editable timeline-info panel. */ function updateTimeline(event) { - alert("TODO: update timeline via AJAX."); - event.preventDefault(); -} + var desc = $("#timeline-desc-input").val(); -/* Show/hide the add notes panel. */ -function showNewNotes(event) { $("#add-notes").slideToggle("slow"); } + $.ajax({url: "/ts_api/timelines/" + user.username + + "/" + activeTimeline.timeline_id, + type: "POST", + data: JSON.stringify({desc: desc, created: activeTimeline.created}), -function toggleEntryNotes(event, entryId) { - var selector = "#" + entryId + " .entry-notes"; - $(selector).slideToggle("slow"); - event.preventDefault(); -} + error: function(jqXHR, textStatus, error) { + // TODO: better error handling + alert("Error updating timeline: \n" + jqXHR.responseText); }, + + success: function(data, testStatus, jqXHR) { + // TODO: check for appropriate data.status value + + // update display + $("#timeline-desc").text(data.timeline.description); + }}); -function editEntry(event, entryId) { - var selector = "#" + entryId; - alert("TODO: implement edit entry. Called for '" + selector + "'"); event.preventDefault(); } @@ -293,9 +284,59 @@ function newEntry(event) { event.preventDefault(); } +function toggleEditEntry(event, entryId) { + $("#entry-" + entryId + " .entry-display").toggle(); + $("#entry-" + entryId + " .entry-edit").toggle(); + event.preventDefault(); +} + +function updateEntry(event, entryId) { + + var mark = $("#entry-" + entryId + "-mark-input").val(); + var notes = $("#entry-" + entryId + "-notes-input").val(); + var timestamp = getUTCTimestamp(); // TODO: define and read from input element + + var payload = JSON.stringify( + { mark: mark, notes: notes, timestamp: timestamp }); + + $.ajax({url: "/ts_api/entries/" + user.username + + "/" + activeTimeline.timeline_id + + "/" + entryId, + type: "POST", + data: payload, + + error: function(jqXHR, textStatus, error) { + // TODO: error handling + alert("Error updating entry: \n" + jqXHR.responseText); }, + + success: function(data, textStatus, jqXHR) { + // TODO: check that data.status is appropriate + + // update the entry display + $("#entry-" + entryId + " .entry-mark").text(data.entry.mark); + $("#entry-" + entryId + " .entry-notes").text(data.entry.notes); + }}); + + toggleEditEntry(event, entryId); +} + /* Delete an entry. */ function deleteEntry(event, entryId) { + $.ajax({url: "/ts_api/entries/" + user.username + + "/" + activeTimeline.timeline_id + + "/" + entryId, + type: "DELETE", + + error: function(jqXHR, textStatus, error) { + // TODO: error handling + alert("Error updating entry: \n" + jqXHR.responseText); }, + success: function(data, textStatus, jqXHR) { + $("#entry-" + entryId).slideUp('slow', + function() {$("#entry-" + entryId).remove(); }); + }}); + + event.preventDefault(); } /* Generate a UTC timestamp string in ISO format. diff --git a/www/ts/index.yaws b/www/ts/index.yaws index 5254a4e..57fc4c4 100644 --- a/www/ts/index.yaws +++ b/www/ts/index.yaws @@ -16,18 +16,39 @@ @@ -40,7 +61,8 @@ - no_user @@ -74,7 +96,7 @@ @@ -93,7 +115,8 @@ timeline description @@ -122,7 +145,8 @@ class="form-submit" type="submit" value="create entry"/>