[release-branch.go1.7] godoc: allow nested toggles and toggles with <a name>

Toggles can now be nested within one another. They can also be
referenced using an <a> element with the name attribute, rather than
an element with the "id" attribute.

Updates golang/go#17574.

Change-Id: I43c17499a6879e983a79a74e14c99128296288e1
Reviewed-on: https://go-review.googlesource.com/34825
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-on: https://go-review.googlesource.com/35094
Reviewed-by: Chris Broadfoot <cbro@golang.org>
diff --git a/godoc/static/godocs.js b/godoc/static/godocs.js
index 10183cb..4f2ce2c 100644
--- a/godoc/static/godocs.js
+++ b/godoc/static/godocs.js
@@ -113,6 +113,11 @@
 
 function bindToggle(el) {
   $('.toggleButton', el).click(function() {
+    if ($(this).closest(".toggle, .toggleVisible")[0] != el) {
+      // Only trigger the closest toggle header.
+      return;
+    }
+
     if ($(el).is('.toggle')) {
       $(el).addClass('toggleVisible').removeClass('toggle');
     } else {
@@ -120,6 +125,7 @@
     }
   });
 }
+
 function bindToggles(selector) {
   $(selector).each(function(i, el) {
     bindToggle(el);
@@ -239,10 +245,17 @@
 }
 
 function toggleHash() {
-    var hash = $(window.location.hash);
-    if (hash.is('.toggle')) {
-      hash.find('.toggleButton').first().click();
+  // Open all of the toggles for a particular hash.
+  var els = $(window.location.hash + ", a[name='" + window.location.hash.substring(1) + "']");
+  while (els.length) {
+    for (var i = 0; i < els.length; i++) {
+      var el = $(els[i]);
+      if (el.is('.toggle')) {
+        el.find('.toggleButton').first().click();
+      }
     }
+    els = el.parent();
+  }
 }
 
 function personalizeInstallInstructions() {
diff --git a/godoc/static/static.go b/godoc/static/static.go
index 923270a..0130f4e 100644
--- a/godoc/static/static.go
+++ b/godoc/static/static.go
@@ -683,6 +683,11 @@
 
 function bindToggle(el) {
   $('.toggleButton', el).click(function() {
+    if ($(this).closest(".toggle, .toggleVisible")[0] != el) {
+      // Only trigger the closest toggle header.
+      return;
+    }
+
     if ($(el).is('.toggle')) {
       $(el).addClass('toggleVisible').removeClass('toggle');
     } else {
@@ -690,6 +695,7 @@
     }
   });
 }
+
 function bindToggles(selector) {
   $(selector).each(function(i, el) {
     bindToggle(el);
@@ -809,10 +815,17 @@
 }
 
 function toggleHash() {
-    var hash = $(window.location.hash);
-    if (hash.is('.toggle')) {
-      hash.find('.toggleButton').first().click();
+  // Open all of the toggles for a particular hash.
+  var els = $(window.location.hash + ", a[name='" + window.location.hash.substring(1) + "']");
+  while (els.length) {
+    for (var i = 0; i < els.length; i++) {
+      var el = $(els[i]);
+      if (el.is('.toggle')) {
+        el.find('.toggleButton').first().click();
+      }
     }
+    els = el.parent();
+  }
 }
 
 function personalizeInstallInstructions() {
@@ -3248,10 +3261,10 @@
 }
 
 .toggleButton { cursor: pointer; }
-.toggle .collapsed { display: block; }
-.toggle .expanded { display: none; }
-.toggleVisible .collapsed { display: none; }
-.toggleVisible .expanded { display: block; }
+.toggle > .collapsed { display: block; }
+.toggle > .expanded { display: none; }
+.toggleVisible > .collapsed { display: none; }
+.toggleVisible > .expanded { display: block; }
 
 table.codetable { margin-left: auto; margin-right: auto; border-style: none; }
 table.codetable td { padding-right: 10px; }
diff --git a/godoc/static/style.css b/godoc/static/style.css
index fd26bd8..95690eb 100644
--- a/godoc/static/style.css
+++ b/godoc/static/style.css
@@ -445,10 +445,10 @@
 }
 
 .toggleButton { cursor: pointer; }
-.toggle .collapsed { display: block; }
-.toggle .expanded { display: none; }
-.toggleVisible .collapsed { display: none; }
-.toggleVisible .expanded { display: block; }
+.toggle > .collapsed { display: block; }
+.toggle > .expanded { display: none; }
+.toggleVisible > .collapsed { display: none; }
+.toggleVisible > .expanded { display: block; }
 
 table.codetable { margin-left: auto; margin-right: auto; border-style: none; }
 table.codetable td { padding-right: 10px; }