diff options
Diffstat (limited to 'httemplate/elements')
40 files changed, 1024 insertions, 283 deletions
diff --git a/httemplate/elements/checkboxes.html b/httemplate/elements/checkboxes.html index ad9d691b9..b07b6545f 100644 --- a/httemplate/elements/checkboxes.html +++ b/httemplate/elements/checkboxes.html @@ -27,7 +27,7 @@ Example: </%doc> -<TABLE CELLSPACING=0 CELLPADDING=0> +<TABLE CELLSPACING=0 CELLPADDING=0 <% $style %>> % unless ( $opt{'disable_links'} ) { @@ -108,4 +108,8 @@ $opt{'error_checked_callback'} ||= sub { $cgi->param($opt{'element_name_prefix'}. $name ); }; +my $style = ''; +if ($opt{'style'}) { + $style = 'STYLE="' . $opt{'style'} . '"'; +} </%init> diff --git a/httemplate/elements/commission_rate.html b/httemplate/elements/commission_rate.html new file mode 100644 index 000000000..071ebb1e3 --- /dev/null +++ b/httemplate/elements/commission_rate.html @@ -0,0 +1,68 @@ +% unless ( $opt{'js_only'} ) { + + <INPUT TYPE="hidden" NAME="<%$name%>" ID="<%$id%>" VALUE="<% $curr_value %>"> + + <& select.html, + field => "${name}_cycle", + options => [ '', 1 .. 12 ], + option_labels => { + '' => '', + 1 => '1st', + 2 => '2nd', + 3 => '3rd', + map { $_ => $_.'th' } 4 .. 12 + }, + onchange => $onchange, + curr_value => $commission_rate->get("cycle"), + &> + <B><% $money_char %></B> + <& input-text.html, + field => "${name}_amount", + size => 8, + curr_value => $commission_rate->get("amount") + || '0.00', + 'text-align' => 'right' + &> + <B> + </B> + <& input-text.html, + field => "${name}_percent", + size => 8, + curr_value => $commission_rate->get("percent") + || '0', + 'text-align' => 'right' + &><B>%</B> +% } +<%init> + +my( %opt ) = @_; + +my $conf = new FS::Conf; +my $money_char = $conf->config('money_char') || '$'; + +my $name = $opt{'field'} || 'commissionratenum'; +my $id = $opt{'id'} || 'commissionratenum'; + +my $curr_value = $opt{'curr_value'} || $opt{'value'}; + +my $onchange = ''; +if ( $opt{'onchange'} ) { + $onchange = $opt{'onchange'}; + $onchange .= '(this)' unless $onchange =~ /\(\w*\);?$/; + $onchange =~ s/\(what\);/\(this\);/g; #ugh, terrible hack. all onchange + #callbacks should act the same + $onchange = 'onChange="'. $onchange. '"'; +} + +my $commission_rate; +if ( $curr_value ) { + $commission_rate = qsearchs('commission_rate', { 'commissionratenum' => $curr_value } ); +} else { + $commission_rate = new FS::commission_rate {}; +} + +foreach my $field (qw( amount percent cycle)) { + my $value = $cgi->param("${name}_${field}"); + $commission_rate->set($field, $value) if $value; +} + +</%init> diff --git a/httemplate/elements/create_uri_query b/httemplate/elements/create_uri_query index 414d53ba4..ce6249e0e 100644 --- a/httemplate/elements/create_uri_query +++ b/httemplate/elements/create_uri_query @@ -18,7 +18,7 @@ my $query = $cgi->query_string; if ( length($query) > 1920 || $opt{secure} ) { #stupid IE 2083 URL limit - my $session = random_id(9); + my $session = int(rand(4294967296)); #XXX my $pref = new FS::access_user_pref({ 'usernum' => $FS::CurrentUser::CurrentUser->usernum, 'prefname' => "redirect$session", diff --git a/httemplate/elements/cust_payby.html b/httemplate/elements/cust_payby.html index c7d4549df..f30d18557 100644 --- a/httemplate/elements/cust_payby.html +++ b/httemplate/elements/cust_payby.html @@ -68,7 +68,7 @@ ID = "<%$id%>_paycvv" SIZE = 2 MAXLENGTH = 4 - VALUE = "<% scalar($cgi->param($name.'_paycvv')) %>" + VALUE = "<% scalar($cgi->param($name.'_paycvv')) || ('*' x length($cust_payby->paycvv)) %>" onChange = "<% $onchange %>" > <BR><FONT SIZE="-1"><% mt('CVV2') |h %> (<A HREF="javascript:void(0);" onClick="overlib( OLiframeContent('<%$p%>docs/cvv2.html', 480, 275, 'cvv2_popup' ), CAPTION, 'CVV2 Help', STICKY, AUTOSTATUSCAP, CLOSECLICK, DRAGGABLE ); return false;"><% mt('help') |h %></A>)</FONT> @@ -298,8 +298,17 @@ if ( $curr_value ) { $cust_payby = new FS::cust_payby {}; } my $sel_payby = $cgi->param($name.'_payby') || $cust_payby->payby; -$sel_payby = 'CARD' if $sel_payby eq 'DCRD' || $sel_payby eq ''; -$sel_payby = 'CHEK' if $sel_payby eq 'DCHK'; +# convert DCRD to CARD + no weight, and the same for DCHK/CHEK +if ($sel_payby eq 'DCRD') { + $sel_payby = 'CARD'; + $cust_payby->weight(''); +} elsif ($sel_payby eq 'DCHK') { + $sel_payby = 'CHEK'; + $cust_payby->weight(''); +} elsif (!$sel_payby) { + # default + $sel_payby = 'CARD'; +} my @payby = FS::payby->cust_payby; my %conf_payby = map { $_=>1 } $conf->config('payby'); diff --git a/httemplate/elements/error.html b/httemplate/elements/error.html index f65785d10..f9664bd65 100644 --- a/httemplate/elements/error.html +++ b/httemplate/elements/error.html @@ -1,4 +1,5 @@ % if ( $cgi->param('error') ) { +% $m->notes('error', $cgi->param('error')); <FONT SIZE="+1" COLOR="#ff0000"><% mt("Error: [_1]", $cgi->param('error')) |h %></FONT> <BR><BR> % } diff --git a/httemplate/elements/errorpage.html b/httemplate/elements/errorpage.html index 0f9808da0..d001bfa89 100644 --- a/httemplate/elements/errorpage.html +++ b/httemplate/elements/errorpage.html @@ -1,3 +1,5 @@ +% my $error = $_[0]; +% $m->notes('error', $error); <& /elements/header.html, mt("Error") &> % while (@_) { @@ -5,6 +7,5 @@ <P><FONT SIZE="+1" COLOR="#ff0000"><% shift |h %></FONT> %} - % $m->flush_buffer(); % $HTML::Mason::Commands::m->abort(); diff --git a/httemplate/elements/freeside-menu.css b/httemplate/elements/freeside-menu.css index a66ebc0db..365b9d443 100644 --- a/httemplate/elements/freeside-menu.css +++ b/httemplate/elements/freeside-menu.css @@ -142,3 +142,13 @@ a:visited:hover.fsdarkbutton { overflow:visible; } + +/* elements/notify-tickets.html is in the menu area */ +.dot { + border-radius: 50%; + border: 1px solid black; + width: 1ex; + height: 1ex; + display: inline-block; + margin-top: 0.3ex; +} diff --git a/httemplate/elements/freeside.css b/httemplate/elements/freeside.css index 7bf374c84..cc104a196 100644 --- a/httemplate/elements/freeside.css +++ b/httemplate/elements/freeside.css @@ -235,7 +235,7 @@ div.fstabcontainer { .fsinnerbox th { font-weight:normal; font-size:80%; - valign: bottom; + vertical-align: bottom; color: #666666; } @@ -341,3 +341,5 @@ div.package-marker-change_from { border-left: solid #bbffbb 30px; display: inline-block; } + + diff --git a/httemplate/elements/header-full.html b/httemplate/elements/header-full.html new file mode 100644 index 000000000..850eaed8c --- /dev/null +++ b/httemplate/elements/header-full.html @@ -0,0 +1,242 @@ +<%doc> + +Example: + + <& /elements/header.html', + { + 'title' => 'Title', + 'menubar' => \@menubar, + 'etc' => '', #included in <BODY> tag, for things like onLoad= + 'head' => '', #included before closing </HEAD> tag + 'nobr' => 0, #1 for no <BR><BR> after the title + 'no_jquery' => #for use from RT, which loads its own + } + &> + + %#old-style + <& /elements/header.html, 'Title', $menubar, $etc, $head &> + +</%doc> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +%#<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +%# above is what RT declares, should we switch now? hopefully no glitches result +%# or just fuck it, XHTML died anyway, HTML 5 or bust? +<HTML> + <HEAD> + <TITLE> + <% encode_entities($title) || $title_noescape |n %> + </TITLE> + <!-- per RT, to prevent IE compatibility mode --> + <meta http-equiv="X-UA-Compatible" content="IE=edge" /> + <!-- The X-UA-Compatible <meta> tag above must be very early in <head> --> + <META HTTP-Equiv="Cache-Control" Content="no-cache"> + <META HTTP-Equiv="Pragma" Content="no-cache"> + <META HTTP-Equiv="Expires" Content="0"> +% if ( $mobile ) { + <META NAME="viewport" content="width=device-width height=device-height user-scalable=yes"> +% } + + <% include('menu.html', 'freeside_baseurl' => $fsurl, + 'position' => $menu_position, + 'nocss' => $nocss, + 'mobile' => $mobile, + ) |n + %> + +% unless ( $no_jquery ) { + <link rel="stylesheet" href="<% $fsurl %>elements/jquery-ui.min.css"> + <SCRIPT SRC="<% $fsurl %>elements/jquery.js"></SCRIPT> + <SCRIPT SRC="<% $fsurl %>elements/jquery-ui.min.js"></SCRIPT> +% if ( $FS::CurrentUser::CurrentUser->option('printtofit') ) { + <SCRIPT SRC="<% $fsurl %>elements/printtofit.js"></SCRIPT> +% } +% } + <% include('init_overlib.html') |n %> + <% include('rs_init_object.html') |n %> + <script type="text/javascript" src="<% $fsurl %>elements/topreload.js"></script> + <% $head |n %> + +%# announce our base path, and the Mason comp path of this page + <script type="text/javascript"> + window.fsurl = <% $fsurl |js_string %>; + window.request_comp_path = <% $m->request_comp->path |js_string %>; + </script> + + </HEAD> + <BODY BGCOLOR="#f8f8f8" <% $etc |n %> STYLE="margin-top:0; margin-bottom:0; margin-left:0px; margin-right:0px"> + <table width="100%" CELLPADDING=0 CELLSPACING=0 STYLE="padding-left:0px; padding-right:4px" CLASS="fshead"> + <tr> + <td BGCOLOR="#ffffff"><% $company_url ? qq(<A HREF="$company_url">) : '' |n %><IMG BORDER=0 ALT="freeside" HEIGHT="36" SRC="<%$fsurl%>view/REAL_logo.cgi"><% $company_url ? '</A>' : '' |n %></td> + <td align=left BGCOLOR="#ffffff"> <!-- valign="top" --> + <font size=6><% $company_name || 'ExampleCo' %></font> + </td> + <td align="right" BGCOLOR="#ffffff"> + <& notify-tickets.html &> + </td> + <td align=right valign=top BGCOLOR="#ffffff"><FONT SIZE="-1">Logged in as <b><% $FS::CurrentUser::CurrentUser->username |h %> </b> <FONT SIZE="-2"><a href="<%$fsurl%>loginout/logout.html">logout</a></FONT><br></FONT><FONT SIZE="-2"><a href="<%$fsurl%>pref/pref.html" STYLE="color: #000000">Preferences</a> +% if ( $conf->config("ticket_system") +% && FS::TicketSystem->access_right(\%session, 'ModifySelf') ) { + | <a href="<%$fsurl%>rt/Prefs/Other.html" STYLE="color: #000000">Ticketing preferences</a> +% } + <BR></FONT> + </td> + </tr> + </table> + + <TABLE WIDTH="100%" CELLSPACING=0 CELLPADDING=0> + +<link href="<%$fsurl%>elements/freeside-menu.css" type="text/css" rel="stylesheet"> + +% if ( $menu_position eq 'top' ) { + + <TR CLASS="fsmenubar"> + +% if ( $mobile ) { + + <TD STYLE="padding:1px 0px 0px 0px;border-top: 1px solid #7e0079;width:auto" BGCOLOR="#dddddd"> + <SCRIPT TYPE="text/javascript"> + document.write(myBar.toString()); + </SCRIPT> + </TD> + <TD STYLE="padding:1px 0px 0px 0px;border-top: 1px solid #7e0079;width:auto" BGCOLOR="#dddddd"> + <% include('searchbar-combined.html') |n %> + </TD> + +% } else { + + <TD COLSPAN="7" WIDTH="100%" STYLE="padding:1px 0px 0px 0px;border-top: 1px solid #7e0079" BGCOLOR="#dddddd"> + <SCRIPT TYPE="text/javascript"> + document.write(myBar); + </SCRIPT> + </TD> + + </TR> + + <TR CLASS="fssearchbar"> + + <TD COLSPAN=1 BGCOLOR="#dddddd" ALIGN="right" STYLE="padding-left:2px"> + <% include('searchbar-prospect.html') |n %> + </TD> + + <TD COLSPAN=1 BGCOLOR="#dddddd" ALIGN="right" STYLE="padding-left:2px"> + <% include('searchbar-cust_main.html') |n %> + </TD> + + <TD COLSPAN=1 BGCOLOR="#dddddd" ALIGN="center"> + <% include('searchbar-address2.html') |n %> + </TD> + + <TD COLSPAN=1 BGCOLOR="#dddddd" ALIGN="right"> + <% include('searchbar-cust_bill.html') |n %> + </TD> + + <TD COLSPAN=1 BGCOLOR="#dddddd" ALIGN="right" STYLE="padding-left:2px"> + <% include('searchbar-cust_svc.html') |n %> + </TD> + + <TD COLSPAN=1 BGCOLOR="#dddddd" ALIGN="right" STYLE="padding-left:2px;padding-right:2px"> + <% include('searchbar-ticket.html') |n %> + </TD> +% } + + </TR> + </TABLE> + +% } else { #$menu_position eq 'left' + + <TR CLASS="fsmenubar"> + + <TD COLSPAN="7" WIDTH="100%" STYLE="padding:1px 0px 0px 0px;border-top: 1px solid #7e0079" BGCOLOR="#dddddd"> + </TD> + + </TR> + +% } + + + <TABLE WIDTH="100%" HEIGHT="100%" CELLSPACING=0 CELLPADDING=4> + + <TR HEIGHT="100%"> + +% if ( $menu_position eq 'left' ) { + + <TD BGCOLOR="#dddddd" ALIGN="left" HEIGHT="100%" WIDTH="154" VALIGN="top" ALIGN="right" CLASS="fsmenubar"> + <SCRIPT TYPE="text/javascript"> + document.write(myBar); + </SCRIPT> + + <BR> + <% include('searchbar-prospect.html') |n %> + <% include('searchbar-cust_main.html') |n %> + <% include('searchbar-address2.html') |n %> + <% include('searchbar-cust_bill.html') |n %> + <% include('searchbar-cust_svc.html') |n %> + <% include('searchbar-ticket.html') |n %> + + </TD> + +% } else { #$menu_position eq 'top' + <BR> +% } +%# page content starts here + <TD CLASS="background" HEIGHT="100%" VALIGN="top"> <!-- WIDTH="100%"> --> + + <H1> + <% $title_noescape || encode_entities($title) %> + </H1> + +% unless ( $nobr ) { + <BR> +% } + + <% $menubar !~ /^\s*$/ ? "$menubar<BR><BR>" : '' %> + +<%init> + +my( $title, $title_noescape, $menubar, $etc, $head ) = ( '', '', '', '', '' ); +my( $nobr, $nocss, $no_jquery ) = ( 0, 0, 0 ); + +my $mobile; + +if ( ref($_[0]) ) { + my $opt = shift; + $title = $opt->{title}; + $title_noescape = $opt->{title_noescape}; + $menubar = $opt->{menubar}; + $etc = $opt->{etc}; + $head = $opt->{head}; + $nobr = $opt->{nobr}; + $nocss = $opt->{nocss}; + $mobile = $opt->{mobile}; + $no_jquery = $opt->{no_jquery}; +} else { + ($title, $menubar) = ( shift, shift ); + $etc = @_ ? shift : ''; #$etc is for things like onLoad= etc. + $head = @_ ? shift : ''; #$head is for things that go in the <HEAD> section +} + +my $conf = new FS::Conf; + +my $curuser = $FS::CurrentUser::CurrentUser; + +my $menu_position = $curuser->option('menu_position') + || 'top'; #new default for 1.9 + +if ( !defined($mobile) ) { + $mobile = $curuser->option('mobile_menu',1) && FS::UI::Web::is_mobile(); +} +if ( $cgi->param('mobile') =~ /^(\d)$/ ) { # allow client to override + $mobile = $1; +} + +my($company_name, $company_url); +my @agentnums = $curuser->agentnums; +if ( scalar(@agentnums) == 1 ) { + $company_name = $conf->config('company_name', $agentnums[0] ); + $company_url = $conf->config('company_url', $agentnums[0] ); +} else { + $company_name = $conf->config('company_name'); + $company_url = $conf->config('company_url'); +} + +</%init> diff --git a/httemplate/elements/header-popup.html b/httemplate/elements/header-popup.html index 17593693e..839a63676 100644 --- a/httemplate/elements/header-popup.html +++ b/httemplate/elements/header-popup.html @@ -30,7 +30,11 @@ Example: <META HTTP-Equiv="Expires" Content="0"> % unless ( $no_jquery ) { <SCRIPT SRC="<% $fsurl %>elements/jquery.js"></SCRIPT> +% if ( $FS::CurrentUser::CurrentUser->option('printtofit') ) { + <SCRIPT SRC="<% $fsurl %>elements/printtofit.js"></SCRIPT> +% } % } + <SCRIPT SRC="<% $fsurl %>elements/topreload.js"></SCRIPT> <% $head |n %> </HEAD> <BODY <% $etc |n %>> diff --git a/httemplate/elements/header.html b/httemplate/elements/header.html index c8a83ca7e..c6b10e301 100644 --- a/httemplate/elements/header.html +++ b/httemplate/elements/header.html @@ -1,228 +1,6 @@ -<%doc> - -Example: - - <& /elements/header.html', - { - 'title' => 'Title', - 'menubar' => \@menubar, - 'etc' => '', #included in <BODY> tag, for things like onLoad= - 'head' => '', #included before closing </HEAD> tag - 'nobr' => 0, #1 for no <BR><BR> after the title - 'no_jquery' => #for use from RT, which loads its own - } - &> - - %#old-style - <& /elements/header.html, 'Title', $menubar, $etc, $head &> - -</%doc> -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> -%#<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -%# above is what RT declares, should we switch now? hopefully no glitches result -%# or just fuck it, XHTML died anyway, HTML 5 or bust? -<HTML> - <HEAD> - <TITLE> - <% encode_entities($title) || $title_noescape |n %> - </TITLE> - <!-- per RT, to prevent IE compatibility mode --> - <meta http-equiv="X-UA-Compatible" content="IE=edge" /> - <!-- The X-UA-Compatible <meta> tag above must be very early in <head> --> - <META HTTP-Equiv="Cache-Control" Content="no-cache"> - <META HTTP-Equiv="Pragma" Content="no-cache"> - <META HTTP-Equiv="Expires" Content="0"> -% if ( $mobile ) { - <META NAME="viewport" content="width=device-width height=device-height user-scalable=yes"> +% # for testing, disable the page menus/search boxes +% if ( $FS::CurrentUser::CurrentUser->option('header-minimal') ) { +<& header-minimal.html, @_ &> +% } else { +<& header-full.html, @_ &> % } - - <% include('menu.html', 'freeside_baseurl' => $fsurl, - 'position' => $menu_position, - 'nocss' => $nocss, - 'mobile' => $mobile, - ) |n - %> - -% unless ( $no_jquery ) { - <link rel="stylesheet" href="<% $fsurl %>elements/jquery-ui.min.css"> - <SCRIPT SRC="<% $fsurl %>elements/jquery.js"></SCRIPT> - <SCRIPT SRC="<% $fsurl %>elements/jquery-ui.min.js"></SCRIPT> -% } - <% include('init_overlib.html') |n %> - <% include('rs_init_object.html') |n %> - - <% $head |n %> - - </HEAD> - <BODY BGCOLOR="#f8f8f8" <% $etc |n %> STYLE="margin-top:0; margin-bottom:0; margin-left:0px; margin-right:0px"> - <table width="100%" CELLPADDING=0 CELLSPACING=0 STYLE="padding-left:0px; padding-right:4px" CLASS="fshead"> - <tr> - <td BGCOLOR="#ffffff"><% $company_url ? qq(<A HREF="$company_url">) : '' |n %><IMG BORDER=0 ALT="freeside" HEIGHT="36" SRC="<%$fsurl%>view/REAL_logo.cgi"><% $company_url ? '</A>' : '' |n %></td> - <td align=left BGCOLOR="#ffffff"> <!-- valign="top" --> - <font size=6><% $company_name || 'ExampleCo' %></font> - </td> - <td align=right valign=top BGCOLOR="#ffffff"><FONT SIZE="-1">Logged in as <b><% $FS::CurrentUser::CurrentUser->username |h %> </b> <FONT SIZE="-2"><a href="<%$fsurl%>loginout/logout.html">logout</a></FONT><br></FONT><FONT SIZE="-2"><a href="<%$fsurl%>pref/pref.html" STYLE="color: #000000">Preferences</a> -% if ( $conf->config("ticket_system") -% && FS::TicketSystem->access_right(\%session, 'ModifySelf') ) { - | <a href="<%$fsurl%>rt/Prefs/Other.html" STYLE="color: #000000">Ticketing preferences</a> -% } - <BR></FONT> - </td> - </tr> - </table> - - <TABLE WIDTH="100%" CELLSPACING=0 CELLPADDING=0> - -<link href="<%$fsurl%>elements/freeside-menu.css" type="text/css" rel="stylesheet"> - -% if ( $menu_position eq 'top' ) { - - <TR CLASS="fsmenubar"> - -% if ( $mobile ) { - - <TD STYLE="padding:1px 0px 0px 0px;border-top: 1px solid #7e0079;width:auto" BGCOLOR="#dddddd"> - <SCRIPT TYPE="text/javascript"> - document.write(myBar.toString()); - </SCRIPT> - </TD> - <TD STYLE="padding:1px 0px 0px 0px;border-top: 1px solid #7e0079;width:auto" BGCOLOR="#dddddd"> - <% include('searchbar-combined.html') |n %> - </TD> - -% } else { - - <TD COLSPAN="7" WIDTH="100%" STYLE="padding:1px 0px 0px 0px;border-top: 1px solid #7e0079" BGCOLOR="#dddddd"> - <SCRIPT TYPE="text/javascript"> - document.write(myBar); - </SCRIPT> - </TD> - - </TR> - - <TR CLASS="fssearchbar"> - - <TD COLSPAN=1 BGCOLOR="#dddddd" ALIGN="right" STYLE="padding-left:2px"> - <% include('searchbar-prospect.html') |n %> - </TD> - - <TD COLSPAN=1 BGCOLOR="#dddddd" ALIGN="right" STYLE="padding-left:2px"> - <% include('searchbar-cust_main.html') |n %> - </TD> - - <TD COLSPAN=1 BGCOLOR="#dddddd" ALIGN="center"> - <% include('searchbar-address2.html') |n %> - </TD> - - <TD COLSPAN=1 BGCOLOR="#dddddd" ALIGN="right"> - <% include('searchbar-cust_bill.html') |n %> - </TD> - - <TD COLSPAN=1 BGCOLOR="#dddddd" ALIGN="right" STYLE="padding-left:2px"> - <% include('searchbar-cust_svc.html') |n %> - </TD> - - <TD COLSPAN=1 BGCOLOR="#dddddd" ALIGN="right" STYLE="padding-left:2px;padding-right:2px"> - <% include('searchbar-ticket.html') |n %> - </TD> -% } - - </TR> - </TABLE> - -% } else { #$menu_position eq 'left' - - <TR CLASS="fsmenubar"> - - <TD COLSPAN="7" WIDTH="100%" STYLE="padding:1px 0px 0px 0px;border-top: 1px solid #7e0079" BGCOLOR="#dddddd"> - </TD> - - </TR> - -% } - - - <TABLE WIDTH="100%" HEIGHT="100%" CELLSPACING=0 CELLPADDING=4> - - <TR HEIGHT="100%"> - -% if ( $menu_position eq 'left' ) { - - <TD BGCOLOR="#dddddd" ALIGN="left" HEIGHT="100%" WIDTH="154" VALIGN="top" ALIGN="right" CLASS="fsmenubar"> - <SCRIPT TYPE="text/javascript"> - document.write(myBar); - </SCRIPT> - - <BR> - <% include('searchbar-prospect.html') |n %> - <% include('searchbar-cust_main.html') |n %> - <% include('searchbar-address2.html') |n %> - <% include('searchbar-cust_bill.html') |n %> - <% include('searchbar-cust_svc.html') |n %> - <% include('searchbar-ticket.html') |n %> - - </TD> - -% } else { #$menu_position eq 'top' - <BR> -% } -%# page content starts here - <TD CLASS="background" HEIGHT="100%" VALIGN="top"> <!-- WIDTH="100%"> --> - - <H1> - <% $title_noescape || encode_entities($title) %> - </H1> - -% unless ( $nobr ) { - <BR> -% } - - <% $menubar !~ /^\s*$/ ? "$menubar<BR><BR>" : '' %> -<%init> - -my( $title, $title_noescape, $menubar, $etc, $head ) = ( '', '', '', '', '' ); -my( $nobr, $nocss, $no_jquery ) = ( 0, 0, 0 ); - -my $mobile; - -if ( ref($_[0]) ) { - my $opt = shift; - $title = $opt->{title}; - $title_noescape = $opt->{title_noescape}; - $menubar = $opt->{menubar}; - $etc = $opt->{etc}; - $head = $opt->{head}; - $nobr = $opt->{nobr}; - $nocss = $opt->{nocss}; - $mobile = $opt->{mobile}; - $no_jquery = $opt->{no_jquery}; -} else { - ($title, $menubar) = ( shift, shift ); - $etc = @_ ? shift : ''; #$etc is for things like onLoad= etc. - $head = @_ ? shift : ''; #$head is for things that go in the <HEAD> section -} - -my $conf = new FS::Conf; - -my $curuser = $FS::CurrentUser::CurrentUser; - -my $menu_position = $curuser->option('menu_position') - || 'top'; #new default for 1.9 - -if ( !defined($mobile) ) { - $mobile = $curuser->option('mobile_menu',1) && FS::UI::Web::is_mobile(); -} -if ( $cgi->param('mobile') =~ /^(\d)$/ ) { # allow client to override - $mobile = $1; -} - -my($company_name, $company_url); -my @agentnums = $curuser->agentnums; -if ( scalar(@agentnums) == 1 ) { - $company_name = $conf->config('company_name', $agentnums[0] ); - $company_url = $conf->config('company_url', $agentnums[0] ); -} else { - $company_name = $conf->config('company_name'); - $company_url = $conf->config('company_url'); -} -</%init> diff --git a/httemplate/elements/location.html b/httemplate/elements/location.html index b5f0a963c..3c8e973ed 100644 --- a/httemplate/elements/location.html +++ b/httemplate/elements/location.html @@ -245,13 +245,13 @@ Example: % } % if ( $opt{enable_district} and $conf->config('tax_district_method') ) { <TR> - <TD ALIGN="right">Tax district</TD> + <TH ALIGN="right">Tax district</TH> <TD COLSPAN=8> <INPUT TYPE="text" SIZE=15 NAME="<%$pre%>district" ID="<%$pre%>district" VALUE="<% $object->district |h %>"> - <% '(automatic)' %> + <FONT SIZE="-1" COLOR="#333333"><% '(automatic)' %></FONT> </TD> </TR> % } else { diff --git a/httemplate/elements/menu.html b/httemplate/elements/menu.html index c385cb4c7..51ec26329 100644 --- a/httemplate/elements/menu.html +++ b/httemplate/elements/menu.html @@ -275,6 +275,7 @@ $report_packages{'Suspension summary'} = [ $fsurl.'search/cust_pkg_susp.html', ' $report_packages{'Customer packages with unconfigured services'} = [ $fsurl.'search/cust_pkg.cgi?APKG_pkgnum', 'List packages which have provisionable services' ]; $report_packages{'FCC Form 477'} = [ $fsurl.'search/report_477.html' ] if $conf->exists('part_pkg-show_fcc_options'); +$report_packages{'Contract end dates'} = [ $fsurl.'search/cust_pkg-date.html?date=contract_end', 'Show packages by contract end date' ]; $report_packages{'Advanced package reports'} = [ $fsurl.'search/report_cust_pkg.html', 'by agent, date range, status, package definition' ]; tie my %report_inventory, 'Tie::IxHash', @@ -320,7 +321,6 @@ tie my %report_ticketing, 'Tie::IxHash', ; tie my %report_bill_event, 'Tie::IxHash', - 'All billing events' => [ $fsurl.'search/report_cust_event.html', 'All billing events for a date range' ], 'Billing event errors' => [ $fsurl.'search/report_cust_event.html?failed=1', 'Failed credit cards, processor or printer problems, etc.' ], ; @@ -365,7 +365,8 @@ tie my %report_commissions, 'Tie::IxHash', 'Agent per package' => [ $fsurl.'search/report_agent_commission_pkg.html' ], 'Sales Person' => [ $fsurl.'search/report_sales_commission.html' ], 'Sales Person per package' => [ $fsurl.'search/report_sales_commission_pkg.html' ], - 'Employee' => [ $fsurl.'search/report_employee_commission.html', '' ] + 'Employee' => [ $fsurl.'search/report_employee_commission.html', '' ], + 'Agent Credits and Payments' => [ $fsurl.'search/report_agent_credit_payment.html' ], ; tie my %report_financial, 'Tie::IxHash'; @@ -404,7 +405,7 @@ tie my %report_payable, 'Tie::IxHash', ; tie my %report_logs, 'Tie::IxHash'; -$report_logs{'Billing events'} = [ \%report_bill_event, 'Billing events' ] +$report_logs{'Billing events'} = [ $fsurl.'search/report_cust_event.html', 'Search billing events by date and status' ] if $curuser->access_right('Billing event reports'); $report_logs{'Credit limit incidents'} = [ $fsurl.'search/report_cust_main_credit_limit.html', '' ] if $curuser->access_right('List rating data'); @@ -672,7 +673,10 @@ $config_cust{'Note classes'} = [ $fsurl.'browse/cust_note_class.html', 'Note cla tie my %config_agent, 'Tie::IxHash', 'Agent types' => [ $fsurl.'browse/agent_type.cgi', 'Agent types define groups of package definitions that you can then assign to particular agents' ], 'Agents' => [ $fsurl.'browse/agent.cgi', 'Agents are resellers of your service. Agents may be limited to a subset of your full offerings (via their type)' ], - 'Agent payment gateways' => [ $fsurl.'browse/payment_gateway.html', 'Credit card and electronic check processors for agent overrides' ]; + 'Agent payment gateways' => [ $fsurl.'browse/payment_gateway.html', 'Credit card and electronic check processors for agent overrides' ], + 'separator' => '', + 'Commission schedules' => [ $fsurl.'browse/commission_schedule.html', + 'Commission schedules for consecutive billing periods' ], ; tie my %config_sales, 'Tie::IxHash', diff --git a/httemplate/elements/notify-tickets.html b/httemplate/elements/notify-tickets.html new file mode 100644 index 000000000..e661737bc --- /dev/null +++ b/httemplate/elements/notify-tickets.html @@ -0,0 +1,27 @@ +% if ($enabled) { +<div style="font-weight: bold; vertical-align: bottom; text-align: left"> +% if ( $UnrepliedTickets->Count > 0 ) { + <a href="<% $fsurl %>rt/Search/UnrepliedTickets.html"> + <div class="dot" style="background-color: green"></div> + <% emt('New activity on [quant,_1,ticket]', $UnrepliedTickets->Count) %> + </a> +% } else { + <% emt('No new activity on tickets') %> +% } +</div> +% } +<%init> +use Class::Load 'load_class'; + +my $enabled = $FS::TicketSystem::system eq 'RT_Internal'; +my $UnrepliedTickets; +if ($enabled) { + my $class = 'RT::Search::UnrepliedTickets'; + load_class($class); + my $session = FS::TicketSystem->session; + my $CurrentUser = $session->{CurrentUser}; + $UnrepliedTickets = RT::Tickets->new($CurrentUser); + my $search = $class->new(TicketsObj => $UnrepliedTickets); + $search->Prepare; +} +</%init> diff --git a/httemplate/elements/page_pref.js b/httemplate/elements/page_pref.js new file mode 100644 index 000000000..253c6da86 --- /dev/null +++ b/httemplate/elements/page_pref.js @@ -0,0 +1,10 @@ +function set_page_pref(prefname, tablenum, prefvalue, success) { + jQuery.post( window.fsurl + 'misc/process/set_page_pref.html', + { path: window.request_comp_path, + name: prefname, + num: tablenum, + value: prefvalue + }, + success + ); +} diff --git a/httemplate/elements/printtofit.js b/httemplate/elements/printtofit.js new file mode 100644 index 000000000..66257fca8 --- /dev/null +++ b/httemplate/elements/printtofit.js @@ -0,0 +1,26 @@ +$().ready(function() { + var beforePrint = function() { + if ($('body').width() > 0) { + // 7.5 inches * 96 DPI; maybe make the width a user pref? + var maxwidth = 7.5 * 96; + $('body').css('zoom', maxwidth / $('body').width()); + } + }; + var afterPrint = function() { + $('body').css('zoom', 1); + } + + if (window.matchMedia) { // chrome, most importantly; also IE10? + window.matchMedia('print').addListener( + function(mq) { + mq.matches ? beforePrint() : afterPrint(); + } + ); + } else { // other IE + $(window).on('beforeprint', beforePrint); + $(window).on('afterprint', afterPrint); + } + // got nothing for firefox + // https://bugzilla.mozilla.org/show_bug.cgi?id=774398 + // but firefox already has "shrink to fit" +}); diff --git a/httemplate/elements/progress-init.html b/httemplate/elements/progress-init.html index e38dde65f..0c2b8165a 100644 --- a/httemplate/elements/progress-init.html +++ b/httemplate/elements/progress-init.html @@ -98,14 +98,14 @@ function <%$key%>process () { overlib( 'Submitting job to server...', WIDTH, 444, HEIGHT, 168, CAPTION, 'Please wait...', STICKY, AUTOSTATUSCAP, CLOSETEXT, '', CLOSECLICK, MIDX, 0, MIDY, 0 ); + // jQuery .serializeArray() maybe? + var copy_fields = <% encode_json(\%copy_fields) %>; var Hash = new Array(); var x = 0; var fieldName; for (var i = 0; i<document.<%$formname%>.elements.length; i++) { field = document.<%$formname%>.elements[i]; - if ( <% join(' || ', map { "(field.name.indexOf('$_') > -1)" } @$fields ) %> - ) - { + if ( <% $all_fields %> || copy_fields[ field.name ] ) { if ( field.type == 'select-multiple' ) { //alert('select-multiple ' + field.name); for (var j=0; j < field.options.length; j++) { @@ -168,6 +168,14 @@ $progress_url->query_form( %dest_info, ); +my $all_fields = 0; +my %copy_fields; +if (grep '/^ALL$/', @$fields) { + $all_fields = 1; +} else { + %copy_fields = map { $_ => 1 } @$fields; +} + #stupid safari is caching the "location" of popup iframs, and submitting them #instead of displaying them. this should prevent that. my $popup_name = 'popup-'.random_id(); diff --git a/httemplate/elements/select-areacode.html b/httemplate/elements/select-areacode.html index f0f56d56d..612f03a8b 100644 --- a/httemplate/elements/select-areacode.html +++ b/httemplate/elements/select-areacode.html @@ -28,6 +28,7 @@ function <% $opt{'prefix'} %>update_areacodes(areacodes) { + var reply = JSON.parse(areacodes); // blank the current areacode for ( var i = what.form.<% $opt{'prefix'} %>areacode.length; i >= 0; i-- ) what.form.<% $opt{'prefix'} %>areacode.options[i] = null; @@ -47,7 +48,7 @@ % } // add the new areacodes - var areacodeArray = eval('(' + areacodes + ')' ); + var areacodeArray = reply.areacodes; for ( var s = 0; s < areacodeArray.length; s++ ) { var areacodeLabel = areacodeArray[s]; if ( areacodeLabel == "" ) @@ -62,6 +63,11 @@ } else { var areacodeerror = document.getElementById('<% $opt{'prefix'} %>areacodeerror'); areacodeerror.style.display = 'inline'; + if ( reply.error ) { + areacodeerror.textContent = reply.error; + } else { + areacodeerror.textContent = 'Select a different state'; + } } //run the callback @@ -78,7 +84,7 @@ <DIV ID="areacodewait" STYLE="display:none"><IMG SRC="<%$fsurl%>images/wait-orange.gif"> <B>Finding area codes</B></DIV> -<DIV ID="areacodeerror" STYLE="display:none"><IMG SRC="<%$fsurl%>images/cross.png"> <B>Select a different state</B></DIV> +<DIV ID="areacodeerror" STYLE="display:none; font-weight: bold"><IMG SRC="<%$fsurl%>images/cross.png"></DIV> <SELECT NAME="<% $opt{'prefix'} %>areacode" onChange="<% $opt{'prefix'} %>areacode_changed(this); <% $opt{'onchange'} %>" <% $opt{'disabled'} %>> <OPTION VALUE="">Select area code</OPTION> diff --git a/httemplate/elements/select-exchange.html b/httemplate/elements/select-exchange.html index b9677094a..33def31b9 100644 --- a/httemplate/elements/select-exchange.html +++ b/httemplate/elements/select-exchange.html @@ -27,6 +27,7 @@ function <% $opt{'prefix'} %>update_exchanges(exchanges) { + var reply = JSON.parse(exchanges); // blank the current exchange for ( var i = what.form.<% $opt{'prefix'} %>exchange.length; i >= 0; i-- ) what.form.<% $opt{'prefix'} %>exchange.options[i] = null; @@ -42,7 +43,7 @@ % } // add the new exchanges - var exchangeArray = eval('(' + exchanges + ')' ); + var exchangeArray = reply.exchanges; for ( var s = 0; s < exchangeArray.length; s++ ) { var exchangeLabel = exchangeArray[s]; if ( exchangeLabel == "" ) @@ -57,6 +58,12 @@ } else { var exchangeerror = document.getElementById('<% $opt{'prefix'} %>exchangeerror'); exchangeerror.style.display = 'inline'; + if ( reply.error ) { + exchangeerror.textContent = reply.error; + } else { + exchangeerror.textContent = 'Select a different area code'; + } + } //run the callback @@ -73,7 +80,7 @@ <DIV ID="exchangewait" STYLE="display:none"><IMG SRC="<%$fsurl%>images/wait-orange.gif"> <B>Finding cities / exchanges</B></DIV> -<DIV ID="exchangeerror" STYLE="display:none"><IMG SRC="<%$fsurl%>images/cross.png"> <B>Select a different area code</B></DIV> +<DIV ID="exchangeerror" STYLE="display:none; font-weight: bold"><IMG SRC="<%$fsurl%>images/cross.png"></DIV> <SELECT NAME="<% $opt{'prefix'} %>exchange" onChange="<% $opt{'prefix'} %>exchange_changed(this); <% $opt{'onchange'} %>" <% $opt{'disabled'} %>> <OPTION VALUE="">Select city / exchange</OPTION> diff --git a/httemplate/elements/select-phonenum.html b/httemplate/elements/select-phonenum.html index 118fe4901..dd1b84736 100644 --- a/httemplate/elements/select-phonenum.html +++ b/httemplate/elements/select-phonenum.html @@ -56,6 +56,7 @@ passing the exchange (or region) and function <% $opt{'prefix'} %>update_phonenums(phonenums) { + var reply = JSON.parse(phonenums); // blank the current phonenum for ( var i = what.form.<% $opt{'prefix'} %>phonenum.length; i >= 0; i-- ) what.form.<% $opt{'prefix'} %>phonenum.options[i] = null; @@ -67,7 +68,7 @@ passing the exchange (or region) and % } // add the new phonenums - var phonenumArray = eval('(' + phonenums + ')' ); + var phonenumArray = reply.phonenums; for ( var s = 0; s < phonenumArray.length; s++ ) { var phonenumLabel = phonenumArray[s]; if ( phonenumLabel == "" ) @@ -86,6 +87,11 @@ passing the exchange (or region) and } else { var phonenumerror = document.getElementById('<% $opt{'prefix'} %>phonenumerror'); phonenumerror.style.display = 'inline'; + if ( reply.error ) { + phonenumerror.textContent = reply.error; + } else { + phonenumerror.textContent = 'Select a different <% $opt{'region'} ? 'region' : 'city/exchange' %>'; + } } //run the callback @@ -157,7 +163,7 @@ passing the exchange (or region) and % unless ( $opt{'tollfree'} ) { <DIV ID="phonenumwait" STYLE="display:none"><IMG SRC="<%$fsurl%>images/wait-orange.gif"> <B>Finding phone numbers</B></DIV> -<DIV ID="phonenumerror" STYLE="display:none"><IMG SRC="<%$fsurl%>images/cross.png"> <B>Select a different <% $opt{'region'} ? 'region' : 'city/exchange' %></B></DIV> +<DIV ID="phonenumerror" STYLE="display:none; font-weight: bold"><IMG SRC="<%$fsurl%>images/cross.png"></DIV> % } <SELECT <% $opt{multiple} ? 'MULTIPLE SIZE=25' : '' %> diff --git a/httemplate/elements/select-region.html b/httemplate/elements/select-region.html index 7ed959269..46c37c935 100644 --- a/httemplate/elements/select-region.html +++ b/httemplate/elements/select-region.html @@ -27,6 +27,7 @@ function <% $opt{'prefix'} %>update_regions(regions) { + var reply = JSON.parse(regions); // blank the current region for ( var i = what.form.<% $opt{'prefix'} %>region.length; i >= 0; i-- ) what.form.<% $opt{'prefix'} %>region.options[i] = null; @@ -42,7 +43,7 @@ % } // add the new regions - var regionArray = eval('(' + regions + ')' ); + var regionArray = reply.regions; for ( var s = 0; s < regionArray.length; s++ ) { var regionLabel = regionArray[s]; if ( regionLabel == "" ) @@ -57,6 +58,11 @@ } else { var regionerror = document.getElementById('<% $opt{'prefix'} %>regionerror'); regionerror.style.display = 'inline'; + if ( reply.error ) { + regionerror.textContent = reply.error; + } else { + regionerror.textContent = 'Select a different state'; + } } //run the callback @@ -73,7 +79,7 @@ <DIV ID="<% $opt{'prefix'} %>regionwait" STYLE="display:none"><IMG SRC="<%$fsurl%>images/wait-orange.gif"> <B>Finding regions</B></DIV> -<DIV ID="<% $opt{'prefix'} %>regionerror" STYLE="display:none"><IMG SRC="<%$fsurl%>images/cross.png"> <B>Select a different state</B></DIV> +<DIV ID="<% $opt{'prefix'} %>regionerror" STYLE="display:none; font-weight: bold"><IMG SRC="<%$fsurl%>images/cross.png"></DIV> <SELECT NAME="<% $opt{'prefix'} %>region" onChange="<% $opt{'prefix'} %>region_changed(this); <% $opt{'onchange'} %>" <% $opt{'disabled'} %>> <OPTION VALUE="">Select region</OPTION> diff --git a/httemplate/elements/select-rt-customfield.html b/httemplate/elements/select-rt-customfield.html index 85758d585..488accac3 100644 --- a/httemplate/elements/select-rt-customfield.html +++ b/httemplate/elements/select-rt-customfield.html @@ -1,31 +1,27 @@ -<SELECT NAME="<% $opt{name} %>"> +<SELECT NAME="<% $opt{'name'} %>"<% $opt{'multiple'} ? ' MULTIPLE' : '' %>> % while ( @fields ) { -<OPTION VALUE="<% shift @fields %>"><% shift @fields %></OPTION> +% my $value = shift @fields; +% my $label = shift @fields; +<OPTION VALUE="<% $value %>"<% $curr_value{$value} ? ' SELECTED' : '' %>><% $label %></OPTION> % } </SELECT> <%init> my %opt = @_; -my $lookuptype = $opt{lookuptype}; -my $valuetype = $opt{valuetype}; -# get a list of TimeValue-type custom fields -my $CurrentUser = RT::CurrentUser->new(); -$CurrentUser->LoadByName($FS::CurrentUser::CurrentUser->username); -die "RT not configured" unless $CurrentUser->id; -my $CFs = RT::CustomFields->new($CurrentUser); -$CFs->Limit(FIELD => 'LookupType', - OPERATOR => 'ENDSWITH', - VALUE => $lookuptype) - if $lookuptype; - -$CFs->Limit(FIELD => 'Type', - VALUE => $valuetype) - if $valuetype; +my %curr_value = map { $_ => 1 } split(', ',$opt{'curr_value'}); my @fields; push @fields, '', $opt{empty_label} if exists($opt{empty_label}); -while (my $CF = $CFs->Next) { - push @fields, $CF->Name, ($CF->Description || $CF->Name); +my $conf = new FS::Conf; + +if ($conf->config('ticket_system') eq 'RT_Internal') { + + push @fields, FS::TicketSystem->custom_fields( + lookuptype => $opt{lookuptype}, + valuetype => $opt{valuetype}, + ); + } + </%init> diff --git a/httemplate/elements/select-rt-queue.html b/httemplate/elements/select-rt-queue.html new file mode 100644 index 000000000..289336516 --- /dev/null +++ b/httemplate/elements/select-rt-queue.html @@ -0,0 +1,24 @@ +<SELECT NAME="<% $opt{'name'} || $opt{'field'} %>"<% $opt{'multiple'} ? ' MULTIPLE' : '' %>> +% while ( @fields ) { +% my $value = shift @fields; +% my $label = shift @fields; +<OPTION VALUE="<% $value %>"<% $curr_value{$value} ? ' SELECTED' : '' %>><% $label %></OPTION> +% } +</SELECT> +<%init> +my %opt = @_; + +my %curr_value = map { $_ => 1 } split(', ',$opt{'curr_value'}); + +my @fields; +push @fields, '', $opt{empty_label} if exists($opt{empty_label}); + +my $conf = new FS::Conf; + +if ($conf->config('ticket_system') eq 'RT_Internal') { + + push @fields, FS::TicketSystem->queues(); + +} + +</%init> diff --git a/httemplate/elements/select-svc.html b/httemplate/elements/select-svc.html new file mode 100644 index 000000000..b439a2852 --- /dev/null +++ b/httemplate/elements/select-svc.html @@ -0,0 +1,73 @@ +<%init> +my %opt = @_; +my $svcdb = $opt{table}; +my $field = $opt{field} || 'svcnum'; +my $id = $opt{id} || $opt{field}; +my $curr_value = [ split(',', $opt{curr_value} || '') ]; +my $label = $opt{name_col} || 'label'; + +# cut-down, jquerified version of select-tiered +# XXX do we need to agent-virt this? edit/part_svc is Configuration-access. +my @part_svc = qsearch('part_svc', { + disabled => '', + svcdb => $svcdb +}); +my %labels; # service labels, of some kind +my %values; # svcnums +my (@all_l, @all_v); +foreach my $part_svc (@part_svc) { + my (@l, @v); + foreach my $svc_x (qsearch({ + 'table' => 'cust_svc', + 'addl_from' => " JOIN $svcdb USING (svcnum)", + 'select' => "$svcdb.*, cust_svc.svcpart", + 'hashref' => { 'svcpart' => $part_svc->svcpart }, + })) + { + push @l, $svc_x->$label; + push @all_l, $svc_x->$label; + push @v, $svc_x->svcnum; + push @all_v, $svc_x->svcnum; + } + $labels{ $part_svc->svcpart } = \@l; + $values{ $part_svc->svcpart } = \@v; +} +$labels{ '' } = \@all_l; +$values{ '' } = \@all_v; + +</%init> +<& /elements/select-table.html, + 'table' => 'part_svc', + 'records' => \@part_svc, + 'id' => $id.'_svcpart', + 'name_col' => 'svc', + 'empty_label' => 'any', + 'curr_value' => '', + 'field' => $id.'_svcpart', # avoid confusion with any other field +&> +<BR> +<& /elements/select.html, + %opt, + 'field' => $field, + 'id' => $id, +&> +<script> +$().ready(function() { + var labels = <% encode_json(\%labels) %>; + var values = <% encode_json(\%values) %>; + var select_svcpart = $('#<% $id.'_svcpart' %>'); + var select_svcnum = $('#<% $id %>'); + var onchange_svcpart = function() { + var l = labels[ this.value ]; + var v = values[ this.value ]; + select_svcnum.empty(); + for (var i = 0; i < v.length; i++) { + var opt = $('<option />').val(v[i]).text(l[i]); + select_svcnum.append(opt); + } + }; + select_svcpart.on('change', onchange_svcpart); + select_svcpart.change(); + select_svcnum.val(<% encode_json($curr_value) %>); +}); +</script> diff --git a/httemplate/elements/select-terms.html b/httemplate/elements/select-terms.html index a330df17c..eda439a4c 100644 --- a/httemplate/elements/select-terms.html +++ b/httemplate/elements/select-terms.html @@ -34,10 +34,7 @@ my $empty_label = my $empty_value = $opt{'empty_value'} || ''; -my @terms = ( emt('Payable upon receipt'), - ( map "Net $_", - 0, 3, 5, 7, 9, 10, 14, 15, 18, 20, 21, 25, 30, 45, 60, 90 ), - ); +my @terms = map emt($_), @FS::Conf::invoice_terms; my @pre_options = $opt{pre_options} ? @{ $opt{pre_options} } : (); diff --git a/httemplate/elements/select.html b/httemplate/elements/select.html index 42cd89504..3a0dc5b68 100644 --- a/httemplate/elements/select.html +++ b/httemplate/elements/select.html @@ -21,6 +21,7 @@ disabled => 0, onchange => 'do_something()', js_only => 0, # disables the whole thing + element_etc => '', # anything else to put in the <select> tag &> </%doc> @@ -35,6 +36,7 @@ <% $style %> <% $opt{disabled} %> <% $onchange %> + <% $opt{'element_etc'} %> > % if ( $opt{options} ) { diff --git a/httemplate/elements/selectlayersx.html b/httemplate/elements/selectlayersx.html new file mode 100644 index 000000000..41f3cb0b7 --- /dev/null +++ b/httemplate/elements/selectlayersx.html @@ -0,0 +1,248 @@ +<%doc> + +Example: + + include( '/elements/selectlayers.html', + 'field' => $key, # SELECT element NAME (passed as form field) + # also used as ID and a unique key for layers and + # functions + 'curr_value' => $selected_layer, + 'options' => [ 'option1', 'option2' ], + 'labels' => { 'option1' => 'Option 1 Label', + 'option2' => 'Option 2 Label', + }, + + #XXX put this handling it its own selectlayers-fields.html element? + 'layer_prefix' => 'prefix_', #optional prefix for fieldnames + 'layer_fields' => { 'layer' => [ 'fieldname', + { label => 'fieldname2', + type => 'text', #implemented: + # text, money, fixed, + # hidden, checkbox, + # checkbox-multiple, + # select, select-agent, + # select-pkg_class, + # select-part_referral, + # select-taxclass, + # select-table, + #XXX tbd: + # more? + }, + ... + ], + 'layer2' => [ 'l2fieldname', + ... + ], + }, + + #current values for layer fields above + 'layer_values' => { 'layer' => { 'fieldname' => 'current_value', + 'fieldname2' => 'field2value', + ... + }, + 'layer2' => { 'l2fieldname' => 'l2value', + ... + }, + ... + }, + + #or manual control, instead of layer_fields and layer_values above + #called with args: my( $layer, $layer_fields, $layer_values, $layer_prefix ) + 'layer_callback' => + + 'html_between => '', #optional HTML displayed between the SELECT and the + #layers, scalar or coderef ('field' passed as a param) + 'onchange' => '', #javascript code run when the SELECT changes + # ("what" is the element) + 'js_only' => 0, #set true to return only the JS portions + 'html_only' => 0, #set true to return only the HTML portions + 'select_only' => 0, #set true to return only the <SELECT> HTML + 'layers_only' => 0, #set true to return only the layers <DIV> HTML + ) + +</%doc> +% unless ( grep $opt{$_}, qw(html_only js_only select_only layers_only) ) { +<SCRIPT TYPE="text/javascript"> +% } +% unless ( grep $opt{$_}, qw(html_only select_only layers_only) ) { + +% unless ($selectlayersx_init) { + +var selectlayerx_info = {}; + +function selectlayersx_changed (field) { + + var what = document.getElementById(field); + selectlayerx_info[field]['onchange'](what); + + var selectedlayer = what.options[what.selectedIndex].value; + for (i=0; i < selectlayerx_info[field]['layers'].length; i++) { + var iterlayer = selectlayerx_info[field]['layers'][i]; + var iterobj = document.getElementById(field+'d'+iterlayer); + if (selectedlayer == iterlayer) { + iterobj.style.display = ""; + iterobj.style.zIndex = 1; + } else { + iterobj.style.display = "none"; + iterobj.style.zIndex = 0; + } + } + +} + +% $selectlayersx_init = 1; +% } #selectlayersx_init + +selectlayerx_info['<% $key %>'] = {}; +selectlayerx_info['<% $key %>']['onchange'] = function (what) { <% $opt{'onchange'} %> }; +selectlayerx_info['<% $key %>']['layers'] = <% encode_json(\@layers) %>; + + +% } #unless html_only/select_only/layers_only +% unless ( grep $opt{$_}, qw(html_only js_only select_only layers_only) ) { +</SCRIPT> +% } +% +% unless ( grep $opt{$_}, qw(js_only layers_only) ) { + + <SELECT NAME = "<% $key %>" + ID = "<% $key %>" + previousValue = "<% $selected %>" + previousText = "<% $options{$selected} %>" + onChange="selectlayersx_changed('<% $key %>')" + > + +% foreach my $option ( keys %$options ) { + + <OPTION VALUE="<% $option %>" + <% $option eq $selected ? ' SELECTED' : '' %> + ><% $options->{$option} |h %></OPTION> + +% } + + </SELECT> + +% } +% unless ( grep $opt{$_}, qw(js_only select_only layers_only) ) { + +<% ref($between) ? &{$between}($key) : $between %> + +% } +% +% unless ( grep $opt{$_}, qw(js_only select_only) ) { + +% foreach my $layer ( @layers ) { +% my $selected_layer; +% $selected_layer = $selected; + + <DIV ID="<% $key %>d<% $layer %>" + STYLE="<% $selected_layer eq $layer + ? 'display: block; z-index: 1' + : 'display: none; z-index: 0' + %>" + > + + <% &{$layer_callback}($layer, $layer_fields, $layer_values, $layer_prefix) %> + + </DIV> + +% } + +% } +<%once> + +my $conf = new FS::Conf; +my $money_char = $conf->config('money_char') || '$'; +my $date_noinit = 0; + +</%once> +<%shared> + +my $selectlayersx_init = 0; + +</%shared> +<%init> + +my %opt = @_; + +#use Data::Dumper; +#warn Dumper(%opt); + +my $key = $opt{field}; # || 'generate_one' #? + +tie my %options, 'Tie::IxHash', + map { $_ => $opt{'labels'}->{$_} } + @{ $opt{'options'} }; #just arrayref for now + +my $between = exists($opt{html_between}) ? $opt{html_between} : ''; +my $options = \%options; + +my @layers = (); +@layers = keys %options; + +my $selected = exists($opt{curr_value}) ? $opt{curr_value} : ''; + +#XXX eek. also eek $layer_fields in the layer_callback() call... +my $layer_fields = $opt{layer_fields}; +my $layer_values = $opt{layer_values}; +my $layer_prefix = $opt{layer_prefix}; + +my $layer_callback = $opt{layer_callback} || \&layer_callback; + +sub layer_callback { + my( $layer, $layer_fields, $layer_values, $layer_prefix ) = @_; + + return '' unless $layer && exists $layer_fields->{$layer}; + tie my %fields, 'Tie::IxHash', @{ $layer_fields->{$layer} }; + + #XXX this should become an element itself... (false laziness w/edit.html) + # but at least all the elements inside are the shared mason elements now + + return '' unless keys %fields; + my $html = "<TABLE>"; + + foreach my $field ( keys %fields ) { + + my $lf = ref($fields{$field}) + ? $fields{$field} + : { 'label'=>$fields{$field} }; + + my $value = $layer_values->{$layer}{$field}; + + my $type = $lf->{type} || 'text'; + + my $include = $type; + + if ( $include eq 'date' ) { + # several important differences from other tr-* + $html .= include( '/elements/tr-input-date-field.html', + { + 'name' => "$layer_prefix$field", + 'value' => $value, + 'label' => $lf->{label}, + 'format'=> $lf->{format}, + 'noinit'=> $date_noinit, + } + ); + $date_noinit = 1; + } + else { + $include = "input-$include" if $include =~ /^(text|money|percentage)$/; + $include = "tr-$include" unless $include eq 'hidden'; + $html .= include( "/elements/$include.html", + %$lf, + 'field' => "$layer_prefix$field", + 'id' => "$layer_prefix$field", #separate? + #don't want field0_label0...? + 'label_id' => $layer_prefix.$field."_label", + + 'value' => ( $lf->{'value'} || $value ), #hmm. + 'curr_value' => $value, + ); + } + } #foreach $field + $html .= '</TABLE>'; + return $html; +} + +</%init> diff --git a/httemplate/elements/standardize_locations.js b/httemplate/elements/standardize_locations.js index 0c4fb029a..15d687cf3 100644 --- a/httemplate/elements/standardize_locations.js +++ b/httemplate/elements/standardize_locations.js @@ -115,7 +115,7 @@ function confirm_standardize(arg) { // then all entered address fields are correct // but we still need to set the lat/long fields and addr_clean - if ( returned['addr_clean'] ) { + if ( returned['all_clean'] ) { status_message('Verified'); } else { status_message('Unverified'); diff --git a/httemplate/elements/table-tickets.html b/httemplate/elements/table-tickets.html index d722c9d2b..b322a5f7c 100644 --- a/httemplate/elements/table-tickets.html +++ b/httemplate/elements/table-tickets.html @@ -14,6 +14,7 @@ View <THEAD> <TR> + <TH CLASS="grid" BGCOLOR="#cccccc"></TH> <TH CLASS="grid" BGCOLOR="#cccccc"><% mt('#') |h %></TH> <TH CLASS="grid" BGCOLOR="#cccccc"><% mt('Subject') |h %></TH> <TH CLASS="grid" BGCOLOR="#cccccc"><% mt('Status') |h %></TH> @@ -42,6 +43,16 @@ View <TR> <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"> +% if ( $ticket->{is_unreplied} ) { + <A CLASS="dot" STYLE="background-color: green" HREF=<%$href%>> +% } else { +% # placeholder + <A CLASS="dot" STYLE="visibility: hidden" HREF=<%$href%>> +% } + </A> + </TD> + + <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"> <A HREF=<%$href%>><% $ticket->{id} %></A> </TD> diff --git a/httemplate/elements/topreload.js b/httemplate/elements/topreload.js new file mode 100644 index 000000000..a66703b29 --- /dev/null +++ b/httemplate/elements/topreload.js @@ -0,0 +1,5 @@ +window.topreload = function() { + if (window != window.top) { + window.top.location.reload(); + } +} diff --git a/httemplate/elements/tower_sector.html b/httemplate/elements/tower_sector.html index 151d3ba65..987177582 100644 --- a/httemplate/elements/tower_sector.html +++ b/httemplate/elements/tower_sector.html @@ -56,8 +56,11 @@ tie my %label, 'Tie::IxHash', 'height' => 'Height', 'freq_mhz' => 'Freq. (MHz)', 'direction' => 'Direction', # or a button to set these to 0 for omni - 'width' => 'Width', # + 'downtilt' => 'Downtilt', + 'width' => 'Horiz. width', + 'v_width' => 'Vert. width', 'sector_range' => 'Range', + 'margin' => 'Signal margin (dB)', ; my @fields = keys %label; diff --git a/httemplate/elements/tr-cust_svc_cancel.html b/httemplate/elements/tr-cust_svc_cancel.html index 44276ec82..52dedd6c8 100644 --- a/httemplate/elements/tr-cust_svc_cancel.html +++ b/httemplate/elements/tr-cust_svc_cancel.html @@ -18,7 +18,14 @@ for use in view/cust_main. % } </B></TD> </TR> -%# no action links, the service is canceled +%# no action links except unprovision, the service is canceled +% if ( $curuser->access_right('Unprovision customer service') && ! $opt{no_links} ) { +<TR> + <TD COLSPAN="2" ALIGN="right" VALIGN="top" STYLE="padding-bottom:5px; padding-top:0px"> + <FONT SIZE="-2">( <% $svc_unprovision_link %> )</FONT> + </TD> +</TR> +% } <%init> my %opt = @_; @@ -29,4 +36,9 @@ my $part_svc = $opt{'part_svc'} || $cust_svc->part_svc; my $cust_pkg = $opt{'cust_pkg'} || $cust_svc->cust_pkg; my $svc_x = $cust_svc->svc_x; +my $svc_unprovision_link = + qq!<A HREF="javascript:areyousure('${p}misc/unprovision.cgi?! . + $cust_svc->svcnum . + qq!', '!.emt('Permanently unprovision and delete this service?').qq!')">!.emt('Unprovision').'</A>'; + </%init> diff --git a/httemplate/elements/tr-freq.html b/httemplate/elements/tr-freq.html index cb58bf6b5..795684cf7 100644 --- a/httemplate/elements/tr-freq.html +++ b/httemplate/elements/tr-freq.html @@ -15,7 +15,7 @@ <% $freq eq $units ? 'SELECTED' : '' %> ><% $freq{$freq} %> % } - </SELECT> + </SELECT><% $opt{'post_text'} || '' %> </TD> diff --git a/httemplate/elements/tr-input-locale-text.html b/httemplate/elements/tr-input-locale-text.html new file mode 100644 index 000000000..110a8aa9b --- /dev/null +++ b/httemplate/elements/tr-input-locale-text.html @@ -0,0 +1,120 @@ +<%doc> +Usage: + +In edit/foo.html: + +<& /elements/tr-input-locale-text.html, + cgi => $cgi, # needed to preserve values in error redirect + object => $record, + field => 'myfield', + label => 'My Field', +&> + +And in edit/process/foo.html: +<& elements/process.html, + ... + process_locale => 'myfield', +&> + +'object' needs to be an FS::Record subclass instance for a table that has +a '_msgcat' localization table. For a table "foo" where "foo.myfield" +contains some customer-visible label (in the default locale), +"foo_msgcat.myfield" contains the translation of that label for a customer +locale. The foreign key in foo_msgcat must have the same name as the primary +key of foo. + +Currently only a single field can be localized this way; including this +element more than once in the form will lead to conflicts. This is how +it should work; if at some point we need to localize several fields of the +same record, we should modify this element to show multiple inputs for each +locale. + +</%doc> +<%init> + +my %opt = @_; +my $object = delete $opt{object}; +my $field = delete $opt{field}; + +# identify our locales +my $conf = FS::Conf->new; +my $default_locale = $conf->config('locale') || 'en_'; +my @locales = grep { ! /^$default_locale/ } $conf->config('available-locales'); + +my $label = delete $opt{label}; +my %labels = map { $_ => "$label—".FS::Locales->description($_) } + @locales; +@locales = sort { $labels{$a} cmp $labels{$b} } @locales; +my %curr_values; + +# where are the msgcat records? +my $msgcat_table = $object->table . '_msgcat'; +my $msgcat_pkey = dbdef->table($msgcat_table)->primary_key; +my %msgcat_pkeyvals; + +# find existing msgcat records, if any, and record their message values +# and pkeys +my $pkey = $object->primary_key; +my $pkeyval = $object->get($pkey); +if ($pkeyval) { # of course if this is a new record there won't be any + my @linked = qsearch($msgcat_table, { $pkey => $pkeyval }); + foreach (@linked) { + $curr_values{ $_->locale } = $_->get( $field ); + $msgcat_pkeyvals{ $_->locale } = $_->get( $msgcat_pkey ); + } +} + +# sticky-on-error the locale inputs +if( my $cgi = $opt{cgi} ) { + my $i = 0; + # they're named 'foomsgnum0_locale' and 'foomsgnum0_myfield' + while ( my $locale = $cgi->param($msgcat_pkey . $i . '_locale') ) { + my $value = $cgi->param($msgcat_pkey . $i . '_' . $field); + $curr_values{ $locale } = $value; + $i++; + } +} + +# compat with tr-input-text for styling +my $cell_style = $opt{'cell_style'} ? 'STYLE="'. $opt{'cell_style'}. '"' : ''; + +my $colspan = $opt{'colspan'} ? 'COLSPAN="'.$opt{'colspan'}.'"' : ''; + + +</%init> +% # pass through %opt on all of these to retain formatting +% # one tr, td, and input for the default locale +<& tr-input-text.html, + %opt, + 'label' => $label, + 'field' => $field +&> +% # and one for each of the others +% my $i = 0; +% foreach my $locale (@locales) { +% my $basename = $msgcat_pkey . $i; +% my $lfield = $basename . '_' . $field; +<& tr-td-label.html, + %opt, + 'id' => $lfield, # uniqueness + 'label' => $labels{$locale} +&> + <TD <% $colspan %><% $cell_style %> ID="<% $lfield %>_input0"> + <& hidden.html, + 'field' => $basename, + 'curr_value' => $msgcat_pkeyvals{$locale}, + # will be empty if this is a new record and/or new locale, that's fine + &> + <& hidden.html, + 'field' => $basename . '_locale', + 'curr_value' => $locale, + &> + <& input-text.html, + %opt, + 'field' => $lfield, + 'curr_value' => $curr_values{$locale}, + &> + </TD> +</TR> +% $i++; +% } # foreach $locale diff --git a/httemplate/elements/tr-select-cust-part_pkg.html b/httemplate/elements/tr-select-cust-part_pkg.html index 6244b6cb7..f4af405fc 100644 --- a/httemplate/elements/tr-select-cust-part_pkg.html +++ b/httemplate/elements/tr-select-cust-part_pkg.html @@ -86,7 +86,7 @@ </TR> % } else { # so that the rest of the page works correctly - <INPUT TYPE="hidden" ID="classnum" NAME="classnum" VALUE="-1`"> + <INPUT TYPE="hidden" ID="classnum" NAME="classnum" VALUE="-1"> % } <TR> diff --git a/httemplate/elements/tr-select-reason.html b/httemplate/elements/tr-select-reason.html index 97466f175..9a430222c 100755 --- a/httemplate/elements/tr-select-reason.html +++ b/httemplate/elements/tr-select-reason.html @@ -188,9 +188,8 @@ my $class = $opt{'reason_class'}; my $init_reason; if ( $opt{'cgi'} ) { $init_reason = $opt{'cgi'}->param($name); -} else { - $init_reason = $opt{'curr_value'}; } +$init_reason ||= $opt{'curr_value'}; my $id = $opt{'id'} || $name; $id =~ s/\./_/g; # for edit/part_event diff --git a/httemplate/elements/tr-select-router_block_ip.html b/httemplate/elements/tr-select-router_block_ip.html index ee135686c..2aa715e29 100644 --- a/httemplate/elements/tr-select-router_block_ip.html +++ b/httemplate/elements/tr-select-router_block_ip.html @@ -56,7 +56,7 @@ function clearhint_ip_addr (what) { ] &> </td></tr> -<& /elements/tr-td-label.html, label => 'IP address', required => $opt{'ip_addr_required'} &> +<& /elements/tr-td-label.html, label => ($opt{'ip_addr_label'} || 'IP address'), required => $opt{'ip_addr_required'} &> <td> % #warn Dumper \%fixed; % if ( exists $fixed{$ip_field} ) { diff --git a/httemplate/elements/tr-select-rt-queue.html b/httemplate/elements/tr-select-rt-queue.html new file mode 100644 index 000000000..ac3689b1c --- /dev/null +++ b/httemplate/elements/tr-select-rt-queue.html @@ -0,0 +1,7 @@ + +<& 'tr-td-label.html', @_ &> +<TD> +<& 'select-rt-queue.html', @_ &> +</TD> +</TR> + diff --git a/httemplate/elements/tr-selectlayersx.html b/httemplate/elements/tr-selectlayersx.html new file mode 100644 index 000000000..ca7a36079 --- /dev/null +++ b/httemplate/elements/tr-selectlayersx.html @@ -0,0 +1,25 @@ +% unless ( $opt{js_only} ) { + + <% include('tr-td-label.html', @_ ) %> + + <TD <% $style %>> + +% } + + <% include('selectlayersx.html', @_ ) %> + +% unless ( $opt{js_only} ) { + + </TD> + + </TR> + +% } + +<%init> + +my %opt = @_; + +my $style = $opt{'cell_style'} ? 'STYLE="'. $opt{'cell_style'}. '"' : ''; + +</%init> diff --git a/httemplate/elements/xmlhttp.html b/httemplate/elements/xmlhttp.html index 2f4f0d555..e70871169 100644 --- a/httemplate/elements/xmlhttp.html +++ b/httemplate/elements/xmlhttp.html @@ -44,7 +44,7 @@ my %initialized = ();#won't work if component is "preloaded"... so don't do that len = args.length - 1; } for (var i = 0; i < len; i++) - content = content + "&arg=" + escape(args[i]); + content = content + "&arg=" + encodeURIComponent(args[i]); content = content.replace( /[+]/g, '%2B'); // fix unescaped plus signs if ( '<%$method%>' == 'GET' ) { |
