refinerycms-stats 0.1
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/app/controllers/admin/stats_controller.rb +5 -0
- data/app/models/stat.rb +7 -0
- data/app/views/admin/stats/index.html.erb +93 -0
- data/config/locales/en.yml +16 -0
- data/config/locales/fr.yml +16 -0
- data/config/routes.rb +11 -0
- data/lib/generators/refinerycms_stats_generator.rb +6 -0
- data/lib/refinerycms-stats.rb +20 -0
- data/lib/tasks/stats.rake +13 -0
- data/public/javascripts/refinerycms-stat-translate.js +33 -0
- data/public/javascripts/refinerycms-stat.js +446 -0
- data/public/stylesheets/stat.css +14 -0
- metadata +65 -0
data/app/models/stat.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
<% content_for :after_javascript_libraries do %>
|
2
|
+
<%= javascript_include_tag 'https://www.google.com/jsapi' %>
|
3
|
+
<%= javascript_include_tag 'refinerycms-stat' %>
|
4
|
+
<%= javascript_include_tag 'refinerycms-stat-translate' %>
|
5
|
+
<% end %>
|
6
|
+
|
7
|
+
<div id="login" style="visibility:hidden;">
|
8
|
+
<form action='#'>
|
9
|
+
<span id='status'><%= t('.login_analytics_html', :analytics_page_code => RefinerySetting.find_or_set(:analytics_page_code, "UA-0000000-0")) %></span>
|
10
|
+
<br/>
|
11
|
+
<input id='buttonLogin' type='button' value='<%= t(".button_login_text") %>'/>
|
12
|
+
</form>
|
13
|
+
</div>
|
14
|
+
<div id="logged" style="visibility:hidden;">
|
15
|
+
<%= t('.link_analytics_html') %>
|
16
|
+
<div id="tabs">
|
17
|
+
<ul>
|
18
|
+
<li><a href="#tabs-1"><%= t('.title_page_views') %></a></li>
|
19
|
+
<li><a href="#tabs-2"><%= t('.title_visits') %></a></li>
|
20
|
+
<li><a href="#tabs-3"><%= t('.title_visitors') %></a></li>
|
21
|
+
<li><a href="#tabs-4"><%= t('.title_average_time') %></a></li>
|
22
|
+
<li><a href="#tabs-5"><%= t('.title_source') %></a></li>
|
23
|
+
<li><a href="#tabs-6"><%= t('.title_keywords') %></a></li>
|
24
|
+
</ul>
|
25
|
+
<div id="page_part_editors">
|
26
|
+
<div id="tabs-1" class="stat">
|
27
|
+
<div id='pageViewsTableDiv'></div>
|
28
|
+
<div id='pageViewsColumnChartDiv' style="display:inline"></div>
|
29
|
+
<div id='pageViewsChartDiv' style="display:inline"></div>
|
30
|
+
</div>
|
31
|
+
<div id="tabs-2" class="stat">
|
32
|
+
<table>
|
33
|
+
<tr>
|
34
|
+
<td><div id='visitsTableDiv' style="display:inline"></div></td>
|
35
|
+
<td><div id='visitsLineChartDiv' style="display:inline"></div></td>
|
36
|
+
</tr>
|
37
|
+
</table>
|
38
|
+
</div>
|
39
|
+
<div id="tabs-3" class="stat">
|
40
|
+
<table>
|
41
|
+
<tr>
|
42
|
+
<td><div id='visitorsTableDiv' style="display:inline"></div></td>
|
43
|
+
<td><div id='visitorsLineChartDiv' style="display:inline"></div></td>
|
44
|
+
</tr>
|
45
|
+
</table>
|
46
|
+
</div>
|
47
|
+
<div id="tabs-4" class="stat">
|
48
|
+
<table>
|
49
|
+
<tr>
|
50
|
+
<td><div id='timesOnSiteTableDiv' style="display:inline"></div></td>
|
51
|
+
<td><div id='timesOnSiteLineChartDiv' style="display:inline"></div></td>
|
52
|
+
</tr>
|
53
|
+
</table>
|
54
|
+
</div>
|
55
|
+
<div id="tabs-5" class="stat">
|
56
|
+
<table>
|
57
|
+
<tr>
|
58
|
+
<td><div id='sourceTableDiv' style="display:inline"></div></td>
|
59
|
+
<td><div id='sourcePieChartDiv' style="display:inline"></div></td>
|
60
|
+
</tr>
|
61
|
+
</table>
|
62
|
+
</div>
|
63
|
+
<div id="tabs-6" class="stat">
|
64
|
+
<table>
|
65
|
+
<tr>
|
66
|
+
<td><div id='keywordTableDiv' style="display:inline"></div></td>
|
67
|
+
<td><div id='keywordPieChartDiv' style="display:inline"></div></td>
|
68
|
+
</tr>
|
69
|
+
</table>
|
70
|
+
</div>
|
71
|
+
</div>
|
72
|
+
<!-- For the API to work in IE, an image must be requested from the same
|
73
|
+
domain the script is hosted on. The image doesn't actually have
|
74
|
+
to exist, just be requested. More info here :
|
75
|
+
http://code.google.com/apis/gdata/client-js.html
|
76
|
+
-->
|
77
|
+
<img style='visibility:hidden' src='__utm.gif' alt='required for GData'/>
|
78
|
+
</div>
|
79
|
+
|
80
|
+
<% content_for :javascripts do %>
|
81
|
+
<script>
|
82
|
+
$(document).ready(function(){
|
83
|
+
$(function() {
|
84
|
+
$( "#tabs" ).tabs();
|
85
|
+
});
|
86
|
+
collectStatsData('<%= RefinerySetting.find_or_set(:analytics_page_code, "UA-0000000-0") %>');
|
87
|
+
});
|
88
|
+
</script>
|
89
|
+
<% end %>
|
90
|
+
|
91
|
+
<% content_for :stylesheets do %>
|
92
|
+
<%= stylesheet_link_tag 'stat' %>
|
93
|
+
<% end %>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
en:
|
2
|
+
plugins:
|
3
|
+
stats:
|
4
|
+
title: Stats
|
5
|
+
admin:
|
6
|
+
stats:
|
7
|
+
index:
|
8
|
+
title_keywords: Keywords
|
9
|
+
title_page_views: Page views
|
10
|
+
title_source: Source
|
11
|
+
title_visitors: Visitors
|
12
|
+
title_visits: Visits
|
13
|
+
title_average_time: Average time
|
14
|
+
link_analytics_html: "You can view more data on the Google Analitycs site : <a href='https://www.google.com/analytics/'>https://www.google.com/analytics/</a><br/>."
|
15
|
+
login_analytics_html: "You need access to your Google Analytics data for this site.<br/>The code of your site for Google Analytics is : %{analytics_page_code}.<br/>You can change this code in <a href='/refinery/settings?search=analytics_page_code'>your settings</a>."
|
16
|
+
button_login_text: "Validate"
|
@@ -0,0 +1,16 @@
|
|
1
|
+
fr:
|
2
|
+
plugins:
|
3
|
+
stats:
|
4
|
+
title: Statistiques
|
5
|
+
admin:
|
6
|
+
stats:
|
7
|
+
index:
|
8
|
+
title_keywords: Mot clés
|
9
|
+
title_page_views: Pages Vues
|
10
|
+
title_source: Sources
|
11
|
+
title_visitors: Visiteurs
|
12
|
+
title_visits: Visites
|
13
|
+
title_average_time: Temps moyen
|
14
|
+
link_analytics_html: "Vous pouvez consulter plus de données sur le site de Google Analitycs : <a href='https://www.google.com/analytics/'>https://www.google.com/analytics/</a><br/>."
|
15
|
+
login_analytics_html: "Vous devez autoriser l'accés à vos données Google Analytics pour ce site.<br/>Le code de votre site pour Google Analytics est : %{analytics_page_code}.<br/>Vous pouvez modifier ce code dans <a href='/refinery/settings?search=analytics_page_code'>vos paramètres</a>."
|
16
|
+
button_login_text: "Valider"
|
data/config/routes.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
::Refinery::Application.routes.draw do
|
2
|
+
resources :stats, :only => [:index, :show]
|
3
|
+
|
4
|
+
scope(:path => 'refinery', :as => 'admin', :module => 'admin') do
|
5
|
+
resources :stats, :except => :show do
|
6
|
+
collection do
|
7
|
+
post :update_positions
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'refinerycms-base'
|
2
|
+
|
3
|
+
module Refinery
|
4
|
+
module Stats
|
5
|
+
class Engine < Rails::Engine
|
6
|
+
initializer "static assets" do |app|
|
7
|
+
app.middleware.insert_after ::ActionDispatch::Static, ::ActionDispatch::Static, "#{root}/public"
|
8
|
+
end
|
9
|
+
|
10
|
+
config.after_initialize do
|
11
|
+
Refinery::Plugin.register do |plugin|
|
12
|
+
plugin.name = "stats"
|
13
|
+
plugin.activity = {
|
14
|
+
:class => Stat
|
15
|
+
}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
var I18n = I18n || {};
|
2
|
+
I18n.translations = {
|
3
|
+
"en":{
|
4
|
+
"admin":{
|
5
|
+
"stats":{
|
6
|
+
"title":"Title",
|
7
|
+
"visits":"Visits",
|
8
|
+
"visitors":"Visitors",
|
9
|
+
"page_views": "Page Views",
|
10
|
+
"keywords": "Keywords",
|
11
|
+
"date": "Date",
|
12
|
+
"average_time": "Average time",
|
13
|
+
"source": "Source",
|
14
|
+
"path": "Path"
|
15
|
+
}
|
16
|
+
}
|
17
|
+
},
|
18
|
+
"fr":{
|
19
|
+
"admin":{
|
20
|
+
"stats":{
|
21
|
+
"title":"Titre",
|
22
|
+
"visits":"Visites",
|
23
|
+
"visitors":"Visiteurs",
|
24
|
+
"page_views": "Pages Vues",
|
25
|
+
"keywords": "Mots clés",
|
26
|
+
"date": "Date",
|
27
|
+
"average_time": "Temps moyen",
|
28
|
+
"source": "Source",
|
29
|
+
"path": "Chemin"
|
30
|
+
}
|
31
|
+
}
|
32
|
+
}
|
33
|
+
};
|
@@ -0,0 +1,446 @@
|
|
1
|
+
// Copyright 2009 Google Inc. All Rights Reserved.
|
2
|
+
|
3
|
+
/* Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
* you may not use this file except in compliance with the License.
|
5
|
+
* You may obtain a copy of the License at
|
6
|
+
*
|
7
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
*
|
9
|
+
* Unless required by applicable law or agreed to in writing, software
|
10
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
* See the License for the specific language governing permissions and
|
13
|
+
* limitations under the License.
|
14
|
+
*/
|
15
|
+
/**
|
16
|
+
* @fileoverview A very simple demo showing how easy it is to visualize
|
17
|
+
* GA data in the Google Visualization API. In this demo we show the
|
18
|
+
* top 10 tracked pages tiles and page URIs by pageviews in a
|
19
|
+
* Gviz Table, Pie Chart and Column Chart.
|
20
|
+
*/
|
21
|
+
|
22
|
+
var myService;
|
23
|
+
var dataTable;
|
24
|
+
var pageViewsTable;
|
25
|
+
var pageViewsChart;
|
26
|
+
var pageViewsColumnChart;
|
27
|
+
var visitsLineChart;
|
28
|
+
var visitsTable;
|
29
|
+
var timesOnSiteLineChart;
|
30
|
+
var timesOnSiteTable;
|
31
|
+
var sourcePieChart;
|
32
|
+
var sourceTable;
|
33
|
+
var keywordPieChart;
|
34
|
+
var keywordTable;
|
35
|
+
var scope = 'https://www.google.com/analytics/feeds';
|
36
|
+
var profileId;
|
37
|
+
var pageCode;
|
38
|
+
|
39
|
+
/**
|
40
|
+
* Initialize all the objects from the Google AJAX Apis once they
|
41
|
+
* have been loaded and are ready to use.
|
42
|
+
*/
|
43
|
+
function collectStatsData(pageCodeArg) {
|
44
|
+
var divLogin = document.getElementById('login');
|
45
|
+
var divLogged = document.getElementById('logged');
|
46
|
+
divLogin.style.visibility = 'hidden';
|
47
|
+
divLogged.style.visibility = 'hidden';
|
48
|
+
|
49
|
+
if (google.accounts.user.checkLogin(scope)) {
|
50
|
+
divLogin.style.visibility = 'hidden';
|
51
|
+
divLogged.style.visibility = 'visible';
|
52
|
+
divLogged.style.position = 'relative';
|
53
|
+
divLogged.style.position = "relative";
|
54
|
+
divLogged.style.top = -divLogin.offsetHeight+"px";
|
55
|
+
|
56
|
+
pageCode = pageCodeArg;
|
57
|
+
myService = new google.gdata.analytics.AnalyticsService('gaExportAPI_gViz_v1.0');
|
58
|
+
pageViewsTable = new google.visualization.Table(document.getElementById('pageViewsTableDiv'));
|
59
|
+
pageViewsChart = new google.visualization.PieChart(document.getElementById('pageViewsChartDiv'));
|
60
|
+
pageViewsColumnChart = new google.visualization.ColumnChart(document.getElementById('pageViewsColumnChartDiv'));
|
61
|
+
|
62
|
+
|
63
|
+
sourcePieChart = new google.visualization.PieChart(document.getElementById('sourcePieChartDiv'));
|
64
|
+
sourceTable = new google.visualization.Table(document.getElementById('sourceTableDiv'));
|
65
|
+
|
66
|
+
keywordPieChart = new google.visualization.PieChart(document.getElementById('keywordPieChartDiv'));
|
67
|
+
keywordTable = new google.visualization.Table(document.getElementById('keywordTableDiv'));
|
68
|
+
|
69
|
+
visitsLineChart = new google.visualization.LineChart(document.getElementById('visitsLineChartDiv'));
|
70
|
+
visitsTable = new google.visualization.Table(document.getElementById('visitsTableDiv'));
|
71
|
+
|
72
|
+
visitorsLineChart = new google.visualization.LineChart(document.getElementById('visitorsLineChartDiv'));
|
73
|
+
visitorsTable = new google.visualization.Table(document.getElementById('visitorsTableDiv'));
|
74
|
+
|
75
|
+
timesOnSiteLineChart = new google.visualization.LineChart(document.getElementById('timesOnSiteLineChartDiv'));
|
76
|
+
timesOnSiteTable = new google.visualization.Table(document.getElementById('timesOnSiteTableDiv'));
|
77
|
+
|
78
|
+
getWebPropertyFeed();
|
79
|
+
} else {
|
80
|
+
divLogin.style.visibility = 'visible';
|
81
|
+
divLogged.style.visibility = 'hidden';
|
82
|
+
document.getElementById('buttonLogin').onclick = handleLogin;
|
83
|
+
}
|
84
|
+
}
|
85
|
+
|
86
|
+
function handleLogin() {
|
87
|
+
google.accounts.user.login(scope);
|
88
|
+
}
|
89
|
+
|
90
|
+
function getWebPropertyFeed() {
|
91
|
+
var webPropertyFeedUri = [scope, '/datasources/ga/accounts/',pageCode.split('-')[1],'/webproperties/',pageCode,'/profiles'].join('');
|
92
|
+
|
93
|
+
// Send asynchronous request to the Management API.
|
94
|
+
myService.getManagementFeed(webPropertyFeedUri, printWebPropertyFeed,handleError);
|
95
|
+
}
|
96
|
+
|
97
|
+
function printWebPropertyFeed(result) {
|
98
|
+
var feed = result.feed;
|
99
|
+
var entries = feed.getEntries();
|
100
|
+
var GAProfileId;
|
101
|
+
if (entries.length) {
|
102
|
+
for (var i = 0, entry; entry = entries[i]; ++i) {
|
103
|
+
GAProfileId = entry.getPropertyValue('ga:profileId');
|
104
|
+
}
|
105
|
+
}
|
106
|
+
profileId = GAProfileId;
|
107
|
+
getPageViewsDataFeed();
|
108
|
+
getVisitsDataFeed();
|
109
|
+
getVisitorsDataFeed();
|
110
|
+
getTimeOnSiteDataFeed();
|
111
|
+
getSourceDataFeed();
|
112
|
+
getKeywordDataFeed();
|
113
|
+
}
|
114
|
+
|
115
|
+
function getDateConditions() {
|
116
|
+
var toDay = new Date();
|
117
|
+
var lastMonth = new Date (toDay.getFullYear(), toDay.getMonth()-1, toDay.getDate());
|
118
|
+
|
119
|
+
var lastMonthStr;
|
120
|
+
if ((lastMonth.getMonth() + 1) < 10) {
|
121
|
+
lastMonthStr = '0'+(lastMonth.getMonth() + 1);
|
122
|
+
} else {
|
123
|
+
lastMonthStr = (lastMonth.getMonth() + 1);
|
124
|
+
}
|
125
|
+
|
126
|
+
var lastMonthDayStr;
|
127
|
+
if (lastMonth.getDate() < 10) {
|
128
|
+
lastMonthDayStr = '0'+(lastMonth.getDate());
|
129
|
+
} else {
|
130
|
+
lastMonthDayStr = (lastMonth.getDate());
|
131
|
+
}
|
132
|
+
|
133
|
+
var currentMonthStr;
|
134
|
+
if ((toDay.getMonth() + 1) < 10) {
|
135
|
+
currentMonthStr = '0'+(toDay.getMonth() + 1);
|
136
|
+
} else {
|
137
|
+
currentMonthStr = (toDay.getMonth() + 1);
|
138
|
+
}
|
139
|
+
|
140
|
+
var currentMonthDayStr;
|
141
|
+
if (toDay.getDate() < 10) {
|
142
|
+
currentMonthDayStr = '0'+(toDay.getDate());
|
143
|
+
} else {
|
144
|
+
currentMonthDayStr = (toDay.getDate());
|
145
|
+
}
|
146
|
+
|
147
|
+
var conditions = '?start-date='+ lastMonth.getFullYear() + '-' + lastMonthStr + '-' + lastMonthDayStr + '&end-date='+ toDay.getFullYear() + '-' + currentMonthStr + '-' + currentMonthDayStr
|
148
|
+
|
149
|
+
return conditions;
|
150
|
+
}
|
151
|
+
|
152
|
+
/**
|
153
|
+
* Request data from GA Export API
|
154
|
+
*/
|
155
|
+
function getPageViewsDataFeed() {
|
156
|
+
var myFeedUri = scope + '/data' + getDateConditions() +
|
157
|
+
'&dimensions=ga:pageTitle,ga:pagePath' +
|
158
|
+
'&metrics=ga:pageviews' +
|
159
|
+
'&sort=-ga:pageviews' +
|
160
|
+
'&max-results=10' +
|
161
|
+
'&ids=ga:' + profileId;
|
162
|
+
|
163
|
+
myService.getDataFeed(myFeedUri, handlePageViewsDataFeed, handleError);
|
164
|
+
}
|
165
|
+
|
166
|
+
/**
|
167
|
+
* Request data from GA Export API
|
168
|
+
*/
|
169
|
+
function getVisitsDataFeed() {
|
170
|
+
var myFeedUri = scope + '/data' + getDateConditions() +
|
171
|
+
'&dimensions=ga:day,ga:year,ga:month,ga:date' +
|
172
|
+
'&metrics=ga:visits' +
|
173
|
+
'&sort=ga:date' +
|
174
|
+
'&ids=ga:' + profileId;
|
175
|
+
|
176
|
+
myService.getDataFeed(myFeedUri, handleVisitsDataFeed, handleError);
|
177
|
+
}
|
178
|
+
|
179
|
+
/**
|
180
|
+
* Request data from GA Export API
|
181
|
+
*/
|
182
|
+
function getVisitorsDataFeed() {
|
183
|
+
var myFeedUri = scope + '/data' + getDateConditions() +
|
184
|
+
'&dimensions=ga:day,ga:year,ga:month,ga:date' +
|
185
|
+
'&metrics=ga:visitors' +
|
186
|
+
'&sort=ga:date' +
|
187
|
+
'&ids=ga:' + profileId;
|
188
|
+
|
189
|
+
myService.getDataFeed(myFeedUri, handleVisitorsDataFeed, handleError);
|
190
|
+
}
|
191
|
+
|
192
|
+
/**
|
193
|
+
* Request data from GA Export API
|
194
|
+
*/
|
195
|
+
function getTimeOnSiteDataFeed() {
|
196
|
+
var myFeedUri = scope + '/data' + getDateConditions() +
|
197
|
+
'&dimensions=ga:day,ga:year,ga:month,ga:date' +
|
198
|
+
'&metrics=ga:timeOnSite,ga:visits' +
|
199
|
+
'&sort=ga:date' +
|
200
|
+
'&ids=ga:' + profileId;
|
201
|
+
|
202
|
+
myService.getDataFeed(myFeedUri, handleTimeOnSiteDataFeed, handleError);
|
203
|
+
}
|
204
|
+
|
205
|
+
/**
|
206
|
+
* Request data from GA Export API
|
207
|
+
*/
|
208
|
+
function getSourceDataFeed() {
|
209
|
+
var myFeedUri = scope + '/data' + getDateConditions() +
|
210
|
+
'&dimensions=ga:source' +
|
211
|
+
'&metrics=ga:visits' +
|
212
|
+
'&sort=-ga:visits' +
|
213
|
+
'&max-results=20' +
|
214
|
+
'&ids=ga:' + profileId;
|
215
|
+
|
216
|
+
myService.getDataFeed(myFeedUri, handleSourceDataFeed, handleError);
|
217
|
+
}
|
218
|
+
|
219
|
+
/**
|
220
|
+
* Request data from GA Export API
|
221
|
+
*/
|
222
|
+
function getKeywordDataFeed() {
|
223
|
+
var myFeedUri = scope + '/data' + getDateConditions() +
|
224
|
+
'&dimensions=ga:keyword' +
|
225
|
+
'&metrics=ga:visits' +
|
226
|
+
'&sort=-ga:visits' +
|
227
|
+
'&max-results=20' +
|
228
|
+
'&ids=ga:' + profileId;
|
229
|
+
|
230
|
+
myService.getDataFeed(myFeedUri, handleKeywordDataFeed, handleError);
|
231
|
+
}
|
232
|
+
|
233
|
+
/**
|
234
|
+
* Handle and display any error that occurs from the API request.
|
235
|
+
* @param {Object} e The error object returned by the Analytics API.
|
236
|
+
*/
|
237
|
+
function handleError(e) {
|
238
|
+
var msg = e.cause ? e.cause.statusText : e.message;
|
239
|
+
msg = 'ERROR: ' + msg;
|
240
|
+
alert(msg);
|
241
|
+
}
|
242
|
+
|
243
|
+
/**
|
244
|
+
* Handle all the data returned by GA Export API.
|
245
|
+
* Delete existing GViz dataTable before creating a new one.
|
246
|
+
* @param {Object} myResultsFeedRoot the feed object
|
247
|
+
* retuned by the data feed.
|
248
|
+
*/
|
249
|
+
function handlePageViewsDataFeed(resultsFeedRoot) {
|
250
|
+
dataTable = new google.visualization.DataTable();
|
251
|
+
fillPageViewsDataTable(dataTable, resultsFeedRoot);
|
252
|
+
pageViewsTable.draw(dataTable);
|
253
|
+
|
254
|
+
// remove the URI column to only graph 1 dimension
|
255
|
+
dataTable.removeColumn(0);
|
256
|
+
pageViewsChart.draw(dataTable, {width: 950, height: 400});
|
257
|
+
pageViewsColumnChart.draw(dataTable, {width: 950, height: 300, legend: 'none'});
|
258
|
+
}
|
259
|
+
|
260
|
+
/**
|
261
|
+
* Handle all the data returned by GA Export API.
|
262
|
+
* Delete existing GViz dataTable before creating a new one.
|
263
|
+
* @param {Object} myResultsFeedRoot the feed object
|
264
|
+
* retuned by the data feed.
|
265
|
+
*/
|
266
|
+
function handleVisitsDataFeed(resultsFeedRoot) {
|
267
|
+
dataTable = new google.visualization.DataTable();
|
268
|
+
fillVisitsDataTable(dataTable, resultsFeedRoot);
|
269
|
+
visitsLineChart.draw(dataTable, {width: 750, height: 500, legend: 'none'});
|
270
|
+
visitsTable.draw(dataTable);
|
271
|
+
}
|
272
|
+
|
273
|
+
function handleVisitorsDataFeed(resultsFeedRoot) {
|
274
|
+
dataTable = new google.visualization.DataTable();
|
275
|
+
fillVisitorsDataTable(dataTable, resultsFeedRoot);
|
276
|
+
visitorsLineChart.draw(dataTable, {width: 750, height: 500, legend: 'none'});
|
277
|
+
visitorsTable.draw(dataTable);
|
278
|
+
}
|
279
|
+
|
280
|
+
function handleTimeOnSiteDataFeed(resultsFeedRoot) {
|
281
|
+
dataTable = new google.visualization.DataTable();
|
282
|
+
fillTimesOnSiteDataTable(dataTable, resultsFeedRoot);
|
283
|
+
timesOnSiteLineChart.draw(dataTable, {width: 750, height: 500, legend: 'none'});
|
284
|
+
timesOnSiteTable.draw(dataTable);
|
285
|
+
}
|
286
|
+
|
287
|
+
function handleSourceDataFeed(resultsFeedRoot) {
|
288
|
+
dataTable = new google.visualization.DataTable();
|
289
|
+
fillSourceDataTable(dataTable, resultsFeedRoot);
|
290
|
+
sourcePieChart.draw(dataTable, {width: 600, height: 400, legend: 'none'});
|
291
|
+
sourceTable.draw(dataTable);
|
292
|
+
}
|
293
|
+
|
294
|
+
function handleKeywordDataFeed(resultsFeedRoot) {
|
295
|
+
dataTable = new google.visualization.DataTable();
|
296
|
+
fillKeywordDataTable(dataTable, resultsFeedRoot);
|
297
|
+
keywordPieChart.draw(dataTable, {width: 600, height: 400, legend: 'none'});
|
298
|
+
keywordTable.draw(dataTable);
|
299
|
+
}
|
300
|
+
|
301
|
+
/**
|
302
|
+
* Put the feed result into a GViz Data Table.
|
303
|
+
* @param {Object} dataTable the GViz dataTable
|
304
|
+
dataTable.setCell(0, 1, '0'); object to put data into.
|
305
|
+
* @param {Object} myResultsFeedRoot the feed returned by the GA Export API.
|
306
|
+
* @return {Objcet} GViz DataTable object.
|
307
|
+
*/
|
308
|
+
function fillPageViewsDataTable(dataTable, myResultsFeedRoot) {
|
309
|
+
var entries = myResultsFeedRoot.feed.getEntries();
|
310
|
+
|
311
|
+
var datas = getGADatasInTable(entries, ['pageTitle','pagePath','pageviews']);
|
312
|
+
fillDataTable(entries, dataTable, [['string', I18n.t('admin.stats.title'), datas[0]],['string', I18n.t('admin.stats.path'), datas[1]],['number', I18n.t('admin.stats.page_views'), datas[2]]]);
|
313
|
+
}
|
314
|
+
|
315
|
+
function fillKeywordDataTable(dataTable, myResultsFeedRoot) {
|
316
|
+
var entries = myResultsFeedRoot.feed.getEntries();
|
317
|
+
var keywords = new Array();
|
318
|
+
var visits = new Array();
|
319
|
+
|
320
|
+
for (var i = 0, entry; entry = entries[i]; ++i) {
|
321
|
+
|
322
|
+
if (entry.getValueOf('ga:keyword') != '(not set)') {
|
323
|
+
keywords.push(entry.getValueOf('ga:keyword'));
|
324
|
+
visits.push(entry.getValueOf('ga:visits'));
|
325
|
+
}
|
326
|
+
}
|
327
|
+
|
328
|
+
fillDataTable(entries, dataTable, [['string', I18n.t('admin.stats.keywords'), keywords],['number', I18n.t('admin.stats.visits'), visits]]);
|
329
|
+
dataTable.removeRow(dataTable.getNumberOfRows()-1);
|
330
|
+
}
|
331
|
+
|
332
|
+
function fillSourceDataTable(dataTable, myResultsFeedRoot) {
|
333
|
+
var entries = myResultsFeedRoot.feed.getEntries();
|
334
|
+
var dates = new Array();
|
335
|
+
|
336
|
+
var datas = getGADatasInTable(entries, ['source', 'visits']);
|
337
|
+
fillDataTable(entries, dataTable, [['string', I18n.t('admin.stats.source'), datas[0]],['number', I18n.t('admin.stats.visits'), datas[1]]]);
|
338
|
+
}
|
339
|
+
|
340
|
+
function fillVisitsDataTable(dataTable, myResultsFeedRoot) {
|
341
|
+
var entries = myResultsFeedRoot.feed.getEntries();
|
342
|
+
var dates = new Array();
|
343
|
+
|
344
|
+
var datas = getGADatasInTable(entries, ['visits'], dates);
|
345
|
+
fillDataTable(entries, dataTable, [['string', I18n.t('admin.stats.date'), dates],['number', I18n.t('admin.stats.visits'), datas[0]]]);
|
346
|
+
}
|
347
|
+
|
348
|
+
function fillVisitorsDataTable(dataTable, myResultsFeedRoot) {
|
349
|
+
var entries = myResultsFeedRoot.feed.getEntries();
|
350
|
+
var dates = new Array();
|
351
|
+
|
352
|
+
var datas = getGADatasInTable(entries, ['visitors'], dates);
|
353
|
+
fillDataTable(entries, dataTable, [['string',I18n.t('admin.stats.date'), dates],['number', I18n.t('admin.stats.visitors'), datas[0]]]);
|
354
|
+
}
|
355
|
+
|
356
|
+
function fillTimesOnSiteDataTable(dataTable, myResultsFeedRoot) {
|
357
|
+
var entries = myResultsFeedRoot.feed.getEntries();
|
358
|
+
var timesOnSite = new Array();
|
359
|
+
var dates = new Array();
|
360
|
+
|
361
|
+
for (var i = 0, entry; entry = entries[i]; ++i) {
|
362
|
+
fillDate(entry, timesOnSite, dates);
|
363
|
+
|
364
|
+
if (entry.getValueOf('ga:visits') != 0) {
|
365
|
+
timesOnSite.push(entry.getValueOf('ga:timeOnSite') / entry.getValueOf('ga:visits'));
|
366
|
+
} else {
|
367
|
+
timesOnSite.push(0);
|
368
|
+
}
|
369
|
+
}
|
370
|
+
|
371
|
+
for (var i = 0; i < timesOnSite.length ; ++i) {
|
372
|
+
timesOnSite[i] = Math.round(timesOnSite[i] / 60);
|
373
|
+
}
|
374
|
+
|
375
|
+
convertDates(dates);
|
376
|
+
|
377
|
+
fillDataTable(entries, dataTable, [['string',I18n.t('admin.stats.date'), dates],['number', I18n.t('admin.stats.average_time'), timesOnSite]]);
|
378
|
+
}
|
379
|
+
|
380
|
+
function fillDate(entry, dataTable, dateTable) {
|
381
|
+
var date = new Date(entry.getValueOf('ga:year'), entry.getValueOf('ga:month')-1, entry.getValueOf('ga:day'));
|
382
|
+
|
383
|
+
// At the beginning of each day, check if data was missing for previous
|
384
|
+
// day. Insert "0" in appropriate visitor's array as necessary, using
|
385
|
+
// fillToSameSize helper method.
|
386
|
+
var lastDate = dateTable[dateTable.length - 1];
|
387
|
+
if(lastDate) {
|
388
|
+
while (Date.parse(date) != Date.parse(lastDate)) {
|
389
|
+
lastDate = new Date (lastDate.getFullYear(), lastDate.getMonth(), lastDate.getDate() + 1);
|
390
|
+
if (Date.parse(date) != Date.parse(lastDate)) {
|
391
|
+
dataTable.push(0);
|
392
|
+
dateTable.push(lastDate);
|
393
|
+
}
|
394
|
+
}
|
395
|
+
}
|
396
|
+
|
397
|
+
dateTable.push(date);
|
398
|
+
}
|
399
|
+
|
400
|
+
function fillDataTable(entries, dataTable, datas) {
|
401
|
+
for (var i = 0; i < datas.length; i++) {
|
402
|
+
dataTable.addColumn(datas[i][0], datas[i][1]);
|
403
|
+
}
|
404
|
+
|
405
|
+
dataTable.addRows(entries.length);
|
406
|
+
|
407
|
+
for (var idx = 0; idx < entries.length; idx++) {
|
408
|
+
var entry = entries[idx];
|
409
|
+
for (var i = 0; i < datas.length; i++) {
|
410
|
+
dataTable.setCell(idx, i, datas[i][2][idx]);
|
411
|
+
}
|
412
|
+
}
|
413
|
+
}
|
414
|
+
|
415
|
+
function getGADatasInTable(entries, datas, dates) {
|
416
|
+
var results = new Array();
|
417
|
+
|
418
|
+
for (var idx = 0; idx < entries.length; idx++) {
|
419
|
+
var entry = entries[idx];
|
420
|
+
for (var i = 0; i <datas.length; i++) {
|
421
|
+
results.push(new Array());
|
422
|
+
var GAData = entry.getValueOf('ga:'+datas[i]);
|
423
|
+
if (dates) {
|
424
|
+
fillDate(entry, results[i], dates);
|
425
|
+
}
|
426
|
+
results[i].push(GAData);
|
427
|
+
}
|
428
|
+
}
|
429
|
+
|
430
|
+
convertDates(dates);
|
431
|
+
return results
|
432
|
+
}
|
433
|
+
|
434
|
+
function convertDates(dates) {
|
435
|
+
if (dates) {
|
436
|
+
for (var i = 0; i < dates.length; i++) {
|
437
|
+
dates[i] = dates[i].toLocaleString().substr(0,10);
|
438
|
+
}
|
439
|
+
}
|
440
|
+
}
|
441
|
+
|
442
|
+
// Load the Google Visualization API client Libraries
|
443
|
+
google.load('visualization', '1', {packages: ['piechart', 'table', 'columnchart', 'linechart']});
|
444
|
+
|
445
|
+
// Load the Google data JavaScript client library
|
446
|
+
google.load('gdata', '2.x', {packages: ['analytics']});
|
@@ -0,0 +1,14 @@
|
|
1
|
+
div.stat {
|
2
|
+
width: 958px;
|
3
|
+
opacity: 1;
|
4
|
+
border-bottom-left-radius: 5px;
|
5
|
+
border-bottom-right-radius: 5px;
|
6
|
+
border-top-right-radius: 5px;
|
7
|
+
background: none repeat scroll 0 0 #FFFFFF;
|
8
|
+
border: 1px solid #CCCCCC;
|
9
|
+
padding: 5px 5px 0;
|
10
|
+
}
|
11
|
+
|
12
|
+
.ui-tabs-nav {
|
13
|
+
padding: 0px;
|
14
|
+
}
|
metadata
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: refinerycms-stats
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: "0.1"
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Guirec CORBEL
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-06-26 00:00:00 Z
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Ruby on Rails Stats engine for Refinery CMS
|
17
|
+
email: guirec.corbel@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- lib/generators/refinerycms_stats_generator.rb
|
26
|
+
- lib/refinerycms-stats.rb
|
27
|
+
- lib/tasks/stats.rake
|
28
|
+
- config/locales/en.yml
|
29
|
+
- config/locales/fr.yml
|
30
|
+
- config/routes.rb
|
31
|
+
- app/controllers/admin/stats_controller.rb
|
32
|
+
- app/models/stat.rb
|
33
|
+
- app/views/admin/stats/index.html.erb
|
34
|
+
- public/javascripts/refinerycms-stat-translate.js
|
35
|
+
- public/javascripts/refinerycms-stat.js
|
36
|
+
- public/stylesheets/stat.css
|
37
|
+
homepage: http://www.guirec-corbel.com
|
38
|
+
licenses: []
|
39
|
+
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options: []
|
42
|
+
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
none: false
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: "0"
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
requirements: []
|
58
|
+
|
59
|
+
rubyforge_project:
|
60
|
+
rubygems_version: 1.8.5
|
61
|
+
signing_key:
|
62
|
+
specification_version: 3
|
63
|
+
summary: Stats engine for Refinery CMS
|
64
|
+
test_files: []
|
65
|
+
|