[Rt-commit] rt branch, 3.999-trunk, updated. 0e1481c9637a9a3c86dbd062f58b18c518c84030

jesse jesse at bestpractical.com
Thu Nov 5 21:05:14 EST 2009


The branch, 3.999-trunk has been updated
       via  0e1481c9637a9a3c86dbd062f58b18c518c84030 (commit)
       via  3c5392a734b770de304a9aabb245b42bb471ee72 (commit)
       via  eb5083994f781813f051dc19e41c0aad194ba291 (commit)
       via  20fdc5f179a20f0adc1530f2675a216d9afbcf6a (commit)
       via  f39e4e7ae94956e2928553aa0cc36b34164b8e26 (commit)
       via  33ddbccf5e829b20cecbdd2333365c8627a0fe9b (commit)
       via  a16b6af4b3ab91a3ea42757dcc24d479b192e155 (commit)
       via  40c61ed0e4c87ccf57b78dab641c3408e1c97bc2 (commit)
       via  54dcf157b1c57a3b629df808a769ac3784cfa1b8 (commit)
       via  69ef54528958856f7f5727d9f1bf2b86e1e2d38b (commit)
       via  e75caec4ea20db7b5f229bb40c8a6f8d9a5b8f53 (commit)
       via  8c36128ee57e7e9d525a63d1e42a0a8177ec165f (commit)
       via  0ee30e6a7ea5de1d39c2787730942df03ab92c0a (commit)
       via  2df7ebc690749164e85d6b7b8be9dca3f6c0c21a (commit)
       via  306d05b930d472069e5b0b9e848976f91a8985e2 (commit)
       via  ebcaa03b0845f2dd435b97ec642504cd6e225bc1 (commit)
       via  d3229b63b34c22e0561a12606da939a5dd4f7f3e (commit)
       via  e08153afd1ace3939b1cf17b36a2c91b9b10209d (commit)
       via  8da265dd6181ffc9f22a42ee14fcf0fb6adb3df1 (commit)
       via  d85893c906619d110c6f71a2ad70144b89fb120a (commit)
       via  2fad999bd772e8e4cf7a113c7a96e8124486874a (commit)
       via  6b08e74a1c449cf301154e87bd17ce0c0157d0ca (commit)
       via  bdb999258e08f19d6c5f2b61beb47565d7dd3c47 (commit)
       via  5dec3e324f0d46891b4cc0c7a13cfc2a6a879a83 (commit)
       via  cf15d14559267c7f4f4849193a3f9dfae487f442 (commit)
       via  048c9f30b546c1856f6163808c45c5357b638e22 (commit)
       via  a76a42f2ab98429c6b4b952249210d96b11c0f2b (commit)
       via  c82f2934a4621d3cde7bb2a591739d437ce77f53 (commit)
       via  7dc91a5149e5743f6ac946bd23593184f0e24d60 (commit)
       via  b2bbf538585fbb95e27693eb7b0f3115e1b294c1 (commit)
       via  1346a0281f28db61a7cd795a4221298431a75730 (commit)
      from  89cba24be778542f3237d8c4323813f7264737eb (commit)

Summary of changes:
 lib/RT/I18N.pm                                     |    2 +-
 lib/RT/Interface/Web.pm                            |   76 ++--
 lib/RT/Interface/Web/QueryBuilder.pm               |  523 ++++++++++++++++++++
 share/html/Elements/CollectionAsTable/Header       |    2 +-
 share/html/Elements/CollectionList                 |    4 +-
 share/html/Elements/ScrubHTML                      |   77 ---
 share/html/Elements/ShowCustomFieldText            |    2 +-
 share/html/Elements/ShowCustomFieldWikitext        |    2 +-
 share/html/Elements/ShowSearch                     |    2 +-
 share/html/Prefs/Search.html                       |    3 +-
 share/html/Prefs/SearchOptions.html                |    3 +-
 share/html/Search/Build.html                       |  212 +++-----
 share/html/Search/Edit.html                        |    2 +-
 share/html/Search/Elements/BuildFormatString       |  230 ---------
 share/html/Search/Elements/DisplayOptions          |    2 +-
 share/html/Search/Elements/EditQuery               |  173 -------
 share/html/Search/Elements/EditSearches            |  154 ------
 .../Ticket/Elements/ShowTransactionAttachments     |    2 +-
 share/html/Ticket/Elements/Tabs                    |    2 +-
 share/html/Ticket/Graphs/index.html                |   14 +-
 share/html/Widgets/SavedSearch                     |    2 +-
 21 files changed, 664 insertions(+), 825 deletions(-)
 create mode 100644 lib/RT/Interface/Web/QueryBuilder.pm
 delete mode 100644 share/html/Elements/ScrubHTML
 delete mode 100644 share/html/Search/Elements/BuildFormatString

- Log -----------------------------------------------------------------
commit 1346a0281f28db61a7cd795a4221298431a75730
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 11:20:06 2009 -0500

    First round of moving Search/Build logic to lib/
    
    Conflicts:
    
    	share/html/Search/Build.html

diff --git a/lib/RT/Interface/Web/QueryBuilder.pm b/lib/RT/Interface/Web/QueryBuilder.pm
new file mode 100644
index 0000000..788a9de
--- /dev/null
+++ b/lib/RT/Interface/Web/QueryBuilder.pm
@@ -0,0 +1,175 @@
+package RT::Interface::Web::QueryBuilder;
+use warnings;
+use strict;
+
+sub process_query {
+	my $self = shift;
+	my $ARGS = shift;
+	my $tree = shift;
+	my $selected = shift;
+	my $new = shift || [];
+
+my @NewSelection = ();
+
+my @results;
+if ( $ARGS->{'up'} || $ARGS->{'down'} ) {
+    if (@$selected) {
+        foreach my $value (@$selected) {
+            my $parent = $value->getParent;
+            my $index = $value->getIndex;
+            my $newindex = $index;
+            $newindex++ if $ARGS->{'down'};
+            $newindex-- if $ARGS->{'up'};
+            if ( $newindex < 0 || $newindex >= $parent->getChildCount ) {
+                push( @results, [ _("error: can't move up"), -1 ] ) if $ARGS->{'up'};
+                push( @results, [ _("error: can't move down"), -1 ] ) if $ARGS->{'down'};
+                next;
+            }
+
+            $parent->removeChild( $index );
+            $parent->insertChild( $newindex, $value );
+        }
+    }
+    else {
+        push( @results, [ _("error: nothing to move"), -1 ] );
+    }
+}
+elsif ( $ARGS->{"left"} ) {
+    if (@$selected) {
+        foreach my $value (@$selected) {
+            my $parent = $value->getParent;
+            if( $value->isRoot || $parent->isRoot ) {
+                push( @results, [ _("error: can't move left"), -1 ] );
+                next;
+            }
+
+            my $grandparent = $parent->getParent;
+            if( $grandparent->isRoot ) {
+                push( @results, [ _("error: can't move left"), -1 ] );
+                next;
+            }
+            
+            my $index = $parent->getIndex;
+            $parent->removeChild($value);
+            $grandparent->insertChild( $index, $value );
+            if ( $parent->isLeaf ) {
+                $grandparent->removeChild($parent);
+            }
+        }
+    }
+    else {
+        push( @results, [ _("error: nothing to move"), -1 ] );
+    }
+}
+elsif ( $ARGS->{"right"} ) {
+    if (@$selected) {
+        foreach my $value (@$selected) {
+            my $parent = $value->getParent;
+            my $index  = $value->getIndex;
+
+            my $newparent;
+            if ( $index > 0 ) {
+                my $sibling = $parent->getChild( $index - 1 );
+                $newparent = $sibling unless $sibling->isLeaf;
+            }
+            $newparent ||= RT::Interface::Web::QueryBuilder::Tree->new( $ARGS->{'and_or'} || 'AND', $parent );
+
+            $parent->removeChild($value);
+            $newparent->addChild($value);
+        }
+    }
+    else {
+        push( @results, [ _("error: nothing to move"), -1 ] );
+    }
+}
+elsif ( $ARGS->{"delete_clause"} ) {
+    if (@$selected) {
+        my (@top);
+        my %Selected = map { $_ => 1 } @$selected;
+        foreach my $node ( @$selected ) {
+            my $tmp = $node->getParent;
+            while ( !$Selected{ $tmp } && !$tmp->isRoot ) {
+                $tmp = $tmp->getParent;
+            }
+            next if $Selected{ $tmp };
+            push @top, $node;
+        }
+
+        my %seen;
+        my @non_siblings_top = grep !$seen{ $_->getParent }++, @top;
+
+        foreach ( @$new ) {
+            my $add = $_->clone;
+            foreach my $sel( @non_siblings_top ) {
+                my $newindex = $sel->getIndex + 1;
+                $sel->insertSibling( $newindex, $add );
+            }
+            $add->getParent->setNodeValue( $ARGS->{'and_or'} );
+            push @NewSelection, $add;
+        }
+        @$new = ();
+    
+        while( my $node = shift @top ) {
+            my $parent = $node->getParent;
+            $parent->removeChild($node);
+            $node->DESTROY;
+        }
+        @$selected = ();
+    }
+    else {
+        push( @results, [ _("error: nothing to delete"), -1 ] );
+    }
+}
+elsif ( $ARGS->{"toggle"} ) {
+    if (@$selected) {
+        my %seen;
+        my @unique_nodes = grep !$seen{ $_ + 0 }++,
+            map ref $_->getNodeValue? $_->getParent: $_,
+            @$selected;
+
+        foreach my $node ( @unique_nodes ) {
+            if ( $node->getNodeValue eq 'AND' ) {
+                $node->setNodeValue('OR');
+            }
+            else {
+                $node->setNodeValue('AND');
+            }
+        }
+    }
+    else {
+        push( @results, [ _("error: nothing to toggle"), -1 ] );
+    }
+}
+
+if ( @$new && @$selected ) {
+    my %seen;
+    my @non_siblings_selected = grep !$seen{ $_->getParent }++, @$selected;
+
+    foreach ( @$new ) {
+        my $add = $_->clone;
+        foreach my $sel( @non_siblings_selected ) {
+            my $newindex = $sel->getIndex + 1;
+            $sel->insertSibling( $newindex, $add );
+        }
+        $add->getParent->setNodeValue( $ARGS->{'and_or'} );
+        push @NewSelection, $add;
+    }
+    @$selected = ();
+}
+elsif ( @$new ) {
+    foreach ( @$new ) {
+        my $add = $_->clone;
+        $tree->addChild( $add );
+        push @NewSelection, $add;
+    }
+    $tree->setNodeValue( $ARGS->{'and_or'} );
+}
+$_->DESTROY foreach @$new;
+
+push @$selected, @NewSelection;
+
+$tree->prune_childless_aggregators;
+
+return @results;
+}
+1;
diff --git a/share/html/Search/Build.html b/share/html/Search/Build.html
index fa10b35..915d5b5 100644
--- a/share/html/Search/Build.html
+++ b/share/html/Search/Build.html
@@ -225,7 +225,7 @@ foreach my $arg ( keys %ARGS ) {
                 $op = "IS NOT";
             }
 
-            # This isn't "right", but...
+            # This is not "right", but...
             # It has to be this way until #5182 is fixed
             $value = "'NULL'";
         }
@@ -245,12 +245,12 @@ foreach my $arg ( keys %ARGS ) {
 }
 
 # }}}
-
-push @actions, $m->comp('Elements/EditQuery:Process',
-    %ARGS,
-    tree     => $tree,
-    selected => \@current_values,
-    new      => \@new_values,
+use RT::Interface::Web::QueryBuilder;
+push @actions, RT::Interface::Web::QueryBuilder->process_query(
+    \%ARGS,
+    $tree,
+    \@current_values,
+    \@new_values,
 );
 
 # {{{ Rebuild $Query based on the additions / movements
@@ -307,7 +307,7 @@ if ($new_query) {
     $query_string = 'new_query=1';
 }
 elsif ( $query{'query'} ) {
-    $query_string = $m->comp('/Elements/QueryString', %query );
+$query_string = URI->new->query_form( %query );
 }
 
 # }}}
diff --git a/share/html/Search/Elements/EditQuery b/share/html/Search/Elements/EditQuery
index c3f0d12..19f9cc8 100644
--- a/share/html/Search/Elements/EditQuery
+++ b/share/html/Search/Elements/EditQuery
@@ -68,176 +68,3 @@ $description => undef
 $optionlist => ''
 $actions => []
 </%ARGS>
-
-<%METHOD Process>
-<%ARGS>
-$tree
-$selected
- at new       => ()
-</%ARGS>
-<%INIT>
-
-my @NewSelection = ();
-
-my @results;
-if ( $ARGS{'up'} || $ARGS{'down'} ) {
-    if (@$selected) {
-        foreach my $value (@$selected) {
-            my $parent = $value->getParent;
-            my $index = $value->getIndex;
-            my $newindex = $index;
-            $newindex++ if $ARGS{'down'};
-            $newindex-- if $ARGS{'up'};
-            if ( $newindex < 0 || $newindex >= $parent->getChildCount ) {
-                push( @results, [ _("error: can't move up"), -1 ] ) if $ARGS{'up'};
-                push( @results, [ _("error: can't move down"), -1 ] ) if $ARGS{'down'};
-                next;
-            }
-
-            $parent->removeChild( $index );
-            $parent->insertChild( $newindex, $value );
-        }
-    }
-    else {
-        push( @results, [ _("error: nothing to move"), -1 ] );
-    }
-}
-elsif ( $ARGS{"left"} ) {
-    if (@$selected) {
-        foreach my $value (@$selected) {
-            my $parent = $value->getParent;
-            if( $value->isRoot || $parent->isRoot ) {
-                push( @results, [ _("error: can't move left"), -1 ] );
-                next;
-            }
-
-            my $grandparent = $parent->getParent;
-            if( $grandparent->isRoot ) {
-                push( @results, [ _("error: can't move left"), -1 ] );
-                next;
-            }
-            
-            my $index = $parent->getIndex;
-            $parent->removeChild($value);
-            $grandparent->insertChild( $index, $value );
-            if ( $parent->isLeaf ) {
-                $grandparent->removeChild($parent);
-            }
-        }
-    }
-    else {
-        push( @results, [ _("error: nothing to move"), -1 ] );
-    }
-}
-elsif ( $ARGS{"right"} ) {
-    if (@$selected) {
-        foreach my $value (@$selected) {
-            my $parent = $value->getParent;
-            my $index  = $value->getIndex;
-
-            my $newparent;
-            if ( $index > 0 ) {
-                my $sibling = $parent->getChild( $index - 1 );
-                $newparent = $sibling unless $sibling->isLeaf;
-            }
-            $newparent ||= RT::Interface::Web::QueryBuilder::Tree->new( $ARGS{'and_or'} || 'AND', $parent );
-
-            $parent->removeChild($value);
-            $newparent->addChild($value);
-        }
-    }
-    else {
-        push( @results, [ _("error: nothing to move"), -1 ] );
-    }
-}
-elsif ( $ARGS{"delete_clause"} ) {
-    if (@$selected) {
-        my (@top);
-        my %Selected = map { $_ => 1 } @$selected;
-        foreach my $node ( @$selected ) {
-            my $tmp = $node->getParent;
-            while ( !$Selected{ $tmp } && !$tmp->isRoot ) {
-                $tmp = $tmp->getParent;
-            }
-            next if $Selected{ $tmp };
-            push @top, $node;
-        }
-
-        my %seen;
-        my @non_siblings_top = grep !$seen{ $_->getParent }++, @top;
-
-        foreach ( @new ) {
-            my $add = $_->clone;
-            foreach my $sel( @non_siblings_top ) {
-                my $newindex = $sel->getIndex + 1;
-                $sel->insertSibling( $newindex, $add );
-            }
-            $add->getParent->setNodeValue( $ARGS{'and_or'} );
-            push @NewSelection, $add;
-        }
-        @new = ();
-    
-        while( my $node = shift @top ) {
-            my $parent = $node->getParent;
-            $parent->removeChild($node);
-            $node->DESTROY;
-        }
-        @$selected = ();
-    }
-    else {
-        push( @results, [ _("error: nothing to delete"), -1 ] );
-    }
-}
-elsif ( $ARGS{"toggle"} ) {
-    if (@$selected) {
-        my %seen;
-        my @unique_nodes = grep !$seen{ $_ + 0 }++,
-            map ref $_->getNodeValue? $_->getParent: $_,
-            @$selected;
-
-        foreach my $node ( @unique_nodes ) {
-            if ( $node->getNodeValue eq 'AND' ) {
-                $node->setNodeValue('OR');
-            }
-            else {
-                $node->setNodeValue('AND');
-            }
-        }
-    }
-    else {
-        push( @results, [ _("error: nothing to toggle"), -1 ] );
-    }
-}
-
-if ( @new && @$selected ) {
-    my %seen;
-    my @non_siblings_selected = grep !$seen{ $_->getParent }++, @$selected;
-
-    foreach ( @new ) {
-        my $add = $_->clone;
-        foreach my $sel( @non_siblings_selected ) {
-            my $newindex = $sel->getIndex + 1;
-            $sel->insertSibling( $newindex, $add );
-        }
-        $add->getParent->setNodeValue( $ARGS{'and_or'} );
-        push @NewSelection, $add;
-    }
-    @$selected = ();
-}
-elsif ( @new ) {
-    foreach ( @new ) {
-        my $add = $_->clone;
-        $tree->addChild( $add );
-        push @NewSelection, $add;
-    }
-    $tree->setNodeValue( $ARGS{'and_or'} );
-}
-$_->DESTROY foreach @new;
-
-push @$selected, @NewSelection;
-
-$tree->prune_childless_aggregators;
-
-return @results;
-</%INIT>
-</%METHOD>

commit b2bbf538585fbb95e27693eb7b0f3115e1b294c1
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 14:28:39 2009 -0500

    tiny change to how we use base in RT/I18N.pm

diff --git a/lib/RT/I18N.pm b/lib/RT/I18N.pm
index f4c45df..a8d1b11 100755
--- a/lib/RT/I18N.pm
+++ b/lib/RT/I18N.pm
@@ -59,7 +59,7 @@ use warnings;
 
 use Locale::Maketext 1.04;
 use Locale::Maketext::Lexicon 0.25;
-use base ('Locale::Maketext::Fuzzy');
+use base 'Locale::Maketext::Fuzzy';
 
 use Encode;
 use MIME::Entity;

commit 7dc91a5149e5743f6ac946bd23593184f0e24d60
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 14:29:47 2009 -0500

    Added a new format_query_params method to RT::Interface::Web to replace /Elements/QueryString

diff --git a/lib/RT/Interface/Web.pm b/lib/RT/Interface/Web.pm
index c948e83..a3a8119 100755
--- a/lib/RT/Interface/Web.pm
+++ b/lib/RT/Interface/Web.pm
@@ -64,6 +64,8 @@ package RT::Interface::Web;
 use RT::Report::Tickets;
 use RT::System;
 use RT::SavedSearches;
+use RT::Interface::Web::QueryBuilder;
+
 use URI qw();
 use Digest::MD5 ();
 use Encode qw();
@@ -289,6 +291,18 @@ sub strip_content {
     return $content;
 }
 
+
+
+sub format_query_params {
+	my $self = shift;
+	my %params = @_;
+
+	my $uri = URI->new;
+	$uri->query_form(%params);
+	return $uri->query;
+}
+
+
 package HTML::Mason::Commands;
 
 use vars qw/$r $m/;
@@ -1493,4 +1507,5 @@ sub _detailed_messages {
 }
 
 
+
 1;

commit c82f2934a4621d3cde7bb2a591739d437ce77f53
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 14:30:36 2009 -0500

    extract saved search related display logic from mason components into a library.

diff --git a/lib/RT/Interface/Web/QueryBuilder.pm b/lib/RT/Interface/Web/QueryBuilder.pm
index 788a9de..a699d67 100644
--- a/lib/RT/Interface/Web/QueryBuilder.pm
+++ b/lib/RT/Interface/Web/QueryBuilder.pm
@@ -3,173 +3,314 @@ use warnings;
 use strict;
 
 sub process_query {
-	my $self = shift;
-	my $ARGS = shift;
-	my $tree = shift;
-	my $selected = shift;
-	my $new = shift || [];
-
-my @NewSelection = ();
-
-my @results;
-if ( $ARGS->{'up'} || $ARGS->{'down'} ) {
-    if (@$selected) {
-        foreach my $value (@$selected) {
-            my $parent = $value->getParent;
-            my $index = $value->getIndex;
-            my $newindex = $index;
-            $newindex++ if $ARGS->{'down'};
-            $newindex-- if $ARGS->{'up'};
-            if ( $newindex < 0 || $newindex >= $parent->getChildCount ) {
-                push( @results, [ _("error: can't move up"), -1 ] ) if $ARGS->{'up'};
-                push( @results, [ _("error: can't move down"), -1 ] ) if $ARGS->{'down'};
-                next;
-            }
+    my $self     = shift;
+    my $ARGS     = shift;
+    my $tree     = shift;
+    my $selected = shift;
+    my $new      = shift || [];
 
-            $parent->removeChild( $index );
-            $parent->insertChild( $newindex, $value );
-        }
-    }
-    else {
-        push( @results, [ _("error: nothing to move"), -1 ] );
-    }
-}
-elsif ( $ARGS->{"left"} ) {
-    if (@$selected) {
-        foreach my $value (@$selected) {
-            my $parent = $value->getParent;
-            if( $value->isRoot || $parent->isRoot ) {
-                push( @results, [ _("error: can't move left"), -1 ] );
-                next;
+    my @NewSelection = ();
+
+    my @results;
+    if ( $ARGS->{'up'} || $ARGS->{'down'} ) {
+        if (@$selected) {
+            foreach my $value (@$selected) {
+                my $parent   = $value->getParent;
+                my $index    = $value->getIndex;
+                my $newindex = $index;
+                $newindex++ if $ARGS->{'down'};
+                $newindex-- if $ARGS->{'up'};
+                if ( $newindex < 0 || $newindex >= $parent->getChildCount ) {
+                    push( @results, [ _("error: can't move up"),   -1 ] ) if $ARGS->{'up'};
+                    push( @results, [ _("error: can't move down"), -1 ] ) if $ARGS->{'down'};
+                    next;
+                }
+
+                $parent->removeChild($index);
+                $parent->insertChild( $newindex, $value );
             }
+        } else {
+            push( @results, [ _("error: nothing to move"), -1 ] );
+        }
+    } elsif ( $ARGS->{"left"} ) {
+        if (@$selected) {
+            foreach my $value (@$selected) {
+                my $parent = $value->getParent;
+                if ( $value->isRoot || $parent->isRoot ) {
+                    push( @results, [ _("error: can't move left"), -1 ] );
+                    next;
+                }
+
+                my $grandparent = $parent->getParent;
+                if ( $grandparent->isRoot ) {
+                    push( @results, [ _("error: can't move left"), -1 ] );
+                    next;
+                }
 
-            my $grandparent = $parent->getParent;
-            if( $grandparent->isRoot ) {
-                push( @results, [ _("error: can't move left"), -1 ] );
-                next;
+                my $index = $parent->getIndex;
+                $parent->removeChild($value);
+                $grandparent->insertChild( $index, $value );
+                if ( $parent->isLeaf ) {
+                    $grandparent->removeChild($parent);
+                }
             }
-            
-            my $index = $parent->getIndex;
-            $parent->removeChild($value);
-            $grandparent->insertChild( $index, $value );
-            if ( $parent->isLeaf ) {
-                $grandparent->removeChild($parent);
+        } else {
+            push( @results, [ _("error: nothing to move"), -1 ] );
+        }
+    } elsif ( $ARGS->{"right"} ) {
+        if (@$selected) {
+            foreach my $value (@$selected) {
+                my $parent = $value->getParent;
+                my $index  = $value->getIndex;
+
+                my $newparent;
+                if ( $index > 0 ) {
+                    my $sibling = $parent->getChild( $index - 1 );
+                    $newparent = $sibling unless $sibling->isLeaf;
+                }
+                $newparent ||= RT::Interface::Web::QueryBuilder::Tree->new( $ARGS->{'and_or'} || 'AND', $parent );
+
+                $parent->removeChild($value);
+                $newparent->addChild($value);
             }
+        } else {
+            push( @results, [ _("error: nothing to move"), -1 ] );
         }
-    }
-    else {
-        push( @results, [ _("error: nothing to move"), -1 ] );
-    }
-}
-elsif ( $ARGS->{"right"} ) {
-    if (@$selected) {
-        foreach my $value (@$selected) {
-            my $parent = $value->getParent;
-            my $index  = $value->getIndex;
-
-            my $newparent;
-            if ( $index > 0 ) {
-                my $sibling = $parent->getChild( $index - 1 );
-                $newparent = $sibling unless $sibling->isLeaf;
+    } elsif ( $ARGS->{"delete_clause"} ) {
+        if (@$selected) {
+            my (@top);
+            my %Selected = map { $_ => 1 } @$selected;
+            foreach my $node (@$selected) {
+                my $tmp = $node->getParent;
+                while ( !$Selected{$tmp} && !$tmp->isRoot ) {
+                    $tmp = $tmp->getParent;
+                }
+                next if $Selected{$tmp};
+                push @top, $node;
+            }
+
+            my %seen;
+            my @non_siblings_top = grep !$seen{ $_->getParent }++, @top;
+
+            foreach (@$new) {
+                my $add = $_->clone;
+                foreach my $sel (@non_siblings_top) {
+                    my $newindex = $sel->getIndex + 1;
+                    $sel->insertSibling( $newindex, $add );
+                }
+                $add->getParent->setNodeValue( $ARGS->{'and_or'} );
+                push @NewSelection, $add;
             }
-            $newparent ||= RT::Interface::Web::QueryBuilder::Tree->new( $ARGS->{'and_or'} || 'AND', $parent );
+            @$new = ();
 
-            $parent->removeChild($value);
-            $newparent->addChild($value);
+            while ( my $node = shift @top ) {
+                my $parent = $node->getParent;
+                $parent->removeChild($node);
+                $node->DESTROY;
+            }
+            @$selected = ();
+        } else {
+            push( @results, [ _("error: nothing to delete"), -1 ] );
         }
-    }
-    else {
-        push( @results, [ _("error: nothing to move"), -1 ] );
-    }
-}
-elsif ( $ARGS->{"delete_clause"} ) {
-    if (@$selected) {
-        my (@top);
-        my %Selected = map { $_ => 1 } @$selected;
-        foreach my $node ( @$selected ) {
-            my $tmp = $node->getParent;
-            while ( !$Selected{ $tmp } && !$tmp->isRoot ) {
-                $tmp = $tmp->getParent;
+    } elsif ( $ARGS->{"toggle"} ) {
+        if (@$selected) {
+            my %seen;
+            my @unique_nodes = grep !$seen{ $_ + 0 }++, map ref $_->getNodeValue ? $_->getParent : $_, @$selected;
+
+            foreach my $node (@unique_nodes) {
+                if ( $node->getNodeValue eq 'AND' ) {
+                    $node->setNodeValue('OR');
+                } else {
+                    $node->setNodeValue('AND');
+                }
             }
-            next if $Selected{ $tmp };
-            push @top, $node;
+        } else {
+            push( @results, [ _("error: nothing to toggle"), -1 ] );
         }
+    }
 
+    if ( @$new && @$selected ) {
         my %seen;
-        my @non_siblings_top = grep !$seen{ $_->getParent }++, @top;
+        my @non_siblings_selected = grep !$seen{ $_->getParent }++, @$selected;
 
-        foreach ( @$new ) {
+        foreach (@$new) {
             my $add = $_->clone;
-            foreach my $sel( @non_siblings_top ) {
+            foreach my $sel (@non_siblings_selected) {
                 my $newindex = $sel->getIndex + 1;
                 $sel->insertSibling( $newindex, $add );
             }
             $add->getParent->setNodeValue( $ARGS->{'and_or'} );
             push @NewSelection, $add;
         }
-        @$new = ();
-    
-        while( my $node = shift @top ) {
-            my $parent = $node->getParent;
-            $parent->removeChild($node);
-            $node->DESTROY;
-        }
         @$selected = ();
+    } elsif (@$new) {
+        foreach (@$new) {
+            my $add = $_->clone;
+            $tree->addChild($add);
+            push @NewSelection, $add;
+        }
+        $tree->setNodeValue( $ARGS->{'and_or'} );
     }
-    else {
-        push( @results, [ _("error: nothing to delete"), -1 ] );
-    }
+    $_->DESTROY foreach @$new;
+
+    push @$selected, @NewSelection;
+
+    $tree->prune_childless_aggregators;
+
+    return @results;
 }
-elsif ( $ARGS->{"toggle"} ) {
-    if (@$selected) {
-        my %seen;
-        my @unique_nodes = grep !$seen{ $_ + 0 }++,
-            map ref $_->getNodeValue? $_->getParent: $_,
-            @$selected;
 
-        foreach my $node ( @unique_nodes ) {
-            if ( $node->getNodeValue eq 'AND' ) {
-                $node->setNodeValue('OR');
-            }
-            else {
-                $node->setNodeValue('AND');
-            }
-        }
-    }
-    else {
-        push( @results, [ _("error: nothing to toggle"), -1 ] );
+
+sub load_saved_search {
+    my $self          = shift;
+    my $ARGS          = shift;
+    my $query         = shift;
+    my $saved_search  = shift;
+    my $search_fields = shift || [qw( query format order_by order rows_per_page)];
+
+    $saved_search->{'id'}          = $ARGS->{'saved_search_id'}          || 'new';
+    $saved_search->{'description'} = $ARGS->{'saved_search_description'} || undef;
+    $saved_search->{'Privacy'}     = $ARGS->{'saved_search_owner'}       || undef;
+
+    my @results;
+
+    if ( $ARGS->{'saved_search_revert'} ) {
+        $ARGS->{'saved_search_load'} = $saved_search->{'id'};
     }
-}
 
-if ( @$new && @$selected ) {
-    my %seen;
-    my @non_siblings_selected = grep !$seen{ $_->getParent }++, @$selected;
+    if ( $ARGS->{'saved_search_load'} ) {
+        my ( $container, $id ) = _parse_saved_search( $ARGS->{'saved_search_load'} );
+        my $search = $container->attributes->with_id($id);
+
+        $saved_search->{'id'}          = $ARGS->{'saved_search_load'};
+        $saved_search->{'object'}      = $search;
+        $saved_search->{'description'} = $search->description;
+        $query->{$_} = $search->sub_value($_) foreach @$search_fields;
+
+        if ( $ARGS->{'saved_search_revert'} ) {
+            push @results, _( 'Loaded original "%1" saved search', $saved_search->{'description'} );
+        } else {
+            push @results, _( 'Loaded saved search "%1"', $saved_search->{'description'} );
+        }
+    } elsif ( $ARGS->{'saved_search_delete'} ) {
+
+        # We set $SearchId to 'new' above already, so peek into the %ARGS
+        my ( $container, $id ) = _parse_saved_search( $saved_search->{'id'} );
+        if ( $container && $container->id ) {
 
-    foreach ( @$new ) {
-        my $add = $_->clone;
-        foreach my $sel( @non_siblings_selected ) {
-            my $newindex = $sel->getIndex + 1;
-            $sel->insertSibling( $newindex, $add );
+            # We have the object the entry is an attribute on; delete the entry...
+            $container->attributes->delete_entry( name => 'saved_search', id => $id );
+        }
+        $saved_search->{'id'}          = 'new';
+        $saved_search->{'object'}      = undef;
+        $saved_search->{'description'} = undef;
+        push @results, _("Deleted saved search");
+    } elsif ( $ARGS->{'saved_search_copy'} ) {
+        my ( $container, $id ) = _parse_saved_search( $ARGS->{'saved_search_id'} );
+        $saved_search->{'object'} = $container->attributes->withid($id);
+        if (   $ARGS->{'saved_search_description'}
+            && $ARGS->{'saved_search_description'} ne $saved_search->{'object'}->description )
+        {
+            $saved_search->{'description'} = $ARGS->{'saved_search_description'};
+        } else {
+            $saved_search->{'description'} = _( "%1 copy", $saved_search->{'object'}->description );
         }
-        $add->getParent->setNodeValue( $ARGS->{'and_or'} );
-        push @NewSelection, $add;
+        $saved_search->{'id'}     = 'new';
+        $saved_search->{'object'} = undef;
     }
-    @$selected = ();
-}
-elsif ( @$new ) {
-    foreach ( @$new ) {
-        my $add = $_->clone;
-        $tree->addChild( $add );
-        push @NewSelection, $add;
+
+    if (   $saved_search->{'id'}
+        && $saved_search->{'id'} ne 'new'
+        && !$saved_search->{'object'} )
+    {
+        my ( $container, $id ) = _parse_saved_search( $ARGS->{'saved_search_id'} );
+        $saved_search->{'object'} = $container->attributes->with_id($id);
+        $saved_search->{'description'} ||= $saved_search->{'object'}->description;
     }
-    $tree->setNodeValue( $ARGS->{'and_or'} );
+
+    return @results;
 }
-$_->DESTROY foreach @$new;
 
-push @$selected, @NewSelection;
 
-$tree->prune_childless_aggregators;
+sub save_search {
+    my $self          = shift;
+    my $ARGS          = shift;
+    my $query         = shift;
+    my $saved_search  = shift;
+    my $search_fields = shift || [qw( query format order_by order rows_per_page)];
+
+    return unless $ARGS->{'saved_search_save'} || $ARGS->{'saved_search_copy'};
+
+    my @results;
+    my $obj  = $saved_search->{'object'};
+    my $id   = $saved_search->{'id'};
+    my $desc = $saved_search->{'description'};
+
+    my $privacy = $saved_search->{'Privacy'};
+
+    my %params = map { $_ => $query->{$_} } @$search_fields;
+    my ( $new_obj_type, $new_obj_id ) = split( /\-/, ( $privacy || '' ) );
 
-return @results;
+    if ( $obj && $obj->id ) {
+
+        # permission check
+        if ( $obj->object->isa('RT::System') ) {
+            unless ( Jifty->web->current_user->has_right( object => RT->system, right => 'SuperUser' ) ) {
+                push @results, _("No permission to save system-wide searches");
+                return @results;
+            }
+        }
+
+        $obj->set_sub_values(%params);
+        $obj->set_description($desc);
+
+        my $obj_type = ref( $obj->object );
+
+        # We need to get current obj_id now, because when we change obj_type to
+        # RT::System, $obj->object->id returns 1, not the old one :(
+        my $obj_id = $obj->object->id;
+
+        if ( $new_obj_type && $new_obj_id ) {
+            my ( $val, $msg );
+            if ( $new_obj_type ne $obj_type ) {
+                ( $val, $msg ) = $obj->set_objectType($new_obj_type);
+                push @results, _( 'Unable to set privacy object: %1', $msg ) unless ($val);
+            }
+            if ( $new_obj_id != $obj_id ) {
+                ( $val, $msg ) = $obj->set_objectid($new_obj_id);
+                push @results, _( 'Unable to set privacy id: %1', $msg ) unless ($val);
+            }
+        } else {
+            push @results, _('Unable to determine object type or id');
+        }
+        push @results, _( 'Updated saved search "%1"', $desc );
+    } elsif ( $id eq 'new' ) {
+        my $saved_search = RT::SavedSearch->new();
+        my ( $status, $msg ) = $saved_search->save(
+            privacy       => $privacy,
+            name          => $desc,
+            type          => $saved_search->{'type'},
+            search_params => \%params,
+        );
+
+        if ($status) {
+            $saved_search->{'object'} = Jifty->web->current_user->user_object->attributes->with_id( $saved_search->id );
+
+            # Build new SearchId
+            $saved_search->{'id'}
+                = ref( Jifty->web->current_user->user_object ) . '-'
+                . Jifty->web->current_user->user_object->id
+                . '-SavedSearch-'
+                . $saved_search->{'object'}->id;
+        } else {
+            push @results, _("Can't find a saved search to work with") . ': ' . _($msg);
+        }
+    } else {
+        push @results, _("Can't save this search");
+    }
+
+    return @results;
 }
+
+
 1;
diff --git a/share/html/Search/Build.html b/share/html/Search/Build.html
index 915d5b5..93b69ed 100644
--- a/share/html/Search/Build.html
+++ b/share/html/Search/Build.html
@@ -125,7 +125,7 @@ for( qw(query format order_by order rows_per_page) ) {
 }
 
 my %saved_search;
-my @actions = $m->comp( 'Elements/EditSearches:Init', %ARGS, query => \%query, saved_search => \%saved_search);
+my @actions = RT::Interface::Web::QueryBuilder->load_saved_search(\%ARGS, \%query, \%saved_search);
 
 if ( $new_query ) {
 
@@ -278,7 +278,8 @@ my ( $AvailableColumns, $current_format );
 # }}}
 
 # if we're asked to save the current search, save it
-push @actions, $m->comp( 'Elements/EditSearches:Save', %ARGS, query => \%query, saved_search => \%saved_search);
+push @actions, RT::Interface::Web::QueryBuilder->save_search(\%ARGS, \%query, \%saved_search);
+
 
 # {{{ Push the updates into the session so we don't loose 'em
 
@@ -307,7 +308,7 @@ if ($new_query) {
     $query_string = 'new_query=1';
 }
 elsif ( $query{'query'} ) {
-$query_string = URI->new->query_form( %query );
+$query_string = RT::Interface::Web->format_query_params( %query );
 }
 
 # }}}
diff --git a/share/html/Search/Elements/EditSearches b/share/html/Search/Elements/EditSearches
index fa0be1a..5bed321 100644
--- a/share/html/Search/Elements/EditSearches
+++ b/share/html/Search/Elements/EditSearches
@@ -135,157 +135,3 @@ $allow_copy     => 1
 $title         => _('Saved searches')
 </%ARGS>
 
-<%METHOD Init>
-<%ARGS>
-$query       => {}
-$saved_search => {}
- at search_fields => qw(Query format order_by order rows_per_page)
-</%ARGS>
-<%INIT>
-
-
-$saved_search->{'id'}          = $ARGS{'saved_search_id'}          || 'new';
-$saved_search->{'description'} = $ARGS{'saved_search_description'} || undef;
-$saved_search->{'Privacy'}     = $ARGS{'saved_search_owner'}       || undef;
-
-my @results;
-
-if ( $ARGS{'saved_search_revert'} ) {
-    $ARGS{'saved_search_load'} = $saved_search->{'id'};
-}
-
-if ( $ARGS{'saved_search_load'} ) {
-    my ($container, $id ) = _parse_saved_search ($ARGS{'saved_search_load'});
-    my $search = $container->attributes->with_id( $id );
-
-    $saved_search->{'id'}          = $ARGS{'saved_search_load'};
-    $saved_search->{'object'}      = $search;
-    $saved_search->{'description'} = $search->description;
-    $query->{$_} = $search->sub_value($_) foreach @search_fields;
-
-    if ( $ARGS{'saved_search_revert'} ) {
-        push @results, _('Loaded original "%1" saved search', $saved_search->{'description'} );
-    } else {
-        push @results, _('Loaded saved search "%1"', $saved_search->{'description'} );
-    }
-}
-elsif ( $ARGS{'saved_search_delete'} ) {
-    # We set $SearchId to 'new' above already, so peek into the %ARGS
-    my ($container, $id) = _parse_saved_search( $saved_search->{'id'} );
-    if ( $container && $container->id ) {
-        # We have the object the entry is an attribute on; delete the entry...
-        $container->attributes->delete_entry( name => 'saved_search', id => $id );
-    }
-    $saved_search->{'id'}          = 'new';
-    $saved_search->{'object'}      = undef;
-    $saved_search->{'description'} = undef;
-    push @results, _("Deleted saved search");
-}
-elsif ( $ARGS{'saved_search_copy'} ) {
-    my ($container, $id ) = _parse_saved_search( $ARGS{'saved_search_id'} );
-    $saved_search->{'object'} = $container->attributes->withid( $id );
-    if ( $ARGS{'saved_search_description'} && $ARGS{'saved_search_description'} ne $saved_search->{'object'}->description ) {
-        $saved_search->{'description'} = $ARGS{'saved_search_description'};
-    } else {
-        $saved_search->{'description'} = _( "%1 copy", $saved_search->{'object'}->description );
-    }
-    $saved_search->{'id'}          = 'new';
-    $saved_search->{'object'}      = undef;
-}
-
-if ( $saved_search->{'id'} && $saved_search->{'id'} ne 'new'
-     && !$saved_search->{'object'} )
-{
-    my ($container, $id ) = _parse_saved_search( $ARGS{'saved_search_id'} );
-    $saved_search->{'object'} = $container->attributes->with_id( $id );
-    $saved_search->{'description'} ||= $saved_search->{'object'}->description;
-}
-
-return @results;
-
-</%INIT>
-</%METHOD>
-
-<%METHOD Save>
-<%ARGS>
-$query        => {}
-$saved_search  => {}
- at search_fields => qw(query format order_by order rows_per_page)
-</%ARGS>
-<%INIT>
-
-return unless $ARGS{'saved_search_save'} || $ARGS{'saved_search_copy'};
-
-my @results;
-my $obj  = $saved_search->{'object'};
-my $id   = $saved_search->{'id'};
-my $desc = $saved_search->{'description'};
-
-my $privacy = $saved_search->{'Privacy'};
-
-my %params = map { $_ => $query->{$_} } @search_fields;
-my ($new_obj_type, $new_obj_id) = split(/\-/, ($privacy || ''));
-
-if ( $obj && $obj->id ) {
-    # permission check
-    if ($obj->object->isa('RT::System')) {
-        unless (Jifty->web->current_user->has_right( object=> RT->system, right => 'SuperUser')) {
-            push @results, _("No permission to save system-wide searches");
-            return @results;
-        }
-    }
-
-    $obj->set_sub_values( %params );
-    $obj->set_description( $desc );
-
-    my $obj_type = ref($obj->object);
-    # We need to get current obj_id now, because when we change obj_type to
-    # RT::System, $obj->object->id returns 1, not the old one :(
-    my $obj_id = $obj->object->id;
-
-    if ( $new_obj_type && $new_obj_id ) {
-        my ($val, $msg);
-        if ( $new_obj_type ne $obj_type ) {
-            ($val, $msg ) = $obj->set_objectType($new_obj_type);
-            push @results, _('Unable to set privacy object: %1', $msg) unless ( $val );
-        }
-        if ( $new_obj_id != $obj_id ) {
-            ($val, $msg) = $obj->set_objectid($new_obj_id);
-            push @results, _('Unable to set privacy id: %1', $msg) unless ( $val );
-        }
-    } else {
-        push @results, _('Unable to determine object type or id');
-    }
-    push @results, _('Updated saved search "%1"', $desc);
-}
-elsif ( $id eq 'new' ) {
-    my $saved_search = RT::SavedSearch->new();
-    my ($status, $msg) = $saved_search->save(
-        privacy      => $privacy,
-        name         => $desc,
-        type         => $saved_search->{'type'},
-        search_params => \%params,
-    );
-
-    if ( $status ) {
-        $saved_search->{'object'} =
-            Jifty->web->current_user->user_object->attributes->with_id( $saved_search->id );
-        # Build new SearchId
-        $saved_search->{'id'} =
-                ref( Jifty->web->current_user->user_object ) . '-'
-                    . Jifty->web->current_user->user_object->id
-                    . '-SavedSearch-'
-                    . $saved_search->{'object'}->id;
-    }
-    else {
-        push @results, _("Can't find a saved search to work with").': '._($msg);
-    }
-}
-else {
-    push @results, _("Can't save this search");
-}
-
-return @results;
-
-</%INIT>
-</%METHOD>
diff --git a/share/html/Ticket/Graphs/index.html b/share/html/Ticket/Graphs/index.html
index 40ba94f..52ab0aa 100644
--- a/share/html/Ticket/Graphs/index.html
+++ b/share/html/Ticket/Graphs/index.html
@@ -84,12 +84,7 @@ foreach my $level ( 0 .. 6 ) {
     push @save_arguments, "Level-". $level ."-Properties";
 }
 my $saved_search = { type => 'Graph' };
-push @results, $m->comp( '/Search/Elements/EditSearches:Init',
-    %ARGS,
-    query        => \%ARGS,
-    saved_search  => $saved_search,
-    search_fields => \@save_arguments,
-);
+push @results, RT::Interface::Web::QueryBuilder->load_saved_search(\%ARGS, \%ARGS, $saved_search, \@save_arguments);
 
 my $id = $ARGS{'id'};
 my $ticket = load_ticket( $id );
@@ -104,12 +99,7 @@ if ( $ARGS{'show_links'} && !ref $ARGS{'show_links'} ) {
 $ARGS{'show_links'} = [ grep $_ ne $ARGS{'leading_link'}, @{ $ARGS{'show_links'} } ];
 $ARGS{'max_depth'} = 3 unless defined $ARGS{'max_depth'} && length $ARGS{'max_depth'};
 
-push @results, $m->comp( '/Search/Elements/EditSearches:Save',
-    %ARGS,
-    query        => \%ARGS,
-    saved_search  => $saved_search,
-    search_fields => \@save_arguments,
-);
+push @results, RT::Interface::Web::QueryBuilder->save_search(\%ARGS, \%ARGS, $saved_search, \@save_arguments);
 
 my $title = _( "Ticket #%1 relationships graph", $id );
 </%INIT>

commit a76a42f2ab98429c6b4b952249210d96b11c0f2b
Merge: c82f293 d70f744
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 14:34:59 2009 -0500

    Merge commit 'origin/3.999-trunk' into librarize-search-logic
    
    * commit 'origin/3.999-trunk':
      ShowLinks was made aware of autovivification of queue objects


commit 048c9f30b546c1856f6163808c45c5357b638e22
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 14:45:26 2009 -0500

    remove  {{{ }}} and tidy Build.html

diff --git a/share/html/Search/Build.html b/share/html/Search/Build.html
index 93b69ed..060801d 100644
--- a/share/html/Search/Build.html
+++ b/share/html/Search/Build.html
@@ -1,4 +1,4 @@
-%# BEGIN BPS TAGGED BLOCK {{{
+%# BEGIN BPS TAGGED BLOCK 
 %# 
 %# COPYRIGHT:
 %# 
@@ -44,7 +44,7 @@
 %# works based on those contributions, and sublicense and distribute
 %# those contributions and any derivatives thereof.
 %# 
-%# END BPS TAGGED BLOCK }}}
+%# END BPS TAGGED BLOCK
 %#
 %# Data flow here:
 %#   The page receives a Query from the previous page, and maybe arguments
@@ -120,14 +120,14 @@
 use RT::Interface::Web::QueryBuilder::Tree;
 
 my %query;
-for( qw(query format order_by order rows_per_page) ) {
+for (qw(query format order_by order rows_per_page)) {
     $query{$_} = $ARGS{$_};
 }
 
 my %saved_search;
-my @actions = RT::Interface::Web::QueryBuilder->load_saved_search(\%ARGS, \%query, \%saved_search);
+my @actions = RT::Interface::Web::QueryBuilder->load_saved_search( \%ARGS, \%query, \%saved_search );
 
-if ( $new_query ) {
+if ($new_query) {
 
     # Wipe all data-carrying variables clear if we want a new
     # search, or we're deleting an old one..
@@ -141,31 +141,32 @@ if ( $new_query ) {
     Jifty->web->session->get('tickets')->clean_slate if defined Jifty->web->session->get('tickets');
 }
 
-{ # Attempt to load what we can from the session and preferences, set defaults
+{    # Attempt to load what we can from the session and preferences, set defaults
 
     my $current = Jifty->web->session->get('CurrentSearchHash');
-    my $prefs = Jifty->web->current_user->user_object->preferences("SearchDisplay") || {};
-    my $default = {query => '', format => '', order_by => 'id', order => 'ASC', rows_per_page => 50 };
+    my $prefs   = Jifty->web->current_user->user_object->preferences("SearchDisplay") || {};
+    my $default = { query => '', format => '', order_by => 'id', order => 'ASC', rows_per_page => 50 };
 
-    for( qw(query format order_by order rows_per_page) ) {
+    for (qw(query format order_by order rows_per_page)) {
         $query{$_} = $current->{$_} unless defined $query{$_};
-        $query{$_} = $prefs->{$_} unless defined $query{$_};
+        $query{$_} = $prefs->{$_}   unless defined $query{$_};
         $query{$_} = $default->{$_} unless defined $query{$_};
     }
 
-    for( qw(order order_by) ) {
-        if (ref $query{$_} eq "ARRAY") {
+    for (qw(order order_by)) {
+        if ( ref $query{$_} eq "ARRAY" ) {
             $query{$_} = join( '|', @{ $query{$_} } );
         }
     }
     if ( $query{'format'} ) {
+
         # Clean unwanted junk from the format
         $query{'format'} = $m->comp( '/Elements/ScrubHTML', content => $query{'format'} );
     }
 }
 
-my $parse_query = sub  {
-    my ($string, $results) = @_;
+my $parse_query = sub {
+    my ( $string, $results ) = @_;
 
     my $tree = RT::Interface::Web::QueryBuilder::Tree->new('AND');
     @$results = $tree->parse_sql( query => $string );
@@ -180,33 +181,35 @@ if ( $actions[0] ) {
     return $m->comp( "Edit.html", query => $query{'query'}, actions => \@actions );
 }
 
-my @options = $tree->get_displayed_nodes;
+my @options        = $tree->get_displayed_nodes;
 my @current_values = grep defined, @options[@clauses];
-my @new_values = ();
+my @new_values     = ();
 
-# {{{ Try to find if we're adding a clause
+#  Try to find if we're adding a clause
 foreach my $arg ( keys %ARGS ) {
-    next unless $arg =~ m/^value_of_(\w+|'CF.{.*?}')$/
-                && ( ref $ARGS{$arg} eq "ARRAY"
-                     ? grep $_ ne '', @{ $ARGS{$arg} }
-                     : $ARGS{$arg} ne '' );
+    next
+        unless $arg =~ m/^value_of_(\w+|'CF.{.*?}')$/
+            && (ref $ARGS{$arg} eq "ARRAY"
+                ? grep $_ ne '', @{ $ARGS{$arg} }
+                : $ARGS{$arg} ne ''
+            );
 
     # We're adding a $1 clause
     my $field = $1;
 
-    my ($op, $value);
+    my ( $op, $value );
 
     #figure out if it's a grouping
     my $keyword = $ARGS{ $field . "_field" } || $field;
 
     my ( @ops, @values );
     if ( ref $ARGS{ 'value_of_' . $field } eq "ARRAY" ) {
+
         # we have many keys/values to iterate over, because there is
         # more than one CF with the same name.
         @ops    = @{ $ARGS{ $field . '_op' } };
         @values = @{ $ARGS{ 'value_of_' . $field } };
-    }
-    else {
+    } else {
         @ops    = ( $ARGS{ $field . '_op' } );
         @values = ( $ARGS{ 'value_of_' . $field } );
     }
@@ -220,16 +223,14 @@ foreach my $arg ( keys %ARGS ) {
         if ( $value eq 'NULL' && $op =~ /=/ ) {
             if ( $op eq '=' ) {
                 $op = "IS";
-            }
-            elsif ( $op eq '!=' ) {
+            } elsif ( $op eq '!=' ) {
                 $op = "IS NOT";
             }
 
             # This is not "right", but...
             # It has to be this way until #5182 is fixed
             $value = "'NULL'";
-        }
-        else {
+        } else {
             $value =~ s/'/\\'/g;
             $value = "'$value'" unless $value =~ /^\d+$/;
         }
@@ -244,74 +245,61 @@ foreach my $arg ( keys %ARGS ) {
     }
 }
 
-# }}}
 use RT::Interface::Web::QueryBuilder;
-push @actions, RT::Interface::Web::QueryBuilder->process_query(
-    \%ARGS,
-    $tree,
-    \@current_values,
-    \@new_values,
-);
+push @actions, RT::Interface::Web::QueryBuilder->process_query( \%ARGS, $tree, \@current_values, \@new_values, );
 
-# {{{ Rebuild $Query based on the additions / movements
+#  Rebuild $Query based on the additions / movements
 
 my $optionlist_arrayref;
-($query{'query'}, $optionlist_arrayref) = $tree->get_query_and_option_list(\@current_values);
+( $query{'query'}, $optionlist_arrayref ) = $tree->get_query_and_option_list( \@current_values );
 
-my $optionlist = join "\n", map { qq(<option value="$_->{INDEX}" $_->{SELECTED}>) 
-                                  . ("&nbsp;" x (5 * $_->{DEPTH}))
-                                  . $m->interp->apply_escapes($_->{TEXT}, 'h') . qq(</option>) } @$optionlist_arrayref;
-
-# }}}
+my $optionlist = join "\n", map {
+          qq(<option value="$_->{INDEX}" $_->{SELECTED}>)
+        . ( "&nbsp;" x ( 5 * $_->{DEPTH} ) )
+        . $m->interp->apply_escapes( $_->{TEXT}, 'h' )
+        . qq(</option>)
+} @$optionlist_arrayref;
 
 my $queues = $tree->get_referenced_queues;
 
-# {{{ Deal with format changes
+#  Deal with format changes
 my ( $AvailableColumns, $current_format );
 ( $query{'format'}, $AvailableColumns, $current_format ) = $m->comp(
     'Elements/BuildFormatString',
     %ARGS,
     cfqueues => $queues,
-    format => $query{'format'},
+    format   => $query{'format'},
 );
 
-# }}}
-
 # if we're asked to save the current search, save it
-push @actions, RT::Interface::Web::QueryBuilder->save_search(\%ARGS, \%query, \%saved_search);
+push @actions, RT::Interface::Web::QueryBuilder->save_search( \%ARGS, \%query, \%saved_search );
 
+#  Push the updates into the session so we don't loose 'em
 
-# {{{ Push the updates into the session so we don't loose 'em
-
-Jifty->web->session->set('CurrentSearchHash', {
-    %query,
-    search_id    => $saved_search{'id'},
-    object      => $saved_search{'object'},
-    description => $saved_search{'description'},
-} );
-
-# }}}
+Jifty->web->session->set(
+    'CurrentSearchHash',
+    {   %query,
+        search_id   => $saved_search{'id'},
+        object      => $saved_search{'object'},
+        description => $saved_search{'description'},
+    }
+);
 
-# {{{ Show the results, if we were asked.
+#  Show the results, if we were asked.
 
 if ( $ARGS{'do_search'} ) {
     $m->comp( 'Results.html', %query );
     $m->abort;
 }
 
-# }}}
-
-# {{{ Build a query_string for the tabs
+#  Build a query_string for the tabs
 
 my $query_string = '';
 if ($new_query) {
     $query_string = 'new_query=1';
+} elsif ( $query{'query'} ) {
+    $query_string = RT::Interface::Web->format_query_params(%query);
 }
-elsif ( $query{'query'} ) {
-$query_string = RT::Interface::Web->format_query_params( %query );
-}
-
-# }}}
 
 </%INIT>
 

commit cf15d14559267c7f4f4849193a3f9dfae487f442
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 15:22:09 2009 -0500

    Replace Elements/ScrubHTML with a library routine

diff --git a/lib/RT/Interface/Web.pm b/lib/RT/Interface/Web.pm
index a3a8119..ea1842f 100755
--- a/lib/RT/Interface/Web.pm
+++ b/lib/RT/Interface/Web.pm
@@ -66,9 +66,12 @@ use RT::System;
 use RT::SavedSearches;
 use RT::Interface::Web::QueryBuilder;
 
+
 use URI qw();
 use Digest::MD5 ();
 use Encode qw();
+use HTML::Scrubber;
+
 
 =head2 web_canonicalize_info();
 
@@ -302,6 +305,33 @@ sub format_query_params {
 	return $uri->query;
 }
 
+my $scrubber = HTML::Scrubber->new();
+$scrubber->default(
+    0,
+    {
+        '*'    => 0,
+        id     => 1,
+        class  => 1,
+        # Match http, ftp and relative urls
+        # XXX: we also scrub format strings with this module then allow simple config options
+        href   => qr{^(?:http:|ftp:|https:|/|__Web(?:Path|baseURL|URL)__)}i,
+        face   => 1,
+        size   => 1,
+        target => 1,
+        style  => qr{^(?:(?:color:\s*rgb\(\d+,\s*\d+,\s*\d+\))|
+                         (?:text-align:\s*))}ix,
+    }
+);
+$scrubber->deny(qw[*]);
+$scrubber->allow( qw[A B U P BR I HR BR SMALL EM FONT SPAN STRONG SUB SUP STRIKE H1 H2 H3 H4 H5 H6 DIV UL OL LI DL DT DD PRE]);
+$scrubber->comment(0);
+
+sub scrub_html {
+	my $self = shift;
+	my $content = shift;
+	return $scrubber->scrub($content);
+}
+
 
 package HTML::Mason::Commands;
 
diff --git a/share/html/Elements/CollectionAsTable/Header b/share/html/Elements/CollectionAsTable/Header
index 6bd146d..283cde1 100644
--- a/share/html/Elements/CollectionAsTable/Header
+++ b/share/html/Elements/CollectionAsTable/Header
@@ -102,7 +102,7 @@ foreach my $col ( @format ) {
     );
 
     unless( $tmp ) {
-        $title = $m->comp('/Elements/ScrubHTML', content => $title);
+        $title = RT::Interface::Web->scrub_html( $title);
     } else {
         if ( UNIVERSAL::isa( $tmp, 'CODE' ) ) {
             my @tmp = $tmp->( $title );
diff --git a/share/html/Elements/CollectionList b/share/html/Elements/CollectionList
index 015a424..89329b5 100644
--- a/share/html/Elements/CollectionList
+++ b/share/html/Elements/CollectionList
@@ -84,8 +84,8 @@ $collection->set_page_info(
 $display_format ||= $format;
 
 # Scrub the html of the format string to remove any potential nasties.
-$format = $m->comp('/Elements/ScrubHTML', content => $format);
-$display_format = $m->comp('/Elements/ScrubHTML', content => $display_format);
+$format = RT::Interface::Web->scrub_html( $format);
+$display_format = RT::Interface::Web->scrub_html( $display_format);
 
 my @format = $m->comp('/Elements/CollectionAsTable/ParseFormat', format => $display_format);
 
diff --git a/share/html/Elements/ScrubHTML b/share/html/Elements/ScrubHTML
deleted file mode 100644
index 912cc80..0000000
--- a/share/html/Elements/ScrubHTML
+++ /dev/null
@@ -1,77 +0,0 @@
-%# BEGIN BPS TAGGED BLOCK {{{
-%# 
-%# COPYRIGHT:
-%# 
-%# This software is Copyright (c) 1996-2008 Best Practical Solutions, LLC
-%#                                          <jesse at bestpractical.com>
-%# 
-%# (Except where explicitly superseded by other copyright notices)
-%# 
-%# 
-%# LICENSE:
-%# 
-%# This work is made available to you under the terms of Version 2 of
-%# the GNU General Public License. A copy of that license should have
-%# been provided with this software, but in any event can be snarfed
-%# from www.gnu.org.
-%# 
-%# This work is distributed in the hope that it will be useful, but
-%# WITHOUT ANY WARRANTY; without even the implied warranty of
-%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-%# General Public License for more details.
-%# 
-%# You should have received a copy of the GNU General Public License
-%# along with this program; if not, write to the Free Software
-%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-%# 02110-1301 or visit their web page on the internet at
-%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
-%# 
-%# 
-%# CONTRIBUTION SUBMISSION POLICY:
-%# 
-%# (The following paragraph is not intended to limit the rights granted
-%# to you to modify and distribute this software under the terms of
-%# the GNU General Public License and is only of importance to you if
-%# you choose to contribute your changes and enhancements to the
-%# community by submitting them to Best Practical Solutions, LLC.)
-%# 
-%# By intentionally submitting any modifications, corrections or
-%# derivatives to this work, or any other work intended for use with
-%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
-%# you are the copyright holder for those contributions and you grant
-%# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
-%# royalty-free, perpetual, license to use, copy, create derivative
-%# works based on those contributions, and sublicense and distribute
-%# those contributions and any derivatives thereof.
-%# 
-%# END BPS TAGGED BLOCK }}}
-<%ONCE>
-my $scrubber = new HTML::Scrubber;
-$scrubber->default(
-    0,
-    {
-        '*'    => 0,
-        id     => 1,
-        class  => 1,
-        # Match http, ftp and relative urls
-        # XXX: we also scrub format strings with this module then allow simple config options
-        href   => qr{^(?:http:|ftp:|https:|/|__Web(?:Path|baseURL|URL)__)}i,
-        face   => 1,
-        size   => 1,
-        target => 1,
-        style  => qr{^(?:(?:color:\s*rgb\(\d+,\s*\d+,\s*\d+\))|
-                         (?:text-align:\s*))}ix,
-    }
-);
-$scrubber->deny(qw[*]);
-$scrubber->allow(
-    qw[A B U P BR I HR BR SMALL EM FONT SPAN STRONG SUB SUP STRIKE H1 H2 H3 H4 H5 H6 DIV UL OL LI DL DT DD PRE]
-);
-$scrubber->comment(0);
-</%ONCE>
-<%init>
-return $scrubber->scrub($content);
-</%init>
-<%args>
-$content => undef
-</%args>
diff --git a/share/html/Elements/ShowCustomFieldText b/share/html/Elements/ShowCustomFieldText
index 6955f4a..c0b0d23 100644
--- a/share/html/Elements/ShowCustomFieldText
+++ b/share/html/Elements/ShowCustomFieldText
@@ -47,7 +47,7 @@
 %# END BPS TAGGED BLOCK }}}
 <%init>
  my $content = $object->large_content || $object->content;
- $content = $m->comp('/Elements/ScrubHTML', content => $content);
+ $content = RT::Interface::Web->scrub_html(  $content);
  $content =~ s|\n|<br />|g;
 </%init>
 <%$content|n%>
diff --git a/share/html/Elements/ShowCustomFieldWikitext b/share/html/Elements/ShowCustomFieldWikitext
index 7be0d7d..4567fec 100644
--- a/share/html/Elements/ShowCustomFieldWikitext
+++ b/share/html/Elements/ShowCustomFieldWikitext
@@ -46,7 +46,7 @@
 %# 
 %# END BPS TAGGED BLOCK }}}
 % my $content = $object->large_content || $object->content;
-% $content = $m->comp('/Elements/ScrubHTML', content => $content);
+% $content = RT::Interface::Web->scrub_html( $content);
 % my $base = $object->object->wiki_base;
 % my $wiki_content = Text::WikiFormat::format( $content."\n" , {}, { extended => 1,  absolute_links => 1, implicit_links => RT->config->get('wiki_implicit_links'), prefix => $base} );
 <%$wiki_content|n%>
diff --git a/share/html/Search/Build.html b/share/html/Search/Build.html
index 060801d..a0332f3 100644
--- a/share/html/Search/Build.html
+++ b/share/html/Search/Build.html
@@ -161,7 +161,7 @@ if ($new_query) {
     if ( $query{'format'} ) {
 
         # Clean unwanted junk from the format
-        $query{'format'} = $m->comp( '/Elements/ScrubHTML', content => $query{'format'} );
+		$query{'format'} = RT::Interface::Web->scrub_html( $query{'format'} );
     }
 }
 
diff --git a/share/html/Search/Edit.html b/share/html/Search/Edit.html
index 4c7c467..9e86374 100755
--- a/share/html/Search/Edit.html
+++ b/share/html/Search/Edit.html
@@ -73,7 +73,7 @@
 </&>
 <%INIT>
 my $title = _("Edit Query");
-$format = $m->comp('/Elements/ScrubHTML', content => $format);
+$format = RT::Interface::Web->scrub_html( $format);
 my $query_string = $m->comp('/Elements/QueryString',
                            query   => $query,
                            format  => $format,
diff --git a/share/html/Ticket/Elements/ShowTransactionAttachments b/share/html/Ticket/Elements/ShowTransactionAttachments
index ae63080..28652f0 100644
--- a/share/html/Ticket/Elements/ShowTransactionAttachments
+++ b/share/html/Ticket/Elements/ShowTransactionAttachments
@@ -117,7 +117,7 @@ unless ( ($message->get_header('Content-Disposition')||"") =~ /attachment/i ) {
 
             # if it's a text/html clean the body and show it
             if ( $message->content_type =~ m{^text/(?:html|enriched)$}i ) {
-                $content = $m->comp( '/Elements/ScrubHTML', content => $content );
+                $content = RT::Interface::Web->scrub_html( $content );
                 if ( $message->content_type eq 'text/html' ) {
                     $m->comp('/Elements/MakeClicky', 
                             content => \$content, html => 1 );

commit 5dec3e324f0d46891b4cc0c7a13cfc2a6a879a83
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 16:27:53 2009 -0500

    librarize BuildFormatString

diff --git a/lib/RT/Interface/Web/QueryBuilder.pm b/lib/RT/Interface/Web/QueryBuilder.pm
index a699d67..6eff61f 100644
--- a/lib/RT/Interface/Web/QueryBuilder.pm
+++ b/lib/RT/Interface/Web/QueryBuilder.pm
@@ -312,5 +312,179 @@ sub save_search {
     return @results;
 }
 
+sub build_format_string {
+    my $self = shift;
+    my %args = (
+        format                  => RT->config->get('default_search_result_format'),
+        cfqueues                => undef,
+        face                    => undef,
+        size                    => undef,
+        link                    => undef,
+        title                   => undef,
+        add_col                 => undef,
+        remove_col              => undef,
+        col_up                  => undef,
+        col_down                => undef,
+        select_display_columns  => undef,
+        current_display_columns => undef,
+        @_
+    );
+
+    # All the things we can display in the format string by default
+    my @fields = qw(
+        id queue_name subject
+        status extended_status update_status
+        type owner_name requestors cc admin_cc created_by last_updated_by
+        priority initial_priority final_priority
+        time_worked time_left time_estimated
+        starts      starts_relative
+        started     started_relative
+        created     created_relative
+        last_updated last_updated_relative
+        told        told_relative
+        due         due_relative
+        resolved    resolved_relative
+        refers_to    referred_to_by
+        depends_on   depended_on_by
+        member_of    members
+        parents     children
+        Bookmark
+        NEWLINE     Bookmark
+        );    # loc_qw
+
+    my $CustomFields = RT::Model::CustomFieldCollection->new();
+    foreach my $id ( keys %{$args{cfqueues}} ) {
+
+        # Gotta load up the $queue object, since queues get stored by name now. my $id
+        my $queue = RT::Model::Queue->new();
+        $queue->load($id);
+        unless ( $queue->id ) {
+
+            # XXX TODO: This ancient code dates from a former developer
+            # we have no idea what it means or why cfqueues are so encoded.
+            $id =~ s/^.'*(.*).'*$/$1/;
+            $queue->load($id);
+        }
+        $CustomFields->limit_to_queue( $queue->id );
+    }
+    $CustomFields->limit_to_global;
+
+    while ( my $CustomField = $CustomFields->next ) {
+        push @fields, "custom_field.{" . $CustomField->name . "}";
+    }
+
+    my (@seen);
+
+    my @format = split( /,\s*/, $args{format} );
+    foreach my $field (@format) {
+        my %column = ();
+        $field =~ s/'(.*)'/$1/;
+        my ( $prefix, $suffix );
+        if ( $field =~ m/(.*)__(.*)__(.*)/ ) {
+            $prefix = $1;
+            $suffix = $3;
+            $field  = $2;
+        }
+        $field = "<blank>" if !$field;
+        $column{Prefix} = $prefix;
+        $column{Suffix} = $suffix;
+        $field =~ s/\s*(.*)\s*/$1/;
+        $column{Column} = $field;
+        push @seen, \%column;
+    }
+
+    if ( $args{remove_col} ) {
+
+        # we do this regex match to avoid a non-numeric warning
+        my ($index) = $args{current_display_columns} =~ /^(\d+)/;
+
+        my $column = $seen[$index];
+        if ($index) {
+            delete $seen[$index];
+            my @temp = @seen;
+            @seen = ();
+            foreach my $element (@temp) {
+                next unless $element;
+                push @seen, $element;
+            }
+        }
+    } elsif ( $args{add_col} ) {
+        if ( defined $args{select_display_columns} ) {
+            my $selected = $args{select_display_columns};
+            my @columns;
+            if ( ref($selected) eq 'ARRAY' ) {
+                @columns = @$selected;
+            } else {
+                push @columns, $selected;
+            }
+            foreach my $col (@columns) {
+                my %column = ();
+                $column{Column} = $col;
+
+                if ( $args{face} eq "Bold" ) {
+                    $column{Prefix} .= "<b>";
+                    $column{Suffix} .= "</b>";
+                }
+                if ( $args{face} eq "Italic" ) {
+                    $column{Prefix} .= "<i>";
+                    $column{Suffix} .= "</i>";
+                }
+                if ($args{size}) {
+                    $column{Prefix} .= "<" . Jifty->web->escape($args{size}) . ">";
+                    $column{Suffix} .= "</" . Jifty->web->escape($args{size}) . ">";
+                }
+                if ( $args{link} eq "Display" ) {
+                    $column{Prefix} .= q{<a HREF="__WebPath__/Ticket/Display.html?id=__id__">};
+                    $column{Suffix} .= "</a>";
+                } elsif ( $args{link} eq "Take" ) {
+                    $column{Prefix} .= q{<a HREF="__WebPath__/Ticket/Display.html?Action=Take&id=__id__">};
+                    $column{Suffix} .= "</a>";
+                }
+
+                if ( $args{title} ) {
+                    $column{Suffix} .= "/TITLE:" . Jifty->web->escape( $args{title} );
+                }
+                push @seen, \%column;
+            }
+        }
+    } elsif ( $args{col_up} ) {
+        my $index = $args{current_display_columns};
+        if ( defined $index && ( $index - 1 ) >= 0 ) {
+            my $column = $seen[$index];
+            $seen[$index]                  = $seen[ $index - 1 ];
+            $seen[ $index - 1 ]            = $column;
+            $args{current_display_columns} = $index - 1;
+        }
+    } elsif ( $args{col_down} ) {
+        my $index = $args{current_display_columns};
+        if ( defined $index && ( $index + 1 ) < scalar @seen ) {
+            my $column = $seen[$index];
+            $seen[$index]                  = $seen[ $index + 1 ];
+            $seen[ $index + 1 ]            = $column;
+            $args{current_display_columns} = $index + 1;
+        }
+    }
+
+    my @format_string;
+    foreach my $field (@seen) {
+        next unless $field;
+        my $row = "'";
+        $row .= $field->{'Prefix'} if defined $field->{'Prefix'};
+        $row .= "__" . (
+              $field->{'Column'} =~ m/\(/
+            ? $field->{'Column'}    # func, don't escape
+            : Jifty->web->escape( $field->{'Column'} )
+            )
+            . "__"
+            unless ( $field->{'Column'} eq "<blank>" );
+        $row .= $field->{'Suffix'} if defined $field->{'Suffix'};
+        $row .= "'";
+        push( @format_string, $row );
+    }
+
+    return ( join( ",\n", @format_string ), \@fields, \@seen );
+
+}
+
 
 1;
diff --git a/share/html/Prefs/Search.html b/share/html/Prefs/Search.html
index 8712afa..6e62506 100644
--- a/share/html/Prefs/Search.html
+++ b/share/html/Prefs/Search.html
@@ -98,8 +98,7 @@ $ARGS{'order'} = join '|', grep defined && /\S/, (ref $ARGS{'order'})? @{$ARGS{'
 $ARGS{'order_by'} = join '|', grep defined && /\S/, (ref $ARGS{'order_by'})? @{$ARGS{'order_by'}}: $ARGS{'order_by'};
 
 my ( $AvailableColumns, $current_format );
-( $ARGS{format}, $AvailableColumns, $current_format ) = $m->comp(
-    '/Search/Elements/BuildFormatString',
+( $ARGS{format}, $AvailableColumns, $current_format ) = RT::Interface::Web::QueryBuilder->build_format_string(
     cfqueues => {}, %ARGS
 );
 
diff --git a/share/html/Prefs/SearchOptions.html b/share/html/Prefs/SearchOptions.html
index c92ee4d..2136df7 100644
--- a/share/html/Prefs/SearchOptions.html
+++ b/share/html/Prefs/SearchOptions.html
@@ -96,8 +96,7 @@ $order_by     ||= ($prefs->{'order_by'} || 'id');
 ($rows_per_page =  defined( $prefs->{'rows_per_page'} ) ? $prefs->{'rows_per_page'}  : 50) unless defined ($rows_per_page);
 
 my ( $AvailableColumns, $current_format );
-( $format, $AvailableColumns, $current_format ) = $m->comp(
-    '/Search/Elements/BuildFormatString',
+( $format, $AvailableColumns, $current_format ) = RT::Interface::Web::QueryBuilder->build_format_string(
     %ARGS, format => $format
 );
 </%INIT>
diff --git a/share/html/Search/Build.html b/share/html/Search/Build.html
index a0332f3..bb49c89 100644
--- a/share/html/Search/Build.html
+++ b/share/html/Search/Build.html
@@ -264,8 +264,8 @@ my $queues = $tree->get_referenced_queues;
 
 #  Deal with format changes
 my ( $AvailableColumns, $current_format );
-( $query{'format'}, $AvailableColumns, $current_format ) = $m->comp(
-    'Elements/BuildFormatString',
+
+( $query{'format'}, $AvailableColumns, $current_format ) = RT::Interface::Web::QueryBuilder->build_format_string(
     %ARGS,
     cfqueues => $queues,
     format   => $query{'format'},
diff --git a/share/html/Search/Elements/BuildFormatString b/share/html/Search/Elements/BuildFormatString
deleted file mode 100644
index eca3fd9..0000000
--- a/share/html/Search/Elements/BuildFormatString
+++ /dev/null
@@ -1,230 +0,0 @@
-%# BEGIN BPS TAGGED BLOCK {{{
-%# 
-%# COPYRIGHT:
-%#  
-%# This software is Copyright (c) 1996-2007 Best Practical Solutions, LLC 
-%#                                          <jesse at bestpractical.com>
-%# 
-%# (Except where explicitly superseded by other copyright notices)
-%# 
-%# 
-%# LICENSE:
-%# 
-%# This work is made available to you under the terms of Version 2 of
-%# the GNU General Public License. A copy of that license should have
-%# been provided with this software, but in any event can be snarfed
-%# from www.gnu.org.
-%# 
-%# This work is distributed in the hope that it will be useful, but
-%# WITHOUT ANY WARRANTY; without even the implied warranty of
-%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-%# General Public License for more details.
-%# 
-%# You should have received a copy of the GNU General Public License
-%# along with this program; if not, write to the Free Software
-%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-%# 02110-1301 or visit their web page on the internet at
-%# http://www.gnu.org/copyleft/gpl.html.
-%# 
-%# 
-%# CONTRIBUTION SUBMISSION POLICY:
-%# 
-%# (The following paragraph is not intended to limit the rights granted
-%# to you to modify and distribute this software under the terms of
-%# the GNU General Public License and is only of importance to you if
-%# you choose to contribute your changes and enhancements to the
-%# community by submitting them to Best Practical Solutions, LLC.)
-%# 
-%# By intentionally submitting any modifications, corrections or
-%# derivatives to this work, or any other work intended for use with
-%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
-%# you are the copyright holder for those contributions and you grant
-%# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
-%# royalty-free, perpetual, license to use, copy, create derivative
-%# works based on those contributions, and sublicense and distribute
-%# those contributions and any derivatives thereof.
-%# 
-%# END BPS TAGGED BLOCK }}}
-<%ARGS>
-$format => RT->config->get('default_search_result_format')
-%cfqueues => ()
-$face => undef
-$size => undef
-$link => undef
-$title => undef
-
-$add_col => undef
-$remove_col => undef
-$col_up => undef
-$col_down => undef
-
-$select_display_columns => undef
-$current_display_columns => undef
-</%ARGS>
-
-<%init>
-# This can't be in a <once> block, because otherwise we return the
-# same \@fields every request, and keep tacking more CustomFields onto
-# it -- and it grows per request.
-
-# All the things we can display in the format string by default
-my @fields = qw(
-    id queue_name subject
-    status extended_status update_status
-    type owner_name requestors cc admin_cc created_by last_updated_by
-    priority initial_priority final_priority
-    time_worked time_left time_estimated
-    starts      starts_relative
-    started     started_relative
-    created     created_relative
-    last_updated last_updated_relative
-    told        told_relative
-    due         due_relative
-    resolved    resolved_relative
-    refers_to    referred_to_by
-    depends_on   depended_on_by
-    member_of    members
-    parents     children
-    Bookmark
-    NEWLINE     Bookmark
-); # loc_qw
-
-$m->callback( callback_once => 1, callback_name => 'SetFieldsOnce', Fields => \@fields );
-
-my $CustomFields = RT::Model::CustomFieldCollection->new( current_user => Jifty->web->current_user);
-foreach my $id (keys %cfqueues) {
-    # Gotta load up the $queue object, since queues get stored by name now. my $id
-    my $queue = RT::Model::Queue->new( current_user => Jifty->web->current_user );
-    $queue->load($id);
-    unless ($queue->id) {
-        # XXX TODO: This ancient code dates from a former developer
-        # we have no idea what it means or why cfqueues are so encoded.
-        $id =~ s/^.'*(.*).'*$/$1/;
-        $queue->load($id);
-    }
-    $CustomFields->limit_to_queue($queue->id);
-}
-$CustomFields->limit_to_global;
-
-while ( my $CustomField = $CustomFields->next ) {
-    push @fields, "custom_field.{" . $CustomField->name . "}";
-}
-
-$m->callback( Fields => \@fields, args_ref => \%ARGS );
-
-my ( @seen);
-
-$format ||= RT->config->get('default_search_result_format');
-my @format = split( /,\s*/, $format );
-foreach my $field (@format) {
-    my %column = ();
-    $field =~ s/'(.*)'/$1/;
-    my ( $prefix, $suffix );
-    if ( $field =~ m/(.*)__(.*)__(.*)/ ) {
-        $prefix = $1;
-        $suffix = $3;
-        $field  = $2;
-    }
-    $field = "<blank>" if !$field;
-    $column{Prefix} = $prefix;
-    $column{Suffix} = $suffix;
-    $field =~ s/\s*(.*)\s*/$1/;
-    $column{Column} = $field;
-    push @seen, \%column;
-}
-
-if ( $remove_col ) {
-    # we do this regex match to avoid a non-numeric warning
-    my ($index) = $current_display_columns =~ /^(\d+)/;
-    
-    my $column = $seen[$index];
-    if ($index) {
-        delete $seen[$index];
-        my @temp = @seen;
-        @seen = ();
-        foreach my $element (@temp) {
-            next unless $element;
-            push @seen, $element;
-        }
-    }
-}
-elsif ( $add_col ) {
-    if ( defined $select_display_columns ) {
-        my $selected = $select_display_columns;
-        my @columns;
-        if (ref($selected) eq 'ARRAY') {
-            @columns = @$selected;
-        } else {
-            push @columns, $selected;
-        }
-        foreach my $col (@columns) {
-            my %column = ();
-            $column{Column} = $col;
-
-            if ( $face eq "Bold" ) {
-                $column{Prefix} .= "<b>";
-                $column{Suffix} .= "</b>";
-            }
-            if ( $face eq "Italic" ) {
-                $column{Prefix} .= "<i>";
-                $column{Suffix} .= "</i>";
-            }
-            if ($size) {
-                $column{Prefix} .= "<" . $m->interp->apply_escapes( $size,  'h' ) . ">";
-                $column{Suffix} .= "</" . $m->interp->apply_escapes( $size, 'h' ) . ">";
-            }
-            if ( $link eq "Display" ) {
-                $column{Prefix} .= q{<a HREF="__WebPath__/Ticket/Display.html?id=__id__">};
-                $column{Suffix} .= "</a>";
-            }
-            elsif ( $link eq "Take" ) {
-                $column{Prefix} .= q{<a HREF="__WebPath__/Ticket/Display.html?Action=Take&id=__id__">};
-                $column{Suffix} .= "</a>";
-            }
-
-            if ($title) {
-                $column{Suffix} .= "/TITLE:" . $m->interp->apply_escapes( $title, 'h' );
-            }
-            push @seen, \%column;
-        }
-    }
-}
-elsif ( $col_up ) {
-    my $index = $current_display_columns;
-    if ( defined $index && ( $index - 1 ) >= 0 ) {
-        my $column = $seen[$index];
-        $seen[$index]       = $seen[ $index - 1 ];
-        $seen[ $index - 1 ] = $column;
-        $current_display_columns     = $index - 1;
-    }
-}
-elsif ( $col_down ) {
-    my $index = $current_display_columns;
-    if ( defined $index && ( $index + 1 ) < scalar @seen ) {
-        my $column = $seen[$index];
-        $seen[$index]       = $seen[ $index + 1 ];
-        $seen[ $index + 1 ] = $column;
-        $current_display_columns     = $index + 1;
-    }
-}
-
-
-my @format_string;
-foreach my $field (@seen) {
-    next unless $field;
-    my $row = "'";
-    $row .= $field->{'Prefix'} if defined $field->{'Prefix'};
-    $row .= "__" . ($field->{'Column'} =~ m/\(/ ? $field->{'Column'} # func, don't escape
-		    : $m->interp->apply_escapes( $field->{'Column'}, 'h' )) . "__"
-      unless ( $field->{'Column'} eq "<blank>" );
-    $row .= $field->{'Suffix'} if defined $field->{'Suffix'};
-    $row .= "'";
-    push( @format_string, $row );
-}
-
-$format = join(",\n", @format_string);
-
-
-return($format, \@fields, \@seen);
-
-</%init>

commit bdb999258e08f19d6c5f2b61beb47565d7dd3c47
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 16:29:23 2009 -0500

    remove a mason escaping call

diff --git a/share/html/Search/Build.html b/share/html/Search/Build.html
index bb49c89..5770448 100644
--- a/share/html/Search/Build.html
+++ b/share/html/Search/Build.html
@@ -256,7 +256,7 @@ my $optionlist_arrayref;
 my $optionlist = join "\n", map {
           qq(<option value="$_->{INDEX}" $_->{SELECTED}>)
         . ( "&nbsp;" x ( 5 * $_->{DEPTH} ) )
-        . $m->interp->apply_escapes( $_->{TEXT}, 'h' )
+		. Jifty->web->escape( $_->{TEXT})
         . qq(</option>)
 } @$optionlist_arrayref;
 

commit 6b08e74a1c449cf301154e87bd17ce0c0157d0ca
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 16:48:59 2009 -0500

    incremental refactoring

diff --git a/share/html/Search/Build.html b/share/html/Search/Build.html
index 5770448..7929b74 100644
--- a/share/html/Search/Build.html
+++ b/share/html/Search/Build.html
@@ -106,7 +106,7 @@
 
 <& Elements/DisplayOptions,
     %ARGS, %query,
-    available_columns => $AvailableColumns,
+    available_columns => $available_columns,
     current_format    => $current_format,
 &>
 
@@ -119,12 +119,8 @@
 <%INIT>
 use RT::Interface::Web::QueryBuilder::Tree;
 
-my %query;
-for (qw(query format order_by order rows_per_page)) {
-    $query{$_} = $ARGS{$_};
-}
-
 my %saved_search;
+my %query = map { $_ => $ARGS{$_} } qw(query format order_by order rows_per_page);
 my @actions = RT::Interface::Web::QueryBuilder->load_saved_search( \%ARGS, \%query, \%saved_search );
 
 if ($new_query) {
@@ -157,24 +153,13 @@ if ($new_query) {
         if ( ref $query{$_} eq "ARRAY" ) {
             $query{$_} = join( '|', @{ $query{$_} } );
         }
-    }
-    if ( $query{'format'} ) {
+	}
 
-        # Clean unwanted junk from the format
-		$query{'format'} = RT::Interface::Web->scrub_html( $query{'format'} );
-    }
+	$query{'format'} = RT::Interface::Web->scrub_html( $query{'format'} ) if ( $query{'format'} );
 }
 
-my $parse_query = sub {
-    my ( $string, $results ) = @_;
-
-    my $tree = RT::Interface::Web::QueryBuilder::Tree->new('AND');
-    @$results = $tree->parse_sql( query => $string );
-
-    return $tree;
-};
-
-my $tree = $parse_query->( $query{'query'}, \@actions );
+my $tree = RT::Interface::Web::QueryBuilder::Tree->new('AND');
+push @actions, = $tree->parse_sql( query => $query{query} );
 
 # if parsing went poorly, send them to the edit page to fix it
 if ( $actions[0] ) {
@@ -185,36 +170,35 @@ my @options        = $tree->get_displayed_nodes;
 my @current_values = grep defined, @options[@clauses];
 my @new_values     = ();
 
-#  Try to find if we're adding a clause
 foreach my $arg ( keys %ARGS ) {
-    next
-        unless $arg =~ m/^value_of_(\w+|'CF.{.*?}')$/
-            && (ref $ARGS{$arg} eq "ARRAY"
-                ? grep $_ ne '', @{ $ARGS{$arg} }
-                : $ARGS{$arg} ne ''
-            );
-
-    # We're adding a $1 clause
-    my $field = $1;
+	#  Try to find if we're adding a clause
+    next unless $arg =~ m/^value_of_(\w+|'CF.{.*?}')$/ && (ref $ARGS{$arg} eq "ARRAY" ? grep $_ ne '', @{ $ARGS{$arg} } : $ARGS{$arg} ne '');
 
+    my $field = $1;
     my ( $op, $value );
 
     #figure out if it's a grouping
     my $keyword = $ARGS{ $field . "_field" } || $field;
 
-    my ( @ops, @values );
-    if ( ref $ARGS{ 'value_of_' . $field } eq "ARRAY" ) {
+	my ( @ops, @values );
+
 
+	my $op_name = $field. "_op";
+	my $op_value = 'value_of_'.$field;
+
+    if ( ref $ARGS{$op_value} eq "ARRAY" ) {
         # we have many keys/values to iterate over, because there is
         # more than one CF with the same name.
-        @ops    = @{ $ARGS{ $field . '_op' } };
-        @values = @{ $ARGS{ 'value_of_' . $field } };
+		@ops    = @{ $ARGS{ $op_name } };
+		@values = @{ $ARGS{ $op_value } };
     } else {
-        @ops    = ( $ARGS{ $field . '_op' } );
-        @values = ( $ARGS{ 'value_of_' . $field } );
-    }
-    Jifty->log->error("Bad Parameters passed into Query Builder")
-        unless @ops == @values;
+        @ops    = ( $ARGS{ $op_name } );
+		@values = ( $ARGS{ $op_value } );
+	}
+
+
+
+    Jifty->log->error("Bad Parameters passed into Query Builder") unless @ops == @values;
 
     for ( my $i = 0; $i < @ops; $i++ ) {
         my ( $op, $value ) = ( $ops[$i], $values[$i] );
@@ -257,15 +241,14 @@ my $optionlist = join "\n", map {
           qq(<option value="$_->{INDEX}" $_->{SELECTED}>)
         . ( "&nbsp;" x ( 5 * $_->{DEPTH} ) )
 		. Jifty->web->escape( $_->{TEXT})
-        . qq(</option>)
-} @$optionlist_arrayref;
+        . qq(</option>) } @$optionlist_arrayref;
 
 my $queues = $tree->get_referenced_queues;
 
 #  Deal with format changes
-my ( $AvailableColumns, $current_format );
+my ( $available_columns, $current_format );
 
-( $query{'format'}, $AvailableColumns, $current_format ) = RT::Interface::Web::QueryBuilder->build_format_string(
+( $query{'format'}, $available_columns, $current_format ) = RT::Interface::Web::QueryBuilder->build_format_string(
     %ARGS,
     cfqueues => $queues,
     format   => $query{'format'},
@@ -276,8 +259,7 @@ push @actions, RT::Interface::Web::QueryBuilder->save_search( \%ARGS, \%query, \
 
 #  Push the updates into the session so we don't loose 'em
 
-Jifty->web->session->set(
-    'CurrentSearchHash',
+Jifty->web->session->set( 'CurrentSearchHash',
     {   %query,
         search_id   => $saved_search{'id'},
         object      => $saved_search{'object'},

commit 2fad999bd772e8e4cf7a113c7a96e8124486874a
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 16:50:24 2009 -0500

    incremental refactoring

diff --git a/share/html/Search/Build.html b/share/html/Search/Build.html
index 7929b74..6a77a0c 100644
--- a/share/html/Search/Build.html
+++ b/share/html/Search/Build.html
@@ -186,15 +186,10 @@ foreach my $arg ( keys %ARGS ) {
 	my $op_name = $field. "_op";
 	my $op_value = 'value_of_'.$field;
 
-    if ( ref $ARGS{$op_value} eq "ARRAY" ) {
-        # we have many keys/values to iterate over, because there is
-        # more than one CF with the same name.
-		@ops    = @{ $ARGS{ $op_name } };
-		@values = @{ $ARGS{ $op_value } };
-    } else {
-        @ops    = ( $ARGS{ $op_name } );
-		@values = ( $ARGS{ $op_value } );
-	}
+        # we may have many keys/values to iterate over, because there
+        # may be more than one CF with the same name.
+		@ops    = ref $ARGS{$op_value} ? @{ $ARGS{ $op_name } } : $ARGS{$op_name};
+		@values    = ref $ARGS{$op_value} ? @{ $ARGS{ $op_value } } : $ARGS{$op_value};
 
 
 

commit d85893c906619d110c6f71a2ad70144b89fb120a
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 16:50:42 2009 -0500

    perltidy

diff --git a/share/html/Search/Build.html b/share/html/Search/Build.html
index 6a77a0c..4ca110e 100644
--- a/share/html/Search/Build.html
+++ b/share/html/Search/Build.html
@@ -171,8 +171,11 @@ my @current_values = grep defined, @options[@clauses];
 my @new_values     = ();
 
 foreach my $arg ( keys %ARGS ) {
-	#  Try to find if we're adding a clause
-    next unless $arg =~ m/^value_of_(\w+|'CF.{.*?}')$/ && (ref $ARGS{$arg} eq "ARRAY" ? grep $_ ne '', @{ $ARGS{$arg} } : $ARGS{$arg} ne '');
+
+    #  Try to find if we're adding a clause
+    next
+        unless $arg =~ m/^value_of_(\w+|'CF.{.*?}')$/
+            && ( ref $ARGS{$arg} eq "ARRAY" ? grep $_ ne '', @{ $ARGS{$arg} } : $ARGS{$arg} ne '' );
 
     my $field = $1;
     my ( $op, $value );
@@ -180,18 +183,15 @@ foreach my $arg ( keys %ARGS ) {
     #figure out if it's a grouping
     my $keyword = $ARGS{ $field . "_field" } || $field;
 
-	my ( @ops, @values );
-
-
-	my $op_name = $field. "_op";
-	my $op_value = 'value_of_'.$field;
-
-        # we may have many keys/values to iterate over, because there
-        # may be more than one CF with the same name.
-		@ops    = ref $ARGS{$op_value} ? @{ $ARGS{ $op_name } } : $ARGS{$op_name};
-		@values    = ref $ARGS{$op_value} ? @{ $ARGS{ $op_value } } : $ARGS{$op_value};
+    my ( @ops, @values );
 
+    my $op_name  = $field . "_op";
+    my $op_value = 'value_of_' . $field;
 
+    # we may have many keys/values to iterate over, because there
+    # may be more than one CF with the same name.
+    @ops    = ref $ARGS{$op_value} ? @{ $ARGS{$op_name} }  : $ARGS{$op_name};
+    @values = ref $ARGS{$op_value} ? @{ $ARGS{$op_value} } : $ARGS{$op_value};
 
     Jifty->log->error("Bad Parameters passed into Query Builder") unless @ops == @values;
 

commit 8da265dd6181ffc9f22a42ee14fcf0fb6adb3df1
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 16:52:01 2009 -0500

    typo fix

diff --git a/share/html/Search/Build.html b/share/html/Search/Build.html
index 4ca110e..df6b6c3 100644
--- a/share/html/Search/Build.html
+++ b/share/html/Search/Build.html
@@ -159,7 +159,7 @@ if ($new_query) {
 }
 
 my $tree = RT::Interface::Web::QueryBuilder::Tree->new('AND');
-push @actions, = $tree->parse_sql( query => $query{query} );
+push @actions, $tree->parse_sql( query => $query{query} );
 
 # if parsing went poorly, send them to the edit page to fix it
 if ( $actions[0] ) {

commit e08153afd1ace3939b1cf17b36a2c91b9b10209d
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 17:38:26 2009 -0500

    remove a temp variable

diff --git a/share/html/Search/Build.html b/share/html/Search/Build.html
index df6b6c3..d2660b1 100644
--- a/share/html/Search/Build.html
+++ b/share/html/Search/Build.html
@@ -214,13 +214,13 @@ foreach my $arg ( keys %ARGS ) {
             $value = "'$value'" unless $value =~ /^\d+$/;
         }
 
-        my $clause = {
-            Key   => $keyword,
-            Op    => $op,
-            Value => $value
-        };
+        push @new_values, RT::Interface::Web::QueryBuilder::Tree->new(
+            {   Key   => $keyword,
+                Op    => $op,
+                Value => $value
+            }
 
-        push @new_values, RT::Interface::Web::QueryBuilder::Tree->new($clause);
+        );
     }
 }
 

commit d3229b63b34c22e0561a12606da939a5dd4f7f3e
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 18:00:10 2009 -0500

    remove a workaround for a bug 4 years ago

diff --git a/share/html/Search/Build.html b/share/html/Search/Build.html
index d2660b1..059f5a6 100644
--- a/share/html/Search/Build.html
+++ b/share/html/Search/Build.html
@@ -205,10 +205,6 @@ foreach my $arg ( keys %ARGS ) {
             } elsif ( $op eq '!=' ) {
                 $op = "IS NOT";
             }
-
-            # This is not "right", but...
-            # It has to be this way until #5182 is fixed
-            $value = "'NULL'";
         } else {
             $value =~ s/'/\\'/g;
             $value = "'$value'" unless $value =~ /^\d+$/;

commit ebcaa03b0845f2dd435b97ec642504cd6e225bc1
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 18:01:11 2009 -0500

    one more line down

diff --git a/share/html/Search/Build.html b/share/html/Search/Build.html
index 059f5a6..1e7ba36 100644
--- a/share/html/Search/Build.html
+++ b/share/html/Search/Build.html
@@ -183,15 +183,13 @@ foreach my $arg ( keys %ARGS ) {
     #figure out if it's a grouping
     my $keyword = $ARGS{ $field . "_field" } || $field;
 
-    my ( @ops, @values );
-
     my $op_name  = $field . "_op";
     my $op_value = 'value_of_' . $field;
 
     # we may have many keys/values to iterate over, because there
     # may be more than one CF with the same name.
-    @ops    = ref $ARGS{$op_value} ? @{ $ARGS{$op_name} }  : $ARGS{$op_name};
-    @values = ref $ARGS{$op_value} ? @{ $ARGS{$op_value} } : $ARGS{$op_value};
+    my @ops    = ref $ARGS{$op_value} ? @{ $ARGS{$op_name} }  : $ARGS{$op_name};
+    my @values = ref $ARGS{$op_value} ? @{ $ARGS{$op_value} } : $ARGS{$op_value};
 
     Jifty->log->error("Bad Parameters passed into Query Builder") unless @ops == @values;
 

commit 306d05b930d472069e5b0b9e848976f91a8985e2
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 18:01:25 2009 -0500

    runtime bad web params don't merit logged errors

diff --git a/share/html/Search/Build.html b/share/html/Search/Build.html
index 1e7ba36..4f31560 100644
--- a/share/html/Search/Build.html
+++ b/share/html/Search/Build.html
@@ -191,7 +191,7 @@ foreach my $arg ( keys %ARGS ) {
     my @ops    = ref $ARGS{$op_value} ? @{ $ARGS{$op_name} }  : $ARGS{$op_name};
     my @values = ref $ARGS{$op_value} ? @{ $ARGS{$op_value} } : $ARGS{$op_value};
 
-    Jifty->log->error("Bad Parameters passed into Query Builder") unless @ops == @values;
+    Jifty->log->debug("Bad Parameters passed into Query Builder") unless @ops == @values;
 
     for ( my $i = 0; $i < @ops; $i++ ) {
         my ( $op, $value ) = ( $ops[$i], $values[$i] );

commit 2df7ebc690749164e85d6b7b8be9dca3f6c0c21a
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 18:02:52 2009 -0500

    declared and then not used

diff --git a/share/html/Search/Build.html b/share/html/Search/Build.html
index 4f31560..0c9b3fa 100644
--- a/share/html/Search/Build.html
+++ b/share/html/Search/Build.html
@@ -178,7 +178,6 @@ foreach my $arg ( keys %ARGS ) {
             && ( ref $ARGS{$arg} eq "ARRAY" ? grep $_ ne '', @{ $ARGS{$arg} } : $ARGS{$arg} ne '' );
 
     my $field = $1;
-    my ( $op, $value );
 
     #figure out if it's a grouping
     my $keyword = $ARGS{ $field . "_field" } || $field;

commit 0ee30e6a7ea5de1d39c2787730942df03ab92c0a
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 18:05:29 2009 -0500

    removed unneeded lines

diff --git a/lib/RT/Interface/Web.pm b/lib/RT/Interface/Web.pm
index ea1842f..06af369 100755
--- a/lib/RT/Interface/Web.pm
+++ b/lib/RT/Interface/Web.pm
@@ -66,7 +66,6 @@ use RT::System;
 use RT::SavedSearches;
 use RT::Interface::Web::QueryBuilder;
 
-
 use URI qw();
 use Digest::MD5 ();
 use Encode qw();
diff --git a/share/html/Search/Build.html b/share/html/Search/Build.html
index 0c9b3fa..24af53b 100644
--- a/share/html/Search/Build.html
+++ b/share/html/Search/Build.html
@@ -217,7 +217,6 @@ foreach my $arg ( keys %ARGS ) {
     }
 }
 
-use RT::Interface::Web::QueryBuilder;
 push @actions, RT::Interface::Web::QueryBuilder->process_query( \%ARGS, $tree, \@current_values, \@new_values, );
 
 #  Rebuild $Query based on the additions / movements

commit 8c36128ee57e7e9d525a63d1e42a0a8177ec165f
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 18:32:08 2009 -0500

    redirect rather than fall through for results display

diff --git a/share/html/Search/Build.html b/share/html/Search/Build.html
index 24af53b..fb5a638 100644
--- a/share/html/Search/Build.html
+++ b/share/html/Search/Build.html
@@ -153,9 +153,9 @@ if ($new_query) {
         if ( ref $query{$_} eq "ARRAY" ) {
             $query{$_} = join( '|', @{ $query{$_} } );
         }
-	}
+    }
 
-	$query{'format'} = RT::Interface::Web->scrub_html( $query{'format'} ) if ( $query{'format'} );
+    $query{'format'} = RT::Interface::Web->scrub_html( $query{'format'} ) if ( $query{'format'} );
 }
 
 my $tree = RT::Interface::Web::QueryBuilder::Tree->new('AND');
@@ -227,7 +227,7 @@ my $optionlist_arrayref;
 my $optionlist = join "\n", map {
           qq(<option value="$_->{INDEX}" $_->{SELECTED}>)
         . ( "&nbsp;" x ( 5 * $_->{DEPTH} ) )
-		. Jifty->web->escape( $_->{TEXT})
+        . Jifty->web->escape( $_->{TEXT})
         . qq(</option>) } @$optionlist_arrayref;
 
 my $queues = $tree->get_referenced_queues;
@@ -257,8 +257,9 @@ Jifty->web->session->set( 'CurrentSearchHash',
 #  Show the results, if we were asked.
 
 if ( $ARGS{'do_search'} ) {
-    $m->comp( 'Results.html', %query );
-    $m->abort;
+    Jifty->web->redirect( Jifty->web->url . "Search/Results.html?" . 
+                          RT::Interface::Web->format_query_params(%query) );
+
 }
 
 #  Build a query_string for the tabs

commit e75caec4ea20db7b5f229bb40c8a6f8d9a5b8f53
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 18:33:03 2009 -0500

    kill a bandaid we haven't needed in a looong time.

diff --git a/share/html/Search/Build.html b/share/html/Search/Build.html
index fb5a638..63acca5 100644
--- a/share/html/Search/Build.html
+++ b/share/html/Search/Build.html
@@ -161,10 +161,6 @@ if ($new_query) {
 my $tree = RT::Interface::Web::QueryBuilder::Tree->new('AND');
 push @actions, $tree->parse_sql( query => $query{query} );
 
-# if parsing went poorly, send them to the edit page to fix it
-if ( $actions[0] ) {
-    return $m->comp( "Edit.html", query => $query{'query'}, actions => \@actions );
-}
 
 my @options        = $tree->get_displayed_nodes;
 my @current_values = grep defined, @options[@clauses];

commit 69ef54528958856f7f5727d9f1bf2b86e1e2d38b
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 18:43:25 2009 -0500

    saved_search is now a ref

diff --git a/share/html/Search/Build.html b/share/html/Search/Build.html
index 63acca5..fd9ea3e 100644
--- a/share/html/Search/Build.html
+++ b/share/html/Search/Build.html
@@ -70,11 +70,11 @@
     current_tab => "Search/Build.html?".$query_string, 
     title => _("Query Builder"),
     %query,
-    saved_search_id => $saved_search{'id'},
+	saved_search_id => $saved_search->{'id'},
 &>
 
 <form method="post" action="Build.html" name="build_query">
-<input type="hidden" class="hidden" name="saved_search_id" value="<% $saved_search{'id'} %>" />
+	<input type="hidden" class="hidden" name="saved_search_id" value="<% $saved_search->{'id'} %>" />
 <input type="hidden" class="hidden" name="query" value="<% $query{'query'} %>" />
 <input type="hidden" class="hidden" name="format" value="<% $query{'format'} %>" />
 
@@ -93,11 +93,11 @@
     %ARGS,
     actions => \@actions,
     optionlist => $optionlist,
-    description => $saved_search{'description'},
+	description => $saved_search->{'description'},
     &>
 </div>
 <div id="editsearches">
-    <& Elements/EditSearches, %saved_search, current_search => \%query &>
+    <& Elements/EditSearches, %$saved_search, current_search => \%query &>
 </div>
 
 
@@ -119,21 +119,19 @@
 <%INIT>
 use RT::Interface::Web::QueryBuilder::Tree;
 
-my %saved_search;
+my $saved_search;
 my %query = map { $_ => $ARGS{$_} } qw(query format order_by order rows_per_page);
-my @actions = RT::Interface::Web::QueryBuilder->load_saved_search( \%ARGS, \%query, \%saved_search );
+my @actions = RT::Interface::Web::QueryBuilder->load_saved_search( \%ARGS, \%query, $saved_search );
 
 if ($new_query) {
 
     # Wipe all data-carrying variables clear if we want a new
     # search, or we're deleting an old one..
     %query = ();
-    %saved_search = ( id => 'new' );
+	$saved_search = { id => 'new'};
 
-    # ..then wipe the session out..
+    # ..then wipe the sessionand the search results.
     Jifty->web->session->remove('CurrentSearchHash');
-
-    # ..and the search results.
     Jifty->web->session->get('tickets')->clean_slate if defined Jifty->web->session->get('tickets');
 }
 
@@ -238,15 +236,15 @@ my ( $available_columns, $current_format );
 );
 
 # if we're asked to save the current search, save it
-push @actions, RT::Interface::Web::QueryBuilder->save_search( \%ARGS, \%query, \%saved_search );
+push @actions, RT::Interface::Web::QueryBuilder->save_search( \%ARGS, \%query, $saved_search );
 
 #  Push the updates into the session so we don't loose 'em
 
 Jifty->web->session->set( 'CurrentSearchHash',
     {   %query,
-        search_id   => $saved_search{'id'},
-        object      => $saved_search{'object'},
-        description => $saved_search{'description'},
+	search_id   => $saved_search->{'id'},
+	object      => $saved_search->{'object'},
+	description => $saved_search->{'description'},
     }
 );
 

commit 54dcf157b1c57a3b629df808a769ac3784cfa1b8
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 18:44:16 2009 -0500

    factor out a "use" line

diff --git a/lib/RT/Interface/Web.pm b/lib/RT/Interface/Web.pm
index 06af369..c06d800 100755
--- a/lib/RT/Interface/Web.pm
+++ b/lib/RT/Interface/Web.pm
@@ -65,6 +65,7 @@ use RT::Report::Tickets;
 use RT::System;
 use RT::SavedSearches;
 use RT::Interface::Web::QueryBuilder;
+use RT::Interface::Web::QueryBuilder::Tree;
 
 use URI qw();
 use Digest::MD5 ();
diff --git a/share/html/Search/Build.html b/share/html/Search/Build.html
index fd9ea3e..a81ce5d 100644
--- a/share/html/Search/Build.html
+++ b/share/html/Search/Build.html
@@ -117,8 +117,6 @@
 
 </&>
 <%INIT>
-use RT::Interface::Web::QueryBuilder::Tree;
-
 my $saved_search;
 my %query = map { $_ => $ARGS{$_} } qw(query format order_by order rows_per_page);
 my @actions = RT::Interface::Web::QueryBuilder->load_saved_search( \%ARGS, \%query, $saved_search );

commit 40c61ed0e4c87ccf57b78dab641c3408e1c97bc2
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 19:06:40 2009 -0500

    remove unneeded current_user

diff --git a/share/html/Search/Elements/DisplayOptions b/share/html/Search/Elements/DisplayOptions
index 36d8c47..797e3e6 100644
--- a/share/html/Search/Elements/DisplayOptions
+++ b/share/html/Search/Elements/DisplayOptions
@@ -101,7 +101,7 @@ selected="selected"
 </&>
 
 <%INIT>
-my $tickets = RT::Model::TicketCollection->new( current_user => Jifty->web->current_user );
+my $tickets = RT::Model::TicketCollection->new( );
 my %fields = %{$tickets->columns};
 map { $fields{$_}->[0] =~ /^(?:ENUM|INT|DATE|STRING|ID)$/ || delete $fields{$_} } keys %fields;
 delete $fields{'effective_id'};

commit a16b6af4b3ab91a3ea42757dcc24d479b192e155
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 19:12:56 2009 -0500

    don't stomp the default format

diff --git a/lib/RT/Interface/Web/QueryBuilder.pm b/lib/RT/Interface/Web/QueryBuilder.pm
index 6eff61f..87fe764 100644
--- a/lib/RT/Interface/Web/QueryBuilder.pm
+++ b/lib/RT/Interface/Web/QueryBuilder.pm
@@ -315,7 +315,7 @@ sub save_search {
 sub build_format_string {
     my $self = shift;
     my %args = (
-        format                  => RT->config->get('default_search_result_format'),
+        format                  => undef,
         cfqueues                => undef,
         face                    => undef,
         size                    => undef,
@@ -329,6 +329,9 @@ sub build_format_string {
         current_display_columns => undef,
         @_
     );
+		
+	
+	$args{format} = RT->config->get('default_search_result_format') unless $args{format};
 
     # All the things we can display in the format string by default
     my @fields = qw(

commit 33ddbccf5e829b20cecbdd2333365c8627a0fe9b
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 19:13:32 2009 -0500

    warning avoidance

diff --git a/share/html/Search/Build.html b/share/html/Search/Build.html
index a81ce5d..928fbbc 100644
--- a/share/html/Search/Build.html
+++ b/share/html/Search/Build.html
@@ -74,9 +74,9 @@
 &>
 
 <form method="post" action="Build.html" name="build_query">
-	<input type="hidden" class="hidden" name="saved_search_id" value="<% $saved_search->{'id'} %>" />
-<input type="hidden" class="hidden" name="query" value="<% $query{'query'} %>" />
-<input type="hidden" class="hidden" name="format" value="<% $query{'format'} %>" />
+<input type="hidden" class="hidden" name="saved_search_id" value="<% $saved_search->{'id'} || '' %>" />
+<input type="hidden" class="hidden" name="query" value="<% $query{'query'} || '' %>" />
+<input type="hidden" class="hidden" name="format" value="<% $query{'format'} || '' %>" />
 
 
 

commit f39e4e7ae94956e2928553aa0cc36b34164b8e26
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 19:16:07 2009 -0500

    capitalization fix

diff --git a/share/html/Ticket/Elements/Tabs b/share/html/Ticket/Elements/Tabs
index 0f21125..d12f63c 100755
--- a/share/html/Ticket/Elements/Tabs
+++ b/share/html/Ticket/Elements/Tabs
@@ -270,7 +270,7 @@ $has_query = 1 if ( $ARGS{'query'} or Jifty->web->session->get('CurrentSearchHas
     $args = "?" . $m->comp( '/Elements/QueryString', %query_args );
 
 $tabs->{"f"} = {
-    path  => "Search/Build.html?NewQuery=1",
+    path  => "Search/Build.html?new_query=1",
     title => _('New Search')
 };
 $tabs->{"g"} = {

commit 20fdc5f179a20f0adc1530f2675a216d9afbcf6a
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 19:19:57 2009 -0500

    minor refactoring to reuse a compiled query string

diff --git a/share/html/Search/Build.html b/share/html/Search/Build.html
index 928fbbc..5e4537b 100644
--- a/share/html/Search/Build.html
+++ b/share/html/Search/Build.html
@@ -247,22 +247,19 @@ Jifty->web->session->set( 'CurrentSearchHash',
 );
 
 #  Show the results, if we were asked.
-
-if ( $ARGS{'do_search'} ) {
-    Jifty->web->redirect( Jifty->web->url . "Search/Results.html?" . 
-                          RT::Interface::Web->format_query_params(%query) );
-
-}
+my $query_string = '';
 
 #  Build a query_string for the tabs
-
-my $query_string = '';
 if ($new_query) {
     $query_string = 'new_query=1';
 } elsif ( $query{'query'} ) {
     $query_string = RT::Interface::Web->format_query_params(%query);
 }
 
+if ( $ARGS{'do_search'} ) {
+	Jifty->web->redirect( Jifty->web->url . "Search/Results.html?" .$query_string;
+}
+
 </%INIT>
 
 <%ARGS>

commit eb5083994f781813f051dc19e41c0aad194ba291
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 20:44:10 2009 -0500

    fix a missing paren

diff --git a/share/html/Search/Build.html b/share/html/Search/Build.html
index 5e4537b..473843f 100644
--- a/share/html/Search/Build.html
+++ b/share/html/Search/Build.html
@@ -117,7 +117,7 @@
 
 </&>
 <%INIT>
-my $saved_search;
+my $saved_search = {};
 my %query = map { $_ => $ARGS{$_} } qw(query format order_by order rows_per_page);
 my @actions = RT::Interface::Web::QueryBuilder->load_saved_search( \%ARGS, \%query, $saved_search );
 
@@ -257,7 +257,7 @@ if ($new_query) {
 }
 
 if ( $ARGS{'do_search'} ) {
-	Jifty->web->redirect( Jifty->web->url . "Search/Results.html?" .$query_string;
+	Jifty->web->redirect( Jifty->web->url . "Search/Results.html?" .$query_string);
 }
 
 </%INIT>

commit 3c5392a734b770de304a9aabb245b42bb471ee72
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 20:44:22 2009 -0500

    refactor saved-search loading code

diff --git a/lib/RT/Interface/Web.pm b/lib/RT/Interface/Web.pm
index c06d800..c7f4a14 100755
--- a/lib/RT/Interface/Web.pm
+++ b/lib/RT/Interface/Web.pm
@@ -1488,37 +1488,6 @@ sub get_column_map_entry {
     return undef;
 }
 
-=head2 _load_container_object ( $type, $id );
-
-Instantiate container object for saving searches.
-
-=cut
-
-sub _load_container_object {
-    my ( $obj_type, $obj_id ) = @_;
-    return RT::SavedSearch->new()->_load_privacy_object( $obj_type, $obj_id );
-}
-
-=head2 _parse_saved_search ( $arg );
-
-Given a serialization string for saved search, and returns the
-container object and the search id.
-
-=cut
-
-sub _parse_saved_search {
-    my $spec = shift;
-    return unless $spec;
-    if ( $spec !~ /^(.*?)-(\d+)-SavedSearch-(\d+)$/ ) {
-        return;
-    }
-    my $obj_type  = $1;
-    my $obj_id    = $2;
-    my $search_id = $3;
-
-    return ( _load_container_object( $obj_type, $obj_id ), $search_id );
-}
-
 =head2 get_jifty_messages
 
 =cut
diff --git a/lib/RT/Interface/Web/QueryBuilder.pm b/lib/RT/Interface/Web/QueryBuilder.pm
index 87fe764..92f84c3 100644
--- a/lib/RT/Interface/Web/QueryBuilder.pm
+++ b/lib/RT/Interface/Web/QueryBuilder.pm
@@ -179,7 +179,7 @@ sub load_saved_search {
     }
 
     if ( $ARGS->{'saved_search_load'} ) {
-        my ( $container, $id ) = _parse_saved_search( $ARGS->{'saved_search_load'} );
+        my ( $container, $id ) = RT::Interface::Web::QueryBuilder::_parse_saved_search( $ARGS->{'saved_search_load'} );
         my $search = $container->attributes->with_id($id);
 
         $saved_search->{'id'}          = $ARGS->{'saved_search_load'};
@@ -195,7 +195,7 @@ sub load_saved_search {
     } elsif ( $ARGS->{'saved_search_delete'} ) {
 
         # We set $SearchId to 'new' above already, so peek into the %ARGS
-        my ( $container, $id ) = _parse_saved_search( $saved_search->{'id'} );
+        my ( $container, $id ) = RT::Interface::Web::QueryBuilder::_parse_saved_search( $saved_search->{'id'} );
         if ( $container && $container->id ) {
 
             # We have the object the entry is an attribute on; delete the entry...
@@ -206,7 +206,7 @@ sub load_saved_search {
         $saved_search->{'description'} = undef;
         push @results, _("Deleted saved search");
     } elsif ( $ARGS->{'saved_search_copy'} ) {
-        my ( $container, $id ) = _parse_saved_search( $ARGS->{'saved_search_id'} );
+        my ( $container, $id ) = RT::Interface::Web::QueryBuilder::_parse_saved_search( $ARGS->{'saved_search_id'} );
         $saved_search->{'object'} = $container->attributes->withid($id);
         if (   $ARGS->{'saved_search_description'}
             && $ARGS->{'saved_search_description'} ne $saved_search->{'object'}->description )
@@ -223,11 +223,10 @@ sub load_saved_search {
         && $saved_search->{'id'} ne 'new'
         && !$saved_search->{'object'} )
     {
-        my ( $container, $id ) = _parse_saved_search( $ARGS->{'saved_search_id'} );
+        my ( $container, $id ) = RT::Interface::Web::QueryBuilder::_parse_saved_search( $ARGS->{'saved_search_id'} );
         $saved_search->{'object'} = $container->attributes->with_id($id);
         $saved_search->{'description'} ||= $saved_search->{'object'}->description;
     }
-
     return @results;
 }
 
@@ -245,7 +244,6 @@ sub save_search {
     my $obj  = $saved_search->{'object'};
     my $id   = $saved_search->{'id'};
     my $desc = $saved_search->{'description'};
-
     my $privacy = $saved_search->{'Privacy'};
 
     my %params = map { $_ => $query->{$_} } @$search_fields;
@@ -312,6 +310,38 @@ sub save_search {
     return @results;
 }
 
+=head2 _parse_saved_search ( $arg );
+
+Given a serialization string for saved search, and returns the
+container object and the search id.
+
+=cut
+
+sub _parse_saved_search {
+    my $spec = shift;
+    return unless $spec;
+    if ( $spec !~ /^(.*?)-(\d+)-SavedSearch-(\d+)$/ ) {
+        return;
+    }
+    my $obj_type  = $1;
+    my $obj_id    = $2;
+    my $search_id = $3;
+
+    return ( _load_container_object( $obj_type, $obj_id ), $search_id );
+}
+
+=head2 _load_container_object ( $type, $id );
+
+Instantiate container object for saving searches.
+
+=cut
+
+sub _load_container_object {
+    my ( $obj_type, $obj_id ) = @_;
+    return RT::SavedSearch->new()->_load_privacy_object( $obj_type, $obj_id );
+}
+
+
 sub build_format_string {
     my $self = shift;
     my %args = (
diff --git a/share/html/Elements/ShowSearch b/share/html/Elements/ShowSearch
index 9a7ff67..a946cc6 100644
--- a/share/html/Elements/ShowSearch
+++ b/share/html/Elements/ShowSearch
@@ -63,7 +63,7 @@ my $query_display_component = '/Elements/CollectionList';
 my $query_link_url = RT->config->get('web_path').'/Search/Results.html';
 
 if ($saved_search) {
-    my ( $container_object, $search_id ) = _parse_saved_search($saved_search);
+    my ( $container_object, $search_id ) = RT::Interface::Web::QueryBuilder::_parse_saved_search($saved_search);
     unless ( $container_object ) {
         $m->out(_("Either you have no rights to view saved search %1 or identifier is incorrect", $saved_search));
         return;
diff --git a/share/html/Widgets/SavedSearch b/share/html/Widgets/SavedSearch
index 7185c0f..bf421e9 100644
--- a/share/html/Widgets/SavedSearch
+++ b/share/html/Widgets/SavedSearch
@@ -62,7 +62,7 @@ push @objects, RT::System->new()
 $self->{SearchId} ||= 'new';
 my $search_params = { map { $_ => $args->{$_} } @{$self->{SearchFields}} };
 
-if ( my ( $container_object, $search_id ) = _parse_saved_search( $args->{'SavedSearchLoad'} ) ) {
+if ( my ( $container_object, $search_id ) = RT::Interface::Web::QueryBuilder::_parse_saved_search( $args->{'SavedSearchLoad'} ) ) {
     my $search = $container_object->attributes->with_id($search_id);
     # We have a $search and now; import the others
     $self->{SearchId} = $args->{'SavedSearchLoad'};

commit 0e1481c9637a9a3c86dbd062f58b18c518c84030
Merge: 3c5392a 89cba24
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Nov 5 20:47:22 2009 -0500

    Merge commit 'origin/3.999-trunk' into librarize-search-logic
    
    * commit 'origin/3.999-trunk':
      update utf8 tests
      Avoid confusing $date->diff logic
      Methods for whether an RT::DateTime is in the past or future
      This is a no-op, SetupWizard already wires up its templates


-----------------------------------------------------------------------


More information about the Rt-commit mailing list