google_data_source 0.7.6
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +7 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +25 -0
- data/Rakefile +31 -0
- data/google_data_source.gemspec +32 -0
- data/lib/assets/images/google_data_source/chart_bar_add.png +0 -0
- data/lib/assets/images/google_data_source/chart_bar_delete.png +0 -0
- data/lib/assets/images/google_data_source/loader.gif +0 -0
- data/lib/assets/javascripts/google_data_source/data_source_init.js +3 -0
- data/lib/assets/javascripts/google_data_source/extended_data_table.js +76 -0
- data/lib/assets/javascripts/google_data_source/filter_form.js +180 -0
- data/lib/assets/javascripts/google_data_source/google_visualization/combo_table.js.erb +113 -0
- data/lib/assets/javascripts/google_data_source/google_visualization/table.js +116 -0
- data/lib/assets/javascripts/google_data_source/google_visualization/timeline.js +13 -0
- data/lib/assets/javascripts/google_data_source/google_visualization/visualization.js.erb +141 -0
- data/lib/assets/javascripts/google_data_source/index.js +7 -0
- data/lib/dummy_engine.rb +5 -0
- data/lib/google_data_source.rb +33 -0
- data/lib/google_data_source/base.rb +281 -0
- data/lib/google_data_source/column.rb +31 -0
- data/lib/google_data_source/csv_data.rb +23 -0
- data/lib/google_data_source/data_date.rb +17 -0
- data/lib/google_data_source/data_date_time.rb +17 -0
- data/lib/google_data_source/helper.rb +69 -0
- data/lib/google_data_source/html_data.rb +6 -0
- data/lib/google_data_source/invalid_data.rb +14 -0
- data/lib/google_data_source/json_data.rb +78 -0
- data/lib/google_data_source/railtie.rb +36 -0
- data/lib/google_data_source/sql/models.rb +266 -0
- data/lib/google_data_source/sql/parser.rb +239 -0
- data/lib/google_data_source/sql_parser.rb +82 -0
- data/lib/google_data_source/template_handler.rb +31 -0
- data/lib/google_data_source/test_helper.rb +26 -0
- data/lib/google_data_source/version.rb +3 -0
- data/lib/google_data_source/xml_data.rb +25 -0
- data/lib/locale/de.yml +5 -0
- data/lib/reporting/action_controller_extension.rb +19 -0
- data/lib/reporting/grouped_set.rb +58 -0
- data/lib/reporting/helper.rb +110 -0
- data/lib/reporting/reporting.rb +352 -0
- data/lib/reporting/reporting_adapter.rb +27 -0
- data/lib/reporting/reporting_entry.rb +147 -0
- data/lib/reporting/sql_reporting.rb +220 -0
- data/test/lib/empty_reporting.rb +2 -0
- data/test/lib/test_reporting.rb +33 -0
- data/test/lib/test_reporting_b.rb +9 -0
- data/test/lib/test_reporting_c.rb +3 -0
- data/test/locales/en.models.yml +6 -0
- data/test/locales/en.reportings.yml +5 -0
- data/test/rails/reporting_renderer_test.rb +47 -0
- data/test/test_helper.rb +50 -0
- data/test/units/base_test.rb +340 -0
- data/test/units/csv_data_test.rb +36 -0
- data/test/units/grouped_set_test.rb +60 -0
- data/test/units/json_data_test.rb +68 -0
- data/test/units/reporting_adapter_test.rb +20 -0
- data/test/units/reporting_entry_test.rb +149 -0
- data/test/units/reporting_test.rb +374 -0
- data/test/units/sql_parser_test.rb +111 -0
- data/test/units/sql_reporting_test.rb +307 -0
- data/test/units/xml_data_test.rb +32 -0
- metadata +286 -0
data/.document
ADDED
data/.gitignore
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
gemspec
|
3
|
+
|
4
|
+
gem "rparsec", :git => 'https://github.com/adyard/rparsec.git'
|
5
|
+
|
6
|
+
# Add dependencies to develop your gem here.
|
7
|
+
# Include everything needed to run rake, tests, features, etc.
|
8
|
+
group :development do
|
9
|
+
gem 'ci_reporter'
|
10
|
+
gem 'geminabox'
|
11
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Claas Abert, Tobias Schlottke
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
= google_data_source
|
2
|
+
|
3
|
+
The google data source plugin consists of two parts:
|
4
|
+
* The Reporting engine is a flexible model toolkit to generate rich queries over multiple tables. It is able to transparently aggregate data from multiple tables, regroup it and prepare it for displaying
|
5
|
+
* The Datasource engine is the representation layer. It renders the data using the google datasource standard (http://code.google.com/intl/de-DE/apis/charttools/index.html). This makes visualizing the data quite easy.
|
6
|
+
|
7
|
+
== TODO
|
8
|
+
* Separate Reporting & Datasource logic into two independent plugins
|
9
|
+
* Add Javascripts and howtos
|
10
|
+
|
11
|
+
== Contributing to google_data_source
|
12
|
+
|
13
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
14
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
15
|
+
* Fork the project
|
16
|
+
* Start a feature/bugfix branch
|
17
|
+
* Commit and push until you are happy with your contribution
|
18
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
19
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
20
|
+
|
21
|
+
== Copyright
|
22
|
+
|
23
|
+
Copyright (c) 2011 Tobias Schlottke. See LICENSE.txt for
|
24
|
+
further details.
|
25
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
require 'rake'
|
4
|
+
|
5
|
+
require 'rake/testtask'
|
6
|
+
task :test => ['test:environment', 'test:units', 'test:rails']
|
7
|
+
namespace :test do
|
8
|
+
|
9
|
+
task :environment do
|
10
|
+
ENV['RACK_ENV'] = 'test'
|
11
|
+
end
|
12
|
+
|
13
|
+
[ :units, :rails ].each do |category|
|
14
|
+
Rake::TestTask.new(category) do |t|
|
15
|
+
t.libs << "lib" << "test"
|
16
|
+
t.test_files = Dir["test/#{category}/**/*_test.rb"]
|
17
|
+
t.verbose = true
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
task :default => :test
|
24
|
+
|
25
|
+
require 'rake/rdoctask'
|
26
|
+
Rake::RDocTask.new do |rdoc|
|
27
|
+
rdoc.rdoc_dir = 'rdoc'
|
28
|
+
rdoc.title = "google_data_source #{GoogleDataSource::VERSION}"
|
29
|
+
rdoc.rdoc_files.include('README*')
|
30
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
31
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/google_data_source/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = %q{google_data_source}
|
6
|
+
s.version = GoogleDataSource::VERSION
|
7
|
+
|
8
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
9
|
+
s.authors = [%q{Claas Abert}, %q{Tobias Schlottke}]
|
10
|
+
s.summary = %q{A highly sophisticated reporting framework}
|
11
|
+
s.description = %q{A highly sophisticated reporting framework}
|
12
|
+
s.email = %q{tobias.schlottke@metrigo.de}
|
13
|
+
|
14
|
+
s.files = `git ls-files`.split("\n")
|
15
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
|
19
|
+
s.add_runtime_dependency(%q<activesupport>, ["~> 3.1.4"])
|
20
|
+
s.add_runtime_dependency(%q<activerecord>, ["~> 3.1.4"])
|
21
|
+
s.add_runtime_dependency(%q<actionpack>, ["~> 3.1.4"])
|
22
|
+
s.add_runtime_dependency(%q<rails>, ["~> 3.1.4"])
|
23
|
+
s.add_runtime_dependency(%q<nokogiri>, [">= 0"])
|
24
|
+
|
25
|
+
s.add_development_dependency(%q<test-unit>, [">= 0"])
|
26
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
27
|
+
s.add_development_dependency(%q<mocha>, [">= 0.9"])
|
28
|
+
s.add_development_dependency(%q<rparsec>, [">= 1.0.1"])
|
29
|
+
s.add_development_dependency(%q<sqlite3>, [">= 0"])
|
30
|
+
|
31
|
+
end
|
32
|
+
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,76 @@
|
|
1
|
+
/**
|
2
|
+
* DataTable subclass with extended features
|
3
|
+
* * Handling of a sum row
|
4
|
+
* * Case insensitive sorting
|
5
|
+
*/
|
6
|
+
function ExtendedDataTable(data, options) {
|
7
|
+
if (typeof data.toJSON == 'function') data = data.toJSON();
|
8
|
+
this.options = options || {};
|
9
|
+
google.visualization.DataTable.call(this, data, this.options['version']);
|
10
|
+
if (this.getNumberOfRows() < 1) return;
|
11
|
+
if (this.options['sumRow']) this._setSumRowStyle();
|
12
|
+
}
|
13
|
+
|
14
|
+
google.load('visualization', '1', {'callback' : function() {
|
15
|
+
ExtendedDataTable.prototype = new google.visualization.DataTable();
|
16
|
+
ExtendedDataTable.prototype._getSumRowIndex = function() {
|
17
|
+
return this.getNumberOfRows() - 1;
|
18
|
+
};
|
19
|
+
|
20
|
+
ExtendedDataTable.prototype._setSumRowStyle = function() {
|
21
|
+
for (var i=0; i<this.getNumberOfColumns(); i++) {
|
22
|
+
this.setProperty(this._getSumRowIndex(), i, 'style', 'font-weight: bold; background: #ccc;');
|
23
|
+
}
|
24
|
+
};
|
25
|
+
|
26
|
+
ExtendedDataTable.prototype.setOption = function(name, value) {
|
27
|
+
this.options[name] = value;
|
28
|
+
};
|
29
|
+
|
30
|
+
// Override the getSortedRows method to keep the sum row in place while sorting
|
31
|
+
// This also affects the sort method
|
32
|
+
ExtendedDataTable.prototype.getSortedRows = function(sortColumns) {
|
33
|
+
var sorted = [];
|
34
|
+
// use standard sorting if caseSensitive option is set
|
35
|
+
if (this.options['caseSensitive']) {
|
36
|
+
sorted = google.visualization.DataTable.prototype.getSortedRows.call(this, sortColumns);
|
37
|
+
// use custom sort method if caseSensitive option is not set
|
38
|
+
} else {
|
39
|
+
if (sortColumns instanceof Array) sortColumns = sortColumns[0];
|
40
|
+
if (typeof sortColumns == 'number') sortColumns = {'column': sortColumns, 'desc': false};
|
41
|
+
var column = sortColumns['column'];
|
42
|
+
var desc = sortColumns['desc'];
|
43
|
+
|
44
|
+
var toSort = [];
|
45
|
+
for (var i=0; i<this.getNumberOfRows(); i++) {
|
46
|
+
toSort.push([i, this.getValue(i, column)]);
|
47
|
+
}
|
48
|
+
toSort.sort(function(a, b) {
|
49
|
+
//TODO use better check for String value
|
50
|
+
var aa = (a[1] && a[1].toLowerCase) ? a[1].toLowerCase() : a[1];
|
51
|
+
var bb = (b[1] && b[1].toLowerCase) ? b[1].toLowerCase() : b[1];
|
52
|
+
var result = (aa < bb) ? 1 : -1;
|
53
|
+
return desc ? result : -result;
|
54
|
+
});
|
55
|
+
for (var i=0; i<toSort.length; i++) {
|
56
|
+
sorted.push(toSort[i][0]);
|
57
|
+
}
|
58
|
+
}
|
59
|
+
|
60
|
+
if (!this.options['sumRow']) return sorted;
|
61
|
+
|
62
|
+
// pull sum row out of the sorted bunch and put it at the end
|
63
|
+
var result = [];
|
64
|
+
var sumRowIndex = this._getSumRowIndex();
|
65
|
+
for (var i=0; i<sorted.length; i++) {
|
66
|
+
if (sorted[i] != sumRowIndex) result.push(sorted[i]);
|
67
|
+
}
|
68
|
+
result.push(sumRowIndex);
|
69
|
+
return result;
|
70
|
+
};
|
71
|
+
}});
|
72
|
+
|
73
|
+
|
74
|
+
|
75
|
+
|
76
|
+
|
@@ -0,0 +1,180 @@
|
|
1
|
+
/*
|
2
|
+
* Helper Methods for the form serialization to the Google query language.
|
3
|
+
* Each field becomes a condition, the conditions are connected with 'and'.
|
4
|
+
* Fields whose names start on 'from_' or 'to_' are translated to '<' and '>' comparisons.
|
5
|
+
* Multiparameter field (date) are put in a single parameter.
|
6
|
+
*/
|
7
|
+
DataSource.FilterForm = function(form) {
|
8
|
+
this._form = $(form);
|
9
|
+
var id = this._form[0].id;
|
10
|
+
// load hooks
|
11
|
+
this._hooks = DataSource.FilterForm._hooks[id] || {};
|
12
|
+
}
|
13
|
+
|
14
|
+
DataSource.FilterForm._hooks = {};
|
15
|
+
DataSource.FilterForm.setHooks = function(id, hooks) {
|
16
|
+
DataSource.FilterForm._hooks[id] = hooks;
|
17
|
+
};
|
18
|
+
|
19
|
+
DataSource.FilterForm.prototype = {
|
20
|
+
getNoQueryValues: function(form) {
|
21
|
+
var result = [];
|
22
|
+
var formdata = this._form.serializeArray();
|
23
|
+
$.each(this._form.find('input.noquery'), function(i, input) {
|
24
|
+
$.each(formdata, function(i, pair) {
|
25
|
+
if (pair.name == input.name && ! $(input).hasClass('ignore')) {
|
26
|
+
result.push(pair);
|
27
|
+
}
|
28
|
+
});
|
29
|
+
});
|
30
|
+
return jQuery.param(result);
|
31
|
+
},
|
32
|
+
|
33
|
+
getValues: function() {
|
34
|
+
var formdata = this._form.serializeArray();
|
35
|
+
$.each(this._form.find('input.noquery'), function(i, input) {
|
36
|
+
var tmp = [];
|
37
|
+
$.each(formdata, function(i, pair) {
|
38
|
+
if (pair.name != input.name) {
|
39
|
+
tmp.push(pair);
|
40
|
+
}
|
41
|
+
});
|
42
|
+
formdata = tmp;
|
43
|
+
});
|
44
|
+
|
45
|
+
var values = {};
|
46
|
+
$.each(formdata, function(i, pair) {
|
47
|
+
// use only the key if field is named model[key]
|
48
|
+
var match = pair.name.match(/\[([^\[\]]+)\](\[\])?$/);
|
49
|
+
if (match) pair.name = match[1] + (match[2] || '');
|
50
|
+
|
51
|
+
// multiparameter
|
52
|
+
var match;
|
53
|
+
if (match = pair.name.match(/^(.*)\(([0-9]+)i\)$/)) {
|
54
|
+
var name = match[1];
|
55
|
+
var part = match[2];
|
56
|
+
if (typeof values[name] == "undefined") values[name] = {'multiparameter': true};
|
57
|
+
values[name][part] = pair.value;
|
58
|
+
}
|
59
|
+
// multiselect
|
60
|
+
else if(match = pair.name.match(/^(.*)\[\]$/)) {
|
61
|
+
var name = match[1];
|
62
|
+
if (typeof values[name] == "undefined") {
|
63
|
+
values[name] = [];
|
64
|
+
values[name].multiselect = true;
|
65
|
+
}
|
66
|
+
values[name].push(pair.value);
|
67
|
+
}
|
68
|
+
// no multiparam field
|
69
|
+
else {
|
70
|
+
values[pair.name] = pair.value;
|
71
|
+
}
|
72
|
+
});
|
73
|
+
|
74
|
+
var result = {};
|
75
|
+
$.each(values, function(key, value) {
|
76
|
+
// convert multiparams field from hash to array
|
77
|
+
if (value.multiparameter) {
|
78
|
+
var i = 1;
|
79
|
+
var subvalues = [];
|
80
|
+
while (typeof value['' + i] != 'undefined') {
|
81
|
+
subvalues.push(value[''+i]);
|
82
|
+
i++;
|
83
|
+
}
|
84
|
+
result[key] = subvalues;
|
85
|
+
result[key].multiparameter = true;
|
86
|
+
}
|
87
|
+
// store non multiparam fields
|
88
|
+
else {
|
89
|
+
result[key] = value;
|
90
|
+
}
|
91
|
+
});
|
92
|
+
return result;
|
93
|
+
},
|
94
|
+
|
95
|
+
toWhereClause: function() {
|
96
|
+
var conditions = [];
|
97
|
+
// putting together the query
|
98
|
+
var values = this.getValues();
|
99
|
+
delete values.groupby;
|
100
|
+
delete values.select;
|
101
|
+
$.each(values, function(key, value) {
|
102
|
+
// handle dates
|
103
|
+
if (value.multiparameter) {
|
104
|
+
if (value[0] && value[1] && value[2]) {
|
105
|
+
value = value.join('-');
|
106
|
+
}
|
107
|
+
else {
|
108
|
+
// TODO continue?
|
109
|
+
value = '';
|
110
|
+
}
|
111
|
+
}
|
112
|
+
|
113
|
+
// default operator
|
114
|
+
var operator = '='
|
115
|
+
|
116
|
+
|
117
|
+
if (value.multiselect) {
|
118
|
+
value = value.join(',');
|
119
|
+
}
|
120
|
+
|
121
|
+
// greater operator
|
122
|
+
var match = key.match(/^from_(.*)$/)
|
123
|
+
if (match) {key = match[1];operator = '>=';}
|
124
|
+
|
125
|
+
// less operator
|
126
|
+
var match = key.match(/^to_(.*)$/)
|
127
|
+
if (match) {key = match[1];operator = '<=';}
|
128
|
+
|
129
|
+
// in operator
|
130
|
+
var match = key.match(/^in_(.*)$/)
|
131
|
+
if (match) {key = match[1];operator = 'in';}
|
132
|
+
|
133
|
+
if (value == '') {
|
134
|
+
// skip empty values
|
135
|
+
return;
|
136
|
+
}
|
137
|
+
|
138
|
+
if (operator == 'in') {
|
139
|
+
var values = value.match(/([^\s;,]+)/g);
|
140
|
+
for (var i=0; i<values.length; i++) {
|
141
|
+
values[i] = '\'' + values[i].replace('\\', '\\\\').replace('\'','\\\'') + '\'';
|
142
|
+
}
|
143
|
+
conditions.push('`' + key + '` in (' + values.join(',') + ')');
|
144
|
+
} else {
|
145
|
+
conditions.push('`' + key + '`' + operator + '\'' + value.replace('\\', '\\\\').replace('\'','\\\'') + '\'');
|
146
|
+
}
|
147
|
+
});
|
148
|
+
return (conditions.length > 0) ? 'where ' + conditions.join(' and ') : '';
|
149
|
+
},
|
150
|
+
|
151
|
+
getGroupByColumns: function() {
|
152
|
+
var result = this.getValues().groupby || [];
|
153
|
+
if (!$.isArray(result)) result = [result];
|
154
|
+
return result;
|
155
|
+
},
|
156
|
+
|
157
|
+
toGroupByClause: function() {
|
158
|
+
var hook = this._hooks.groupby || this.getGroupByColumns;
|
159
|
+
var escaped = [];
|
160
|
+
$.each(hook.call(this), function(i, column) {
|
161
|
+
if (column != '') escaped.push('`' + column + '`');
|
162
|
+
});
|
163
|
+
return (escaped.length > 0) ? 'group by ' + escaped.join(', ') : '';
|
164
|
+
},
|
165
|
+
|
166
|
+
getSelectColumns: function() {
|
167
|
+
var result = this.getValues().select || [];
|
168
|
+
if (!$.isArray(result)) result = [result];
|
169
|
+
return result;
|
170
|
+
},
|
171
|
+
|
172
|
+
toSelectClause: function() {
|
173
|
+
var hook = this._hooks.select || this.getSelectColumns;
|
174
|
+
var escaped = [];
|
175
|
+
$.each(hook.call(this), function(i, column) {
|
176
|
+
if (column != '') escaped.push('`' + column + '`');
|
177
|
+
});
|
178
|
+
return (escaped.length > 0) ? 'select ' + escaped.join(', ') : '';
|
179
|
+
}
|
180
|
+
}
|
@@ -0,0 +1,113 @@
|
|
1
|
+
DataSource.ComboTable = function(query, container, options) {
|
2
|
+
DataSource.Table.call(this, query, container, options);
|
3
|
+
this.activeGraphed = [ 0 ];
|
4
|
+
}
|
5
|
+
|
6
|
+
|
7
|
+
DataSource.ComboTable.prototype = new DataSource.Table();
|
8
|
+
|
9
|
+
DataSource.ComboTable.prototype.edit = function(){
|
10
|
+
if (typeof this.chartWrapper == 'undefined') {
|
11
|
+
return;
|
12
|
+
}
|
13
|
+
// Handler for the "Open Editor" button.
|
14
|
+
var editor = new google.visualization.ChartEditor();
|
15
|
+
self = this;
|
16
|
+
google.visualization.events.addListener(editor, 'ok', function() {
|
17
|
+
editor.getChartWrapper().draw(self.graphContainer);
|
18
|
+
|
19
|
+
self.drawEditButton();
|
20
|
+
});
|
21
|
+
editor.openDialog(this.chartWrapper);
|
22
|
+
}
|
23
|
+
|
24
|
+
DataSource.ComboTable.prototype.drawEditButton = function(){
|
25
|
+
var edit = document.createElement('a');
|
26
|
+
jQuery(edit).addClass('graphEditButton');
|
27
|
+
jQuery(this.graphContainer).append(edit);
|
28
|
+
var self = this;
|
29
|
+
jQuery(edit).click(function(){
|
30
|
+
self.edit();
|
31
|
+
})
|
32
|
+
}
|
33
|
+
// draw the combotable
|
34
|
+
DataSource.ComboTable.prototype.draw = function() {
|
35
|
+
//draw the table itself
|
36
|
+
this.visualization.draw(this.currentDataTable, this.options);
|
37
|
+
|
38
|
+
|
39
|
+
// add a chart
|
40
|
+
var self = this;
|
41
|
+
|
42
|
+
window.setTimeout(function(){
|
43
|
+
jQuery(self.container).find('.google-visualization-table-th').each(function(){
|
44
|
+
var a = document.createElement('img')
|
45
|
+
jQuery(a).addClass('graphIcon')
|
46
|
+
a.src = '<%= asset_path('google_data_source/chart_bar_add.png') %>'
|
47
|
+
|
48
|
+
a.onclick = function(event){
|
49
|
+
// find out which column is being clicked
|
50
|
+
var clicked = this.parentNode;
|
51
|
+
var i = 0;
|
52
|
+
|
53
|
+
// find all active columns
|
54
|
+
jQuery(self.container).find('.google-visualization-table-th').each(function() {
|
55
|
+
if (this == clicked) {
|
56
|
+
// only add the column if it is not already in
|
57
|
+
var activeIndex = false;
|
58
|
+
for (var col=0; col < self.activeGraphed.length; col++) {
|
59
|
+
if (self.activeGraphed[col] == i) {
|
60
|
+
activeIndex = col;
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
// remove the deleted items, add the active
|
65
|
+
if (!activeIndex) {
|
66
|
+
self.activeGraphed.push(i);
|
67
|
+
} else {
|
68
|
+
self.activeGraphed.splice(activeIndex, activeIndex);
|
69
|
+
}
|
70
|
+
}
|
71
|
+
var active = false;
|
72
|
+
|
73
|
+
i++;
|
74
|
+
});
|
75
|
+
var dataView = new google.visualization.DataView(self.currentDataTable);
|
76
|
+
dataView.setColumns(self.activeGraphed.sort());
|
77
|
+
|
78
|
+
|
79
|
+
// hide the last row as it is the sum row
|
80
|
+
var lastRow = dataView.getViewRows().length - 1;
|
81
|
+
if (lastRow > 0) {
|
82
|
+
dataView.hideRows([ lastRow ]);
|
83
|
+
}
|
84
|
+
|
85
|
+
|
86
|
+
// create a graph container
|
87
|
+
if (typeof self.graphContainer == 'undefined') {
|
88
|
+
self.graphContainer = document.createElement('div');
|
89
|
+
self.container.parentNode.insertBefore(self.graphContainer, self.container);
|
90
|
+
}
|
91
|
+
|
92
|
+
//actually draw the chart
|
93
|
+
var wrapper = new google.visualization.ChartWrapper({
|
94
|
+
chartType: 'LineChart',
|
95
|
+
dataTable: dataView,
|
96
|
+
width: $(self.graphContainer).width(),
|
97
|
+
height: 200
|
98
|
+
});
|
99
|
+
wrapper.draw(self.graphContainer);
|
100
|
+
|
101
|
+
self.chartWrapper = wrapper;
|
102
|
+
}
|
103
|
+
|
104
|
+
this.appendChild(a);
|
105
|
+
})
|
106
|
+
|
107
|
+
for (var col=0; col < self.activeGraphed.length; col++) {
|
108
|
+
jQuery(self.container).find(".google-visualization-table-th:nth("+self.activeGraphed[col]+") img").attr('src', '<%= asset_path('google_data_source/chart_bar_delete.png') %>')
|
109
|
+
}
|
110
|
+
|
111
|
+
self.drawEditButton();
|
112
|
+
}, 100);
|
113
|
+
}
|