.
The Open Protein Structure Annotation Network
PDB Keyword
.

Template:TSTable

    Table of contents
    No headers
    // UNSAFECONTENT PERMISSION CHECK
    // This code checks if the template is properly installed for unsafe content execution,
    // and may be removed if this check is not desired.  If you leave this here, add your new code
    // in a new DekiScript block below this one.
    var chkunsafe = wiki.inclusions()[-1];
    if (!wiki.pagepermissions(chkunsafe.id, chkunsafe.author.id).unsafecontent)
      <div style="color:red; width:75%; padding:5px; border:1px solid red;">
        "WARNING: The page '"..chkunsafe.path.."' must be re-saved by a user with UNSAFECONTENT permission in order to work correctly. ";
        <a href="http://developer.mindtouch.com/en/kb/Using_templates_which_require_UNSAFECONTENT_permission"> "See this" </a>;
        " for more info."; 
      </div>;
    // TsTable template, by neilw, 2009
    // Versions
    //    1.00    7/27/2009   neilw    First published version
    //    1.10    7/29/2009   neilw    Added pagination support (doesn't work with filter yet)
    //    1.11    8/25/2009   neilw    Fixed bug with pager and fewer than 10 rows
    //    1.12    9/25/2009   neilw    Added support for data as list of lists
    //    1.13    10/8/2009   neilw    Put in a spacer for empty table cells
    //    1.14    10/9/2009   neilw    Fixed a bug introduced in 1.13 (sigh)
    //    1.15    10/12/2009  neilw    Cleaned up CSS, especially for IE
    //    1.16    10/13/2009  neilw    Added default filter option, reduced spurious error alerts
    //    1.17    2/12/2010   neilw    Improved table header HTML for improved reliability
    //    1.18    2/23/2010   neilw    Added UNSAFECONTENT permission check
    //    1.20    7/14/2010   neilw    Added full support for "sorter" option in columns
    //                                 Added "nosort" option for table
    //    1.21    7/19/2010   neilw    Now properly recognize "0" as a number (new tablesorter script, new name!!!)
    //    1.22    7/26/2010   neilw    Improved "sort:false" option
    //    1.23    8/13/2010   neilw    Cleaned up stylesheet a *little*
    //    1.24    11/22/2010  neilw    Added "nodata" option
    
    // LOCAL SETTINGS
    
    //This template requires the following files to be installed as specified below:
    var tablesorter_uri      = "http://developer.mindtouch.com/@api/deki/files/6272/=tstable.tablesorter.min.js";
    var tablesorter_bg_uri   = "http://developer.mindtouch.com/@api/deki/files/4627/=tablesorter_bg.gif";
    var tablesorter_asc_uri  = "http://developer.mindtouch.com/@api/deki/files/4626/=tablesorter_asc.gif";
    var tablesorter_desc_uri = "http://developer.mindtouch.com/@api/deki/files/4624/=tablesorter_desc.gif";
    
    var pager_uri            = "http://developer.mindtouch.com/@api/deki/files/4651/=jquery.tablesorter.pager.js";
    var pager_first_uri      = "http://developer.mindtouch.com/@api/deki/files/4648/=pager_first.png";
    var pager_prev_uri       = "http://developer.mindtouch.com/@api/deki/files/4647/=pager_prev.png";
    var pager_next_uri       = "http://developer.mindtouch.com/@api/deki/files/4650/=pager_next.png";
    var pager_last_uri       = "http://developer.mindtouch.com/@api/deki/files/4649/=pager_last.png";
    
    // The following variables define important styles for this template:
    var thead_unsel_color = "#D0E0E0";  // Color of unselected header cell
    var thead_sel_color   = "#8DBDD8";  // Color of selected header cell
    var zebra_color       = "#ECECF0";  // Color of odd rows when "zebra" is specified
    
    // USAGE: template.TsTable(options, columns, data)
    //    "columns": Optional array of column specifications, one for each table column. Each column spec can be either a
    //        simple string or a map.  This argument only applies if "data" is also specified (GENERATE mode).  If it's a
    //        string, then it specifies the key and title for the column data.  If it's a map, then the possible fields are:
    //            key: keyname for the map element containing the cell data.  THIS IS THE ONE AND ONLY FIELD THAT IS
    //                REQUIRED.  If surrounded by parentheses, will be evaluated as a Dekiscript expression to provided
    //                the cell value (see docs).  
    //            title: Title for the column.  If not specified, will use "key".
    //            width: width of column
    //            style: style to apply to this cell.  If surrounded by parentheses, will be evalauted as a Dekiscript
    //                expression (see docs)
    //            initial: set this column as initial sort column; 0 ==> ascending, 1 ==> descending
    //            sorter: control sortability on this column (this is case sensitive!):
    //                false ==> disable sorting on this column
    //                "text" ==> sort column as text
    //                "digit" ==> sort column as numbers
    //                "currency" ==> sort column as currency values (ignore leading currency symbol)
    //                "ipAddress" ==> sort as IP addresses
    //                "url" ==> sort as URL; ignore protocol prefix
    //                "isoDate" ==> sort as ISO formatted date (yyyy-M-d; separator may be "-" or "/")
    //                "percent" ==> sort as percentage (ignore trailing "%")
    //                "usLongDate" ==> sort as date (MMM dd, (yyyy | 'yy) [hh:mm:ss (AM|PM))
    //                "usShortDate" ==> sort as date (MM-dd-(yyyy|yy)
    //                "time" ==> sort as time (hh:mm (am|pm))
    //            date: TBD
    //    "options": Optional map containing an assortment of options that apply to the whole table:
    //        id: ID attribute of the table element.  If we're applying tablesorter to an existing table, the template
    //            will look for a table with this name.  If we're generating a table, its ID will be set to this value
    //        width: width of the entire table
    //        initial: initial sort order for the table.  This is the "sortlist" parameter for the tablesorter extension.
    //        rowstyle: style applied to each row.  If surrounded by parentheses, will be evaluated as a Dekiscript
    //            expression (see docs)
    //        zebra: set to true to enable zebra-striping of the table row
    //        pager: enable the table pager (doesn't work with filters yet!)
    //        sort: enable or disable sorting on the entire table (default:true)
    //        nodata: message to be printed when there is no data (default:  "(no data)")
    //    "data": array of maps or lists containing data for each row of the table.  The "columns" argument specified in the "key"
    //        element which element of the map will be used to supply data for this cell.  Additional elements may be
    //        present in the map for purposes of style or content evaluation (see docs), or it will be ignored.  If a data row is
    //        a list, then the elements will be used in order.
    //    "filter": array of 2-element arrays, each specifying optional filters that may be applied to the table.
    //        The first sub-array element specifies the name of the filter, which will be displayed in the
    //        <select> widget.  The second element is Dekiscript code which is applied to each row in the table;
    //        if the code evaluates to "true" then the row will be displayed when that option is selected.
    //        The first selection, and the default, is always "show all items", so you don't need to specify
    //        that one.  See docs for more details.
    
    /**** Misc "globals" ****/
    var options_arg = $1 ?? $options ?? {};
    var columns_arg = $0 ?? $columns;
    var data_arg    = $2 ?? $data;
    if (data_arg is map)
        let data_arg = map.values(data_arg);
    var filter_arg  = $3 ?? $filter;
    var apply = (data_arg == nil); // if no data, modify existing table (APPLY mode)
    
    var eval_re = "(^\\((.*)\\)$)";    // regular expression to detect "eval"
    var errors = [];     // list of error messages
    
    /**** Argument Processing ****/ 
    //
    // "columns" arg
    //
    var c_series = [];
    var columns = [];    // processed list of column specifications
    var headers = {};    // "headers" arg for tablesorter
    var sortlist = [];   // "sortlist" arg for tablesorter
    if (columns_arg == nil) {
        if (!apply) let errors ..= [ "must specify COLUMNS when DATA is also specified ('generate' mode)" ];
    }
    else {
        let c_series = num.series(0, #columns_arg - 1);
        if (apply) let errors ..= [ "WARNING: ignoring COLUMNS in 'apply' mode" ];
        else if (columns_arg is not list) let errors ..= [ 'COLUMNS: must be a list' ];
        else foreach (var i in c_series) {
            var c = columns_arg[i];
            if (c is str)
                let c = { key:c };
        // check for bogus extra fields
            foreach (var k in map.keys(c))
                if (!list.contains([ "title","key","width","sorter","initial","style" ], //"date","type","hide" ]
                    string.tolower(k))) let errors ..= [ "COLUMNS["..i.."]: unknown field: '"..k.."'" ];
        // "key" field
            if (c.key == nil) {
                let errors ..= [ "COLUMNS["..i.."]: no KEY supplied" ];
                let c ..= { key:"xxx" };
            }
            else if (string.match(c.key, eval_re)) let c ..= { eval_key:true };
        // "title" field
            if (c.title == nil) let c ..= { title:c.key };
        // "sorter" field
            if (c.sorter is bool || c.sorter is str) {
                var sorterOptions = [ "text", "digit", "currency", "ipAddress", "url", "isoDate",
                    "percent", "usLongDate", "shortDate", "time", "metadata" ];
                if (c.sorter is str && !list.contains(sorterOptions, c.sorter))
                    let errors ..= [ "COLUMNS["..i.."]: invalid SORTER option '"..c.sorter.."'" ];
                else
                    let headers ..= { (i):{ sorter:c.sorter } };
            }
        // "initial" field
            if (c.initial != nil) {
                if (!string.match(c.initial, "(^[01]$)")) let errors ..= [ "COLUMNS["..i.."]: INITIAL must be 0 or 1" ];
                else let sortlist ..= [ [i,c.initial] ];
            }
        // "style" field
            if (c.style != nil && string.match(c.style, eval_re)) let c ..= { eval_style:true };
        // Build columns
            let columns ..= [ c ];
        }
    }
    //
    // "options" arg
    //
    
    // check for bogus extra fields
    foreach (var k in map.keys(options_arg))
        if (!list.contains(["id","width","zebra","initial","rowstyle","pager","sort","nodata" ], string.tolower(k)))
            let errors ..= [ 'OPTIONS: unknown option: ' .. k ];
    // simple fields
    var tname    = options_arg.id?? (apply ? nil : @tname);
    var find     = (tname == nil);
    if (find) let tname = @tname; 
    var width    = options_arg.width;
    var widgets  = options_arg.zebra == true ? [ 'zebra' ] : [];
    let sortlist = options_arg.initial ?? sortlist;
    var pager    = options_arg.pager ?? false;
    var perpage  = [ 10, 25, 50, 100, 250, 500 ];
    var enableSorting   = options_arg.sort ?? true;
    var noData = options_arg.nodata;
    if (noData is not str) let noData = "(no data)";
    
    // "rowstyle" field
    if (options_arg.rowstyle != nil && string.match(options_arg.rowstyle, eval_re))
        let options_arg ..= { eval_rowstyle:true };
    
    //
    // "data" and "filter" arg
    //
    var filter = [];
    var filter_default = -1;
    var filter_code = [];
    if (filter_arg) {
        if (filter_arg is not list) let errors ..= [ "expected FILTER arg to be a list" ];
        else if (pager)             let errors ..= [ "filter won't work when pager is enabled (disabling filter)" ];
        else {
            let filter = [ ];
            let  filter_default = 0;
            let filter_code = [ ];
            foreach (var i in num.series(0,#filter_arg-1)) {
                var f = filter_arg[i];
                if (f is not list)
                    let errors ..= [ "FILTER: option "..i.." is not a list" ];
                else {
                    if (#f != 2 && !(#f == 3 && f[2] is bool))
                    let errors ..= [ "FILTER: option "..i.." is not a list of two elementsvalid" ];
                    
                else { 
                    let filter ..= [ f[0] ];                 
                    let filter_code ..= [ f[1] ];
                        if (f[2]) let filter_default = i;
                    }
                }
            }
        }
    }
    
    var space = web.html("&nbsp;");
    var data = [];       // processed data array
    if (!apply) {
        foreach (var r in data_arg) {
            if (r is list) let r = { (i):r[i] foreach var i in num.series(0,#r-1) };
            if (r is map) {
                let class = [];
                let r ..= { rowstyle:(options_arg.eval_rowstyle ?
                    list.apply([r],options_arg.rowstyle)[0] : options_arg.rowstyle) };
                foreach (var i in c_series) {
                    var c = columns[i];
                    if (c.eval_key || r[c.key] != nil)
                        let r ..= { (i): (c.eval_key ? list.apply([r],c.key)[0] : r[c.key]) };
                }
                foreach (var i in c_series) {
                    var c = columns[i];
                    if (c.style) let r ..= { ("style"..i): (c.eval_style ? list.apply([r],c.style)[0] : c.style ) };
                }
                if (#filter_code)
                    foreach (var i in num.series(0,#filter_code-1))
                        if (list.apply([r],filter_code[i])[0])
                            let class ..= [ "tsf"..i ];
                let data ..= [ r..{ class:string.join(class," ") } ];
            }
            else
                let errors ..= [ "DATA: item ".. __index .. " is not a map or list" ];
        }
    }
    else if (filter_arg)
        let errors ..= [ "WARNING: ignoring FILTER arg in 'apply' mode" ];
    
    //
    // Output XML
    //
    <html>
    // Scripts and stylesheets go in the head
    <head>
    <script type="text/javascript" src=(tablesorter_uri)></script>;
    <script type="text/javascript"> var garbage = 0; </script>;
    <script type="text/javascript" src=(pager_uri)></script>;
    
    <script type="text/javascript">"
    // Call main tablesorter function
    DekiWiki.$(document).ready(function($) {
        tstableApply($, "..json.emit(apply)..","..json.emit(find)..","..json.emit(@id)..","..
            json.emit(tname)..","..json.emit(headers)..","..json.emit(sortlist)..","..
            json.emit(widgets)..","..json.emit(filter_default)..","..json.emit(pager)..","..json.emit(enableSorting)..");
    });
    "</script>;
    <script type="text/javascript">"
    // Apply tablesorter to table
    function tstableApply($, apply, find, id, name, headers, sortlist, widgets, filter, pager, enable) {
    // Find the table
        var $table;
        if (!find)
            $table = $('table#'+name);
        else {
            var pid = 'p#' + id;
            var $nodes = $(pid).nextAll();
            for (var i = 0; i < $nodes.length; i++) {
                $table = $nodes.eq(i);
                if ($table.is('table')) break;
                $table = $table.find('table:first');
                if ($table.length) break;
            }
            if (!$table.length) {
                alert(\"ERROR: TsTable: can't find table\"); 
                return;
            }
            $table.attr({'id':name, 'border':'0', 'cellspacing':'0px', 'cellpadding':'3px'});
        }
    // set 'tablesorter' class if necessary
        if (!$table.hasClass('tablesorter')) $table.addClass('tablesorter');
    // Copy header row to 'thead' element if necessary
        var $header = $table.find('thead tr');
        if (!$header.length) {
            var $ohr = $table.find('tr:eq(0)');
            if (!$ohr.length) return;	// table is empty, bail out
            $table.prepend('<thead><tr>'+$ohr.html()+'</tr></thead>');
            $ohr.remove();
            $header = $table.find('thead tr');
        }
    // Convert header <td> to <th> if necessary
        if (apply) {
            var hdrhtml = '';
            $header.children().each(function() { hdrhtml += '<th>'+$(this).html()+'</th>'; });
            $header.html(hdrhtml);
        }
    // Convert format of each header element to reserve room for arrow
        $header.children().each(function() {
            $(this).css('padding-right','20px');
        });
    // Clean up leading and trailing space
        $table.find('td,th').each(function() {
     	$(this).find('p:first-child').css({'margin-top':'0px','padding-top':'0px'});
    	$(this).find('p:last-child').css({'margin-bottom':'0px','padding-bottom':'0px'});
            var html = $(this).html();
            html = html.replace(/^(\\s*(\\&nbsp;)*(\\<br ?\\/?\\>)*)*/,'');
            html = html.replace( /(\\s*(\\&nbsp;)*(\\<br ?\\/?\\>)*)*$/,'');
            $(this).html(html);
        });
    // If we're not going to enable sorting, get out
        if (!enable) return;
    // Install filter
        if (filter >= 0) {
            var selectid = 'select#tsf' + id;
            $(selectid).change(function() {
                var $options = $(this).find('option:selected');
                $table.find('tbody.tsf > tr').each(function() {
                    var show = false;
                    var $row = $(this);
                    $options.each(function() { show |= $row.hasClass($(this).attr('value')); } );
                    if (show)    $row.show();
                    else         $row.hide();
                });
                $table.trigger('applyWidgets');
                return(false);
            });
            $(selectid).find('option').each(function(i) { $(this).attr('selected',i==filter?'selected':''); });
            $(selectid).change();
        }
    // Now activate tablesorter
        $table.tablesorter({ 
            headers: headers, sortList: sortlist, widgets: widgets,
            cssHeader: 'tsHeader', cssAsc: 'tsHeaderSortUp', cssDesc: 'tsHeaderSortDown'
        });
        if (pager) {
            var pagerid = '#'+id+'pager';
            $(pagerid).find('option').each(function(i) { $(this).attr('selected',i==0?'selected':''); });
            $table.tablesorterPager({container: $('#'+id+'pager'), positionFixed:false});
        }
    }
    "</script>;
    
    // Styles
    var tid = "table.tablesorter#"..tname;
    <style type="text/css">"
    .tablesorter {
        border-collapse: separate;
        border-left: solid #808080 1px;
        border-top:  solid #808080 1px;
    }
    .tablesorter > thead > tr > th, .tablesorter > tbody > tr > td, .tablesorter > tfoot > tr > td {
        border-right:  solid #808080 1px;
        border-bottom: solid #808080 1px;
    }
    .tablesorter > thead > tr > th, .tablesorter > tfoot > tr > th {
        background-color: "..thead_unsel_color..";
        font-weight: bold;
    }
    .tsHeader {
            background-image: url("..tablesorter_bg_uri..");
            background-repeat: no-repeat;
            background-position: center right;
            cursor: pointer;
    }
    .tablesorter > tbody tr.odd    { background-color:"..zebra_color.."; }
    .tsHeader.tsHeaderSortUp   {
        background-image: url("..tablesorter_asc_uri..");
        background-color: "..thead_sel_color..";
    }
    .tsHeader.tsHeaderSortDown {
        background-image: url("..tablesorter_desc_uri..");
        background-color: "..thead_sel_color..";
    }
    "</style>;
    </head>
    
    // Generate table HTML in the body
    <body>
    // Error messages
        if (#errors)
          <div style="color:red; font-weight:bold;"> "TSTABLE ERRORS:";
            <ul> foreach (var e in errors) <li> e </li>; </ul>
          </div>;
    // Insert marker if applying
        if (apply) { <p id=(@id) style="display:none;" /><div />; }
    // Else generate table
        else {
          if (#filter) {
            <p><span>"Show: "</span><select id=("tsf"..@id)>
                foreach (var i in num.series(0,#filter-1))
                    <option value=("tsf"..i) selected=(i==0?"selected":"")> filter[i] </option>;
            </select></p>;
          }  
          <table class="tablesorter" id=(tname) width=(width) cellpadding="3px" cellspacing="0px">
        // Header
            <thead><tr> foreach (var c in columns) <th width=(c.width)>c.title</th>; </tr></thead>
        // Body
            <tbody class="tsf">
                foreach (var r in data) <tr style=(r.rowstyle) class=(r.class)>
                    foreach (var i in c_series) <td style=(r["style"..i])> (r[i]==nil || r[i]=="") ? space : r[i] </td>;
                </tr>;
                if (!#data) <tr><td colspan=(#columns)> noData </td></tr>;
            </tbody>
            if (pager) {
              <tfoot style=(#data > perpage[0] ? "" : "display:none")>
               <tr bgcolor=(thead_unsel_color)><td id=(@id .. "pager") colspan=(#columns) align="center">
                <img class="first" style="cursor:pointer" src=(pager_first_uri) />
                <img class="prev" style="cursor:pointer" src=(pager_prev_uri) />
                <img src="/skins/common/icons/icon-trans.gif" width="8" height="8" />
                <span class="pagedisplay"> " " </span>
                <img src="/skins/common/icons/icon-trans.gif" width="8" height="8" />
                <img class="next" style="cursor:pointer" src=(pager_next_uri) />
                <img class="last" style="cursor:pointer" src=(pager_last_uri) />
                <select class="pagesize" style="float:right">
                  foreach (var pp in perpage) {
                      <option value=(pp) selected=(__index == 0 ? "selected" : "")> (pp>#data ? "all":pp) </option>;
                      if (pp > #data) break;
                  }
    	    </select>
              </td></tr></tfoot>;
            }
          </table>;
        }
    </body>
    </html>;

    Reviews

    References

     

    No references found.

    Tag page
    • No tags

    Files (0)

     
    You must login to post a comment.
    All content on this site is licensed under a Creative Commons Attribution 3.0 License
    Powered by MindTouch