acts_as_dashboard 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/VERSION +1 -1
- data/acts_as_dashboard.gemspec +5 -8
- data/generators/dashboard/dashboard_generator.rb +2 -2
- data/lib/acts_as_dashboard/app/views/dashboards/show.html.erb +70 -70
- data/lib/acts_as_dashboard/public/javascripts/dashboard.js +304 -304
- data/lib/acts_as_dashboard/public/stylesheets/dashboard.css +86 -86
- metadata +13 -7
- data/tasks/install.rake +0 -8
- data/tasks/install_javascript.rake +0 -7
- data/tasks/install_stylesheets.rake +0 -7
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.2
|
data/acts_as_dashboard.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{acts_as_dashboard}
|
8
|
-
s.version = "0.3.
|
8
|
+
s.version = "0.3.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Nick Hoffman"]
|
12
|
-
s.date = %q{2010-08-
|
12
|
+
s.date = %q{2010-08-04}
|
13
13
|
s.description = %q{acts_as_dashboard makes it easy to create dashboards in Rails apps. Very little configuration is required. Read the docs to get started.}
|
14
14
|
s.email = %q{nick@deadorange.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -142,15 +142,12 @@ Gem::Specification.new do |s|
|
|
142
142
|
"spec/acts_as_dashboard_spec.rb",
|
143
143
|
"spec/shared/widget_behaviours.rb",
|
144
144
|
"spec/spec.opts",
|
145
|
-
"spec/spec_helper.rb"
|
146
|
-
"tasks/install.rake",
|
147
|
-
"tasks/install_javascript.rake",
|
148
|
-
"tasks/install_stylesheets.rake"
|
145
|
+
"spec/spec_helper.rb"
|
149
146
|
]
|
150
147
|
s.homepage = %q{http://github.com/nickhoffman/acts_as_dashboard}
|
151
148
|
s.rdoc_options = ["--charset=UTF-8"]
|
152
149
|
s.require_paths = ["lib"]
|
153
|
-
s.rubygems_version = %q{1.3.
|
150
|
+
s.rubygems_version = %q{1.3.7}
|
154
151
|
s.summary = %q{Create dashboards in Rails apps easily.}
|
155
152
|
s.test_files = [
|
156
153
|
"spec/acts_as_dashboard_spec.rb",
|
@@ -168,7 +165,7 @@ Gem::Specification.new do |s|
|
|
168
165
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
169
166
|
s.specification_version = 3
|
170
167
|
|
171
|
-
if Gem::Version.new(Gem::
|
168
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
172
169
|
s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
|
173
170
|
s.add_development_dependency(%q<rspec-rails>, [">= 1.3.2"])
|
174
171
|
else
|
@@ -78,8 +78,8 @@ class DashboardGenerator < Rails::Generator::Base
|
|
78
78
|
|
79
79
|
def build_routes(controller_name) # {{{
|
80
80
|
controller = controller_name.downcase.gsub /controller$/, ''
|
81
|
-
@singleton_resource = %Q(map.resource :#{controller}, :only => :show)
|
82
|
-
@widgets_route = %Q(map.connect '#{controller}/widgets/*path', :controller => :#{controller.pluralize}, :action => 'widget_data')
|
81
|
+
@singleton_resource = %Q(map.resource :#{controller.singularize}, :only => :show)
|
82
|
+
@widgets_route = %Q(map.connect '#{controller.singularize}/widgets/*path', :controller => :#{controller.pluralize}, :action => 'widget_data')
|
83
83
|
end # }}}
|
84
84
|
|
85
85
|
def add_dashboard_routes(controller_name) # {{{
|
@@ -1,70 +1,70 @@
|
|
1
|
-
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
2
|
-
|
3
|
-
<html>
|
4
|
-
|
5
|
-
<head>
|
6
|
-
<style type="text/css">
|
7
|
-
<%# @dashboard_css %>
|
8
|
-
</style>
|
9
|
-
|
10
|
-
<%= javascript_include_tag 'http://code.jquery.com/jquery-1.4.2.min.js' %>
|
11
|
-
<%= javascript_include_tag 'jquery-ui/js/jquery-ui-1.8.2.custom.min.js' %>
|
12
|
-
<%= javascript_include_tag 'http://plugins.jquery.com/files/jquery.timers-1.2.js.txt' %>
|
13
|
-
<%= javascript_include_tag 'js.class-2.1.4/min/core.js' %>
|
14
|
-
<%= javascript_include_tag 'jqplot-0.9.7/jquery.jqplot.min.js' %>
|
15
|
-
<%= javascript_include_tag 'dashboard' %>
|
16
|
-
|
17
|
-
<%= stylesheet_link_tag 'jquery-ui/css/ui-darkness/jquery-ui-1.8.2.custom.css' %>
|
18
|
-
<%= stylesheet_link_tag 'dashboard' %>
|
19
|
-
<%= stylesheet_link_tag 'jquery.jqplot.min.css' %>
|
20
|
-
|
21
|
-
<script type='text/javascript'>
|
22
|
-
jQuery(document).ready(function() {
|
23
|
-
dashboard = new Dashboard({basePath: '<%= @dashboard_path -%>'});
|
24
|
-
json_widgets = '<%= @json_widgets -%>';
|
25
|
-
|
26
|
-
buildTheDashboard();
|
27
|
-
});
|
28
|
-
</script>
|
29
|
-
|
30
|
-
<script type='text/javascript'>
|
31
|
-
<%# @dashboard_js %>
|
32
|
-
</script>
|
33
|
-
</head>
|
34
|
-
|
35
|
-
<body>
|
36
|
-
<div id='dashboard'>
|
37
|
-
<div class='dashboard-numbers'>
|
38
|
-
<div class='ui-widget widget-template' style='display: none;'>
|
39
|
-
<div class="ui-widget-header ui-corner-tl ui-corner-tr widget-title"></div>
|
40
|
-
<div class="ui-widget-content ui-corner-bl ui-corner-br widget-data"></div>
|
41
|
-
</div>
|
42
|
-
</div>
|
43
|
-
|
44
|
-
<div class='dashboard-clear'></div>
|
45
|
-
|
46
|
-
<div class='dashboard-short-messages'>
|
47
|
-
<div class='ui-widget widget-template' style='display: none;'>
|
48
|
-
<div class="ui-widget-header ui-corner-all widget-title"></div>
|
49
|
-
<div class="widget-data">
|
50
|
-
<ul>
|
51
|
-
<li class='ui-widget-content ui-corner-all widget-data widget-data-template' style='display: none;'></li>
|
52
|
-
</ul>
|
53
|
-
</div>
|
54
|
-
</div>
|
55
|
-
</div>
|
56
|
-
|
57
|
-
<div class='dashboard-clear'></div>
|
58
|
-
|
59
|
-
<div class='dashboard-line-graphs'>
|
60
|
-
<div class='ui-widget widget-template' style='display: none;'>
|
61
|
-
<div class='ui-widget-header ui-corner-tl ui-corner-tr widget-title'></div>
|
62
|
-
<div class='ui-widget-content ui-corner-bl ui-corner-br widget-data'></div>
|
63
|
-
</div>
|
64
|
-
</div>
|
65
|
-
|
66
|
-
<div class='dashboard-clear'></div>
|
67
|
-
</div>
|
68
|
-
</body>
|
69
|
-
|
70
|
-
</html>
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
2
|
+
|
3
|
+
<html>
|
4
|
+
|
5
|
+
<head>
|
6
|
+
<style type="text/css">
|
7
|
+
<%# @dashboard_css %>
|
8
|
+
</style>
|
9
|
+
|
10
|
+
<%= javascript_include_tag 'http://code.jquery.com/jquery-1.4.2.min.js' %>
|
11
|
+
<%= javascript_include_tag 'jquery-ui/js/jquery-ui-1.8.2.custom.min.js' %>
|
12
|
+
<%= javascript_include_tag 'http://plugins.jquery.com/files/jquery.timers-1.2.js.txt' %>
|
13
|
+
<%= javascript_include_tag 'js.class-2.1.4/min/core.js' %>
|
14
|
+
<%= javascript_include_tag 'jqplot-0.9.7/jquery.jqplot.min.js' %>
|
15
|
+
<%= javascript_include_tag 'dashboard' %>
|
16
|
+
|
17
|
+
<%= stylesheet_link_tag 'jquery-ui/css/ui-darkness/jquery-ui-1.8.2.custom.css' %>
|
18
|
+
<%= stylesheet_link_tag 'dashboard' %>
|
19
|
+
<%= stylesheet_link_tag 'jquery.jqplot.min.css' %>
|
20
|
+
|
21
|
+
<script type='text/javascript'>
|
22
|
+
jQuery(document).ready(function() {
|
23
|
+
dashboard = new Dashboard({basePath: '<%= @dashboard_path -%>'});
|
24
|
+
json_widgets = '<%= @json_widgets -%>';
|
25
|
+
|
26
|
+
buildTheDashboard();
|
27
|
+
});
|
28
|
+
</script>
|
29
|
+
|
30
|
+
<script type='text/javascript'>
|
31
|
+
<%# @dashboard_js %>
|
32
|
+
</script>
|
33
|
+
</head>
|
34
|
+
|
35
|
+
<body>
|
36
|
+
<div id='dashboard'>
|
37
|
+
<div class='dashboard-numbers'>
|
38
|
+
<div class='ui-widget widget-template' style='display: none;'>
|
39
|
+
<div class="ui-widget-header ui-corner-tl ui-corner-tr widget-title"></div>
|
40
|
+
<div class="ui-widget-content ui-corner-bl ui-corner-br"><div class="widget-data"></div></div>
|
41
|
+
</div>
|
42
|
+
</div>
|
43
|
+
|
44
|
+
<div class='dashboard-clear'></div>
|
45
|
+
|
46
|
+
<div class='dashboard-short-messages'>
|
47
|
+
<div class='ui-widget widget-template' style='display: none;'>
|
48
|
+
<div class="ui-widget-header ui-corner-all widget-title"></div>
|
49
|
+
<div class="widget-data">
|
50
|
+
<ul>
|
51
|
+
<li class='ui-widget-content ui-corner-all widget-data widget-data-template' style='display: none;'></li>
|
52
|
+
</ul>
|
53
|
+
</div>
|
54
|
+
</div>
|
55
|
+
</div>
|
56
|
+
|
57
|
+
<div class='dashboard-clear'></div>
|
58
|
+
|
59
|
+
<div class='dashboard-line-graphs'>
|
60
|
+
<div class='ui-widget widget-template' style='display: none;'>
|
61
|
+
<div class='ui-widget-header ui-corner-tl ui-corner-tr widget-title'></div>
|
62
|
+
<div class='ui-widget-content ui-corner-bl ui-corner-br widget-data'></div>
|
63
|
+
</div>
|
64
|
+
</div>
|
65
|
+
|
66
|
+
<div class='dashboard-clear'></div>
|
67
|
+
</div>
|
68
|
+
</body>
|
69
|
+
|
70
|
+
</html>
|
@@ -1,304 +1,304 @@
|
|
1
|
-
// function includeJavaScriptFile(path) {{{
|
2
|
-
//
|
3
|
-
// Creates a JavaScript <script> element and appends it
|
4
|
-
// to the <head>.
|
5
|
-
//
|
6
|
-
function includeJavaScriptFile(path) {
|
7
|
-
// Ensure that we have a non-empty string.'
|
8
|
-
if ((typeof(path) != 'string') || (!path))
|
9
|
-
{return;}
|
10
|
-
|
11
|
-
// Ensure that we can find the <head>.
|
12
|
-
var head = jQuery('head');
|
13
|
-
if (!head)
|
14
|
-
{return;}
|
15
|
-
|
16
|
-
var element = document.createElement('script');
|
17
|
-
element.type = 'text/javascript';
|
18
|
-
element.src = path;
|
19
|
-
|
20
|
-
head.append(element);
|
21
|
-
|
22
|
-
return true;
|
23
|
-
} // }}}
|
24
|
-
|
25
|
-
// function buildTheDashboard() {{{
|
26
|
-
//
|
27
|
-
// Determines which dashboard widgets to build,
|
28
|
-
// builds them, and adds them to the DOM.
|
29
|
-
//
|
30
|
-
function buildTheDashboard() {
|
31
|
-
var parsed_widgets = jQuery.parseJSON(json_widgets);
|
32
|
-
|
33
|
-
jQuery.each(parsed_widgets, function(index, widget) {
|
34
|
-
if (widget.type == 'number')
|
35
|
-
{dashboard.addNumberWidget(widget);}
|
36
|
-
else if (widget.type == 'short_messages')
|
37
|
-
{dashboard.addShortMessagesWidget(widget);}
|
38
|
-
else if (widget.type == 'line_graph')
|
39
|
-
{dashboard.addLineGraphWidget(widget);}
|
40
|
-
});
|
41
|
-
} // }}}
|
42
|
-
|
43
|
-
function createUpdateTimerFor(widget) { // {{{
|
44
|
-
$(this).everyTime(widget.update_interval, widget.name, function() {
|
45
|
-
widget.updateData();
|
46
|
-
});
|
47
|
-
} // }}}
|
48
|
-
|
49
|
-
// Begin Dashboard class. {{{
|
50
|
-
var Dashboard = new JS.Class({
|
51
|
-
initialize: function(options) { // {{{
|
52
|
-
this.basePath = options.basePath;
|
53
|
-
|
54
|
-
this.numberWidgets = new Array();
|
55
|
-
this.shortMessagesWidgets = new Array();
|
56
|
-
this.lineGraphWidgets = new Array();
|
57
|
-
|
58
|
-
this.div = jQuery('#dashboard');
|
59
|
-
this.numberWidgetsDiv = this.div.find('.dashboard-numbers');
|
60
|
-
this.shortMessagesWidgetsDiv = this.div.find('.dashboard-short-messages');
|
61
|
-
this.lineGraphWidgetsDiv = this.div.find('.dashboard-line-graphs');
|
62
|
-
}, // }}}
|
63
|
-
|
64
|
-
addNumberWidget: function(options) { // {{{
|
65
|
-
var widget = new NumberWidget(options);
|
66
|
-
var templateDiv = this.numberWidgetsDiv.find('.widget-template');
|
67
|
-
|
68
|
-
var widgetDiv = templateDiv.clone(false)
|
69
|
-
.removeClass('widget-template')
|
70
|
-
.addClass('number-widget')
|
71
|
-
.attr('id', widget.divID())
|
72
|
-
.appendTo(this.numberWidgetsDiv);
|
73
|
-
|
74
|
-
// Set the new div's title.
|
75
|
-
widgetDiv.find('.widget-title').html(widget.title);
|
76
|
-
|
77
|
-
widget.setDataDivTo(widgetDiv.find('.widget-data'));
|
78
|
-
widget.updateData();
|
79
|
-
|
80
|
-
createUpdateTimerFor(widget);
|
81
|
-
|
82
|
-
this.numberWidgets.push(widget);
|
83
|
-
|
84
|
-
widgetDiv.show();
|
85
|
-
}, // }}}
|
86
|
-
|
87
|
-
addShortMessagesWidget: function(options) { // {{{
|
88
|
-
var widget = new ShortMessagesWidget(options);
|
89
|
-
var templateDiv = this.shortMessagesWidgetsDiv.find('.widget-template');
|
90
|
-
|
91
|
-
var widgetDiv = templateDiv.clone(false)
|
92
|
-
.removeClass('widget-template')
|
93
|
-
.addClass('short-messages-widget')
|
94
|
-
.attr('id', widget.divID())
|
95
|
-
.appendTo(this.shortMessagesWidgetsDiv);
|
96
|
-
|
97
|
-
// Set the new div's title.
|
98
|
-
widgetDiv.find('.widget-title').html(widget.title);
|
99
|
-
|
100
|
-
widget.setDataDivTo(widgetDiv.find('.widget-data'));
|
101
|
-
widget.updateData();
|
102
|
-
|
103
|
-
createUpdateTimerFor(widget);
|
104
|
-
|
105
|
-
this.shortMessagesWidgets.push(widget);
|
106
|
-
|
107
|
-
widgetDiv.show();
|
108
|
-
}, // }}}
|
109
|
-
|
110
|
-
addLineGraphWidget: function(options) { // {{{
|
111
|
-
var widget = new LineGraphWidget(options);
|
112
|
-
var templateDiv = this.lineGraphWidgetsDiv.find('.widget-template');
|
113
|
-
|
114
|
-
var widgetDiv = templateDiv.clone(false)
|
115
|
-
.removeClass('widget-template')
|
116
|
-
.addClass('line-graph-widget')
|
117
|
-
.attr('id', widget.divID())
|
118
|
-
.appendTo(this.lineGraphWidgetsDiv);
|
119
|
-
|
120
|
-
// Set the new div's title.
|
121
|
-
widgetDiv.find('.widget-title').html(widget.title);
|
122
|
-
|
123
|
-
var dataDiv = widgetDiv.find('.widget-data')
|
124
|
-
.attr('id', widget.divID() + '-data');
|
125
|
-
|
126
|
-
widget.setDataDivTo(dataDiv);
|
127
|
-
|
128
|
-
widget.updateData();
|
129
|
-
|
130
|
-
// I don't know why, but setting these properties when dataDiv
|
131
|
-
// is initialized fails to work. They work here, though...
|
132
|
-
dataDiv.css('height', widget.height)
|
133
|
-
dataDiv.css('width', widget.width)
|
134
|
-
|
135
|
-
createUpdateTimerFor(widget);
|
136
|
-
|
137
|
-
this.lineGraphWidgets.push(widget);
|
138
|
-
|
139
|
-
widgetDiv.show();
|
140
|
-
} // }}}
|
141
|
-
});
|
142
|
-
// End Dashboard class. }}}
|
143
|
-
|
144
|
-
// Begin DashboardWidget class. {{{
|
145
|
-
var DashboardWidget = new JS.Class({
|
146
|
-
initialize: function(options) {
|
147
|
-
this.type = options.type;
|
148
|
-
this.name = options.name;
|
149
|
-
this.title = options.title;
|
150
|
-
this.update_interval = options.update_interval;
|
151
|
-
},
|
152
|
-
|
153
|
-
dataURL: function() {
|
154
|
-
return dashboard.basePath + this.name;
|
155
|
-
},
|
156
|
-
|
157
|
-
divID: function() {
|
158
|
-
return this.name + '-' + this.type + '-widget';
|
159
|
-
},
|
160
|
-
|
161
|
-
setDataDivTo: function(element) {
|
162
|
-
this.dataDiv = element;
|
163
|
-
}
|
164
|
-
});
|
165
|
-
// End DashboardWidget class. }}}
|
166
|
-
|
167
|
-
// Begin NumberWidget class. {{{
|
168
|
-
var NumberWidget = new JS.Class(DashboardWidget, {
|
169
|
-
initialize: function(options) {
|
170
|
-
options['type'] = 'number';
|
171
|
-
this.callSuper(options);
|
172
|
-
},
|
173
|
-
|
174
|
-
updateData: function() {
|
175
|
-
if (!this.dataDiv)
|
176
|
-
{return false;}
|
177
|
-
|
178
|
-
// This is needed so that the dataDiv property is accessible with jQuery.get() .
|
179
|
-
var element = this.dataDiv;
|
180
|
-
|
181
|
-
jQuery.get(this.dataURL(), function(data) {
|
182
|
-
element.fadeOut(400, function() {
|
183
|
-
element.html(data);
|
184
|
-
element.fadeIn();
|
185
|
-
});
|
186
|
-
}, 'text');
|
187
|
-
}
|
188
|
-
});
|
189
|
-
// End NumberWidget class. }}}
|
190
|
-
|
191
|
-
// Begin ShortMessagesWidget class. {{{
|
192
|
-
var ShortMessagesWidget = new JS.Class(DashboardWidget, {
|
193
|
-
initialize: function(options) {
|
194
|
-
options['type'] = 'short_messages';
|
195
|
-
this.callSuper(options);
|
196
|
-
this.maxDataItems = 5;
|
197
|
-
},
|
198
|
-
|
199
|
-
firstDataItem: function() {
|
200
|
-
return this.dataDiv.find('li.widget-data-item:first');
|
201
|
-
},
|
202
|
-
|
203
|
-
dataItemsCount: function() {
|
204
|
-
return this.dataDiv.find('li.widget-data-item').length;
|
205
|
-
},
|
206
|
-
|
207
|
-
createDataItem: function() {
|
208
|
-
return this.dataDiv.find('li.widget-data-template')
|
209
|
-
.clone(false)
|
210
|
-
.removeClass('widget-data-template')
|
211
|
-
.addClass('widget-data-item');
|
212
|
-
},
|
213
|
-
|
214
|
-
updateData: function() {
|
215
|
-
if (!this.dataDiv)
|
216
|
-
{return false;}
|
217
|
-
|
218
|
-
var new_data = '';
|
219
|
-
var new_li = this.createDataItem();
|
220
|
-
|
221
|
-
// We use ajax() instead of get() because the "async" option must
|
222
|
-
// be false. If it isn't, we're unable to determine if data was
|
223
|
-
// obtained.
|
224
|
-
var get_result = jQuery.ajax({
|
225
|
-
url: this.dataURL(),
|
226
|
-
type: 'GET',
|
227
|
-
async: false,
|
228
|
-
cache: false,
|
229
|
-
dataType: 'text',
|
230
|
-
timeout: this.updateInterval,
|
231
|
-
success: function(data) {
|
232
|
-
new_li.html(data);
|
233
|
-
new_data = data;
|
234
|
-
}
|
235
|
-
});
|
236
|
-
|
237
|
-
// If no data was obtained, return. Otherwise, an empty list item
|
238
|
-
// will be shown.
|
239
|
-
if (new_data == '')
|
240
|
-
{return false;}
|
241
|
-
|
242
|
-
new_li.appendTo(this.dataDiv.find('ul'));
|
243
|
-
|
244
|
-
// Hide the first list item if we've reached the maximum number of
|
245
|
-
// list items to show in this widget.
|
246
|
-
if (this.dataItemsCount() > this.maxDataItems) {
|
247
|
-
var firstDataItem = this.firstDataItem();
|
248
|
-
|
249
|
-
firstDataItem.slideUp(400, function() {
|
250
|
-
firstDataItem.remove();
|
251
|
-
});
|
252
|
-
}
|
253
|
-
|
254
|
-
new_li.slideDown();
|
255
|
-
}
|
256
|
-
});
|
257
|
-
// End ShortMessagesWidget class. }}}
|
258
|
-
|
259
|
-
// Begin LineGraphWidget class. {{{
|
260
|
-
var LineGraphWidget = new JS.Class(DashboardWidget, {
|
261
|
-
initialize: function(options) {
|
262
|
-
this.height = options.height;
|
263
|
-
this.width = options.width;
|
264
|
-
this.seriesColours = options.line_colours;
|
265
|
-
this.x_axis = options.x_axis;
|
266
|
-
|
267
|
-
options.type = 'line_graph';
|
268
|
-
this.callSuper(options);
|
269
|
-
},
|
270
|
-
|
271
|
-
updateData: function() {
|
272
|
-
if (!this.graph)
|
273
|
-
{this.createGraph();}
|
274
|
-
|
275
|
-
// This is needed so that the dataDiv property is accessible with jQuery.get() .
|
276
|
-
var graph = this.graph;
|
277
|
-
|
278
|
-
jQuery.get(this.dataURL(), function(data) {
|
279
|
-
graph.series[0].data = data;
|
280
|
-
graph.replot({resetAxes: true});
|
281
|
-
}, 'json');
|
282
|
-
},
|
283
|
-
|
284
|
-
createGraph: function() {
|
285
|
-
includeJavaScriptFile('/javascripts/jqplot-0.9.7/plugins/jqplot.dateAxisRenderer.min.js');
|
286
|
-
|
287
|
-
var x_axis_format = {};
|
288
|
-
if (this.x_axis === 'dates') {
|
289
|
-
var x_axis_format = {
|
290
|
-
renderer: jQuery.jqplot.DateAxisRenderer,
|
291
|
-
tickOptions: {formatString: '%Y-%m-%d'}
|
292
|
-
}
|
293
|
-
}
|
294
|
-
|
295
|
-
this.graph = jQuery.jqplot(this.dataDiv.attr('id'), [ [] ], {
|
296
|
-
seriesColors: this.seriesColours,
|
297
|
-
axes: {
|
298
|
-
xaxis: x_axis_format
|
299
|
-
}
|
300
|
-
});
|
301
|
-
}
|
302
|
-
});
|
303
|
-
// End LineGraphWidget class. }}}
|
304
|
-
|
1
|
+
// function includeJavaScriptFile(path) {{{
|
2
|
+
//
|
3
|
+
// Creates a JavaScript <script> element and appends it
|
4
|
+
// to the <head>.
|
5
|
+
//
|
6
|
+
function includeJavaScriptFile(path) {
|
7
|
+
// Ensure that we have a non-empty string.'
|
8
|
+
if ((typeof(path) != 'string') || (!path))
|
9
|
+
{return;}
|
10
|
+
|
11
|
+
// Ensure that we can find the <head>.
|
12
|
+
var head = jQuery('head');
|
13
|
+
if (!head)
|
14
|
+
{return;}
|
15
|
+
|
16
|
+
var element = document.createElement('script');
|
17
|
+
element.type = 'text/javascript';
|
18
|
+
element.src = path;
|
19
|
+
|
20
|
+
head.append(element);
|
21
|
+
|
22
|
+
return true;
|
23
|
+
} // }}}
|
24
|
+
|
25
|
+
// function buildTheDashboard() {{{
|
26
|
+
//
|
27
|
+
// Determines which dashboard widgets to build,
|
28
|
+
// builds them, and adds them to the DOM.
|
29
|
+
//
|
30
|
+
function buildTheDashboard() {
|
31
|
+
var parsed_widgets = jQuery.parseJSON(json_widgets);
|
32
|
+
|
33
|
+
jQuery.each(parsed_widgets, function(index, widget) {
|
34
|
+
if (widget.type == 'number')
|
35
|
+
{dashboard.addNumberWidget(widget);}
|
36
|
+
else if (widget.type == 'short_messages')
|
37
|
+
{dashboard.addShortMessagesWidget(widget);}
|
38
|
+
else if (widget.type == 'line_graph')
|
39
|
+
{dashboard.addLineGraphWidget(widget);}
|
40
|
+
});
|
41
|
+
} // }}}
|
42
|
+
|
43
|
+
function createUpdateTimerFor(widget) { // {{{
|
44
|
+
$(this).everyTime(widget.update_interval, widget.name, function() {
|
45
|
+
widget.updateData();
|
46
|
+
});
|
47
|
+
} // }}}
|
48
|
+
|
49
|
+
// Begin Dashboard class. {{{
|
50
|
+
var Dashboard = new JS.Class({
|
51
|
+
initialize: function(options) { // {{{
|
52
|
+
this.basePath = options.basePath;
|
53
|
+
|
54
|
+
this.numberWidgets = new Array();
|
55
|
+
this.shortMessagesWidgets = new Array();
|
56
|
+
this.lineGraphWidgets = new Array();
|
57
|
+
|
58
|
+
this.div = jQuery('#dashboard');
|
59
|
+
this.numberWidgetsDiv = this.div.find('.dashboard-numbers');
|
60
|
+
this.shortMessagesWidgetsDiv = this.div.find('.dashboard-short-messages');
|
61
|
+
this.lineGraphWidgetsDiv = this.div.find('.dashboard-line-graphs');
|
62
|
+
}, // }}}
|
63
|
+
|
64
|
+
addNumberWidget: function(options) { // {{{
|
65
|
+
var widget = new NumberWidget(options);
|
66
|
+
var templateDiv = this.numberWidgetsDiv.find('.widget-template');
|
67
|
+
|
68
|
+
var widgetDiv = templateDiv.clone(false)
|
69
|
+
.removeClass('widget-template')
|
70
|
+
.addClass('number-widget')
|
71
|
+
.attr('id', widget.divID())
|
72
|
+
.appendTo(this.numberWidgetsDiv);
|
73
|
+
|
74
|
+
// Set the new div's title.
|
75
|
+
widgetDiv.find('.widget-title').html(widget.title);
|
76
|
+
|
77
|
+
widget.setDataDivTo(widgetDiv.find('.widget-data'));
|
78
|
+
widget.updateData();
|
79
|
+
|
80
|
+
createUpdateTimerFor(widget);
|
81
|
+
|
82
|
+
this.numberWidgets.push(widget);
|
83
|
+
|
84
|
+
widgetDiv.show();
|
85
|
+
}, // }}}
|
86
|
+
|
87
|
+
addShortMessagesWidget: function(options) { // {{{
|
88
|
+
var widget = new ShortMessagesWidget(options);
|
89
|
+
var templateDiv = this.shortMessagesWidgetsDiv.find('.widget-template');
|
90
|
+
|
91
|
+
var widgetDiv = templateDiv.clone(false)
|
92
|
+
.removeClass('widget-template')
|
93
|
+
.addClass('short-messages-widget')
|
94
|
+
.attr('id', widget.divID())
|
95
|
+
.appendTo(this.shortMessagesWidgetsDiv);
|
96
|
+
|
97
|
+
// Set the new div's title.
|
98
|
+
widgetDiv.find('.widget-title').html(widget.title);
|
99
|
+
|
100
|
+
widget.setDataDivTo(widgetDiv.find('.widget-data'));
|
101
|
+
widget.updateData();
|
102
|
+
|
103
|
+
createUpdateTimerFor(widget);
|
104
|
+
|
105
|
+
this.shortMessagesWidgets.push(widget);
|
106
|
+
|
107
|
+
widgetDiv.show();
|
108
|
+
}, // }}}
|
109
|
+
|
110
|
+
addLineGraphWidget: function(options) { // {{{
|
111
|
+
var widget = new LineGraphWidget(options);
|
112
|
+
var templateDiv = this.lineGraphWidgetsDiv.find('.widget-template');
|
113
|
+
|
114
|
+
var widgetDiv = templateDiv.clone(false)
|
115
|
+
.removeClass('widget-template')
|
116
|
+
.addClass('line-graph-widget')
|
117
|
+
.attr('id', widget.divID())
|
118
|
+
.appendTo(this.lineGraphWidgetsDiv);
|
119
|
+
|
120
|
+
// Set the new div's title.
|
121
|
+
widgetDiv.find('.widget-title').html(widget.title);
|
122
|
+
|
123
|
+
var dataDiv = widgetDiv.find('.widget-data')
|
124
|
+
.attr('id', widget.divID() + '-data');
|
125
|
+
|
126
|
+
widget.setDataDivTo(dataDiv);
|
127
|
+
|
128
|
+
widget.updateData();
|
129
|
+
|
130
|
+
// I don't know why, but setting these properties when dataDiv
|
131
|
+
// is initialized fails to work. They work here, though...
|
132
|
+
dataDiv.css('height', widget.height)
|
133
|
+
dataDiv.css('width', widget.width)
|
134
|
+
|
135
|
+
createUpdateTimerFor(widget);
|
136
|
+
|
137
|
+
this.lineGraphWidgets.push(widget);
|
138
|
+
|
139
|
+
widgetDiv.show();
|
140
|
+
} // }}}
|
141
|
+
});
|
142
|
+
// End Dashboard class. }}}
|
143
|
+
|
144
|
+
// Begin DashboardWidget class. {{{
|
145
|
+
var DashboardWidget = new JS.Class({
|
146
|
+
initialize: function(options) {
|
147
|
+
this.type = options.type;
|
148
|
+
this.name = options.name;
|
149
|
+
this.title = options.title;
|
150
|
+
this.update_interval = options.update_interval;
|
151
|
+
},
|
152
|
+
|
153
|
+
dataURL: function() {
|
154
|
+
return dashboard.basePath + this.name;
|
155
|
+
},
|
156
|
+
|
157
|
+
divID: function() {
|
158
|
+
return this.name + '-' + this.type + '-widget';
|
159
|
+
},
|
160
|
+
|
161
|
+
setDataDivTo: function(element) {
|
162
|
+
this.dataDiv = element;
|
163
|
+
}
|
164
|
+
});
|
165
|
+
// End DashboardWidget class. }}}
|
166
|
+
|
167
|
+
// Begin NumberWidget class. {{{
|
168
|
+
var NumberWidget = new JS.Class(DashboardWidget, {
|
169
|
+
initialize: function(options) {
|
170
|
+
options['type'] = 'number';
|
171
|
+
this.callSuper(options);
|
172
|
+
},
|
173
|
+
|
174
|
+
updateData: function() {
|
175
|
+
if (!this.dataDiv)
|
176
|
+
{return false;}
|
177
|
+
|
178
|
+
// This is needed so that the dataDiv property is accessible with jQuery.get() .
|
179
|
+
var element = this.dataDiv;
|
180
|
+
|
181
|
+
jQuery.get(this.dataURL(), function(data) {
|
182
|
+
element.fadeOut(400, function() {
|
183
|
+
element.html(data);
|
184
|
+
element.fadeIn();
|
185
|
+
});
|
186
|
+
}, 'text');
|
187
|
+
}
|
188
|
+
});
|
189
|
+
// End NumberWidget class. }}}
|
190
|
+
|
191
|
+
// Begin ShortMessagesWidget class. {{{
|
192
|
+
var ShortMessagesWidget = new JS.Class(DashboardWidget, {
|
193
|
+
initialize: function(options) {
|
194
|
+
options['type'] = 'short_messages';
|
195
|
+
this.callSuper(options);
|
196
|
+
this.maxDataItems = 5;
|
197
|
+
},
|
198
|
+
|
199
|
+
firstDataItem: function() {
|
200
|
+
return this.dataDiv.find('li.widget-data-item:first');
|
201
|
+
},
|
202
|
+
|
203
|
+
dataItemsCount: function() {
|
204
|
+
return this.dataDiv.find('li.widget-data-item').length;
|
205
|
+
},
|
206
|
+
|
207
|
+
createDataItem: function() {
|
208
|
+
return this.dataDiv.find('li.widget-data-template')
|
209
|
+
.clone(false)
|
210
|
+
.removeClass('widget-data-template')
|
211
|
+
.addClass('widget-data-item');
|
212
|
+
},
|
213
|
+
|
214
|
+
updateData: function() {
|
215
|
+
if (!this.dataDiv)
|
216
|
+
{return false;}
|
217
|
+
|
218
|
+
var new_data = '';
|
219
|
+
var new_li = this.createDataItem();
|
220
|
+
|
221
|
+
// We use ajax() instead of get() because the "async" option must
|
222
|
+
// be false. If it isn't, we're unable to determine if data was
|
223
|
+
// obtained.
|
224
|
+
var get_result = jQuery.ajax({
|
225
|
+
url: this.dataURL(),
|
226
|
+
type: 'GET',
|
227
|
+
async: false,
|
228
|
+
cache: false,
|
229
|
+
dataType: 'text',
|
230
|
+
timeout: this.updateInterval,
|
231
|
+
success: function(data) {
|
232
|
+
new_li.html(data);
|
233
|
+
new_data = data;
|
234
|
+
}
|
235
|
+
});
|
236
|
+
|
237
|
+
// If no data was obtained, return. Otherwise, an empty list item
|
238
|
+
// will be shown.
|
239
|
+
if (new_data == '')
|
240
|
+
{return false;}
|
241
|
+
|
242
|
+
new_li.appendTo(this.dataDiv.find('ul'));
|
243
|
+
|
244
|
+
// Hide the first list item if we've reached the maximum number of
|
245
|
+
// list items to show in this widget.
|
246
|
+
if (this.dataItemsCount() > this.maxDataItems) {
|
247
|
+
var firstDataItem = this.firstDataItem();
|
248
|
+
|
249
|
+
firstDataItem.slideUp(400, function() {
|
250
|
+
firstDataItem.remove();
|
251
|
+
});
|
252
|
+
}
|
253
|
+
|
254
|
+
new_li.slideDown();
|
255
|
+
}
|
256
|
+
});
|
257
|
+
// End ShortMessagesWidget class. }}}
|
258
|
+
|
259
|
+
// Begin LineGraphWidget class. {{{
|
260
|
+
var LineGraphWidget = new JS.Class(DashboardWidget, {
|
261
|
+
initialize: function(options) {
|
262
|
+
this.height = options.height;
|
263
|
+
this.width = options.width;
|
264
|
+
this.seriesColours = options.line_colours;
|
265
|
+
this.x_axis = options.x_axis;
|
266
|
+
|
267
|
+
options.type = 'line_graph';
|
268
|
+
this.callSuper(options);
|
269
|
+
},
|
270
|
+
|
271
|
+
updateData: function() {
|
272
|
+
if (!this.graph)
|
273
|
+
{this.createGraph();}
|
274
|
+
|
275
|
+
// This is needed so that the dataDiv property is accessible with jQuery.get() .
|
276
|
+
var graph = this.graph;
|
277
|
+
|
278
|
+
jQuery.get(this.dataURL(), function(data) {
|
279
|
+
graph.series[0].data = data;
|
280
|
+
graph.replot({resetAxes: true});
|
281
|
+
}, 'json');
|
282
|
+
},
|
283
|
+
|
284
|
+
createGraph: function() {
|
285
|
+
includeJavaScriptFile('/javascripts/jqplot-0.9.7/plugins/jqplot.dateAxisRenderer.min.js');
|
286
|
+
|
287
|
+
var x_axis_format = {};
|
288
|
+
if (this.x_axis === 'dates') {
|
289
|
+
var x_axis_format = {
|
290
|
+
renderer: jQuery.jqplot.DateAxisRenderer,
|
291
|
+
tickOptions: {formatString: '%Y-%m-%d'}
|
292
|
+
}
|
293
|
+
}
|
294
|
+
|
295
|
+
this.graph = jQuery.jqplot(this.dataDiv.attr('id'), [ [] ], {
|
296
|
+
seriesColors: this.seriesColours,
|
297
|
+
axes: {
|
298
|
+
xaxis: x_axis_format
|
299
|
+
}
|
300
|
+
});
|
301
|
+
}
|
302
|
+
});
|
303
|
+
// End LineGraphWidget class. }}}
|
304
|
+
|
@@ -1,86 +1,86 @@
|
|
1
|
-
body {
|
2
|
-
background-color: black;
|
3
|
-
color: white;
|
4
|
-
}
|
5
|
-
|
6
|
-
.dashboard-clear {
|
7
|
-
clear: both;
|
8
|
-
}
|
9
|
-
|
10
|
-
#dashboard {
|
11
|
-
width: 100%;
|
12
|
-
}
|
13
|
-
#dashboard .widget {
|
14
|
-
}
|
15
|
-
|
16
|
-
#dashboard .dashboard-numbers {
|
17
|
-
}
|
18
|
-
#dashboard .dashboard-numbers .number-widget {
|
19
|
-
float: left;
|
20
|
-
margin: 1em;
|
21
|
-
text-align: center;
|
22
|
-
}
|
23
|
-
#dashboard .dashboard-numbers .number-widget .widget-title {
|
24
|
-
padding: 0.25em;
|
25
|
-
border-top: 1px solid #666666;
|
26
|
-
border-bottom: none;
|
27
|
-
border-left: 1px solid #666666;
|
28
|
-
border-right: 1px solid #666666;
|
29
|
-
}
|
30
|
-
#dashboard .dashboard-numbers .number-widget .widget-data {
|
31
|
-
font-size: 4em;
|
32
|
-
border-top: none;
|
33
|
-
border-bottom: 1px solid #666666;
|
34
|
-
border-left: 1px solid #666666;
|
35
|
-
border-right: 1px solid #666666;
|
36
|
-
}
|
37
|
-
|
38
|
-
/* dashboard-short-message is not complete */
|
39
|
-
#dashboard .dashboard-short-messages {
|
40
|
-
}
|
41
|
-
#dashboard .dashboard-short-messages .short-messages-widget {
|
42
|
-
float: left;
|
43
|
-
margin: 1em;
|
44
|
-
}
|
45
|
-
#dashboard .dashboard-short-messages .short-messages-widget .widget-title {
|
46
|
-
padding: 0.5em;
|
47
|
-
text-align: center;
|
48
|
-
font-weight: bold;
|
49
|
-
}
|
50
|
-
#dashboard .dashboard-short-messages .short-messages-widget .widget-data {
|
51
|
-
margin: 0;
|
52
|
-
padding: 0;
|
53
|
-
}
|
54
|
-
#dashboard .dashboard-short-messages .short-messages-widget .widget-data ul {
|
55
|
-
margin: 0;
|
56
|
-
padding: 0;
|
57
|
-
}
|
58
|
-
#dashboard .dashboard-short-messages .short-messages-widget .widget-data li {
|
59
|
-
margin-top: 4px;
|
60
|
-
padding: 0.25em;
|
61
|
-
list-style-type: none;
|
62
|
-
font-size: 0.8em;
|
63
|
-
}
|
64
|
-
|
65
|
-
#dashboard .dashboard-line-graphs {
|
66
|
-
}
|
67
|
-
#dashboard .dashboard-line-graphs .line-graph-widget {
|
68
|
-
float: left;
|
69
|
-
margin: 1em;
|
70
|
-
}
|
71
|
-
#dashboard .dashboard-line-graphs .line-graph-widget .widget-title {
|
72
|
-
text-align: center;
|
73
|
-
border-top: 1px solid #666666;
|
74
|
-
border-bottom: none;
|
75
|
-
border-left: 1px solid #666666;
|
76
|
-
border-right: 1px solid #666666;
|
77
|
-
}
|
78
|
-
#dashboard .dashboard-line-graphs .line-graph-widget .widget-data {
|
79
|
-
xborder: none;
|
80
|
-
border-top: none;
|
81
|
-
border-bottom: 1px solid #666666;
|
82
|
-
border-left: 1px solid #666666;
|
83
|
-
border-right: 1px solid #666666;
|
84
|
-
padding-right: 1.5em;
|
85
|
-
}
|
86
|
-
|
1
|
+
body {
|
2
|
+
background-color: black;
|
3
|
+
color: white;
|
4
|
+
}
|
5
|
+
|
6
|
+
.dashboard-clear {
|
7
|
+
clear: both;
|
8
|
+
}
|
9
|
+
|
10
|
+
#dashboard {
|
11
|
+
width: 100%;
|
12
|
+
}
|
13
|
+
#dashboard .widget {
|
14
|
+
}
|
15
|
+
|
16
|
+
#dashboard .dashboard-numbers {
|
17
|
+
}
|
18
|
+
#dashboard .dashboard-numbers .number-widget {
|
19
|
+
float: left;
|
20
|
+
margin: 1em;
|
21
|
+
text-align: center;
|
22
|
+
}
|
23
|
+
#dashboard .dashboard-numbers .number-widget .widget-title {
|
24
|
+
padding: 0.25em;
|
25
|
+
border-top: 1px solid #666666;
|
26
|
+
border-bottom: none;
|
27
|
+
border-left: 1px solid #666666;
|
28
|
+
border-right: 1px solid #666666;
|
29
|
+
}
|
30
|
+
#dashboard .dashboard-numbers .number-widget .widget-data {
|
31
|
+
font-size: 4em;
|
32
|
+
border-top: none;
|
33
|
+
border-bottom: 1px solid #666666;
|
34
|
+
border-left: 1px solid #666666;
|
35
|
+
border-right: 1px solid #666666;
|
36
|
+
}
|
37
|
+
|
38
|
+
/* dashboard-short-message is not complete */
|
39
|
+
#dashboard .dashboard-short-messages {
|
40
|
+
}
|
41
|
+
#dashboard .dashboard-short-messages .short-messages-widget {
|
42
|
+
float: left;
|
43
|
+
margin: 1em;
|
44
|
+
}
|
45
|
+
#dashboard .dashboard-short-messages .short-messages-widget .widget-title {
|
46
|
+
padding: 0.5em;
|
47
|
+
text-align: center;
|
48
|
+
font-weight: bold;
|
49
|
+
}
|
50
|
+
#dashboard .dashboard-short-messages .short-messages-widget .widget-data {
|
51
|
+
margin: 0;
|
52
|
+
padding: 0;
|
53
|
+
}
|
54
|
+
#dashboard .dashboard-short-messages .short-messages-widget .widget-data ul {
|
55
|
+
margin: 0;
|
56
|
+
padding: 0;
|
57
|
+
}
|
58
|
+
#dashboard .dashboard-short-messages .short-messages-widget .widget-data li {
|
59
|
+
margin-top: 4px;
|
60
|
+
padding: 0.25em;
|
61
|
+
list-style-type: none;
|
62
|
+
font-size: 0.8em;
|
63
|
+
}
|
64
|
+
|
65
|
+
#dashboard .dashboard-line-graphs {
|
66
|
+
}
|
67
|
+
#dashboard .dashboard-line-graphs .line-graph-widget {
|
68
|
+
float: left;
|
69
|
+
margin: 1em;
|
70
|
+
}
|
71
|
+
#dashboard .dashboard-line-graphs .line-graph-widget .widget-title {
|
72
|
+
text-align: center;
|
73
|
+
border-top: 1px solid #666666;
|
74
|
+
border-bottom: none;
|
75
|
+
border-left: 1px solid #666666;
|
76
|
+
border-right: 1px solid #666666;
|
77
|
+
}
|
78
|
+
#dashboard .dashboard-line-graphs .line-graph-widget .widget-data {
|
79
|
+
xborder: none;
|
80
|
+
border-top: none;
|
81
|
+
border-bottom: 1px solid #666666;
|
82
|
+
border-left: 1px solid #666666;
|
83
|
+
border-right: 1px solid #666666;
|
84
|
+
padding-right: 1.5em;
|
85
|
+
}
|
86
|
+
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acts_as_dashboard
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
4
5
|
prerelease: false
|
5
6
|
segments:
|
6
7
|
- 0
|
7
8
|
- 3
|
8
|
-
-
|
9
|
-
version: 0.3.
|
9
|
+
- 2
|
10
|
+
version: 0.3.2
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Nick Hoffman
|
@@ -14,16 +15,18 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date: 2010-08-
|
18
|
+
date: 2010-08-04 00:00:00 -04:00
|
18
19
|
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
21
22
|
name: rspec
|
22
23
|
prerelease: false
|
23
24
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
24
26
|
requirements:
|
25
27
|
- - ">="
|
26
28
|
- !ruby/object:Gem::Version
|
29
|
+
hash: 13
|
27
30
|
segments:
|
28
31
|
- 1
|
29
32
|
- 2
|
@@ -35,9 +38,11 @@ dependencies:
|
|
35
38
|
name: rspec-rails
|
36
39
|
prerelease: false
|
37
40
|
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
38
42
|
requirements:
|
39
43
|
- - ">="
|
40
44
|
- !ruby/object:Gem::Version
|
45
|
+
hash: 31
|
41
46
|
segments:
|
42
47
|
- 1
|
43
48
|
- 3
|
@@ -181,9 +186,6 @@ files:
|
|
181
186
|
- spec/shared/widget_behaviours.rb
|
182
187
|
- spec/spec.opts
|
183
188
|
- spec/spec_helper.rb
|
184
|
-
- tasks/install.rake
|
185
|
-
- tasks/install_javascript.rake
|
186
|
-
- tasks/install_stylesheets.rake
|
187
189
|
has_rdoc: true
|
188
190
|
homepage: http://github.com/nickhoffman/acts_as_dashboard
|
189
191
|
licenses: []
|
@@ -194,23 +196,27 @@ rdoc_options:
|
|
194
196
|
require_paths:
|
195
197
|
- lib
|
196
198
|
required_ruby_version: !ruby/object:Gem::Requirement
|
199
|
+
none: false
|
197
200
|
requirements:
|
198
201
|
- - ">="
|
199
202
|
- !ruby/object:Gem::Version
|
203
|
+
hash: 3
|
200
204
|
segments:
|
201
205
|
- 0
|
202
206
|
version: "0"
|
203
207
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
208
|
+
none: false
|
204
209
|
requirements:
|
205
210
|
- - ">="
|
206
211
|
- !ruby/object:Gem::Version
|
212
|
+
hash: 3
|
207
213
|
segments:
|
208
214
|
- 0
|
209
215
|
version: "0"
|
210
216
|
requirements: []
|
211
217
|
|
212
218
|
rubyforge_project:
|
213
|
-
rubygems_version: 1.3.
|
219
|
+
rubygems_version: 1.3.7
|
214
220
|
signing_key:
|
215
221
|
specification_version: 3
|
216
222
|
summary: Create dashboards in Rails apps easily.
|
data/tasks/install.rake
DELETED