Implemented entry creation, pagination. Some restyling and bugfixes.

- Bug fix in ts_api:list_entries/3. Case statement matching on atoms but
  input is a list (string).
- Bug fix in ts_api:put_entry/3. Was expecting the wrong result from
  ts_entry:new/1.
- Bug fix in ts_entry:list/4. Code crashed when the starting offset was
  greater than the total number of elements. Now returns [].
- Fixed ts_json:encode_datetime/1 and ts_json:decode_datetime/1 to handle
  millisecond values in the datetime string (per ISO standard).
- Broke out ``control-links`` style to a top-level class.
- Added showdown.js, a JS Markdown processor. Not hooked up to anything
  yet but intend to display entry notes with Markdown.
- Added code for entry pagination. Loads the most recent 20 entries and
  loads more upon demand in batches of 20.
- Fixed bug in login routine that kept the user edit fields from being
  pre-populated.
- Rewrote the loadEntries function to double for new entries and loading
  more existing entries.
- Commented displayEntries. Also refactored into displayNewerEntries,
  which pushed new entries on to the top of the stack, and
  displayOlderEntries, which tags them onto the bottom.
- Implemented hidden notes field for new entry input.
- Implemented new entry creation.
- Created a helper function to ISO format a Date object.
- Expanded entry template to show control links (edit, show notes, del).
- Activated the 'load more entries' button.
This commit is contained in:
Jonathan Bernard
2011-03-07 16:43:40 -06:00
parent c185c8cd81
commit 1b1e31059b
14 changed files with 1720 additions and 114 deletions

View File

@ -392,13 +392,13 @@ list_entries(YArg, Username, TimelineId) ->
% read or default the Start
Start = case lists:keyfind("start", 1, QueryData) of
{start, StartVal} -> list_to_integer(StartVal);
{"start", StartVal} -> list_to_integer(StartVal);
false -> 0
end,
% read or default the Length
Length = case lists:keyfind("length", 1, QueryData) of
{length, LengthVal} ->
{"length", LengthVal} ->
erlang:min(list_to_integer(LengthVal), 500);
false -> 50
end,
@ -443,7 +443,8 @@ put_entry(YArg, Username, TimelineId) ->
case ts_entry:new(NewRecord) of
% record created
ok -> [{status, 201}, make_json_200(YArg, NewRecord)];
{ok, CreatedRecord} ->
[{status, 201}, make_json_200(YArg, CreatedRecord)];
% will not create, record exists
{error, {record_exists, ExistingRecord}} ->
@ -456,7 +457,9 @@ put_entry(YArg, Username, TimelineId) ->
{content, "application/json", JSONResponse};
_Error -> make_json_500(YArg)
OtherError ->
io:format("Could not create entry: ~p", [OtherError]),
make_json_500(YArg)
end.
post_entry(YArg, Username, TimelineId, EntryId) ->

View File

@ -51,7 +51,10 @@ when is_integer(Start) and is_integer(Length) ->
% return only the range selected.
% TODO: can we do this without selecting all entries?
lists:sublist(SortedEntries, Start + 1, Length);
case length(SortedEntries) > Start of
true -> lists:sublist(SortedEntries, Start + 1, Length);
false -> []
end;
list({Username, Timeline}, StartDateTime, EndDateTime, OrderFun) ->

View File

@ -40,8 +40,8 @@ record_to_ejson(Record=#ts_entry{}) ->
{notes, Record#ts_entry.notes}]}.
encode_datetime({{Year, Month, Day}, {Hour, Minute, Second}}) ->
lists:flatten(io_lib:format("~4.10.0B-~2.10.0B-~2.10.0BT~2.10.0B:~2.10.0B:~2.10.0BZ",
[Year, Month, Day, Hour, Minute, Second])).
lists:flatten(io_lib:format("~4.10.0B-~2.10.0B-~2.10.0BT~2.10.0B:~2.10.0B:~2.10.0B~3.10.0BZ",
[Year, Month, Day, Hour, Minute, Second, 000])).
ejson_to_record(_Empty=#ts_timeline{}, EJSON) ->
{struct, Fields} = EJSON,
@ -70,8 +70,11 @@ decode_datetime(DateTimeString) ->
[YearString, MonthString, DayString] =
re:split(DateString, "-", [{return, list}]),
[HourString, MinuteString, SecondString] =
re:split(TimeString, ":", [{return, list}]),
[HourString, MinuteString, SecondString] =
case re:split(TimeString, "[:\\.]", [{return, list}]) of
[HS, MS, SS, _MSS] -> [HS, MS, SS];
[HS, MS, SS] -> [HS, MS, SS]
end,
Date = {list_to_integer(YearString), list_to_integer(MonthString),
list_to_integer(DayString)},