Markdown: display section link icon on hover

When hovering over a section header a link icon now appears in
the left margin. This link can be easily copied to reference the
section from another document or sent by IM or email.

Change-Id: If7af4fa1c17e30f2ea167a6f7ee8f2acdbbdb196
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/doc/DocServlet.java b/gitiles-servlet/src/main/java/com/google/gitiles/doc/DocServlet.java
index 076ee62..cd67d9c 100644
--- a/gitiles-servlet/src/main/java/com/google/gitiles/doc/DocServlet.java
+++ b/gitiles-servlet/src/main/java/com/google/gitiles/doc/DocServlet.java
@@ -67,7 +67,7 @@
   // Generation of ETag logic. Bump this only if DocServlet logic changes
   // significantly enough to impact cached pages. Soy template and source
   // files are automatically hashed as part of the ETag.
-  private static final int ETAG_GEN = 1;
+  private static final int ETAG_GEN = 2;
 
   public DocServlet(GitilesAccess.Factory accessFactory, Renderer renderer) {
     super(renderer, accessFactory);
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/doc/MarkdownToHtml.java b/gitiles-servlet/src/main/java/com/google/gitiles/doc/MarkdownToHtml.java
index 33cbdfa..4138f0a 100644
--- a/gitiles-servlet/src/main/java/com/google/gitiles/doc/MarkdownToHtml.java
+++ b/gitiles-servlet/src/main/java/com/google/gitiles/doc/MarkdownToHtml.java
@@ -178,19 +178,21 @@
 
   @Override
   public void visit(HeaderNode node) {
+    outputNamedAnchor = false;
+    String tag = "h" + node.getLevel();
+    html.open(tag);
     String id = toc.idFromHeader(node);
     if (id != null) {
-      html.open("a").attribute("name", id);
+      html.open("a")
+          .attribute("class", "h")
+          .attribute("name", id)
+          .attribute("href", "#" + id)
+          .open("span").close("span")
+          .close("a");
     }
-    try {
-      outputNamedAnchor = false;
-      wrapChildren("h" + node.getLevel(), node);
-    } finally {
-      outputNamedAnchor = true;
-    }
-    if (id != null) {
-      html.close("a");
-    }
+    visitChildren(node);
+    html.close(tag);
+    outputNamedAnchor = true;
   }
 
   @Override
diff --git a/gitiles-servlet/src/main/resources/com/google/gitiles/static/doc.css b/gitiles-servlet/src/main/resources/com/google/gitiles/static/doc.css
index c397424..672797c 100644
--- a/gitiles-servlet/src/main/resources/com/google/gitiles/static/doc.css
+++ b/gitiles-servlet/src/main/resources/com/google/gitiles/static/doc.css
@@ -169,6 +169,31 @@
 .doc a:visited { color: #7759ae; }
 .doc a:hover { text-decoration: underline; }
 
+.doc a.h {
+  display: inline-block;
+  font-weight: normal;
+  width: 1.5em;
+  margin-left: -1.5em;
+  margin-top: -1em;
+  margin-bottom: -1em;
+}
+.doc a.h:link,
+.doc a.h:visited { color: #444; }
+.doc a.h:focus { outline: none; }
+.doc a.h:hover { text-decoration: none; }
+.doc a.h span {
+  display: inline-block;
+  width: 1.5em;
+}
+.doc h1:hover a.h span:before,
+.doc h2:hover a.h span:before,
+.doc h3:hover a.h span:before,
+.doc h4:hover a.h span:before,
+.doc h5:hover a.h span:before,
+.doc h6:hover a.h span:before {
+  content: '\1f517'; /* Unicode 'LINK SYMBOL' */
+}
+
 .doc ul, .doc ol {
   margin: 10px 10px 10px 30px;
   padding: 0;