UI for per-city taxes (setup and assigning to customers/package locations), RT#5852
authorivan <ivan>
Mon, 12 Oct 2009 01:45:12 +0000 (01:45 +0000)
committerivan <ivan>
Mon, 12 Oct 2009 01:45:12 +0000 (01:45 +0000)
14 files changed:
FS/FS/Mason.pm
FS/FS/Misc.pm
FS/FS/Schema.pm
FS/FS/cust_main_county.pm
httemplate/browse/cust_main_county.cgi
httemplate/edit/cust_main.cgi
httemplate/edit/cust_main_county-expand.cgi
httemplate/edit/process/cust_main_county-collapse.cgi
httemplate/edit/process/cust_main_county-expand.cgi
httemplate/elements/city.html [new file with mode: 0644]
httemplate/elements/location.html
httemplate/elements/select-county.html
httemplate/elements/tr-select-cust_location.html
httemplate/misc/cities.cgi [new file with mode: 0644]

index 6e6072e..98cf254 100644 (file)
@@ -118,7 +118,9 @@ if ( -e $addl_handler_use_file ) {
   use FS::UI::Web::small_custview qw(small_custview);
   use FS::UI::bytecount;
   use FS::Msgcat qw(gettext geterror);
-  use FS::Misc qw( send_email send_fax states_hash counties state_label );
+  use FS::Misc qw( send_email send_fax
+                   states_hash counties cities state_label
+                 );
   use FS::Misc::eps2png qw( eps2png );
   use FS::Report::Table::Monthly;
   use FS::TicketSystem;
index 5231350..dca906c 100644 (file)
@@ -14,7 +14,7 @@ use File::Temp;
 
 @ISA = qw( Exporter );
 @EXPORT_OK = qw( generate_email send_email send_fax
-                 states_hash counties state_label
+                 states_hash counties cities state_label
                  card_types
                  generate_ps generate_pdf do_print
                  csv_from_fixed
@@ -556,6 +556,7 @@ Returns a list of counties for this state and country.
 sub counties {
   my( $state, $country ) = @_;
 
+  map { $_ } #return num_counties($state, $country) unless wantarray;
   sort map { s/[\n\r]//g; $_; }
        map { $_->county }
            qsearch({
@@ -567,6 +568,28 @@ sub counties {
            });
 }
 
+=item cities COUNTY STATE COUNTRY
+
+Returns a list of cities for this county, state and country.
+
+=cut
+
+sub cities {
+  my( $county, $state, $country ) = @_;
+
+  map { $_ } #return num_cities($county, $state, $country) unless wantarray;
+  sort map { s/[\n\r]//g; $_; }
+       map { $_->city }
+           qsearch({
+             'select'  => 'DISTINCT city',
+             'table'   => 'cust_main_county',
+             'hashref' => { 'county'  => $county,
+                            'state'   => $state,
+                            'country' => $country,
+                          },
+           });
+}
+
 =item state_label STATE COUNTRY_OR_LOCALE_SUBCOUNRY_OBJECT
 
 =cut
index 6f53b2a..946cf7f 100644 (file)
@@ -405,12 +405,13 @@ sub tables_hashref {
         'printed',      'int',     '', '', '', '', 
 
         #specific use cases
-        'closed',      'char', 'NULL',  1, '', '', 
+        'closed',      'char', 'NULL',  1, '', '', #not yet used much
         'statementnum', 'int', 'NULL', '', '', '', #invoice aggregate statements
+        'agent_invid',  'int', 'NULL', '', '', '', #(varchar?) importing legacy
       ],
       'primary_key' => 'invnum',
-      'unique' => [],
-      'index' => [ ['custnum'], ['_date'], ['statementnum'], ],
+      'unique' => [ [ 'custnum', 'agent_invid' ] ], #agentnum?  huh
+      'index' => [ ['custnum'], ['_date'], ['statementnum'], ['agent_invid'] ],
     },
 
     'cust_statement' => {
@@ -866,8 +867,9 @@ sub tables_hashref {
                             # a tax rate.
       'columns' => [
         'taxnum',   'serial',   '',    '', '', '', 
-        'state',    'varchar',  'NULL',    $char_d, '', '', 
+        'city',     'varchar',  'NULL',    $char_d, '', '',
         'county',   'varchar',  'NULL',    $char_d, '', '', 
+        'state',    'varchar',  'NULL',    $char_d, '', '', 
         'country',  'char',  '', 2, '', '', 
         'taxclass',   'varchar', 'NULL', $char_d, '', '', 
         'exempt_amount', @money_type, '', '', 
@@ -879,7 +881,7 @@ sub tables_hashref {
       'primary_key' => 'taxnum',
       'unique' => [],
   #    'unique' => [ ['taxnum'], ['state', 'county'] ],
-      'index' => [ [ 'county' ], [ 'state' ], [ 'country' ],
+      'index' => [ [ 'city' ], [ 'county' ], [ 'state' ], [ 'country' ],
                    [ 'taxclass' ],
                  ],
     },
index bb60abb..ab1ac1e 100644 (file)
@@ -2,7 +2,7 @@ package FS::cust_main_county;
 
 use strict;
 use vars qw( @ISA @EXPORT_OK $conf
-             @cust_main_county %cust_main_county $countyflag );
+             @cust_main_county %cust_main_county $countyflag ); # $cityflag );
 use Exporter;
 use FS::Record qw( qsearch dbh );
 use FS::cust_bill_pkg;
@@ -17,6 +17,7 @@ use FS::cust_tax_exempt_pkg;
 
 @cust_main_county = ();
 $countyflag = '';
+#$cityflag = '';
 
 #ask FS::UID to run this stuff for us later
 $FS::UID::callback{'FS::cust_main_county'} = sub { 
@@ -55,10 +56,12 @@ currently supported:
 
 =item taxnum - primary key (assigned automatically for new tax rates)
 
-=item state
+=item city
 
 =item county
 
+=item state
+
 =item country
 
 =item tax - percentage
@@ -116,8 +119,9 @@ sub check {
   $self->exempt_amount(0) unless $self->exempt_amount;
 
   $self->ut_numbern('taxnum')
-    || $self->ut_anything('state')
+    || $self->ut_textn('city')
     || $self->ut_textn('county')
+    || $self->ut_anything('state')
     || $self->ut_text('country')
     || $self->ut_float('tax')
     || $self->ut_textn('taxclass') # ...
index 232e688..d94e892 100755 (executable)
@@ -45,22 +45,22 @@ my $exempt_sub = sub {
   [ map [ {'data'=>$_} ], @exempt ];
 };
 
-my $oldrow;
+my $cs_oldrow;
 my $cell_style;
 my $cell_style_sub = sub {
   my $row = shift;
-  if ( $oldrow ne $row ) {
-    if ( $oldrow ) {
-      if ( $oldrow->country ne $row->country ) {
+  if ( $cs_oldrow ne $row ) {
+    if ( $cs_oldrow ) {
+      if ( $cs_oldrow->country ne $row->country ) {
         $cell_style = 'border-top:1px solid #000000';
-      } elsif ( $oldrow->state ne $row->state ) {
+      } elsif ( $cs_oldrow->state ne $row->state ) {
         $cell_style = 'border-top:1px solid #cccccc'; #default?
-      } elsif ( $oldrow->state eq $row->state ) {
+      } elsif ( $cs_oldrow->state eq $row->state ) {
         #$cell_style = 'border-top:dashed 1px dark gray';
         $cell_style = 'border-top:1px dashed #cccccc';
       }
     }
-    $oldrow = $row;
+    $cs_oldrow = $row;
   }
   return $cell_style;
 };
@@ -80,9 +80,16 @@ my $edit_onclick = sub {
          );
 };
 
+my $ex_oldrow;
 sub expand_link {
   my %param = @_;
 
+  if ( $ex_oldrow eq $param{'row'} ) {
+    return '';
+  } else {
+    $ex_oldrow = $param{'row'};
+  }
+
   my $taxnum = $param{'row'}->taxnum;
   my $url = "${p}edit/cust_main_county-expand.cgi?$taxnum";
 
@@ -101,9 +108,30 @@ sub expand_link {
 sub collapse_link {
   my %param = @_;
 
+  my $row = $param{'row'};
+  my $col = $param{'col'};
+  return ''
+    if $col eq 'county' and $row->city
+                            || qsearch({
+                                 'table'   => 'cust_main_county',
+                                 'hashref' => {
+                                   'country' => $row->country,
+                                   'state'   => $row->state,
+                                   'city'    => { op=>'!=', value=>'' },
+                                 },
+                                 'order_by' => 'LIMIT 1',
+                               });
+
+  my %above = ( 'city'   => 'county',
+                'county' => 'state',
+              );
+
+  #XXX can still show the link when you have some counties broken down into
+  #cities and others not :/
+
   my $taxnum = $param{'row'}->taxnum;
   my $url = "${p}edit/process/cust_main_county-collapse.cgi?$taxnum";
-  $url = "javascript:collapse_areyousure('$url')";
+  $url = "javascript:collapse_areyousure('$url', '$col', '$above{$col}')";
 
   qq(<FONT SIZE="-1"><A HREF="$url">$param{'label'}</A></FONT>);
 }
@@ -133,14 +161,15 @@ my @menubar;
 
 my $html_init = <<END;
   <SCRIPT>
-    function collapse_areyousure(href) {
-     if (confirm("Are you sure you want to remove all county tax rates for this state?") == true)
+    function collapse_areyousure(href,col,above) {
+     if (confirm('Are you sure you want to remove all ' + col + ' tax rates for this ' + above + '?') == true)
        window.location.href = href;
     }
   </SCRIPT>
 
   Click on <u>add states</u> to specify a country's tax rates by state or province.
   <BR>Click on <u>add counties</u> to specify a state's tax rates by county, or <u>remove counties</u> to remove per-county tax rates.
+  <BR>Click on <u>add cities</u> to specify a county's tax rates by city, or <u>remove cities</u> to remove per-city tax rates.
 END
 
 $html_init .= "<BR>Click on <u>separate taxclasses</u> to specify taxes per taxclass."
@@ -359,11 +388,11 @@ if ( $taxclass ) {
 
 $cell_style = '';
 
-my @header        = ( 'Country', 'State/Province', 'County',);
-my @header2       = ( '', '', '', );
-my @links         = ( '', '', '', );
-my @link_onclicks = ( '', '', '', );
-my $align = 'lll';
+my @header        = ( 'Country', 'State/Province', 'County', 'City' );
+my @header2       = ( '', '', '', '', );
+my @links         = ( '', '', '', '', );
+my @link_onclicks = ( '', '', '', '', );
+my $align = 'llll';
 
 my @fields = (
   sub { my $country = shift->country;
@@ -380,7 +409,8 @@ my @fields = (
       },
   sub { $_[0]->county
           ? $_[0]->county. '&nbsp'.
-              collapse_link( label=> 'remove&nbsp;counties',
+              collapse_link( col  => 'county',
+                             label=> 'remove&nbsp;counties',
                              row  => $_[0],
                            )
           : '(all)&nbsp'.
@@ -389,12 +419,25 @@ my @fields = (
                              label => 'add&nbsp;counties',
                          );
       },
+  sub { $_[0]->city
+          ? $_[0]->city. '&nbsp'.
+              collapse_link( col  => 'city',
+                             label=> 'remove&nbsp;cities',
+                             row  => $_[0],
+                           )
+          : '(all)&nbsp'.
+              expand_link(   desc  => 'Add Cities',
+                             row   => $_[0],
+                             label => 'add&nbsp;cities',
+                         );
+      },
 );
 
 my @color = (
   '000000',
   sub { shift->state  ? '000000' : '999999' },
   sub { shift->county ? '000000' : '999999' },
+  sub { shift->city   ? '000000' : '999999' },
 );
 
 if ( $conf->exists('enable_taxclasses') ) {
@@ -430,9 +473,10 @@ my $cb_sub = sub {
   my $cust_main_county = shift;
 
   if ( $cb_oldrow ) {
-    if (    $cb_oldrow->country  ne $cust_main_county->country 
-         || $cb_oldrow->state    ne $cust_main_county->state  
+    if (    $cb_oldrow->city     ne $cust_main_county->city 
          || $cb_oldrow->county   ne $cust_main_county->county  
+         || $cb_oldrow->state    ne $cust_main_county->state  
+         || $cb_oldrow->country  ne $cust_main_county->country 
          || $cb_oldrow->taxclass ne $cust_main_county->taxclass )
     {
       $newregion = 1;
index 15c9f45..fac7ef2 100755 (executable)
 
 %  my $same_checked = '';
 %  my $ship_disabled = '';
+%  my @ship_style = ();
 %  unless ( $cust_main->ship_last && $same ne 'Y' ) {
 %    $same_checked = 'CHECKED';
-%    $ship_disabled = 'DISABLED STYLE="background-color: #dddddd"';
+%    $ship_disabled = 'DISABLED';
+%    push @ship_style, 'background-color:#dddddd';
 %    foreach (
 %      qw( last first company address1 address2 city county state zip country
 %          daytime night fax )
 function bill_changed(what) {
   if ( what.form.same.checked ) {
 % for (qw( last first company address1 address2 city zip daytime night fax )) { 
-
     what.form.ship_<%$_%>.value = what.form.<%$_%>.value;
 % } 
 
     what.form.ship_country.selectedIndex = what.form.country.selectedIndex;
 
+    function fix_ship_city() {
+      what.form.ship_city_select.selectedIndex = what.form.city_select.selectedIndex;
+      what.form.ship_city.style.display = what.form.city.style.display;
+      what.form.ship_city_select.style.display = what.form.city_select.style.display;
+    }
+
     function fix_ship_county() {
       what.form.ship_county.selectedIndex = what.form.county.selectedIndex;
+      ship_county_changed(what.form.ship_county, fix_ship_city );
     }
 
     function fix_ship_state() {
@@ -97,7 +105,8 @@ function samechanged(what) {
   if ( what.checked ) {
     bill_changed(what);
 
-%   for (qw( last first company address1 address2 city county state zip country daytime night fax )) { 
+%   my @fields = qw( last first company address1 address2 city city_select county state zip country daytime night fax );
+%   for (@fields) { 
       what.form.ship_<%$_%>.disabled = true;
       what.form.ship_<%$_%>.style.backgroundColor = '#dddddd';
 %   } 
@@ -111,7 +120,7 @@ function samechanged(what) {
 
   } else {
 
-%   for (qw( last first company address1 address2 city county state zip country daytime night fax )) { 
+%   for (@fields) { 
       what.form.ship_<%$_%>.disabled = false;
       what.form.ship_<%$_%>.style.backgroundColor = '#ffffff';
 %   } 
@@ -136,6 +145,7 @@ function samechanged(what) {
              'pre'       => 'ship_',
              'onchange'  => '',
              'disabled'  => $ship_disabled,
+             'style'     => \@ship_style
           )
 %>
 
index d5297ab..265dd1d 100755 (executable)
@@ -37,9 +37,11 @@ my $cust_main_county = qsearchs('cust_main_county',{'taxnum'=>$taxnum})
 
 my $title;
 
-die "Can't expand entry!" if $cust_main_county->county;
+die "Can't expand entry!" if $cust_main_county->city;
 
-if ( $cust_main_county->state ) {
+if ( $cust_main_county->county ) {
+  $title = 'Cities';
+} elsif ( $cust_main_county->state ) {
   $title = 'Counties';
 } else {
   $title = 'States/Provinces';
index 18bd1fd..9608fc9 100755 (executable)
@@ -12,10 +12,15 @@ my $cust_main_county = qsearchs('cust_main_county', { 'taxnum' => $taxnum } )
 
 #really should do this in a .pm & start transaction
 
-foreach my $delete ( qsearch('cust_main_county', {
-                    'country' => $cust_main_county->country,
-                    'state' => $cust_main_county->state  
-                 } ) ) {
+my %search = (
+               'country' => $cust_main_county->country,
+               'state'   => $cust_main_county->state,
+             );
+
+$search{'county'} = $cust_main_county->county
+  if $cust_main_county->city;
+
+foreach my $delete ( qsearch('cust_main_county', \%search) ) {
 #  unless ( qsearch('cust_main',{
 #    'state'  => $cust_main_county->getfield('state'),
 #    'county' => $cust_main_county->getfield('county'),
@@ -30,7 +35,11 @@ foreach my $delete ( qsearch('cust_main_county', {
 }
 
 $cust_main_county->taxnum('');
-$cust_main_county->county('');
+if ( $cust_main_county->city ) {
+  $cust_main_county->city('');
+} else {
+  $cust_main_county->county('');
+}
 my $error = $cust_main_county->insert;
 die $error if $error;
 
index 04533a5..9984b08 100755 (executable)
@@ -48,17 +48,21 @@ foreach ( @expansion) {
     $new->setfield('taxclass', $_);
   } elsif ( ! $cust_main_county->state ) {
     $new->setfield('state',$_);
-  } else {
+  } elsif ( ! $cust_main_county->county ) {
     $new->setfield('county',$_);
+  } else {
+    #uppercase cities in the US to try and agree with USPS validation
+    $new->setfield('city', $new->country eq 'US' ? uc($_) : $_ );
   }
   my $error = $new->insert;
   die $error if $error;
 }
 
 unless ( qsearch( 'cust_main', {
-                                 'state'  => $cust_main_county->state,
-                                 'county' => $cust_main_county->county,
-                                 'country' =>  $cust_main_county->country,
+                                 'city'    => $cust_main_county->city,
+                                 'county'  => $cust_main_county->county,
+                                 'state'   => $cust_main_county->state,
+                                 'country' => $cust_main_county->country,
                                } )
          || ! @expansion
 ) {
@@ -68,8 +72,9 @@ unless ( qsearch( 'cust_main', {
 
 if ( $cgi->param('taxclass') ) {
   print $cgi->redirect(popurl(3). "browse/cust_main_county.cgi?".
-                         'state='.   uri_escape($cust_main_county->state  ).';'.
+                         'city='.    uri_escape($cust_main_county->city   ).';'.
                          'county='.  uri_escape($cust_main_county->county ).';'.
+                         'state='.   uri_escape($cust_main_county->state  ).';'.
                          'country='. uri_escape($cust_main_county->country)
                       );
   myexit;
diff --git a/httemplate/elements/city.html b/httemplate/elements/city.html
new file mode 100644 (file)
index 0000000..1659ebf
--- /dev/null
@@ -0,0 +1,142 @@
+<%doc>
+
+Example:
+
+  include( '/elements/city.html',
+    #recommended
+    country    => $current_country,
+    state      => $current_state,
+    county     => $current_county,
+    city       => $current_city,
+
+    #optional
+    prefix        => $optional_unique_prefix,
+    onchange      => $javascript,
+    disabled      => 0, #bool
+#    disable_empty => 1, #defaults to 1, disable the empty option
+#    empty_label   => 'all', #label for empty option
+    style         => [ 'attribute:value', 'another:value' ],
+  );
+
+</%doc>
+
+<% include('/elements/xmlhttp.html',
+              'url'  => $p.'misc/cities.cgi',
+              'subs' => [ $pre. 'get_cities' ],
+           )
+%>
+
+<SCRIPT TYPE="text/javascript">
+
+  function opt(what,value,text) {
+    var optionName = new Option(text, value, false, false);
+    var length = what.length;
+    what.options[length] = optionName;
+  }
+
+  var saved_<%$pre%>city= '';
+
+  function <% $pre %>county_changed(what, callback) {
+
+    county  = what.options[what.selectedIndex].value;
+    state   = what.form.<% $pre %>state.options[what.form.<% $pre %>state.selectedIndex].value;
+    country = what.form.<% $pre %>country.options[what.form.<% $pre %>country.selectedIndex].value;
+
+    function <% $pre %>update_cities(cities) {
+     
+      // blank the current city list
+      for ( var i = what.form.<% $pre %>city_select.length; i >= 0; i-- )
+          what.form.<% $pre %>city_select.options[i] = null;
+
+      // add the new cities
+      var citiesArray = eval('(' + cities + ')' );
+
+      for ( var s = 0; s < citiesArray.length; s++ ) {
+          var cityLabel = citiesArray[s];
+          if ( cityLabel == "" )
+              cityLabel = '(n/a)';
+          opt(what.form.<% $pre %>city_select, citiesArray[s], cityLabel);
+      }
+
+     if ( citiesArray.length > 1 || citiesArray[0].length ) { 
+        // turn off the text city, turn on the select
+        saved_<%$pre%>city = what.form.<%$ pre %>city.value;
+        what.form.<% $pre %>city.style.display = 'none';
+        what.form.<% $pre %>city_select.style.display = '';
+      } else {
+        // turn on the text city, turn off the select
+        what.form.<%$ pre %>city.value = saved_<%$pre%>city;
+        what.form.<% $pre %>city.style.display = '';
+        what.form.<% $pre %>city_select.style.display = 'none';
+      }
+
+      //run the callback
+      if ( callback != null )
+        callback();
+    }
+
+    // go get the new cities
+    <% $pre %>get_cities( county, state, country, <% $pre %>update_cities );
+
+  }
+
+  function <%$pre%>city_select_changed(what) {
+    what.form.<%$pre%>city.value = what.options[what.selectedIndex].value;
+  }
+
+</SCRIPT>
+
+<INPUT TYPE     = "text"
+       NAME     = "<%$pre%>city"
+       ID       = "<%$pre%>city"
+       VALUE    = "<% $opt{'city'} |h %>"
+       onChange = "<% $opt{'onchange'} %>"
+       <% $opt{'disabled'} %>
+       <% $text_style %>
+>
+
+<SELECT NAME     = "<%$pre%>city_select"
+        ID       = "<%$pre%>city_select"
+        onChange = "<%$pre%>city_select_changed(this); <% $opt{'onchange'} %>"
+        <% $opt{'disabled'} %>
+        <% $select_style %>
+>
+
+% foreach my $city ( @cities ) {
+
+    <OPTION VALUE="<% $city |h %>"
+            <% $city eq $opt{'city'} ? 'SELECTED' : '' %>
+    ><% $city eq $opt{'empty_data_value'} ? $opt{'empty_data_label'} : $city %>
+
+% }
+
+</SELECT>
+
+%#           VALUE    = "<% $curr_value |h %>"
+<%init>
+
+my %opt = @_;
+
+my $pre = $opt{'prefix'};
+
+my $text_style   = $opt{'style'} ? [ @{ $opt{'style'} } ] : [];
+my $select_style = $opt{'style'} ? [ @{ $opt{'style'} } ] : [];
+
+my @cities = cities( $opt{'county'}, $opt{'state'}, $opt{'country'} );
+if ( scalar(@cities) > 1 || $cities[0] ) {
+  push @$text_style, 'display:none';
+} else {
+  push @$select_style, 'display:none';
+}
+
+$text_style =
+  scalar(@$text_style)
+    ? 'STYLE="'. join(';', @$text_style). '"'
+    : '';
+
+$select_style =
+  scalar(@$select_style)
+    ? 'STYLE="'. join(';', @$select_style). '"'
+    : '';
+
+</%init>
index 07aaa69..5478e1e 100644 (file)
@@ -49,16 +49,7 @@ Example:
 
 <TR>
   <TH ALIGN="right"><%$r%>City</TH>
-  <TD WIDTH="1">
-    <INPUT TYPE     = "text"
-           NAME     = "<%$pre%>city"
-           ID       = "<%$pre%>city"
-           VALUE    = "<% $object->get($pre.'city') |h %>"
-           onChange = "<% $onchange %>"
-           <% $disabled %>
-           <% $style %>
-    >
-  </TD>
+  <TD WIDTH="1"><% include('/elements/city.html', %select_hash) %></TD>
   <TH ALIGN="right" ID="<%$pre%>countylabel" <%$county_style%>><%$r%>County</TH>
   <TD><% include('/elements/select-county.html', %select_hash ) %></TD>
   <TH ALIGN="right" WIDTH="1"><%$r%>State</TH>
@@ -123,7 +114,7 @@ $object->set($pre.'state', $statedefault )
          || $object->get($pre.'country') ne $countrydefault;
 
 my @style = ();
-push @style, 'background-color: #dddddd"' if $disabled;
+push @style, 'background-color: #dddddd' if $disabled;
 
 my @address2_label_style = ();
 push @address2_label_style, 'visibility:hidden'
@@ -152,6 +143,7 @@ my $county_style =
     : '';
 
 my %select_hash = (
+  'city'     => $object->get($pre.'city'),
   'county'   => $object->get($pre.'county'),
   'state'    => $object->get($pre.'state'),
   'country'  => $object->get($pre.'country'),
index aa88abe..aa9f453 100644 (file)
@@ -67,8 +67,11 @@ Example:
         }
 
         //run the callback
-        if ( callback != null ) 
+        if ( callback != null )  {
           callback();
+        } else {
+          <% $pre %>county_changed(what.form.<% $pre %>county);
+        }
       }
   
       // go get the new counties
@@ -80,7 +83,7 @@ Example:
 
   <SELECT NAME    = "<% $pre %>county"
           ID      = "<% $pre %>county"
-          onChange= "<% $opt{'onchange'} %>"
+          onChange= "<% $onchange %>"
           <% $opt{'disabled'} %>
           <% $style %>
   >
@@ -127,11 +130,13 @@ $opt{'disable_empty'} = 1 unless exists($opt{'disable_empty'});
 
 my $pre = $opt{'prefix'};
 
+
+# disable_cityupdate?
+my $onchange =
+  ( $opt{'disable_cityupdate'} ? '' : $pre.'county_changed(this); ' ).
+  $opt{'onchange'};
+
 $opt{'style'} ||= [];
-my $style =
-  scalar(@{$opt{style}})
-    ? 'STYLE="'. join(';', @{$opt{style}}). '"'
-    : '';
 
 my @counties = ();
 if ( $countyflag ) {
@@ -139,17 +144,16 @@ if ( $countyflag ) {
   @counties = map { length($_) ? $_ : $opt{'empty_data_value'} }
                   counties( $opt{'state'}, $opt{'country'} );
 
-  # this is very hacky
-  unless ( scalar(@counties) > 1 ) {
-    if ( $opt{'disabled'} =~ /STYLE=/i ) {
-      $opt{'disabled'} =~ s/STYLE="([^"]+)"/STYLE="$1; display:none"/i;
-    } else {
-      $opt{'disabled'} .= ' STYLE="display:none"';
-    }
-  }
+  push @{ $opt{'style'} }, 'display:none'
+    unless scalar(@counties) > 1;
 
 }
 
+my $style =
+  scalar(@{$opt{style}})
+    ? 'STYLE="'. join(';', @{$opt{style}}). '"'
+    : '';
+
 </%init>
 <%once>
 
index da16dfe..ab043ee 100644 (file)
@@ -21,7 +21,7 @@ Example:
     var locationnum = what.options[what.selectedIndex].value;
     if ( locationnum == -1 ) {
 
-%     for (@location_fields) { 
+%     for (@location_fields, 'city_select') { 
         what.form.<%$_%>.disabled = false;
         what.form.<%$_%>.style.backgroundColor = '#ffffff';
 %     } 
@@ -60,7 +60,7 @@ Example:
       } 
 
 %#sleep/wait until dropdowns are updated?
-%     for (@location_fields) { 
+%     for (@location_fields, 'city_select') { 
         what.form.<%$_%>.disabled = true;
         what.form.<%$_%>.style.backgroundColor = '#dddddd';
 %     } 
@@ -85,6 +85,7 @@ Example:
       } else {
         county_el.selectedIndex = 0;
       }
+      county_changed(county_el);
     }
     return fix_county;
   }
diff --git a/httemplate/misc/cities.cgi b/httemplate/misc/cities.cgi
new file mode 100644 (file)
index 0000000..c92485e
--- /dev/null
@@ -0,0 +1,7 @@
+[ <% join(', ', map { qq("$_") } @cities) %> ]
+<%init>
+
+my( $county, $state, $country ) = $cgi->param('arg');
+my @cities = cities($county, $state, $country);
+
+</%init>