![]() |
Search:
|
Page last modified 02:28, 6 Nov 2011 by tehmina.khan
Template:MindTouch > ToBeDeveloped > Task/To Do Lists > Template:TSTable
Template:TSTableTable of contentsNo 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(" "); 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*(\\ )*(\\<br ?\\/?\\>)*)*/,''); html = html.replace( /(\\s*(\\ )*(\\<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>; |
|
Powered by MindTouch Core |