Author: jkoster Date: 2010-07-15 11:59:30 +0200 (Thu, 15 Jul 2010) New Revision: 42899
Added: CMSContainer/trunk/CMSContainer/migration/migration_1.8.3_to_1.8.4.txt Modified: CMSContainer/trunk/CMSContainer/cmsc/taglib/src/java/com/finalist/cmsc/taglib/stats/GoogleAnalyticsTag.java CMSContainer/trunk/CMSContainer/cmsc/taglib/src/tld/cmsc.tld Log: CMSC-1704 - Update Google Analytics code to latest version; use Asynchronous tracking. Also added force-attribute for testing. Modified: CMSContainer/trunk/CMSContainer/cmsc/taglib/src/java/com/finalist/cmsc/taglib/stats/GoogleAnalyticsTag.java =================================================================== --- CMSContainer/trunk/CMSContainer/cmsc/taglib/src/java/com/finalist/cmsc/taglib/stats/GoogleAnalyticsTag.java 2010-07-15 09:37:14 UTC (rev 42898) +++ CMSContainer/trunk/CMSContainer/cmsc/taglib/src/java/com/finalist/cmsc/taglib/stats/GoogleAnalyticsTag.java 2010-07-15 09:59:30 UTC (rev 42899) @@ -38,6 +38,7 @@ private final static String TYPE_SCRIPT = "script"; // init script private final static String TYPE_PAGE_COUNTER = "pagecounter"; // page counter code private final static String TYPE_EVENT = "event"; // event code, category and action are required + private static boolean isLiveProduction; private String accountParameter; private String categoryParameter; @@ -46,115 +47,136 @@ private String labelParameter; private String valueParameter; private String typeParameter = TYPE_BASIC; + private boolean force; //testing purposes + private static String contextAccount; static { InitialContext context; try { + isLiveProduction = (ServerUtil.isProduction() && (ServerUtil.isLive() || ServerUtil.isSingle())); + context = new InitialContext(); Context env = (Context) context.lookup("java:comp/env"); contextAccount = (String) env.lookup("googleAnalytics/account"); } catch (NamingException e) { - log.info("No default account found in the context. Provide account information as attribute."); + log.info("No default Google Analytics account found in the context. Provide account information as attribute."); } } @Override public void doTag() throws IOException { - /* - * Find out where to get our account from, search order: + * Find out where to get the Google Analytics account from, search order: * 1) The "account"-parameter passed to the tag (only when available, live and production) - * 2) The "googleAnalytics/account" setting in the context XML (only when available, one of the two prefered methods) + * 2) The "googleAnalytics/account" setting in the context XML (only when available, one of the two preferred methods) * 3) The "googleanalytics.account" system property, from the system properties (only when available, live and production) - * 4) The googleanaliticsId field of the site (only when available, the other prefered method) + * 4) The googleanalyticsId field of the site (only when available, the other preferred method) */ String account = null; - boolean isLiveProduction = (ServerUtil.isProduction() && (ServerUtil.isLive() || ServerUtil.isSingle())); + String parameterAccount = PropertiesUtil.getProperty("googleanalytics.account"); - if (StringUtils.isNotBlank(accountParameter) && isLiveProduction) { + if (force) { + if (ServerUtil.isProduction()) { + log.error("Google Analytics tag: the 'force' attribute should NOT be used in production environments!"); + } + } + + if (StringUtils.isNotBlank(accountParameter) && (isLiveProduction || force)) { account = accountParameter; } else if (StringUtils.isNotBlank(contextAccount)) { account = contextAccount; - } else if (StringUtils.isNotBlank(parameterAccount) && isLiveProduction) { + } else if (StringUtils.isNotBlank(parameterAccount) && (isLiveProduction || force)) { account = parameterAccount; - } else if (isLiveProduction) { + } else if (isLiveProduction || force) { Site site = SiteManagement.getSiteFromPath(getPath()); account = site.getGoogleanalyticsid(); } - // Include the google analytics code + // Include the Google Analytics code if (StringUtils.isNotBlank(account)) { + + PageContext ctx = (PageContext) getJspContext(); + final String domain = ctx.getRequest().getServerName(); StringBuilder javascript = new StringBuilder(); if (typeParameter.equals(TYPE_BASIC)) { + appendPageCounter(javascript, account, domain); appendGAScript(javascript); - appendPageCounter(javascript, account); } if (typeParameter.equals(TYPE_SCRIPT)) { appendGAScript(javascript); } if (typeParameter.equals(TYPE_PAGE_COUNTER)) { - appendPageCounter(javascript, account); + appendPageCounter(javascript, account, domain); } - if (typeParameter.equals(TYPE_EVENT)) { - javascript.append("<script type=\"text/javascript\">"); - if (StringUtils.isNotBlank(nodeNumberParameter)) { - actionParameter = getActionFromNodeNumber(nodeNumberParameter); - } - - if (StringUtils.isBlank(categoryParameter) - || StringUtils.isBlank(actionParameter)) { - throw new IllegalArgumentException( - "Both category and (action or nodeNumber) parameters are required when using type " - + TYPE_EVENT); - } - javascript.append("pageTracker._trackEvent('"); - javascript.append(escapeParameter(categoryParameter)); - javascript.append("','"); - javascript.append(escapeParameter(actionParameter)); - if (StringUtils.isNotBlank(labelParameter)) { - javascript.append("','"); - javascript.append(escapeParameter(labelParameter)); - if (StringUtils.isNotBlank(valueParameter)) { - javascript.append("','"); - javascript.append(valueParameter); - } - } - javascript.append("');\r\n"); - javascript.append("</script>\r\n"); + appendTrackEvents(javascript); } - - PageContext ctx = (PageContext) getJspContext(); + ctx.getOut().write(javascript.toString()); } } private void appendGAScript(StringBuilder javascript) { - javascript.append("<script type=\"text/javascript\">\r\n"); - javascript.append("var gaJsHost = ((\"https:\" == document.location.protocol) ? \"https://ssl.\" : \"http://www.\");\r\n"); - javascript.append("document.write(unescape(\"%3Cscript src='\" + gaJsHost + \"google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E\"));\r\n"); + if (! typeParameter.equals(TYPE_BASIC)) { + javascript.append("<script type=\"text/javascript\">\r\n"); + } + javascript.append("try{\r\n" + + " (function() {\r\n" + + " var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;\r\n" + + " ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';\r\n" + + " var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);\r\n" + + " })();\r\n" + + "} catch(err) {}\r\n"); javascript.append("</script>\r\n"); } - private void appendPageCounter(StringBuilder javascript, String account) { - PageContext ctx = (PageContext) getJspContext(); - String domain = ctx.getRequest().getServerName(); + private void appendPageCounter(StringBuilder javascript, final String account, final String domain) { + javascript.append("<script type=\"text/javascript\">\r\n"); - javascript.append("<script type=\"text/javascript\">\r\n"); - javascript.append("try{\r\n"); - javascript.append("var pageTracker = _gat._getTracker(\"").append(account).append("\");\r\n"); // Workaround for http://support.microsoft.com/kb/310676 - // Internet Explorer does not set a cookie for two-letter domains like 12.nl - javascript.append("pageTracker._setDomainName(\"").append(domain).append("\");\r\n"); - javascript.append("pageTracker._trackPageview();\r\n"); - javascript.append("} catch(err) {}\r\n"); + // Internet Explorer 6 does not set a cookie for two-letter domains like 12.nl + + javascript.append("var _gaq = _gaq || [];\r\n" + + "_gaq.push(['_setAccount', '").append(account).append("'],\r\n" + + " ['_setDomainName', '").append(domain).append("'],\r\n" + + " ['_trackPageview']);\r\n"); + if (! typeParameter.equals(TYPE_BASIC)) { + javascript.append("</script>\r\n"); + } + } + + private void appendTrackEvents(StringBuilder javascript) { + javascript.append("<script type=\"text/javascript\">"); + if (StringUtils.isNotBlank(nodeNumberParameter)) { + actionParameter = getActionFromNodeNumber(nodeNumberParameter); + } + + if (StringUtils.isBlank(categoryParameter) + || StringUtils.isBlank(actionParameter)) { + throw new IllegalArgumentException( + "Both category and (action or nodeNumber) parameters are required when using type " + + TYPE_EVENT); + } + javascript.append("_gaq.push(['_trackEvent', '"); + javascript.append(escapeParameter(categoryParameter)); + javascript.append("', '"); + javascript.append(escapeParameter(actionParameter)+"'"); + if (StringUtils.isNotBlank(labelParameter)) { + javascript.append(", '"); + javascript.append(escapeParameter(labelParameter) + "'"); + if (StringUtils.isNotBlank(valueParameter)) { + javascript.append(", " + valueParameter); + } + } + javascript.append("]);\r\n"); javascript.append("</script>\r\n"); } + private String escapeParameter(String parameter) { return parameter.replace("'", "\\'"); } @@ -199,7 +221,7 @@ } else { throw new IllegalArgumentException( "type parameter should be empty, \"" + TYPE_BASIC - + "\", \"" + TYPE_EVENT + "\""); + + "\", or \"" + TYPE_EVENT + "\""); } } @@ -222,5 +244,32 @@ public void setValue(String valueParameter) { this.valueParameter = valueParameter; } + + public void setForce(boolean force) { + this.force = force; + } + public boolean isForce() { + return force; + } + + /* For testing purposes only + public static void main(String args[]) { + GoogleAnalyticsTag gat = new GoogleAnalyticsTag(); + GoogleAnalyticsTag.contextAccount = "UA-17606XX-1"; + + StringBuilder javascript = new StringBuilder(); + String domain = "www.cmscontainer.org"; + gat.categoryParameter ="content"; + gat.actionParameter = "action"; + + gat.appendPageCounter(javascript,contextAccount,domain); + gat.appendGAScript(javascript); + + gat.appendTrackEvents(javascript); + + System.out.println(javascript.toString()); + } + */ + } Modified: CMSContainer/trunk/CMSContainer/cmsc/taglib/src/tld/cmsc.tld =================================================================== --- CMSContainer/trunk/CMSContainer/cmsc/taglib/src/tld/cmsc.tld 2010-07-15 09:37:14 UTC (rev 42898) +++ CMSContainer/trunk/CMSContainer/cmsc/taglib/src/tld/cmsc.tld 2010-07-15 09:59:30 UTC (rev 42899) @@ -1562,10 +1562,10 @@ Meant to put in the body of a page, please note that if you want to use events, there has to be a normal tag first. Search order of the google analytics account used: - * 1) The "account"-parameter passed to the tag (only when available, live and production) - * 2) The "googleAnalytics/account" setting in the context XML (only when available, one of the two prefered methods) - * 3) The "googleanalytics.account" system property, from the system properties (only when available, live and production) - * 4) The googleanaliticsId field of the site (only when available, the other prefered method) + * 1) The "account"-parameter passed to the tag (only when available, live and production) + * 2) The "googleAnalytics/account" setting in the context XML (only when available, one of the two preferred methods) + * 3) The "googleanalytics.account" system property, from the system properties (only when available, live and production) + * 4) The googleanalyticsId field of the site (only when available, the other preferred method) </description> <name>google-analytics</name> <tag-class>com.finalist.cmsc.taglib.stats.GoogleAnalyticsTag</tag-class> @@ -1614,6 +1614,12 @@ <required>false</required> <rtexprvalue>true</rtexprvalue> </attribute> + <attribute> + <description>Forces output for testing purposes, while not in production and not live.</description> + <name>force</name> + <required>false</required> + <rtexprvalue>false</rtexprvalue> + </attribute> </tag> <!-- ################ --> Added: CMSContainer/trunk/CMSContainer/migration/migration_1.8.3_to_1.8.4.txt =================================================================== --- CMSContainer/trunk/CMSContainer/migration/migration_1.8.3_to_1.8.4.txt (rev 0) +++ CMSContainer/trunk/CMSContainer/migration/migration_1.8.3_to_1.8.4.txt 2010-07-15 09:59:30 UTC (rev 42899) @@ -0,0 +1,25 @@ +Migration document: + +Part: core +From version: 1.8.3 +To version: 1.8.4 + +Name: Upgrade to use the new Google Analytics tag. +Goal: upgrade tag usage location +Type: manual action +--- Start script --- +Note: the new Google Analytics tag uses the Asynchronous Snippet. +http://code.google.com/apis/analytics/docs/tracking/asyncTracking.html +Therefore, the normal usage of the tag needs to be started in the <head> instead +of in the body! + +Action +- search for google-analytics in all client JSPs (layouts) and move the tag location to inside the head. + +New +- the attribute 'force' is added for testing purposes. Usage: force="true". + +--- End script --- + + + _______________________________________________ Cvs mailing list Cvs@lists.mmbase.org http://lists.mmbase.org/mailman/listinfo/cvs