<%doc> Example: include( '/elements/customer-table.html', ### # required ### #listrefs... 'header' => [ '#', 'Item' ], 'fields' => [ 'column', sub { my ($row,$param) = @_; $param->{"column$row"}; }, ], ### # optional ### 'name_singular' => 'customer', #label 'custnum_update_callback' => 'name_of_js_callback' #passed a rownum #listrefs 'type' => ['immutable', ''], # immutable, checkbox, date or ''/text 'align' => [ 'c', 'l', 'r', '' ], 'size' => [], # sizes ignored for immutable 'color' => [], 'footer' => ['string', '_TOTAL'], # strings or the special #value _TOTAL 'footer_align' => [ 'c', 'l', 'r', '' ], 'param' => { column0 => 1 }, # preset column of row 0 to 1 ) Some incomplete notes for javascript programmers: On page load, existing rows are initialized by passing values to addRow based on existing cgi values. An empty row (marked with the 'emptyrow' attribute) is created by invoking addRow without values. After that, to keep the non-empty row count (totalrows) accurate, use newEmptyRow to create the next row. There should only be one empty row at a time. Global vars: total_el - element for displaying total number of rows totalrows - total number of non-empty rows rownum - really more of a "next row" value, used by addRow allrows - array of tr elements, one for each row Don't confuse the global rownum with the element attribute rownum that is set as a reference point on some of the elements generated by this script. They have different values. Some of the functions: updateTotalRow() - updates total_el based on value of totalrows addDeleteButton(searchrow) - adds delete button to searchrow newEmptyRow() - replaces old empty row deleteRow() - removes the row specified by this.rownum addRow(values) - adds a new row (marked as empty if values aren't specified) This mason element is currently only used by misc/batch-cust_pay.html, and probably should be cleaned up more before being used by anything else. % foreach my $header ( @{$opt{header}} ) { % } % my @rownums = sort { $a <=> $b } map /^custnum(\d+)$/, keys %$param; % my $col = 0; % foreach my $footer ( @{$opt{footer}} ) { % my $align = $align{ $opt{'footer_align'}->[$col] || 'c' }; % if ($footer eq '_TOTAL' ) { % my $id = $opt{'fields'}->[$col]; % $id = ref($id) ? "column${col}_TOTAL" : "${id}_TOTAL"; % } else { % } % $col++; % }
Inv # Cust # Status Customer Balance<% $header %>
Total <% @rownums || 0 %> <% PL($opt{name_singular} || 'customer', ( @rownums || 0 ) ) %>  <% sprintf('%.2f', $total[$col] ) %><% $footer %>
<% include('/elements/xmlhttp.html', 'url' => $p. 'misc/xmlhttp-cust_main-search.cgi', 'subs' => [qw( custnum_search smart_search invnum_search )], ) %> <%init> my(%opt) = @_; my $conf = new FS::Conf; my $date_format = $conf->config('date_format') || '%m/%d/%Y'; my $types = $opt{'type'} ? [ @{$opt{'type'}} ] : []; my $sizes = $opt{'size'} ? [ @{$opt{'size'}} ] : []; my $param = $opt{param}; $param = $cgi->Vars if $cgi->param('error'); $opt{$_} ||= [] foreach qw(align color footer footer_align); my @total = map 0, @{$opt{footer}}; my %align = ( 'l' => 'left', 'r' => 'right', 'c' => 'center', ); my $money_char = $conf->config('money_char') || '$';