Current section
Files
Jump to
Current section
Files
src/elements/other/element_calendar.erl
%% vim: ft=nitrogen
-module(element_calendar).
-include("wf.hrl").
-export([
reflect/0,
transform_element/1,
event/1,
drop_event/2
]).
-record(drop_tag, {calendar_tag, delegate, date}).
-spec reflect() -> [atom()].
reflect() -> record_info(fields, calendar).
-spec transform_element(#calendar{}) -> body().
transform_element(_Rec = #calendar{id=Id0, delegate=Delegate0, actions=Actions, aria=Aria,
class=Class, style=Style, tag=CalTag, month=M, year=Y, html_id=Htmlid, data_fields=Data}) ->
Delegate = wf:coalesce([Delegate0, wf:page_module()]),
FirstDay = {{Y, M, 1}, {0,0,0}},
%% Start Week on Sunday
Start = qdate:beginning_week(7, FirstDay),
%% end at the end of the week for the last week of the month (so end on Saturday)
End = qdate:end_week(7, qdate:end_month(FirstDay)),
Id = ?WF_IF(Id0==undefined, wf:temp_id(), Id0),
DateTimes = [qdate:to_date(D) || D <- qdate:range_days(1, Start, End)],
Days = [Date || {Date, _Time} <- DateTimes],
Items = load_items(Delegate, CalTag, Y, M),
{Today, _} = qdate:to_date(os:timestamp()),
#panel{id=Id, class=[nitrogen_calendar, Class], style=Style, actions=Actions, aria=Aria, html_id=Htmlid, data_fields=Data, body=[
#table{rows=[
#tablerow{cells=[
#tableheader{colspan=7, body=[
#h3{style="text-align:center", text=qdate:to_string("F Y", FirstDay)}
]}
]},
#tablerow{class=nitrogen_calendar_day_header, cells=[
#tableheader{text="Sunday"},
#tableheader{text="Monday"},
#tableheader{text="Tuesday"},
#tableheader{text="Wednesday"},
#tableheader{text="Thursday"},
#tableheader{text="Friday"},
#tableheader{text="Saturday"}
]},
draw_weeks(Today, Delegate, CalTag, Items, Days)
]}
]}.
draw_weeks(_, _, _, _, []) ->
[];
%% We're garuanteed that the "Days" list is a multiple of 7, because we're always getting the Sunday through Saturday, padding at the front and back as necessary
draw_weeks(Today, Delegate, CalTag, Items, [D1,D2,D3,D4,D5,D6,D7 | Rest]) ->
[
draw_days(Today, Delegate, CalTag, Items, [D1,D2,D3,D4,D5,D6,D7]),
draw_weeks(Today, Delegate, CalTag, Items, Rest)
].
draw_days(Today, Delegate, CalTag, Items, Days) ->
#tablerow{cells=[
[draw_day(Today, Delegate, CalTag, Items, D) || D <- Days]
]}.
draw_day(Today, Delegate, CalTag, Items, Date = {_, _, D}) ->
DayItems = get_date_items(Date, Items),
IsInvalidDrop = has_invalid_drop(DayItems),
Body = draw_items(DayItems),
CellClass = ?WF_IF(Today==Date, calendar_today, ""),
Body2 = case IsInvalidDrop of
true -> Body;
false ->
DropTag = #drop_tag{
delegate=Delegate,
calendar_tag=CalTag,
date=Date
},
#droppable{class=nitrogen_calendar_drop, delegate=?MODULE, tag=DropTag, body=Body}
end,
#tablecell{class=CellClass, body=[
#panel{class=nitrogen_calendar_day_wrapper, body=[
#panel{class=nitrogen_calendar_day, text=D},
#panel{class=nitrogen_calendar_day_body, body=[
Body2
]}
]}
]}.
has_invalid_drop(Items) ->
lists:any(fun(#calendar_invalid_drop{}) -> true;
(_) -> false
end, Items).
draw_items(Items) ->
[draw_item(I) || I <- Items].
draw_item(I = #calendar_item{draggable=false}) ->
#panel{class=nitrogen_calendar_static_item, body=draw_item_body(I)};
draw_item(I = #calendar_item{draggable=true, tag=ItemTag}) ->
#draggable{tag=ItemTag, class=nitrogen_calendar_draggable_item, body=draw_item_body(I)};
draw_item(_) ->
[].
draw_item_body(I) ->
#panel{
class=[I#calendar_item.class, nitrogen_calendar_item_body],
body=I#calendar_item.body,
text=I#calendar_item.text
}.
get_date_items(_, undefined) -> [];
get_date_items(Day, Items) ->
case dict:find(Day, Items) of
{ok, Is} -> Is;
error -> []
end.
load_items(Delegate, Tag, Y, M) ->
case erlang:function_exported(Delegate, calendar_load_event, 3) of
true ->
RawItems = Delegate:calendar_load_event(Tag, Y, M),
lists:foldl(fun(Item, Acc) ->
Date = extract_item_date(Item),
dict:append(Date, Item, Acc)
end, dict:new(), RawItems);
false ->
undefined
end.
extract_item_date(#calendar_item{date=Date}) ->
Date;
extract_item_date(#calendar_invalid_drop{date=Date}) ->
Date.
drop_event(ItemTag, #drop_tag{calendar_tag=CalTag, delegate=Delegate, date=Date}) ->
ok.
event(_) ->
ok.