#167 JS development of hashchange-dependant tabbing mechanism, and of Rickshaw graphs with separate legends.
#167 JS development of hashchange-dependant tabbing mechanism, and of Rickshaw graphs with separate legends.

--- a/ckanext/ga_report/ga_model.py
+++ b/ckanext/ga_report/ga_model.py
@@ -214,7 +214,7 @@
                   'pageviews': views[key],
                   'visits': visits[key],
                   'department_id': publisher,
-                  'package_id': publisher
+                  'package_id': package
                   }
         model.Session.add(GA_Url(**values))
     model.Session.commit()
@@ -227,7 +227,7 @@
     stores them in GA_Url under the period and recalculates the totals for
     the 'All' period.
     '''
-    progress_total = len(progress_data)
+    progress_total = len(url_data)
     progress_count = 0
     for url, views, visits in url_data:
         progress_count += 1

--- a/ckanext/ga_report/helpers.py
+++ b/ckanext/ga_report/helpers.py
@@ -106,6 +106,10 @@
     for entry in entries:
         if len(datasets) < count:
             p = model.Package.get(entry.url[len('/dataset/'):])
+            if not p:
+                _log.warning("Could not find Package for {url}".format(url=entry.url))
+                continue
+
             if not p in datasets:
                 datasets[p] = {'views':0, 'visits': 0}
             datasets[p]['views'] = datasets[p]['views'] + int(entry.pageviews)

--- a/ckanext/ga_report/public/css/ga_report.css
+++ b/ckanext/ga_report/public/css/ga_report.css
@@ -16,16 +16,8 @@
   bottom: 0;
 }
 .rickshaw_legend {
-  position: absolute;
-  right: 0;
-  top: 0;
-  margin-left: 15px;
-  padding: 0 5px;
   background: transparent;
-  max-width: 150px;
-  overflow: hidden;
-  background: rgba(0,0,0,0.05);
-  border-radius:5px;
+  width: 100%;
 }
 .rickshaw_y_axis {
   position: absolute;

--- a/ckanext/ga_report/public/scripts/ckanext_ga_reports.js
+++ b/ckanext/ga_report/public/scripts/ckanext_ga_reports.js
@@ -3,6 +3,9 @@
 CKAN.GA_Reports = {};
 
 CKAN.GA_Reports.render_rickshaw = function( css_name, data, mode, colorscheme ) {
+    var graphLegends = $('#graph-legend-container');
+    var myLegend = $('<div id="legend_'+css_name+'"/>').appendTo(graphLegends);
+
     var palette = new Rickshaw.Color.Palette( { scheme: colorscheme } );
     $.each(data, function(i, object) {
         object['color'] = palette.color();
@@ -39,4 +42,73 @@
     graph.render();
 };
 
+CKAN.GA_Reports.bind_sparklines = function() {
+  /* 
+   * Bind to the 'totals' tab being on screen, when the 
+   * Sparkline graphs should be drawn.
+   * Note that they cannot be drawn sooner.
+   */
+  $('a[href="#totals"]').on(
+    'shown', 
+    function() {
+      var sparkOptions = {
+        enableTagOptions: true,
+        type: 'line',
+        width: 100,
+        height: 26,
+        chartRangeMin: 0,
+        spotColor: '',
+        maxSpotColor: '',
+        minSpotColor: '',
+        highlightSpotColor: '000000',
+        lineColor: '3F8E6D',
+        fillColor: 'B7E66B'
+      };
+      $('.sparkline').sparkline('html',sparkOptions);
+    }
+  );
+};
 
+CKAN.GA_Reports.bind_sidebar = function() {
+  /* 
+   * Bind to changes in the tab behaviour: 
+   * Show the correct rickshaw graph in the sidebar. 
+   * Not to be called before all graphs load.
+   */
+  $('a[data-toggle="hashchange"]').on(
+    'shown',
+    function(e) {
+      var href = $(e.target).attr('href');
+      var pane = $(href);
+      if (!pane.length) { console.err('bad href',href); return; }
+      var legend_name = "none";
+      var graph = pane.find('.rickshaw_chart');
+      if (graph.length) {
+        legend_name = graph.attr('id').replace('chart_','');
+      }
+      legend_name = '#legend_'+legend_name;
+      $('#graph-legend-container > *').hide();
+      $(legend_name).show();
+    }
+  );
+};
+
+/* 
+ * Custom bootstrap plugin for handling data-toggle="hashchange".
+ * Behaves like data-toggle="tab" but I respond to the hashchange.
+ * Page state is memo-ized in the URL this way. Why doesn't Bootstrap do this?
+ */
+$(function() {
+  var mapping = {};
+  $('a[data-toggle="hashchange"]').each(
+    function(i,link) {
+      link = $(link);
+      mapping[link.attr('href')] = link;
+    }
+  );
+  $(window).hashchange(function() {
+    var link = mapping[window.location.hash];
+    if (link) { link.tab('show'); }
+  });
+});
+

--- a/ckanext/ga_report/templates/ga_report/ga_util.html
+++ b/ckanext/ga_report/templates/ga_report/ga_util.html
@@ -34,7 +34,6 @@
   <div id="chart_container_$id" class="rickshaw_chart_container">
     <div id="y_axis_$id" class="rickshaw_y_axis"></div>
     <div id="chart_$id" class="rickshaw_chart"></div>
-    <div id="legend_$id" class="rickshaw_legend"></div>
     <script type="text/javascript">
       $(function() {
           CKAN.GA_Reports.render_rickshaw('$id', $items_json, '$mode', '$colorscheme');

--- a/ckanext/ga_report/templates/ga_report/notes.html
+++ b/ckanext/ga_report/templates/ga_report/notes.html
@@ -7,7 +7,7 @@
       <h4>Notes</h4>
       <ul>
           <li>"Views" is the number of times a page was loaded in users' browsers.</li>
-          <li>"Downloads" is the number of times a user has clicked to download either an original or cached resource for a particular dataset. Download information is only available from 2nd December 2012, 'No data' is shown for records before that date.</li>
+          <li>"Downloads" is the number of times a user has clicked to download either an original or cached resource for a particular dataset. Download information is only available from 2nd December 2012; 'No data' is shown for records before that date.</li>
           <li>These usage statistics are confined to users with javascript enabled, which excludes web crawlers and API calls.</li>
           <li>The results are not shown when the number of views/visits is tiny. Where these relate to site pages, results are available in full in the CSV download. Where these relate to users' web browser information, results are not disclosed, for privacy reasons.</li>
       </ul>

--- a/ckanext/ga_report/templates/ga_report/site/index.html
+++ b/ckanext/ga_report/templates/ga_report/site/index.html
@@ -24,6 +24,12 @@
           <a class="btn button btn-primary" href="${h.url_for(controller='ckanext.ga_report.controller:GaReport',action='csv',month=c.month or 'all')}">Download as CSV</a></center>
       </p>
     </li>
+    <li class="widget-container boxed widget_text">
+      <h4>Graph Legend</h4>
+      <div id="graph-legend-container">
+        <div id="legend_none">(No graph loaded)</div>
+      </div>
+    </li>
     <xi:include href="../notes.html" />
 
   </py:match>
@@ -43,38 +49,36 @@
 
     <div class="tabbable">
       <ul class="nav nav-tabs">
-        <li class="active"><a href="#totals" data-toggle="tab">Totals</a></li>
+        <li><a href="#totals" data-toggle="hashchange">Totals</a></li>
         <li class="dropdown">
-            <a href="#browsers" class="dropdown-toggle" data-toggle="dropdown">Browsers
+            <a href="#" class="dropdown-toggle" data-toggle="dropdown">Browsers
                 <b class="caret"></b></a>
             <ul class="dropdown-menu">
-                <li><a href="#browsers_names" data-toggle="tab">Browsers</a></li>
-                <li><a href="#browsers_versions" data-toggle="tab">Versions</a></li>
+                <li><a href="#browsers_names" data-toggle="hashchange">Browsers</a></li>
+                <li><a href="#browsers_versions" data-toggle="hashchange">Versions</a></li>
             </ul>
         </li>
         <li class="dropdown">
-            <a href="#browsers" class="dropdown-toggle" data-toggle="dropdown">Operating<br/>Systems
+            <a href="#" class="dropdown-toggle" data-toggle="dropdown">Operating Systems
                 <b class="caret"></b></a>
             <ul class="dropdown-menu">
-                <li><a href="#os" data-toggle="tab">Operating Systems</a></li>
-                <li><a href="#os_versions" data-toggle="tab">Versions</a></li>
+                <li><a href="#os" data-toggle="hashchange">Operating Systems</a></li>
+                <li><a href="#os_versions" data-toggle="hashchange">Versions</a></li>
             </ul>
         </li>
         <li class="dropdown">
-            <a href="#browsers" class="dropdown-toggle" data-toggle="dropdown">Social Networks
+            <a href="#" class="dropdown-toggle" data-toggle="dropdown">Social
                 <b class="caret"></b></a>
             <ul class="dropdown-menu">
-                <li><a href="#social_networks" data-toggle="tab">All networks</a></li>
-                <li><a href="#social_referrals_totals" data-toggle="tab">Referral links</a></li>
+                <li><a href="#social_networks" data-toggle="hashchange">All networks</a></li>
+                <li><a href="#social_referrals_totals" data-toggle="hashchange">Referral links</a></li>
             </ul>
         </li>
-
-        <li><a href="#social_networks" data-toggle="tab"></a></li>
-        <li><a href="#languages" data-toggle="tab">Languages</a></li>
-        <li><a href="#country" data-toggle="tab">Country</a></li>
+        <li><a href="#languages" data-toggle="hashchange">Languages</a></li>
+        <li><a href="#country" data-toggle="hashchange">Country</a></li>
       </ul>
       <div class="tab-content">
-        <div class="tab-pane active" id="totals">
+        <div class="tab-pane" id="totals">
              <table class="table table-condensed table-bordered table-striped">
             	 <tr>
             	   <th>Name</th>
@@ -136,20 +140,9 @@
   <py:def function="optional_footer">
     <script type="text/javascript">
       $(function() {
-          var sparkOptions = {
-            enableTagOptions: true,
-            type: 'line',
-            width: 100,
-            height: 26,
-            chartRangeMin: 0,
-            spotColor: '',
-            maxSpotColor: '',
-            minSpotColor: '',
-            highlightSpotColor: '000000',
-            lineColor: '3F8E6D',
-            fillColor: 'B7E66B'
-          };
-          $('.sparkline').sparkline('html',sparkOptions);
+        CKAN.GA_Reports.bind_sparklines();
+        CKAN.GA_Reports.bind_sidebar();
+        $(window).trigger('hashchange');
       });  
     </script>
   </py:def>