[yocto] [PATCH 1/1] error-report-web: Sorting error tables

Roxana Ciobanu roxana.ciobanu at intel.com
Mon Sep 8 07:07:41 PDT 2014


Add sorting functionality to the search results page.

[YOCTO #6539]

Signed-off-by: Roxana Ciobanu <roxana.ciobanu at intel.com>
---
 Post/static/css/custom.css    |  15 ++
 Post/views.py                 | 135 +++++++++++--
 templates/latest-errors.html  | 391 ++++++++++++++++++++++++++----------
 templates/search-details.html | 446 +++++++++++++++++++++++++++++-------------
 4 files changed, 732 insertions(+), 255 deletions(-)

diff --git a/Post/static/css/custom.css b/Post/static/css/custom.css
index c274b67..f2a35a6 100644
--- a/Post/static/css/custom.css
+++ b/Post/static/css/custom.css
@@ -68,3 +68,18 @@ td a:visited {
 .dropdown-menu {
 	padding: 10px;
 }
+
+.sorted {
+	color: #333;
+	font-weight: bold;
+}
+.sorting-arrows {
+	font-size: 12px;
+}
+.sorted:hover {
+	color: #000;
+	text-decoration: underline;
+}
+th a, th span {
+	font-weight: normal;
+}
diff --git a/Post/views.py b/Post/views.py
index 79d688e..6d8ec3f 100644
--- a/Post/views.py
+++ b/Post/views.py
@@ -30,6 +30,61 @@ from django.core.urlresolvers import reverse_lazy
 from django.contrib.sites.models import RequestSite
 from collections import OrderedDict
 
+def sort_elems(elems, ordering_string, default_orderby):
+    aux = ordering_string
+    if ordering_string:
+        column, order = aux.split(':')
+    else:
+        column, order = default_orderby.split(':')
+    if order == '-':
+        rev = True
+    else:
+        rev = False
+
+    if column == "submitted_on":
+        elems.sort(key=lambda r : r.BUILD.DATE, reverse=not rev)
+        return elems
+    else:
+        elems.sort(key=lambda r : r.BUILD.DATE, reverse=True) # Secondary sorting criteria
+
+    if column == "machine":
+        elems.sort(key=lambda r : r.BUILD.MACHINE, reverse=rev)
+    elif column == "branch":
+        elems.sort(key=lambda r : r.BUILD.BRANCH, reverse=rev)
+    elif column == "target":
+        elems.sort(key=lambda r : r.BUILD.TARGET, reverse=rev)
+    elif column == "distro":
+        elems.sort(key=lambda r : r.BUILD.DISTRO, reverse=rev)
+    elif column == "host_distro":
+        elems.sort(key=lambda r : r.BUILD.NATIVELSBSTRING, reverse=rev)
+    elif column == "build_sys":
+        elems.sort(key=lambda r : r.BUILD.BUILD_SYS, reverse=rev)
+    elif column == "target_sys":
+        elems.sort(key=lambda r : r.BUILD.TARGET_SYS, reverse=rev)
+    elif column == "submitter":
+        elems.sort(key=lambda r : r.BUILD.NAME, reverse=rev)
+    elif column == "email":
+        elems.sort(key=lambda r : r.BUILD.EMAIL, reverse=rev)
+    elif column == "task":
+        elems.sort(key=lambda r : r.TASK, reverse=rev)
+    elif column == "recipe":
+        elems.sort(key=lambda r : r.RECIPE, reverse=rev)
+    return elems
+
+def _get_toggle_order(request, orderkey, reverse = False):
+    if reverse:
+        return "%s:+" % orderkey if request.GET.get('orderby', "") == "%s:-" % orderkey else "%s:-" % orderkey
+    else:
+        return "%s:-" % orderkey if request.GET.get('orderby', "") == "%s:+" % orderkey else "%s:+" % orderkey
+
+def _get_toggle_order_icon(request, orderkey):
+    if request.GET.get('orderby', "") == "%s:+"%orderkey:
+        return "down"
+    elif request.GET.get('orderby', "") == "%s:-"%orderkey:
+        return "up"
+    else:
+        return ""
+
 @csrf_exempt
 def addData(request):
     response = ''
@@ -53,14 +108,20 @@ def viewEntry(request,template_name, page=None, query=None):
     return HttpResponseRedirect(reverse('entry', args=(), kwargs={"items":10, "page":page, "query":query}))
 
 @csrf_exempt
-def search(request, template_name, items = None, page = None, query = None):
+def search(request, template_name, items = None, page = None, query = None, orderby = None):
     if items == None and page == None and query == None:
          page = request.GET.get('page', '')
          query = request.GET.get('query', '')
          items = request.GET.get('items', '')
+         orderby = request.GET.get('orderby', '')
 
-    latest = False
+    default_orderby = 'submitted_on:+';
+    if orderby == "":
+        get_values = request.GET.copy()
+        get_values['orderby'] = default_orderby
+        request.GET = get_values
 
+    latest = False
     if "latest" in query:
          latest = True
          query = query.replace("_latest", "")
@@ -68,7 +129,7 @@ def search(request, template_name, items = None, page = None, query = None):
     if query == "" or query.isspace():
         query = "all"
     elems = Info().getSearchResult(query.strip())
-    elems.sort(key=lambda r : r.BUILD.DATE, reverse=True)
+    elems = sort_elems(elems, orderby, default_orderby)
     no = len(elems)
     if no == 0:
         return render_to_response("error-page.html", {"latest" : latest,  "query" : query}, RequestContext(request))
@@ -105,20 +166,64 @@ def search(request, template_name, items = None, page = None, query = None):
         "no" : no,
         'list' : paginator.page_range[index:end],
         'items' : items,
+        'orderby': orderby,
+        'default_orderby' : default_orderby,
         'objectname' : 'errors',
         'tablecols' : [
-        {'name': 'Submitted on', 'clclass': 'submitted_on'},
-        {'name': 'Recipe'},
-        {'name': 'Recipe version', 'clclass': 'recipe_version'},
-        {'name': 'Task'},
-        {'name': 'Machine'},
-        {'name': 'Distro'},
-        {'name': 'Build system', 'clclass': 'build_sys', 'hidden': 1},
-        {'name': 'Target system', 'clclass': 'target_sys', 'hidden': 1},
-        {'name': 'Host distro', 'clclass': 'host_distro'},
-        {'name': 'Branch', 'clclass': 'branch'},
-        {'name': 'Commit', 'clclass': 'commit'},
-        {'name': 'Submitter', 'clclass': 'submitter','hidden': 1}],
+        {'name': 'Submitted on',
+         'orderfield': _get_toggle_order(request, "submitted_on", True),      # adds ordering by the field value;
+         'ordericon':_get_toggle_order_icon(request, "submitted_on"),
+        },
+        {'name': 'Recipe',
+         'orderfield': _get_toggle_order(request, "recipe", False),
+         'ordericon':_get_toggle_order_icon(request, "recipe"),
+        },
+        {'name': 'Recipe version',
+         'clclass': 'recipe_version',
+        },
+        {'name': 'Task',
+         'orderfield': _get_toggle_order(request, "task", False),
+         'ordericon':_get_toggle_order_icon(request, "task"),
+        },
+        {'name': 'Machine',
+         'orderfield': _get_toggle_order(request, "machine", False),
+         'ordericon':_get_toggle_order_icon(request, "machine"),
+        },
+        {'name': 'Distro',
+         'orderfield': _get_toggle_order(request, "distro", False),
+         'ordericon':_get_toggle_order_icon(request, "distro"),
+        },
+        {'name': 'Build system',
+         'clclass': 'build_sys',
+         'hidden': 1,
+         'orderfield': _get_toggle_order(request, "build_sys", False),
+         'ordericon':_get_toggle_order_icon(request, "build_sys"),
+        },
+        {'name': 'Target system',
+         'clclass': 'target_sys',
+         'hidden': 1,
+         'orderfield': _get_toggle_order(request, "target_sys", False),
+         'ordericon':_get_toggle_order_icon(request, "target_sys"),
+        },
+        {'name': 'Host distro',
+         'clclass': 'host_distro',
+         'orderfield': _get_toggle_order(request, "host_distro", False),
+         'ordericon':_get_toggle_order_icon(request, "host_distro"),
+        },
+        {'name': 'Branch',
+         'clclass': 'branch',
+         'orderfield': _get_toggle_order(request, "branch", False),
+         'ordericon':_get_toggle_order_icon(request, "branch"),
+        },
+        {'name': 'Commit',
+         'clclass': 'commit',
+        },
+        {'name': 'Submitter',
+         'clclass': 'submitter',
+         'hidden': 1,
+         'orderfield': _get_toggle_order(request, "submitter", False),
+         'ordericon':_get_toggle_order_icon(request, "submitter"),
+        }],
     }
 
     return render_to_response(template_name, context, RequestContext(request))
diff --git a/templates/latest-errors.html b/templates/latest-errors.html
index 3927100..d002a65 100644
--- a/templates/latest-errors.html
+++ b/templates/latest-errors.html
@@ -7,42 +7,199 @@
 	<body>
 		{% block content %}
 		<script>$
-		function showhideTableColumn( clname, sh) {
-			if ( sh ) {
-				$('.' + clname ).show( 100 );
-			}
-			else {
-				$('.' + clname ).hide( 100 );
-			}
-			// save cookie for all checkboxes$
-			save = '';
-			$( '.chbxtoggle' ).each(function( ) {
-				if ( $( this ).attr( 'id' ) != undefined ) {
-					save += ';' + $( this ).attr( 'id' ) +':'+ $( this ).is( ':checked' )
-				}
-			});
-			$.cookie( '_displaycols_{{objectname}}', save );
-			save = '';
-		}
+
+    function reload_params(params) {
+        uri = window.location.href;
+        splitlist = uri.split("?");
+        url = splitlist[0], parameters=splitlist[1];
+        // deserialize the call parameters
+        if(parameters){
+            cparams = parameters.split("&");
+        }else{
+            cparams = []
+        }
+        nparams = {}
+        for (i = 0; i < cparams.length; i++) {
+            temp = cparams[i].split("=");
+            nparams[temp[0]] = temp[1];
+        }
+        // update parameter values
+        for (i in params) {
+            nparams[encodeURIComponent(i)] = encodeURIComponent(params[i]);
+        }
+        // serialize the structure
+        callparams = []
+        for (i in nparams) {
+            callparams.push(i+"="+nparams[i]);
+        }
+        window.location.href = url+"?"+callparams.join('&');
+}
+
+    // most of the following javascript is for managing the 'Edit Columns'
+    // pop-up dialog and actions. the idea is that there are 2 types
+    // of actions: immediate - performed while the dialog is still
+    // visible - hide/show columns, and delayed - performed when the
+    // dialog becomes invisible - any resorting if necessary.
+    //
+    // When the dialog is open, an interval timer is set up to
+    // determine if the dialog is still visible. when the dialog
+    // closes - goes invisible, the delayed actions are performed.
+    //
+    // the interval timer and interrupt handler is a way of simulating
+    // an onclose event. there is probably a simpler way to do this
+    // however the pop-up window id was elusive.
+    //
+
+    var editColTimer;
+    var editColAction;
+
+    //
+    // this is the target function of the interval timeout.
+    // check to see if the dialog is visible. if the dialog
+    // has gone invisible since the last check, take any delayed
+    // actions indicated in the action list and clear the timer.
+    //
+
+    function checkVisible( ) {
+        editcol = document.getElementById( 'editcol' );
+        if ( editcol.offsetWidth <= 0 ) {
+            clearInterval( editColTimer );
+            editColTimer = false;
+            hideshowColumns( );
+            editColAction = [ ];
+        }
+    }
+
+    //
+    // determine the value of the indicated url arg.
+    // this is needed to determine whether a resort
+    // is necessary. it looks like a lot of gorp stuff
+    // but its actually pretty simple.
+    //
+
+    function getURLParameter( name ) {
+        return decodeURIComponent((new RegExp('[?|&]' + name + '=' +
+          '([^&;]+?)(&|#|;|$)').exec(location.search)||[,""])[1].replace(/\+/g,
+          '%20'))||null
+    }
+
+    //
+    // when the dialog box goes invisible
+    // this function is called to interpret
+    // the action list and take any delayed actions necessary.
+    // the editColAction list is a hash table with
+    // the column name as the hash key, the hash value
+    // is a 2 element list. the first element is a flag
+    // indicating whether the column is on or off. the
+    // 2nd element is the sort order indicator for the column.
+    //
+
+    function hideshowColumns( ) {
+        for( var k in editColAction ) {
+            showhideDelayedTableAction( k, editColAction[ k ][ 0 ], editColAction[ k ][ 1 ]);
+        }
+    }
+
+    //
+    // this function actually performs the delayed table actions
+    // namely any resorting if necessary
+    //
+
+    function showhideDelayedTableAction( clname, sh, orderkey) {
+        if ( !sh && orderkey) {
+            orderkey = orderkey.split( ":" )[ 0 ];
+            p = getURLParameter( "orderby" ).split( ":" )[ 0 ];
+            if ( p == orderkey ) {
+                reload_params({ 'orderby' : '{{default_orderby}}'});
+            }
+        }
+    }
+
+    //
+    // this function actually performs the immediate table actions
+    // namely any colums that need to be hidden/shown
+    //
+
+    function showhideImmediateTableAction( clname, sh, orderkey ) {
+        if ( sh ) {
+            $( '.' + clname ).show( 100 );
+        }
+        else {
+            $( '.' + clname ).hide( 100 );
+        }
+
+        // save cookie for all checkboxes
+        save = '';
+        $( '.chbxtoggle' ).each(function( ) {
+            if ( $( this ).attr( 'id' ) != undefined ) {
+                save += ';' + $( this ).attr( 'id' ) +':'+ $( this ).is( ':checked' )
+            }
+        });
+        $.cookie( '_displaycols_{{objectname}}', save );
+        save = '';
+    }
+
+    //
+    // this is the onclick handler for all of the check box
+    // items in edit columns dialog
+    //
+
+    function showhideTableColumn( clname, sh, orderkey ) {
+        editcol = document.getElementById( 'editcol' );
+        if ( editcol.offsetWidth <= 0 ) {
+
+            //
+            // this path is taken when the page is first
+            // getting initialized - no dialog visible,
+            // perform both the immediate and delayed actions
+            //
+
+            showhideImmediateTableAction( clname, sh, orderkey );
+            showhideDelayedTableAction( clname, sh, orderkey );
+            return;
+        }
+        if ( !editColTimer ) {
+
+            //
+            // we don't have a timer active so set one up
+            // and clear the action list
+            //
+
+            editColTimer = setInterval( checkVisible, 250 );
+            editColAction = [ ];
+        }
+
+        //
+        // save the action to be taken when the dialog closes
+        //
+
+        editColAction[ clname ] = [ sh, orderkey ];
+        showhideImmediateTableAction( clname, sh, orderkey );
+        showhideDelayedTableAction( clname, sh, orderkey);
+	}
+
 		</script>
 
+
 		<div class="row-fluid">
 			<ul class="nav nav-pills">
 				{% ifequal d 'autobuilder' %}
-					<li> <a href="{% url latest_errors %}?items=25&page=1&query=all_latest" >Latest errors</a> </li>
-					<li class="active"> <a href="{% url latest_errors %}?items=25&page=1&query=autobuilder_latest" >Latest Autobuilder errors</a></li>
+					<li class="active"> <a href="javascript:reload_params({'query' : 'latest_all'})">Latest errors</a></li>
+					<li> <a href="javascript:reload_params({})">Latest Autobuilder errors</a></li>
+
 				{% else %}
-					<li class="active"> <a href="{% url latest_errors %}?items=25&page=1&query=all_latest" >Latest errors</a> </li>
-					<li> <a href="{% url latest_errors %}?items=25&page=1&query=autobuilder_latest" >Latest Autobuilder errors</a></li>
+					<li class="active"> <a href="javascript:reload_params({})">Latest errors</a></li>
+					<li > <a href="javascript:reload_params({'query' : 'latest_autobuilder'})">Latest Autobuilder errors</a></li>
 				{% endifequal %}
 					<li> <a href="{% url main %}" >Statistics </a> </li>
 			</ul>
 			<div class="navbar">
 				<div class="navbar-inner">
 					{% if no > 10 %}
-						<form class="form-inline pull-right">
-							<label>Show latest:</label>
-								<select class="paginationLimit input-mini" onchange="javascript:window.open('{% url latest_errors %}?items='+this.value+'&page={{ details.number }}', '_self')">
+					<form class="form-inline pull-right">
+						<label>Show latest:</label>
+						<form>
+							<select class="paginationLimit input-mini" onchange="javascript:reload_params({'page': '1', 'items' : +this.value })">
 								{% ifequal items "10" %}
 									<option selected="selected" value = "10">10</option>
 									<option value = "25">25</option>
@@ -78,53 +235,75 @@
 									<option value = "100">100</option>
 									<option selected="selected" value = "150">150</option>
 								{%endifequal%}
-								</select>
+							</select>
 						</form>
-						<span class="divider-vertical pull-right"></span>
+					</form>
+					<span class="divider-vertical pull-right"></span>
 					{% endif %}
 					<div class="btn-group pull-right">
-					{% ifequal d "autobuilder" %}
-						<form style="display:inline" action="{% url entry_args %}" method="GET">
-							<div class="input-append">
-								<input type="text" name="items" value=10 style="display: none;">
-								<input type="text" name="page" value=1 style="display: none;">
-								<input type="text" name="query" value=autobuilder style="display: none;">
-							</div>
-							<button type="submit" value="View All" class="btn dropdown-toggle">View all Autobuilder errors </button>
-						</form>
-					{% endifequal %}
-					{% if tablecols %}
-						<button class="btn dropdown-toggle" data-toggle="dropdown">Edit columns
-							<span class="caret"></span>
-						</button>
-						<ul id='editcol' class="dropdown-menu">
-							{% for i in tablecols|sortcols %}
-							<li>
-							<label {% if not i.clclass %} class="checkbox muted" {%else%} class="checkbox" {%endif%}>
-								<input type="checkbox" class="chbxtoggle"
-								{% if i.clclass %}
-									id="{{i.clclass}}"
-									value="ct{{i.name}}"
-									{% if not i.hidden %}
-										checked="checked"
-									{%endif%}
-									onclick="showhideTableColumn($(this).attr('id'), $(this).is(':checked'))"
-								{%else%}
-									checked disabled
-								{% endif %}/>   {{i.name}}
-							</label>
-							</li>
-							{% endfor %}
-						</ul>
-					{% endif %}
+						{% ifequal d "autobuilder" %}
+							<form style="display:inline" action="{% url entry_args %}" method="GET">
+								<div class="input-append">
+									<input type="text" name="items" value=10 style="display: none;">
+									<input type="text" name="page" value=1 style="display: none;">
+									<input type="text" name="query" value=autobuilder style="display: none;">
+								</div>
+								<button type="submit" value="View All" class="btn dropdown-toggle">View all Autobuilder errors </button>
+							</form>
+						{% endifequal %}
+						{% if tablecols %}
+							<button class="btn dropdown-toggle" data-toggle="dropdown">Edit columns
+								<span class="caret"></span>
+							</button>
+							<ul id='editcol' class="dropdown-menu">
+								{% for i in tablecols|sortcols %}
+								<li>
+									<label
+										{% if not i.clclass %} class="checkbox muted" {%else%} class="checkbox" {%endif%}>
+										<input type="checkbox" class="chbxtoggle"
+										{% if i.clclass %}
+											id="{{i.clclass}}"
+											value="ct{{i.name}}"
+											{% if not i.hidden %}
+												checked="checked"
+											{%endif%}
+											onclick="showhideTableColumn($(this).attr('id'), $(this).is(':checked'), '{{i.orderfield}}')"
+										{%else%}
+											checked disabled
+										{% endif %}
+										/> {{i.name}}
+									</label>
+								</li>
+								{% endfor %}
+							</ul>
+						{% endif %}
 					</div>
 				</div> <!-- navbar-inner -->
 			</div>
 			{% if details %}
 				<table class="table table-bordered table-hover">
 					<thead>
+					<!-- Table header row; generated from "tablecols" entry in the context dict -->
 						<tr>
-							{% for i in tablecols %} <th class="{{i.dclass}} {{i.clclass}}"> {{i.name}} </th> {%endfor%}
+							{% for i in tablecols %}
+								<th class="{{i.clclass}}">
+										{%if i.orderfield%}
+											<a {%if i.ordericon%} class="sorted" {%endif%}
+												href="javascript:reload_params({'page': 1, 'orderby' : '{{i.orderfield}}' })" >
+												{{i.name}}
+											</a>
+										{%else%}
+											<span class="muted">
+												{{i.name}}
+											</span>
+										{%endif%}
+										{% if i.ordericon%}
+											<span class="sorting-arrows">
+												{% ifequal i.ordericon "down" %} &#9660 {% else %} &#9650 {% endifequal %}
+											</span>
+										{%endif%}
+									</th>
+							{%endfor%}
 						</tr>
 					</thead>
 					<tbody>
@@ -152,52 +331,52 @@
 						{%endfor%}
 					</tbody>
 				</table>
-					<div class="pagination pagination-centered">
-						<form class="form-inline pull-right">
-						{% if no > 10 %}
+				<div class="pagination pagination-centered">
+					<form class="form-inline pull-right">
+					{% if no > 10 %}
 						<label>Show latest:</label>
-								<form>
-									<select class="paginationLimit input-mini" onchange="javascript:window.open('{% url latest_errors %}?items='+this.value+'&page={{details.number}}', '_self')">
-										{% ifequal items "10" %}
-											<option selected="selected" value = "10">10</option>
-											<option value = "25">25</option>
-											<option value = "50">50</option>
-											<option value = "100">100</option>
-											<option value = "150">150</option>
-										{%endifequal%}
-										{% ifequal items "25"%}
-											<option value = "10">10</option>
-											<option selected="selected" value = "25">25</option>
-											<option value = "50">50</option>
-											<option value = "100">100</option>
-											<option value = "150">150</option>
-										{%endifequal%}
-										{% ifequal items "50"%}
-											<option value = "10">10</option>
-											<option value = "25">25</option>
-											<option selected="selected" value = "50">50</option>
-											<option value = "100">100</option>
-											<option value = "150">150</option>
-										{%endifequal%}
-										{% ifequal items "100"%}
-											<option value = "10">10</option>
-											<option value = "25">25</option>
-											<option value = "50">50</option>
-											<option selected="selected" value = "100">100</option>
-											<option value = "150">150</option>
-										{%endifequal%}
-										{% ifequal items "150"%}
-											<option value = "10">10</option>
-											<option value = "25">25</option>
-											<option value = "50">50</option>
-											<option value = "100">100</option>
-											<option selected="selected" value = "150">150</option>
-										{%endifequal%}
-									</select>
-								</form>
+						<form>
+							<select class="paginationLimit input-mini" onchange="javascript:reload_params({'page': '1', 'items' : +this.value })">
+								{% ifequal items "10" %}
+									<option selected="selected" value = "10">10</option>
+									<option value = "25">25</option>
+									<option value = "50">50</option>
+									<option value = "100">100</option>
+									<option value = "150">150</option>
+								{%endifequal%}
+								{% ifequal items "25"%}
+									<option value = "10">10</option>
+									<option selected="selected" value = "25">25</option>
+									<option value = "50">50</option>
+									<option value = "100">100</option>
+									<option value = "150">150</option>
+								{%endifequal%}
+								{% ifequal items "50"%}
+									<option value = "10">10</option>
+									<option value = "25">25</option>
+									<option selected="selected" value = "50">50</option>
+									<option value = "100">100</option>
+									<option value = "150">150</option>
+								{%endifequal%}
+								{% ifequal items "100"%}
+									<option value = "10">10</option>
+									<option value = "25">25</option>
+									<option value = "50">50</option>
+									<option selected="selected" value = "100">100</option>
+									<option value = "150">150</option>
+								{%endifequal%}
+								{% ifequal items "150"%}
+									<option value = "10">10</option>
+									<option value = "25">25</option>
+									<option value = "50">50</option>
+									<option value = "100">100</option>
+									<option selected="selected" value = "150">150</option>
+								{%endifequal%}
+							</select>
 						</form>
-						{% endif %}
-					</div>
+					</form>
+					{% endif %}
+				</div>
 			{% endif %}
 			{% if result %}
 			           <h4>Nothing matches your search!</h4>
@@ -206,7 +385,7 @@
 		<script>
 			$(document).ready(function() {
 				$('.commit > div').popover({placement:'left'})
-            
+
 				// we load cookies for the column display$
 				save = $.cookie('_displaycols_{{objectname}}');
 				if (save != undefined) {
diff --git a/templates/search-details.html b/templates/search-details.html
index ef586cd..fbba5a9 100644
--- a/templates/search-details.html
+++ b/templates/search-details.html
@@ -7,24 +7,181 @@
 	<body>
 		{% block content %}
 		<script>$
-		function showhideTableColumn( clname, sh) {
-			if ( sh ) {
-				$('.' + clname ).show( 100 );
-			}
-			else {
-				$('.' + clname ).hide( 100 );
-			}
-			// save cookie for all checkboxes$
-			save = '';
-			$( '.chbxtoggle' ).each(function( ) {
-				if ( $( this ).attr( 'id' ) != undefined ) {
-					save += ';' + $( this ).attr( 'id' ) +':'+ $( this ).is( ':checked' )
-				}
-			});
-			$.cookie( '_displaycols_{{objectname}}', save );
-			save = '';
-		}
-		</script>
+
+    function reload_params(params) {
+        uri = window.location.href;
+        splitlist = uri.split("?");
+        url = splitlist[0], parameters=splitlist[1];
+        // deserialize the call parameters
+        if(parameters){
+            cparams = parameters.split("&");
+        }else{
+            cparams = []
+        }
+        nparams = {}
+        for (i = 0; i < cparams.length; i++) {
+            temp = cparams[i].split("=");
+            nparams[temp[0]] = temp[1];
+        }
+        // update parameter values
+        for (i in params) {
+            nparams[encodeURIComponent(i)] = encodeURIComponent(params[i]);
+        }
+        // serialize the structure
+        callparams = []
+        for (i in nparams) {
+            callparams.push(i+"="+nparams[i]);
+        }
+        window.location.href = url+"?"+callparams.join('&');
+}
+
+    // most of the following javascript is for managing the 'Edit Columns'
+    // pop-up dialog and actions. the idea is that there are 2 types
+    // of actions: immediate - performed while the dialog is still
+    // visible - hide/show columns, and delayed - performed when the
+    // dialog becomes invisible - any resorting if necessary.
+    //
+    // When the dialog is open, an interval timer is set up to
+    // determine if the dialog is still visible. when the dialog
+    // closes - goes invisible, the delayed actions are performed.
+    //
+    // the interval timer and interrupt handler is a way of simulating
+    // an onclose event. there is probably a simpler way to do this
+    // however the pop-up window id was elusive.
+    //
+
+    var editColTimer;
+    var editColAction;
+
+    //
+    // this is the target function of the interval timeout.
+    // check to see if the dialog is visible. if the dialog
+    // has gone invisible since the last check, take any delayed
+    // actions indicated in the action list and clear the timer.
+    //
+
+    function checkVisible( ) {
+        editcol = document.getElementById( 'editcol' );
+        if ( editcol.offsetWidth <= 0 ) {
+            clearInterval( editColTimer );
+            editColTimer = false;
+            hideshowColumns( );
+            editColAction = [ ];
+        }
+    }
+
+    //
+    // determine the value of the indicated url arg.
+    // this is needed to determine whether a resort
+    // is necessary. it looks like a lot of gorp stuff
+    // but its actually pretty simple.
+    //
+
+    function getURLParameter( name ) {
+        return decodeURIComponent((new RegExp('[?|&]' + name + '=' +
+          '([^&;]+?)(&|#|;|$)').exec(location.search)||[,""])[1].replace(/\+/g,
+          '%20'))||null
+    }
+
+    //
+    // when the dialog box goes invisible
+    // this function is called to interpret
+    // the action list and take any delayed actions necessary.
+    // the editColAction list is a hash table with
+    // the column name as the hash key, the hash value
+    // is a 2 element list. the first element is a flag
+    // indicating whether the column is on or off. the
+    // 2nd element is the sort order indicator for the column.
+    //
+
+    function hideshowColumns( ) {
+        for( var k in editColAction ) {
+            showhideDelayedTableAction( k, editColAction[ k ][ 0 ], editColAction[ k ][ 1 ]);
+        }
+    }
+
+    //
+    // this function actually performs the delayed table actions
+    // namely any resorting if necessary
+    //
+
+    function showhideDelayedTableAction( clname, sh, orderkey) {
+        if ( !sh && orderkey) {
+            orderkey = orderkey.split( ":" )[ 0 ];
+            p = getURLParameter( "orderby" ).split( ":" )[ 0 ];
+            if ( p == orderkey ) {
+                reload_params({ 'orderby' : '{{default_orderby}}'});
+            }
+        }
+    }
+
+    //
+    // this function actually performs the immediate table actions
+    // namely any colums that need to be hidden/shown
+    //
+
+    function showhideImmediateTableAction( clname, sh, orderkey ) {
+        if ( sh ) {
+            $( '.' + clname ).show( 100 );
+        }
+        else {
+            $( '.' + clname ).hide( 100 );
+        }
+
+        // save cookie for all checkboxes
+        save = '';
+        $( '.chbxtoggle' ).each(function( ) {
+            if ( $( this ).attr( 'id' ) != undefined ) {
+                save += ';' + $( this ).attr( 'id' ) +':'+ $( this ).is( ':checked' )
+            }
+        });
+        $.cookie( '_displaycols_{{objectname}}', save );
+        save = '';
+}
+
+    //
+    // this is the onclick handler for all of the check box
+    // items in edit columns dialog
+    //
+
+    function showhideTableColumn( clname, sh, orderkey ) {
+        editcol = document.getElementById( 'editcol' );
+        if ( editcol.offsetWidth <= 0 ) {
+
+            //
+            // this path is taken when the page is first
+            // getting initialized - no dialog visible,
+            // perform both the immediate and delayed actions
+            //
+
+            showhideImmediateTableAction( clname, sh, orderkey );
+            showhideDelayedTableAction( clname, sh, orderkey );
+            return;
+        }
+        if ( !editColTimer ) {
+
+            //
+            // we don't have a timer active so set one up
+            // and clear the action list
+            //
+
+            editColTimer = setInterval( checkVisible, 250 );
+            editColAction = [ ];
+        }
+
+        //
+        // save the action to be taken when the dialog closes
+        //
+
+        editColAction[ clname ] = [ sh, orderkey ];
+        showhideImmediateTableAction( clname, sh, orderkey );
+        showhideDelayedTableAction( clname, sh, orderkey);
+    }
+
+    </script>
+
+
+
 
 			<div class="row-fluid">
 				<div class="page-header">
@@ -34,10 +191,138 @@
 				</div>
 				<div class="navbar">
 					<div class="navbar-inner">
+						{% if no > 10 %}
 						<form class="form-inline pull-right">
+							<label>Show rows: </label>
+							<form>
+								<select class="paginationLimit input-mini" onchange="javascript:reload_params({'page': '1', 'items' : +this.value })">
+									{% ifequal items "10" %}
+										<option selected="selected" value = "10">10</option>
+										<option value = "25">25</option>
+										<option value = "50">50</option>
+										<option value = "100">100</option>
+										<option value = "150">150</option>
+									{%endifequal%}
+									{% ifequal items "25"%}
+										<option value = "10">10</option>
+										<option selected="selected" value = "25">25</option>
+										<option value = "50">50</option>
+										<option value = "100">100</option>
+										<option value = "150">150</option>
+									{%endifequal%}
+									{% ifequal items "50"%}
+										<option value = "10">10</option>
+										<option value = "25">25</option>
+										<option selected="selected" value = "50">50</option>
+										<option value = "100">100</option>
+										<option value = "150">150</option>
+									{%endifequal%}
+									{% ifequal items "100"%}
+										<option value = "10">10</option>
+										<option value = "25">25</option>
+										<option value = "50">50</option>
+										<option selected="selected" value = "100">100</option>
+										<option value = "150">150</option>
+									{%endifequal%}
+									{% ifequal items "150"%}
+										<option value = "10">10</option>
+										<option value = "25">25</option>
+										<option value = "50">50</option>
+										<option value = "100">100</option>
+										<option selected="selected" value = "150">150</option>
+									{%endifequal%}
+								</select>
+							</form>
+						</form>
+						<span class="divider-vertical pull-right"></span>
+						{% endif %}
+						{% if tablecols %}
+							<div class="btn-group pull-right">
+								<button class="btn dropdown-toggle" data-toggle="dropdown">Edit columns
+									<span class="caret"></span>
+								</button>
+								<ul id='editcol' class="dropdown-menu">
+									{% for i in tablecols|sortcols %}
+									<li>
+									<label
+										{% if not i.clclass %} class="checkbox muted" {%else%} class="checkbox" {%endif%}>
+										<input type="checkbox" class="chbxtoggle"
+										{% if i.clclass %}
+											id="{{i.clclass}}"
+											value="ct{{i.name}}"
+											{% if not i.hidden %}
+												checked="checked"
+											{%endif%}
+											onclick="showhideTableColumn($(this).attr('id'), $(this).is(':checked'), '{{i.orderfield}}')"
+										{%else%}
+											checked disabled
+										{% endif %}
+										/> {{i.name}}
+									</label>
+									</li>
+									{% endfor %}
+								</ul>
+						{% endif %}
+					</div>
+				</div> <!-- navbar-inner -->
+			</div>
+			{% if details %}
+				<table class="table table-bordered table-hover tablesorter">
+					<thead>
+					<!-- Table header row; generated from "tablecols" entry in the context dict -->
+						<tr>
+							{% for i in tablecols %}
+								<th class="{{i.clclass}}">
+									{%if i.orderfield%}
+										<a {%if i.ordericon%} class="sorted" {%endif%}
+											href="javascript:reload_params({'page': 1, 'orderby' : '{{i.orderfield}}' })" >
+											{{i.name}}
+										</a>
+									{%else%}
+										<span class="muted">
+											{{i.name}}
+										</span>
+									{%endif%}
+									{% if i.ordericon%}
+										<span class="sorting-arrows">
+											{% ifequal i.ordericon "down" %} &#9660 {% else %} &#9650 {% endifequal %}
+										</span>
+									{%endif%}
+								</th>
+							{%endfor%}
+						</tr>
+					</thead>
+					<tbody>
+						{%for detail in details %}
+							<tr class="data">
+								<td class="submitted_on"> <a href="{% url id detail.id details.number items d %}">{{ detail.BUILD.DATE|date:"d/m/y H:i"}}</a></td>
+								<td class="recipe"><a href="{% url id detail.id details.number items d %}">{{ detail.RECIPE }}</a></td>
+								<td class="recipe_version"><a href="{% url id detail.id details.number items d %}">{{ detail.RECIPE_VERSION }}</a></td>
+								<td class="task"><a href="{% url id detail.id details.number items d %}">{{ detail.TASK }}</a></td>
+								<td class="machine"><a href="{% url id detail.id details.number items d %}">{{ detail.BUILD.MACHINE }}</a></td>
+								<td class="distro"><a href="{% url id detail.id details.number items d %}">{{ detail.BUILD.DISTRO }}</a></td>
+								<td class="build_sys"><a href="{% url id detail.id details.number items d %}">{{ detail.BUILD.BUILD_SYS }}</a></td>
+								<td class="target_sys"><a href="{% url id detail.id details.number items d %}">{{ detail.BUILD.TARGET_SYS }}</a></td>
+								<td class="host_distro"><a href="{% url id detail.id details.number items d %}">{{ detail.BUILD.NATIVELSBSTRING }}</a></td>
+								<td class="branch"><a href="{% url id detail.id details.number items d %}">{{ detail.BUILD.BRANCH }} </a></td>
+								<td class="commit">
+									{% autoescape off %}
+										<div class="btn" rel="popover" data-content= {{ detail.BUILD.COMMIT|escape}} title="">
+											{% endautoescape %}
+										{{ detail.BUILD.COMMIT|truncatechars:10}}
+										</div>
+								</td>
+								<td class="submitter"><a href="{% url id detail.id details.number items d %}">{{ detail.BUILD.NAME }} </a></td>
+							</tr>
+						{%endfor%}
+					</tbody>
+					</table>
+						<div class="pagination pagination-centered">
+							<form class="form-inline pull-right">
 							{% if no > 10 %}
-								<label>Show rows:</label>
-										<select class="paginationLimit input-mini" style="margin-top:5px;margin-bottom:0px;width:60px;" onchange="javascript:window.open('{% url entry_args %}?items='+this.value+'&page={{ details.number }}&query={{ d }}', '_self')">
+							<label>Show rows:</label>
+								<form>
+									<select class="paginationLimit input-mini" onchange="javascript:reload_params({'page': '1', 'items' : +this.value })">
 										{% ifequal items "10" %}
 											<option selected="selected" value = "10">10</option>
 											<option value = "25">25</option>
@@ -73,139 +358,32 @@
 											<option value = "100">100</option>
 											<option selected="selected" value = "150">150</option>
 										{%endifequal%}
-										</select>
-						</form>
-						<span class="divider-vertical pull-right"></span>
-							{% endif %}
-						{% if tablecols %}
-							<div class="btn-group pull-right">
-								<button class="btn dropdown-toggle" data-toggle="dropdown">Edit columns
-									<span class="caret"></span>
-								</button>
-								<ul id='editcol' class="dropdown-menu">
-									{% for i in tablecols|sortcols %}
-									<li>
-									<label {% if not i.clclass %} class="checkbox muted" {%else%} class="checkbox" {%endif%}>
-										<input type="checkbox" class="chbxtoggle"
-										{% if i.clclass %}
-											id="{{i.clclass}}"
-											value="ct{{i.name}}"
-											{% if not i.hidden %}
-												checked="checked"
-											{%endif%}
-											onclick="showhideTableColumn($(this).attr('id'), $(this).is(':checked'))"
-										{%else%}
-											checked disabled
-										{% endif %}/>   {{i.name}}
-									</label>
-									</li>
-									{% endfor %}
-								</ul>
-						{% endif %}
-					</div>
-				</div> <!-- navbar-inner -->
-			</div>
-			{% if details %}
-					<table class="table table-bordered table-hover">
-						<thead>
-							<tr>
-								{% for i in tablecols %} <th class="{{i.dclass}} {{i.clclass}}"> {{i.name}} </th> {%endfor%}
-							</tr>
-						</thead>
-						<tbody>
-							{%for detail in details %}
-								<tr class="data">
-									<td class="submitted_on"> <a href="{% url id detail.id details.number items d %}">{{ detail.BUILD.DATE|date:"d/m/y H:i"}}</a></td>
-									<td class="recipe"><a href="{% url id detail.id details.number items d %}">{{ detail.RECIPE }}</a></td>
-									<td class="recipe_version"><a href="{% url id detail.id details.number items d %}">{{ detail.RECIPE_VERSION }}</a></td>
-									<td class="task"><a href="{% url id detail.id details.number items d %}">{{ detail.TASK }}</a></td>
-									<td class="machine"><a href="{% url id detail.id details.number items d %}">{{ detail.BUILD.MACHINE }}</a></td>
-									<td class="distro"><a href="{% url id detail.id details.number items d %}">{{ detail.BUILD.DISTRO }}</a></td>
-									<td class="build_sys"><a href="{% url id detail.id details.number items d %}">{{ detail.BUILD.BUILD_SYS }}</a></td>
-									<td class="target_sys"><a href="{% url id detail.id details.number items d %}">{{ detail.BUILD.TARGET_SYS }}</a></td>
-									<td class="host_distro"><a href="{% url id detail.id details.number items d %}">{{ detail.BUILD.NATIVELSBSTRING }}</a></td>
-									<td class="branch"><a href="{% url id detail.id details.number items d %}">{{ detail.BUILD.BRANCH }} </a></td>
-									<td class="commit">
-										{% autoescape off %}
-											<div class="btn" rel="popover" data-content= {{ detail.BUILD.COMMIT|escape}} title="">
-												{% endautoescape %}
-											{{ detail.BUILD.COMMIT|truncatechars:10}}
-											</div>
-									</td>
-									<td class="submitter"><a href="{% url id detail.id details.number items d %}">{{ detail.BUILD.NAME }} </a></td>
-								</tr>
-							{%endfor%}
-						</tbody>
-					</table>
-						<div class="pagination pagination-centered">
-							<form class="form-inline pull-right">
-							{% if no > 10 %}
-							<label>Show rows:</label>
-									<form>
-										<select class="paginationLimit" style="margin-top:5px;margin-bottom:0px;width:60px;" onchange="javascript:window.open('{% url entry_args %}?items='+this.value+'&page={{ details.number }}&query={{ d }}', '_self')">
-											{% ifequal items "10" %}
-												<option selected="selected" value = "10">10</option>
-												<option value = "25">25</option>
-												<option value = "50">50</option>
-												<option value = "100">100</option>
-												<option value = "150">150</option>
-											{%endifequal%}
-											{% ifequal items "25"%}
-												<option value = "10">10</option>
-												<option selected="selected" value = "25">25</option>
-												<option value = "50">50</option>
-												<option value = "100">100</option>
-												<option value = "150">150</option>
-											{%endifequal%}
-											{% ifequal items "50"%}
-												<option value = "10">10</option>
-												<option value = "25">25</option>
-												<option selected="selected" value = "50">50</option>
-												<option value = "100">100</option>
-												<option value = "150">150</option>
-											{%endifequal%}
-											{% ifequal items "100"%}
-												<option value = "10">10</option>
-												<option value = "25">25</option>
-												<option value = "50">50</option>
-												<option selected="selected" value = "100">100</option>
-												<option value = "150">150</option>
-											{%endifequal%}
-											{% ifequal items "150"%}
-												<option value = "10">10</option>
-												<option value = "25">25</option>
-												<option value = "50">50</option>
-												<option value = "100">100</option>
-												<option selected="selected" value = "150">150</option>
-											{%endifequal%}
-										</select>
-									</form>
+									</select>
+								</form>
 							</form>
 							{% endif %}
 							 <ul>
 								{% if details.has_previous %}
-								<li><a href="?items={{items}}&page={{ details.previous_page_number }}&query={{ d }}">Previous</a></li>
+								<li><a href="javascript:reload_params({'page' : '{{ details.previous_page_number }}'})">Previous</a></li>
 								{% else %}
 									<li class="disabled"><span>Previous</span></li>
 								{% endif %}
-								
+
 								{% for pnum in list %}
 									{% if pnum == details.number %}
 										   <li class="active"><span>{{ details.number }}</span></li>
 									{% else %}
-									<li><a href="?items={{items}}&page={{ pnum }}&query={{ d }}">{{ pnum }}</a></li>
+									<li><a href="javascript:reload_params({'page' : '{{ details.next_page_number }}'})">{{ pnum }}</a></li>
 									{% endif %}
 								{% endfor %}
-							
+
 								{% if details.has_next %}
-								<li class="next"><a href="?items={{items}}&page={{ details.next_page_number }}&query={{ d }}">Next</a></li>
+								<li class="next"> <a href="javascript:reload_params({'page' : '{{ details.next_page_number }}'})">Next</a></li>
 								{% else %}
 									<li class="disabled"><span>Next</span></li>
 								{% endif %}
 							</ul>
 						</div>
-						
-						
 				{% endif %}
 				{% if result %}
 				           <h4>Nothing matches your search!</h4>
-- 
1.9.1




More information about the yocto mailing list