-%
-%
% # options example...
% # (everything not commented required is optional)
% #
% # # basic options, required
-% # 'title' => 'Page title',
-% # 'name' => 'items', #name for the records returned
+% # 'title' => 'Page title',
+% #
+% # 'name_singular' => 'item', #singular name for the records returned
+% # #OR# # (preferred, will be pluralized automatically)
+% # 'name' => 'items', #plural name for the records returned
+% # # (deprecated, will be singularlized
+% # # simplisticly)
% #
% # # some HTML callbacks...
% # 'menubar' => '', #menubar arrayref
% # 'html_init' => '', #after the header/menubar and before the pager
+% # 'html_form' => '', #after the pager, right before the results
+% # # (only shown if there are results)
+% # # (use this for any form-opening tag rather than
+% # # html_init, to avoid a nested form)
% # 'html_foot' => '', #at the bottom
% # 'html_posttotal' => '', #at the bottom
% # # (these three can be strings or coderefs)
% # 'select' => '*',
% # 'addl_from' => '', #'LEFT JOIN othertable USING ( key )',
% # 'extra_sql' => '', #'AND otherstuff', #'WHERE onlystuff',
-% #
+% # 'order_by' => 'ORDER BY something',
% #
% # },
% # # "select * from tablename";
% # 'disable_nonefound' => '', # set true to disable the "No matching Xs found"
% # # message
% #
+% # 'disableable' => 1, # set true if this table has a "disabled" field, to
+% # # hide disabled records & have "show disabled" links
+% # 'disabled_statuspos' => 3, #optional position (starting from 0) to insert
+% # #a Status column when showing disabled records
+% # #(query needs to be a qsearch hashref and
+% # # header & fields need to be defined)
+
+% # 'agent_virt' => 1, # set true if this search should be agent-virtualized
+% # 'agent_null_right' => 'Access Right', #opt. right to view global records
+% # 'agent_pos' => 3, #optional position (starting from 0) to insert
+% # #an Agent column
+% # #(query needs to be a qsearch hashref and
+% # # header & fields need to be defined)
+% #
% # #listref - each item is a literal column name (or method) or coderef
% # #if not specified all columns will be shown
% # 'fields' => [
% # # listref of URL base and column name (or method)
% # # or a coderef that returns the same
% # 'redirect' =>
-%
-% my $DEBUG = 0;
+% #
+% # #set to 1 (or column position for "disabled" status col) to enable
+% # #"show disabled/hide disabled" links
+% # #(can't be used with a literal query)
+% # 'disableable' => 1,
%
% my(%opt) = @_;
% #warn join(' / ', map { "$_ => $opt{$_}" } keys %opt ). "\n";
%
+% my $curuser = $FS::CurrentUser::CurrentUser;
+%
% my %align = (
% 'l' => 'left',
% 'r' => 'right',
% $opt{align} = [ map $align{$_}, split(//, $opt{align}) ],
% unless !$opt{align} || ref($opt{align});
%
+% if ( $opt{'agent_virt'} ) {
+%
+% my $agentnums_sql = $curuser->agentnums_sql(
+% 'null_right' => $opt{'agent_null_right'}
+% );
+%
+% $opt{'query'}{'extra_sql'} .=
+% ( $opt{'query'} =~ /WHERE/i ? ' AND ' : ' WHERE ' ).
+% $agentnums_sql;
+% $opt{'count_query'} .=
+% ( $opt{'count_query'} =~ /WHERE/i ? ' AND ' : ' WHERE ' ).
+% $agentnums_sql;
+%
+% if ( $opt{'agent_pos'} || $opt{'agent_pos'} eq '0'
+% and scalar($curuser->agentnums) > 1 ) {
+% #false laziness w/statuspos above
+% my $pos = $opt{'agent_pos'};
+%
+% foreach my $att (qw( align style color size )) {
+% $opt{$att} ||= [ map '', @{ $opt{'fields'} } ];
+% }
+%
+% splice @{ $opt{'header'} }, $pos, 0, 'Agent';
+% splice @{ $opt{'align'} }, $pos, 0, 'c';
+% splice @{ $opt{'style'} }, $pos, 0, '';
+% splice @{ $opt{'size'} }, $pos, 0, '';
+% splice @{ $opt{'fields'} }, $pos, 0,
+% sub { $_[0]->agentnum ? $_[0]->agent->agent : '(global)'; };
+% splice @{ $opt{'color'} }, $pos, 0, '';
+% splice @{ $opt{'links'} }, $pos, 0, '' #[ 'agent link?', 'agentnum' ]
+% if $opt{'links'};
+%
+% }
+%
+% }
+%
+% if ( $opt{'disableable'} ) {
+%
+% unless ( $cgi->param('showdisabled') ) { #modify searches
+%
+% $opt{'query'}{'hashref'}{'disabled'} = '';
+% $opt{'query'}{'extra_sql'} =~ s/^\s*WHERE/ AND/i;
+%
+% $opt{'count_query'} .=
+% ( $opt{'count_query'} =~ /WHERE/i ? ' AND ' : ' WHERE ' ).
+% "( disabled = '' OR disabled IS NULL )";
+%
+% } elsif ( $opt{'disabled_statuspos'}
+% || $opt{'disabled_statuspos'} eq '0' ) { #add status column
+%
+% my $pos = $opt{'disabled_statuspos'};
+%
+% foreach my $att (qw( align style color size )) {
+% $opt{$att} ||= [ map '', @{ $opt{'fields'} } ];
+% }
+%
+% splice @{ $opt{'header'} }, $pos, 0, 'Status';
+% splice @{ $opt{'align'} }, $pos, 0, 'c';
+% splice @{ $opt{'style'} }, $pos, 0, 'b';
+% splice @{ $opt{'size'} }, $pos, 0, '';
+% splice @{ $opt{'fields'} }, $pos, 0,
+% sub { shift->disabled ? 'DISABLED' : 'Active'; };
+% splice @{ $opt{'color'} }, $pos, 0,
+% sub { shift->disabled ? 'FF0000' : '00CC00'; };
+% splice @{ $opt{'links'} }, $pos, 0, ''
+% if $opt{'links'};
+% }
+%
+% #add show/hide disabled links
+% my $items = $opt{'name'} || PL($opt{'name_singular'});
+% if ( $cgi->param('showdisabled') ) {
+% $cgi->param('showdisabled', 0);
+% $opt{'html_posttotal'} .=
+% '( <a href="'. $cgi->self_url. qq!">hide disabled $items</a> )!;
+% $cgi->param('showdisabled', 1);
+% } else {
+% $cgi->param('showdisabled', 1);
+% $opt{'html_posttotal'} .=
+% '( <a href="'. $cgi->self_url. qq!">show disabled $items</a> )!;
+% $cgi->param('showdisabled', 0);
+% }
+%
+% }
+%
% my $type = '';
% my $limit = '';
-% my($maxrecords, $total, $offset, $count_arrayref);
+% my($confmax, $maxrecords, $total, $offset, $count_arrayref);
%
% if ( $cgi->param('_type') =~ /^(csv|\w*\.xls)$/ ) {
%
%
% } else { #setup some pagination things if we're in html mode
%
-% unless (exists($opt{'count_query'}) && length($opt{'count_query'})) {
-% ( $opt{'count_query'} = $opt{'query'} ) =~
-% s/^\s*SELECT\s*(.*?)\s+FROM\s/SELECT COUNT(*) FROM /i;
+% unless (exists($opt{count_query}) && length($opt{count_query})) {
+% ( $opt{count_query} = $opt{query} ) =~
+% s/^\s*SELECT\s*(.*?)\s+FROM\s/SELECT COUNT(*) FROM /i; #silly vim:/
+% }
+%
+% if ( $opt{disableable} && ! $cgi->param('showdisabled') ) {
+% $opt{count_query} .=
+% ( ( $opt{count_query} =~ /WHERE/i ) ? ' AND ' : ' WHERE ' ).
+% "( disabled = '' OR disabled IS NULL )";
% }
%
% my $conf = new FS::Conf;
-% $maxrecords = $conf->config('maxsearchrecordsperpage');
+% $confmax = $conf->config('maxsearchrecordsperpage');
+% if ( $cgi->param('maxrecords') =~ /^(\d+)$/ ) {
+% $maxrecords = $1;
+% } else {
+% $maxrecords ||= $confmax;
+% }
%
% $limit = $maxrecords ? "LIMIT $maxrecords" : '';
%
%
% # run the query
%
-% my $header = $opt{'header'};
+% my $header = $opt{header};
% my $rows;
-% if ( ref($opt{'query'}) ) {
+% if ( ref($opt{query}) ) {
%
-% #eval "use FS::$opt{'query'};";
-% $rows = [ qsearch(
-% $opt{'query'}->{'table'},
-% $opt{'query'}->{'hashref'} || {},
-% $opt{'query'}->{'select'},
-% $opt{'query'}->{'extra_sql'}. " $limit",
-% '',
-% (exists($opt{'query'}->{'addl_from'}) ? $opt{'query'}->{'addl_from'} : '')
-% ) ];
+% if ( $opt{disableable} && ! $cgi->param('showdisabled') ) {
+% #%search = ( 'disabled' => '' );
+% $opt{'query'}->{'hashref'}->{'disabled'} = '';
+% $opt{'query'}->{'extra_sql'} =~ s/^\s*WHERE/ AND/i;
+% }
%
+% #eval "use FS::$opt{'query'};";
+% $rows = [ qsearch({
+% 'select' => $opt{'query'}->{'select'},
+% 'table' => $opt{'query'}->{'table'},
+% 'addl_from' => (exists($opt{'query'}->{'addl_from'}) ? $opt{'query'}->{'addl_from'} : ''),
+% 'hashref' => $opt{'query'}->{'hashref'} || {},
+% 'extra_sql' => $opt{'query'}->{'extra_sql'},
+% 'order_by' => $opt{'query'}->{'order_by'}. " $limit",
+% }) ];
% } else {
-%
% my $sth = dbh->prepare("$opt{'query'} $limit")
% or die "Error preparing $opt{'query'}: ". dbh->errstr;
% $sth->execute
% $rows = $sth->fetchall_arrayref;
%
% $header ||= $sth->{NAME};
-%
% }
%
-% warn scalar(@$rows). ' rows returned from '.
-% ( ref($opt{'query'}) ? 'qsearch query' : 'literal SQL query' )
-% if $DEBUG || $opt{'debug'};
-%
-% # display the results - csv, xls or html
-%
% if ( $type eq 'csv' ) {
%
% #http_header('Content-Type' => 'text/comma-separated-values' ); #IE chokes
% my( $url, $method ) = @$redirect;
% redirect( $url. $rows->[0]->$method() );
% } else {
+% if ( $opt{'name_singular'} ) {
+% $opt{'name'} = PL($opt{'name_singular'});
+% }
% ( my $xlsname = $opt{'name'} ) =~ s/\W//g;
-% #$opt{'name'} =~ s/s$// if $total == 1;
-% $opt{'name'} =~ s/((s)e)?s$/$2/ if $total == 1; #should use Lingua::bs
-% # to "depluralize"
+% if ( $total == 1 ) {
+% if ( $opt{'name_singular'} ) {
+% $opt{'name'} = $opt{'name_singular'}
+% } else {
+% #$opt{'name'} =~ s/s$// if $total == 1;
+% $opt{'name'} =~ s/((s)e)?s$/$2/ if $total == 1;
+% }
+% }
%
% my @menubar = ();
% if ( $opt{'menubar'} ) {
% @menubar = @{ $opt{'menubar'} };
-% } else {
-% @menubar = ( 'Main menu' => $p );
+% #} else {
+% # @menubar = ( 'Main menu' => $p );
% }
-%
-%
-%
<% include( '/elements/header.html', $opt{'title'},
include( '/elements/menubar.html', @menubar )
)
: ''
%>
-% my $pager = include ( '/elements/pager.html',
-% 'offset' => $offset,
-% 'num_rows' => scalar(@$rows),
-% 'total' => $total,
-% 'maxrecords' => $maxrecords,
-% );
%
% unless ( $total ) {
% unless ( $opt{'disable_nonefound'} ) {
% }
% } else {
-
<TABLE>
<TR>
+
<TD VALIGN="bottom">
+
+ <FORM>
+
<% $total %> total <% $opt{'name'} %>
+
+% if ( $confmax && $total > $confmax ) {
+% $cgi->delete('maxrecords');
+% $cgi->param('_dummy', 1);
+
+%# ( show <SELECT NAME="maxrecords" onChange="this.form.submit();">
+ ( show <SELECT NAME="maxrecords" onChange="window.location = '<% $cgi->self_url %>;maxrecords=' + this.options[this.selectedIndex].value;">
+
+% foreach my $max ( map { $_ * $confmax } qw( 1 5 10 25 ) ) {
+ <OPTION VALUE="<% $max %>" <% ( $maxrecords == $max ) ? 'SELECTED' : '' %>><% $max %></OPTION>
+% }
+
+ </SELECT> per page )
+
+% $cgi->param('maxrecords', $maxrecords);
+% }
+
<% defined($opt{'html_posttotal'})
? ( ref($opt{'html_posttotal'})
? &{$opt{'html_posttotal'}}()
: ''
%>
<BR>
+
% if ( $opt{'count_addl'} ) {
-% my $n=0; foreach my $count ( @{$opt{'count_addl'}} ) {
+% my $n=0; foreach my $count ( @{$opt{'count_addl'}} ) {
- <% sprintf( $count, $count_arrayref->[++$n] ) %><BR>
-% }
+ <% sprintf( $count, $count_arrayref->[++$n] ) %><BR>
+
+% }
% }
+ </FORM>
</TD>
+
% unless ( $opt{'disable_download'} ) {
<TD ALIGN="right">
as <A HREF="<% $cgi->self_url %>">CSV file</A>
</TD>
+% $cgi->param('_type', "html" );
% }
</TR>
<TR>
<TD COLSPAN=2>
- <% $pager %>
+
+ <% my $pager = include ( '/elements/pager.html',
+ 'offset' => $offset,
+ 'num_rows' => scalar(@$rows),
+ 'total' => $total,
+ 'maxrecords' => $maxrecords,
+ ) %>
+
+ <% defined($opt{'html_form'})
+ ? ( ref($opt{'html_form'})
+ ? &{$opt{'html_form'}}()
+ : $opt{'html_form'}
+ )
+ : ''
+ %>
<% include('/elements/table-grid.html') %>
%
% my $tableref = $_;
%
-% '<TABLE CLASS="inv" CELLSPACING=0 CELLPADDING=0>'.
+% '<TABLE CLASS="inv" CELLSPACING=0 CELLPADDING=0 WIDTH="100%">'.
%
% join('', map {
%
%
% join('', map {
%
-% my $element = $_;
+% my $e = $_;
%
-% '<TD'.
-% ( $element->{'align'}
-% ? ' ALIGN="'. $element->{'align'}. '"'
+% '<TD '.
+% join(' ', map {
+% uc($_).'="'. $e->{$_}. '"';
+% }
+% grep exists($e->{$_}),
+% qw( align bgcolor colspan rowspan
+% style valign width )
+% ).
+% '>'.
+%
+% ( $e->{'link'}
+% ? '<A HREF="'. $e->{'link'}. '">'
% : ''
-% ). '>'.
-% ( $element->{'link'}
-% ? '<A HREF="'. $element->{'link'}.'">'
+% ).
+% ( $e->{'size'}
+% ? '<FONT SIZE="'.uc($e->{'size'}).'">'
+% : ''
+% ).
+% ( $e->{'data_style'}
+% ? '<'. uc($e->{'data_style'}). '>'
% : ''
% ).
-% $element->{'data'}.
-% ( $element->{'link'}
-% ? '</A>'
+% $e->{'data'}.
+% ( $e->{'data_style'}
+% ? '</'. uc($e->{'data_style'}). '>'
% : ''
% ).
+% ( $e->{'size'} ? '</FONT>' : '' ).
+% ( $e->{'link'} ? '</A>' : '' ).
% '</td>';
%
% } @$rowref ).
% } else {
% foreach ( @$row ) {
- <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"><% $_ %></TD>
+ <TD CLASS="grid" BGCOLOR="$bgcolor"><% $_ %></TD>
% }
% }
<% include( '/elements/footer.html' ) %>
% }
% }
-