fix broadband reporting with giant query URLs (large numbers of package defs, etc...
[freeside.git] / httemplate / search / elements / search-html.html
1 %   if ( exists($opt{'redirect'}) && $opt{'redirect'}
2 %        && scalar(@$rows) == 1 && $total == 1
3 %        && $type ne 'html-print'
4 %      ) {
5 %     my $redirect = $opt{'redirect'};
6 %     $redirect = &{$redirect}($rows->[0], $cgi) if ref($redirect) eq 'CODE';
7 %     my( $url, $method ) = @$redirect;
8 %     redirect( $url. $rows->[0]->$method() );
9 %   } elsif ( exists($opt{'redirect_empty'}) && ! scalar(@$rows) && $total == 0
10 %             && $type ne 'html-print'
11 %             && $opt{'redirect_empty'}
12 %             && ( ref($opt{'redirect_empty'}) ne 'CODE'
13 %                  || &{$opt{'redirect_empty'}}($cgi)    )
14 %      ) {
15 %     my $redirect = $opt{'redirect_empty'};
16 %     $redirect = &{$redirect}($cgi) if ref($redirect) eq 'CODE';
17 %     redirect( $redirect );
18 %   } else {
19 %     if ( $opt{'name_singular'} ) {
20 %       $opt{'name'} = PL($opt{'name_singular'});
21 %     }
22 %     ( my $xlsname = $opt{'name'} ) =~ s/\W//g;
23 %     if ( $total == 1 ) {
24 %       if ( $opt{'name_singular'} ) {
25 %         $opt{'name'} = $opt{'name_singular'}
26 %       } else {
27 %         #$opt{'name'} =~ s/s$// if $total == 1;
28 %         $opt{'name'} =~ s/((s)e)?s$/$2/ if $total == 1;
29 %       }
30 %     }
31 %
32 %     unless ( $opt{nohtmlheader} ) {
33 %
34 %       if ( $type eq 'html-print' ) {
35           <& /elements/header-popup.html, $opt{'title'} &>
36 %       } else {
37 %         if ( $type eq 'select' ) {
38             <&/elements/header-popup.html, $opt{'title'} &>
39 %         } else {
40 %
41 %           my @menubar = ();
42 %           if ( $opt{'menubar'} ) {
43 %             @menubar = @{ $opt{'menubar'} };
44 %           #} else {
45 %           #  @menubar = ( 'Main menu' => $p );
46 %           }
47
48             <& /elements/header.html, $opt{'title'},
49                  include( '/elements/menubar.html', @menubar )
50             &>
51
52 %         }
53 %       }
54 %
55 %     }
56 %
57 %     unless ( $type eq 'html-print' ) {
58
59 %       if ( $opt{'add_link'} ) { #or after html_init?
60           <A HREF="<%$p%>edit/<% $opt{query}->{table} %>.html"><I>Add a <% $opt{'name_singular'} %></I></A><BR><BR>
61 %       }
62
63         <% defined($opt{'html_init'}) 
64               ? ( ref($opt{'html_init'})
65                     ? &{$opt{'html_init'}}($opt{html_init_data})
66                     : $opt{'html_init'}
67                 )
68               : ''
69         %>
70
71 %     }
72
73 %     unless ( $total ) { 
74 %       unless ( $opt{'disable_nonefound'} ) { 
75           <BR><BR>No matching <% $opt{'name'} %> found.<BR>
76 %       } 
77 %     }
78 %
79 %     if ( $total || $opt{'disableable'} ) { #hmm... and there *are* ones to show??
80
81         <TABLE>
82           <TR>
83
84             <TD VALIGN="bottom">
85
86               <FORM>
87
88 %               if (! $opt{'disable_total'}) {
89                   <% $total %> total <% $opt{'name'} %>
90 %               }
91
92 %               if ( $confmax && $total > $confmax
93 %                    && ! $opt{'disable_maxselect'}
94 %                    && $type ne 'html-print' )
95 %               {
96 %                 $cgi->delete('maxrecords');
97 %                 $cgi->param('_dummy', 1);
98 %                 my $query = $m->scomp('/elements/create_uri_query');
99
100                   ( show <SELECT NAME="maxrecords" onChange="window.location = '<% "$self_url?$query" %>;maxrecords=' + this.options[this.selectedIndex].value;">
101
102 %                   foreach my $max ( map { $_ * $confmax } qw( 1 5 10 25 ) ) {
103                   <OPTION VALUE="<% $max %>" <% ( $maxrecords == $max ) ? 'SELECTED' : '' %>><% $max %></OPTION>
104 %                   }
105
106                   </SELECT> per page )
107
108 %                 $cgi->param('maxrecords', $maxrecords);
109 %               }
110
111 %               if ( defined($opt{'html_posttotal'}) && $type ne 'html-print' ) {
112                     <% ref($opt{'html_posttotal'})
113                          ? &{$opt{'html_posttotal'}}()
114                          : $opt{'html_posttotal'}
115                     %>
116 %               }
117                 <BR>
118
119 %               if ( $opt{'count_addl'} ) { 
120 %                 my $n=0;
121 %                 foreach my $count ( @{$opt{'count_addl'}} ) { 
122 %                   my $data = $count_arrayref->[++$n];
123 %                   if ( ref($count) ) {
124                       <% &{ $count }( $data ) %>
125 %                   } else {
126                       <% sprintf( $count, $data ) %><BR>
127 %                   }
128 %                 } 
129 %               } 
130               </FORM>
131
132             </TD>
133
134 %           if ( $curuser->access_right('Download report data')
135 %                 and !$opt{'disable_download'}
136 %                 and $type ne 'html-print' ) { 
137
138               <TD ALIGN="right" CLASS="noprint">
139
140                 <% $opt{'download_label'} || 'Download results:' %>
141
142 %               $cgi->param('_type', "$xlsname.xls" ); 
143 %               my $query = $m->scomp('/elements/create_uri_query');
144                 <A HREF="<% "$self_url?$query" %>">Spreadsheet</A>&nbsp;|&nbsp;
145
146 %               $cgi->param('_type', 'csv'); 
147 %               my $query = $m->scomp('/elements/create_uri_query');
148                 <A HREF="<% "$self_url?$query" %>">CSV</A>&nbsp;|&nbsp;
149
150 %             if ( defined($opt{xml_elements}) ) {
151 %               $cgi->param('_type', 'xml'); 
152 %               my $query = $m->scomp('/elements/create_uri_query');
153                 <A HREF="<% "$self_url?$query" %>">XML</A>&nbsp;|&nbsp;
154 %             }
155
156 %               $cgi->param('_type', 'html-print'); 
157 %               my $query = $m->scomp('/elements/create_uri_query');
158                 <A HREF="<% "$self_url?$query" %>">webpage</A>
159
160 %# "save search" -- for now, obey disable_download and the 'Download
161 %# report data' ACL, because saving a search allows the user to receive
162 %# copies of the data.
163                 <BR>
164 %# XXX should do a check here on whether the user already has this
165 %# search saved...
166                 <& /elements/popup_link.html,
167                   'action'        => $fsurl.'/edit/saved_search.html?title='.
168                                        uri_escape($opt{title}),
169                   'label'         => 'Save this search',
170                   'actionlabel'   => 'Save this search',
171                   'width'         => 650,
172                   'height'        => 500,
173                 &>
174               </TD>
175 %             $cgi->param('_type', "html" ); 
176 %           } 
177
178           </TR>
179           <TR>
180             <TD COLSPAN=2>
181
182 %             my $pager = '';
183 %             unless ( $type eq 'html_print' ) {
184
185                 <% $pager = include( '/elements/pager.html',
186                                        'offset'     => $offset,
187                                        'num_rows'   => scalar(@$rows),
188                                        'total'      => $total,
189                                        'maxrecords' => $maxrecords,
190                                    )
191                 %>
192
193                 <% defined($opt{'html_form'}) 
194                      ? ( ref($opt{'html_form'})
195                            ? &{$opt{'html_form'}}()
196                            : $opt{'html_form'}
197                        )
198                      : ''
199                 %>
200
201 %             }
202
203               <& SELF:data_table,
204                   rows            => $rows,
205                   null_link       => $null_link,
206                   link_agentnums  => \@link_agentnums,
207                   self_url        => $self_url,
208                   %opt
209               &>
210
211               <% $pager %>
212   
213             </TD>
214           </TR>
215         </TABLE>
216 %     }
217
218 %     if ( $type eq 'html-print' ) {
219 %       unless ( $opt{nohtmlheader} ) {
220
221         </BODY></HTML>
222       
223 %       }
224 %     } else {
225
226         <% defined($opt{'html_foot'}) 
227               ? ( ref($opt{'html_foot'})
228                     ? &{$opt{'html_foot'}}()
229                     : $opt{'html_foot'}
230                 )
231               : ''
232         %>
233
234         <% $opt{nohtmlheader}
235              ? ''
236              : include( '/elements/footer.html' )
237         %>
238
239 %     }
240
241 %   } 
242 <%init>
243
244 my $curuser = $FS::CurrentUser::CurrentUser;
245
246 my %args = @_;
247 my $type           = $args{'type'};
248 my $header         = $args{'header'};
249 my $rows           = $args{'rows'};
250 my @link_agentnums = @{ $args{'link_agentnums'} };
251 my $null_link      = $args{'null_link'};
252 my $confmax        = $args{'confmax'};
253 my $maxrecords     = $args{'maxrecords'};
254 my $offset         = $args{'offset'};
255 my %opt            = %{ $args{'opt'} };
256
257 # must be an arrayref of the row count, followed by any other totals
258 my $count_arrayref = $args{'totals'};
259 my $total = $count_arrayref->[0];
260
261 # there used to be an option to override this, for highly dubious reasons
262 my $self_url = $cgi->url('-path_info' => 1, '-full' =>1);
263
264 </%init>
265 <%method data_table>
266 % my %opt = @_;
267 % my $rows = delete $opt{rows};
268 % my $self_url = delete $opt{self_url};
269 <& /elements/table-grid.html &>
270
271 <THEAD>
272 <& SELF:header_row,
273   'header'      => $opt{'header'},
274   'header2'     => $opt{'header2'},
275   'sort_fields' => ($opt{'sort_fields'} || $opt{'fields'}),
276 &>
277 </THEAD>
278
279 <TBODY>
280 <& SELF:data_rows, rows => $rows, opt => \%opt &>
281 </TBODY>
282
283 % if ( $opt{'footer'} ) {
284 <TFOOT>
285 <& SELF:footer_row, row => $opt{'footer'}, opt => \%opt &>
286 </TFOOT> 
287 % } 
288 </TABLE>
289 </%method>
290 <%method header_row>
291 <%args>
292 @sort_fields
293 @header
294 @header2 => ()
295 </%args>
296   <TR>
297 % my $h2 = 0;
298 % my $colspan = 0;
299 % my $order_by = $cgi->param('order_by');
300 % my $self_url = $cgi->url('-path_info' => 1, '-full' =>1);
301 % foreach my $header ( @header ) { 
302 %
303 %   my $field = shift @sort_fields;
304 %
305 %   $colspan-- if $colspan > 0;
306 %   next if $colspan;
307 %
308 %   my $label = ref($header) ? $header->{label} : $header;
309 %   unless ( ref($field) || !$field ) {
310 %     if ( $order_by eq $field ) {
311 %       $cgi->param('order_by', "$field DESC");
312 %     } else {
313 %       $cgi->param('order_by', $field);
314 %     }
315 %     my $query = $m->scomp('/elements/create_uri_query');
316 %     $label = qq(<A HREF="$self_url?$query">$label</A>);
317 %   }
318 %
319 %   $colspan = ref($header) ? $header->{colspan} : 0;
320 %   my $rowspan = 1;
321 %   my $style = '';
322 %   if ( @header2 ) {
323 %     if ( !length($header2[$h2]) ) {
324 %       $rowspan = 2;
325 %       splice @header2, $h2, 1;
326 %     } else {
327 %       $h2++;
328 %       $style = 'STYLE="border-bottom: none"'
329 %     }
330 %   }
331     <TH CLASS   = "grid"
332         BGCOLOR = "#cccccc"
333         ROWSPAN = "<% $rowspan %>"
334         <% $colspan ? 'COLSPAN = "'.$colspan.'"' : '' %>
335         <% $style %>
336
337     >
338       <% $label %>
339     </TH>
340 % } 
341   </TR>
342
343 % if ( @header2 ) {
344   <TR>
345 %   foreach my $header ( @header2 ) { 
346 %     my $label = ref($header) ? $header->{label} : $header;
347       <TH CLASS="grid" BGCOLOR="#cccccc">
348         <FONT SIZE="-1"><% $label %></FONT>
349       </TH>
350 %   } 
351   </TR>
352 % }
353 </%method>
354 <%method data_rows>
355 <%args>
356 $rows => []
357 %opt
358 </%args>
359 % my %align = (
360 %   'l' => 'left',
361 %   'r' => 'right',
362 %   'c' => 'center',
363 %   ' ' => '',
364 %   '.' => '',
365 % );
366 % if ( $opt{align} and !ref($opt{align}) ) {
367 %   $opt{align} = [ map $align{$_}, split(//, $opt{align}) ];
368 % }
369
370 % my $i = 0; # for row striping # XXX CSS - nth-child
371 % my $id = 0;
372 % foreach my $row ( @$rows ) {
373 %
374 %   my $rowstyle = '';
375 %   if ( $row eq $opt{'footer_data'} ) { # XXX CSS - tfoot
376 %     $rowstyle = ' STYLE="border-top: dashed 1px black; font-style: italic background-color=#dddddd"';
377 %   }
378 %
379 %   my $trid = '';
380 %   if ( $opt{'link_field' } ) {
381 %     my $link_field = $opt{'link_field'};
382 %     if ( ref($link_field) eq 'CODE' ) {
383 %       $trid = &{$link_field}($row);
384 %     } else {
385 %       $trid = $row->$link_field();
386 %     }
387 %   }
388     <TR ID="<%$trid |h%>" CLASS="row<% $i % 2 %>"<%$rowstyle%>>
389
390 %   if ( $opt{'fields'} ) {
391 %
392 %     my $links    = $opt{'links'} ? [ @{$opt{'links'}} ] : '';
393 %     my $onclicks = $opt{'link_onclicks'} ? [ @{$opt{'link_onclicks'}} ] : [];
394 %     my $tooltips = $opt{'tooltips'} ? [ @{$opt{'tooltips'}} ] : [];
395 %     my $aligns   = $opt{'align'} ? [ @{$opt{'align'}} ] : '';
396 %     my $colors   = $opt{'color'} ? [ @{$opt{'color'}} ] : [];
397 %     my $sizes    = $opt{'size'}  ? [ @{$opt{'size'}}  ] : [];
398 %     my $styles   = $opt{'style'} ? [ @{$opt{'style'}} ] : [];
399 %     my $cstyles  = $opt{'cell_style'} ? [ @{$opt{'cell_style'}} ] : [];
400 %     my $formats  = $opt{'format'} ? [ @{$opt{'format'}} ] : [];
401 %
402 %     foreach my $field (
403 %
404 %       # if the value of the field is an arrayref, then construct a table in
405 %       # the cell.
406 %       # if it's a (non-empty) scalar, and a format has been specified, then
407 %       # format the scalar with that.
408 %       # otherwise, just output the value.
409 %       # XXX we should also do date formats like this
410 %       map {
411 %             if ( ref($_) eq 'ARRAY' ) {
412 %
413 %               my $tableref = $_;
414 %
415 %               '<TABLE CLASS="inv" CELLSPACING=0 CELLPADDING=0 WIDTH="100%">'.
416 %
417 %               join('', map {
418 %
419 %                 my $rowref = $_;
420 %
421 %                 '<tr>'.
422 %
423 %                 join('', map {
424 %
425 %                   my $e = $_;
426 %
427 %                   '<TD '.
428 %                     join(' ', map {
429 %                       uc($_).'="'. $e->{$_}. '"';
430 %                     }
431 %                     grep exists($e->{$_}),
432 %                          qw( align bgcolor colspan rowspan
433 %                              style valign width )
434 %                     ).
435 %                   '>'.
436 %
437 %                   ( $e->{'link'}
438 %                       ? '<A HREF="'. $e->{'link'}. '">'
439 %                       : ''
440 %                   ).
441 %                   ( $e->{'onclick'} # don't use with 'link'
442 %                       ? '<A HREF="#" onclick="' .
443 %                         $e->{'onclick'}.'">'
444 %                       : ''
445 %                   ).
446 %                   ( $e->{'size'}
447 %                      ? '<FONT SIZE="'.uc($e->{'size'}).'">'
448 %                      : ''
449 %                   ).
450 %                   ( $e->{'data_style'}
451 %                       ? '<'. uc($e->{'data_style'}). '>'
452 %                       : ''
453 %                   ).
454 %                   $e->{'data'}.
455 %                   ( $e->{'data_style'}
456 %                       ? '</'. uc($e->{'data_style'}). '>'
457 %                       : ''
458 %                   ).
459 %                   ( $e->{'size'} ? '</FONT>' : '' ).
460 %                   ( $e->{'link'} || $e->{'onclick'} 
461 %                       ? '</A>'
462 %                       : '' ).
463 %                   '</td>';
464 %
465 %                 } @$rowref ).
466 %
467 %                 '</tr>';
468 %               } @$tableref ).
469 %
470 %               '</table>';
471 %
472 %             } else {
473 %               if ( length($_) > 0 and my $format = shift @$formats ) {
474 %                 $_ = sprintf($format, $_);
475 %               }
476 %               $_;
477 %             }
478 %           }
479 %
480 %       # get the value of the field spec:
481 %       # - if the spec is a coderef, evaluate the coderef
482 %       # - if the spec is a string, call that string as a method
483 %       # - if the spec is an integer, get the field in that position
484 %       map {
485 %             if ( ref($_) eq 'CODE' ) {
486 %               &{$_}($row);
487 %             } elsif ( ref($row) eq 'ARRAY' and 
488 %                       $_ =~ /^\d+$/ ) {
489 %             # for the 'straight SQL' case: specify fields
490 %             # by position
491 %               encode_entities($row->[$_]);
492 %             } else {
493 %               encode_entities($row->$_());
494 %             }
495 %           }
496 %       @{$opt{'fields'}}
497 %
498 %     ) {
499 %
500 %       my $class = ( $field =~ /^<TABLE/i ) ? 'inv' : 'grid';
501 %       my $class = 'grid';
502 %
503 %       my $align = $aligns ? shift @$aligns : '';
504 %       $align = " ALIGN=$align" if $align;
505 %
506 %       my $a = '';
507 %       if ( $links ) {
508 %         my $link = shift @$links;
509 %         my $onclick = shift @$onclicks;
510 %         my $tooltip = shift @$tooltips;
511 %
512 %         if (    ! $opt{'agent_virt'}
513 %              || ( $opt{'null_link'} && ! $row->agentnum )
514 %              || grep { $row->agentnum == $_ }
515 %                      @{ $opt{link_agentnums} }
516 %            ) {
517 %
518 %           $link = &{$link}($row)
519 %             if ref($link) eq 'CODE';
520 %
521 %           $onclick = &{$onclick}($row)
522 %             if ref($onclick) eq 'CODE';
523 %           $onclick = qq( onClick="$onclick") if $onclick;
524 %
525 %           $tooltip = &{$tooltip}($row)
526 %             if ref($tooltip) eq 'CODE';
527 %           $tooltip = qq! id="a$id" !.
528 %             qq! onmouseover="return overlib(!.
529 %             $m->interp->apply_escapes($tooltip, 'h', 'js_string').
530 %             qq!, FGCLASS, 'tooltip', REF, 'a$id', !.
531 %             qq!REFC, 'LL', REFP, 'UL')"! if $tooltip;
532 %
533 %           if ( $link ) {
534 %             my( $url, $method ) = @{$link};
535 %             if ( ref($method) eq 'CODE' ) {
536 %               $a = $url. &{$method}($row);
537 %             } else {
538 %               $a = $url. $row->$method();
539 %             }
540 %             $a = qq(<A HREF="$a"$onclick$tooltip>);
541 %           }
542 %           elsif ( $onclick ) {
543 %             $a = qq(<A HREF="javascript:void(0);"$onclick>);
544 %           }
545 %           elsif ( $tooltip ) {
546 %             $a = qq(<A $tooltip>);
547 %           }
548 %           $id++;
549
550 %         }
551 %
552 %       }
553 %
554 %       my $font = '';
555 %       my $color = shift @$colors;
556 %       $color = &{$color}($row) if ref($color) eq 'CODE';
557 %       my $size = shift @$sizes;
558 %       $size = &{$size}($row) if ref($size) eq 'CODE';
559 %       if ( $color || $size ) {
560 %         $font = '<FONT '.
561 %                 ( $color ? "COLOR=#$color "   : '' ).
562 %                 ( $size  ? qq(SIZE="$size" )  : '' ).
563 %                 '>';
564 %       }
565 %
566 %       my($s, $es) = ( '', '' );
567 %       my $style = shift @$styles;
568 %       $style = &{$style}($row) if ref($style) eq 'CODE';
569 %       if ( $style ) {
570 %         $s = join( '', map "<$_>", split('', $style) );
571 %         $es = join( '', map "</$_>", split('', $style) );
572 %       }
573 %
574 %       my $cstyle = shift @$cstyles;
575 %       $cstyle = &{$cstyle}($row) if ref($cstyle) eq 'CODE';
576 %       $cstyle = qq(STYLE="$cstyle")
577 %         if $cstyle;
578
579         <TD CLASS="<% $class %>" <% $align %> <% $cstyle %>><% $a %><% $font %><% $s %><% $field %><% $es %><% $font ? '</FONT>' : '' %><% $a ? '</A>' : '' %></TD>
580
581 %     } 
582 %
583 %   } else { # not $opt{'fields'}
584 %
585 %     foreach ( @$row ) { 
586         <TD CLASS="grid"><% $_ %></TD>
587 %     }
588 %
589 %   }
590
591     </TR>
592
593 %   $i++;
594 %
595 % } # foreach $row
596 </%method>
597 <%method footer_row>
598 <%args>
599 $row
600 %opt
601 </%args>
602 %# don't try to respect all the styling options, just the ones that are
603 %# hard to replicate with CSS
604 % my %align = (
605 %   'l' => 'left',
606 %   'r' => 'right',
607 %   'c' => 'center',
608 %   ' ' => '',
609 %   '.' => '',
610 % );
611 % if ( $opt{align} and !ref($opt{align}) ) {
612 %   $opt{align} = [ map $align{$_}, split(//, $opt{align}) ];
613 % }
614 % my @aligns = @{ $opt{align} };
615
616 <TR>
617 % foreach my $footer ( @$row ) {
618 %   $footer = &{$footer}() if ref($footer) eq 'CODE';
619 %   my $align = shift @aligns;
620 %   my $style = '';
621 %   $style .= "text-align: $align;" if $align;
622     <TD CLASS="grid" STYLE="<% $style %>"><% $footer %></TD>
623 % } 
624 </TR>
625 </%method>
626