[FIX] Pass the right object when binding to 'state_pushed'
[odoo/odoo.git] / addons / web_analytics / static / src / js / web_analytics.js
1
2 var _gaq = _gaq || [];  // asynchronous stack used by google analytics
3
4 openerp.web_analytics = function(instance) {
5
6     /*
7     *  The Web Analytics Module inserts the Google Analytics JS Snippet
8     *  at the top of the page, and sends to google an url each time the
9     *  openerp url is changed.
10     *  The pushes of the urls is made by triggering the 'state_pushed' event in the
11     *  web_client.do_push_state() method which is responsible of changing the openerp current url
12     */
13
14     // Google Analytics Code snippet
15     (function() {
16         var ga   = document.createElement('script');
17         ga.type  = 'text/javascript';
18         ga.async = true;
19         ga.src   = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
20         var s = document.getElementsByTagName('script')[0];
21         s.parentNode.insertBefore(ga,s);
22     })();
23
24     instance.web_analytics.Tracker = instance.web.Class.extend({
25         /*
26         * This method initializes the tracker
27         */
28         init: function() {
29             /* Comment this lines when going on production, only used for testing on localhost
30             _gaq.push(['_setAccount', 'UA-35793871-1']);
31             _gaq.push(['_setDomainName', 'none']);
32             */
33
34             /* Uncomment this lines when going on production */
35             _gaq.push(['_setAccount', 'UA-7333765-1']);
36             _gaq.push(['_setDomainName', '.openerp.com']);  // Allow multi-domain
37             /**/
38         },
39         /*
40         * This method MUST be overriden by saas_demo and saas_trial in order to
41         * set the correct user type. By default, the user connected is local to the DB.
42         */
43         _get_user_type: function() {
44             return 'Local User';
45         },
46         /*
47         * This method gets the user access level, to be used as CV in GA
48         */
49         _get_user_access_level: function() {
50             if (instance.session.uid === 1) {
51                 return 'Admin User';
52             // Make the difference between portal users and anonymous users
53             } else if (instance.session.username.indexOf('@') !== -1) {
54                 if (instance.session.username.indexOf('anonymous') === -1) {
55                     return 'Portal User';
56                 } else {
57                     return 'Anonymous User';
58                 }
59             } else if (instance.session.username.indexOf('anonymous') !== -1) {
60                 return 'Anonymous User';
61             } else {
62                 return 'Normal User';
63             }
64         },
65         /*
66         * This method contains the initialization of all user-related custom variables
67         * stored in GA. Also other modules can override it to add new custom variables
68         */
69         initialize_custom: function() {
70             // Track User Access Level, Custom Variable 4 in GA with visitor level scope
71             // Values: 'Admin User', 'Normal User', 'Portal User', 'Anonymous User'
72             _gaq.push(['_setCustomVar', 4, 'User Access Level', this.user_access_level, 1]);
73
74             // Track User Type Conversion, Custom Variable 3 in GA with session level scope
75             // Values: 'Visitor', 'Demo', 'Online Trial', 'Online Paying', 'Local User'
76             _gaq.push(['_setCustomVar', 1, 'User Type Conversion', this._get_user_type(), 2]);
77
78             return instance.session.rpc("/web/webclient/version_info", {})
79                 .done(function(res) {
80                     _gaq.push(['_setCustomVar', 5, 'Version', res.server_version, 3]);
81                     return;
82                 });
83         },
84         /*
85         * Method called in order to send _trackEvent to GA
86         */
87         _push_event: function(options) {
88             _gaq.push(['_trackEvent',
89                 options.category,
90                 options.action,
91                 options.label,
92                 options.value,
93                 options.noninteraction
94             ]);
95         },
96         /*
97         * Method called in order to send ecommerce transactions to GA
98         */
99         _push_ecommerce: function(trans_data, item_list) {
100             _gaq.push(['_addTrans',
101                 trans_data.order_id,
102                 trans_data.store_name,
103                 trans_data.total,
104                 trans_data.tax,
105                 trans_data.shipping,
106                 trans_data.city,
107                 trans_data.state,
108                 trans_data.country,
109             ]);
110             _.each(item_list, function(item) {
111                 _gaq.push(['_addItem',
112                     item.order_id,
113                     item.sku,
114                     item.name,
115                     item.category,
116                     item.price,
117                     item.quantity,
118                 ]);
119             });
120             _gaq.push(['_trackTrans']);
121         },
122         /*
123         *  This method contains the initialization of the object and view type
124         *  as an event in GA.
125         */
126         on_state_pushed: function(state) {
127             // Track only pages corresponding to a 'normal' view of OpenERP, views
128             // related to client actions are tracked by the action manager
129             if (state.model && state.view_type) {
130                 // Track the page
131                 var url = instance.web_analytics.generateUrl({'model': state.model, 'view_type': state.view_type});
132                 this._push_event({
133                     'category': state.model,
134                     'action': state.view_type,
135                     'label': url,
136                 });
137             }
138         },
139         /*
140         * This method includes the tracker into views and managers. It can be overriden
141         * by other modules in order to extend tracking functionalities
142         */
143         include_tracker: function() {
144             var t = this;
145             // Track the events related with the creation and the  modification of records,
146             // the view type is always form
147             instance.web.FormView.include({
148                 init: function(parent, dataset, view_id, options) {
149                     this._super.apply(this, arguments);
150                     var self = this;
151                     this.on('record_created', self, function(r) {
152                         var url = instance.web_analytics.generateUrl({'model': r.model, 'view_type': 'form'});
153                         t._push_event({
154                             'category': r.model,
155                             'action': 'form',
156                             'label': url,
157                         });
158                     });
159                     this.on('record_saved', self, function(r) {
160                         var url = instance.web_analytics.generateUrl({'model': r.model, 'view_type': 'form'});
161                         t._push_event({
162                             'category': r.model,
163                             'action': 'form',
164                             'label': url,
165                         });
166                     });
167                 }
168             });
169
170             // Track client actions
171             instance.web.ActionManager.include({
172                 ir_actions_client: function (action, options) {
173                     var url = instance.web_analytics.generateUrl({'action': action.tag});
174                     var category = action.res_model || action.type;
175                     t._push_event({
176                         'category': action.res_model || action.type,
177                         'action': action.name || action.tag,
178                         'label': url,
179                     });
180                     return this._super.apply(this, arguments);
181                 },
182             });
183
184             // Track button events
185             instance.web.View.include({
186                 do_execute_action: function(action_data, dataset, record_id, on_closed) {
187                     var category = this.model || dataset.model || '';
188                     var action;
189                     if (action_data.name && _.isNaN(action_data.name-0)) {
190                         action = action_data.name;
191                     } else {
192                         action = action_data.string || action_data.special || '';
193                     }
194                     var url = instance.web_analytics.generateUrl({'model': category, 'view_type': this.view_type});
195                     t._push_event({
196                         'category': category,
197                         'action': action,
198                         'label': url,
199                     });
200                     return this._super.apply(this, arguments);
201                 },
202             });
203
204             // Track error events
205             instance.web.CrashManager.include({
206                 show_error: function(error) {
207                     var hash = window.location.hash;
208                     var params = $.deparam(hash.substr(hash.indexOf('#')+1));
209                     var options = {};
210                     if (params.model && params.view_type) {
211                         options = {'model': params.model, 'view_type': params.view_type};
212                     } else {
213                         options = {'action': params.action};
214                     }
215                     var url = instance.web_analytics.generateUrl(options);
216                     if (error.code) {
217                         t._push_event({
218                             'category': error.message,
219                             'action': error.data.fault_code,
220                             'label': url,
221                             'noninteraction': true,
222                         });
223                     } else {
224                         t._push_event({
225                             'category': error.type,
226                             'action': error.data.debug,
227                             'label': url,
228                             'noninteraction': true,
229                         });
230                     }
231                     this._super.apply(this, arguments);
232                 },
233             });
234         },
235     });
236
237     // ----------------------------------------------------------------
238     // utility functions
239     // ----------------------------------------------------------------
240
241     instance.web_analytics.generateUrl = function(options) {
242         var url = '';
243         _.each(options, function(value, key) {
244             url += '/' + key + '=' + value;
245         });
246         return url;
247     };
248
249     instance.web_analytics.setupTracker = function(wc) {
250         var t = wc.tracker;
251         return $.when(t._get_user_access_level()).then(function(r) {
252             t.user_access_level = r;
253             t.initialize_custom().then(function() {
254                 wc.on('state_pushed', t, t.on_state_pushed);
255                 t.include_tracker();
256             });
257         });
258     };
259
260     // Set correctly the tracker in the current instance
261     if (instance.client instanceof instance.web.WebClient) {        // not for embedded clients
262         instance.webclient.tracker = new instance.web_analytics.Tracker();
263         instance.web_analytics.setupTracker(instance.webclient);
264     } else if (!instance.client) {
265         // client does not already exists, we are in monodb mode
266         instance.web.WebClient.include({
267             start: function() {
268                 var d = this._super.apply(this, arguments);
269                 this.tracker = new instance.web_analytics.Tracker();
270                 return d;
271             },
272             show_application: function() {
273                 var self = this;
274                 instance.web_analytics.setupTracker(self).always(function() {
275                     self._super();
276                 });
277             },
278         });
279     }
280
281 };