00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00018
00047
00048 #ifndef NET_INSTAWEB_REWRITER_PUBLIC_GOOGLE_ANALYTICS_FILTER_H_
00049 #define NET_INSTAWEB_REWRITER_PUBLIC_GOOGLE_ANALYTICS_FILTER_H_
00050
00051 #include <vector>
00052
00053 #include "base/scoped_ptr.h"
00054 #include "net/instaweb/htmlparse/public/empty_html_filter.h"
00055 #include "net/instaweb/htmlparse/public/html_parser_types.h"
00056 #include "net/instaweb/util/public/basictypes.h"
00057 #include "net/instaweb/util/public/string.h"
00058 #include "net/instaweb/util/public/string_util.h"
00059
00060 namespace net_instaweb {
00061 class HtmlCdataNode;
00062 class HtmlCharactersNode;
00063 class HtmlCommentNode;
00064 class HtmlElement;
00065 class HtmlIEDirectiveNode;
00066 class HtmlParse;
00067 class Statistics;
00068 class Variable;
00069
00070
00072 class ScriptEditor {
00073 public:
00074 enum Type {
00075 kGaJsScriptSrcLoad = 0,
00076 kGaJsDocWriteLoad,
00077 kGaJsInit,
00078 };
00079 ScriptEditor(HtmlElement* script_element_,
00080 HtmlCharactersNode* characters_node,
00081 GoogleString::size_type pos,
00082 GoogleString::size_type len,
00083 Type editor_type);
00084
00085 HtmlElement* GetScriptElement() const { return script_element_; }
00086 HtmlCharactersNode* GetScriptCharactersNode() const {
00087 return script_characters_node_;
00088 }
00089 Type GetType() const { return editor_type_; }
00090
00091 void NewContents(const StringPiece &replacement,
00092 GoogleString* contents) const;
00093
00094 private:
00095 HtmlElement* script_element_;
00096 HtmlCharactersNode* script_characters_node_;
00097
00098 GoogleString::size_type pos_;
00099 GoogleString::size_type len_;
00100
00101 Type editor_type_;
00102 DISALLOW_COPY_AND_ASSIGN(ScriptEditor);
00103 };
00104
00105
00108 class GoogleAnalyticsFilter : public EmptyHtmlFilter {
00109 public:
00110 typedef StringPieceVector MethodVector;
00111
00112 explicit GoogleAnalyticsFilter(HtmlParse* html_parse,
00113 Statistics* statistics);
00114 virtual ~GoogleAnalyticsFilter();
00115
00117 explicit GoogleAnalyticsFilter(HtmlParse* html_parse,
00118 Statistics* statistics,
00119 MethodVector* glue_methods,
00120 MethodVector* unhandled_methods);
00121
00122 static void Initialize(Statistics* statistics);
00123
00124 virtual void StartDocument();
00125 virtual void EndDocument();
00126 virtual void StartElement(HtmlElement* element);
00127 virtual void EndElement(HtmlElement* element);
00128
00129 virtual void Flush();
00130
00132 virtual void Characters(HtmlCharactersNode* characters_node);
00133
00135 virtual void Comment(HtmlCommentNode* comment);
00136 virtual void Cdata(HtmlCdataNode* cdata);
00137 virtual void IEDirective(HtmlIEDirectiveNode* directive);
00138
00139 virtual const char* Name() const { return "GoogleAnalytics"; }
00140
00141 static const char kPageLoadCount[];
00142 static const char kRewrittenCount[];
00143
00144 private:
00145 void ResetFilter();
00146
00147 bool MatchSyncLoad(StringPiece contents,
00148 GoogleString::size_type &pos,
00149 GoogleString::size_type &len) const;
00150 bool MatchSyncInit(StringPiece contents,
00151 GoogleString::size_type start_pos,
00152 GoogleString::size_type &pos,
00153 GoogleString::size_type &len) const;
00154 bool MatchUnhandledCalls(StringPiece contents,
00155 GoogleString::size_type start_pos) const;
00156 void FindRewritableScripts();
00157 void GetSyncToAsyncScript(GoogleString *buffer) const;
00158 bool RewriteAsAsync();
00159
00160 bool is_load_found_;
00161 bool is_init_found_;
00162 std::vector<ScriptEditor*> script_editors_;
00163
00164 scoped_ptr<MethodVector> glue_methods_;
00165 scoped_ptr<MethodVector> unhandled_methods_;
00166
00167 HtmlParse* html_parse_;
00168 HtmlElement* script_element_;
00169 HtmlCharactersNode* script_characters_node_;
00170
00171 Variable* page_load_count_;
00172 Variable* rewritten_count_;
00173
00174 DISALLOW_COPY_AND_ASSIGN(GoogleAnalyticsFilter);
00175 };
00176
00177 }
00178
00179 #endif ///< NET_INSTAWEB_REWRITER_PUBLIC_GOOGLE_ANALYTICS_FILTER_H_