Fossil SCM

Add javascript to ticket reports tables so that clicking on column headers causes the table to be sorted by that header. Clicking again reverses the sort order.

drh 2012-11-30 15:16 trunk merge
Commit 20f17aeb05940bccd8af63ad09a480c0281efaaa
1 file changed +67 -4
+67 -4
--- src/report.c
+++ src/report.c
@@ -694,11 +694,11 @@
694694
}
695695
}
696696
697697
/* The first time this routine is called, output a table header
698698
*/
699
- @ <tr>
699
+ @ <thead><tr>
700700
zTid = 0;
701701
for(i=0; i<nArg; i++){
702702
char *zName = azName[i];
703703
if( i==pState->iBg ) continue;
704704
if( pState->iNewRow>=0 && i>=pState->iNewRow ){
@@ -716,11 +716,11 @@
716716
}
717717
}
718718
if( g.perm.Write && zTid ){
719719
@ <th>&nbsp;</th>
720720
}
721
- @ </tr>
721
+ @ </tr></thead><tbody>
722722
}
723723
if( azArg==0 ){
724724
@ <tr><td colspan="%d(pState->nCol)">
725725
@ <i>No records match the report criteria</i>
726726
@ </td></tr>
@@ -914,10 +914,71 @@
914914
rc = sqlite3_finalize(pStmt);
915915
fossil_free(azVals);
916916
return rc;
917917
}
918918
919
+/*
920
+** Output Javascript code that will enables sorting of the table with
921
+** the id zTableId by clicking.
922
+**
923
+** The javascript is derived from:
924
+**
925
+** http://www.webtoolkit.info/sortable-html-table.html
926
+**
927
+*/
928
+static void output_table_sorting_javascript(const char *zTableId){
929
+ @ <script>
930
+ @ function SortableTable(tableEl){
931
+ @ this.tbody = tableEl.getElementsByTagName('tbody');
932
+ @ this.sort = function (cell) {
933
+ @ var column = cell.cellIndex;
934
+ @ this.sortIndex = column;
935
+ @ var newRows = new Array();
936
+ @ for (j = 0; j < this.tbody[0].rows.length; j++) {
937
+ @ newRows[j] = this.tbody[0].rows[j];
938
+ @ }
939
+ @ newRows.sort(this.sortText);
940
+ @ if (cell.getAttribute("sortdir") == 'down') {
941
+ @ newRows.reverse();
942
+ @ cell.setAttribute('sortdir','up');
943
+ @ } else {
944
+ @ cell.setAttribute('sortdir','down');
945
+ @ }
946
+ @ for (i=0;i<newRows.length;i++) {
947
+ @ this.tbody[0].appendChild(newRows[i]);
948
+ @ }
949
+ @ }
950
+ @ this.sortText = function(a,b) {
951
+ @ var i = thisObject.sortIndex;
952
+ @ aa = a.cells[i].textContent.replace(/^\W+/,'').toLowerCase();
953
+ @ bb = b.cells[i].textContent.replace(/^\W+/,'').toLowerCase();
954
+ @ if(aa==bb) return 0;
955
+ @ if(aa<bb) return -1;
956
+ @ return 1;
957
+ @ }
958
+ @ var thisObject = this;
959
+ @ var x = tableEl.getElementsByTagName('thead');
960
+ @ if(!(this.tbody && this.tbody[0].rows && this.tbody[0].rows.length>0)){
961
+ @ return;
962
+ @ }
963
+ @ if(x && x[0].rows && x[0].rows.length > 0) {
964
+ @ var sortRow = x[0].rows[0];
965
+ @ } else {
966
+ @ return;
967
+ @ }
968
+ @ for (var i=0; i<sortRow.cells.length; i++) {
969
+ @ sortRow.cells[i].sTable = this;
970
+ @ sortRow.cells[i].onclick = function () {
971
+ @ this.sTable.sort(this);
972
+ @ return false;
973
+ @ }
974
+ @ }
975
+ @ }
976
+ @ var t = new SortableTable(gebi("%s(zTableId)"));
977
+ @ </script>
978
+}
979
+
919980
920981
/*
921982
** WEBPAGE: /rptview
922983
**
923984
** Generate a report. The rn query parameter is the report number
@@ -992,22 +1053,24 @@
9921053
"%s/tktnew", g.zTop);
9931054
}
9941055
style_header(zTitle);
9951056
output_color_key(zClrKey, 1,
9961057
"border=\"0\" cellpadding=\"3\" cellspacing=\"0\" class=\"report\"");
997
- @ <table border="1" cellpadding="2" cellspacing="0" class="report">
1058
+ @ <table border="1" cellpadding="2" cellspacing="0" class="report"
1059
+ @ id="reportTable">
9981060
sState.rn = rn;
9991061
sState.nCount = 0;
10001062
report_restrict_sql(&zErr1);
10011063
sqlite3_exec_readonly(g.db, zSql, generate_html, &sState, &zErr2);
10021064
report_unrestrict_sql();
1003
- @ </table>
1065
+ @ </tbody></table>
10041066
if( zErr1 ){
10051067
@ <p class="reportError">Error: %h(zErr1)</p>
10061068
}else if( zErr2 ){
10071069
@ <p class="reportError">Error: %h(zErr2)</p>
10081070
}
1071
+ output_table_sorting_javascript("reportTable");
10091072
style_footer();
10101073
}else{
10111074
report_restrict_sql(&zErr1);
10121075
sqlite3_exec_readonly(g.db, zSql, output_tab_separated, &count, &zErr2);
10131076
report_unrestrict_sql();
10141077
--- src/report.c
+++ src/report.c
@@ -694,11 +694,11 @@
694 }
695 }
696
697 /* The first time this routine is called, output a table header
698 */
699 @ <tr>
700 zTid = 0;
701 for(i=0; i<nArg; i++){
702 char *zName = azName[i];
703 if( i==pState->iBg ) continue;
704 if( pState->iNewRow>=0 && i>=pState->iNewRow ){
@@ -716,11 +716,11 @@
716 }
717 }
718 if( g.perm.Write && zTid ){
719 @ <th>&nbsp;</th>
720 }
721 @ </tr>
722 }
723 if( azArg==0 ){
724 @ <tr><td colspan="%d(pState->nCol)">
725 @ <i>No records match the report criteria</i>
726 @ </td></tr>
@@ -914,10 +914,71 @@
914 rc = sqlite3_finalize(pStmt);
915 fossil_free(azVals);
916 return rc;
917 }
918
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
919
920 /*
921 ** WEBPAGE: /rptview
922 **
923 ** Generate a report. The rn query parameter is the report number
@@ -992,22 +1053,24 @@
992 "%s/tktnew", g.zTop);
993 }
994 style_header(zTitle);
995 output_color_key(zClrKey, 1,
996 "border=\"0\" cellpadding=\"3\" cellspacing=\"0\" class=\"report\"");
997 @ <table border="1" cellpadding="2" cellspacing="0" class="report">
 
998 sState.rn = rn;
999 sState.nCount = 0;
1000 report_restrict_sql(&zErr1);
1001 sqlite3_exec_readonly(g.db, zSql, generate_html, &sState, &zErr2);
1002 report_unrestrict_sql();
1003 @ </table>
1004 if( zErr1 ){
1005 @ <p class="reportError">Error: %h(zErr1)</p>
1006 }else if( zErr2 ){
1007 @ <p class="reportError">Error: %h(zErr2)</p>
1008 }
 
1009 style_footer();
1010 }else{
1011 report_restrict_sql(&zErr1);
1012 sqlite3_exec_readonly(g.db, zSql, output_tab_separated, &count, &zErr2);
1013 report_unrestrict_sql();
1014
--- src/report.c
+++ src/report.c
@@ -694,11 +694,11 @@
694 }
695 }
696
697 /* The first time this routine is called, output a table header
698 */
699 @ <thead><tr>
700 zTid = 0;
701 for(i=0; i<nArg; i++){
702 char *zName = azName[i];
703 if( i==pState->iBg ) continue;
704 if( pState->iNewRow>=0 && i>=pState->iNewRow ){
@@ -716,11 +716,11 @@
716 }
717 }
718 if( g.perm.Write && zTid ){
719 @ <th>&nbsp;</th>
720 }
721 @ </tr></thead><tbody>
722 }
723 if( azArg==0 ){
724 @ <tr><td colspan="%d(pState->nCol)">
725 @ <i>No records match the report criteria</i>
726 @ </td></tr>
@@ -914,10 +914,71 @@
914 rc = sqlite3_finalize(pStmt);
915 fossil_free(azVals);
916 return rc;
917 }
918
919 /*
920 ** Output Javascript code that will enables sorting of the table with
921 ** the id zTableId by clicking.
922 **
923 ** The javascript is derived from:
924 **
925 ** http://www.webtoolkit.info/sortable-html-table.html
926 **
927 */
928 static void output_table_sorting_javascript(const char *zTableId){
929 @ <script>
930 @ function SortableTable(tableEl){
931 @ this.tbody = tableEl.getElementsByTagName('tbody');
932 @ this.sort = function (cell) {
933 @ var column = cell.cellIndex;
934 @ this.sortIndex = column;
935 @ var newRows = new Array();
936 @ for (j = 0; j < this.tbody[0].rows.length; j++) {
937 @ newRows[j] = this.tbody[0].rows[j];
938 @ }
939 @ newRows.sort(this.sortText);
940 @ if (cell.getAttribute("sortdir") == 'down') {
941 @ newRows.reverse();
942 @ cell.setAttribute('sortdir','up');
943 @ } else {
944 @ cell.setAttribute('sortdir','down');
945 @ }
946 @ for (i=0;i<newRows.length;i++) {
947 @ this.tbody[0].appendChild(newRows[i]);
948 @ }
949 @ }
950 @ this.sortText = function(a,b) {
951 @ var i = thisObject.sortIndex;
952 @ aa = a.cells[i].textContent.replace(/^\W+/,'').toLowerCase();
953 @ bb = b.cells[i].textContent.replace(/^\W+/,'').toLowerCase();
954 @ if(aa==bb) return 0;
955 @ if(aa<bb) return -1;
956 @ return 1;
957 @ }
958 @ var thisObject = this;
959 @ var x = tableEl.getElementsByTagName('thead');
960 @ if(!(this.tbody && this.tbody[0].rows && this.tbody[0].rows.length>0)){
961 @ return;
962 @ }
963 @ if(x && x[0].rows && x[0].rows.length > 0) {
964 @ var sortRow = x[0].rows[0];
965 @ } else {
966 @ return;
967 @ }
968 @ for (var i=0; i<sortRow.cells.length; i++) {
969 @ sortRow.cells[i].sTable = this;
970 @ sortRow.cells[i].onclick = function () {
971 @ this.sTable.sort(this);
972 @ return false;
973 @ }
974 @ }
975 @ }
976 @ var t = new SortableTable(gebi("%s(zTableId)"));
977 @ </script>
978 }
979
980
981 /*
982 ** WEBPAGE: /rptview
983 **
984 ** Generate a report. The rn query parameter is the report number
@@ -992,22 +1053,24 @@
1053 "%s/tktnew", g.zTop);
1054 }
1055 style_header(zTitle);
1056 output_color_key(zClrKey, 1,
1057 "border=\"0\" cellpadding=\"3\" cellspacing=\"0\" class=\"report\"");
1058 @ <table border="1" cellpadding="2" cellspacing="0" class="report"
1059 @ id="reportTable">
1060 sState.rn = rn;
1061 sState.nCount = 0;
1062 report_restrict_sql(&zErr1);
1063 sqlite3_exec_readonly(g.db, zSql, generate_html, &sState, &zErr2);
1064 report_unrestrict_sql();
1065 @ </tbody></table>
1066 if( zErr1 ){
1067 @ <p class="reportError">Error: %h(zErr1)</p>
1068 }else if( zErr2 ){
1069 @ <p class="reportError">Error: %h(zErr2)</p>
1070 }
1071 output_table_sorting_javascript("reportTable");
1072 style_footer();
1073 }else{
1074 report_restrict_sql(&zErr1);
1075 sqlite3_exec_readonly(g.db, zSql, output_tab_separated, &count, &zErr2);
1076 report_unrestrict_sql();
1077

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button