Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Merge master

  • Loading branch information...
commit 8d5fd3bd140cd08ce17c30cf1505d41f13e53ad7 2 parents d86fae0 + 4c17271
Andreas Stenius kaos authored
251 src/element_flot_chart/element_flot_chart.erl
... ... @@ -0,0 +1,251 @@
  1 +-module(element_flot_chart).
  2 +-compile(export_all).
  3 +
  4 +-include_lib("nitrogen/include/wf.inc").
  5 +-include("elements.hrl").
  6 +
  7 +reflect() -> record_info(fields, flot_chart).
  8 +
  9 +rec() -> #flot_chart{}.
  10 +
  11 +render(ControlId, Record) ->
  12 + %% handle multiple datasets
  13 + Data = Record#flot_chart.values
  14 + , DataSet = data_as_js(Data)
  15 + %% description of the graph
  16 + , _Title = Record#flot_chart.title
  17 + , Width = Record#flot_chart.width
  18 + , Height = Record#flot_chart.height
  19 + % TODO(jwall): dual axis support
  20 + , Lines = Record#flot_chart.lines
  21 + , Points = Record#flot_chart.points
  22 + , Bar = Record#flot_chart.bar
  23 + , SelectMode = Record#flot_chart.selectmode
  24 + %% IDs for the elements
  25 + , TargetId = case Record#flot_chart.placeholder of
  26 + undefined ->
  27 + wf:temp_id();
  28 + PlaceHolder ->
  29 + PlaceHolder
  30 + end
  31 + , PlotId = case Record#flot_chart.id of
  32 + undefined ->
  33 + wf:temp_id();
  34 + Id ->
  35 + Id
  36 + end
  37 + , LegendId = case Record#flot_chart.legend of
  38 + undefined ->
  39 + wf:temp_id();
  40 + Legend ->
  41 + Legend
  42 + end
  43 + , GraphId = wf:temp_id()
  44 + , ToolTipId = wf:temp_id()
  45 + %% TODO(jwall): support date formatting for timeseries data
  46 + %% TODO(jwall): colors
  47 + , Script = wf:f("var " ++ PlotId ++ ";"
  48 + ++ "$(function() { ~n"
  49 + ++ "var d = ~s;~n" % DataSet
  50 + ++ PlotId ++ " = $.plot($('#' + ~p), d, ~n{" % TargetId
  51 + ++ xaxis(Record) ++ ",~n"
  52 + ++ yaxis(Record) ++ ",~n"
  53 + ++ x2axis(Record) ++ ",~n"
  54 + ++ y2axis(Record) ++ ",~n"
  55 + % insert optional y2axis here
  56 + ++ "lines: {show: ~p},~n" % Lines
  57 + ++ "points: {show: ~p},~n" % Points
  58 + ++ "bars: {show: ~p},~n" % Bar
  59 + ++ "selection: {mode: ~p},~n" % SelectMode
  60 + ++ "grid: {hoverable: true, clickable: true},~n"
  61 + %% Legend
  62 + ++ "legend: { container: $('#' + ~p) } " % LegendId
  63 + ++ "});~n"
  64 + %% tooltip code
  65 + ++ "function showTooltip(x, y, contents) {~n"
  66 + ++ " $('<div id=~p>' + contents + '</div>').css( {~n" % ToolTipId
  67 + ++ " position: 'absolute',~n"
  68 + ++ " display: 'none',~n"
  69 + ++ " top: y + 5,~n"
  70 + ++ " left: x + 5,~n"
  71 + ++ " border: '1px solid #fdd',~n"
  72 + ++ " padding: '2px',~n"
  73 + ++ " 'background-color': '#fee',~n"
  74 + ++ " opacity: 0.80~n"
  75 + ++ " }).appendTo('body').fadeIn(200);~n"
  76 + ++ "}~n"
  77 + % now bind to the plothover event
  78 + ++ "var previousPoint = null;~n"
  79 + ++ "$('#' + ~p).bind('plothover', function(event, pos, item) {~n" % TargetId
  80 + ++ " $('#x').text(pos.x.toFixed(2));~n"
  81 + ++ " $('#y').text(pos.y.toFixed(2));~n"
  82 + ++ " if (item) {~n"
  83 + ++ " if(previousPoint != item.datapoint) {~n"
  84 + ++ " previousPoint = item.datapoint;~n"
  85 + ++ " $('#' + ~p).remove();~n" % ToolTipId
  86 + ++ " var x = item.datapoint[0].toFixed(2),~n"
  87 + ++ " y = item.datapoint[1].toFixed(2);~n"
  88 + ++ " showTooltip(item.pageX, item.pageY, y);~n"
  89 + ++ " } else {~n"
  90 + ++ " $('#' + ~p).remove();~n" % ToolTipId
  91 + ++ " previousPoint = null;~n"
  92 + ++ " }~n"
  93 + ++ " }~n"
  94 + ++ "})~n"
  95 + %% TODO(jwall): select event custom?
  96 + ++ "$('#' + ~p).bind('plotselected', function (event, ranges) {~n" % TargetId
  97 + ++ " //alert(ranges.xaxis.from.toFixed(1) + ',' + ranges.yaxis.from.toFixed(1))~n"
  98 + ++ " //alert(ranges.xaxis.to.toFixed(1) + ',' + ranges.yaxis.to.toFixed(1))~n"
  99 + ++ "})~n"
  100 + %% TODO(jwall): click event custom?
  101 + ++ "$('#' + ~p).bind('plotclick', function (event, pos, item) {~n" % TargetId
  102 + ++ " //alert(item.dataIndex + ' = ' + d[item.dataIndex]);~n"
  103 + ++ "})~n"
  104 + ++ "});~n"
  105 + , [DataSet, TargetId
  106 + , Lines, Points, Bar, SelectMode, LegendId
  107 + , ToolTipId, TargetId, ToolTipId, ToolTipId
  108 + , TargetId, TargetId
  109 + ])
  110 + %% TODO(jwall): dataset manipulation
  111 + %% TODO(jwall): zoom controls?
  112 + %% TODO(jwall): pan buttons?
  113 + , LegendPanel = #panel{id=LegendId}
  114 + , Panel = #panel{id=TargetId, style=wf:f("width:~ppx;height:~ppx", [Width, Height])}
  115 + , wf:wire(TargetId, #event{type='timer', delay=10
  116 + , actions=#script{script=Script}})
  117 + , element_singlerow:render(ControlId, #singlerow{id=GraphId, cells=[#tablecell{body=Panel}
  118 + , #tablecell{body=LegendPanel}]})
  119 +.
  120 +
  121 +data_as_js(T) when is_tuple(T) ->
  122 + data_as_js([T]);
  123 +data_as_js(L) ->
  124 + List = data_as_js_preparse(L)
  125 + , "[" ++ string:join(List, ",") ++ "]"
  126 +.
  127 +
  128 +data_as_js_preparse([]) ->
  129 + [];
  130 +data_as_js_preparse([H | T]) when is_tuple(H) ->
  131 + [ data_as_js_preparse(H) | data_as_js_preparse(T)];
  132 +data_as_js_preparse([H | T]) when is_list(H) ->
  133 + [ data_as_js_preparse({"undefined", H}) | data_as_js_preparse(T)];
  134 +data_as_js_preparse({Label, Data}) when is_list(Data) ->
  135 + wf:f("{ label: '~s', data: ~w}", [Label, Data]);
  136 +data_as_js_preparse({Label, Data, Opts})
  137 + when is_list(Data) and is_list(Opts) ->
  138 + OptString = create_options(Opts)
  139 + , wf:f("{ label: '~s', data: ~w, ~s}", [Label, Data, OptString]);
  140 +data_as_js_preparse({Label, Data, {Axis, Num}})
  141 + when is_list(Data) and is_atom(Axis) and is_integer(Num) ->
  142 + wf:f("{ label: '~s', data: ~w, ~p: ~p}", [Label, Data, Axis, Num])
  143 +.
  144 +
  145 +xaxis(Record) ->
  146 + Min = Record#flot_chart.minx
  147 + , Max = Record#flot_chart.maxx
  148 + , Mode = Record#flot_chart.modex
  149 + , Ticks = Record#flot_chart.xticks
  150 + , create_option(xaxis, [opt(min, Min)
  151 + , opt(max, Max), opt(ticks, Ticks)
  152 + , opt(mode, Mode)])
  153 +.
  154 +
  155 +yaxis(Record) ->
  156 + Min = Record#flot_chart.miny
  157 + , Max = Record#flot_chart.maxy
  158 + , Mode = Record#flot_chart.modey
  159 + , Ticks = Record#flot_chart.yticks
  160 + , create_option(yaxis, [opt(min, Min)
  161 + , opt(max, Max), opt(ticks, Ticks)
  162 + , opt(mode, Mode)])
  163 +.
  164 +
  165 +x2axis(Record) ->
  166 + Min = Record#flot_chart.minx2
  167 + , Max = Record#flot_chart.maxx2
  168 + , Mode = Record#flot_chart.modex2
  169 + , Ticks = Record#flot_chart.x2ticks
  170 + , create_option(x2axis, [opt(min, Min)
  171 + , opt(max, Max), opt(ticks, Ticks)
  172 + , opt(mode, Mode)])
  173 +.
  174 +
  175 +y2axis(Record) ->
  176 + Min = Record#flot_chart.miny2
  177 + , Max = Record#flot_chart.maxy2
  178 + , Mode = Record#flot_chart.modey2
  179 + , Ticks = Record#flot_chart.y2ticks
  180 + , create_option(y2axis, [opt(min, Min)
  181 + , opt(max, Max), opt(ticks, Ticks)
  182 + , opt(mode, Mode)])
  183 +.
  184 +
  185 +create_options(L) when is_list(L) ->
  186 + lists:join(create_options_from_list(L), ",")
  187 +.
  188 +
  189 +create_options_from_list([{Name, Items} | T]) ->
  190 + [create_option(Name, Items) | create_options(T)]
  191 +.
  192 +
  193 +create_option(Name, Items) when is_list(Items) ->
  194 + Opts = string:join(create_opts(Items), ",")
  195 + , lists:flatten([wf:f("~p: {~n", [Name])
  196 + , Opts, "}~n"])
  197 +.
  198 +
  199 +opt(Type, Value) ->
  200 + {Type, Value}
  201 +.
  202 +
  203 +create_opts([]) ->
  204 + "";
  205 +create_opts([H |T]) ->
  206 + [create_opt(H) | create_opts(T)]
  207 +.
  208 +
  209 +create_opt({Type, undefined}) ->
  210 + wf:f("~p: null", [Type]);
  211 +create_opt({mode, Value}) when Value == "time" ->
  212 + wf:f("mode: ~p", [Value]);
  213 +create_opt({show, Value}) when is_boolean(Value) ->
  214 + wf:f("show: ~p", [Value]);
  215 +create_opt({min, Value}) when is_integer(Value) or is_float(Value) ->
  216 + wf:f("min: ~p", [Value]);
  217 +create_opt({max, Value}) when is_integer(Value) or is_float(Value) ->
  218 + wf:f("max: ~p", [Value]);
  219 +create_opt({autoscale, Value}) when is_integer(Value) or is_float(Value) ->
  220 + wf:f("autoscaleWidth: ~p", [Value]);
  221 +create_opt({labelwidth, Value}) when is_integer(Value) or is_float(Value) ->
  222 + wf:f("labelWidth: ~p", [Value]);
  223 +create_opt({labelheight, Value}) when is_integer(Value) or is_float(Value) ->
  224 + wf:f("LabelHeight: ~p", [Value]);
  225 +create_opt({ticks, Value}) when is_integer(Value) or is_list(Value) ->
  226 + wf:f("ticks: ~p", [Value]);
  227 +create_opt({ticksize, Value}) when is_integer(Value) or is_float(Value) ->
  228 + wf:f("tickSize: ~p", [Value]);
  229 +create_opt({tickformatter, Value}) when is_list(Value) ->
  230 + wf:f("tickFormatter: ~p", [Value]);
  231 +create_opt({tickdecimals, Value}) when is_integer(Value) ->
  232 + wf:f("tickDecimals: ~p", [Value])
  233 +.
  234 +
  235 +generate_ticks([[]]) ->
  236 + [];
  237 +generate_ticks([H | T]) ->
  238 + [generate_tick(0, H) | generate_ticks(1, T)]
  239 +.
  240 +
  241 +generate_ticks(_, []) ->
  242 + [];
  243 +generate_ticks(N, [H | T]) ->
  244 + [generate_tick(N, H) | generate_ticks(N+1, T)]
  245 +.
  246 +
  247 +generate_tick(N, Tick) ->
  248 + [N, Tick]
  249 +.
  250 +
  251 +
7 src/element_flot_chart/elements.hrl
... ... @@ -0,0 +1,7 @@
  1 +-record(flot_chart, {?ELEMENT_BASE(element_flot_chart), width, height, title
  2 + , minx, maxx, miny, maxy, xticks, yticks
  3 + , modex, modey, modex2, modey2
  4 + , minx2, maxx2, miny2, maxy2, x2ticks, y2ticks
  5 + , values, lines=true, points=true, bar=false, selectmode="xy"
  6 + , placeholder, legend
  7 + , hover, click, select}).
47 src/element_notify/element_notify.erl
... ... @@ -0,0 +1,47 @@
  1 +-module(element_notify).
  2 +-compile(export_all).
  3 +
  4 +-include_lib("nitrogen/include/wf.inc").
  5 +-include("elements.hrl").
  6 +
  7 +reflect() -> record_info(fields, notify).
  8 +
  9 +render() ->
  10 + wf:render(#panel{id=notification_area})
  11 +.
  12 +
  13 +-define(HIDE(Type, Delay, Id), #event{type=Type, delay=Delay
  14 + , actions=#hide{effect=blind, target=Id}}).
  15 +
  16 +render(ControlId, R) when is_record(R, notify) ->
  17 + Id = ControlId
  18 + , case R#notify.expire of
  19 + false ->
  20 + undefined;
  21 + N when is_integer(N) ->
  22 + % we expire in this many seconds
  23 + wf:wire(Id, ?HIDE('timer', N, Id));
  24 + Err ->
  25 + % log error and don't expire
  26 + iterate_log:log_warning(wf:f("encountered unknown expire value: ~p"
  27 + , [Err]))
  28 + , undefined
  29 + end
  30 + , Link = #link{text="dismiss", actions=?HIDE(click, undefined, Id)}
  31 + , InnerPanel = #panel{class="notify_inner", body=R#notify.msg}
  32 + , Panel = #panel{id=Id
  33 + , class=["notify ", R#notify.class]
  34 + , body=#singlerow{
  35 + cells=[#tablecell{align=left, body=InnerPanel}
  36 + , #tablecell{align=right, body=Link}]}
  37 + }
  38 + , element_panel:render(Id, Panel)
  39 +.
  40 +
  41 +msg(Content) ->
  42 + wf:insert_bottom(notification_area, #notify{msg=Content})
  43 +.
  44 +
  45 +msg(Content, Expire) ->
  46 + wf:insert_bottom(notification_area, #notify{msg=Content, expire=Expire})
  47 +.
1  src/element_notify/elements.hrl
... ... @@ -0,0 +1 @@
  1 +-record(notify, {?ELEMENT_BASE(element_notify), expire=false, msg}).
2  src/element_textarea_x.erl
@@ -16,5 +16,5 @@ render(ControlID, Record) ->
16 16 {class, [textarea, Record#textarea_x.class]},
17 17 {style, Record#textarea_x.style},
18 18 {rows, Record#textarea_x.rows},
19   - {columns, Record#textarea_x.columns}
  19 + {cols, Record#textarea_x.columns}
20 20 ]).
38 src/nitrogen_extended/element_lightbox_transparent.erl
... ... @@ -0,0 +1,38 @@
  1 +-module (element_lightbox_transparent).
  2 +
  3 +-include_lib("eunit/include/eunit.hrl").
  4 +-include("dinamo_wf.hrl").
  5 +-include("dinamo.hrl").
  6 +
  7 +-compile(export_all).
  8 +
  9 +-record(lightbox_transparent, {?ELEMENT_BASE(element_lightbox_transparent), body="" }).
  10 +
  11 +% desc: the same as basic lightbox, but with transparent background
  12 +
  13 +reflect() -> record_info(fields, lightbox_transparent).
  14 +
  15 +render(ControlID, Record) ->
  16 + Terms = #panel {
  17 + class=lightbox,
  18 + style="position: fixed; top: 0px; left: 0px; bottom: 0px; right: 0px;",
  19 + body=[
  20 + #panel{
  21 + class=lightbox_background,
  22 + style=
  23 + "position: fixed; top: 0px; left: 0px; bottom: 0px; right: 0px;"
  24 + " z-index: 98; background-color: #000;"
  25 + " opacity: .70; " % FOR ALL OTHER BROWSERS AND DEVICES
  26 + " filter: alpha(opacity=70); " % FOR IE7
  27 + },
  28 + #table {
  29 + style="position: fixed; top: 0px; left: 0px; width: 100%; height: 100%; z-index: 99; overflow:auto;",
  30 + rows=#tablerow {
  31 + cells=#tablecell{
  32 + align=center,
  33 + valign=middle,
  34 + style="vertical-align: middle;",
  35 + body=Record#lightbox_transparent.body
  36 + }}}]
  37 + },
  38 + element_panel:render(ControlID, Terms).
27 src/nitrogen_extended/element_menu.erl
... ... @@ -0,0 +1,27 @@
  1 +-module (element_menu).
  2 +-compile(export_all).
  3 +
  4 +-include_lib("lib/nitrogen/include/wf.inc").
  5 +-record(menu, {?ELEMENT_BASE(element_menu), text="", body=[]}).
  6 +
  7 +% desc: Provides a collapsable menu. The menu options are specified
  8 +% as listitem elements in the body.
  9 +
  10 +reflect() -> record_info(fields, menu).
  11 +
  12 +render(ControlID, Record) ->
  13 + Script = wf:f("$('#~s ul').hide();~n$('#~s li a').click(~nfunction() {~n$(this).next().slideToggle('normal');~n}~n);", [ControlID, ControlID]),
  14 + wf:wire(Script),
  15 + Title = wf:render(Record#menu.text),
  16 + Content = wf:render(Record#menu.body),
  17 + wf_tags:emit_tag(ul,
  18 + wf_tags:emit_tag(li,
  19 + Title++wf_tags:emit_tag(ul, Content, []),
  20 + []),
  21 + [
  22 + {id, ControlID},
  23 + {class, Record#menu.class},
  24 + {style, Record#menu.style}
  25 + ]
  26 + ).
  27 +

0 comments on commit 8d5fd3b

Please sign in to comment.
Something went wrong with that request. Please try again.