PageRenderTime 39ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/Web/Controls/Analytics/AnalyticsAsyncTopScript.cs

#
C# | 347 lines | 231 code | 69 blank | 47 comment | 28 complexity | 6cec293376e1128457a07ccc1ae7445c MD5 | raw file
Possible License(s): LGPL-2.1, Apache-2.0, BSD-3-Clause, CPL-1.0, CC-BY-SA-3.0, GPL-2.0
  1. // Author: Joe Audette
  2. // Created: 2010-03-15
  3. // Last Modified: 2011-05-06
  4. //
  5. // The use and distribution terms for this software are covered by the
  6. // Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
  7. // which can be found in the file CPL.TXT at the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by
  9. // the terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. using System;
  13. using System.Collections.Generic;
  14. using System.Configuration;
  15. using System.Web;
  16. using System.Web.UI;
  17. using System.Web.UI.WebControls;
  18. using mojoPortal.Business;
  19. using mojoPortal.Business.WebHelpers;
  20. using mojoPortal.Web.Controls.google;
  21. namespace mojoPortal.Web.UI
  22. {
  23. /// <summary>
  24. /// This control is used in conjunction with AnalyticsAsyncBottomScript and in replacement for mojoGoogleAnalyticsScript
  25. /// if you want to use the async loading approach described here:
  26. /// http://code.google.com/apis/analytics/docs/tracking/asyncUsageGuide.html#SplitSnippet
  27. ///
  28. /// Remove mojoGoogleAnalyticsScript from your layout.master and replace with AnalyticsAsyncBottomScript just before the closing form element
  29. /// Add AnalyticsAsyncTopScript to layout.master just below the opening body element
  30. public class AnalyticsAsyncTopScript : WebControl
  31. {
  32. private SiteSettings siteSettings = null;
  33. private string googleAnalyticsProfileId = string.Empty;
  34. private List<AnalyticsTransaction> transactions = new List<AnalyticsTransaction>();
  35. private string memberLabel = "member-type";
  36. private string memberType = "member";
  37. private string pageToTrack = string.Empty;
  38. private string sectionKey = "section";
  39. private string section = string.Empty;
  40. private string overrideDomain = string.Empty;
  41. private bool logToLocalServer = false;
  42. /// <summary>
  43. /// Requires at least one item
  44. /// </summary>
  45. public List<AnalyticsTransaction> Transactions
  46. {
  47. get { return transactions; }
  48. }
  49. /// <summary>
  50. /// If true pageTracker._setLocalRemoteServerMode(); wil be called resulting in analytics data appearing in the web logs.
  51. /// This data can be used for additional offline processing using Urchin.
  52. /// </summary>
  53. public bool LogToLocalServer
  54. {
  55. get { return logToLocalServer; }
  56. set { logToLocalServer = value; }
  57. }
  58. /// <summary>
  59. /// If you want to ovveride how the page is tracked you can enter it here.
  60. /// Like in SearchResults.aspx we track /SearchResults.aspx?q=searchterm
  61. /// </summary>
  62. public string PageToTrack
  63. {
  64. get { return pageToTrack; }
  65. set { pageToTrack = value; }
  66. }
  67. /// <summary>
  68. /// If specified will set a customVar at page level scope in slot 2
  69. /// </summary>
  70. public string Section
  71. {
  72. get { return section; }
  73. set { section = value; }
  74. }
  75. /// <summary>
  76. /// If you specify an overridedomain, ._setDomainName(...) will be called
  77. /// http://code.google.com/apis/analytics/docs/tracking/gaTrackingSite.html
  78. /// </summary>
  79. public string OverrideDomain
  80. {
  81. get { return overrideDomain; }
  82. set { overrideDomain = value; }
  83. }
  84. private bool setAllowLinker = true;
  85. public bool SetAllowLinker
  86. {
  87. get { return setAllowLinker; }
  88. set { setAllowLinker = value; }
  89. }
  90. private bool setAllowHash = true;
  91. public bool SetAllowHash
  92. {
  93. get { return setAllowHash; }
  94. set { setAllowHash = value; }
  95. }
  96. private bool trackPageLoadTime = true;
  97. public bool TrackPageLoadTime
  98. {
  99. get { return trackPageLoadTime; }
  100. set { trackPageLoadTime = value; }
  101. }
  102. protected override void OnInit(EventArgs e)
  103. {
  104. base.OnInit(e);
  105. DoInit();
  106. }
  107. protected override void OnLoad(EventArgs e)
  108. {
  109. base.OnLoad(e);
  110. }
  111. protected override void OnPreRender(EventArgs e)
  112. {
  113. base.OnPreRender(e);
  114. if (string.IsNullOrEmpty(section))
  115. {
  116. if (Page is mojoBasePage)
  117. {
  118. mojoBasePage basePage = Page as mojoBasePage;
  119. section = basePage.AnalyticsSection;
  120. }
  121. }
  122. }
  123. protected override void Render(HtmlTextWriter writer)
  124. {
  125. if (HttpContext.Current == null)
  126. {
  127. writer.Write("[" + this.ID + "]");
  128. }
  129. else
  130. {
  131. if (string.IsNullOrEmpty(googleAnalyticsProfileId)) { return; }
  132. writer.Write("<script type=\"text/javascript\"> ");
  133. writer.Write("\n");
  134. writer.Write("var _gaq = _gaq || []; ");
  135. writer.Write("\n");
  136. writer.Write("_gaq.push(['_setAccount','" + googleAnalyticsProfileId + "']); ");
  137. writer.Write("\n");
  138. if (overrideDomain.Length > 0)
  139. {
  140. //http://code.google.com/apis/analytics/docs/tracking/gaTrackingSite.html
  141. writer.Write("_gaq.push(['_setDomainName','" + overrideDomain + "']);");
  142. // default is false so we only have to set it if we want true
  143. if (setAllowLinker)
  144. {
  145. writer.Write("_gaq.push(['_setAllowLinker',true]);");
  146. }
  147. //default is true so we only have to set it if we want false
  148. if (!setAllowHash)
  149. {
  150. writer.Write("_gaq.push(['_setAllowHash',false]);");
  151. }
  152. }
  153. if (logToLocalServer)
  154. {
  155. writer.Write("_gaq.push(['_setLocalRemoteServerMode']);");
  156. }
  157. SetupUserTracking(writer);
  158. SetupSectionTracking(writer);
  159. SetupTransactions(writer);
  160. if (pageToTrack.Length > 0)
  161. {
  162. writer.Write(" _gaq.push(['_trackPageview','" + pageToTrack.Replace("'", string.Empty).Replace("\"", string.Empty) + "']); ");
  163. }
  164. else
  165. {
  166. writer.Write(" _gaq.push(['_trackPageview']); ");
  167. }
  168. writer.Write("\n");
  169. // new feature in google analytics 2011-05-06 Site Speed Report
  170. if (trackPageLoadTime)
  171. {
  172. writer.Write(" _gaq.push(['_trackPageLoadTime']); ");
  173. writer.Write("\n");
  174. }
  175. writer.Write(" </script>");
  176. }
  177. }
  178. //http://code.google.com/apis/analytics/docs/gaJS/gaJSApiBasicConfiguration.html#_gat.GA_Tracker_._setCustomVar
  179. //http://code.google.com/apis/analytics/docs/tracking/gaTrackingCustomVariables.html#mixedTypes
  180. //http://conversionroom.blogspot.com/2010/02/spotlight-on-google-analytics-features.html
  181. // we are using slot 1 for visitor and slot 2 for section, must use one of the 3 other slots for other custom vars
  182. private void SetupSectionTracking(HtmlTextWriter writer)
  183. {
  184. if (string.IsNullOrEmpty(section)) { return; }
  185. writer.Write("_gaq.push(['_setCustomVar', 2, '" + sectionKey + "', '" + section + "', 3]);");
  186. }
  187. private void SetupUserTracking(HtmlTextWriter writer)
  188. {
  189. if (string.IsNullOrEmpty(memberLabel)) { return; }
  190. writer.Write("_gaq.push(['_setCustomVar', 1, '" + memberType + "', '" + memberLabel + "', 1]);");
  191. }
  192. private void SetupTransactions(HtmlTextWriter writer)
  193. {
  194. bool foundValidTransactions = false;
  195. foreach (AnalyticsTransaction transaction in transactions)
  196. {
  197. if (transaction.IsValid())
  198. {
  199. foundValidTransactions = true;
  200. writer.Write("_gaq.push(['_addTrans',");
  201. writer.Write("'" + transaction.OrderId + "',");
  202. writer.Write("'" + transaction.StoreName + "',");
  203. writer.Write("\"" + transaction.Total + "\",");
  204. writer.Write("\"" + transaction.Tax + "\",");
  205. writer.Write("\"" + transaction.Shipping + "\",");
  206. writer.Write("\"" + transaction.City + "\",");
  207. writer.Write("\"" + transaction.State + "\",");
  208. writer.Write("\"" + transaction.Country + "\"");
  209. writer.Write("]);");
  210. SetupTransactionItems(writer, transaction);
  211. }
  212. }
  213. if (foundValidTransactions)
  214. {
  215. writer.Write("_gaq.push(['_trackTrans']);");
  216. writer.Write("_gaq.push(['_trackPageview','/TransactionComplete.aspx']);");
  217. }
  218. }
  219. private void SetupTransactionItems(HtmlTextWriter writer, AnalyticsTransaction transaction)
  220. {
  221. foreach (AnalyticsTransactionItem item in transaction.Items)
  222. {
  223. if (item.IsValid())
  224. {
  225. writer.Write("_gaq.push(['_addItem',");
  226. writer.Write("'" + item.OrderId + "',");
  227. writer.Write("'" + item.Sku + "',");
  228. writer.Write("'" + item.ProductName + "',");
  229. writer.Write("'" + item.Category + "',");
  230. writer.Write("'" + item.Price + "',");
  231. writer.Write("'" + item.Quantity + "'");
  232. writer.Write("]);");
  233. }
  234. }
  235. }
  236. private void DoInit()
  237. {
  238. if (HttpContext.Current == null) { return; }
  239. this.EnableViewState = false;
  240. memberType = WebConfigSettings.GoogleAnalyticsMemberLabel;
  241. memberLabel = WebConfigSettings.GoogleAnalyticsMemberTypeAnonymous;
  242. LogToLocalServer = WebConfigSettings.LogGoogleAnalyticsDataToLocalWebLog;
  243. sectionKey = WebConfigSettings.GoogleAnalyticsSectionLabel;
  244. // lets always label Admins as admins, regardless whether they are also customers
  245. if (WebUser.IsAdminOrContentAdmin)
  246. {
  247. memberLabel = WebConfigSettings.GoogleAnalyticsMemberTypeAdmin;
  248. }
  249. else
  250. {
  251. if (HttpContext.Current.Request.IsAuthenticated)
  252. {
  253. SiteUser siteUser = SiteUtils.GetCurrentSiteUser();
  254. if ((siteUser != null) && (siteUser.TotalRevenue > 0))
  255. {
  256. memberLabel = WebConfigSettings.GoogleAnalyticsMemberTypeCustomer;
  257. }
  258. else
  259. {
  260. memberLabel = WebConfigSettings.GoogleAnalyticsMemberTypeAuthenticated;
  261. }
  262. }
  263. }
  264. // let Web.config setting trump site settings. this meets my needs where I want to track the demo site but am letting people login as admin
  265. // this way if the remove or change it in site settings it still uses my profile id
  266. if (ConfigurationManager.AppSettings["GoogleAnalyticsProfileId"] != null)
  267. {
  268. googleAnalyticsProfileId = ConfigurationManager.AppSettings["GoogleAnalyticsProfileId"].ToString();
  269. return;
  270. }
  271. siteSettings = CacheHelper.GetCurrentSiteSettings();
  272. if ((siteSettings != null) && (siteSettings.GoogleAnalyticsAccountCode.Length > 0))
  273. {
  274. googleAnalyticsProfileId = siteSettings.GoogleAnalyticsAccountCode;
  275. }
  276. }
  277. }
  278. }