At the moment all the posts on the front page are displayed in full. It's already getting a bit crowded so I want to just show the a small part of each post. Not particularly exciting but a little fiddly.
This would be pretty easy to accomplish by using css to restrict the size of the boxes but then we would still be sending all the content. Taking the first n characters doesn't work either because the resulting html will be broken.
The output of simple_markup's parser is a list of <p>s so a simple solution is to ask for just one <p>. main.ml now contains:
let interact () =
let len =
bitmatch (bitstring_of_chan_max stdin 4) with
| { len:4*8 } -> Int32.to_int len in
bitmatch (bitstring_of_chan_max stdin len) with
| { abridge:8 ; input:(len-1)*8:string } ->
let markup = parse_text input in
let html =
to_html
~render_pre:render_pre
~render_link:render_link
~render_img:render_img markup in
let html =
match abridge with
| 0 -> html
| _ -> [List.hd html] in
let html_pretty = Xhtmlpretty.xhtml_list_print html in
let output =
let len = String.length html_pretty in
BITSTRING { (Int32.of_int len):4*8 ; html_pretty:len*8:string } in
Bitstring.bitstring_to_chan output stdout;
flush stdout
The first part of the port command determines whether or not the output will be abridged. It only requires 1 bit to communicate this but I would prefer to keep the remaining string aligned so we use a whole byte.
Having got into the habit of doing erlang-style error handling I originally wrote the match as...
let html =
match abridge with
| 0 -> html
| 1 -> [List.hd html] in
...with a match failure occuring for anything else. Unfortunately, omake seems to build with -warn-error by default so this will not compile. Handling this properly in ocaml requires defining an exception type and adding an extra case whereas in erlang just letting the match fail would be sufficient.
The port command in markup.erl needs changing to match:
handle_call({to_html, Markup, Abridge}, _From, State) ->
Command =
case Abridge of
false -> [0, Markup];
true -> [1, Markup]
end,
true = port_command(State#state.port, Command),
Response = case collect_response(State#state.port) of
{ok, Html} -> {reply, Html, State}
end,
Response.
item_template.et gets passed a boolean argument telling it whether to abridge the body of the post and insert a 'read more' link.
<%
{Items, Abridge} = Data,
[ item(Item, Abridge) || Item <- Items ]
%>
<%! end of template %>
<%@ item(Item, Abridge) %>
<div class="item">
<div class="header">
<div class="title">
<% anchor(by_pubdate(Item#item.pubdate), Item#item.title) %>
</div>
<div class="date"><% date(Item#item.pubdate) %></div>
</div>
<div class="divider"></div>
<div class="body"><% markup:to_html(Item#item.body, Abridge) %></div>
<div class="more">
<%
case Abridge of
true -> anchor(by_pubdate(Item#item.pubdate), "read more...");
false -> ""
end
%>
</div>
<div class="tags">
<% [ anchor(by_tag(Tag), Tag) || Tag <- Item#item.tags ] %>
</div>
</div>
item_all_resource.erl gets a new 'abridge' argument which is used on the front page.
to_html(Reqdata, Context) ->
Items = get_items(Reqdata),
ok = erltl:compile("src/item_template.et"),
Abridge =
case lists:keyfind("abridge",1,wrq:req_qs(Reqdata)) of
{"abridge","true"} -> true;
_ -> false
end,
Body = item_template:render({Items, Abridge}),
ok = erltl:compile("src/blog_template.et"),
Html = blog_template:render(Body),
{Html, Reqdata, Context}.