1{% load projecttags %} 2<!-- component to display a generic table --> 3 <script> 4 5 // 6 // most of the following javascript is for managing the 'Edit Columns' 7 // pop-up dialog and actions. the idea is that there are 2 types 8 // of actions: immediate - performed while the dialog is still 9 // visible - hide/show columns, and delayed - performed when the 10 // dialog becomes invisible - any resorting if necessary. 11 // 12 // When the dialog is open, an interval timer is set up to 13 // determine if the dialog is still visible. when the dialog 14 // closes - goes invisible, the delayed actions are performed. 15 // 16 // the interval timer and interrupt handler is a way of simulating 17 // an onclose event. there is probably a simpler way to do this 18 // however the pop-up window id was elusive. 19 // 20 21 var editColTimer; 22 var editColAction; 23 24 // 25 // this is the target function of the interval timeout. 26 // check to see if the dialog is visible. if the dialog 27 // has gone invisible since the last check, take any delayed 28 // actions indicated in the action list and clear the timer. 29 // 30 31 function checkVisible( ) { 32 editcol = document.getElementById( 'editcol' ); 33 if ( editcol.offsetWidth <= 0 ) { 34 clearInterval( editColTimer ); 35 editColTimer = false; 36 hideshowColumns( ); 37 editColAction = [ ]; 38 } 39 } 40 41 function filterTableRows(test) { 42 if (test.length > 0) { 43 var r = test.split(/[ ,]+/).map(function (e) { return new RegExp(e, 'i') }); 44 $('tr.data').map( function (i, el) { 45 (! r.map(function (j) { return j.test($(el).html())}).reduce(function (c, p) { return c && p;} )) ? $(el).hide() : $(el).show(); 46 }); 47 } else 48 { 49 $('tr.data').show(); 50 } 51 } 52 53 // 54 // determine the value of the indicated url arg. 55 // this is needed to determine whether a resort 56 // is necessary. it looks like a lot of gorp stuff 57 // but its actually pretty simple. 58 // 59 60 function getURLParameter( name ) { 61 return decodeURIComponent((new RegExp('[?|&]' + name + '=' + 62 '([^&;]+?)(&|#|;|$)').exec(location.search)||[,""])[1].replace(/\+/g, 63 '%20'))||null 64 } 65 66 // 67 // when the dialog box goes invisible 68 // this function is called to interpret 69 // the action list and take any delayed actions necessary. 70 // the editColAction list is a hash table with 71 // the column name as the hash key, the hash value 72 // is a 2 element list. the first element is a flag 73 // indicating whether the column is on or off. the 74 // 2nd element is the sort order indicator for the column. 75 // 76 77 function hideshowColumns( ) { 78 for( var k in editColAction ) { 79 showhideDelayedTableAction( k, editColAction[ k ][ 0 ], editColAction[ k ][ 1 ]); 80 } 81 } 82 83 // 84 // this function actually performs the delayed table actions 85 // namely any resorting if necessary 86 // 87 88 function showhideDelayedTableAction( clname, sh, orderkey ) { 89 if ( !sh ) { 90 p = getURLParameter( "orderby" ).split( ":" )[ 0 ]; 91 if ( p == orderkey ) { 92 reload_params({ 'orderby' : '{{default_orderby}}'}); 93 } 94 } 95 } 96 97 // 98 // this function actually performs the immediate table actions 99 // namely any colums that need to be hidden/shown 100 // 101 102 function showhideImmediateTableAction( clname, sh, orderkey ) { 103 if ( sh ) { 104 $( '.' + clname ).show( 100 ); 105 } 106 else { 107 $( '.' + clname ).hide( 100 ); 108 } 109 110 // save cookie for all checkboxes 111 save = ''; 112 $( '.chbxtoggle' ).each(function( ) { 113 if ( $( this ).attr( 'id' ) != undefined ) { 114 save += ';' + $( this ).attr( 'id' ) +':'+ $( this ).is( ':checked' ) 115 } 116 }); 117 $.cookie( '_displaycols_{{objectname}}', save ); 118 save = ''; 119 } 120 121 // 122 // this is the onclick handler for all of the check box 123 // items in edit columns dialog 124 // 125 126 function showhideTableColumn( clname, sh, orderkey ) { 127 editcol = document.getElementById( 'editcol' ); 128 if ( editcol.offsetWidth <= 0 ) { 129 130 // 131 // this path is taken when the page is first 132 // getting initialized - no dialog visible, 133 // perform both the immediate and delayed actions 134 // 135 136 showhideImmediateTableAction( clname, sh, orderkey ); 137 showhideDelayedTableAction( clname, sh, orderkey ); 138 return; 139 } 140 if ( !editColTimer ) { 141 142 // 143 // we don't have a timer active so set one up 144 // and clear the action list 145 // 146 147 editColTimer = setInterval( checkVisible, 250 ); 148 editColAction = [ ]; 149 } 150 151 // 152 // save the action to be taken when the dialog closes 153 // 154 155 editColAction[ clname ] = [ sh, orderkey ]; 156 showhideImmediateTableAction( clname, sh, orderkey ); 157 } 158 159 </script> 160 161<!-- control header --> 162<div class="navbar navbar-default"> 163 <div class="container-fluid"> 164 <div class="navbar-header"> 165 <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#table-chrome-collapse-variablehistory" aria-expanded="false"> 166 <span class="sr-only">Toggle table options</span> 167 <span class="icon-bar"></span> 168 <span class="icon-bar"></span> 169 <span class="icon-bar"></span> 170 </button> 171 </div> 172 <div class="collapse navbar-collapse" id="table-chrome-collapse-variablehistory"> 173 <form class="navbar-form navbar-left" id="searchform"> 174 <div class="form-group"> 175 <div class="btn-group"> 176 <input class="form-control" id="search" name="search" type="text" placeholder="Search {%if object_search_display %}{{object_search_display}}{%else%}{{objectname}}{%endif%}" value="{%if request.GET.search %}{{request.GET.search}}{% endif %}"/> 177 {% if request.GET.search %}<a href="javascript:$('#search').val('');searchform.submit()" tabindex="-1"><span class="remove-search-btn-variables glyphicon glyphicon-remove-circle"></span></a>{%endif%} 178 </div> 179 </div> 180 <input type="hidden" name="orderby" value="{{request.GET.orderby}}"> 181 <input type="hidden" name="page" value="1"> 182 <button class="btn btn-default" id="search-button" type="submit" value="Search">Search</button> 183 </form> 184 <form class="navbar-form navbar-right"> 185 <div class="form-group"> 186 <label>Show rows:</label> 187 <select class="pagesize form-control"> 188 {% with "10 25 50 100 150" as list%} 189 {% for i in list.split %} 190 <option value="{{i}}">{{i}}</option> 191 {% endfor %} 192 {% endwith %} 193 </select> 194 </div> 195 </form> 196 197 <div class="btn-group navbar-right"> 198 {% if tablecols %} 199 <button id="edit-columns-button" class="btn btn-default navbar-btn dropdown-toggle" data-toggle="dropdown">Edit columns 200 <span class="caret"></span> 201 </button> 202<!-- 203 {{tablecols|sortcols}} 204--> 205 <ul id="editcol" class="dropdown-menu editcol"> 206 {% for i in tablecols|sortcols %} 207 <li> 208 <div class="checkbox"> 209 <label {% if not i.clclass %} class="muted" {%endif%}> 210 <input type="checkbox" class="chbxtoggle" 211 {% if i.clclass %} 212 id="{{i.clclass}}" 213 value="ct{{i.name}}" 214 {% if not i.hidden %} 215 checked="checked" 216 {%endif%} 217 onclick="showhideTableColumn( 218 $(this).attr('id'), 219 $(this).is(':checked'), 220 {% if i.ordericon %} 221 '{{i.orderkey}}' 222 {% else %} 223 undefined 224 {% endif %} 225 )" 226 {%else%} 227 checked disabled 228 {% endif %}/>{{i.name}} 229 </label> 230 </div> 231 </li> 232 {% endfor %} 233 </ul> 234 {% endif %} 235 </div> 236 </div> <!-- navbar-collapse --> 237 </div> <!-- container-fluid --> 238</div> <!-- navbar-default --> 239 240<!-- the actual rows of the table --> 241 <table class="table table-bordered table-hover tablesorter" id="otable"> 242 <thead> 243 <!-- Table header row; generated from "tablecols" entry in the context dict --> 244 <tr> 245 {% for tc in tablecols %}<th class="{%if tc.dclass%}{{tc.dclass}}{%endif%} {% if tc.clclass %}{{tc.clclass}}{% endif %}"> 246 {%if tc.qhelp%}<span class="glyphicon glyphicon-question-sign get-help" title="{{tc.qhelp}}"></span>{%endif%} 247 {%if tc.orderfield%}<a {%if tc.ordericon%} class="sorted" {%endif%}href="javascript:reload_params({'page': 1, 'orderby' : '{{tc.orderfield}}' })">{{tc.name}}</a>{%else%}<span class="text-muted">{{tc.name}}</span>{%endif%} 248 {%if tc.ordericon%} <i class="icon-caret-{{tc.ordericon}}"></i>{%endif%} 249 {%if tc.filter%}<div class="btn-group pull-right"> 250 <a href="#filter_{{tc.filter.class}}" role="button" class="btn btn-xs {%if request.GET.filter%}{{tc.filter.options|filtered_icon:request.GET.filter}} {%endif%}" {%if request.GET.filter and tc.filter.options|filtered_tooltip:request.GET.filter %} title="<p>{{tc.filter.options|filtered_tooltip:request.GET.filter}}</p><p><a class='btn btn-sm btn-primary' href=javascript:reload_params({'filter':''})>Show all {% if filter_search_display %}{{filter_search_display}}{% else %}{{objectname}}{% endif %}</a></p>" {%endif%} data-toggle="modal"> <span class="glyphicon glyphicon-filter filtered"></span> </a> 251 </div>{%endif%} 252 </th>{% endfor %} 253 </tr> 254 </thead> 255 <tbody> 256 257