Skip to content

Commit

Permalink
Merge master
Browse files Browse the repository at this point in the history
  • Loading branch information
kaos committed May 30, 2009
2 parents d86fae0 + 4c17271 commit 8d5fd3b
Show file tree
Hide file tree
Showing 7 changed files with 372 additions and 1 deletion.
251 changes: 251 additions & 0 deletions src/element_flot_chart/element_flot_chart.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
-module(element_flot_chart).
-compile(export_all).

-include_lib("nitrogen/include/wf.inc").
-include("elements.hrl").

reflect() -> record_info(fields, flot_chart).

rec() -> #flot_chart{}.

render(ControlId, Record) ->
%% handle multiple datasets
Data = Record#flot_chart.values
, DataSet = data_as_js(Data)
%% description of the graph
, _Title = Record#flot_chart.title
, Width = Record#flot_chart.width
, Height = Record#flot_chart.height
% TODO(jwall): dual axis support
, Lines = Record#flot_chart.lines
, Points = Record#flot_chart.points
, Bar = Record#flot_chart.bar
, SelectMode = Record#flot_chart.selectmode
%% IDs for the elements
, TargetId = case Record#flot_chart.placeholder of
undefined ->
wf:temp_id();
PlaceHolder ->
PlaceHolder
end
, PlotId = case Record#flot_chart.id of
undefined ->
wf:temp_id();
Id ->
Id
end
, LegendId = case Record#flot_chart.legend of
undefined ->
wf:temp_id();
Legend ->
Legend
end
, GraphId = wf:temp_id()
, ToolTipId = wf:temp_id()
%% TODO(jwall): support date formatting for timeseries data
%% TODO(jwall): colors
, Script = wf:f("var " ++ PlotId ++ ";"
++ "$(function() { ~n"
++ "var d = ~s;~n" % DataSet
++ PlotId ++ " = $.plot($('#' + ~p), d, ~n{" % TargetId
++ xaxis(Record) ++ ",~n"
++ yaxis(Record) ++ ",~n"
++ x2axis(Record) ++ ",~n"
++ y2axis(Record) ++ ",~n"
% insert optional y2axis here
++ "lines: {show: ~p},~n" % Lines
++ "points: {show: ~p},~n" % Points
++ "bars: {show: ~p},~n" % Bar
++ "selection: {mode: ~p},~n" % SelectMode
++ "grid: {hoverable: true, clickable: true},~n"
%% Legend
++ "legend: { container: $('#' + ~p) } " % LegendId
++ "});~n"
%% tooltip code
++ "function showTooltip(x, y, contents) {~n"
++ " $('<div id=~p>' + contents + '</div>').css( {~n" % ToolTipId
++ " position: 'absolute',~n"
++ " display: 'none',~n"
++ " top: y + 5,~n"
++ " left: x + 5,~n"
++ " border: '1px solid #fdd',~n"
++ " padding: '2px',~n"
++ " 'background-color': '#fee',~n"
++ " opacity: 0.80~n"
++ " }).appendTo('body').fadeIn(200);~n"
++ "}~n"
% now bind to the plothover event
++ "var previousPoint = null;~n"
++ "$('#' + ~p).bind('plothover', function(event, pos, item) {~n" % TargetId
++ " $('#x').text(pos.x.toFixed(2));~n"
++ " $('#y').text(pos.y.toFixed(2));~n"
++ " if (item) {~n"
++ " if(previousPoint != item.datapoint) {~n"
++ " previousPoint = item.datapoint;~n"
++ " $('#' + ~p).remove();~n" % ToolTipId
++ " var x = item.datapoint[0].toFixed(2),~n"
++ " y = item.datapoint[1].toFixed(2);~n"
++ " showTooltip(item.pageX, item.pageY, y);~n"
++ " } else {~n"
++ " $('#' + ~p).remove();~n" % ToolTipId
++ " previousPoint = null;~n"
++ " }~n"
++ " }~n"
++ "})~n"
%% TODO(jwall): select event custom?
++ "$('#' + ~p).bind('plotselected', function (event, ranges) {~n" % TargetId
++ " //alert(ranges.xaxis.from.toFixed(1) + ',' + ranges.yaxis.from.toFixed(1))~n"
++ " //alert(ranges.xaxis.to.toFixed(1) + ',' + ranges.yaxis.to.toFixed(1))~n"
++ "})~n"
%% TODO(jwall): click event custom?
++ "$('#' + ~p).bind('plotclick', function (event, pos, item) {~n" % TargetId
++ " //alert(item.dataIndex + ' = ' + d[item.dataIndex]);~n"
++ "})~n"
++ "});~n"
, [DataSet, TargetId
, Lines, Points, Bar, SelectMode, LegendId
, ToolTipId, TargetId, ToolTipId, ToolTipId
, TargetId, TargetId
])
%% TODO(jwall): dataset manipulation
%% TODO(jwall): zoom controls?
%% TODO(jwall): pan buttons?
, LegendPanel = #panel{id=LegendId}
, Panel = #panel{id=TargetId, style=wf:f("width:~ppx;height:~ppx", [Width, Height])}
, wf:wire(TargetId, #event{type='timer', delay=10
, actions=#script{script=Script}})
, element_singlerow:render(ControlId, #singlerow{id=GraphId, cells=[#tablecell{body=Panel}
, #tablecell{body=LegendPanel}]})
.

data_as_js(T) when is_tuple(T) ->
data_as_js([T]);
data_as_js(L) ->
List = data_as_js_preparse(L)
, "[" ++ string:join(List, ",") ++ "]"
.

data_as_js_preparse([]) ->
[];
data_as_js_preparse([H | T]) when is_tuple(H) ->
[ data_as_js_preparse(H) | data_as_js_preparse(T)];
data_as_js_preparse([H | T]) when is_list(H) ->
[ data_as_js_preparse({"undefined", H}) | data_as_js_preparse(T)];
data_as_js_preparse({Label, Data}) when is_list(Data) ->
wf:f("{ label: '~s', data: ~w}", [Label, Data]);
data_as_js_preparse({Label, Data, Opts})
when is_list(Data) and is_list(Opts) ->
OptString = create_options(Opts)
, wf:f("{ label: '~s', data: ~w, ~s}", [Label, Data, OptString]);
data_as_js_preparse({Label, Data, {Axis, Num}})
when is_list(Data) and is_atom(Axis) and is_integer(Num) ->
wf:f("{ label: '~s', data: ~w, ~p: ~p}", [Label, Data, Axis, Num])
.

xaxis(Record) ->
Min = Record#flot_chart.minx
, Max = Record#flot_chart.maxx
, Mode = Record#flot_chart.modex
, Ticks = Record#flot_chart.xticks
, create_option(xaxis, [opt(min, Min)
, opt(max, Max), opt(ticks, Ticks)
, opt(mode, Mode)])
.

yaxis(Record) ->
Min = Record#flot_chart.miny
, Max = Record#flot_chart.maxy
, Mode = Record#flot_chart.modey
, Ticks = Record#flot_chart.yticks
, create_option(yaxis, [opt(min, Min)
, opt(max, Max), opt(ticks, Ticks)
, opt(mode, Mode)])
.

x2axis(Record) ->
Min = Record#flot_chart.minx2
, Max = Record#flot_chart.maxx2
, Mode = Record#flot_chart.modex2
, Ticks = Record#flot_chart.x2ticks
, create_option(x2axis, [opt(min, Min)
, opt(max, Max), opt(ticks, Ticks)
, opt(mode, Mode)])
.

y2axis(Record) ->
Min = Record#flot_chart.miny2
, Max = Record#flot_chart.maxy2
, Mode = Record#flot_chart.modey2
, Ticks = Record#flot_chart.y2ticks
, create_option(y2axis, [opt(min, Min)
, opt(max, Max), opt(ticks, Ticks)
, opt(mode, Mode)])
.

create_options(L) when is_list(L) ->
lists:join(create_options_from_list(L), ",")
.

create_options_from_list([{Name, Items} | T]) ->
[create_option(Name, Items) | create_options(T)]
.

create_option(Name, Items) when is_list(Items) ->
Opts = string:join(create_opts(Items), ",")
, lists:flatten([wf:f("~p: {~n", [Name])
, Opts, "}~n"])
.

opt(Type, Value) ->
{Type, Value}
.

create_opts([]) ->
"";
create_opts([H |T]) ->
[create_opt(H) | create_opts(T)]
.

create_opt({Type, undefined}) ->
wf:f("~p: null", [Type]);
create_opt({mode, Value}) when Value == "time" ->
wf:f("mode: ~p", [Value]);
create_opt({show, Value}) when is_boolean(Value) ->
wf:f("show: ~p", [Value]);
create_opt({min, Value}) when is_integer(Value) or is_float(Value) ->
wf:f("min: ~p", [Value]);
create_opt({max, Value}) when is_integer(Value) or is_float(Value) ->
wf:f("max: ~p", [Value]);
create_opt({autoscale, Value}) when is_integer(Value) or is_float(Value) ->
wf:f("autoscaleWidth: ~p", [Value]);
create_opt({labelwidth, Value}) when is_integer(Value) or is_float(Value) ->
wf:f("labelWidth: ~p", [Value]);
create_opt({labelheight, Value}) when is_integer(Value) or is_float(Value) ->
wf:f("LabelHeight: ~p", [Value]);
create_opt({ticks, Value}) when is_integer(Value) or is_list(Value) ->
wf:f("ticks: ~p", [Value]);
create_opt({ticksize, Value}) when is_integer(Value) or is_float(Value) ->
wf:f("tickSize: ~p", [Value]);
create_opt({tickformatter, Value}) when is_list(Value) ->
wf:f("tickFormatter: ~p", [Value]);
create_opt({tickdecimals, Value}) when is_integer(Value) ->
wf:f("tickDecimals: ~p", [Value])
.

generate_ticks([[]]) ->
[];
generate_ticks([H | T]) ->
[generate_tick(0, H) | generate_ticks(1, T)]
.

generate_ticks(_, []) ->
[];
generate_ticks(N, [H | T]) ->
[generate_tick(N, H) | generate_ticks(N+1, T)]
.

generate_tick(N, Tick) ->
[N, Tick]
.


7 changes: 7 additions & 0 deletions src/element_flot_chart/elements.hrl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-record(flot_chart, {?ELEMENT_BASE(element_flot_chart), width, height, title
, minx, maxx, miny, maxy, xticks, yticks
, modex, modey, modex2, modey2
, minx2, maxx2, miny2, maxy2, x2ticks, y2ticks
, values, lines=true, points=true, bar=false, selectmode="xy"
, placeholder, legend
, hover, click, select}).
47 changes: 47 additions & 0 deletions src/element_notify/element_notify.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
-module(element_notify).
-compile(export_all).

-include_lib("nitrogen/include/wf.inc").
-include("elements.hrl").

reflect() -> record_info(fields, notify).

render() ->
wf:render(#panel{id=notification_area})
.

-define(HIDE(Type, Delay, Id), #event{type=Type, delay=Delay
, actions=#hide{effect=blind, target=Id}}).

render(ControlId, R) when is_record(R, notify) ->
Id = ControlId
, case R#notify.expire of
false ->
undefined;
N when is_integer(N) ->
% we expire in this many seconds
wf:wire(Id, ?HIDE('timer', N, Id));
Err ->
% log error and don't expire
iterate_log:log_warning(wf:f("encountered unknown expire value: ~p"
, [Err]))
, undefined
end
, Link = #link{text="dismiss", actions=?HIDE(click, undefined, Id)}
, InnerPanel = #panel{class="notify_inner", body=R#notify.msg}
, Panel = #panel{id=Id
, class=["notify ", R#notify.class]
, body=#singlerow{
cells=[#tablecell{align=left, body=InnerPanel}
, #tablecell{align=right, body=Link}]}
}
, element_panel:render(Id, Panel)
.

msg(Content) ->
wf:insert_bottom(notification_area, #notify{msg=Content})
.

msg(Content, Expire) ->
wf:insert_bottom(notification_area, #notify{msg=Content, expire=Expire})
.
1 change: 1 addition & 0 deletions src/element_notify/elements.hrl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-record(notify, {?ELEMENT_BASE(element_notify), expire=false, msg}).
2 changes: 1 addition & 1 deletion src/element_textarea_x.erl
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ render(ControlID, Record) ->
{class, [textarea, Record#textarea_x.class]},
{style, Record#textarea_x.style},
{rows, Record#textarea_x.rows},
{columns, Record#textarea_x.columns}
{cols, Record#textarea_x.columns}
]).
38 changes: 38 additions & 0 deletions src/nitrogen_extended/element_lightbox_transparent.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
-module (element_lightbox_transparent).

-include_lib("eunit/include/eunit.hrl").
-include("dinamo_wf.hrl").
-include("dinamo.hrl").

-compile(export_all).

-record(lightbox_transparent, {?ELEMENT_BASE(element_lightbox_transparent), body="" }).

% desc: the same as basic lightbox, but with transparent background

reflect() -> record_info(fields, lightbox_transparent).

render(ControlID, Record) ->
Terms = #panel {
class=lightbox,
style="position: fixed; top: 0px; left: 0px; bottom: 0px; right: 0px;",
body=[
#panel{
class=lightbox_background,
style=
"position: fixed; top: 0px; left: 0px; bottom: 0px; right: 0px;"
" z-index: 98; background-color: #000;"
" opacity: .70; " % FOR ALL OTHER BROWSERS AND DEVICES
" filter: alpha(opacity=70); " % FOR IE7
},
#table {
style="position: fixed; top: 0px; left: 0px; width: 100%; height: 100%; z-index: 99; overflow:auto;",
rows=#tablerow {
cells=#tablecell{
align=center,
valign=middle,
style="vertical-align: middle;",
body=Record#lightbox_transparent.body
}}}]
},
element_panel:render(ControlID, Terms).
27 changes: 27 additions & 0 deletions src/nitrogen_extended/element_menu.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
-module (element_menu).
-compile(export_all).

-include_lib("lib/nitrogen/include/wf.inc").
-record(menu, {?ELEMENT_BASE(element_menu), text="", body=[]}).

% desc: Provides a collapsable menu. The menu options are specified
% as listitem elements in the body.

reflect() -> record_info(fields, menu).

render(ControlID, Record) ->
Script = wf:f("$('#~s ul').hide();~n$('#~s li a').click(~nfunction() {~n$(this).next().slideToggle('normal');~n}~n);", [ControlID, ControlID]),
wf:wire(Script),
Title = wf:render(Record#menu.text),
Content = wf:render(Record#menu.body),
wf_tags:emit_tag(ul,
wf_tags:emit_tag(li,
Title++wf_tags:emit_tag(ul, Content, []),
[]),
[
{id, ControlID},
{class, Record#menu.class},
{style, Record#menu.style}
]
).

0 comments on commit 8d5fd3b

Please sign in to comment.