[329] Rebase hashchange tab code on core plugin developed for ticket 329.
[329] Rebase hashchange tab code on core plugin developed for ticket 329.

.table-condensed td.sparkline-cell { .table-condensed td.sparkline-cell {
padding: 1px 0 0 0; padding: 1px 0 0 0;
width: 108px; width: 108px;
text-align: center; text-align: center;
} }
.rickshaw_chart_container { .rickshaw_chart_container {
position: relative; position: relative;
height: 350px; height: 350px;
margin: 0 auto 20px auto; margin: 0 auto 20px auto;
} }
.rickshaw_chart { .rickshaw_chart {
position: absolute; position: absolute;
left: 40px; left: 40px;
width: 500px; width: 500px;
top: 0; top: 0;
bottom: 0; bottom: 0;
} }
.rickshaw_legend { .rickshaw_legend {
background: transparent; background: transparent;
width: 100%; width: 100%;
  padding-top: 4px;
} }
.rickshaw_y_axis { .rickshaw_y_axis {
position: absolute; position: absolute;
top: 0; top: 0;
bottom: 0; bottom: 0;
width: 40px; width: 40px;
} }
.rickshaw_legend .label { .rickshaw_legend .label {
background: transparent !important; background: transparent !important;
color: #000000 !important; color: #000000 !important;
font-weight: normal !important; font-weight: normal !important;
  }
  .rickshaw_legend .instructions {
  color: #000;
  margin-bottom: 6px;
} }
   
.rickshaw_legend .line .action { .rickshaw_legend .line .action {
display: none; display: none;
} }
.rickshaw_legend .line .swatch { .rickshaw_legend .line .swatch {
display: block; display: block;
float: left; float: left;
} }
.rickshaw_legend .line .label { .rickshaw_legend .line .label {
display: block; display: block;
white-space: normal; white-space: normal;
float: left; float: left;
width: 200px; width: 200px;
} }
  .rickshaw_legend .line .label:hover {
  text-decoration: underline;
  }
   
.ga-reports-table .td-numeric { .ga-reports-table .td-numeric {
text-align: center; text-align: center;
} }
   
var CKAN = CKAN || {}; var CKAN = CKAN || {};
CKAN.GA_Reports = {}; CKAN.GA_Reports = {};
   
CKAN.GA_Reports.render_rickshaw = function( css_name, data, mode, colorscheme ) { CKAN.GA_Reports.render_rickshaw = function( css_name, data, mode, colorscheme ) {
var graphLegends = $('#graph-legend-container'); var graphLegends = $('#graph-legend-container');
   
if (!Modernizr.svg) { if (!Modernizr.svg) {
$("#chart_"+css_name) $("#chart_"+css_name)
.html( '<div class="alert">Your browser does not support vector graphics. No graphs can be rendered.</div>') .html( '<div class="alert">Your browser does not support vector graphics. No graphs can be rendered.</div>')
.closest('.rickshaw_chart_container').css('height',50); .closest('.rickshaw_chart_container').css('height',50);
var myLegend = $('<div id="legend_'+css_name+'"/>') var myLegend = $('<div id="legend_'+css_name+'"/>')
.html('(Graph cannot be rendered)') .html('(Graph cannot be rendered)')
.appendTo(graphLegends); .appendTo(graphLegends);
return; return;
} }
var myLegend = $('<div id="legend_'+css_name+'"/>').appendTo(graphLegends); var myLegend = $('<div id="legend_'+css_name+'"/>').appendTo(graphLegends);
   
var palette = new Rickshaw.Color.Palette( { scheme: colorscheme } ); var palette = new Rickshaw.Color.Palette( { scheme: colorscheme } );
$.each(data, function(i, object) { $.each(data, function(i, object) {
object['color'] = palette.color(); object['color'] = palette.color();
}); });
// Rickshaw renders the legend in reverse order... // Rickshaw renders the legend in reverse order...
data.reverse(); data.reverse();
   
var graphElement = document.querySelector("#chart_"+css_name); var graphElement = document.querySelector("#chart_"+css_name);
   
var graph = new Rickshaw.Graph( { var graph = new Rickshaw.Graph( {
element: document.querySelector("#chart_"+css_name), element: document.querySelector("#chart_"+css_name),
renderer: mode, renderer: mode,
series: data , series: data ,
height: 328 height: 328
}); });
var x_axis = new Rickshaw.Graph.Axis.Time( { graph: graph } ); var x_axis = new Rickshaw.Graph.Axis.Time( { graph: graph } );
var y_axis = new Rickshaw.Graph.Axis.Y( { var y_axis = new Rickshaw.Graph.Axis.Y( {
graph: graph, graph: graph,
orientation: 'left', orientation: 'left',
tickFormat: Rickshaw.Fixtures.Number.formatKMBT, tickFormat: Rickshaw.Fixtures.Number.formatKMBT,
element: document.getElementById('y_axis_'+css_name) element: document.getElementById('y_axis_'+css_name)
} ); } );
var legend = new Rickshaw.Graph.Legend( { var legend = new Rickshaw.Graph.Legend( {
element: document.querySelector('#legend_'+css_name), element: document.querySelector('#legend_'+css_name),
graph: graph graph: graph
} ); } );
var shelving = new Rickshaw.Graph.Behavior.Series.Toggle( { var shelving = new Rickshaw.Graph.Behavior.Series.Toggle( {
graph: graph, graph: graph,
legend: legend legend: legend
} ); } );
  myLegend.prepend('<div class="instructions">Click on a series below to isolate its graph:</div>');
graph.render(); graph.render();
}; };
   
CKAN.GA_Reports.bind_sparklines = function() { CKAN.GA_Reports.bind_sparklines = function() {
/* /*
* Bind to the 'totals' tab being on screen, when the * Bind to the 'totals' tab being on screen, when the
* Sparkline graphs should be drawn. * Sparkline graphs should be drawn.
* Note that they cannot be drawn sooner. * Note that they cannot be drawn sooner.
*/ */
  var created = false;
$('a[href="#totals"]').on( $('a[href="#totals"]').on(
'shown', 'shown',
function() { function() {
var sparkOptions = { if (!created) {
enableTagOptions: true, var sparkOptions = {
type: 'line', enableTagOptions: true,
width: 100, type: 'line',
height: 26, width: 100,
chartRangeMin: 0, height: 26,
spotColor: '', chartRangeMin: 0,
maxSpotColor: '', spotColor: '',
minSpotColor: '', maxSpotColor: '',
highlightSpotColor: '000000', minSpotColor: '',
lineColor: '3F8E6D', highlightSpotColor: '#000000',
fillColor: 'B7E66B' lineColor: '#3F8E6D',
}; fillColor: '#B7E66B'
$('.sparkline').sparkline('html',sparkOptions); };
} $('.sparkline').sparkline('html',sparkOptions);
  created = true;
  }
  $.sparkline_display_visible();
  }
); );
}; };
   
CKAN.GA_Reports.bind_sidebar = function() { CKAN.GA_Reports.bind_sidebar = function() {
/* /*
* Bind to changes in the tab behaviour: * Bind to changes in the tab behaviour:
* Show the correct rickshaw graph in the sidebar. * Show the correct rickshaw graph in the sidebar.
* Not to be called before all graphs load. * Not to be called before all graphs load.
*/ */
$('a[data-toggle="hashchange"]').on( $('a[data-toggle="hashtab"]').on(
'shown', 'shown',
function(e) { function(e) {
var href = $(e.target).attr('href'); var href = $(e.target).attr('href');
var pane = $(href); var pane = $(href);
if (!pane.length) { console.err('bad href',href); return; } if (!pane.length) { console.err('bad href',href); return; }
var legend_name = "none"; var legend_name = "none";
var graph = pane.find('.rickshaw_chart'); var graph = pane.find('.rickshaw_chart');
if (graph.length) { if (graph.length) {
legend_name = graph.attr('id').replace('chart_',''); legend_name = graph.attr('id').replace('chart_','');
} }
legend_name = '#legend_'+legend_name; legend_name = '#legend_'+legend_name;
$('#graph-legend-container > *').hide(); $('#graph-legend-container > *').hide();
  $('#graph-legend-container .instructions').show();
$(legend_name).show(); $(legend_name).show();
} }
); );
  /* The first tab might already have been shown */
  $('li.active > a[data-toggle="hashtab"]').trigger('shown');
}; };
   
CKAN.GA_Reports.bind_month_selector = function() { CKAN.GA_Reports.bind_month_selector = function() {
var handler = function(e) { var handler = function(e) {
var target = $(e.delegateTarget); var target = $(e.delegateTarget);
var form = target.closest('form'); var form = target.closest('form');
var url = form.attr('action')+'?month='+target.val()+window.location.hash; var url = form.attr('action')+'?month='+target.val()+window.location.hash;
window.location = url; window.location = url;
}; };
var selectors = $('select[name="month"]'); var selectors = $('select[name="month"]');
assert(selectors.length>0); assert(selectors.length>0);
selectors.bind('change', handler); selectors.bind('change', handler);
}; };
   
/*  
* 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'); }  
});  
});  
   
<html xmlns:py="http://genshi.edgewall.org/" <html xmlns:py="http://genshi.edgewall.org/"
xmlns:i18n="http://genshi.edgewall.org/i18n" xmlns:i18n="http://genshi.edgewall.org/i18n"
xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xi="http://www.w3.org/2001/XInclude"
py:strip=""> py:strip="">
   
<xi:include href="../ga_util.html" /> <xi:include href="../ga_util.html" />
   
<py:def function="page_title">Usage by Publisher</py:def> <py:def function="page_title">Usage by Publisher</py:def>
   
<py:match path="primarysidebar"> <py:match path="primarysidebar">
<li class="widget-container boxed widget_text"> <li class="widget-container boxed widget_text">
<h4>Download</h4> <h4>Download</h4>
<p><center> <p><center>
<a class="btn button btn-primary" href="${h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport',action='publisher_csv',month=c.month or 'all')}">Download as CSV</a></center> <a class="btn button btn-primary" href="${h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport',action='publisher_csv',month=c.month or 'all')}">Download as CSV</a></center>
</p> </p>
</li> </li>
<li class="widget-container boxed widget_text"> <li class="widget-container boxed widget_text">
<h4>Graph Legend</h4> <h4>Graph Legend</h4>
<div id="graph-legend-container"> <div id="graph-legend-container">
</div> </div>
</li> </li>
<xi:include href="../notes.html" /> <xi:include href="../notes.html" />
</py:match> </py:match>
   
<py:def function="optional_head"> <py:def function="optional_head">
<link rel="stylesheet" type="text/css" href="/scripts/vendor/rickshaw.min.css"/> <link rel="stylesheet" type="text/css" href="/scripts/vendor/rickshaw.min.css"/>
<link rel="stylesheet" type="text/css" href="/css/ga_report.css"/> <link rel="stylesheet" type="text/css" href="/css/ga_report.css?1"/>
<script type="text/javascript" src="/scripts/ckanext_ga_reports.js"></script> <script type="text/javascript" src="/scripts/ckanext_ga_reports.js?1"></script>
<script type="text/javascript" src="/scripts/vendor/jquery.sparkline.modified.js"></script> <script type="text/javascript" src="/scripts/vendor/jquery.sparkline.modified.js"></script>
<script type="text/javascript" src="/scripts/rickshaw_ie7_shim.js"></script> <script type="text/javascript" src="/scripts/rickshaw_ie7_shim.js"></script>
<script type="text/javascript" src="/scripts/vendor/d3.v2.js"></script> <script type="text/javascript" src="/scripts/vendor/d3.v2.js"></script>
<script type="text/javascript" src="/scripts/vendor/d3.layout.min.js"></script> <script type="text/javascript" src="/scripts/vendor/d3.layout.min.js"></script>
<script type="text/javascript" src="/scripts/vendor/rickshaw.min.js"></script> <script type="text/javascript" src="/scripts/vendor/rickshaw.min.js"></script>
</py:def> </py:def>
   
<div py:match="content"> <div py:match="content">
   
<h1>Site Usage</h1> <h1>Site Usage</h1>
   
${usage_nav('Publishers')} ${usage_nav('Publishers')}
   
   
${rickshaw_graph(c.top_publishers_graph,'publishers')} ${rickshaw_graph(c.top_publishers_graph,'publishers')}
<form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport',action='publishers')}" method="get"> <form class="form-inline" action="${h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport',action='publishers')}" method="get">
<div class="controls"> <div class="controls">
<label>Show stats table for:</label> <label>Show stats table for:</label>
${month_selector(c.month, c.months, c.day)} ${month_selector(c.month, c.months, c.day)}
</div> </div>
</form> </form>
   
<table class="ga-reports-table table table-condensed table-bordered table-striped"> <table class="ga-reports-table table table-condensed table-bordered table-striped">
<tr> <tr>
<th>Publisher</th> <th>Publisher</th>
<th class="td-numeric">Dataset Views</th> <th class="td-numeric">Dataset Views</th>
</tr> </tr>
<py:for each="publisher, views, visits in c.top_publishers"> <py:for each="publisher, views, visits in c.top_publishers">
<tr> <tr>
<td> <td>
${h.link_to(publisher.title, h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport', action='read_publisher', id=publisher.name) + (("?month=" + c.month) if c.month else ''))} ${h.link_to(publisher.title, h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport', action='read_publisher', id=publisher.name) + (("?month=" + c.month) if c.month else ''))}
</td> </td>
<td class="td-numeric">${views}</td> <td class="td-numeric">${views}</td>
</tr> </tr>
</py:for> </py:for>
</table> </table>
   
   
</div> </div>
   
<py:def function="optional_footer"> <py:def function="optional_footer">
<script type="text/javascript"> <script type="text/javascript">
$(function() { $(function() {
CKAN.GA_Reports.bind_month_selector(); CKAN.GA_Reports.bind_month_selector();
}); });
</script> </script>
</py:def> </py:def>
<xi:include href="../../layout.html" /> <xi:include href="../../layout.html" />
   
</html> </html>
   
   
<html xmlns:py="http://genshi.edgewall.org/" <html xmlns:py="http://genshi.edgewall.org/"
xmlns:i18n="http://genshi.edgewall.org/i18n" xmlns:i18n="http://genshi.edgewall.org/i18n"
xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xi="http://www.w3.org/2001/XInclude"
py:strip=""> py:strip="">
   
<xi:include href="../ga_util.html" /> <xi:include href="../ga_util.html" />
   
<py:def function="page_title">Usage by Dataset</py:def> <py:def function="page_title">Usage by Dataset</py:def>
   
<py:def function="optional_head"> <py:def function="optional_head">
<link rel="stylesheet" type="text/css" href="/scripts/vendor/rickshaw.min.css"/> <link rel="stylesheet" type="text/css" href="/scripts/vendor/rickshaw.min.css"/>
<link rel="stylesheet" type="text/css" href="/css/ga_report.css"/> <link rel="stylesheet" type="text/css" href="/css/ga_report.css?1"/>
<script type="text/javascript" src="/scripts/ckanext_ga_reports.js"></script> <script type="text/javascript" src="/scripts/ckanext_ga_reports.js?1"></script>
<script type="text/javascript" src="/scripts/vendor/jquery.sparkline.modified.js"></script> <script type="text/javascript" src="/scripts/vendor/jquery.sparkline.modified.js"></script>
<script type="text/javascript" src="/scripts/rickshaw_ie7_shim.js"></script> <script type="text/javascript" src="/scripts/rickshaw_ie7_shim.js"></script>
<script type="text/javascript" src="/scripts/vendor/d3.v2.js"></script> <script type="text/javascript" src="/scripts/vendor/d3.v2.js"></script>
<script type="text/javascript" src="/scripts/vendor/d3.layout.min.js"></script> <script type="text/javascript" src="/scripts/vendor/d3.layout.min.js"></script>
<script type="text/javascript" src="/scripts/vendor/rickshaw.min.js"></script> <script type="text/javascript" src="/scripts/vendor/rickshaw.min.js"></script>
</py:def> </py:def>
   
<py:match path="primarysidebar"> <py:match path="primarysidebar">
<li class="widget-container boxed widget_text"> <li class="widget-container boxed widget_text">
<h4>Download</h4> <h4>Download</h4>
<p><center> <p><center>
<a class="btn button btn-primary" href="${h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport',action='dataset_csv',id=c.publisher_name or 'all',month=c.month or 'all')}">Download as CSV</a></center> <a class="btn button btn-primary" href="${h.url_for(controller='ckanext.ga_report.controller:GaDatasetReport',action='dataset_csv',id=c.publisher_name or 'all',month=c.month or 'all')}">Download as CSV</a></center>
</p> </p>
</li> </li>
<li class="widget-container boxed widget_text"> <li class="widget-container boxed widget_text">
<h4>Graph Legend</h4> <h4>Graph Legend</h4>
<div id="graph-legend-container"> <div id="graph-legend-container">
</div> </div>
</li> </li>
<xi:include href="../notes.html" /> <xi:include href="../notes.html" />
</py:match> </py:match>
   
   
<div py:match="content"> <div py:match="content">
<h1>Site Usage</h1> <h1>Site Usage</h1>
   
${usage_nav('Datasets')} ${usage_nav('Datasets')}
   
   
<h3 py:if="c.publisher"><a href="${h.url_for(controller='ckanext.dgu.controllers.publisher:PublisherController',action='read',id=c.publisher.name)}">${c.publisher.title}</a></h3> <h3 py:if="c.publisher"><a href="${h.url_for(controller='ckanext.dgu.controllers.publisher:PublisherController',action='read',id=c.publisher.name)}">${c.publisher.title}</a></h3>